diff options
| -rw-r--r-- | fs/ext4/namei.c | 68 |
1 files changed, 33 insertions, 35 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index a1f72d217c7c..5295a9225cf9 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
| @@ -159,7 +159,7 @@ static void dx_set_count(struct dx_entry *entries, unsigned value); | |||
| 159 | static void dx_set_limit(struct dx_entry *entries, unsigned value); | 159 | static void dx_set_limit(struct dx_entry *entries, unsigned value); |
| 160 | static unsigned dx_root_limit(struct inode *dir, unsigned infosize); | 160 | static unsigned dx_root_limit(struct inode *dir, unsigned infosize); |
| 161 | static unsigned dx_node_limit(struct inode *dir); | 161 | static unsigned dx_node_limit(struct inode *dir); |
| 162 | static struct dx_frame *dx_probe(struct dentry *dentry, | 162 | static struct dx_frame *dx_probe(const struct qstr *d_name, |
| 163 | struct inode *dir, | 163 | struct inode *dir, |
| 164 | struct dx_hash_info *hinfo, | 164 | struct dx_hash_info *hinfo, |
| 165 | struct dx_frame *frame, | 165 | struct dx_frame *frame, |
| @@ -177,8 +177,10 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash, | |||
| 177 | struct dx_frame *frame, | 177 | struct dx_frame *frame, |
| 178 | struct dx_frame *frames, | 178 | struct dx_frame *frames, |
| 179 | __u32 *start_hash); | 179 | __u32 *start_hash); |
| 180 | static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, | 180 | static struct buffer_head * ext4_dx_find_entry(struct inode *dir, |
| 181 | struct ext4_dir_entry_2 **res_dir, int *err); | 181 | const struct qstr *d_name, |
| 182 | struct ext4_dir_entry_2 **res_dir, | ||
| 183 | int *err); | ||
| 182 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | 184 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, |
| 183 | struct inode *inode); | 185 | struct inode *inode); |
| 184 | 186 | ||
| @@ -345,7 +347,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, | |||
| 345 | * back to userspace. | 347 | * back to userspace. |
| 346 | */ | 348 | */ |
| 347 | static struct dx_frame * | 349 | static struct dx_frame * |
| 348 | dx_probe(struct dentry *dentry, struct inode *dir, | 350 | dx_probe(const struct qstr *d_name, struct inode *dir, |
| 349 | struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) | 351 | struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) |
| 350 | { | 352 | { |
| 351 | unsigned count, indirect; | 353 | unsigned count, indirect; |
| @@ -356,8 +358,6 @@ dx_probe(struct dentry *dentry, struct inode *dir, | |||
| 356 | u32 hash; | 358 | u32 hash; |
| 357 | 359 | ||
| 358 | frame->bh = NULL; | 360 | frame->bh = NULL; |
| 359 | if (dentry) | ||
| 360 | dir = dentry->d_parent->d_inode; | ||
| 361 | if (!(bh = ext4_bread (NULL,dir, 0, 0, err))) | 361 | if (!(bh = ext4_bread (NULL,dir, 0, 0, err))) |
| 362 | goto fail; | 362 | goto fail; |
| 363 | root = (struct dx_root *) bh->b_data; | 363 | root = (struct dx_root *) bh->b_data; |
| @@ -373,8 +373,8 @@ dx_probe(struct dentry *dentry, struct inode *dir, | |||
| 373 | } | 373 | } |
| 374 | hinfo->hash_version = root->info.hash_version; | 374 | hinfo->hash_version = root->info.hash_version; |
| 375 | hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; | 375 | hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; |
| 376 | if (dentry) | 376 | if (d_name) |
| 377 | ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); | 377 | ext4fs_dirhash(d_name->name, d_name->len, hinfo); |
| 378 | hash = hinfo->hash; | 378 | hash = hinfo->hash; |
| 379 | 379 | ||
| 380 | if (root->info.unused_flags & 1) { | 380 | if (root->info.unused_flags & 1) { |
| @@ -649,7 +649,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, | |||
| 649 | } | 649 | } |
| 650 | hinfo.hash = start_hash; | 650 | hinfo.hash = start_hash; |
| 651 | hinfo.minor_hash = 0; | 651 | hinfo.minor_hash = 0; |
| 652 | frame = dx_probe(NULL, dir_file->f_path.dentry->d_inode, &hinfo, frames, &err); | 652 | frame = dx_probe(NULL, dir, &hinfo, frames, &err); |
| 653 | if (!frame) | 653 | if (!frame) |
| 654 | return err; | 654 | return err; |
| 655 | 655 | ||
| @@ -805,15 +805,15 @@ static inline int ext4_match (int len, const char * const name, | |||
| 805 | */ | 805 | */ |
| 806 | static inline int search_dirblock(struct buffer_head *bh, | 806 | static inline int search_dirblock(struct buffer_head *bh, |
| 807 | struct inode *dir, | 807 | struct inode *dir, |
| 808 | struct dentry *dentry, | 808 | const struct qstr *d_name, |
| 809 | unsigned long offset, | 809 | unsigned long offset, |
| 810 | struct ext4_dir_entry_2 ** res_dir) | 810 | struct ext4_dir_entry_2 ** res_dir) |
| 811 | { | 811 | { |
| 812 | struct ext4_dir_entry_2 * de; | 812 | struct ext4_dir_entry_2 * de; |
| 813 | char * dlimit; | 813 | char * dlimit; |
| 814 | int de_len; | 814 | int de_len; |
| 815 | const char *name = dentry->d_name.name; | 815 | const char *name = d_name->name; |
| 816 | int namelen = dentry->d_name.len; | 816 | int namelen = d_name->len; |
| 817 | 817 | ||
| 818 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 818 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
| 819 | dlimit = bh->b_data + dir->i_sb->s_blocksize; | 819 | dlimit = bh->b_data + dir->i_sb->s_blocksize; |
| @@ -852,7 +852,8 @@ static inline int search_dirblock(struct buffer_head *bh, | |||
| 852 | * The returned buffer_head has ->b_count elevated. The caller is expected | 852 | * The returned buffer_head has ->b_count elevated. The caller is expected |
| 853 | * to brelse() it when appropriate. | 853 | * to brelse() it when appropriate. |
| 854 | */ | 854 | */ |
| 855 | static struct buffer_head * ext4_find_entry (struct dentry *dentry, | 855 | static struct buffer_head * ext4_find_entry (struct inode *dir, |
| 856 | const struct qstr *d_name, | ||
| 856 | struct ext4_dir_entry_2 ** res_dir) | 857 | struct ext4_dir_entry_2 ** res_dir) |
| 857 | { | 858 | { |
| 858 | struct super_block *sb; | 859 | struct super_block *sb; |
| @@ -866,16 +867,15 @@ static struct buffer_head * ext4_find_entry (struct dentry *dentry, | |||
| 866 | int num = 0; | 867 | int num = 0; |
| 867 | ext4_lblk_t nblocks; | 868 | ext4_lblk_t nblocks; |
| 868 | int i, err; | 869 | int i, err; |
| 869 | struct inode *dir = dentry->d_parent->d_inode; | ||
| 870 | int namelen; | 870 | int namelen; |
| 871 | 871 | ||
| 872 | *res_dir = NULL; | 872 | *res_dir = NULL; |
| 873 | sb = dir->i_sb; | 873 | sb = dir->i_sb; |
| 874 | namelen = dentry->d_name.len; | 874 | namelen = d_name->len; |
| 875 | if (namelen > EXT4_NAME_LEN) | 875 | if (namelen > EXT4_NAME_LEN) |
| 876 | return NULL; | 876 | return NULL; |
| 877 | if (is_dx(dir)) { | 877 | if (is_dx(dir)) { |
| 878 | bh = ext4_dx_find_entry(dentry, res_dir, &err); | 878 | bh = ext4_dx_find_entry(dir, d_name, res_dir, &err); |
| 879 | /* | 879 | /* |
| 880 | * On success, or if the error was file not found, | 880 | * On success, or if the error was file not found, |
| 881 | * return. Otherwise, fall back to doing a search the | 881 | * return. Otherwise, fall back to doing a search the |
| @@ -928,7 +928,7 @@ restart: | |||
| 928 | brelse(bh); | 928 | brelse(bh); |
| 929 | goto next; | 929 | goto next; |
| 930 | } | 930 | } |
| 931 | i = search_dirblock(bh, dir, dentry, | 931 | i = search_dirblock(bh, dir, d_name, |
| 932 | block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); | 932 | block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); |
| 933 | if (i == 1) { | 933 | if (i == 1) { |
| 934 | EXT4_I(dir)->i_dir_start_lookup = block; | 934 | EXT4_I(dir)->i_dir_start_lookup = block; |
| @@ -962,7 +962,7 @@ cleanup_and_exit: | |||
| 962 | return ret; | 962 | return ret; |
| 963 | } | 963 | } |
| 964 | 964 | ||
| 965 | static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, | 965 | static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name, |
| 966 | struct ext4_dir_entry_2 **res_dir, int *err) | 966 | struct ext4_dir_entry_2 **res_dir, int *err) |
| 967 | { | 967 | { |
| 968 | struct super_block * sb; | 968 | struct super_block * sb; |
| @@ -973,14 +973,13 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, | |||
| 973 | struct buffer_head *bh; | 973 | struct buffer_head *bh; |
| 974 | ext4_lblk_t block; | 974 | ext4_lblk_t block; |
| 975 | int retval; | 975 | int retval; |
| 976 | int namelen = dentry->d_name.len; | 976 | int namelen = d_name->len; |
| 977 | const u8 *name = dentry->d_name.name; | 977 | const u8 *name = d_name->name; |
| 978 | struct inode *dir = dentry->d_parent->d_inode; | ||
| 979 | 978 | ||
| 980 | sb = dir->i_sb; | 979 | sb = dir->i_sb; |
| 981 | /* NFS may look up ".." - look at dx_root directory block */ | 980 | /* NFS may look up ".." - look at dx_root directory block */ |
| 982 | if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ | 981 | if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ |
| 983 | if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) | 982 | if (!(frame = dx_probe(d_name, dir, &hinfo, frames, err))) |
| 984 | return NULL; | 983 | return NULL; |
| 985 | } else { | 984 | } else { |
| 986 | frame = frames; | 985 | frame = frames; |
| @@ -1041,7 +1040,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru | |||
| 1041 | if (dentry->d_name.len > EXT4_NAME_LEN) | 1040 | if (dentry->d_name.len > EXT4_NAME_LEN) |
| 1042 | return ERR_PTR(-ENAMETOOLONG); | 1041 | return ERR_PTR(-ENAMETOOLONG); |
| 1043 | 1042 | ||
| 1044 | bh = ext4_find_entry(dentry, &de); | 1043 | bh = ext4_find_entry(dir, &dentry->d_name, &de); |
| 1045 | inode = NULL; | 1044 | inode = NULL; |
| 1046 | if (bh) { | 1045 | if (bh) { |
| 1047 | unsigned long ino = le32_to_cpu(de->inode); | 1046 | unsigned long ino = le32_to_cpu(de->inode); |
| @@ -1064,15 +1063,14 @@ struct dentry *ext4_get_parent(struct dentry *child) | |||
| 1064 | unsigned long ino; | 1063 | unsigned long ino; |
| 1065 | struct dentry *parent; | 1064 | struct dentry *parent; |
| 1066 | struct inode *inode; | 1065 | struct inode *inode; |
| 1067 | struct dentry dotdot; | 1066 | static const struct qstr dotdot = { |
| 1067 | .name = "..", | ||
| 1068 | .len = 2, | ||
| 1069 | }; | ||
| 1068 | struct ext4_dir_entry_2 * de; | 1070 | struct ext4_dir_entry_2 * de; |
| 1069 | struct buffer_head *bh; | 1071 | struct buffer_head *bh; |
| 1070 | 1072 | ||
| 1071 | dotdot.d_name.name = ".."; | 1073 | bh = ext4_find_entry(child->d_inode, &dotdot, &de); |
| 1072 | dotdot.d_name.len = 2; | ||
| 1073 | dotdot.d_parent = child; /* confusing, isn't it! */ | ||
| 1074 | |||
| 1075 | bh = ext4_find_entry(&dotdot, &de); | ||
| 1076 | inode = NULL; | 1074 | inode = NULL; |
| 1077 | if (!bh) | 1075 | if (!bh) |
| 1078 | return ERR_PTR(-ENOENT); | 1076 | return ERR_PTR(-ENOENT); |
| @@ -1508,7 +1506,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
| 1508 | struct ext4_dir_entry_2 *de; | 1506 | struct ext4_dir_entry_2 *de; |
| 1509 | int err; | 1507 | int err; |
| 1510 | 1508 | ||
| 1511 | frame = dx_probe(dentry, NULL, &hinfo, frames, &err); | 1509 | frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); |
| 1512 | if (!frame) | 1510 | if (!frame) |
| 1513 | return err; | 1511 | return err; |
| 1514 | entries = frame->entries; | 1512 | entries = frame->entries; |
| @@ -2089,7 +2087,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 2089 | return PTR_ERR(handle); | 2087 | return PTR_ERR(handle); |
| 2090 | 2088 | ||
| 2091 | retval = -ENOENT; | 2089 | retval = -ENOENT; |
| 2092 | bh = ext4_find_entry(dentry, &de); | 2090 | bh = ext4_find_entry(dir, &dentry->d_name, &de); |
| 2093 | if (!bh) | 2091 | if (!bh) |
| 2094 | goto end_rmdir; | 2092 | goto end_rmdir; |
| 2095 | 2093 | ||
| @@ -2151,7 +2149,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) | |||
| 2151 | handle->h_sync = 1; | 2149 | handle->h_sync = 1; |
| 2152 | 2150 | ||
| 2153 | retval = -ENOENT; | 2151 | retval = -ENOENT; |
| 2154 | bh = ext4_find_entry(dentry, &de); | 2152 | bh = ext4_find_entry(dir, &dentry->d_name, &de); |
| 2155 | if (!bh) | 2153 | if (!bh) |
| 2156 | goto end_unlink; | 2154 | goto end_unlink; |
| 2157 | 2155 | ||
| @@ -2312,7 +2310,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2312 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) | 2310 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) |
| 2313 | handle->h_sync = 1; | 2311 | handle->h_sync = 1; |
| 2314 | 2312 | ||
| 2315 | old_bh = ext4_find_entry(old_dentry, &old_de); | 2313 | old_bh = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de); |
| 2316 | /* | 2314 | /* |
| 2317 | * Check for inode number is _not_ due to possible IO errors. | 2315 | * Check for inode number is _not_ due to possible IO errors. |
| 2318 | * We might rmdir the source, keep it as pwd of some process | 2316 | * We might rmdir the source, keep it as pwd of some process |
| @@ -2325,7 +2323,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2325 | goto end_rename; | 2323 | goto end_rename; |
| 2326 | 2324 | ||
| 2327 | new_inode = new_dentry->d_inode; | 2325 | new_inode = new_dentry->d_inode; |
| 2328 | new_bh = ext4_find_entry(new_dentry, &new_de); | 2326 | new_bh = ext4_find_entry(new_dir, &new_dentry->d_name, &new_de); |
| 2329 | if (new_bh) { | 2327 | if (new_bh) { |
| 2330 | if (!new_inode) { | 2328 | if (!new_inode) { |
| 2331 | brelse(new_bh); | 2329 | brelse(new_bh); |
| @@ -2392,7 +2390,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2392 | struct buffer_head *old_bh2; | 2390 | struct buffer_head *old_bh2; |
| 2393 | struct ext4_dir_entry_2 *old_de2; | 2391 | struct ext4_dir_entry_2 *old_de2; |
| 2394 | 2392 | ||
| 2395 | old_bh2 = ext4_find_entry(old_dentry, &old_de2); | 2393 | old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2); |
| 2396 | if (old_bh2) { | 2394 | if (old_bh2) { |
| 2397 | retval = ext4_delete_entry(handle, old_dir, | 2395 | retval = ext4_delete_entry(handle, old_dir, |
| 2398 | old_de2, old_bh2); | 2396 | old_de2, old_bh2); |
