Commit 8261c271 authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] make loop set right queue restrictions

This makes loop honor the queue restrictions by basically stacking all
of those, and mirroring the merge_bvec_fn() on the target queue. It also
switches loop to use per-loop device queues, since that is the only sane
way to do this from a performance POV. Also, in principle I find it to
be much nicer if every distinct block device has its own queue.
parent cc27d75d
......@@ -500,15 +500,13 @@ bio_transfer(struct loop_device *lo, struct bio *to_bio,
static int loop_make_request(request_queue_t *q, struct bio *old_bio)
{
struct bio *new_bio = NULL;
struct loop_device *lo;
struct loop_device *lo = q->queuedata;
unsigned long IV;
int rw = bio_rw(old_bio);
int unit = minor(to_kdev_t(old_bio->bi_bdev->bd_dev));
if (unit >= max_loop)
if (!lo)
goto out;
lo = &loop_dev[unit];
spin_lock_irq(&lo->lo_lock);
if (lo->lo_state != Lo_bound)
goto inactive;
......@@ -712,6 +710,29 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
set_blocksize(bdev, block_size(lo_device));
lo->lo_bio = lo->lo_biotail = NULL;
/*
* set queue make_request_fn, and add limits based on lower level
* device
*/
blk_queue_make_request(&lo->lo_queue, loop_make_request);
blk_queue_bounce_limit(&lo->lo_queue, BLK_BOUNCE_HIGH);
lo->lo_queue.queuedata = lo;
/*
* we remap to a block device, make sure we correctly stack limits
*/
if (S_ISBLK(inode->i_mode)) {
request_queue_t *q = bdev_get_queue(lo_device);
blk_queue_max_sectors(&lo->lo_queue, q->max_sectors);
blk_queue_max_phys_segments(&lo->lo_queue,q->max_phys_segments);
blk_queue_max_hw_segments(&lo->lo_queue, q->max_hw_segments);
blk_queue_max_segment_size(&lo->lo_queue, q->max_segment_size);
blk_queue_segment_boundary(&lo->lo_queue, q->seg_boundary_mask);
blk_queue_merge_bvec(&lo->lo_queue, q->merge_bvec_fn);
}
kernel_thread(loop_thread, lo, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
down(&lo->lo_sem);
......@@ -991,6 +1012,16 @@ int loop_unregister_transfer(int number)
EXPORT_SYMBOL(loop_register_transfer);
EXPORT_SYMBOL(loop_unregister_transfer);
request_queue_t *loop_get_queue(kdev_t dev)
{
int minor = minor(dev);
if (minor < max_loop)
return &loop_dev[minor].lo_queue;
return NULL;
}
int __init loop_init(void)
{
int i;
......@@ -1023,9 +1054,6 @@ int __init loop_init(void)
names = kmalloc(max_loop * 8, GFP_KERNEL);
blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), loop_make_request);
blk_queue_bounce_limit(BLK_DEFAULT_QUEUE(MAJOR_NR), BLK_BOUNCE_HIGH);
for (i = 0; i < max_loop; i++) {
struct loop_device *lo = &loop_dev[i];
struct gendisk *disk = disks + i;
......@@ -1044,6 +1072,8 @@ int __init loop_init(void)
add_disk(disk);
}
blk_dev[LOOP_MAJOR].queue = loop_get_queue;
printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
return 0;
......
......@@ -56,6 +56,8 @@ struct loop_device {
struct semaphore lo_ctl_mutex;
struct semaphore lo_bh_mutex;
atomic_t lo_pending;
request_queue_t lo_queue;
};
typedef int (* transfer_proc_t)(struct loop_device *, int cmd,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment