diff options
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 361 |
1 files changed, 194 insertions, 167 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 603e4ebbd0ac..426211882f72 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -53,7 +53,7 @@ static struct buffer_head *ext4_append(handle_t *handle, | |||
53 | ext4_lblk_t *block) | 53 | ext4_lblk_t *block) |
54 | { | 54 | { |
55 | struct buffer_head *bh; | 55 | struct buffer_head *bh; |
56 | int err = 0; | 56 | int err; |
57 | 57 | ||
58 | if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb && | 58 | if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb && |
59 | ((inode->i_size >> 10) >= | 59 | ((inode->i_size >> 10) >= |
@@ -62,9 +62,9 @@ static struct buffer_head *ext4_append(handle_t *handle, | |||
62 | 62 | ||
63 | *block = inode->i_size >> inode->i_sb->s_blocksize_bits; | 63 | *block = inode->i_size >> inode->i_sb->s_blocksize_bits; |
64 | 64 | ||
65 | bh = ext4_bread(handle, inode, *block, 1, &err); | 65 | bh = ext4_bread(handle, inode, *block, 1); |
66 | if (!bh) | 66 | if (IS_ERR(bh)) |
67 | return ERR_PTR(err); | 67 | return bh; |
68 | inode->i_size += inode->i_sb->s_blocksize; | 68 | inode->i_size += inode->i_sb->s_blocksize; |
69 | EXT4_I(inode)->i_disksize = inode->i_size; | 69 | EXT4_I(inode)->i_disksize = inode->i_size; |
70 | BUFFER_TRACE(bh, "get_write_access"); | 70 | BUFFER_TRACE(bh, "get_write_access"); |
@@ -94,20 +94,20 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode, | |||
94 | { | 94 | { |
95 | struct buffer_head *bh; | 95 | struct buffer_head *bh; |
96 | struct ext4_dir_entry *dirent; | 96 | struct ext4_dir_entry *dirent; |
97 | int err = 0, is_dx_block = 0; | 97 | int is_dx_block = 0; |
98 | 98 | ||
99 | bh = ext4_bread(NULL, inode, block, 0, &err); | 99 | bh = ext4_bread(NULL, inode, block, 0); |
100 | if (!bh) { | 100 | if (IS_ERR(bh)) { |
101 | if (err == 0) { | ||
102 | ext4_error_inode(inode, __func__, line, block, | ||
103 | "Directory hole found"); | ||
104 | return ERR_PTR(-EIO); | ||
105 | } | ||
106 | __ext4_warning(inode->i_sb, __func__, line, | 101 | __ext4_warning(inode->i_sb, __func__, line, |
107 | "error reading directory block " | 102 | "error %ld reading directory block " |
108 | "(ino %lu, block %lu)", inode->i_ino, | 103 | "(ino %lu, block %lu)", PTR_ERR(bh), inode->i_ino, |
109 | (unsigned long) block); | 104 | (unsigned long) block); |
110 | return ERR_PTR(err); | 105 | |
106 | return bh; | ||
107 | } | ||
108 | if (!bh) { | ||
109 | ext4_error_inode(inode, __func__, line, block, "Directory hole found"); | ||
110 | return ERR_PTR(-EIO); | ||
111 | } | 111 | } |
112 | dirent = (struct ext4_dir_entry *) bh->b_data; | 112 | dirent = (struct ext4_dir_entry *) bh->b_data; |
113 | /* Determine whether or not we have an index block */ | 113 | /* Determine whether or not we have an index block */ |
@@ -124,8 +124,7 @@ static struct buffer_head *__ext4_read_dirblock(struct inode *inode, | |||
124 | "directory leaf block found instead of index block"); | 124 | "directory leaf block found instead of index block"); |
125 | return ERR_PTR(-EIO); | 125 | return ERR_PTR(-EIO); |
126 | } | 126 | } |
127 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 127 | if (!ext4_has_metadata_csum(inode->i_sb) || |
128 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) || | ||
129 | buffer_verified(bh)) | 128 | buffer_verified(bh)) |
130 | return bh; | 129 | return bh; |
131 | 130 | ||
@@ -253,8 +252,7 @@ static unsigned dx_node_limit(struct inode *dir); | |||
253 | static struct dx_frame *dx_probe(const struct qstr *d_name, | 252 | static struct dx_frame *dx_probe(const struct qstr *d_name, |
254 | struct inode *dir, | 253 | struct inode *dir, |
255 | struct dx_hash_info *hinfo, | 254 | struct dx_hash_info *hinfo, |
256 | struct dx_frame *frame, | 255 | struct dx_frame *frame); |
257 | int *err); | ||
258 | static void dx_release(struct dx_frame *frames); | 256 | static void dx_release(struct dx_frame *frames); |
259 | static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, | 257 | static int dx_make_map(struct ext4_dir_entry_2 *de, unsigned blocksize, |
260 | struct dx_hash_info *hinfo, struct dx_map_entry map[]); | 258 | struct dx_hash_info *hinfo, struct dx_map_entry map[]); |
@@ -270,8 +268,7 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash, | |||
270 | __u32 *start_hash); | 268 | __u32 *start_hash); |
271 | static struct buffer_head * ext4_dx_find_entry(struct inode *dir, | 269 | static struct buffer_head * ext4_dx_find_entry(struct inode *dir, |
272 | const struct qstr *d_name, | 270 | const struct qstr *d_name, |
273 | struct ext4_dir_entry_2 **res_dir, | 271 | struct ext4_dir_entry_2 **res_dir); |
274 | int *err); | ||
275 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | 272 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, |
276 | struct inode *inode); | 273 | struct inode *inode); |
277 | 274 | ||
@@ -340,8 +337,7 @@ int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) | |||
340 | { | 337 | { |
341 | struct ext4_dir_entry_tail *t; | 338 | struct ext4_dir_entry_tail *t; |
342 | 339 | ||
343 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 340 | if (!ext4_has_metadata_csum(inode->i_sb)) |
344 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
345 | return 1; | 341 | return 1; |
346 | 342 | ||
347 | t = get_dirent_tail(inode, dirent); | 343 | t = get_dirent_tail(inode, dirent); |
@@ -362,8 +358,7 @@ static void ext4_dirent_csum_set(struct inode *inode, | |||
362 | { | 358 | { |
363 | struct ext4_dir_entry_tail *t; | 359 | struct ext4_dir_entry_tail *t; |
364 | 360 | ||
365 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 361 | if (!ext4_has_metadata_csum(inode->i_sb)) |
366 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
367 | return; | 362 | return; |
368 | 363 | ||
369 | t = get_dirent_tail(inode, dirent); | 364 | t = get_dirent_tail(inode, dirent); |
@@ -438,8 +433,7 @@ static int ext4_dx_csum_verify(struct inode *inode, | |||
438 | struct dx_tail *t; | 433 | struct dx_tail *t; |
439 | int count_offset, limit, count; | 434 | int count_offset, limit, count; |
440 | 435 | ||
441 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 436 | if (!ext4_has_metadata_csum(inode->i_sb)) |
442 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
443 | return 1; | 437 | return 1; |
444 | 438 | ||
445 | c = get_dx_countlimit(inode, dirent, &count_offset); | 439 | c = get_dx_countlimit(inode, dirent, &count_offset); |
@@ -468,8 +462,7 @@ static void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent) | |||
468 | struct dx_tail *t; | 462 | struct dx_tail *t; |
469 | int count_offset, limit, count; | 463 | int count_offset, limit, count; |
470 | 464 | ||
471 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 465 | if (!ext4_has_metadata_csum(inode->i_sb)) |
472 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
473 | return; | 466 | return; |
474 | 467 | ||
475 | c = get_dx_countlimit(inode, dirent, &count_offset); | 468 | c = get_dx_countlimit(inode, dirent, &count_offset); |
@@ -557,8 +550,7 @@ static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) | |||
557 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - | 550 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - |
558 | EXT4_DIR_REC_LEN(2) - infosize; | 551 | EXT4_DIR_REC_LEN(2) - infosize; |
559 | 552 | ||
560 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | 553 | if (ext4_has_metadata_csum(dir->i_sb)) |
561 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
562 | entry_space -= sizeof(struct dx_tail); | 554 | entry_space -= sizeof(struct dx_tail); |
563 | return entry_space / sizeof(struct dx_entry); | 555 | return entry_space / sizeof(struct dx_entry); |
564 | } | 556 | } |
@@ -567,8 +559,7 @@ static inline unsigned dx_node_limit(struct inode *dir) | |||
567 | { | 559 | { |
568 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); | 560 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); |
569 | 561 | ||
570 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | 562 | if (ext4_has_metadata_csum(dir->i_sb)) |
571 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
572 | entry_space -= sizeof(struct dx_tail); | 563 | entry_space -= sizeof(struct dx_tail); |
573 | return entry_space / sizeof(struct dx_entry); | 564 | return entry_space / sizeof(struct dx_entry); |
574 | } | 565 | } |
@@ -641,7 +632,9 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, | |||
641 | u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; | 632 | u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; |
642 | struct stats stats; | 633 | struct stats stats; |
643 | printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); | 634 | printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); |
644 | if (!(bh = ext4_bread (NULL,dir, block, 0,&err))) continue; | 635 | bh = ext4_bread(NULL,dir, block, 0); |
636 | if (!bh || IS_ERR(bh)) | ||
637 | continue; | ||
645 | stats = levels? | 638 | stats = levels? |
646 | dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): | 639 | dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): |
647 | dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0); | 640 | dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0); |
@@ -669,29 +662,25 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, | |||
669 | */ | 662 | */ |
670 | static struct dx_frame * | 663 | static struct dx_frame * |
671 | dx_probe(const struct qstr *d_name, struct inode *dir, | 664 | dx_probe(const struct qstr *d_name, struct inode *dir, |
672 | struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) | 665 | struct dx_hash_info *hinfo, struct dx_frame *frame_in) |
673 | { | 666 | { |
674 | unsigned count, indirect; | 667 | unsigned count, indirect; |
675 | struct dx_entry *at, *entries, *p, *q, *m; | 668 | struct dx_entry *at, *entries, *p, *q, *m; |
676 | struct dx_root *root; | 669 | struct dx_root *root; |
677 | struct buffer_head *bh; | ||
678 | struct dx_frame *frame = frame_in; | 670 | struct dx_frame *frame = frame_in; |
671 | struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); | ||
679 | u32 hash; | 672 | u32 hash; |
680 | 673 | ||
681 | frame->bh = NULL; | 674 | frame->bh = ext4_read_dirblock(dir, 0, INDEX); |
682 | bh = ext4_read_dirblock(dir, 0, INDEX); | 675 | if (IS_ERR(frame->bh)) |
683 | if (IS_ERR(bh)) { | 676 | return (struct dx_frame *) frame->bh; |
684 | *err = PTR_ERR(bh); | 677 | |
685 | goto fail; | 678 | root = (struct dx_root *) frame->bh->b_data; |
686 | } | ||
687 | root = (struct dx_root *) bh->b_data; | ||
688 | if (root->info.hash_version != DX_HASH_TEA && | 679 | if (root->info.hash_version != DX_HASH_TEA && |
689 | root->info.hash_version != DX_HASH_HALF_MD4 && | 680 | root->info.hash_version != DX_HASH_HALF_MD4 && |
690 | root->info.hash_version != DX_HASH_LEGACY) { | 681 | root->info.hash_version != DX_HASH_LEGACY) { |
691 | ext4_warning(dir->i_sb, "Unrecognised inode hash code %d", | 682 | ext4_warning(dir->i_sb, "Unrecognised inode hash code %d", |
692 | root->info.hash_version); | 683 | root->info.hash_version); |
693 | brelse(bh); | ||
694 | *err = ERR_BAD_DX_DIR; | ||
695 | goto fail; | 684 | goto fail; |
696 | } | 685 | } |
697 | hinfo->hash_version = root->info.hash_version; | 686 | hinfo->hash_version = root->info.hash_version; |
@@ -705,16 +694,12 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
705 | if (root->info.unused_flags & 1) { | 694 | if (root->info.unused_flags & 1) { |
706 | ext4_warning(dir->i_sb, "Unimplemented inode hash flags: %#06x", | 695 | ext4_warning(dir->i_sb, "Unimplemented inode hash flags: %#06x", |
707 | root->info.unused_flags); | 696 | root->info.unused_flags); |
708 | brelse(bh); | ||
709 | *err = ERR_BAD_DX_DIR; | ||
710 | goto fail; | 697 | goto fail; |
711 | } | 698 | } |
712 | 699 | ||
713 | if ((indirect = root->info.indirect_levels) > 1) { | 700 | if ((indirect = root->info.indirect_levels) > 1) { |
714 | ext4_warning(dir->i_sb, "Unimplemented inode hash depth: %#06x", | 701 | ext4_warning(dir->i_sb, "Unimplemented inode hash depth: %#06x", |
715 | root->info.indirect_levels); | 702 | root->info.indirect_levels); |
716 | brelse(bh); | ||
717 | *err = ERR_BAD_DX_DIR; | ||
718 | goto fail; | 703 | goto fail; |
719 | } | 704 | } |
720 | 705 | ||
@@ -724,27 +709,21 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
724 | if (dx_get_limit(entries) != dx_root_limit(dir, | 709 | if (dx_get_limit(entries) != dx_root_limit(dir, |
725 | root->info.info_length)) { | 710 | root->info.info_length)) { |
726 | ext4_warning(dir->i_sb, "dx entry: limit != root limit"); | 711 | ext4_warning(dir->i_sb, "dx entry: limit != root limit"); |
727 | brelse(bh); | ||
728 | *err = ERR_BAD_DX_DIR; | ||
729 | goto fail; | 712 | goto fail; |
730 | } | 713 | } |
731 | 714 | ||
732 | dxtrace(printk("Look up %x", hash)); | 715 | dxtrace(printk("Look up %x", hash)); |
733 | while (1) | 716 | while (1) { |
734 | { | ||
735 | count = dx_get_count(entries); | 717 | count = dx_get_count(entries); |
736 | if (!count || count > dx_get_limit(entries)) { | 718 | if (!count || count > dx_get_limit(entries)) { |
737 | ext4_warning(dir->i_sb, | 719 | ext4_warning(dir->i_sb, |
738 | "dx entry: no count or count > limit"); | 720 | "dx entry: no count or count > limit"); |
739 | brelse(bh); | 721 | goto fail; |
740 | *err = ERR_BAD_DX_DIR; | ||
741 | goto fail2; | ||
742 | } | 722 | } |
743 | 723 | ||
744 | p = entries + 1; | 724 | p = entries + 1; |
745 | q = entries + count - 1; | 725 | q = entries + count - 1; |
746 | while (p <= q) | 726 | while (p <= q) { |
747 | { | ||
748 | m = p + (q - p)/2; | 727 | m = p + (q - p)/2; |
749 | dxtrace(printk(".")); | 728 | dxtrace(printk(".")); |
750 | if (dx_get_hash(m) > hash) | 729 | if (dx_get_hash(m) > hash) |
@@ -753,8 +732,7 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
753 | p = m + 1; | 732 | p = m + 1; |
754 | } | 733 | } |
755 | 734 | ||
756 | if (0) // linear search cross check | 735 | if (0) { // linear search cross check |
757 | { | ||
758 | unsigned n = count - 1; | 736 | unsigned n = count - 1; |
759 | at = entries; | 737 | at = entries; |
760 | while (n--) | 738 | while (n--) |
@@ -771,38 +749,35 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
771 | 749 | ||
772 | at = p - 1; | 750 | at = p - 1; |
773 | dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at))); | 751 | dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at))); |
774 | frame->bh = bh; | ||
775 | frame->entries = entries; | 752 | frame->entries = entries; |
776 | frame->at = at; | 753 | frame->at = at; |
777 | if (!indirect--) return frame; | 754 | if (!indirect--) |
778 | bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX); | 755 | return frame; |
779 | if (IS_ERR(bh)) { | 756 | frame++; |
780 | *err = PTR_ERR(bh); | 757 | frame->bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX); |
781 | goto fail2; | 758 | if (IS_ERR(frame->bh)) { |
759 | ret_err = (struct dx_frame *) frame->bh; | ||
760 | frame->bh = NULL; | ||
761 | goto fail; | ||
782 | } | 762 | } |
783 | entries = ((struct dx_node *) bh->b_data)->entries; | 763 | entries = ((struct dx_node *) frame->bh->b_data)->entries; |
784 | 764 | ||
785 | if (dx_get_limit(entries) != dx_node_limit (dir)) { | 765 | if (dx_get_limit(entries) != dx_node_limit (dir)) { |
786 | ext4_warning(dir->i_sb, | 766 | ext4_warning(dir->i_sb, |
787 | "dx entry: limit != node limit"); | 767 | "dx entry: limit != node limit"); |
788 | brelse(bh); | 768 | goto fail; |
789 | *err = ERR_BAD_DX_DIR; | ||
790 | goto fail2; | ||
791 | } | 769 | } |
792 | frame++; | ||
793 | frame->bh = NULL; | ||
794 | } | 770 | } |
795 | fail2: | 771 | fail: |
796 | while (frame >= frame_in) { | 772 | while (frame >= frame_in) { |
797 | brelse(frame->bh); | 773 | brelse(frame->bh); |
798 | frame--; | 774 | frame--; |
799 | } | 775 | } |
800 | fail: | 776 | if (ret_err == ERR_PTR(ERR_BAD_DX_DIR)) |
801 | if (*err == ERR_BAD_DX_DIR) | ||
802 | ext4_warning(dir->i_sb, | 777 | ext4_warning(dir->i_sb, |
803 | "Corrupt dir inode %lu, running e2fsck is " | 778 | "Corrupt dir inode %lu, running e2fsck is " |
804 | "recommended.", dir->i_ino); | 779 | "recommended.", dir->i_ino); |
805 | return NULL; | 780 | return ret_err; |
806 | } | 781 | } |
807 | 782 | ||
808 | static void dx_release (struct dx_frame *frames) | 783 | static void dx_release (struct dx_frame *frames) |
@@ -988,9 +963,9 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, | |||
988 | } | 963 | } |
989 | hinfo.hash = start_hash; | 964 | hinfo.hash = start_hash; |
990 | hinfo.minor_hash = 0; | 965 | hinfo.minor_hash = 0; |
991 | frame = dx_probe(NULL, dir, &hinfo, frames, &err); | 966 | frame = dx_probe(NULL, dir, &hinfo, frames); |
992 | if (!frame) | 967 | if (IS_ERR(frame)) |
993 | return err; | 968 | return PTR_ERR(frame); |
994 | 969 | ||
995 | /* Add '.' and '..' from the htree header */ | 970 | /* Add '.' and '..' from the htree header */ |
996 | if (!start_hash && !start_minor_hash) { | 971 | if (!start_hash && !start_minor_hash) { |
@@ -1227,8 +1202,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, | |||
1227 | buffer */ | 1202 | buffer */ |
1228 | int num = 0; | 1203 | int num = 0; |
1229 | ext4_lblk_t nblocks; | 1204 | ext4_lblk_t nblocks; |
1230 | int i, err = 0; | 1205 | int i, namelen; |
1231 | int namelen; | ||
1232 | 1206 | ||
1233 | *res_dir = NULL; | 1207 | *res_dir = NULL; |
1234 | sb = dir->i_sb; | 1208 | sb = dir->i_sb; |
@@ -1258,17 +1232,13 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, | |||
1258 | goto restart; | 1232 | goto restart; |
1259 | } | 1233 | } |
1260 | if (is_dx(dir)) { | 1234 | if (is_dx(dir)) { |
1261 | bh = ext4_dx_find_entry(dir, d_name, res_dir, &err); | 1235 | bh = ext4_dx_find_entry(dir, d_name, res_dir); |
1262 | /* | 1236 | /* |
1263 | * On success, or if the error was file not found, | 1237 | * On success, or if the error was file not found, |
1264 | * return. Otherwise, fall back to doing a search the | 1238 | * return. Otherwise, fall back to doing a search the |
1265 | * old fashioned way. | 1239 | * old fashioned way. |
1266 | */ | 1240 | */ |
1267 | if (err == -ENOENT) | 1241 | if (!IS_ERR(bh) || PTR_ERR(bh) != ERR_BAD_DX_DIR) |
1268 | return NULL; | ||
1269 | if (err && err != ERR_BAD_DX_DIR) | ||
1270 | return ERR_PTR(err); | ||
1271 | if (bh) | ||
1272 | return bh; | 1242 | return bh; |
1273 | dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " | 1243 | dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " |
1274 | "falling back\n")); | 1244 | "falling back\n")); |
@@ -1298,10 +1268,10 @@ restart: | |||
1298 | break; | 1268 | break; |
1299 | } | 1269 | } |
1300 | num++; | 1270 | num++; |
1301 | bh = ext4_getblk(NULL, dir, b++, 0, &err); | 1271 | bh = ext4_getblk(NULL, dir, b++, 0); |
1302 | if (unlikely(err)) { | 1272 | if (unlikely(IS_ERR(bh))) { |
1303 | if (ra_max == 0) | 1273 | if (ra_max == 0) |
1304 | return ERR_PTR(err); | 1274 | return bh; |
1305 | break; | 1275 | break; |
1306 | } | 1276 | } |
1307 | bh_use[ra_max] = bh; | 1277 | bh_use[ra_max] = bh; |
@@ -1366,7 +1336,7 @@ cleanup_and_exit: | |||
1366 | } | 1336 | } |
1367 | 1337 | ||
1368 | static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name, | 1338 | static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name, |
1369 | struct ext4_dir_entry_2 **res_dir, int *err) | 1339 | struct ext4_dir_entry_2 **res_dir) |
1370 | { | 1340 | { |
1371 | struct super_block * sb = dir->i_sb; | 1341 | struct super_block * sb = dir->i_sb; |
1372 | struct dx_hash_info hinfo; | 1342 | struct dx_hash_info hinfo; |
@@ -1375,25 +1345,23 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q | |||
1375 | ext4_lblk_t block; | 1345 | ext4_lblk_t block; |
1376 | int retval; | 1346 | int retval; |
1377 | 1347 | ||
1378 | if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err))) | 1348 | frame = dx_probe(d_name, dir, &hinfo, frames); |
1379 | return NULL; | 1349 | if (IS_ERR(frame)) |
1350 | return (struct buffer_head *) frame; | ||
1380 | do { | 1351 | do { |
1381 | block = dx_get_block(frame->at); | 1352 | block = dx_get_block(frame->at); |
1382 | bh = ext4_read_dirblock(dir, block, DIRENT); | 1353 | bh = ext4_read_dirblock(dir, block, DIRENT); |
1383 | if (IS_ERR(bh)) { | 1354 | if (IS_ERR(bh)) |
1384 | *err = PTR_ERR(bh); | ||
1385 | goto errout; | 1355 | goto errout; |
1386 | } | 1356 | |
1387 | retval = search_dirblock(bh, dir, d_name, | 1357 | retval = search_dirblock(bh, dir, d_name, |
1388 | block << EXT4_BLOCK_SIZE_BITS(sb), | 1358 | block << EXT4_BLOCK_SIZE_BITS(sb), |
1389 | res_dir); | 1359 | res_dir); |
1390 | if (retval == 1) { /* Success! */ | 1360 | if (retval == 1) |
1391 | dx_release(frames); | 1361 | goto success; |
1392 | return bh; | ||
1393 | } | ||
1394 | brelse(bh); | 1362 | brelse(bh); |
1395 | if (retval == -1) { | 1363 | if (retval == -1) { |
1396 | *err = ERR_BAD_DX_DIR; | 1364 | bh = ERR_PTR(ERR_BAD_DX_DIR); |
1397 | goto errout; | 1365 | goto errout; |
1398 | } | 1366 | } |
1399 | 1367 | ||
@@ -1402,18 +1370,19 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q | |||
1402 | frames, NULL); | 1370 | frames, NULL); |
1403 | if (retval < 0) { | 1371 | if (retval < 0) { |
1404 | ext4_warning(sb, | 1372 | ext4_warning(sb, |
1405 | "error reading index page in directory #%lu", | 1373 | "error %d reading index page in directory #%lu", |
1406 | dir->i_ino); | 1374 | retval, dir->i_ino); |
1407 | *err = retval; | 1375 | bh = ERR_PTR(retval); |
1408 | goto errout; | 1376 | goto errout; |
1409 | } | 1377 | } |
1410 | } while (retval == 1); | 1378 | } while (retval == 1); |
1411 | 1379 | ||
1412 | *err = -ENOENT; | 1380 | bh = NULL; |
1413 | errout: | 1381 | errout: |
1414 | dxtrace(printk(KERN_DEBUG "%s not found\n", d_name->name)); | 1382 | dxtrace(printk(KERN_DEBUG "%s not found\n", d_name->name)); |
1415 | dx_release (frames); | 1383 | success: |
1416 | return NULL; | 1384 | dx_release(frames); |
1385 | return bh; | ||
1417 | } | 1386 | } |
1418 | 1387 | ||
1419 | static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | 1388 | static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) |
@@ -1441,7 +1410,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi | |||
1441 | dentry); | 1410 | dentry); |
1442 | return ERR_PTR(-EIO); | 1411 | return ERR_PTR(-EIO); |
1443 | } | 1412 | } |
1444 | inode = ext4_iget(dir->i_sb, ino); | 1413 | inode = ext4_iget_normal(dir->i_sb, ino); |
1445 | if (inode == ERR_PTR(-ESTALE)) { | 1414 | if (inode == ERR_PTR(-ESTALE)) { |
1446 | EXT4_ERROR_INODE(dir, | 1415 | EXT4_ERROR_INODE(dir, |
1447 | "deleted inode referenced: %u", | 1416 | "deleted inode referenced: %u", |
@@ -1474,7 +1443,7 @@ struct dentry *ext4_get_parent(struct dentry *child) | |||
1474 | return ERR_PTR(-EIO); | 1443 | return ERR_PTR(-EIO); |
1475 | } | 1444 | } |
1476 | 1445 | ||
1477 | return d_obtain_alias(ext4_iget(child->d_inode->i_sb, ino)); | 1446 | return d_obtain_alias(ext4_iget_normal(child->d_inode->i_sb, ino)); |
1478 | } | 1447 | } |
1479 | 1448 | ||
1480 | /* | 1449 | /* |
@@ -1533,7 +1502,7 @@ static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize) | |||
1533 | */ | 1502 | */ |
1534 | static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | 1503 | static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, |
1535 | struct buffer_head **bh,struct dx_frame *frame, | 1504 | struct buffer_head **bh,struct dx_frame *frame, |
1536 | struct dx_hash_info *hinfo, int *error) | 1505 | struct dx_hash_info *hinfo) |
1537 | { | 1506 | { |
1538 | unsigned blocksize = dir->i_sb->s_blocksize; | 1507 | unsigned blocksize = dir->i_sb->s_blocksize; |
1539 | unsigned count, continued; | 1508 | unsigned count, continued; |
@@ -1548,16 +1517,14 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1548 | int csum_size = 0; | 1517 | int csum_size = 0; |
1549 | int err = 0, i; | 1518 | int err = 0, i; |
1550 | 1519 | ||
1551 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | 1520 | if (ext4_has_metadata_csum(dir->i_sb)) |
1552 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1553 | csum_size = sizeof(struct ext4_dir_entry_tail); | 1521 | csum_size = sizeof(struct ext4_dir_entry_tail); |
1554 | 1522 | ||
1555 | bh2 = ext4_append(handle, dir, &newblock); | 1523 | bh2 = ext4_append(handle, dir, &newblock); |
1556 | if (IS_ERR(bh2)) { | 1524 | if (IS_ERR(bh2)) { |
1557 | brelse(*bh); | 1525 | brelse(*bh); |
1558 | *bh = NULL; | 1526 | *bh = NULL; |
1559 | *error = PTR_ERR(bh2); | 1527 | return (struct ext4_dir_entry_2 *) bh2; |
1560 | return NULL; | ||
1561 | } | 1528 | } |
1562 | 1529 | ||
1563 | BUFFER_TRACE(*bh, "get_write_access"); | 1530 | BUFFER_TRACE(*bh, "get_write_access"); |
@@ -1617,8 +1584,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1617 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); | 1584 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); |
1618 | 1585 | ||
1619 | /* Which block gets the new entry? */ | 1586 | /* Which block gets the new entry? */ |
1620 | if (hinfo->hash >= hash2) | 1587 | if (hinfo->hash >= hash2) { |
1621 | { | ||
1622 | swap(*bh, bh2); | 1588 | swap(*bh, bh2); |
1623 | de = de2; | 1589 | de = de2; |
1624 | } | 1590 | } |
@@ -1638,8 +1604,7 @@ journal_error: | |||
1638 | brelse(bh2); | 1604 | brelse(bh2); |
1639 | *bh = NULL; | 1605 | *bh = NULL; |
1640 | ext4_std_error(dir->i_sb, err); | 1606 | ext4_std_error(dir->i_sb, err); |
1641 | *error = err; | 1607 | return ERR_PTR(err); |
1642 | return NULL; | ||
1643 | } | 1608 | } |
1644 | 1609 | ||
1645 | int ext4_find_dest_de(struct inode *dir, struct inode *inode, | 1610 | int ext4_find_dest_de(struct inode *dir, struct inode *inode, |
@@ -1718,8 +1683,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1718 | int csum_size = 0; | 1683 | int csum_size = 0; |
1719 | int err; | 1684 | int err; |
1720 | 1685 | ||
1721 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 1686 | if (ext4_has_metadata_csum(inode->i_sb)) |
1722 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1723 | csum_size = sizeof(struct ext4_dir_entry_tail); | 1687 | csum_size = sizeof(struct ext4_dir_entry_tail); |
1724 | 1688 | ||
1725 | if (!de) { | 1689 | if (!de) { |
@@ -1786,8 +1750,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1786 | struct fake_dirent *fde; | 1750 | struct fake_dirent *fde; |
1787 | int csum_size = 0; | 1751 | int csum_size = 0; |
1788 | 1752 | ||
1789 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 1753 | if (ext4_has_metadata_csum(inode->i_sb)) |
1790 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1791 | csum_size = sizeof(struct ext4_dir_entry_tail); | 1754 | csum_size = sizeof(struct ext4_dir_entry_tail); |
1792 | 1755 | ||
1793 | blocksize = dir->i_sb->s_blocksize; | 1756 | blocksize = dir->i_sb->s_blocksize; |
@@ -1853,31 +1816,39 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1853 | hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; | 1816 | hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; |
1854 | hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; | 1817 | hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; |
1855 | ext4fs_dirhash(name, namelen, &hinfo); | 1818 | ext4fs_dirhash(name, namelen, &hinfo); |
1819 | memset(frames, 0, sizeof(frames)); | ||
1856 | frame = frames; | 1820 | frame = frames; |
1857 | frame->entries = entries; | 1821 | frame->entries = entries; |
1858 | frame->at = entries; | 1822 | frame->at = entries; |
1859 | frame->bh = bh; | 1823 | frame->bh = bh; |
1860 | bh = bh2; | 1824 | bh = bh2; |
1861 | 1825 | ||
1862 | ext4_handle_dirty_dx_node(handle, dir, frame->bh); | 1826 | retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1863 | ext4_handle_dirty_dirent_node(handle, dir, bh); | 1827 | if (retval) |
1828 | goto out_frames; | ||
1829 | retval = ext4_handle_dirty_dirent_node(handle, dir, bh); | ||
1830 | if (retval) | ||
1831 | goto out_frames; | ||
1864 | 1832 | ||
1865 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); | 1833 | de = do_split(handle,dir, &bh, frame, &hinfo); |
1866 | if (!de) { | 1834 | if (IS_ERR(de)) { |
1867 | /* | 1835 | retval = PTR_ERR(de); |
1868 | * Even if the block split failed, we have to properly write | 1836 | goto out_frames; |
1869 | * out all the changes we did so far. Otherwise we can end up | ||
1870 | * with corrupted filesystem. | ||
1871 | */ | ||
1872 | ext4_mark_inode_dirty(handle, dir); | ||
1873 | dx_release(frames); | ||
1874 | return retval; | ||
1875 | } | 1837 | } |
1876 | dx_release(frames); | 1838 | dx_release(frames); |
1877 | 1839 | ||
1878 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); | 1840 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1879 | brelse(bh); | 1841 | brelse(bh); |
1880 | return retval; | 1842 | return retval; |
1843 | out_frames: | ||
1844 | /* | ||
1845 | * Even if the block split failed, we have to properly write | ||
1846 | * out all the changes we did so far. Otherwise we can end up | ||
1847 | * with corrupted filesystem. | ||
1848 | */ | ||
1849 | ext4_mark_inode_dirty(handle, dir); | ||
1850 | dx_release(frames); | ||
1851 | return retval; | ||
1881 | } | 1852 | } |
1882 | 1853 | ||
1883 | /* | 1854 | /* |
@@ -1904,8 +1875,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1904 | ext4_lblk_t block, blocks; | 1875 | ext4_lblk_t block, blocks; |
1905 | int csum_size = 0; | 1876 | int csum_size = 0; |
1906 | 1877 | ||
1907 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 1878 | if (ext4_has_metadata_csum(inode->i_sb)) |
1908 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1909 | csum_size = sizeof(struct ext4_dir_entry_tail); | 1879 | csum_size = sizeof(struct ext4_dir_entry_tail); |
1910 | 1880 | ||
1911 | sb = dir->i_sb; | 1881 | sb = dir->i_sb; |
@@ -1982,9 +1952,9 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1982 | struct ext4_dir_entry_2 *de; | 1952 | struct ext4_dir_entry_2 *de; |
1983 | int err; | 1953 | int err; |
1984 | 1954 | ||
1985 | frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); | 1955 | frame = dx_probe(&dentry->d_name, dir, &hinfo, frames); |
1986 | if (!frame) | 1956 | if (IS_ERR(frame)) |
1987 | return err; | 1957 | return PTR_ERR(frame); |
1988 | entries = frame->entries; | 1958 | entries = frame->entries; |
1989 | at = frame->at; | 1959 | at = frame->at; |
1990 | bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT); | 1960 | bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT); |
@@ -2095,9 +2065,11 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
2095 | goto cleanup; | 2065 | goto cleanup; |
2096 | } | 2066 | } |
2097 | } | 2067 | } |
2098 | de = do_split(handle, dir, &bh, frame, &hinfo, &err); | 2068 | de = do_split(handle, dir, &bh, frame, &hinfo); |
2099 | if (!de) | 2069 | if (IS_ERR(de)) { |
2070 | err = PTR_ERR(de); | ||
2100 | goto cleanup; | 2071 | goto cleanup; |
2072 | } | ||
2101 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); | 2073 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); |
2102 | goto cleanup; | 2074 | goto cleanup; |
2103 | 2075 | ||
@@ -2167,8 +2139,7 @@ static int ext4_delete_entry(handle_t *handle, | |||
2167 | return err; | 2139 | return err; |
2168 | } | 2140 | } |
2169 | 2141 | ||
2170 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | 2142 | if (ext4_has_metadata_csum(dir->i_sb)) |
2171 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2172 | csum_size = sizeof(struct ext4_dir_entry_tail); | 2143 | csum_size = sizeof(struct ext4_dir_entry_tail); |
2173 | 2144 | ||
2174 | BUFFER_TRACE(bh, "get_write_access"); | 2145 | BUFFER_TRACE(bh, "get_write_access"); |
@@ -2387,8 +2358,7 @@ static int ext4_init_new_dir(handle_t *handle, struct inode *dir, | |||
2387 | int csum_size = 0; | 2358 | int csum_size = 0; |
2388 | int err; | 2359 | int err; |
2389 | 2360 | ||
2390 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | 2361 | if (ext4_has_metadata_csum(dir->i_sb)) |
2391 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2392 | csum_size = sizeof(struct ext4_dir_entry_tail); | 2362 | csum_size = sizeof(struct ext4_dir_entry_tail); |
2393 | 2363 | ||
2394 | if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { | 2364 | if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { |
@@ -2403,10 +2373,6 @@ static int ext4_init_new_dir(handle_t *handle, struct inode *dir, | |||
2403 | dir_block = ext4_append(handle, inode, &block); | 2373 | dir_block = ext4_append(handle, inode, &block); |
2404 | if (IS_ERR(dir_block)) | 2374 | if (IS_ERR(dir_block)) |
2405 | return PTR_ERR(dir_block); | 2375 | return PTR_ERR(dir_block); |
2406 | BUFFER_TRACE(dir_block, "get_write_access"); | ||
2407 | err = ext4_journal_get_write_access(handle, dir_block); | ||
2408 | if (err) | ||
2409 | goto out; | ||
2410 | de = (struct ext4_dir_entry_2 *)dir_block->b_data; | 2376 | de = (struct ext4_dir_entry_2 *)dir_block->b_data; |
2411 | ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); | 2377 | ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); |
2412 | set_nlink(inode, 2); | 2378 | set_nlink(inode, 2); |
@@ -2573,7 +2539,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2573 | int err = 0, rc; | 2539 | int err = 0, rc; |
2574 | bool dirty = false; | 2540 | bool dirty = false; |
2575 | 2541 | ||
2576 | if (!sbi->s_journal) | 2542 | if (!sbi->s_journal || is_bad_inode(inode)) |
2577 | return 0; | 2543 | return 0; |
2578 | 2544 | ||
2579 | WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) && | 2545 | WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) && |
@@ -3190,6 +3156,39 @@ static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) | |||
3190 | } | 3156 | } |
3191 | } | 3157 | } |
3192 | 3158 | ||
3159 | static struct inode *ext4_whiteout_for_rename(struct ext4_renament *ent, | ||
3160 | int credits, handle_t **h) | ||
3161 | { | ||
3162 | struct inode *wh; | ||
3163 | handle_t *handle; | ||
3164 | int retries = 0; | ||
3165 | |||
3166 | /* | ||
3167 | * for inode block, sb block, group summaries, | ||
3168 | * and inode bitmap | ||
3169 | */ | ||
3170 | credits += (EXT4_MAXQUOTAS_TRANS_BLOCKS(ent->dir->i_sb) + | ||
3171 | EXT4_XATTR_TRANS_BLOCKS + 4); | ||
3172 | retry: | ||
3173 | wh = ext4_new_inode_start_handle(ent->dir, S_IFCHR | WHITEOUT_MODE, | ||
3174 | &ent->dentry->d_name, 0, NULL, | ||
3175 | EXT4_HT_DIR, credits); | ||
3176 | |||
3177 | handle = ext4_journal_current_handle(); | ||
3178 | if (IS_ERR(wh)) { | ||
3179 | if (handle) | ||
3180 | ext4_journal_stop(handle); | ||
3181 | if (PTR_ERR(wh) == -ENOSPC && | ||
3182 | ext4_should_retry_alloc(ent->dir->i_sb, &retries)) | ||
3183 | goto retry; | ||
3184 | } else { | ||
3185 | *h = handle; | ||
3186 | init_special_inode(wh, wh->i_mode, WHITEOUT_DEV); | ||
3187 | wh->i_op = &ext4_special_inode_operations; | ||
3188 | } | ||
3189 | return wh; | ||
3190 | } | ||
3191 | |||
3193 | /* | 3192 | /* |
3194 | * Anybody can rename anything with this: the permission checks are left to the | 3193 | * Anybody can rename anything with this: the permission checks are left to the |
3195 | * higher-level routines. | 3194 | * higher-level routines. |
@@ -3199,7 +3198,8 @@ static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) | |||
3199 | * This comes from rename(const char *oldpath, const char *newpath) | 3198 | * This comes from rename(const char *oldpath, const char *newpath) |
3200 | */ | 3199 | */ |
3201 | static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | 3200 | static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, |
3202 | struct inode *new_dir, struct dentry *new_dentry) | 3201 | struct inode *new_dir, struct dentry *new_dentry, |
3202 | unsigned int flags) | ||
3203 | { | 3203 | { |
3204 | handle_t *handle = NULL; | 3204 | handle_t *handle = NULL; |
3205 | struct ext4_renament old = { | 3205 | struct ext4_renament old = { |
@@ -3214,6 +3214,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3214 | }; | 3214 | }; |
3215 | int force_reread; | 3215 | int force_reread; |
3216 | int retval; | 3216 | int retval; |
3217 | struct inode *whiteout = NULL; | ||
3218 | int credits; | ||
3219 | u8 old_file_type; | ||
3217 | 3220 | ||
3218 | dquot_initialize(old.dir); | 3221 | dquot_initialize(old.dir); |
3219 | dquot_initialize(new.dir); | 3222 | dquot_initialize(new.dir); |
@@ -3252,11 +3255,17 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3252 | if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) | 3255 | if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) |
3253 | ext4_alloc_da_blocks(old.inode); | 3256 | ext4_alloc_da_blocks(old.inode); |
3254 | 3257 | ||
3255 | handle = ext4_journal_start(old.dir, EXT4_HT_DIR, | 3258 | credits = (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + |
3256 | (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + | 3259 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2); |
3257 | EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); | 3260 | if (!(flags & RENAME_WHITEOUT)) { |
3258 | if (IS_ERR(handle)) | 3261 | handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits); |
3259 | return PTR_ERR(handle); | 3262 | if (IS_ERR(handle)) |
3263 | return PTR_ERR(handle); | ||
3264 | } else { | ||
3265 | whiteout = ext4_whiteout_for_rename(&old, credits, &handle); | ||
3266 | if (IS_ERR(whiteout)) | ||
3267 | return PTR_ERR(whiteout); | ||
3268 | } | ||
3260 | 3269 | ||
3261 | if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) | 3270 | if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) |
3262 | ext4_handle_sync(handle); | 3271 | ext4_handle_sync(handle); |
@@ -3284,13 +3293,26 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3284 | */ | 3293 | */ |
3285 | force_reread = (new.dir->i_ino == old.dir->i_ino && | 3294 | force_reread = (new.dir->i_ino == old.dir->i_ino && |
3286 | ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); | 3295 | ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); |
3296 | |||
3297 | old_file_type = old.de->file_type; | ||
3298 | if (whiteout) { | ||
3299 | /* | ||
3300 | * Do this before adding a new entry, so the old entry is sure | ||
3301 | * to be still pointing to the valid old entry. | ||
3302 | */ | ||
3303 | retval = ext4_setent(handle, &old, whiteout->i_ino, | ||
3304 | EXT4_FT_CHRDEV); | ||
3305 | if (retval) | ||
3306 | goto end_rename; | ||
3307 | ext4_mark_inode_dirty(handle, whiteout); | ||
3308 | } | ||
3287 | if (!new.bh) { | 3309 | if (!new.bh) { |
3288 | retval = ext4_add_entry(handle, new.dentry, old.inode); | 3310 | retval = ext4_add_entry(handle, new.dentry, old.inode); |
3289 | if (retval) | 3311 | if (retval) |
3290 | goto end_rename; | 3312 | goto end_rename; |
3291 | } else { | 3313 | } else { |
3292 | retval = ext4_setent(handle, &new, | 3314 | retval = ext4_setent(handle, &new, |
3293 | old.inode->i_ino, old.de->file_type); | 3315 | old.inode->i_ino, old_file_type); |
3294 | if (retval) | 3316 | if (retval) |
3295 | goto end_rename; | 3317 | goto end_rename; |
3296 | } | 3318 | } |
@@ -3305,10 +3327,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3305 | old.inode->i_ctime = ext4_current_time(old.inode); | 3327 | old.inode->i_ctime = ext4_current_time(old.inode); |
3306 | ext4_mark_inode_dirty(handle, old.inode); | 3328 | ext4_mark_inode_dirty(handle, old.inode); |
3307 | 3329 | ||
3308 | /* | 3330 | if (!whiteout) { |
3309 | * ok, that's it | 3331 | /* |
3310 | */ | 3332 | * ok, that's it |
3311 | ext4_rename_delete(handle, &old, force_reread); | 3333 | */ |
3334 | ext4_rename_delete(handle, &old, force_reread); | ||
3335 | } | ||
3312 | 3336 | ||
3313 | if (new.inode) { | 3337 | if (new.inode) { |
3314 | ext4_dec_count(handle, new.inode); | 3338 | ext4_dec_count(handle, new.inode); |
@@ -3344,6 +3368,12 @@ end_rename: | |||
3344 | brelse(old.dir_bh); | 3368 | brelse(old.dir_bh); |
3345 | brelse(old.bh); | 3369 | brelse(old.bh); |
3346 | brelse(new.bh); | 3370 | brelse(new.bh); |
3371 | if (whiteout) { | ||
3372 | if (retval) | ||
3373 | drop_nlink(whiteout); | ||
3374 | unlock_new_inode(whiteout); | ||
3375 | iput(whiteout); | ||
3376 | } | ||
3347 | if (handle) | 3377 | if (handle) |
3348 | ext4_journal_stop(handle); | 3378 | ext4_journal_stop(handle); |
3349 | return retval; | 3379 | return retval; |
@@ -3476,18 +3506,15 @@ static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry, | |||
3476 | struct inode *new_dir, struct dentry *new_dentry, | 3506 | struct inode *new_dir, struct dentry *new_dentry, |
3477 | unsigned int flags) | 3507 | unsigned int flags) |
3478 | { | 3508 | { |
3479 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) | 3509 | if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) |
3480 | return -EINVAL; | 3510 | return -EINVAL; |
3481 | 3511 | ||
3482 | if (flags & RENAME_EXCHANGE) { | 3512 | if (flags & RENAME_EXCHANGE) { |
3483 | return ext4_cross_rename(old_dir, old_dentry, | 3513 | return ext4_cross_rename(old_dir, old_dentry, |
3484 | new_dir, new_dentry); | 3514 | new_dir, new_dentry); |
3485 | } | 3515 | } |
3486 | /* | 3516 | |
3487 | * Existence checking was done by the VFS, otherwise "RENAME_NOREPLACE" | 3517 | return ext4_rename(old_dir, old_dentry, new_dir, new_dentry, flags); |
3488 | * is equivalent to regular rename. | ||
3489 | */ | ||
3490 | return ext4_rename(old_dir, old_dentry, new_dir, new_dentry); | ||
3491 | } | 3518 | } |
3492 | 3519 | ||
3493 | /* | 3520 | /* |