diff options
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 450 |
1 files changed, 420 insertions, 30 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 349d7b3671c..5845cd97bf8 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -145,6 +145,14 @@ struct dx_map_entry | |||
145 | u16 size; | 145 | u16 size; |
146 | }; | 146 | }; |
147 | 147 | ||
148 | /* | ||
149 | * This goes at the end of each htree block. | ||
150 | */ | ||
151 | struct dx_tail { | ||
152 | u32 dt_reserved; | ||
153 | __le32 dt_checksum; /* crc32c(uuid+inum+dirblock) */ | ||
154 | }; | ||
155 | |||
148 | static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); | 156 | static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); |
149 | static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); | 157 | static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); |
150 | static inline unsigned dx_get_hash(struct dx_entry *entry); | 158 | static inline unsigned dx_get_hash(struct dx_entry *entry); |
@@ -180,6 +188,230 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, | |||
180 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | 188 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, |
181 | struct inode *inode); | 189 | struct inode *inode); |
182 | 190 | ||
191 | /* checksumming functions */ | ||
192 | #define EXT4_DIRENT_TAIL(block, blocksize) \ | ||
193 | ((struct ext4_dir_entry_tail *)(((void *)(block)) + \ | ||
194 | ((blocksize) - \ | ||
195 | sizeof(struct ext4_dir_entry_tail)))) | ||
196 | |||
197 | static void initialize_dirent_tail(struct ext4_dir_entry_tail *t, | ||
198 | unsigned int blocksize) | ||
199 | { | ||
200 | memset(t, 0, sizeof(struct ext4_dir_entry_tail)); | ||
201 | t->det_rec_len = ext4_rec_len_to_disk( | ||
202 | sizeof(struct ext4_dir_entry_tail), blocksize); | ||
203 | t->det_reserved_ft = EXT4_FT_DIR_CSUM; | ||
204 | } | ||
205 | |||
206 | /* Walk through a dirent block to find a checksum "dirent" at the tail */ | ||
207 | static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode, | ||
208 | struct ext4_dir_entry *de) | ||
209 | { | ||
210 | struct ext4_dir_entry_tail *t; | ||
211 | |||
212 | #ifdef PARANOID | ||
213 | struct ext4_dir_entry *d, *top; | ||
214 | |||
215 | d = de; | ||
216 | top = (struct ext4_dir_entry *)(((void *)de) + | ||
217 | (EXT4_BLOCK_SIZE(inode->i_sb) - | ||
218 | sizeof(struct ext4_dir_entry_tail))); | ||
219 | while (d < top && d->rec_len) | ||
220 | d = (struct ext4_dir_entry *)(((void *)d) + | ||
221 | le16_to_cpu(d->rec_len)); | ||
222 | |||
223 | if (d != top) | ||
224 | return NULL; | ||
225 | |||
226 | t = (struct ext4_dir_entry_tail *)d; | ||
227 | #else | ||
228 | t = EXT4_DIRENT_TAIL(de, EXT4_BLOCK_SIZE(inode->i_sb)); | ||
229 | #endif | ||
230 | |||
231 | if (t->det_reserved_zero1 || | ||
232 | le16_to_cpu(t->det_rec_len) != sizeof(struct ext4_dir_entry_tail) || | ||
233 | t->det_reserved_zero2 || | ||
234 | t->det_reserved_ft != EXT4_FT_DIR_CSUM) | ||
235 | return NULL; | ||
236 | |||
237 | return t; | ||
238 | } | ||
239 | |||
240 | static __le32 ext4_dirent_csum(struct inode *inode, | ||
241 | struct ext4_dir_entry *dirent, int size) | ||
242 | { | ||
243 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
244 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
245 | __u32 csum; | ||
246 | |||
247 | csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); | ||
248 | return cpu_to_le32(csum); | ||
249 | } | ||
250 | |||
251 | int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) | ||
252 | { | ||
253 | struct ext4_dir_entry_tail *t; | ||
254 | |||
255 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
256 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
257 | return 1; | ||
258 | |||
259 | t = get_dirent_tail(inode, dirent); | ||
260 | if (!t) { | ||
261 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir " | ||
262 | "leaf for checksum. Please run e2fsck -D."); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | if (t->det_checksum != ext4_dirent_csum(inode, dirent, | ||
267 | (void *)t - (void *)dirent)) | ||
268 | return 0; | ||
269 | |||
270 | return 1; | ||
271 | } | ||
272 | |||
273 | static void ext4_dirent_csum_set(struct inode *inode, | ||
274 | struct ext4_dir_entry *dirent) | ||
275 | { | ||
276 | struct ext4_dir_entry_tail *t; | ||
277 | |||
278 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
279 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
280 | return; | ||
281 | |||
282 | t = get_dirent_tail(inode, dirent); | ||
283 | if (!t) { | ||
284 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir " | ||
285 | "leaf for checksum. Please run e2fsck -D."); | ||
286 | return; | ||
287 | } | ||
288 | |||
289 | t->det_checksum = ext4_dirent_csum(inode, dirent, | ||
290 | (void *)t - (void *)dirent); | ||
291 | } | ||
292 | |||
293 | static inline int ext4_handle_dirty_dirent_node(handle_t *handle, | ||
294 | struct inode *inode, | ||
295 | struct buffer_head *bh) | ||
296 | { | ||
297 | ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); | ||
298 | return ext4_handle_dirty_metadata(handle, inode, bh); | ||
299 | } | ||
300 | |||
301 | static struct dx_countlimit *get_dx_countlimit(struct inode *inode, | ||
302 | struct ext4_dir_entry *dirent, | ||
303 | int *offset) | ||
304 | { | ||
305 | struct ext4_dir_entry *dp; | ||
306 | struct dx_root_info *root; | ||
307 | int count_offset; | ||
308 | |||
309 | if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) | ||
310 | count_offset = 8; | ||
311 | else if (le16_to_cpu(dirent->rec_len) == 12) { | ||
312 | dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); | ||
313 | if (le16_to_cpu(dp->rec_len) != | ||
314 | EXT4_BLOCK_SIZE(inode->i_sb) - 12) | ||
315 | return NULL; | ||
316 | root = (struct dx_root_info *)(((void *)dp + 12)); | ||
317 | if (root->reserved_zero || | ||
318 | root->info_length != sizeof(struct dx_root_info)) | ||
319 | return NULL; | ||
320 | count_offset = 32; | ||
321 | } else | ||
322 | return NULL; | ||
323 | |||
324 | if (offset) | ||
325 | *offset = count_offset; | ||
326 | return (struct dx_countlimit *)(((void *)dirent) + count_offset); | ||
327 | } | ||
328 | |||
329 | static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent, | ||
330 | int count_offset, int count, struct dx_tail *t) | ||
331 | { | ||
332 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
333 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
334 | __u32 csum, old_csum; | ||
335 | int size; | ||
336 | |||
337 | size = count_offset + (count * sizeof(struct dx_entry)); | ||
338 | old_csum = t->dt_checksum; | ||
339 | t->dt_checksum = 0; | ||
340 | csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); | ||
341 | csum = ext4_chksum(sbi, csum, (__u8 *)t, sizeof(struct dx_tail)); | ||
342 | t->dt_checksum = old_csum; | ||
343 | |||
344 | return cpu_to_le32(csum); | ||
345 | } | ||
346 | |||
347 | static int ext4_dx_csum_verify(struct inode *inode, | ||
348 | struct ext4_dir_entry *dirent) | ||
349 | { | ||
350 | struct dx_countlimit *c; | ||
351 | struct dx_tail *t; | ||
352 | int count_offset, limit, count; | ||
353 | |||
354 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
355 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
356 | return 1; | ||
357 | |||
358 | c = get_dx_countlimit(inode, dirent, &count_offset); | ||
359 | if (!c) { | ||
360 | EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); | ||
361 | return 1; | ||
362 | } | ||
363 | limit = le16_to_cpu(c->limit); | ||
364 | count = le16_to_cpu(c->count); | ||
365 | if (count_offset + (limit * sizeof(struct dx_entry)) > | ||
366 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { | ||
367 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space for " | ||
368 | "tree checksum found. Run e2fsck -D."); | ||
369 | return 1; | ||
370 | } | ||
371 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); | ||
372 | |||
373 | if (t->dt_checksum != ext4_dx_csum(inode, dirent, count_offset, | ||
374 | count, t)) | ||
375 | return 0; | ||
376 | return 1; | ||
377 | } | ||
378 | |||
379 | static void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent) | ||
380 | { | ||
381 | struct dx_countlimit *c; | ||
382 | struct dx_tail *t; | ||
383 | int count_offset, limit, count; | ||
384 | |||
385 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
386 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
387 | return; | ||
388 | |||
389 | c = get_dx_countlimit(inode, dirent, &count_offset); | ||
390 | if (!c) { | ||
391 | EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); | ||
392 | return; | ||
393 | } | ||
394 | limit = le16_to_cpu(c->limit); | ||
395 | count = le16_to_cpu(c->count); | ||
396 | if (count_offset + (limit * sizeof(struct dx_entry)) > | ||
397 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { | ||
398 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space for " | ||
399 | "tree checksum. Run e2fsck -D."); | ||
400 | return; | ||
401 | } | ||
402 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); | ||
403 | |||
404 | t->dt_checksum = ext4_dx_csum(inode, dirent, count_offset, count, t); | ||
405 | } | ||
406 | |||
407 | static inline int ext4_handle_dirty_dx_node(handle_t *handle, | ||
408 | struct inode *inode, | ||
409 | struct buffer_head *bh) | ||
410 | { | ||
411 | ext4_dx_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); | ||
412 | return ext4_handle_dirty_metadata(handle, inode, bh); | ||
413 | } | ||
414 | |||
183 | /* | 415 | /* |
184 | * p is at least 6 bytes before the end of page | 416 | * p is at least 6 bytes before the end of page |
185 | */ | 417 | */ |
@@ -239,12 +471,20 @@ static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) | |||
239 | { | 471 | { |
240 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - | 472 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - |
241 | EXT4_DIR_REC_LEN(2) - infosize; | 473 | EXT4_DIR_REC_LEN(2) - infosize; |
474 | |||
475 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
476 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
477 | entry_space -= sizeof(struct dx_tail); | ||
242 | return entry_space / sizeof(struct dx_entry); | 478 | return entry_space / sizeof(struct dx_entry); |
243 | } | 479 | } |
244 | 480 | ||
245 | static inline unsigned dx_node_limit(struct inode *dir) | 481 | static inline unsigned dx_node_limit(struct inode *dir) |
246 | { | 482 | { |
247 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); | 483 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); |
484 | |||
485 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
486 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
487 | entry_space -= sizeof(struct dx_tail); | ||
248 | return entry_space / sizeof(struct dx_entry); | 488 | return entry_space / sizeof(struct dx_entry); |
249 | } | 489 | } |
250 | 490 | ||
@@ -390,6 +630,15 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
390 | goto fail; | 630 | goto fail; |
391 | } | 631 | } |
392 | 632 | ||
633 | if (!buffer_verified(bh) && | ||
634 | !ext4_dx_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) { | ||
635 | ext4_warning(dir->i_sb, "Root failed checksum"); | ||
636 | brelse(bh); | ||
637 | *err = ERR_BAD_DX_DIR; | ||
638 | goto fail; | ||
639 | } | ||
640 | set_buffer_verified(bh); | ||
641 | |||
393 | entries = (struct dx_entry *) (((char *)&root->info) + | 642 | entries = (struct dx_entry *) (((char *)&root->info) + |
394 | root->info.info_length); | 643 | root->info.info_length); |
395 | 644 | ||
@@ -450,6 +699,17 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
450 | if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) | 699 | if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) |
451 | goto fail2; | 700 | goto fail2; |
452 | at = entries = ((struct dx_node *) bh->b_data)->entries; | 701 | at = entries = ((struct dx_node *) bh->b_data)->entries; |
702 | |||
703 | if (!buffer_verified(bh) && | ||
704 | !ext4_dx_csum_verify(dir, | ||
705 | (struct ext4_dir_entry *)bh->b_data)) { | ||
706 | ext4_warning(dir->i_sb, "Node failed checksum"); | ||
707 | brelse(bh); | ||
708 | *err = ERR_BAD_DX_DIR; | ||
709 | goto fail; | ||
710 | } | ||
711 | set_buffer_verified(bh); | ||
712 | |||
453 | if (dx_get_limit(entries) != dx_node_limit (dir)) { | 713 | if (dx_get_limit(entries) != dx_node_limit (dir)) { |
454 | ext4_warning(dir->i_sb, | 714 | ext4_warning(dir->i_sb, |
455 | "dx entry: limit != node limit"); | 715 | "dx entry: limit != node limit"); |
@@ -549,6 +809,15 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash, | |||
549 | if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at), | 809 | if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at), |
550 | 0, &err))) | 810 | 0, &err))) |
551 | return err; /* Failure */ | 811 | return err; /* Failure */ |
812 | |||
813 | if (!buffer_verified(bh) && | ||
814 | !ext4_dx_csum_verify(dir, | ||
815 | (struct ext4_dir_entry *)bh->b_data)) { | ||
816 | ext4_warning(dir->i_sb, "Node failed checksum"); | ||
817 | return -EIO; | ||
818 | } | ||
819 | set_buffer_verified(bh); | ||
820 | |||
552 | p++; | 821 | p++; |
553 | brelse(p->bh); | 822 | brelse(p->bh); |
554 | p->bh = bh; | 823 | p->bh = bh; |
@@ -577,6 +846,11 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
577 | if (!(bh = ext4_bread (NULL, dir, block, 0, &err))) | 846 | if (!(bh = ext4_bread (NULL, dir, block, 0, &err))) |
578 | return err; | 847 | return err; |
579 | 848 | ||
849 | if (!buffer_verified(bh) && | ||
850 | !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) | ||
851 | return -EIO; | ||
852 | set_buffer_verified(bh); | ||
853 | |||
580 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 854 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
581 | top = (struct ext4_dir_entry_2 *) ((char *) de + | 855 | top = (struct ext4_dir_entry_2 *) ((char *) de + |
582 | dir->i_sb->s_blocksize - | 856 | dir->i_sb->s_blocksize - |
@@ -936,6 +1210,15 @@ restart: | |||
936 | brelse(bh); | 1210 | brelse(bh); |
937 | goto next; | 1211 | goto next; |
938 | } | 1212 | } |
1213 | if (!buffer_verified(bh) && | ||
1214 | !ext4_dirent_csum_verify(dir, | ||
1215 | (struct ext4_dir_entry *)bh->b_data)) { | ||
1216 | EXT4_ERROR_INODE(dir, "checksumming directory " | ||
1217 | "block %lu", (unsigned long)block); | ||
1218 | brelse(bh); | ||
1219 | goto next; | ||
1220 | } | ||
1221 | set_buffer_verified(bh); | ||
939 | i = search_dirblock(bh, dir, d_name, | 1222 | i = search_dirblock(bh, dir, d_name, |
940 | block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); | 1223 | block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); |
941 | if (i == 1) { | 1224 | if (i == 1) { |
@@ -987,6 +1270,16 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q | |||
987 | if (!(bh = ext4_bread(NULL, dir, block, 0, err))) | 1270 | if (!(bh = ext4_bread(NULL, dir, block, 0, err))) |
988 | goto errout; | 1271 | goto errout; |
989 | 1272 | ||
1273 | if (!buffer_verified(bh) && | ||
1274 | !ext4_dirent_csum_verify(dir, | ||
1275 | (struct ext4_dir_entry *)bh->b_data)) { | ||
1276 | EXT4_ERROR_INODE(dir, "checksumming directory " | ||
1277 | "block %lu", (unsigned long)block); | ||
1278 | brelse(bh); | ||
1279 | *err = -EIO; | ||
1280 | goto errout; | ||
1281 | } | ||
1282 | set_buffer_verified(bh); | ||
990 | retval = search_dirblock(bh, dir, d_name, | 1283 | retval = search_dirblock(bh, dir, d_name, |
991 | block << EXT4_BLOCK_SIZE_BITS(sb), | 1284 | block << EXT4_BLOCK_SIZE_BITS(sb), |
992 | res_dir); | 1285 | res_dir); |
@@ -1037,6 +1330,12 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru | |||
1037 | EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); | 1330 | EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); |
1038 | return ERR_PTR(-EIO); | 1331 | return ERR_PTR(-EIO); |
1039 | } | 1332 | } |
1333 | if (unlikely(ino == dir->i_ino)) { | ||
1334 | EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir", | ||
1335 | dentry->d_name.len, | ||
1336 | dentry->d_name.name); | ||
1337 | return ERR_PTR(-EIO); | ||
1338 | } | ||
1040 | inode = ext4_iget(dir->i_sb, ino); | 1339 | inode = ext4_iget(dir->i_sb, ino); |
1041 | if (inode == ERR_PTR(-ESTALE)) { | 1340 | if (inode == ERR_PTR(-ESTALE)) { |
1042 | EXT4_ERROR_INODE(dir, | 1341 | EXT4_ERROR_INODE(dir, |
@@ -1052,10 +1351,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru | |||
1052 | struct dentry *ext4_get_parent(struct dentry *child) | 1351 | struct dentry *ext4_get_parent(struct dentry *child) |
1053 | { | 1352 | { |
1054 | __u32 ino; | 1353 | __u32 ino; |
1055 | static const struct qstr dotdot = { | 1354 | static const struct qstr dotdot = QSTR_INIT("..", 2); |
1056 | .name = "..", | ||
1057 | .len = 2, | ||
1058 | }; | ||
1059 | struct ext4_dir_entry_2 * de; | 1355 | struct ext4_dir_entry_2 * de; |
1060 | struct buffer_head *bh; | 1356 | struct buffer_head *bh; |
1061 | 1357 | ||
@@ -1159,8 +1455,14 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1159 | char *data1 = (*bh)->b_data, *data2; | 1455 | char *data1 = (*bh)->b_data, *data2; |
1160 | unsigned split, move, size; | 1456 | unsigned split, move, size; |
1161 | struct ext4_dir_entry_2 *de = NULL, *de2; | 1457 | struct ext4_dir_entry_2 *de = NULL, *de2; |
1458 | struct ext4_dir_entry_tail *t; | ||
1459 | int csum_size = 0; | ||
1162 | int err = 0, i; | 1460 | int err = 0, i; |
1163 | 1461 | ||
1462 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
1463 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1464 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1465 | |||
1164 | bh2 = ext4_append (handle, dir, &newblock, &err); | 1466 | bh2 = ext4_append (handle, dir, &newblock, &err); |
1165 | if (!(bh2)) { | 1467 | if (!(bh2)) { |
1166 | brelse(*bh); | 1468 | brelse(*bh); |
@@ -1207,10 +1509,20 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1207 | /* Fancy dance to stay within two buffers */ | 1509 | /* Fancy dance to stay within two buffers */ |
1208 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); | 1510 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); |
1209 | de = dx_pack_dirents(data1, blocksize); | 1511 | de = dx_pack_dirents(data1, blocksize); |
1210 | de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de, | 1512 | de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - |
1513 | (char *) de, | ||
1211 | blocksize); | 1514 | blocksize); |
1212 | de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2, | 1515 | de2->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) - |
1516 | (char *) de2, | ||
1213 | blocksize); | 1517 | blocksize); |
1518 | if (csum_size) { | ||
1519 | t = EXT4_DIRENT_TAIL(data2, blocksize); | ||
1520 | initialize_dirent_tail(t, blocksize); | ||
1521 | |||
1522 | t = EXT4_DIRENT_TAIL(data1, blocksize); | ||
1523 | initialize_dirent_tail(t, blocksize); | ||
1524 | } | ||
1525 | |||
1214 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); | 1526 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); |
1215 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); | 1527 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); |
1216 | 1528 | ||
@@ -1221,10 +1533,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1221 | de = de2; | 1533 | de = de2; |
1222 | } | 1534 | } |
1223 | dx_insert_block(frame, hash2 + continued, newblock); | 1535 | dx_insert_block(frame, hash2 + continued, newblock); |
1224 | err = ext4_handle_dirty_metadata(handle, dir, bh2); | 1536 | err = ext4_handle_dirty_dirent_node(handle, dir, bh2); |
1225 | if (err) | 1537 | if (err) |
1226 | goto journal_error; | 1538 | goto journal_error; |
1227 | err = ext4_handle_dirty_metadata(handle, dir, frame->bh); | 1539 | err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1228 | if (err) | 1540 | if (err) |
1229 | goto journal_error; | 1541 | goto journal_error; |
1230 | brelse(bh2); | 1542 | brelse(bh2); |
@@ -1261,11 +1573,16 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1261 | unsigned short reclen; | 1573 | unsigned short reclen; |
1262 | int nlen, rlen, err; | 1574 | int nlen, rlen, err; |
1263 | char *top; | 1575 | char *top; |
1576 | int csum_size = 0; | ||
1577 | |||
1578 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
1579 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1580 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1264 | 1581 | ||
1265 | reclen = EXT4_DIR_REC_LEN(namelen); | 1582 | reclen = EXT4_DIR_REC_LEN(namelen); |
1266 | if (!de) { | 1583 | if (!de) { |
1267 | de = (struct ext4_dir_entry_2 *)bh->b_data; | 1584 | de = (struct ext4_dir_entry_2 *)bh->b_data; |
1268 | top = bh->b_data + blocksize - reclen; | 1585 | top = bh->b_data + (blocksize - csum_size) - reclen; |
1269 | while ((char *) de <= top) { | 1586 | while ((char *) de <= top) { |
1270 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1587 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) |
1271 | return -EIO; | 1588 | return -EIO; |
@@ -1298,11 +1615,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1298 | de = de1; | 1615 | de = de1; |
1299 | } | 1616 | } |
1300 | de->file_type = EXT4_FT_UNKNOWN; | 1617 | de->file_type = EXT4_FT_UNKNOWN; |
1301 | if (inode) { | 1618 | de->inode = cpu_to_le32(inode->i_ino); |
1302 | de->inode = cpu_to_le32(inode->i_ino); | 1619 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); |
1303 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); | ||
1304 | } else | ||
1305 | de->inode = 0; | ||
1306 | de->name_len = namelen; | 1620 | de->name_len = namelen; |
1307 | memcpy(de->name, name, namelen); | 1621 | memcpy(de->name, name, namelen); |
1308 | /* | 1622 | /* |
@@ -1321,7 +1635,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1321 | dir->i_version++; | 1635 | dir->i_version++; |
1322 | ext4_mark_inode_dirty(handle, dir); | 1636 | ext4_mark_inode_dirty(handle, dir); |
1323 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 1637 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1324 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 1638 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
1325 | if (err) | 1639 | if (err) |
1326 | ext4_std_error(dir->i_sb, err); | 1640 | ext4_std_error(dir->i_sb, err); |
1327 | return 0; | 1641 | return 0; |
@@ -1342,6 +1656,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1342 | struct dx_frame frames[2], *frame; | 1656 | struct dx_frame frames[2], *frame; |
1343 | struct dx_entry *entries; | 1657 | struct dx_entry *entries; |
1344 | struct ext4_dir_entry_2 *de, *de2; | 1658 | struct ext4_dir_entry_2 *de, *de2; |
1659 | struct ext4_dir_entry_tail *t; | ||
1345 | char *data1, *top; | 1660 | char *data1, *top; |
1346 | unsigned len; | 1661 | unsigned len; |
1347 | int retval; | 1662 | int retval; |
@@ -1349,6 +1664,11 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1349 | struct dx_hash_info hinfo; | 1664 | struct dx_hash_info hinfo; |
1350 | ext4_lblk_t block; | 1665 | ext4_lblk_t block; |
1351 | struct fake_dirent *fde; | 1666 | struct fake_dirent *fde; |
1667 | int csum_size = 0; | ||
1668 | |||
1669 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
1670 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1671 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1352 | 1672 | ||
1353 | blocksize = dir->i_sb->s_blocksize; | 1673 | blocksize = dir->i_sb->s_blocksize; |
1354 | dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); | 1674 | dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); |
@@ -1369,7 +1689,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1369 | brelse(bh); | 1689 | brelse(bh); |
1370 | return -EIO; | 1690 | return -EIO; |
1371 | } | 1691 | } |
1372 | len = ((char *) root) + blocksize - (char *) de; | 1692 | len = ((char *) root) + (blocksize - csum_size) - (char *) de; |
1373 | 1693 | ||
1374 | /* Allocate new block for the 0th block's dirents */ | 1694 | /* Allocate new block for the 0th block's dirents */ |
1375 | bh2 = ext4_append(handle, dir, &block, &retval); | 1695 | bh2 = ext4_append(handle, dir, &block, &retval); |
@@ -1385,8 +1705,15 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1385 | top = data1 + len; | 1705 | top = data1 + len; |
1386 | while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) | 1706 | while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) |
1387 | de = de2; | 1707 | de = de2; |
1388 | de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de, | 1708 | de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - |
1709 | (char *) de, | ||
1389 | blocksize); | 1710 | blocksize); |
1711 | |||
1712 | if (csum_size) { | ||
1713 | t = EXT4_DIRENT_TAIL(data1, blocksize); | ||
1714 | initialize_dirent_tail(t, blocksize); | ||
1715 | } | ||
1716 | |||
1390 | /* Initialize the root; the dot dirents already exist */ | 1717 | /* Initialize the root; the dot dirents already exist */ |
1391 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); | 1718 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); |
1392 | de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2), | 1719 | de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2), |
@@ -1411,8 +1738,8 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1411 | frame->bh = bh; | 1738 | frame->bh = bh; |
1412 | bh = bh2; | 1739 | bh = bh2; |
1413 | 1740 | ||
1414 | ext4_handle_dirty_metadata(handle, dir, frame->bh); | 1741 | ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1415 | ext4_handle_dirty_metadata(handle, dir, bh); | 1742 | ext4_handle_dirty_dirent_node(handle, dir, bh); |
1416 | 1743 | ||
1417 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); | 1744 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); |
1418 | if (!de) { | 1745 | if (!de) { |
@@ -1448,11 +1775,17 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1448 | struct inode *dir = dentry->d_parent->d_inode; | 1775 | struct inode *dir = dentry->d_parent->d_inode; |
1449 | struct buffer_head *bh; | 1776 | struct buffer_head *bh; |
1450 | struct ext4_dir_entry_2 *de; | 1777 | struct ext4_dir_entry_2 *de; |
1778 | struct ext4_dir_entry_tail *t; | ||
1451 | struct super_block *sb; | 1779 | struct super_block *sb; |
1452 | int retval; | 1780 | int retval; |
1453 | int dx_fallback=0; | 1781 | int dx_fallback=0; |
1454 | unsigned blocksize; | 1782 | unsigned blocksize; |
1455 | ext4_lblk_t block, blocks; | 1783 | ext4_lblk_t block, blocks; |
1784 | int csum_size = 0; | ||
1785 | |||
1786 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
1787 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1788 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1456 | 1789 | ||
1457 | sb = dir->i_sb; | 1790 | sb = dir->i_sb; |
1458 | blocksize = sb->s_blocksize; | 1791 | blocksize = sb->s_blocksize; |
@@ -1471,6 +1804,11 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1471 | bh = ext4_bread(handle, dir, block, 0, &retval); | 1804 | bh = ext4_bread(handle, dir, block, 0, &retval); |
1472 | if(!bh) | 1805 | if(!bh) |
1473 | return retval; | 1806 | return retval; |
1807 | if (!buffer_verified(bh) && | ||
1808 | !ext4_dirent_csum_verify(dir, | ||
1809 | (struct ext4_dir_entry *)bh->b_data)) | ||
1810 | return -EIO; | ||
1811 | set_buffer_verified(bh); | ||
1474 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | 1812 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
1475 | if (retval != -ENOSPC) { | 1813 | if (retval != -ENOSPC) { |
1476 | brelse(bh); | 1814 | brelse(bh); |
@@ -1487,7 +1825,13 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1487 | return retval; | 1825 | return retval; |
1488 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 1826 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1489 | de->inode = 0; | 1827 | de->inode = 0; |
1490 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); | 1828 | de->rec_len = ext4_rec_len_to_disk(blocksize - csum_size, blocksize); |
1829 | |||
1830 | if (csum_size) { | ||
1831 | t = EXT4_DIRENT_TAIL(bh->b_data, blocksize); | ||
1832 | initialize_dirent_tail(t, blocksize); | ||
1833 | } | ||
1834 | |||
1491 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); | 1835 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1492 | brelse(bh); | 1836 | brelse(bh); |
1493 | if (retval == 0) | 1837 | if (retval == 0) |
@@ -1519,6 +1863,11 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1519 | if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err))) | 1863 | if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err))) |
1520 | goto cleanup; | 1864 | goto cleanup; |
1521 | 1865 | ||
1866 | if (!buffer_verified(bh) && | ||
1867 | !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) | ||
1868 | goto journal_error; | ||
1869 | set_buffer_verified(bh); | ||
1870 | |||
1522 | BUFFER_TRACE(bh, "get_write_access"); | 1871 | BUFFER_TRACE(bh, "get_write_access"); |
1523 | err = ext4_journal_get_write_access(handle, bh); | 1872 | err = ext4_journal_get_write_access(handle, bh); |
1524 | if (err) | 1873 | if (err) |
@@ -1586,7 +1935,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1586 | dxtrace(dx_show_index("node", frames[1].entries)); | 1935 | dxtrace(dx_show_index("node", frames[1].entries)); |
1587 | dxtrace(dx_show_index("node", | 1936 | dxtrace(dx_show_index("node", |
1588 | ((struct dx_node *) bh2->b_data)->entries)); | 1937 | ((struct dx_node *) bh2->b_data)->entries)); |
1589 | err = ext4_handle_dirty_metadata(handle, dir, bh2); | 1938 | err = ext4_handle_dirty_dx_node(handle, dir, bh2); |
1590 | if (err) | 1939 | if (err) |
1591 | goto journal_error; | 1940 | goto journal_error; |
1592 | brelse (bh2); | 1941 | brelse (bh2); |
@@ -1612,7 +1961,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1612 | if (err) | 1961 | if (err) |
1613 | goto journal_error; | 1962 | goto journal_error; |
1614 | } | 1963 | } |
1615 | err = ext4_handle_dirty_metadata(handle, dir, frames[0].bh); | 1964 | err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); |
1616 | if (err) { | 1965 | if (err) { |
1617 | ext4_std_error(inode->i_sb, err); | 1966 | ext4_std_error(inode->i_sb, err); |
1618 | goto cleanup; | 1967 | goto cleanup; |
@@ -1644,12 +1993,17 @@ static int ext4_delete_entry(handle_t *handle, | |||
1644 | { | 1993 | { |
1645 | struct ext4_dir_entry_2 *de, *pde; | 1994 | struct ext4_dir_entry_2 *de, *pde; |
1646 | unsigned int blocksize = dir->i_sb->s_blocksize; | 1995 | unsigned int blocksize = dir->i_sb->s_blocksize; |
1996 | int csum_size = 0; | ||
1647 | int i, err; | 1997 | int i, err; |
1648 | 1998 | ||
1999 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
2000 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2001 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
2002 | |||
1649 | i = 0; | 2003 | i = 0; |
1650 | pde = NULL; | 2004 | pde = NULL; |
1651 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2005 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1652 | while (i < bh->b_size) { | 2006 | while (i < bh->b_size - csum_size) { |
1653 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) | 2007 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) |
1654 | return -EIO; | 2008 | return -EIO; |
1655 | if (de == de_del) { | 2009 | if (de == de_del) { |
@@ -1670,7 +2024,7 @@ static int ext4_delete_entry(handle_t *handle, | |||
1670 | de->inode = 0; | 2024 | de->inode = 0; |
1671 | dir->i_version++; | 2025 | dir->i_version++; |
1672 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 2026 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1673 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 2027 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
1674 | if (unlikely(err)) { | 2028 | if (unlikely(err)) { |
1675 | ext4_std_error(dir->i_sb, err); | 2029 | ext4_std_error(dir->i_sb, err); |
1676 | return err; | 2030 | return err; |
@@ -1812,9 +2166,15 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1812 | struct inode *inode; | 2166 | struct inode *inode; |
1813 | struct buffer_head *dir_block = NULL; | 2167 | struct buffer_head *dir_block = NULL; |
1814 | struct ext4_dir_entry_2 *de; | 2168 | struct ext4_dir_entry_2 *de; |
2169 | struct ext4_dir_entry_tail *t; | ||
1815 | unsigned int blocksize = dir->i_sb->s_blocksize; | 2170 | unsigned int blocksize = dir->i_sb->s_blocksize; |
2171 | int csum_size = 0; | ||
1816 | int err, retries = 0; | 2172 | int err, retries = 0; |
1817 | 2173 | ||
2174 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
2175 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2176 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
2177 | |||
1818 | if (EXT4_DIR_LINK_MAX(dir)) | 2178 | if (EXT4_DIR_LINK_MAX(dir)) |
1819 | return -EMLINK; | 2179 | return -EMLINK; |
1820 | 2180 | ||
@@ -1855,16 +2215,24 @@ retry: | |||
1855 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | 2215 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); |
1856 | de = ext4_next_entry(de, blocksize); | 2216 | de = ext4_next_entry(de, blocksize); |
1857 | de->inode = cpu_to_le32(dir->i_ino); | 2217 | de->inode = cpu_to_le32(dir->i_ino); |
1858 | de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(1), | 2218 | de->rec_len = ext4_rec_len_to_disk(blocksize - |
2219 | (csum_size + EXT4_DIR_REC_LEN(1)), | ||
1859 | blocksize); | 2220 | blocksize); |
1860 | de->name_len = 2; | 2221 | de->name_len = 2; |
1861 | strcpy(de->name, ".."); | 2222 | strcpy(de->name, ".."); |
1862 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | 2223 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); |
1863 | set_nlink(inode, 2); | 2224 | set_nlink(inode, 2); |
2225 | |||
2226 | if (csum_size) { | ||
2227 | t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize); | ||
2228 | initialize_dirent_tail(t, blocksize); | ||
2229 | } | ||
2230 | |||
1864 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); | 2231 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); |
1865 | err = ext4_handle_dirty_metadata(handle, inode, dir_block); | 2232 | err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); |
1866 | if (err) | 2233 | if (err) |
1867 | goto out_clear_inode; | 2234 | goto out_clear_inode; |
2235 | set_buffer_verified(dir_block); | ||
1868 | err = ext4_mark_inode_dirty(handle, inode); | 2236 | err = ext4_mark_inode_dirty(handle, inode); |
1869 | if (!err) | 2237 | if (!err) |
1870 | err = ext4_add_entry(handle, dentry, inode); | 2238 | err = ext4_add_entry(handle, dentry, inode); |
@@ -1914,6 +2282,14 @@ static int empty_dir(struct inode *inode) | |||
1914 | inode->i_ino); | 2282 | inode->i_ino); |
1915 | return 1; | 2283 | return 1; |
1916 | } | 2284 | } |
2285 | if (!buffer_verified(bh) && | ||
2286 | !ext4_dirent_csum_verify(inode, | ||
2287 | (struct ext4_dir_entry *)bh->b_data)) { | ||
2288 | EXT4_ERROR_INODE(inode, "checksum error reading directory " | ||
2289 | "lblock 0"); | ||
2290 | return -EIO; | ||
2291 | } | ||
2292 | set_buffer_verified(bh); | ||
1917 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2293 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1918 | de1 = ext4_next_entry(de, sb->s_blocksize); | 2294 | de1 = ext4_next_entry(de, sb->s_blocksize); |
1919 | if (le32_to_cpu(de->inode) != inode->i_ino || | 2295 | if (le32_to_cpu(de->inode) != inode->i_ino || |
@@ -1945,6 +2321,14 @@ static int empty_dir(struct inode *inode) | |||
1945 | offset += sb->s_blocksize; | 2321 | offset += sb->s_blocksize; |
1946 | continue; | 2322 | continue; |
1947 | } | 2323 | } |
2324 | if (!buffer_verified(bh) && | ||
2325 | !ext4_dirent_csum_verify(inode, | ||
2326 | (struct ext4_dir_entry *)bh->b_data)) { | ||
2327 | EXT4_ERROR_INODE(inode, "checksum error " | ||
2328 | "reading directory lblock 0"); | ||
2329 | return -EIO; | ||
2330 | } | ||
2331 | set_buffer_verified(bh); | ||
1948 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2332 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1949 | } | 2333 | } |
1950 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { | 2334 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { |
@@ -2013,7 +2397,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2013 | /* Insert this inode at the head of the on-disk orphan list... */ | 2397 | /* Insert this inode at the head of the on-disk orphan list... */ |
2014 | NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); | 2398 | NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); |
2015 | EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); | 2399 | EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); |
2016 | err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); | 2400 | err = ext4_handle_dirty_super_now(handle, sb); |
2017 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); | 2401 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); |
2018 | if (!err) | 2402 | if (!err) |
2019 | err = rc; | 2403 | err = rc; |
@@ -2086,7 +2470,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2086 | if (err) | 2470 | if (err) |
2087 | goto out_brelse; | 2471 | goto out_brelse; |
2088 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); | 2472 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); |
2089 | err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); | 2473 | err = ext4_handle_dirty_super_now(handle, inode->i_sb); |
2090 | } else { | 2474 | } else { |
2091 | struct ext4_iloc iloc2; | 2475 | struct ext4_iloc iloc2; |
2092 | struct inode *i_prev = | 2476 | struct inode *i_prev = |
@@ -2445,6 +2829,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2445 | dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); | 2829 | dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); |
2446 | if (!dir_bh) | 2830 | if (!dir_bh) |
2447 | goto end_rename; | 2831 | goto end_rename; |
2832 | if (!buffer_verified(dir_bh) && | ||
2833 | !ext4_dirent_csum_verify(old_inode, | ||
2834 | (struct ext4_dir_entry *)dir_bh->b_data)) | ||
2835 | goto end_rename; | ||
2836 | set_buffer_verified(dir_bh); | ||
2448 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, | 2837 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, |
2449 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) | 2838 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) |
2450 | goto end_rename; | 2839 | goto end_rename; |
@@ -2475,7 +2864,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2475 | ext4_current_time(new_dir); | 2864 | ext4_current_time(new_dir); |
2476 | ext4_mark_inode_dirty(handle, new_dir); | 2865 | ext4_mark_inode_dirty(handle, new_dir); |
2477 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); | 2866 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); |
2478 | retval = ext4_handle_dirty_metadata(handle, new_dir, new_bh); | 2867 | retval = ext4_handle_dirty_dirent_node(handle, new_dir, new_bh); |
2479 | if (unlikely(retval)) { | 2868 | if (unlikely(retval)) { |
2480 | ext4_std_error(new_dir->i_sb, retval); | 2869 | ext4_std_error(new_dir->i_sb, retval); |
2481 | goto end_rename; | 2870 | goto end_rename; |
@@ -2529,7 +2918,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2529 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = | 2918 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = |
2530 | cpu_to_le32(new_dir->i_ino); | 2919 | cpu_to_le32(new_dir->i_ino); |
2531 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); | 2920 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); |
2532 | retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh); | 2921 | retval = ext4_handle_dirty_dirent_node(handle, old_inode, |
2922 | dir_bh); | ||
2533 | if (retval) { | 2923 | if (retval) { |
2534 | ext4_std_error(old_dir->i_sb, retval); | 2924 | ext4_std_error(old_dir->i_sb, retval); |
2535 | goto end_rename; | 2925 | goto end_rename; |