aboutsummaryrefslogtreecommitdiffstats
path: root/block/blk-cgroup.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2019-11-05 11:09:51 -0500
committerJens Axboe <axboe@kernel.dk>2019-11-06 19:08:38 -0500
commitb0814361a25cba73a224548843ed92d8ea78715a (patch)
tree9c9c269d564efa33f2d3a6eebfd6f5a51db2e970 /block/blk-cgroup.c
parent0473976c3568cbe7ef4b4af5c134960cb7bb2779 (diff)
blkcg: make blkcg_print_stat() print stats only for online blkgs
blkcg_print_stat() iterates blkgs under RCU and doesn't test whether the blkg is online. This can call into pd_stat_fn() on a pd which is still being initialized leading to an oops. The heaviest operation - recursively summing up rwstat counters - is already done while holding the queue_lock. Expand queue_lock to cover the other operations and skip the blkg if it isn't online yet. The online state is protected by both blkcg and queue locks, so this guarantees that only online blkgs are processed. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: Roman Gushchin <guro@fb.com> Cc: Josef Bacik <jbacik@fb.com> Fixes: 903d23f0a354 ("blk-cgroup: allow controllers to output their own stats") Cc: stable@vger.kernel.org # v4.19+ Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/blk-cgroup.c')
-rw-r--r--block/blk-cgroup.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 5d21027b1faf..1eb8895be4c6 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -934,9 +934,14 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
934 int i; 934 int i;
935 bool has_stats = false; 935 bool has_stats = false;
936 936
937 spin_lock_irq(&blkg->q->queue_lock);
938
939 if (!blkg->online)
940 goto skip;
941
937 dname = blkg_dev_name(blkg); 942 dname = blkg_dev_name(blkg);
938 if (!dname) 943 if (!dname)
939 continue; 944 goto skip;
940 945
941 /* 946 /*
942 * Hooray string manipulation, count is the size written NOT 947 * Hooray string manipulation, count is the size written NOT
@@ -946,8 +951,6 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
946 */ 951 */
947 off += scnprintf(buf+off, size-off, "%s ", dname); 952 off += scnprintf(buf+off, size-off, "%s ", dname);
948 953
949 spin_lock_irq(&blkg->q->queue_lock);
950
951 blkg_rwstat_recursive_sum(blkg, NULL, 954 blkg_rwstat_recursive_sum(blkg, NULL,
952 offsetof(struct blkcg_gq, stat_bytes), &rwstat); 955 offsetof(struct blkcg_gq, stat_bytes), &rwstat);
953 rbytes = rwstat.cnt[BLKG_RWSTAT_READ]; 956 rbytes = rwstat.cnt[BLKG_RWSTAT_READ];
@@ -960,8 +963,6 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
960 wios = rwstat.cnt[BLKG_RWSTAT_WRITE]; 963 wios = rwstat.cnt[BLKG_RWSTAT_WRITE];
961 dios = rwstat.cnt[BLKG_RWSTAT_DISCARD]; 964 dios = rwstat.cnt[BLKG_RWSTAT_DISCARD];
962 965
963 spin_unlock_irq(&blkg->q->queue_lock);
964
965 if (rbytes || wbytes || rios || wios) { 966 if (rbytes || wbytes || rios || wios) {
966 has_stats = true; 967 has_stats = true;
967 off += scnprintf(buf+off, size-off, 968 off += scnprintf(buf+off, size-off,
@@ -999,6 +1000,8 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
999 seq_commit(sf, -1); 1000 seq_commit(sf, -1);
1000 } 1001 }
1001 } 1002 }
1003 skip:
1004 spin_unlock_irq(&blkg->q->queue_lock);
1002 } 1005 }
1003 1006
1004 rcu_read_unlock(); 1007 rcu_read_unlock();