diff options
author | Chris Mason <clm@fb.com> | 2015-04-24 14:00:00 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-04-24 14:52:25 -0400 |
commit | a3bdccc4e683f0ac69230707ed3fa20e7cf73a79 (patch) | |
tree | 7cec1e92ccfa9fc236190810acb55f025e480d9d | |
parent | 85db36cfb3de1422aeafb4e2ce83396333b744bb (diff) |
Btrfs: prevent list corruption during free space cache processing
__btrfs_write_out_cache is holding the ctl->tree_lock while it prepares
a list of bitmaps to record in the free space cache. It was dropping
the lock while it worked on other components, which made a window for
free_bitmap() to free the bitmap struct without removing it from the
list.
This changes things to hold the lock the whole time, and also makes sure
we hold the lock during enospc cleanup.
Reported-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r-- | fs/btrfs/free-space-cache.c | 32 |
1 files changed, 18 insertions, 14 deletions
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index d773f229d14d..81fa75a8e1f3 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -1119,10 +1119,7 @@ static int flush_dirty_cache(struct inode *inode) | |||
1119 | } | 1119 | } |
1120 | 1120 | ||
1121 | static void noinline_for_stack | 1121 | static void noinline_for_stack |
1122 | cleanup_write_cache_enospc(struct inode *inode, | 1122 | cleanup_bitmap_list(struct list_head *bitmap_list) |
1123 | struct btrfs_io_ctl *io_ctl, | ||
1124 | struct extent_state **cached_state, | ||
1125 | struct list_head *bitmap_list) | ||
1126 | { | 1123 | { |
1127 | struct list_head *pos, *n; | 1124 | struct list_head *pos, *n; |
1128 | 1125 | ||
@@ -1131,6 +1128,14 @@ cleanup_write_cache_enospc(struct inode *inode, | |||
1131 | list_entry(pos, struct btrfs_free_space, list); | 1128 | list_entry(pos, struct btrfs_free_space, list); |
1132 | list_del_init(&entry->list); | 1129 | list_del_init(&entry->list); |
1133 | } | 1130 | } |
1131 | } | ||
1132 | |||
1133 | static void noinline_for_stack | ||
1134 | cleanup_write_cache_enospc(struct inode *inode, | ||
1135 | struct btrfs_io_ctl *io_ctl, | ||
1136 | struct extent_state **cached_state, | ||
1137 | struct list_head *bitmap_list) | ||
1138 | { | ||
1134 | io_ctl_drop_pages(io_ctl); | 1139 | io_ctl_drop_pages(io_ctl); |
1135 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, | 1140 | unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, |
1136 | i_size_read(inode) - 1, cached_state, | 1141 | i_size_read(inode) - 1, cached_state, |
@@ -1266,11 +1271,8 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | |||
1266 | ret = write_cache_extent_entries(io_ctl, ctl, | 1271 | ret = write_cache_extent_entries(io_ctl, ctl, |
1267 | block_group, &entries, &bitmaps, | 1272 | block_group, &entries, &bitmaps, |
1268 | &bitmap_list); | 1273 | &bitmap_list); |
1269 | spin_unlock(&ctl->tree_lock); | 1274 | if (ret) |
1270 | if (ret) { | 1275 | goto out_nospc_locked; |
1271 | mutex_unlock(&ctl->cache_writeout_mutex); | ||
1272 | goto out_nospc; | ||
1273 | } | ||
1274 | 1276 | ||
1275 | /* | 1277 | /* |
1276 | * Some spaces that are freed in the current transaction are pinned, | 1278 | * Some spaces that are freed in the current transaction are pinned, |
@@ -1281,17 +1283,14 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, | |||
1281 | * the dirty list and redo it. No locking needed | 1283 | * the dirty list and redo it. No locking needed |
1282 | */ | 1284 | */ |
1283 | ret = write_pinned_extent_entries(root, block_group, io_ctl, &entries); | 1285 | ret = write_pinned_extent_entries(root, block_group, io_ctl, &entries); |
1284 | if (ret) { | 1286 | if (ret) |
1285 | mutex_unlock(&ctl->cache_writeout_mutex); | 1287 | goto out_nospc_locked; |
1286 | goto out_nospc; | ||
1287 | } | ||
1288 | 1288 | ||
1289 | /* | 1289 | /* |
1290 | * At last, we write out all the bitmaps and keep cache_writeout_mutex | 1290 | * At last, we write out all the bitmaps and keep cache_writeout_mutex |
1291 | * locked while doing it because a concurrent trim can be manipulating | 1291 | * locked while doing it because a concurrent trim can be manipulating |
1292 | * or freeing the bitmap. | 1292 | * or freeing the bitmap. |
1293 | */ | 1293 | */ |
1294 | spin_lock(&ctl->tree_lock); | ||
1295 | ret = write_bitmap_entries(io_ctl, &bitmap_list); | 1294 | ret = write_bitmap_entries(io_ctl, &bitmap_list); |
1296 | spin_unlock(&ctl->tree_lock); | 1295 | spin_unlock(&ctl->tree_lock); |
1297 | mutex_unlock(&ctl->cache_writeout_mutex); | 1296 | mutex_unlock(&ctl->cache_writeout_mutex); |
@@ -1344,6 +1343,11 @@ out: | |||
1344 | iput(inode); | 1343 | iput(inode); |
1345 | return ret; | 1344 | return ret; |
1346 | 1345 | ||
1346 | out_nospc_locked: | ||
1347 | cleanup_bitmap_list(&bitmap_list); | ||
1348 | spin_unlock(&ctl->tree_lock); | ||
1349 | mutex_unlock(&ctl->cache_writeout_mutex); | ||
1350 | |||
1347 | out_nospc: | 1351 | out_nospc: |
1348 | cleanup_write_cache_enospc(inode, io_ctl, &cached_state, &bitmap_list); | 1352 | cleanup_write_cache_enospc(inode, io_ctl, &cached_state, &bitmap_list); |
1349 | 1353 | ||