aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namei.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namei.c')
-rw-r--r--fs/namei.c61
1 files changed, 15 insertions, 46 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 6a82fb7e2127..70580ab1445c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3030,9 +3030,13 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
3030 } 3030 }
3031 if (*opened & FILE_CREATED) 3031 if (*opened & FILE_CREATED)
3032 fsnotify_create(dir, dentry); 3032 fsnotify_create(dir, dentry);
3033 path->dentry = dentry; 3033 if (unlikely(d_is_negative(dentry))) {
3034 path->mnt = nd->path.mnt; 3034 error = -ENOENT;
3035 return 1; 3035 } else {
3036 path->dentry = dentry;
3037 path->mnt = nd->path.mnt;
3038 return 1;
3039 }
3036 } 3040 }
3037 } 3041 }
3038 dput(dentry); 3042 dput(dentry);
@@ -3201,9 +3205,7 @@ static int do_last(struct nameidata *nd,
3201 int acc_mode = op->acc_mode; 3205 int acc_mode = op->acc_mode;
3202 unsigned seq; 3206 unsigned seq;
3203 struct inode *inode; 3207 struct inode *inode;
3204 struct path save_parent = { .dentry = NULL, .mnt = NULL };
3205 struct path path; 3208 struct path path;
3206 bool retried = false;
3207 int error; 3209 int error;
3208 3210
3209 nd->flags &= ~LOOKUP_PARENT; 3211 nd->flags &= ~LOOKUP_PARENT;
@@ -3246,7 +3248,6 @@ static int do_last(struct nameidata *nd,
3246 return -EISDIR; 3248 return -EISDIR;
3247 } 3249 }
3248 3250
3249retry_lookup:
3250 if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { 3251 if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) {
3251 error = mnt_want_write(nd->path.mnt); 3252 error = mnt_want_write(nd->path.mnt);
3252 if (!error) 3253 if (!error)
@@ -3298,6 +3299,10 @@ retry_lookup:
3298 got_write = false; 3299 got_write = false;
3299 } 3300 }
3300 3301
3302 error = follow_managed(&path, nd);
3303 if (unlikely(error < 0))
3304 return error;
3305
3301 if (unlikely(d_is_negative(path.dentry))) { 3306 if (unlikely(d_is_negative(path.dentry))) {
3302 path_to_nameidata(&path, nd); 3307 path_to_nameidata(&path, nd);
3303 return -ENOENT; 3308 return -ENOENT;
@@ -3313,10 +3318,6 @@ retry_lookup:
3313 return -EEXIST; 3318 return -EEXIST;
3314 } 3319 }
3315 3320
3316 error = follow_managed(&path, nd);
3317 if (unlikely(error < 0))
3318 return error;
3319
3320 seq = 0; /* out of RCU mode, so the value doesn't matter */ 3321 seq = 0; /* out of RCU mode, so the value doesn't matter */
3321 inode = d_backing_inode(path.dentry); 3322 inode = d_backing_inode(path.dentry);
3322finish_lookup: 3323finish_lookup:
@@ -3327,23 +3328,14 @@ finish_lookup:
3327 if (unlikely(error)) 3328 if (unlikely(error))
3328 return error; 3329 return error;
3329 3330
3330 if ((nd->flags & LOOKUP_RCU) || nd->path.mnt != path.mnt) { 3331 path_to_nameidata(&path, nd);
3331 path_to_nameidata(&path, nd);
3332 } else {
3333 save_parent.dentry = nd->path.dentry;
3334 save_parent.mnt = mntget(path.mnt);
3335 nd->path.dentry = path.dentry;
3336
3337 }
3338 nd->inode = inode; 3332 nd->inode = inode;
3339 nd->seq = seq; 3333 nd->seq = seq;
3340 /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ 3334 /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */
3341finish_open: 3335finish_open:
3342 error = complete_walk(nd); 3336 error = complete_walk(nd);
3343 if (error) { 3337 if (error)
3344 path_put(&save_parent);
3345 return error; 3338 return error;
3346 }
3347 audit_inode(nd->name, nd->path.dentry, 0); 3339 audit_inode(nd->name, nd->path.dentry, 0);
3348 error = -EISDIR; 3340 error = -EISDIR;
3349 if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) 3341 if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry))
@@ -3366,13 +3358,9 @@ finish_open_created:
3366 goto out; 3358 goto out;
3367 BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ 3359 BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
3368 error = vfs_open(&nd->path, file, current_cred()); 3360 error = vfs_open(&nd->path, file, current_cred());
3369 if (!error) { 3361 if (error)
3370 *opened |= FILE_OPENED;
3371 } else {
3372 if (error == -EOPENSTALE)
3373 goto stale_open;
3374 goto out; 3362 goto out;
3375 } 3363 *opened |= FILE_OPENED;
3376opened: 3364opened:
3377 error = open_check_o_direct(file); 3365 error = open_check_o_direct(file);
3378 if (!error) 3366 if (!error)
@@ -3388,26 +3376,7 @@ out:
3388 } 3376 }
3389 if (got_write) 3377 if (got_write)
3390 mnt_drop_write(nd->path.mnt); 3378 mnt_drop_write(nd->path.mnt);
3391 path_put(&save_parent);
3392 return error; 3379 return error;
3393
3394stale_open:
3395 /* If no saved parent or already retried then can't retry */
3396 if (!save_parent.dentry || retried)
3397 goto out;
3398
3399 BUG_ON(save_parent.dentry != dir);
3400 path_put(&nd->path);
3401 nd->path = save_parent;
3402 nd->inode = dir->d_inode;
3403 save_parent.mnt = NULL;
3404 save_parent.dentry = NULL;
3405 if (got_write) {
3406 mnt_drop_write(nd->path.mnt);
3407 got_write = false;
3408 }
3409 retried = true;
3410 goto retry_lookup;
3411} 3380}
3412 3381
3413static int do_tmpfile(struct nameidata *nd, unsigned flags, 3382static int do_tmpfile(struct nameidata *nd, unsigned flags,