[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: