diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/Kconfig | 65 | ||||
-rw-r--r-- | block/blk-map.c | 46 | ||||
-rw-r--r-- | block/blk-merge.c | 9 | ||||
-rw-r--r-- | block/blk-sysfs.c | 10 |
4 files changed, 81 insertions, 49 deletions
diff --git a/block/Kconfig b/block/Kconfig index 7db9a411649..3e97f2bc446 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -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 diff --git a/block/blk-map.c b/block/blk-map.c index c07d9c8317f..3c942bd6422 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -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; diff --git a/block/blk-merge.c b/block/blk-merge.c index 0f58616bcd7..b5c5c4a9e3f 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -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); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 54d0db11615..fc41d83be22 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -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); |