Fix: blocking O_NONBLOCK process bug in sleep.c

There is a subtle bug that if the atomic flag changes
between the time it was checked and the second time
it was checked, sleep.c would potentially block a
process that had specified O_NONBLOCK. This fixes
the bug by using atomic_cmpxchg instead of atomic_read.
This commit is contained in:
Aykhan Hagverdili 2024-08-11 21:52:05 +02:00
parent 84cc7fee1c
commit 4adbf1dd9b

View File

@ -92,12 +92,18 @@ static DECLARE_WAIT_QUEUE_HEAD(waitq);
/* Called when the /proc file is opened */ /* Called when the /proc file is opened */
static int module_open(struct inode *inode, struct file *file) static int module_open(struct inode *inode, struct file *file)
{ {
/* Try to get without blocking */
if (!atomic_cmpxchg(&already_open, 0, 1)) {
/* Success without blocking, allow the access */
try_module_get(THIS_MODULE);
return 0;
}
/* If the file's flags include O_NONBLOCK, it means the process does not /* If the file's flags include O_NONBLOCK, it means the process does not
* want to wait for the file. In this case, if the file is already open, * want to wait for the file. In this case, because the file is already open,
* we should fail with -EAGAIN, meaning "you will have to try again", * we should fail with -EAGAIN, meaning "you will have to try again",
* instead of blocking a process which would rather stay awake. * instead of blocking a process which would rather stay awake.
*/ */
if ((file->f_flags & O_NONBLOCK) && atomic_read(&already_open)) if (file->f_flags & O_NONBLOCK)
return -EAGAIN; return -EAGAIN;
/* This is the correct place for try_module_get(THIS_MODULE) because if /* This is the correct place for try_module_get(THIS_MODULE) because if