diff options
Diffstat (limited to 'fs/ext3/namei.c')
-rw-r--r-- | fs/ext3/namei.c | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index de13e919cd81..3e5edc92aa0b 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/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(struct qstr *entry, |
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, |
@@ -176,8 +176,9 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash, | |||
176 | struct dx_frame *frame, | 176 | struct dx_frame *frame, |
177 | struct dx_frame *frames, | 177 | struct dx_frame *frames, |
178 | __u32 *start_hash); | 178 | __u32 *start_hash); |
179 | static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, | 179 | static struct buffer_head * ext3_dx_find_entry(struct inode *dir, |
180 | struct ext3_dir_entry_2 **res_dir, int *err); | 180 | struct qstr *entry, struct ext3_dir_entry_2 **res_dir, |
181 | int *err); | ||
181 | static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, | 182 | static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, |
182 | struct inode *inode); | 183 | struct inode *inode); |
183 | 184 | ||
@@ -342,7 +343,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, | |||
342 | * back to userspace. | 343 | * back to userspace. |
343 | */ | 344 | */ |
344 | static struct dx_frame * | 345 | static struct dx_frame * |
345 | dx_probe(struct dentry *dentry, struct inode *dir, | 346 | dx_probe(struct qstr *entry, struct inode *dir, |
346 | struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) | 347 | struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) |
347 | { | 348 | { |
348 | unsigned count, indirect; | 349 | unsigned count, indirect; |
@@ -353,8 +354,6 @@ dx_probe(struct dentry *dentry, struct inode *dir, | |||
353 | u32 hash; | 354 | u32 hash; |
354 | 355 | ||
355 | frame->bh = NULL; | 356 | frame->bh = NULL; |
356 | if (dentry) | ||
357 | dir = dentry->d_parent->d_inode; | ||
358 | if (!(bh = ext3_bread (NULL,dir, 0, 0, err))) | 357 | if (!(bh = ext3_bread (NULL,dir, 0, 0, err))) |
359 | goto fail; | 358 | goto fail; |
360 | root = (struct dx_root *) bh->b_data; | 359 | root = (struct dx_root *) bh->b_data; |
@@ -370,8 +369,8 @@ dx_probe(struct dentry *dentry, struct inode *dir, | |||
370 | } | 369 | } |
371 | hinfo->hash_version = root->info.hash_version; | 370 | hinfo->hash_version = root->info.hash_version; |
372 | hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed; | 371 | hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed; |
373 | if (dentry) | 372 | if (entry) |
374 | ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo); | 373 | ext3fs_dirhash(entry->name, entry->len, hinfo); |
375 | hash = hinfo->hash; | 374 | hash = hinfo->hash; |
376 | 375 | ||
377 | if (root->info.unused_flags & 1) { | 376 | if (root->info.unused_flags & 1) { |
@@ -803,15 +802,15 @@ static inline int ext3_match (int len, const char * const name, | |||
803 | */ | 802 | */ |
804 | static inline int search_dirblock(struct buffer_head * bh, | 803 | static inline int search_dirblock(struct buffer_head * bh, |
805 | struct inode *dir, | 804 | struct inode *dir, |
806 | struct dentry *dentry, | 805 | struct qstr *child, |
807 | unsigned long offset, | 806 | unsigned long offset, |
808 | struct ext3_dir_entry_2 ** res_dir) | 807 | struct ext3_dir_entry_2 ** res_dir) |
809 | { | 808 | { |
810 | struct ext3_dir_entry_2 * de; | 809 | struct ext3_dir_entry_2 * de; |
811 | char * dlimit; | 810 | char * dlimit; |
812 | int de_len; | 811 | int de_len; |
813 | const char *name = dentry->d_name.name; | 812 | const char *name = child->name; |
814 | int namelen = dentry->d_name.len; | 813 | int namelen = child->len; |
815 | 814 | ||
816 | de = (struct ext3_dir_entry_2 *) bh->b_data; | 815 | de = (struct ext3_dir_entry_2 *) bh->b_data; |
817 | dlimit = bh->b_data + dir->i_sb->s_blocksize; | 816 | dlimit = bh->b_data + dir->i_sb->s_blocksize; |
@@ -850,8 +849,9 @@ static inline int search_dirblock(struct buffer_head * bh, | |||
850 | * The returned buffer_head has ->b_count elevated. The caller is expected | 849 | * The returned buffer_head has ->b_count elevated. The caller is expected |
851 | * to brelse() it when appropriate. | 850 | * to brelse() it when appropriate. |
852 | */ | 851 | */ |
853 | static struct buffer_head * ext3_find_entry (struct dentry *dentry, | 852 | static struct buffer_head *ext3_find_entry(struct inode *dir, |
854 | struct ext3_dir_entry_2 ** res_dir) | 853 | struct qstr *entry, |
854 | struct ext3_dir_entry_2 **res_dir) | ||
855 | { | 855 | { |
856 | struct super_block * sb; | 856 | struct super_block * sb; |
857 | struct buffer_head * bh_use[NAMEI_RA_SIZE]; | 857 | struct buffer_head * bh_use[NAMEI_RA_SIZE]; |
@@ -863,16 +863,15 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, | |||
863 | buffer */ | 863 | buffer */ |
864 | int num = 0; | 864 | int num = 0; |
865 | int nblocks, i, err; | 865 | int nblocks, i, err; |
866 | struct inode *dir = dentry->d_parent->d_inode; | ||
867 | int namelen; | 866 | int namelen; |
868 | 867 | ||
869 | *res_dir = NULL; | 868 | *res_dir = NULL; |
870 | sb = dir->i_sb; | 869 | sb = dir->i_sb; |
871 | namelen = dentry->d_name.len; | 870 | namelen = entry->len; |
872 | if (namelen > EXT3_NAME_LEN) | 871 | if (namelen > EXT3_NAME_LEN) |
873 | return NULL; | 872 | return NULL; |
874 | if (is_dx(dir)) { | 873 | if (is_dx(dir)) { |
875 | bh = ext3_dx_find_entry(dentry, res_dir, &err); | 874 | bh = ext3_dx_find_entry(dir, entry, res_dir, &err); |
876 | /* | 875 | /* |
877 | * On success, or if the error was file not found, | 876 | * On success, or if the error was file not found, |
878 | * return. Otherwise, fall back to doing a search the | 877 | * return. Otherwise, fall back to doing a search the |
@@ -923,7 +922,7 @@ restart: | |||
923 | brelse(bh); | 922 | brelse(bh); |
924 | goto next; | 923 | goto next; |
925 | } | 924 | } |
926 | i = search_dirblock(bh, dir, dentry, | 925 | i = search_dirblock(bh, dir, entry, |
927 | block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); | 926 | block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); |
928 | if (i == 1) { | 927 | if (i == 1) { |
929 | EXT3_I(dir)->i_dir_start_lookup = block; | 928 | EXT3_I(dir)->i_dir_start_lookup = block; |
@@ -957,8 +956,9 @@ cleanup_and_exit: | |||
957 | return ret; | 956 | return ret; |
958 | } | 957 | } |
959 | 958 | ||
960 | static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, | 959 | static struct buffer_head * ext3_dx_find_entry(struct inode *dir, |
961 | struct ext3_dir_entry_2 **res_dir, int *err) | 960 | struct qstr *entry, struct ext3_dir_entry_2 **res_dir, |
961 | int *err) | ||
962 | { | 962 | { |
963 | struct super_block * sb; | 963 | struct super_block * sb; |
964 | struct dx_hash_info hinfo; | 964 | struct dx_hash_info hinfo; |
@@ -968,14 +968,13 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, | |||
968 | struct buffer_head *bh; | 968 | struct buffer_head *bh; |
969 | unsigned long block; | 969 | unsigned long block; |
970 | int retval; | 970 | int retval; |
971 | int namelen = dentry->d_name.len; | 971 | int namelen = entry->len; |
972 | const u8 *name = dentry->d_name.name; | 972 | const u8 *name = entry->name; |
973 | struct inode *dir = dentry->d_parent->d_inode; | ||
974 | 973 | ||
975 | sb = dir->i_sb; | 974 | sb = dir->i_sb; |
976 | /* NFS may look up ".." - look at dx_root directory block */ | 975 | /* NFS may look up ".." - look at dx_root directory block */ |
977 | if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){ | 976 | if (namelen > 2 || name[0] != '.'|| (namelen == 2 && name[1] != '.')) { |
978 | if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) | 977 | if (!(frame = dx_probe(entry, dir, &hinfo, frames, err))) |
979 | return NULL; | 978 | return NULL; |
980 | } else { | 979 | } else { |
981 | frame = frames; | 980 | frame = frames; |
@@ -1036,7 +1035,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str | |||
1036 | if (dentry->d_name.len > EXT3_NAME_LEN) | 1035 | if (dentry->d_name.len > EXT3_NAME_LEN) |
1037 | return ERR_PTR(-ENAMETOOLONG); | 1036 | return ERR_PTR(-ENAMETOOLONG); |
1038 | 1037 | ||
1039 | bh = ext3_find_entry(dentry, &de); | 1038 | bh = ext3_find_entry(dir, &dentry->d_name, &de); |
1040 | inode = NULL; | 1039 | inode = NULL; |
1041 | if (bh) { | 1040 | if (bh) { |
1042 | unsigned long ino = le32_to_cpu(de->inode); | 1041 | unsigned long ino = le32_to_cpu(de->inode); |
@@ -1057,18 +1056,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str | |||
1057 | struct dentry *ext3_get_parent(struct dentry *child) | 1056 | struct dentry *ext3_get_parent(struct dentry *child) |
1058 | { | 1057 | { |
1059 | unsigned long ino; | 1058 | unsigned long ino; |
1060 | struct dentry *parent; | 1059 | struct qstr dotdot = {.name = "..", .len = 2}; |
1061 | struct inode *inode; | ||
1062 | struct dentry dotdot; | ||
1063 | struct ext3_dir_entry_2 * de; | 1060 | struct ext3_dir_entry_2 * de; |
1064 | struct buffer_head *bh; | 1061 | struct buffer_head *bh; |
1065 | 1062 | ||
1066 | dotdot.d_name.name = ".."; | 1063 | bh = ext3_find_entry(child->d_inode, &dotdot, &de); |
1067 | dotdot.d_name.len = 2; | ||
1068 | dotdot.d_parent = child; /* confusing, isn't it! */ | ||
1069 | |||
1070 | bh = ext3_find_entry(&dotdot, &de); | ||
1071 | inode = NULL; | ||
1072 | if (!bh) | 1064 | if (!bh) |
1073 | return ERR_PTR(-ENOENT); | 1065 | return ERR_PTR(-ENOENT); |
1074 | ino = le32_to_cpu(de->inode); | 1066 | ino = le32_to_cpu(de->inode); |
@@ -1080,16 +1072,7 @@ struct dentry *ext3_get_parent(struct dentry *child) | |||
1080 | return ERR_PTR(-EIO); | 1072 | return ERR_PTR(-EIO); |
1081 | } | 1073 | } |
1082 | 1074 | ||
1083 | inode = ext3_iget(child->d_inode->i_sb, ino); | 1075 | return d_obtain_alias(ext3_iget(child->d_inode->i_sb, ino)); |
1084 | if (IS_ERR(inode)) | ||
1085 | return ERR_CAST(inode); | ||
1086 | |||
1087 | parent = d_alloc_anon(inode); | ||
1088 | if (!parent) { | ||
1089 | iput(inode); | ||
1090 | parent = ERR_PTR(-ENOMEM); | ||
1091 | } | ||
1092 | return parent; | ||
1093 | } | 1076 | } |
1094 | 1077 | ||
1095 | #define S_SHIFT 12 | 1078 | #define S_SHIFT 12 |
@@ -1503,7 +1486,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1503 | struct ext3_dir_entry_2 *de; | 1486 | struct ext3_dir_entry_2 *de; |
1504 | int err; | 1487 | int err; |
1505 | 1488 | ||
1506 | frame = dx_probe(dentry, NULL, &hinfo, frames, &err); | 1489 | frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); |
1507 | if (!frame) | 1490 | if (!frame) |
1508 | return err; | 1491 | return err; |
1509 | entries = frame->entries; | 1492 | entries = frame->entries; |
@@ -2056,7 +2039,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) | |||
2056 | return PTR_ERR(handle); | 2039 | return PTR_ERR(handle); |
2057 | 2040 | ||
2058 | retval = -ENOENT; | 2041 | retval = -ENOENT; |
2059 | bh = ext3_find_entry (dentry, &de); | 2042 | bh = ext3_find_entry(dir, &dentry->d_name, &de); |
2060 | if (!bh) | 2043 | if (!bh) |
2061 | goto end_rmdir; | 2044 | goto end_rmdir; |
2062 | 2045 | ||
@@ -2118,7 +2101,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) | |||
2118 | handle->h_sync = 1; | 2101 | handle->h_sync = 1; |
2119 | 2102 | ||
2120 | retval = -ENOENT; | 2103 | retval = -ENOENT; |
2121 | bh = ext3_find_entry (dentry, &de); | 2104 | bh = ext3_find_entry(dir, &dentry->d_name, &de); |
2122 | if (!bh) | 2105 | if (!bh) |
2123 | goto end_unlink; | 2106 | goto end_unlink; |
2124 | 2107 | ||
@@ -2276,7 +2259,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2276 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) | 2259 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) |
2277 | handle->h_sync = 1; | 2260 | handle->h_sync = 1; |
2278 | 2261 | ||
2279 | old_bh = ext3_find_entry (old_dentry, &old_de); | 2262 | old_bh = ext3_find_entry(old_dir, &old_dentry->d_name, &old_de); |
2280 | /* | 2263 | /* |
2281 | * Check for inode number is _not_ due to possible IO errors. | 2264 | * Check for inode number is _not_ due to possible IO errors. |
2282 | * We might rmdir the source, keep it as pwd of some process | 2265 | * We might rmdir the source, keep it as pwd of some process |
@@ -2289,7 +2272,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2289 | goto end_rename; | 2272 | goto end_rename; |
2290 | 2273 | ||
2291 | new_inode = new_dentry->d_inode; | 2274 | new_inode = new_dentry->d_inode; |
2292 | new_bh = ext3_find_entry (new_dentry, &new_de); | 2275 | new_bh = ext3_find_entry(new_dir, &new_dentry->d_name, &new_de); |
2293 | if (new_bh) { | 2276 | if (new_bh) { |
2294 | if (!new_inode) { | 2277 | if (!new_inode) { |
2295 | brelse (new_bh); | 2278 | brelse (new_bh); |
@@ -2355,7 +2338,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2355 | struct buffer_head *old_bh2; | 2338 | struct buffer_head *old_bh2; |
2356 | struct ext3_dir_entry_2 *old_de2; | 2339 | struct ext3_dir_entry_2 *old_de2; |
2357 | 2340 | ||
2358 | old_bh2 = ext3_find_entry(old_dentry, &old_de2); | 2341 | old_bh2 = ext3_find_entry(old_dir, &old_dentry->d_name, |
2342 | &old_de2); | ||
2359 | if (old_bh2) { | 2343 | if (old_bh2) { |
2360 | retval = ext3_delete_entry(handle, old_dir, | 2344 | retval = ext3_delete_entry(handle, old_dir, |
2361 | old_de2, old_bh2); | 2345 | old_de2, old_bh2); |