diff options
Diffstat (limited to 'fs/ext2')
-rw-r--r-- | fs/ext2/ext2.h | 3 | ||||
-rw-r--r-- | fs/ext2/super.c | 25 | ||||
-rw-r--r-- | fs/ext2/xattr.c | 139 | ||||
-rw-r--r-- | fs/ext2/xattr.h | 21 |
4 files changed, 90 insertions, 98 deletions
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 4c69c94cafd8..170939f379d7 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
@@ -61,6 +61,8 @@ struct ext2_block_alloc_info { | |||
61 | #define rsv_start rsv_window._rsv_start | 61 | #define rsv_start rsv_window._rsv_start |
62 | #define rsv_end rsv_window._rsv_end | 62 | #define rsv_end rsv_window._rsv_end |
63 | 63 | ||
64 | struct mb_cache; | ||
65 | |||
64 | /* | 66 | /* |
65 | * second extended-fs super-block data in memory | 67 | * second extended-fs super-block data in memory |
66 | */ | 68 | */ |
@@ -111,6 +113,7 @@ struct ext2_sb_info { | |||
111 | * of the mount options. | 113 | * of the mount options. |
112 | */ | 114 | */ |
113 | spinlock_t s_lock; | 115 | spinlock_t s_lock; |
116 | struct mb_cache *s_mb_cache; | ||
114 | }; | 117 | }; |
115 | 118 | ||
116 | static inline spinlock_t * | 119 | static inline spinlock_t * |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 2a188413a2b0..b78caf25f746 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -131,7 +131,10 @@ static void ext2_put_super (struct super_block * sb) | |||
131 | 131 | ||
132 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); | 132 | dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); |
133 | 133 | ||
134 | ext2_xattr_put_super(sb); | 134 | if (sbi->s_mb_cache) { |
135 | ext2_xattr_destroy_cache(sbi->s_mb_cache); | ||
136 | sbi->s_mb_cache = NULL; | ||
137 | } | ||
135 | if (!(sb->s_flags & MS_RDONLY)) { | 138 | if (!(sb->s_flags & MS_RDONLY)) { |
136 | struct ext2_super_block *es = sbi->s_es; | 139 | struct ext2_super_block *es = sbi->s_es; |
137 | 140 | ||
@@ -1104,6 +1107,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) | |||
1104 | ext2_msg(sb, KERN_ERR, "error: insufficient memory"); | 1107 | ext2_msg(sb, KERN_ERR, "error: insufficient memory"); |
1105 | goto failed_mount3; | 1108 | goto failed_mount3; |
1106 | } | 1109 | } |
1110 | |||
1111 | #ifdef CONFIG_EXT2_FS_XATTR | ||
1112 | sbi->s_mb_cache = ext2_xattr_create_cache(); | ||
1113 | if (!sbi->s_mb_cache) { | ||
1114 | ext2_msg(sb, KERN_ERR, "Failed to create an mb_cache"); | ||
1115 | goto failed_mount3; | ||
1116 | } | ||
1117 | #endif | ||
1107 | /* | 1118 | /* |
1108 | * set up enough so that it can read an inode | 1119 | * set up enough so that it can read an inode |
1109 | */ | 1120 | */ |
@@ -1149,6 +1160,8 @@ cantfind_ext2: | |||
1149 | sb->s_id); | 1160 | sb->s_id); |
1150 | goto failed_mount; | 1161 | goto failed_mount; |
1151 | failed_mount3: | 1162 | failed_mount3: |
1163 | if (sbi->s_mb_cache) | ||
1164 | ext2_xattr_destroy_cache(sbi->s_mb_cache); | ||
1152 | percpu_counter_destroy(&sbi->s_freeblocks_counter); | 1165 | percpu_counter_destroy(&sbi->s_freeblocks_counter); |
1153 | percpu_counter_destroy(&sbi->s_freeinodes_counter); | 1166 | percpu_counter_destroy(&sbi->s_freeinodes_counter); |
1154 | percpu_counter_destroy(&sbi->s_dirs_counter); | 1167 | percpu_counter_destroy(&sbi->s_dirs_counter); |
@@ -1555,20 +1568,17 @@ MODULE_ALIAS_FS("ext2"); | |||
1555 | 1568 | ||
1556 | static int __init init_ext2_fs(void) | 1569 | static int __init init_ext2_fs(void) |
1557 | { | 1570 | { |
1558 | int err = init_ext2_xattr(); | 1571 | int err; |
1559 | if (err) | 1572 | |
1560 | return err; | ||
1561 | err = init_inodecache(); | 1573 | err = init_inodecache(); |
1562 | if (err) | 1574 | if (err) |
1563 | goto out1; | 1575 | return err; |
1564 | err = register_filesystem(&ext2_fs_type); | 1576 | err = register_filesystem(&ext2_fs_type); |
1565 | if (err) | 1577 | if (err) |
1566 | goto out; | 1578 | goto out; |
1567 | return 0; | 1579 | return 0; |
1568 | out: | 1580 | out: |
1569 | destroy_inodecache(); | 1581 | destroy_inodecache(); |
1570 | out1: | ||
1571 | exit_ext2_xattr(); | ||
1572 | return err; | 1582 | return err; |
1573 | } | 1583 | } |
1574 | 1584 | ||
@@ -1576,7 +1586,6 @@ static void __exit exit_ext2_fs(void) | |||
1576 | { | 1586 | { |
1577 | unregister_filesystem(&ext2_fs_type); | 1587 | unregister_filesystem(&ext2_fs_type); |
1578 | destroy_inodecache(); | 1588 | destroy_inodecache(); |
1579 | exit_ext2_xattr(); | ||
1580 | } | 1589 | } |
1581 | 1590 | ||
1582 | MODULE_AUTHOR("Remy Card and others"); | 1591 | MODULE_AUTHOR("Remy Card and others"); |
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index f57a7aba32eb..1a5e3bff0b63 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c | |||
@@ -90,14 +90,12 @@ | |||
90 | static int ext2_xattr_set2(struct inode *, struct buffer_head *, | 90 | static int ext2_xattr_set2(struct inode *, struct buffer_head *, |
91 | struct ext2_xattr_header *); | 91 | struct ext2_xattr_header *); |
92 | 92 | ||
93 | static int ext2_xattr_cache_insert(struct buffer_head *); | 93 | static int ext2_xattr_cache_insert(struct mb_cache *, struct buffer_head *); |
94 | static struct buffer_head *ext2_xattr_cache_find(struct inode *, | 94 | static struct buffer_head *ext2_xattr_cache_find(struct inode *, |
95 | struct ext2_xattr_header *); | 95 | struct ext2_xattr_header *); |
96 | static void ext2_xattr_rehash(struct ext2_xattr_header *, | 96 | static void ext2_xattr_rehash(struct ext2_xattr_header *, |
97 | struct ext2_xattr_entry *); | 97 | struct ext2_xattr_entry *); |
98 | 98 | ||
99 | static struct mb_cache *ext2_xattr_cache; | ||
100 | |||
101 | static const struct xattr_handler *ext2_xattr_handler_map[] = { | 99 | static const struct xattr_handler *ext2_xattr_handler_map[] = { |
102 | [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, | 100 | [EXT2_XATTR_INDEX_USER] = &ext2_xattr_user_handler, |
103 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | 101 | #ifdef CONFIG_EXT2_FS_POSIX_ACL |
@@ -152,6 +150,7 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name, | |||
152 | size_t name_len, size; | 150 | size_t name_len, size; |
153 | char *end; | 151 | char *end; |
154 | int error; | 152 | int error; |
153 | struct mb_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache; | ||
155 | 154 | ||
156 | ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", | 155 | ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", |
157 | name_index, name, buffer, (long)buffer_size); | 156 | name_index, name, buffer, (long)buffer_size); |
@@ -196,7 +195,7 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", | |||
196 | goto found; | 195 | goto found; |
197 | entry = next; | 196 | entry = next; |
198 | } | 197 | } |
199 | if (ext2_xattr_cache_insert(bh)) | 198 | if (ext2_xattr_cache_insert(ext2_mb_cache, bh)) |
200 | ea_idebug(inode, "cache insert failed"); | 199 | ea_idebug(inode, "cache insert failed"); |
201 | error = -ENODATA; | 200 | error = -ENODATA; |
202 | goto cleanup; | 201 | goto cleanup; |
@@ -209,7 +208,7 @@ found: | |||
209 | le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) | 208 | le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) |
210 | goto bad_block; | 209 | goto bad_block; |
211 | 210 | ||
212 | if (ext2_xattr_cache_insert(bh)) | 211 | if (ext2_xattr_cache_insert(ext2_mb_cache, bh)) |
213 | ea_idebug(inode, "cache insert failed"); | 212 | ea_idebug(inode, "cache insert failed"); |
214 | if (buffer) { | 213 | if (buffer) { |
215 | error = -ERANGE; | 214 | error = -ERANGE; |
@@ -247,6 +246,7 @@ ext2_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) | |||
247 | char *end; | 246 | char *end; |
248 | size_t rest = buffer_size; | 247 | size_t rest = buffer_size; |
249 | int error; | 248 | int error; |
249 | struct mb_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache; | ||
250 | 250 | ||
251 | ea_idebug(inode, "buffer=%p, buffer_size=%ld", | 251 | ea_idebug(inode, "buffer=%p, buffer_size=%ld", |
252 | buffer, (long)buffer_size); | 252 | buffer, (long)buffer_size); |
@@ -281,7 +281,7 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", | |||
281 | goto bad_block; | 281 | goto bad_block; |
282 | entry = next; | 282 | entry = next; |
283 | } | 283 | } |
284 | if (ext2_xattr_cache_insert(bh)) | 284 | if (ext2_xattr_cache_insert(ext2_mb_cache, bh)) |
285 | ea_idebug(inode, "cache insert failed"); | 285 | ea_idebug(inode, "cache insert failed"); |
286 | 286 | ||
287 | /* list the attribute names */ | 287 | /* list the attribute names */ |
@@ -483,22 +483,23 @@ bad_block: ext2_error(sb, "ext2_xattr_set", | |||
483 | /* Here we know that we can set the new attribute. */ | 483 | /* Here we know that we can set the new attribute. */ |
484 | 484 | ||
485 | if (header) { | 485 | if (header) { |
486 | struct mb_cache_entry *ce; | ||
487 | |||
488 | /* assert(header == HDR(bh)); */ | 486 | /* assert(header == HDR(bh)); */ |
489 | ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, | ||
490 | bh->b_blocknr); | ||
491 | lock_buffer(bh); | 487 | lock_buffer(bh); |
492 | if (header->h_refcount == cpu_to_le32(1)) { | 488 | if (header->h_refcount == cpu_to_le32(1)) { |
489 | __u32 hash = le32_to_cpu(header->h_hash); | ||
490 | |||
493 | ea_bdebug(bh, "modifying in-place"); | 491 | ea_bdebug(bh, "modifying in-place"); |
494 | if (ce) | 492 | /* |
495 | mb_cache_entry_free(ce); | 493 | * This must happen under buffer lock for |
494 | * ext2_xattr_set2() to reliably detect modified block | ||
495 | */ | ||
496 | mb_cache_entry_delete_block(EXT2_SB(sb)->s_mb_cache, | ||
497 | hash, bh->b_blocknr); | ||
498 | |||
496 | /* keep the buffer locked while modifying it. */ | 499 | /* keep the buffer locked while modifying it. */ |
497 | } else { | 500 | } else { |
498 | int offset; | 501 | int offset; |
499 | 502 | ||
500 | if (ce) | ||
501 | mb_cache_entry_release(ce); | ||
502 | unlock_buffer(bh); | 503 | unlock_buffer(bh); |
503 | ea_bdebug(bh, "cloning"); | 504 | ea_bdebug(bh, "cloning"); |
504 | header = kmalloc(bh->b_size, GFP_KERNEL); | 505 | header = kmalloc(bh->b_size, GFP_KERNEL); |
@@ -626,6 +627,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
626 | struct super_block *sb = inode->i_sb; | 627 | struct super_block *sb = inode->i_sb; |
627 | struct buffer_head *new_bh = NULL; | 628 | struct buffer_head *new_bh = NULL; |
628 | int error; | 629 | int error; |
630 | struct mb_cache *ext2_mb_cache = EXT2_SB(sb)->s_mb_cache; | ||
629 | 631 | ||
630 | if (header) { | 632 | if (header) { |
631 | new_bh = ext2_xattr_cache_find(inode, header); | 633 | new_bh = ext2_xattr_cache_find(inode, header); |
@@ -653,7 +655,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
653 | don't need to change the reference count. */ | 655 | don't need to change the reference count. */ |
654 | new_bh = old_bh; | 656 | new_bh = old_bh; |
655 | get_bh(new_bh); | 657 | get_bh(new_bh); |
656 | ext2_xattr_cache_insert(new_bh); | 658 | ext2_xattr_cache_insert(ext2_mb_cache, new_bh); |
657 | } else { | 659 | } else { |
658 | /* We need to allocate a new block */ | 660 | /* We need to allocate a new block */ |
659 | ext2_fsblk_t goal = ext2_group_first_block_no(sb, | 661 | ext2_fsblk_t goal = ext2_group_first_block_no(sb, |
@@ -674,7 +676,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
674 | memcpy(new_bh->b_data, header, new_bh->b_size); | 676 | memcpy(new_bh->b_data, header, new_bh->b_size); |
675 | set_buffer_uptodate(new_bh); | 677 | set_buffer_uptodate(new_bh); |
676 | unlock_buffer(new_bh); | 678 | unlock_buffer(new_bh); |
677 | ext2_xattr_cache_insert(new_bh); | 679 | ext2_xattr_cache_insert(ext2_mb_cache, new_bh); |
678 | 680 | ||
679 | ext2_xattr_update_super_block(sb); | 681 | ext2_xattr_update_super_block(sb); |
680 | } | 682 | } |
@@ -707,19 +709,21 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
707 | 709 | ||
708 | error = 0; | 710 | error = 0; |
709 | if (old_bh && old_bh != new_bh) { | 711 | if (old_bh && old_bh != new_bh) { |
710 | struct mb_cache_entry *ce; | ||
711 | |||
712 | /* | 712 | /* |
713 | * If there was an old block and we are no longer using it, | 713 | * If there was an old block and we are no longer using it, |
714 | * release the old block. | 714 | * release the old block. |
715 | */ | 715 | */ |
716 | ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev, | ||
717 | old_bh->b_blocknr); | ||
718 | lock_buffer(old_bh); | 716 | lock_buffer(old_bh); |
719 | if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { | 717 | if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) { |
718 | __u32 hash = le32_to_cpu(HDR(old_bh)->h_hash); | ||
719 | |||
720 | /* | ||
721 | * This must happen under buffer lock for | ||
722 | * ext2_xattr_set2() to reliably detect freed block | ||
723 | */ | ||
724 | mb_cache_entry_delete_block(ext2_mb_cache, | ||
725 | hash, old_bh->b_blocknr); | ||
720 | /* Free the old block. */ | 726 | /* Free the old block. */ |
721 | if (ce) | ||
722 | mb_cache_entry_free(ce); | ||
723 | ea_bdebug(old_bh, "freeing"); | 727 | ea_bdebug(old_bh, "freeing"); |
724 | ext2_free_blocks(inode, old_bh->b_blocknr, 1); | 728 | ext2_free_blocks(inode, old_bh->b_blocknr, 1); |
725 | mark_inode_dirty(inode); | 729 | mark_inode_dirty(inode); |
@@ -730,8 +734,6 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
730 | } else { | 734 | } else { |
731 | /* Decrement the refcount only. */ | 735 | /* Decrement the refcount only. */ |
732 | le32_add_cpu(&HDR(old_bh)->h_refcount, -1); | 736 | le32_add_cpu(&HDR(old_bh)->h_refcount, -1); |
733 | if (ce) | ||
734 | mb_cache_entry_release(ce); | ||
735 | dquot_free_block_nodirty(inode, 1); | 737 | dquot_free_block_nodirty(inode, 1); |
736 | mark_inode_dirty(inode); | 738 | mark_inode_dirty(inode); |
737 | mark_buffer_dirty(old_bh); | 739 | mark_buffer_dirty(old_bh); |
@@ -757,7 +759,6 @@ void | |||
757 | ext2_xattr_delete_inode(struct inode *inode) | 759 | ext2_xattr_delete_inode(struct inode *inode) |
758 | { | 760 | { |
759 | struct buffer_head *bh = NULL; | 761 | struct buffer_head *bh = NULL; |
760 | struct mb_cache_entry *ce; | ||
761 | 762 | ||
762 | down_write(&EXT2_I(inode)->xattr_sem); | 763 | down_write(&EXT2_I(inode)->xattr_sem); |
763 | if (!EXT2_I(inode)->i_file_acl) | 764 | if (!EXT2_I(inode)->i_file_acl) |
@@ -777,19 +778,22 @@ ext2_xattr_delete_inode(struct inode *inode) | |||
777 | EXT2_I(inode)->i_file_acl); | 778 | EXT2_I(inode)->i_file_acl); |
778 | goto cleanup; | 779 | goto cleanup; |
779 | } | 780 | } |
780 | ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_bdev, bh->b_blocknr); | ||
781 | lock_buffer(bh); | 781 | lock_buffer(bh); |
782 | if (HDR(bh)->h_refcount == cpu_to_le32(1)) { | 782 | if (HDR(bh)->h_refcount == cpu_to_le32(1)) { |
783 | if (ce) | 783 | __u32 hash = le32_to_cpu(HDR(bh)->h_hash); |
784 | mb_cache_entry_free(ce); | 784 | |
785 | /* | ||
786 | * This must happen under buffer lock for ext2_xattr_set2() to | ||
787 | * reliably detect freed block | ||
788 | */ | ||
789 | mb_cache_entry_delete_block(EXT2_SB(inode->i_sb)->s_mb_cache, | ||
790 | hash, bh->b_blocknr); | ||
785 | ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); | 791 | ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1); |
786 | get_bh(bh); | 792 | get_bh(bh); |
787 | bforget(bh); | 793 | bforget(bh); |
788 | unlock_buffer(bh); | 794 | unlock_buffer(bh); |
789 | } else { | 795 | } else { |
790 | le32_add_cpu(&HDR(bh)->h_refcount, -1); | 796 | le32_add_cpu(&HDR(bh)->h_refcount, -1); |
791 | if (ce) | ||
792 | mb_cache_entry_release(ce); | ||
793 | ea_bdebug(bh, "refcount now=%d", | 797 | ea_bdebug(bh, "refcount now=%d", |
794 | le32_to_cpu(HDR(bh)->h_refcount)); | 798 | le32_to_cpu(HDR(bh)->h_refcount)); |
795 | unlock_buffer(bh); | 799 | unlock_buffer(bh); |
@@ -806,18 +810,6 @@ cleanup: | |||
806 | } | 810 | } |
807 | 811 | ||
808 | /* | 812 | /* |
809 | * ext2_xattr_put_super() | ||
810 | * | ||
811 | * This is called when a file system is unmounted. | ||
812 | */ | ||
813 | void | ||
814 | ext2_xattr_put_super(struct super_block *sb) | ||
815 | { | ||
816 | mb_cache_shrink(sb->s_bdev); | ||
817 | } | ||
818 | |||
819 | |||
820 | /* | ||
821 | * ext2_xattr_cache_insert() | 813 | * ext2_xattr_cache_insert() |
822 | * | 814 | * |
823 | * Create a new entry in the extended attribute cache, and insert | 815 | * Create a new entry in the extended attribute cache, and insert |
@@ -826,28 +818,20 @@ ext2_xattr_put_super(struct super_block *sb) | |||
826 | * Returns 0, or a negative error number on failure. | 818 | * Returns 0, or a negative error number on failure. |
827 | */ | 819 | */ |
828 | static int | 820 | static int |
829 | ext2_xattr_cache_insert(struct buffer_head *bh) | 821 | ext2_xattr_cache_insert(struct mb_cache *cache, struct buffer_head *bh) |
830 | { | 822 | { |
831 | __u32 hash = le32_to_cpu(HDR(bh)->h_hash); | 823 | __u32 hash = le32_to_cpu(HDR(bh)->h_hash); |
832 | struct mb_cache_entry *ce; | ||
833 | int error; | 824 | int error; |
834 | 825 | ||
835 | ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS); | 826 | error = mb_cache_entry_create(cache, GFP_NOFS, hash, bh->b_blocknr, 1); |
836 | if (!ce) | ||
837 | return -ENOMEM; | ||
838 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); | ||
839 | if (error) { | 827 | if (error) { |
840 | mb_cache_entry_free(ce); | ||
841 | if (error == -EBUSY) { | 828 | if (error == -EBUSY) { |
842 | ea_bdebug(bh, "already in cache (%d cache entries)", | 829 | ea_bdebug(bh, "already in cache (%d cache entries)", |
843 | atomic_read(&ext2_xattr_cache->c_entry_count)); | 830 | atomic_read(&ext2_xattr_cache->c_entry_count)); |
844 | error = 0; | 831 | error = 0; |
845 | } | 832 | } |
846 | } else { | 833 | } else |
847 | ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, | 834 | ea_bdebug(bh, "inserting [%x]", (int)hash); |
848 | atomic_read(&ext2_xattr_cache->c_entry_count)); | ||
849 | mb_cache_entry_release(ce); | ||
850 | } | ||
851 | return error; | 835 | return error; |
852 | } | 836 | } |
853 | 837 | ||
@@ -904,22 +888,16 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) | |||
904 | { | 888 | { |
905 | __u32 hash = le32_to_cpu(header->h_hash); | 889 | __u32 hash = le32_to_cpu(header->h_hash); |
906 | struct mb_cache_entry *ce; | 890 | struct mb_cache_entry *ce; |
891 | struct mb_cache *ext2_mb_cache = EXT2_SB(inode->i_sb)->s_mb_cache; | ||
907 | 892 | ||
908 | if (!header->h_hash) | 893 | if (!header->h_hash) |
909 | return NULL; /* never share */ | 894 | return NULL; /* never share */ |
910 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); | 895 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); |
911 | again: | 896 | again: |
912 | ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev, | 897 | ce = mb_cache_entry_find_first(ext2_mb_cache, hash); |
913 | hash); | ||
914 | while (ce) { | 898 | while (ce) { |
915 | struct buffer_head *bh; | 899 | struct buffer_head *bh; |
916 | 900 | ||
917 | if (IS_ERR(ce)) { | ||
918 | if (PTR_ERR(ce) == -EAGAIN) | ||
919 | goto again; | ||
920 | break; | ||
921 | } | ||
922 | |||
923 | bh = sb_bread(inode->i_sb, ce->e_block); | 901 | bh = sb_bread(inode->i_sb, ce->e_block); |
924 | if (!bh) { | 902 | if (!bh) { |
925 | ext2_error(inode->i_sb, "ext2_xattr_cache_find", | 903 | ext2_error(inode->i_sb, "ext2_xattr_cache_find", |
@@ -927,7 +905,21 @@ again: | |||
927 | inode->i_ino, (unsigned long) ce->e_block); | 905 | inode->i_ino, (unsigned long) ce->e_block); |
928 | } else { | 906 | } else { |
929 | lock_buffer(bh); | 907 | lock_buffer(bh); |
930 | if (le32_to_cpu(HDR(bh)->h_refcount) > | 908 | /* |
909 | * We have to be careful about races with freeing or | ||
910 | * rehashing of xattr block. Once we hold buffer lock | ||
911 | * xattr block's state is stable so we can check | ||
912 | * whether the block got freed / rehashed or not. | ||
913 | * Since we unhash mbcache entry under buffer lock when | ||
914 | * freeing / rehashing xattr block, checking whether | ||
915 | * entry is still hashed is reliable. | ||
916 | */ | ||
917 | if (hlist_bl_unhashed(&ce->e_hash_list)) { | ||
918 | mb_cache_entry_put(ext2_mb_cache, ce); | ||
919 | unlock_buffer(bh); | ||
920 | brelse(bh); | ||
921 | goto again; | ||
922 | } else if (le32_to_cpu(HDR(bh)->h_refcount) > | ||
931 | EXT2_XATTR_REFCOUNT_MAX) { | 923 | EXT2_XATTR_REFCOUNT_MAX) { |
932 | ea_idebug(inode, "block %ld refcount %d>%d", | 924 | ea_idebug(inode, "block %ld refcount %d>%d", |
933 | (unsigned long) ce->e_block, | 925 | (unsigned long) ce->e_block, |
@@ -936,13 +928,14 @@ again: | |||
936 | } else if (!ext2_xattr_cmp(header, HDR(bh))) { | 928 | } else if (!ext2_xattr_cmp(header, HDR(bh))) { |
937 | ea_bdebug(bh, "b_count=%d", | 929 | ea_bdebug(bh, "b_count=%d", |
938 | atomic_read(&(bh->b_count))); | 930 | atomic_read(&(bh->b_count))); |
939 | mb_cache_entry_release(ce); | 931 | mb_cache_entry_touch(ext2_mb_cache, ce); |
932 | mb_cache_entry_put(ext2_mb_cache, ce); | ||
940 | return bh; | 933 | return bh; |
941 | } | 934 | } |
942 | unlock_buffer(bh); | 935 | unlock_buffer(bh); |
943 | brelse(bh); | 936 | brelse(bh); |
944 | } | 937 | } |
945 | ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); | 938 | ce = mb_cache_entry_find_next(ext2_mb_cache, ce); |
946 | } | 939 | } |
947 | return NULL; | 940 | return NULL; |
948 | } | 941 | } |
@@ -1015,17 +1008,15 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *header, | |||
1015 | 1008 | ||
1016 | #undef BLOCK_HASH_SHIFT | 1009 | #undef BLOCK_HASH_SHIFT |
1017 | 1010 | ||
1018 | int __init | 1011 | #define HASH_BUCKET_BITS 10 |
1019 | init_ext2_xattr(void) | 1012 | |
1013 | struct mb_cache *ext2_xattr_create_cache(void) | ||
1020 | { | 1014 | { |
1021 | ext2_xattr_cache = mb_cache_create("ext2_xattr", 6); | 1015 | return mb_cache_create(HASH_BUCKET_BITS); |
1022 | if (!ext2_xattr_cache) | ||
1023 | return -ENOMEM; | ||
1024 | return 0; | ||
1025 | } | 1016 | } |
1026 | 1017 | ||
1027 | void | 1018 | void ext2_xattr_destroy_cache(struct mb_cache *cache) |
1028 | exit_ext2_xattr(void) | ||
1029 | { | 1019 | { |
1030 | mb_cache_destroy(ext2_xattr_cache); | 1020 | if (cache) |
1021 | mb_cache_destroy(cache); | ||
1031 | } | 1022 | } |
diff --git a/fs/ext2/xattr.h b/fs/ext2/xattr.h index 60edf298644e..6f82ab1b00ca 100644 --- a/fs/ext2/xattr.h +++ b/fs/ext2/xattr.h | |||
@@ -53,6 +53,8 @@ struct ext2_xattr_entry { | |||
53 | #define EXT2_XATTR_SIZE(size) \ | 53 | #define EXT2_XATTR_SIZE(size) \ |
54 | (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND) | 54 | (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND) |
55 | 55 | ||
56 | struct mb_cache; | ||
57 | |||
56 | # ifdef CONFIG_EXT2_FS_XATTR | 58 | # ifdef CONFIG_EXT2_FS_XATTR |
57 | 59 | ||
58 | extern const struct xattr_handler ext2_xattr_user_handler; | 60 | extern const struct xattr_handler ext2_xattr_user_handler; |
@@ -65,10 +67,9 @@ extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t); | |||
65 | extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int); | 67 | extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int); |
66 | 68 | ||
67 | extern void ext2_xattr_delete_inode(struct inode *); | 69 | extern void ext2_xattr_delete_inode(struct inode *); |
68 | extern void ext2_xattr_put_super(struct super_block *); | ||
69 | 70 | ||
70 | extern int init_ext2_xattr(void); | 71 | extern struct mb_cache *ext2_xattr_create_cache(void); |
71 | extern void exit_ext2_xattr(void); | 72 | extern void ext2_xattr_destroy_cache(struct mb_cache *cache); |
72 | 73 | ||
73 | extern const struct xattr_handler *ext2_xattr_handlers[]; | 74 | extern const struct xattr_handler *ext2_xattr_handlers[]; |
74 | 75 | ||
@@ -93,19 +94,7 @@ ext2_xattr_delete_inode(struct inode *inode) | |||
93 | { | 94 | { |
94 | } | 95 | } |
95 | 96 | ||
96 | static inline void | 97 | static inline void ext2_xattr_destroy_cache(struct mb_cache *cache) |
97 | ext2_xattr_put_super(struct super_block *sb) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | static inline int | ||
102 | init_ext2_xattr(void) | ||
103 | { | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static inline void | ||
108 | exit_ext2_xattr(void) | ||
109 | { | 98 | { |
110 | } | 99 | } |
111 | 100 | ||