diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2008-02-23 10:14:28 -0500 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-03-19 06:55:46 -0400 |
| commit | a02f76c34d7d6d30b63ac64a8b34dea68593e8da (patch) | |
| tree | 4186495ccb3d6ef3cec8b5f8cf964212f746ab55 | |
| parent | b4d232e65fa274a715dae39f77191071324e602a (diff) | |
[PATCH] get stack footprint of pathname resolution back to relative sanity
Somebody had put struct nameidata in stack frame of link_path_walk().
Unfortunately, there are certain realities to deal with:
* It's in the middle of recursion. Depth is equal to the nesting
depth of symlinks, i.e. up to 8.
* struct namiedata is, even if one discards the intent junk,
at least 12 pointers + 5 ints.
* moreover, adding a stack frame is not free in that situation.
* there are fs methods called on top of that, and they also have
stack footprint.
* kernel stack is not infinite.
The thing is, even if one chooses to deal with -ESTALE that way (and it's
one hell of an overkill), the only thing that needs to be preserved is
vfsmount + dentry, not the entire struct nameidata.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
| -rw-r--r-- | fs/namei.c | 63 |
1 files changed, 32 insertions, 31 deletions
diff --git a/fs/namei.c b/fs/namei.c index 941c8e8228c0..7346e99d9283 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -106,7 +106,7 @@ | |||
| 106 | * any extra contention... | 106 | * any extra contention... |
| 107 | */ | 107 | */ |
| 108 | 108 | ||
| 109 | static int link_path_walk(const char *name, struct nameidata *nd); | 109 | static int __link_path_walk(const char *name, struct nameidata *nd); |
| 110 | 110 | ||
| 111 | /* In order to reduce some races, while at the same time doing additional | 111 | /* In order to reduce some races, while at the same time doing additional |
| 112 | * checking and hopefully speeding things up, we copy filenames to the | 112 | * checking and hopefully speeding things up, we copy filenames to the |
| @@ -563,6 +563,37 @@ walk_init_root(const char *name, struct nameidata *nd) | |||
| 563 | return 1; | 563 | return 1; |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | /* | ||
| 567 | * Wrapper to retry pathname resolution whenever the underlying | ||
| 568 | * file system returns an ESTALE. | ||
| 569 | * | ||
| 570 | * Retry the whole path once, forcing real lookup requests | ||
| 571 | * instead of relying on the dcache. | ||
| 572 | */ | ||
| 573 | static __always_inline int link_path_walk(const char *name, struct nameidata *nd) | ||
| 574 | { | ||
| 575 | struct path save = nd->path; | ||
| 576 | int result; | ||
| 577 | |||
| 578 | /* make sure the stuff we saved doesn't go away */ | ||
| 579 | dget(save.dentry); | ||
| 580 | mntget(save.mnt); | ||
| 581 | |||
| 582 | result = __link_path_walk(name, nd); | ||
| 583 | if (result == -ESTALE) { | ||
| 584 | /* nd->path had been dropped */ | ||
| 585 | nd->path = save; | ||
| 586 | dget(nd->path.dentry); | ||
| 587 | mntget(nd->path.mnt); | ||
| 588 | nd->flags |= LOOKUP_REVAL; | ||
| 589 | result = __link_path_walk(name, nd); | ||
| 590 | } | ||
| 591 | |||
| 592 | path_put(&save); | ||
| 593 | |||
| 594 | return result; | ||
| 595 | } | ||
| 596 | |||
| 566 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 597 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
| 567 | { | 598 | { |
| 568 | int res = 0; | 599 | int res = 0; |
| @@ -1020,36 +1051,6 @@ return_err: | |||
| 1020 | return err; | 1051 | return err; |
| 1021 | } | 1052 | } |
| 1022 | 1053 | ||
| 1023 | /* | ||
| 1024 | * Wrapper to retry pathname resolution whenever the underlying | ||
| 1025 | * file system returns an ESTALE. | ||
| 1026 | * | ||
| 1027 | * Retry the whole path once, forcing real lookup requests | ||
| 1028 | * instead of relying on the dcache. | ||
| 1029 | */ | ||
| 1030 | static int link_path_walk(const char *name, struct nameidata *nd) | ||
| 1031 | { | ||
| 1032 | struct nameidata save = *nd; | ||
| 1033 | int result; | ||
| 1034 | |||
| 1035 | /* make sure the stuff we saved doesn't go away */ | ||
| 1036 | dget(save.path.dentry); | ||
| 1037 | mntget(save.path.mnt); | ||
| 1038 | |||
| 1039 | result = __link_path_walk(name, nd); | ||
| 1040 | if (result == -ESTALE) { | ||
| 1041 | *nd = save; | ||
| 1042 | dget(nd->path.dentry); | ||
| 1043 | mntget(nd->path.mnt); | ||
| 1044 | nd->flags |= LOOKUP_REVAL; | ||
| 1045 | result = __link_path_walk(name, nd); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | path_put(&save.path); | ||
| 1049 | |||
| 1050 | return result; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | static int path_walk(const char *name, struct nameidata *nd) | 1054 | static int path_walk(const char *name, struct nameidata *nd) |
| 1054 | { | 1055 | { |
| 1055 | current->total_link_count = 0; | 1056 | current->total_link_count = 0; |
