diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-08-24 07:26:48 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-10-23 05:13:08 -0400 |
commit | 734711abac46c8fee4d70cc9876ebc6d9edb4971 (patch) | |
tree | 8e93a3530b9bc6142316441b2e6e396cadb00f2f | |
parent | 5f556aab907a358c7837cc9a83c3aea4e69cff5b (diff) |
[PATCH] get rid of on-stack fake dentry in ext3_get_parent()
Better pass parent and qstr to ext3_find_entry() explicitly than
use such kludges, especially since the stack footprint is nasty
enough and we have every chance to be deep in call chain.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/ext3/namei.c | 70 |
1 files changed, 33 insertions, 37 deletions
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 880b54400ac0..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,15 +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 dotdot; | 1059 | struct qstr dotdot = {.name = "..", .len = 2}; |
1061 | struct ext3_dir_entry_2 * de; | 1060 | struct ext3_dir_entry_2 * de; |
1062 | struct buffer_head *bh; | 1061 | struct buffer_head *bh; |
1063 | 1062 | ||
1064 | dotdot.d_name.name = ".."; | 1063 | bh = ext3_find_entry(child->d_inode, &dotdot, &de); |
1065 | dotdot.d_name.len = 2; | ||
1066 | dotdot.d_parent = child; /* confusing, isn't it! */ | ||
1067 | |||
1068 | bh = ext3_find_entry(&dotdot, &de); | ||
1069 | if (!bh) | 1064 | if (!bh) |
1070 | return ERR_PTR(-ENOENT); | 1065 | return ERR_PTR(-ENOENT); |
1071 | ino = le32_to_cpu(de->inode); | 1066 | ino = le32_to_cpu(de->inode); |
@@ -1491,7 +1486,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1491 | struct ext3_dir_entry_2 *de; | 1486 | struct ext3_dir_entry_2 *de; |
1492 | int err; | 1487 | int err; |
1493 | 1488 | ||
1494 | frame = dx_probe(dentry, NULL, &hinfo, frames, &err); | 1489 | frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); |
1495 | if (!frame) | 1490 | if (!frame) |
1496 | return err; | 1491 | return err; |
1497 | entries = frame->entries; | 1492 | entries = frame->entries; |
@@ -2044,7 +2039,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) | |||
2044 | return PTR_ERR(handle); | 2039 | return PTR_ERR(handle); |
2045 | 2040 | ||
2046 | retval = -ENOENT; | 2041 | retval = -ENOENT; |
2047 | bh = ext3_find_entry (dentry, &de); | 2042 | bh = ext3_find_entry(dir, &dentry->d_name, &de); |
2048 | if (!bh) | 2043 | if (!bh) |
2049 | goto end_rmdir; | 2044 | goto end_rmdir; |
2050 | 2045 | ||
@@ -2106,7 +2101,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) | |||
2106 | handle->h_sync = 1; | 2101 | handle->h_sync = 1; |
2107 | 2102 | ||
2108 | retval = -ENOENT; | 2103 | retval = -ENOENT; |
2109 | bh = ext3_find_entry (dentry, &de); | 2104 | bh = ext3_find_entry(dir, &dentry->d_name, &de); |
2110 | if (!bh) | 2105 | if (!bh) |
2111 | goto end_unlink; | 2106 | goto end_unlink; |
2112 | 2107 | ||
@@ -2264,7 +2259,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2264 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) | 2259 | if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) |
2265 | handle->h_sync = 1; | 2260 | handle->h_sync = 1; |
2266 | 2261 | ||
2267 | old_bh = ext3_find_entry (old_dentry, &old_de); | 2262 | old_bh = ext3_find_entry(old_dir, &old_dentry->d_name, &old_de); |
2268 | /* | 2263 | /* |
2269 | * Check for inode number is _not_ due to possible IO errors. | 2264 | * Check for inode number is _not_ due to possible IO errors. |
2270 | * 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 |
@@ -2277,7 +2272,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2277 | goto end_rename; | 2272 | goto end_rename; |
2278 | 2273 | ||
2279 | new_inode = new_dentry->d_inode; | 2274 | new_inode = new_dentry->d_inode; |
2280 | new_bh = ext3_find_entry (new_dentry, &new_de); | 2275 | new_bh = ext3_find_entry(new_dir, &new_dentry->d_name, &new_de); |
2281 | if (new_bh) { | 2276 | if (new_bh) { |
2282 | if (!new_inode) { | 2277 | if (!new_inode) { |
2283 | brelse (new_bh); | 2278 | brelse (new_bh); |
@@ -2343,7 +2338,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2343 | struct buffer_head *old_bh2; | 2338 | struct buffer_head *old_bh2; |
2344 | struct ext3_dir_entry_2 *old_de2; | 2339 | struct ext3_dir_entry_2 *old_de2; |
2345 | 2340 | ||
2346 | old_bh2 = ext3_find_entry(old_dentry, &old_de2); | 2341 | old_bh2 = ext3_find_entry(old_dir, &old_dentry->d_name, |
2342 | &old_de2); | ||
2347 | if (old_bh2) { | 2343 | if (old_bh2) { |
2348 | retval = ext3_delete_entry(handle, old_dir, | 2344 | retval = ext3_delete_entry(handle, old_dir, |
2349 | old_de2, old_bh2); | 2345 | old_de2, old_bh2); |