]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'for-2.6.26' of git://git.kernel.dk/linux-2.6-block
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Apr 2008 23:03:40 +0000 (16:03 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 21 Apr 2008 23:03:40 +0000 (16:03 -0700)
* 'for-2.6.26' of git://git.kernel.dk/linux-2.6-block:
  block: fix blk_register_queue() return value
  block: fix memory hotplug and bouncing in block layer
  block: replace remaining __FUNCTION__ occurrences
  Kconfig: clean up block/Kconfig help descriptions
  cciss: fix warning oops on rmmod of driver
  cciss: Fix race between disk-adding code and interrupt handler
  block: move the padding adjustment to blk_rq_map_sg
  block: add bio_copy_user_iov support to blk_rq_map_user_iov
  block: convert bio_copy_user to bio_copy_user_iov
  loop: manage partitions in disk image
  cdrom: use kmalloced buffers instead of buffers on stack
  cdrom: make unregister_cdrom() return void
  cdrom: use list_head for cdrom_device_info list
  cdrom: protect cdrom_device_info list by mutex
  cdrom: cleanup hardcoded error-code
  cdrom: remove ifdef CONFIG_SYSCTL

18 files changed:
Documentation/cdrom/cdrom-standard.tex
block/Kconfig
block/blk-map.c
block/blk-merge.c
block/blk-sysfs.c
drivers/block/cciss.c
drivers/block/cciss_scsi.c
drivers/block/loop.c
drivers/block/sx8.c
drivers/cdrom/cdrom.c
drivers/cdrom/gdrom.c
drivers/cdrom/viocd.c
drivers/ide/ide-cd.c
drivers/scsi/scsi.c
fs/bio.c
include/linux/bio.h
include/linux/blkdev.h
include/linux/cdrom.h

index c713aeb020c40f6bfba883031d87e83e9d783b09..c06233fe52ac2bea917e4e850551b2733f8d341f 100644 (file)
@@ -777,7 +777,7 @@ Note that a driver must have one static structure, $<device>_dops$, while
 it may have as many structures $<device>_info$ as there are minor devices
 active. $Register_cdrom()$ builds a linked list from these. 
 
-\subsection{$Int\ unregister_cdrom(struct\ cdrom_device_info * cdi)$}
+\subsection{$Void\ unregister_cdrom(struct\ cdrom_device_info * cdi)$}
 
 Unregistering device $cdi$ with minor number $MINOR(cdi\to dev)$ removes
 the minor device from the list. If it was the last registered minor for
index 7db9a411649d996e6b5ae9f78f1134d96fb4c27c..3e97f2bc446f367fb8a3ffd28972d20a4176564f 100644 (file)
@@ -5,14 +5,18 @@ menuconfig BLOCK
        bool "Enable the block layer" if EMBEDDED
        default y
        help
-        This permits the block layer to be removed from the kernel if it's not
-        needed (on some embedded devices for example).  If this option is
-        disabled, then blockdev files will become unusable and some
-        filesystems (such as ext3) will become unavailable.
+        Provide block layer support for the kernel.
 
-        This option will also disable SCSI character devices and USB storage
-        since they make use of various block layer definitions and
-        facilities.
+        Disable this option to remove the block layer support from the
+        kernel. This may be useful for embedded devices.
+
+        If this option is disabled:
+
+          - block device files will become unusable
+          - some filesystems (such as ext3) will become unavailable.
+
+        Also, SCSI character devices and USB storage will be disabled since
+        they make use of various block layer definitions and facilities.
 
         Say Y here unless you know you really don't want to mount disks and
         suchlike.
@@ -23,9 +27,20 @@ config LBD
        bool "Support for Large Block Devices"
        depends on !64BIT
        help
-         Say Y here if you want to attach large (bigger than 2TB) discs to
-         your machine, or if you want to have a raid or loopback device
-         bigger than 2TB.  Otherwise say N.
+         Enable block devices of size 2TB and larger.
+
+         This option is required to support the full capacity of large
+         (2TB+) block devices, including RAID, disk, Network Block Device,
+         Logical Volume Manager (LVM) and loopback.
+
+         For example, RAID devices are frequently bigger than the capacity
+         of the largest individual hard drive.
+
+         This option is not required if you have individual disk drives
+         which total 2TB+ and you are not aggregating the capacity into
+         a large block device (e.g. using RAID or LVM).
+
+         If unsure, say N.
 
 config BLK_DEV_IO_TRACE
        bool "Support for tracing block io actions"
@@ -33,19 +48,21 @@ config BLK_DEV_IO_TRACE
        select RELAY
        select DEBUG_FS
        help
-         Say Y here, if you want to be able to trace the block layer actions
+         Say Y here if you want to be able to trace the block layer actions
          on a given queue. Tracing allows you to see any traffic happening
-         on a block device queue. For more information (and the user space
-         support tools needed), fetch the blktrace app from:
+         on a block device queue. For more information (and the userspace
+         support tools needed), fetch the blktrace tools from:
 
          git://git.kernel.dk/blktrace.git
 
+         If unsure, say N.
+
 config LSF
        bool "Support for Large Single Files"
        depends on !64BIT
        help
-         Say Y here if you want to be able to handle very large files (bigger
-         than 2TB), otherwise say N.
+         Say Y here if you want to be able to handle very large files (2TB
+         and larger), otherwise say N.
 
          If unsure, say Y.
 
@@ -53,14 +70,16 @@ config BLK_DEV_BSG
        bool "Block layer SG support v4 (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        ---help---
-       Saying Y here will enable generic SG (SCSI generic) v4 support
-       for any block device.
-
-       Unlike SG v3 (aka block/scsi_ioctl.c drivers/scsi/sg.c), SG v4
-       can handle complicated SCSI commands: tagged variable length cdbs
-       with bidirectional data transfers and generic request/response
-       protocols (e.g. Task Management Functions and SMP in Serial
-       Attached SCSI).
+         Saying Y here will enable generic SG (SCSI generic) v4 support
+         for any block device.
+
+         Unlike SG v3 (aka block/scsi_ioctl.c drivers/scsi/sg.c), SG v4
+         can handle complicated SCSI commands: tagged variable length cdbs
+         with bidirectional data transfers and generic request/response
+         protocols (e.g. Task Management Functions and SMP in Serial
+         Attached SCSI).
+
+         If unsure, say N.
 
 endif # BLOCK
 
index c07d9c8317f4c055d3821302c22df20cf2627195..3c942bd6422a2ba639597ace2ad9f3768ccf1456 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/bio.h>
 #include <linux/blkdev.h>
+#include <scsi/sg.h>           /* for struct sg_iovec */
 
 #include "blk.h"
 
@@ -140,25 +141,8 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
                ubuf += ret;
        }
 
-       /*
-        * __blk_rq_map_user() copies the buffers if starting address
-        * or length isn't aligned to dma_pad_mask.  As the copied
-        * buffer is always page aligned, we know that there's enough
-        * room for padding.  Extend the last bio and update
-        * rq->data_len accordingly.
-        *
-        * On unmap, bio_uncopy_user() will use unmodified
-        * bio_map_data pointed to by bio->bi_private.
-        */
-       if (len & q->dma_pad_mask) {
-               unsigned int pad_len = (q->dma_pad_mask & ~len) + 1;
-               struct bio *tail = rq->biotail;
-
-               tail->bi_io_vec[tail->bi_vcnt - 1].bv_len += pad_len;
-               tail->bi_size += pad_len;
-
-               rq->extra_len += pad_len;
-       }
+       if (!bio_flagged(bio, BIO_USER_MAPPED))
+               rq->cmd_flags |= REQ_COPY_USER;
 
        rq->buffer = rq->data = NULL;
        return 0;
@@ -194,15 +178,26 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                        struct sg_iovec *iov, int iov_count, unsigned int len)
 {
        struct bio *bio;
+       int i, read = rq_data_dir(rq) == READ;
+       int unaligned = 0;
 
        if (!iov || iov_count <= 0)
                return -EINVAL;
 
-       /* we don't allow misaligned data like bio_map_user() does.  If the
-        * user is using sg, they're expected to know the alignment constraints
-        * and respect them accordingly */
-       bio = bio_map_user_iov(q, NULL, iov, iov_count,
-                               rq_data_dir(rq) == READ);
+       for (i = 0; i < iov_count; i++) {
+               unsigned long uaddr = (unsigned long)iov[i].iov_base;
+
+               if (uaddr & queue_dma_alignment(q)) {
+                       unaligned = 1;
+                       break;
+               }
+       }
+
+       if (unaligned || (q->dma_pad_mask & len))
+               bio = bio_copy_user_iov(q, iov, iov_count, read);
+       else
+               bio = bio_map_user_iov(q, NULL, iov, iov_count, read);
+
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
@@ -212,6 +207,9 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
                return -EINVAL;
        }
 
+       if (!bio_flagged(bio, BIO_USER_MAPPED))
+               rq->cmd_flags |= REQ_COPY_USER;
+
        bio_get(bio);
        blk_rq_bio_prep(q, rq, bio);
        rq->buffer = rq->data = NULL;
index 0f58616bcd7f183514c43eb913f0e0c23c855215..b5c5c4a9e3f08d051a25d44e92689580d19cbce5 100644 (file)
@@ -220,6 +220,15 @@ new_segment:
                bvprv = bvec;
        } /* segments in rq */
 
+
+       if (unlikely(rq->cmd_flags & REQ_COPY_USER) &&
+           (rq->data_len & q->dma_pad_mask)) {
+               unsigned int pad_len = (q->dma_pad_mask & ~rq->data_len) + 1;
+
+               sg->length += pad_len;
+               rq->extra_len += pad_len;
+       }
+
        if (q->dma_drain_size && q->dma_drain_needed(rq)) {
                if (rq->cmd_flags & REQ_RW)
                        memset(q->dma_drain_buffer, 0, q->dma_drain_size);
index 54d0db116153c943674217aac801144a8c55553b..fc41d83be22bb02bab61f09b4b356dbba4697a05 100644 (file)
@@ -276,9 +276,12 @@ int blk_register_queue(struct gendisk *disk)
 
        struct request_queue *q = disk->queue;
 
-       if (!q || !q->request_fn)
+       if (WARN_ON(!q))
                return -ENXIO;
 
+       if (!q->request_fn)
+               return 0;
+
        ret = kobject_add(&q->kobj, kobject_get(&disk->dev.kobj),
                          "%s", "queue");
        if (ret < 0)
@@ -300,7 +303,10 @@ void blk_unregister_queue(struct gendisk *disk)
 {
        struct request_queue *q = disk->queue;
 
-       if (q && q->request_fn) {
+       if (WARN_ON(!q))
+               return;
+
+       if (q->request_fn) {
                elv_unregister_queue(q);
 
                kobject_uevent(&q->kobj, KOBJ_REMOVE);
index 9c9627e8e3348ba9b146dcd6f9d6dadea5ba8181..cf6083a1f9280e5f0008363de88c532abb04b527 100644 (file)
@@ -1349,6 +1349,10 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
                spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
                h->drv[drv_index].busy_configuring = 1;
                spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
+
+               /* deregister_disk sets h->drv[drv_index].queue = NULL */
+               /* which keeps the interrupt handler from starting */
+               /* the queue. */
                ret = deregister_disk(h->gendisk[drv_index],
                                      &h->drv[drv_index], 0);
                h->drv[drv_index].busy_configuring = 0;
@@ -1419,6 +1423,10 @@ geo_inq:
                blk_queue_hardsect_size(disk->queue,
                                        hba[ctlr]->drv[drv_index].block_size);
 
+               /* Make sure all queue data is written out before */
+               /* setting h->drv[drv_index].queue, as setting this */
+               /* allows the interrupt handler to start the queue */
+               wmb();
                h->drv[drv_index].queue = disk->queue;
                add_disk(disk);
        }
@@ -3520,10 +3528,17 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
                        continue;
                blk_queue_hardsect_size(q, drv->block_size);
                set_capacity(disk, drv->nr_blocks);
-               add_disk(disk);
                j++;
        } while (j <= hba[i]->highest_lun);
 
+       /* Make sure all queue data is written out before */
+       /* interrupt handler, triggered by add_disk,  */
+       /* is allowed to start them. */
+       wmb();
+
+       for (j = 0; j <= hba[i]->highest_lun; j++)
+               add_disk(hba[i]->gendisk[j]);
+
        return 1;
 
       clean4:
index 45ac09300eb338c50f372bd51f2532e8bdec8d1b..e4bf9a11ca0d0b1c0cc6a619b4d1fa59bedd5508 100644 (file)
@@ -1349,9 +1349,9 @@ cciss_unregister_scsi(int ctlr)
        /* set scsi_host to NULL so our detect routine will 
           find us on register */
        sa->scsi_host = NULL;
+       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
        scsi_cmd_stack_free(ctlr);
        kfree(sa);
-       spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 }
 
 static int 
index 91ebb007416c185587b22ac08e46993f09fcb7dc..f7f163557aa0f3ea88bd1bf91efd41942b59dfc0 100644 (file)
@@ -82,6 +82,9 @@
 static LIST_HEAD(loop_devices);
 static DEFINE_MUTEX(loop_devices_mutex);
 
+static int max_part;
+static int part_shift;
+
 /*
  * Transfer functions
  */
@@ -692,6 +695,8 @@ static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
                goto out_putf;
 
        fput(old_file);
+       if (max_part > 0)
+               ioctl_by_bdev(bdev, BLKRRPART, 0);
        return 0;
 
  out_putf:
@@ -819,6 +824,8 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
        }
        lo->lo_state = Lo_bound;
        wake_up_process(lo->lo_thread);
+       if (max_part > 0)
+               ioctl_by_bdev(bdev, BLKRRPART, 0);
        return 0;
 
 out_clr:
@@ -919,6 +926,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
        fput(filp);
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
+       if (max_part > 0)
+               ioctl_by_bdev(bdev, BLKRRPART, 0);
        return 0;
 }
 
@@ -1360,6 +1369,8 @@ static struct block_device_operations lo_fops = {
 static int max_loop;
 module_param(max_loop, int, 0);
 MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
+module_param(max_part, int, 0);
+MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
 
@@ -1412,7 +1423,7 @@ static struct loop_device *loop_alloc(int i)
        if (!lo->lo_queue)
                goto out_free_dev;
 
-       disk = lo->lo_disk = alloc_disk(1);
+       disk = lo->lo_disk = alloc_disk(1 << part_shift);
        if (!disk)
                goto out_free_queue;
 
@@ -1422,7 +1433,7 @@ static struct loop_device *loop_alloc(int i)
        init_waitqueue_head(&lo->lo_event);
        spin_lock_init(&lo->lo_lock);
        disk->major             = LOOP_MAJOR;
-       disk->first_minor       = i;
+       disk->first_minor       = i << part_shift;
        disk->fops              = &lo_fops;
        disk->private_data      = lo;
        disk->queue             = lo->lo_queue;
@@ -1502,7 +1513,12 @@ static int __init loop_init(void)
         *     themselves and have kernel automatically instantiate actual
         *     device on-demand.
         */
-       if (max_loop > 1UL << MINORBITS)
+
+       part_shift = 0;
+       if (max_part > 0)
+               part_shift = fls(max_part);
+
+       if (max_loop > 1UL << (MINORBITS - part_shift))
                return -EINVAL;
 
        if (max_loop) {
@@ -1510,7 +1526,7 @@ static int __init loop_init(void)
                range = max_loop;
        } else {
                nr = 8;
-               range = 1UL << MINORBITS;
+               range = 1UL << (MINORBITS - part_shift);
        }
 
        if (register_blkdev(LOOP_MAJOR, "loop"))
@@ -1549,7 +1565,7 @@ static void __exit loop_exit(void)
        unsigned long range;
        struct loop_device *lo, *next;
 
-       range = max_loop ? max_loop :  1UL << MINORBITS;
+       range = max_loop ? max_loop :  1UL << (MINORBITS - part_shift);
 
        list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
                loop_del_one(lo);
index cd5674b63faffb7215c7f02358a1cb9791579913..a18e1ca0f76197e32bdef59323936a627372253e 100644 (file)
@@ -79,9 +79,9 @@ MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30
 
 /* note: prints function name for you */
 #ifdef CARM_DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args)
 #ifdef CARM_VERBOSE_DEBUG
-#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args)
 #else
 #define VPRINTK(fmt, args...)
 #endif /* CARM_VERBOSE_DEBUG */
@@ -96,7 +96,7 @@ MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30
 #define assert(expr) \
         if(unlikely(!(expr))) {                                   \
         printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
-        #expr,__FILE__,__FUNCTION__,__LINE__);          \
+       #expr, __FILE__, __func__, __LINE__);          \
         }
 #endif
 
index 12f5baea439bbf8a85874188b4e2dbeb4d79459a..ac3829030ac581bca1475b9f345e4f7a3f7e7f85 100644 (file)
@@ -360,10 +360,9 @@ static int cdrom_mrw_exit(struct cdrom_device_info *cdi);
 
 static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di);
 
-#ifdef CONFIG_SYSCTL
 static void cdrom_sysctl_register(void);
-#endif /* CONFIG_SYSCTL */ 
-static struct cdrom_device_info *topCdromPtr;
+
+static LIST_HEAD(cdrom_list);
 
 static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
                                      struct packet_command *cgc)
@@ -394,13 +393,11 @@ int register_cdrom(struct cdrom_device_info *cdi)
        cdinfo(CD_OPEN, "entering register_cdrom\n"); 
 
        if (cdo->open == NULL || cdo->release == NULL)
-               return -2;
+               return -EINVAL;
        if (!banner_printed) {
                printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n");
                banner_printed = 1;
-#ifdef CONFIG_SYSCTL
                cdrom_sysctl_register();
-#endif /* CONFIG_SYSCTL */ 
        }
 
        ENSURE(drive_status, CDC_DRIVE_STATUS );
@@ -439,35 +436,18 @@ int register_cdrom(struct cdrom_device_info *cdi)
 
        cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
        mutex_lock(&cdrom_mutex);
-       cdi->next = topCdromPtr;        
-       topCdromPtr = cdi;
+       list_add(&cdi->list, &cdrom_list);
        mutex_unlock(&cdrom_mutex);
        return 0;
 }
 #undef ENSURE
 
-int unregister_cdrom(struct cdrom_device_info *unreg)
+void unregister_cdrom(struct cdrom_device_info *cdi)
 {
-       struct cdrom_device_info *cdi, *prev;
        cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
 
-       prev = NULL;
        mutex_lock(&cdrom_mutex);
-       cdi = topCdromPtr;
-       while (cdi && cdi != unreg) {
-               prev = cdi;
-               cdi = cdi->next;
-       }
-
-       if (cdi == NULL) {
-               mutex_unlock(&cdrom_mutex);
-               return -2;
-       }
-       if (prev)
-               prev->next = cdi->next;
-       else
-               topCdromPtr = cdi->next;
-
+       list_del(&cdi->list);
        mutex_unlock(&cdrom_mutex);
 
        if (cdi->exit)
@@ -475,34 +455,43 @@ int unregister_cdrom(struct cdrom_device_info *unreg)
 
        cdi->ops->n_minors--;
        cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
-       return 0;
 }
 
 int cdrom_get_media_event(struct cdrom_device_info *cdi,
                          struct media_event_desc *med)
 {
        struct packet_command cgc;
-       unsigned char buffer[8];
-       struct event_header *eh = (struct event_header *) buffer;
+       unsigned char *buffer;
+       struct event_header *eh;
+       int ret = 1;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       buffer = kmalloc(8, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       eh = (struct event_header *)buffer;
+
+       init_cdrom_command(&cgc, buffer, 8, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
        cgc.cmd[1] = 1;         /* IMMED */
        cgc.cmd[4] = 1 << 4;    /* media event */
-       cgc.cmd[8] = sizeof(buffer);
+       cgc.cmd[8] = 8;
        cgc.quiet = 1;
 
        if (cdi->ops->generic_packet(cdi, &cgc))
-               return 1;
+               goto err;
 
        if (be16_to_cpu(eh->data_len) < sizeof(*med))
-               return 1;
+               goto err;
 
        if (eh->nea || eh->notification_class != 0x4)
-               return 1;
+               goto err;
 
-       memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
-       return 0;
+       memcpy(med, buffer + sizeof(*eh), sizeof(*med));
+       ret = 0;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 /*
@@ -512,68 +501,82 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi,
 static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char buffer[16];
+       char *buffer;
+       int ret = 1;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       buffer = kmalloc(16, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
 
        cgc.timeout = HZ;
        cgc.quiet = 1;
 
        if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) {
                cdi->mrw_mode_page = MRW_MODE_PC;
-               return 0;
+               ret = 0;
        } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) {
                cdi->mrw_mode_page = MRW_MODE_PC_PRE1;
-               return 0;
+               ret = 0;
        }
-
-       return 1;
+       kfree(buffer);
+       return ret;
 }
 
 static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write)
 {
        struct packet_command cgc;
        struct mrw_feature_desc *mfd;
-       unsigned char buffer[16];
+       unsigned char *buffer;
        int ret;
 
        *write = 0;
+       buffer = kmalloc(16, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[3] = CDF_MRW;
-       cgc.cmd[8] = sizeof(buffer);
+       cgc.cmd[8] = 16;
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];
-       if (be16_to_cpu(mfd->feature_code) != CDF_MRW)
-               return 1;
+       if (be16_to_cpu(mfd->feature_code) != CDF_MRW) {
+               ret = 1;
+               goto err;
+       }
        *write = mfd->write;
 
        if ((ret = cdrom_mrw_probe_pc(cdi))) {
                *write = 0;
-               return ret;
        }
-
-       return 0;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont)
 {
        struct packet_command cgc;
-       unsigned char buffer[12];
+       unsigned char *buffer;
        int ret;
 
        printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : "");
 
+       buffer = kmalloc(12, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
        /*
         * FmtData bit set (bit 4), format type is 1
         */
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE);
+       init_cdrom_command(&cgc, buffer, 12, CGC_DATA_WRITE);
        cgc.cmd[0] = GPCMD_FORMAT_UNIT;
        cgc.cmd[1] = (1 << 4) | 1;
 
@@ -600,6 +603,7 @@ static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont)
        if (ret)
                printk(KERN_INFO "cdrom: bgformat failed\n");
 
+       kfree(buffer);
        return ret;
 }
 
@@ -659,16 +663,17 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
 {
        struct packet_command cgc;
        struct mode_page_header *mph;
-       char buffer[16];
+       char *buffer;
        int ret, offset, size;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       buffer = kmalloc(16, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
 
-       cgc.buffer = buffer;
-       cgc.buflen = sizeof(buffer);
+       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
 
        if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0)))
-               return ret;
+               goto err;
 
        mph = (struct mode_page_header *) buffer;
        offset = be16_to_cpu(mph->desc_length);
@@ -678,55 +683,70 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
        cgc.buflen = size;
 
        if ((ret = cdrom_mode_select(cdi, &cgc)))
-               return ret;
+               goto err;
 
        printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]);
-       return 0;
+       ret = 0;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 static int cdrom_get_random_writable(struct cdrom_device_info *cdi,
                              struct rwrt_feature_desc *rfd)
 {
        struct packet_command cgc;
-       char buffer[24];
+       char *buffer;
        int ret;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       buffer = kmalloc(24, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buffer, 24, CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;   /* often 0x46 */
        cgc.cmd[3] = CDF_RWRT;                  /* often 0x0020 */
-       cgc.cmd[8] = sizeof(buffer);            /* often 0x18 */
+       cgc.cmd[8] = 24;                        /* often 0x18 */
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd));
-       return 0;
+       ret = 0;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char buffer[16];
+       char *buffer;
        __be16 *feature_code;
        int ret;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       buffer = kmalloc(16, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[3] = CDF_HWDM;
-       cgc.cmd[8] = sizeof(buffer);
+       cgc.cmd[8] = 16;
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        feature_code = (__be16 *) &buffer[sizeof(struct feature_header)];
        if (be16_to_cpu(*feature_code) == CDF_HWDM)
-               return 0;
-
-       return 1;
+               ret = 0;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 
@@ -817,10 +837,14 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi)
 static int mo_open_write(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char buffer[255];
+       char *buffer;
        int ret;
 
-       init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ);
+       buffer = kmalloc(255, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buffer, 4, CGC_DATA_READ);
        cgc.quiet = 1;
 
        /*
@@ -837,10 +861,15 @@ static int mo_open_write(struct cdrom_device_info *cdi)
        }
 
        /* drive gave us no info, let the user go ahead */
-       if (ret)
-               return 0;
+       if (ret) {
+               ret = 0;
+               goto err;
+       }
 
-       return buffer[3] & 0x80;
+       ret = buffer[3] & 0x80;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
@@ -863,15 +892,19 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
 static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
 {
        struct packet_command cgc;
-       char buffer[32];
+       char *buffer;
        int ret, mmc3_profile;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       buffer = kmalloc(32, GFP_KERNEL);
+       if (!buffer)
+               return;
+
+       init_cdrom_command(&cgc, buffer, 32, CGC_DATA_READ);
 
        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[1] = 0;
        cgc.cmd[2] = cgc.cmd[3] = 0;            /* Starting Feature Number */
-       cgc.cmd[8] = sizeof(buffer);            /* Allocation Length */
+       cgc.cmd[8] = 32;                        /* Allocation Length */
        cgc.quiet = 1;
 
        if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
@@ -880,6 +913,7 @@ static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
                mmc3_profile = (buffer[6] << 8) | buffer[7];
 
        cdi->mmc3_profile = mmc3_profile;
+       kfree(buffer);
 }
 
 static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
@@ -1594,12 +1628,15 @@ static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned t
 static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 {
        int ret;
-       u_char buf[20];
+       u_char *buf;
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
-       rpc_state_t rpc_state;
+       rpc_state_t *rpc_state;
+
+       buf = kzalloc(20, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
-       memset(buf, 0, sizeof(buf));
        init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ);
 
        switch (ai->type) {
@@ -1610,7 +1647,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsa.agid, 0);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
                ai->lsa.agid = buf[7] >> 6;
                /* Returning data, let host change state */
@@ -1621,7 +1658,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsk.agid, 2);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
                copy_key(ai->lsk.key, &buf[4]);
                /* Returning data, let host change state */
@@ -1632,7 +1669,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsc.agid, 1);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
                copy_chal(ai->lsc.chal, &buf[4]);
                /* Returning data, let host change state */
@@ -1649,7 +1686,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                cgc.cmd[2] = ai->lstk.lba >> 24;
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
                ai->lstk.cpm = (buf[4] >> 7) & 1;
                ai->lstk.cp_sec = (buf[4] >> 6) & 1;
@@ -1663,7 +1700,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                setup_report_key(&cgc, ai->lsasf.agid, 5);
                
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
                ai->lsasf.asf = buf[7] & 1;
                break;
@@ -1676,7 +1713,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                copy_chal(&buf[4], ai->hsc.chal);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
                ai->type = DVD_LU_SEND_KEY1;
                break;
@@ -1689,7 +1726,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
                if ((ret = cdo->generic_packet(cdi, &cgc))) {
                        ai->type = DVD_AUTH_FAILURE;
-                       return ret;
+                       goto err;
                }
                ai->type = DVD_AUTH_ESTABLISHED;
                break;
@@ -1700,24 +1737,23 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); 
                setup_report_key(&cgc, ai->lsa.agid, 0x3f);
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
                break;
 
        /* Get region settings */
        case DVD_LU_SEND_RPC_STATE:
                cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
                setup_report_key(&cgc, 0, 8);
-               memset(&rpc_state, 0, sizeof(rpc_state_t));
-               cgc.buffer = (char *) &rpc_state;
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
 
-               ai->lrpcs.type = rpc_state.type_code;
-               ai->lrpcs.vra = rpc_state.vra;
-               ai->lrpcs.ucca = rpc_state.ucca;
-               ai->lrpcs.region_mask = rpc_state.region_mask;
-               ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme;
+               rpc_state = (rpc_state_t *)buf;
+               ai->lrpcs.type = rpc_state->type_code;
+               ai->lrpcs.vra = rpc_state->vra;
+               ai->lrpcs.ucca = rpc_state->ucca;
+               ai->lrpcs.region_mask = rpc_state->region_mask;
+               ai->lrpcs.rpc_scheme = rpc_state->rpc_scheme;
                break;
 
        /* Set region settings */
@@ -1728,20 +1764,23 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                buf[4] = ai->hrpcs.pdrc;
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
-                       return ret;
+                       goto err;
                break;
 
        default:
                cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
-               return -ENOTTY;
+               ret = -ENOTTY;
+               goto err;
        }
-
-       return 0;
+       ret = 0;
+err:
+       kfree(buf);
+       return ret;
 }
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-       unsigned char buf[21], *base;
+       unsigned char *buf, *base;
        struct dvd_layer *layer;
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
@@ -1750,7 +1789,11 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        if (layer_num >= DVD_LAYERS)
                return -EINVAL;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
+       buf = kmalloc(21, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buf, 21, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[6] = layer_num;
        cgc.cmd[7] = s->type;
@@ -1762,7 +1805,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        cgc.quiet = 1;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        base = &buf[4];
        layer = &s->physical.layer[layer_num];
@@ -1786,17 +1829,24 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
        layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
        layer->bca = base[16] >> 7;
 
-       return 0;
+       ret = 0;
+err:
+       kfree(buf);
+       return ret;
 }
 
 static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
 {
        int ret;
-       u_char buf[8];
+       u_char *buf;
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
+       buf = kmalloc(8, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buf, 8, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[6] = s->copyright.layer_num;
        cgc.cmd[7] = s->type;
@@ -1804,12 +1854,15 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s)
        cgc.cmd[9] = cgc.buflen & 0xff;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        s->copyright.cpst = buf[4];
        s->copyright.rmi = buf[5];
 
-       return 0;
+       ret = 0;
+err:
+       kfree(buf);
+       return ret;
 }
 
 static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
@@ -1841,26 +1894,33 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s)
 static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
 {
        int ret;
-       u_char buf[4 + 188];
+       u_char *buf;
        struct packet_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
 
-       init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
+       buf = kmalloc(4 + 188, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       init_cdrom_command(&cgc, buf, 4 + 188, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
        cgc.cmd[7] = s->type;
        cgc.cmd[9] = cgc.buflen & 0xff;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        s->bca.len = buf[0] << 8 | buf[1];
        if (s->bca.len < 12 || s->bca.len > 188) {
                cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len);
-               return -EIO;
+               ret = -EIO;
+               goto err;
        }
        memcpy(s->bca.value, &buf[4], s->bca.len);
-
-       return 0;
+       ret = 0;
+err:
+       kfree(buf);
+       return ret;
 }
 
 static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s)
@@ -1960,9 +2020,13 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
-       char buffer[32];
+       char *buffer;
        int ret;
 
+       buffer = kmalloc(32, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
        init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);
        cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
        cgc.cmd[1] = 2;     /* MSF addressing */
@@ -1971,7 +2035,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
        cgc.cmd[8] = 16;
 
        if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+               goto err;
 
        subchnl->cdsc_audiostatus = cgc.buffer[1];
        subchnl->cdsc_format = CDROM_MSF;
@@ -1986,7 +2050,10 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi,
        subchnl->cdsc_absaddr.msf.second = cgc.buffer[10];
        subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11];
 
-       return 0;
+       ret = 0;
+err:
+       kfree(buffer);
+       return ret;
 }
 
 /*
@@ -3309,7 +3376,7 @@ static int cdrom_print_info(const char *header, int val, char *info,
 
        *pos += ret;
 
-       for (cdi = topCdromPtr; cdi; cdi = cdi->next) {
+       list_for_each_entry(cdi, &cdrom_list, list) {
                switch (option) {
                case CTL_NAME:
                        ret = scnprintf(info + *pos, max_size - *pos,
@@ -3430,7 +3497,8 @@ static void cdrom_update_settings(void)
 {
        struct cdrom_device_info *cdi;
 
-       for (cdi = topCdromPtr; cdi != NULL; cdi = cdi->next) {
+       mutex_lock(&cdrom_mutex);
+       list_for_each_entry(cdi, &cdrom_list, list) {
                if (autoclose && CDROM_CAN(CDC_CLOSE_TRAY))
                        cdi->options |= CDO_AUTO_CLOSE;
                else if (!autoclose)
@@ -3448,6 +3516,7 @@ static void cdrom_update_settings(void)
                else
                        cdi->options &= ~CDO_CHECK_TYPE;
        }
+       mutex_unlock(&cdrom_mutex);
 }
 
 static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
@@ -3571,22 +3640,29 @@ static void cdrom_sysctl_unregister(void)
                unregister_sysctl_table(cdrom_sysctl_header);
 }
 
+#else /* CONFIG_SYSCTL */
+
+static void cdrom_sysctl_register(void)
+{
+}
+
+static void cdrom_sysctl_unregister(void)
+{
+}
+
 #endif /* CONFIG_SYSCTL */
 
 static int __init cdrom_init(void)
 {
-#ifdef CONFIG_SYSCTL
        cdrom_sysctl_register();
-#endif
+
        return 0;
 }
 
 static void __exit cdrom_exit(void)
 {
        printk(KERN_INFO "Uniform CD-ROM driver unloaded\n");
-#ifdef CONFIG_SYSCTL
        cdrom_sysctl_unregister();
-#endif
 }
 
 module_init(cdrom_init);
index 4e2bbcccc0641c33b22669dcaa352e3d7893591e..71ec426ecffc4f17d9c9237b6aebdc4e13cc385f 100644 (file)
@@ -827,7 +827,9 @@ static int __devexit remove_gdrom(struct platform_device *devptr)
        del_gendisk(gd.disk);
        if (gdrom_major)
                unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
-       return unregister_cdrom(gd.cd_info);
+       unregister_cdrom(gd.cd_info);
+
+       return 0;
 }
 
 static struct platform_driver gdrom_driver = {
index cac06bc1754b327f7e88605c4f1ed838d8187966..b74b6c2768a8fbcd15d0468dc33fbe450e843609 100644 (file)
@@ -650,10 +650,7 @@ static int viocd_remove(struct vio_dev *vdev)
 {
        struct disk_info *d = &viocd_diskinfo[vdev->unit_address];
 
-       if (unregister_cdrom(&d->viocd_info) != 0)
-               printk(VIOCD_KERN_WARNING
-                               "Cannot unregister viocd CD-ROM %s!\n",
-                               d->viocd_info.name);
+       unregister_cdrom(&d->viocd_info);
        del_gendisk(d->viocd_disk);
        blk_cleanup_queue(d->viocd_disk->queue);
        put_disk(d->viocd_disk);
index 396000208f81ddd19062259724de074863110a3c..fe5aefbf83392fae89553050dd484dcf108fd428 100644 (file)
@@ -2032,9 +2032,8 @@ static void ide_cd_release(struct kref *kref)
 
        kfree(info->buffer);
        kfree(info->toc);
-       if (devinfo->handle == drive && unregister_cdrom(devinfo))
-               printk(KERN_ERR "%s: %s failed to unregister device from the cdrom "
-                               "driver.\n", __FUNCTION__, drive->name);
+       if (devinfo->handle == drive)
+               unregister_cdrom(devinfo);
        drive->dsc_overlap = 0;
        drive->driver_data = NULL;
        blk_queue_prep_rq(drive->queue, NULL);
index f6980bd9d8f9a9a8b75a57de89cd9c8e26cc214c..12d69d7c85775475ce89de8fc6a6381ba4453809 100644 (file)
@@ -852,7 +852,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
                                "Notifying upper driver of completion "
                                "(result %x)\n", cmd->result));
 
-       good_bytes = scsi_bufflen(cmd) + cmd->request->extra_len;
+       good_bytes = scsi_bufflen(cmd);
         if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
                drv = scsi_cmd_to_driver(cmd);
                if (drv->done)
index 553b5b7960ad1a3f380f03afbf780f0867767972..6e0b6f66df0315a450f467c1025c8b1042845ced 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -444,22 +444,27 @@ int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
 
 struct bio_map_data {
        struct bio_vec *iovecs;
-       void __user *userptr;
+       int nr_sgvecs;
+       struct sg_iovec *sgvecs;
 };
 
-static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio)
+static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio,
+                            struct sg_iovec *iov, int iov_count)
 {
        memcpy(bmd->iovecs, bio->bi_io_vec, sizeof(struct bio_vec) * bio->bi_vcnt);
+       memcpy(bmd->sgvecs, iov, sizeof(struct sg_iovec) * iov_count);
+       bmd->nr_sgvecs = iov_count;
        bio->bi_private = bmd;
 }
 
 static void bio_free_map_data(struct bio_map_data *bmd)
 {
        kfree(bmd->iovecs);
+       kfree(bmd->sgvecs);
        kfree(bmd);
 }
 
-static struct bio_map_data *bio_alloc_map_data(int nr_segs)
+static struct bio_map_data *bio_alloc_map_data(int nr_segs, int iov_count)
 {
        struct bio_map_data *bmd = kmalloc(sizeof(*bmd), GFP_KERNEL);
 
@@ -467,13 +472,71 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs)
                return NULL;
 
        bmd->iovecs = kmalloc(sizeof(struct bio_vec) * nr_segs, GFP_KERNEL);
-       if (bmd->iovecs)
+       if (!bmd->iovecs) {
+               kfree(bmd);
+               return NULL;
+       }
+
+       bmd->sgvecs = kmalloc(sizeof(struct sg_iovec) * iov_count, GFP_KERNEL);
+       if (bmd->sgvecs)
                return bmd;
 
+       kfree(bmd->iovecs);
        kfree(bmd);
        return NULL;
 }
 
+static int __bio_copy_iov(struct bio *bio, struct sg_iovec *iov, int iov_count,
+                         int uncopy)
+{
+       int ret = 0, i;
+       struct bio_vec *bvec;
+       int iov_idx = 0;
+       unsigned int iov_off = 0;
+       int read = bio_data_dir(bio) == READ;
+
+       __bio_for_each_segment(bvec, bio, i, 0) {
+               char *bv_addr = page_address(bvec->bv_page);
+               unsigned int bv_len = bvec->bv_len;
+
+               while (bv_len && iov_idx < iov_count) {
+                       unsigned int bytes;
+                       char *iov_addr;
+
+                       bytes = min_t(unsigned int,
+                                     iov[iov_idx].iov_len - iov_off, bv_len);
+                       iov_addr = iov[iov_idx].iov_base + iov_off;
+
+                       if (!ret) {
+                               if (!read && !uncopy)
+                                       ret = copy_from_user(bv_addr, iov_addr,
+                                                            bytes);
+                               if (read && uncopy)
+                                       ret = copy_to_user(iov_addr, bv_addr,
+                                                          bytes);
+
+                               if (ret)
+                                       ret = -EFAULT;
+                       }
+
+                       bv_len -= bytes;
+                       bv_addr += bytes;
+                       iov_addr += bytes;
+                       iov_off += bytes;
+
+                       if (iov[iov_idx].iov_len == iov_off) {
+                               iov_idx++;
+                               iov_off = 0;
+                       }
+               }
+
+               if (uncopy)
+                       __free_page(bvec->bv_page);
+       }
+
+       return ret;
+}
+
 /**
  *     bio_uncopy_user -       finish previously mapped bio
  *     @bio: bio being terminated
@@ -484,55 +547,56 @@ static struct bio_map_data *bio_alloc_map_data(int nr_segs)
 int bio_uncopy_user(struct bio *bio)
 {
        struct bio_map_data *bmd = bio->bi_private;
-       const int read = bio_data_dir(bio) == READ;
-       struct bio_vec *bvec;
-       int i, ret = 0;
+       int ret;
 
-       __bio_for_each_segment(bvec, bio, i, 0) {
-               char *addr = page_address(bvec->bv_page);
-               unsigned int len = bmd->iovecs[i].bv_len;
+       ret = __bio_copy_iov(bio, bmd->sgvecs, bmd->nr_sgvecs, 1);
 
-               if (read && !ret && copy_to_user(bmd->userptr, addr, len))
-                       ret = -EFAULT;
-
-               __free_page(bvec->bv_page);
-               bmd->userptr += len;
-       }
        bio_free_map_data(bmd);
        bio_put(bio);
        return ret;
 }
 
 /**
- *     bio_copy_user   -       copy user data to bio
+ *     bio_copy_user_iov       -       copy user data to bio
  *     @q: destination block queue
- *     @uaddr: start of user address
- *     @len: length in bytes
+ *     @iov:   the iovec.
+ *     @iov_count: number of elements in the iovec
  *     @write_to_vm: bool indicating writing to pages or not
  *
  *     Prepares and returns a bio for indirect user io, bouncing data
  *     to/from kernel pages as necessary. Must be paired with
  *     call bio_uncopy_user() on io completion.
  */
-struct bio *bio_copy_user(struct request_queue *q, unsigned long uaddr,
-                         unsigned int len, int write_to_vm)
+struct bio *bio_copy_user_iov(struct request_queue *q, struct sg_iovec *iov,
+                             int iov_count, int write_to_vm)
 {
-       unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       unsigned long start = uaddr >> PAGE_SHIFT;
        struct bio_map_data *bmd;
        struct bio_vec *bvec;
        struct page *page;
        struct bio *bio;
        int i, ret;
+       int nr_pages = 0;
+       unsigned int len = 0;
 
-       bmd = bio_alloc_map_data(end - start);
+       for (i = 0; i < iov_count; i++) {
+               unsigned long uaddr;
+               unsigned long end;
+               unsigned long start;
+
+               uaddr = (unsigned long)iov[i].iov_base;
+               end = (uaddr + iov[i].iov_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+               start = uaddr >> PAGE_SHIFT;
+
+               nr_pages += end - start;
+               len += iov[i].iov_len;
+       }
+
+       bmd = bio_alloc_map_data(nr_pages, iov_count);
        if (!bmd)
                return ERR_PTR(-ENOMEM);
 
-       bmd->userptr = (void __user *) uaddr;
-
        ret = -ENOMEM;
-       bio = bio_alloc(GFP_KERNEL, end - start);
+       bio = bio_alloc(GFP_KERNEL, nr_pages);
        if (!bio)
                goto out_bmd;
 
@@ -564,22 +628,12 @@ struct bio *bio_copy_user(struct request_queue *q, unsigned long uaddr,
         * success
         */
        if (!write_to_vm) {
-               char __user *p = (char __user *) uaddr;
-
-               /*
-                * for a write, copy in data to kernel pages
-                */
-               ret = -EFAULT;
-               bio_for_each_segment(bvec, bio, i) {
-                       char *addr = page_address(bvec->bv_page);
-
-                       if (copy_from_user(addr, p, bvec->bv_len))
-                               goto cleanup;
-                       p += bvec->bv_len;
-               }
+               ret = __bio_copy_iov(bio, iov, iov_count, 0);
+               if (ret)
+                       goto cleanup;
        }
 
-       bio_set_map_data(bmd, bio);
+       bio_set_map_data(bmd, bio, iov, iov_count);
        return bio;
 cleanup:
        bio_for_each_segment(bvec, bio, i)
@@ -591,6 +645,28 @@ out_bmd:
        return ERR_PTR(ret);
 }
 
+/**
+ *     bio_copy_user   -       copy user data to bio
+ *     @q: destination block queue
+ *     @uaddr: start of user address
+ *     @len: length in bytes
+ *     @write_to_vm: bool indicating writing to pages or not
+ *
+ *     Prepares and returns a bio for indirect user io, bouncing data
+ *     to/from kernel pages as necessary. Must be paired with
+ *     call bio_uncopy_user() on io completion.
+ */
+struct bio *bio_copy_user(struct request_queue *q, unsigned long uaddr,
+                         unsigned int len, int write_to_vm)
+{
+       struct sg_iovec iov;
+
+       iov.iov_base = (void __user *)uaddr;
+       iov.iov_len = len;
+
+       return bio_copy_user_iov(q, &iov, 1, write_to_vm);
+}
+
 static struct bio *__bio_map_user_iov(struct request_queue *q,
                                      struct block_device *bdev,
                                      struct sg_iovec *iov, int iov_count,
index 4c59bdccd3ee7412a26dfe9eae9ba88f58a54686..d259690863fb0494a5d1ceeb580f30d0ac793eef 100644 (file)
@@ -327,6 +327,8 @@ extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
 extern void bio_set_pages_dirty(struct bio *bio);
 extern void bio_check_pages_dirty(struct bio *bio);
 extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int);
+extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *,
+                                    int, int);
 extern int bio_uncopy_user(struct bio *);
 void zero_fill_bio(struct bio *bio);
 
index 6f79d40dd3c01f25c105b9bdae4f5e70a7c88e1e..c5065e3d2ca9eea3e1a4319d117cdf4d5abbd539 100644 (file)
@@ -112,6 +112,7 @@ enum rq_flag_bits {
        __REQ_RW_SYNC,          /* request is sync (O_DIRECT) */
        __REQ_ALLOCED,          /* request came from our alloc pool */
        __REQ_RW_META,          /* metadata io request */
+       __REQ_COPY_USER,        /* contains copies of user pages */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -133,6 +134,7 @@ enum rq_flag_bits {
 #define REQ_RW_SYNC    (1 << __REQ_RW_SYNC)
 #define REQ_ALLOCED    (1 << __REQ_ALLOCED)
 #define REQ_RW_META    (1 << __REQ_RW_META)
+#define REQ_COPY_USER  (1 << __REQ_COPY_USER)
 
 #define BLK_MAX_CDB    16
 
@@ -533,8 +535,13 @@ extern unsigned long blk_max_low_pfn, blk_max_pfn;
  * BLK_BOUNCE_ANY      : don't bounce anything
  * BLK_BOUNCE_ISA      : bounce pages above ISA DMA boundary
  */
+
+#if BITS_PER_LONG == 32
 #define BLK_BOUNCE_HIGH                ((u64)blk_max_low_pfn << PAGE_SHIFT)
-#define BLK_BOUNCE_ANY         ((u64)blk_max_pfn << PAGE_SHIFT)
+#else
+#define BLK_BOUNCE_HIGH                -1ULL
+#endif
+#define BLK_BOUNCE_ANY         (-1ULL)
 #define BLK_BOUNCE_ISA         (ISA_DMA_THRESHOLD)
 
 /*
index a5cd2047624ef4e721914e52cf051521c134f704..5db265ea60f625a8e281f3ae004a7d90f15f6e00 100644 (file)
@@ -910,6 +910,7 @@ struct mode_page_header {
 #ifdef __KERNEL__
 #include <linux/fs.h>          /* not really needed, later.. */
 #include <linux/device.h>
+#include <linux/list.h>
 
 struct packet_command
 {
@@ -934,7 +935,7 @@ struct packet_command
 /* Uniform cdrom data structures for cdrom.c */
 struct cdrom_device_info {
        struct cdrom_device_ops  *ops;  /* link to device_ops */
-       struct cdrom_device_info *next; /* next device_info for this major */
+       struct list_head list;          /* linked list of all device_info */
        struct gendisk *disk;           /* matching block layer disk */
        void *handle;                   /* driver-dependent data */
 /* specifications */
@@ -994,7 +995,7 @@ extern int cdrom_ioctl(struct file *file, struct cdrom_device_info *cdi,
 extern int cdrom_media_changed(struct cdrom_device_info *);
 
 extern int register_cdrom(struct cdrom_device_info *cdi);
-extern int unregister_cdrom(struct cdrom_device_info *cdi);
+extern void unregister_cdrom(struct cdrom_device_info *cdi);
 
 typedef struct {
     int data;