Introduce RCU string API
Subsystems (2)
v8 cover Introduce RCU string API
Hi, everyone,
Now that the merge window and the holidays are over, I've rebased this on v3.19-rc3 for the next merge window.
This patch series introduces the RCU string API and cleans up the wreckage of sparse warnings which follow from it (shown here from when the patch was briefly in the btrfs integration tree):
Quoted 10 lines · kbuild test robot
tree: git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git integration head: c7a37618b60026121255c69e042d74ae5631470c commit: 37aad79d90a0cbf82a5eda62dfe3af4241f5aca3 [38/39] Move BTRFS RCU string to common library reproduce: # apt-get install sparse git checkout 37aad79d90a0cbf82a5eda62dfe3af4241f5aca3 make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__
Quoted 5 lines
sparse warnings: (new ones prefixed by >>)
Quoted 1 line
Quoted 1 line
fs/btrfs/check-integrity.c:848:25: sparse: incorrect type in argument 1 (different address spaces)
fs/btrfs/check-integrity.c:848:25: expected structrcu_string[noderef] <asn:4>*rcu_str
fs/btrfs/check-integrity.c:848:25: got structrcu_string*name
[snip]
Version 8 combines the original patch with another patch series I posted to fix these warnings, which fixes the botched __rcu annotations that caused some of the warnings and refactors the existing uses of rcustring to get rid of the rest. There's also a patch to fix an RCU misuse.
Thanks!
v8: Get the __rcu annotations right, clean up RCU string-related sparse noise
v7: Add arguments to kernel doc for printk wrappers, use ##__VA_ARGS
v6: Add header dependencies to rcustring.h
v5: Rebase against v3.18-rc3
v4: Don't return anything from the printk wrappers on the assumption that printk will return void someday
v3: Add __rcu annotation to relevant functions, add Paul's ack and Josh's review
Omar Sandoval (3):
Move BTRFS RCU string to common library
btrfs: refactor btrfs_device->name updates
btrfs: fix suspicious RCU in BTRFS_IOC_DEV_INFO
fs/btrfs/check-integrity.c | 6 +-- fs/btrfs/dev-replace.c | 19 ++++---- fs/btrfs/disk-io.c | 6 +-- fs/btrfs/extent_io.c | 4 +- fs/btrfs/ioctl.c | 14 +++--- fs/btrfs/raid56.c | 2 +- fs/btrfs/rcu-string.h | 56 ------------------------ fs/btrfs/scrub.c | 15 ++++--- fs/btrfs/super.c | 2 +- fs/btrfs/volumes.c | 107 ++++++++++++++++++++++++++++++--------------- fs/btrfs/volumes.h | 2 +- include/linux/rcustring.h | 97 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 204 insertions(+), 126 deletions(-) delete mode 100644 fs/btrfs/rcu-string.h create mode 100644 include/linux/rcustring.h
Signature · 1 line
2.2.1
PATCH RESEND v8 1/3 Move BTRFS RCU string to common library
The RCU-friendly string API used internally by BTRFS is generic enough for common use. This doesn't add any new functionality but instead just moves the code and documents the existing API.
--- fs/btrfs/check-integrity.c | 6 +-- fs/btrfs/dev-replace.c | 19 ++++----- fs/btrfs/disk-io.c | 6 +-- fs/btrfs/extent_io.c | 4 +- fs/btrfs/ioctl.c | 4 +- fs/btrfs/raid56.c | 2 +- fs/btrfs/rcu-string.h | 56 -------------------------- fs/btrfs/scrub.c | 15 +++---- fs/btrfs/super.c | 2 +- fs/btrfs/volumes.c | 14 +++---- include/linux/rcustring.h | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 134 insertions(+), 91 deletions(-) delete mode 100644 fs/btrfs/rcu-string.h create mode 100644 include/linux/rcustring.h
fs/btrfs/check-integrity.c +3 -3
@@ -95,6 +95,7 @@#include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/vmalloc.h> +#include <linux/rcustring.h> #include "ctree.h" #include "disk-io.h" #include "hash.h"
@@ -104,7 +105,6 @@#include "print-tree.h" #include "locking.h" #include "check-integrity.h" -#include "rcu-string.h" #define BTRFSIC_BLOCK_HASHTABLE_SIZE 0x10000#define BTRFSIC_BLOCK_LINK_HASHTABLE_SIZE 0x10000
@@ -848,8 +848,8 @@ static int btrfsic_process_superblock_dev_mirror(printk_in_rcu (KERN_INFO "New initial S-block (bdev %p, %s)" " @%llu (%s/%llu/%d)\n" , superblock_bdev, -rcu_str_deref (device->name), dev_bytenr, - dev_state->name, dev_bytenr, +rcu_string_dereference (device->name), + dev_bytenr, dev_state->name, dev_bytenr, superblock_mirror_num);list_add (&superblock_tmp->all_blocks_node, &state->all_blocks_list);
fs/btrfs/dev-replace.c +10 -9
@@ -25,6 +25,7 @@#include <linux/capability.h> #include <linux/kthread.h> #include <linux/math64.h> +#include <linux/rcustring.h> #include <asm/div64.h> #include "ctree.h" #include "extent_map.h"
@@ -34,7 +35,6 @@#include "volumes.h" #include "async-thread.h" #include "check-integrity.h" -#include "rcu-string.h" #include "dev-replace.h" #include "sysfs.h"
@@ -379,9 +379,9 @@ int btrfs_dev_replace_start(struct btrfs_root *root,printk_in_rcu (KERN_INFO "BTRFS: dev_replace from %s (devid %llu) to %s started\n" , src_device->missing ?"<missing disk>" : -rcu_str_deref (src_device->name), +rcu_string_dereference (src_device->name), src_device->devid, -rcu_str_deref (tgt_device->name)); +rcu_string_dereference (tgt_device->name));/* * from now on, the writes to the srcdev are all duplicated to
@@ -532,9 +532,10 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,printk_in_rcu (KERN_ERR "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n" , src_device->missing ?"<missing disk>" : -rcu_str_deref (src_device->name), +rcu_string_dereference (src_device->name), src_device->devid, -rcu_str_deref (tgt_device->name), scrub_ret); +rcu_string_dereference (tgt_device->name), + scrub_ret);btrfs_dev_replace_unlock (dev_replace);mutex_unlock (&root->fs_info->chunk_mutex);mutex_unlock (&root->fs_info->fs_devices->device_list_mutex);
@@ -549,9 +550,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,printk_in_rcu (KERN_INFO "BTRFS: dev_replace from %s (devid %llu) to %s finished\n" , src_device->missing ?"<missing disk>" : -rcu_str_deref (src_device->name), +rcu_string_dereference (src_device->name), src_device->devid, -rcu_str_deref (tgt_device->name)); +rcu_string_dereference (tgt_device->name)); tgt_device->is_tgtdev_for_dev_replace =0 ; tgt_device->devid = src_device->devid; src_device->devid =BTRFS_DEV_REPLACE_DEVID ;
@@ -819,10 +820,10 @@ static int btrfs_dev_replace_kthread(void *data)printk_in_rcu (KERN_INFO "BTRFS: continuing dev_replace from %s (devid %llu) to %s @%u%%\n" , dev_replace->srcdev->missing ?"<missing disk>" : -rcu_str_deref (dev_replace->srcdev->name), +rcu_string_dereference (dev_replace->srcdev->name), dev_replace->srcdev->devid, dev_replace->tgtdev ? -rcu_str_deref (dev_replace->tgtdev->name) : +rcu_string_dereference (dev_replace->tgtdev->name) :"<missing target disk>" , (unsigned int )progress); }
fs/btrfs/disk-io.c +3 -3
@@ -31,6 +31,7 @@#include <linux/ratelimit.h> #include <linux/uuid.h> #include <linux/semaphore.h> +#include <linux/rcustring.h> #include <asm/unaligned.h> #include "ctree.h" #include "disk-io.h"
@@ -44,7 +45,6 @@#include "free-space-cache.h" #include "inode-map.h" #include "check-integrity.h" -#include "rcu-string.h" #include "dev-replace.h" #include "raid56.h" #include "sysfs.h"
@@ -3062,7 +3062,7 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)printk_ratelimited_in_rcu (KERN_WARNING "BTRFS: lost page write due to " "I/O error on %s\n" , -rcu_str_deref (device->name)); +rcu_string_dereference (device->name));/* note, we dont' set_buffer_write_io_error because we have * our own ways of dealing with the IO errors */
@@ -3251,7 +3251,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)if (bio_flagged (bio,BIO_EOPNOTSUPP )) {printk_in_rcu ("BTRFS: disabling barriers on dev %s\n" , -rcu_str_deref (device->name)); +rcu_string_dereference (device->name)); device->nobarriers =1 ; }else if (!bio_flagged (bio,BIO_UPTODATE )) { ret = -EIO ;
fs/btrfs/extent_io.c +2 -2
@@ -11,6 +11,7 @@#include <linux/pagevec.h> #include <linux/prefetch.h> #include <linux/cleancache.h> +#include <linux/rcustring.h> #include "extent_io.h" #include "extent_map.h" #include "ctree.h"
@@ -18,7 +19,6 @@#include "volumes.h" #include "check-integrity.h" #include "locking.h" -#include "rcu-string.h" #include "backref.h" static struct kmem_cache *extent_state_cache;
@@ -2075,7 +2075,7 @@ int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical,printk_ratelimited_in_rcu (KERN_INFO "BTRFS: read error corrected: ino %llu off %llu (dev %s sector %llu)\n" ,btrfs_ino (inode), start, -rcu_str_deref (dev->name), sector); +rcu_string_dereference (dev->name), sector);bio_put (bio);return 0 ; }
fs/btrfs/ioctl.c +2 -2
@@ -44,6 +44,7 @@#include <linux/uuid.h> #include <linux/btrfs.h> #include <linux/uaccess.h> +#include <linux/rcustring.h> #include "ctree.h" #include "disk-io.h" #include "transaction.h"
@@ -53,7 +54,6 @@#include "locking.h" #include "inode-map.h" #include "backref.h" -#include "rcu-string.h" #include "send.h" #include "dev-replace.h" #include "props.h"
@@ -1568,7 +1568,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, new_size *= root->sectorsize;printk_in_rcu (KERN_INFO "BTRFS: new size for %s is %llu\n" , -rcu_str_deref (device->name), new_size); +rcu_string_dereference (device->name), new_size);if (new_size > old_size) { trans =btrfs_start_transaction (root,0 );
fs/btrfs/raid56.c +1 -1
@@ -32,6 +32,7 @@#include <linux/list_sort.h> #include <linux/raid/xor.h> #include <linux/vmalloc.h> +#include <linux/rcustring.h> #include <asm/div64.h> #include "ctree.h" #include "extent_map.h"
@@ -42,7 +43,6 @@#include "raid56.h" #include "async-thread.h" #include "check-integrity.h" -#include "rcu-string.h" /* set when additional merges to this rbio are not allowed */ #define RBIO_RMW_LOCKED_BIT 1
fs/btrfs/rcu-string.h deleted +0 -56
56 lines not on this page · raw message
fs/btrfs/scrub.c +8 -7
@@ -18,6 +18,7 @@#include <linux/blkdev.h> #include <linux/ratelimit.h> +#include <linux/rcustring.h> #include "ctree.h" #include "volumes.h" #include "disk-io.h"
@@ -27,7 +28,6 @@#include "extent_io.h" #include "dev-replace.h" #include "check-integrity.h" -#include "rcu-string.h" #include "raid56.h" /*
@@ -562,7 +562,8 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,printk_in_rcu (KERN_WARNING "BTRFS: %s at logical %llu on dev " "%s, sector %llu, root %llu, inode %llu, offset %llu, " "length %llu, links %u (path: %s)\n" , swarn->errstr, - swarn->logical,rcu_str_deref (swarn->dev->name), + swarn->logical, +rcu_string_dereference (swarn->dev->name), (unsigned long long )swarn->sector, root, inum, offset,min (isize - offset, (u64 )PAGE_SIZE ), nlink, (char *)(unsigned long )ipath->fspath->val[i]);
@@ -574,7 +575,7 @@ err:printk_in_rcu (KERN_WARNING "BTRFS: %s at logical %llu on dev " "%s, sector %llu, root %llu, inode %llu, offset %llu: path " "resolving failed with ret=%d\n" , swarn->errstr, - swarn->logical,rcu_str_deref (swarn->dev->name), + swarn->logical,rcu_string_dereference (swarn->dev->name), (unsigned long long )swarn->sector, root, inum, offset, ret);free_ipath (ipath);
@@ -632,7 +633,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)"BTRFS: %s at logical %llu on dev %s, " "sector %llu: metadata %s (level %d) in tree " "%llu\n" , errstr, swarn.logical, -rcu_str_deref (dev->name), +rcu_string_dereference (dev->name), (unsigned long long )swarn.sector, ref_level ?"node" :"leaf" , ret < 0 ? -1 : ref_level,
@@ -831,7 +832,7 @@ out: num_uncorrectable_read_errors);printk_ratelimited_in_rcu (KERN_ERR "BTRFS: " "unable to fixup (nodatasum) error at logical %llu on dev %s\n" , - fixup->logical,rcu_str_deref (fixup->dev->name)); + fixup->logical,rcu_string_dereference (fixup->dev->name)); }btrfs_free_path (path);
@@ -1249,7 +1250,7 @@ corrected_error:spin_unlock (&sctx->stat_lock);printk_ratelimited_in_rcu (KERN_ERR "BTRFS: fixed up error at logical %llu on dev %s\n" , - logical,rcu_str_deref (dev->name)); + logical,rcu_string_dereference (dev->name)); } }else { did_not_correct_error:
@@ -1258,7 +1259,7 @@ did_not_correct_error:spin_unlock (&sctx->stat_lock);printk_ratelimited_in_rcu (KERN_ERR "BTRFS: unable to fixup (regular) error at logical %llu on dev %s\n" , - logical,rcu_str_deref (dev->name)); + logical,rcu_string_dereference (dev->name)); } out:
fs/btrfs/super.c +1 -1
@@ -42,6 +42,7 @@#include <linux/cleancache.h> #include <linux/ratelimit.h> #include <linux/btrfs.h> +#include <linux/rcustring.h> #include "delayed-inode.h" #include "ctree.h" #include "disk-io.h"
@@ -54,7 +55,6 @@#include "volumes.h" #include "export.h" #include "compression.h" -#include "rcu-string.h" #include "dev-replace.h" #include "free-space-cache.h" #include "backref.h"
fs/btrfs/volumes.c +7 -7
@@ -27,6 +27,7 @@#include <linux/kthread.h> #include <linux/raid/pq.h> #include <linux/semaphore.h> +#include <linux/rcustring.h> #include <asm/div64.h> #include "ctree.h" #include "extent_map.h"
@@ -37,7 +38,6 @@#include "raid56.h" #include "async-thread.h" #include "check-integrity.h" -#include "rcu-string.h" #include "math.h" #include "dev-replace.h" #include "sysfs.h"
@@ -6474,7 +6474,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,if (ret <0 ) {printk_in_rcu (KERN_WARNING "BTRFS: " "error %d while searching for dev_stats item for device %s!\n" , - ret,rcu_str_deref (device->name)); + ret,rcu_string_dereference (device->name)); goto out; }
@@ -6485,7 +6485,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,if (ret !=0 ) {printk_in_rcu (KERN_WARNING "BTRFS: " "delete too small dev_stats item for device %s failed %d!\n" , -rcu_str_deref (device->name), ret); +rcu_string_dereference (device->name), ret); goto out; } ret =1 ;
@@ -6498,8 +6498,8 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans, &key, sizeof(*ptr));if (ret <0 ) {printk_in_rcu (KERN_WARNING "BTRFS: " -"insert dev_stats item for device %s failed %d!\n" , -rcu_str_deref (device->name), ret); +"insert dev_stats item for device %s failed %d!\n" , +rcu_string_dereference (device->name), ret); goto out; } }
@@ -6555,7 +6555,7 @@ static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev)return ; printk_ratelimited_in_rcu(KERN_ERR "BTRFS: " "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n", - rcu_str_deref(dev->name), + rcu_string_dereference(dev->name), btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS), btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS), btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS),
@@ -6575,7 +6575,7 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev) printk_in_rcu(KERN_INFO "BTRFS: " "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n", - rcu_str_deref(dev->name), + rcu_string_dereference(dev->name), btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS), btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS), btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS),
include/linux/rcustring.h new file +97 -0
97 lines not on this page · raw message
Signature · 1 line
2.2.1
PATCH RESEND v8 2/3 btrfs: refactor btrfs_device->name updates
In reply to Omar SandovalThe rcu_string API introduced some new sparse errors but also revealed existing ones. First of all, the name in struct btrfs_device should be annotated as __rcu to prevent unsafe reads. Additionally, updates should go through rcu_dereference_protected to make it clear what's going on. This introduces some helper functions that factor out this functionality.
--- fs/btrfs/volumes.c | 93 +++++++++++++++++++++++++++++++++++++----------------- fs/btrfs/volumes.h | 2 +- 2 files changed, 65 insertions(+), 30 deletions(-)
fs/btrfs/volumes.c +64 -29
@@ -53,6 +53,45 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *device);DEFINE_MUTEX (uuid_mutex);static LIST_HEAD (fs_uuids); +/* +* Dereference the device name under the uuid_mutex. +*/ +static inline struct rcu_string * +btrfs_dev_rcu_protected_name (struct btrfs_device *dev) +__must_hold(&uuid_mutex) +{ +return rcu_dereference_protected (dev->name, +lockdep_is_held (&uuid_mutex)); +} + +/* +* Use when the caller is the only possible updater. +*/ +static inline struct rcu_string * +btrfs_dev_rcu_only_name (struct btrfs_device *dev) +{ +return rcu_dereference_protected (dev->name,1 ); +} + +/* +* Rename a device under the uuid_mutex. +*/ +static inline int btrfs_dev_rename (struct btrfs_device *dev,const char *name) +__must_hold(&uuid_mutex) +{ +struct rcu_string *old_name, *new_name; + + new_name =rcu_string_strdup (name,GFP_NOFS ); +if (!new_name) +return -ENOMEM ; + + old_name =btrfs_dev_rcu_protected_name (dev); +rcu_assign_pointer (dev->name, new_name); +rcu_string_free (old_name); + +return 0 ; +} +static struct btrfs_fs_devices *__alloc_fs_devices (void ) {struct btrfs_fs_devices *fs_devs;
@@ -104,7 +143,7 @@ static void free_fs_devices(struct btrfs_fs_devices *fs_devices) device =list_entry (fs_devices->devices.next, struct btrfs_device, dev_list);list_del (&device->dev_list); -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));kfree (device); }kfree (fs_devices);
@@ -485,12 +524,10 @@ static noinline int device_list_add(const char *path,return PTR_ERR (device); } - name =rcu_string_strdup (path,GFP_NOFS ); -if (!name) { +if (btrfs_dev_rename (device, path)) {kfree (device);return -ENOMEM ; } -rcu_assign_pointer (device->name, name);mutex_lock (&fs_devices->device_list_mutex);list_add_rcu (&device->dev_list, &fs_devices->devices);
@@ -499,7 +536,11 @@ static noinline int device_list_add(const char *path, ret =1 ; device->fs_devices = fs_devices; - }else if (!device->name ||strcmp (device->name->str, path)) { + }else { + name =btrfs_dev_rcu_protected_name (device); +if (name &&strcmp (name->str, path) ==0 ) + goto out; +/* * When FS is already mounted. * 1. If you are here and if the device->name is NULL that
@@ -537,17 +578,15 @@ static noinline int device_list_add(const char *path,return -EEXIST ; } - name =rcu_string_strdup (path,GFP_NOFS ); -if (!name) +if (btrfs_dev_rename (device, path))return -ENOMEM ; -rcu_string_free (device->name); -rcu_assign_pointer (device->name, name);if (device->missing) { fs_devices->missing_devices--; device->missing =0 ; } } +out:/* * Unmount does not free the btrfs_device struct but would zero * generation along with most of the other members. So just update
@@ -584,17 +623,12 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)if (IS_ERR (device)) goto error; -/* -* This is ok to do without rcu read locked because we hold the -* uuid mutex so nothing we touch in here is going to disappear. -*/ -if (orig_dev->name) { - name =rcu_string_strdup (orig_dev->name->str,GFP_NOFS ); -if (!name) { + name =btrfs_dev_rcu_protected_name (orig_dev); +if (name) { +if (btrfs_dev_rename (device, name->str)) {kfree (device); goto error; } -rcu_assign_pointer (device->name, name); }list_add (&device->dev_list, &fs_devices->devices);
@@ -656,7 +690,7 @@ again: }list_del_init (&device->dev_list); fs_devices->num_devices--; -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));kfree (device); }
@@ -679,7 +713,7 @@ static void __free_device(struct work_struct *work)if (device->bdev)blkdev_put (device->bdev, device->mode); -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));kfree (device); }
@@ -721,11 +755,10 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) device->uuid);BUG_ON (IS_ERR (new_device));/* -ENOMEM */ -/* Safe because we are under uuid_mutex */ -if (device->name) { - name =rcu_string_strdup (device->name->str,GFP_NOFS ); -BUG_ON (!name);/* -ENOMEM */ -rcu_assign_pointer (new_device->name, name); + name =btrfs_dev_rcu_protected_name (device); +if (name) { +if (btrfs_dev_rename (new_device, name->str)) +BUG_ON (1 );/* -ENOMEM */ }list_replace_rcu (&device->dev_list, &new_device->dev_list);
@@ -784,18 +817,20 @@ static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices,u64 devid;int seeding =1 ;int ret =0 ; +struct rcu_string *name; flags |=FMODE_EXCL ;list_for_each_entry (device, head, dev_list) {if (device->bdev)continue ; -if (!device->name) + name =btrfs_dev_rcu_protected_name (device); +if (!name)continue ;/* Just open everything we can; ignore failures here */ -if (btrfs_get_bdev_and_sb (device->name->str, flags, holder,1 , - &bdev, &bh)) +if (btrfs_get_bdev_and_sb (name->str, flags, holder,1 , &bdev, + &bh))continue ; disk_super = (struct btrfs_super_block *)bh->b_data;
@@ -2142,7 +2177,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) trans =btrfs_start_transaction (root,0 );if (IS_ERR (trans)) { -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));kfree (device); ret =PTR_ERR (trans); goto error;
@@ -2279,7 +2314,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path) error_trans:btrfs_end_transaction (trans, root); -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));btrfs_kobj_rm_device (root->fs_info, device);kfree (device); error:
fs/btrfs/volumes.h +1 -1
@@ -54,7 +54,7 @@ struct btrfs_device {struct btrfs_root *dev_root; -struct rcu_string *name; +struct rcu_string __rcu *name;u64 generation;
Signature · 1 line
2.2.1
PATCH RESEND v8 3/3 btrfs: fix suspicious RCU in BTRFS_IOC_DEV_INFO
In reply to Omar SandovalA naked read of the value of an RCU pointer isn't safe. Put the whole access in an RCU critical section, not just the pointer dereference.
--- fs/btrfs/ioctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/btrfs/ioctl.c +5 -5
@@ -2706,6 +2706,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;int ret =0 ;char *s_uuid =NULL ; +struct rcu_string *name; di_args =memdup_user (arg,sizeof (*di_args));if (IS_ERR (di_args))
@@ -2726,17 +2727,16 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg) di_args->bytes_used =btrfs_device_get_bytes_used (dev); di_args->total_bytes =btrfs_device_get_total_bytes (dev);memcpy (di_args->uuid, dev->uuid,sizeof (di_args->uuid)); -if (dev->name) { -struct rcu_string *name; -rcu_read_lock (); - name =rcu_dereference (dev->name); +rcu_read_lock (); + name =rcu_dereference (dev->name); +if (name) {strncpy (di_args->path, name->str,sizeof (di_args->path)); -rcu_read_unlock (); di_args->path[sizeof (di_args->path) -1 ] =0 ; }else { di_args->path[0 ] ='\0' ; } +rcu_read_unlock (); out:mutex_unlock (&fs_devices->device_list_mutex);
Signature · 1 line
2.2.1
Quoted 4 lines · Omar Sandoval
Hi, everyone,
Now that the merge window and the holidays are over, I've rebased this on v3.19-rc3 for the next merge window.
Wasn't btrfs going to take this one?
If I am supposed to take it, please split out the RCU infrastructure portion so that I can push it separately.
Thanx, Paul
Quoted 62 lines
This patch series introduces the RCU string API and cleans up the wreckage of sparse warnings which follow from it (shown here from when the patch was briefly in the btrfs integration tree):
Quoted 10 lines · kbuild test robot
tree: git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git integration head: c7a37618b60026121255c69e042d74ae5631470c commit: 37aad79d90a0cbf82a5eda62dfe3af4241f5aca3 [38/39] Move BTRFS RCU string to common library reproduce: # apt-get install sparse git checkout 37aad79d90a0cbf82a5eda62dfe3af4241f5aca3 make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__Quoted 5 lines
sparse warnings: (new ones prefixed by >>)
Quoted 1 line
Quoted 1 line
fs/btrfs/check-integrity.c:848:25: sparse: incorrect type in argument 1 (different address spaces)
fs/btrfs/check-integrity.c:848:25: expected structrcu_string[noderef] <asn:4>*rcu_str
fs/btrfs/check-integrity.c:848:25: got structrcu_string*name[snip]
Version 8 combines the original patch with another patch series I posted to fix these warnings, which fixes the botched
__rcuannotations that caused some of the warnings and refactors the existing uses of rcustring to get rid of the rest. There's also a patch to fix an RCU misuse.Thanks!
v8: Get the
__rcuannotations right, clean up RCU string-related sparse noise
v7: Add arguments to kernel doc for printk wrappers, use ##__VA_ARGS
v6: Add header dependencies torcustring.h
v5: Rebase against v3.18-rc3
v4: Don't return anything from the printk wrappers on the assumption that printk will return void someday
v3: Add__rcuannotation to relevant functions, add Paul's ack and Josh's reviewOmar Sandoval (3):
Move BTRFS RCU string to common library
btrfs: refactorbtrfs_device->nameupdates
btrfs: fix suspicious RCU inBTRFS_IOC_DEV_INFOfs/btrfs/check-integrity.c | 6 +-- fs/btrfs/dev-replace.c | 19 ++++---- fs/btrfs/disk-io.c | 6 +-- fs/btrfs/extent_io.c | 4 +- fs/btrfs/ioctl.c | 14 +++--- fs/btrfs/raid56.c | 2 +- fs/btrfs/rcu-string.h | 56 ------------------------ fs/btrfs/scrub.c | 15 ++++--- fs/btrfs/super.c | 2 +- fs/btrfs/volumes.c | 107 ++++++++++++++++++++++++++++++--------------- fs/btrfs/volumes.h | 2 +- include/linux/rcustring.h | 97 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 204 insertions(+), 126 deletions(-) delete mode 100644 fs/btrfs/rcu-string.h create mode 100644 include/linux/rcustring.hSignature · 1 line
2.2.1
Quoted 6 lines · Paul E. McKenney
Quoted 4 lines · Omar Sandoval
Hi, everyone,
Now that the merge window and the holidays are over, I've rebased this on v3.19-rc3 for the next merge window.
Quoted 70 lines
Wasn't btrfs going to take this one?
If I am supposed to take it, please split out the RCU infrastructure portion so that I can push it separately.
Thanx, Paul
Quoted 62 lines
This patch series introduces the RCU string API and cleans up the wreckage of sparse warnings which follow from it (shown here from when the patch was briefly in the btrfs integration tree):
Quoted 10 lines · kbuild test robot
tree: git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs.git integration head: c7a37618b60026121255c69e042d74ae5631470c commit: 37aad79d90a0cbf82a5eda62dfe3af4241f5aca3 [38/39] Move BTRFS RCU string to common library reproduce: # apt-get install sparse git checkout 37aad79d90a0cbf82a5eda62dfe3af4241f5aca3 make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__Quoted 5 lines
sparse warnings: (new ones prefixed by >>)
Quoted 1 line
Quoted 1 line
fs/btrfs/check-integrity.c:848:25: sparse: incorrect type in argument 1 (different address spaces)
fs/btrfs/check-integrity.c:848:25: expected structrcu_string[noderef] <asn:4>*rcu_str
fs/btrfs/check-integrity.c:848:25: got structrcu_string*name[snip]
Version 8 combines the original patch with another patch series I posted to fix these warnings, which fixes the botched
__rcuannotations that caused some of the warnings and refactors the existing uses of rcustring to get rid of the rest. There's also a patch to fix an RCU misuse.Thanks!
v8: Get the
__rcuannotations right, clean up RCU string-related sparse noise
v7: Add arguments to kernel doc for printk wrappers, use ##__VA_ARGS
v6: Add header dependencies torcustring.h
v5: Rebase against v3.18-rc3
v4: Don't return anything from the printk wrappers on the assumption that printk will return void someday
v3: Add__rcuannotation to relevant functions, add Paul's ack and Josh's reviewOmar Sandoval (3):
Move BTRFS RCU string to common library
btrfs: refactorbtrfs_device->nameupdates
btrfs: fix suspicious RCU inBTRFS_IOC_DEV_INFOfs/btrfs/check-integrity.c | 6 +-- fs/btrfs/dev-replace.c | 19 ++++---- fs/btrfs/disk-io.c | 6 +-- fs/btrfs/extent_io.c | 4 +- fs/btrfs/ioctl.c | 14 +++--- fs/btrfs/raid56.c | 2 +- fs/btrfs/rcu-string.h | 56 ------------------------ fs/btrfs/scrub.c | 15 ++++--- fs/btrfs/super.c | 2 +- fs/btrfs/volumes.c | 107 ++++++++++++++++++++++++++++++--------------- fs/btrfs/volumes.h | 2 +- include/linux/rcustring.h | 97 ++++++++++++++++++++++++++++++++++++++++ 12 files changed, 204 insertions(+), 126 deletions(-) delete mode 100644 fs/btrfs/rcu-string.h create mode 100644 include/linux/rcustring.hSignature · 1 line
2.2.1
Hi, Paul,
I believe Chris is still going to take this one, just wanted to keep you and the RCU reviewers in the loop.
Thanks!
Signature · 1 line
Omar