aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-06-07 23:41:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-06-07 23:41:36 -0400
commitc8ae067f2635be0f8c7e5db1bb74b757d623e05b (patch)
treefbb47b67af51d6ab824094d1c9a178543df596fb
parent2051877c4c8526abc0a1d514e76f95610b4ab8f3 (diff)
parent1607f09c226d1378439c411baaaa020042750338 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro: "Fixes for crap of assorted ages: EOPENSTALE one is 4.2+, autofs one is 4.6, d_walk - 3.2+. The atomic_open() and coredump ones are regressions from this window" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: coredump: fix dumping through pipes fix a regression in atomic_open() fix d_walk()/non-delayed __d_free() race autofs braino fix for do_last() fix EOPENSTALE bug in do_last()
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c2
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/binfmt_elf_fdpic.c2
-rw-r--r--fs/coredump.c4
-rw-r--r--fs/dcache.c4
-rw-r--r--fs/namei.c61
-rw-r--r--include/linux/binfmts.h1
7 files changed, 24 insertions, 52 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 84fb984f29c1..85c85eb3e245 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -172,7 +172,7 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i,
172 if (rc < 0) 172 if (rc < 0)
173 goto out; 173 goto out;
174 174
175 skip = roundup(cprm->file->f_pos - total + sz, 4) - cprm->file->f_pos; 175 skip = roundup(cprm->pos - total + sz, 4) - cprm->pos;
176 if (!dump_skip(cprm, skip)) 176 if (!dump_skip(cprm, skip))
177 goto Eio; 177 goto Eio;
178out: 178out:
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index e158b22ef32f..a7a28110dc80 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -2275,7 +2275,7 @@ static int elf_core_dump(struct coredump_params *cprm)
2275 goto end_coredump; 2275 goto end_coredump;
2276 2276
2277 /* Align to page */ 2277 /* Align to page */
2278 if (!dump_skip(cprm, dataoff - cprm->file->f_pos)) 2278 if (!dump_skip(cprm, dataoff - cprm->pos))
2279 goto end_coredump; 2279 goto end_coredump;
2280 2280
2281 for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; 2281 for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 71ade0e556b7..203589311bf8 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1787,7 +1787,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
1787 goto end_coredump; 1787 goto end_coredump;
1788 } 1788 }
1789 1789
1790 if (!dump_skip(cprm, dataoff - cprm->file->f_pos)) 1790 if (!dump_skip(cprm, dataoff - cprm->pos))
1791 goto end_coredump; 1791 goto end_coredump;
1792 1792
1793 if (!elf_fdpic_dump_segments(cprm)) 1793 if (!elf_fdpic_dump_segments(cprm))
diff --git a/fs/coredump.c b/fs/coredump.c
index 38a7ab87e10a..281b768000e6 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -794,6 +794,7 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
794 return 0; 794 return 0;
795 file->f_pos = pos; 795 file->f_pos = pos;
796 cprm->written += n; 796 cprm->written += n;
797 cprm->pos += n;
797 nr -= n; 798 nr -= n;
798 } 799 }
799 return 1; 800 return 1;
@@ -808,6 +809,7 @@ int dump_skip(struct coredump_params *cprm, size_t nr)
808 if (dump_interrupted() || 809 if (dump_interrupted() ||
809 file->f_op->llseek(file, nr, SEEK_CUR) < 0) 810 file->f_op->llseek(file, nr, SEEK_CUR) < 0)
810 return 0; 811 return 0;
812 cprm->pos += nr;
811 return 1; 813 return 1;
812 } else { 814 } else {
813 while (nr > PAGE_SIZE) { 815 while (nr > PAGE_SIZE) {
@@ -822,7 +824,7 @@ EXPORT_SYMBOL(dump_skip);
822 824
823int dump_align(struct coredump_params *cprm, int align) 825int dump_align(struct coredump_params *cprm, int align)
824{ 826{
825 unsigned mod = cprm->file->f_pos & (align - 1); 827 unsigned mod = cprm->pos & (align - 1);
826 if (align & (align - 1)) 828 if (align & (align - 1))
827 return 0; 829 return 0;
828 return mod ? dump_skip(cprm, align - mod) : 1; 830 return mod ? dump_skip(cprm, align - mod) : 1;
diff --git a/fs/dcache.c b/fs/dcache.c
index ad4a542e9bab..817c243c1ff1 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1636,7 +1636,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
1636 struct dentry *dentry = __d_alloc(parent->d_sb, name); 1636 struct dentry *dentry = __d_alloc(parent->d_sb, name);
1637 if (!dentry) 1637 if (!dentry)
1638 return NULL; 1638 return NULL;
1639 1639 dentry->d_flags |= DCACHE_RCUACCESS;
1640 spin_lock(&parent->d_lock); 1640 spin_lock(&parent->d_lock);
1641 /* 1641 /*
1642 * don't need child lock because it is not subject 1642 * don't need child lock because it is not subject
@@ -2358,7 +2358,6 @@ static void __d_rehash(struct dentry * entry, struct hlist_bl_head *b)
2358{ 2358{
2359 BUG_ON(!d_unhashed(entry)); 2359 BUG_ON(!d_unhashed(entry));
2360 hlist_bl_lock(b); 2360 hlist_bl_lock(b);
2361 entry->d_flags |= DCACHE_RCUACCESS;
2362 hlist_bl_add_head_rcu(&entry->d_hash, b); 2361 hlist_bl_add_head_rcu(&entry->d_hash, b);
2363 hlist_bl_unlock(b); 2362 hlist_bl_unlock(b);
2364} 2363}
@@ -2843,6 +2842,7 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
2843 /* ... and switch them in the tree */ 2842 /* ... and switch them in the tree */
2844 if (IS_ROOT(dentry)) { 2843 if (IS_ROOT(dentry)) {
2845 /* splicing a tree */ 2844 /* splicing a tree */
2845 dentry->d_flags |= DCACHE_RCUACCESS;
2846 dentry->d_parent = target->d_parent; 2846 dentry->d_parent = target->d_parent;
2847 target->d_parent = target; 2847 target->d_parent = target;
2848 list_del_init(&target->d_child); 2848 list_del_init(&target->d_child);
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,
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 576e4639ca60..314b3caa701c 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -65,6 +65,7 @@ struct coredump_params {
65 unsigned long limit; 65 unsigned long limit;
66 unsigned long mm_flags; 66 unsigned long mm_flags;
67 loff_t written; 67 loff_t written;
68 loff_t pos;
68}; 69};
69 70
70/* 71/*