diff options
author | Josef Bacik <josef@redhat.com> | 2012-06-04 14:03:51 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-06-14 21:29:16 -0400 |
commit | 606686eeac4550d2212bf3d621a810407ef5e9bf (patch) | |
tree | 50adade3a750137b68304dc280d7a75436417b12 /fs/btrfs/ioctl.c | |
parent | 17ca04aff7e6171df684b7b65804df8830eb8c15 (diff) |
Btrfs: use rcu to protect device->name
Al pointed out that we can just toss out the old name on a device and add a
new one arbitrarily, so anybody who uses device->name in printk could
possibly use free'd memory. Instead of adding locking around all of this he
suggested doing it with RCU, so I've introduced a struct rcu_string that
does just that and have gone through and protected all accesses to
device->name that aren't under the uuid_mutex with rcu_read_lock(). This
protects us and I will use it for dealing with removing the device that we
used to mount the file system in a later patch. Thanks,
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 24b776c08d99..c5254dde1f0f 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -52,6 +52,7 @@ | |||
52 | #include "locking.h" | 52 | #include "locking.h" |
53 | #include "inode-map.h" | 53 | #include "inode-map.h" |
54 | #include "backref.h" | 54 | #include "backref.h" |
55 | #include "rcu-string.h" | ||
55 | 56 | ||
56 | /* Mask out flags that are inappropriate for the given type of inode. */ | 57 | /* Mask out flags that are inappropriate for the given type of inode. */ |
57 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) | 58 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) |
@@ -1345,8 +1346,9 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
1345 | do_div(new_size, root->sectorsize); | 1346 | do_div(new_size, root->sectorsize); |
1346 | new_size *= root->sectorsize; | 1347 | new_size *= root->sectorsize; |
1347 | 1348 | ||
1348 | printk(KERN_INFO "btrfs: new size for %s is %llu\n", | 1349 | printk_in_rcu(KERN_INFO "btrfs: new size for %s is %llu\n", |
1349 | device->name, (unsigned long long)new_size); | 1350 | rcu_str_deref(device->name), |
1351 | (unsigned long long)new_size); | ||
1350 | 1352 | ||
1351 | if (new_size > old_size) { | 1353 | if (new_size > old_size) { |
1352 | trans = btrfs_start_transaction(root, 0); | 1354 | trans = btrfs_start_transaction(root, 0); |
@@ -2264,7 +2266,12 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg) | |||
2264 | di_args->total_bytes = dev->total_bytes; | 2266 | di_args->total_bytes = dev->total_bytes; |
2265 | memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); | 2267 | memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); |
2266 | if (dev->name) { | 2268 | if (dev->name) { |
2267 | strncpy(di_args->path, dev->name, sizeof(di_args->path)); | 2269 | struct rcu_string *name; |
2270 | |||
2271 | rcu_read_lock(); | ||
2272 | name = rcu_dereference(dev->name); | ||
2273 | strncpy(di_args->path, name->str, sizeof(di_args->path)); | ||
2274 | rcu_read_unlock(); | ||
2268 | di_args->path[sizeof(di_args->path) - 1] = 0; | 2275 | di_args->path[sizeof(di_args->path) - 1] = 0; |
2269 | } else { | 2276 | } else { |
2270 | di_args->path[0] = '\0'; | 2277 | di_args->path[0] = '\0'; |