diff options
Diffstat (limited to 'fs/btrfs')
| -rw-r--r-- | fs/btrfs/backref.c | 1 | ||||
| -rw-r--r-- | fs/btrfs/ctree.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/discard.c | 1 | ||||
| -rw-r--r-- | fs/btrfs/disk-io.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/extent_io.c | 43 | ||||
| -rw-r--r-- | fs/btrfs/file.c | 1 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 32 | ||||
| -rw-r--r-- | fs/btrfs/ref-verify.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/space-info.c | 2 | ||||
| -rw-r--r-- | fs/btrfs/super.c | 6 | ||||
| -rw-r--r-- | fs/btrfs/volumes.c | 8 | ||||
| -rw-r--r-- | fs/btrfs/volumes.h | 2 | 
12 files changed, 59 insertions, 47 deletions
| diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index d888e71e66b6..ea10f7bc99ab 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c @@ -1461,6 +1461,7 @@ static int btrfs_find_all_roots_safe(struct btrfs_trans_handle *trans,  		if (ret < 0 && ret != -ENOENT) {  			ulist_free(tmp);  			ulist_free(*roots); +			*roots = NULL;  			return ret;  		}  		node = ulist_next(tmp, &uiter); diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 3a7648bff42c..82ab6e5a386d 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c @@ -1196,7 +1196,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,  		switch (tm->op) {  		case MOD_LOG_KEY_REMOVE_WHILE_FREEING:  			BUG_ON(tm->slot < n); -			/* Fallthrough */ +			fallthrough;  		case MOD_LOG_KEY_REMOVE_WHILE_MOVING:  		case MOD_LOG_KEY_REMOVE:  			btrfs_set_node_key(eb, &tm->key, tm->slot); diff --git a/fs/btrfs/discard.c b/fs/btrfs/discard.c index 5615320fa659..741c7e19c32f 100644 --- a/fs/btrfs/discard.c +++ b/fs/btrfs/discard.c @@ -619,6 +619,7 @@ void btrfs_discard_punt_unused_bgs_list(struct btrfs_fs_info *fs_info)  	list_for_each_entry_safe(block_group, next, &fs_info->unused_bgs,  				 bg_list) {  		list_del_init(&block_group->bg_list); +		btrfs_put_block_group(block_group);  		btrfs_discard_queue_work(&fs_info->discard_ctl, block_group);  	}  	spin_unlock(&fs_info->unused_bgs_lock); diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 7c6f0bbb54a5..b1a148058773 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2593,10 +2593,12 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)  		    !extent_buffer_uptodate(tree_root->node)) {  			handle_error = true; -			if (IS_ERR(tree_root->node)) +			if (IS_ERR(tree_root->node)) {  				ret = PTR_ERR(tree_root->node); -			else if (!extent_buffer_uptodate(tree_root->node)) +				tree_root->node = NULL; +			} else if (!extent_buffer_uptodate(tree_root->node)) {  				ret = -EUCLEAN; +			}  			btrfs_warn(fs_info, "failed to read tree root");  			continue; diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 68c96057ad2d..60278e52c37a 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1999,7 +1999,8 @@ static int __process_pages_contig(struct address_space *mapping,  				if (!PageDirty(pages[i]) ||  				    pages[i]->mapping != mapping) {  					unlock_page(pages[i]); -					put_page(pages[i]); +					for (; i < ret; i++) +						put_page(pages[i]);  					err = -EAGAIN;  					goto out;  				} @@ -5058,25 +5059,28 @@ struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,  static void check_buffer_tree_ref(struct extent_buffer *eb)  {  	int refs; -	/* the ref bit is tricky.  We have to make sure it is set -	 * if we have the buffer dirty.   Otherwise the -	 * code to free a buffer can end up dropping a dirty -	 * page +	/* +	 * The TREE_REF bit is first set when the extent_buffer is added +	 * to the radix tree. It is also reset, if unset, when a new reference +	 * is created by find_extent_buffer.  	 * -	 * Once the ref bit is set, it won't go away while the -	 * buffer is dirty or in writeback, and it also won't -	 * go away while we have the reference count on the -	 * eb bumped. +	 * It is only cleared in two cases: freeing the last non-tree +	 * reference to the extent_buffer when its STALE bit is set or +	 * calling releasepage when the tree reference is the only reference.  	 * -	 * We can't just set the ref bit without bumping the -	 * ref on the eb because free_extent_buffer might -	 * see the ref bit and try to clear it.  If this happens -	 * free_extent_buffer might end up dropping our original -	 * ref by mistake and freeing the page before we are able -	 * to add one more ref. +	 * In both cases, care is taken to ensure that the extent_buffer's +	 * pages are not under io. However, releasepage can be concurrently +	 * called with creating new references, which is prone to race +	 * conditions between the calls to check_buffer_tree_ref in those +	 * codepaths and clearing TREE_REF in try_release_extent_buffer.  	 * -	 * So bump the ref count first, then set the bit.  If someone -	 * beat us to it, drop the ref we added. +	 * The actual lifetime of the extent_buffer in the radix tree is +	 * adequately protected by the refcount, but the TREE_REF bit and +	 * its corresponding reference are not. To protect against this +	 * class of races, we call check_buffer_tree_ref from the codepaths +	 * which trigger io after they set eb->io_pages. Note that once io is +	 * initiated, TREE_REF can no longer be cleared, so that is the +	 * moment at which any such race is best fixed.  	 */  	refs = atomic_read(&eb->refs);  	if (refs >= 2 && test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) @@ -5527,6 +5531,11 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num)  	clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);  	eb->read_mirror = 0;  	atomic_set(&eb->io_pages, num_reads); +	/* +	 * It is possible for releasepage to clear the TREE_REF bit before we +	 * set io_pages. See check_buffer_tree_ref for a more detailed comment. +	 */ +	check_buffer_tree_ref(eb);  	for (i = 0; i < num_pages; i++) {  		page = eb->pages[i]; diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 2520605afc25..b0d2c976587e 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -3509,6 +3509,7 @@ const struct file_operations btrfs_file_operations = {  	.read_iter      = generic_file_read_iter,  	.splice_read	= generic_file_splice_read,  	.write_iter	= btrfs_file_write_iter, +	.splice_write	= iter_file_splice_write,  	.mmap		= btrfs_file_mmap,  	.open		= btrfs_file_open,  	.release	= btrfs_release_file, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 18d384f4af54..6862cd7e21a9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1690,12 +1690,8 @@ out_check:  			ret = fallback_to_cow(inode, locked_page, cow_start,  					      found_key.offset - 1,  					      page_started, nr_written); -			if (ret) { -				if (nocow) -					btrfs_dec_nocow_writers(fs_info, -								disk_bytenr); +			if (ret)  				goto error; -			}  			cow_start = (u64)-1;  		} @@ -1711,9 +1707,6 @@ out_check:  					  ram_bytes, BTRFS_COMPRESS_NONE,  					  BTRFS_ORDERED_PREALLOC);  			if (IS_ERR(em)) { -				if (nocow) -					btrfs_dec_nocow_writers(fs_info, -								disk_bytenr);  				ret = PTR_ERR(em);  				goto error;  			} @@ -8130,20 +8123,17 @@ again:  	/*  	 * Qgroup reserved space handler  	 * Page here will be either -	 * 1) Already written to disk -	 *    In this case, its reserved space is released from data rsv map -	 *    and will be freed by delayed_ref handler finally. -	 *    So even we call qgroup_free_data(), it won't decrease reserved -	 *    space. -	 * 2) Not written to disk -	 *    This means the reserved space should be freed here. However, -	 *    if a truncate invalidates the page (by clearing PageDirty) -	 *    and the page is accounted for while allocating extent -	 *    in btrfs_check_data_free_space() we let delayed_ref to -	 *    free the entire extent. +	 * 1) Already written to disk or ordered extent already submitted +	 *    Then its QGROUP_RESERVED bit in io_tree is already cleaned. +	 *    Qgroup will be handled by its qgroup_record then. +	 *    btrfs_qgroup_free_data() call will do nothing here. +	 * +	 * 2) Not written to disk yet +	 *    Then btrfs_qgroup_free_data() call will clear the QGROUP_RESERVED +	 *    bit of its io_tree, and free the qgroup reserved data space. +	 *    Since the IO will never happen for this page.  	 */ -	if (PageDirty(page)) -		btrfs_qgroup_free_data(inode, NULL, page_start, PAGE_SIZE); +	btrfs_qgroup_free_data(inode, NULL, page_start, PAGE_SIZE);  	if (!inode_evicting) {  		clear_extent_bit(tree, page_start, page_end, EXTENT_LOCKED |  				 EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | diff --git a/fs/btrfs/ref-verify.c b/fs/btrfs/ref-verify.c index 7887317033c9..af92525dbb16 100644 --- a/fs/btrfs/ref-verify.c +++ b/fs/btrfs/ref-verify.c @@ -509,7 +509,7 @@ static int process_leaf(struct btrfs_root *root,  		switch (key.type) {  		case BTRFS_EXTENT_ITEM_KEY:  			*num_bytes = key.offset; -			/* fall through */ +			fallthrough;  		case BTRFS_METADATA_ITEM_KEY:  			*bytenr = key.objectid;  			ret = process_extent_item(fs_info, path, &key, i, diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 41ee88633769..c7bd3fdd7792 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -879,8 +879,8 @@ static bool steal_from_global_rsv(struct btrfs_fs_info *fs_info,  		return false;  	}  	global_rsv->reserved -= ticket->bytes; +	remove_ticket(space_info, ticket);  	ticket->bytes = 0; -	list_del_init(&ticket->list);  	wake_up(&ticket->wait);  	space_info->tickets_id++;  	if (global_rsv->reserved < global_rsv->size) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index bc73fd670702..c3826ae883f0 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -523,7 +523,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,  		case Opt_compress_force:  		case Opt_compress_force_type:  			compress_force = true; -			/* Fallthrough */ +			fallthrough;  		case Opt_compress:  		case Opt_compress_type:  			saved_compress_type = btrfs_test_opt(info, @@ -622,7 +622,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,  			btrfs_set_opt(info->mount_opt, NOSSD);  			btrfs_clear_and_info(info, SSD,  					     "not using ssd optimizations"); -			/* Fallthrough */ +			fallthrough;  		case Opt_nossd_spread:  			btrfs_clear_and_info(info, SSD_SPREAD,  					     "not using spread ssd allocation scheme"); @@ -793,7 +793,7 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,  		case Opt_recovery:  			btrfs_warn(info,  				   "'recovery' is deprecated, use 'usebackuproot' instead"); -			/* fall through */ +			fallthrough;  		case Opt_usebackuproot:  			btrfs_info(info,  				   "trying to use backup root at mount time"); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0d6e785bcb98..f403fb1e6d37 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -7052,6 +7052,14 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)  	mutex_lock(&fs_info->chunk_mutex);  	/* +	 * It is possible for mount and umount to race in such a way that +	 * we execute this code path, but open_fs_devices failed to clear +	 * total_rw_bytes. We certainly want it cleared before reading the +	 * device items, so clear it here. +	 */ +	fs_info->fs_devices->total_rw_bytes = 0; + +	/*  	 * Read all device items, and then all the chunk items. All  	 * device items are found before any chunk item (their object id  	 * is smaller than the lowest possible object id for a chunk diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index f067b5934c46..75af2334b2e3 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -408,7 +408,7 @@ static inline enum btrfs_map_op btrfs_op(struct bio *bio)  		return BTRFS_MAP_WRITE;  	default:  		WARN_ON_ONCE(1); -		/* fall through */ +		fallthrough;  	case REQ_OP_READ:  		return BTRFS_MAP_READ;  	} | 
