Messages in this thread Patch in this message | | | Date | Mon, 26 Jul 2004 12:15:36 +0200 | From | Ingo Molnar <> | Subject | Re: [patch] voluntary-preempt-2.6.8-rc2-J4 |
| |
> Changes since -J3: > > - make block device max_sectors sysfs tunable. There's a new entry > /sys/block/*/queue/max_sectors_kb which stores the current max > request size in KB. You can write it to change the size. > > Jens: i've attached a standalone patch against 2.6.8-rc2 below. > Please apply if it looks good to you. (I've added extra locking to > make sure max_sectors and readahead_pages gets updated at once, for > the unlikely event of two CPUs updating max_sectors at once.) I've > tested this on IDE using the UP kernel.
i've refined the patch (new version attached below): drivers use blk_queue_max_sectors() to set the maximum # of sectors that the driver or hw can handle.
so i've introduced a new queue entry called max_hw_sectors, and the new /sys entry listens to this maximum and only updates max_sectors. This entry is also exported to /sys as a readonly entry. (so that users can see the maximum the driver supports.)
i've added another fix as well: do not allow users to set a max_sectors value lower than the pagecache page size.
these changes should make the new tunable pretty fool-proof.
Ingo
Signed-off-by: Ingo Molnar <mingo@elte.hu>
--- linux/include/linux/blkdev.h.orig +++ linux/include/linux/blkdev.h @@ -338,6 +338,7 @@ struct request_queue unsigned int nr_congestion_off; unsigned short max_sectors; + unsigned short max_hw_sectors; unsigned short max_phys_segments; unsigned short max_hw_segments; unsigned short hardsect_size; --- linux/drivers/block/ll_rw_blk.c.orig +++ linux/drivers/block/ll_rw_blk.c @@ -311,7 +311,7 @@ void blk_queue_max_sectors(request_queue printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors); } - q->max_sectors = max_sectors; + q->max_sectors = q->max_hw_sectors = max_sectors; } EXPORT_SYMBOL(blk_queue_max_sectors); @@ -3062,13 +3063,61 @@ queue_ra_store(struct request_queue *q, unsigned long ra_kb; ssize_t ret = queue_var_store(&ra_kb, page, count); + spin_lock_irq(q->queue_lock); if (ra_kb > (q->max_sectors >> 1)) ra_kb = (q->max_sectors >> 1); q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10); + spin_unlock_irq(q->queue_lock); + return ret; } +static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) +{ + int max_sectors_kb = q->max_sectors >> 1; + + return queue_var_show(max_sectors_kb, (page)); +} + +static ssize_t +queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) +{ + unsigned long max_sectors_kb, + max_hw_sectors_kb = q->max_hw_sectors >> 1, + page_kb = 1 << (PAGE_CACHE_SHIFT - 10); + ssize_t ret = queue_var_store(&max_sectors_kb, page, count); + int ra_kb; + + if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) + return -EINVAL; + /* + * Take the queue lock to update the readahead and max_sectors + * values synchronously: + */ + spin_lock_irq(q->queue_lock); + /* + * Trim readahead window as well, if necessary: + */ + ra_kb = q->backing_dev_info.ra_pages << (PAGE_CACHE_SHIFT - 10); + if (ra_kb > max_sectors_kb) + q->backing_dev_info.ra_pages = + max_sectors_kb >> (PAGE_CACHE_SHIFT - 10); + + q->max_sectors = max_sectors_kb << 1; + spin_unlock_irq(q->queue_lock); + + return ret; +} + +static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page) +{ + int max_hw_sectors_kb = q->max_hw_sectors >> 1; + + return queue_var_show(max_hw_sectors_kb, (page)); +} + + static struct queue_sysfs_entry queue_requests_entry = { .attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR }, .show = queue_requests_show, @@ -3081,9 +3130,22 @@ static struct queue_sysfs_entry queue_ra .store = queue_ra_store, }; +static struct queue_sysfs_entry queue_max_sectors_entry = { + .attr = {.name = "max_sectors_kb", .mode = S_IRUGO | S_IWUSR }, + .show = queue_max_sectors_show, + .store = queue_max_sectors_store, +}; + +static struct queue_sysfs_entry queue_max_hw_sectors_entry = { + .attr = {.name = "max_hw_sectors_kb", .mode = S_IRUGO }, + .show = queue_max_hw_sectors_show, +}; + static struct attribute *default_attrs[] = { &queue_requests_entry.attr, &queue_ra_entry.attr, + &queue_max_hw_sectors_entry.attr, + &queue_max_sectors_entry.attr, NULL, }; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |