diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/Kconfig | 11 | ||||
-rw-r--r-- | block/Makefile | 1 | ||||
-rw-r--r-- | block/as-iosched.c | 26 | ||||
-rw-r--r-- | block/blktrace.c | 82 | ||||
-rw-r--r-- | block/bsg.c | 160 | ||||
-rw-r--r-- | block/cfq-iosched.c | 106 | ||||
-rw-r--r-- | block/compat_ioctl.c | 814 | ||||
-rw-r--r-- | block/deadline-iosched.c | 18 | ||||
-rw-r--r-- | block/elevator.c | 77 | ||||
-rw-r--r-- | block/genhd.c | 35 | ||||
-rw-r--r-- | block/ioctl.c | 21 | ||||
-rw-r--r-- | block/ll_rw_blk.c | 529 | ||||
-rw-r--r-- | block/noop-iosched.c | 14 | ||||
-rw-r--r-- | block/scsi_ioctl.c | 38 |
14 files changed, 1356 insertions, 576 deletions
diff --git a/block/Kconfig b/block/Kconfig index 0768741d681..9bda7bc8030 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -49,11 +49,9 @@ config LSF If unsure, say Y. -endif # BLOCK - config BLK_DEV_BSG bool "Block layer SG support v4 (EXPERIMENTAL)" - depends on (SCSI=y) && EXPERIMENTAL + depends on EXPERIMENTAL ---help--- Saying Y here will enable generic SG (SCSI generic) v4 support for any block device. @@ -64,4 +62,11 @@ config BLK_DEV_BSG protocols (e.g. Task Management Functions and SMP in Serial Attached SCSI). +endif # BLOCK + +config BLOCK_COMPAT + bool + depends on BLOCK && COMPAT + default y + source block/Kconfig.iosched diff --git a/block/Makefile b/block/Makefile index 959feeb253b..826108190f0 100644 --- a/block/Makefile +++ b/block/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o +obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o diff --git a/block/as-iosched.c b/block/as-iosched.c index 3e316dd7252..dc715a562e1 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c @@ -796,7 +796,7 @@ static void update_write_batch(struct as_data *ad) * as_completed_request is to be called when a request has completed and * returned something to the requesting process, be it an error or data. */ -static void as_completed_request(request_queue_t *q, struct request *rq) +static void as_completed_request(struct request_queue *q, struct request *rq) { struct as_data *ad = q->elevator->elevator_data; @@ -853,7 +853,8 @@ out: * reference unless it replaces the request at somepart of the elevator * (ie. the dispatch queue) */ -static void as_remove_queued_request(request_queue_t *q, struct request *rq) +static void as_remove_queued_request(struct request_queue *q, + struct request *rq) { const int data_dir = rq_is_sync(rq); struct as_data *ad = q->elevator->elevator_data; @@ -978,7 +979,7 @@ static void as_move_to_dispatch(struct as_data *ad, struct request *rq) * read/write expire, batch expire, etc, and moves it to the dispatch * queue. Returns 1 if a request was found, 0 otherwise. */ -static int as_dispatch_request(request_queue_t *q, int force) +static int as_dispatch_request(struct request_queue *q, int force) { struct as_data *ad = q->elevator->elevator_data; const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]); @@ -1139,7 +1140,7 @@ fifo_expired: /* * add rq to rbtree and fifo */ -static void as_add_request(request_queue_t *q, struct request *rq) +static void as_add_request(struct request_queue *q, struct request *rq) { struct as_data *ad = q->elevator->elevator_data; int data_dir; @@ -1167,7 +1168,7 @@ static void as_add_request(request_queue_t *q, struct request *rq) RQ_SET_STATE(rq, AS_RQ_QUEUED); } -static void as_activate_request(request_queue_t *q, struct request *rq) +static void as_activate_request(struct request_queue *q, struct request *rq) { WARN_ON(RQ_STATE(rq) != AS_RQ_DISPATCHED); RQ_SET_STATE(rq, AS_RQ_REMOVED); @@ -1175,7 +1176,7 @@ static void as_activate_request(request_queue_t *q, struct request *rq) atomic_dec(&RQ_IOC(rq)->aic->nr_dispatched); } -static void as_deactivate_request(request_queue_t *q, struct request *rq) +static void as_deactivate_request(struct request_queue *q, struct request *rq) { WARN_ON(RQ_STATE(rq) != AS_RQ_REMOVED); RQ_SET_STATE(rq, AS_RQ_DISPATCHED); @@ -1189,7 +1190,7 @@ static void as_deactivate_request(request_queue_t *q, struct request *rq) * is not empty - it is used in the block layer to check for plugging and * merging opportunities */ -static int as_queue_empty(request_queue_t *q) +static int as_queue_empty(struct request_queue *q) { struct as_data *ad = q->elevator->elevator_data; @@ -1198,7 +1199,7 @@ static int as_queue_empty(request_queue_t *q) } static int -as_merge(request_queue_t *q, struct request **req, struct bio *bio) +as_merge(struct request_queue *q, struct request **req, struct bio *bio) { struct as_data *ad = q->elevator->elevator_data; sector_t rb_key = bio->bi_sector + bio_sectors(bio); @@ -1216,7 +1217,8 @@ as_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; } -static void as_merged_request(request_queue_t *q, struct request *req, int type) +static void as_merged_request(struct request_queue *q, struct request *req, + int type) { struct as_data *ad = q->elevator->elevator_data; @@ -1234,7 +1236,7 @@ static void as_merged_request(request_queue_t *q, struct request *req, int type) } } -static void as_merged_requests(request_queue_t *q, struct request *req, +static void as_merged_requests(struct request_queue *q, struct request *req, struct request *next) { /* @@ -1285,7 +1287,7 @@ static void as_work_handler(struct work_struct *work) spin_unlock_irqrestore(q->queue_lock, flags); } -static int as_may_queue(request_queue_t *q, int rw) +static int as_may_queue(struct request_queue *q, int rw) { int ret = ELV_MQUEUE_MAY; struct as_data *ad = q->elevator->elevator_data; @@ -1318,7 +1320,7 @@ static void as_exit_queue(elevator_t *e) /* * initialize elevator private data (as_data). */ -static void *as_init_queue(request_queue_t *q) +static void *as_init_queue(struct request_queue *q) { struct as_data *ad; diff --git a/block/blktrace.c b/block/blktrace.c index 3f0e7c37c05..775471ef84a 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -41,7 +41,7 @@ static void trace_note(struct blk_trace *bt, pid_t pid, int action, const int cpu = smp_processor_id(); t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; - t->time = sched_clock() - per_cpu(blk_trace_cpu_offset, cpu); + t->time = cpu_clock(cpu) - per_cpu(blk_trace_cpu_offset, cpu); t->device = bt->dev; t->action = action; t->pid = pid; @@ -159,7 +159,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, t->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION; t->sequence = ++(*sequence); - t->time = sched_clock() - per_cpu(blk_trace_cpu_offset, cpu); + t->time = cpu_clock(cpu) - per_cpu(blk_trace_cpu_offset, cpu); t->sector = sector; t->bytes = bytes; t->action = what; @@ -231,7 +231,7 @@ static void blk_trace_cleanup(struct blk_trace *bt) kfree(bt); } -static int blk_trace_remove(request_queue_t *q) +static int blk_trace_remove(struct request_queue *q) { struct blk_trace *bt; @@ -312,33 +312,26 @@ static struct rchan_callbacks blk_relay_callbacks = { /* * Setup everything required to start tracing */ -static int blk_trace_setup(request_queue_t *q, struct block_device *bdev, - char __user *arg) +int do_blk_trace_setup(struct request_queue *q, struct block_device *bdev, + struct blk_user_trace_setup *buts) { - struct blk_user_trace_setup buts; struct blk_trace *old_bt, *bt = NULL; struct dentry *dir = NULL; char b[BDEVNAME_SIZE]; int ret, i; - if (copy_from_user(&buts, arg, sizeof(buts))) - return -EFAULT; - - if (!buts.buf_size || !buts.buf_nr) + if (!buts->buf_size || !buts->buf_nr) return -EINVAL; - strcpy(buts.name, bdevname(bdev, b)); + strcpy(buts->name, bdevname(bdev, b)); /* * some device names have larger paths - convert the slashes * to underscores for this to work as expected */ - for (i = 0; i < strlen(buts.name); i++) - if (buts.name[i] == '/') - buts.name[i] = '_'; - - if (copy_to_user(arg, &buts, sizeof(buts))) - return -EFAULT; + for (i = 0; i < strlen(buts->name); i++) + if (buts->name[i] == '/') + buts->name[i] = '_'; ret = -ENOMEM; bt = kzalloc(sizeof(*bt), GFP_KERNEL); @@ -350,7 +343,7 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev, goto err; ret = -ENOENT; - dir = blk_create_tree(buts.name); + dir = blk_create_tree(buts->name); if (!dir) goto err; @@ -363,20 +356,21 @@ static int blk_trace_setup(request_queue_t *q, struct block_device *bdev, if (!bt->dropped_file) goto err; - bt->rchan = relay_open("trace", dir, buts.buf_size, buts.buf_nr, &blk_relay_callbacks, bt); + bt->rchan = relay_open("trace", dir, buts->buf_size, + buts->buf_nr, &blk_relay_callbacks, bt); if (!bt->rchan) goto err; - bt->act_mask = buts.act_mask; + bt->act_mask = buts->act_mask; if (!bt->act_mask) bt->act_mask = (u16) -1; - bt->start_lba = buts.start_lba; - bt->end_lba = buts.end_lba; + bt->start_lba = buts->start_lba; + bt->end_lba = buts->end_lba; if (!bt->end_lba) bt->end_lba = -1ULL; - bt->pid = buts.pid; + bt->pid = buts->pid; bt->trace_state = Blktrace_setup; ret = -EBUSY; @@ -401,7 +395,27 @@ err: return ret; } -static int blk_trace_startstop(request_queue_t *q, int start) +static int blk_trace_setup(struct request_queue *q, struct block_device *bdev, + char __user *arg) +{ + struct blk_user_trace_setup buts; + int ret; + + ret = copy_from_user(&buts, arg, sizeof(buts)); + if (ret) + return -EFAULT; + + ret = do_blk_trace_setup(q, bdev, &buts); + if (ret) + return ret; + + if (copy_to_user(arg, &buts, sizeof(buts))) + return -EFAULT; + + return 0; +} + +static int blk_trace_startstop(struct request_queue *q, int start) { struct blk_trace *bt; int ret; @@ -444,7 +458,7 @@ static int blk_trace_startstop(request_queue_t *q, int start) **/ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg) { - request_queue_t *q; + struct request_queue *q; int ret, start = 0; q = bdev_get_queue(bdev); @@ -479,7 +493,7 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg) * @q: the request queue associated with the device * **/ -void blk_trace_shutdown(request_queue_t *q) +void blk_trace_shutdown(struct request_queue *q) { if (q->blk_trace) { blk_trace_startstop(q, 0); @@ -488,17 +502,17 @@ void blk_trace_shutdown(request_queue_t *q) } /* - * Average offset over two calls to sched_clock() with a gettimeofday() + * Average offset over two calls to cpu_clock() with a gettimeofday() * in the middle */ -static void blk_check_time(unsigned long long *t) +static void blk_check_time(unsigned long long *t, int this_cpu) { unsigned long long a, b; struct timeval tv; - a = sched_clock(); + a = cpu_clock(this_cpu); do_gettimeofday(&tv); - b = sched_clock(); + b = cpu_clock(this_cpu); *t = tv.tv_sec * 1000000000 + tv.tv_usec * 1000; *t -= (a + b) / 2; @@ -510,16 +524,16 @@ static void blk_check_time(unsigned long long *t) static void blk_trace_check_cpu_time(void *data) { unsigned long long *t; - int cpu = get_cpu(); + int this_cpu = get_cpu(); - t = &per_cpu(blk_trace_cpu_offset, cpu); + t = &per_cpu(blk_trace_cpu_offset, this_cpu); /* * Just call it twice, hopefully the second call will be cache hot * and a little more precise */ - blk_check_time(t); - blk_check_time(t); + blk_check_time(t, this_cpu); + blk_check_time(t, this_cpu); put_cpu(); } diff --git a/block/bsg.c b/block/bsg.c index baa04e7adf1..b8ddfc66f21 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -1,5 +1,5 @@ /* - * bsg.c - block layer implementation of the sg v3 interface + * bsg.c - block layer implementation of the sg v4 interface * * Copyright (C) 2004 Jens Axboe <axboe@suse.de> SUSE Labs * Copyright (C) 2004 Peter M. Jones <pjones@redhat.com> @@ -9,13 +9,6 @@ * archive for more details. * */ -/* - * TODO - * - Should this get merged, block/scsi_ioctl.c will be migrated into - * this file. To keep maintenance down, it's easier to have them - * seperated right now. - * - */ #include <linux/module.h> #include <linux/init.h> #include <linux/file.h> @@ -24,6 +17,7 @@ #include <linux/cdev.h> #include <linux/percpu.h> #include <linux/uio.h> +#include <linux/idr.h> #include <linux/bsg.h> #include <scsi/scsi.h> @@ -37,7 +31,7 @@ #define BSG_VERSION "0.4" struct bsg_device { - request_queue_t *queue; + struct request_queue *queue; spinlock_t lock; struct list_head busy_list; struct list_head done_list; @@ -70,13 +64,12 @@ enum { #endif static DEFINE_MUTEX(bsg_mutex); -static int bsg_device_nr, bsg_minor_idx; +static DEFINE_IDR(bsg_minor_idr); #define BSG_LIST_ARRAY_SIZE 8 static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE]; static struct class *bsg_class; -static LIST_HEAD(bsg_class_list); static int bsg_major; static struct kmem_cache *bsg_cmd_cachep; @@ -92,7 +85,6 @@ struct bsg_command { struct bio *bidi_bio; int err; struct sg_io_v4 hdr; - struct sg_io_v4 __user *uhdr; char sense[SCSI_SENSE_BUFFERSIZE]; }; @@ -180,7 +172,7 @@ unlock: return ret; } -static int blk_fill_sgv4_hdr_rq(request_queue_t *q, struct request *rq, +static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, struct sg_io_v4 *hdr, int has_write_perm) { memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ @@ -214,7 +206,7 @@ static int blk_fill_sgv4_hdr_rq(request_queue_t *q, struct request *rq, * Check if sg_io_v4 from user is allowed and valid */ static int -bsg_validate_sgv4_hdr(request_queue_t *q, struct sg_io_v4 *hdr, int *rw) +bsg_validate_sgv4_hdr(struct request_queue *q, struct sg_io_v4 *hdr, int *rw) { int ret = 0; @@ -250,7 +242,7 @@ bsg_validate_sgv4_hdr(request_queue_t *q, struct sg_io_v4 *hdr, int *rw) static struct request * bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr) { - request_queue_t *q = bd->queue; + struct request_queue *q = bd->queue; struct request *rq, *next_rq = NULL; int ret, rw; unsigned int dxfer_len; @@ -345,7 +337,7 @@ static void bsg_rq_end_io(struct request *rq, int uptodate) * do final setup of a 'bc' and submit the matching 'rq' to the block * layer for io */ -static void bsg_add_command(struct bsg_device *bd, request_queue_t *q, +static void bsg_add_command(struct bsg_device *bd, struct request_queue *q, struct bsg_command *bc, struct request *rq) { rq->sense = bc->sense; @@ -429,7 +421,6 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, hdr->info = 0; if (hdr->device_status || hdr->transport_status || hdr->driver_status) hdr->info |= SG_INFO_CHECK; - hdr->din_resid = rq->data_len; hdr->response_len = 0; if (rq->sense_len && hdr->response) { @@ -445,9 +436,14 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr, } if (rq->next_rq) { + hdr->dout_resid = rq->data_len; + hdr->din_resid = rq->next_rq->data_len; blk_rq_unmap_user(bidi_bio); blk_put_request(rq->next_rq); - } + } else if (rq_data_dir(rq) == READ) + hdr->din_resid = rq->data_len; + else + hdr->dout_resid = rq->data_len; blk_rq_unmap_user(bio); blk_put_request(rq); @@ -611,7 +607,7 @@ static int __bsg_write(struct bsg_device *bd, const char __user *buf, bc = NULL; ret = 0; while (nr_commands) { - request_queue_t *q = bd->queue; + struct request_queue *q = bd->queue; bc = bsg_alloc_command(bd); if (IS_ERR(bc)) { @@ -620,7 +616,6 @@ static int __bsg_write(struct bsg_device *bd, const char __user *buf, break; } - bc->uhdr = (struct sg_io_v4 __user *) buf; if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) { ret = -EFAULT; break; @@ -781,23 +776,18 @@ static struct bsg_device *__bsg_get_device(int minor) static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file) { - struct bsg_device *bd = __bsg_get_device(iminor(inode)); - struct bsg_class_device *bcd, *__bcd; + struct bsg_device *bd; + struct bsg_class_device *bcd; + bd = __bsg_get_device(iminor(inode)); if (bd) return bd; /* * find the class device */ - bcd = NULL; mutex_lock(&bsg_mutex); - list_for_each_entry(__bcd, &bsg_class_list, list) { - if (__bcd->minor == iminor(inode)) { - bcd = __bcd; - break; - } - } + bcd = idr_find(&bsg_minor_idr, iminor(inode)); mutex_unlock(&bsg_mutex); if (!bcd) @@ -932,24 +922,33 @@ void bsg_unregister_queue(struct request_queue *q) { struct bsg_class_device *bcd = &q->bsg_dev; - WARN_ON(!bcd->class_dev); + if (!bcd->class_dev) + return; mutex_lock(&bsg_mutex); + idr_remove(&bsg_minor_idr, bcd->minor); sysfs_remove_link(&q->kobj, "bsg"); - class_device_destroy(bsg_class, MKDEV(bsg_major, bcd->minor)); + class_device_unregister(bcd->class_dev); + put_device(bcd->dev); bcd->class_dev = NULL; - list_del_init(&bcd->list); - bsg_device_nr--; + bcd->dev = NULL; mutex_unlock(&bsg_mutex); } EXPORT_SYMBOL_GPL(bsg_unregister_queue); -int bsg_register_queue(struct request_queue *q, const char *name) +int bsg_register_queue(struct request_queue *q, struct device *gdev, + const char *name) { - struct bsg_class_device *bcd, *__bcd; + struct bsg_class_device *bcd; dev_t dev; - int ret = -EMFILE; + int ret, minor; struct class_device *class_dev = NULL; + const char *devname; + + if (name) + devname = name; + else + devname = gdev->bus_id; /* * we need a proper transport to send commands, not a stacked device @@ -959,83 +958,59 @@ int bsg_register_queue(struct request_queue *q, const char *name) bcd = &q->bsg_dev; memset(bcd, 0, sizeof(*bcd)); - INIT_LIST_HEAD(&bcd->list); mutex_lock(&bsg_mutex); - if (bsg_device_nr == BSG_MAX_DEVS) { - printk(KERN_ERR "bsg: too many bsg devices\n"); - goto err; - } -retry: - list_for_each_entry(__bcd, &bsg_class_list, list) { - if (__bcd->minor == bsg_minor_idx) { - bsg_minor_idx++; - if (bsg_minor_idx == BSG_MAX_DEVS) - bsg_minor_idx = 0; - goto retry; - } + ret = idr_pre_get(&bsg_minor_idr, GFP_KERNEL); + if (!ret) { + ret = -ENOMEM; + goto unlock; } - bcd->minor = bsg_minor_idx++; - if (bsg_minor_idx == BSG_MAX_DEVS) - bsg_minor_idx = 0; + ret = idr_get_new(&bsg_minor_idr, bcd, &minor); + if (ret < 0) + goto unlock; + + if (minor >= BSG_MAX_DEVS) { + printk(KERN_ERR "bsg: too many bsg devices\n"); + ret = -EINVAL; + goto remove_idr; + } + bcd->minor = minor; bcd->queue = q; + bcd->dev = get_device(gdev); dev = MKDEV(bsg_major, bcd->minor); - class_dev = class_device_create(bsg_class, NULL, dev, bcd->dev, "%s", name); + class_dev = class_device_create(bsg_class, NULL, dev, gdev, "%s", + devname); if (IS_ERR(class_dev)) { ret = PTR_ERR(class_dev); - goto err; + goto put_dev; } bcd->class_dev = class_dev; if (q->kobj.sd) { ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg"); if (ret) - goto err; + goto unregister_class_dev; } - list_add_tail(&bcd->list, &bsg_class_list); - bsg_device_nr++; - mutex_unlock(&bsg_mutex); return 0; -err: - if (class_dev) - class_device_destroy(bsg_class, MKDEV(bsg_major, bcd->minor)); + +unregister_class_dev: + class_device_unregister(class_dev); +put_dev: + put_device(gdev); +remove_idr: + idr_remove(&bsg_minor_idr, minor); +unlock: mutex_unlock(&bsg_mutex); return ret; } EXPORT_SYMBOL_GPL(bsg_register_queue); -static int bsg_add(struct class_device *cl_dev, struct class_interface *cl_intf) -{ - int ret; - struct scsi_device *sdp = to_scsi_device(cl_dev->dev); - struct request_queue *rq = sdp->request_queue; - - if (rq->kobj.parent) - ret = bsg_register_queue(rq, kobject_name(rq->kobj.parent)); - else - ret = bsg_register_queue(rq, kobject_name(&sdp->sdev_gendev.kobj)); - return ret; -} - -static void bsg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) -{ - bsg_unregister_queue(to_scsi_device(cl_dev->dev)->request_queue); -} - -static struct class_interface bsg_intf = { - .add = bsg_add, - .remove = bsg_remove, -}; - -static struct cdev bsg_cdev = { - .kobj = {.name = "bsg", }, - .owner = THIS_MODULE, -}; +static struct cdev bsg_cdev; static int __init bsg_init(void) { @@ -1043,7 +1018,7 @@ static int __init bsg_init(void) dev_t devid; bsg_cmd_cachep = kmem_cache_create("bsg_cmd", - sizeof(struct bsg_command), 0, 0, NULL, NULL); + sizeof(struct bsg_command), 0, 0, NULL); if (!bsg_cmd_cachep) { printk(KERN_ERR "bsg: failed creating slab cache\n"); return -ENOMEM; @@ -1069,16 +1044,9 @@ static int __init bsg_init(void) if (ret) goto unregister_chrdev; - ret = scsi_register_interface(&bsg_intf); - if (ret) - goto remove_cdev; - printk(KERN_INFO BSG_DESCRIPTION " version " BSG_VERSION " loaded (major %d)\n", bsg_major); return 0; -remove_cdev: - printk(KERN_ERR "bsg: failed register scsi interface %d\n", ret); - cdev_del(&bsg_cdev); unregister_chrdev: unregister_chrdev_region(MKDEV(bsg_major, 0), BSG_MAX_DEVS); destroy_bsg_class: diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 9755a3cfad2..54dc0543900 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -71,7 +71,7 @@ struct cfq_rb_root { * Per block device queue structure */ struct cfq_data { - request_queue_t *queue; + struct request_queue *queue; /* * rr list of queues with requests and the count of them @@ -92,7 +92,11 @@ struct cfq_data { struct cfq_queue *active_queue; struct cfq_io_context *active_cic; - struct cfq_queue *async_cfqq[IOPRIO_BE_NR]; + /* + * async queue for each priority case + */ + struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; + struct cfq_queue *async_idle_cfqq; struct timer_list idle_class_timer; @@ -111,9 +115,6 @@ struct cfq_data { unsigned int cfq_slice_idle; struct list_head cic_list; - - sector_t new_seek_mean; - u64 new_seek_total; }; /* @@ -153,8 +154,6 @@ struct cfq_queue { /* various state flags, see below */ unsigned int flags; - - sector_t last_request_pos; }; enum cfqq_state_flags { @@ -198,7 +197,7 @@ CFQ_CFQQ_FNS(slice_new); CFQ_CFQQ_FNS(sync); #undef CFQ_CFQQ_FNS -static void cfq_dispatch_insert(request_queue_t *, struct request *); +static void cfq_dispatch_insert(struct request_queue *, struct request *); static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, struct task_struct *, gfp_t); static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *, @@ -238,7 +237,7 @@ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) kblockd_schedule_work(&cfqd->unplug_work); } -static int cfq_queue_empty(request_queue_t *q) +static int cfq_queue_empty(struct request_queue *q) { struct cfq_data *cfqd = q->elevator->elevator_data; @@ -624,7 +623,7 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio) return NULL; } -static void cfq_activate_request(request_queue_t *q, struct request *rq) +static void cfq_activate_request(struct request_queue *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; @@ -642,7 +641,7 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq) cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors; } -static void cfq_deactivate_request(request_queue_t *q, struct request *rq) +static void cfq_deactivate_request(struct request_queue *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; @@ -666,7 +665,8 @@ static void cfq_remove_request(struct request *rq) } } -static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) +static int cfq_merge(struct request_queue *q, struct request **req, + struct bio *bio) { struct cfq_data *cfqd = q->elevator->elevator_data; struct request *__rq; @@ -680,7 +680,7 @@ static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; } -static void cfq_merged_request(request_queue_t *q, struct request *req, +static void cfq_merged_request(struct request_queue *q, struct request *req, int type) { if (type == ELEVATOR_FRONT_MERGE) { @@ -691,7 +691,7 @@ static void cfq_merged_request(request_queue_t *q, struct request *req, } static void -cfq_merged_requests(request_queue_t *q, struct request *rq, +cfq_merged_requests(struct request_queue *q, struct request *rq, struct request *next) { /* @@ -704,7 +704,7 @@ cfq_merged_requests(request_queue_t *q, struct request *rq, cfq_remove_request(next); } -static int cfq_allow_merge(request_queue_t *q, struct request *rq, +static int cfq_allow_merge(struct request_queue *q, struct request *rq, struct bio *bio) { struct cfq_data *cfqd = q->elevator->elevator_data; @@ -914,7 +914,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) /* * Move request from internal lists to the request queue dispatch list. */ -static void cfq_dispatch_insert(request_queue_t *q, struct request *rq) +static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); @@ -1094,7 +1094,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) return dispatched; } -static int cfq_dispatch_requests(request_queue_t *q, int force) +static int cfq_dispatch_requests(struct request_queue *q, int force) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq; @@ -1215,7 +1215,7 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic) struct cfq_data *cfqd = cic->key; if (cfqd) { - request_queue_t *q = cfqd->queue; + struct request_queue *q = cfqd->queue; spin_lock_irq(q->queue_lock); __cfq_exit_single_io_context(cfqd, cic); @@ -1414,24 +1414,44 @@ out: return cfqq; } +static struct cfq_queue ** +cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio) +{ + switch(ioprio_class) { + case IOPRIO_CLASS_RT: + return &cfqd->async_cfqq[0][ioprio]; + case IOPRIO_CLASS_BE: + return &cfqd->async_cfqq[1][ioprio]; + case IOPRIO_CLASS_IDLE: + return &cfqd->async_idle_cfqq; + default: + BUG(); + } +} + static struct cfq_queue * cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk, gfp_t gfp_mask) { const int ioprio = task_ioprio(tsk); + const int ioprio_class = task_ioprio_class(tsk); + struct cfq_queue **async_cfqq = NULL; struct cfq_queue *cfqq = NULL; - if (!is_sync) - cfqq = cfqd->async_cfqq[ioprio]; + if (!is_sync) { + async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio); + cfqq = *async_cfqq; + } + if (!cfqq) cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask); /* * pin the queue now that it's allocated, scheduler exit will prune it */ - if (!is_sync && !cfqd->async_cfqq[ioprio]) { + if (!is_sync && !(*async_cfqq)) { atomic_inc(&cfqq->ref); - cfqd->async_cfqq[ioprio] = cfqq; + *async_cfqq = cfqq; } atomic_inc(&cfqq->ref); @@ -1597,11 +1617,6 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, else sdist = cic->last_request_pos - rq->sector; - if (!cic->seek_samples) { - cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8; - cfqd->new_seek_mean = cfqd->new_seek_total / 256; - } - /* * Don't allow the seek distance to get too large from the * odd fragment, pagein, etc @@ -1737,7 +1752,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, cfq_update_idle_window(cfqd, cfqq, cic); cic->last_request_pos = rq->sector + rq->nr_sectors; - cfqq->last_request_pos = cic->last_request_pos; if (cfqq == cfqd->active_queue) { /* @@ -1762,7 +1776,7 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, } } -static void cfq_insert_request(request_queue_t *q, struct request *rq) +static void cfq_insert_request(struct request_queue *q, struct request *rq) { struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); @@ -1776,7 +1790,7 @@ static void cfq_insert_request(request_queue_t *q, struct request *rq) cfq_rq_enqueued(cfqd, cfqq, rq); } -static void cfq_completed_request(request_queue_t *q, struct request *rq) +static void cfq_completed_request(struct request_queue *q, struct request *rq) { struct cfq_queue *cfqq = RQ_CFQQ(rq); struct cfq_data *cfqd = cfqq->cfqd; @@ -1855,7 +1869,7 @@ static inline int __cfq_may_queue(struct cfq_queue *cfqq) return ELV_MQUEUE_MAY; } -static int cfq_may_queue(request_queue_t *q, int rw) +static int cfq_may_queue(struct request_queue *q, int rw) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; @@ -1909,7 +1923,7 @@ static void cfq_put_request(struct request *rq) * Allocate cfq data structures associated with this request. */ static int -cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) +cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) { struct cfq_data *cfqd = q->elevator->elevator_data; struct task_struct *tsk = current; @@ -1961,7 +1975,7 @@ static void cfq_kick_queue(struct work_struct *work) { struct cfq_data *cfqd = container_of(work, struct cfq_data, unplug_work); - request_queue_t *q = cfqd->queue; + struct request_queue *q = cfqd->queue; unsigned long flags; spin_lock_irqsave(q->queue_lock, flags); @@ -2042,11 +2056,24 @@ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) blk_sync_queue(cfqd->queue); } +static void cfq_put_async_queues(struct cfq_data *cfqd) +{ + int i; + + for (i = 0; i < IOPRIO_BE_NR; i++) { + if (cfqd->async_cfqq[0][i]) + cfq_put_queue(cfqd->async_cfqq[0][i]); + if (cfqd->async_cfqq[1][i]) + cfq_put_queue(cfqd->async_cfqq[1][i]); + if (cfqd->async_idle_cfqq) + cfq_put_queue(cfqd->async_idle_cfqq); + } +} + static void cfq_exit_queue(elevator_t *e) { struct cfq_data *cfqd = e->elevator_data; - request_queue_t *q = cfqd->queue; - int i; + struct request_queue *q = cfqd->queue; cfq_shutdown_timer_wq(cfqd); @@ -2063,12 +2090,7 @@ static void cfq_exit_queue(elevator_t *e) __cfq_exit_single_io_context(cfqd, cic); } - /* - * Put the async queues - */ - for (i = 0; i < IOPRIO_BE_NR; i++) - if (cfqd->async_cfqq[i]) - cfq_put_queue(cfqd->async_cfqq[i]); + cfq_put_async_queues(cfqd); spin_unlock_irq(q->queue_lock); @@ -2077,7 +2099,7 @@ static void cfq_exit_queue(elevator_t *e) kfree(cfqd); } -static void *cfq_init_queue(request_queue_t *q) +static void *cfq_init_queue(struct request_queue *q) { struct cfq_data *cfqd; diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c new file mode 100644 index 00000000000..f84093b97f7 --- /dev/null +++ b/block/compat_ioctl.c @@ -0,0 +1,814 @@ +#include <linux/blkdev.h> +#include <linux/blkpg.h> +#include <linux/blktrace_api.h> +#include <linux/cdrom.h> +#include <linux/compat.h> +#include <linux/elevator.h> +#include <linux/fd.h> +#include <linux/hdreg.h> +#include <linux/syscalls.h> +#include <linux/smp_lock.h> +#include <linux/types.h> +#include <linux/uaccess.h> + +static int compat_put_ushort(unsigned long arg, unsigned short val) +{ + return put_user(val, (unsigned short __user *)compat_ptr(arg)); +} + +static int compat_put_int(unsigned long arg, int val) +{ + return put_user(val, (compat_int_t __user *)compat_ptr(arg)); +} + +static int compat_put_long(unsigned long arg, long val) +{ + return put_user(val, (compat_long_t __user *)compat_ptr(arg)); +} + +static int compat_put_ulong(unsigned long arg, compat_ulong_t val) +{ + return put_user(val, (compat_ulong_t __user *)compat_ptr(arg)); +} + +static int compat_put_u64(unsigned long arg, u64 val) +{ + return put_user(val, (compat_u64 __user *)compat_ptr(arg)); +} + +struct compat_hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + u32 start; +}; + +static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev, + struct compat_hd_geometry __user *ugeo) +{ + struct hd_geometry geo; + int ret; + + if (!ugeo) + return -EINVAL; + if (!disk->fops->getgeo) + return -ENOTTY; + + /* + * We need to set the startsect first, the driver may + * want to override it. + */ + geo.start = get_start_sect(bdev); + ret = disk->fops->getgeo(bdev, &geo); + if (ret) + return ret; + + ret = copy_to_user(ugeo, &geo, 4); + ret |= __put_user(geo.start, &ugeo->start); + if (ret) + ret = -EFAULT; + + return ret; +} + +static int compat_hdio_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + unsigned long kval; + unsigned int __user *uvp; + int error; + + set_fs(KERNEL_DS); + error = blkdev_driver_ioctl(inode, file, disk, + cmd, (unsigned long)(&kval)); + set_fs(old_fs); + + if (error == 0) { + uvp = compat_ptr(arg); + if (put_user(kval, uvp)) + error = -EFAULT; + } + return error; +} + +struct compat_cdrom_read_audio { + union cdrom_addr addr; + u8 addr_format; + compat_int_t nframes; + compat_caddr_t buf; +}; + +struct compat_cdrom_generic_command { + unsigned char cmd[CDROM_PACKET_SIZE]; + compat_caddr_t buffer; + compat_uint_t buflen; + compat_int_t stat; + compat_caddr_t sense; + unsigned char data_direction; + compat_int_t quiet; + compat_int_t timeout; + 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) +{ + struct cdrom_read_audio __user *cdread_audio; + struct compat_cdrom_read_audio __user *cdread_audio32; + __u32 data; + void __user *datap; + + cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio)); + cdread_audio32 = compat_ptr(arg); + + if (copy_in_user(&cdread_audio->addr, + &cdread_audio32->addr, + (sizeof(*cdread_audio32) - + sizeof(compat_caddr_t)))) + return -EFAULT; + + if (get_user(data, &cdread_audio32->buf)) + return -EFAULT; + datap = compat_ptr(data); + if (put_user(datap, &cdread_audio->buf)) + return -EFAULT; + + return blkdev_driver_ioctl(inode, file, disk, 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) +{ + struct cdrom_generic_command __user *cgc; + struct compat_cdrom_generic_command __user *cgc32; + u32 data; + unsigned char dir; + int itmp; + + cgc = compat_alloc_user_space(sizeof(*cgc)); + cgc32 = compat_ptr(arg); + + if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) || + get_user(data, &cgc32->buffer) || + put_user(compat_ptr(data), &cgc->buffer) || + copy_in_user(&cgc->buflen, &cgc32->buflen, + (sizeof(unsigned int) + sizeof(int))) || + get_user(data, &cgc32->sense) || + put_user(compat_ptr(data), &cgc->sense) || + get_user(dir, &cgc32->data_direction) || + put_user(dir, &cgc->data_direction) || + get_user(itmp, &cgc32->quiet) || + put_user(itmp, &cgc->quiet) || + get_user(itmp, &cgc32->timeout) || + put_user(itmp, &cgc->timeout) || + get_user(data, &cgc32->reserved[0]) || + put_user(compat_ptr(data), &cgc->reserved[0])) + return -EFAULT; + + return blkdev_driver_ioctl(inode, file, disk, cmd, (unsigned long)cgc); +} + +struct compat_blkpg_ioctl_arg { + compat_int_t op; + compat_int_t flags; + compat_int_t datalen; + compat_caddr_t data; +}; + +static int compat_blkpg_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, struct compat_blkpg_ioctl_arg __user *ua32) +{ + struct blkpg_ioctl_arg __user *a = compat_alloc_user_space(sizeof(*a)); + compat_caddr_t udata; + compat_int_t n; + int err; + + err = get_user(n, &ua32->op); + err |= put_user(n, &a->op); + err |= get_user(n, &ua32->flags); + err |= put_user(n, &a->flags); + err |= get_user(n, &ua32->datalen); + err |= put_user(n, &a->datalen); + err |= get_user(udata, &ua32->data); + err |= put_user(compat_ptr(udata), &a->data); + if (err) + return err; + + return blkdev_ioctl(inode, file, cmd, (unsigned long)a); +} + +#define BLKBSZGET_32 _IOR(0x12, 112, int) +#define BLKBSZSET_32 _IOW(0x12, 113, int) +#define BLKGETSIZE64_32 _IOR(0x12, 114, int) + +struct compat_floppy_struct { + compat_uint_t size; + compat_uint_t sect; + compat_uint_t head; + compat_uint_t track; + compat_uint_t stretch; + unsigned char gap; + unsigned char rate; + unsigned char spec1; + unsigned char fmt_gap; + const compat_caddr_t name; +}; + +struct compat_floppy_drive_params { + char cmos; + compat_ulong_t max_dtr; + compat_ulong_t hlt; + compat_ulong_t hut; + compat_ulong_t srt; + compat_ulong_t spinup; + compat_ulong_t spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + compat_ulong_t timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + compat_int_t checkfreq; + compat_int_t native_format; +}; + +struct compat_floppy_drive_struct { + signed char flags; + compat_ulong_t spinup_date; + compat_ulong_t select_date; + compat_ulong_t first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + compat_int_t generation; + compat_int_t keep_data; + compat_int_t fd_ref; + compat_int_t fd_device; + compat_int_t last_checked; + compat_caddr_t dmabuf; + compat_int_t bufblocks; +}; + +struct compat_floppy_fdc_state { + compat_int_t spec1; + compat_int_t spec2; + compat_int_t dtr; + unsigned char version; + unsigned char dor; + compat_ulong_t address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct compat_floppy_write_errors { + unsigned int write_errors; + compat_ulong_t first_error_sector; + compat_int_t first_error_generation; + compat_ulong_t last_error_sector; + compat_int_t last_error_generation; + compat_uint_t badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct) +#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct) +#define FDGETPRM32 _IOR(2, 0x04, struct compat_floppy_struct) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state) +#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} fd_ioctl_trans_table[] = { + { FDSETPRM32, FDSETPRM }, + { FDDEFPRM32, FDDEFPRM }, + { FDGETPRM32, FDGETPRM }, + { FDSETDRVPRM32, FDSETDRVPRM }, + { FDGETDRVPRM32, FDGETDRVPRM }, + { FDGETDRVSTAT32, FDGETDRVSTAT }, + { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, + { FDGETFDCSTAT32, FDGETFDCSTAT }, + { FDWERRORGET32, FDWERRORGET } +}; + +#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) +{ + mm_segment_t old_fs = get_fs(); + void *karg = NULL; + unsigned int kcmd = 0; + int i, err; + + for (i = 0; i < NR_FD_IOCTL_TRANS; i++) + if (cmd == fd_ioctl_trans_table[i].cmd32) { + kcmd = fd_ioctl_trans_table[i].cmd; + break; + } + if (!kcmd) + return -EINVAL; + + switch (cmd) { + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + { + compat_uptr_t name; + struct compat_floppy_struct __user *uf; + struct floppy_struct *f; + + uf = compat_ptr(arg); + f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETPRM32) + break; + err = __get_user(f->size, &uf->size); + err |= __get_user(f->sect, &uf->sect); + err |= __get_user(f->head, &uf->head); + err |= __get_user(f->track, &uf->track); + err |= __get_user(f->stretch, &uf->stretch); + err |= __get_user(f->gap, &uf->gap); + err |= __get_user(f->rate, &uf->rate); + err |= __get_user(f->spec1, &uf->spec1); + err |= __get_user(f->fmt_gap, &uf->fmt_gap); + err |= __get_user(name, &uf->name); + f->name = compat_ptr(name); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDSETDRVPRM32: + case FDGETDRVPRM32: + { + struct compat_floppy_drive_params __user *uf; + struct floppy_drive_params *f; + + uf = compat_ptr(arg); + f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETDRVPRM32) + break; + err = __get_user(f->cmos, &uf->cmos); + err |= __get_user(f->max_dtr, &uf->max_dtr); + err |= __get_user(f->hlt, &uf->hlt); + err |= __get_user(f->hut, &uf->hut); + err |= __get_user(f->srt, &uf->srt); + err |= __get_user(f->spinup, &uf->spinup); + err |= __get_user(f->spindown, &uf->spindown); + err |= __get_user(f->spindown_offset, &uf->spindown_offset); + err |= __get_user(f->select_delay, &uf->select_delay); + err |= __get_user(f->rps, &uf->rps); + err |= __get_user(f->tracks, &uf->tracks); + err |= __get_user(f->timeout, &uf->timeout); + err |= __get_user(f->interleave_sect, &uf->interleave_sect); + err |= __copy_from_user(&f->max_errors, &uf->max_errors, sizeof(f->max_errors)); + err |= __get_user(f->flags, &uf->flags); + err |= __get_user(f->read_track, &uf->read_track); + err |= __copy_from_user(f->autodetect, uf->autodetect, sizeof(f->autodetect)); + err |= __get_user(f->checkfreq, &uf->checkfreq); + err |= __get_user(f->native_format, &uf->native_format); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDGETFDCSTAT32: + karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDWERRORGET32: + karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + default: + return -EINVAL; + } + set_fs(KERNEL_DS); + err = blkdev_driver_ioctl(inode, file, disk, kcmd, (unsigned long)karg); + set_fs(old_fs); + if (err) + goto out; + switch (cmd) { + case FDGETPRM32: + { + struct floppy_struct *f = karg; + struct compat_floppy_struct __user *uf = compat_ptr(arg); + + err = __put_user(f->size, &uf->size); + err |= __put_user(f->sect, &uf->sect); + err |= __put_user(f->head, &uf->head); + err |= __put_user(f->track, &uf->track); + err |= __put_user(f->stretch, &uf->stretch); + err |= __put_user(f->gap, &uf->gap); + err |= __put_user(f->rate, &uf->rate); + err |= __put_user(f->spec1, &uf->spec1); + err |= __put_user(f->fmt_gap, &uf->fmt_gap); + err |= __put_user((u64)f->name, (compat_caddr_t __user *)&uf->name); + break; + } + case FDGETDRVPRM32: + { + struct compat_floppy_drive_params __user *uf; + struct floppy_drive_params *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->cmos, &uf->cmos); + err |= __put_user(f->max_dtr, &uf->max_dtr); + err |= __put_user(f->hlt, &uf->hlt); + err |= __put_user(f->hut, &uf->hut); + err |= __put_user(f->srt, &uf->srt); + err |= __put_user(f->spinup, &uf->spinup); + err |= __put_user(f->spindown, &uf->spindown); + err |= __put_user(f->spindown_offset, &uf->spindown_offset); + err |= __put_user(f->select_delay, &uf->select_delay); + err |= __put_user(f->rps, &uf->rps); + err |= __put_user(f->tracks, &uf->tracks); + err |= __put_user(f->timeout, &uf->timeout); + err |= __put_user(f->interleave_sect, &uf->interleave_sect); + err |= __copy_to_user(&uf->max_errors, &f->max_errors, sizeof(f->max_errors)); + err |= __put_user(f->flags, &uf->flags); + err |= __put_user(f->read_track, &uf->read_track); + err |= __copy_to_user(uf->autodetect, f->autodetect, sizeof(f->autodetect)); + err |= __put_user(f->checkfreq, &uf->checkfreq); + err |= __put_user(f->native_format, &uf->native_format); + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + { + struct compat_floppy_drive_struct __user *uf; + struct floppy_drive_struct *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->flags, &uf->flags); + err |= __put_user(f->spinup_date, &uf->spinup_date); + err |= __put_user(f->select_date, &uf->select_date); + err |= __put_user(f->first_read_date, &uf->first_read_date); + err |= __put_user(f->probed_format, &uf->probed_format); + err |= __put_user(f->track, &uf->track); + err |= __put_user(f->maxblock, &uf->maxblock); + err |= __put_user(f->maxtrack, &uf->maxtrack); + err |= __put_user(f->generation, &uf->generation); + err |= __put_user(f->keep_data, &uf->keep_data); + err |= __put_user(f->fd_ref, &uf->fd_ref); + err |= __put_user(f->fd_device, &uf->fd_device); + err |= __put_user(f->last_checked, &uf->last_checked); + err |= __put_user((u64)f->dmabuf, &uf->dmabuf); + err |= __put_user((u64)f->bufblocks, &uf->bufblocks); + break; + } + case FDGETFDCSTAT32: + { + struct compat_floppy_fdc_state __user *uf; + struct floppy_fdc_state *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->spec1, &uf->spec1); + err |= __put_user(f->spec2, &uf->spec2); + err |= __put_user(f->dtr, &uf->dtr); + err |= __put_user(f->version, &uf->version); + err |= __put_user(f->dor, &uf->dor); + err |= __put_user(f->address, &uf->address); + err |= __copy_to_user((char __user *)&uf->address + sizeof(uf->address), + (char *)&f->address + sizeof(f->address), sizeof(int)); + err |= __put_user(f->driver_version, &uf->driver_version); + err |= __copy_to_user(uf->track, f->track, sizeof(f->track)); + break; + } + case FDWERRORGET32: + { + struct compat_floppy_write_errors __user *uf; + struct floppy_write_errors *f = karg; + + uf = compat_ptr(arg); + err = __put_user(f->write_errors, &uf->write_errors); + err |= __put_user(f->first_error_sector, &uf->first_error_sector); + err |= __put_user(f->first_error_generation, &uf->first_error_generation); + err |= __put_user(f->last_error_sector, &uf->last_error_sector); + err |= __put_user(f->last_error_generation, &uf->last_error_generation); + err |= __put_user(f->badness, &uf->badness); + break; + } + default: + break; + } + if (err) + err = -EFAULT; + +out: + kfree(karg); + return err; +} + +struct compat_blk_user_trace_setup { + char name[32]; + u16 act_mask; + u32 buf_size; + u32 buf_nr; + compat_u64 start_lba; + compat_u64 end_lba; + u32 pid; +}; +#define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup) + +static int compat_blk_trace_setup(struct block_device *bdev, char __user *arg) +{ + struct blk_user_trace_setup buts; + struct compat_blk_user_trace_setup cbuts; + struct request_queue *q; + int ret; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + + if (copy_from_user(&cbuts, arg, sizeof(cbuts))) + return -EFAULT; + + buts = (struct blk_user_trace_setup) { + .act_mask = cbuts.act_mask, + .buf_size = cbuts.buf_size, + .buf_nr = cbuts.buf_nr, + .start_lba = cbuts.start_lba, + .end_lba = cbuts.end_lba, + .pid = cbuts.pid, + }; + memcpy(&buts.name, &cbuts.name, 32); + + mutex_lock(&bdev->bd_mutex); + ret = do_blk_trace_setup(q, bdev, &buts); + mutex_unlock(&bdev->bd_mutex); + if (ret) + return ret; + + if (copy_to_user(arg, &buts.name, 32)) + return -EFAULT; + + return 0; +} + +static int compat_blkdev_driver_ioctl(struct inode *inode, struct file *file, + struct gendisk *disk, unsigned cmd, unsigned long arg) +{ + int ret; + + switch (arg) { + case HDIO_GET_UNMASKINTR: + case HDIO_GET_MULTCOUNT: + case HDIO_GET_KEEPSETTINGS: + case HDIO_GET_32BIT: + case HDIO_GET_NOWERR: + case HDIO_GET_DMA: + case HDIO_GET_NICE: + case HDIO_GET_WCACHE: + case HDIO_GET_ACOUSTIC: + case HDIO_GET_ADDRESS: + case HDIO_GET_BUSSTATE: + return compat_hdio_ioctl(inode, file, disk, cmd, arg); + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + case FDSETDRVPRM32: + case FDGETDRVPRM32: + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + case FDGETFDCSTAT32: + case FDWERRORGET32: + return compat_fd_ioctl(inode, file, disk, cmd, arg); + case CDROMREADAUDIO: + return compat_cdrom_read_audio(inode, file, disk, cmd, arg); + case CDROM_SEND_PACKET: + return compat_cdrom_generic_command(inode, file, disk, cmd, arg); + + /* + * No handler required for the ones below, we just need to + * convert arg to a 64 bit pointer. + */ + case BLKSECTSET: + /* + * 0x03 -- HD/IDE ioctl's used by hdparm and friends. + * Some need translations, these do not. + */ + case HDIO_GET_IDENTITY: + case HDIO_DRIVE_TASK: + case HDIO_DRIVE_CMD: + case HDIO_SCAN_HWIF: + /* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */ + case 0x330: + /* 0x02 -- Floppy ioctls */ + case FDMSGON: + case FDMSGOFF: + case FDSETEMSGTRESH: + case FDFLUSH: + case FDWERRORCLR: + case FDSETMAXERRS: + case FDGETMAXERRS: + case FDGETDRVTYP: + case FDEJECT: + case FDCLRPRM: + case FDFMTBEG: + case FDFMTEND: + case FDRESET: + case FDTWADDLE: + case FDFMTTRK: + case FDRAWCMD: + /* CDROM stuff */ + case CDROMPAUSE: + case CDROMRESUME: + case CDROMPLAYMSF: + case CDROMPLAYTRKIND: + case CDROMREADTOCHDR: + case CDROMREADTOCENTRY: + case CDROMSTOP: + case CDROMSTART: + case CDROMEJECT: + case CDROMVOLCTRL: + case CDROMSUBCHNL: + case CDROMMULTISESSION: + case CDROM_GET_MCN: + case CDROMRESET: + case CDROMVOLREAD: + case CDROMSEEK: + case CDROMPLAYBLK: + case CDROMCLOSETRAY: + case CDROM_DISC_STATUS: + case CDROM_CHANGER_NSLOTS: + case CDROM_GET_CAPABILITY: + /* Ignore cdrom.h about these next 5 ioctls, they absolutely do + * not take a struct cdrom_read, instead they take a struct cdrom_msf + * which is compatible. + */ + case CDROMREADMODE2: + case CDROMREADMODE1: + case CDROMREADRAW: + case CDROMREADCOOKED: + case CDROMREADALL: + /* DVD ioctls */ + case DVD_READ_STRUCT: + case DVD_WRITE_STRUCT: + case DVD_AUTH: + arg = (unsigned long)compat_ptr(arg); + /* These intepret arg as an unsigned long, not as a pointer, + * so we must not do compat_ptr() conversion. */ + case HDIO_SET_MULTCOUNT: + case HDIO_SET_UNMASKINTR: + case HDIO_SET_KEEPSETTINGS: + case HDIO_SET_32BIT: + case HDIO_SET_NOWERR: + case HDIO_SET_DMA: + case HDIO_SET_PIO_MODE: + case HDIO_SET_NICE: + case HDIO_SET_WCACHE: + case HDIO_SET_ACOUSTIC: + case HDIO_SET_BUSSTATE: + case HDIO_SET_ADDRESS: + case CDROMEJECT_SW: + case CDROM_SET_OPTIONS: + case CDROM_CLEAR_OPTIONS: + case CDROM_SELECT_SPEED: + case CDROM_SELECT_DISC: + case CDROM_MEDIA_CHANGED: + case CDROM_DRIVE_STATUS: + case CDROM_LOCKDOOR: + case CDROM_DEBUG: + break; + default: + /* unknown ioctl number */ + 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; +} + +static int compat_blkdev_locked_ioctl(struct inode *inode, struct file *file, + struct block_device *bdev, + unsigned cmd, unsigned long arg) +{ + struct backing_dev_info *bdi; + + switch (cmd) { + case BLKRAGET: + case BLKFRAGET: + if (!arg) + return -EINVAL; + bdi = blk_get_backing_dev_info(bdev); + if (bdi == NULL) + return -ENOTTY; + return compat_put_long(arg, + (bdi->ra_pages * PAGE_CACHE_SIZE) / 512); + case BLKROGET: /* compatible */ + return compat_put_int(arg, bdev_read_only(bdev) != 0); + case BLKBSZGET_32: /* get the logical block size (cf. BLKSSZGET) */ + return compat_put_int(arg, block_size(bdev)); + case BLKSSZGET: /* get block device hardware sector size */ + return compat_put_int(arg, bdev_hardsect_size(bdev)); + case BLKSECTGET: + return compat_put_ushort(arg, + bdev_get_queue(bdev)->max_sectors); + case BLKRASET: /* compatible, but no compat_ptr (!) */ + 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 BLKGETSIZE: + if ((bdev->bd_inode->i_size >> 9) > ~0UL) + return -EFBIG; + return compat_put_ulong(arg, bdev->bd_inode->i_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)); + 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: + /* + * 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) + return ret; + + return compat_blkdev_driver_ioctl(inode, file, disk, cmd, arg); +} diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c index 87ca02ac84c..1a511ffaf8a 100644 --- a/block/deadline-iosched.c +++ b/block/deadline-iosched.c @@ -106,7 +106,7 @@ deadline_add_request(struct request_queue *q, struct request *rq) /* * remove rq from rbtree and fifo. */ -static void deadline_remove_request(request_queue_t *q, struct request *rq) +static void deadline_remove_request(struct request_queue *q, struct request *rq) { struct deadline_data *dd = q->elevator->elevator_data; @@ -115,7 +115,7 @@ static void deadline_remove_request(request_queue_t *q, struct request *rq) } static int -deadline_merge(request_queue_t *q, struct request **req, struct bio *bio) +deadline_merge(struct request_queue *q, struct request **req, struct bio *bio) { struct deadline_data *dd = q->elevator->elevator_data; struct request *__rq; @@ -144,8 +144,8 @@ out: return ret; } -static void deadline_merged_request(request_queue_t *q, struct request *req, - int type) +static void deadline_merged_request(struct request_queue *q, + struct request *req, int type) { struct deadline_data *dd = q->elevator->elevator_data; @@ -159,7 +159,7 @@ static void deadline_merged_request(request_queue_t *q, struct request *req, } static void -deadline_merged_requests(request_queue_t *q, struct request *req, +deadline_merged_requests(struct request_queue *q, struct request *req, struct request *next) { /* @@ -185,7 +185,7 @@ deadline_merged_requests(request_queue_t *q, struct request *req, static inline void deadline_move_to_dispatch(struct deadline_data *dd, struct request *rq) { - request_queue_t *q = rq->q; + struct request_queue *q = rq->q; deadline_remove_request(q, rq); elv_dispatch_add_tail(q, rq); @@ -236,7 +236,7 @@ static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) * deadline_dispatch_requests selects the best request according to * read/write expire, fifo_batch, etc */ -static int deadline_dispatch_requests(request_queue_t *q, int force) +static int deadline_dispatch_requests(struct request_queue *q, int force) { struct deadline_data *dd = q->elevator->elevator_data; const int reads = !list_empty(&dd->fifo_list[READ]); @@ -335,7 +335,7 @@ dispatch_request: return 1; } -static int deadline_queue_empty(request_queue_t *q) +static int deadline_queue_empty(struct request_queue *q) { struct deadline_data *dd = q->elevator->elevator_data; @@ -356,7 +356,7 @@ static void deadline_exit_queue(elevator_t *e) /* * initialize elevator private data (deadline_data). */ -static void *deadline_init_queue(request_queue_t *q) +static void *deadline_init_queue(struct request_queue *q) { struct deadline_data *dd; diff --git a/block/elevator.c b/block/elevator.c index d265963d1ed..b9c518afe1f 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -56,7 +56,7 @@ static const int elv_hash_shift = 6; */ static int elv_iosched_allow_merge(struct request *rq, struct bio *bio) { - request_queue_t *q = rq->q; + struct request_queue *q = rq->q; elevator_t *e = q->elevator; if (e->ops->elevator_allow_merge_fn) @@ -141,12 +141,13 @@ static struct elevator_type *elevator_get(const char *name) return e; } -static void *elevator_init_queue(request_queue_t *q, struct elevator_queue *eq) +static void *elevator_init_queue(struct request_queue *q, + struct elevator_queue *eq) { return eq->ops->elevator_init_fn(q); } -static void elevator_attach(request_queue_t *q, struct elevator_queue *eq, +static void elevator_attach(struct request_queue *q, struct elevator_queue *eq, void *data) { q->elevator = eq; @@ -172,7 +173,8 @@ __setup("elevator=", elevator_setup); static struct kobj_type elv_ktype; -static elevator_t *elevator_alloc(request_queue_t *q, struct elevator_type *e) +static elevator_t *elevator_alloc(struct request_queue *q, + struct elevator_type *e) { elevator_t *eq; int i; @@ -184,7 +186,7 @@ static elevator_t *elevator_alloc(request_queue_t *q, struct elevator_type *e) eq->ops = &e->ops; eq->elevator_type = e; kobject_init(&eq->kobj); - snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched"); + kobject_set_name(&eq->kobj, "%s", "iosched"); eq->kobj.ktype = &elv_ktype; mutex_init(&eq->sysfs_lock); @@ -212,7 +214,7 @@ static void elevator_release(struct kobject *kobj) kfree(e); } -int elevator_init(request_queue_t *q, char *name) +int elevator_init(struct request_queue *q, char *name) { struct elevator_type *e = NULL; struct elevator_queue *eq; @@ -264,7 +266,7 @@ void elevator_exit(elevator_t *e) EXPORT_SYMBOL(elevator_exit); -static void elv_activate_rq(request_queue_t *q, struct request *rq) +static void elv_activate_rq(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -272,7 +274,7 @@ static void elv_activate_rq(request_queue_t *q, struct request *rq) e->ops->elevator_activate_req_fn(q, rq); } -static void elv_deactivate_rq(request_queue_t *q, struct request *rq) +static void elv_deactivate_rq(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -285,13 +287,13 @@ static inline void __elv_rqhash_del(struct request *rq) hlist_del_init(&rq->hash); } -static void elv_rqhash_del(request_queue_t *q, struct request *rq) +static void elv_rqhash_del(struct request_queue *q, struct request *rq) { if (ELV_ON_HASH(rq)) __elv_rqhash_del(rq); } -static void elv_rqhash_add(request_queue_t *q, struct request *rq) +static void elv_rqhash_add(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -299,13 +301,13 @@ static void elv_rqhash_add(request_queue_t *q, struct request *rq) hlist_add_head(&rq->hash, &e->hash[ELV_HASH_FN(rq_hash_key(rq))]); } -static void elv_rqhash_reposition(request_queue_t *q, struct request *rq) +static void elv_rqhash_reposition(struct request_queue *q, struct request *rq) { __elv_rqhash_del(rq); elv_rqhash_add(q, rq); } -static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset) +static struct request *elv_rqhash_find(struct request_queue *q, sector_t offset) { elevator_t *e = q->elevator; struct hlist_head *hash_list = &e->hash[ELV_HASH_FN(offset)]; @@ -391,7 +393,7 @@ EXPORT_SYMBOL(elv_rb_find); * entry. rq is sort insted into the dispatch queue. To be used by * specific elevators. */ -void elv_dispatch_sort(request_queue_t *q, struct request *rq) +void elv_dispatch_sort(struct request_queue *q, struct request *rq) { sector_t boundary; struct list_head *entry; @@ -449,7 +451,7 @@ void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) EXPORT_SYMBOL(elv_dispatch_add_tail); -int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) +int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) { elevator_t *e = q->elevator; struct request *__rq; @@ -481,7 +483,7 @@ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) return ELEVATOR_NO_MERGE; } -void elv_merged_request(request_queue_t *q, struct request *rq, int type) +void elv_merged_request(struct request_queue *q, struct request *rq, int type) { elevator_t *e = q->elevator; @@ -494,7 +496,7 @@ void elv_merged_request(request_queue_t *q, struct request *rq, int type) q->last_merge = rq; } -void elv_merge_requests(request_queue_t *q, struct request *rq, +void elv_merge_requests(struct request_queue *q, struct request *rq, struct request *next) { elevator_t *e = q->elevator; @@ -509,7 +511,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, q->last_merge = rq; } -void elv_requeue_request(request_queue_t *q, struct request *rq) +void elv_requeue_request(struct request_queue *q, struct request *rq) { /* * it already went through dequeue, we need to decrement the @@ -526,7 +528,7 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE); } -static void elv_drain_elevator(request_queue_t *q) +static void elv_drain_elevator(struct request_queue *q) { static int printed; while (q->elevator->ops->elevator_dispatch_fn(q, 1)) @@ -540,7 +542,7 @@ static void elv_drain_elevator(request_queue_t *q) } } -void elv_insert(request_queue_t *q, struct request *rq, int where) +void elv_insert(struct request_queue *q, struct request *rq, int where) { struct list_head *pos; unsigned ordseq; @@ -638,7 +640,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where) } } -void __elv_add_request(request_queue_t *q, struct request *rq, int where, +void __elv_add_request(struct request_queue *q, struct request *rq, int where, int plug) { if (q->ordcolor) @@ -676,7 +678,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where, EXPORT_SYMBOL(__elv_add_request); -void elv_add_request(request_queue_t *q, struct request *rq, int where, +void elv_add_request(struct request_queue *q, struct request *rq, int where, int plug) { unsigned long flags; @@ -688,7 +690,7 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where, EXPORT_SYMBOL(elv_add_request); -static inline struct request *__elv_next_request(request_queue_t *q) +static inline struct request *__elv_next_request(struct request_queue *q) { struct request *rq; @@ -704,7 +706,7 @@ static inline struct request *__elv_next_request(request_queue_t *q) } } -struct request *elv_next_request(request_queue_t *q) +struct request *elv_next_request(struct request_queue *q) { struct request *rq; int ret; @@ -770,7 +772,7 @@ struct request *elv_next_request(request_queue_t *q) EXPORT_SYMBOL(elv_next_request); -void elv_dequeue_request(request_queue_t *q, struct request *rq) +void elv_dequeue_request(struct request_queue *q, struct request *rq) { BUG_ON(list_empty(&rq->queuelist)); BUG_ON(ELV_ON_HASH(rq)); @@ -788,7 +790,7 @@ void elv_dequeue_request(request_queue_t *q, struct request *rq) EXPORT_SYMBOL(elv_dequeue_request); -int elv_queue_empty(request_queue_t *q) +int elv_queue_empty(struct request_queue *q) { elevator_t *e = q->elevator; @@ -803,7 +805,7 @@ int elv_queue_empty(request_queue_t *q) EXPORT_SYMBOL(elv_queue_empty); -struct request *elv_latter_request(request_queue_t *q, struct request *rq) +struct request *elv_latter_request(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -812,7 +814,7 @@ struct request *elv_latter_request(request_queue_t *q, struct request *rq) return NULL; } -struct request *elv_former_request(request_queue_t *q, struct request *rq) +struct request *elv_former_request(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -821,7 +823,7 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq) return NULL; } -int elv_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) +int elv_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) { elevator_t *e = q->elevator; @@ -832,7 +834,7 @@ int elv_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask) return 0; } -void elv_put_request(request_queue_t *q, struct request *rq) +void elv_put_request(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -840,7 +842,7 @@ void elv_put_request(request_queue_t *q, struct request *rq) e->ops->elevator_put_req_fn(rq); } -int elv_may_queue(request_queue_t *q, int rw) +int elv_may_queue(struct request_queue *q, int rw) { elevator_t *e = q->elevator; @@ -850,7 +852,7 @@ int elv_may_queue(request_queue_t *q, int rw) return ELV_MQUEUE_MAY; } -void elv_completed_request(request_queue_t *q, struct request *rq) +void elv_completed_request(struct request_queue *q, struct request *rq) { elevator_t *e = q->elevator; @@ -1006,7 +1008,7 @@ EXPORT_SYMBOL_GPL(elv_unregister); * need for the new one. this way we have a chance of going back to the old * one, if the new one fails init for some reason. */ -static int elevator_switch(request_queue_t *q, struct elevator_type *new_e) +static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) { elevator_t *old_elevator, *e; void *data; @@ -1078,7 +1080,8 @@ fail_register: return 0; } -ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count) +ssize_t elv_iosched_store(struct request_queue *q, const char *name, + size_t count) { char elevator_name[ELV_NAME_MAX]; size_t len; @@ -1107,7 +1110,7 @@ ssize_t elv_iosched_store(request_queue_t *q, const char *name, size_t count) return count; } -ssize_t elv_iosched_show(request_queue_t *q, char *name) +ssize_t elv_iosched_show(struct request_queue *q, char *name) { elevator_t *e = q->elevator; struct elevator_type *elv = e->elevator_type; @@ -1127,7 +1130,8 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) return len; } -struct request *elv_rb_former_request(request_queue_t *q, struct request *rq) +struct request *elv_rb_former_request(struct request_queue *q, + struct request *rq) { struct rb_node *rbprev = rb_prev(&rq->rb_node); @@ -1139,7 +1143,8 @@ struct request *elv_rb_former_request(request_queue_t *q, struct request *rq) EXPORT_SYMBOL(elv_rb_former_request); -struct request *elv_rb_latter_request(request_queue_t *q, struct request *rq) +struct request *elv_rb_latter_request(struct request_queue *q, + struct request *rq) { struct rb_node *rbnext = rb_next(&rq->rb_node); diff --git a/block/genhd.c b/block/genhd.c index 3af1e7a378d..e609996f2e7 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -540,61 +540,42 @@ static int block_uevent_filter(struct kset *kset, struct kobject *kobj) return ((ktype == &ktype_block) || (ktype == &ktype_part)); } -static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp, - int num_envp, char *buffer, int buffer_size) +static int block_uevent(struct kset *kset, struct kobject *kobj, + struct kobj_uevent_env *env) { struct kobj_type *ktype = get_ktype(kobj); struct device *physdev; struct gendisk *disk; struct hd_struct *part; - int length = 0; - int i = 0; if (ktype == &ktype_block) { disk = container_of(kobj, struct gendisk, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", disk->first_minor); + add_uevent_var(env, "MINOR=%u", disk->first_minor); } else if (ktype == &ktype_part) { disk = container_of(kobj->parent, struct gendisk, kobj); part = container_of(kobj, struct hd_struct, kobj); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "MINOR=%u", + add_uevent_var(env, "MINOR=%u", disk->first_minor + part->partno); } else return 0; - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, - "MAJOR=%u", disk->major); + add_uevent_var(env, "MAJOR=%u", disk->major); /* add physical device, backing this device */ physdev = disk->driverfs_dev; if (physdev) { char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL); - add_uevent_var(envp, num_envp, &i, buffer, buffer_size, - &length, "PHYSDEVPATH=%s", path); + add_uevent_var(env, "PHYSDEVPATH=%s", path); kfree(path); if (physdev->bus) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVBUS=%s", - physdev->bus->name); + add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name); if (physdev->driver) - add_uevent_var(envp, num_envp, &i, - buffer, buffer_size, &length, - "PHYSDEVDRIVER=%s", - physdev->driver->name); + add_uevent_var(env, physdev->driver->name); } - /* terminate, set to next free slot, shrink available space */ - envp[i] = NULL; - envp = &envp[i]; - num_envp -= i; - buffer = &buffer[length]; - buffer_size -= length; - return 0; } diff --git a/block/ioctl.c b/block/ioctl.c index f7e3e8abf88..52d6385216a 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -217,6 +217,10 @@ int blkdev_driver_ioctl(struct inode *inode, struct file *file, } 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, unsigned long arg) { @@ -284,21 +288,4 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, return blkdev_driver_ioctl(inode, file, disk, cmd, 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) -{ - struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev; - struct gendisk *disk = bdev->bd_disk; - int ret = -ENOIOCTLCMD; - if (disk->fops->compat_ioctl) { - lock_kernel(); - ret = disk->fops->compat_ioctl(file, cmd, arg); - unlock_kernel(); - } - return ret; -} - EXPORT_SYMBOL_GPL(blkdev_ioctl); diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index d7cadf30416..d875673e76c 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -40,8 +40,11 @@ static void blk_unplug_work(struct work_struct *work); static void blk_unplug_timeout(unsigned long data); static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io); static void init_request_from_bio(struct request *req, struct bio *bio); -static int __make_request(request_queue_t *q, struct bio *bio); +static int __make_request(struct request_queue *q, struct bio *bio); static struct io_context *current_io_context(gfp_t gfp_flags, int node); +static void blk_recalc_rq_segments(struct request *rq); +static void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio); /* * For the allocated request tables @@ -121,7 +124,7 @@ static void blk_queue_congestion_threshold(struct request_queue *q) struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev) { struct backing_dev_info *ret = NULL; - request_queue_t *q = bdev_get_queue(bdev); + struct request_queue *q = bdev_get_queue(bdev); if (q) ret = &q->backing_dev_info; @@ -140,7 +143,7 @@ EXPORT_SYMBOL(blk_get_backing_dev_info); * cdb from the request data for instance. * */ -void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn) +void blk_queue_prep_rq(struct request_queue *q, prep_rq_fn *pfn) { q->prep_rq_fn = pfn; } @@ -163,14 +166,14 @@ EXPORT_SYMBOL(blk_queue_prep_rq); * no merge_bvec_fn is defined for a queue, and only the fixed limits are * honored. */ -void blk_queue_merge_bvec(request_queue_t *q, merge_bvec_fn *mbfn) +void blk_queue_merge_bvec(struct request_queue *q, merge_bvec_fn *mbfn) { q->merge_bvec_fn = mbfn; } EXPORT_SYMBOL(blk_queue_merge_bvec); -void blk_queue_softirq_done(request_queue_t *q, softirq_done_fn *fn) +void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn) { q->softirq_done_fn = fn; } @@ -199,7 +202,7 @@ EXPORT_SYMBOL(blk_queue_softirq_done); * __bio_kmap_atomic() to get a temporary kernel mapping, or by calling * blk_queue_bounce() to create a buffer in normal memory. **/ -void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) +void blk_queue_make_request(struct request_queue * q, make_request_fn * mfn) { /* * set defaults @@ -235,7 +238,7 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn) EXPORT_SYMBOL(blk_queue_make_request); -static void rq_init(request_queue_t *q, struct request *rq) +static void rq_init(struct request_queue *q, struct request *rq) { INIT_LIST_HEAD(&rq->queuelist); INIT_LIST_HEAD(&rq->donelist); @@ -272,7 +275,7 @@ static void rq_init(request_queue_t *q, struct request *rq) * feature should call this function and indicate so. * **/ -int blk_queue_ordered(request_queue_t *q, unsigned ordered, +int blk_queue_ordered(struct request_queue *q, unsigned ordered, prepare_flush_fn *prepare_flush_fn) { if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) && @@ -311,7 +314,7 @@ EXPORT_SYMBOL(blk_queue_ordered); * to the block layer by defining it through this call. * **/ -void blk_queue_issue_flush_fn(request_queue_t *q, issue_flush_fn *iff) +void blk_queue_issue_flush_fn(struct request_queue *q, issue_flush_fn *iff) { q->issue_flush_fn = iff; } @@ -321,7 +324,7 @@ EXPORT_SYMBOL(blk_queue_issue_flush_fn); /* * Cache flushing for ordered writes handling */ -inline unsigned blk_ordered_cur_seq(request_queue_t *q) +inline unsigned blk_ordered_cur_seq(struct request_queue *q) { if (!q->ordseq) return 0; @@ -330,7 +333,7 @@ inline unsigned blk_ordered_cur_seq(request_queue_t *q) unsigned blk_ordered_req_seq(struct request *rq) { - request_queue_t *q = rq->q; + struct request_queue *q = rq->q; BUG_ON(q->ordseq == 0); @@ -357,7 +360,7 @@ unsigned blk_ordered_req_seq(struct request *rq) return QUEUE_ORDSEQ_DONE; } -void blk_ordered_complete_seq(request_queue_t *q, unsigned seq, int error) +void blk_ordered_complete_seq(struct request_queue *q, unsigned seq, int error) { struct request *rq; int uptodate; @@ -401,7 +404,7 @@ static void post_flush_end_io(struct request *rq, int error) blk_ordered_complete_seq(rq->q, QUEUE_ORDSEQ_POSTFLUSH, error); } -static void queue_flush(request_queue_t *q, unsigned which) +static void queue_flush(struct request_queue *q, unsigned which) { struct request *rq; rq_end_io_fn *end_io; @@ -425,10 +428,9 @@ static void queue_flush(request_queue_t *q, unsigned which) elv_insert(q, rq, ELEVATOR_INSERT_FRONT); } -static inline struct request *start_ordered(request_queue_t *q, +static inline struct request *start_ordered(struct request_queue *q, struct request *rq) { - q->bi_size = 0; q->orderr = 0; q->ordered = q->next_ordered; q->ordseq |= QUEUE_ORDSEQ_STARTED; @@ -476,7 +478,7 @@ static inline struct request *start_ordered(request_queue_t *q, return rq; } -int blk_do_ordered(request_queue_t *q, struct request **rqp) +int blk_do_ordered(struct request_queue *q, struct request **rqp) { struct request *rq = *rqp; int is_barrier = blk_fs_request(rq) && blk_barrier_rq(rq); @@ -525,56 +527,36 @@ int blk_do_ordered(request_queue_t *q, struct request **rqp) return 1; } -static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error) +static void req_bio_endio(struct request *rq, struct bio *bio, + unsigned int nbytes, int error) { - request_queue_t *q = bio->bi_private; + struct request_queue *q = rq->q; - /* - * This is dry run, restore bio_sector and size. We'll finish - * this request again with the original bi_end_io after an - * error occurs or post flush is complete. - */ - q->bi_size += bytes; - - if (bio->bi_size) - return 1; - - /* Reset bio */ - set_bit(BIO_UPTODATE, &bio->bi_flags); - bio->bi_size = q->bi_size; - bio->bi_sector -= (q->bi_size >> 9); - q->bi_size = 0; - - return 0; -} - -static int ordered_bio_endio(struct request *rq, struct bio *bio, - unsigned int nbytes, int error) -{ - request_queue_t *q = rq->q; - bio_end_io_t *endio; - void *private; - - if (&q->bar_rq != rq) - return 0; - - /* - * Okay, this is the barrier request in progress, dry finish it. - */ - if (error && !q->orderr) - q->orderr = error; + if (&q->bar_rq != rq) { + if (error) + clear_bit(BIO_UPTODATE, &bio->bi_flags); + else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + error = -EIO; - endio = bio->bi_end_io; - private = bio->bi_private; - bio->bi_end_io = flush_dry_bio_endio; - bio->bi_private = q; - - bio_endio(bio, nbytes, error); + if (unlikely(nbytes > bio->bi_size)) { + printk("%s: want %u bytes done, only %u left\n", + __FUNCTION__, nbytes, bio->bi_size); + nbytes = bio->bi_size; + } - bio->bi_end_io = endio; - bio->bi_private = private; + bio->bi_size -= nbytes; + bio->bi_sector += (nbytes >> 9); + if (bio->bi_size == 0) + bio_endio(bio, error); + } else { - return 1; + /* + * Okay, this is the barrier request in progress, just + * record the error; + */ + if (error && !q->orderr) + q->orderr = error; + } } /** @@ -588,7 +570,7 @@ static int ordered_bio_endio(struct request *rq, struct bio *bio, * blk_queue_bounce_limit to have lower memory pages allocated as bounce * buffers for doing I/O to pages residing above @page. **/ -void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr) +void blk_queue_bounce_limit(struct request_queue *q, u64 dma_addr) { unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT; int dma = 0; @@ -624,7 +606,7 @@ EXPORT_SYMBOL(blk_queue_bounce_limit); * Enables a low level driver to set an upper limit on the size of * received requests. **/ -void blk_queue_max_sectors(request_queue_t *q, unsigned int max_sectors) +void blk_queue_max_sectors(struct request_queue *q, unsigned int max_sectors) { if ((max_sectors << 9) < PAGE_CACHE_SIZE) { max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); @@ -651,7 +633,8 @@ EXPORT_SYMBOL(blk_queue_max_sectors); * physical data segments in a request. This would be the largest sized * scatter list the driver could handle. **/ -void blk_queue_max_phys_segments(request_queue_t *q, unsigned short max_segments) +void blk_queue_max_phys_segments(struct request_queue *q, + unsigned short max_segments) { if (!max_segments) { max_segments = 1; @@ -674,7 +657,8 @@ EXPORT_SYMBOL(blk_queue_max_phys_segments); * address/length pairs the host adapter can actually give as once * to the device. **/ -void blk_queue_max_hw_segments(request_queue_t *q, unsigned short max_segments) +void blk_queue_max_hw_segments(struct request_queue *q, + unsigned short max_segments) { if (!max_segments) { max_segments = 1; @@ -695,7 +679,7 @@ EXPORT_SYMBOL(blk_queue_max_hw_segments); * Enables a low level driver to set an upper limit on the size of a * coalesced segment **/ -void blk_queue_max_segment_size(request_queue_t *q, unsigned int max_size) +void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size) { if (max_size < PAGE_CACHE_SIZE) { max_size = PAGE_CACHE_SIZE; @@ -718,7 +702,7 @@ EXPORT_SYMBOL(blk_queue_max_segment_size); * even internal read-modify-write operations). Usually the default * of 512 covers most hardware. **/ -void blk_queue_hardsect_size(request_queue_t *q, unsigned short size) +void blk_queue_hardsect_size(struct request_queue *q, unsigned short size) { q->hardsect_size = size; } @@ -735,7 +719,7 @@ EXPORT_SYMBOL(blk_queue_hardsect_size); * @t: the stacking driver (top) * @b: the underlying device (bottom) **/ -void blk_queue_stack_limits(request_queue_t *t, request_queue_t *b) +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); @@ -756,7 +740,7 @@ EXPORT_SYMBOL(blk_queue_stack_limits); * @q: the request queue for the device * @mask: the memory boundary mask **/ -void blk_queue_segment_boundary(request_queue_t *q, unsigned long mask) +void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask) { if (mask < PAGE_CACHE_SIZE - 1) { mask = PAGE_CACHE_SIZE - 1; @@ -778,7 +762,7 @@ EXPORT_SYMBOL(blk_queue_segment_boundary); * this is used when buiding direct io requests for the queue. * **/ -void blk_queue_dma_alignment(request_queue_t *q, int mask) +void blk_queue_dma_alignment(struct request_queue *q, int mask) { q->dma_alignment = mask; } @@ -796,7 +780,7 @@ EXPORT_SYMBOL(blk_queue_dma_alignment); * * no locks need be held. **/ -struct request *blk_queue_find_tag(request_queue_t *q, int tag) +struct request *blk_queue_find_tag(struct request_queue *q, int tag) { return blk_map_queue_find_tag(q->queue_tags, tag); } @@ -840,7 +824,7 @@ static int __blk_free_tags(struct blk_queue_tag *bqt) * blk_cleanup_queue() will take care of calling this function, if tagging * has been used. So there's no need to call this directly. **/ -static void __blk_queue_free_tags(request_queue_t *q) +static void __blk_queue_free_tags(struct request_queue *q) { struct blk_queue_tag *bqt = q->queue_tags; @@ -877,7 +861,7 @@ EXPORT_SYMBOL(blk_free_tags); * This is used to disabled tagged queuing to a device, yet leave * queue in function. **/ -void blk_queue_free_tags(request_queue_t *q) +void blk_queue_free_tags(struct request_queue *q) { clear_bit(QUEUE_FLAG_QUEUED, &q->queue_flags); } @@ -885,7 +869,7 @@ void blk_queue_free_tags(request_queue_t *q) EXPORT_SYMBOL(blk_queue_free_tags); static int -init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) +init_tag_map(struct request_queue *q, struct blk_queue_tag *tags, int depth) { struct request **tag_index; unsigned long *tag_map; @@ -955,7 +939,7 @@ EXPORT_SYMBOL(blk_init_tags); * @depth: the maximum queue depth supported * @tags: the tag to use **/ -int blk_queue_init_tags(request_queue_t *q, int depth, +int blk_queue_init_tags(struct request_queue *q, int depth, struct blk_queue_tag *tags) { int rc; @@ -996,7 +980,7 @@ EXPORT_SYMBOL(blk_queue_init_tags); * Notes: * Must be called with the queue lock held. **/ -int blk_queue_resize_tags(request_queue_t *q, int new_depth) +int blk_queue_resize_tags(struct request_queue *q, int new_depth) { struct blk_queue_tag *bqt = q->queue_tags; struct request **tag_index; @@ -1059,7 +1043,7 @@ EXPORT_SYMBOL(blk_queue_resize_tags); * Notes: * queue lock must be held. **/ -void blk_queue_end_tag(request_queue_t *q, struct request *rq) +void blk_queue_end_tag(struct request_queue *q, struct request *rq) { struct blk_queue_tag *bqt = q->queue_tags; int tag = rq->tag; @@ -1073,12 +1057,6 @@ void blk_queue_end_tag(request_queue_t *q, struct request *rq) */ return; - if (unlikely(!__test_and_clear_bit(tag, bqt->tag_map))) { - printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n", - __FUNCTION__, tag); - return; - } - list_del_init(&rq->queuelist); rq->cmd_flags &= ~REQ_QUEUED; rq->tag = -1; @@ -1088,6 +1066,19 @@ void blk_queue_end_tag(request_queue_t *q, struct request *rq) __FUNCTION__, tag); bqt->tag_index[tag] = NULL; + + /* + * We use test_and_clear_bit's memory ordering properties here. + * The tag_map bit acts as a lock for tag_index[bit], so we need + * a barrer before clearing the bit (precisely: release semantics). + * Could use clear_bit_unlock when it is merged. + */ + if (unlikely(!test_and_clear_bit(tag, bqt->tag_map))) { + printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n", + __FUNCTION__, tag); + return; + } + bqt->busy--; } @@ -1111,7 +1102,7 @@ EXPORT_SYMBOL(blk_queue_end_tag); * Notes: * queue lock must be held. **/ -int blk_queue_start_tag(request_queue_t *q, struct request *rq) +int blk_queue_start_tag(struct request_queue *q, struct request *rq) { struct blk_queue_tag *bqt = q->queue_tags; int tag; @@ -1134,6 +1125,10 @@ int blk_queue_start_tag(request_queue_t *q, struct request *rq) return 1; } while (test_and_set_bit(tag, bqt->tag_map)); + /* + * We rely on test_and_set_bit providing lock memory ordering semantics + * (could use test_and_set_bit_lock when it is merged). + */ rq->cmd_flags |= REQ_QUEUED; rq->tag = tag; @@ -1158,7 +1153,7 @@ EXPORT_SYMBOL(blk_queue_start_tag); * Notes: * queue lock must be held. **/ -void blk_queue_invalidate_tags(request_queue_t *q) +void blk_queue_invalidate_tags(struct request_queue *q) { struct blk_queue_tag *bqt = q->queue_tags; struct list_head *tmp, *n; @@ -1205,18 +1200,42 @@ void blk_dump_rq_flags(struct request *rq, char *msg) EXPORT_SYMBOL(blk_dump_rq_flags); -void blk_recount_segments(request_queue_t *q, struct bio *bio) +void blk_recount_segments(struct request_queue *q, struct bio *bio) +{ + struct request rq; + struct bio *nxt = bio->bi_next; + rq.q = q; + rq.bio = rq.biotail = bio; + bio->bi_next = NULL; + blk_recalc_rq_segments(&rq); + bio->bi_next = nxt; + bio->bi_phys_segments = rq.nr_phys_segments; + bio->bi_hw_segments = rq.nr_hw_segments; + bio->bi_flags |= (1 << BIO_SEG_VALID); +} +EXPORT_SYMBOL(blk_recount_segments); + +static void blk_recalc_rq_segments(struct request *rq) { + int nr_phys_segs; + int nr_hw_segs; + unsigned int phys_size; + unsigned int hw_size; struct bio_vec *bv, *bvprv = NULL; - int i, nr_phys_segs, nr_hw_segs, seg_size, hw_seg_size, cluster; + int seg_size; + int hw_seg_size; + int cluster; + struct req_iterator iter; int high, highprv = 1; + struct request_queue *q = rq->q; - if (unlikely(!bio->bi_io_vec)) + if (!rq->bio) return; cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); - hw_seg_size = seg_size = nr_phys_segs = nr_hw_segs = 0; - bio_for_each_segment(bv, bio, i) { + hw_seg_size = seg_size = 0; + phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; + rq_for_each_segment(bv, rq, iter) { /* * the trick here is making sure that a high page is never * considered part of another segment, since that might @@ -1242,12 +1261,13 @@ void blk_recount_segments(request_queue_t *q, struct bio *bio) } new_segment: if (BIOVEC_VIRT_MERGEABLE(bvprv, bv) && - !BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len)) { + !BIOVEC_VIRT_OVERSIZE(hw_seg_size + bv->bv_len)) hw_seg_size += bv->bv_len; - } else { + else { new_hw_segment: - if (hw_seg_size > bio->bi_hw_front_size) - bio->bi_hw_front_size = hw_seg_size; + if (nr_hw_segs == 1 && + hw_seg_size > rq->bio->bi_hw_front_size) + rq->bio->bi_hw_front_size = hw_seg_size; hw_seg_size = BIOVEC_VIRT_START_SIZE(bv) + bv->bv_len; nr_hw_segs++; } @@ -1257,17 +1277,17 @@ new_hw_segment: seg_size = bv->bv_len; highprv = high; } - if (hw_seg_size > bio->bi_hw_back_size) - bio->bi_hw_back_size = hw_seg_size; - if (nr_hw_segs == 1 && hw_seg_size > bio->bi_hw_front_size) - bio->bi_hw_front_size = hw_seg_size; - bio->bi_phys_segments = nr_phys_segs; - bio->bi_hw_segments = nr_hw_segs; - bio->bi_flags |= (1 << BIO_SEG_VALID); + + if (nr_hw_segs == 1 && + hw_seg_size > rq->bio->bi_hw_front_size) + rq->bio->bi_hw_front_size = hw_seg_size; + if (hw_seg_size > rq->biotail->bi_hw_back_size) + rq->biotail->bi_hw_back_size = hw_seg_size; + rq->nr_phys_segments = nr_phys_segs; + rq->nr_hw_segments = nr_hw_segs; } -EXPORT_SYMBOL(blk_recount_segments); -static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, +static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, struct bio *nxt) { if (!(q->queue_flags & (1 << QUEUE_FLAG_CLUSTER))) @@ -1288,7 +1308,7 @@ static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio, return 0; } -static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio, +static int blk_hw_contig_segment(struct request_queue *q, struct bio *bio, struct bio *nxt) { if (unlikely(!bio_flagged(bio, BIO_SEG_VALID))) @@ -1308,11 +1328,12 @@ static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio, * map a request to scatterlist, return number of sg entries setup. Caller * must make sure sg can hold rq->nr_phys_segments entries */ -int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg) +int blk_rq_map_sg(struct request_queue *q, struct request *rq, + struct scatterlist *sg) { struct bio_vec *bvec, *bvprv; - struct bio *bio; - int nsegs, i, cluster; + struct req_iterator iter; + int nsegs, cluster; nsegs = 0; cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER); @@ -1321,35 +1342,30 @@ int blk_rq_map_sg(request_queue_t *q, struct request *rq, struct scatterlist *sg * for each bio in rq */ bvprv = NULL; - rq_for_each_bio(bio, rq) { - /* - * for each segment in bio - */ - bio_for_each_segment(bvec, bio, i) { - int nbytes = bvec->bv_len; + rq_for_each_segment(bvec, rq, iter) { + int nbytes = bvec->bv_len; - if (bvprv && cluster) { - if (sg[nsegs - 1].length + nbytes > q->max_segment_size) - goto new_segment; + if (bvprv && cluster) { + if (sg[nsegs - 1].length + nbytes > q->max_segment_size) + goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) - goto new_segment; + if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) + goto new_segment; + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) + goto new_segment; - sg[nsegs - 1].length += nbytes; - } else { + sg[nsegs - 1].length += nbytes; + } else { new_segment: - memset(&sg[nsegs],0,sizeof(struct scatterlist)); - sg[nsegs].page = bvec->bv_page; - sg[nsegs].length = nbytes; - sg[nsegs].offset = bvec->bv_offset; + memset(&sg[nsegs],0,sizeof(struct scatterlist)); + sg[nsegs].page = bvec->bv_page; + sg[nsegs].length = nbytes; + sg[nsegs].offset = bvec->bv_offset; - nsegs++; - } - bvprv = bvec; - } /* segments in bio */ - } /* bios in rq */ + nsegs++; + } + bvprv = bvec; + } /* segments in rq */ return nsegs; } @@ -1361,7 +1377,7 @@ EXPORT_SYMBOL(blk_rq_map_sg); * specific ones if so desired */ -static inline int ll_new_mergeable(request_queue_t *q, +static inline int ll_new_mergeable(struct request_queue *q, struct request *req, struct bio *bio) { @@ -1382,7 +1398,7 @@ static inline int ll_new_mergeable(request_queue_t *q, return 1; } -static inline int ll_new_hw_segment(request_queue_t *q, +static inline int ll_new_hw_segment(struct request_queue *q, struct request *req, struct bio *bio) { @@ -1406,7 +1422,8 @@ static inline int ll_new_hw_segment(request_queue_t *q, return 1; } -int ll_back_merge_fn(request_queue_t *q, struct request *req, struct bio *bio) +static int ll_back_merge_fn(struct request_queue *q, struct request *req, + struct bio *bio) { unsigned short max_sectors; int len; @@ -1442,9 +1459,8 @@ int ll_back_merge_fn(request_queue_t *q, struct request *req, struct bio *bio) return ll_new_hw_segment(q, req, bio); } -EXPORT_SYMBOL(ll_back_merge_fn); -static int ll_front_merge_fn(request_queue_t *q, struct request *req, +static int ll_front_merge_fn(struct request_queue *q, struct request *req, struct bio *bio) { unsigned short max_sectors; @@ -1483,7 +1499,7 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req, return ll_new_hw_segment(q, req, bio); } -static int ll_merge_requests_fn(request_queue_t *q, struct request *req, +static int ll_merge_requests_fn(struct request_queue *q, struct request *req, struct request *next) { int total_phys_segments; @@ -1539,7 +1555,7 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req, * This is called with interrupts off and no requests on the queue and * with the queue lock held. */ -void blk_plug_device(request_queue_t *q) +void blk_plug_device(struct request_queue *q) { WARN_ON(!irqs_disabled()); @@ -1562,7 +1578,7 @@ EXPORT_SYMBOL(blk_plug_device); * remove the queue from the plugged list, if present. called with * queue lock held and interrupts disabled. */ -int blk_remove_plug(request_queue_t *q) +int blk_remove_plug(struct request_queue *q) { WARN_ON(!irqs_disabled()); @@ -1578,7 +1594,7 @@ EXPORT_SYMBOL(blk_remove_plug); /* * remove the plug and let it rip.. */ -void __generic_unplug_device(request_queue_t *q) +void __generic_unplug_device(struct request_queue *q) { if (unlikely(blk_queue_stopped(q))) return; @@ -1592,7 +1608,7 @@ EXPORT_SYMBOL(__generic_unplug_device); /** * generic_unplug_device - fire a request queue - * @q: The &request_queue_t in question + * @q: The &struct request_queue in question * * Description: * Linux uses plugging to build bigger requests queues before letting @@ -1601,7 +1617,7 @@ EXPORT_SYMBOL(__generic_unplug_device); * gets unplugged, the request_fn defined for the queue is invoked and * transfers started. **/ -void generic_unplug_device(request_queue_t *q) +void generic_unplug_device(struct request_queue *q) { spin_lock_irq(q->queue_lock); __generic_unplug_device(q); @@ -1612,7 +1628,7 @@ EXPORT_SYMBOL(generic_unplug_device); static void blk_backing_dev_unplug(struct backing_dev_info *bdi, struct page *page) { - request_queue_t *q = bdi->unplug_io_data; + struct request_queue *q = bdi->unplug_io_data; /* * devices don't necessarily have an ->unplug_fn defined @@ -1627,7 +1643,8 @@ static void blk_backing_dev_unplug(struct backing_dev_info *bdi, static void blk_unplug_work(struct work_struct *work) { - request_queue_t *q = container_of(work, request_queue_t, unplug_work); + struct request_queue *q = + container_of(work, struct request_queue, unplug_work); blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_IO, NULL, q->rq.count[READ] + q->rq.count[WRITE]); @@ -1637,7 +1654,7 @@ static void blk_unplug_work(struct work_struct *work) static void blk_unplug_timeout(unsigned long data) { - request_queue_t *q = (request_queue_t *)data; + struct request_queue *q = (struct request_queue *)data; blk_add_trace_pdu_int(q, BLK_TA_UNPLUG_TIMER, NULL, q->rq.count[READ] + q->rq.count[WRITE]); @@ -1647,14 +1664,14 @@ static void blk_unplug_timeout(unsigned long data) /** * blk_start_queue - restart a previously stopped queue - * @q: The &request_queue_t in question + * @q: The &struct request_queue in question * * Description: * blk_start_queue() will clear the stop flag on the queue, and call * the request_fn for the queue if it was in a stopped state when * entered. Also see blk_stop_queue(). Queue lock must be held. **/ -void blk_start_queue(request_queue_t *q) +void blk_start_queue(struct request_queue *q) { WARN_ON(!irqs_disabled()); @@ -1677,7 +1694,7 @@ EXPORT_SYMBOL(blk_start_queue); /** * blk_stop_queue - stop a queue - * @q: The &request_queue_t in question + * @q: The &struct request_queue in question * * Description: * The Linux block layer assumes that a block driver will consume all @@ -1689,7 +1706,7 @@ EXPORT_SYMBOL(blk_start_queue); * the driver has signalled it's ready to go again. This happens by calling * blk_start_queue() to restart queue operations. Queue lock must be held. **/ -void blk_stop_queue(request_queue_t *q) +void blk_stop_queue(struct request_queue *q) { blk_remove_plug(q); set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); @@ -1746,7 +1763,7 @@ void blk_run_queue(struct request_queue *q) EXPORT_SYMBOL(blk_run_queue); /** - * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed + * blk_cleanup_queue: - release a &struct request_queue when it is no longer needed * @kobj: the kobj belonging of the request queue to be released * * Description: @@ -1762,7 +1779,8 @@ EXPORT_SYMBOL(blk_run_queue); **/ static void blk_release_queue(struct kobject *kobj) { - request_queue_t *q = container_of(kobj, struct request_queue, kobj); + struct request_queue *q = + container_of(kobj, struct request_queue, kobj); struct request_list *rl = &q->rq; blk_sync_queue(q); @@ -1778,13 +1796,13 @@ static void blk_release_queue(struct kobject *kobj) kmem_cache_free(requestq_cachep, q); } -void blk_put_queue(request_queue_t *q) +void blk_put_queue(struct request_queue *q) { kobject_put(&q->kobj); } EXPORT_SYMBOL(blk_put_queue); -void blk_cleanup_queue(request_queue_t * q) +void blk_cleanup_queue(struct request_queue * q) { mutex_lock(&q->sysfs_lock); set_bit(QUEUE_FLAG_DEAD, &q->queue_flags); @@ -1798,7 +1816,7 @@ void blk_cleanup_queue(request_queue_t * q) EXPORT_SYMBOL(blk_cleanup_queue); -static int blk_init_free_list(request_queue_t *q) +static int blk_init_free_list(struct request_queue *q) { struct request_list *rl = &q->rq; @@ -1817,7 +1835,7 @@ static int blk_init_free_list(request_queue_t *q) return 0; } -request_queue_t *blk_alloc_queue(gfp_t gfp_mask) +struct request_queue *blk_alloc_queue(gfp_t gfp_mask) { return blk_alloc_queue_node(gfp_mask, -1); } @@ -1825,9 +1843,9 @@ EXPORT_SYMBOL(blk_alloc_queue); static struct kobj_type queue_ktype; -request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) +struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) { - request_queue_t *q; + struct request_queue *q; q = kmem_cache_alloc_node(requestq_cachep, gfp_mask | __GFP_ZERO, node_id); @@ -1836,7 +1854,7 @@ request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) init_timer(&q->unplug_timer); - snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue"); + kobject_set_name(&q->kobj, "%s", "queue"); q->kobj.ktype = &queue_ktype; kobject_init(&q->kobj); @@ -1882,16 +1900,16 @@ EXPORT_SYMBOL(blk_alloc_queue_node); * when the block device is deactivated (such as at module unload). **/ -request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock) +struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock) { return blk_init_queue_node(rfn, lock, -1); } EXPORT_SYMBOL(blk_init_queue); -request_queue_t * +struct request_queue * blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) { - request_queue_t *q = blk_alloc_queue_node(GFP_KERNEL, node_id); + struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id); if (!q) return NULL; @@ -1940,7 +1958,7 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) } EXPORT_SYMBOL(blk_init_queue_node); -int blk_get_queue(request_queue_t *q) +int blk_get_queue(struct request_queue *q) { if (likely(!test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) { kobject_get(&q->kobj); @@ -1952,7 +1970,7 @@ int blk_get_queue(request_queue_t *q) EXPORT_SYMBOL(blk_get_queue); -static inline void blk_free_request(request_queue_t *q, struct request *rq) +static inline void blk_free_request(struct request_queue *q, struct request *rq) { if (rq->cmd_flags & REQ_ELVPRIV) elv_put_request(q, rq); @@ -1960,7 +1978,7 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq) } static struct request * -blk_alloc_request(request_queue_t *q, int rw, int priv, gfp_t gfp_mask) +blk_alloc_request(struct request_queue *q, int rw, int priv, gfp_t gfp_mask) { struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask); @@ -1988,7 +2006,7 @@ blk_alloc_request(request_queue_t *q, int rw, int priv, gfp_t gfp_mask) * ioc_batching returns true if the ioc is a valid batching request and * should be given priority access to a request. */ -static inline int ioc_batching(request_queue_t *q, struct io_context *ioc) +static inline int ioc_batching(struct request_queue *q, struct io_context *ioc) { if (!ioc) return 0; @@ -2009,7 +2027,7 @@ static inline int ioc_batching(request_queue_t *q, struct io_context *ioc) * is the behaviour we want though - once it gets a wakeup it should be given * a nice run. */ -static void ioc_set_batching(request_queue_t *q, struct io_context *ioc) +static void ioc_set_batching(struct request_queue *q, struct io_context *ioc) { if (!ioc || ioc_batching(q, ioc)) return; @@ -2018,7 +2036,7 @@ static void ioc_set_batching(request_queue_t *q, struct io_context *ioc) ioc->last_waited = jiffies; } -static void __freed_request(request_queue_t *q, int rw) +static void __freed_request(struct request_queue *q, int rw) { struct request_list *rl = &q->rq; @@ -2037,7 +2055,7 @@ static void __freed_request(request_queue_t *q, int rw) * A request has just been released. Account for it, update the full and * congestion status, wake up any waiters. Called under q->queue_lock. */ -static void freed_request(request_queue_t *q, int rw, int priv) +static void freed_request(struct request_queue *q, int rw, int priv) { struct request_list *rl = &q->rq; @@ -2057,7 +2075,7 @@ static void freed_request(request_queue_t *q, int rw, int priv) * Returns NULL on failure, with queue_lock held. * Returns !NULL on success, with queue_lock *not held*. */ -static struct request *get_request(request_queue_t *q, int rw_flags, +static struct request *get_request(struct request_queue *q, int rw_flags, struct bio *bio, gfp_t gfp_mask) { struct request *rq = NULL; @@ -2162,7 +2180,7 @@ out: * * Called with q->queue_lock held, and returns with it unlocked. */ -static struct request *get_request_wait(request_queue_t *q, int rw_flags, +static struct request *get_request_wait(struct request_queue *q, int rw_flags, struct bio *bio) { const int rw = rw_flags & 0x01; @@ -2204,7 +2222,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw_flags, return rq; } -struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask) +struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) { struct request *rq; @@ -2234,7 +2252,7 @@ EXPORT_SYMBOL(blk_get_request); * * The queue lock must be held with interrupts disabled. */ -void blk_start_queueing(request_queue_t *q) +void blk_start_queueing(struct request_queue *q) { if (!blk_queue_plugged(q)) q->request_fn(q); @@ -2253,7 +2271,7 @@ EXPORT_SYMBOL(blk_start_queueing); * more, when that condition happens we need to put the request back * on the queue. Must be called with queue lock held. */ -void blk_requeue_request(request_queue_t *q, struct request *rq) +void blk_requeue_request(struct request_queue *q, struct request *rq) { blk_add_trace_rq(q, rq, BLK_TA_REQUEUE); @@ -2284,7 +2302,7 @@ EXPORT_SYMBOL(blk_requeue_request); * of the queue for things like a QUEUE_FULL message from a device, or a * host that is unable to accept a particular command. */ -void blk_insert_request(request_queue_t *q, struct request *rq, +void blk_insert_request(struct request_queue *q, struct request *rq, int at_head, void *data) { int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; @@ -2330,7 +2348,24 @@ static int __blk_rq_unmap_user(struct bio *bio) return ret; } -static int __blk_rq_map_user(request_queue_t *q, struct request *rq, +int blk_rq_append_bio(struct request_queue *q, struct request *rq, + struct bio *bio) +{ + if (!rq->bio) + blk_rq_bio_prep(q, rq, bio); + else if (!ll_back_merge_fn(q, rq, bio)) + return -EINVAL; + else { + rq->biotail->bi_next = bio; + rq->biotail = bio; + + rq->data_len += bio->bi_size; + } + return 0; +} +EXPORT_SYMBOL(blk_rq_append_bio); + +static int __blk_rq_map_user(struct request_queue *q, struct request *rq, void __user *ubuf, unsigned int len) { unsigned long uaddr; @@ -2361,23 +2396,12 @@ static int __blk_rq_map_user(request_queue_t *q, struct request *rq, */ bio_get(bio); - if (!rq->bio) - blk_rq_bio_prep(q, rq, bio); - else if (!ll_back_merge_fn(q, rq, bio)) { - ret = -EINVAL; - goto unmap_bio; - } else { - rq->biotail->bi_next = bio; - rq->biotail = bio; - - rq->data_len += bio->bi_size; - } + ret = blk_rq_append_bio(q, rq, bio); + if (!ret) + return bio->bi_size; - return bio->bi_size; - -unmap_bio: /* if it was boucned we must call the end io function */ - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); __blk_rq_unmap_user(orig_bio); bio_put(bio); return ret; @@ -2403,8 +2427,8 @@ unmap_bio: * original bio must be passed back in to blk_rq_unmap_user() for proper * unmapping. */ -int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, - unsigned long len) +int blk_rq_map_user(struct request_queue *q, struct request *rq, + void __user *ubuf, unsigned long len) { unsigned long bytes_read = 0; struct bio *bio = NULL; @@ -2470,7 +2494,7 @@ EXPORT_SYMBOL(blk_rq_map_user); * original bio must be passed back in to blk_rq_unmap_user() for proper * unmapping. */ -int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, +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; @@ -2486,7 +2510,7 @@ int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, return PTR_ERR(bio); if (bio->bi_size != len) { - bio_endio(bio, bio->bi_size, 0); + bio_endio(bio, 0); bio_unmap_user(bio); return -EINVAL; } @@ -2540,7 +2564,7 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * @len: length of user data * @gfp_mask: memory allocation flags */ -int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, +int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, unsigned int len, gfp_t gfp_mask) { struct bio *bio; @@ -2577,7 +2601,7 @@ EXPORT_SYMBOL(blk_rq_map_kern); * Insert a fully prepared request at the back of the io scheduler queue * for execution. Don't wait for completion. */ -void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk, +void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, struct request *rq, int at_head, rq_end_io_fn *done) { @@ -2605,7 +2629,7 @@ EXPORT_SYMBOL_GPL(blk_execute_rq_nowait); * Insert a fully prepared request at the back of the io scheduler queue * for execution and wait for completion. */ -int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, +int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk, struct request *rq, int at_head) { DECLARE_COMPLETION_ONSTACK(wait); @@ -2648,7 +2672,7 @@ EXPORT_SYMBOL(blk_execute_rq); */ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) { - request_queue_t *q; + struct request_queue *q; if (bdev->bd_disk == NULL) return -ENXIO; @@ -2684,7 +2708,7 @@ static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) * queue lock is held and interrupts disabled, as we muck with the * request queue list. */ -static inline void add_request(request_queue_t * q, struct request * req) +static inline void add_request(struct request_queue * q, struct request * req) { drive_stat_acct(req, req->nr_sectors, 1); @@ -2730,7 +2754,7 @@ EXPORT_SYMBOL_GPL(disk_round_stats); /* * queue lock must be held */ -void __blk_put_request(request_queue_t *q, struct request *req) +void __blk_put_request(struct request_queue *q, struct request *req) { if (unlikely(!q)) return; @@ -2760,7 +2784,7 @@ EXPORT_SYMBOL_GPL(__blk_put_request); void blk_put_request(struct request *req) { unsigned long flags; - request_queue_t *q = req->q; + struct request_queue *q = req->q; /* * Gee, IDE calls in w/ NULL q. Fix IDE and remove the @@ -2798,7 +2822,7 @@ EXPORT_SYMBOL(blk_end_sync_rq); /* * Has to be called with the request spinlock acquired */ -static int attempt_merge(request_queue_t *q, struct request *req, +static int attempt_merge(struct request_queue *q, struct request *req, struct request *next) { if (!rq_mergeable(req) || !rq_mergeable(next)) @@ -2851,7 +2875,8 @@ static int attempt_merge(request_queue_t *q, struct request *req, return 1; } -static inline int attempt_back_merge(request_queue_t *q, struct request *rq) +static inline int attempt_back_merge(struct request_queue *q, + struct request *rq) { struct request *next = elv_latter_request(q, rq); @@ -2861,7 +2886,8 @@ static inline int attempt_back_merge(request_queue_t *q, struct request *rq) return 0; } -static inline int attempt_front_merge(request_queue_t *q, struct request *rq) +static inline int attempt_front_merge(struct request_queue *q, + struct request *rq) { struct request *prev = elv_former_request(q, rq); @@ -2894,18 +2920,12 @@ static void init_request_from_bio(struct request *req, struct bio *bio) req->errors = 0; req->hard_sector = req->sector = bio->bi_sector; - req->hard_nr_sectors = req->nr_sectors = bio_sectors(bio); - req->current_nr_sectors = req->hard_cur_sectors = bio_cur_sectors(bio); - req->nr_phys_segments = bio_phys_segments(req->q, bio); - req->nr_hw_segments = bio_hw_segments(req->q, bio); - req->buffer = bio_data(bio); /* see ->buffer comment above */ - req->bio = req->biotail = bio; req->ioprio = bio_prio(bio); - req->rq_disk = bio->bi_bdev->bd_disk; req->start_time = jiffies; + blk_rq_bio_prep(req->q, req, bio); } -static int __make_request(request_queue_t *q, struct bio *bio) +static int __make_request(struct request_queue *q, struct bio *bio) { struct request *req; int el_ret, nr_sectors, barrier, err; @@ -3020,7 +3040,7 @@ out: return 0; end_io: - bio_endio(bio, nr_sectors << 9, err); + bio_endio(bio, err); return 0; } @@ -3040,6 +3060,10 @@ static inline void blk_partition_remap(struct bio *bio) bio->bi_sector += p->start_sect; bio->bi_bdev = bdev->bd_contains; + + blk_add_trace_remap(bdev_get_queue(bio->bi_bdev), bio, + bdev->bd_dev, bio->bi_sector, + bio->bi_sector - p->start_sect); } } @@ -3119,7 +3143,7 @@ static inline int should_fail_request(struct bio *bio) */ static inline void __generic_make_request(struct bio *bio) { - request_queue_t *q; + struct request_queue *q; sector_t maxsector; sector_t old_sector; int ret, nr_sectors = bio_sectors(bio); @@ -3163,7 +3187,7 @@ static inline void __generic_make_request(struct bio *bio) bdevname(bio->bi_bdev, b), (long long) bio->bi_sector); end_io: - bio_endio(bio, bio->bi_size, -EIO); + bio_endio(bio, -EIO); break; } @@ -3307,48 +3331,6 @@ void submit_bio(int rw, struct bio *bio) EXPORT_SYMBOL(submit_bio); -static void blk_recalc_rq_segments(struct request *rq) -{ - struct bio *bio, *prevbio = NULL; - int nr_phys_segs, nr_hw_segs; - unsigned int phys_size, hw_size; - request_queue_t *q = rq->q; - - if (!rq->bio) - return; - - phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0; - rq_for_each_bio(bio, rq) { - /* Force bio hw/phys segs to be recalculated. */ - bio->bi_flags &= ~(1 << BIO_SEG_VALID); - - nr_phys_segs += bio_phys_segments(q, bio); - nr_hw_segs += bio_hw_segments(q, bio); - if (prevbio) { - int pseg = phys_size + prevbio->bi_size + bio->bi_size; - int hseg = hw_size + prevbio->bi_size + bio->bi_size; - - if (blk_phys_contig_segment(q, prevbio, bio) && - pseg <= q->max_segment_size) { - nr_phys_segs--; - phys_size += prevbio->bi_size + bio->bi_size; - } else - phys_size = 0; - - if (blk_hw_contig_segment(q, prevbio, bio) && - hseg <= q->max_segment_size) { - nr_hw_segs--; - hw_size += prevbio->bi_size + bio->bi_size; - } else - hw_size = 0; - } - prevbio = bio; - } - - rq->nr_phys_segments = nr_phys_segs; - rq->nr_hw_segments = nr_hw_segs; -} - static void blk_recalc_rq_sectors(struct request *rq, int nsect) { if (blk_fs_request(rq)) { @@ -3420,8 +3402,7 @@ static int __end_that_request_first(struct request *req, int uptodate, if (nr_bytes >= bio->bi_size) { req->bio = bio->bi_next; nbytes = bio->bi_size; - if (!ordered_bio_endio(req, bio, nbytes, error)) - bio_endio(bio, nbytes, error); + req_bio_endio(req, bio, nbytes, error); next_idx = 0; bio_nbytes = 0; } else { @@ -3476,8 +3457,7 @@ static int __end_that_request_first(struct request *req, int uptodate, * if the request wasn't completed, update state */ if (bio_nbytes) { - if (!ordered_bio_endio(req, bio, bio_nbytes, error)) - bio_endio(bio, bio_nbytes, error); + req_bio_endio(req, bio, bio_nbytes, error); bio->bi_idx += next_idx; bio_iovec(bio)->bv_offset += nr_bytes; bio_iovec(bio)->bv_len -= nr_bytes; @@ -3552,7 +3532,7 @@ static void blk_done_softirq(struct softirq_action *h) } } -static int blk_cpu_notify(struct notifier_block *self, unsigned long action, +static int __cpuinit blk_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { /* @@ -3573,7 +3553,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action, } -static struct notifier_block __devinitdata blk_cpu_notifier = { +static struct notifier_block blk_cpu_notifier __cpuinitdata = { .notifier_call = blk_cpu_notify, }; @@ -3658,7 +3638,8 @@ void end_request(struct request *req, int uptodate) EXPORT_SYMBOL(end_request); -void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio) +static void blk_rq_bio_prep(struct request_queue *q, struct request *rq, + struct bio *bio) { /* first two bits are identical in rq->cmd_flags and bio->bi_rw */ rq->cmd_flags |= (bio->bi_rw & 3); @@ -3672,9 +3653,10 @@ void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio) rq->data_len = bio->bi_size; rq->bio = rq->biotail = bio; -} -EXPORT_SYMBOL(blk_rq_bio_prep); + if (bio->bi_bdev) + rq->rq_disk = bio->bi_bdev->bd_disk; +} int kblockd_schedule_work(struct work_struct *work) { @@ -3698,13 +3680,13 @@ int __init blk_dev_init(void) panic("Failed to create kblockd\n"); request_cachep = kmem_cache_create("blkdev_requests", - sizeof(struct request), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct request), 0, SLAB_PANIC, NULL); requestq_cachep = kmem_cache_create("blkdev_queue", - sizeof(request_queue_t), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct request_queue), 0, SLAB_PANIC, NULL); iocontext_cachep = kmem_cache_create("blkdev_ioc", - sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL); + sizeof(struct io_context), 0, SLAB_PANIC, NULL); for_each_possible_cpu(i) INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); @@ -4021,7 +4003,8 @@ static ssize_t queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page) { struct queue_sysfs_entry *entry = to_queue(attr); - request_queue_t *q = container_of(kobj, struct request_queue, kobj); + struct request_queue *q = + container_of(kobj, struct request_queue, kobj); ssize_t res; if (!entry->show) @@ -4041,7 +4024,7 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr, const char *page, size_t length) { struct queue_sysfs_entry *entry = to_queue(attr); - request_queue_t *q = container_of(kobj, struct request_queue, kobj); + struct request_queue *q = container_of(kobj, struct request_queue, kobj); ssize_t res; @@ -4072,7 +4055,7 @@ int blk_register_queue(struct gendisk *disk) { int ret; - request_queue_t *q = disk->queue; + struct request_queue *q = disk->queue; if (!q || !q->request_fn) return -ENXIO; @@ -4097,7 +4080,7 @@ int blk_register_queue(struct gendisk *disk) void blk_unregister_queue(struct gendisk *disk) { - request_queue_t *q = disk->queue; + struct request_queue *q = disk->queue; if (q && q->request_fn) { elv_unregister_queue(q); diff --git a/block/noop-iosched.c b/block/noop-iosched.c index 1c3de2b9a6b..7563d8aa394 100644 --- a/block/noop-iosched.c +++ b/block/noop-iosched.c @@ -11,13 +11,13 @@ struct noop_data { struct list_head queue; }; -static void noop_merged_requests(request_queue_t *q, struct request *rq, +static void noop_merged_requests(struct request_queue *q, struct request *rq, struct request *next) { list_del_init(&next->queuelist); } -static int noop_dispatch(request_queue_t *q, int force) +static int noop_dispatch(struct request_queue *q, int force) { struct noop_data *nd = q->elevator->elevator_data; @@ -31,14 +31,14 @@ static int noop_dispatch(request_queue_t *q, int force) return 0; } -static void noop_add_request(request_queue_t *q, struct request *rq) +static void noop_add_request(struct request_queue *q, struct request *rq) { struct noop_data *nd = q->elevator->elevator_data; list_add_tail(&rq->queuelist, &nd->queue); } -static int noop_queue_empty(request_queue_t *q) +static int noop_queue_empty(struct request_queue *q) { struct noop_data *nd = q->elevator->elevator_data; @@ -46,7 +46,7 @@ static int noop_queue_empty(request_queue_t *q) } static struct request * -noop_former_request(request_queue_t *q, struct request *rq) +noop_former_request(struct request_queue *q, struct request *rq) { struct noop_data *nd = q->elevator->elevator_data; @@ -56,7 +56,7 @@ noop_former_request(request_queue_t *q, struct request *rq) } static struct request * -noop_latter_request(request_queue_t *q, struct request *rq) +noop_latter_request(struct request_queue *q, struct request *rq) { struct noop_data *nd = q->elevator->elevator_data; @@ -65,7 +65,7 @@ noop_latter_request(request_queue_t *q, struct request *rq) return list_entry(rq->queuelist.next, struct request, queuelist); } -static void *noop_init_queue(request_queue_t *q) +static void *noop_init_queue(struct request_queue *q) { struct noop_data *nd; diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index a26ba07955f..91c73224f4c 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -49,22 +49,22 @@ static int sg_get_version(int __user *p) return put_user(sg_version_num, p); } -static int scsi_get_idlun(request_queue_t *q, int __user *p) +static int scsi_get_idlun(struct request_queue *q, int __user *p) { return put_user(0, p); } -static int scsi_get_bus(request_queue_t *q, int __user *p) +static int scsi_get_bus(struct request_queue *q, int __user *p) { return put_user(0, p); } -static int sg_get_timeout(request_queue_t *q) +static int sg_get_timeout(struct request_queue *q) { return q->sg_timeout / (HZ / USER_HZ); } -static int sg_set_timeout(request_queue_t *q, int __user *p) +static int sg_set_timeout(struct request_queue *q, int __user *p) { int timeout, err = get_user(timeout, p); @@ -74,14 +74,14 @@ static int sg_set_timeout(request_queue_t *q, int __user *p) return err; } -static int sg_get_reserved_size(request_queue_t *q, int __user *p) +static int sg_get_reserved_size(struct request_queue *q, int __user *p) { unsigned val = min(q->sg_reserved_size, q->max_sectors << 9); return put_user(val, p); } -static int sg_set_reserved_size(request_queue_t *q, int __user *p) +static int sg_set_reserved_size(struct request_queue *q, int __user *p) { int size, err = get_user(size, p); @@ -101,7 +101,7 @@ static int sg_set_reserved_size(request_queue_t *q, int __user *p) * will always return that we are ATAPI even for a real SCSI drive, I'm not * so sure this is worth doing anything about (why would you care??) */ -static int sg_emulated_host(request_queue_t *q, int __user *p) +static int sg_emulated_host(struct request_queue *q, int __user *p) { return put_user(1, p); } @@ -214,8 +214,8 @@ int blk_verify_command(unsigned char *cmd, int has_write_perm) } EXPORT_SYMBOL_GPL(blk_verify_command); -int blk_fill_sghdr_rq(request_queue_t *q, struct request *rq, - struct sg_io_hdr *hdr, int has_write_perm) +static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, + struct sg_io_hdr *hdr, int has_write_perm) { memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ @@ -238,22 +238,20 @@ int blk_fill_sghdr_rq(request_queue_t *q, struct request *rq, return 0; } -EXPORT_SYMBOL_GPL(blk_fill_sghdr_rq); /* * unmap a request that was previously mapped to this sg_io_hdr. handles * both sg and non-sg sg_io_hdr. */ -int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr) +static int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr) { blk_rq_unmap_user(rq->bio); blk_put_request(rq); return 0; } -EXPORT_SYMBOL_GPL(blk_unmap_sghdr_rq); -int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, - struct bio *bio) +static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, + struct bio *bio) { int r, ret = 0; @@ -287,9 +285,8 @@ int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, return r; } -EXPORT_SYMBOL_GPL(blk_complete_sghdr_rq); -static int sg_io(struct file *file, request_queue_t *q, +static int sg_io(struct file *file, struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; @@ -436,11 +433,10 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, bytes = max(in_len, out_len); if (bytes) { - buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); + buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); if (!buffer) return -ENOMEM; - memset(buffer, 0, bytes); } rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT); @@ -523,7 +519,8 @@ error: EXPORT_SYMBOL_GPL(sg_scsi_ioctl); /* Send basic block requests */ -static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int cmd, int data) +static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, + int cmd, int data) { struct request *rq; int err; @@ -543,7 +540,8 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c return err; } -static inline int blk_send_start_stop(request_queue_t *q, struct gendisk *bd_disk, int data) +static inline int blk_send_start_stop(struct request_queue *q, + struct gendisk *bd_disk, int data) { return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); } |