diff options
author | Theodore Ts'o <tytso@mit.edu> | 2008-09-22 15:21:01 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2008-09-22 15:21:01 -0400 |
commit | f702ba0fd7d50b5f5f5aea5317875a10d40b869f (patch) | |
tree | bd31cefb5b88b882f4088007482266a3f5ad93ab /fs/ext4 | |
parent | 914258bf2cb22bf4336a1b1d90c551b4b11ca5aa (diff) |
ext4: Don't use 'struct dentry' for internal lookups
This is a port of a patch from Linus which fixes a 200+ byte stack
usage problem in ext4_get_parent().
It's more efficient to pass down only the actual parts of the dentry
that matter: the parent inode and the name, instead of allocating a
struct dentry on the stack.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-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); |