diff options
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.c | 8 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_attr_leaf.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_attr_inactive.c | 83 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 12 |
4 files changed, 58 insertions, 47 deletions
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index 04e79d57bca6..e9d401ce93bb 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c | |||
| @@ -574,8 +574,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) | |||
| 574 | * After the last attribute is removed revert to original inode format, | 574 | * After the last attribute is removed revert to original inode format, |
| 575 | * making all literal area available to the data fork once more. | 575 | * making all literal area available to the data fork once more. |
| 576 | */ | 576 | */ |
| 577 | STATIC void | 577 | void |
| 578 | xfs_attr_fork_reset( | 578 | xfs_attr_fork_remove( |
| 579 | struct xfs_inode *ip, | 579 | struct xfs_inode *ip, |
| 580 | struct xfs_trans *tp) | 580 | struct xfs_trans *tp) |
| 581 | { | 581 | { |
| @@ -641,7 +641,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) | |||
| 641 | (mp->m_flags & XFS_MOUNT_ATTR2) && | 641 | (mp->m_flags & XFS_MOUNT_ATTR2) && |
| 642 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && | 642 | (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && |
| 643 | !(args->op_flags & XFS_DA_OP_ADDNAME)) { | 643 | !(args->op_flags & XFS_DA_OP_ADDNAME)) { |
| 644 | xfs_attr_fork_reset(dp, args->trans); | 644 | xfs_attr_fork_remove(dp, args->trans); |
| 645 | } else { | 645 | } else { |
| 646 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); | 646 | xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); |
| 647 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); | 647 | dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); |
| @@ -905,7 +905,7 @@ xfs_attr3_leaf_to_shortform( | |||
| 905 | if (forkoff == -1) { | 905 | if (forkoff == -1) { |
| 906 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); | 906 | ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); |
| 907 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); | 907 | ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); |
| 908 | xfs_attr_fork_reset(dp, args->trans); | 908 | xfs_attr_fork_remove(dp, args->trans); |
| 909 | goto out; | 909 | goto out; |
| 910 | } | 910 | } |
| 911 | 911 | ||
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h index 025c4b820c03..882c8d338891 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.h +++ b/fs/xfs/libxfs/xfs_attr_leaf.h | |||
| @@ -53,7 +53,7 @@ int xfs_attr_shortform_remove(struct xfs_da_args *args); | |||
| 53 | int xfs_attr_shortform_list(struct xfs_attr_list_context *context); | 53 | int xfs_attr_shortform_list(struct xfs_attr_list_context *context); |
| 54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); | 54 | int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); |
| 55 | int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); | 55 | int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); |
| 56 | 56 | void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); | |
| 57 | 57 | ||
| 58 | /* | 58 | /* |
| 59 | * Internal routines when attribute fork size == XFS_LBSIZE(mp). | 59 | * Internal routines when attribute fork size == XFS_LBSIZE(mp). |
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c index f9c1c64782d3..3fbf167cfb4c 100644 --- a/fs/xfs/xfs_attr_inactive.c +++ b/fs/xfs/xfs_attr_inactive.c | |||
| @@ -380,23 +380,31 @@ xfs_attr3_root_inactive( | |||
| 380 | return error; | 380 | return error; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | /* | ||
| 384 | * xfs_attr_inactive kills all traces of an attribute fork on an inode. It | ||
| 385 | * removes both the on-disk and in-memory inode fork. Note that this also has to | ||
| 386 | * handle the condition of inodes without attributes but with an attribute fork | ||
| 387 | * configured, so we can't use xfs_inode_hasattr() here. | ||
| 388 | * | ||
| 389 | * The in-memory attribute fork is removed even on error. | ||
| 390 | */ | ||
| 383 | int | 391 | int |
| 384 | xfs_attr_inactive(xfs_inode_t *dp) | 392 | xfs_attr_inactive( |
| 393 | struct xfs_inode *dp) | ||
| 385 | { | 394 | { |
| 386 | xfs_trans_t *trans; | 395 | struct xfs_trans *trans; |
| 387 | xfs_mount_t *mp; | 396 | struct xfs_mount *mp; |
| 388 | int error; | 397 | int cancel_flags = 0; |
| 398 | int lock_mode = XFS_ILOCK_SHARED; | ||
| 399 | int error = 0; | ||
| 389 | 400 | ||
| 390 | mp = dp->i_mount; | 401 | mp = dp->i_mount; |
| 391 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); | 402 | ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); |
| 392 | 403 | ||
| 393 | xfs_ilock(dp, XFS_ILOCK_SHARED); | 404 | xfs_ilock(dp, lock_mode); |
| 394 | if (!xfs_inode_hasattr(dp) || | 405 | if (!XFS_IFORK_Q(dp)) |
| 395 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 406 | goto out_destroy_fork; |
| 396 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | 407 | xfs_iunlock(dp, lock_mode); |
| 397 | return 0; | ||
| 398 | } | ||
| 399 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
| 400 | 408 | ||
| 401 | /* | 409 | /* |
| 402 | * Start our first transaction of the day. | 410 | * Start our first transaction of the day. |
| @@ -408,13 +416,18 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
| 408 | * the inode in every transaction to let it float upward through | 416 | * the inode in every transaction to let it float upward through |
| 409 | * the log. | 417 | * the log. |
| 410 | */ | 418 | */ |
| 419 | lock_mode = 0; | ||
| 411 | trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); | 420 | trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); |
| 412 | error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0); | 421 | error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0); |
| 413 | if (error) { | 422 | if (error) |
| 414 | xfs_trans_cancel(trans, 0); | 423 | goto out_cancel; |
| 415 | return error; | 424 | |
| 416 | } | 425 | lock_mode = XFS_ILOCK_EXCL; |
| 417 | xfs_ilock(dp, XFS_ILOCK_EXCL); | 426 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT; |
| 427 | xfs_ilock(dp, lock_mode); | ||
| 428 | |||
| 429 | if (!XFS_IFORK_Q(dp)) | ||
| 430 | goto out_cancel; | ||
| 418 | 431 | ||
| 419 | /* | 432 | /* |
| 420 | * No need to make quota reservations here. We expect to release some | 433 | * No need to make quota reservations here. We expect to release some |
| @@ -422,29 +435,31 @@ xfs_attr_inactive(xfs_inode_t *dp) | |||
| 422 | */ | 435 | */ |
| 423 | xfs_trans_ijoin(trans, dp, 0); | 436 | xfs_trans_ijoin(trans, dp, 0); |
| 424 | 437 | ||
| 425 | /* | 438 | /* invalidate and truncate the attribute fork extents */ |
| 426 | * Decide on what work routines to call based on the inode size. | 439 | if (dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) { |
| 427 | */ | 440 | error = xfs_attr3_root_inactive(&trans, dp); |
| 428 | if (!xfs_inode_hasattr(dp) || | 441 | if (error) |
| 429 | dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | 442 | goto out_cancel; |
| 430 | error = 0; | 443 | |
| 431 | goto out; | 444 | error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); |
| 445 | if (error) | ||
| 446 | goto out_cancel; | ||
| 432 | } | 447 | } |
| 433 | error = xfs_attr3_root_inactive(&trans, dp); | ||
| 434 | if (error) | ||
| 435 | goto out; | ||
| 436 | 448 | ||
| 437 | error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); | 449 | /* Reset the attribute fork - this also destroys the in-core fork */ |
| 438 | if (error) | 450 | xfs_attr_fork_remove(dp, trans); |
| 439 | goto out; | ||
| 440 | 451 | ||
| 441 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); | 452 | error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES); |
| 442 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 453 | xfs_iunlock(dp, lock_mode); |
| 443 | |||
| 444 | return error; | 454 | return error; |
| 445 | 455 | ||
| 446 | out: | 456 | out_cancel: |
| 447 | xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | 457 | xfs_trans_cancel(trans, cancel_flags); |
| 448 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 458 | out_destroy_fork: |
| 459 | /* kill the in-core attr fork before we drop the inode lock */ | ||
| 460 | if (dp->i_afp) | ||
| 461 | xfs_idestroy_fork(dp, XFS_ATTR_FORK); | ||
| 462 | if (lock_mode) | ||
| 463 | xfs_iunlock(dp, lock_mode); | ||
| 449 | return error; | 464 | return error; |
| 450 | } | 465 | } |
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d6ebc85192b7..1117dd3ba123 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c | |||
| @@ -1946,21 +1946,17 @@ xfs_inactive( | |||
| 1946 | /* | 1946 | /* |
| 1947 | * If there are attributes associated with the file then blow them away | 1947 | * If there are attributes associated with the file then blow them away |
| 1948 | * now. The code calls a routine that recursively deconstructs the | 1948 | * now. The code calls a routine that recursively deconstructs the |
| 1949 | * attribute fork. We need to just commit the current transaction | 1949 | * attribute fork. If also blows away the in-core attribute fork. |
| 1950 | * because we can't use it for xfs_attr_inactive(). | ||
| 1951 | */ | 1950 | */ |
| 1952 | if (ip->i_d.di_anextents > 0) { | 1951 | if (XFS_IFORK_Q(ip)) { |
| 1953 | ASSERT(ip->i_d.di_forkoff != 0); | ||
| 1954 | |||
| 1955 | error = xfs_attr_inactive(ip); | 1952 | error = xfs_attr_inactive(ip); |
| 1956 | if (error) | 1953 | if (error) |
| 1957 | return; | 1954 | return; |
| 1958 | } | 1955 | } |
| 1959 | 1956 | ||
| 1960 | if (ip->i_afp) | 1957 | ASSERT(!ip->i_afp); |
| 1961 | xfs_idestroy_fork(ip, XFS_ATTR_FORK); | ||
| 1962 | |||
| 1963 | ASSERT(ip->i_d.di_anextents == 0); | 1958 | ASSERT(ip->i_d.di_anextents == 0); |
| 1959 | ASSERT(ip->i_d.di_forkoff == 0); | ||
| 1964 | 1960 | ||
| 1965 | /* | 1961 | /* |
| 1966 | * Free the inode. | 1962 | * Free the inode. |
