Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'for-4.15-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs fixes from David Sterba:
"We have two more fixes for 4.15, both aimed for stable.

The leak fix is obvious, the second patch fixes a bug revealed by the
refcount API, when it behaves differently than previous atomic_t and
reports refs going from 0 to 1 in one case"

* tag 'for-4.15-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux:
btrfs: fix refcount_t usage when deleting btrfs_delayed_nodes
btrfs: Fix flush bio leak

+34 -12
+34 -11
fs/btrfs/delayed-inode.c
··· 87 87 88 88 spin_lock(&root->inode_lock); 89 89 node = radix_tree_lookup(&root->delayed_nodes_tree, ino); 90 + 90 91 if (node) { 91 92 if (btrfs_inode->delayed_node) { 92 93 refcount_inc(&node->refs); /* can be accessed */ ··· 95 94 spin_unlock(&root->inode_lock); 96 95 return node; 97 96 } 98 - btrfs_inode->delayed_node = node; 99 - /* can be accessed and cached in the inode */ 100 - refcount_add(2, &node->refs); 97 + 98 + /* 99 + * It's possible that we're racing into the middle of removing 100 + * this node from the radix tree. In this case, the refcount 101 + * was zero and it should never go back to one. Just return 102 + * NULL like it was never in the radix at all; our release 103 + * function is in the process of removing it. 104 + * 105 + * Some implementations of refcount_inc refuse to bump the 106 + * refcount once it has hit zero. If we don't do this dance 107 + * here, refcount_inc() may decide to just WARN_ONCE() instead 108 + * of actually bumping the refcount. 109 + * 110 + * If this node is properly in the radix, we want to bump the 111 + * refcount twice, once for the inode and once for this get 112 + * operation. 113 + */ 114 + if (refcount_inc_not_zero(&node->refs)) { 115 + refcount_inc(&node->refs); 116 + btrfs_inode->delayed_node = node; 117 + } else { 118 + node = NULL; 119 + } 120 + 101 121 spin_unlock(&root->inode_lock); 102 122 return node; 103 123 } ··· 276 254 mutex_unlock(&delayed_node->mutex); 277 255 278 256 if (refcount_dec_and_test(&delayed_node->refs)) { 279 - bool free = false; 280 257 struct btrfs_root *root = delayed_node->root; 258 + 281 259 spin_lock(&root->inode_lock); 282 - if (refcount_read(&delayed_node->refs) == 0) { 283 - radix_tree_delete(&root->delayed_nodes_tree, 284 - delayed_node->inode_id); 285 - free = true; 286 - } 260 + /* 261 + * Once our refcount goes to zero, nobody is allowed to bump it 262 + * back up. We can delete it now. 263 + */ 264 + ASSERT(refcount_read(&delayed_node->refs) == 0); 265 + radix_tree_delete(&root->delayed_nodes_tree, 266 + delayed_node->inode_id); 287 267 spin_unlock(&root->inode_lock); 288 - if (free) 289 - kmem_cache_free(delayed_node_cache, delayed_node); 268 + kmem_cache_free(delayed_node_cache, delayed_node); 290 269 } 291 270 } 292 271
-1
fs/btrfs/volumes.c
··· 237 237 kfree(dev); 238 238 return ERR_PTR(-ENOMEM); 239 239 } 240 - bio_get(dev->flush_bio); 241 240 242 241 INIT_LIST_HEAD(&dev->dev_list); 243 242 INIT_LIST_HEAD(&dev->dev_alloc_list);