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

scsi: sr: get rid of sr global mutex

When replacing the Big Kernel Lock in commit 2a48fc0ab242 ("block:
autoconvert trivial BKL users to private mutex"), the lock was replaced
with a sr-wide lock.

This causes very poor performance when using multiple sr devices, as the sr
driver was not able to execute more than one command to one drive at any
given time, even when there were many CD drives available.

Replace the global mutex with per-sr-device mutex.

Someone tried this patch at the time, but it never made it upstream, due to
possible concerns with race conditions, but it's not clear the patch
actually caused those:

https://www.spinics.net/lists/linux-scsi/msg63706.html
https://www.spinics.net/lists/linux-scsi/msg63750.html

Also see

http://lists.xiph.org/pipermail/paranoia/2019-December/001647.html

Link: https://lore.kernel.org/r/20200218143918.30267-1-merlijn@archive.org
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Merlijn Wajer <merlijn@archive.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Merlijn Wajer and committed by
Martin K. Petersen
51a85881 679b2ec8

+13 -9
+11 -9
drivers/scsi/sr.c
··· 79 79 CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ 80 80 CDC_MRW|CDC_MRW_W|CDC_RAM) 81 81 82 - static DEFINE_MUTEX(sr_mutex); 83 82 static int sr_probe(struct device *); 84 83 static int sr_remove(struct device *); 85 84 static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); ··· 535 536 scsi_autopm_get_device(sdev); 536 537 check_disk_change(bdev); 537 538 538 - mutex_lock(&sr_mutex); 539 + mutex_lock(&cd->lock); 539 540 ret = cdrom_open(&cd->cdi, bdev, mode); 540 - mutex_unlock(&sr_mutex); 541 + mutex_unlock(&cd->lock); 541 542 542 543 scsi_autopm_put_device(sdev); 543 544 if (ret) ··· 550 551 static void sr_block_release(struct gendisk *disk, fmode_t mode) 551 552 { 552 553 struct scsi_cd *cd = scsi_cd(disk); 553 - mutex_lock(&sr_mutex); 554 + mutex_lock(&cd->lock); 554 555 cdrom_release(&cd->cdi, mode); 555 556 scsi_cd_put(cd); 556 - mutex_unlock(&sr_mutex); 557 + mutex_unlock(&cd->lock); 557 558 } 558 559 559 560 static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, ··· 564 565 void __user *argp = (void __user *)arg; 565 566 int ret; 566 567 567 - mutex_lock(&sr_mutex); 568 + mutex_lock(&cd->lock); 568 569 569 570 ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, 570 571 (mode & FMODE_NDELAY) != 0); ··· 594 595 scsi_autopm_put_device(sdev); 595 596 596 597 out: 597 - mutex_unlock(&sr_mutex); 598 + mutex_unlock(&cd->lock); 598 599 return ret; 599 600 } 600 601 ··· 607 608 void __user *argp = compat_ptr(arg); 608 609 int ret; 609 610 610 - mutex_lock(&sr_mutex); 611 + mutex_lock(&cd->lock); 611 612 612 613 ret = scsi_ioctl_block_when_processing_errors(sdev, cmd, 613 614 (mode & FMODE_NDELAY) != 0); ··· 637 638 scsi_autopm_put_device(sdev); 638 639 639 640 out: 640 - mutex_unlock(&sr_mutex); 641 + mutex_unlock(&cd->lock); 641 642 return ret; 642 643 643 644 } ··· 744 745 disk = alloc_disk(1); 745 746 if (!disk) 746 747 goto fail_free; 748 + mutex_init(&cd->lock); 747 749 748 750 spin_lock(&sr_index_lock); 749 751 minor = find_first_zero_bit(sr_index_bits, SR_DISKS); ··· 1054 1054 disk->private_data = NULL; 1055 1055 1056 1056 put_disk(disk); 1057 + 1058 + mutex_destroy(&cd->lock); 1057 1059 1058 1060 kfree(cd); 1059 1061 }
+2
drivers/scsi/sr.h
··· 20 20 21 21 #include <linux/genhd.h> 22 22 #include <linux/kref.h> 23 + #include <linux/mutex.h> 23 24 24 25 #define MAX_RETRIES 3 25 26 #define SR_TIMEOUT (30 * HZ) ··· 52 51 bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */ 53 52 54 53 struct cdrom_device_info cdi; 54 + struct mutex lock; 55 55 /* We hold gendisk and scsi_device references on probe and use 56 56 * the refs on this kref to decide when to release them */ 57 57 struct kref kref;