diff options
author | Joel Becker <joel.becker@oracle.com> | 2009-08-19 00:03:24 -0400 |
---|---|---|
committer | Joel Becker <joel.becker@oracle.com> | 2010-02-26 18:41:12 -0500 |
commit | c5d95df5f78312c879f3058059c98a08821897a5 (patch) | |
tree | ae8b3549b50a664b1f48d8608488362a8597d9a5 /fs/ocfs2/xattr.c | |
parent | bca5e9bd1eb2a9422a2ff29e822a956310653754 (diff) |
ocfs2: Let ocfs2_xa_prepare_entry() do space checks.
ocfs2_xattr_set_in_bucket() doesn't need to do its own hacky space
checking. Let's let ocfs2_xa_prepare_entry() (via ocfs2_xa_set()) do
the more accurate work. Whenever it doesn't have space,
ocfs2_xattr_set_in_bucket() can try to get more space.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r-- | fs/ocfs2/xattr.c | 270 |
1 files changed, 93 insertions, 177 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 98c18fbfc28..e7630a77a6c 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -322,14 +322,6 @@ static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb) | |||
322 | return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); | 322 | return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits); |
323 | } | 323 | } |
324 | 324 | ||
325 | static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb) | ||
326 | { | ||
327 | u16 len = sb->s_blocksize - | ||
328 | offsetof(struct ocfs2_xattr_header, xh_entries); | ||
329 | |||
330 | return len / sizeof(struct ocfs2_xattr_entry); | ||
331 | } | ||
332 | |||
333 | #define bucket_blkno(_b) ((_b)->bu_bhs[0]->b_blocknr) | 325 | #define bucket_blkno(_b) ((_b)->bu_bhs[0]->b_blocknr) |
334 | #define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data) | 326 | #define bucket_block(_b, _n) ((_b)->bu_bhs[(_n)]->b_data) |
335 | #define bucket_xh(_b) ((struct ocfs2_xattr_header *)bucket_block((_b), 0)) | 327 | #define bucket_xh(_b) ((struct ocfs2_xattr_header *)bucket_block((_b), 0)) |
@@ -5418,42 +5410,6 @@ out: | |||
5418 | } | 5410 | } |
5419 | 5411 | ||
5420 | /* | 5412 | /* |
5421 | * Set the xattr name/value in the bucket specified in xs. | ||
5422 | */ | ||
5423 | static int ocfs2_xattr_set_in_bucket(struct inode *inode, | ||
5424 | struct ocfs2_xattr_info *xi, | ||
5425 | struct ocfs2_xattr_search *xs, | ||
5426 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
5427 | { | ||
5428 | int ret; | ||
5429 | u64 blkno; | ||
5430 | struct ocfs2_xa_loc loc; | ||
5431 | |||
5432 | if (!xs->bucket->bu_bhs[1]) { | ||
5433 | blkno = bucket_blkno(xs->bucket); | ||
5434 | ocfs2_xattr_bucket_relse(xs->bucket); | ||
5435 | ret = ocfs2_read_xattr_bucket(xs->bucket, blkno); | ||
5436 | if (ret) { | ||
5437 | mlog_errno(ret); | ||
5438 | goto out; | ||
5439 | } | ||
5440 | } | ||
5441 | |||
5442 | ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket, | ||
5443 | xs->not_found ? NULL : xs->here); | ||
5444 | ret = ocfs2_xa_set(&loc, xi, ctxt); | ||
5445 | if (ret) { | ||
5446 | if (ret != -ENOSPC) | ||
5447 | mlog_errno(ret); | ||
5448 | goto out; | ||
5449 | } | ||
5450 | xs->here = loc.xl_entry; | ||
5451 | |||
5452 | out: | ||
5453 | return ret; | ||
5454 | } | ||
5455 | |||
5456 | /* | ||
5457 | * check whether the xattr bucket is filled up with the same hash value. | 5413 | * check whether the xattr bucket is filled up with the same hash value. |
5458 | * If we want to insert the xattr with the same hash, return -ENOSPC. | 5414 | * If we want to insert the xattr with the same hash, return -ENOSPC. |
5459 | * If we want to insert a xattr with different hash value, go ahead | 5415 | * If we want to insert a xattr with different hash value, go ahead |
@@ -5481,156 +5437,116 @@ static int ocfs2_check_xattr_bucket_collision(struct inode *inode, | |||
5481 | return 0; | 5437 | return 0; |
5482 | } | 5438 | } |
5483 | 5439 | ||
5484 | static int ocfs2_xattr_set_entry_index_block(struct inode *inode, | 5440 | /* |
5485 | struct ocfs2_xattr_info *xi, | 5441 | * Try to set the entry in the current bucket. If we fail, the caller |
5486 | struct ocfs2_xattr_search *xs, | 5442 | * will handle getting us another bucket. |
5487 | struct ocfs2_xattr_set_ctxt *ctxt) | 5443 | */ |
5444 | static int ocfs2_xattr_set_entry_bucket(struct inode *inode, | ||
5445 | struct ocfs2_xattr_info *xi, | ||
5446 | struct ocfs2_xattr_search *xs, | ||
5447 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
5488 | { | 5448 | { |
5489 | struct ocfs2_xattr_header *xh; | 5449 | int ret; |
5490 | struct ocfs2_xattr_entry *xe; | 5450 | struct ocfs2_xa_loc loc; |
5491 | u16 count, header_size, xh_free_start; | ||
5492 | int free, max_free, need, old; | ||
5493 | size_t value_size = 0; | ||
5494 | size_t blocksize = inode->i_sb->s_blocksize; | ||
5495 | int ret, allocation = 0; | ||
5496 | |||
5497 | mlog_entry("Set xattr %s in xattr index block\n", xi->xi_name); | ||
5498 | |||
5499 | try_again: | ||
5500 | xh = xs->header; | ||
5501 | count = le16_to_cpu(xh->xh_count); | ||
5502 | xh_free_start = le16_to_cpu(xh->xh_free_start); | ||
5503 | header_size = sizeof(struct ocfs2_xattr_header) + | ||
5504 | count * sizeof(struct ocfs2_xattr_entry); | ||
5505 | max_free = OCFS2_XATTR_BUCKET_SIZE - header_size - | ||
5506 | le16_to_cpu(xh->xh_name_value_len) - OCFS2_XATTR_HEADER_GAP; | ||
5507 | |||
5508 | mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size " | ||
5509 | "of %u which exceed block size\n", | ||
5510 | (unsigned long long)bucket_blkno(xs->bucket), | ||
5511 | header_size); | ||
5512 | 5451 | ||
5513 | if (xi->xi_value && xi->xi_value_len > OCFS2_XATTR_INLINE_SIZE) | 5452 | mlog_entry("Set xattr %s in xattr bucket\n", xi->xi_name); |
5514 | value_size = OCFS2_XATTR_ROOT_SIZE; | ||
5515 | else if (xi->xi_value) | ||
5516 | value_size = OCFS2_XATTR_SIZE(xi->xi_value_len); | ||
5517 | 5453 | ||
5518 | if (xs->not_found) | 5454 | ocfs2_init_xattr_bucket_xa_loc(&loc, xs->bucket, |
5519 | need = sizeof(struct ocfs2_xattr_entry) + | 5455 | xs->not_found ? NULL : xs->here); |
5520 | OCFS2_XATTR_SIZE(xi->xi_name_len) + value_size; | 5456 | ret = ocfs2_xa_set(&loc, xi, ctxt); |
5521 | else { | 5457 | if (!ret) { |
5522 | need = value_size + OCFS2_XATTR_SIZE(xi->xi_name_len); | 5458 | xs->here = loc.xl_entry; |
5459 | goto out; | ||
5460 | } | ||
5461 | if (ret != -ENOSPC) { | ||
5462 | mlog_errno(ret); | ||
5463 | goto out; | ||
5464 | } | ||
5523 | 5465 | ||
5524 | /* | 5466 | /* Ok, we need space. Let's try defragmenting the bucket. */ |
5525 | * We only replace the old value if the new length is smaller | 5467 | ret = ocfs2_defrag_xattr_bucket(inode, ctxt->handle, |
5526 | * than the old one. Otherwise we will allocate new space in the | 5468 | xs->bucket); |
5527 | * bucket to store it. | 5469 | if (ret) { |
5528 | */ | 5470 | mlog_errno(ret); |
5529 | xe = xs->here; | 5471 | goto out; |
5530 | if (ocfs2_xattr_is_local(xe)) | 5472 | } |
5531 | old = OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size)); | ||
5532 | else | ||
5533 | old = OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE); | ||
5534 | 5473 | ||
5535 | if (old >= value_size) | 5474 | ret = ocfs2_xa_set(&loc, xi, ctxt); |
5536 | need = 0; | 5475 | if (!ret) { |
5476 | xs->here = loc.xl_entry; | ||
5477 | goto out; | ||
5537 | } | 5478 | } |
5479 | if (ret != -ENOSPC) | ||
5480 | mlog_errno(ret); | ||
5538 | 5481 | ||
5539 | free = xh_free_start - header_size - OCFS2_XATTR_HEADER_GAP; | ||
5540 | /* | ||
5541 | * We need to make sure the new name/value pair | ||
5542 | * can exist in the same block. | ||
5543 | */ | ||
5544 | if (xh_free_start % blocksize < need) | ||
5545 | free -= xh_free_start % blocksize; | ||
5546 | |||
5547 | mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, " | ||
5548 | "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len =" | ||
5549 | " %u\n", xs->not_found, | ||
5550 | (unsigned long long)bucket_blkno(xs->bucket), | ||
5551 | free, need, max_free, le16_to_cpu(xh->xh_free_start), | ||
5552 | le16_to_cpu(xh->xh_name_value_len)); | ||
5553 | |||
5554 | if (free < need || | ||
5555 | (xs->not_found && | ||
5556 | count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb))) { | ||
5557 | if (need <= max_free && | ||
5558 | count < ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) { | ||
5559 | /* | ||
5560 | * We can create the space by defragment. Since only the | ||
5561 | * name/value will be moved, the xe shouldn't be changed | ||
5562 | * in xs. | ||
5563 | */ | ||
5564 | ret = ocfs2_defrag_xattr_bucket(inode, ctxt->handle, | ||
5565 | xs->bucket); | ||
5566 | if (ret) { | ||
5567 | mlog_errno(ret); | ||
5568 | goto out; | ||
5569 | } | ||
5570 | 5482 | ||
5571 | xh_free_start = le16_to_cpu(xh->xh_free_start); | 5483 | out: |
5572 | free = xh_free_start - header_size | 5484 | mlog_exit(ret); |
5573 | - OCFS2_XATTR_HEADER_GAP; | 5485 | return ret; |
5574 | if (xh_free_start % blocksize < need) | 5486 | } |
5575 | free -= xh_free_start % blocksize; | ||
5576 | 5487 | ||
5577 | if (free >= need) | 5488 | static int ocfs2_xattr_set_entry_index_block(struct inode *inode, |
5578 | goto xattr_set; | 5489 | struct ocfs2_xattr_info *xi, |
5490 | struct ocfs2_xattr_search *xs, | ||
5491 | struct ocfs2_xattr_set_ctxt *ctxt) | ||
5492 | { | ||
5493 | int ret; | ||
5579 | 5494 | ||
5580 | mlog(0, "Can't get enough space for xattr insert by " | 5495 | mlog_entry("Set xattr %s in xattr index block\n", xi->xi_name); |
5581 | "defragment. Need %u bytes, but we have %d, so " | ||
5582 | "allocate new bucket for it.\n", need, free); | ||
5583 | } | ||
5584 | 5496 | ||
5585 | /* | 5497 | ret = ocfs2_xattr_set_entry_bucket(inode, xi, xs, ctxt); |
5586 | * We have to add new buckets or clusters and one | 5498 | if (!ret) |
5587 | * allocation should leave us enough space for insert. | 5499 | goto out; |
5588 | */ | 5500 | if (ret != -ENOSPC) { |
5589 | BUG_ON(allocation); | 5501 | mlog_errno(ret); |
5502 | goto out; | ||
5503 | } | ||
5590 | 5504 | ||
5591 | /* | 5505 | /* Ack, need more space. Let's try to get another bucket! */ |
5592 | * We do not allow for overlapping ranges between buckets. And | ||
5593 | * the maximum number of collisions we will allow for then is | ||
5594 | * one bucket's worth, so check it here whether we need to | ||
5595 | * add a new bucket for the insert. | ||
5596 | */ | ||
5597 | ret = ocfs2_check_xattr_bucket_collision(inode, | ||
5598 | xs->bucket, | ||
5599 | xi->xi_name); | ||
5600 | if (ret) { | ||
5601 | mlog_errno(ret); | ||
5602 | goto out; | ||
5603 | } | ||
5604 | 5506 | ||
5605 | ret = ocfs2_add_new_xattr_bucket(inode, | 5507 | /* |
5606 | xs->xattr_bh, | 5508 | * We do not allow for overlapping ranges between buckets. And |
5509 | * the maximum number of collisions we will allow for then is | ||
5510 | * one bucket's worth, so check it here whether we need to | ||
5511 | * add a new bucket for the insert. | ||
5512 | */ | ||
5513 | ret = ocfs2_check_xattr_bucket_collision(inode, | ||
5607 | xs->bucket, | 5514 | xs->bucket, |
5608 | ctxt); | 5515 | xi->xi_name); |
5609 | if (ret) { | 5516 | if (ret) { |
5610 | mlog_errno(ret); | 5517 | mlog_errno(ret); |
5611 | goto out; | 5518 | goto out; |
5612 | } | 5519 | } |
5613 | 5520 | ||
5614 | /* | 5521 | ret = ocfs2_add_new_xattr_bucket(inode, |
5615 | * ocfs2_add_new_xattr_bucket() will have updated | 5522 | xs->xattr_bh, |
5616 | * xs->bucket if it moved, but it will not have updated | 5523 | xs->bucket, |
5617 | * any of the other search fields. Thus, we drop it and | 5524 | ctxt); |
5618 | * re-search. Everything should be cached, so it'll be | 5525 | if (ret) { |
5619 | * quick. | 5526 | mlog_errno(ret); |
5620 | */ | 5527 | goto out; |
5621 | ocfs2_xattr_bucket_relse(xs->bucket); | ||
5622 | ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh, | ||
5623 | xi->xi_name_index, | ||
5624 | xi->xi_name, xs); | ||
5625 | if (ret && ret != -ENODATA) | ||
5626 | goto out; | ||
5627 | xs->not_found = ret; | ||
5628 | allocation = 1; | ||
5629 | goto try_again; | ||
5630 | } | 5528 | } |
5631 | 5529 | ||
5632 | xattr_set: | 5530 | /* |
5633 | ret = ocfs2_xattr_set_in_bucket(inode, xi, xs, ctxt); | 5531 | * ocfs2_add_new_xattr_bucket() will have updated |
5532 | * xs->bucket if it moved, but it will not have updated | ||
5533 | * any of the other search fields. Thus, we drop it and | ||
5534 | * re-search. Everything should be cached, so it'll be | ||
5535 | * quick. | ||
5536 | */ | ||
5537 | ocfs2_xattr_bucket_relse(xs->bucket); | ||
5538 | ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh, | ||
5539 | xi->xi_name_index, | ||
5540 | xi->xi_name, xs); | ||
5541 | if (ret && ret != -ENODATA) | ||
5542 | goto out; | ||
5543 | xs->not_found = ret; | ||
5544 | |||
5545 | /* Ok, we have a new bucket, let's try again */ | ||
5546 | ret = ocfs2_xattr_set_entry_bucket(inode, xi, xs, ctxt); | ||
5547 | if (ret && (ret != -ENOSPC)) | ||
5548 | mlog_errno(ret); | ||
5549 | |||
5634 | out: | 5550 | out: |
5635 | mlog_exit(ret); | 5551 | mlog_exit(ret); |
5636 | return ret; | 5552 | return ret; |