diff options
| author | Christoph Hellwig <hch@infradead.org> | 2011-02-13 08:26:42 -0500 |
|---|---|---|
| committer | Alex Elder <aelder@sgi.com> | 2011-02-22 21:32:28 -0500 |
| commit | ec3ba85f4083d10e32fe58b46db02d78ef71f6b8 (patch) | |
| tree | bf8e3b41e913c80f24673b87fb390ce6903d82ac /fs | |
| parent | 1050c71e2925ab0cb025e4c89e08b15529a1ee36 (diff) | |
xfs: more sensible inode refcounting for ialloc
Currently we return iodes from xfs_ialloc with just a single reference held.
But we need two references, as one is dropped during transaction commit and
the second needs to be transfered to the VFS. Change xfs_ialloc to use
xfs_iget plus xfs_trans_ijoin_ref to grab two references to the inode,
and remove the now superflous IHOLD calls from all callers. This also
greatly simplifies the error handling in xfs_create and also allow to remove
xfs_trans_iget as no other callers are left.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/xfs/quota/xfs_qm.c | 7 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 5 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans_inode.c | 22 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 61 |
5 files changed, 19 insertions, 78 deletions
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 206a2815ced6..f517963aec07 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
| @@ -1230,13 +1230,6 @@ xfs_qm_qino_alloc( | |||
| 1230 | } | 1230 | } |
| 1231 | 1231 | ||
| 1232 | /* | 1232 | /* |
| 1233 | * Keep an extra reference to this quota inode. This inode is | ||
| 1234 | * locked exclusively and joined to the transaction already. | ||
| 1235 | */ | ||
| 1236 | ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL)); | ||
| 1237 | IHOLD(*ip); | ||
| 1238 | |||
| 1239 | /* | ||
| 1240 | * Make the changes in the superblock, and log those too. | 1233 | * Make the changes in the superblock, and log those too. |
| 1241 | * sbfields arg may contain fields other than *QUOTINO; | 1234 | * sbfields arg may contain fields other than *QUOTINO; |
| 1242 | * VERSIONNUM for example. | 1235 | * VERSIONNUM for example. |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index be7cf625421f..c39278b6c871 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1016,8 +1016,8 @@ xfs_ialloc( | |||
| 1016 | * This is because we're setting fields here we need | 1016 | * This is because we're setting fields here we need |
| 1017 | * to prevent others from looking at until we're done. | 1017 | * to prevent others from looking at until we're done. |
| 1018 | */ | 1018 | */ |
| 1019 | error = xfs_trans_iget(tp->t_mountp, tp, ino, | 1019 | error = xfs_iget(tp->t_mountp, tp, ino, XFS_IGET_CREATE, |
| 1020 | XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip); | 1020 | XFS_ILOCK_EXCL, &ip); |
| 1021 | if (error) | 1021 | if (error) |
| 1022 | return error; | 1022 | return error; |
| 1023 | ASSERT(ip != NULL); | 1023 | ASSERT(ip != NULL); |
| @@ -1166,6 +1166,7 @@ xfs_ialloc( | |||
| 1166 | /* | 1166 | /* |
| 1167 | * Log the new values stuffed into the inode. | 1167 | * Log the new values stuffed into the inode. |
| 1168 | */ | 1168 | */ |
| 1169 | xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL); | ||
| 1169 | xfs_trans_log_inode(tp, ip, flags); | 1170 | xfs_trans_log_inode(tp, ip, flags); |
| 1170 | 1171 | ||
| 1171 | /* now that we have an i_mode we can setup inode ops and unlock */ | 1172 | /* now that we have an i_mode we can setup inode ops and unlock */ |
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index c2042b736b81..06a9759b6352 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h | |||
| @@ -469,8 +469,6 @@ void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); | |||
| 469 | void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); | 469 | void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); |
| 470 | void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); | 470 | void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); |
| 471 | void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); | 471 | void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); |
| 472 | int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, | ||
| 473 | xfs_ino_t , uint, uint, struct xfs_inode **); | ||
| 474 | void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); | 472 | void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); |
| 475 | void xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint); | 473 | void xfs_trans_ijoin_ref(struct xfs_trans *, struct xfs_inode *, uint); |
| 476 | void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *); | 474 | void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *); |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index ccb34532768b..16084d8ea231 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
| @@ -44,28 +44,6 @@ xfs_trans_inode_broot_debug( | |||
| 44 | #endif | 44 | #endif |
| 45 | 45 | ||
| 46 | /* | 46 | /* |
| 47 | * Get an inode and join it to the transaction. | ||
| 48 | */ | ||
| 49 | int | ||
| 50 | xfs_trans_iget( | ||
| 51 | xfs_mount_t *mp, | ||
| 52 | xfs_trans_t *tp, | ||
| 53 | xfs_ino_t ino, | ||
| 54 | uint flags, | ||
| 55 | uint lock_flags, | ||
| 56 | xfs_inode_t **ipp) | ||
| 57 | { | ||
| 58 | int error; | ||
| 59 | |||
| 60 | error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp); | ||
| 61 | if (!error && tp) { | ||
| 62 | xfs_trans_ijoin(tp, *ipp); | ||
| 63 | (*ipp)->i_itemp->ili_lock_flags = lock_flags; | ||
| 64 | } | ||
| 65 | return error; | ||
| 66 | } | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Add a locked inode to the transaction. | 47 | * Add a locked inode to the transaction. |
| 70 | * | 48 | * |
| 71 | * The inode must be locked, and it cannot be associated with any transaction. | 49 | * The inode must be locked, and it cannot be associated with any transaction. |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index d8e6f8cd6f0c..258d4f98eb9b 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -1310,7 +1310,7 @@ xfs_create( | |||
| 1310 | error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid, | 1310 | error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid, |
| 1311 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); | 1311 | XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp); |
| 1312 | if (error) | 1312 | if (error) |
| 1313 | goto std_return; | 1313 | return error; |
| 1314 | 1314 | ||
| 1315 | if (is_dir) { | 1315 | if (is_dir) { |
| 1316 | rdev = 0; | 1316 | rdev = 0; |
| @@ -1390,12 +1390,6 @@ xfs_create( | |||
| 1390 | } | 1390 | } |
| 1391 | 1391 | ||
| 1392 | /* | 1392 | /* |
| 1393 | * At this point, we've gotten a newly allocated inode. | ||
| 1394 | * It is locked (and joined to the transaction). | ||
| 1395 | */ | ||
| 1396 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | ||
| 1397 | |||
| 1398 | /* | ||
| 1399 | * Now we join the directory inode to the transaction. We do not do it | 1393 | * Now we join the directory inode to the transaction. We do not do it |
| 1400 | * earlier because xfs_dir_ialloc might commit the previous transaction | 1394 | * earlier because xfs_dir_ialloc might commit the previous transaction |
| 1401 | * (and release all the locks). An error from here on will result in | 1395 | * (and release all the locks). An error from here on will result in |
| @@ -1440,22 +1434,13 @@ xfs_create( | |||
| 1440 | */ | 1434 | */ |
| 1441 | xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp); | 1435 | xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp); |
| 1442 | 1436 | ||
| 1443 | /* | ||
| 1444 | * xfs_trans_commit normally decrements the vnode ref count | ||
| 1445 | * when it unlocks the inode. Since we want to return the | ||
| 1446 | * vnode to the caller, we bump the vnode ref count now. | ||
| 1447 | */ | ||
| 1448 | IHOLD(ip); | ||
| 1449 | |||
| 1450 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 1437 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
| 1451 | if (error) | 1438 | if (error) |
| 1452 | goto out_abort_rele; | 1439 | goto out_bmap_cancel; |
| 1453 | 1440 | ||
| 1454 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 1441 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
| 1455 | if (error) { | 1442 | if (error) |
| 1456 | IRELE(ip); | 1443 | goto out_release_inode; |
| 1457 | goto out_dqrele; | ||
| 1458 | } | ||
| 1459 | 1444 | ||
| 1460 | xfs_qm_dqrele(udqp); | 1445 | xfs_qm_dqrele(udqp); |
| 1461 | xfs_qm_dqrele(gdqp); | 1446 | xfs_qm_dqrele(gdqp); |
| @@ -1469,27 +1454,21 @@ xfs_create( | |||
| 1469 | cancel_flags |= XFS_TRANS_ABORT; | 1454 | cancel_flags |= XFS_TRANS_ABORT; |
| 1470 | out_trans_cancel: | 1455 | out_trans_cancel: |
| 1471 | xfs_trans_cancel(tp, cancel_flags); | 1456 | xfs_trans_cancel(tp, cancel_flags); |
| 1472 | out_dqrele: | 1457 | out_release_inode: |
| 1458 | /* | ||
| 1459 | * Wait until after the current transaction is aborted to | ||
| 1460 | * release the inode. This prevents recursive transactions | ||
| 1461 | * and deadlocks from xfs_inactive. | ||
| 1462 | */ | ||
| 1463 | if (ip) | ||
| 1464 | IRELE(ip); | ||
| 1465 | |||
| 1473 | xfs_qm_dqrele(udqp); | 1466 | xfs_qm_dqrele(udqp); |
| 1474 | xfs_qm_dqrele(gdqp); | 1467 | xfs_qm_dqrele(gdqp); |
| 1475 | 1468 | ||
| 1476 | if (unlock_dp_on_error) | 1469 | if (unlock_dp_on_error) |
| 1477 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 1470 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
| 1478 | std_return: | ||
| 1479 | return error; | 1471 | return error; |
| 1480 | |||
| 1481 | out_abort_rele: | ||
| 1482 | /* | ||
| 1483 | * Wait until after the current transaction is aborted to | ||
| 1484 | * release the inode. This prevents recursive transactions | ||
| 1485 | * and deadlocks from xfs_inactive. | ||
| 1486 | */ | ||
| 1487 | xfs_bmap_cancel(&free_list); | ||
| 1488 | cancel_flags |= XFS_TRANS_ABORT; | ||
| 1489 | xfs_trans_cancel(tp, cancel_flags); | ||
| 1490 | IRELE(ip); | ||
| 1491 | unlock_dp_on_error = B_FALSE; | ||
| 1492 | goto out_dqrele; | ||
| 1493 | } | 1472 | } |
| 1494 | 1473 | ||
| 1495 | #ifdef DEBUG | 1474 | #ifdef DEBUG |
| @@ -2114,9 +2093,8 @@ xfs_symlink( | |||
| 2114 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, | 2093 | XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, |
| 2115 | &first_block, resblks, mval, &nmaps, | 2094 | &first_block, resblks, mval, &nmaps, |
| 2116 | &free_list); | 2095 | &free_list); |
| 2117 | if (error) { | 2096 | if (error) |
| 2118 | goto error1; | 2097 | goto error2; |
| 2119 | } | ||
| 2120 | 2098 | ||
| 2121 | if (resblks) | 2099 | if (resblks) |
| 2122 | resblks -= fs_blocks; | 2100 | resblks -= fs_blocks; |
| @@ -2148,7 +2126,7 @@ xfs_symlink( | |||
| 2148 | error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, | 2126 | error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, |
| 2149 | &first_block, &free_list, resblks); | 2127 | &first_block, &free_list, resblks); |
| 2150 | if (error) | 2128 | if (error) |
| 2151 | goto error1; | 2129 | goto error2; |
| 2152 | xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 2130 | xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |
| 2153 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); | 2131 | xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); |
| 2154 | 2132 | ||
| @@ -2161,13 +2139,6 @@ xfs_symlink( | |||
| 2161 | xfs_trans_set_sync(tp); | 2139 | xfs_trans_set_sync(tp); |
| 2162 | } | 2140 | } |
| 2163 | 2141 | ||
| 2164 | /* | ||
| 2165 | * xfs_trans_commit normally decrements the vnode ref count | ||
| 2166 | * when it unlocks the inode. Since we want to return the | ||
| 2167 | * vnode to the caller, we bump the vnode ref count now. | ||
| 2168 | */ | ||
| 2169 | IHOLD(ip); | ||
| 2170 | |||
| 2171 | error = xfs_bmap_finish(&tp, &free_list, &committed); | 2142 | error = xfs_bmap_finish(&tp, &free_list, &committed); |
| 2172 | if (error) { | 2143 | if (error) { |
| 2173 | goto error2; | 2144 | goto error2; |
