anonfd: Allow making anon files read-only
authorRoland Dreier <rdreier@cisco.com>
Fri, 18 Dec 2009 17:41:24 +0000 (09:41 -0800)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 22 Dec 2009 17:27:34 +0000 (12:27 -0500)
It seems a couple places such as arch/ia64/kernel/perfmon.c and
drivers/infiniband/core/uverbs_main.c could use anon_inode_getfile()
instead of a private pseudo-fs + alloc_file(), if only there were a way
to get a read-only file.  So provide this by having anon_inode_getfile()
create a read-only file if we pass O_RDONLY in flags.

Signed-off-by: Roland Dreier <rolandd@cisco.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/anon_inodes.c
fs/eventfd.c
fs/eventpoll.c
fs/signalfd.c
fs/timerfd.c
kernel/perf_event.c
virt/kvm/kvm_main.c

index 2c994591f4d7a4fe89021c00110df70b5df8a433..598237e972212b4908dd61db2824107c92c0f2f2 100644 (file)
@@ -89,11 +89,19 @@ struct file *anon_inode_getfile(const char *name,
        struct qstr this;
        struct path path;
        struct file *file;
+       fmode_t mode;
        int error;
 
        if (IS_ERR(anon_inode_inode))
                return ERR_PTR(-ENODEV);
 
+       switch (flags & O_ACCMODE) {
+       case O_RDONLY: mode = FMODE_READ;               break;
+       case O_WRONLY: mode = FMODE_WRITE;              break;
+       case O_RDWR:   mode = FMODE_READ | FMODE_WRITE; break;
+       default:       return ERR_PTR(-EINVAL);
+       }
+
        if (fops->owner && !try_module_get(fops->owner))
                return ERR_PTR(-ENOENT);
 
@@ -121,13 +129,13 @@ struct file *anon_inode_getfile(const char *name,
        d_instantiate(path.dentry, anon_inode_inode);
 
        error = -ENFILE;
-       file = alloc_file(&path, FMODE_READ | FMODE_WRITE, fops);
+       file = alloc_file(&path, mode, fops);
        if (!file)
                goto err_dput;
        file->f_mapping = anon_inode_inode->i_mapping;
 
        file->f_pos = 0;
-       file->f_flags = O_RDWR | (flags & O_NONBLOCK);
+       file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
        file->f_version = 0;
        file->private_data = priv;
 
index 8b47e4200e65e00a64be1bb60a80091b6940ddb2..d26402ff06eaa1fbef5e347e627b029cc8239e8c 100644 (file)
@@ -339,7 +339,7 @@ struct file *eventfd_file_create(unsigned int count, int flags)
        ctx->flags = flags;
 
        file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx,
-                                 flags & EFD_SHARED_FCNTL_FLAGS);
+                                 O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS));
        if (IS_ERR(file))
                eventfd_free_ctx(ctx);
 
index 366c503f9657376e969b590cf182da5939dcb1ca..bd056a5b4efc59ceccb8b121100d40e2bb16cf3f 100644 (file)
@@ -1206,7 +1206,7 @@ SYSCALL_DEFINE1(epoll_create1, int, flags)
         * a file structure and a free file descriptor.
         */
        error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep,
-                                flags & O_CLOEXEC);
+                                O_RDWR | (flags & O_CLOEXEC));
        if (error < 0)
                ep_free(ep);
 
index b07565c9438672015aa041e3fb57e4b01ca6e27c..1dabe4ee02fe93931ae741344405bee1daca3cd0 100644 (file)
@@ -236,7 +236,7 @@ SYSCALL_DEFINE4(signalfd4, int, ufd, sigset_t __user *, user_mask,
                 * anon_inode_getfd() will install the fd.
                 */
                ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx,
-                                      flags & (O_CLOEXEC | O_NONBLOCK));
+                                      O_RDWR | (flags & (O_CLOEXEC | O_NONBLOCK)));
                if (ufd < 0)
                        kfree(ctx);
        } else {
index b042bd7034b1fc74d6cd6399e24b3a2057689a2f..1bfc95ad5f716a70dda692a250aee1231b4f608e 100644 (file)
@@ -200,7 +200,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
        hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
 
        ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
-                              flags & TFD_SHARED_FCNTL_FLAGS);
+                              O_RDWR | (flags & TFD_SHARED_FCNTL_FLAGS));
        if (ufd < 0)
                kfree(ctx);
 
index e0eb4a2fe1833e9de3b5ff10f6959358d31e2806..1f38270f08c7d62613665ac6cbb07fccef1c51b6 100644 (file)
@@ -4724,7 +4724,7 @@ SYSCALL_DEFINE5(perf_event_open,
        if (IS_ERR(event))
                goto err_put_context;
 
-       err = anon_inode_getfd("[perf_event]", &perf_fops, event, 0);
+       err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
        if (err < 0)
                goto err_free_put_context;
 
index e1f2bf8d7b1e06903ea499df764a2c0dbe1a66e1..b5af88167613ded2aba4ebcdca2cb702d47c84eb 100644 (file)
@@ -1177,7 +1177,7 @@ static struct file_operations kvm_vcpu_fops = {
  */
 static int create_vcpu_fd(struct kvm_vcpu *vcpu)
 {
-       return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, 0);
+       return anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu, O_RDWR);
 }
 
 /*
@@ -1638,7 +1638,7 @@ static int kvm_dev_ioctl_create_vm(void)
        kvm = kvm_create_vm();
        if (IS_ERR(kvm))
                return PTR_ERR(kvm);
-       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, 0);
+       fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm, O_RDWR);
        if (fd < 0)
                kvm_put_kvm(kvm);