diff options
Diffstat (limited to 'fs/ocfs2/dir.c')
-rw-r--r-- | fs/ocfs2/dir.c | 399 |
1 files changed, 314 insertions, 85 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 026e6eb85187..f2c4098cf337 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/types.h> | 40 | #include <linux/types.h> |
41 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
42 | #include <linux/highmem.h> | 42 | #include <linux/highmem.h> |
43 | #include <linux/quotaops.h> | ||
43 | 44 | ||
44 | #define MLOG_MASK_PREFIX ML_NAMEI | 45 | #define MLOG_MASK_PREFIX ML_NAMEI |
45 | #include <cluster/masklog.h> | 46 | #include <cluster/masklog.h> |
@@ -47,6 +48,7 @@ | |||
47 | #include "ocfs2.h" | 48 | #include "ocfs2.h" |
48 | 49 | ||
49 | #include "alloc.h" | 50 | #include "alloc.h" |
51 | #include "blockcheck.h" | ||
50 | #include "dir.h" | 52 | #include "dir.h" |
51 | #include "dlmglue.h" | 53 | #include "dlmglue.h" |
52 | #include "extent_map.h" | 54 | #include "extent_map.h" |
@@ -82,47 +84,72 @@ static int ocfs2_do_extend_dir(struct super_block *sb, | |||
82 | struct ocfs2_alloc_context *meta_ac, | 84 | struct ocfs2_alloc_context *meta_ac, |
83 | struct buffer_head **new_bh); | 85 | struct buffer_head **new_bh); |
84 | 86 | ||
85 | static struct buffer_head *ocfs2_bread(struct inode *inode, | 87 | /* |
86 | int block, int *err, int reada) | 88 | * These are distinct checks because future versions of the file system will |
89 | * want to have a trailing dirent structure independent of indexing. | ||
90 | */ | ||
91 | static int ocfs2_dir_has_trailer(struct inode *dir) | ||
87 | { | 92 | { |
88 | struct buffer_head *bh = NULL; | 93 | if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) |
89 | int tmperr; | 94 | return 0; |
90 | u64 p_blkno; | ||
91 | int readflags = 0; | ||
92 | 95 | ||
93 | if (reada) | 96 | return ocfs2_meta_ecc(OCFS2_SB(dir->i_sb)); |
94 | readflags |= OCFS2_BH_READAHEAD; | 97 | } |
95 | 98 | ||
96 | if (((u64)block << inode->i_sb->s_blocksize_bits) >= | 99 | static int ocfs2_supports_dir_trailer(struct ocfs2_super *osb) |
97 | i_size_read(inode)) { | 100 | { |
98 | BUG_ON(!reada); | 101 | return ocfs2_meta_ecc(osb); |
99 | return NULL; | 102 | } |
100 | } | ||
101 | 103 | ||
102 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | 104 | static inline unsigned int ocfs2_dir_trailer_blk_off(struct super_block *sb) |
103 | tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, | 105 | { |
104 | NULL); | 106 | return sb->s_blocksize - sizeof(struct ocfs2_dir_block_trailer); |
105 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | 107 | } |
106 | if (tmperr < 0) { | ||
107 | mlog_errno(tmperr); | ||
108 | goto fail; | ||
109 | } | ||
110 | 108 | ||
111 | tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags); | 109 | #define ocfs2_trailer_from_bh(_bh, _sb) ((struct ocfs2_dir_block_trailer *) ((_bh)->b_data + ocfs2_dir_trailer_blk_off((_sb)))) |
112 | if (tmperr < 0) | ||
113 | goto fail; | ||
114 | 110 | ||
115 | tmperr = 0; | 111 | /* XXX ocfs2_block_dqtrailer() is similar but not quite - can we make |
112 | * them more consistent? */ | ||
113 | struct ocfs2_dir_block_trailer *ocfs2_dir_trailer_from_size(int blocksize, | ||
114 | void *data) | ||
115 | { | ||
116 | char *p = data; | ||
116 | 117 | ||
117 | *err = 0; | 118 | p += blocksize - sizeof(struct ocfs2_dir_block_trailer); |
118 | return bh; | 119 | return (struct ocfs2_dir_block_trailer *)p; |
120 | } | ||
119 | 121 | ||
120 | fail: | 122 | /* |
121 | brelse(bh); | 123 | * XXX: This is executed once on every dirent. We should consider optimizing |
122 | bh = NULL; | 124 | * it. |
125 | */ | ||
126 | static int ocfs2_skip_dir_trailer(struct inode *dir, | ||
127 | struct ocfs2_dir_entry *de, | ||
128 | unsigned long offset, | ||
129 | unsigned long blklen) | ||
130 | { | ||
131 | unsigned long toff = blklen - sizeof(struct ocfs2_dir_block_trailer); | ||
123 | 132 | ||
124 | *err = -EIO; | 133 | if (!ocfs2_dir_has_trailer(dir)) |
125 | return NULL; | 134 | return 0; |
135 | |||
136 | if (offset != toff) | ||
137 | return 0; | ||
138 | |||
139 | return 1; | ||
140 | } | ||
141 | |||
142 | static void ocfs2_init_dir_trailer(struct inode *inode, | ||
143 | struct buffer_head *bh) | ||
144 | { | ||
145 | struct ocfs2_dir_block_trailer *trailer; | ||
146 | |||
147 | trailer = ocfs2_trailer_from_bh(bh, inode->i_sb); | ||
148 | strcpy(trailer->db_signature, OCFS2_DIR_TRAILER_SIGNATURE); | ||
149 | trailer->db_compat_rec_len = | ||
150 | cpu_to_le16(sizeof(struct ocfs2_dir_block_trailer)); | ||
151 | trailer->db_parent_dinode = cpu_to_le64(OCFS2_I(inode)->ip_blkno); | ||
152 | trailer->db_blkno = cpu_to_le64(bh->b_blocknr); | ||
126 | } | 153 | } |
127 | 154 | ||
128 | /* | 155 | /* |
@@ -231,7 +258,7 @@ static struct buffer_head *ocfs2_find_entry_id(const char *name, | |||
231 | struct ocfs2_dinode *di; | 258 | struct ocfs2_dinode *di; |
232 | struct ocfs2_inline_data *data; | 259 | struct ocfs2_inline_data *data; |
233 | 260 | ||
234 | ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh); | 261 | ret = ocfs2_read_inode_block(dir, &di_bh); |
235 | if (ret) { | 262 | if (ret) { |
236 | mlog_errno(ret); | 263 | mlog_errno(ret); |
237 | goto out; | 264 | goto out; |
@@ -250,6 +277,108 @@ out: | |||
250 | return NULL; | 277 | return NULL; |
251 | } | 278 | } |
252 | 279 | ||
280 | static int ocfs2_validate_dir_block(struct super_block *sb, | ||
281 | struct buffer_head *bh) | ||
282 | { | ||
283 | int rc; | ||
284 | struct ocfs2_dir_block_trailer *trailer = | ||
285 | ocfs2_trailer_from_bh(bh, sb); | ||
286 | |||
287 | |||
288 | /* | ||
289 | * We don't validate dirents here, that's handled | ||
290 | * in-place when the code walks them. | ||
291 | */ | ||
292 | mlog(0, "Validating dirblock %llu\n", | ||
293 | (unsigned long long)bh->b_blocknr); | ||
294 | |||
295 | BUG_ON(!buffer_uptodate(bh)); | ||
296 | |||
297 | /* | ||
298 | * If the ecc fails, we return the error but otherwise | ||
299 | * leave the filesystem running. We know any error is | ||
300 | * local to this block. | ||
301 | * | ||
302 | * Note that we are safe to call this even if the directory | ||
303 | * doesn't have a trailer. Filesystems without metaecc will do | ||
304 | * nothing, and filesystems with it will have one. | ||
305 | */ | ||
306 | rc = ocfs2_validate_meta_ecc(sb, bh->b_data, &trailer->db_check); | ||
307 | if (rc) | ||
308 | mlog(ML_ERROR, "Checksum failed for dinode %llu\n", | ||
309 | (unsigned long long)bh->b_blocknr); | ||
310 | |||
311 | return rc; | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * This function forces all errors to -EIO for consistency with its | ||
316 | * predecessor, ocfs2_bread(). We haven't audited what returning the | ||
317 | * real error codes would do to callers. We log the real codes with | ||
318 | * mlog_errno() before we squash them. | ||
319 | */ | ||
320 | static int ocfs2_read_dir_block(struct inode *inode, u64 v_block, | ||
321 | struct buffer_head **bh, int flags) | ||
322 | { | ||
323 | int rc = 0; | ||
324 | struct buffer_head *tmp = *bh; | ||
325 | struct ocfs2_dir_block_trailer *trailer; | ||
326 | |||
327 | rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, flags, | ||
328 | ocfs2_validate_dir_block); | ||
329 | if (rc) { | ||
330 | mlog_errno(rc); | ||
331 | goto out; | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * We check the trailer here rather than in | ||
336 | * ocfs2_validate_dir_block() because that function doesn't have | ||
337 | * the inode to test. | ||
338 | */ | ||
339 | if (!(flags & OCFS2_BH_READAHEAD) && | ||
340 | ocfs2_dir_has_trailer(inode)) { | ||
341 | trailer = ocfs2_trailer_from_bh(tmp, inode->i_sb); | ||
342 | if (!OCFS2_IS_VALID_DIR_TRAILER(trailer)) { | ||
343 | rc = -EINVAL; | ||
344 | ocfs2_error(inode->i_sb, | ||
345 | "Invalid dirblock #%llu: " | ||
346 | "signature = %.*s\n", | ||
347 | (unsigned long long)tmp->b_blocknr, 7, | ||
348 | trailer->db_signature); | ||
349 | goto out; | ||
350 | } | ||
351 | if (le64_to_cpu(trailer->db_blkno) != tmp->b_blocknr) { | ||
352 | rc = -EINVAL; | ||
353 | ocfs2_error(inode->i_sb, | ||
354 | "Directory block #%llu has an invalid " | ||
355 | "db_blkno of %llu", | ||
356 | (unsigned long long)tmp->b_blocknr, | ||
357 | (unsigned long long)le64_to_cpu(trailer->db_blkno)); | ||
358 | goto out; | ||
359 | } | ||
360 | if (le64_to_cpu(trailer->db_parent_dinode) != | ||
361 | OCFS2_I(inode)->ip_blkno) { | ||
362 | rc = -EINVAL; | ||
363 | ocfs2_error(inode->i_sb, | ||
364 | "Directory block #%llu on dinode " | ||
365 | "#%llu has an invalid parent_dinode " | ||
366 | "of %llu", | ||
367 | (unsigned long long)tmp->b_blocknr, | ||
368 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
369 | (unsigned long long)le64_to_cpu(trailer->db_blkno)); | ||
370 | goto out; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | /* If ocfs2_read_virt_blocks() got us a new bh, pass it up. */ | ||
375 | if (!*bh) | ||
376 | *bh = tmp; | ||
377 | |||
378 | out: | ||
379 | return rc ? -EIO : 0; | ||
380 | } | ||
381 | |||
253 | static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, | 382 | static struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen, |
254 | struct inode *dir, | 383 | struct inode *dir, |
255 | struct ocfs2_dir_entry **res_dir) | 384 | struct ocfs2_dir_entry **res_dir) |
@@ -296,15 +425,17 @@ restart: | |||
296 | } | 425 | } |
297 | num++; | 426 | num++; |
298 | 427 | ||
299 | bh = ocfs2_bread(dir, b++, &err, 1); | 428 | bh = NULL; |
429 | err = ocfs2_read_dir_block(dir, b++, &bh, | ||
430 | OCFS2_BH_READAHEAD); | ||
300 | bh_use[ra_max] = bh; | 431 | bh_use[ra_max] = bh; |
301 | } | 432 | } |
302 | } | 433 | } |
303 | if ((bh = bh_use[ra_ptr++]) == NULL) | 434 | if ((bh = bh_use[ra_ptr++]) == NULL) |
304 | goto next; | 435 | goto next; |
305 | if (ocfs2_read_block(dir, block, &bh)) { | 436 | if (ocfs2_read_dir_block(dir, block, &bh, 0)) { |
306 | /* read error, skip block & hope for the best. | 437 | /* read error, skip block & hope for the best. |
307 | * ocfs2_read_block() has released the bh. */ | 438 | * ocfs2_read_dir_block() has released the bh. */ |
308 | ocfs2_error(dir->i_sb, "reading directory %llu, " | 439 | ocfs2_error(dir->i_sb, "reading directory %llu, " |
309 | "offset %lu\n", | 440 | "offset %lu\n", |
310 | (unsigned long long)OCFS2_I(dir)->ip_blkno, | 441 | (unsigned long long)OCFS2_I(dir)->ip_blkno, |
@@ -381,14 +512,18 @@ int ocfs2_update_entry(struct inode *dir, handle_t *handle, | |||
381 | struct inode *new_entry_inode) | 512 | struct inode *new_entry_inode) |
382 | { | 513 | { |
383 | int ret; | 514 | int ret; |
515 | ocfs2_journal_access_func access = ocfs2_journal_access_db; | ||
384 | 516 | ||
385 | /* | 517 | /* |
386 | * The same code works fine for both inline-data and extent | 518 | * The same code works fine for both inline-data and extent |
387 | * based directories, so no need to split this up. | 519 | * based directories, so no need to split this up. The only |
520 | * difference is the journal_access function. | ||
388 | */ | 521 | */ |
389 | 522 | ||
390 | ret = ocfs2_journal_access(handle, dir, de_bh, | 523 | if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) |
391 | OCFS2_JOURNAL_ACCESS_WRITE); | 524 | access = ocfs2_journal_access_di; |
525 | |||
526 | ret = access(handle, dir, de_bh, OCFS2_JOURNAL_ACCESS_WRITE); | ||
392 | if (ret) { | 527 | if (ret) { |
393 | mlog_errno(ret); | 528 | mlog_errno(ret); |
394 | goto out; | 529 | goto out; |
@@ -410,9 +545,13 @@ static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir, | |||
410 | { | 545 | { |
411 | struct ocfs2_dir_entry *de, *pde; | 546 | struct ocfs2_dir_entry *de, *pde; |
412 | int i, status = -ENOENT; | 547 | int i, status = -ENOENT; |
548 | ocfs2_journal_access_func access = ocfs2_journal_access_db; | ||
413 | 549 | ||
414 | mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh); | 550 | mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh); |
415 | 551 | ||
552 | if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) | ||
553 | access = ocfs2_journal_access_di; | ||
554 | |||
416 | i = 0; | 555 | i = 0; |
417 | pde = NULL; | 556 | pde = NULL; |
418 | de = (struct ocfs2_dir_entry *) first_de; | 557 | de = (struct ocfs2_dir_entry *) first_de; |
@@ -423,8 +562,8 @@ static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir, | |||
423 | goto bail; | 562 | goto bail; |
424 | } | 563 | } |
425 | if (de == de_del) { | 564 | if (de == de_del) { |
426 | status = ocfs2_journal_access(handle, dir, bh, | 565 | status = access(handle, dir, bh, |
427 | OCFS2_JOURNAL_ACCESS_WRITE); | 566 | OCFS2_JOURNAL_ACCESS_WRITE); |
428 | if (status < 0) { | 567 | if (status < 0) { |
429 | status = -EIO; | 568 | status = -EIO; |
430 | mlog_errno(status); | 569 | mlog_errno(status); |
@@ -458,7 +597,7 @@ static inline int ocfs2_delete_entry_id(handle_t *handle, | |||
458 | struct ocfs2_dinode *di; | 597 | struct ocfs2_dinode *di; |
459 | struct ocfs2_inline_data *data; | 598 | struct ocfs2_inline_data *data; |
460 | 599 | ||
461 | ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh); | 600 | ret = ocfs2_read_inode_block(dir, &di_bh); |
462 | if (ret) { | 601 | if (ret) { |
463 | mlog_errno(ret); | 602 | mlog_errno(ret); |
464 | goto out; | 603 | goto out; |
@@ -576,6 +715,16 @@ int __ocfs2_add_entry(handle_t *handle, | |||
576 | goto bail; | 715 | goto bail; |
577 | } | 716 | } |
578 | 717 | ||
718 | /* We're guaranteed that we should have space, so we | ||
719 | * can't possibly have hit the trailer...right? */ | ||
720 | mlog_bug_on_msg(ocfs2_skip_dir_trailer(dir, de, offset, size), | ||
721 | "Hit dir trailer trying to insert %.*s " | ||
722 | "(namelen %d) into directory %llu. " | ||
723 | "offset is %lu, trailer offset is %d\n", | ||
724 | namelen, name, namelen, | ||
725 | (unsigned long long)parent_fe_bh->b_blocknr, | ||
726 | offset, ocfs2_dir_trailer_blk_off(dir->i_sb)); | ||
727 | |||
579 | if (ocfs2_dirent_would_fit(de, rec_len)) { | 728 | if (ocfs2_dirent_would_fit(de, rec_len)) { |
580 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | 729 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; |
581 | retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); | 730 | retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh); |
@@ -584,8 +733,14 @@ int __ocfs2_add_entry(handle_t *handle, | |||
584 | goto bail; | 733 | goto bail; |
585 | } | 734 | } |
586 | 735 | ||
587 | status = ocfs2_journal_access(handle, dir, insert_bh, | 736 | if (insert_bh == parent_fe_bh) |
588 | OCFS2_JOURNAL_ACCESS_WRITE); | 737 | status = ocfs2_journal_access_di(handle, dir, |
738 | insert_bh, | ||
739 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
740 | else | ||
741 | status = ocfs2_journal_access_db(handle, dir, | ||
742 | insert_bh, | ||
743 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
589 | /* By now the buffer is marked for journaling */ | 744 | /* By now the buffer is marked for journaling */ |
590 | offset += le16_to_cpu(de->rec_len); | 745 | offset += le16_to_cpu(de->rec_len); |
591 | if (le64_to_cpu(de->inode)) { | 746 | if (le64_to_cpu(de->inode)) { |
@@ -611,6 +766,7 @@ int __ocfs2_add_entry(handle_t *handle, | |||
611 | retval = 0; | 766 | retval = 0; |
612 | goto bail; | 767 | goto bail; |
613 | } | 768 | } |
769 | |||
614 | offset += le16_to_cpu(de->rec_len); | 770 | offset += le16_to_cpu(de->rec_len); |
615 | de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); | 771 | de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len)); |
616 | } | 772 | } |
@@ -636,7 +792,7 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode, | |||
636 | struct ocfs2_inline_data *data; | 792 | struct ocfs2_inline_data *data; |
637 | struct ocfs2_dir_entry *de; | 793 | struct ocfs2_dir_entry *de; |
638 | 794 | ||
639 | ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh); | 795 | ret = ocfs2_read_inode_block(inode, &di_bh); |
640 | if (ret) { | 796 | if (ret) { |
641 | mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", | 797 | mlog(ML_ERROR, "Unable to read inode block for dir %llu\n", |
642 | (unsigned long long)OCFS2_I(inode)->ip_blkno); | 798 | (unsigned long long)OCFS2_I(inode)->ip_blkno); |
@@ -724,7 +880,6 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, | |||
724 | int i, stored; | 880 | int i, stored; |
725 | struct buffer_head * bh, * tmp; | 881 | struct buffer_head * bh, * tmp; |
726 | struct ocfs2_dir_entry * de; | 882 | struct ocfs2_dir_entry * de; |
727 | int err; | ||
728 | struct super_block * sb = inode->i_sb; | 883 | struct super_block * sb = inode->i_sb; |
729 | unsigned int ra_sectors = 16; | 884 | unsigned int ra_sectors = 16; |
730 | 885 | ||
@@ -735,12 +890,8 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, | |||
735 | 890 | ||
736 | while (!error && !stored && *f_pos < i_size_read(inode)) { | 891 | while (!error && !stored && *f_pos < i_size_read(inode)) { |
737 | blk = (*f_pos) >> sb->s_blocksize_bits; | 892 | blk = (*f_pos) >> sb->s_blocksize_bits; |
738 | bh = ocfs2_bread(inode, blk, &err, 0); | 893 | if (ocfs2_read_dir_block(inode, blk, &bh, 0)) { |
739 | if (!bh) { | 894 | /* Skip the corrupt dirblock and keep trying */ |
740 | mlog(ML_ERROR, | ||
741 | "directory #%llu contains a hole at offset %lld\n", | ||
742 | (unsigned long long)OCFS2_I(inode)->ip_blkno, | ||
743 | *f_pos); | ||
744 | *f_pos += sb->s_blocksize - offset; | 895 | *f_pos += sb->s_blocksize - offset; |
745 | continue; | 896 | continue; |
746 | } | 897 | } |
@@ -754,8 +905,10 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode, | |||
754 | || (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) { | 905 | || (((last_ra_blk - blk) << 9) <= (ra_sectors / 2))) { |
755 | for (i = ra_sectors >> (sb->s_blocksize_bits - 9); | 906 | for (i = ra_sectors >> (sb->s_blocksize_bits - 9); |
756 | i > 0; i--) { | 907 | i > 0; i--) { |
757 | tmp = ocfs2_bread(inode, ++blk, &err, 1); | 908 | tmp = NULL; |
758 | brelse(tmp); | 909 | if (!ocfs2_read_dir_block(inode, ++blk, &tmp, |
910 | OCFS2_BH_READAHEAD)) | ||
911 | brelse(tmp); | ||
759 | } | 912 | } |
760 | last_ra_blk = blk; | 913 | last_ra_blk = blk; |
761 | ra_sectors = 8; | 914 | ra_sectors = 8; |
@@ -828,6 +981,7 @@ revalidate: | |||
828 | } | 981 | } |
829 | offset = 0; | 982 | offset = 0; |
830 | brelse(bh); | 983 | brelse(bh); |
984 | bh = NULL; | ||
831 | } | 985 | } |
832 | 986 | ||
833 | stored = 0; | 987 | stored = 0; |
@@ -1050,9 +1204,15 @@ int ocfs2_empty_dir(struct inode *inode) | |||
1050 | return !priv.seen_other; | 1204 | return !priv.seen_other; |
1051 | } | 1205 | } |
1052 | 1206 | ||
1053 | static void ocfs2_fill_initial_dirents(struct inode *inode, | 1207 | /* |
1054 | struct inode *parent, | 1208 | * Fills "." and ".." dirents in a new directory block. Returns dirent for |
1055 | char *start, unsigned int size) | 1209 | * "..", which might be used during creation of a directory with a trailing |
1210 | * header. It is otherwise safe to ignore the return code. | ||
1211 | */ | ||
1212 | static struct ocfs2_dir_entry *ocfs2_fill_initial_dirents(struct inode *inode, | ||
1213 | struct inode *parent, | ||
1214 | char *start, | ||
1215 | unsigned int size) | ||
1056 | { | 1216 | { |
1057 | struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start; | 1217 | struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start; |
1058 | 1218 | ||
@@ -1069,6 +1229,8 @@ static void ocfs2_fill_initial_dirents(struct inode *inode, | |||
1069 | de->name_len = 2; | 1229 | de->name_len = 2; |
1070 | strcpy(de->name, ".."); | 1230 | strcpy(de->name, ".."); |
1071 | ocfs2_set_de_type(de, S_IFDIR); | 1231 | ocfs2_set_de_type(de, S_IFDIR); |
1232 | |||
1233 | return de; | ||
1072 | } | 1234 | } |
1073 | 1235 | ||
1074 | /* | 1236 | /* |
@@ -1086,8 +1248,8 @@ static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb, | |||
1086 | struct ocfs2_inline_data *data = &di->id2.i_data; | 1248 | struct ocfs2_inline_data *data = &di->id2.i_data; |
1087 | unsigned int size = le16_to_cpu(data->id_count); | 1249 | unsigned int size = le16_to_cpu(data->id_count); |
1088 | 1250 | ||
1089 | ret = ocfs2_journal_access(handle, inode, di_bh, | 1251 | ret = ocfs2_journal_access_di(handle, inode, di_bh, |
1090 | OCFS2_JOURNAL_ACCESS_WRITE); | 1252 | OCFS2_JOURNAL_ACCESS_WRITE); |
1091 | if (ret) { | 1253 | if (ret) { |
1092 | mlog_errno(ret); | 1254 | mlog_errno(ret); |
1093 | goto out; | 1255 | goto out; |
@@ -1121,10 +1283,15 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb, | |||
1121 | struct ocfs2_alloc_context *data_ac) | 1283 | struct ocfs2_alloc_context *data_ac) |
1122 | { | 1284 | { |
1123 | int status; | 1285 | int status; |
1286 | unsigned int size = osb->sb->s_blocksize; | ||
1124 | struct buffer_head *new_bh = NULL; | 1287 | struct buffer_head *new_bh = NULL; |
1288 | struct ocfs2_dir_entry *de; | ||
1125 | 1289 | ||
1126 | mlog_entry_void(); | 1290 | mlog_entry_void(); |
1127 | 1291 | ||
1292 | if (ocfs2_supports_dir_trailer(osb)) | ||
1293 | size = ocfs2_dir_trailer_blk_off(parent->i_sb); | ||
1294 | |||
1128 | status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, | 1295 | status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh, |
1129 | data_ac, NULL, &new_bh); | 1296 | data_ac, NULL, &new_bh); |
1130 | if (status < 0) { | 1297 | if (status < 0) { |
@@ -1134,16 +1301,17 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb, | |||
1134 | 1301 | ||
1135 | ocfs2_set_new_buffer_uptodate(inode, new_bh); | 1302 | ocfs2_set_new_buffer_uptodate(inode, new_bh); |
1136 | 1303 | ||
1137 | status = ocfs2_journal_access(handle, inode, new_bh, | 1304 | status = ocfs2_journal_access_db(handle, inode, new_bh, |
1138 | OCFS2_JOURNAL_ACCESS_CREATE); | 1305 | OCFS2_JOURNAL_ACCESS_CREATE); |
1139 | if (status < 0) { | 1306 | if (status < 0) { |
1140 | mlog_errno(status); | 1307 | mlog_errno(status); |
1141 | goto bail; | 1308 | goto bail; |
1142 | } | 1309 | } |
1143 | memset(new_bh->b_data, 0, osb->sb->s_blocksize); | 1310 | memset(new_bh->b_data, 0, osb->sb->s_blocksize); |
1144 | 1311 | ||
1145 | ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data, | 1312 | de = ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data, size); |
1146 | osb->sb->s_blocksize); | 1313 | if (ocfs2_supports_dir_trailer(osb)) |
1314 | ocfs2_init_dir_trailer(inode, new_bh); | ||
1147 | 1315 | ||
1148 | status = ocfs2_journal_dirty(handle, new_bh); | 1316 | status = ocfs2_journal_dirty(handle, new_bh); |
1149 | if (status < 0) { | 1317 | if (status < 0) { |
@@ -1184,13 +1352,27 @@ int ocfs2_fill_new_dir(struct ocfs2_super *osb, | |||
1184 | data_ac); | 1352 | data_ac); |
1185 | } | 1353 | } |
1186 | 1354 | ||
1355 | /* | ||
1356 | * Expand rec_len of the rightmost dirent in a directory block so that it | ||
1357 | * contains the end of our valid space for dirents. We do this during | ||
1358 | * expansion from an inline directory to one with extents. The first dir block | ||
1359 | * in that case is taken from the inline data portion of the inode block. | ||
1360 | * | ||
1361 | * We add the dir trailer if this filesystem wants it. | ||
1362 | */ | ||
1187 | static void ocfs2_expand_last_dirent(char *start, unsigned int old_size, | 1363 | static void ocfs2_expand_last_dirent(char *start, unsigned int old_size, |
1188 | unsigned int new_size) | 1364 | struct super_block *sb) |
1189 | { | 1365 | { |
1190 | struct ocfs2_dir_entry *de; | 1366 | struct ocfs2_dir_entry *de; |
1191 | struct ocfs2_dir_entry *prev_de; | 1367 | struct ocfs2_dir_entry *prev_de; |
1192 | char *de_buf, *limit; | 1368 | char *de_buf, *limit; |
1193 | unsigned int bytes = new_size - old_size; | 1369 | unsigned int new_size = sb->s_blocksize; |
1370 | unsigned int bytes; | ||
1371 | |||
1372 | if (ocfs2_supports_dir_trailer(OCFS2_SB(sb))) | ||
1373 | new_size = ocfs2_dir_trailer_blk_off(sb); | ||
1374 | |||
1375 | bytes = new_size - old_size; | ||
1194 | 1376 | ||
1195 | limit = start + old_size; | 1377 | limit = start + old_size; |
1196 | de_buf = start; | 1378 | de_buf = start; |
@@ -1216,9 +1398,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1216 | unsigned int blocks_wanted, | 1398 | unsigned int blocks_wanted, |
1217 | struct buffer_head **first_block_bh) | 1399 | struct buffer_head **first_block_bh) |
1218 | { | 1400 | { |
1219 | int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS; | ||
1220 | u32 alloc, bit_off, len; | 1401 | u32 alloc, bit_off, len; |
1221 | struct super_block *sb = dir->i_sb; | 1402 | struct super_block *sb = dir->i_sb; |
1403 | int ret, credits = ocfs2_inline_to_extents_credits(sb); | ||
1222 | u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits; | 1404 | u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits; |
1223 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); | 1405 | struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); |
1224 | struct ocfs2_inode_info *oi = OCFS2_I(dir); | 1406 | struct ocfs2_inode_info *oi = OCFS2_I(dir); |
@@ -1227,6 +1409,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1227 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 1409 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
1228 | handle_t *handle; | 1410 | handle_t *handle; |
1229 | struct ocfs2_extent_tree et; | 1411 | struct ocfs2_extent_tree et; |
1412 | int did_quota = 0; | ||
1230 | 1413 | ||
1231 | ocfs2_init_dinode_extent_tree(&et, dir, di_bh); | 1414 | ocfs2_init_dinode_extent_tree(&et, dir, di_bh); |
1232 | 1415 | ||
@@ -1264,6 +1447,12 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1264 | goto out_sem; | 1447 | goto out_sem; |
1265 | } | 1448 | } |
1266 | 1449 | ||
1450 | if (vfs_dq_alloc_space_nodirty(dir, | ||
1451 | ocfs2_clusters_to_bytes(osb->sb, alloc))) { | ||
1452 | ret = -EDQUOT; | ||
1453 | goto out_commit; | ||
1454 | } | ||
1455 | did_quota = 1; | ||
1267 | /* | 1456 | /* |
1268 | * Try to claim as many clusters as the bitmap can give though | 1457 | * Try to claim as many clusters as the bitmap can give though |
1269 | * if we only get one now, that's enough to continue. The rest | 1458 | * if we only get one now, that's enough to continue. The rest |
@@ -1290,8 +1479,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1290 | 1479 | ||
1291 | ocfs2_set_new_buffer_uptodate(dir, dirdata_bh); | 1480 | ocfs2_set_new_buffer_uptodate(dir, dirdata_bh); |
1292 | 1481 | ||
1293 | ret = ocfs2_journal_access(handle, dir, dirdata_bh, | 1482 | ret = ocfs2_journal_access_db(handle, dir, dirdata_bh, |
1294 | OCFS2_JOURNAL_ACCESS_CREATE); | 1483 | OCFS2_JOURNAL_ACCESS_CREATE); |
1295 | if (ret) { | 1484 | if (ret) { |
1296 | mlog_errno(ret); | 1485 | mlog_errno(ret); |
1297 | goto out_commit; | 1486 | goto out_commit; |
@@ -1300,8 +1489,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1300 | memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir)); | 1489 | memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir)); |
1301 | memset(dirdata_bh->b_data + i_size_read(dir), 0, | 1490 | memset(dirdata_bh->b_data + i_size_read(dir), 0, |
1302 | sb->s_blocksize - i_size_read(dir)); | 1491 | sb->s_blocksize - i_size_read(dir)); |
1303 | ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), | 1492 | ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir), sb); |
1304 | sb->s_blocksize); | 1493 | if (ocfs2_supports_dir_trailer(osb)) |
1494 | ocfs2_init_dir_trailer(dir, dirdata_bh); | ||
1305 | 1495 | ||
1306 | ret = ocfs2_journal_dirty(handle, dirdata_bh); | 1496 | ret = ocfs2_journal_dirty(handle, dirdata_bh); |
1307 | if (ret) { | 1497 | if (ret) { |
@@ -1317,8 +1507,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1317 | * We let the later dirent insert modify c/mtime - to the user | 1507 | * We let the later dirent insert modify c/mtime - to the user |
1318 | * the data hasn't changed. | 1508 | * the data hasn't changed. |
1319 | */ | 1509 | */ |
1320 | ret = ocfs2_journal_access(handle, dir, di_bh, | 1510 | ret = ocfs2_journal_access_di(handle, dir, di_bh, |
1321 | OCFS2_JOURNAL_ACCESS_CREATE); | 1511 | OCFS2_JOURNAL_ACCESS_CREATE); |
1322 | if (ret) { | 1512 | if (ret) { |
1323 | mlog_errno(ret); | 1513 | mlog_errno(ret); |
1324 | goto out_commit; | 1514 | goto out_commit; |
@@ -1386,6 +1576,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh, | |||
1386 | dirdata_bh = NULL; | 1576 | dirdata_bh = NULL; |
1387 | 1577 | ||
1388 | out_commit: | 1578 | out_commit: |
1579 | if (ret < 0 && did_quota) | ||
1580 | vfs_dq_free_space_nodirty(dir, | ||
1581 | ocfs2_clusters_to_bytes(osb->sb, 2)); | ||
1389 | ocfs2_commit_trans(osb, handle); | 1582 | ocfs2_commit_trans(osb, handle); |
1390 | 1583 | ||
1391 | out_sem: | 1584 | out_sem: |
@@ -1410,7 +1603,7 @@ static int ocfs2_do_extend_dir(struct super_block *sb, | |||
1410 | struct buffer_head **new_bh) | 1603 | struct buffer_head **new_bh) |
1411 | { | 1604 | { |
1412 | int status; | 1605 | int status; |
1413 | int extend; | 1606 | int extend, did_quota = 0; |
1414 | u64 p_blkno, v_blkno; | 1607 | u64 p_blkno, v_blkno; |
1415 | 1608 | ||
1416 | spin_lock(&OCFS2_I(dir)->ip_lock); | 1609 | spin_lock(&OCFS2_I(dir)->ip_lock); |
@@ -1420,6 +1613,13 @@ static int ocfs2_do_extend_dir(struct super_block *sb, | |||
1420 | if (extend) { | 1613 | if (extend) { |
1421 | u32 offset = OCFS2_I(dir)->ip_clusters; | 1614 | u32 offset = OCFS2_I(dir)->ip_clusters; |
1422 | 1615 | ||
1616 | if (vfs_dq_alloc_space_nodirty(dir, | ||
1617 | ocfs2_clusters_to_bytes(sb, 1))) { | ||
1618 | status = -EDQUOT; | ||
1619 | goto bail; | ||
1620 | } | ||
1621 | did_quota = 1; | ||
1622 | |||
1423 | status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset, | 1623 | status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset, |
1424 | 1, 0, parent_fe_bh, handle, | 1624 | 1, 0, parent_fe_bh, handle, |
1425 | data_ac, meta_ac, NULL); | 1625 | data_ac, meta_ac, NULL); |
@@ -1445,6 +1645,8 @@ static int ocfs2_do_extend_dir(struct super_block *sb, | |||
1445 | } | 1645 | } |
1446 | status = 0; | 1646 | status = 0; |
1447 | bail: | 1647 | bail: |
1648 | if (did_quota && status < 0) | ||
1649 | vfs_dq_free_space_nodirty(dir, ocfs2_clusters_to_bytes(sb, 1)); | ||
1448 | mlog_exit(status); | 1650 | mlog_exit(status); |
1449 | return status; | 1651 | return status; |
1450 | } | 1652 | } |
@@ -1569,16 +1771,22 @@ do_extend: | |||
1569 | 1771 | ||
1570 | ocfs2_set_new_buffer_uptodate(dir, new_bh); | 1772 | ocfs2_set_new_buffer_uptodate(dir, new_bh); |
1571 | 1773 | ||
1572 | status = ocfs2_journal_access(handle, dir, new_bh, | 1774 | status = ocfs2_journal_access_db(handle, dir, new_bh, |
1573 | OCFS2_JOURNAL_ACCESS_CREATE); | 1775 | OCFS2_JOURNAL_ACCESS_CREATE); |
1574 | if (status < 0) { | 1776 | if (status < 0) { |
1575 | mlog_errno(status); | 1777 | mlog_errno(status); |
1576 | goto bail; | 1778 | goto bail; |
1577 | } | 1779 | } |
1578 | memset(new_bh->b_data, 0, sb->s_blocksize); | 1780 | memset(new_bh->b_data, 0, sb->s_blocksize); |
1781 | |||
1579 | de = (struct ocfs2_dir_entry *) new_bh->b_data; | 1782 | de = (struct ocfs2_dir_entry *) new_bh->b_data; |
1580 | de->inode = 0; | 1783 | de->inode = 0; |
1581 | de->rec_len = cpu_to_le16(sb->s_blocksize); | 1784 | if (ocfs2_dir_has_trailer(dir)) { |
1785 | de->rec_len = cpu_to_le16(ocfs2_dir_trailer_blk_off(sb)); | ||
1786 | ocfs2_init_dir_trailer(dir, new_bh); | ||
1787 | } else { | ||
1788 | de->rec_len = cpu_to_le16(sb->s_blocksize); | ||
1789 | } | ||
1582 | status = ocfs2_journal_dirty(handle, new_bh); | 1790 | status = ocfs2_journal_dirty(handle, new_bh); |
1583 | if (status < 0) { | 1791 | if (status < 0) { |
1584 | mlog_errno(status); | 1792 | mlog_errno(status); |
@@ -1620,11 +1828,21 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, | |||
1620 | unsigned int *blocks_wanted) | 1828 | unsigned int *blocks_wanted) |
1621 | { | 1829 | { |
1622 | int ret; | 1830 | int ret; |
1831 | struct super_block *sb = dir->i_sb; | ||
1623 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | 1832 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; |
1624 | struct ocfs2_dir_entry *de, *last_de = NULL; | 1833 | struct ocfs2_dir_entry *de, *last_de = NULL; |
1625 | char *de_buf, *limit; | 1834 | char *de_buf, *limit; |
1626 | unsigned long offset = 0; | 1835 | unsigned long offset = 0; |
1627 | unsigned int rec_len, new_rec_len; | 1836 | unsigned int rec_len, new_rec_len, free_space = dir->i_sb->s_blocksize; |
1837 | |||
1838 | /* | ||
1839 | * This calculates how many free bytes we'd have in block zero, should | ||
1840 | * this function force expansion to an extent tree. | ||
1841 | */ | ||
1842 | if (ocfs2_supports_dir_trailer(OCFS2_SB(sb))) | ||
1843 | free_space = ocfs2_dir_trailer_blk_off(sb) - i_size_read(dir); | ||
1844 | else | ||
1845 | free_space = dir->i_sb->s_blocksize - i_size_read(dir); | ||
1628 | 1846 | ||
1629 | de_buf = di->id2.i_data.id_data; | 1847 | de_buf = di->id2.i_data.id_data; |
1630 | limit = de_buf + i_size_read(dir); | 1848 | limit = de_buf + i_size_read(dir); |
@@ -1641,6 +1859,11 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, | |||
1641 | ret = -EEXIST; | 1859 | ret = -EEXIST; |
1642 | goto out; | 1860 | goto out; |
1643 | } | 1861 | } |
1862 | /* | ||
1863 | * No need to check for a trailing dirent record here as | ||
1864 | * they're not used for inline dirs. | ||
1865 | */ | ||
1866 | |||
1644 | if (ocfs2_dirent_would_fit(de, rec_len)) { | 1867 | if (ocfs2_dirent_would_fit(de, rec_len)) { |
1645 | /* Ok, we found a spot. Return this bh and let | 1868 | /* Ok, we found a spot. Return this bh and let |
1646 | * the caller actually fill it in. */ | 1869 | * the caller actually fill it in. */ |
@@ -1661,7 +1884,7 @@ static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh, | |||
1661 | * dirent can be found. | 1884 | * dirent can be found. |
1662 | */ | 1885 | */ |
1663 | *blocks_wanted = 1; | 1886 | *blocks_wanted = 1; |
1664 | new_rec_len = le16_to_cpu(last_de->rec_len) + (dir->i_sb->s_blocksize - i_size_read(dir)); | 1887 | new_rec_len = le16_to_cpu(last_de->rec_len) + free_space; |
1665 | if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len))) | 1888 | if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len))) |
1666 | *blocks_wanted = 2; | 1889 | *blocks_wanted = 2; |
1667 | 1890 | ||
@@ -1679,9 +1902,10 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, | |||
1679 | struct ocfs2_dir_entry *de; | 1902 | struct ocfs2_dir_entry *de; |
1680 | struct super_block *sb = dir->i_sb; | 1903 | struct super_block *sb = dir->i_sb; |
1681 | int status; | 1904 | int status; |
1905 | int blocksize = dir->i_sb->s_blocksize; | ||
1682 | 1906 | ||
1683 | bh = ocfs2_bread(dir, 0, &status, 0); | 1907 | status = ocfs2_read_dir_block(dir, 0, &bh, 0); |
1684 | if (!bh) { | 1908 | if (status) { |
1685 | mlog_errno(status); | 1909 | mlog_errno(status); |
1686 | goto bail; | 1910 | goto bail; |
1687 | } | 1911 | } |
@@ -1702,11 +1926,10 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, | |||
1702 | status = -ENOSPC; | 1926 | status = -ENOSPC; |
1703 | goto bail; | 1927 | goto bail; |
1704 | } | 1928 | } |
1705 | bh = ocfs2_bread(dir, | 1929 | status = ocfs2_read_dir_block(dir, |
1706 | offset >> sb->s_blocksize_bits, | 1930 | offset >> sb->s_blocksize_bits, |
1707 | &status, | 1931 | &bh, 0); |
1708 | 0); | 1932 | if (status) { |
1709 | if (!bh) { | ||
1710 | mlog_errno(status); | 1933 | mlog_errno(status); |
1711 | goto bail; | 1934 | goto bail; |
1712 | } | 1935 | } |
@@ -1721,6 +1944,11 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, | |||
1721 | status = -EEXIST; | 1944 | status = -EEXIST; |
1722 | goto bail; | 1945 | goto bail; |
1723 | } | 1946 | } |
1947 | |||
1948 | if (ocfs2_skip_dir_trailer(dir, de, offset % blocksize, | ||
1949 | blocksize)) | ||
1950 | goto next; | ||
1951 | |||
1724 | if (ocfs2_dirent_would_fit(de, rec_len)) { | 1952 | if (ocfs2_dirent_would_fit(de, rec_len)) { |
1725 | /* Ok, we found a spot. Return this bh and let | 1953 | /* Ok, we found a spot. Return this bh and let |
1726 | * the caller actually fill it in. */ | 1954 | * the caller actually fill it in. */ |
@@ -1729,6 +1957,7 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name, | |||
1729 | status = 0; | 1957 | status = 0; |
1730 | goto bail; | 1958 | goto bail; |
1731 | } | 1959 | } |
1960 | next: | ||
1732 | offset += le16_to_cpu(de->rec_len); | 1961 | offset += le16_to_cpu(de->rec_len); |
1733 | de = (struct ocfs2_dir_entry *)((char *) de + le16_to_cpu(de->rec_len)); | 1962 | de = (struct ocfs2_dir_entry *)((char *) de + le16_to_cpu(de->rec_len)); |
1734 | } | 1963 | } |