diff options
Diffstat (limited to 'fs/ext4/xattr.c')
-rw-r--r-- | fs/ext4/xattr.c | 166 |
1 files changed, 100 insertions, 66 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index a95151e875bd..0441e055c8e8 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -545,30 +545,44 @@ static void | |||
545 | ext4_xattr_release_block(handle_t *handle, struct inode *inode, | 545 | ext4_xattr_release_block(handle_t *handle, struct inode *inode, |
546 | struct buffer_head *bh) | 546 | struct buffer_head *bh) |
547 | { | 547 | { |
548 | struct mb_cache_entry *ce = NULL; | ||
549 | int error = 0; | ||
550 | struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); | 548 | struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); |
549 | u32 hash, ref; | ||
550 | int error = 0; | ||
551 | 551 | ||
552 | ce = mb_cache_entry_get(ext4_mb_cache, bh->b_bdev, bh->b_blocknr); | ||
553 | BUFFER_TRACE(bh, "get_write_access"); | 552 | BUFFER_TRACE(bh, "get_write_access"); |
554 | error = ext4_journal_get_write_access(handle, bh); | 553 | error = ext4_journal_get_write_access(handle, bh); |
555 | if (error) | 554 | if (error) |
556 | goto out; | 555 | goto out; |
557 | 556 | ||
558 | lock_buffer(bh); | 557 | lock_buffer(bh); |
559 | if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { | 558 | hash = le32_to_cpu(BHDR(bh)->h_hash); |
559 | ref = le32_to_cpu(BHDR(bh)->h_refcount); | ||
560 | if (ref == 1) { | ||
560 | ea_bdebug(bh, "refcount now=0; freeing"); | 561 | ea_bdebug(bh, "refcount now=0; freeing"); |
561 | if (ce) | 562 | /* |
562 | mb_cache_entry_free(ce); | 563 | * This must happen under buffer lock for |
564 | * ext4_xattr_block_set() to reliably detect freed block | ||
565 | */ | ||
566 | mb_cache_entry_delete_block(ext4_mb_cache, hash, bh->b_blocknr); | ||
563 | get_bh(bh); | 567 | get_bh(bh); |
564 | unlock_buffer(bh); | 568 | unlock_buffer(bh); |
565 | ext4_free_blocks(handle, inode, bh, 0, 1, | 569 | ext4_free_blocks(handle, inode, bh, 0, 1, |
566 | EXT4_FREE_BLOCKS_METADATA | | 570 | EXT4_FREE_BLOCKS_METADATA | |
567 | EXT4_FREE_BLOCKS_FORGET); | 571 | EXT4_FREE_BLOCKS_FORGET); |
568 | } else { | 572 | } else { |
569 | le32_add_cpu(&BHDR(bh)->h_refcount, -1); | 573 | ref--; |
570 | if (ce) | 574 | BHDR(bh)->h_refcount = cpu_to_le32(ref); |
571 | mb_cache_entry_release(ce); | 575 | if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) { |
576 | struct mb_cache_entry *ce; | ||
577 | |||
578 | ce = mb_cache_entry_get(ext4_mb_cache, hash, | ||
579 | bh->b_blocknr); | ||
580 | if (ce) { | ||
581 | ce->e_reusable = 1; | ||
582 | mb_cache_entry_put(ext4_mb_cache, ce); | ||
583 | } | ||
584 | } | ||
585 | |||
572 | /* | 586 | /* |
573 | * Beware of this ugliness: Releasing of xattr block references | 587 | * Beware of this ugliness: Releasing of xattr block references |
574 | * from different inodes can race and so we have to protect | 588 | * from different inodes can race and so we have to protect |
@@ -790,8 +804,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
790 | if (i->value && i->value_len > sb->s_blocksize) | 804 | if (i->value && i->value_len > sb->s_blocksize) |
791 | return -ENOSPC; | 805 | return -ENOSPC; |
792 | if (s->base) { | 806 | if (s->base) { |
793 | ce = mb_cache_entry_get(ext4_mb_cache, bs->bh->b_bdev, | ||
794 | bs->bh->b_blocknr); | ||
795 | BUFFER_TRACE(bs->bh, "get_write_access"); | 807 | BUFFER_TRACE(bs->bh, "get_write_access"); |
796 | error = ext4_journal_get_write_access(handle, bs->bh); | 808 | error = ext4_journal_get_write_access(handle, bs->bh); |
797 | if (error) | 809 | if (error) |
@@ -799,10 +811,15 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
799 | lock_buffer(bs->bh); | 811 | lock_buffer(bs->bh); |
800 | 812 | ||
801 | if (header(s->base)->h_refcount == cpu_to_le32(1)) { | 813 | if (header(s->base)->h_refcount == cpu_to_le32(1)) { |
802 | if (ce) { | 814 | __u32 hash = le32_to_cpu(BHDR(bs->bh)->h_hash); |
803 | mb_cache_entry_free(ce); | 815 | |
804 | ce = NULL; | 816 | /* |
805 | } | 817 | * This must happen under buffer lock for |
818 | * ext4_xattr_block_set() to reliably detect modified | ||
819 | * block | ||
820 | */ | ||
821 | mb_cache_entry_delete_block(ext4_mb_cache, hash, | ||
822 | bs->bh->b_blocknr); | ||
806 | ea_bdebug(bs->bh, "modifying in-place"); | 823 | ea_bdebug(bs->bh, "modifying in-place"); |
807 | error = ext4_xattr_set_entry(i, s); | 824 | error = ext4_xattr_set_entry(i, s); |
808 | if (!error) { | 825 | if (!error) { |
@@ -826,10 +843,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
826 | int offset = (char *)s->here - bs->bh->b_data; | 843 | int offset = (char *)s->here - bs->bh->b_data; |
827 | 844 | ||
828 | unlock_buffer(bs->bh); | 845 | unlock_buffer(bs->bh); |
829 | if (ce) { | ||
830 | mb_cache_entry_release(ce); | ||
831 | ce = NULL; | ||
832 | } | ||
833 | ea_bdebug(bs->bh, "cloning"); | 846 | ea_bdebug(bs->bh, "cloning"); |
834 | s->base = kmalloc(bs->bh->b_size, GFP_NOFS); | 847 | s->base = kmalloc(bs->bh->b_size, GFP_NOFS); |
835 | error = -ENOMEM; | 848 | error = -ENOMEM; |
@@ -872,6 +885,8 @@ inserted: | |||
872 | if (new_bh == bs->bh) | 885 | if (new_bh == bs->bh) |
873 | ea_bdebug(new_bh, "keeping"); | 886 | ea_bdebug(new_bh, "keeping"); |
874 | else { | 887 | else { |
888 | u32 ref; | ||
889 | |||
875 | /* The old block is released after updating | 890 | /* The old block is released after updating |
876 | the inode. */ | 891 | the inode. */ |
877 | error = dquot_alloc_block(inode, | 892 | error = dquot_alloc_block(inode, |
@@ -884,9 +899,40 @@ inserted: | |||
884 | if (error) | 899 | if (error) |
885 | goto cleanup_dquot; | 900 | goto cleanup_dquot; |
886 | lock_buffer(new_bh); | 901 | lock_buffer(new_bh); |
887 | le32_add_cpu(&BHDR(new_bh)->h_refcount, 1); | 902 | /* |
903 | * We have to be careful about races with | ||
904 | * freeing, rehashing or adding references to | ||
905 | * xattr block. Once we hold buffer lock xattr | ||
906 | * block's state is stable so we can check | ||
907 | * whether the block got freed / rehashed or | ||
908 | * not. Since we unhash mbcache entry under | ||
909 | * buffer lock when freeing / rehashing xattr | ||
910 | * block, checking whether entry is still | ||
911 | * hashed is reliable. Same rules hold for | ||
912 | * e_reusable handling. | ||
913 | */ | ||
914 | if (hlist_bl_unhashed(&ce->e_hash_list) || | ||
915 | !ce->e_reusable) { | ||
916 | /* | ||
917 | * Undo everything and check mbcache | ||
918 | * again. | ||
919 | */ | ||
920 | unlock_buffer(new_bh); | ||
921 | dquot_free_block(inode, | ||
922 | EXT4_C2B(EXT4_SB(sb), | ||
923 | 1)); | ||
924 | brelse(new_bh); | ||
925 | mb_cache_entry_put(ext4_mb_cache, ce); | ||
926 | ce = NULL; | ||
927 | new_bh = NULL; | ||
928 | goto inserted; | ||
929 | } | ||
930 | ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1; | ||
931 | BHDR(new_bh)->h_refcount = cpu_to_le32(ref); | ||
932 | if (ref >= EXT4_XATTR_REFCOUNT_MAX) | ||
933 | ce->e_reusable = 0; | ||
888 | ea_bdebug(new_bh, "reusing; refcount now=%d", | 934 | ea_bdebug(new_bh, "reusing; refcount now=%d", |
889 | le32_to_cpu(BHDR(new_bh)->h_refcount)); | 935 | ref); |
890 | unlock_buffer(new_bh); | 936 | unlock_buffer(new_bh); |
891 | error = ext4_handle_dirty_xattr_block(handle, | 937 | error = ext4_handle_dirty_xattr_block(handle, |
892 | inode, | 938 | inode, |
@@ -894,7 +940,8 @@ inserted: | |||
894 | if (error) | 940 | if (error) |
895 | goto cleanup_dquot; | 941 | goto cleanup_dquot; |
896 | } | 942 | } |
897 | mb_cache_entry_release(ce); | 943 | mb_cache_entry_touch(ext4_mb_cache, ce); |
944 | mb_cache_entry_put(ext4_mb_cache, ce); | ||
898 | ce = NULL; | 945 | ce = NULL; |
899 | } else if (bs->bh && s->base == bs->bh->b_data) { | 946 | } else if (bs->bh && s->base == bs->bh->b_data) { |
900 | /* We were modifying this block in-place. */ | 947 | /* We were modifying this block in-place. */ |
@@ -959,7 +1006,7 @@ getblk_failed: | |||
959 | 1006 | ||
960 | cleanup: | 1007 | cleanup: |
961 | if (ce) | 1008 | if (ce) |
962 | mb_cache_entry_release(ce); | 1009 | mb_cache_entry_put(ext4_mb_cache, ce); |
963 | brelse(new_bh); | 1010 | brelse(new_bh); |
964 | if (!(bs->bh && s->base == bs->bh->b_data)) | 1011 | if (!(bs->bh && s->base == bs->bh->b_data)) |
965 | kfree(s->base); | 1012 | kfree(s->base); |
@@ -1070,6 +1117,17 @@ static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, | |||
1070 | return 0; | 1117 | return 0; |
1071 | } | 1118 | } |
1072 | 1119 | ||
1120 | static int ext4_xattr_value_same(struct ext4_xattr_search *s, | ||
1121 | struct ext4_xattr_info *i) | ||
1122 | { | ||
1123 | void *value; | ||
1124 | |||
1125 | if (le32_to_cpu(s->here->e_value_size) != i->value_len) | ||
1126 | return 0; | ||
1127 | value = ((void *)s->base) + le16_to_cpu(s->here->e_value_offs); | ||
1128 | return !memcmp(value, i->value, i->value_len); | ||
1129 | } | ||
1130 | |||
1073 | /* | 1131 | /* |
1074 | * ext4_xattr_set_handle() | 1132 | * ext4_xattr_set_handle() |
1075 | * | 1133 | * |
@@ -1146,6 +1204,13 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
1146 | else if (!bs.s.not_found) | 1204 | else if (!bs.s.not_found) |
1147 | error = ext4_xattr_block_set(handle, inode, &i, &bs); | 1205 | error = ext4_xattr_block_set(handle, inode, &i, &bs); |
1148 | } else { | 1206 | } else { |
1207 | error = 0; | ||
1208 | /* Xattr value did not change? Save us some work and bail out */ | ||
1209 | if (!is.s.not_found && ext4_xattr_value_same(&is.s, &i)) | ||
1210 | goto cleanup; | ||
1211 | if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i)) | ||
1212 | goto cleanup; | ||
1213 | |||
1149 | error = ext4_xattr_ibody_set(handle, inode, &i, &is); | 1214 | error = ext4_xattr_ibody_set(handle, inode, &i, &is); |
1150 | if (!error && !bs.s.not_found) { | 1215 | if (!error && !bs.s.not_found) { |
1151 | i.value = NULL; | 1216 | i.value = NULL; |
@@ -1512,17 +1577,6 @@ cleanup: | |||
1512 | } | 1577 | } |
1513 | 1578 | ||
1514 | /* | 1579 | /* |
1515 | * ext4_xattr_put_super() | ||
1516 | * | ||
1517 | * This is called when a file system is unmounted. | ||
1518 | */ | ||
1519 | void | ||
1520 | ext4_xattr_put_super(struct super_block *sb) | ||
1521 | { | ||
1522 | mb_cache_shrink(sb->s_bdev); | ||
1523 | } | ||
1524 | |||
1525 | /* | ||
1526 | * ext4_xattr_cache_insert() | 1580 | * ext4_xattr_cache_insert() |
1527 | * | 1581 | * |
1528 | * Create a new entry in the extended attribute cache, and insert | 1582 | * Create a new entry in the extended attribute cache, and insert |
@@ -1533,26 +1587,19 @@ ext4_xattr_put_super(struct super_block *sb) | |||
1533 | static void | 1587 | static void |
1534 | ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh) | 1588 | ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh) |
1535 | { | 1589 | { |
1536 | __u32 hash = le32_to_cpu(BHDR(bh)->h_hash); | 1590 | struct ext4_xattr_header *header = BHDR(bh); |
1537 | struct mb_cache_entry *ce; | 1591 | __u32 hash = le32_to_cpu(header->h_hash); |
1592 | int reusable = le32_to_cpu(header->h_refcount) < | ||
1593 | EXT4_XATTR_REFCOUNT_MAX; | ||
1538 | int error; | 1594 | int error; |
1539 | 1595 | ||
1540 | ce = mb_cache_entry_alloc(ext4_mb_cache, GFP_NOFS); | 1596 | error = mb_cache_entry_create(ext4_mb_cache, GFP_NOFS, hash, |
1541 | if (!ce) { | 1597 | bh->b_blocknr, reusable); |
1542 | ea_bdebug(bh, "out of memory"); | ||
1543 | return; | ||
1544 | } | ||
1545 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); | ||
1546 | if (error) { | 1598 | if (error) { |
1547 | mb_cache_entry_free(ce); | 1599 | if (error == -EBUSY) |
1548 | if (error == -EBUSY) { | ||
1549 | ea_bdebug(bh, "already in cache"); | 1600 | ea_bdebug(bh, "already in cache"); |
1550 | error = 0; | 1601 | } else |
1551 | } | ||
1552 | } else { | ||
1553 | ea_bdebug(bh, "inserting [%x]", (int)hash); | 1602 | ea_bdebug(bh, "inserting [%x]", (int)hash); |
1554 | mb_cache_entry_release(ce); | ||
1555 | } | ||
1556 | } | 1603 | } |
1557 | 1604 | ||
1558 | /* | 1605 | /* |
@@ -1614,33 +1661,20 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header, | |||
1614 | if (!header->h_hash) | 1661 | if (!header->h_hash) |
1615 | return NULL; /* never share */ | 1662 | return NULL; /* never share */ |
1616 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); | 1663 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); |
1617 | again: | 1664 | ce = mb_cache_entry_find_first(ext4_mb_cache, hash); |
1618 | ce = mb_cache_entry_find_first(ext4_mb_cache, inode->i_sb->s_bdev, | ||
1619 | hash); | ||
1620 | while (ce) { | 1665 | while (ce) { |
1621 | struct buffer_head *bh; | 1666 | struct buffer_head *bh; |
1622 | 1667 | ||
1623 | if (IS_ERR(ce)) { | ||
1624 | if (PTR_ERR(ce) == -EAGAIN) | ||
1625 | goto again; | ||
1626 | break; | ||
1627 | } | ||
1628 | bh = sb_bread(inode->i_sb, ce->e_block); | 1668 | bh = sb_bread(inode->i_sb, ce->e_block); |
1629 | if (!bh) { | 1669 | if (!bh) { |
1630 | EXT4_ERROR_INODE(inode, "block %lu read error", | 1670 | EXT4_ERROR_INODE(inode, "block %lu read error", |
1631 | (unsigned long) ce->e_block); | 1671 | (unsigned long) ce->e_block); |
1632 | } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= | ||
1633 | EXT4_XATTR_REFCOUNT_MAX) { | ||
1634 | ea_idebug(inode, "block %lu refcount %d>=%d", | ||
1635 | (unsigned long) ce->e_block, | ||
1636 | le32_to_cpu(BHDR(bh)->h_refcount), | ||
1637 | EXT4_XATTR_REFCOUNT_MAX); | ||
1638 | } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { | 1672 | } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { |
1639 | *pce = ce; | 1673 | *pce = ce; |
1640 | return bh; | 1674 | return bh; |
1641 | } | 1675 | } |
1642 | brelse(bh); | 1676 | brelse(bh); |
1643 | ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); | 1677 | ce = mb_cache_entry_find_next(ext4_mb_cache, ce); |
1644 | } | 1678 | } |
1645 | return NULL; | 1679 | return NULL; |
1646 | } | 1680 | } |
@@ -1716,9 +1750,9 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header, | |||
1716 | #define HASH_BUCKET_BITS 10 | 1750 | #define HASH_BUCKET_BITS 10 |
1717 | 1751 | ||
1718 | struct mb_cache * | 1752 | struct mb_cache * |
1719 | ext4_xattr_create_cache(char *name) | 1753 | ext4_xattr_create_cache(void) |
1720 | { | 1754 | { |
1721 | return mb_cache_create(name, HASH_BUCKET_BITS); | 1755 | return mb_cache_create(HASH_BUCKET_BITS); |
1722 | } | 1756 | } |
1723 | 1757 | ||
1724 | void ext4_xattr_destroy_cache(struct mb_cache *cache) | 1758 | void ext4_xattr_destroy_cache(struct mb_cache *cache) |