aboutsummaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
Diffstat (limited to 'block')
-rw-r--r--block/blk-barrier.c4
-rw-r--r--block/blk-core.c30
-rw-r--r--block/blk-map.c8
-rw-r--r--block/blk-merge.c21
-rw-r--r--block/blk-settings.c4
-rw-r--r--block/blk-timeout.c20
-rw-r--r--block/bsg.c11
-rw-r--r--block/cmd-filter.c2
-rw-r--r--block/compat_ioctl.c160
-rw-r--r--block/elevator.c7
-rw-r--r--block/genhd.c41
-rw-r--r--block/ioctl.c180
-rw-r--r--block/scsi_ioctl.c35
13 files changed, 272 insertions, 251 deletions
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index 5c99ff8d2db..6e72d661ae4 100644
--- a/block/blk-barrier.c
+++ b/block/blk-barrier.c
@@ -161,7 +161,7 @@ static inline struct request *start_ordered(struct request_queue *q,
/*
* Prep proxy barrier request.
*/
- blkdev_dequeue_request(rq);
+ elv_dequeue_request(q, rq);
q->orig_bar_rq = rq;
rq = &q->bar_rq;
blk_rq_init(q, rq);
@@ -219,7 +219,7 @@ int blk_do_ordered(struct request_queue *q, struct request **rqp)
* This can happen when the queue switches to
* ORDERED_NONE while this request is on it.
*/
- blkdev_dequeue_request(rq);
+ elv_dequeue_request(q, rq);
if (__blk_end_request(rq, -EOPNOTSUPP,
blk_rq_bytes(rq)))
BUG();
diff --git a/block/blk-core.c b/block/blk-core.c
index c3df30cfb3f..c36aa98fafa 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -592,7 +592,7 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
1 << QUEUE_FLAG_STACKABLE);
q->queue_lock = lock;
- blk_queue_segment_boundary(q, 0xffffffff);
+ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
blk_queue_make_request(q, __make_request);
blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
@@ -1637,6 +1637,28 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
/**
+ * blkdev_dequeue_request - dequeue request and start timeout timer
+ * @req: request to dequeue
+ *
+ * Dequeue @req and start timeout timer on it. This hands off the
+ * request to the driver.
+ *
+ * Block internal functions which don't want to start timer should
+ * call elv_dequeue_request().
+ */
+void blkdev_dequeue_request(struct request *req)
+{
+ elv_dequeue_request(req->q, req);
+
+ /*
+ * We are now handing the request to the hardware, add the
+ * timeout handler.
+ */
+ blk_add_timer(req);
+}
+EXPORT_SYMBOL(blkdev_dequeue_request);
+
+/**
* __end_that_request_first - end I/O on a request
* @req: the request being processed
* @error: %0 for success, < %0 for error
@@ -1770,17 +1792,17 @@ static void end_that_request_last(struct request *req, int error)
{
struct gendisk *disk = req->rq_disk;
- blk_delete_timer(req);
-
if (blk_rq_tagged(req))
blk_queue_end_tag(req->q, req);
if (blk_queued_rq(req))
- blkdev_dequeue_request(req);
+ elv_dequeue_request(req->q, req);
if (unlikely(laptop_mode) && blk_fs_request(req))
laptop_io_completion();
+ blk_delete_timer(req);
+
/*
* Account IO completion. bar_rq isn't accounted as a normal
* IO on queueing nor completion. Accounting the containing
diff --git a/block/blk-map.c b/block/blk-map.c
index 4849fa36161..2990447f45e 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -217,8 +217,14 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
return PTR_ERR(bio);
if (bio->bi_size != len) {
+ /*
+ * Grab an extra reference to this bio, as bio_unmap_user()
+ * expects to be able to drop it twice as it happens on the
+ * normal IO completion path
+ */
+ bio_get(bio);
bio_endio(bio, 0);
- bio_unmap_user(bio);
+ __blk_rq_unmap_user(bio);
return -EINVAL;
}
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 8681cd6f991..b92f5b0866b 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -222,27 +222,6 @@ new_segment:
}
EXPORT_SYMBOL(blk_rq_map_sg);
-static inline int ll_new_mergeable(struct request_queue *q,
- struct request *req,
- struct bio *bio)
-{
- int nr_phys_segs = bio_phys_segments(q, bio);
-
- if (req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
- req->cmd_flags |= REQ_NOMERGE;
- if (req == q->last_merge)
- q->last_merge = NULL;
- return 0;
- }
-
- /*
- * A hw segment is just getting larger, bump just the phys
- * counter.
- */
- req->nr_phys_segments += nr_phys_segs;
- return 1;
-}
-
static inline int ll_new_hw_segment(struct request_queue *q,
struct request *req,
struct bio *bio)
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 41392fbe19f..afa55e14e27 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -125,6 +125,9 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
q->nr_requests = BLKDEV_MAX_RQ;
blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
+ blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
+ blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
+
q->make_request_fn = mfn;
q->backing_dev_info.ra_pages =
(VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
@@ -314,6 +317,7 @@ void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b)
/* zero is "infinity" */
t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
+ t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, b->seg_boundary_mask);
t->max_phys_segments = min(t->max_phys_segments, b->max_phys_segments);
t->max_hw_segments = min(t->max_hw_segments, b->max_hw_segments);
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index 972a63f848f..69185ea9fae 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -75,14 +75,7 @@ void blk_delete_timer(struct request *req)
{
struct request_queue *q = req->q;
- /*
- * Nothing to detach
- */
- if (!q->rq_timed_out_fn || !req->deadline)
- return;
-
list_del_init(&req->timeout_list);
-
if (list_empty(&q->timeout_list))
del_timer(&q->timeout);
}
@@ -142,7 +135,7 @@ void blk_rq_timed_out_timer(unsigned long data)
}
if (next_set && !list_empty(&q->timeout_list))
- mod_timer(&q->timeout, round_jiffies(next));
+ mod_timer(&q->timeout, round_jiffies_up(next));
spin_unlock_irqrestore(q->queue_lock, flags);
}
@@ -198,17 +191,10 @@ void blk_add_timer(struct request *req)
/*
* If the timer isn't already pending or this timeout is earlier
- * than an existing one, modify the timer. Round to next nearest
+ * than an existing one, modify the timer. Round up to next nearest
* second.
*/
- expiry = round_jiffies(req->deadline);
-
- /*
- * We use ->deadline == 0 to detect whether a timer was added or
- * not, so just increase to next jiffy for that specific case
- */
- if (unlikely(!req->deadline))
- req->deadline = 1;
+ expiry = round_jiffies_up(req->deadline);
if (!timer_pending(&q->timeout) ||
time_before(expiry, q->timeout.expires))
diff --git a/block/bsg.c b/block/bsg.c
index 034112bfe1f..e73e50daf3d 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -173,7 +173,7 @@ unlock:
static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
struct sg_io_v4 *hdr, struct bsg_device *bd,
- int has_write_perm)
+ fmode_t has_write_perm)
{
if (hdr->request_len > BLK_MAX_CDB) {
rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
@@ -202,6 +202,8 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
rq->timeout = q->sg_timeout;
if (!rq->timeout)
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
+ if (rq->timeout < BLK_MIN_SG_TIMEOUT)
+ rq->timeout = BLK_MIN_SG_TIMEOUT;
return 0;
}
@@ -242,7 +244,7 @@ bsg_validate_sgv4_hdr(struct request_queue *q, struct sg_io_v4 *hdr, int *rw)
* map sg_io_v4 to a request.
*/
static struct request *
-bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, int has_write_perm)
+bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm)
{
struct request_queue *q = bd->queue;
struct request *rq, *next_rq = NULL;
@@ -601,7 +603,8 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
}
static int __bsg_write(struct bsg_device *bd, const char __user *buf,
- size_t count, ssize_t *bytes_written, int has_write_perm)
+ size_t count, ssize_t *bytes_written,
+ fmode_t has_write_perm)
{
struct bsg_command *bc;
struct request *rq;
@@ -913,7 +916,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case SG_EMULATED_HOST:
case SCSI_IOCTL_SEND_COMMAND: {
void __user *uarg = (void __user *) arg;
- return scsi_cmd_ioctl(file, bd->queue, NULL, cmd, uarg);
+ return scsi_cmd_ioctl(bd->queue, NULL, file->f_mode, cmd, uarg);
}
case SG_IO: {
struct request *rq;
diff --git a/block/cmd-filter.c b/block/cmd-filter.c
index e669aed4c6b..504b275e1b9 100644
--- a/block/cmd-filter.c
+++ b/block/cmd-filter.c
@@ -27,7 +27,7 @@
#include <linux/cdrom.h>
int blk_verify_command(struct blk_cmd_filter *filter,
- unsigned char *cmd, int has_write_perm)
+ unsigned char *cmd, fmode_t has_write_perm)
{
/* root can do any command. */
if (capable(CAP_SYS_RAWIO))
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 1e559fba7bd..67eb93cff69 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -71,8 +71,8 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
return ret;
}
-static int compat_hdio_ioctl(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_hdio_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
mm_segment_t old_fs = get_fs();
unsigned long kval;
@@ -80,7 +80,7 @@ static int compat_hdio_ioctl(struct inode *inode, struct file *file,
int error;
set_fs(KERNEL_DS);
- error = blkdev_driver_ioctl(inode, file, disk,
+ error = __blkdev_driver_ioctl(bdev, mode,
cmd, (unsigned long)(&kval));
set_fs(old_fs);
@@ -111,8 +111,8 @@ struct compat_cdrom_generic_command {
compat_caddr_t reserved[1];
};
-static int compat_cdrom_read_audio(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_cdrom_read_audio(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
struct cdrom_read_audio __user *cdread_audio;
struct compat_cdrom_read_audio __user *cdread_audio32;
@@ -134,12 +134,12 @@ static int compat_cdrom_read_audio(struct inode *inode, struct file *file,
if (put_user(datap, &cdread_audio->buf))
return -EFAULT;
- return blkdev_driver_ioctl(inode, file, disk, cmd,
+ return __blkdev_driver_ioctl(bdev, mode, cmd,
(unsigned long)cdread_audio);
}
-static int compat_cdrom_generic_command(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_cdrom_generic_command(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
struct cdrom_generic_command __user *cgc;
struct compat_cdrom_generic_command __user *cgc32;
@@ -167,7 +167,7 @@ static int compat_cdrom_generic_command(struct inode *inode, struct file *file,
put_user(compat_ptr(data), &cgc->reserved[0]))
return -EFAULT;
- return blkdev_driver_ioctl(inode, file, disk, cmd, (unsigned long)cgc);
+ return __blkdev_driver_ioctl(bdev, mode, cmd, (unsigned long)cgc);
}
struct compat_blkpg_ioctl_arg {
@@ -177,7 +177,7 @@ struct compat_blkpg_ioctl_arg {
compat_caddr_t data;
};
-static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
+static int compat_blkpg_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32)
{
struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a));
@@ -196,7 +196,7 @@ static int compat_blkpg_ioctl(struct inode *inode, struct file *file,
if (err)
return err;
- return blkdev_ioctl(inode, file, cmd, (unsigned long)a);
+ return blkdev_ioctl(bdev, mode, cmd, (unsigned long)a);
}
#define BLKBSZGET_32 _IOR(0x12, 112, int)
@@ -308,8 +308,8 @@ static struct {
#define NR_FD_IOCTL_TRANS ARRAY_SIZE(fd_ioctl_trans_table)
-static int compat_fd_ioctl(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned int cmd, unsigned long arg)
+static int compat_fd_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
{
mm_segment_t old_fs = get_fs();
void *karg = NULL;
@@ -413,7 +413,7 @@ static int compat_fd_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
set_fs(KERNEL_DS);
- err = blkdev_driver_ioctl(inode, file, disk, kcmd, (unsigned long)karg);
+ err = __blkdev_driver_ioctl(bdev, mode, kcmd, (unsigned long)karg);
set_fs(old_fs);
if (err)
goto out;
@@ -579,11 +579,9 @@ static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg)
return 0;
}
-static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned cmd, unsigned long arg)
+static int compat_blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
{
- int ret;
-
switch (cmd) {
case HDIO_GET_UNMASKINTR:
case HDIO_GET_MULTCOUNT:
@@ -596,7 +594,7 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
case HDIO_GET_ACOUSTIC:
case HDIO_GET_ADDRESS:
case HDIO_GET_BUSSTATE:
- return compat_hdio_ioctl(inode, file, disk, cmd, arg);
+ return compat_hdio_ioctl(bdev, mode, cmd, arg);
case FDSETPRM32:
case FDDEFPRM32:
case FDGETPRM32:
@@ -606,11 +604,11 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
case FDPOLLDRVSTAT32:
case FDGETFDCSTAT32:
case FDWERRORGET32:
- return compat_fd_ioctl(inode, file, disk, cmd, arg);
+ return compat_fd_ioctl(bdev, mode, cmd, arg);
case CDROMREADAUDIO:
- return compat_cdrom_read_audio(inode, file, disk, cmd, arg);
+ return compat_cdrom_read_audio(bdev, mode, cmd, arg);
case CDROM_SEND_PACKET:
- return compat_cdrom_generic_command(inode, file, disk, cmd, arg);
+ return compat_cdrom_generic_command(bdev, mode, cmd, arg);
/*
* No handler required for the ones below, we just need to
@@ -708,26 +706,49 @@ static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file,
return -ENOIOCTLCMD;
}
- if (disk->fops->unlocked_ioctl)
- return disk->fops->unlocked_ioctl(file, cmd, arg);
-
- if (disk->fops->ioctl) {
- lock_kernel();
- ret = disk->fops->ioctl(inode, file, cmd, arg);
- unlock_kernel();
- return ret;
- }
-
- return -ENOTTY;
+ return __blkdev_driver_ioctl(bdev, mode, cmd, arg);
}
-static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
- struct block_device *bdev,
- unsigned cmd, unsigned long arg)
+/* Most of the generic ioctls are handled in the normal fallback path.
+ This assumes the blkdev's low level compat_ioctl always returns
+ ENOIOCTLCMD for unknown ioctls. */
+long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
+ int ret = -ENOIOCTLCMD;
+ struct inode *inode = file->f_mapping->host;
+ struct block_device *bdev = inode->i_bdev;
+ struct gendisk *disk = bdev->bd_disk;
+ fmode_t mode = file->f_mode;
struct backing_dev_info *bdi;
+ loff_t size;
+
+ /*
+ * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
+ * to updated it before every ioctl.
+ */
+ if (file->f_flags & O_NDELAY)
+ mode |= FMODE_NDELAY;
+ else
+ mode &= ~FMODE_NDELAY;
switch (cmd) {
+ case HDIO_GETGEO:
+ return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
+ case BLKFLSBUF:
+ case BLKROSET:
+ case BLKDISCARD:
+ /*
+ * the ones below are implemented in blkdev_locked_ioctl,
+ * but we call blkdev_ioctl, which gets the lock for us
+ */
+ case BLKRRPART:
+ return blkdev_ioctl(bdev, mode, cmd,
+ (unsigned long)compat_ptr(arg));
+ case BLKBSZSET_32:
+ return blkdev_ioctl(bdev, mode, BLKBSZSET,
+ (unsigned long)compat_ptr(arg));
+ case BLKPG:
+ return compat_blkpg_ioctl(bdev, mode, cmd, compat_ptr(arg));
case BLKRAGET:
case BLKFRAGET:
if (!arg)
@@ -753,65 +774,36 @@ static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file,
bdi = blk_get_backing_dev_info(bdev);
if (bdi == NULL)
return -ENOTTY;
+ lock_kernel();
bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+ unlock_kernel();
return 0;
case BLKGETSIZE:
- if ((bdev->bd_inode->i_size >> 9) > ~0UL)
+ size = bdev->bd_inode->i_size;
+ if ((size >> 9) > ~0UL)
return -EFBIG;
- return compat_put_ulong(arg, bdev->bd_inode->i_size >> 9);
+ return compat_put_ulong(arg, size >> 9);
case BLKGETSIZE64_32:
return compat_put_u64(arg, bdev->bd_inode->i_size);
case BLKTRACESETUP32:
- return compat_blk_trace_setup(bdev, compat_ptr(arg));
+ lock_kernel();
+ ret = compat_blk_trace_setup(bdev, compat_ptr(arg));
+ unlock_kernel();
+ return ret;
case BLKTRACESTART: /* compatible */
case BLKTRACESTOP: /* compatible */
case BLKTRACETEARDOWN: /* compatible */
- return blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
- }
- return -ENOIOCTLCMD;
-}
-
-/* Most of the generic ioctls are handled in the normal fallback path.
- This assumes the blkdev's low level compat_ioctl always returns
- ENOIOCTLCMD for unknown ioctls. */
-long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
-{
- int ret = -ENOIOCTLCMD;
- struct inode *inode = file->f_mapping->host;
- struct block_device *bdev = inode->i_bdev;
- struct gendisk *disk = bdev->bd_disk;
-
- switch (cmd) {
- case HDIO_GETGEO:
- return compat_hdio_getgeo(disk, bdev, compat_ptr(arg));
- case BLKFLSBUF:
- case BLKROSET:
- case BLKDISCARD:
- /*
- * the ones below are implemented in blkdev_locked_ioctl,
- * but we call blkdev_ioctl, which gets the lock for us
- */
- case BLKRRPART:
- return blkdev_ioctl(inode, file, cmd,
- (unsigned long)compat_ptr(arg));
- case BLKBSZSET_32:
- return blkdev_ioctl(inode, file, BLKBSZSET,
- (unsigned long)compat_ptr(arg));
- case BLKPG:
- return compat_blkpg_ioctl(inode, file, cmd, compat_ptr(arg));
- }
-
- lock_kernel();
- ret = compat_blkdev_locked_ioctl(inode, file, bdev, cmd, arg);
- /* FIXME: why do we assume -> compat_ioctl needs the BKL? */
- if (ret == -ENOIOCTLCMD && disk->fops->compat_ioctl)
- ret = disk->fops->compat_ioctl(file, cmd, arg);
- unlock_kernel();
-
- if (ret != -ENOIOCTLCMD)
+ lock_kernel();
+ ret = blk_trace_ioctl(bdev, cmd, compat_ptr(arg));
+ unlock_kernel();
return ret;
-
- return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg);
+ default:
+ if (disk->fops->compat_ioctl)
+ ret = disk->fops->compat_ioctl(bdev, mode, cmd, arg);
+ if (ret == -ENOIOCTLCMD)
+ ret = compat_blkdev_driver_ioctl(bdev, mode, cmd, arg);
+ return ret;
+ }
}
diff --git a/block/elevator.c b/block/elevator.c
index 59173a69ebd..a6951f76ba0 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -773,12 +773,6 @@ struct request *elv_next_request(struct request_queue *q)
*/
rq->cmd_flags |= REQ_STARTED;
blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
-
- /*
- * We are now handing the request to the hardware,
- * add the timeout handler
- */
- blk_add_timer(rq);
}
if (!q->boundary_rq || q->boundary_rq == rq) {
@@ -851,7 +845,6 @@ void elv_dequeue_request(struct request_queue *q, struct request *rq)
if (blk_account_rq(rq))
q->in_flight++;
}
-EXPORT_SYMBOL(elv_dequeue_request);
int elv_queue_empty(struct request_queue *q)
{
diff --git a/block/genhd.c b/block/genhd.c
index 646e1d2507c..2f7feda61e3 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -10,6 +10,7 @@
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/kmod.h>
@@ -727,12 +728,24 @@ static int show_partition(struct seq_file *seqf, void *v)
return 0;
}
-const struct seq_operations partitions_op = {
+static const struct seq_operations partitions_op = {
.start = show_partition_start,
.next = disk_seqf_next,
.stop = disk_seqf_stop,
.show = show_partition
};
+
+static int partitions_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &partitions_op);
+}
+
+static const struct file_operations proc_partitions_operations = {
+ .open = partitions_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
#endif
@@ -755,6 +768,8 @@ static int __init genhd_device_init(void)
bdev_map = kobj_map_init(base_probe, &block_class_lock);
blk_dev_init();
+ register_blkdev(BLOCK_EXT_MAJOR, "blkext");
+
#ifndef CONFIG_SYSFS_DEPRECATED
/* create top-level block dir */
block_depr = kobject_create_and_add("block", NULL);
@@ -992,12 +1007,32 @@ static int diskstats_show(struct seq_file *seqf, void *v)
return 0;
}
-const struct seq_operations diskstats_op = {
+static const struct seq_operations diskstats_op = {
.start = disk_seqf_start,
.next = disk_seqf_next,
.stop = disk_seqf_stop,
.show = diskstats_show
};
+
+static int diskstats_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &diskstats_op);
+}
+
+static const struct file_operations proc_diskstats_operations = {
+ .open = diskstats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init proc_genhd_init(void)
+{
+ proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
+ proc_create("partitions", 0, NULL, &proc_partitions_operations);
+ return 0;
+}
+module_init(proc_genhd_init);
#endif /* CONFIG_PROC_FS */
static void media_change_notify_thread(struct work_struct *work)
@@ -1067,6 +1102,7 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
kfree(disk);
return NULL;
}
+ disk->node_id = node_id;
if (disk_expand_part_tbl(disk, 0)) {
free_part_stats(&disk->part0);
kfree(disk);
@@ -1081,7 +1117,6 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
device_initialize(disk_to_dev(disk));
INIT_WORK(&disk->async_notify,
media_change_notify_thread);
- disk->node_id = node_id;
}
return disk;
}
diff --git a/block/ioctl.c b/block/ioctl.c
index 38bee321e1f..d03985b04d6 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -18,7 +18,6 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
struct disk_part_iter piter;
long long start, length;
int partno;
- int err;
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -61,10 +60,10 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
disk_part_iter_exit(&piter);
/* all seems OK */
- err = add_partition(disk, partno, start, length,
- ADDPART_FLAG_NONE);
+ part = add_partition(disk, partno, start, length,
+ ADDPART_FLAG_NONE);
mutex_unlock(&bdev->bd_mutex);
- return err;
+ return IS_ERR(part) ? PTR_ERR(part) : 0;
case BLKPG_DEL_PARTITION:
part = disk_get_part(disk, partno);
if (!part)
@@ -201,97 +200,41 @@ static int put_u64(unsigned long arg, u64 val)
return put_user(val, (u64 __user *)arg);
}
-static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
- unsigned cmd, unsigned long arg)
-{
- struct backing_dev_info *bdi;
- int ret, n;
-
- switch (cmd) {
- case BLKRAGET:
- case BLKFRAGET:
- if (!arg)
- return -EINVAL;
- bdi = blk_get_backing_dev_info(bdev);
- if (bdi == NULL)
- return -ENOTTY;
- return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
- case BLKROGET:
- return put_int(arg, bdev_read_only(bdev) != 0);
- case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
- return put_int(arg, block_size(bdev));
- case BLKSSZGET: /* get block device hardware sector size */
- return put_int(arg, bdev_hardsect_size(bdev));
- case BLKSECTGET:
- return put_ushort(arg, bdev_get_queue(bdev)->max_sectors);
- case BLKRASET:
- case BLKFRASET:
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
- bdi = blk_get_backing_dev_info(bdev);
- if (bdi == NULL)
- return -ENOTTY;
- bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
- return 0;
- case BLKBSZSET:
- /* set the logical block size */
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (!arg)
- return -EINVAL;
- if (get_user(n, (int __user *) arg))
- return -EFAULT;
- if (bd_claim(bdev, file) < 0)
- return -EBUSY;
- ret = set_blocksize(bdev, n);
- bd_release(bdev);
- return ret;
- case BLKPG:
- return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
- case BLKRRPART:
- return blkdev_reread_part(bdev);
- case BLKGETSIZE:
- if ((bdev->bd_inode->i_size >> 9) > ~0UL)
- return -EFBIG;
- return put_ulong(arg, bdev->bd_inode->i_size >> 9);
- case BLKGETSIZE64:
- return put_u64(arg, bdev->bd_inode->i_size);
- case BLKTRACESTART:
- case BLKTRACESTOP:
- case BLKTRACESETUP:
- case BLKTRACETEARDOWN:
- return blk_trace_ioctl(bdev, cmd, (char __user *) arg);
- }
- return -ENOIOCTLCMD;
-}
-
-int blkdev_driver_ioctl(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned cmd, unsigned long arg)
+int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
{
+ struct gendisk *disk = bdev->bd_disk;
int ret;
- if (disk->fops->unlocked_ioctl)
- return disk->fops->unlocked_ioctl(file, cmd, arg);
- if (disk->fops->ioctl) {
+ if (disk->fops->ioctl)
+ return disk->fops->ioctl(bdev, mode, cmd, arg);
+
+ if (disk->fops->locked_ioctl) {
lock_kernel();
- ret = disk->fops->ioctl(inode, file, cmd, arg);
+ ret = disk->fops->locked_ioctl(bdev, mode, cmd, arg);
unlock_kernel();
return ret;
}
return -ENOTTY;
}
-EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
+/*
+ * For the record: _GPL here is only because somebody decided to slap it
+ * on the previous export. Sheer idiocy, since it wasn't copyrightable
+ * at all and could be open-coded without any exports by anybody who cares.
+ */
+EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
/*
* always keep this in sync with compat_blkdev_ioctl() and
* compat_blkdev_locked_ioctl()
*/
-int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
unsigned long arg)
{
- struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
+ struct backing_dev_info *bdi;
+ loff_t size;
int ret, n;
switch(cmd) {
@@ -299,7 +242,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
+ ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
/* -EINVAL to handle old uncorrected drivers */
if (ret != -EINVAL && ret != -ENOTTY)
return ret;
@@ -311,7 +254,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
return 0;
case BLKROSET:
- ret = blkdev_driver_ioctl(inode, file, disk, cmd, arg);
+ ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
/* -EINVAL to handle old uncorrected drivers */
if (ret != -EINVAL && ret != -ENOTTY)
return ret;
@@ -327,7 +270,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
case BLKDISCARD: {
uint64_t range[2];
- if (!(file->f_mode & FMODE_WRITE))
+ if (!(mode & FMODE_WRITE))
return -EBADF;
if (copy_from_user(range, (void __user *)arg, sizeof(range)))
@@ -357,14 +300,75 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
return -EFAULT;
return 0;
}
- }
-
- lock_kernel();
- ret = blkdev_locked_ioctl(file, bdev, cmd, arg);
- unlock_kernel();
- if (ret != -ENOIOCTLCMD)
+ case BLKRAGET:
+ case BLKFRAGET:
+ if (!arg)
+ return -EINVAL;
+ bdi = blk_get_backing_dev_info(bdev);
+ if (bdi == NULL)
+ return -ENOTTY;
+ return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
+ case BLKROGET:
+ return put_int(arg, bdev_read_only(bdev) != 0);
+ case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
+ return put_int(arg, block_size(bdev));
+ case BLKSSZGET: /* get block device hardware sector size */
+ return put_int(arg, bdev_hardsect_size(bdev));
+ case BLKSECTGET:
+ return put_ushort(arg, bdev_get_queue(bdev)->max_sectors);
+ case BLKRASET:
+ case BLKFRASET:
+ if(!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ bdi = blk_get_backing_dev_info(bdev);
+ if (bdi == NULL)
+ return -ENOTTY;
+ lock_kernel();
+ bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+ unlock_kernel();
+ return 0;
+ case BLKBSZSET:
+ /* set the logical block size */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (!arg)
+ return -EINVAL;
+ if (get_user(n, (int __user *) arg))
+ return -EFAULT;
+ if (!(mode & FMODE_EXCL) && bd_claim(bdev, &bdev) < 0)
+ return -EBUSY;
+ ret = set_blocksize(bdev, n);
+ if (!(mode & FMODE_EXCL))
+ bd_release(bdev);
return ret;
-
- return blkdev_driver_ioctl(inode, file, disk, cmd, arg);
+ case BLKPG:
+ lock_kernel();
+ ret = blkpg_ioctl(bdev, (struct blkpg_ioctl_arg __user *) arg);
+ unlock_kernel();
+ break;
+ case BLKRRPART:
+ lock_kernel();
+ ret = blkdev_reread_part(bdev);
+ unlock_kernel();
+ break;
+ case BLKGETSIZE:
+ size = bdev->bd_inode->i_size;
+ if ((size >> 9) > ~0UL)
+ return -EFBIG;
+ return put_ulong(arg, size >> 9);
+ case BLKGETSIZE64:
+ return put_u64(arg, bdev->bd_inode->i_size);
+ case BLKTRACESTART:
+ case BLKTRACESTOP:
+ case BLKTRACESETUP:
+ case BLKTRACETEARDOWN:
+ lock_kernel();
+ ret = blk_trace_ioctl(bdev, cmd, (char __user *) arg);
+ unlock_kernel();
+ break;
+ default:
+ ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+ }
+ return ret;
}
EXPORT_SYMBOL_GPL(blkdev_ioctl);
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index c34272a348f..d0bb92cbefb 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -190,12 +190,11 @@ void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
EXPORT_SYMBOL_GPL(blk_set_cmd_filter_defaults);
static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
- struct sg_io_hdr *hdr, struct file *file)
+ struct sg_io_hdr *hdr, fmode_t mode)
{
if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
return -EFAULT;
- if (blk_verify_command(&q->cmd_filter, rq->cmd,
- file->f_mode & FMODE_WRITE))
+ if (blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE))
return -EPERM;
/*
@@ -209,6 +208,8 @@ static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
rq->timeout = q->sg_timeout;
if (!rq->timeout)
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
+ if (rq->timeout < BLK_MIN_SG_TIMEOUT)
+ rq->timeout = BLK_MIN_SG_TIMEOUT;
return 0;
}
@@ -260,8 +261,8 @@ static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
return r;
}
-static int sg_io(struct file *file, struct request_queue *q,
- struct gendisk *bd_disk, struct sg_io_hdr *hdr)
+static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
+ struct sg_io_hdr *hdr, fmode_t mode)
{
unsigned long start_time;
int writing = 0, ret = 0;
@@ -293,7 +294,7 @@ static int sg_io(struct file *file, struct request_queue *q,
if (!rq)
return -ENOMEM;
- if (blk_fill_sghdr_rq(q, rq, hdr, file)) {
+ if (blk_fill_sghdr_rq(q, rq, hdr, mode)) {
blk_put_request(rq);
return -EFAULT;
}
@@ -380,11 +381,11 @@ out:
* bytes in one int) where the lowest byte is the SCSI status.
*/
#define OMAX_SB_LEN 16 /* For backward compatibility */
-int sg_scsi_ioctl(struct file *file, struct request_queue *q,
- struct gendisk *disk, struct scsi_ioctl_command __user *sic)
+int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode,
+ struct scsi_ioctl_command __user *sic)
{
struct request *rq;
- int err, write_perm = 0;
+ int err;
unsigned int in_len, out_len, bytes, opcode, cmdlen;
char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE];
@@ -426,11 +427,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
goto error;
- /* scsi_ioctl passes NULL */
- if (file && (file->f_mode & FMODE_WRITE))
- write_perm = 1;
-
- err = blk_verify_command(&q->cmd_filter, rq->cmd, write_perm);
+ err = blk_verify_command(&q->cmd_filter, rq->cmd, mode & FMODE_WRITE);
if (err)
goto error;
@@ -522,8 +519,8 @@ static inline int blk_send_start_stop(struct request_queue *q,
return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
}
-int scsi_cmd_ioctl(struct file *file, struct request_queue *q,
- struct gendisk *bd_disk, unsigned int cmd, void __user *arg)
+int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode,
+ unsigned int cmd, void __user *arg)
{
int err;
@@ -564,7 +561,7 @@ int scsi_cmd_ioctl(struct file *file, struct request_queue *q,
err = -EFAULT;
if (copy_from_user(&hdr, arg, sizeof(hdr)))
break;
- err = sg_io(file, q, bd_disk, &hdr);
+ err = sg_io(q, bd_disk, &hdr, mode);
if (err == -EFAULT)
break;
@@ -612,7 +609,7 @@ int scsi_cmd_ioctl(struct file *file, struct request_queue *q,
hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd;
hdr.cmd_len = sizeof(cgc.cmd);
- err = sg_io(file, q, bd_disk, &hdr);
+ err = sg_io(q, bd_disk, &hdr, mode);
if (err == -EFAULT)
break;
@@ -636,7 +633,7 @@ int scsi_cmd_ioctl(struct file *file, struct request_queue *q,
if (!arg)
break;
- err = sg_scsi_ioctl(file, q, bd_disk, arg);
+ err = sg_scsi_ioctl(q, bd_disk, mode, arg);
break;
case CDROMCLOSETRAY:
err = blk_send_start_stop(q, bd_disk, 0x03);