Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

eventfd use waitqueue lock ...

The eventfd was using the unlocked waitqueue operations, but it was
using a different lock, so poll_wait() would race with it.

This makes eventfd directly use the waitqueue lock.

Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Davide Libenzi and committed by
Linus Torvalds
d48eb233 347b4599

+12 -14
+12 -14
fs/eventfd.c
··· 17 17 #include <linux/eventfd.h> 18 18 19 19 struct eventfd_ctx { 20 - spinlock_t lock; 21 20 wait_queue_head_t wqh; 22 21 /* 23 22 * Every time that a write(2) is performed on an eventfd, the ··· 44 45 45 46 if (n < 0) 46 47 return -EINVAL; 47 - spin_lock_irqsave(&ctx->lock, flags); 48 + spin_lock_irqsave(&ctx->wqh.lock, flags); 48 49 if (ULLONG_MAX - ctx->count < n) 49 50 n = (int) (ULLONG_MAX - ctx->count); 50 51 ctx->count += n; 51 52 if (waitqueue_active(&ctx->wqh)) 52 53 wake_up_locked(&ctx->wqh); 53 - spin_unlock_irqrestore(&ctx->lock, flags); 54 + spin_unlock_irqrestore(&ctx->wqh.lock, flags); 54 55 55 56 return n; 56 57 } ··· 69 70 70 71 poll_wait(file, &ctx->wqh, wait); 71 72 72 - spin_lock_irqsave(&ctx->lock, flags); 73 + spin_lock_irqsave(&ctx->wqh.lock, flags); 73 74 if (ctx->count > 0) 74 75 events |= POLLIN; 75 76 if (ctx->count == ULLONG_MAX) 76 77 events |= POLLERR; 77 78 if (ULLONG_MAX - 1 > ctx->count) 78 79 events |= POLLOUT; 79 - spin_unlock_irqrestore(&ctx->lock, flags); 80 + spin_unlock_irqrestore(&ctx->wqh.lock, flags); 80 81 81 82 return events; 82 83 } ··· 91 92 92 93 if (count < sizeof(ucnt)) 93 94 return -EINVAL; 94 - spin_lock_irq(&ctx->lock); 95 + spin_lock_irq(&ctx->wqh.lock); 95 96 res = -EAGAIN; 96 97 ucnt = ctx->count; 97 98 if (ucnt > 0) ··· 109 110 res = -ERESTARTSYS; 110 111 break; 111 112 } 112 - spin_unlock_irq(&ctx->lock); 113 + spin_unlock_irq(&ctx->wqh.lock); 113 114 schedule(); 114 - spin_lock_irq(&ctx->lock); 115 + spin_lock_irq(&ctx->wqh.lock); 115 116 } 116 117 __remove_wait_queue(&ctx->wqh, &wait); 117 118 __set_current_state(TASK_RUNNING); ··· 121 122 if (waitqueue_active(&ctx->wqh)) 122 123 wake_up_locked(&ctx->wqh); 123 124 } 124 - spin_unlock_irq(&ctx->lock); 125 + spin_unlock_irq(&ctx->wqh.lock); 125 126 if (res > 0 && put_user(ucnt, (__u64 __user *) buf)) 126 127 return -EFAULT; 127 128 ··· 142 143 return -EFAULT; 143 144 if (ucnt == ULLONG_MAX) 144 145 return -EINVAL; 145 - spin_lock_irq(&ctx->lock); 146 + spin_lock_irq(&ctx->wqh.lock); 146 147 res = -EAGAIN; 147 148 if (ULLONG_MAX - ctx->count > ucnt) 148 149 res = sizeof(ucnt); ··· 158 159 res = -ERESTARTSYS; 159 160 break; 160 161 } 161 - spin_unlock_irq(&ctx->lock); 162 + spin_unlock_irq(&ctx->wqh.lock); 162 163 schedule(); 163 - spin_lock_irq(&ctx->lock); 164 + spin_lock_irq(&ctx->wqh.lock); 164 165 } 165 166 __remove_wait_queue(&ctx->wqh, &wait); 166 167 __set_current_state(TASK_RUNNING); ··· 170 171 if (waitqueue_active(&ctx->wqh)) 171 172 wake_up_locked(&ctx->wqh); 172 173 } 173 - spin_unlock_irq(&ctx->lock); 174 + spin_unlock_irq(&ctx->wqh.lock); 174 175 175 176 return res; 176 177 } ··· 209 210 return -ENOMEM; 210 211 211 212 init_waitqueue_head(&ctx->wqh); 212 - spin_lock_init(&ctx->lock); 213 213 ctx->count = count; 214 214 215 215 /*