aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.com>2018-03-15 22:27:02 -0400
committerDavid Sterba <dsterba@suse.com>2018-03-30 20:01:06 -0400
commit88c14590cdd6f3cafc7ea7487d5f4532db8c551e (patch)
tree70a5fd92672f1a7a83c63a9b993557b4e7684277
parentd1980131ca7f0776542f776ceb777cd01eb983e2 (diff)
btrfs: use RCU in btrfs_show_devname for device list traversal
The show_devname callback is used to print device name in /proc/self/mounts, we need to traverse the device list consistently and read the name that's copied to a seq buffer so we don't need further locking. If the first device is being deleted at the same time, the RCU will allow us to read the device name, though it will become stale right after the RCU protection ends. This is unavoidable and the user can expect that the device will disappear from the filesystem's list at some point. The device_list_mutex was pretty heavy as it is used eg. for writing superblock and a few other IO related contexts. This can stall any application that reads the proc file for no reason. Reviewed-by: Anand Jain <anand.jain@oracle.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/super.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d41d5960ef4a..170baef49fae 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -2304,11 +2304,18 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
2304 struct list_head *head; 2304 struct list_head *head;
2305 struct rcu_string *name; 2305 struct rcu_string *name;
2306 2306
2307 mutex_lock(&fs_info->fs_devices->device_list_mutex); 2307 /*
2308 * Lightweight locking of the devices. We should not need
2309 * device_list_mutex here as we only read the device data and the list
2310 * is protected by RCU. Even if a device is deleted during the list
2311 * traversals, we'll get valid data, the freeing callback will wait at
2312 * least until until the rcu_read_unlock.
2313 */
2314 rcu_read_lock();
2308 cur_devices = fs_info->fs_devices; 2315 cur_devices = fs_info->fs_devices;
2309 while (cur_devices) { 2316 while (cur_devices) {
2310 head = &cur_devices->devices; 2317 head = &cur_devices->devices;
2311 list_for_each_entry(dev, head, dev_list) { 2318 list_for_each_entry_rcu(dev, head, dev_list) {
2312 if (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state)) 2319 if (test_bit(BTRFS_DEV_STATE_MISSING, &dev->dev_state))
2313 continue; 2320 continue;
2314 if (!dev->name) 2321 if (!dev->name)
@@ -2320,14 +2327,12 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
2320 } 2327 }
2321 2328
2322 if (first_dev) { 2329 if (first_dev) {
2323 rcu_read_lock();
2324 name = rcu_dereference(first_dev->name); 2330 name = rcu_dereference(first_dev->name);
2325 seq_escape(m, name->str, " \t\n\\"); 2331 seq_escape(m, name->str, " \t\n\\");
2326 rcu_read_unlock();
2327 } else { 2332 } else {
2328 WARN_ON(1); 2333 WARN_ON(1);
2329 } 2334 }
2330 mutex_unlock(&fs_info->fs_devices->device_list_mutex); 2335 rcu_read_unlock();
2331 return 0; 2336 return 0;
2332} 2337}
2333 2338