diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 11:46:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 11:46:08 -0400 |
commit | 7e5cb5e151c5474b4a468f437f5038ba9f67ef4d (patch) | |
tree | 899f42e88f926fb4501402cf4ee4aa0903421ef5 /fs/namei.c | |
parent | 8c12fec90c54cfabdd57b2726a1defbc07c19a55 (diff) | |
parent | e994defb7b6813ba6fa7a2a36e86d2455ad1dc35 (diff) |
Merge branch 'vfs-cleanups' (random vfs cleanups)
This teaches vfs_fstat() to use the appropriate f[get|put]_light
functions, allowing it to avoid some unnecessary locking for the common
case.
More noticeably, it also cleans up and simplifies the "getname_flags()"
function, which now relies on the architecture strncpy_from_user() doing
all the user access checks properly, instead of hacking around the fact
that on x86 it didn't use to do it right (see commit 92ae03f2ef99: "x86:
merge 32/64-bit versions of 'strncpy_from_user()' and speed it up").
* vfs-cleanups:
VFS: make vfs_fstat() use f[get|put]_light()
VFS: clean up and simplify getname_flags()
x86: make word-at-a-time strncpy_from_user clear bytes at the end
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 58 |
1 files changed, 24 insertions, 34 deletions
diff --git a/fs/namei.c b/fs/namei.c index c42791914f82..709fb2c17b5f 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -116,47 +116,37 @@ | |||
116 | * POSIX.1 2.4: an empty pathname is invalid (ENOENT). | 116 | * POSIX.1 2.4: an empty pathname is invalid (ENOENT). |
117 | * PATH_MAX includes the nul terminator --RR. | 117 | * PATH_MAX includes the nul terminator --RR. |
118 | */ | 118 | */ |
119 | static int do_getname(const char __user *filename, char *page) | ||
120 | { | ||
121 | int retval; | ||
122 | unsigned long len = PATH_MAX; | ||
123 | |||
124 | if (!segment_eq(get_fs(), KERNEL_DS)) { | ||
125 | if ((unsigned long) filename >= TASK_SIZE) | ||
126 | return -EFAULT; | ||
127 | if (TASK_SIZE - (unsigned long) filename < PATH_MAX) | ||
128 | len = TASK_SIZE - (unsigned long) filename; | ||
129 | } | ||
130 | |||
131 | retval = strncpy_from_user(page, filename, len); | ||
132 | if (retval > 0) { | ||
133 | if (retval < len) | ||
134 | return 0; | ||
135 | return -ENAMETOOLONG; | ||
136 | } else if (!retval) | ||
137 | retval = -ENOENT; | ||
138 | return retval; | ||
139 | } | ||
140 | |||
141 | static char *getname_flags(const char __user *filename, int flags, int *empty) | 119 | static char *getname_flags(const char __user *filename, int flags, int *empty) |
142 | { | 120 | { |
143 | char *result = __getname(); | 121 | char *result = __getname(), *err; |
144 | int retval; | 122 | int len; |
145 | 123 | ||
146 | if (!result) | 124 | if (unlikely(!result)) |
147 | return ERR_PTR(-ENOMEM); | 125 | return ERR_PTR(-ENOMEM); |
148 | 126 | ||
149 | retval = do_getname(filename, result); | 127 | len = strncpy_from_user(result, filename, PATH_MAX); |
150 | if (retval < 0) { | 128 | err = ERR_PTR(len); |
151 | if (retval == -ENOENT && empty) | 129 | if (unlikely(len < 0)) |
130 | goto error; | ||
131 | |||
132 | /* The empty path is special. */ | ||
133 | if (unlikely(!len)) { | ||
134 | if (empty) | ||
152 | *empty = 1; | 135 | *empty = 1; |
153 | if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { | 136 | err = ERR_PTR(-ENOENT); |
154 | __putname(result); | 137 | if (!(flags & LOOKUP_EMPTY)) |
155 | return ERR_PTR(retval); | 138 | goto error; |
156 | } | ||
157 | } | 139 | } |
158 | audit_getname(result); | 140 | |
159 | return result; | 141 | err = ERR_PTR(-ENAMETOOLONG); |
142 | if (likely(len < PATH_MAX)) { | ||
143 | audit_getname(result); | ||
144 | return result; | ||
145 | } | ||
146 | |||
147 | error: | ||
148 | __putname(result); | ||
149 | return err; | ||
160 | } | 150 | } |
161 | 151 | ||
162 | char *getname(const char __user * filename) | 152 | char *getname(const char __user * filename) |