aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2008-01-28 05:38:15 -0500
committerJens Axboe <jens.axboe@oracle.com>2008-01-28 05:38:15 -0500
commit0871714e08fed7ba66cadad11b2e4f85a9dc9b96 (patch)
tree3b0bcb433294bb144b778ae97296ad4d8626ad47
parentfadad878cc0640cc9cd5569998bf54b693f7b38b (diff)
cfq-iosched: relax IOPRIO_CLASS_IDLE restrictions
Currently you must be root to set idle io prio class on a process. This is due to the fact that the idle class is implemented as a true idle class, meaning that it will not make progress if someone else is requesting disk access. Unfortunately this means that it opens DOS opportunities by locking down file system resources, hence it is root only at the moment. This patch relaxes the idle class a little, by removing the truly idle part (which entals a grace period with associated timer). The modifications make the idle class as close to zero impact as can be done while still guarenteeing progress. This means we can relax the root only criteria as well. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--block/cfq-iosched.c117
-rw-r--r--fs/ioprio.c2
2 files changed, 34 insertions, 85 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 8830893e062f..8fe1a0ddb511 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -26,9 +26,9 @@ static const int cfq_slice_async_rq = 2;
26static int cfq_slice_idle = HZ / 125; 26static int cfq_slice_idle = HZ / 125;
27 27
28/* 28/*
29 * grace period before allowing idle class to get disk access 29 * offset from end of service tree
30 */ 30 */
31#define CFQ_IDLE_GRACE (HZ / 10) 31#define CFQ_IDLE_DELAY (HZ / 5)
32 32
33/* 33/*
34 * below this threshold, we consider thinktime immediate 34 * below this threshold, we consider thinktime immediate
@@ -98,8 +98,6 @@ struct cfq_data {
98 struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; 98 struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
99 struct cfq_queue *async_idle_cfqq; 99 struct cfq_queue *async_idle_cfqq;
100 100
101 struct timer_list idle_class_timer;
102
103 sector_t last_position; 101 sector_t last_position;
104 unsigned long last_end_request; 102 unsigned long last_end_request;
105 103
@@ -384,12 +382,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
384/* 382/*
385 * The below is leftmost cache rbtree addon 383 * The below is leftmost cache rbtree addon
386 */ 384 */
387static struct rb_node *cfq_rb_first(struct cfq_rb_root *root) 385static struct cfq_queue *cfq_rb_first(struct cfq_rb_root *root)
388{ 386{
389 if (!root->left) 387 if (!root->left)
390 root->left = rb_first(&root->rb); 388 root->left = rb_first(&root->rb);
391 389
392 return root->left; 390 if (root->left)
391 return rb_entry(root->left, struct cfq_queue, rb_node);
392
393 return NULL;
393} 394}
394 395
395static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root) 396static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
@@ -446,12 +447,20 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
446static void cfq_service_tree_add(struct cfq_data *cfqd, 447static void cfq_service_tree_add(struct cfq_data *cfqd,
447 struct cfq_queue *cfqq, int add_front) 448 struct cfq_queue *cfqq, int add_front)
448{ 449{
449 struct rb_node **p = &cfqd->service_tree.rb.rb_node; 450 struct rb_node **p, *parent;
450 struct rb_node *parent = NULL; 451 struct cfq_queue *__cfqq;
451 unsigned long rb_key; 452 unsigned long rb_key;
452 int left; 453 int left;
453 454
454 if (!add_front) { 455 if (cfq_class_idle(cfqq)) {
456 rb_key = CFQ_IDLE_DELAY;
457 parent = rb_last(&cfqd->service_tree.rb);
458 if (parent && parent != &cfqq->rb_node) {
459 __cfqq = rb_entry(parent, struct cfq_queue, rb_node);
460 rb_key += __cfqq->rb_key;
461 } else
462 rb_key += jiffies;
463 } else if (!add_front) {
455 rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies; 464 rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
456 rb_key += cfqq->slice_resid; 465 rb_key += cfqq->slice_resid;
457 cfqq->slice_resid = 0; 466 cfqq->slice_resid = 0;
@@ -469,8 +478,9 @@ static void cfq_service_tree_add(struct cfq_data *cfqd,
469 } 478 }
470 479
471 left = 1; 480 left = 1;
481 parent = NULL;
482 p = &cfqd->service_tree.rb.rb_node;
472 while (*p) { 483 while (*p) {
473 struct cfq_queue *__cfqq;
474 struct rb_node **n; 484 struct rb_node **n;
475 485
476 parent = *p; 486 parent = *p;
@@ -736,11 +746,6 @@ static inline void
736__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) 746__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
737{ 747{
738 if (cfqq) { 748 if (cfqq) {
739 /*
740 * stop potential idle class queues waiting service
741 */
742 del_timer(&cfqd->idle_class_timer);
743
744 cfqq->slice_end = 0; 749 cfqq->slice_end = 0;
745 cfq_clear_cfqq_must_alloc_slice(cfqq); 750 cfq_clear_cfqq_must_alloc_slice(cfqq);
746 cfq_clear_cfqq_fifo_expire(cfqq); 751 cfq_clear_cfqq_fifo_expire(cfqq);
@@ -789,47 +794,16 @@ static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
789 __cfq_slice_expired(cfqd, cfqq, timed_out); 794 __cfq_slice_expired(cfqd, cfqq, timed_out);
790} 795}
791 796
792static int start_idle_class_timer(struct cfq_data *cfqd)
793{
794 unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
795 unsigned long now = jiffies;
796
797 if (time_before(now, end) &&
798 time_after_eq(now, cfqd->last_end_request)) {
799 mod_timer(&cfqd->idle_class_timer, end);
800 return 1;
801 }
802
803 return 0;
804}
805
806/* 797/*
807 * Get next queue for service. Unless we have a queue preemption, 798 * Get next queue for service. Unless we have a queue preemption,
808 * we'll simply select the first cfqq in the service tree. 799 * we'll simply select the first cfqq in the service tree.
809 */ 800 */
810static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) 801static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
811{ 802{
812 struct cfq_queue *cfqq;
813 struct rb_node *n;
814
815 if (RB_EMPTY_ROOT(&cfqd->service_tree.rb)) 803 if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
816 return NULL; 804 return NULL;
817 805
818 n = cfq_rb_first(&cfqd->service_tree); 806 return cfq_rb_first(&cfqd->service_tree);
819 cfqq = rb_entry(n, struct cfq_queue, rb_node);
820
821 if (cfq_class_idle(cfqq)) {
822 /*
823 * if we have idle queues and no rt or be queues had
824 * pending requests, either allow immediate service if
825 * the grace period has passed or arm the idle grace
826 * timer
827 */
828 if (start_idle_class_timer(cfqd))
829 cfqq = NULL;
830 }
831
832 return cfqq;
833} 807}
834 808
835/* 809/*
@@ -1087,14 +1061,11 @@ static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
1087 */ 1061 */
1088static int cfq_forced_dispatch(struct cfq_data *cfqd) 1062static int cfq_forced_dispatch(struct cfq_data *cfqd)
1089{ 1063{
1064 struct cfq_queue *cfqq;
1090 int dispatched = 0; 1065 int dispatched = 0;
1091 struct rb_node *n;
1092
1093 while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) {
1094 struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node);
1095 1066
1067 while ((cfqq = cfq_rb_first(&cfqd->service_tree)) != NULL)
1096 dispatched += __cfq_forced_dispatch_cfqq(cfqq); 1068 dispatched += __cfq_forced_dispatch_cfqq(cfqq);
1097 }
1098 1069
1099 cfq_slice_expired(cfqd, 0); 1070 cfq_slice_expired(cfqd, 0);
1100 1071
@@ -1437,15 +1408,16 @@ retry:
1437 atomic_set(&cfqq->ref, 0); 1408 atomic_set(&cfqq->ref, 0);
1438 cfqq->cfqd = cfqd; 1409 cfqq->cfqd = cfqd;
1439 1410
1440 if (is_sync) {
1441 cfq_mark_cfqq_idle_window(cfqq);
1442 cfq_mark_cfqq_sync(cfqq);
1443 }
1444
1445 cfq_mark_cfqq_prio_changed(cfqq); 1411 cfq_mark_cfqq_prio_changed(cfqq);
1446 cfq_mark_cfqq_queue_new(cfqq); 1412 cfq_mark_cfqq_queue_new(cfqq);
1447 1413
1448 cfq_init_prio_data(cfqq, ioc); 1414 cfq_init_prio_data(cfqq, ioc);
1415
1416 if (is_sync) {
1417 if (!cfq_class_idle(cfqq))
1418 cfq_mark_cfqq_idle_window(cfqq);
1419 cfq_mark_cfqq_sync(cfqq);
1420 }
1449 } 1421 }
1450 1422
1451 if (new_cfqq) 1423 if (new_cfqq)
@@ -1697,7 +1669,10 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1697{ 1669{
1698 int enable_idle; 1670 int enable_idle;
1699 1671
1700 if (!cfq_cfqq_sync(cfqq)) 1672 /*
1673 * Don't idle for async or idle io prio class
1674 */
1675 if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq))
1701 return; 1676 return;
1702 1677
1703 enable_idle = cfq_cfqq_idle_window(cfqq); 1678 enable_idle = cfq_cfqq_idle_window(cfqq);
@@ -1876,7 +1851,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
1876 cfq_set_prio_slice(cfqd, cfqq); 1851 cfq_set_prio_slice(cfqd, cfqq);
1877 cfq_clear_cfqq_slice_new(cfqq); 1852 cfq_clear_cfqq_slice_new(cfqq);
1878 } 1853 }
1879 if (cfq_slice_used(cfqq)) 1854 if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq))
1880 cfq_slice_expired(cfqd, 1); 1855 cfq_slice_expired(cfqd, 1);
1881 else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) 1856 else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
1882 cfq_arm_slice_timer(cfqd); 1857 cfq_arm_slice_timer(cfqd);
@@ -2080,29 +2055,9 @@ out_cont:
2080 spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); 2055 spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
2081} 2056}
2082 2057
2083/*
2084 * Timer running if an idle class queue is waiting for service
2085 */
2086static void cfq_idle_class_timer(unsigned long data)
2087{
2088 struct cfq_data *cfqd = (struct cfq_data *) data;
2089 unsigned long flags;
2090
2091 spin_lock_irqsave(cfqd->queue->queue_lock, flags);
2092
2093 /*
2094 * race with a non-idle queue, reset timer
2095 */
2096 if (!start_idle_class_timer(cfqd))
2097 cfq_schedule_dispatch(cfqd);
2098
2099 spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
2100}
2101
2102static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) 2058static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
2103{ 2059{
2104 del_timer_sync(&cfqd->idle_slice_timer); 2060 del_timer_sync(&cfqd->idle_slice_timer);
2105 del_timer_sync(&cfqd->idle_class_timer);
2106 kblockd_flush_work(&cfqd->unplug_work); 2061 kblockd_flush_work(&cfqd->unplug_work);
2107} 2062}
2108 2063
@@ -2167,10 +2122,6 @@ static void *cfq_init_queue(struct request_queue *q)
2167 cfqd->idle_slice_timer.function = cfq_idle_slice_timer; 2122 cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
2168 cfqd->idle_slice_timer.data = (unsigned long) cfqd; 2123 cfqd->idle_slice_timer.data = (unsigned long) cfqd;
2169 2124
2170 init_timer(&cfqd->idle_class_timer);
2171 cfqd->idle_class_timer.function = cfq_idle_class_timer;
2172 cfqd->idle_class_timer.data = (unsigned long) cfqd;
2173
2174 INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); 2125 INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
2175 2126
2176 cfqd->last_end_request = jiffies; 2127 cfqd->last_end_request = jiffies;
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 06b5d97c5fdd..c4a1c3c65aac 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -85,8 +85,6 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
85 85
86 break; 86 break;
87 case IOPRIO_CLASS_IDLE: 87 case IOPRIO_CLASS_IDLE:
88 if (!capable(CAP_SYS_ADMIN))
89 return -EPERM;
90 break; 88 break;
91 case IOPRIO_CLASS_NONE: 89 case IOPRIO_CLASS_NONE:
92 if (data) 90 if (data)