diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-14 16:32:07 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-14 16:32:07 -0500 |
commit | 6ab82196492a0b6968a654a06aae923b28afef0d (patch) | |
tree | 8affe1097bba194fe677d5399f47693dc0363dd8 | |
parent | 6f7f7caab259026234277b659485d22c1dcb1ab4 (diff) | |
parent | 49731baa41df404c2c3f44555869ab387363af43 (diff) |
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
-rw-r--r-- | block/cfq-iosched.c | 28 | ||||
-rw-r--r-- | drivers/md/dm-table.c | 1 | ||||
-rw-r--r-- | drivers/md/md.c | 1 | ||||
-rw-r--r-- | fs/block_dev.c | 93 | ||||
-rw-r--r-- | include/linux/fs.h | 8 |
5 files changed, 108 insertions, 23 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 8427697c5437..501ffdf0399c 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -598,8 +598,8 @@ cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg) | |||
598 | return cfq_target_latency * cfqg->weight / st->total_weight; | 598 | return cfq_target_latency * cfqg->weight / st->total_weight; |
599 | } | 599 | } |
600 | 600 | ||
601 | static inline void | 601 | static inline unsigned |
602 | cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 602 | cfq_scaled_group_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
603 | { | 603 | { |
604 | unsigned slice = cfq_prio_to_slice(cfqd, cfqq); | 604 | unsigned slice = cfq_prio_to_slice(cfqd, cfqq); |
605 | if (cfqd->cfq_latency) { | 605 | if (cfqd->cfq_latency) { |
@@ -625,6 +625,14 @@ cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
625 | low_slice); | 625 | low_slice); |
626 | } | 626 | } |
627 | } | 627 | } |
628 | return slice; | ||
629 | } | ||
630 | |||
631 | static inline void | ||
632 | cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) | ||
633 | { | ||
634 | unsigned slice = cfq_scaled_group_slice(cfqd, cfqq); | ||
635 | |||
628 | cfqq->slice_start = jiffies; | 636 | cfqq->slice_start = jiffies; |
629 | cfqq->slice_end = jiffies + slice; | 637 | cfqq->slice_end = jiffies + slice; |
630 | cfqq->allocated_slice = slice; | 638 | cfqq->allocated_slice = slice; |
@@ -1661,8 +1669,11 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
1661 | /* | 1669 | /* |
1662 | * store what was left of this slice, if the queue idled/timed out | 1670 | * store what was left of this slice, if the queue idled/timed out |
1663 | */ | 1671 | */ |
1664 | if (timed_out && !cfq_cfqq_slice_new(cfqq)) { | 1672 | if (timed_out) { |
1665 | cfqq->slice_resid = cfqq->slice_end - jiffies; | 1673 | if (cfq_cfqq_slice_new(cfqq)) |
1674 | cfqq->slice_resid = cfq_scaled_group_slice(cfqd, cfqq); | ||
1675 | else | ||
1676 | cfqq->slice_resid = cfqq->slice_end - jiffies; | ||
1666 | cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid); | 1677 | cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid); |
1667 | } | 1678 | } |
1668 | 1679 | ||
@@ -3284,10 +3295,19 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, | |||
3284 | */ | 3295 | */ |
3285 | static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 3296 | static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
3286 | { | 3297 | { |
3298 | struct cfq_queue *old_cfqq = cfqd->active_queue; | ||
3299 | |||
3287 | cfq_log_cfqq(cfqd, cfqq, "preempt"); | 3300 | cfq_log_cfqq(cfqd, cfqq, "preempt"); |
3288 | cfq_slice_expired(cfqd, 1); | 3301 | cfq_slice_expired(cfqd, 1); |
3289 | 3302 | ||
3290 | /* | 3303 | /* |
3304 | * workload type is changed, don't save slice, otherwise preempt | ||
3305 | * doesn't happen | ||
3306 | */ | ||
3307 | if (cfqq_type(old_cfqq) != cfqq_type(cfqq)) | ||
3308 | cfqq->cfqg->saved_workload_slice = 0; | ||
3309 | |||
3310 | /* | ||
3291 | * Put the new queue at the front of the of the current list, | 3311 | * Put the new queue at the front of the of the current list, |
3292 | * so we know that it will be selected next. | 3312 | * so we know that it will be selected next. |
3293 | */ | 3313 | */ |
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index dffa0ac7c4f0..38e4eb1bb965 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c | |||
@@ -350,6 +350,7 @@ static void close_dev(struct dm_dev_internal *d, struct mapped_device *md) | |||
350 | if (!d->dm_dev.bdev) | 350 | if (!d->dm_dev.bdev) |
351 | return; | 351 | return; |
352 | 352 | ||
353 | bd_unlink_disk_holder(d->dm_dev.bdev, dm_disk(md)); | ||
353 | blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL); | 354 | blkdev_put(d->dm_dev.bdev, d->dm_dev.mode | FMODE_EXCL); |
354 | d->dm_dev.bdev = NULL; | 355 | d->dm_dev.bdev = NULL; |
355 | } | 356 | } |
diff --git a/drivers/md/md.c b/drivers/md/md.c index cf8594c5ea21..b76cfc89e1b5 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1912,6 +1912,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) | |||
1912 | MD_BUG(); | 1912 | MD_BUG(); |
1913 | return; | 1913 | return; |
1914 | } | 1914 | } |
1915 | bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk); | ||
1915 | list_del_rcu(&rdev->same_set); | 1916 | list_del_rcu(&rdev->same_set); |
1916 | printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); | 1917 | printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); |
1917 | rdev->mddev = NULL; | 1918 | rdev->mddev = NULL; |
diff --git a/fs/block_dev.c b/fs/block_dev.c index fe3f59c14a02..333a7bb4cb9c 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -432,6 +432,9 @@ static void init_once(void *foo) | |||
432 | mutex_init(&bdev->bd_mutex); | 432 | mutex_init(&bdev->bd_mutex); |
433 | INIT_LIST_HEAD(&bdev->bd_inodes); | 433 | INIT_LIST_HEAD(&bdev->bd_inodes); |
434 | INIT_LIST_HEAD(&bdev->bd_list); | 434 | INIT_LIST_HEAD(&bdev->bd_list); |
435 | #ifdef CONFIG_SYSFS | ||
436 | INIT_LIST_HEAD(&bdev->bd_holder_disks); | ||
437 | #endif | ||
435 | inode_init_once(&ei->vfs_inode); | 438 | inode_init_once(&ei->vfs_inode); |
436 | /* Initialize mutex for freeze. */ | 439 | /* Initialize mutex for freeze. */ |
437 | mutex_init(&bdev->bd_fsfreeze_mutex); | 440 | mutex_init(&bdev->bd_fsfreeze_mutex); |
@@ -779,6 +782,23 @@ static struct block_device *bd_start_claiming(struct block_device *bdev, | |||
779 | } | 782 | } |
780 | 783 | ||
781 | #ifdef CONFIG_SYSFS | 784 | #ifdef CONFIG_SYSFS |
785 | struct bd_holder_disk { | ||
786 | struct list_head list; | ||
787 | struct gendisk *disk; | ||
788 | int refcnt; | ||
789 | }; | ||
790 | |||
791 | static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev, | ||
792 | struct gendisk *disk) | ||
793 | { | ||
794 | struct bd_holder_disk *holder; | ||
795 | |||
796 | list_for_each_entry(holder, &bdev->bd_holder_disks, list) | ||
797 | if (holder->disk == disk) | ||
798 | return holder; | ||
799 | return NULL; | ||
800 | } | ||
801 | |||
782 | static int add_symlink(struct kobject *from, struct kobject *to) | 802 | static int add_symlink(struct kobject *from, struct kobject *to) |
783 | { | 803 | { |
784 | return sysfs_create_link(from, to, kobject_name(to)); | 804 | return sysfs_create_link(from, to, kobject_name(to)); |
@@ -794,6 +814,8 @@ static void del_symlink(struct kobject *from, struct kobject *to) | |||
794 | * @bdev: the claimed slave bdev | 814 | * @bdev: the claimed slave bdev |
795 | * @disk: the holding disk | 815 | * @disk: the holding disk |
796 | * | 816 | * |
817 | * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. | ||
818 | * | ||
797 | * This functions creates the following sysfs symlinks. | 819 | * This functions creates the following sysfs symlinks. |
798 | * | 820 | * |
799 | * - from "slaves" directory of the holder @disk to the claimed @bdev | 821 | * - 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 | */ | 839 | */ |
818 | int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) | 840 | int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) |
819 | { | 841 | { |
842 | struct bd_holder_disk *holder; | ||
820 | int ret = 0; | 843 | int ret = 0; |
821 | 844 | ||
822 | mutex_lock(&bdev->bd_mutex); | 845 | mutex_lock(&bdev->bd_mutex); |
823 | 846 | ||
824 | WARN_ON_ONCE(!bdev->bd_holder || bdev->bd_holder_disk); | 847 | WARN_ON_ONCE(!bdev->bd_holder); |
825 | 848 | ||
826 | /* FIXME: remove the following once add_disk() handles errors */ | 849 | /* FIXME: remove the following once add_disk() handles errors */ |
827 | if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) | 850 | if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) |
828 | goto out_unlock; | 851 | goto out_unlock; |
829 | 852 | ||
830 | ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | 853 | holder = bd_find_holder_disk(bdev, disk); |
831 | if (ret) | 854 | if (holder) { |
855 | holder->refcnt++; | ||
832 | goto out_unlock; | 856 | goto out_unlock; |
857 | } | ||
833 | 858 | ||
834 | ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); | 859 | holder = kzalloc(sizeof(*holder), GFP_KERNEL); |
835 | if (ret) { | 860 | if (!holder) { |
836 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | 861 | ret = -ENOMEM; |
837 | goto out_unlock; | 862 | goto out_unlock; |
838 | } | 863 | } |
839 | 864 | ||
840 | bdev->bd_holder_disk = disk; | 865 | INIT_LIST_HEAD(&holder->list); |
866 | holder->disk = disk; | ||
867 | holder->refcnt = 1; | ||
868 | |||
869 | ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | ||
870 | if (ret) | ||
871 | goto out_free; | ||
872 | |||
873 | ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); | ||
874 | if (ret) | ||
875 | goto out_del; | ||
876 | |||
877 | list_add(&holder->list, &bdev->bd_holder_disks); | ||
878 | goto out_unlock; | ||
879 | |||
880 | out_del: | ||
881 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | ||
882 | out_free: | ||
883 | kfree(holder); | ||
841 | out_unlock: | 884 | out_unlock: |
842 | mutex_unlock(&bdev->bd_mutex); | 885 | mutex_unlock(&bdev->bd_mutex); |
843 | return ret; | 886 | return ret; |
844 | } | 887 | } |
845 | EXPORT_SYMBOL_GPL(bd_link_disk_holder); | 888 | EXPORT_SYMBOL_GPL(bd_link_disk_holder); |
846 | 889 | ||
847 | static void bd_unlink_disk_holder(struct block_device *bdev) | 890 | /** |
891 | * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder() | ||
892 | * @bdev: the calimed slave bdev | ||
893 | * @disk: the holding disk | ||
894 | * | ||
895 | * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. | ||
896 | * | ||
897 | * CONTEXT: | ||
898 | * Might sleep. | ||
899 | */ | ||
900 | void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) | ||
848 | { | 901 | { |
849 | struct gendisk *disk = bdev->bd_holder_disk; | 902 | struct bd_holder_disk *holder; |
850 | 903 | ||
851 | bdev->bd_holder_disk = NULL; | 904 | mutex_lock(&bdev->bd_mutex); |
852 | if (!disk) | ||
853 | return; | ||
854 | 905 | ||
855 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | 906 | holder = bd_find_holder_disk(bdev, disk); |
856 | del_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); | 907 | |
908 | if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) { | ||
909 | del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); | ||
910 | del_symlink(bdev->bd_part->holder_dir, | ||
911 | &disk_to_dev(disk)->kobj); | ||
912 | list_del_init(&holder->list); | ||
913 | kfree(holder); | ||
914 | } | ||
915 | |||
916 | mutex_unlock(&bdev->bd_mutex); | ||
857 | } | 917 | } |
858 | #else | 918 | EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); |
859 | static inline void bd_unlink_disk_holder(struct block_device *bdev) | ||
860 | { } | ||
861 | #endif | 919 | #endif |
862 | 920 | ||
863 | /** | 921 | /** |
@@ -1380,7 +1438,6 @@ int blkdev_put(struct block_device *bdev, fmode_t mode) | |||
1380 | * unblock evpoll if it was a write holder. | 1438 | * unblock evpoll if it was a write holder. |
1381 | */ | 1439 | */ |
1382 | if (bdev_free) { | 1440 | if (bdev_free) { |
1383 | bd_unlink_disk_holder(bdev); | ||
1384 | if (bdev->bd_write_holder) { | 1441 | if (bdev->bd_write_holder) { |
1385 | disk_unblock_events(bdev->bd_disk); | 1442 | disk_unblock_events(bdev->bd_disk); |
1386 | bdev->bd_write_holder = false; | 1443 | bdev->bd_write_holder = false; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index ed6ee473cc8a..08824e0ef381 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -666,7 +666,7 @@ struct block_device { | |||
666 | int bd_holders; | 666 | int bd_holders; |
667 | bool bd_write_holder; | 667 | bool bd_write_holder; |
668 | #ifdef CONFIG_SYSFS | 668 | #ifdef CONFIG_SYSFS |
669 | struct gendisk * bd_holder_disk; /* for sysfs slave linkng */ | 669 | struct list_head bd_holder_disks; |
670 | #endif | 670 | #endif |
671 | struct block_device * bd_contains; | 671 | struct block_device * bd_contains; |
672 | unsigned bd_block_size; | 672 | unsigned bd_block_size; |
@@ -2057,12 +2057,18 @@ extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, | |||
2057 | extern int blkdev_put(struct block_device *bdev, fmode_t mode); | 2057 | extern int blkdev_put(struct block_device *bdev, fmode_t mode); |
2058 | #ifdef CONFIG_SYSFS | 2058 | #ifdef CONFIG_SYSFS |
2059 | extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); | 2059 | extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); |
2060 | extern void bd_unlink_disk_holder(struct block_device *bdev, | ||
2061 | struct gendisk *disk); | ||
2060 | #else | 2062 | #else |
2061 | static inline int bd_link_disk_holder(struct block_device *bdev, | 2063 | static inline int bd_link_disk_holder(struct block_device *bdev, |
2062 | struct gendisk *disk) | 2064 | struct gendisk *disk) |
2063 | { | 2065 | { |
2064 | return 0; | 2066 | return 0; |
2065 | } | 2067 | } |
2068 | static inline void bd_unlink_disk_holder(struct block_device *bdev, | ||
2069 | struct gendisk *disk) | ||
2070 | { | ||
2071 | } | ||
2066 | #endif | 2072 | #endif |
2067 | #endif | 2073 | #endif |
2068 | 2074 | ||