* ensure we still have some free space after marking this
* block group RO.
*/
+/*
+ * A buffered NOCOW write decides to write in place at write() time
+ * (btrfs_check_nocow_lock()) but takes the group's nocow_writers only at
+ * writeback. If the group goes read-only in between -- scrub, balance,
+ * zoned reclaim -- the writeback finds ->ro, falls back to COW with a data
+ * reservation that never went through admission (fallback_to_cow()), and
+ * on a full filesystem cow_file_range() fails and the pages are dropped.
+ *
+ * Drain the group before making it read-only: refuse new NOCOW decisions
+ * into it, wait for the write() calls that already decided to finish
+ * dirtying their pages, then flush delalloc and wait for the group's
+ * ordered extents so every pending NOCOW range lands in place while the
+ * group is still writable. The flush is skipped when no write() has
+ * decided to NOCOW into the group since it was last drained. Must not be
+ * called with a transaction handle held: the flush completes ordered
+ * extents, which join transactions.
+ */
+static int btrfs_bg_drain_nocow_writes(struct btrfs_block_group *bg)
+{
+ struct btrfs_fs_info *fs_info = bg->fs_info;
+ bool pending;
+ int ret;
+
+ spin_lock(&bg->lock);
+ bg->nocow_blocked = true;
+ pending = bg->nocow_pending;
+ bg->nocow_pending = false;
+ spin_unlock(&bg->lock);
+ wait_var_event(&fs_info->nocow_write_inflight,
+ !atomic_read(&fs_info->nocow_write_inflight));
+ if (!pending)
+ return 0;
+ ret = btrfs_start_delalloc_roots(fs_info, LONG_MAX, false);
+ if (ret < 0)
+ return ret;
+ btrfs_wait_ordered_roots(fs_info, U64_MAX, bg);
+ btrfs_wait_nocow_writers(bg);
+ return 0;
+}
+
+static void btrfs_bg_unblock_nocow(struct btrfs_block_group *bg)
+{
+ spin_lock(&bg->lock);
+ bg->nocow_blocked = false;
+ spin_unlock(&bg->lock);
+}
+
int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
bool do_chunk_alloc)
{
return ret;
}
+ if (cache->flags & BTRFS_BLOCK_GROUP_DATA) {
+ ret = btrfs_bg_drain_nocow_writes(cache);
+ if (ret) {
+ btrfs_bg_unblock_nocow(cache);
+ return ret;
+ }
+ }
+
do {
trans = btrfs_join_transaction(root);
if (IS_ERR(trans))
mutex_unlock(&fs_info->ro_block_group_mutex);
btrfs_end_transaction(trans);
+ if (ret)
+ btrfs_bg_unblock_nocow(cache);
return ret;
}
spin_lock(&sinfo->lock);
spin_lock(&cache->lock);
if (!--cache->ro) {
+ cache->nocow_blocked = false;
if (btrfs_is_zoned(cache->fs_info)) {
/* Migrate zone_unusable bytes back */
cache->zone_unusable =
* writes through direct IO.
*/
atomic_t nocow_writers;
+ /*
+ * Both under *lock*. nocow_blocked: the group is being made read-only
+ * (or is), so no write() may decide to NOCOW into it any more.
+ * nocow_pending: some write() has decided to NOCOW into it since the
+ * last read-only transition drained it, so pending NOCOW delalloc may
+ * point here. See btrfs_bg_drain_nocow_writes().
+ */
+ bool nocow_blocked;
+ bool nocow_pending;
/* Lock for free space tree operations. */
struct mutex free_space_lock;
if (!btrfs_drew_try_write_lock(&root->snapshot_lock))
return -EAGAIN;
+ /*
+ * Held until btrfs_check_nocow_unlock(), i.e. until the pages are
+ * dirtied: a block group going read-only waits for it, so it cannot
+ * turn a range we decided to NOCOW into a COW fallback at writeback.
+ * Taken before the decision so a group's read-only transition that
+ * lands during it sees us either way.
+ */
+ atomic_inc(&fs_info->nocow_write_inflight);
lockstart = round_down(pos, fs_info->sectorsize);
lockend = round_up(pos + *write_bytes,
if (nowait) {
if (!btrfs_try_lock_ordered_range(inode, lockstart, lockend,
&cached_state)) {
- btrfs_drew_write_unlock(&root->snapshot_lock);
+ btrfs_check_nocow_unlock(inode);
return -EAGAIN;
}
} else {
* snapshot lock.
*/
if (cur_offset == lockstart)
- btrfs_drew_write_unlock(&root->snapshot_lock);
+ btrfs_check_nocow_unlock(inode);
break;
}
cur_offset += num_bytes;
void btrfs_check_nocow_unlock(struct btrfs_inode *inode)
{
+ struct btrfs_fs_info *fs_info = inode->root->fs_info;
+
btrfs_drew_write_unlock(&inode->root->snapshot_lock);
+ if (atomic_dec_and_test(&fs_info->nocow_write_inflight))
+ wake_up_var(&fs_info->nocow_write_inflight);
}
int btrfs_write_check(struct kiocb *iocb, size_t count)
atomic_t nr_delayed_iputs;
wait_queue_head_t delayed_iputs_wait;
+ /*
+ * write() calls between deciding to NOCOW (btrfs_check_nocow_lock())
+ * and having dirtied their pages (btrfs_check_nocow_unlock()). A
+ * block group going read-only waits for them before flushing the
+ * pending NOCOW ranges; see btrfs_bg_drain_nocow_writes().
+ */
+ atomic_t nocow_write_inflight;
+
atomic64_t tree_mod_seq;
/* This protects tree_mod_log and tree_mod_seq_list */
bool readonly = false;
block_group = btrfs_lookup_block_group(fs_info, bytenr);
- if (!block_group || block_group->ro)
+ if (!block_group)
+ return true;
+ spin_lock(&block_group->lock);
+ if (block_group->ro || block_group->nocow_blocked) {
readonly = true;
- if (block_group)
- btrfs_put_block_group(block_group);
+ } else {
+ /*
+ * The caller may now dirty a NOCOW range against this group;
+ * a later read-only transition has to flush it first.
+ */
+ block_group->nocow_pending = true;
+ }
+ spin_unlock(&block_group->lock);
+ btrfs_put_block_group(block_group);
return readonly;
}