* Calls are serialized by the transaction commit; @trans may be NULL for
* the final cleanup call.
*/
+/*
+ * Teardown: release every open stripe run and the block group reference
+ * each group with runs holds. The commit normally retires runs, and the
+ * release of a group's last run drops its membership here; a mount that
+ * fails after log replay has already allocated tree blocks, and an unmount
+ * after a transaction abort, never commit again, and
+ * btrfs_free_block_groups() then asserts on the leftover references. By
+ * the time this runs the workers are stopped and the roots dropped, so no
+ * IO is left to report; a run still counting bytes in flight is noted and
+ * released all the same.
+ */
+void btrfs_free_open_stripe_runs(struct btrfs_fs_info *fs_info)
+{
+ LIST_HEAD(bgs);
+ struct btrfs_block_group *bg, *tmp_bg;
+ unsigned long flags;
+
+ spin_lock(&fs_info->open_stripe_lock);
+ list_splice_init(&fs_info->open_stripe_bgs, &bgs);
+ spin_unlock(&fs_info->open_stripe_lock);
+
+ list_for_each_entry_safe(bg, tmp_bg, &bgs, open_stripe_bg_list) {
+ struct btrfs_open_stripe_run *run, *tmp;
+
+ list_del_init(&bg->open_stripe_bg_list);
+ spin_lock_irqsave(&bg->stripe_run_lock, flags);
+ list_for_each_entry_safe(run, tmp, &bg->open_stripe_runs, list) {
+ if (run->inflight_bytes)
+ btrfs_warn(fs_info,
+"stripe run %llu-%llu in block group %llu released at teardown with %llu bytes still in flight",
+ run->start, run->end, bg->start,
+ run->inflight_bytes);
+ list_del(&run->list);
+ bitmap_free(run->live);
+ kfree(run);
+ }
+ memset(bg->open_stripe, 0, sizeof(bg->open_stripe));
+ bg->stripe_open_remainder = 0;
+ spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
+ stripe_open_remainder_sync(bg);
+ btrfs_put_block_group(bg);
+ }
+}
+
/*
* Close and drain the metadata stripe runs, once every tree block this
* transaction allocated has reached the disk.
u64 *open_seq);
void btrfs_close_bg_open_stripes(struct btrfs_block_group *bg);
void btrfs_retire_meta_stripes(struct btrfs_fs_info *fs_info, u64 transid);
+void btrfs_free_open_stripe_runs(struct btrfs_fs_info *fs_info);
void btrfs_retire_block_group_stripes(struct btrfs_block_group *bg);
bool btrfs_stripe_in_open_run(struct btrfs_fs_info *fs_info, u64 logical);
bool btrfs_defer_stripe_meta_write(struct btrfs_fs_info *fs_info,
fail_sb_buffer:
btrfs_stop_all_workers(fs_info);
+ btrfs_free_open_stripe_runs(fs_info);
btrfs_free_block_groups(fs_info);
fail_alloc:
btrfs_mapping_tree_free(fs_info);
* accounting appear to be wrong because there's pending reserved bytes,
* so make sure we do the block group cleanup afterwards.
*/
+ btrfs_free_open_stripe_runs(fs_info);
btrfs_free_block_groups(fs_info);
iput(fs_info->btree_inode);