aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavide Libenzi <davidel@xmailserver.org>2009-09-22 19:43:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:29 -0400
commit562787a5c32ccdf182de27793a83a9f2ee86cd77 (patch)
tree3308afd59d3b7449afa3d6a6cd624d06ce035e88
parent515350b6fd041396f425180589e08812dd13615f (diff)
anonfd: split interface into file creation and install
Split the anonfd interface into a bare file pointer creation one, and a file pointer creation plus install one. There are cases, like the usage of eventfds inside other kernel interfaces, where the file pointer created by anonfd needs to be used inside the initialization of other structures. As it is right now, as soon as anon_inode_getfd() returns, the kenrle can race with userspace closing the newly installed file descriptor. This patch, while keeping the old anon_inode_getfd(), introduces a new anon_inode_getfile() (whose services are reused in anon_inode_getfd()) that allows to split the file creation phase and the fd install one. Once all the kernel structures are initialized, the code can call the proper fd_install(). Gregory manifested the need for something like this inside KVM. Signed-off-by: Davide Libenzi <davidel@xmailserver.org> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: James Morris <jmorris@namei.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Gregory Haskins <ghaskins@novell.com> Acked-by: Serge Hallyn <serue@us.ibm.com> Acked-by: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/anon_inodes.c68
-rw-r--r--fs/eventfd.c67
-rw-r--r--include/linux/anon_inodes.h3
-rw-r--r--include/linux/eventfd.h6
4 files changed, 114 insertions, 30 deletions
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 47d4a01c5393..d11c51fc2a3f 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -77,28 +77,24 @@ static const struct address_space_operations anon_aops = {
77 * 77 *
78 * Creates a new file by hooking it on a single inode. This is useful for files 78 * Creates a new file by hooking it on a single inode. This is useful for files
79 * that do not need to have a full-fledged inode in order to operate correctly. 79 * that do not need to have a full-fledged inode in order to operate correctly.
80 * All the files created with anon_inode_getfd() will share a single inode, 80 * All the files created with anon_inode_getfile() will share a single inode,
81 * hence saving memory and avoiding code duplication for the file/inode/dentry 81 * hence saving memory and avoiding code duplication for the file/inode/dentry
82 * setup. Returns new descriptor or -error. 82 * setup. Returns the newly created file* or an error pointer.
83 */ 83 */
84int anon_inode_getfd(const char *name, const struct file_operations *fops, 84struct file *anon_inode_getfile(const char *name,
85 void *priv, int flags) 85 const struct file_operations *fops,
86 void *priv, int flags)
86{ 87{
87 struct qstr this; 88 struct qstr this;
88 struct dentry *dentry; 89 struct dentry *dentry;
89 struct file *file; 90 struct file *file;
90 int error, fd; 91 int error;
91 92
92 if (IS_ERR(anon_inode_inode)) 93 if (IS_ERR(anon_inode_inode))
93 return -ENODEV; 94 return ERR_PTR(-ENODEV);
94 95
95 if (fops->owner && !try_module_get(fops->owner)) 96 if (fops->owner && !try_module_get(fops->owner))
96 return -ENOENT; 97 return ERR_PTR(-ENOENT);
97
98 error = get_unused_fd_flags(flags);
99 if (error < 0)
100 goto err_module;
101 fd = error;
102 98
103 /* 99 /*
104 * Link the inode to a directory entry by creating a unique name 100 * Link the inode to a directory entry by creating a unique name
@@ -110,7 +106,7 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
110 this.hash = 0; 106 this.hash = 0;
111 dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); 107 dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
112 if (!dentry) 108 if (!dentry)
113 goto err_put_unused_fd; 109 goto err_module;
114 110
115 /* 111 /*
116 * We know the anon_inode inode count is always greater than zero, 112 * We know the anon_inode inode count is always greater than zero,
@@ -136,16 +132,54 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
136 file->f_version = 0; 132 file->f_version = 0;
137 file->private_data = priv; 133 file->private_data = priv;
138 134
135 return file;
136
137err_dput:
138 dput(dentry);
139err_module:
140 module_put(fops->owner);
141 return ERR_PTR(error);
142}
143EXPORT_SYMBOL_GPL(anon_inode_getfile);
144
145/**
146 * anon_inode_getfd - creates a new file instance by hooking it up to an
147 * anonymous inode, and a dentry that describe the "class"
148 * of the file
149 *
150 * @name: [in] name of the "class" of the new file
151 * @fops: [in] file operations for the new file
152 * @priv: [in] private data for the new file (will be file's private_data)
153 * @flags: [in] flags
154 *
155 * Creates a new file by hooking it on a single inode. This is useful for files
156 * that do not need to have a full-fledged inode in order to operate correctly.
157 * All the files created with anon_inode_getfd() will share a single inode,
158 * hence saving memory and avoiding code duplication for the file/inode/dentry
159 * setup. Returns new descriptor or an error code.
160 */
161int anon_inode_getfd(const char *name, const struct file_operations *fops,
162 void *priv, int flags)
163{
164 int error, fd;
165 struct file *file;
166
167 error = get_unused_fd_flags(flags);
168 if (error < 0)
169 return error;
170 fd = error;
171
172 file = anon_inode_getfile(name, fops, priv, flags);
173 if (IS_ERR(file)) {
174 error = PTR_ERR(file);
175 goto err_put_unused_fd;
176 }
139 fd_install(fd, file); 177 fd_install(fd, file);
140 178
141 return fd; 179 return fd;
142 180
143err_dput:
144 dput(dentry);
145err_put_unused_fd: 181err_put_unused_fd:
146 put_unused_fd(fd); 182 put_unused_fd(fd);
147err_module:
148 module_put(fops->owner);
149 return error; 183 return error;
150} 184}
151EXPORT_SYMBOL_GPL(anon_inode_getfd); 185EXPORT_SYMBOL_GPL(anon_inode_getfd);
diff --git a/fs/eventfd.c b/fs/eventfd.c
index 31d12de83a2a..8b47e4200e65 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -68,11 +68,16 @@ int eventfd_signal(struct eventfd_ctx *ctx, int n)
68} 68}
69EXPORT_SYMBOL_GPL(eventfd_signal); 69EXPORT_SYMBOL_GPL(eventfd_signal);
70 70
71static void eventfd_free_ctx(struct eventfd_ctx *ctx)
72{
73 kfree(ctx);
74}
75
71static void eventfd_free(struct kref *kref) 76static void eventfd_free(struct kref *kref)
72{ 77{
73 struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref); 78 struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref);
74 79
75 kfree(ctx); 80 eventfd_free_ctx(ctx);
76} 81}
77 82
78/** 83/**
@@ -298,9 +303,23 @@ struct eventfd_ctx *eventfd_ctx_fileget(struct file *file)
298} 303}
299EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); 304EXPORT_SYMBOL_GPL(eventfd_ctx_fileget);
300 305
301SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) 306/**
307 * eventfd_file_create - Creates an eventfd file pointer.
308 * @count: Initial eventfd counter value.
309 * @flags: Flags for the eventfd file.
310 *
311 * This function creates an eventfd file pointer, w/out installing it into
312 * the fd table. This is useful when the eventfd file is used during the
313 * initialization of data structures that require extra setup after the eventfd
314 * creation. So the eventfd creation is split into the file pointer creation
315 * phase, and the file descriptor installation phase.
316 * In this way races with userspace closing the newly installed file descriptor
317 * can be avoided.
318 * Returns an eventfd file pointer, or a proper error pointer.
319 */
320struct file *eventfd_file_create(unsigned int count, int flags)
302{ 321{
303 int fd; 322 struct file *file;
304 struct eventfd_ctx *ctx; 323 struct eventfd_ctx *ctx;
305 324
306 /* Check the EFD_* constants for consistency. */ 325 /* Check the EFD_* constants for consistency. */
@@ -308,26 +327,48 @@ SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
308 BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); 327 BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK);
309 328
310 if (flags & ~EFD_FLAGS_SET) 329 if (flags & ~EFD_FLAGS_SET)
311 return -EINVAL; 330 return ERR_PTR(-EINVAL);
312 331
313 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); 332 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
314 if (!ctx) 333 if (!ctx)
315 return -ENOMEM; 334 return ERR_PTR(-ENOMEM);
316 335
317 kref_init(&ctx->kref); 336 kref_init(&ctx->kref);
318 init_waitqueue_head(&ctx->wqh); 337 init_waitqueue_head(&ctx->wqh);
319 ctx->count = count; 338 ctx->count = count;
320 ctx->flags = flags; 339 ctx->flags = flags;
321 340
322 /* 341 file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx,
323 * When we call this, the initialization must be complete, since 342 flags & EFD_SHARED_FCNTL_FLAGS);
324 * anon_inode_getfd() will install the fd. 343 if (IS_ERR(file))
325 */ 344 eventfd_free_ctx(ctx);
326 fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx, 345
327 flags & EFD_SHARED_FCNTL_FLAGS); 346 return file;
328 if (fd < 0) 347}
329 kfree(ctx); 348
349SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags)
350{
351 int fd, error;
352 struct file *file;
353
354 error = get_unused_fd_flags(flags & EFD_SHARED_FCNTL_FLAGS);
355 if (error < 0)
356 return error;
357 fd = error;
358
359 file = eventfd_file_create(count, flags);
360 if (IS_ERR(file)) {
361 error = PTR_ERR(file);
362 goto err_put_unused_fd;
363 }
364 fd_install(fd, file);
365
330 return fd; 366 return fd;
367
368err_put_unused_fd:
369 put_unused_fd(fd);
370
371 return error;
331} 372}
332 373
333SYSCALL_DEFINE1(eventfd, unsigned int, count) 374SYSCALL_DEFINE1(eventfd, unsigned int, count)
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
index e0a0cdc2da43..69a21e0ebd33 100644
--- a/include/linux/anon_inodes.h
+++ b/include/linux/anon_inodes.h
@@ -8,6 +8,9 @@
8#ifndef _LINUX_ANON_INODES_H 8#ifndef _LINUX_ANON_INODES_H
9#define _LINUX_ANON_INODES_H 9#define _LINUX_ANON_INODES_H
10 10
11struct file *anon_inode_getfile(const char *name,
12 const struct file_operations *fops,
13 void *priv, int flags);
11int anon_inode_getfd(const char *name, const struct file_operations *fops, 14int anon_inode_getfd(const char *name, const struct file_operations *fops,
12 void *priv, int flags); 15 void *priv, int flags);
13 16
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
index 3b85ba6479f4..94dd10366a78 100644
--- a/include/linux/eventfd.h
+++ b/include/linux/eventfd.h
@@ -27,6 +27,7 @@
27 27
28#ifdef CONFIG_EVENTFD 28#ifdef CONFIG_EVENTFD
29 29
30struct file *eventfd_file_create(unsigned int count, int flags);
30struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx); 31struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx);
31void eventfd_ctx_put(struct eventfd_ctx *ctx); 32void eventfd_ctx_put(struct eventfd_ctx *ctx);
32struct file *eventfd_fget(int fd); 33struct file *eventfd_fget(int fd);
@@ -40,6 +41,11 @@ int eventfd_signal(struct eventfd_ctx *ctx, int n);
40 * Ugly ugly ugly error layer to support modules that uses eventfd but 41 * Ugly ugly ugly error layer to support modules that uses eventfd but
41 * pretend to work in !CONFIG_EVENTFD configurations. Namely, AIO. 42 * pretend to work in !CONFIG_EVENTFD configurations. Namely, AIO.
42 */ 43 */
44static inline struct file *eventfd_file_create(unsigned int count, int flags)
45{
46 return ERR_PTR(-ENOSYS);
47}
48
43static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd) 49static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd)
44{ 50{
45 return ERR_PTR(-ENOSYS); 51 return ERR_PTR(-ENOSYS);