]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Dave Chinner <david@fromorbit.com> |
2 | Subject: [XFS] handle memory allocation failures during log initialisation | |
3 | References: bnc#450658 | |
4 | Patch-mainline: ? | |
5 | ||
6 | When there is no memory left in the system, xfs_buf_get_noaddr() | |
7 | can fail. If this happens at mount time during xlog_alloc_log() | |
8 | we fail to catch the error and oops. | |
9 | ||
10 | Catch the error from xfs_buf_get_noaddr(), and allow other memory | |
11 | allocations to fail and catch those errors too. Report the error | |
12 | to the console and fail the mount with ENOMEM. | |
13 | ||
14 | Tested by manually injecting errors into xfs_buf_get_noaddr() and | |
15 | xlog_alloc_log(). | |
16 | ||
17 | Version 2: | |
18 | o remove unnecessary casts of the returned pointer from kmem_zalloc() | |
19 | ||
20 | SGI-PV: 987246 | |
21 | ||
22 | Signed-off-by: Dave Chinner <david@fromorbit.com> | |
23 | Reviewed-by: Christoph Hellwig <hch@lst.de> | |
24 | Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> | |
25 | Acked-by: Jan Kara <jack@suse.cz> | |
26 | ||
27 | diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c | |
28 | index 5184017..92c20a8 100644 | |
29 | --- a/fs/xfs/xfs_log.c | |
30 | +++ b/fs/xfs/xfs_log.c | |
31 | @@ -563,6 +563,11 @@ xfs_log_mount( | |
32 | } | |
33 | ||
34 | mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); | |
35 | + if (!mp->m_log) { | |
36 | + cmn_err(CE_WARN, "XFS: Log allocation failed: No memory!"); | |
37 | + error = ENOMEM; | |
38 | + goto out; | |
39 | + } | |
40 | ||
41 | /* | |
42 | * Initialize the AIL now we have a log. | |
43 | @@ -601,6 +606,7 @@ xfs_log_mount( | |
44 | return 0; | |
45 | error: | |
46 | xfs_log_unmount_dealloc(mp); | |
47 | +out: | |
48 | return error; | |
49 | } /* xfs_log_mount */ | |
50 | ||
51 | @@ -1217,7 +1223,9 @@ xlog_alloc_log(xfs_mount_t *mp, | |
52 | int i; | |
53 | int iclogsize; | |
54 | ||
55 | - log = (xlog_t *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP); | |
56 | + log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL); | |
57 | + if (!log) | |
58 | + return NULL; | |
59 | ||
60 | log->l_mp = mp; | |
61 | log->l_targ = log_target; | |
62 | @@ -1249,6 +1257,8 @@ xlog_alloc_log(xfs_mount_t *mp, | |
63 | xlog_get_iclog_buffer_size(mp, log); | |
64 | ||
65 | bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp); | |
66 | + if (!bp) | |
67 | + goto out_free_log; | |
68 | XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); | |
69 | XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); | |
70 | XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); | |
71 | @@ -1275,13 +1285,17 @@ xlog_alloc_log(xfs_mount_t *mp, | |
72 | iclogsize = log->l_iclog_size; | |
73 | ASSERT(log->l_iclog_size >= 4096); | |
74 | for (i=0; i < log->l_iclog_bufs; i++) { | |
75 | - *iclogp = (xlog_in_core_t *) | |
76 | - kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); | |
77 | + *iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL); | |
78 | + if (!*iclogp) | |
79 | + goto out_free_iclog; | |
80 | + | |
81 | iclog = *iclogp; | |
82 | iclog->ic_prev = prev_iclog; | |
83 | prev_iclog = iclog; | |
84 | ||
85 | bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp); | |
86 | + if (!bp) | |
87 | + goto out_free_iclog; | |
88 | if (!XFS_BUF_CPSEMA(bp)) | |
89 | ASSERT(0); | |
90 | XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); | |
91 | @@ -1323,6 +1337,25 @@ xlog_alloc_log(xfs_mount_t *mp, | |
92 | log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ | |
93 | ||
94 | return log; | |
95 | + | |
96 | +out_free_iclog: | |
97 | + for (iclog = log->l_iclog; iclog; iclog = prev_iclog) { | |
98 | + prev_iclog = iclog->ic_next; | |
99 | + if (iclog->ic_bp) { | |
100 | + sv_destroy(&iclog->ic_force_wait); | |
101 | + sv_destroy(&iclog->ic_write_wait); | |
102 | + xfs_buf_free(iclog->ic_bp); | |
103 | + xlog_trace_iclog_dealloc(iclog); | |
104 | + } | |
105 | + kmem_free(iclog); | |
106 | + } | |
107 | + spinlock_destroy(&log->l_icloglock); | |
108 | + spinlock_destroy(&log->l_grant_lock); | |
109 | + xlog_trace_loggrant_dealloc(log); | |
110 | + xfs_buf_free(log->l_xbuf); | |
111 | +out_free_log: | |
112 | + kmem_free(log); | |
113 | + return NULL; | |
114 | } /* xlog_alloc_log */ | |
115 | ||
116 |