aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2008-09-22 15:21:01 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-09-22 15:21:01 -0400
commitf702ba0fd7d50b5f5f5aea5317875a10d40b869f (patch)
treebd31cefb5b88b882f4088007482266a3f5ad93ab
parent914258bf2cb22bf4336a1b1d90c551b4b11ca5aa (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>
-rw-r--r--fs/ext4/namei.c68
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);
159static void dx_set_limit(struct dx_entry *entries, unsigned value); 159static void dx_set_limit(struct dx_entry *entries, unsigned value);
160static unsigned dx_root_limit(struct inode *dir, unsigned infosize); 160static unsigned dx_root_limit(struct inode *dir, unsigned infosize);
161static unsigned dx_node_limit(struct inode *dir); 161static unsigned dx_node_limit(struct inode *dir);
162static struct dx_frame *dx_probe(struct dentry *dentry, 162static 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);
180static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, 180static 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);
182static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, 184static 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 */
347static struct dx_frame * 349static struct dx_frame *
348dx_probe(struct dentry *dentry, struct inode *dir, 350dx_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 */
806static inline int search_dirblock(struct buffer_head *bh, 806static 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 */
855static struct buffer_head * ext4_find_entry (struct dentry *dentry, 855static 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
965static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry, 965static 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);