diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-11 12:32:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-11 12:32:58 -0500 |
commit | 04ca2c17e3fae2d3f73aa5ad533242d556cadf5a (patch) | |
tree | f83be0272c50d6f23e5c94446d9da91a87665092 /fs | |
parent | ad1164b79f1905ec1611cdc2a44949618bced2a6 (diff) | |
parent | 220ca310a53200b4bfbc7c4c6e365eea284ec44f (diff) |
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
* 'for-linus' of git://oss.sgi.com/xfs/xfs:
[XFS] XFS: Check for valid transaction headers in recovery
[XFS] handle memory allocation failures during log initialisation
[XFS] Account for allocated blocks when expanding directories
[XFS] Wait for all I/O on truncate to zero file size
[XFS] Fix use-after-free with log and quotas
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_da_btree.c | 5 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_log.c | 39 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 8 | ||||
-rw-r--r-- | fs/xfs/xfs_mount.c | 5 |
6 files changed, 58 insertions, 7 deletions
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 9e561a9cefca..a11a8390bf6c 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c | |||
@@ -1566,11 +1566,14 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
1566 | int nmap, error, w, count, c, got, i, mapi; | 1566 | int nmap, error, w, count, c, got, i, mapi; |
1567 | xfs_trans_t *tp; | 1567 | xfs_trans_t *tp; |
1568 | xfs_mount_t *mp; | 1568 | xfs_mount_t *mp; |
1569 | xfs_drfsbno_t nblks; | ||
1569 | 1570 | ||
1570 | dp = args->dp; | 1571 | dp = args->dp; |
1571 | mp = dp->i_mount; | 1572 | mp = dp->i_mount; |
1572 | w = args->whichfork; | 1573 | w = args->whichfork; |
1573 | tp = args->trans; | 1574 | tp = args->trans; |
1575 | nblks = dp->i_d.di_nblocks; | ||
1576 | |||
1574 | /* | 1577 | /* |
1575 | * For new directories adjust the file offset and block count. | 1578 | * For new directories adjust the file offset and block count. |
1576 | */ | 1579 | */ |
@@ -1647,6 +1650,8 @@ xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) | |||
1647 | } | 1650 | } |
1648 | if (mapp != &map) | 1651 | if (mapp != &map) |
1649 | kmem_free(mapp); | 1652 | kmem_free(mapp); |
1653 | /* account for newly allocated blocks in reserved blocks total */ | ||
1654 | args->total -= dp->i_d.di_nblocks - nblks; | ||
1650 | *new_blkno = (xfs_dablk_t)bno; | 1655 | *new_blkno = (xfs_dablk_t)bno; |
1651 | return 0; | 1656 | return 0; |
1652 | } | 1657 | } |
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index 80e0dc51361c..1afb12278b8d 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c | |||
@@ -525,11 +525,13 @@ xfs_dir2_grow_inode( | |||
525 | xfs_mount_t *mp; | 525 | xfs_mount_t *mp; |
526 | int nmap; /* number of bmap entries */ | 526 | int nmap; /* number of bmap entries */ |
527 | xfs_trans_t *tp; | 527 | xfs_trans_t *tp; |
528 | xfs_drfsbno_t nblks; | ||
528 | 529 | ||
529 | xfs_dir2_trace_args_s("grow_inode", args, space); | 530 | xfs_dir2_trace_args_s("grow_inode", args, space); |
530 | dp = args->dp; | 531 | dp = args->dp; |
531 | tp = args->trans; | 532 | tp = args->trans; |
532 | mp = dp->i_mount; | 533 | mp = dp->i_mount; |
534 | nblks = dp->i_d.di_nblocks; | ||
533 | /* | 535 | /* |
534 | * Set lowest possible block in the space requested. | 536 | * Set lowest possible block in the space requested. |
535 | */ | 537 | */ |
@@ -622,7 +624,11 @@ xfs_dir2_grow_inode( | |||
622 | */ | 624 | */ |
623 | if (mapp != &map) | 625 | if (mapp != &map) |
624 | kmem_free(mapp); | 626 | kmem_free(mapp); |
627 | |||
628 | /* account for newly allocated blocks in reserved blocks total */ | ||
629 | args->total -= dp->i_d.di_nblocks - nblks; | ||
625 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); | 630 | *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno); |
631 | |||
626 | /* | 632 | /* |
627 | * Update file's size if this is the data space and it grew. | 633 | * Update file's size if this is the data space and it grew. |
628 | */ | 634 | */ |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index dbd9cef852ec..a391b955df01 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
@@ -1414,7 +1414,7 @@ xfs_itruncate_start( | |||
1414 | mp = ip->i_mount; | 1414 | mp = ip->i_mount; |
1415 | 1415 | ||
1416 | /* wait for the completion of any pending DIOs */ | 1416 | /* wait for the completion of any pending DIOs */ |
1417 | if (new_size < ip->i_size) | 1417 | if (new_size == 0 || new_size < ip->i_size) |
1418 | vn_iowait(ip); | 1418 | vn_iowait(ip); |
1419 | 1419 | ||
1420 | /* | 1420 | /* |
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; |
602 | error: | 607 | error: |
603 | xfs_log_unmount_dealloc(mp); | 608 | xfs_log_unmount_dealloc(mp); |
609 | out: | ||
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 | |||
1341 | out_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); | ||
1356 | out_free_log: | ||
1357 | kmem_free(log); | ||
1358 | return NULL; | ||
1326 | } /* xlog_alloc_log */ | 1359 | } /* xlog_alloc_log */ |
1327 | 1360 | ||
1328 | 1361 | ||
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 82d46ce69d5f..70e3ba32e6be 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -1419,7 +1419,13 @@ xlog_recover_add_to_trans( | |||
1419 | return 0; | 1419 | return 0; |
1420 | item = trans->r_itemq; | 1420 | item = trans->r_itemq; |
1421 | if (item == NULL) { | 1421 | if (item == NULL) { |
1422 | ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC); | 1422 | /* we need to catch log corruptions here */ |
1423 | if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { | ||
1424 | xlog_warn("XFS: xlog_recover_add_to_trans: " | ||
1425 | "bad header magic number"); | ||
1426 | ASSERT(0); | ||
1427 | return XFS_ERROR(EIO); | ||
1428 | } | ||
1423 | if (len == sizeof(xfs_trans_header_t)) | 1429 | if (len == sizeof(xfs_trans_header_t)) |
1424 | xlog_recover_add_item(&trans->r_itemq); | 1430 | xlog_recover_add_item(&trans->r_itemq); |
1425 | memcpy(&trans->r_theader, dp, len); /* d, s, l */ | 1431 | memcpy(&trans->r_theader, dp, len); /* d, s, l */ |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index a4503f5e9497..15f5dd22fbb2 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -1245,6 +1245,9 @@ xfs_unmountfs( | |||
1245 | 1245 | ||
1246 | XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING); | 1246 | XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING); |
1247 | 1247 | ||
1248 | if (mp->m_quotainfo) | ||
1249 | XFS_QM_DONE(mp); | ||
1250 | |||
1248 | /* | 1251 | /* |
1249 | * Flush out the log synchronously so that we know for sure | 1252 | * Flush out the log synchronously so that we know for sure |
1250 | * that nothing is pinned. This is important because bflush() | 1253 | * that nothing is pinned. This is important because bflush() |
@@ -1297,8 +1300,6 @@ xfs_unmountfs( | |||
1297 | xfs_errortag_clearall(mp, 0); | 1300 | xfs_errortag_clearall(mp, 0); |
1298 | #endif | 1301 | #endif |
1299 | xfs_free_perag(mp); | 1302 | xfs_free_perag(mp); |
1300 | if (mp->m_quotainfo) | ||
1301 | XFS_QM_DONE(mp); | ||
1302 | } | 1303 | } |
1303 | 1304 | ||
1304 | STATIC void | 1305 | STATIC void |