aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
Diffstat (limited to 'block')
-rw-r--r--block/Kconfig65
-rw-r--r--block/blk-map.c46
-rw-r--r--block/blk-merge.c9
-rw-r--r--block/blk-sysfs.c10
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);