Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block: block: restore multiple bd_link_disk_holder() support block cfq: compensate preempted queue even if it has no slice assigned block cfq: make queue preempt work for queues from different workload
This commit is contained in:
commit
6ab8219649
5 changed files with 110 additions and 25 deletions
|
|
@ -598,8 +598,8 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg)
|
||||||
return cfq_target_latency * cfqg->weight / st->total_weight;
|
return cfq_target_latency * cfqg->weight / st->total_weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline unsigned
|
||||||
cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
||||||
{
|
{
|
||||||
unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
|
unsigned slice = cfq_prio_to_slice(cfqd, cfqq);
|
||||||
if (cfqd->cfq_latency) {
|
if (cfqd->cfq_latency) {
|
||||||
|
|
@ -625,6 +625,14 @@ cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
||||||
low_slice);
|
low_slice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
||||||
|
{
|
||||||
|
unsigned slice = cfq_scaled_group_slice(cfqd, cfqq);
|
||||||
|
|
||||||
cfqq->slice_start = jiffies;
|
cfqq->slice_start = jiffies;
|
||||||
cfqq->slice_end = jiffies + slice;
|
cfqq->slice_end = jiffies + slice;
|
||||||
cfqq->allocated_slice = slice;
|
cfqq->allocated_slice = slice;
|
||||||
|
|
@ -1661,8 +1669,11 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
|
||||||
/*
|
/*
|
||||||
* store what was left of this slice, if the queue idled/timed out
|
* store what was left of this slice, if the queue idled/timed out
|
||||||
*/
|
*/
|
||||||
if (timed_out && !cfq_cfqq_slice_new(cfqq)) {
|
if (timed_out) {
|
||||||
cfqq->slice_resid = cfqq->slice_end - jiffies;
|
if (cfq_cfqq_slice_new(cfqq))
|
||||||
|
cfqq->slice_resid = cfq_scaled_group_slice(cfqd, cfqq);
|
||||||
|
else
|
||||||
|
cfqq->slice_resid = cfqq->slice_end - jiffies;
|
||||||
cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
|
cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3284,9 +3295,18 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
|
||||||
*/
|
*/
|
||||||
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
||||||
{
|
{
|
||||||
|
struct cfq_queue *old_cfqq = cfqd->active_queue;
|
||||||
|
|
||||||
cfq_log_cfqq(cfqd, cfqq, "preempt");
|
cfq_log_cfqq(cfqd, cfqq, "preempt");
|
||||||
cfq_slice_expired(cfqd, 1);
|
cfq_slice_expired(cfqd, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* workload type is changed, don't save slice, otherwise preempt
|
||||||
|
* doesn't happen
|
||||||
|
*/
|
||||||
|
if (cfqq_type(old_cfqq) != cfqq_type(cfqq))
|
||||||
|
cfqq->cfqg->saved_workload_slice = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put the new queue at the front of the of the current list,
|
* Put the new queue at the front of the of the current list,
|
||||||
* so we know that it will be selected next.
|
* so we know that it will be selected next.
|
||||||
|
|
|
||||||
|
|
@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md)
|
||||||
if (!d->dm_dev.bdev)
|
if (!d->dm_dev.bdev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md));
|
||||||
blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
|
blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL);
|
||||||
d->dm_dev.bdev = NULL;
|
d->dm_dev.bdev = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
|
||||||
MD_BUG();
|
MD_BUG();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
|
||||||
list_del_rcu(&rdev->same_set);
|
list_del_rcu(&rdev->same_set);
|
||||||
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
|
printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
|
||||||
rdev->mddev = NULL;
|
rdev->mddev = NULL;
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,9 @@ static void init_once(void *foo)
|
||||||
mutex_init(&bdev->bd_mutex);
|
mutex_init(&bdev->bd_mutex);
|
||||||
INIT_LIST_HEAD(&bdev->bd_inodes);
|
INIT_LIST_HEAD(&bdev->bd_inodes);
|
||||||
INIT_LIST_HEAD(&bdev->bd_list);
|
INIT_LIST_HEAD(&bdev->bd_list);
|
||||||
|
#ifdef CONFIG_SYSFS
|
||||||
|
INIT_LIST_HEAD(&bdev->bd_holder_disks);
|
||||||
|
#endif
|
||||||
inode_init_once(&ei->vfs_inode);
|
inode_init_once(&ei->vfs_inode);
|
||||||
/* Initialize mutex for freeze. */
|
/* Initialize mutex for freeze. */
|
||||||
mutex_init(&bdev->bd_fsfreeze_mutex);
|
mutex_init(&bdev->bd_fsfreeze_mutex);
|
||||||
|
|
@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
|
struct bd_holder_disk {
|
||||||
|
struct list_head list;
|
||||||
|
struct gendisk *disk;
|
||||||
|
int refcnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev,
|
||||||
|
struct gendisk *disk)
|
||||||
|
{
|
||||||
|
struct bd_holder_disk *holder;
|
||||||
|
|
||||||
|
list_for_each_entry(holder, &bdev->bd_holder_disks, list)
|
||||||
|
if (holder->disk == disk)
|
||||||
|
return holder;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int add_symlink(struct kobject *from, struct kobject *to)
|
static int add_symlink(struct kobject *from, struct kobject *to)
|
||||||
{
|
{
|
||||||
return sysfs_create_link(from, to, kobject_name(to));
|
return sysfs_create_link(from, to, kobject_name(to));
|
||||||
|
|
@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to)
|
||||||
* @bdev: the claimed slave bdev
|
* @bdev: the claimed slave bdev
|
||||||
* @disk: the holding disk
|
* @disk: the holding disk
|
||||||
*
|
*
|
||||||
|
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
|
||||||
|
*
|
||||||
* This functions creates the following sysfs symlinks.
|
* This functions creates the following sysfs symlinks.
|
||||||
*
|
*
|
||||||
* - from "slaves" directory of the holder @disk to the claimed @bdev
|
* - from "slaves" directory of the holder @disk to the claimed @bdev
|
||||||
|
|
@ -817,47 +839,83 @@ static void del_symlink(struct kobject *from, struct kobject *to)
|
||||||
*/
|
*/
|
||||||
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
|
int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk)
|
||||||
{
|
{
|
||||||
|
struct bd_holder_disk *holder;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&bdev->bd_mutex);
|
mutex_lock(&bdev->bd_mutex);
|
||||||
|
|
||||||
WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk);
|
WARN_ON_ONCE(!bdev->bd_holder);
|
||||||
|
|
||||||
/* FIXME: remove the following once add_disk() handles errors */
|
/* FIXME: remove the following once add_disk() handles errors */
|
||||||
if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
|
if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
|
holder = bd_find_holder_disk(bdev, disk);
|
||||||
if (ret)
|
if (holder) {
|
||||||
goto out_unlock;
|
holder->refcnt++;
|
||||||
|
|
||||||
ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
|
|
||||||
if (ret) {
|
|
||||||
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
|
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
bdev->bd_holder_disk = disk;
|
holder = kzalloc(sizeof(*holder), GFP_KERNEL);
|
||||||
|
if (!holder) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&holder->list);
|
||||||
|
holder->disk = disk;
|
||||||
|
holder->refcnt = 1;
|
||||||
|
|
||||||
|
ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
|
||||||
|
if (ret)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
|
||||||
|
if (ret)
|
||||||
|
goto out_del;
|
||||||
|
|
||||||
|
list_add(&holder->list, &bdev->bd_holder_disks);
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
out_del:
|
||||||
|
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
|
||||||
|
out_free:
|
||||||
|
kfree(holder);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&bdev->bd_mutex);
|
mutex_unlock(&bdev->bd_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
|
EXPORT_SYMBOL_GPL(bd_link_disk_holder);
|
||||||
|
|
||||||
static void bd_unlink_disk_holder(struct block_device *bdev)
|
/**
|
||||||
|
* bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder()
|
||||||
|
* @bdev: the calimed slave bdev
|
||||||
|
* @disk: the holding disk
|
||||||
|
*
|
||||||
|
* DON'T USE THIS UNLESS YOU'RE ALREADY USING IT.
|
||||||
|
*
|
||||||
|
* CONTEXT:
|
||||||
|
* Might sleep.
|
||||||
|
*/
|
||||||
|
void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
|
||||||
{
|
{
|
||||||
struct gendisk *disk = bdev->bd_holder_disk;
|
struct bd_holder_disk *holder;
|
||||||
|
|
||||||
bdev->bd_holder_disk = NULL;
|
mutex_lock(&bdev->bd_mutex);
|
||||||
if (!disk)
|
|
||||||
return;
|
|
||||||
|
|
||||||
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
|
holder = bd_find_holder_disk(bdev, disk);
|
||||||
del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj);
|
|
||||||
|
if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
|
||||||
|
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj);
|
||||||
|
del_symlink(bdev->bd_part->holder_dir,
|
||||||
|
&disk_to_dev(disk)->kobj);
|
||||||
|
list_del_init(&holder->list);
|
||||||
|
kfree(holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&bdev->bd_mutex);
|
||||||
}
|
}
|
||||||
#else
|
EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
|
||||||
static inline void bd_unlink_disk_holder(struct block_device *bdev)
|
|
||||||
{ }
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode)
|
||||||
* unblock evpoll if it was a write holder.
|
* unblock evpoll if it was a write holder.
|
||||||
*/
|
*/
|
||||||
if (bdev_free) {
|
if (bdev_free) {
|
||||||
bd_unlink_disk_holder(bdev);
|
|
||||||
if (bdev->bd_write_holder) {
|
if (bdev->bd_write_holder) {
|
||||||
disk_unblock_events(bdev->bd_disk);
|
disk_unblock_events(bdev->bd_disk);
|
||||||
bdev->bd_write_holder = false;
|
bdev->bd_write_holder = false;
|
||||||
|
|
|
||||||
|
|
@ -666,7 +666,7 @@ struct block_device {
|
||||||
int bd_holders;
|
int bd_holders;
|
||||||
bool bd_write_holder;
|
bool bd_write_holder;
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
struct gendisk * bd_holder_disk; /* for sysfs slave linkng */
|
struct list_head bd_holder_disks;
|
||||||
#endif
|
#endif
|
||||||
struct block_device * bd_contains;
|
struct block_device * bd_contains;
|
||||||
unsigned bd_block_size;
|
unsigned bd_block_size;
|
||||||
|
|
@ -2057,12 +2057,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode,
|
||||||
extern int blkdev_put(struct block_device *bdev, fmode_t mode);
|
extern int blkdev_put(struct block_device *bdev, fmode_t mode);
|
||||||
#ifdef CONFIG_SYSFS
|
#ifdef CONFIG_SYSFS
|
||||||
extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
|
extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
|
||||||
|
extern void bd_unlink_disk_holder(struct block_device *bdev,
|
||||||
|
struct gendisk *disk);
|
||||||
#else
|
#else
|
||||||
static inline int bd_link_disk_holder(struct block_device *bdev,
|
static inline int bd_link_disk_holder(struct block_device *bdev,
|
||||||
struct gendisk *disk)
|
struct gendisk *disk)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline void bd_unlink_disk_holder(struct block_device *bdev,
|
||||||
|
struct gendisk *disk)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue