aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2008-11-10 00:50:24 -0500
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-11-10 01:57:06 -0500
commit8f330f5149ef41ff943b04d914406cc417f62784 (patch)
treed3e52f1cb1563c09c40768f043bfe5e487f0f142
parent6f9f51adb6ac0a49fce49e01c47dcfc2810c6e9d (diff)
[XFS] handle memory allocation failures during log initialisation
When there is no memory left in the system, xfs_buf_get_noaddr() can fail. If this happens at mount time during xlog_alloc_log() we fail to catch the error and oops. Catch the error from xfs_buf_get_noaddr(), and allow other memory allocations to fail and catch those errors too. Report the error to the console and fail the mount with ENOMEM. Tested by manually injecting errors into xfs_buf_get_noaddr() and xlog_alloc_log(). Version 2: o remove unnecessary casts of the returned pointer from kmem_zalloc() SGI-PV: 987246 Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
-rw-r--r--fs/xfs/xfs_log.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 0b02c6443551..3608a0f0a5f6 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -563,6 +563,11 @@ xfs_log_mount(
563 } 563 }
564 564
565 mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); 565 mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks);
566 if (!mp->m_log) {
567 cmn_err(CE_WARN, "XFS: Log allocation failed: No memory!");
568 error = ENOMEM;
569 goto out;
570 }
566 571
567 /* 572 /*
568 * Initialize the AIL now we have a log. 573 * Initialize the AIL now we have a log.
@@ -601,6 +606,7 @@ xfs_log_mount(
601 return 0; 606 return 0;
602error: 607error:
603 xfs_log_unmount_dealloc(mp); 608 xfs_log_unmount_dealloc(mp);
609out:
604 return error; 610 return error;
605} /* xfs_log_mount */ 611} /* xfs_log_mount */
606 612
@@ -1217,7 +1223,9 @@ xlog_alloc_log(xfs_mount_t *mp,
1217 int i; 1223 int i;
1218 int iclogsize; 1224 int iclogsize;
1219 1225
1220 log = (xlog_t *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP); 1226 log = kmem_zalloc(sizeof(xlog_t), KM_MAYFAIL);
1227 if (!log)
1228 return NULL;
1221 1229
1222 log->l_mp = mp; 1230 log->l_mp = mp;
1223 log->l_targ = log_target; 1231 log->l_targ = log_target;
@@ -1249,6 +1257,8 @@ xlog_alloc_log(xfs_mount_t *mp,
1249 xlog_get_iclog_buffer_size(mp, log); 1257 xlog_get_iclog_buffer_size(mp, log);
1250 1258
1251 bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp); 1259 bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
1260 if (!bp)
1261 goto out_free_log;
1252 XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); 1262 XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
1253 XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); 1263 XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
1254 XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); 1264 XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
@@ -1275,13 +1285,17 @@ xlog_alloc_log(xfs_mount_t *mp,
1275 iclogsize = log->l_iclog_size; 1285 iclogsize = log->l_iclog_size;
1276 ASSERT(log->l_iclog_size >= 4096); 1286 ASSERT(log->l_iclog_size >= 4096);
1277 for (i=0; i < log->l_iclog_bufs; i++) { 1287 for (i=0; i < log->l_iclog_bufs; i++) {
1278 *iclogp = (xlog_in_core_t *) 1288 *iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL);
1279 kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP); 1289 if (!*iclogp)
1290 goto out_free_iclog;
1291
1280 iclog = *iclogp; 1292 iclog = *iclogp;
1281 iclog->ic_prev = prev_iclog; 1293 iclog->ic_prev = prev_iclog;
1282 prev_iclog = iclog; 1294 prev_iclog = iclog;
1283 1295
1284 bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp); 1296 bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp);
1297 if (!bp)
1298 goto out_free_iclog;
1285 if (!XFS_BUF_CPSEMA(bp)) 1299 if (!XFS_BUF_CPSEMA(bp))
1286 ASSERT(0); 1300 ASSERT(0);
1287 XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); 1301 XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
@@ -1323,6 +1337,25 @@ xlog_alloc_log(xfs_mount_t *mp,
1323 log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ 1337 log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */
1324 1338
1325 return log; 1339 return log;
1340
1341out_free_iclog:
1342 for (iclog = log->l_iclog; iclog; iclog = prev_iclog) {
1343 prev_iclog = iclog->ic_next;
1344 if (iclog->ic_bp) {
1345 sv_destroy(&iclog->ic_force_wait);
1346 sv_destroy(&iclog->ic_write_wait);
1347 xfs_buf_free(iclog->ic_bp);
1348 xlog_trace_iclog_dealloc(iclog);
1349 }
1350 kmem_free(iclog);
1351 }
1352 spinlock_destroy(&log->l_icloglock);
1353 spinlock_destroy(&log->l_grant_lock);
1354 xlog_trace_loggrant_dealloc(log);
1355 xfs_buf_free(log->l_xbuf);
1356out_free_log:
1357 kmem_free(log);
1358 return NULL;
1326} /* xlog_alloc_log */ 1359} /* xlog_alloc_log */
1327 1360
1328 1361