Bug#816211: linux-image-3.16.0-0.bpo.4-amd64: /dev/sr? access is not parallel
Package: src:linux
Version: 3.16.7-ckt20-1+deb8u3~bpo70+1
Severity: normal
Dear Maintainer,
There was a regression in the Linux kernel which made the I/Os to
sr devices (especially when ejecting or writing to DVD-Rs) synchronous
(non parallel).
If you write to a few DVD writes simultaneously, a 5-7x performance
degradation will occur.
You can reproduce the bug easily with:
for i in /dev/sr?; do (eject $i&); done
If the drives do not open (almost) simultaneously but sequentially, the
bug is present.
Reference: http://linux-scsi.vger.kernel.narkive.com/JLvupYok/patch-scsi-sr-fix-multi-drive-performance-by-using-per-device-mutexes
I adapted a patch for that version below and successfully tested it.
-- Package-specific info:
** Version:
Linux version 3.16.0-0.bpo.4-amd64 (debian-kernel@lists.debian.org) (gcc version 4.6.3 (Debian 4.6.3-14) ) #1 SMP Debian 3.16.7-ckt20-1+deb8u3~bpo70+1 (2016-01-19)
** Command line:
BOOT_IMAGE=/vmlinuz-3.16.0-0.bpo.4-amd64 root=/dev/mapper/vg1-root ro quiet
--- drivers/scsi/sr.c 2015-11-18 11:08:46.000000000 +0100
+++ drivers/scsi/sr.c.NEW 2016-02-28 19:51:54.957158326 +0100
@@ -76,7 +76,6 @@
CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \
CDC_MRW|CDC_MRW_W|CDC_RAM)
-static DEFINE_MUTEX(sr_mutex);
static int sr_probe(struct device *);
static int sr_remove(struct device *);
static int sr_init_command(struct scsi_cmnd *SCpnt);
@@ -520,24 +519,24 @@
struct scsi_cd *cd;
int ret = -ENXIO;
- mutex_lock(&sr_mutex);
cd = scsi_cd_get(bdev->bd_disk);
if (cd) {
+ mutex_lock(&cd->lock);
ret = cdrom_open(&cd->cdi, bdev, mode);
+ mutex_unlock(&cd->lock);
if (ret)
scsi_cd_put(cd);
}
- mutex_unlock(&sr_mutex);
return ret;
}
static void sr_block_release(struct gendisk *disk, fmode_t mode)
{
struct scsi_cd *cd = scsi_cd(disk);
- mutex_lock(&sr_mutex);
+ mutex_lock(&cd->lock);
cdrom_release(&cd->cdi, mode);
+ mutex_unlock(&cd->lock);
scsi_cd_put(cd);
- mutex_unlock(&sr_mutex);
}
static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
@@ -548,7 +547,7 @@
void __user *argp = (void __user *)arg;
int ret;
- mutex_lock(&sr_mutex);
+ mutex_lock(&cd->lock);
/*
* Send SCSI addressing ioctls directly to mid level, send other
@@ -578,7 +577,7 @@
ret = scsi_ioctl(sdev, cmd, argp);
out:
- mutex_unlock(&sr_mutex);
+ mutex_unlock(&cd->lock);
return ret;
}
@@ -673,6 +672,8 @@
if (!disk)
goto fail_free;
+ mutex_init(&cd->lock);
+
spin_lock(&sr_index_lock);
minor = find_first_zero_bit(sr_index_bits, SR_DISKS);
if (minor == SR_DISKS) {
@@ -742,6 +743,7 @@
fail_put:
put_disk(disk);
+ mutex_destroy(&cd->lock);
fail_free:
kfree(cd);
fail:
@@ -978,6 +980,8 @@
put_disk(disk);
+ mutex_destroy(&cd->lock);
+
kfree(cd);
}
--- drivers/scsi/sr.h 2015-11-18 11:08:46.000000000 +0100
+++ drivers/scsi/sr.h.NEW 2016-02-28 19:45:26.533162171 +0100
@@ -19,6 +19,7 @@
#include <linux/genhd.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#define MAX_RETRIES 3
#define SR_TIMEOUT (30 * HZ)
@@ -49,6 +50,7 @@
bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */
struct cdrom_device_info cdi;
+ struct mutex lock;
/* We hold gendisk and scsi_device references on probe and use
* the refs on this kref to decide when to release them */
struct kref kref;
Reply to: