diff options
Diffstat (limited to 'fs/ocfs2')
-rw-r--r-- | fs/ocfs2/xattr.c | 169 |
1 files changed, 104 insertions, 65 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 5efcf4e85d7c..5be99666f02c 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -170,6 +170,11 @@ static int ocfs2_xattr_set_entry_index_block(struct inode *inode, | |||
170 | 170 | ||
171 | static int ocfs2_delete_xattr_index_block(struct inode *inode, | 171 | static int ocfs2_delete_xattr_index_block(struct inode *inode, |
172 | struct buffer_head *xb_bh); | 172 | struct buffer_head *xb_bh); |
173 | static int ocfs2_cp_xattr_bucket(struct inode *inode, | ||
174 | handle_t *handle, | ||
175 | u64 s_blkno, | ||
176 | u64 t_blkno, | ||
177 | int t_is_new); | ||
173 | 178 | ||
174 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) | 179 | static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb) |
175 | { | 180 | { |
@@ -3526,13 +3531,21 @@ out: | |||
3526 | } | 3531 | } |
3527 | 3532 | ||
3528 | /* | 3533 | /* |
3529 | * Move half nums of the xattr bucket in the previous cluster to this new | 3534 | * prev_blkno points to the start of an existing extent. new_blkno |
3530 | * cluster. We only touch the last cluster of the previous extend record. | 3535 | * points to a newly allocated extent. Because we know each of our |
3536 | * clusters contains more than bucket, we can easily split one cluster | ||
3537 | * at a bucket boundary. So we take the last cluster of the existing | ||
3538 | * extent and split it down the middle. We move the last half of the | ||
3539 | * buckets in the last cluster of the existing extent over to the new | ||
3540 | * extent. | ||
3541 | * | ||
3542 | * first_bh is the buffer at prev_blkno so we can update the existing | ||
3543 | * extent's bucket count. header_bh is the bucket were we were hoping | ||
3544 | * to insert our xattr. If the bucket move places the target in the new | ||
3545 | * extent, we'll update first_bh and header_bh after modifying the old | ||
3546 | * extent. | ||
3531 | * | 3547 | * |
3532 | * first_bh is the first buffer_head of a series of bucket in the same | 3548 | * first_hash will be set as the 1st xe's name_hash in the new extent. |
3533 | * extent rec and header_bh is the header of one bucket in this cluster. | ||
3534 | * They will be updated if we move the data header_bh contains to the new | ||
3535 | * cluster. first_hash will be set as the 1st xe's name_hash of the new cluster. | ||
3536 | */ | 3549 | */ |
3537 | static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode, | 3550 | static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode, |
3538 | handle_t *handle, | 3551 | handle_t *handle, |
@@ -3545,105 +3558,131 @@ static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode, | |||
3545 | { | 3558 | { |
3546 | int i, ret, credits; | 3559 | int i, ret, credits; |
3547 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 3560 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
3561 | int blks_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb); | ||
3548 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); | 3562 | int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); |
3549 | int num_buckets = ocfs2_xattr_buckets_per_cluster(osb); | 3563 | int num_buckets = ocfs2_xattr_buckets_per_cluster(osb); |
3550 | int blocksize = inode->i_sb->s_blocksize; | 3564 | int to_move = num_buckets / 2; |
3551 | struct buffer_head *old_bh, *new_bh, *prev_bh, *new_first_bh = NULL; | 3565 | u64 last_cluster_blkno, src_blkno; |
3552 | struct ocfs2_xattr_header *new_xh; | ||
3553 | struct ocfs2_xattr_header *xh = | 3566 | struct ocfs2_xattr_header *xh = |
3554 | (struct ocfs2_xattr_header *)((*first_bh)->b_data); | 3567 | (struct ocfs2_xattr_header *)((*first_bh)->b_data); |
3568 | struct ocfs2_xattr_bucket *old_first, *new_first; | ||
3555 | 3569 | ||
3556 | BUG_ON(le16_to_cpu(xh->xh_num_buckets) < num_buckets); | 3570 | BUG_ON(le16_to_cpu(xh->xh_num_buckets) < num_buckets); |
3557 | BUG_ON(OCFS2_XATTR_BUCKET_SIZE == osb->s_clustersize); | 3571 | BUG_ON(OCFS2_XATTR_BUCKET_SIZE == osb->s_clustersize); |
3558 | 3572 | ||
3559 | prev_bh = *first_bh; | 3573 | last_cluster_blkno = prev_blkno + ((num_clusters - 1) * bpc); |
3560 | get_bh(prev_bh); | 3574 | src_blkno = last_cluster_blkno + (to_move * blks_per_bucket); |
3561 | xh = (struct ocfs2_xattr_header *)prev_bh->b_data; | ||
3562 | |||
3563 | prev_blkno += (num_clusters - 1) * bpc + bpc / 2; | ||
3564 | 3575 | ||
3565 | mlog(0, "move half of xattrs in cluster %llu to %llu\n", | 3576 | mlog(0, "move half of xattrs in cluster %llu to %llu\n", |
3566 | (unsigned long long)prev_blkno, (unsigned long long)new_blkno); | 3577 | (unsigned long long)prev_blkno, (unsigned long long)new_blkno); |
3567 | 3578 | ||
3579 | /* The first bucket of the original extent */ | ||
3580 | old_first = ocfs2_xattr_bucket_new(inode); | ||
3581 | /* The first bucket of the new extent */ | ||
3582 | new_first = ocfs2_xattr_bucket_new(inode); | ||
3583 | if (!old_first || !new_first) { | ||
3584 | ret = -ENOMEM; | ||
3585 | mlog_errno(ret); | ||
3586 | goto out; | ||
3587 | } | ||
3588 | |||
3589 | ret = ocfs2_read_xattr_bucket(old_first, prev_blkno); | ||
3590 | if (ret) { | ||
3591 | mlog_errno(ret); | ||
3592 | goto out; | ||
3593 | } | ||
3594 | |||
3568 | /* | 3595 | /* |
3569 | * We need to update the 1st half of the new cluster and | 3596 | * We need to update the 1st half of the new extent, and we |
3570 | * 1 more for the update of the 1st bucket of the previous | 3597 | * need to update the first bucket of the old extent. |
3571 | * extent record. | ||
3572 | */ | 3598 | */ |
3573 | credits = bpc / 2 + 1 + handle->h_buffer_credits; | 3599 | credits = ((to_move + 1) * blks_per_bucket) + handle->h_buffer_credits; |
3574 | ret = ocfs2_extend_trans(handle, credits); | 3600 | ret = ocfs2_extend_trans(handle, credits); |
3575 | if (ret) { | 3601 | if (ret) { |
3576 | mlog_errno(ret); | 3602 | mlog_errno(ret); |
3577 | goto out; | 3603 | goto out; |
3578 | } | 3604 | } |
3579 | 3605 | ||
3580 | ret = ocfs2_journal_access(handle, inode, prev_bh, | 3606 | ret = ocfs2_xattr_bucket_journal_access(handle, old_first, |
3581 | OCFS2_JOURNAL_ACCESS_WRITE); | 3607 | OCFS2_JOURNAL_ACCESS_WRITE); |
3582 | if (ret) { | 3608 | if (ret) { |
3583 | mlog_errno(ret); | 3609 | mlog_errno(ret); |
3584 | goto out; | 3610 | goto out; |
3585 | } | 3611 | } |
3586 | 3612 | ||
3587 | for (i = 0; i < bpc / 2; i++, prev_blkno++, new_blkno++) { | 3613 | for (i = 0; i < to_move; i++) { |
3588 | old_bh = new_bh = NULL; | 3614 | ret = ocfs2_cp_xattr_bucket(inode, handle, |
3589 | new_bh = sb_getblk(inode->i_sb, new_blkno); | 3615 | src_blkno + (i * blks_per_bucket), |
3590 | if (!new_bh) { | 3616 | new_blkno + (i * blks_per_bucket), |
3591 | ret = -EIO; | 3617 | 1); |
3618 | if (ret) { | ||
3592 | mlog_errno(ret); | 3619 | mlog_errno(ret); |
3593 | goto out; | 3620 | goto out; |
3594 | } | 3621 | } |
3622 | } | ||
3595 | 3623 | ||
3596 | ocfs2_set_new_buffer_uptodate(inode, new_bh); | 3624 | /* |
3625 | * Get the new bucket ready before we dirty anything | ||
3626 | * (This actually shouldn't fail, because we already dirtied | ||
3627 | * it once in ocfs2_cp_xattr_bucket()). | ||
3628 | */ | ||
3629 | ret = ocfs2_read_xattr_bucket(new_first, new_blkno); | ||
3630 | if (ret) { | ||
3631 | mlog_errno(ret); | ||
3632 | goto out; | ||
3633 | } | ||
3634 | ret = ocfs2_xattr_bucket_journal_access(handle, new_first, | ||
3635 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
3636 | if (ret) { | ||
3637 | mlog_errno(ret); | ||
3638 | goto out; | ||
3639 | } | ||
3597 | 3640 | ||
3598 | ret = ocfs2_journal_access(handle, inode, new_bh, | 3641 | /* Now update the headers */ |
3599 | OCFS2_JOURNAL_ACCESS_CREATE); | 3642 | le16_add_cpu(&bucket_xh(old_first)->xh_num_buckets, -to_move); |
3600 | if (ret < 0) { | 3643 | ocfs2_xattr_bucket_journal_dirty(handle, old_first); |
3601 | mlog_errno(ret); | ||
3602 | brelse(new_bh); | ||
3603 | goto out; | ||
3604 | } | ||
3605 | 3644 | ||
3606 | ret = ocfs2_read_block(inode, prev_blkno, &old_bh, NULL); | 3645 | bucket_xh(new_first)->xh_num_buckets = cpu_to_le16(to_move); |
3607 | if (ret < 0) { | 3646 | ocfs2_xattr_bucket_journal_dirty(handle, new_first); |
3608 | mlog_errno(ret); | ||
3609 | brelse(new_bh); | ||
3610 | goto out; | ||
3611 | } | ||
3612 | 3647 | ||
3613 | memcpy(new_bh->b_data, old_bh->b_data, blocksize); | 3648 | if (first_hash) |
3649 | *first_hash = le32_to_cpu(bucket_xh(new_first)->xh_entries[0].xe_name_hash); | ||
3614 | 3650 | ||
3615 | if (i == 0) { | 3651 | /* |
3616 | new_xh = (struct ocfs2_xattr_header *)new_bh->b_data; | 3652 | * If the target bucket is anywhere past src_blkno, we moved |
3617 | new_xh->xh_num_buckets = cpu_to_le16(num_buckets / 2); | 3653 | * it to the new extent. We need to update first_bh and header_bh. |
3654 | */ | ||
3655 | if ((*header_bh)->b_blocknr >= src_blkno) { | ||
3656 | /* We're done with old_first, so we can re-use it. */ | ||
3657 | ocfs2_xattr_bucket_relse(old_first); | ||
3618 | 3658 | ||
3619 | if (first_hash) | 3659 | /* Find the block for the new target bucket */ |
3620 | *first_hash = le32_to_cpu( | 3660 | src_blkno = new_blkno + |
3621 | new_xh->xh_entries[0].xe_name_hash); | 3661 | ((*header_bh)->b_blocknr - src_blkno); |
3622 | new_first_bh = new_bh; | ||
3623 | get_bh(new_first_bh); | ||
3624 | } | ||
3625 | 3662 | ||
3626 | ocfs2_journal_dirty(handle, new_bh); | 3663 | /* |
3664 | * This shouldn't fail - the buffers are in the | ||
3665 | * journal from ocfs2_cp_xattr_bucket(). | ||
3666 | */ | ||
3667 | ret = ocfs2_read_xattr_bucket(old_first, src_blkno); | ||
3668 | if (ret) { | ||
3669 | mlog_errno(ret); | ||
3670 | goto out; | ||
3671 | } | ||
3627 | 3672 | ||
3628 | if (*header_bh == old_bh) { | 3673 | brelse(*first_bh); |
3629 | brelse(*header_bh); | 3674 | *first_bh = new_first->bu_bhs[0]; |
3630 | *header_bh = new_bh; | 3675 | get_bh(*first_bh); |
3631 | get_bh(*header_bh); | ||
3632 | 3676 | ||
3633 | brelse(*first_bh); | 3677 | brelse(*header_bh); |
3634 | *first_bh = new_first_bh; | 3678 | *header_bh = old_first->bu_bhs[0]; |
3635 | get_bh(*first_bh); | 3679 | get_bh(*header_bh); |
3636 | } | ||
3637 | brelse(new_bh); | ||
3638 | brelse(old_bh); | ||
3639 | } | 3680 | } |
3640 | 3681 | ||
3641 | le16_add_cpu(&xh->xh_num_buckets, -(num_buckets / 2)); | ||
3642 | |||
3643 | ocfs2_journal_dirty(handle, prev_bh); | ||
3644 | out: | 3682 | out: |
3645 | brelse(prev_bh); | 3683 | ocfs2_xattr_bucket_free(new_first); |
3646 | brelse(new_first_bh); | 3684 | ocfs2_xattr_bucket_free(old_first); |
3685 | |||
3647 | return ret; | 3686 | return ret; |
3648 | } | 3687 | } |
3649 | 3688 | ||