aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@redhat.com>2010-12-01 13:34:52 -0500
committerJens Axboe <jaxboe@fusionio.com>2010-12-01 13:34:52 -0500
commit04a6b516cdc6efc2500b52a540cf65be8c5aaf9e (patch)
treefa5d6675308df0ff42eceeec1b406d2ce5eb2ff6 /block
parentd1ae8ffdfaa16b2ab2e9346e81cf0ab6eaaae347 (diff)
blk-throttle: Correct the placement of smp_rmb()
o I was discussing what are the variable being updated without spin lock and why do we need barriers and Oleg pointed out that location of smp_rmb() should be between read of td->limits_changed and tg->limits_changed. This patch fixes it. o Following is one possible sequence of events. Say cpu0 is executing throtl_update_blkio_group_read_bps() and cpu1 is executing throtl_process_limit_change(). cpu0 cpu1 tg->limits_changed = true; smp_mb__before_atomic_inc(); atomic_inc(&td->limits_changed); if (!atomic_read(&td->limits_changed)) return; if (tg->limits_changed) do_something; If cpu0 has updated tg->limits_changed and td->limits_changed, we want to make sure that if update to td->limits_changed is visible on cpu1, then update to tg->limits_changed should also be visible. Oleg pointed out to ensure that we need to insert an smp_rmb() between td->limits_changed read and tg->limits_changed read. o I had erroneously put smp_rmb() before atomic_read(&td->limits_changed). This patch fixes it. Reported-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-throttle.c23
1 files changed, 9 insertions, 14 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 2d134b7c40a3..381b09bb562b 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -725,26 +725,21 @@ static void throtl_process_limit_change(struct throtl_data *td)
725 struct throtl_grp *tg; 725 struct throtl_grp *tg;
726 struct hlist_node *pos, *n; 726 struct hlist_node *pos, *n;
727 727
728 /*
729 * Make sure atomic_inc() effects from
730 * throtl_update_blkio_group_read_bps(), group of functions are
731 * visible.
732 * Is this required or smp_mb__after_atomic_inc() was suffcient
733 * after the atomic_inc().
734 */
735 smp_rmb();
736 if (!atomic_read(&td->limits_changed)) 728 if (!atomic_read(&td->limits_changed))
737 return; 729 return;
738 730
739 throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed)); 731 throtl_log(td, "limit changed =%d", atomic_read(&td->limits_changed));
740 732
741 hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) { 733 /*
742 /* 734 * Make sure updates from throtl_update_blkio_group_read_bps() group
743 * Do I need an smp_rmb() here to make sure tg->limits_changed 735 * of functions to tg->limits_changed are visible. We do not
744 * update is visible. I am relying on smp_rmb() at the 736 * want update td->limits_changed to be visible but update to
745 * beginning of function and not putting a new one here. 737 * tg->limits_changed not being visible yet on this cpu. Hence
746 */ 738 * the read barrier.
739 */
740 smp_rmb();
747 741
742 hlist_for_each_entry_safe(tg, pos, n, &td->tg_list, tg_node) {
748 if (throtl_tg_on_rr(tg) && tg->limits_changed) { 743 if (throtl_tg_on_rr(tg) && tg->limits_changed) {
749 throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu" 744 throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
750 " riops=%u wiops=%u", tg->bps[READ], 745 " riops=%u wiops=%u", tg->bps[READ],