aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-03-05 22:58:25 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-03-14 09:15:26 -0400
commitfe2d35ff0d18a2c93993b0d7d46f846ff4331b72 (patch)
tree0a60fd245b1aff56a0b1470cadd6e242bfd4a2de /fs/namei.c
parent70e9b3571107b88674cd55ae4bed33f76261e7d3 (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.c100
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 */
2183static struct file *do_last(struct nameidata *nd, struct path *path, 2183static 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:
2303static struct file *path_openat(int dfd, const char *pathname, 2359static 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
2343creat: 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:
2386out: 2419out:
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
2392exit_dput: 2427exit_dput:
2393 path_put_conditional(&path, &nd); 2428 path_put_conditional(&path, &nd);
2394out_path:
2395 path_put(&nd.path); 2429 path_put(&nd.path);
2396out_filp: 2430out_filp:
2397 filp = ERR_PTR(error); 2431 filp = ERR_PTR(error);