return ret;
}
+/*
+ * A live stripe run's address range must not be re-claimed while the run
+ * object still exists: an ENOSPC discard storm can return every byte of a
+ * stripe to the free cache while its run is still draining other stripes'
+ * IO, and a second run claimed over the same range would make the
+ * range-to-run lookups (ordered extent attach, IO reporting) ambiguous and
+ * corrupt the inflight accounting. Trim the candidate to end before the
+ * first overlapping run; reject it outright if its head overlaps. Caller
+ * holds ctl->tree_lock; stripe_run_lock nests inside it.
+ */
+bool btrfs_stripe_run_range_usable(struct btrfs_block_group *bg,
+ u64 run_start, u64 *run_len)
+{
+ struct btrfs_open_stripe_run *run;
+ unsigned long flags;
+ u64 len = *run_len;
+
+ spin_lock_irqsave(&bg->stripe_run_lock, flags);
+ list_for_each_entry(run, &bg->open_stripe_runs, list) {
+ if (run->end <= run_start || run->start >= run_start + len)
+ continue;
+ if (run->start <= run_start) {
+ len = 0;
+ break;
+ }
+ len = run->start - run_start;
+ }
+ spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
+ if (len < bg->full_stripe_len)
+ return false;
+ *run_len = len;
+ return true;
+}
+
/*
* Does @logical lie within a stripe run (open or draining)? Used by the
* raid56 layer to decide whether a partial write to this stripe may be
void btrfs_close_bg_open_stripes(struct btrfs_block_group *bg);
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_stripe_run_range_usable(struct btrfs_block_group *bg,
+ u64 run_start, u64 *run_len);
void btrfs_retire_open_stripes(struct btrfs_fs_info *fs_info,
struct btrfs_transaction *trans);
void btrfs_clear_data_reloc_bg(struct btrfs_block_group *bg);
if (entry->bitmap) {
if (find_stripe_run_in_bitmap(ctl, entry, want_bytes,
- &run_start, &run_len))
+ &run_start, &run_len) &&
+ btrfs_stripe_run_range_usable(block_group,
+ run_start, &run_len))
goto found;
continue;
}
run_len = min(want_bytes,
div64_u64(entry->offset + entry->bytes - run_start,
fsl) * fsl);
+ if (!btrfs_stripe_run_range_usable(block_group, run_start,
+ &run_len))
+ continue;
goto found;
}
goto out;