diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-26 20:42:55 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-03-26 20:42:55 -0400 |
| commit | de55eb1d60d2ed0f1ba5e13226d91b3bfbe1c108 (patch) | |
| tree | 8f2a62f811562b4008dd1cd50a0ebf5603b13a76 | |
| parent | b175293ccc98ab84e93d25472d7422b4a897614b (diff) | |
| parent | e8cd81693bbbb15db57d3c9aa7dd90eda4842874 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"stable fodder; assorted deadlock fixes"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
vt: synchronize_rcu() under spinlock is not nice...
Nest rename_lock inside vfsmount_lock
Don't bother with redoing rw_verify_area() from default_file_splice_from()
| -rw-r--r-- | drivers/tty/vt/vc_screen.c | 6 | ||||
| -rw-r--r-- | fs/dcache.c | 16 | ||||
| -rw-r--r-- | fs/internal.h | 5 | ||||
| -rw-r--r-- | fs/read_write.c | 25 | ||||
| -rw-r--r-- | fs/splice.c | 4 |
5 files changed, 48 insertions, 8 deletions
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index e4ca345873c3..d7799deacb21 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c | |||
| @@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll) | |||
| 93 | static struct vcs_poll_data * | 93 | static struct vcs_poll_data * |
| 94 | vcs_poll_data_get(struct file *file) | 94 | vcs_poll_data_get(struct file *file) |
| 95 | { | 95 | { |
| 96 | struct vcs_poll_data *poll = file->private_data; | 96 | struct vcs_poll_data *poll = file->private_data, *kill = NULL; |
| 97 | 97 | ||
| 98 | if (poll) | 98 | if (poll) |
| 99 | return poll; | 99 | return poll; |
| @@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file) | |||
| 122 | file->private_data = poll; | 122 | file->private_data = poll; |
| 123 | } else { | 123 | } else { |
| 124 | /* someone else raced ahead of us */ | 124 | /* someone else raced ahead of us */ |
| 125 | vcs_poll_data_free(poll); | 125 | kill = poll; |
| 126 | poll = file->private_data; | 126 | poll = file->private_data; |
| 127 | } | 127 | } |
| 128 | spin_unlock(&file->f_lock); | 128 | spin_unlock(&file->f_lock); |
| 129 | if (kill) | ||
| 130 | vcs_poll_data_free(kill); | ||
| 129 | 131 | ||
| 130 | return poll; | 132 | return poll; |
| 131 | } | 133 | } |
diff --git a/fs/dcache.c b/fs/dcache.c index fbfae008ba44..e8bc3420d63e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -2542,7 +2542,6 @@ static int prepend_path(const struct path *path, | |||
| 2542 | bool slash = false; | 2542 | bool slash = false; |
| 2543 | int error = 0; | 2543 | int error = 0; |
| 2544 | 2544 | ||
| 2545 | br_read_lock(&vfsmount_lock); | ||
| 2546 | while (dentry != root->dentry || vfsmnt != root->mnt) { | 2545 | while (dentry != root->dentry || vfsmnt != root->mnt) { |
| 2547 | struct dentry * parent; | 2546 | struct dentry * parent; |
| 2548 | 2547 | ||
| @@ -2572,8 +2571,6 @@ static int prepend_path(const struct path *path, | |||
| 2572 | if (!error && !slash) | 2571 | if (!error && !slash) |
| 2573 | error = prepend(buffer, buflen, "/", 1); | 2572 | error = prepend(buffer, buflen, "/", 1); |
| 2574 | 2573 | ||
| 2575 | out: | ||
| 2576 | br_read_unlock(&vfsmount_lock); | ||
| 2577 | return error; | 2574 | return error; |
| 2578 | 2575 | ||
| 2579 | global_root: | 2576 | global_root: |
| @@ -2590,7 +2587,7 @@ global_root: | |||
| 2590 | error = prepend(buffer, buflen, "/", 1); | 2587 | error = prepend(buffer, buflen, "/", 1); |
| 2591 | if (!error) | 2588 | if (!error) |
| 2592 | error = is_mounted(vfsmnt) ? 1 : 2; | 2589 | error = is_mounted(vfsmnt) ? 1 : 2; |
| 2593 | goto out; | 2590 | return error; |
| 2594 | } | 2591 | } |
| 2595 | 2592 | ||
| 2596 | /** | 2593 | /** |
| @@ -2617,9 +2614,11 @@ char *__d_path(const struct path *path, | |||
| 2617 | int error; | 2614 | int error; |
| 2618 | 2615 | ||
| 2619 | prepend(&res, &buflen, "\0", 1); | 2616 | prepend(&res, &buflen, "\0", 1); |
| 2617 | br_read_lock(&vfsmount_lock); | ||
| 2620 | write_seqlock(&rename_lock); | 2618 | write_seqlock(&rename_lock); |
| 2621 | error = prepend_path(path, root, &res, &buflen); | 2619 | error = prepend_path(path, root, &res, &buflen); |
| 2622 | write_sequnlock(&rename_lock); | 2620 | write_sequnlock(&rename_lock); |
| 2621 | br_read_unlock(&vfsmount_lock); | ||
| 2623 | 2622 | ||
| 2624 | if (error < 0) | 2623 | if (error < 0) |
| 2625 | return ERR_PTR(error); | 2624 | return ERR_PTR(error); |
| @@ -2636,9 +2635,11 @@ char *d_absolute_path(const struct path *path, | |||
| 2636 | int error; | 2635 | int error; |
| 2637 | 2636 | ||
| 2638 | prepend(&res, &buflen, "\0", 1); | 2637 | prepend(&res, &buflen, "\0", 1); |
| 2638 | br_read_lock(&vfsmount_lock); | ||
| 2639 | write_seqlock(&rename_lock); | 2639 | write_seqlock(&rename_lock); |
| 2640 | error = prepend_path(path, &root, &res, &buflen); | 2640 | error = prepend_path(path, &root, &res, &buflen); |
| 2641 | write_sequnlock(&rename_lock); | 2641 | write_sequnlock(&rename_lock); |
| 2642 | br_read_unlock(&vfsmount_lock); | ||
| 2642 | 2643 | ||
| 2643 | if (error > 1) | 2644 | if (error > 1) |
| 2644 | error = -EINVAL; | 2645 | error = -EINVAL; |
| @@ -2702,11 +2703,13 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
| 2702 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | 2703 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
| 2703 | 2704 | ||
| 2704 | get_fs_root(current->fs, &root); | 2705 | get_fs_root(current->fs, &root); |
| 2706 | br_read_lock(&vfsmount_lock); | ||
| 2705 | write_seqlock(&rename_lock); | 2707 | write_seqlock(&rename_lock); |
| 2706 | error = path_with_deleted(path, &root, &res, &buflen); | 2708 | error = path_with_deleted(path, &root, &res, &buflen); |
| 2709 | write_sequnlock(&rename_lock); | ||
| 2710 | br_read_unlock(&vfsmount_lock); | ||
| 2707 | if (error < 0) | 2711 | if (error < 0) |
| 2708 | res = ERR_PTR(error); | 2712 | res = ERR_PTR(error); |
| 2709 | write_sequnlock(&rename_lock); | ||
| 2710 | path_put(&root); | 2713 | path_put(&root); |
| 2711 | return res; | 2714 | return res; |
| 2712 | } | 2715 | } |
| @@ -2830,6 +2833,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
| 2830 | get_fs_root_and_pwd(current->fs, &root, &pwd); | 2833 | get_fs_root_and_pwd(current->fs, &root, &pwd); |
| 2831 | 2834 | ||
| 2832 | error = -ENOENT; | 2835 | error = -ENOENT; |
| 2836 | br_read_lock(&vfsmount_lock); | ||
| 2833 | write_seqlock(&rename_lock); | 2837 | write_seqlock(&rename_lock); |
| 2834 | if (!d_unlinked(pwd.dentry)) { | 2838 | if (!d_unlinked(pwd.dentry)) { |
| 2835 | unsigned long len; | 2839 | unsigned long len; |
| @@ -2839,6 +2843,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
| 2839 | prepend(&cwd, &buflen, "\0", 1); | 2843 | prepend(&cwd, &buflen, "\0", 1); |
| 2840 | error = prepend_path(&pwd, &root, &cwd, &buflen); | 2844 | error = prepend_path(&pwd, &root, &cwd, &buflen); |
| 2841 | write_sequnlock(&rename_lock); | 2845 | write_sequnlock(&rename_lock); |
| 2846 | br_read_unlock(&vfsmount_lock); | ||
| 2842 | 2847 | ||
| 2843 | if (error < 0) | 2848 | if (error < 0) |
| 2844 | goto out; | 2849 | goto out; |
| @@ -2859,6 +2864,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
| 2859 | } | 2864 | } |
| 2860 | } else { | 2865 | } else { |
| 2861 | write_sequnlock(&rename_lock); | 2866 | write_sequnlock(&rename_lock); |
| 2867 | br_read_unlock(&vfsmount_lock); | ||
| 2862 | } | 2868 | } |
| 2863 | 2869 | ||
| 2864 | out: | 2870 | out: |
diff --git a/fs/internal.h b/fs/internal.h index 507141fceb99..4be78237d896 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -125,3 +125,8 @@ extern int invalidate_inodes(struct super_block *, bool); | |||
| 125 | * dcache.c | 125 | * dcache.c |
| 126 | */ | 126 | */ |
| 127 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | 127 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); |
| 128 | |||
| 129 | /* | ||
| 130 | * read_write.c | ||
| 131 | */ | ||
| 132 | extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); | ||
diff --git a/fs/read_write.c b/fs/read_write.c index a698eff457fb..f7b5a23b804b 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/splice.h> | 17 | #include <linux/splice.h> |
| 18 | #include <linux/compat.h> | 18 | #include <linux/compat.h> |
| 19 | #include "read_write.h" | 19 | #include "read_write.h" |
| 20 | #include "internal.h" | ||
| 20 | 21 | ||
| 21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
| 22 | #include <asm/unistd.h> | 23 | #include <asm/unistd.h> |
| @@ -417,6 +418,30 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof | |||
| 417 | 418 | ||
| 418 | EXPORT_SYMBOL(do_sync_write); | 419 | EXPORT_SYMBOL(do_sync_write); |
| 419 | 420 | ||
| 421 | ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) | ||
| 422 | { | ||
| 423 | mm_segment_t old_fs; | ||
| 424 | const char __user *p; | ||
| 425 | ssize_t ret; | ||
| 426 | |||
| 427 | old_fs = get_fs(); | ||
| 428 | set_fs(get_ds()); | ||
| 429 | p = (__force const char __user *)buf; | ||
| 430 | if (count > MAX_RW_COUNT) | ||
| 431 | count = MAX_RW_COUNT; | ||
| 432 | if (file->f_op->write) | ||
| 433 | ret = file->f_op->write(file, p, count, pos); | ||
| 434 | else | ||
| 435 | ret = do_sync_write(file, p, count, pos); | ||
| 436 | set_fs(old_fs); | ||
| 437 | if (ret > 0) { | ||
| 438 | fsnotify_modify(file); | ||
| 439 | add_wchar(current, ret); | ||
