Btrfs: bugs found by sparse and RCU strings
Subsystems (2)
cover Btrfs: bugs found by sparse and RCU strings
From: Omar Sandoval <[email protected]>
I came across my ancient RCU string branch [1] and decided to revive it and finally put it to rest. In the process of checking it with sparse, I found a handful of other issues.
Patch 1 should probably go in 4.13, as it fixes bugs introduced this cycle by the conversion to blk_status_t. Patch 2 is an old bug, so it could wait for 4.14 but it might as well go in for 4.13. Patches 3-5 are the RCU string series. Patches 6 and 7 are minor cleanups found by sparse. Patches 3-7 can wait for 4.14 or 4.15.
Based on 4.13-rc6.
Thanks!
1: https://lwn.net/Articles/629048/
Omar Sandoval (7):
Btrfs: fix blk_status_t/errno confusion
Btrfs: fix incorrect {node,sector}size endianness from
BTRFS_IOC_FS_INFO
Move Btrfs RCU string to common library
Btrfs: refactor btrfs_device->name updates
Btrfs: fix suspicious RCU in BTRFS_IOC_DEV_INFO
Btrfs: make some volumes.c functions static
Btrfs: fix __user casting in ioctl.c
fs/btrfs/check-integrity.c | 12 +-- fs/btrfs/dev-replace.c | 37 +++++---- fs/btrfs/disk-io.c | 10 +-- fs/btrfs/extent_io.c | 8 +- fs/btrfs/inode.c | 70 ++++++++-------- fs/btrfs/ioctl.c | 30 +++---- fs/btrfs/raid56.c | 35 ++++---- fs/btrfs/rcu-string.h | 56 ------------- fs/btrfs/scrub.c | 42 +++++----- fs/btrfs/super.c | 7 +- fs/btrfs/volumes.c | 199 +++++++++++++++++++++++++++------------------ fs/btrfs/volumes.h | 8 +- include/linux/rcustring.h | 97 ++++++++++++++++++++++ 13 files changed, 351 insertions(+), 260 deletions(-) delete mode 100644 fs/btrfs/rcu-string.h create mode 100644 include/linux/rcustring.h
Signature · 1 line
2.14.1
PATCH 1/7 Btrfs: fix blk_status_t/errno confusion
From: Omar Sandoval <[email protected]>
This fixes several instances of blk_status_t and bare errno ints being mixed up, some of which are real bugs.
--- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/inode.c | 70 +++++++++++++++++++++++++++++------------------------- fs/btrfs/raid56.c | 34 +++++++++++++------------- fs/btrfs/volumes.c | 10 ++++---- fs/btrfs/volumes.h | 6 ++--- 5 files changed, 64 insertions(+), 60 deletions(-)
fs/btrfs/disk-io.c +2 -2
@@ -3516,7 +3516,7 @@ static blk_status_t wait_dev_flush(struct btrfs_device *device)struct bio *bio = device->flush_bio;if (!device->flush_bio_sent) -return 0 ; +return BLK_STS_OK ; device->flush_bio_sent =0 ;wait_for_completion_io (&device->flush_wait);
@@ -3563,7 +3563,7 @@ static int barrier_all_devices(struct btrfs_fs_info *info)continue ;write_dev_flush (dev); - dev->last_flush_error =0 ; + dev->last_flush_error =BLK_STS_OK ; }/* wait for all the barriers */
fs/btrfs/inode.c +37 -33
168 lines not on this page · raw message
fs/btrfs/raid56.c +17 -17
@@ -905,7 +905,7 @@ static void raid_write_end_io(struct bio *bio)if (!atomic_dec_and_test (&rbio->stripes_pending))return ; - err =0 ; + err =BLK_STS_OK ;/* OK, we have read all the stripes we need to. */ max_errors = (rbio->operation == BTRFS_RBIO_PARITY_SCRUB) ?
@@ -1324,7 +1324,7 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio)return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }/*
@@ -1475,7 +1475,7 @@ static void raid_rmw_end_io(struct bio *bio) cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }static void async_rmw_stripe (struct btrfs_raid_bio *rbio)
@@ -1579,7 +1579,7 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio)return 0 ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );return -EIO ; finish:
@@ -1795,12 +1795,12 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)void **pointers;int faila =-1 , failb =-1 ;struct page *page; -int err; +blk_status_t err;int i; pointers =kcalloc (rbio->real_stripes,sizeof (void *),GFP_NOFS );if (!pointers) { - err = -ENOMEM ; + err =BLK_STS_RESOURCE ; goto cleanup_io; }
@@ -1856,7 +1856,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)* a bad data or Q stripe. * TODO, we should redo the xor here. */ - err = -EIO ; + err =BLK_STS_IOERR ; goto cleanup; }/*
@@ -1882,7 +1882,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)if (rbio->bbio->raid_map[failb] ==RAID6_Q_STRIPE ) {if (rbio->bbio->raid_map[faila] ==RAID5_P_STRIPE ) { - err = -EIO ; + err =BLK_STS_IOERR ; goto cleanup; }/*
@@ -1954,13 +1954,13 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) } } - err =0 ; + err =BLK_STS_OK ; cleanup:kfree (pointers); cleanup_io:if (rbio->operation ==BTRFS_RBIO_READ_REBUILD ) { -if (err ==0 ) +if (err ==BLK_STS_OK )cache_rbio_pages (rbio);else clear_bit (RBIO_CACHE_READY_BIT , &rbio->flags);
@@ -1968,7 +1968,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)rbio_orig_end_io (rbio, err); }else if (rbio->operation ==BTRFS_RBIO_REBUILD_MISSING ) {rbio_orig_end_io (rbio, err); - }else if (err ==0 ) { + }else if (err ==BLK_STS_OK ) { rbio->faila =-1 ; rbio->failb =-1 ;
@@ -2005,7 +2005,7 @@ static void raid_recover_end_io(struct bio *bio)return ;if (atomic_read (&rbio->error) > rbio->bbio->max_errors) -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );else __raid_recover_end_io (rbio); }
@@ -2104,7 +2104,7 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) cleanup:if (rbio->operation ==BTRFS_RBIO_READ_REBUILD || rbio->operation ==BTRFS_RBIO_REBUILD_MISSING ) -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );return -EIO ; }
@@ -2431,7 +2431,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, nr_data =bio_list_size (&bio_list);if (!nr_data) {/* Every parity is right */ -rbio_orig_end_io (rbio,0 ); +rbio_orig_end_io (rbio,BLK_STS_OK );return ; }
@@ -2451,7 +2451,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }static inline int is_data_stripe (struct btrfs_raid_bio *rbio,int stripe)
@@ -2519,7 +2519,7 @@ static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio)return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }/*
@@ -2633,7 +2633,7 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio)return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );return ; finish:
fs/btrfs/volumes.c +5 -5
@@ -6212,8 +6212,8 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) } } -int btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, -int mirror_num,int async_submit) +blk_status_t btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, +int mirror_num,int async_submit) {struct btrfs_device *dev;struct bio *first_bio = bio;
@@ -6233,7 +6233,7 @@ int btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, &map_length, &bbio, mirror_num, 1);if (ret) {btrfs_bio_counter_dec (fs_info); -return ret; +return errno_to_blk_status (ret); } total_devs = bbio->num_stripes;
@@ -6256,7 +6256,7 @@ int btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, }btrfs_bio_counter_dec (fs_info); -return ret; +return errno_to_blk_status (ret); }if (map_length < length) {
@@ -6283,7 +6283,7 @@ int btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, dev_nr, async_submit); }btrfs_bio_counter_dec (fs_info); -return 0 ; +return BLK_STS_OK ; } struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,
fs/btrfs/volumes.h +3 -3
@@ -74,7 +74,7 @@ struct btrfs_device {int missing;int can_discard;int is_tgtdev_for_dev_replace; -int last_flush_error; +blk_status_t last_flush_error;int flush_bio_sent;#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
@@ -416,8 +416,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 type);void btrfs_mapping_init (struct btrfs_mapping_tree *tree);void btrfs_mapping_tree_free (struct btrfs_mapping_tree *tree); -int btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, -int mirror_num,int async_submit); +blk_status_t btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, +int mirror_num,int async_submit);int btrfs_open_devices (struct btrfs_fs_devices *fs_devices,fmode_t flags,void *holder); int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
Signature · 1 line
2.14.1
Re: [PATCH 1/7] Btrfs: fix blk_status_t/errno confusion
Quoted 4 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
This fixes several instances of
blk_status_tand bare errno ints being mixed up, some of which are real bugs.
The real bugs are lurking in the error cases, other than BLK_STS_OK that is equivalent to the old return values.
Seems like blk_status_t conversion of raid56.c has been entirely skipped, and maybe some of the changes brought by the btrfs pull. Thanks for catching it. I'll prepare a pull request with this one for 4.13-rc7. The other patch 2/7 is not that urgent and can wait.
Re: [PATCH 1/7] Btrfs: fix blk_status_t/errno confusion
In reply to Omar SandovalQuoted 47 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
This fixes several instances of
blk_status_tand bare errno ints being mixed up, some of which are real bugs.Fixes 4e4cbee93d56 ("block: switch bios to blk_status_t")Signed-off-by Omar Sandoval <[email protected]>--- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/inode.c | 70 +++++++++++++++++++++++++++++------------------------- fs/btrfs/raid56.c | 34 +++++++++++++------------- fs/btrfs/volumes.c | 10 ++++---- fs/btrfs/volumes.h | 6 ++--- 5 files changed, 64 insertions(+), 60 deletions(-)fs/btrfs/disk-io.c +2
-2@@ -3516,7 +3516,7 @@ static blk_status_t wait_dev_flush(struct btrfs_device *device)struct bio *bio = device->flush_bio;if (!device->flush_bio_sent) -return 0 ; +return BLK_STS_OK ; device->flush_bio_sent =0 ;wait_for_completion_io (&device->flush_wait);@@ -3563,7 +3563,7 @@ static int barrier_all_devices(struct btrfs_fs_info *info)continue ;write_dev_flush (dev); - dev->last_flush_error =0 ; + dev->last_flush_error =BLK_STS_OK ; }/* wait for all the barriers */ fs/btrfs/inode.c +0
-2@@ -7924,11 +7924,12 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,return ret; } -static inline int submit_dio_repair_bio (struct inode *inode,struct bio *bio, -int mirror_num)
fs/btrfs/inode.c static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, · line 7935
Quoted 10 lines
fs/btrfs/inode.c +4
-1+static inline blk_status_t submit_dio_repair_bio (struct inode *inode, +struct bio *bio, +int mirror_num) {struct btrfs_fs_info *fs_info =btrfs_sb (inode->i_sb); -int ret; +blk_status_t ret;BUG_ON (bio_op (bio) ==REQ_OP_WRITE );
In this function, there is btrfs_map_bio() who returns 0 or error code, errno_to_blk_status() is also needed for that conversion.
With that,
Thanks,
-liubo
Quoted 390 lines
fs/btrfs/inode.c +33
-30@@ -7980,10 +7981,10 @@ static int btrfs_check_dio_repairable(struct inode *inode,return 1 ; } -static int dio_read_error (struct inode *inode,struct bio *failed_bio, -struct page *page,unsigned int pgoff, -u64 start,u64 end,int failed_mirror, -bio_end_io_t *repair_endio,void *repair_arg) +static blk_status_t dio_read_error (struct inode *inode,struct bio *failed_bio, +struct page *page,unsigned int pgoff, +u64 start,u64 end,int failed_mirror, +bio_end_io_t *repair_endio,void *repair_arg) {struct io_failure_record *failrec;struct extent_io_tree *io_tree = &BTRFS_I (inode)->io_tree;@@ -7993,18 +7994,19 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,int read_mode =0 ;int segs;int ret; +blk_status_t status;BUG_ON (bio_op (failed_bio) ==REQ_OP_WRITE ); ret =btrfs_get_io_failure_record (inode, start, end, &failrec);if (ret) -return ret; +return errno_to_blk_status (ret); ret =btrfs_check_dio_repairable (inode, failed_bio, failrec, failed_mirror);if (!ret) {free_io_failure (failure_tree, io_tree, failrec); -return -EIO ; +return BLK_STS_IOERR ; } segs =bio_segments (failed_bio);@@ -8022,13 +8024,13 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,"Repair DIO Read Error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d\n" , read_mode, failrec->this_mirror, failrec->in_validation); - ret =submit_dio_repair_bio (inode, bio, failrec->this_mirror); -if (ret) { + status =submit_dio_repair_bio (inode, bio, failrec->this_mirror); +if (status) {free_io_failure (failure_tree, io_tree, failrec);bio_put (bio); } -return ret; +return status; }struct btrfs_retry_complete {@@ -8065,8 +8067,8 @@ static void btrfs_retry_endio_nocsum(struct bio *bio)bio_put (bio); } -static int __btrfs_correct_data_nocsum (struct inode *inode, -struct btrfs_io_bio *io_bio) +static blk_status_t __btrfs_correct_data_nocsum (struct inode *inode, +struct btrfs_io_bio *io_bio) {struct btrfs_fs_info *fs_info;struct bio_vec bvec;@@ -8076,8 +8078,8 @@ static int __btrfs_correct_data_nocsum(struct inode *inode,unsigned int pgoff;u32 sectorsize;int nr_sectors; -int ret; -int err =0 ; +blk_status_t ret; +blk_status_t err =BLK_STS_OK ; fs_info =BTRFS_I (inode)->root->fs_info; sectorsize = fs_info->sectorsize;@@ -8183,11 +8185,12 @@ static blk_status_t __btrfs_subio_endio_read(struct inode *inode,int csum_pos;bool uptodate = (err ==0 );int ret; +blk_status_t status; fs_info =BTRFS_I (inode)->root->fs_info; sectorsize = fs_info->sectorsize; - err =0 ; + err =BLK_STS_OK ; start = io_bio->logical; done.inode = inode; io_bio->bio.bi_iter = io_bio->iter;@@ -8209,12 +8212,12 @@ static blk_status_t __btrfs_subio_endio_read(struct inode *inode, done.start = start;init_completion (&done.done); - ret =dio_read_error (inode, &io_bio->bio, bvec.bv_page, - pgoff, start, start + sectorsize -1 , - io_bio->mirror_num, - btrfs_retry_endio, &done); -if (ret) { - err =errno_to_blk_status (ret); + status =dio_read_error (inode, &io_bio->bio, bvec.bv_page, + pgoff, start, start + sectorsize -1 , + io_bio->mirror_num, btrfs_retry_endio, + &done); +if (status) { + err = status; goto next; }@@ -8250,7 +8253,7 @@ static blk_status_t btrfs_subio_endio_read(struct inode *inode,if (unlikely (err))return __btrfs_correct_data_nocsum (inode, io_bio);else -return 0 ; +return BLK_STS_OK ; }else {return __btrfs_subio_endio_read (inode, io_bio, err); }@@ -8423,9 +8426,9 @@ static inline blk_status_t btrfs_lookup_and_bind_dio_csum(struct inode *inode,return 0 ; } -static inline int __btrfs_submit_dio_bio (struct bio *bio,struct inode *inode, -u64 file_offset,int skip_sum, -int async_submit) +static inline blk_status_t +__btrfs_submit_dio_bio (struct bio *bio,struct inode *inode,u64 file_offset, +int skip_sum,int async_submit) {struct btrfs_fs_info *fs_info =btrfs_sb (inode->i_sb);struct btrfs_dio_private *dip = bio->bi_private;@@ -8488,6 +8491,7 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,int clone_offset =0 ;int clone_len;int ret; +blk_status_t status; map_length = orig_bio->bi_iter.bi_size; submit_len = map_length;@@ -8537,9 +8541,9 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip,*/ atomic_inc (&dip->pending_bios); - ret =__btrfs_submit_dio_bio (bio, inode, file_offset, skip_sum, - async_submit); -if (ret) { + status =__btrfs_submit_dio_bio (bio, inode, file_offset, skip_sum, + async_submit); +if (status) {bio_put (bio);atomic_dec (&dip->pending_bios); goto out_err;@@ -8557,9 +8561,9 @@ static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip, }while (submit_len >0 ); submit: - ret =__btrfs_submit_dio_bio (bio, inode, file_offset, skip_sum, - async_submit); -if (!ret) + status =__btrfs_submit_dio_bio (bio, inode, file_offset, skip_sum, + async_submit); +if (!status)return 0 ;bio_put (bio);fs/btrfs/raid56.c +17
-17@@ -905,7 +905,7 @@ static void raid_write_end_io(struct bio *bio)if (!atomic_dec_and_test (&rbio->stripes_pending))return ; - err =0 ; + err =BLK_STS_OK ;/* OK, we have read all the stripes we need to. */ max_errors = (rbio->operation == BTRFS_RBIO_PARITY_SCRUB) ?@@ -1324,7 +1324,7 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio)return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }/* @@ -1475,7 +1475,7 @@ static void raid_rmw_end_io(struct bio *bio) cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }static void async_rmw_stripe (struct btrfs_raid_bio *rbio)@@ -1579,7 +1579,7 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio)return 0 ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );return -EIO ; finish:@@ -1795,12 +1795,12 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)void **pointers;int faila =-1 , failb =-1 ;struct page *page; -int err; +blk_status_t err;int i; pointers =kcalloc (rbio->real_stripes,sizeof (void *),GFP_NOFS );if (!pointers) { - err = -ENOMEM ; + err =BLK_STS_RESOURCE ; goto cleanup_io; }@@ -1856,7 +1856,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)* a bad data or Q stripe. * TODO, we should redo the xor here. */ - err = -EIO ; + err =BLK_STS_IOERR ; goto cleanup; }/* @@ -1882,7 +1882,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)if (rbio->bbio->raid_map[failb] ==RAID6_Q_STRIPE ) {if (rbio->bbio->raid_map[faila] ==RAID5_P_STRIPE ) { - err = -EIO ; + err =BLK_STS_IOERR ; goto cleanup; }/* @@ -1954,13 +1954,13 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) } } - err =0 ; + err =BLK_STS_OK ; cleanup:kfree (pointers); cleanup_io:if (rbio->operation ==BTRFS_RBIO_READ_REBUILD ) { -if (err ==0 ) +if (err ==BLK_STS_OK )cache_rbio_pages (rbio);else clear_bit (RBIO_CACHE_READY_BIT , &rbio->flags);@@ -1968,7 +1968,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)rbio_orig_end_io (rbio, err); }else if (rbio->operation ==BTRFS_RBIO_REBUILD_MISSING ) {rbio_orig_end_io (rbio, err); - }else if (err ==0 ) { + }else if (err ==BLK_STS_OK ) { rbio->faila =-1 ; rbio->failb =-1 ;@@ -2005,7 +2005,7 @@ static void raid_recover_end_io(struct bio *bio)return ;if (atomic_read (&rbio->error) > rbio->bbio->max_errors) -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );else __raid_recover_end_io (rbio); }@@ -2104,7 +2104,7 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) cleanup:if (rbio->operation ==BTRFS_RBIO_READ_REBUILD || rbio->operation ==BTRFS_RBIO_REBUILD_MISSING ) -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );return -EIO ; }@@ -2431,7 +2431,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, nr_data =bio_list_size (&bio_list);if (!nr_data) {/* Every parity is right */ -rbio_orig_end_io (rbio,0 ); +rbio_orig_end_io (rbio,BLK_STS_OK );return ; }@@ -2451,7 +2451,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }static inline int is_data_stripe (struct btrfs_raid_bio *rbio,int stripe)@@ -2519,7 +2519,7 @@ static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio)return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR ); }/* @@ -2633,7 +2633,7 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio)return ; cleanup: -rbio_orig_end_io (rbio, -EIO ); +rbio_orig_end_io (rbio,BLK_STS_IOERR );return ; finish:fs/btrfs/volumes.c +5
-5@@ -6212,8 +6212,8 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) } } -int btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, -int mirror_num,int async_submit) +blk_status_t btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, +int mirror_num,int async_submit) {struct btrfs_device *dev;struct bio *first_bio = bio;@@ -6233,7 +6233,7 @@ int btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, &map_length, &bbio, mirror_num, 1);if (ret) {btrfs_bio_counter_dec (fs_info); -return ret; +return errno_to_blk_status (ret); } total_devs = bbio->num_stripes;@@ -6256,7 +6256,7 @@ int btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, }btrfs_bio_counter_dec (fs_info); -return ret; +return errno_to_blk_status (ret); }if (map_length < length) {@@ -6283,7 +6283,7 @@ int btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio, dev_nr, async_submit); }btrfs_bio_counter_dec (fs_info); -return 0 ; +return BLK_STS_OK ; } struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid,fs/btrfs/volumes.h +3
-3@@ -74,7 +74,7 @@ struct btrfs_device {int missing;int can_discard;int is_tgtdev_for_dev_replace; -int last_flush_error; +blk_status_t last_flush_error;int flush_bio_sent;#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED@@ -416,8 +416,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, u64 type);void btrfs_mapping_init (struct btrfs_mapping_tree *tree);void btrfs_mapping_tree_free (struct btrfs_mapping_tree *tree); -int btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, -int mirror_num,int async_submit); +blk_status_t btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, +int mirror_num,int async_submit);int btrfs_open_devices (struct btrfs_fs_devices *fs_devices,fmode_t flags,void *holder); int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,Signature · 6 lines
2.14.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 1/7] Btrfs: fix blk_status_t/errno confusion
Quoted 56 lines · Liu Bo
Quoted 55 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
This fixes several instances of
blk_status_tand bare errno ints being mixed up, some of which are real bugs.Fixes 4e4cbee93d56 ("block: switch bios to blk_status_t")Signed-off-by Omar Sandoval <[email protected]>--- fs/btrfs/disk-io.c | 4 ++-- fs/btrfs/inode.c | 70 +++++++++++++++++++++++++++++------------------------- fs/btrfs/raid56.c | 34 +++++++++++++------------- fs/btrfs/volumes.c | 10 ++++---- fs/btrfs/volumes.h | 6 ++--- 5 files changed, 64 insertions(+), 60 deletions(-)fs/btrfs/disk-io.c +2
-2@@ -3516,7 +3516,7 @@ static blk_status_t wait_dev_flush(struct btrfs_device *device)struct bio *bio = device->flush_bio;if (!device->flush_bio_sent) -return 0 ; +return BLK_STS_OK ; device->flush_bio_sent =0 ;wait_for_completion_io (&device->flush_wait);@@ -3563,7 +3563,7 @@ static int barrier_all_devices(struct btrfs_fs_info *info)continue ;write_dev_flush (dev); - dev->last_flush_error =0 ; + dev->last_flush_error =BLK_STS_OK ; }/* wait for all the barriers */ fs/btrfs/inode.c +4
-3@@ -7924,11 +7924,12 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,return ret; } -static inline int submit_dio_repair_bio (struct inode *inode,struct bio *bio, -int mirror_num) +static inline blk_status_t submit_dio_repair_bio (struct inode *inode, +struct bio *bio, +int mirror_num) {struct btrfs_fs_info *fs_info =btrfs_sb (inode->i_sb); -int ret; +blk_status_t ret;
Quoted 5 lines
fs/btrfs/inode.c static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, · line 7935
Quoted 2 lines
fs/btrfs/inode.c +0
-0BUG_ON (bio_op (bio) ==REQ_OP_WRITE );In this function, there is
btrfs_map_bio()who returns 0 or error code,errno_to_blk_status()is also needed for that conversion.
See below, btrfs_map_bio() returns blk_status_t now.
Quoted 3 lines
With that,
Reviewed-by Liu Bo <[email protected]>
Thanks!
Quoted 12 lines
Quoted 12 lines
fs/btrfs/volumes.c +2
-2@@ -6212,8 +6212,8 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) } } -int btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, -int mirror_num,int async_submit) +blk_status_t btrfs_map_bio (struct btrfs_fs_info *fs_info,struct bio *bio, +int mirror_num,int async_submit)
PATCH 2/7 Btrfs: fix incorrect {node,sector}size endianness from BTRFS_IOC_FS_INFO
In reply to Omar SandovalFrom: Omar Sandoval <[email protected]>
fs_info->super_copy->{node,sector}size are little-endian, but the ioctl should return the values in native endianness. Use the cached values in btrfs_fs_info instead. Found with sparse.
--- fs/btrfs/ioctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/btrfs/ioctl.c +3 -3
@@ -2804,9 +2804,9 @@ static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info, }mutex_unlock (&fs_devices->device_list_mutex); - fi_args->nodesize = fs_info->super_copy->nodesize; - fi_args->sectorsize = fs_info->super_copy->sectorsize; - fi_args->clone_alignment = fs_info->super_copy->sectorsize; + fi_args->nodesize = fs_info->nodesize; + fi_args->sectorsize = fs_info->sectorsize; + fi_args->clone_alignment = fs_info->sectorsize;if (copy_to_user (arg, fi_args,sizeof (*fi_args))) ret = -EFAULT ;
Signature · 1 line
2.14.1
Re: [PATCH 2/7] Btrfs: fix incorrect {node,sector}size endianness from BTRFS_IOC_FS_INFO
Quoted 8 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
fs_info->super_copy->{node,sector}size are little-endian, but the ioctl should return the values in native endianness. Use the cached values in
btrfs_fs_infoinstead. Found with sparse.Fixes 80a773fbfc2d ("btrfs: retrieve more info from FS_INFO ioctl")Signed-off-by Omar Sandoval <[email protected]>
PATCH 3/7 Move Btrfs RCU string to common library
In reply to Omar SandovalFrom: Omar Sandoval <[email protected]>
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 | 12 +++--- fs/btrfs/dev-replace.c | 37 +++++++++--------- fs/btrfs/disk-io.c | 6 +-- fs/btrfs/extent_io.c | 8 ++-- fs/btrfs/ioctl.c | 4 +- fs/btrfs/raid56.c | 1 - fs/btrfs/rcu-string.h | 56 -------------------------- fs/btrfs/scrub.c | 42 ++++++++++---------- fs/btrfs/super.c | 7 ++-- fs/btrfs/volumes.c | 58 ++++++++++++++------------- include/linux/rcustring.h | 97 ++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 187 insertions(+), 141 deletions(-) delete mode 100644 fs/btrfs/rcu-string.h create mode 100644 include/linux/rcustring.h
fs/btrfs/check-integrity.c +6 -6
@@ -95,6 +95,7 @@#include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/mm.h> +#include <linux/rcustring.h> #include <linux/string.h> #include "ctree.h" #include "disk-io.h"
@@ -105,7 +106,6 @@#include "print-tree.h" #include "locking.h" #include "check-integrity.h" -#include "rcu-string.h" #include "compression.h" #define BTRFSIC_BLOCK_HASHTABLE_SIZE 0x10000
@@ -834,11 +834,11 @@ static int btrfsic_process_superblock_dev_mirror( superblock_tmp->mirror_num =1 + superblock_mirror_num;if (state->print_mask &BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE )btrfs_info_in_rcu (fs_info, -"new initial S-block (bdev %p, %s) @%llu (%s/%llu/%d)" , - superblock_bdev, -rcu_str_deref (device->name), dev_bytenr, - dev_state->name, dev_bytenr, - superblock_mirror_num); +"new initial S-block (bdev %p, %s) @%llu (%s/%llu/%d)" , + superblock_bdev, +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); btrfsic_block_hashtable_add(superblock_tmp,
fs/btrfs/dev-replace.c +19 -18
@@ -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"
@@ -362,11 +362,11 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info, dev_replace->tgtdev = tgt_device;btrfs_info_in_rcu (fs_info, -"dev_replace from %s (devid %llu) to %s started" , - src_device->missing ?"<missing disk>" : -rcu_str_deref (src_device->name), - src_device->devid, -rcu_str_deref (tgt_device->name)); +"dev_replace from %s (devid %llu) to %s started" , + src_device->missing ?"<missing disk>" : +rcu_string_dereference (src_device->name), + src_device->devid, +rcu_string_dereference (tgt_device->name));/* * from now on, the writes to the srcdev are all duplicated to
@@ -539,9 +539,10 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,btrfs_err_in_rcu (fs_info,"btrfs_scrub_dev(%s, %llu, %s) failed %d" , 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,1 );mutex_unlock (&fs_info->chunk_mutex);mutex_unlock (&fs_info->fs_devices->device_list_mutex);
@@ -558,9 +559,9 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,btrfs_info_in_rcu (fs_info,"dev_replace from %s (devid %llu) to %s finished" , 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 ;
@@ -805,14 +806,14 @@ static int btrfs_dev_replace_kthread(void *data)kfree (status_args); progress =div_u64 (progress,10 );btrfs_info_in_rcu (fs_info, -"continuing dev_replace from %s (devid %llu) to %s @%u%%" , - dev_replace->srcdev->missing ?"<missing disk>" : -rcu_str_deref (dev_replace->srcdev->name), - dev_replace->srcdev->devid, - dev_replace->tgtdev ? -rcu_str_deref (dev_replace->tgtdev->name) : -"<missing target disk>" , - (unsigned int )progress); +"continuing dev_replace from %s (devid %llu) to %s @%u%%" , + dev_replace->srcdev->missing ?"<missing disk>" : +rcu_string_dereference (dev_replace->srcdev->name), + dev_replace->srcdev->devid, + dev_replace->tgtdev ? +rcu_string_dereference (dev_replace->tgtdev->name) : +"<missing target disk>" , + (unsigned int )progress); }btrfs_dev_replace_continue_on_mount (fs_info);clear_bit (BTRFS_FS_EXCL_OP , &fs_info->flags);
fs/btrfs/disk-io.c +3 -3
@@ -28,6 +28,7 @@#include <linux/slab.h> #include <linux/migrate.h> #include <linux/ratelimit.h> +#include <linux/rcustring.h> #include <linux/uuid.h> #include <linux/semaphore.h> #include <asm/unaligned.h>
@@ -44,7 +45,6 @@#include "free-space-tree.h" #include "inode-map.h" #include "check-integrity.h" -#include "rcu-string.h" #include "dev-replace.h" #include "raid56.h" #include "sysfs.h"
@@ -3298,8 +3298,8 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) bh->b_private;btrfs_warn_rl_in_rcu (device->fs_info, -"lost page write due to IO error on %s" , -rcu_str_deref (device->name)); +"lost page write due to IO error on %s" , +rcu_string_dereference (device->name));/* note, we don't set_buffer_write_io_error because we have * our own ways of dealing with the IO errors */
fs/btrfs/extent_io.c +4 -4
@@ -6,6 +6,7 @@#include <linux/page-flags.h> #include <linux/spinlock.h> #include <linux/blkdev.h> +#include <linux/rcustring.h> #include <linux/swap.h> #include <linux/writeback.h> #include <linux/pagevec.h>
@@ -18,7 +19,6 @@#include "volumes.h" #include "check-integrity.h" #include "locking.h" -#include "rcu-string.h" #include "backref.h" #include "transaction.h"
@@ -2046,9 +2046,9 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start, }btrfs_info_rl_in_rcu (fs_info, -"read error corrected: ino %llu off %llu (dev %s sector %llu)" , - ino, start, -rcu_str_deref (dev->name), sector); +"read error corrected: ino %llu off %llu (dev %s sector %llu)" , + ino, start,rcu_string_dereference (dev->name), + sector);btrfs_bio_counter_dec (fs_info);bio_put (bio);return 0 ;
fs/btrfs/ioctl.c +2 -2
@@ -31,6 +31,7 @@#include <linux/mount.h> #include <linux/mpage.h> #include <linux/namei.h> +#include <linux/rcustring.h> #include <linux/swap.h> #include <linux/writeback.h> #include <linux/compat.h>
@@ -52,7 +53,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"
@@ -1604,7 +1604,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, new_size *= fs_info->sectorsize;btrfs_info_in_rcu (fs_info,"new size for %s is %llu" , -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 +0 -1
@@ -42,7 +42,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 +22 -20
101 lines not on this page · raw message
fs/btrfs/super.c +3 -4
@@ -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"
@@ -2221,7 +2221,6 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)struct btrfs_fs_devices *cur_devices;struct btrfs_device *dev, *first_dev =NULL ;struct list_head *head; -struct rcu_string *name;mutex_lock (&fs_info->fs_devices->device_list_mutex); cur_devices = fs_info->fs_devices;
@@ -2240,8 +2239,8 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)if (first_dev) {rcu_read_lock (); - name =rcu_dereference (first_dev->name); -seq_escape (m, name->str," \t\n\\" ); +seq_escape (m,rcu_string_dereference (first_dev->name), +" \t\n\\" );rcu_read_unlock (); }else {WARN_ON (1 );
fs/btrfs/volumes.c +31 -27
118 lines not on this page · raw message
include/linux/rcustring.h new file +97 -0
97 lines not on this page · raw message
Signature · 1 line
2.14.1
Re: [PATCH 3/7] Move Btrfs RCU string to common library
Quoted 5 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
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.
Ok for the changes, but please drop anything that just reformats the argument list and/or shifts the long strings out of 80 columns. I personally hate the "arguments aligned under the opening (" style and can somehow live with that in new code, but if it's part of a patch that's pure noise as I have to read all the changed lines and figure out if they really are different or not. Thanks.
Re: [PATCH 3/7] Move Btrfs RCU string to common library
Quoted 10 lines · David Sterba
Quoted 5 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
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.
Ok for the changes, but please drop anything that just reformats the argument list and/or shifts the long strings out of 80 columns. I personally hate the "arguments aligned under the opening (" style
Well that's the kernel style ;)
Quoted 3 lines
and can somehow live with that in new code, but if it's part of a patch that's pure noise as I have to read all the changed lines and figure out if they really are different or not. Thanks.
I only reflowed calls where I changed something, so that shouldn't be an issue. If you really prefer I can resend it without reflowing anything, but that's going to leave the code looking worse than before.
PATCH 4/7 Btrfs: refactor btrfs_device->name updates
In reply to Omar SandovalFrom: Omar Sandoval <[email protected]>
The 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 | 117 +++++++++++++++++++++++++++++++++++------------------ fs/btrfs/volumes.h | 2 +- 2 files changed, 79 insertions(+), 40 deletions(-)
fs/btrfs/volumes.c +78 -39
@@ -152,6 +152,46 @@ struct list_head *btrfs_get_fs_uuids(void)return &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, +gfp_t gfp_mask) + __must_hold(&uuid_mutex) +{ +struct rcu_string *old_name, *new_name; + + new_name =rcu_string_strdup (name, gfp_mask); +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;
@@ -203,7 +243,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);
@@ -600,7 +640,7 @@ void btrfs_free_stale_device(struct btrfs_device *cur_dev) }else { fs_devs->num_devices--;list_del (&dev->dev_list); -rcu_string_free (dev->name); +rcu_string_free (btrfs_dev_rcu_only_name (dev));kfree (dev); }break ;
@@ -651,12 +691,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,GFP_NOFS )) {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);
@@ -665,13 +703,17 @@ 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 -* means this device was missing at time of FS mount. -* 2. If you are here and if the device->name is different -* from 'path' that means either +* 1. If you are here and if the name is NULL that means this +* device was missing at time of FS mount. +* 2. If you are here and if the name is different from 'path' +* that means either * a. The same device disappeared and reappeared with * different name. or * b. The missing-disk-which-was-replaced, has
@@ -703,17 +745,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,GFP_NOFS ))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
@@ -757,18 +797,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_KERNEL ); -if (!name) { + name =btrfs_dev_rcu_protected_name (orig_dev); +if (name) { +if (btrfs_dev_rename (device, name->str,GFP_KERNEL )) {kfree (device); goto error; } -rcu_assign_pointer (device->name, name); }list_add (&device->dev_list, &fs_devices->devices);
@@ -829,7 +863,7 @@ void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step) }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); }
@@ -848,7 +882,7 @@ static void __free_device(struct work_struct *work)struct btrfs_device *device; device = container_of(work, struct btrfs_device, rcu_work); -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));bio_put (device->flush_bio);kfree (device); }
@@ -896,11 +930,10 @@ static void btrfs_prepare_close_one_device(struct btrfs_device *device) 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,GFP_NOFS )) +BUG_ON (1 );/* -ENOMEM */ }list_replace_rcu (&device->dev_list, &new_device->dev_list);
@@ -987,18 +1020,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;
@@ -1966,8 +2001,10 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, const char *device_path,* the devices list. All that's left is to zero out the old * supers and free the device. */ -if (device->writeable) -btrfs_scratch_superblocks (device->bdev, device->name->str); +if (device->writeable) { +btrfs_scratch_superblocks (device->bdev, +btrfs_dev_rcu_protected_name (device)->str); + }btrfs_close_bdev (device);call_rcu (&device->rcu, free_device);
@@ -2040,7 +2077,8 @@ void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info,if (srcdev->writeable) {/* zero out the old super if it is writable */ -btrfs_scratch_superblocks (srcdev->bdev, srcdev->name->str); +btrfs_scratch_superblocks (srcdev->bdev, +btrfs_dev_rcu_only_name (srcdev)->str); }btrfs_close_bdev (srcdev);
@@ -2099,7 +2137,8 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,* is already out of device list, so we don't have to hold * the device_list_mutex lock. */ -btrfs_scratch_superblocks (tgtdev->bdev, tgtdev->name->str); +btrfs_scratch_superblocks (tgtdev->bdev, +btrfs_dev_rcu_only_name (tgtdev)->str);btrfs_close_bdev (tgtdev);call_rcu (&tgtdev->rcu, free_device);
@@ -2383,7 +2422,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const 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;
@@ -2517,7 +2556,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path error_trans:btrfs_end_transaction (trans); -rcu_string_free (device->name); +rcu_string_free (btrfs_dev_rcu_only_name (device));btrfs_sysfs_rm_device_link (fs_info->fs_devices, device);kfree (device); error:
fs/btrfs/volumes.h +1 -1
@@ -53,7 +53,7 @@ struct btrfs_device {struct btrfs_fs_devices *fs_devices;struct btrfs_fs_info *fs_info; -struct rcu_string *name; +struct rcu_string __rcu *name;u64 generation;
Signature · 1 line
2.14.1
PATCH 5/7 Btrfs: fix suspicious RCU in BTRFS_IOC_DEV_INFO
In reply to Omar SandovalFrom: Omar Sandoval <[email protected]>
A 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
@@ -2823,6 +2823,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,struct btrfs_fs_devices *fs_devices = 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))
@@ -2843,17 +2844,16 @@ static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info, 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.14.1
Re: [PATCH 5/7] Btrfs: fix suspicious RCU in BTRFS_IOC_DEV_INFO
Quoted 4 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
A 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.
In this case it is safe, as the device will not go away (and potentially free dev->name) because it's under the device_list_mutex.
The locking around devices and related structures is not exactly straightforward, but here I don't think we need to stick to the RCU pattern if the protection is guaranteed by other means. This applies to uuid_mutex and device_list_mutex.
Re: [PATCH 5/7] Btrfs: fix suspicious RCU in BTRFS_IOC_DEV_INFO
Quoted 6 lines · David Sterba
Quoted 4 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
A 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.
Quoted 7 lines
In this case it is safe, as the device will not go away (and potentially free
dev->name) because it's under thedevice_list_mutex.The locking around devices and related structures is not exactly straightforward, but here I don't think we need to stick to the RCU pattern if the protection is guaranteed by other means. This applies to
uuid_mutexanddevice_list_mutex.
You're right, it's a little confusing because uuid_mutex protects device->name, so under device_list_mutex, device->name might change but will never become NULL. We can just drop this one, thanks!
PATCH 6/7 Btrfs: make some volumes.c functions static
In reply to Omar SandovalFrom: Omar Sandoval <[email protected]>
These aren't used outside of volumes.c.
--- fs/btrfs/volumes.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
fs/btrfs/volumes.c +8 -6
@@ -594,7 +594,7 @@ static void pending_bios_fn(struct btrfs_work *work) } -void btrfs_free_stale_device (struct btrfs_device *cur_dev) +static void btrfs_free_stale_device (struct btrfs_device *cur_dev) {struct btrfs_fs_devices *fs_devs;struct btrfs_device *dev;
@@ -1110,14 +1110,15 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,return ret; } -void btrfs_release_disk_super (struct page *page) +static void btrfs_release_disk_super (struct page *page) {kunmap (page);put_page (page); } -int btrfs_read_disk_super (struct block_device *bdev,u64 bytenr, -struct page **page,struct btrfs_super_block **disk_super) +static int btrfs_read_disk_super (struct block_device *bdev,u64 bytenr, +struct page **page, +struct btrfs_super_block **disk_super) {void *p;pgoff_t index;
@@ -1860,8 +1861,9 @@ static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info,return 0 ; } -struct btrfs_device *btrfs_find_next_active_device (struct btrfs_fs_devices *fs_devs, -struct btrfs_device *device) +static struct btrfs_device * +btrfs_find_next_active_device (struct btrfs_fs_devices *fs_devs, +struct btrfs_device *device) {struct btrfs_device *next_device;
Signature · 1 line
2.14.1
Re: [PATCH 6/7] Btrfs: make some volumes.c functions static
Quoted 42 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
These aren't used outside of
volumes.c.Signed-off-by Omar Sandoval <[email protected]>--- fs/btrfs/volumes.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)fs/btrfs/volumes.c +5
-4@@ -594,7 +594,7 @@ static void pending_bios_fn(struct btrfs_work *work) } -void btrfs_free_stale_device (struct btrfs_device *cur_dev) +static void btrfs_free_stale_device (struct btrfs_device *cur_dev) {struct btrfs_fs_devices *fs_devs;struct btrfs_device *dev;@@ -1110,14 +1110,15 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,return ret; } -void btrfs_release_disk_super (struct page *page) +static void btrfs_release_disk_super (struct page *page) {kunmap (page);put_page (page); } -int btrfs_read_disk_super (struct block_device *bdev,u64 bytenr, -struct page **page,struct btrfs_super_block **disk_super) +static int btrfs_read_disk_super (struct block_device *bdev,u64 bytenr, +struct page **page, +struct btrfs_super_block **disk_super) {void *p;pgoff_t index;
fs/btrfs/volumes.c static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info, · line 1866
Quoted 8 lines
fs/btrfs/volumes.c +3
-2@@ -1860,8 +1861,9 @@ static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info,return 0 ; } -struct btrfs_device *btrfs_find_next_active_device (struct btrfs_fs_devices *fs_devs, -struct btrfs_device *device) +static struct btrfs_device * +btrfs_find_next_active_device (struct btrfs_fs_devices *fs_devs, +struct btrfs_device *device)
Please do not switch from the preferred declaration style where the type is on the same line as the function name. In case it's too long, put that on the next line. As this one is trivial, I'll fix that at commit time, but please keep that in mind in the future.
PATCH 7/7 Btrfs: fix __user casting in ioctl.c
In reply to Omar SandovalFrom: Omar Sandoval <[email protected]>
--- fs/btrfs/ioctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/btrfs/ioctl.c +5 -5
@@ -2210,7 +2210,7 @@ static noinline int btrfs_ioctl_tree_search_v2(struct file *file, inode =file_inode (file); ret =search_ioctl (inode, &args.key, &buf_size, - (char *)(&uarg->buf[0 ])); + (char __user *)(&uarg->buf[0 ]));if (ret ==0 &©_to_user (&uarg->key, &args.key,sizeof (args.key))) ret = -EFAULT ; else if (ret == -EOVERFLOW &&
@@ -4512,8 +4512,8 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) ipath->fspath->val[i] = rel_ptr; } - ret =copy_to_user ((void *)(unsigned long )ipa->fspath, - (void *)(unsigned long )ipath->fspath, size); + ret =copy_to_user ((void __user *)(unsigned long )ipa->fspath, + ipath->fspath, size);if (ret) { ret = -EFAULT ; goto out;
@@ -4584,8 +4584,8 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info,if (ret <0 ) goto out; - ret =copy_to_user ((void *)(unsigned long )loi->inodes, - (void *)(unsigned long )inodes, size); + ret =copy_to_user ((void __user *)(unsigned long )loi->inodes, inodes, + size);if (ret) ret = -EFAULT ;
Signature · 1 line
2.14.1
Re: [PATCH 7/7] Btrfs: fix __user casting in ioctl.c
Quoted 3 lines · Omar Sandoval
From: Omar Sandoval <[email protected]>
Signed-off-by Omar Sandoval <[email protected]>