diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/xattr.c | 92 |
1 files changed, 77 insertions, 15 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index e88748e55c0f..e56c9ed7d6e3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -122,6 +122,58 @@ const struct xattr_handler *ext4_xattr_handlers[] = { | |||
122 | NULL | 122 | NULL |
123 | }; | 123 | }; |
124 | 124 | ||
125 | static __le32 ext4_xattr_block_csum(struct inode *inode, | ||
126 | sector_t block_nr, | ||
127 | struct ext4_xattr_header *hdr) | ||
128 | { | ||
129 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
130 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
131 | __u32 csum, old; | ||
132 | |||
133 | old = hdr->h_checksum; | ||
134 | hdr->h_checksum = 0; | ||
135 | if (le32_to_cpu(hdr->h_refcount) != 1) { | ||
136 | block_nr = cpu_to_le64(block_nr); | ||
137 | csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&block_nr, | ||
138 | sizeof(block_nr)); | ||
139 | } else | ||
140 | csum = ei->i_csum_seed; | ||
141 | csum = ext4_chksum(sbi, csum, (__u8 *)hdr, | ||
142 | EXT4_BLOCK_SIZE(inode->i_sb)); | ||
143 | hdr->h_checksum = old; | ||
144 | return cpu_to_le32(csum); | ||
145 | } | ||
146 | |||
147 | static int ext4_xattr_block_csum_verify(struct inode *inode, | ||
148 | sector_t block_nr, | ||
149 | struct ext4_xattr_header *hdr) | ||
150 | { | ||
151 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
152 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && | ||
153 | (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr))) | ||
154 | return 0; | ||
155 | return 1; | ||
156 | } | ||
157 | |||
158 | static void ext4_xattr_block_csum_set(struct inode *inode, | ||
159 | sector_t block_nr, | ||
160 | struct ext4_xattr_header *hdr) | ||
161 | { | ||
162 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
163 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
164 | return; | ||
165 | |||
166 | hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr); | ||
167 | } | ||
168 | |||
169 | static inline int ext4_handle_dirty_xattr_block(handle_t *handle, | ||
170 | struct inode *inode, | ||
171 | struct buffer_head *bh) | ||
172 | { | ||
173 | ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh)); | ||
174 | return ext4_handle_dirty_metadata(handle, inode, bh); | ||
175 | } | ||
176 | |||
125 | static inline const struct xattr_handler * | 177 | static inline const struct xattr_handler * |
126 | ext4_xattr_handler(int name_index) | 178 | ext4_xattr_handler(int name_index) |
127 | { | 179 | { |
@@ -156,12 +208,22 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end) | |||
156 | } | 208 | } |
157 | 209 | ||
158 | static inline int | 210 | static inline int |
159 | ext4_xattr_check_block(struct buffer_head *bh) | 211 | ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) |
160 | { | 212 | { |
213 | int error; | ||
214 | |||
215 | if (buffer_verified(bh)) | ||
216 | return 0; | ||
217 | |||
161 | if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || | 218 | if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || |
162 | BHDR(bh)->h_blocks != cpu_to_le32(1)) | 219 | BHDR(bh)->h_blocks != cpu_to_le32(1)) |
163 | return -EIO; | 220 | return -EIO; |
164 | return ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); | 221 | if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) |
222 | return -EIO; | ||
223 | error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); | ||
224 | if (!error) | ||
225 | set_buffer_verified(bh); | ||
226 | return error; | ||
165 | } | 227 | } |
166 | 228 | ||
167 | static inline int | 229 | static inline int |
@@ -224,7 +286,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, | |||
224 | goto cleanup; | 286 | goto cleanup; |
225 | ea_bdebug(bh, "b_count=%d, refcount=%d", | 287 | ea_bdebug(bh, "b_count=%d, refcount=%d", |
226 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); | 288 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); |
227 | if (ext4_xattr_check_block(bh)) { | 289 | if (ext4_xattr_check_block(inode, bh)) { |
228 | bad_block: | 290 | bad_block: |
229 | EXT4_ERROR_INODE(inode, "bad block %llu", | 291 | EXT4_ERROR_INODE(inode, "bad block %llu", |
230 | EXT4_I(inode)->i_file_acl); | 292 | EXT4_I(inode)->i_file_acl); |
@@ -369,7 +431,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) | |||
369 | goto cleanup; | 431 | goto cleanup; |
370 | ea_bdebug(bh, "b_count=%d, refcount=%d", | 432 | ea_bdebug(bh, "b_count=%d, refcount=%d", |
371 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); | 433 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); |
372 | if (ext4_xattr_check_block(bh)) { | 434 | if (ext4_xattr_check_block(inode, bh)) { |
373 | EXT4_ERROR_INODE(inode, "bad block %llu", | 435 | EXT4_ERROR_INODE(inode, "bad block %llu", |
374 | EXT4_I(inode)->i_file_acl); | 436 | EXT4_I(inode)->i_file_acl); |
375 | error = -EIO; | 437 | error = -EIO; |
@@ -492,7 +554,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, | |||
492 | if (ce) | 554 | if (ce) |
493 | mb_cache_entry_release(ce); | 555 | mb_cache_entry_release(ce); |
494 | unlock_buffer(bh); | 556 | unlock_buffer(bh); |
495 | error = ext4_handle_dirty_metadata(handle, inode, bh); | 557 | error = ext4_handle_dirty_xattr_block(handle, inode, bh); |
496 | if (IS_SYNC(inode)) | 558 | if (IS_SYNC(inode)) |
497 | ext4_handle_sync(handle); | 559 | ext4_handle_sync(handle); |
498 | dquot_free_block(inode, 1); | 560 | dquot_free_block(inode, 1); |
@@ -662,7 +724,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, | |||
662 | ea_bdebug(bs->bh, "b_count=%d, refcount=%d", | 724 | ea_bdebug(bs->bh, "b_count=%d, refcount=%d", |
663 | atomic_read(&(bs->bh->b_count)), | 725 | atomic_read(&(bs->bh->b_count)), |
664 | le32_to_cpu(BHDR(bs->bh)->h_refcount)); | 726 | le32_to_cpu(BHDR(bs->bh)->h_refcount)); |
665 | if (ext4_xattr_check_block(bs->bh)) { | 727 | if (ext4_xattr_check_block(inode, bs->bh)) { |
666 | EXT4_ERROR_INODE(inode, "bad block %llu", | 728 | EXT4_ERROR_INODE(inode, "bad block %llu", |
667 | EXT4_I(inode)->i_file_acl); | 729 | EXT4_I(inode)->i_file_acl); |
668 | error = -EIO; | 730 | error = -EIO; |
@@ -725,9 +787,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
725 | if (error == -EIO) | 787 | if (error == -EIO) |
726 | goto bad_block; | 788 | goto bad_block; |
727 | if (!error) | 789 | if (!error) |
728 | error = ext4_handle_dirty_metadata(handle, | 790 | error = ext4_handle_dirty_xattr_block(handle, |
729 | inode, | 791 | inode, |
730 | bs->bh); | 792 | bs->bh); |
731 | if (error) | 793 | if (error) |
732 | goto cleanup; | 794 | goto cleanup; |
733 | goto inserted; | 795 | goto inserted; |
@@ -796,9 +858,9 @@ inserted: | |||
796 | ea_bdebug(new_bh, "reusing; refcount now=%d", | 858 | ea_bdebug(new_bh, "reusing; refcount now=%d", |
797 | le32_to_cpu(BHDR(new_bh)->h_refcount)); | 859 | le32_to_cpu(BHDR(new_bh)->h_refcount)); |
798 | unlock_buffer(new_bh); | 860 | unlock_buffer(new_bh); |
799 | error = ext4_handle_dirty_metadata(handle, | 861 | error = ext4_handle_dirty_xattr_block(handle, |
800 | inode, | 862 | inode, |
801 | new_bh); | 863 | new_bh); |
802 | if (error) | 864 | if (error) |
803 | goto cleanup_dquot; | 865 | goto cleanup_dquot; |
804 | } | 866 | } |
@@ -855,8 +917,8 @@ getblk_failed: | |||
855 | set_buffer_uptodate(new_bh); | 917 | set_buffer_uptodate(new_bh); |
856 | unlock_buffer(new_bh); | 918 | unlock_buffer(new_bh); |
857 | ext4_xattr_cache_insert(new_bh); | 919 | ext4_xattr_cache_insert(new_bh); |
858 | error = ext4_handle_dirty_metadata(handle, | 920 | error = ext4_handle_dirty_xattr_block(handle, |
859 | inode, new_bh); | 921 | inode, new_bh); |
860 | if (error) | 922 | if (error) |
861 | goto cleanup; | 923 | goto cleanup; |
862 | } | 924 | } |
@@ -1193,7 +1255,7 @@ retry: | |||
1193 | error = -EIO; | 1255 | error = -EIO; |
1194 | if (!bh) | 1256 | if (!bh) |
1195 | goto cleanup; | 1257 | goto cleanup; |
1196 | if (ext4_xattr_check_block(bh)) { | 1258 | if (ext4_xattr_check_block(inode, bh)) { |
1197 | EXT4_ERROR_INODE(inode, "bad block %llu", | 1259 | EXT4_ERROR_INODE(inode, "bad block %llu", |
1198 | EXT4_I(inode)->i_file_acl); | 1260 | EXT4_I(inode)->i_file_acl); |
1199 | error = -EIO; | 1261 | error = -EIO; |