The LOGICAL_INO ioctl is a simple wrapper around an internal btrfs kernel
function which iterates over references to a data extent. This function
can operate in two modes:
#1 joins the current transaction to get up to date information
on uncommitted references. LOGICAL_INO can run for a long
time--seconds to minutes on deduped filesystems--and all that
time gets added to the latency of transaction commits. This slows
down other threads writing to the filesystem, as well as reducing
concurrency in LOGICAL_INO itself.
#2 doesn't join a transaction, and just searches commit roots
instead. This loses access to backref data from uncommitted
references, but doesn't add latency to all other users of the
filesystem while it runs.
Userspace has no mechanism to prevent concurrent changes on the
filesystem, so userspace must tolerate out-of-date backref information
e.g. looping removing extent refs until LOGICAL_INO gives no more
reachable references. With a switch from the #1 mode to the #2 mode,
userspace must ensure a commit occurs between loops, either by calling
fssync itself, or by finding something else to do between loop iterations
until a commit occurs naturally.
This is a change in behavior, so we don't do it by default. Add a new
flag SEARCH_COMMIT_ROOT for LOGICAL_INO_V2 so that users can request
the faster, lower-latency version.
Signed-off-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
(cherry picked from commit
f35030f24f09ae428a3c069151ee8aaac5d5d041)
(cherry picked from commit
32c0c08a2c7cb65131c2679add5a302eb24c01f2)
(cherry picked from commit
d753020b163b1b2ccba6fc39009a11e2c13633e4)
(cherry picked from commit
6c8b74540686d3096f8f0a85749eb71ae0c5e629)
v2: fixed logic to verify that all flags are supported.
(cherry picked from commit
403cd2651289de590d098dce433671eecc092cad)
struct btrfs_ioctl_logical_ino_args *loi;
struct btrfs_data_container *inodes = NULL;
struct btrfs_path *path = NULL;
- bool ignore_offset;
+ bool ignore_offset = false;
+ bool search_commit_root = false;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
return PTR_ERR(loi);
if (version == 1) {
- ignore_offset = false;
size = min_t(u32, loi->size, SZ_64K);
} else {
+ u64 flags = loi->flags;
/* All reserved bits must be 0 for now */
if (memchr_inv(loi->reserved, 0, sizeof(loi->reserved))) {
ret = -EINVAL;
goto out_loi;
}
+ if (flags & BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET) {
+ ignore_offset = true;
+ flags &= ~BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET;
+ }
+ if (flags & BTRFS_LOGICAL_INO_ARGS_SEARCH_COMMIT_ROOT) {
+ search_commit_root = true;
+ flags &= ~BTRFS_LOGICAL_INO_ARGS_SEARCH_COMMIT_ROOT;
+ }
/* Only accept flags we have defined so far */
- if (loi->flags & ~(BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET)) {
+ if (flags) {
ret = -EINVAL;
goto out_loi;
}
- ignore_offset = loi->flags & BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET;
size = min_t(u32, loi->size, SZ_16M);
}
ret = -ENOMEM;
goto out;
}
+ path->search_commit_root = search_commit_root;
+ path->skip_locking = search_commit_root;
inodes = init_data_container(size);
if (IS_ERR(inodes)) {
};
/* Return every ref to the extent, not just those containing logical block.
* Requires logical == extent bytenr. */
-#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET (1ULL << 0)
+#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET (1ULL << 0)
+/* Search the commit root instead of joining the current transaction.
+ * Avoids transaction commit latency, but results may be out of date. */
+#define BTRFS_LOGICAL_INO_ARGS_SEARCH_COMMIT_ROOT (1ULL << 1)
enum btrfs_dev_stat_values {
/* disk I/O failure stats */