Skip to content

Commit de55eb1

Browse files
committed
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()
2 parents b175293 + e8cd816 commit de55eb1

File tree

5 files changed

+48
-8
lines changed

5 files changed

+48
-8
lines changed

drivers/tty/vt/vc_screen.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll)
9393
static struct vcs_poll_data *
9494
vcs_poll_data_get(struct file *file)
9595
{
96-
struct vcs_poll_data *poll = file->private_data;
96+
struct vcs_poll_data *poll = file->private_data, *kill = NULL;
9797

9898
if (poll)
9999
return poll;
@@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file)
122122
file->private_data = poll;
123123
} else {
124124
/* someone else raced ahead of us */
125-
vcs_poll_data_free(poll);
125+
kill = poll;
126126
poll = file->private_data;
127127
}
128128
spin_unlock(&file->f_lock);
129+
if (kill)
130+
vcs_poll_data_free(kill);
129131

130132
return poll;
131133
}

fs/dcache.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,7 +2542,6 @@ static int prepend_path(const struct path *path,
25422542
bool slash = false;
25432543
int error = 0;
25442544

2545-
br_read_lock(&vfsmount_lock);
25462545
while (dentry != root->dentry || vfsmnt != root->mnt) {
25472546
struct dentry * parent;
25482547

@@ -2572,8 +2571,6 @@ static int prepend_path(const struct path *path,
25722571
if (!error && !slash)
25732572
error = prepend(buffer, buflen, "/", 1);
25742573

2575-
out:
2576-
br_read_unlock(&vfsmount_lock);
25772574
return error;
25782575

25792576
global_root:
@@ -2590,7 +2587,7 @@ static int prepend_path(const struct path *path,
25902587
error = prepend(buffer, buflen, "/", 1);
25912588
if (!error)
25922589
error = is_mounted(vfsmnt) ? 1 : 2;
2593-
goto out;
2590+
return error;
25942591
}
25952592

25962593
/**
@@ -2617,9 +2614,11 @@ char *__d_path(const struct path *path,
26172614
int error;
26182615

26192616
prepend(&res, &buflen, "\0", 1);
2617+
br_read_lock(&vfsmount_lock);
26202618
write_seqlock(&rename_lock);
26212619
error = prepend_path(path, root, &res, &buflen);
26222620
write_sequnlock(&rename_lock);
2621+
br_read_unlock(&vfsmount_lock);
26232622

26242623
if (error < 0)
26252624
return ERR_PTR(error);
@@ -2636,9 +2635,11 @@ char *d_absolute_path(const struct path *path,
26362635
int error;
26372636

26382637
prepend(&res, &buflen, "\0", 1);
2638+
br_read_lock(&vfsmount_lock);
26392639
write_seqlock(&rename_lock);
26402640
error = prepend_path(path, &root, &res, &buflen);
26412641
write_sequnlock(&rename_lock);
2642+
br_read_unlock(&vfsmount_lock);
26422643

26432644
if (error > 1)
26442645
error = -EINVAL;
@@ -2702,11 +2703,13 @@ char *d_path(const struct path *path, char *buf, int buflen)
27022703
return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
27032704

27042705
get_fs_root(current->fs, &root);
2706+
br_read_lock(&vfsmount_lock);
27052707
write_seqlock(&rename_lock);
27062708
error = path_with_deleted(path, &root, &res, &buflen);
2709+
write_sequnlock(&rename_lock);
2710+
br_read_unlock(&vfsmount_lock);
27072711
if (error < 0)
27082712
res = ERR_PTR(error);
2709-
write_sequnlock(&rename_lock);
27102713
path_put(&root);
27112714
return res;
27122715
}
@@ -2830,6 +2833,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
28302833
get_fs_root_and_pwd(current->fs, &root, &pwd);
28312834

28322835
error = -ENOENT;
2836+
br_read_lock(&vfsmount_lock);
28332837
write_seqlock(&rename_lock);
28342838
if (!d_unlinked(pwd.dentry)) {
28352839
unsigned long len;
@@ -2839,6 +2843,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
28392843
prepend(&cwd, &buflen, "\0", 1);
28402844
error = prepend_path(&pwd, &root, &cwd, &buflen);
28412845
write_sequnlock(&rename_lock);
2846+
br_read_unlock(&vfsmount_lock);
28422847

28432848
if (error < 0)
28442849
goto out;
@@ -2859,6 +2864,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
28592864
}
28602865
} else {
28612866
write_sequnlock(&rename_lock);
2867+
br_read_unlock(&vfsmount_lock);
28622868
}
28632869

28642870
out:

fs/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,8 @@ extern int invalidate_inodes(struct super_block *, bool);
125125
* dcache.c
126126
*/
127127
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 *);

fs/read_write.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/splice.h>
1818
#include <linux/compat.h>
1919
#include "read_write.h"
20+
#include "internal.h"
2021

2122
#include <asm/uaccess.h>
2223
#include <asm/unistd.h>
@@ -417,6 +418,30 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof
417418

418419
EXPORT_SYMBOL(do_sync_write);
419420

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);
440+
}
441+
inc_syscw(current);
442+
return ret;
443+
}
444+
420445
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
421446
{
422447
ssize_t ret;

fs/splice.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/security.h>
3232
#include <linux/gfp.h>
3333
#include <linux/socket.h>
34+
#include "internal.h"
3435

3536
/*
3637
* Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -1048,9 +1049,10 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
10481049
{
10491050
int ret;
10501051
void *data;
1052+
loff_t tmp = sd->pos;
10511053

10521054
data = buf->ops->map(pipe, buf, 0);
1053-
ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos);
1055+
ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp);
10541056
buf->ops->unmap(pipe, buf, data);
10551057

10561058
return ret;

0 commit comments

Comments
 (0)