u64 owner; /* LOG class: btrfs_ino of the owner */
enum btrfs_stripe_run_class class;
bool open; /* accepting allocations */
+ bool persistent; /* survives commits; see close_block_group_stripe_runs() */
/*
* One bit per sector of the run: set while that sector holds an
* allocation someone still intends to write, clear otherwise.
}
new_run->bg = bg;
new_run->class = class;
+ new_run->persistent = false;
new_run->owner = 0;
new_run->transid = transid;
new_run->start = start;
}
new_run->bg = bg;
new_run->class = class;
+ /*
+ * A NOCOW run outlives commits only while the stripe_alloc_allow_rmw
+ * policy lets nocow data be written in place at all (see
+ * close_block_group_stripe_runs()). Decided once, here: the commit
+ * path's close and settle predicates must agree with each other for
+ * the run's whole life, whatever the policy does meanwhile.
+ */
+ new_run->persistent = class == BTRFS_STRIPE_RUN_NOCOW &&
+ (btrfs_stripe_allow_rmw(fs_info) &
+ (BTRFS_STRIPE_RMW_NODATACOW |
+ BTRFS_STRIPE_RMW_PREALLOC));
new_run->owner = ino;
new_run->start = start;
new_run->end = start + len;
continue;
/*
* A nodatacow inode's private run survives transaction
- * commits: its stripes hold only that inode's expendable
- * (write-hole-waived) data, so invariant I2 has nothing to
- * protect there, and closing would burn a stripe per commit
- * for a slowly appended nocow file. Forced quiescing
+ * commits while the stripe_alloc_allow_rmw policy lets its
+ * data be written in place: its stripes then hold only that
+ * inode's expendable (write-hole-waived) data, so invariant
+ * I2 has nothing to protect there, and closing would burn a
+ * stripe per commit for a slowly appended nocow file. With
+ * nothing waived the run holds ordinary COWed extents (or
+ * unwritten preallocation) and closes like a COW run: kept
+ * open, it only strands the whole stripes freed inside its
+ * range until the inode is evicted. Forced quiescing
* (read-only, removal, unmount: seq == U64_MAX) still closes
- * them, as does the owning inode's eviction.
+ * persistent runs, as does the owning inode's eviction.
*/
- if (run->class == BTRFS_STRIPE_RUN_NOCOW && seq != U64_MAX)
+ if (run->persistent && seq != U64_MAX)
continue;
/*
* Metadata runs are still being filled at this point in the
spin_lock_irqsave(&bg->stripe_run_lock, flags);
list_for_each_entry(run, &bg->open_stripe_runs, list) {
/* Persistent nocow runs are not part of any commit window. */
- if (run->class == BTRFS_STRIPE_RUN_NOCOW && seq != U64_MAX)
+ if (run->persistent && seq != U64_MAX)
continue;
/* Metadata drains after tree writeback, not here. */
if (run->class == BTRFS_STRIPE_RUN_META && seq != U64_MAX)
* seeded with the run's location as the search hint. NOCOW class
* for preallocated extents and nodatacow files' extents (candidates
* for future write-in-place, which must never share a stripe with
- * any other file's data); LOG class for log-active inodes (see
- * BTRFS_INODE_LOG_ALLOC). Purely placement: any allocation that
- * cannot be served from a private run falls back to the shared runs.
+ * any other file's data) -- but only while the stripe_alloc_allow_rmw
+ * policy lets that kind of extent be written in place: otherwise
+ * every write to it is COWed like anyone else's, and a private run
+ * (which outlives commits) would only strand the whole stripes freed
+ * inside its range until the inode is evicted; LOG class for
+ * log-active inodes (see BTRFS_INODE_LOG_ALLOC). Purely placement:
+ * any allocation that cannot be served from a private run falls back
+ * to the shared runs.
*/
if (inode && is_data && !for_data_reloc &&
btrfs_test_opt(fs_info, STRIPE_ALLOC)) {
- if (for_prealloc || (inode->flags & BTRFS_INODE_NODATACOW)) {
+ const u32 rmw = btrfs_stripe_allow_rmw(fs_info);
+
+ if ((for_prealloc && (rmw & BTRFS_STRIPE_RMW_PREALLOC)) ||
+ (!for_prealloc && (inode->flags & BTRFS_INODE_NODATACOW) &&
+ (rmw & BTRFS_STRIPE_RMW_NODATACOW))) {
steer_inode = inode;
steer_class = BTRFS_STRIPE_RUN_NOCOW;
} else if (test_bit(BTRFS_INODE_LOG_ALLOC,