diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-05 22:58:25 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-03-14 09:15:26 -0400 |
commit | fe2d35ff0d18a2c93993b0d7d46f846ff4331b72 (patch) | |
tree | 0a60fd245b1aff56a0b1470cadd6e242bfd4a2de /fs/namei.c | |
parent | 70e9b3571107b88674cd55ae4bed33f76261e7d3 (diff) |
switch non-create side of open() to use of do_last()
Instead of path_lookupat() doing trailing symlink resolution,
use the same scheme as on the O_CREAT side. Walk with
LOOKUP_PARENT, then (in do_last()) look the final component
up, then either open it or return error or, if it's a symlink,
give the symlink back to path_openat() to be resolved there.
The really messy complication here is RCU. We don't want to drop
out of RCU mode before the final lookup, since we don't want to
bounce parent directory ->d_count without a good reason.
Result is _not_ pretty; later in the series we'll clean it up.
For now we are roughly back where we'd been before the revert
done by Nick's series - top-level logics of path_openat() is
cleaned up, do_last() does actual opening, symlink resolution is
done uniformly.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 100 |
1 files changed, 67 insertions, 33 deletions
diff --git a/fs/namei.c b/fs/namei.c index a260a306daf5..9595b4a55c39 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2178,13 +2178,14 @@ exit: | |||
2178 | } | 2178 | } |
2179 | 2179 | ||
2180 | /* | 2180 | /* |
2181 | * Handle O_CREAT case for do_filp_open | 2181 | * Handle the last step of open() |
2182 | */ | 2182 | */ |
2183 | static struct file *do_last(struct nameidata *nd, struct path *path, | 2183 | static struct file *do_last(struct nameidata *nd, struct path *path, |
2184 | const struct open_flags *op, const char *pathname) | 2184 | const struct open_flags *op, const char *pathname) |
2185 | { | 2185 | { |
2186 | struct dentry *dir = nd->path.dentry; | 2186 | struct dentry *dir = nd->path.dentry; |
2187 | struct file *filp; | 2187 | struct file *filp; |
2188 | struct inode *inode; | ||
2188 | int error; | 2189 | int error; |
2189 | 2190 | ||
2190 | nd->flags &= ~LOOKUP_PARENT; | 2191 | nd->flags &= ~LOOKUP_PARENT; |
@@ -2192,17 +2193,27 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2192 | 2193 | ||
2193 | switch (nd->last_type) { | 2194 | switch (nd->last_type) { |
2194 | case LAST_DOTDOT: | 2195 | case LAST_DOTDOT: |
2195 | follow_dotdot(nd); | ||
2196 | dir = nd->path.dentry; | ||
2197 | case LAST_DOT: | 2196 | case LAST_DOT: |
2197 | error = handle_dots(nd, nd->last_type); | ||
2198 | if (error) | ||
2199 | return ERR_PTR(error); | ||
2198 | /* fallthrough */ | 2200 | /* fallthrough */ |
2199 | case LAST_ROOT: | 2201 | case LAST_ROOT: |
2202 | if (nd->flags & LOOKUP_RCU) { | ||
2203 | if (nameidata_drop_rcu_last(nd)) | ||
2204 | return ERR_PTR(-ECHILD); | ||
2205 | } | ||
2200 | error = handle_reval_path(nd); | 2206 | error = handle_reval_path(nd); |
2201 | if (error) | 2207 | if (error) |
2202 | goto exit; | 2208 | goto exit; |
2203 | error = -EISDIR; | 2209 | audit_inode(pathname, nd->path.dentry); |
2204 | goto exit; | 2210 | if (op->open_flag & O_CREAT) { |
2211 | error = -EISDIR; | ||
2212 | goto exit; | ||
2213 | } | ||
2214 | goto ok; | ||
2205 | case LAST_BIND: | 2215 | case LAST_BIND: |
2216 | /* can't be RCU mode here */ | ||
2206 | error = handle_reval_path(nd); | 2217 | error = handle_reval_path(nd); |
2207 | if (error) | 2218 | if (error) |
2208 | goto exit; | 2219 | goto exit; |
@@ -2210,6 +2221,51 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
2210 | goto ok; | 2221 | goto ok; |
2211 | } | 2222 | } |
2212 | 2223 | ||
2224 | if (!(op->open_flag & O_CREAT)) { | ||
2225 | if (nd->last.name[nd->last.len]) | ||
2226 | nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | ||
2227 | /* we _can_ be in RCU mode here */ | ||
2228 | error = do_lookup(nd, &nd->last, path, &inode); | ||
2229 | if (error) { | ||
2230 | terminate_walk(nd); | ||
2231 | return ERR_PTR(error); | ||
2232 | } | ||
2233 | if (!inode) { | ||
2234 | path_to_nameidata(path, nd); | ||
2235 | terminate_walk(nd); | ||
2236 | return ERR_PTR(-ENOENT); | ||
2237 | } | ||
2238 | if (unlikely(inode->i_op->follow_link)) { | ||
2239 | /* We drop rcu-walk here */ | ||
2240 | if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry)) | ||
2241 | return ERR_PTR(-ECHILD); | ||
2242 | return NULL; | ||
2243 | } | ||
2244 | path_to_nameidata(path, nd); | ||
2245 | nd->inode = inode; | ||
2246 | /* sayonara */ | ||
2247 | if (nd->flags & LOOKUP_RCU) { | ||
2248 | if (nameidata_drop_rcu_last(nd)) | ||
2249 | return ERR_PTR(-ECHILD); | ||
2250 | } | ||
2251 | |||
2252 | error = -ENOTDIR; | ||
2253 | if (nd->flags & LOOKUP_DIRECTORY) { | ||
2254 | if (!inode->i_op->lookup) | ||
2255 | goto exit; | ||
2256 | } | ||
2257 | audit_inode(pathname, nd->path.dentry); | ||
2258 | goto ok; | ||
2259 | } | ||
2260 | |||
2261 | /* create side of things */ | ||
2262 | |||
2263 | if (nd->flags & LOOKUP_RCU) { | ||
2264 | if (nameidata_drop_rcu_last(nd)) | ||
2265 | return ERR_PTR(-ECHILD); | ||
2266 | } | ||
2267 | |||
2268 | audit_inode(pathname, dir); | ||
2213 | error = -EISDIR; | 2269 | error = -EISDIR; |
2214 | /* trailing slashes? */ | 2270 | /* trailing slashes? */ |
2215 | if (nd->last.name[nd->last.len]) | 2271 | if (nd->last.name[nd->last.len]) |
@@ -2303,6 +2359,7 @@ exit: | |||
2303 | static struct file *path_openat(int dfd, const char *pathname, | 2359 | static struct file *path_openat(int dfd, const char *pathname, |
2304 | const struct open_flags *op, int flags) | 2360 | const struct open_flags *op, int flags) |
2305 | { | 2361 | { |
2362 | struct file *base = NULL; | ||
2306 | struct file *filp; | 2363 | struct file *filp; |
2307 | struct nameidata nd; | 2364 | struct nameidata nd; |
2308 | struct path path; | 2365 | struct path path; |
@@ -2318,39 +2375,15 @@ static struct file *path_openat(int dfd, const char *pathname, | |||
2318 | nd.intent.open.flags = open_to_namei_flags(op->open_flag); | 2375 | nd.intent.open.flags = open_to_namei_flags(op->open_flag); |
2319 | nd.intent.open.create_mode = op->mode; | 2376 | nd.intent.open.create_mode = op->mode; |
2320 | 2377 | ||
2321 | if (op->open_flag & O_CREAT) | 2378 | error = path_init(dfd, pathname, flags | LOOKUP_PARENT, &nd, &base); |
2322 | goto creat; | ||
2323 | |||
2324 | /* !O_CREAT, simple open */ | ||
2325 | error = path_lookupat(dfd, pathname, flags | op->intent, &nd); | ||
2326 | if (unlikely(error)) | 2379 | if (unlikely(error)) |
2327 | goto out_filp; | 2380 | goto out_filp; |
2328 | error = -ELOOP; | ||
2329 | if (!(nd.flags & LOOKUP_FOLLOW)) { | ||
2330 | if (nd.inode->i_op->follow_link) | ||
2331 | goto out_path; | ||
2332 | } | ||
2333 | error = -ENOTDIR; | ||
2334 | if (nd.flags & LOOKUP_DIRECTORY) { | ||
2335 | if (!nd.inode->i_op->lookup) | ||
2336 | goto out_path; | ||
2337 | } | ||
2338 | audit_inode(pathname, nd.path.dentry); | ||
2339 | filp = finish_open(&nd, op->open_flag, op->acc_mode); | ||
2340 | release_open_intent(&nd); | ||
2341 | return filp; | ||
2342 | 2381 | ||
2343 | creat: | 2382 | current->total_link_count = 0; |
2344 | /* OK, have to create the file. Find the parent. */ | 2383 | error = link_path_walk(pathname, &nd); |
2345 | error = path_lookupat(dfd, pathname, LOOKUP_PARENT | flags, &nd); | ||
2346 | if (unlikely(error)) | 2384 | if (unlikely(error)) |
2347 | goto out_filp; | 2385 | goto out_filp; |
2348 | if (unlikely(!audit_dummy_context())) | ||
2349 | audit_inode(pathname, nd.path.dentry); | ||
2350 | 2386 | ||
2351 | /* | ||
2352 | * We have the parent and last component. | ||
2353 | */ | ||
2354 | filp = do_last(&nd, &path, op, pathname); | 2387 | filp = do_last(&nd, &path, op, pathname); |
2355 | while (unlikely(!filp)) { /* trailing symlink */ | 2388 | while (unlikely(!filp)) { /* trailing symlink */ |
2356 | struct path link = path; | 2389 | struct path link = path; |
@@ -2386,12 +2419,13 @@ creat: | |||
2386 | out: | 2419 | out: |
2387 | if (nd.root.mnt) | 2420 | if (nd.root.mnt) |
2388 | path_put(&nd.root); | 2421 | path_put(&nd.root); |
2422 | if (base) | ||
2423 | fput(base); | ||
2389 | release_open_intent(&nd); | 2424 | release_open_intent(&nd); |
2390 | return filp; | 2425 | return filp; |
2391 | 2426 | ||
2392 | exit_dput: | 2427 | exit_dput: |
2393 | path_put_conditional(&path, &nd); | 2428 | path_put_conditional(&path, &nd); |
2394 | out_path: | ||
2395 | path_put(&nd.path); | 2429 | path_put(&nd.path); |
2396 | out_filp: | 2430 | out_filp: |
2397 | filp = ERR_PTR(error); | 2431 | filp = ERR_PTR(error); |