Commit 6ab82196 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 6f7f7caa 49731baa
...@@ -598,8 +598,8 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) {
holder->refcnt++;
goto out_unlock; goto out_unlock;
}
ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); holder = kzalloc(sizeof(*holder), GFP_KERNEL);
if (ret) { if (!holder) {
del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); ret = -ENOMEM;
goto out_unlock; goto out_unlock;
} }
bdev->bd_holder_disk = disk; 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) ...@@ -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 { ...@@ -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, ...@@ -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
......
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