Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm raid1: use timer

This patch replaces the schedule() in the main kmirrord thread with a timer.
The schedule() could introduce an unwanted delay when work is ready to be
processed.

The code instead calls wake() when there's work to be done immediately, and
delayed_wake() after a failure to give a short delay before retrying.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

authored by

Mikulas Patocka and committed by
Alasdair G Kergon
a2aebe03 a765e20e

+28 -20
+28 -20
drivers/md/dm-raid1.c
··· 154 154 155 155 struct workqueue_struct *kmirrord_wq; 156 156 struct work_struct kmirrord_work; 157 + struct timer_list timer; 158 + unsigned long timer_pending; 159 + 157 160 struct work_struct trigger_event; 158 161 159 162 unsigned int nr_mirrors; ··· 179 176 static void wake(struct mirror_set *ms) 180 177 { 181 178 queue_work(ms->kmirrord_wq, &ms->kmirrord_work); 179 + } 180 + 181 + static void delayed_wake_fn(unsigned long data) 182 + { 183 + struct mirror_set *ms = (struct mirror_set *) data; 184 + 185 + clear_bit(0, &ms->timer_pending); 186 + wake(ms); 187 + } 188 + 189 + static void delayed_wake(struct mirror_set *ms) 190 + { 191 + if (test_and_set_bit(0, &ms->timer_pending)) 192 + return; 193 + 194 + ms->timer.expires = jiffies + HZ / 5; 195 + ms->timer.data = (unsigned long) ms; 196 + ms->timer.function = delayed_wake_fn; 197 + add_timer(&ms->timer); 182 198 } 183 199 184 200 /* FIXME move this */ ··· 1202 1180 spin_lock_irq(&ms->lock); 1203 1181 bio_list_merge(&ms->failures, &sync); 1204 1182 spin_unlock_irq(&ms->lock); 1183 + wake(ms); 1205 1184 } else 1206 1185 while ((bio = bio_list_pop(&sync))) 1207 1186 do_write(ms, bio); ··· 1262 1239 bio_list_merge(&ms->failures, failures); 1263 1240 spin_unlock_irq(&ms->lock); 1264 1241 1265 - wake(ms); 1242 + delayed_wake(ms); 1266 1243 } 1267 1244 1268 1245 static void trigger_event(struct work_struct *work) ··· 1276 1253 /*----------------------------------------------------------------- 1277 1254 * kmirrord 1278 1255 *---------------------------------------------------------------*/ 1279 - static int _do_mirror(struct work_struct *work) 1256 + static void do_mirror(struct work_struct *work) 1280 1257 { 1281 1258 struct mirror_set *ms =container_of(work, struct mirror_set, 1282 1259 kmirrord_work); ··· 1297 1274 do_reads(ms, &reads); 1298 1275 do_writes(ms, &writes); 1299 1276 do_failures(ms, &failures); 1300 - 1301 - return (ms->failures.head) ? 1 : 0; 1302 - } 1303 - 1304 - static void do_mirror(struct work_struct *work) 1305 - { 1306 - /* 1307 - * If _do_mirror returns 1, we give it 1308 - * another shot. This helps for cases like 1309 - * 'suspend' where we call flush_workqueue 1310 - * and expect all work to be finished. If 1311 - * a failure happens during a suspend, we 1312 - * couldn't issue a 'wake' because it would 1313 - * not be honored. Therefore, we return '1' 1314 - * from _do_mirror, and retry here. 1315 - */ 1316 - while (_do_mirror(work)) 1317 - schedule(); 1318 1277 } 1319 1278 1320 1279 ··· 1550 1545 goto err_free_context; 1551 1546 } 1552 1547 INIT_WORK(&ms->kmirrord_work, do_mirror); 1548 + init_timer(&ms->timer); 1549 + ms->timer_pending = 0; 1553 1550 INIT_WORK(&ms->trigger_event, trigger_event); 1554 1551 1555 1552 r = parse_features(ms, argc, argv, &args_used); ··· 1594 1587 { 1595 1588 struct mirror_set *ms = (struct mirror_set *) ti->private; 1596 1589 1590 + del_timer_sync(&ms->timer); 1597 1591 flush_workqueue(ms->kmirrord_wq); 1598 1592 dm_kcopyd_client_destroy(ms->kcopyd_client); 1599 1593 destroy_workqueue(ms->kmirrord_wq);