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.

usb: using mutex lock and supporting O_NONBLOCK flag in iowarrior_read()

iowarrior_read() uses the iowarrior dev structure, but does not use any
lock on the structure. This can cause various bugs including data-races,
so it is more appropriate to use a mutex lock to safely protect the
iowarrior dev structure. When using a mutex lock, you should split the
branch to prevent blocking when the O_NONBLOCK flag is set.

In addition, it is unnecessary to check for NULL on the iowarrior dev
structure obtained by reading file->private_data. Therefore, it is
better to remove the check.

Fixes: 946b960d13c1 ("USB: add driver for iowarrior devices.")
Signed-off-by: Jeongjun Park <aha310510@gmail.com>
Link: https://lore.kernel.org/r/20240919103403.3986-1-aha310510@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Jeongjun Park and committed by
Greg Kroah-Hartman
44feafba 67c6150c

+36 -10
+36 -10
drivers/usb/misc/iowarrior.c
··· 277 277 struct iowarrior *dev; 278 278 int read_idx; 279 279 int offset; 280 + int retval; 280 281 281 282 dev = file->private_data; 282 283 284 + if (file->f_flags & O_NONBLOCK) { 285 + retval = mutex_trylock(&dev->mutex); 286 + if (!retval) 287 + return -EAGAIN; 288 + } else { 289 + retval = mutex_lock_interruptible(&dev->mutex); 290 + if (retval) 291 + return -ERESTARTSYS; 292 + } 293 + 283 294 /* verify that the device wasn't unplugged */ 284 - if (!dev || !dev->present) 285 - return -ENODEV; 295 + if (!dev->present) { 296 + retval = -ENODEV; 297 + goto exit; 298 + } 286 299 287 300 dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", 288 301 dev->minor, count); 289 302 290 303 /* read count must be packet size (+ time stamp) */ 291 304 if ((count != dev->report_size) 292 - && (count != (dev->report_size + 1))) 293 - return -EINVAL; 305 + && (count != (dev->report_size + 1))) { 306 + retval = -EINVAL; 307 + goto exit; 308 + } 294 309 295 310 /* repeat until no buffer overrun in callback handler occur */ 296 311 do { 297 312 atomic_set(&dev->overflow_flag, 0); 298 313 if ((read_idx = read_index(dev)) == -1) { 299 314 /* queue empty */ 300 - if (file->f_flags & O_NONBLOCK) 301 - return -EAGAIN; 315 + if (file->f_flags & O_NONBLOCK) { 316 + retval = -EAGAIN; 317 + goto exit; 318 + } 302 319 else { 303 320 //next line will return when there is either new data, or the device is unplugged 304 321 int r = wait_event_interruptible(dev->read_wait, ··· 326 309 -1)); 327 310 if (r) { 328 311 //we were interrupted by a signal 329 - return -ERESTART; 312 + retval = -ERESTART; 313 + goto exit; 330 314 } 331 315 if (!dev->present) { 332 316 //The device was unplugged 333 - return -ENODEV; 317 + retval = -ENODEV; 318 + goto exit; 334 319 } 335 320 if (read_idx == -1) { 336 321 // Can this happen ??? 337 - return 0; 322 + retval = 0; 323 + goto exit; 338 324 } 339 325 } 340 326 } 341 327 342 328 offset = read_idx * (dev->report_size + 1); 343 329 if (copy_to_user(buffer, dev->read_queue + offset, count)) { 344 - return -EFAULT; 330 + retval = -EFAULT; 331 + goto exit; 345 332 } 346 333 } while (atomic_read(&dev->overflow_flag)); 347 334 348 335 read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; 349 336 atomic_set(&dev->read_idx, read_idx); 337 + mutex_unlock(&dev->mutex); 350 338 return count; 339 + 340 + exit: 341 + mutex_unlock(&dev->mutex); 342 + return retval; 351 343 } 352 344 353 345 /*