diff options
-rw-r--r-- | fs/ocfs2/xattr.c | 74 |
1 files changed, 28 insertions, 46 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 3b9634c7d296..6db68a23a296 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -4580,31 +4580,6 @@ out: | |||
4580 | return ret; | 4580 | return ret; |
4581 | } | 4581 | } |
4582 | 4582 | ||
4583 | static int ocfs2_xattr_value_update_size(struct inode *inode, | ||
4584 | handle_t *handle, | ||
4585 | struct buffer_head *xe_bh, | ||
4586 | struct ocfs2_xattr_entry *xe, | ||
4587 | u64 new_size) | ||
4588 | { | ||
4589 | int ret; | ||
4590 | |||
4591 | ret = ocfs2_journal_access(handle, inode, xe_bh, | ||
4592 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
4593 | if (ret < 0) { | ||
4594 | mlog_errno(ret); | ||
4595 | goto out; | ||
4596 | } | ||
4597 | |||
4598 | xe->xe_value_size = cpu_to_le64(new_size); | ||
4599 | |||
4600 | ret = ocfs2_journal_dirty(handle, xe_bh); | ||
4601 | if (ret < 0) | ||
4602 | mlog_errno(ret); | ||
4603 | |||
4604 | out: | ||
4605 | return ret; | ||
4606 | } | ||
4607 | |||
4608 | /* | 4583 | /* |
4609 | * Truncate the specified xe_off entry in xattr bucket. | 4584 | * Truncate the specified xe_off entry in xattr bucket. |
4610 | * bucket is indicated by header_bh and len is the new length. | 4585 | * bucket is indicated by header_bh and len is the new length. |
@@ -4613,7 +4588,7 @@ out: | |||
4613 | * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed. | 4588 | * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed. |
4614 | */ | 4589 | */ |
4615 | static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, | 4590 | static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, |
4616 | struct buffer_head *header_bh, | 4591 | struct ocfs2_xattr_bucket *bucket, |
4617 | int xe_off, | 4592 | int xe_off, |
4618 | int len, | 4593 | int len, |
4619 | struct ocfs2_xattr_set_ctxt *ctxt) | 4594 | struct ocfs2_xattr_set_ctxt *ctxt) |
@@ -4623,8 +4598,7 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, | |||
4623 | struct buffer_head *value_bh = NULL; | 4598 | struct buffer_head *value_bh = NULL; |
4624 | struct ocfs2_xattr_value_root *xv; | 4599 | struct ocfs2_xattr_value_root *xv; |
4625 | struct ocfs2_xattr_entry *xe; | 4600 | struct ocfs2_xattr_entry *xe; |
4626 | struct ocfs2_xattr_header *xh = | 4601 | struct ocfs2_xattr_header *xh = bucket_xh(bucket); |
4627 | (struct ocfs2_xattr_header *)header_bh->b_data; | ||
4628 | size_t blocksize = inode->i_sb->s_blocksize; | 4602 | size_t blocksize = inode->i_sb->s_blocksize; |
4629 | 4603 | ||
4630 | xe = &xh->xh_entries[xe_off]; | 4604 | xe = &xh->xh_entries[xe_off]; |
@@ -4638,34 +4612,41 @@ static int ocfs2_xattr_bucket_value_truncate(struct inode *inode, | |||
4638 | 4612 | ||
4639 | /* We don't allow ocfs2_xattr_value to be stored in different block. */ | 4613 | /* We don't allow ocfs2_xattr_value to be stored in different block. */ |
4640 | BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize); | 4614 | BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize); |
4641 | value_blk += header_bh->b_blocknr; | ||
4642 | 4615 | ||
4643 | ret = ocfs2_read_block(inode, value_blk, &value_bh, NULL); | 4616 | value_bh = bucket->bu_bhs[value_blk]; |
4644 | if (ret) { | 4617 | BUG_ON(!value_bh); |
4645 | mlog_errno(ret); | ||
4646 | goto out; | ||
4647 | } | ||
4648 | 4618 | ||
4649 | xv = (struct ocfs2_xattr_value_root *) | 4619 | xv = (struct ocfs2_xattr_value_root *) |
4650 | (value_bh->b_data + offset % blocksize); | 4620 | (value_bh->b_data + offset % blocksize); |
4651 | 4621 | ||
4652 | mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n", | 4622 | ret = ocfs2_xattr_bucket_journal_access(ctxt->handle, bucket, |
4653 | xe_off, (unsigned long long)header_bh->b_blocknr, len); | 4623 | OCFS2_JOURNAL_ACCESS_WRITE); |
4654 | ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len, ctxt); | ||
4655 | if (ret) { | 4624 | if (ret) { |
4656 | mlog_errno(ret); | 4625 | mlog_errno(ret); |
4657 | goto out; | 4626 | goto out; |
4658 | } | 4627 | } |
4659 | 4628 | ||
4660 | ret = ocfs2_xattr_value_update_size(inode, ctxt->handle, | 4629 | /* |
4661 | header_bh, xe, len); | 4630 | * From here on out we have to dirty the bucket. The generic |
4631 | * value calls only modify one of the bucket's bhs, but we need | ||
4632 | * to send the bucket at once. So if they error, they *could* have | ||
4633 | * modified something. We have to assume they did, and dirty | ||
4634 | * the whole bucket. This leaves us in a consistent state. | ||
4635 | */ | ||
4636 | mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n", | ||
4637 | xe_off, (unsigned long long)bucket_blkno(bucket), len); | ||
4638 | ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len, ctxt); | ||
4662 | if (ret) { | 4639 | if (ret) { |
4663 | mlog_errno(ret); | 4640 | mlog_errno(ret); |
4664 | goto out; | 4641 | goto out_dirty; |
4665 | } | 4642 | } |
4666 | 4643 | ||
4644 | xe->xe_value_size = cpu_to_le64(len); | ||
4645 | |||
4646 | out_dirty: | ||
4647 | ocfs2_xattr_bucket_journal_dirty(ctxt->handle, bucket); | ||
4648 | |||
4667 | out: | 4649 | out: |
4668 | brelse(value_bh); | ||
4669 | return ret; | 4650 | return ret; |
4670 | } | 4651 | } |
4671 | 4652 | ||
@@ -4681,7 +4662,7 @@ static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode, | |||
4681 | BUG_ON(!xs->bucket->bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe)); | 4662 | BUG_ON(!xs->bucket->bu_bhs[0] || !xe || ocfs2_xattr_is_local(xe)); |
4682 | 4663 | ||
4683 | offset = xe - xh->xh_entries; | 4664 | offset = xe - xh->xh_entries; |
4684 | ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket->bu_bhs[0], | 4665 | ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket, |
4685 | offset, len, ctxt); | 4666 | offset, len, ctxt); |
4686 | if (ret) | 4667 | if (ret) |
4687 | mlog_errno(ret); | 4668 | mlog_errno(ret); |
@@ -5107,11 +5088,13 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |||
5107 | struct ocfs2_xattr_entry *xe; | 5088 | struct ocfs2_xattr_entry *xe; |
5108 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 5089 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
5109 | struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,}; | 5090 | struct ocfs2_xattr_set_ctxt ctxt = {NULL, NULL,}; |
5091 | int credits = ocfs2_remove_extent_credits(osb->sb) + | ||
5092 | ocfs2_blocks_per_xattr_bucket(inode->i_sb); | ||
5093 | |||
5110 | 5094 | ||
5111 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); | 5095 | ocfs2_init_dealloc_ctxt(&ctxt.dealloc); |
5112 | 5096 | ||
5113 | ctxt.handle = ocfs2_start_trans(osb, | 5097 | ctxt.handle = ocfs2_start_trans(osb, credits); |
5114 | ocfs2_remove_extent_credits(osb->sb)); | ||
5115 | if (IS_ERR(ctxt.handle)) { | 5098 | if (IS_ERR(ctxt.handle)) { |
5116 | ret = PTR_ERR(ctxt.handle); | 5099 | ret = PTR_ERR(ctxt.handle); |
5117 | mlog_errno(ret); | 5100 | mlog_errno(ret); |
@@ -5123,8 +5106,7 @@ static int ocfs2_delete_xattr_in_bucket(struct inode *inode, | |||
5123 | if (ocfs2_xattr_is_local(xe)) | 5106 | if (ocfs2_xattr_is_local(xe)) |
5124 | continue; | 5107 | continue; |
5125 | 5108 | ||
5126 | ret = ocfs2_xattr_bucket_value_truncate(inode, | 5109 | ret = ocfs2_xattr_bucket_value_truncate(inode, bucket, |
5127 | bucket->bu_bhs[0], | ||
5128 | i, 0, &ctxt); | 5110 | i, 0, &ctxt); |
5129 | if (ret) { | 5111 | if (ret) { |
5130 | mlog_errno(ret); | 5112 | mlog_errno(ret); |