diff options
author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:48 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:29:25 -0400 |
commit | 4a3fd211ccfc08a88edc824300e25a87785c6a5f (patch) | |
tree | 99f1a76a99fa78464b8de731f7fdb5bcc9667a5e /ipc | |
parent | 42a74f206b914db13ee1f5ae932dcd91a77c8579 (diff) |
[PATCH] r/o bind mounts: elevate write count for open()s
This is the first really tricky patch in the series. It elevates the writer
count on a mount each time a non-special file is opened for write.
We used to do this in may_open(), but Miklos pointed out that __dentry_open()
is used as well to create filps. This will cover even those cases, while a
call in may_open() would not have.
There is also an elevated count around the vfs_create() call in open_namei().
See the comments for more details, but we need this to fix a 'create, remount,
fail r/w open()' race.
Some filesystems forego the use of normal vfs calls to create
struct files. Make sure that these users elevate the mnt
writer count because they will get __fput(), and we need
to make sure they're balanced.
Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/mqueue.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 34262c11f480..94fd3b08fb77 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
@@ -598,6 +598,7 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry, | |||
598 | int oflag, mode_t mode, struct mq_attr __user *u_attr) | 598 | int oflag, mode_t mode, struct mq_attr __user *u_attr) |
599 | { | 599 | { |
600 | struct mq_attr attr; | 600 | struct mq_attr attr; |
601 | struct file *result; | ||
601 | int ret; | 602 | int ret; |
602 | 603 | ||
603 | if (u_attr) { | 604 | if (u_attr) { |
@@ -612,13 +613,24 @@ static struct file *do_create(struct dentry *dir, struct dentry *dentry, | |||
612 | } | 613 | } |
613 | 614 | ||
614 | mode &= ~current->fs->umask; | 615 | mode &= ~current->fs->umask; |
616 | ret = mnt_want_write(mqueue_mnt); | ||
617 | if (ret) | ||
618 | goto out; | ||
615 | ret = vfs_create(dir->d_inode, dentry, mode, NULL); | 619 | ret = vfs_create(dir->d_inode, dentry, mode, NULL); |
616 | dentry->d_fsdata = NULL; | 620 | dentry->d_fsdata = NULL; |
617 | if (ret) | 621 | if (ret) |
618 | goto out; | 622 | goto out_drop_write; |
619 | 623 | ||
620 | return dentry_open(dentry, mqueue_mnt, oflag); | 624 | result = dentry_open(dentry, mqueue_mnt, oflag); |
625 | /* | ||
626 | * dentry_open() took a persistent mnt_want_write(), | ||
627 | * so we can now drop this one. | ||
628 | */ | ||
629 | mnt_drop_write(mqueue_mnt); | ||
630 | return result; | ||
621 | 631 | ||
632 | out_drop_write: | ||
633 | mnt_drop_write(mqueue_mnt); | ||
622 | out: | 634 | out: |
623 | dput(dentry); | 635 | dput(dentry); |
624 | mntput(mqueue_mnt); | 636 | mntput(mqueue_mnt); |