diff options
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 445 |
1 files changed, 419 insertions, 26 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index e2a3f4b0ff78..5845cd97bf8b 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, |
@@ -1156,8 +1455,14 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1156 | char *data1 = (*bh)->b_data, *data2; | 1455 | char *data1 = (*bh)->b_data, *data2; |
1157 | unsigned split, move, size; | 1456 | unsigned split, move, size; |
1158 | 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; | ||
1159 | int err = 0, i; | 1460 | int err = 0, i; |
1160 | 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 | |||
1161 | bh2 = ext4_append (handle, dir, &newblock, &err); | 1466 | bh2 = ext4_append (handle, dir, &newblock, &err); |
1162 | if (!(bh2)) { | 1467 | if (!(bh2)) { |
1163 | brelse(*bh); | 1468 | brelse(*bh); |
@@ -1204,10 +1509,20 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1204 | /* Fancy dance to stay within two buffers */ | 1509 | /* Fancy dance to stay within two buffers */ |
1205 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); | 1510 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); |
1206 | de = dx_pack_dirents(data1, blocksize); | 1511 | de = dx_pack_dirents(data1, blocksize); |
1207 | 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, | ||
1208 | blocksize); | 1514 | blocksize); |
1209 | 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, | ||
1210 | 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 | |||
1211 | 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)); |
1212 | 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)); |
1213 | 1528 | ||
@@ -1218,10 +1533,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1218 | de = de2; | 1533 | de = de2; |
1219 | } | 1534 | } |
1220 | dx_insert_block(frame, hash2 + continued, newblock); | 1535 | dx_insert_block(frame, hash2 + continued, newblock); |
1221 | err = ext4_handle_dirty_metadata(handle, dir, bh2); | 1536 | err = ext4_handle_dirty_dirent_node(handle, dir, bh2); |
1222 | if (err) | 1537 | if (err) |
1223 | goto journal_error; | 1538 | goto journal_error; |
1224 | err = ext4_handle_dirty_metadata(handle, dir, frame->bh); | 1539 | err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1225 | if (err) | 1540 | if (err) |
1226 | goto journal_error; | 1541 | goto journal_error; |
1227 | brelse(bh2); | 1542 | brelse(bh2); |
@@ -1258,11 +1573,16 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1258 | unsigned short reclen; | 1573 | unsigned short reclen; |
1259 | int nlen, rlen, err; | 1574 | int nlen, rlen, err; |
1260 | 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); | ||
1261 | 1581 | ||
1262 | reclen = EXT4_DIR_REC_LEN(namelen); | 1582 | reclen = EXT4_DIR_REC_LEN(namelen); |
1263 | if (!de) { | 1583 | if (!de) { |
1264 | de = (struct ext4_dir_entry_2 *)bh->b_data; | 1584 | de = (struct ext4_dir_entry_2 *)bh->b_data; |
1265 | top = bh->b_data + blocksize - reclen; | 1585 | top = bh->b_data + (blocksize - csum_size) - reclen; |
1266 | while ((char *) de <= top) { | 1586 | while ((char *) de <= top) { |
1267 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1587 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) |
1268 | return -EIO; | 1588 | return -EIO; |
@@ -1295,11 +1615,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1295 | de = de1; | 1615 | de = de1; |
1296 | } | 1616 | } |
1297 | de->file_type = EXT4_FT_UNKNOWN; | 1617 | de->file_type = EXT4_FT_UNKNOWN; |
1298 | if (inode) { | 1618 | de->inode = cpu_to_le32(inode->i_ino); |
1299 | de->inode = cpu_to_le32(inode->i_ino); | 1619 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); |
1300 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); | ||
1301 | } else | ||
1302 | de->inode = 0; | ||
1303 | de->name_len = namelen; | 1620 | de->name_len = namelen; |
1304 | memcpy(de->name, name, namelen); | 1621 | memcpy(de->name, name, namelen); |
1305 | /* | 1622 | /* |
@@ -1318,7 +1635,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1318 | dir->i_version++; | 1635 | dir->i_version++; |
1319 | ext4_mark_inode_dirty(handle, dir); | 1636 | ext4_mark_inode_dirty(handle, dir); |
1320 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 1637 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1321 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 1638 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
1322 | if (err) | 1639 | if (err) |
1323 | ext4_std_error(dir->i_sb, err); | 1640 | ext4_std_error(dir->i_sb, err); |
1324 | return 0; | 1641 | return 0; |
@@ -1339,6 +1656,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1339 | struct dx_frame frames[2], *frame; | 1656 | struct dx_frame frames[2], *frame; |
1340 | struct dx_entry *entries; | 1657 | struct dx_entry *entries; |
1341 | struct ext4_dir_entry_2 *de, *de2; | 1658 | struct ext4_dir_entry_2 *de, *de2; |
1659 | struct ext4_dir_entry_tail *t; | ||
1342 | char *data1, *top; | 1660 | char *data1, *top; |
1343 | unsigned len; | 1661 | unsigned len; |
1344 | int retval; | 1662 | int retval; |
@@ -1346,6 +1664,11 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1346 | struct dx_hash_info hinfo; | 1664 | struct dx_hash_info hinfo; |
1347 | ext4_lblk_t block; | 1665 | ext4_lblk_t block; |
1348 | 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); | ||
1349 | 1672 | ||
1350 | blocksize = dir->i_sb->s_blocksize; | 1673 | blocksize = dir->i_sb->s_blocksize; |
1351 | 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)); |
@@ -1366,7 +1689,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1366 | brelse(bh); | 1689 | brelse(bh); |
1367 | return -EIO; | 1690 | return -EIO; |
1368 | } | 1691 | } |
1369 | len = ((char *) root) + blocksize - (char *) de; | 1692 | len = ((char *) root) + (blocksize - csum_size) - (char *) de; |
1370 | 1693 | ||
1371 | /* Allocate new block for the 0th block's dirents */ | 1694 | /* Allocate new block for the 0th block's dirents */ |
1372 | bh2 = ext4_append(handle, dir, &block, &retval); | 1695 | bh2 = ext4_append(handle, dir, &block, &retval); |
@@ -1382,8 +1705,15 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1382 | top = data1 + len; | 1705 | top = data1 + len; |
1383 | while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) | 1706 | while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) |
1384 | de = de2; | 1707 | de = de2; |
1385 | 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, | ||
1386 | blocksize); | 1710 | blocksize); |
1711 | |||
1712 | if (csum_size) { | ||
1713 | t = EXT4_DIRENT_TAIL(data1, blocksize); | ||
1714 | initialize_dirent_tail(t, blocksize); | ||
1715 | } | ||
1716 | |||
1387 | /* Initialize the root; the dot dirents already exist */ | 1717 | /* Initialize the root; the dot dirents already exist */ |
1388 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); | 1718 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); |
1389 | 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), |
@@ -1408,8 +1738,8 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1408 | frame->bh = bh; | 1738 | frame->bh = bh; |
1409 | bh = bh2; | 1739 | bh = bh2; |
1410 | 1740 | ||
1411 | ext4_handle_dirty_metadata(handle, dir, frame->bh); | 1741 | ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1412 | ext4_handle_dirty_metadata(handle, dir, bh); | 1742 | ext4_handle_dirty_dirent_node(handle, dir, bh); |
1413 | 1743 | ||
1414 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); | 1744 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); |
1415 | if (!de) { | 1745 | if (!de) { |
@@ -1445,11 +1775,17 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1445 | struct inode *dir = dentry->d_parent->d_inode; | 1775 | struct inode *dir = dentry->d_parent->d_inode; |
1446 | struct buffer_head *bh; | 1776 | struct buffer_head *bh; |
1447 | struct ext4_dir_entry_2 *de; | 1777 | struct ext4_dir_entry_2 *de; |
1778 | struct ext4_dir_entry_tail *t; | ||
1448 | struct super_block *sb; | 1779 | struct super_block *sb; |
1449 | int retval; | 1780 | int retval; |
1450 | int dx_fallback=0; | 1781 | int dx_fallback=0; |
1451 | unsigned blocksize; | 1782 | unsigned blocksize; |
1452 | 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); | ||
1453 | 1789 | ||
1454 | sb = dir->i_sb; | 1790 | sb = dir->i_sb; |
1455 | blocksize = sb->s_blocksize; | 1791 | blocksize = sb->s_blocksize; |
@@ -1468,6 +1804,11 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1468 | bh = ext4_bread(handle, dir, block, 0, &retval); | 1804 | bh = ext4_bread(handle, dir, block, 0, &retval); |
1469 | if(!bh) | 1805 | if(!bh) |
1470 | 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); | ||
1471 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | 1812 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
1472 | if (retval != -ENOSPC) { | 1813 | if (retval != -ENOSPC) { |
1473 | brelse(bh); | 1814 | brelse(bh); |
@@ -1484,7 +1825,13 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1484 | return retval; | 1825 | return retval; |
1485 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 1826 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1486 | de->inode = 0; | 1827 | de->inode = 0; |
1487 | 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 | |||
1488 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); | 1835 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1489 | brelse(bh); | 1836 | brelse(bh); |
1490 | if (retval == 0) | 1837 | if (retval == 0) |
@@ -1516,6 +1863,11 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1516 | 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))) |
1517 | goto cleanup; | 1864 | goto cleanup; |
1518 | 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 | |||
1519 | BUFFER_TRACE(bh, "get_write_access"); | 1871 | BUFFER_TRACE(bh, "get_write_access"); |
1520 | err = ext4_journal_get_write_access(handle, bh); | 1872 | err = ext4_journal_get_write_access(handle, bh); |
1521 | if (err) | 1873 | if (err) |
@@ -1583,7 +1935,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1583 | dxtrace(dx_show_index("node", frames[1].entries)); | 1935 | dxtrace(dx_show_index("node", frames[1].entries)); |
1584 | dxtrace(dx_show_index("node", | 1936 | dxtrace(dx_show_index("node", |
1585 | ((struct dx_node *) bh2->b_data)->entries)); | 1937 | ((struct dx_node *) bh2->b_data)->entries)); |
1586 | err = ext4_handle_dirty_metadata(handle, dir, bh2); | 1938 | err = ext4_handle_dirty_dx_node(handle, dir, bh2); |
1587 | if (err) | 1939 | if (err) |
1588 | goto journal_error; | 1940 | goto journal_error; |
1589 | brelse (bh2); | 1941 | brelse (bh2); |
@@ -1609,7 +1961,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1609 | if (err) | 1961 | if (err) |
1610 | goto journal_error; | 1962 | goto journal_error; |
1611 | } | 1963 | } |
1612 | err = ext4_handle_dirty_metadata(handle, dir, frames[0].bh); | 1964 | err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); |
1613 | if (err) { | 1965 | if (err) { |
1614 | ext4_std_error(inode->i_sb, err); | 1966 | ext4_std_error(inode->i_sb, err); |
1615 | goto cleanup; | 1967 | goto cleanup; |
@@ -1641,12 +1993,17 @@ static int ext4_delete_entry(handle_t *handle, | |||
1641 | { | 1993 | { |
1642 | struct ext4_dir_entry_2 *de, *pde; | 1994 | struct ext4_dir_entry_2 *de, *pde; |
1643 | unsigned int blocksize = dir->i_sb->s_blocksize; | 1995 | unsigned int blocksize = dir->i_sb->s_blocksize; |
1996 | int csum_size = 0; | ||
1644 | int i, err; | 1997 | int i, err; |
1645 | 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 | |||
1646 | i = 0; | 2003 | i = 0; |
1647 | pde = NULL; | 2004 | pde = NULL; |
1648 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2005 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1649 | while (i < bh->b_size) { | 2006 | while (i < bh->b_size - csum_size) { |
1650 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) | 2007 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) |
1651 | return -EIO; | 2008 | return -EIO; |
1652 | if (de == de_del) { | 2009 | if (de == de_del) { |
@@ -1667,7 +2024,7 @@ static int ext4_delete_entry(handle_t *handle, | |||
1667 | de->inode = 0; | 2024 | de->inode = 0; |
1668 | dir->i_version++; | 2025 | dir->i_version++; |
1669 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 2026 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1670 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 2027 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
1671 | if (unlikely(err)) { | 2028 | if (unlikely(err)) { |
1672 | ext4_std_error(dir->i_sb, err); | 2029 | ext4_std_error(dir->i_sb, err); |
1673 | return err; | 2030 | return err; |
@@ -1809,9 +2166,15 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1809 | struct inode *inode; | 2166 | struct inode *inode; |
1810 | struct buffer_head *dir_block = NULL; | 2167 | struct buffer_head *dir_block = NULL; |
1811 | struct ext4_dir_entry_2 *de; | 2168 | struct ext4_dir_entry_2 *de; |
2169 | struct ext4_dir_entry_tail *t; | ||
1812 | unsigned int blocksize = dir->i_sb->s_blocksize; | 2170 | unsigned int blocksize = dir->i_sb->s_blocksize; |
2171 | int csum_size = 0; | ||
1813 | int err, retries = 0; | 2172 | int err, retries = 0; |
1814 | 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 | |||
1815 | if (EXT4_DIR_LINK_MAX(dir)) | 2178 | if (EXT4_DIR_LINK_MAX(dir)) |
1816 | return -EMLINK; | 2179 | return -EMLINK; |
1817 | 2180 | ||
@@ -1852,16 +2215,24 @@ retry: | |||
1852 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | 2215 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); |
1853 | de = ext4_next_entry(de, blocksize); | 2216 | de = ext4_next_entry(de, blocksize); |
1854 | de->inode = cpu_to_le32(dir->i_ino); | 2217 | de->inode = cpu_to_le32(dir->i_ino); |
1855 | 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)), | ||
1856 | blocksize); | 2220 | blocksize); |
1857 | de->name_len = 2; | 2221 | de->name_len = 2; |
1858 | strcpy(de->name, ".."); | 2222 | strcpy(de->name, ".."); |
1859 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | 2223 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); |
1860 | 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 | |||
1861 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); | 2231 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); |
1862 | err = ext4_handle_dirty_metadata(handle, inode, dir_block); | 2232 | err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); |
1863 | if (err) | 2233 | if (err) |
1864 | goto out_clear_inode; | 2234 | goto out_clear_inode; |
2235 | set_buffer_verified(dir_block); | ||
1865 | err = ext4_mark_inode_dirty(handle, inode); | 2236 | err = ext4_mark_inode_dirty(handle, inode); |
1866 | if (!err) | 2237 | if (!err) |
1867 | err = ext4_add_entry(handle, dentry, inode); | 2238 | err = ext4_add_entry(handle, dentry, inode); |
@@ -1911,6 +2282,14 @@ static int empty_dir(struct inode *inode) | |||
1911 | inode->i_ino); | 2282 | inode->i_ino); |
1912 | return 1; | 2283 | return 1; |
1913 | } | 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); | ||
1914 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2293 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1915 | de1 = ext4_next_entry(de, sb->s_blocksize); | 2294 | de1 = ext4_next_entry(de, sb->s_blocksize); |
1916 | if (le32_to_cpu(de->inode) != inode->i_ino || | 2295 | if (le32_to_cpu(de->inode) != inode->i_ino || |
@@ -1942,6 +2321,14 @@ static int empty_dir(struct inode *inode) | |||
1942 | offset += sb->s_blocksize; | 2321 | offset += sb->s_blocksize; |
1943 | continue; | 2322 | continue; |
1944 | } | 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); | ||
1945 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2332 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1946 | } | 2333 | } |
1947 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { | 2334 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { |
@@ -2010,7 +2397,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2010 | /* 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... */ |
2011 | 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); |
2012 | 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); |
2013 | err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); | 2400 | err = ext4_handle_dirty_super_now(handle, sb); |
2014 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); | 2401 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); |
2015 | if (!err) | 2402 | if (!err) |
2016 | err = rc; | 2403 | err = rc; |
@@ -2083,7 +2470,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2083 | if (err) | 2470 | if (err) |
2084 | goto out_brelse; | 2471 | goto out_brelse; |
2085 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); | 2472 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); |
2086 | err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); | 2473 | err = ext4_handle_dirty_super_now(handle, inode->i_sb); |
2087 | } else { | 2474 | } else { |
2088 | struct ext4_iloc iloc2; | 2475 | struct ext4_iloc iloc2; |
2089 | struct inode *i_prev = | 2476 | struct inode *i_prev = |
@@ -2442,6 +2829,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2442 | dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); | 2829 | dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); |
2443 | if (!dir_bh) | 2830 | if (!dir_bh) |
2444 | 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); | ||
2445 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, | 2837 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, |
2446 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) | 2838 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) |
2447 | goto end_rename; | 2839 | goto end_rename; |
@@ -2472,7 +2864,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2472 | ext4_current_time(new_dir); | 2864 | ext4_current_time(new_dir); |
2473 | ext4_mark_inode_dirty(handle, new_dir); | 2865 | ext4_mark_inode_dirty(handle, new_dir); |
2474 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); | 2866 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); |
2475 | retval = ext4_handle_dirty_metadata(handle, new_dir, new_bh); | 2867 | retval = ext4_handle_dirty_dirent_node(handle, new_dir, new_bh); |
2476 | if (unlikely(retval)) { | 2868 | if (unlikely(retval)) { |
2477 | ext4_std_error(new_dir->i_sb, retval); | 2869 | ext4_std_error(new_dir->i_sb, retval); |
2478 | goto end_rename; | 2870 | goto end_rename; |
@@ -2526,7 +2918,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2526 | 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) = |
2527 | cpu_to_le32(new_dir->i_ino); | 2919 | cpu_to_le32(new_dir->i_ino); |
2528 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); | 2920 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); |
2529 | retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh); | 2921 | retval = ext4_handle_dirty_dirent_node(handle, old_inode, |
2922 | dir_bh); | ||
2530 | if (retval) { | 2923 | if (retval) { |
2531 | ext4_std_error(old_dir->i_sb, retval); | 2924 | ext4_std_error(old_dir->i_sb, retval); |
2532 | goto end_rename; | 2925 | goto end_rename; |