diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-07 23:41:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-06-07 23:41:36 -0400 |
commit | c8ae067f2635be0f8c7e5db1bb74b757d623e05b (patch) | |
tree | fbb47b67af51d6ab824094d1c9a178543df596fb | |
parent | 2051877c4c8526abc0a1d514e76f95610b4ab8f3 (diff) | |
parent | 1607f09c226d1378439c411baaaa020042750338 (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.c | 2 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 2 | ||||
-rw-r--r-- | fs/binfmt_elf_fdpic.c | 2 | ||||
-rw-r--r-- | fs/coredump.c | 4 | ||||
-rw-r--r-- | fs/dcache.c | 4 | ||||
-rw-r--r-- | fs/namei.c | 61 | ||||
-rw-r--r-- | include/linux/binfmts.h | 1 |
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; |
178 | out: | 178 | out: |
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 | ||
823 | int dump_align(struct coredump_params *cprm, int align) | 825 | int 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 | ||
3249 | retry_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); |
3322 | finish_lookup: | 3323 | finish_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... */ |
3341 | finish_open: | 3335 | finish_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; |
3376 | opened: | 3364 | opened: |
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 | |||
3394 | stale_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 | ||
3413 | static int do_tmpfile(struct nameidata *nd, unsigned flags, | 3382 | static 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 | /* |