char: xillybus: Improve control of execution flow with mutexes

This commit addresses two issues by using mutexes:

(1) Add a mutex to protect the fifo_buf_order global variable. The
    purpose of this variable is avoid repeated failed calls to
    __get_free_pages() for allocating FIFO memory, when the chunk
    size was too big. However, if two drivers are initialized at the
    same time, fifo_init() may run in parallel, and fifo_buf_order
    may be reduced too much. This is a far-fetched scenario, now
    completely prevented by fifo_buf_order_mutex.

(2) setup_channels() acquires process_in_mutex to prevent
    process_bulk_in() from accessing the xillyusb_dev struct. With
    correctly working hardware, process_bulk_in() is never called while
    setup_channels() runs, because the device has no reason to send data
    in that phase. The mutex ensures that process_bulk_in() does not
    touch the members that setup_channels() alters.

    There is no similar protection for data flow in the other direction,
    because during the setup process, the only outbound data is the
    BULK endpoint used for commands, and it remains untouched after its
    initial setup.

Assisted-by: Deepseek:v4-pro Kimi:K2.6 ChatGPT:GPT-5.5 Claude:Sonnet-4.6
Assisted-by: Sashiko-0.2.5:gemini-3.1-pro-preview
Signed-off-by: Eli Billauer <eli.billauer@gmail.com>
Link: https://patch.msgid.link/20261009074557.19996-2-eli.billauer@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Eli Billauer 2026-10-09 09:45:51 +02:00 committed by Greg Kroah-Hartman
parent fe26c195c2
commit 305876de50

View File

@ -50,6 +50,7 @@ MODULE_LICENSE("GPL v2");
static const char xillyname[] = "xillyusb";
static unsigned int fifo_buf_order;
static DEFINE_MUTEX(fifo_buf_order_mutex);
static struct workqueue_struct *wakeup_wq;
#define USB_VENDOR_ID_XILINX 0x03fd
@ -372,6 +373,8 @@ static int fifo_init(struct xillyfifo *fifo,
unsigned int log2_fifo_buf_size;
mutex_lock(&fifo_buf_order_mutex);
retry:
log2_fifo_buf_size = fifo_buf_order + PAGE_SHIFT;
@ -388,8 +391,10 @@ static int fifo_init(struct xillyfifo *fifo,
fifo->mem = kmalloc_array(fifo->bufnum, sizeof(void *), GFP_KERNEL);
if (!fifo->mem)
if (!fifo->mem) {
mutex_unlock(&fifo_buf_order_mutex);
return -ENOMEM;
}
for (i = 0; i < fifo->bufnum; i++) {
fifo->mem[i] = kmalloc(fifo->bufsize, GFP_KERNEL);
@ -405,6 +410,8 @@ static int fifo_init(struct xillyfifo *fifo,
fifo->writebuf = 0;
spin_lock_init(&fifo->lock);
init_waitqueue_head(&fifo->waitq);
mutex_unlock(&fifo_buf_order_mutex);
return 0;
memfail:
@ -418,6 +425,7 @@ static int fifo_init(struct xillyfifo *fifo,
fifo_buf_order--;
goto retry;
} else {
mutex_unlock(&fifo_buf_order_mutex);
return -ENOMEM;
}
}
@ -1932,6 +1940,9 @@ static int setup_channels(struct xillyusb_dev *xdev,
struct xillyusb_channel *chan, *new_channels;
int i;
/* Don't let process_bulk_in() run while we change the channels */
guard(mutex)(&xdev->process_in_mutex);
chan = kzalloc_objs(*chan, num_channels);
if (!chan)
return -ENOMEM;