.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * fs/eventfd.c |
---|
3 | 4 | * |
---|
.. | .. |
---|
21 | 22 | #include <linux/eventfd.h> |
---|
22 | 23 | #include <linux/proc_fs.h> |
---|
23 | 24 | #include <linux/seq_file.h> |
---|
| 25 | +#include <linux/idr.h> |
---|
| 26 | +#include <linux/uio.h> |
---|
24 | 27 | |
---|
25 | 28 | DEFINE_PER_CPU(int, eventfd_wake_count); |
---|
| 29 | + |
---|
| 30 | +static DEFINE_IDA(eventfd_ida); |
---|
26 | 31 | |
---|
27 | 32 | struct eventfd_ctx { |
---|
28 | 33 | struct kref kref; |
---|
.. | .. |
---|
37 | 42 | */ |
---|
38 | 43 | __u64 count; |
---|
39 | 44 | unsigned int flags; |
---|
| 45 | + int id; |
---|
40 | 46 | }; |
---|
41 | 47 | |
---|
42 | | -/** |
---|
43 | | - * eventfd_signal - Adds @n to the eventfd counter. |
---|
44 | | - * @ctx: [in] Pointer to the eventfd context. |
---|
45 | | - * @n: [in] Value of the counter to be added to the eventfd internal counter. |
---|
46 | | - * The value cannot be negative. |
---|
47 | | - * |
---|
48 | | - * This function is supposed to be called by the kernel in paths that do not |
---|
49 | | - * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX |
---|
50 | | - * value, and we signal this as overflow condition by returning a EPOLLERR |
---|
51 | | - * to poll(2). |
---|
52 | | - * |
---|
53 | | - * Returns the amount by which the counter was incremented. This will be less |
---|
54 | | - * than @n if the counter has overflowed. |
---|
55 | | - */ |
---|
56 | | -__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n) |
---|
| 48 | +__u64 eventfd_signal_mask(struct eventfd_ctx *ctx, __u64 n, unsigned mask) |
---|
57 | 49 | { |
---|
58 | 50 | unsigned long flags; |
---|
59 | 51 | |
---|
.. | .. |
---|
74 | 66 | n = ULLONG_MAX - ctx->count; |
---|
75 | 67 | ctx->count += n; |
---|
76 | 68 | if (waitqueue_active(&ctx->wqh)) |
---|
77 | | - wake_up_locked_poll(&ctx->wqh, EPOLLIN); |
---|
| 69 | + wake_up_locked_poll(&ctx->wqh, EPOLLIN | mask); |
---|
78 | 70 | this_cpu_dec(eventfd_wake_count); |
---|
79 | 71 | spin_unlock_irqrestore(&ctx->wqh.lock, flags); |
---|
80 | 72 | |
---|
81 | 73 | return n; |
---|
82 | 74 | } |
---|
| 75 | + |
---|
| 76 | +/** |
---|
| 77 | + * eventfd_signal - Adds @n to the eventfd counter. |
---|
| 78 | + * @ctx: [in] Pointer to the eventfd context. |
---|
| 79 | + * @n: [in] Value of the counter to be added to the eventfd internal counter. |
---|
| 80 | + * The value cannot be negative. |
---|
| 81 | + * |
---|
| 82 | + * This function is supposed to be called by the kernel in paths that do not |
---|
| 83 | + * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX |
---|
| 84 | + * value, and we signal this as overflow condition by returning a EPOLLERR |
---|
| 85 | + * to poll(2). |
---|
| 86 | + * |
---|
| 87 | + * Returns the amount by which the counter was incremented. This will be less |
---|
| 88 | + * than @n if the counter has overflowed. |
---|
| 89 | + */ |
---|
| 90 | +__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n) |
---|
| 91 | +{ |
---|
| 92 | + return eventfd_signal_mask(ctx, n, 0); |
---|
| 93 | +} |
---|
83 | 94 | EXPORT_SYMBOL_GPL(eventfd_signal); |
---|
84 | 95 | |
---|
85 | 96 | static void eventfd_free_ctx(struct eventfd_ctx *ctx) |
---|
86 | 97 | { |
---|
| 98 | + if (ctx->id >= 0) |
---|
| 99 | + ida_simple_remove(&eventfd_ida, ctx->id); |
---|
87 | 100 | kfree(ctx); |
---|
88 | 101 | } |
---|
89 | 102 | |
---|
.. | .. |
---|
209 | 222 | } |
---|
210 | 223 | EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue); |
---|
211 | 224 | |
---|
212 | | -static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, |
---|
213 | | - loff_t *ppos) |
---|
| 225 | +static ssize_t eventfd_read(struct kiocb *iocb, struct iov_iter *to) |
---|
214 | 226 | { |
---|
| 227 | + struct file *file = iocb->ki_filp; |
---|
215 | 228 | struct eventfd_ctx *ctx = file->private_data; |
---|
216 | | - ssize_t res; |
---|
217 | 229 | __u64 ucnt = 0; |
---|
218 | 230 | DECLARE_WAITQUEUE(wait, current); |
---|
219 | 231 | |
---|
220 | | - if (count < sizeof(ucnt)) |
---|
| 232 | + if (iov_iter_count(to) < sizeof(ucnt)) |
---|
221 | 233 | return -EINVAL; |
---|
222 | | - |
---|
223 | 234 | spin_lock_irq(&ctx->wqh.lock); |
---|
224 | | - res = -EAGAIN; |
---|
225 | | - if (ctx->count > 0) |
---|
226 | | - res = sizeof(ucnt); |
---|
227 | | - else if (!(file->f_flags & O_NONBLOCK)) { |
---|
| 235 | + if (!ctx->count) { |
---|
| 236 | + if ((file->f_flags & O_NONBLOCK) || |
---|
| 237 | + (iocb->ki_flags & IOCB_NOWAIT)) { |
---|
| 238 | + spin_unlock_irq(&ctx->wqh.lock); |
---|
| 239 | + return -EAGAIN; |
---|
| 240 | + } |
---|
228 | 241 | __add_wait_queue(&ctx->wqh, &wait); |
---|
229 | 242 | for (;;) { |
---|
230 | 243 | set_current_state(TASK_INTERRUPTIBLE); |
---|
231 | | - if (ctx->count > 0) { |
---|
232 | | - res = sizeof(ucnt); |
---|
| 244 | + if (ctx->count) |
---|
233 | 245 | break; |
---|
234 | | - } |
---|
235 | 246 | if (signal_pending(current)) { |
---|
236 | | - res = -ERESTARTSYS; |
---|
237 | | - break; |
---|
| 247 | + __remove_wait_queue(&ctx->wqh, &wait); |
---|
| 248 | + __set_current_state(TASK_RUNNING); |
---|
| 249 | + spin_unlock_irq(&ctx->wqh.lock); |
---|
| 250 | + return -ERESTARTSYS; |
---|
238 | 251 | } |
---|
239 | 252 | spin_unlock_irq(&ctx->wqh.lock); |
---|
240 | 253 | schedule(); |
---|
.. | .. |
---|
243 | 256 | __remove_wait_queue(&ctx->wqh, &wait); |
---|
244 | 257 | __set_current_state(TASK_RUNNING); |
---|
245 | 258 | } |
---|
246 | | - if (likely(res > 0)) { |
---|
247 | | - eventfd_ctx_do_read(ctx, &ucnt); |
---|
248 | | - if (waitqueue_active(&ctx->wqh)) |
---|
249 | | - wake_up_locked_poll(&ctx->wqh, EPOLLOUT); |
---|
250 | | - } |
---|
| 259 | + eventfd_ctx_do_read(ctx, &ucnt); |
---|
| 260 | + if (waitqueue_active(&ctx->wqh)) |
---|
| 261 | + wake_up_locked_poll(&ctx->wqh, EPOLLOUT); |
---|
251 | 262 | spin_unlock_irq(&ctx->wqh.lock); |
---|
252 | | - |
---|
253 | | - if (res > 0 && put_user(ucnt, (__u64 __user *)buf)) |
---|
| 263 | + if (unlikely(copy_to_iter(&ucnt, sizeof(ucnt), to) != sizeof(ucnt))) |
---|
254 | 264 | return -EFAULT; |
---|
255 | 265 | |
---|
256 | | - return res; |
---|
| 266 | + return sizeof(ucnt); |
---|
257 | 267 | } |
---|
258 | 268 | |
---|
259 | 269 | static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count, |
---|
.. | .. |
---|
312 | 322 | seq_printf(m, "eventfd-count: %16llx\n", |
---|
313 | 323 | (unsigned long long)ctx->count); |
---|
314 | 324 | spin_unlock_irq(&ctx->wqh.lock); |
---|
| 325 | + seq_printf(m, "eventfd-id: %d\n", ctx->id); |
---|
315 | 326 | } |
---|
316 | 327 | #endif |
---|
317 | 328 | |
---|
.. | .. |
---|
321 | 332 | #endif |
---|
322 | 333 | .release = eventfd_release, |
---|
323 | 334 | .poll = eventfd_poll, |
---|
324 | | - .read = eventfd_read, |
---|
| 335 | + .read_iter = eventfd_read, |
---|
325 | 336 | .write = eventfd_write, |
---|
326 | 337 | .llseek = noop_llseek, |
---|
327 | 338 | }; |
---|
.. | .. |
---|
398 | 409 | static int do_eventfd(unsigned int count, int flags) |
---|
399 | 410 | { |
---|
400 | 411 | struct eventfd_ctx *ctx; |
---|
| 412 | + struct file *file; |
---|
401 | 413 | int fd; |
---|
402 | 414 | |
---|
403 | 415 | /* Check the EFD_* constants for consistency. */ |
---|
.. | .. |
---|
415 | 427 | init_waitqueue_head(&ctx->wqh); |
---|
416 | 428 | ctx->count = count; |
---|
417 | 429 | ctx->flags = flags; |
---|
| 430 | + ctx->id = ida_simple_get(&eventfd_ida, 0, 0, GFP_KERNEL); |
---|
418 | 431 | |
---|
419 | | - fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx, |
---|
420 | | - O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); |
---|
| 432 | + flags &= EFD_SHARED_FCNTL_FLAGS; |
---|
| 433 | + flags |= O_RDWR; |
---|
| 434 | + fd = get_unused_fd_flags(flags); |
---|
421 | 435 | if (fd < 0) |
---|
422 | | - eventfd_free_ctx(ctx); |
---|
| 436 | + goto err; |
---|
423 | 437 | |
---|
| 438 | + file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, flags); |
---|
| 439 | + if (IS_ERR(file)) { |
---|
| 440 | + put_unused_fd(fd); |
---|
| 441 | + fd = PTR_ERR(file); |
---|
| 442 | + goto err; |
---|
| 443 | + } |
---|
| 444 | + |
---|
| 445 | + file->f_mode |= FMODE_NOWAIT; |
---|
| 446 | + fd_install(fd, file); |
---|
| 447 | + return fd; |
---|
| 448 | +err: |
---|
| 449 | + eventfd_free_ctx(ctx); |
---|
424 | 450 | return fd; |
---|
425 | 451 | } |
---|
426 | 452 | |
---|