diff options
-rw-r--r-- | fs/anon_inodes.c | 68 | ||||
-rw-r--r-- | fs/eventfd.c | 67 | ||||
-rw-r--r-- | include/linux/anon_inodes.h | 3 | ||||
-rw-r--r-- | include/linux/eventfd.h | 6 |
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 | */ |
84 | int anon_inode_getfd(const char *name, const struct file_operations *fops, | 84 | struct 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 | |||
137 | err_dput: | ||
138 | dput(dentry); | ||
139 | err_module: | ||
140 | module_put(fops->owner); | ||
141 | return ERR_PTR(error); | ||
142 | } | ||
143 | EXPORT_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 | */ | ||
161 | int 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 | ||
143 | err_dput: | ||
144 | dput(dentry); | ||
145 | err_put_unused_fd: | 181 | err_put_unused_fd: |
146 | put_unused_fd(fd); | 182 | put_unused_fd(fd); |
147 | err_module: | ||
148 | module_put(fops->owner); | ||
149 | return error; | 183 | return error; |
150 | } | 184 | } |
151 | EXPORT_SYMBOL_GPL(anon_inode_getfd); | 185 | EXPORT_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 | } |
69 | EXPORT_SYMBOL_GPL(eventfd_signal); | 69 | EXPORT_SYMBOL_GPL(eventfd_signal); |
70 | 70 | ||
71 | static void eventfd_free_ctx(struct eventfd_ctx *ctx) | ||
72 | { | ||
73 | kfree(ctx); | ||
74 | } | ||
75 | |||
71 | static void eventfd_free(struct kref *kref) | 76 | static 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 | } |
299 | EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); | 304 | EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); |
300 | 305 | ||
301 | SYSCALL_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 | */ | ||
320 | struct 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 | |
349 | SYSCALL_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 | |||
368 | err_put_unused_fd: | ||
369 | put_unused_fd(fd); | ||
370 | |||
371 | return error; | ||
331 | } | 372 | } |
332 | 373 | ||
333 | SYSCALL_DEFINE1(eventfd, unsigned int, count) | 374 | SYSCALL_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 | ||
11 | struct file *anon_inode_getfile(const char *name, | ||
12 | const struct file_operations *fops, | ||
13 | void *priv, int flags); | ||
11 | int anon_inode_getfd(const char *name, const struct file_operations *fops, | 14 | int 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 | ||
30 | struct file *eventfd_file_create(unsigned int count, int flags); | ||
30 | struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx); | 31 | struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx); |
31 | void eventfd_ctx_put(struct eventfd_ctx *ctx); | 32 | void eventfd_ctx_put(struct eventfd_ctx *ctx); |
32 | struct file *eventfd_fget(int fd); | 33 | struct 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 | */ |
44 | static inline struct file *eventfd_file_create(unsigned int count, int flags) | ||
45 | { | ||
46 | return ERR_PTR(-ENOSYS); | ||
47 | } | ||
48 | |||
43 | static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd) | 49 | static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd) |
44 | { | 50 | { |
45 | return ERR_PTR(-ENOSYS); | 51 | return ERR_PTR(-ENOSYS); |