*tail_start = run->offset;
tail_len = run->end - run->offset;
run->end = run->offset;
+ bg->stripe_open_remainder -= tail_len;
if (open_stripe_run_drained(run))
free_open_stripe_run(bg, run);
return tail_len;
}
+/*
+ * Fold this block group's open-run remainder delta into the space_info
+ * counter that reservations see. Bytes inside an open run are invisible
+ * to the free space cache (the claim removed them) and will either be
+ * allocated or become trapped tails when the run closes, so the data
+ * reservation path must not admit writes against them: a reservation
+ * that cannot allocate at writeback time discards the pages silently.
+ * Called after every remainder mutation. Compute and apply are one
+ * critical section (sinfo->lock nests inside stripe_run_lock): applied
+ * out of order, a negative delta could overtake the positive it was
+ * computed against and transiently underflow the space_info sum.
+ */
+static void stripe_open_remainder_sync(struct btrfs_block_group *bg)
+{
+ struct btrfs_space_info *sinfo = bg->space_info;
+ unsigned long flags;
+ s64 delta;
+
+ spin_lock_irqsave(&bg->stripe_run_lock, flags);
+ delta = (s64)(bg->stripe_open_remainder - bg->stripe_open_reported);
+ bg->stripe_open_reported = bg->stripe_open_remainder;
+ if (delta && sinfo) {
+ spin_lock(&sinfo->lock);
+ if (delta < 0 && sinfo->bytes_stripe_open < (u64)-delta) {
+ WARN_ON_ONCE(1);
+ sinfo->bytes_stripe_open = 0;
+ } else {
+ sinfo->bytes_stripe_open += delta;
+ }
+ spin_unlock(&sinfo->lock);
+ }
+ spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
+}
+
/*
* Install @run (not currently in any band slot) into its remaining-space band.
* If a run already occupies that band, keep whichever has more remaining -- it
*ret_offset = run->offset;
run->offset += num_bytes;
run->inflight_bytes += num_bytes;
+ bg->stripe_open_remainder -= num_bytes;
if (run->offset == run->end)
run->open = false; /* full; drains then is freed */
else
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
if (tail_len)
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
return 0;
}
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
r->end = start + len;
r->offset += num_bytes;
r->inflight_bytes += num_bytes;
+ bg->stripe_open_remainder += len;
+ bg->stripe_open_remainder -= num_bytes;
if (r->offset == r->end)
r->open = false; /* full; drains then is freed */
else
spin_unlock(&fs_info->open_stripe_lock);
if (tail_len)
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
ret = 0;
goto out; /* frees the unused new_run */
}
new_run->open_seq = fs_info->stripe_retire_seq;
new_run->open = (new_run->offset != new_run->end);
list_add_tail(&new_run->list, &bg->open_stripe_runs);
+ bg->stripe_open_remainder += new_run->end - new_run->offset;
/*
* Place the new run in its remaining-space band, closing whichever run
* loses a band collision (the last, fuller opener wins). Other bands'
if (tail_len)
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
*ret_offset = start;
new_run = NULL;
ret = 0;
*ret_offset = run->offset;
run->offset += num_bytes;
run->inflight_bytes += num_bytes;
+ bg->stripe_open_remainder -= num_bytes;
if (run->offset == run->end)
run->open = false; /* full; drains, is freed */
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
+ stripe_open_remainder_sync(bg);
return 0;
}
tail_len = close_open_stripe_run(bg, run, &tail_start);
break;
}
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
- if (tail_len)
+ if (tail_len) {
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
+ }
new_run = kmalloc(sizeof(*new_run), GFP_NOFS);
if (!new_run)
new_run->open_seq = fs_info->stripe_retire_seq;
new_run->open = (new_run->offset != new_run->end);
list_add_tail(&new_run->list, &bg->open_stripe_runs);
+ bg->stripe_open_remainder += new_run->end - new_run->offset;
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
spin_unlock(&fs_info->open_stripe_lock);
+ stripe_open_remainder_sync(bg);
*ret_offset = start;
new_run = NULL;
ret = 0;
btrfs_get_block_group(bg);
spin_unlock(&fs_info->open_stripe_lock);
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
btrfs_put_block_group(bg);
goto restart;
}
log_carry_record(inode, file_start, file_len, bytenr, num_bytes,
ps_start, ps_len);
- if (tail_len)
+ if (tail_len) {
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
+ }
if (flush_len) {
btrfs_flush_parked_rbios(fs_info, flush_start, flush_len);
wait_var_event(&bg->open_stripe_runs,
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);
if (tail_len)
btrfs_add_free_space(bg, tail_start, tail_len);
+ stripe_open_remainder_sync(bg);
goto restart;
}
spin_unlock_irqrestore(&bg->stripe_run_lock, flags);