From ed46e08c0ac4faefb399100579615f438d65c26d Mon Sep 17 00:00:00 2001 From: Thomas Tsai Date: Tue, 11 Jun 2024 14:00:29 +0800 Subject: [PATCH] update btrfs to 6.8.1 --- src/btrfs/check/qgroup-verify.c | 2 +- src/btrfs/check/repair.c | 2 +- src/btrfs/common/device-scan.c | 19 +- src/btrfs/common/device-scan.h | 24 +- src/btrfs/common/device-utils.c | 34 +- src/btrfs/common/device-utils.h | 10 +- src/btrfs/common/extent-cache.c | 24 +- src/btrfs/common/filesystem-utils.c | 5 +- src/btrfs/common/fsfeatures.c | 63 ++- src/btrfs/common/fsfeatures.h | 3 +- src/btrfs/common/messages.c | 3 + src/btrfs/common/messages.h | 3 + src/btrfs/common/open-utils.c | 140 ++---- src/btrfs/common/open-utils.h | 13 +- src/btrfs/common/parse-utils.c | 87 ++-- src/btrfs/common/parse-utils.h | 2 +- src/btrfs/common/path-utils.c | 37 +- src/btrfs/common/path-utils.h | 2 + src/btrfs/common/rbtree-utils.c | 2 +- src/btrfs/common/rbtree-utils.h | 9 +- src/btrfs/common/string-utils.c | 41 +- src/btrfs/common/string-utils.h | 9 + src/btrfs/common/sysfs-utils.c | 82 +++- src/btrfs/common/sysfs-utils.h | 5 + src/btrfs/common/tree-search.h | 33 ++ src/btrfs/common/utils.c | 108 +++-- src/btrfs/common/utils.h | 18 + src/btrfs/crypto/hash.c | 108 +++++ src/btrfs/include/kerncompat.h | 2 +- src/btrfs/kernel-shared/accessors.c | 6 +- src/btrfs/kernel-shared/accessors.h | 88 ++-- src/btrfs/kernel-shared/compression.h | 19 +- src/btrfs/kernel-shared/ctree.c | 6 +- src/btrfs/kernel-shared/ctree.h | 11 +- src/btrfs/kernel-shared/delayed-ref.h | 18 +- src/btrfs/kernel-shared/dir-item.c | 1 - src/btrfs/kernel-shared/disk-io.c | 36 +- src/btrfs/kernel-shared/disk-io.h | 8 +- src/btrfs/kernel-shared/extent-tree.c | 21 +- src/btrfs/kernel-shared/extent_io.c | 7 +- src/btrfs/kernel-shared/extent_io.h | 2 +- src/btrfs/kernel-shared/file-item.c | 10 +- src/btrfs/kernel-shared/file-item.h | 5 +- src/btrfs/kernel-shared/free-space-cache.c | 2 +- src/btrfs/kernel-shared/free-space-tree.c | 18 +- src/btrfs/kernel-shared/free-space-tree.h | 5 + src/btrfs/kernel-shared/inode-item.c | 51 +- src/btrfs/kernel-shared/messages.c | 22 +- src/btrfs/kernel-shared/messages.h | 5 + src/btrfs/kernel-shared/misc.h | 20 + src/btrfs/kernel-shared/print-tree.c | 2 - src/btrfs/kernel-shared/print-tree.h | 10 +- src/btrfs/kernel-shared/root-tree.c | 18 +- src/btrfs/kernel-shared/transaction.h | 8 +- src/btrfs/kernel-shared/tree-checker.c | 112 ++++- src/btrfs/kernel-shared/tree-checker.h | 3 +- src/btrfs/kernel-shared/uapi/btrfs.h | 6 +- src/btrfs/kernel-shared/ulist.c | 3 +- src/btrfs/kernel-shared/uuid-tree.c | 22 +- src/btrfs/kernel-shared/volumes.c | 10 +- src/btrfs/kernel-shared/zoned.c | 4 +- src/btrfs/libbtrfs/ctree.h | 24 +- src/btrfs/libbtrfs/kerncompat.h | 2 +- src/btrfs/libbtrfs/version.h | 2 +- src/btrfs/libbtrfsutil/btrfs.h | 101 +++- src/btrfs/libbtrfsutil/btrfs_tree.h | 105 +++- src/btrfs/libbtrfsutil/btrfsutil.h | 501 +++++++++++++++----- src/btrfs/libbtrfsutil/btrfsutil_internal.h | 1 + src/btrfs/libbtrfsutil/qgroup.c | 4 + src/btrfs/libbtrfsutil/subvolume.c | 99 +++- src/version.h | 2 +- 71 files changed, 1651 insertions(+), 639 deletions(-) create mode 100644 src/btrfs/common/tree-search.h diff --git a/src/btrfs/check/qgroup-verify.c b/src/btrfs/check/qgroup-verify.c index 890e5410..4fa51446 100644 --- a/src/btrfs/check/qgroup-verify.c +++ b/src/btrfs/check/qgroup-verify.c @@ -960,9 +960,9 @@ static int load_quota_info(struct btrfs_fs_info *info) * items. The 2nd pass picks up relation items and glues them to their * respective count structures. */ - key.offset = 0; key.objectid = search_relations ? 0 : BTRFS_QGROUP_RELATION_KEY; key.type = 0; + key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); if (ret < 0) { diff --git a/src/btrfs/check/repair.c b/src/btrfs/check/repair.c index c81f19ba..e500c4fa 100644 --- a/src/btrfs/check/repair.c +++ b/src/btrfs/check/repair.c @@ -227,9 +227,9 @@ static int populate_used_from_extent_root(struct btrfs_root *root, int slot; int ret; - key.offset = 0; key.objectid = 0; key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0); if (ret < 0) return ret; diff --git a/src/btrfs/common/device-scan.c b/src/btrfs/common/device-scan.c index c1cd7266..bf6b6d57 100644 --- a/src/btrfs/common/device-scan.c +++ b/src/btrfs/common/device-scan.c @@ -144,10 +144,9 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, device_total_bytes = (device_total_bytes / sectorsize) * sectorsize; device = calloc(1, sizeof(*device)); - if (!device) { - ret = -ENOMEM; - goto out; - } + if (!device) + return -ENOMEM; + buf = calloc(1, sectorsize); if (!buf) { ret = -ENOMEM; @@ -208,7 +207,11 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, ret = sbwrite(fd, buf, BTRFS_SUPER_INFO_OFFSET); /* Ensure super block was written to the device */ - BUG_ON(ret != BTRFS_SUPER_INFO_SIZE); + if (ret != BTRFS_SUPER_INFO_SIZE) { + error_msg(ERROR_MSG_WRITE, "superblock when adding device: %m"); + ret = -EIO; + goto out; + } free(buf); list_add(&device->dev_list, &fs_info->fs_devices->devices); device->fs_devices = fs_info->fs_devices; @@ -313,8 +316,7 @@ int is_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[]) return 0; } -int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[], - int fd, DIR *dirstream) +int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[], int fd) { u8 hash = fsid[0]; int slot = hash % SEEN_FSID_HASH_SIZE; @@ -342,7 +344,6 @@ int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[], alloc->next = NULL; memcpy(alloc->fsid, fsid, BTRFS_FSID_SIZE); alloc->fd = fd; - alloc->dirstream = dirstream; if (seen) seen->next = alloc; @@ -362,7 +363,7 @@ void free_seen_fsid(struct seen_fsid *seen_fsid_hash[]) seen = seen_fsid_hash[slot]; while (seen) { next = seen->next; - close_file_or_dir(seen->fd, seen->dirstream); + close(seen->fd); free(seen); seen = next; } diff --git a/src/btrfs/common/device-scan.h b/src/btrfs/common/device-scan.h index 8a875832..1cc370b9 100644 --- a/src/btrfs/common/device-scan.h +++ b/src/btrfs/common/device-scan.h @@ -22,16 +22,18 @@ #include "kernel-lib/bitops.h" #include "kernel-shared/uapi/btrfs.h" -#define BTRFS_SCAN_MOUNTED (1ULL << 0) -#define BTRFS_SCAN_LBLKID (1ULL << 1) - -#define BTRFS_UPDATE_KERNEL 1 +enum { + BTRFS_SCAN_MOUNTED = (1ULL << 0), + BTRFS_SCAN_LBLKID = (1ULL << 1) +}; -#define BTRFS_ARG_UNKNOWN 0 -#define BTRFS_ARG_MNTPOINT 1 -#define BTRFS_ARG_UUID 2 -#define BTRFS_ARG_BLKDEV 3 -#define BTRFS_ARG_REG 4 +enum { + BTRFS_ARG_UNKNOWN, + BTRFS_ARG_MNTPOINT, + BTRFS_ARG_UUID, + BTRFS_ARG_BLKDEV, + BTRFS_ARG_REG, +}; #define SEEN_FSID_HASH_SIZE 256 @@ -41,7 +43,6 @@ struct btrfs_trans_handle; struct seen_fsid { u8 fsid[BTRFS_FSID_SIZE]; struct seen_fsid *next; - DIR *dirstream; int fd; }; @@ -56,8 +57,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans, int btrfs_device_already_in_root(struct btrfs_root *root, int fd, int super_offset); int is_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[]); -int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[], - int fd, DIR *dirstream); +int add_seen_fsid(u8 *fsid, struct seen_fsid *seen_fsid_hash[], int fd); void free_seen_fsid(struct seen_fsid *seen_fsid_hash[]); int test_uuid_unique(const char *uuid_str); diff --git a/src/btrfs/common/device-utils.c b/src/btrfs/common/device-utils.c index a34770f7..d086e9ea 100644 --- a/src/btrfs/common/device-utils.c +++ b/src/btrfs/common/device-utils.c @@ -112,8 +112,11 @@ int device_zero_blocks(int fd, off_t start, size_t len, bool direct) return -ENOMEM; memset(buf, 0, len); written = btrfs_pwrite(fd, buf, len, start, direct); - if (written != len) + if (written != len) { + error_msg(ERROR_MSG_WRITE, "zeroing range from %llu: %m", + (unsigned long long)start); ret = -EIO; + } free(buf); return ret; } @@ -340,14 +343,14 @@ static u64 device_get_partition_size_sysfs(const char *dev) char path[PATH_MAX] = {}; char sysfs[PATH_MAX] = {}; char sizebuf[128] = {}; - char *name = NULL; + const char *name = NULL; int sysfd; unsigned long long size = 0; name = realpath(dev, path); if (!name) return 0; - name = basename(path); + name = path_basename(path); ret = path_cat3_out(sysfs, "/sys/class/block", name, "size"); if (ret < 0) @@ -437,29 +440,25 @@ int device_get_queue_param(const char *file, const char *param, char *buf, size_ */ u64 device_get_zone_unusable(int fd, u64 flags) { - char buf[64]; - int sys_fd; - u64 unusable = DEVICE_ZONE_UNUSABLE_UNKNOWN; + int ret; + u64 unusable; /* Don't report it for a regular fs */ - sys_fd = sysfs_open_fsid_file(fd, "features/zoned"); - if (sys_fd < 0) + ret = sysfs_open_fsid_file(fd, "features/zoned"); + if (ret < 0) return DEVICE_ZONE_UNUSABLE_UNKNOWN; - close(sys_fd); - sys_fd = -1; + close(ret); + ret = -1; if ((flags & BTRFS_BLOCK_GROUP_DATA) == BTRFS_BLOCK_GROUP_DATA) - sys_fd = sysfs_open_fsid_file(fd, "allocation/data/bytes_zone_unusable"); + ret = sysfs_read_fsid_file_u64(fd, "allocation/data/bytes_zone_unusable", &unusable); else if ((flags & BTRFS_BLOCK_GROUP_METADATA) == BTRFS_BLOCK_GROUP_METADATA) - sys_fd = sysfs_open_fsid_file(fd, "allocation/metadata/bytes_zone_unusable"); + ret = sysfs_read_fsid_file_u64(fd, "allocation/metadata/bytes_zone_unusable", &unusable); else if ((flags & BTRFS_BLOCK_GROUP_SYSTEM) == BTRFS_BLOCK_GROUP_SYSTEM) - sys_fd = sysfs_open_fsid_file(fd, "allocation/system/bytes_zone_unusable"); + ret = sysfs_read_fsid_file_u64(fd, "allocation/system/bytes_zone_unusable", &unusable); - if (sys_fd < 0) + if (ret < 0) return DEVICE_ZONE_UNUSABLE_UNKNOWN; - sysfs_read_file(sys_fd, buf, sizeof(buf)); - unusable = strtoull(buf, NULL, 10); - close(sys_fd); return unusable; } @@ -504,6 +503,7 @@ u64 device_get_zone_size(int fd, const char *name) /* /sys/fs/btrfs/FSID/devices/NAME/queue/chunk_sectors */ queue_fd = sysfs_open_fsid_file(fd, queue); if (queue_fd < 0) { + queue_fd = -1; ret = 0; break; } diff --git a/src/btrfs/common/device-utils.h b/src/btrfs/common/device-utils.h index 853d17b5..97dceb85 100644 --- a/src/btrfs/common/device-utils.h +++ b/src/btrfs/common/device-utils.h @@ -28,10 +28,12 @@ struct stat; /* * Options for btrfs_prepare_device */ -#define PREP_DEVICE_ZERO_END (1U << 0) -#define PREP_DEVICE_DISCARD (1U << 1) -#define PREP_DEVICE_VERBOSE (1U << 2) -#define PREP_DEVICE_ZONED (1U << 3) +enum { + PREP_DEVICE_ZERO_END = (1U << 0), + PREP_DEVICE_DISCARD = (1U << 1), + PREP_DEVICE_VERBOSE = (1U << 2), + PREP_DEVICE_ZONED = (1U << 3), +}; /* Placeholder to denote no results for the zone_unusable sysfs value */ #define DEVICE_ZONE_UNUSABLE_UNKNOWN ((u64)-1) diff --git a/src/btrfs/common/extent-cache.c b/src/btrfs/common/extent-cache.c index 4f6d48cd..4434fdca 100644 --- a/src/btrfs/common/extent-cache.c +++ b/src/btrfs/common/extent-cache.c @@ -29,12 +29,12 @@ struct cache_extent_search_range { u64 size; }; -static int cache_tree_comp_range(struct rb_node *node, void *data) +static int cache_tree_comp_range(const struct rb_node *node, const void *data) { - struct cache_extent *entry; - struct cache_extent_search_range *range; + const struct cache_extent *entry; + const struct cache_extent_search_range *range; - range = (struct cache_extent_search_range *)data; + range = (const struct cache_extent_search_range *)data; entry = rb_entry(node, struct cache_extent, rb_node); if (entry->start + entry->size <= range->start) @@ -45,9 +45,9 @@ static int cache_tree_comp_range(struct rb_node *node, void *data) return 0; } -static int cache_tree_comp_nodes(struct rb_node *node1, struct rb_node *node2) +static int cache_tree_comp_nodes(const struct rb_node *node1, const struct rb_node *node2) { - struct cache_extent *entry; + const struct cache_extent *entry; struct cache_extent_search_range range; entry = rb_entry(node2, struct cache_extent, rb_node); @@ -57,10 +57,10 @@ static int cache_tree_comp_nodes(struct rb_node *node1, struct rb_node *node2) return cache_tree_comp_range(node1, (void *)&range); } -static int cache_tree_comp_range2(struct rb_node *node, void *data) +static int cache_tree_comp_range2(const struct rb_node *node, const void *data) { - struct cache_extent *entry; - struct cache_extent_search_range *range; + const struct cache_extent *entry; + const struct cache_extent_search_range *range; range = (struct cache_extent_search_range *)data; entry = rb_entry(node, struct cache_extent, rb_node); @@ -77,9 +77,9 @@ static int cache_tree_comp_range2(struct rb_node *node, void *data) return 0; } -static int cache_tree_comp_nodes2(struct rb_node *node1, struct rb_node *node2) +static int cache_tree_comp_nodes2(const struct rb_node *node1, const struct rb_node *node2) { - struct cache_extent *entry; + const struct cache_extent *entry; struct cache_extent_search_range range; entry = rb_entry(node2, struct cache_extent, rb_node); @@ -87,7 +87,7 @@ static int cache_tree_comp_nodes2(struct rb_node *node1, struct rb_node *node2) range.start = entry->start; range.size = entry->size; - return cache_tree_comp_range2(node1, (void *)&range); + return cache_tree_comp_range2(node1, &range); } void cache_tree_init(struct cache_tree *tree) diff --git a/src/btrfs/common/filesystem-utils.c b/src/btrfs/common/filesystem-utils.c index 8c159365..66269ad9 100644 --- a/src/btrfs/common/filesystem-utils.c +++ b/src/btrfs/common/filesystem-utils.c @@ -98,7 +98,10 @@ static int set_label_unmounted(const char *dev, const char *label) return -1; trans = btrfs_start_transaction(root, 1); - BUG_ON(IS_ERR(trans)); + if (IS_ERR(trans)) { + error_msg(ERROR_MSG_START_TRANS, "set label"); + return PTR_ERR(trans); + } __strncpy_null(root->fs_info->super_copy->label, label, BTRFS_LABEL_SIZE - 1); btrfs_commit_transaction(trans, root); diff --git a/src/btrfs/common/fsfeatures.c b/src/btrfs/common/fsfeatures.c index 8ce9d1dc..c5e81629 100644 --- a/src/btrfs/common/fsfeatures.c +++ b/src/btrfs/common/fsfeatures.c @@ -31,6 +31,7 @@ #include "common/string-utils.h" #include "common/sysfs-utils.h" #include "common/messages.h" +#include "common/tree-search.h" /* * Insert a root item for temporary tree root @@ -121,7 +122,7 @@ static const struct btrfs_feature mkfs_features[] = { VERSION_TO_STRING2(compat, 3,4), VERSION_NULL(safe), VERSION_NULL(default), - .desc = "quota support (qgroups)" + .desc = "hierarchical quota group support (qgroups)" }, { .name = "extref", @@ -172,7 +173,7 @@ static const struct btrfs_feature mkfs_features[] = { VERSION_TO_STRING2(compat, 4,5), VERSION_TO_STRING2(safe, 4,9), VERSION_TO_STRING2(default, 5,15), - .desc = "free space tree (space_cache=v2)" + .desc = "free space tree, improved space tracking (space_cache=v2)" }, { .name = "raid1c34", @@ -191,7 +192,7 @@ static const struct btrfs_feature mkfs_features[] = { VERSION_TO_STRING2(compat, 5,12), VERSION_NULL(safe), VERSION_NULL(default), - .desc = "support zoned devices" + .desc = "support zoned (SMR/ZBC/ZNS) devices" }, #endif #if EXPERIMENTAL @@ -219,7 +220,7 @@ static const struct btrfs_feature mkfs_features[] = { VERSION_TO_STRING2(compat, 6,1), VERSION_NULL(safe), VERSION_NULL(default), - .desc = "block group tree to reduce mount time" + .desc = "block group tree, more efficient block group tracking to reduce mount time" }, { .name = "rst", @@ -235,7 +236,7 @@ static const struct btrfs_feature mkfs_features[] = { VERSION_TO_STRING2(compat, 6,7), VERSION_NULL(safe), VERSION_NULL(default), - .desc = "raid stripe tree" + .desc = "raid stripe tree, enhanced file extent tracking" }, { .name = "squota", @@ -312,12 +313,21 @@ void btrfs_assert_feature_buf_size(void) for (i = 0; i < ARRAY_SIZE(mkfs_features); i++) /* The extra 2 bytes are for the ", " prefix. */ total_size += strlen(mkfs_features[i].name) + 2; - BUG_ON(BTRFS_FEATURE_STRING_BUF_SIZE < total_size); + + if (BTRFS_FEATURE_STRING_BUF_SIZE < total_size) { + internal_error("string buffer for freature list too small: want %d\n", + total_size); + abort(); + } total_size = 0; for (i = 0; i < ARRAY_SIZE(runtime_features); i++) total_size += strlen(runtime_features[i].name) + 2; - BUG_ON(BTRFS_FEATURE_STRING_BUF_SIZE < total_size); + if (BTRFS_FEATURE_STRING_BUF_SIZE < total_size) { + internal_error("string buffer for freature list too small: want %d\n", + total_size); + abort(); + } } static size_t get_feature_array_size(enum feature_source source) @@ -628,8 +638,10 @@ int btrfs_check_sectorsize(u32 sectorsize) if (!sectorsize_checked) warning( -"the filesystem may not be mountable, sectorsize %u doesn't match page size %u", - sectorsize, page_size); +"sectorsize %u does not match host CPU page size %u, with kernels 6.x and up\n" +"\t the 4KiB sectorsize is supported on all architectures but other combinations\n" +"\t may fail the filesystem mount, use \"--sectorsize %u\" to override that\n", + sectorsize, page_size, page_size); return 0; } @@ -669,6 +681,35 @@ int btrfs_check_features(const struct btrfs_mkfs_features *features, return 0; } +static bool tree_search_v2_supported = false; +static bool tree_search_v2_initialized = false; + +/* + * Call the highest supported TREE_SEARCH ioctl version, autodetect support. + */ +int btrfs_tree_search_ioctl(int fd, struct btrfs_tree_search_args *sa) +{ + /* On first use check the supported status and save it. */ + if (!tree_search_v2_initialized) { +#if 0 + /* + * Keep using v1 until v2 is fully tested, in some cases it + * does not return properly formatted results in the buffer. + */ + if (btrfs_tree_search2_ioctl_supported(fd) == 1) + tree_search_v2_supported = true; +#endif + tree_search_v2_initialized = true; + } + sa->use_v2 = tree_search_v2_supported; + + if (sa->use_v2) { + sa->args2.buf_size = BTRFS_TREE_SEARCH_V2_BUF_SIZE; + return ioctl(fd, BTRFS_IOC_TREE_SEARCH_V2, &sa->args2); + } + return ioctl(fd, BTRFS_IOC_TREE_SEARCH, &sa->args1); +} + /* * Check if the BTRFS_IOC_TREE_SEARCH_V2 ioctl is supported on a given * filesystem, opened at fd @@ -689,10 +730,10 @@ int btrfs_tree_search2_ioctl_supported(int fd) */ sk->tree_id = BTRFS_ROOT_TREE_OBJECTID; sk->min_objectid = BTRFS_EXTENT_TREE_OBJECTID; - sk->max_objectid = BTRFS_EXTENT_TREE_OBJECTID; sk->min_type = BTRFS_ROOT_ITEM_KEY; - sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->min_offset = 0; + sk->max_objectid = BTRFS_EXTENT_TREE_OBJECTID; + sk->max_type = BTRFS_ROOT_ITEM_KEY; sk->max_offset = (u64)-1; sk->min_transid = 0; sk->max_transid = (u64)-1; diff --git a/src/btrfs/common/fsfeatures.h b/src/btrfs/common/fsfeatures.h index f636171f..5b241bdf 100644 --- a/src/btrfs/common/fsfeatures.h +++ b/src/btrfs/common/fsfeatures.h @@ -68,7 +68,8 @@ static const struct btrfs_mkfs_features btrfs_convert_allowed_features = { BTRFS_FEATURE_INCOMPAT_BIG_METADATA | BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | - BTRFS_FEATURE_INCOMPAT_NO_HOLES, + BTRFS_FEATURE_INCOMPAT_NO_HOLES | + BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE, .runtime_flags = BTRFS_FEATURE_RUNTIME_QUOTA, }; diff --git a/src/btrfs/common/messages.c b/src/btrfs/common/messages.c index 0cdf56a7..a349965b 100644 --- a/src/btrfs/common/messages.c +++ b/src/btrfs/common/messages.c @@ -24,6 +24,9 @@ static const char *common_error_string[] = { [ERROR_MSG_MEMORY] = "not enough memory", [ERROR_MSG_START_TRANS] = "failed to start transaction", [ERROR_MSG_COMMIT_TRANS] = "failed to commit transaction", + [ERROR_MSG_UNEXPECTED] = "unexpected condition, probably corruption", + [ERROR_MSG_READ] = "write() failed", + [ERROR_MSG_WRITE] = "read() failed", }; __attribute__ ((format (printf, 1, 2))) diff --git a/src/btrfs/common/messages.h b/src/btrfs/common/messages.h index 4ade6d25..d6d4044d 100644 --- a/src/btrfs/common/messages.h +++ b/src/btrfs/common/messages.h @@ -190,6 +190,9 @@ enum common_error { ERROR_MSG_MEMORY, ERROR_MSG_START_TRANS, ERROR_MSG_COMMIT_TRANS, + ERROR_MSG_UNEXPECTED, + ERROR_MSG_READ, + ERROR_MSG_WRITE, }; __attribute__ ((format (printf, 2, 3))) diff --git a/src/btrfs/common/open-utils.c b/src/btrfs/common/open-utils.c index 111a51d9..95294f63 100644 --- a/src/btrfs/common/open-utils.c +++ b/src/btrfs/common/open-utils.c @@ -184,137 +184,81 @@ int get_btrfs_mount(const char *dev, char *mp, size_t mp_size) } /* - * Given a pathname, return a filehandle to: - * the original pathname or, - * if the pathname is a mounted btrfs device, to its mountpoint. + * Open the given path and check if it's a btrfs filesystem. * - * On error, return -1, errno should be set. + * Return the file descriptor or -errno. */ -int open_path_or_dev_mnt(const char *path, DIR **dirstream, int verbose) -{ - char mp[PATH_MAX]; - int ret; - - if (path_is_block_device(path)) { - ret = get_btrfs_mount(path, mp, sizeof(mp)); - if (ret < 0) { - /* not a mounted btrfs dev */ - error_on(verbose, "'%s' is not a mounted btrfs device", - path); - errno = EINVAL; - return -1; - } - ret = open_file_or_dir(mp, dirstream); - error_on(verbose && ret < 0, "can't access '%s': %m", - path); - } else { - ret = btrfs_open_dir(path, dirstream, 1); - } - - return ret; -} - -/* - * Do the following checks before calling open_file_or_dir(): - * 1: path is in a btrfs filesystem - * 2: path is a directory if dir_only is 1 - */ -int btrfs_open(const char *path, DIR **dirstream, int verbose, int dir_only) +int btrfs_open_path(const char *path, bool read_write, bool dir_only) { struct statfs stfs; struct stat st; int ret; - if (stat(path, &st) != 0) { - error_on(verbose, "cannot access '%s': %m", path); - return -1; + if (stat(path, &st) < 0) { + error("cannot access '%s': %m", path); + return -errno; } if (dir_only && !S_ISDIR(st.st_mode)) { - error_on(verbose, "not a directory: %s", path); - return -3; + error("not a directory: %s", path); + return -ENOTDIR; } - if (statfs(path, &stfs) != 0) { - error_on(verbose, "cannot access '%s': %m", path); - return -1; + if (statfs(path, &stfs) < 0) { + error("cannot access '%s': %m", path); + return -errno; } if (stfs.f_type != BTRFS_SUPER_MAGIC) { - error_on(verbose, "not a btrfs filesystem: %s", path); - return -2; + error("not a btrfs filesystem: %s", path); + return -EINVAL; } - ret = open_file_or_dir(path, dirstream); + if (S_ISDIR(st.st_mode) || !read_write) + ret = open(path, O_RDONLY); + else + ret = open(path, O_RDWR); + if (ret < 0) { - error_on(verbose, "cannot access '%s': %m", path); + error("cannot access '%s': %m", path); + ret = -errno; } return ret; } -int btrfs_open_dir(const char *path, DIR **dirstream, int verbose) +int btrfs_open_file_or_dir(const char *path) { - return btrfs_open(path, dirstream, verbose, 1); + return btrfs_open_path(path, true, false); } -int btrfs_open_file_or_dir(const char *path, DIR **dirstream, int verbose) +/* Open the path for write and check that it's a directory. */ +int btrfs_open_dir(const char *path) { - return btrfs_open(path, dirstream, verbose, 0); + return btrfs_open_path(path, true, true); } -int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags) +/* + * Given a path, return a file descriptor to the original path name or, if the + * pathname is a mounted btrfs device, to its mountpoint. + * + * Return the file descriptor or -errno. + */ +int btrfs_open_mnt(const char *path) { + char mp[PATH_MAX]; int ret; - struct stat st; - int fd; - ret = stat(fname, &st); - if (ret < 0) { - return -1; - } - if (S_ISDIR(st.st_mode)) { - *dirstream = opendir(fname); - if (!*dirstream) - return -1; - fd = dirfd(*dirstream); - } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { - fd = open(fname, open_flags); - } else { - /* - * we set this on purpose, in case the caller output - * strerror(errno) as success - */ - errno = EINVAL; - return -1; - } - if (fd < 0) { - fd = -1; - if (*dirstream) { - closedir(*dirstream); - *dirstream = NULL; + if (path_is_block_device(path)) { + ret = get_btrfs_mount(path, mp, sizeof(mp)); + if (ret < 0) { + error("'%s' is not a mounted btrfs device", path); + return -EINVAL; } - } - return fd; -} - -int open_file_or_dir(const char *fname, DIR **dirstream) -{ - return open_file_or_dir3(fname, dirstream, O_RDWR); -} - -void close_file_or_dir(int fd, DIR *dirstream) -{ - int old_errno; - - old_errno = errno; - if (dirstream) { - closedir(dirstream); - } else if (fd >= 0) { - close(fd); + ret = btrfs_open_dir(mp); + } else { + ret = btrfs_open_dir(path); } - errno = old_errno; + return ret; } - - diff --git a/src/btrfs/common/open-utils.h b/src/btrfs/common/open-utils.h index 3f8c004e..04fd8eb1 100644 --- a/src/btrfs/common/open-utils.h +++ b/src/btrfs/common/open-utils.h @@ -28,15 +28,10 @@ int check_mounted_where(int fd, const char *file, char *where, int size, bool noscan); int check_mounted(const char* file); int get_btrfs_mount(const char *dev, char *mp, size_t mp_size); -int open_path_or_dev_mnt(const char *path, DIR **dirstream, int verbose); -int open_file_or_dir3(const char *fname, DIR **dirstream, int open_flags); -int open_file_or_dir(const char *fname, DIR **dirstream); - -int btrfs_open(const char *path, DIR **dirstream, int verbose, int dir_only); -int btrfs_open_dir(const char *path, DIR **dirstream, int verbose); -int btrfs_open_file_or_dir(const char *path, DIR **dirstream, int verbose); - -void close_file_or_dir(int fd, DIR *dirstream); +int btrfs_open_path(const char *path, bool read_write, bool dir_only); +int btrfs_open_file_or_dir(const char *path); +int btrfs_open_dir(const char *path); +int btrfs_open_mnt(const char *path); #endif diff --git a/src/btrfs/common/parse-utils.c b/src/btrfs/common/parse-utils.c index 74542a79..a722d035 100644 --- a/src/btrfs/common/parse-utils.c +++ b/src/btrfs/common/parse-utils.c @@ -31,14 +31,31 @@ #include "common/messages.h" #include "common/utils.h" +/* + * Parse a string to u64. + * + * Return 0 if there is a valid numeric string and result would be stored in + * @result. + * Return -EINVAL if the string is not valid (no numeric string at all, or + * has any tailing characters, or a negative value). + * Return -ERANGE if the value is too large for u64. + */ int parse_u64(const char *str, u64 *result) { char *endptr; u64 val; + /* + * Although strtoull accepts a negative number and converts it u64, we + * don't really want to utilize this as the helper is meant for u64 only. + */ + if (str[0] == '-') + return -EINVAL; val = strtoull(str, &endptr, 10); if (*endptr) - return 1; + return -EINVAL; + if (val == ULLONG_MAX && errno == ERANGE) + return -ERANGE; *result = val; return 0; @@ -143,39 +160,45 @@ int parse_range_strict(const char *range, u64 *start, u64 *end) return 1; } -u64 parse_size_from_string(const char *s) +/* + * Parse a string to u64, with support for size suffixes. + * + * The suffixes are all 1024 based, and is case-insensitive. + * The supported ones are "KMGPTE", with one extra suffix "B" supported. + * "B" just means byte, thus it won't change the value. + * + * After one or less suffix, there should be no extra character other than + * a tailing NUL. + * + * Return 0 if there is a valid numeric string and result would be stored in + * @result. + * Return -EINVAL if the string is not valid (no numeric string at all, has any + * tailing characters, or a negative value). + * Return -ERANGE if the value is too large for u64. + */ +int parse_u64_with_suffix(const char *s, u64 *value_ret) { char c; char *endptr; u64 mult = 1; - u64 ret; + u64 value; + + if (!s) + return -EINVAL; + if (s[0] == '-') + return -EINVAL; + + errno = 0; + value = strtoull(s, &endptr, 10); + if (endptr == s) + return -EINVAL; - if (!s) { - error("size value is empty"); - exit(1); - } - if (s[0] == '-') { - error("size value '%s' is less equal than 0", s); - exit(1); - } - ret = strtoull(s, &endptr, 10); - if (endptr == s) { - error("size value '%s' is invalid", s); - exit(1); - } - if (endptr[0] && endptr[1]) { - error("illegal suffix contains character '%c' in wrong position", - endptr[1]); - exit(1); - } /* * strtoll returns LLONG_MAX when overflow, if this happens, * need to call strtoull to get the real size */ - if (errno == ERANGE && ret == ULLONG_MAX) { - error("size value '%s' is too large for u64", s); - exit(1); - } + if (errno == ERANGE && value == ULLONG_MAX) + return -ERANGE; if (endptr[0]) { c = tolower(endptr[0]); switch (c) { @@ -200,17 +223,21 @@ u64 parse_size_from_string(const char *s) case 'b': break; default: - error("unknown size descriptor '%c'", c); - exit(1); + return -EINVAL; } + endptr++; } + /* Tailing character check. */ + if (endptr[0] != '\0') + return -EINVAL; /* Check whether ret * mult overflow */ - if (fls64(ret) + fls64(mult) - 1 > 64) { + if (fls64(value) + fls64(mult) - 1 > 64) { error("size value '%s' is too large for u64", s); exit(1); } - ret *= mult; - return ret; + value *= mult; + *value_ret = value; + return 0; } enum btrfs_csum_type parse_csum_type(const char *s) diff --git a/src/btrfs/common/parse-utils.h b/src/btrfs/common/parse-utils.h index 47f202c6..33ff9ca1 100644 --- a/src/btrfs/common/parse-utils.h +++ b/src/btrfs/common/parse-utils.h @@ -19,10 +19,10 @@ #include "kerncompat.h" -u64 parse_size_from_string(const char *s); enum btrfs_csum_type parse_csum_type(const char *s); int parse_u64(const char *str, u64 *result); +int parse_u64_with_suffix(const char *s, u64 *value_ret); int parse_range_u32(const char *range, u32 *start, u32 *end); int parse_range(const char *range, u64 *start, u64 *end); int parse_range_strict(const char *range, u64 *start, u64 *end); diff --git a/src/btrfs/common/path-utils.c b/src/btrfs/common/path-utils.c index a47ca422..494fe828 100644 --- a/src/btrfs/common/path-utils.c +++ b/src/btrfs/common/path-utils.c @@ -28,6 +28,11 @@ #include #include #include +/* + * For dirname() and basename(), but never use basename directly, there's + * path_basename() with unified GNU behaviour regardless of the includes and + * conditional defines. See basename(3) for more. + */ #include #include #include "common/path-utils.h" @@ -394,10 +399,12 @@ int path_is_dir(const char *path) */ int path_is_in_dir(const char *parent, const char *path) { - char *tmp = strdup(path); + char tmp[PATH_MAX]; char *curr_dir = tmp; int ret; + strncpy_null(tmp, path); + while (strcmp(parent, curr_dir) != 0) { if (strcmp(curr_dir, "/") == 0) { ret = 0; @@ -408,7 +415,6 @@ int path_is_in_dir(const char *parent, const char *path) ret = 1; out: - free(tmp); return ret; } @@ -481,3 +487,30 @@ int test_issubvolname(const char *name) strcmp(name, ".") && strcmp(name, ".."); } +/* + * Unified GNU semantics basename helper, never changing the argument. Always + * use this instead of basename(). + */ +char *path_basename(char *path) +{ +#if 0 + const char *tmp = strrchr(path, '/'); + + /* Special case when the whole path is just "/". */ + if (path[0] == '/' && path[1] == 0) + return path; + + return tmp ? tmp + 1 : path; +#else + return basename(path); +#endif +} + +/* + * Return dirname component of path, may change the argument. + * Own helper for parity with path_basename(). + */ +char *path_dirname(char *path) +{ + return dirname(path); +} diff --git a/src/btrfs/common/path-utils.h b/src/btrfs/common/path-utils.h index 08ae0ff1..da7e81e6 100644 --- a/src/btrfs/common/path-utils.h +++ b/src/btrfs/common/path-utils.h @@ -39,6 +39,8 @@ int path_is_dir(const char *path); int is_same_loop_file(const char *a, const char *b); int path_is_reg_or_block_device(const char *filename); int path_is_in_dir(const char *parent, const char *path); +char *path_basename(char *path); +char *path_dirname(char *path); int test_issubvolname(const char *name); diff --git a/src/btrfs/common/rbtree-utils.c b/src/btrfs/common/rbtree-utils.c index 5aa9b433..61ade288 100644 --- a/src/btrfs/common/rbtree-utils.c +++ b/src/btrfs/common/rbtree-utils.c @@ -46,7 +46,7 @@ int rb_insert(struct rb_root *root, struct rb_node *node, return 0; } -struct rb_node *rb_search(struct rb_root *root, void *key, rb_compare_keys comp, +struct rb_node *rb_search(struct rb_root *root, const void *key, rb_compare_keys comp, struct rb_node **next_ret) { struct rb_node *n = root->rb_node; diff --git a/src/btrfs/common/rbtree-utils.h b/src/btrfs/common/rbtree-utils.h index 4006c684..1f288b0f 100644 --- a/src/btrfs/common/rbtree-utils.h +++ b/src/btrfs/common/rbtree-utils.h @@ -23,17 +23,16 @@ struct rb_node; struct rb_root; /* The common insert/search/free functions */ -typedef int (*rb_compare_nodes)(struct rb_node *node1, struct rb_node *node2); -typedef int (*rb_compare_keys)(struct rb_node *node, void *key); +typedef int (*rb_compare_nodes)(const struct rb_node *node1, const struct rb_node *node2); +typedef int (*rb_compare_keys)(const struct rb_node *node, const void *key); typedef void (*rb_free_node)(struct rb_node *node); -int rb_insert(struct rb_root *root, struct rb_node *node, - rb_compare_nodes comp); +int rb_insert(struct rb_root *root, struct rb_node *node, rb_compare_nodes comp); /* * In some cases, we need return the next node if we don't find the node we * specify. At this time, we can use next_ret. */ -struct rb_node *rb_search(struct rb_root *root, void *key, rb_compare_keys comp, +struct rb_node *rb_search(struct rb_root *root, const void *key, rb_compare_keys comp, struct rb_node **next_ret); void rb_free_nodes(struct rb_root *root, rb_free_node free_node); diff --git a/src/btrfs/common/string-utils.c b/src/btrfs/common/string-utils.c index e338afa7..c6e16ddc 100644 --- a/src/btrfs/common/string-utils.c +++ b/src/btrfs/common/string-utils.c @@ -20,6 +20,7 @@ #include #include "common/string-utils.h" #include "common/messages.h" +#include "common/parse-utils.h" int string_is_numerical(const char *str) { @@ -50,26 +51,38 @@ int string_has_prefix(const char *str, const char *prefix) u64 arg_strtou64(const char *str) { u64 value; - char *ptr_parse_end = NULL; + int ret; - value = strtoull(str, &ptr_parse_end, 0); - if (ptr_parse_end && *ptr_parse_end != '\0') { - error("%s is not a valid numeric value", str); + ret = parse_u64(str, &value); + if (ret == -ERANGE) { + error("%s is too large", str); exit(1); - } - - /* - * if we pass a negative number to strtoull, it will return an - * unexpected number to us, so let's do the check ourselves. - */ - if (str[0] == '-') { - error("%s: negative value is invalid", str); + } else if (ret == -EINVAL) { + if (str[0] == '-') + error("%s: negative value is invalid", str); + else + error("%s is not a valid numeric value", str); exit(1); } - if (value == ULLONG_MAX) { + return value; +} + +u64 arg_strtou64_with_suffix(const char *str) +{ + u64 value; + int ret; + + ret = parse_u64_with_suffix(str, &value); + if (ret == -ERANGE) { error("%s is too large", str); exit(1); + } else if (ret == -EINVAL) { + error("%s is not a valid numeric value with supported size suffixes", str); + exit(1); + } else if (ret < 0) { + errno = -ret; + error("failed to parse string '%s': %m", str); + exit(1); } return value; } - diff --git a/src/btrfs/common/string-utils.h b/src/btrfs/common/string-utils.h index ade8fcd1..1a46315c 100644 --- a/src/btrfs/common/string-utils.h +++ b/src/btrfs/common/string-utils.h @@ -17,8 +17,17 @@ #ifndef __BTRFS_STRING_UTILS_H__ #define __BTRFS_STRING_UTILS_H__ +#include "kerncompat.h" + int string_is_numerical(const char *str); int string_has_prefix(const char *str, const char *prefix); + +/* + * Helpers prefixed by arg_* can exit if the argument is invalid and are supposed + * to be used when parsing command line options where the immediate exit is valid + * error handling. + */ u64 arg_strtou64(const char *str); +u64 arg_strtou64_with_suffix(const char *str); #endif diff --git a/src/btrfs/common/sysfs-utils.c b/src/btrfs/common/sysfs-utils.c index 6bc546d9..d7634987 100644 --- a/src/btrfs/common/sysfs-utils.c +++ b/src/btrfs/common/sysfs-utils.c @@ -26,7 +26,7 @@ * Open a file in fsid directory in sysfs and return the file descriptor or * error */ -int sysfs_open_fsid_file(int fd, const char *filename) +static int sysfs_open_fsid_file_flags(int fd, const char *filename, int flags) { u8 fsid[BTRFS_UUID_SIZE]; char fsid_str[BTRFS_UUID_UNPARSED_SIZE]; @@ -42,14 +42,25 @@ int sysfs_open_fsid_file(int fd, const char *filename) if (ret < 0) return ret; - return open(sysfs_file, O_RDONLY); + ret = open(sysfs_file, flags); + return (ret < 0 ? -errno : ret); +} + +int sysfs_open_fsid_file(int fd, const char *filename) +{ + return sysfs_open_fsid_file_flags(fd, filename, O_RDONLY); +} + +int sysfs_open_fsid_file_rw(int fd, const char *filename) +{ + return sysfs_open_fsid_file_flags(fd, filename, O_RDWR); } /* * Open a file in the toplevel sysfs directory and return the file descriptor * or error. */ -int sysfs_open_file(const char *name) +static int sysfs_open_file_flags(const char *name, int flags) { char path[PATH_MAX]; int ret; @@ -57,7 +68,18 @@ int sysfs_open_file(const char *name) ret = path_cat_out(path, "/sys/fs/btrfs", name); if (ret < 0) return ret; - return open(path, O_RDONLY); + ret = open(path, flags); + return (ret < 0 ? -errno : ret); +} + +int sysfs_open_file(const char *name) +{ + return sysfs_open_file_flags(name, O_RDONLY); +} + +int sysfs_open_file_rw(const char *name) +{ + return sysfs_open_file_flags(name, O_RDWR); } /* @@ -81,7 +103,8 @@ int sysfs_open_fsid_dir(int fd, const char *dirname) if (ret < 0) return ret; - return open(sysfs_file, O_DIRECTORY | O_RDONLY); + ret = open(sysfs_file, O_DIRECTORY | O_RDONLY); + return (ret < 0 ? -errno : ret); } /* @@ -89,9 +112,21 @@ int sysfs_open_fsid_dir(int fd, const char *dirname) */ int sysfs_read_file(int fd, char *buf, size_t size) { + int ret; + lseek(fd, 0, SEEK_SET); memset(buf, 0, size); - return read(fd, buf, size); + ret = read(fd, buf, size); + return (ret < 0 ? -errno : ret); +} + +int sysfs_write_file(int fd, const char *buf, size_t size) +{ + int ret; + + lseek(fd, 0, SEEK_SET); + ret = write(fd, buf, size); + return (ret < 0 ? -errno : ret); } int sysfs_read_file_u64(const char *name, u64 *value) @@ -108,12 +143,30 @@ int sysfs_read_file_u64(const char *name, u64 *value) if (ret < 0) goto out; /* Raw value in any numeric format should work, followed by a newline. */ + errno = 0; *value = strtoull(str, NULL, 0); + ret = -errno; out: close(fd); return ret; } +int sysfs_write_file_u64(const char *name, u64 value) +{ + int fd; + int ret; + char str[32] = { 0 }; + + fd = sysfs_open_file_rw(name); + if (fd < 0) + return fd; + + ret = snprintf(str, sizeof(str), "%llu", value); + ret = sysfs_write_file(fd, str, ret); + close(fd); + return ret; +} + int sysfs_read_fsid_file_u64(int fd, const char *name, u64 *value) { int ret; @@ -127,8 +180,25 @@ int sysfs_read_fsid_file_u64(int fd, const char *name, u64 *value) if (ret < 0) goto out; /* Raw value in any numeric format should work, followed by a newline. */ + errno = 0; *value = strtoull(str, NULL, 0); + ret = -errno; out: close(fd); return ret; } + +int sysfs_write_fsid_file_u64(int fd, const char *name, u64 value) +{ + int ret; + char str[32] = { 0 }; + + fd = sysfs_open_fsid_file_rw(fd, name); + if (fd < 0) + return fd; + + ret = snprintf(str, sizeof(str), "%llu", value); + ret = sysfs_write_file(fd, str, ret); + close(fd); + return ret; +} diff --git a/src/btrfs/common/sysfs-utils.h b/src/btrfs/common/sysfs-utils.h index ca8fb924..728ed994 100644 --- a/src/btrfs/common/sysfs-utils.h +++ b/src/btrfs/common/sysfs-utils.h @@ -20,10 +20,15 @@ #include int sysfs_open_file(const char *name); +int sysfs_open_file_rw(const char *name); int sysfs_open_fsid_file(int fd, const char *filename); +int sysfs_open_fsid_file_rw(int fd, const char *filename); int sysfs_open_fsid_dir(int fd, const char *dirname); int sysfs_read_fsid_file_u64(int fd, const char *name, u64 *value); +int sysfs_write_fsid_file_u64(int fd, const char *name, u64 value); int sysfs_read_file(int fd, char *buf, size_t size); +int sysfs_write_file(int fd, const char *buf, size_t size); int sysfs_read_file_u64(const char *name, u64 *value); +int sysfs_write_file_u64(const char *name, u64 value); #endif diff --git a/src/btrfs/common/tree-search.h b/src/btrfs/common/tree-search.h new file mode 100644 index 00000000..5a9c917a --- /dev/null +++ b/src/btrfs/common/tree-search.h @@ -0,0 +1,33 @@ +#ifndef __COMMON_TREE_SEARCH_H__ +#define __COMMON_TREE_SEARCH_H__ + +#include "kernel-shared/uapi/btrfs_tree.h" +#include "kernel-shared/uapi/btrfs.h" + +#define BTRFS_TREE_SEARCH_V2_BUF_SIZE 65536 + +struct btrfs_tree_search_args { + union { + struct btrfs_ioctl_search_args args1; + struct btrfs_ioctl_search_args_v2 args2; + u8 filler[sizeof(struct btrfs_ioctl_search_args_v2) + + BTRFS_TREE_SEARCH_V2_BUF_SIZE]; + }; + bool use_v2; +}; + +int btrfs_tree_search_ioctl(int fd, struct btrfs_tree_search_args *sa); + +static inline struct btrfs_ioctl_search_key *btrfs_tree_search_sk(struct btrfs_tree_search_args *sa) +{ + /* Same offset for v1 and v2. */ + return &sa->args1.key; +} + +static inline void *btrfs_tree_search_data(struct btrfs_tree_search_args *sa, unsigned long offset) { + if (sa->use_v2) + return (void *)(sa->args2.buf + offset); + return (void *)(sa->args1.buf + offset); +} + +#endif diff --git a/src/btrfs/common/utils.c b/src/btrfs/common/utils.c index 0c2fa8fe..3ca7cff3 100644 --- a/src/btrfs/common/utils.c +++ b/src/btrfs/common/utils.c @@ -45,6 +45,7 @@ #include "common/open-utils.h" #include "common/sysfs-utils.h" #include "common/messages.h" +#include "common/tree-search.h" #include "cmds/commands.h" #include "mkfs/common.h" @@ -120,11 +121,10 @@ int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret) } -static u64 find_max_device_id(struct btrfs_ioctl_search_args *search_args, - int nr_items) +static u64 find_max_device_id(struct btrfs_tree_search_args *args, int nr_items) { struct btrfs_dev_item *dev_item; - char *buf = search_args->buf; + char *buf = btrfs_tree_search_data(args, 0); buf += (nr_items - 1) * (sizeof(struct btrfs_ioctl_search_header) + sizeof(struct btrfs_dev_item)); @@ -141,8 +141,8 @@ static int search_chunk_tree_for_fs_info(int fd, int ret; int max_items; u64 start_devid = 1; - struct btrfs_ioctl_search_args search_args; - struct btrfs_ioctl_search_key *search_key = &search_args.key; + struct btrfs_tree_search_args args; + struct btrfs_ioctl_search_key *sk; fi_args->num_devices = 0; @@ -150,41 +150,41 @@ static int search_chunk_tree_for_fs_info(int fd, / (sizeof(struct btrfs_ioctl_search_header) + sizeof(struct btrfs_dev_item)); - search_key->tree_id = BTRFS_CHUNK_TREE_OBJECTID; - search_key->min_objectid = BTRFS_DEV_ITEMS_OBJECTID; - search_key->max_objectid = BTRFS_DEV_ITEMS_OBJECTID; - search_key->min_type = BTRFS_DEV_ITEM_KEY; - search_key->max_type = BTRFS_DEV_ITEM_KEY; - search_key->min_transid = 0; - search_key->max_transid = (u64)-1; - search_key->nr_items = max_items; - search_key->max_offset = (u64)-1; + memset(&args, 0, sizeof(args)); + sk = btrfs_tree_search_sk(&args); + sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID; + sk->min_objectid = BTRFS_DEV_ITEMS_OBJECTID; + sk->min_type = BTRFS_DEV_ITEM_KEY; + sk->max_objectid = BTRFS_DEV_ITEMS_OBJECTID; + sk->max_type = BTRFS_DEV_ITEM_KEY; + sk->min_transid = 0; + sk->max_transid = (u64)-1; + sk->nr_items = max_items; + sk->max_offset = (u64)-1; again: - search_key->min_offset = start_devid; + sk->min_offset = start_devid; - ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &search_args); + ret = btrfs_tree_search_ioctl(fd, &args); if (ret < 0) return -errno; - fi_args->num_devices += (u64)search_key->nr_items; + fi_args->num_devices += (u64)sk->nr_items; - if (search_key->nr_items == max_items) { - start_devid = find_max_device_id(&search_args, - search_key->nr_items) + 1; + if (sk->nr_items == max_items) { + start_devid = find_max_device_id(&args, sk->nr_items) + 1; goto again; } /* Get the latest max_id to stay consistent with the num_devices */ - if (search_key->nr_items == 0) + if (sk->nr_items == 0) /* * last tree_search returns an empty buf, use the devid of * the last dev_item of the previous tree_search */ fi_args->max_id = start_devid - 1; else - fi_args->max_id = find_max_device_id(&search_args, - search_key->nr_items); + fi_args->max_id = find_max_device_id(&args, sk->nr_items); return 0; } @@ -211,7 +211,6 @@ int get_fs_info(const char *path, struct btrfs_ioctl_fs_info_args *fi_args, struct btrfs_ioctl_dev_info_args *di_args; struct btrfs_ioctl_dev_info_args tmp; char mp[PATH_MAX]; - DIR *dirstream = NULL; memset(fi_args, 0, sizeof(*fi_args)); @@ -251,9 +250,9 @@ int get_fs_info(const char *path, struct btrfs_ioctl_fs_info_args *fi_args, } /* at this point path must not be for a block device */ - fd = open_file_or_dir(path, &dirstream); + fd = btrfs_open_file_or_dir(path); if (fd < 0) { - ret = -errno; + ret = fd; goto out; } @@ -317,7 +316,7 @@ int get_fs_info(const char *path, struct btrfs_ioctl_fs_info_args *fi_args, } out: - close_file_or_dir(fd, dirstream); + close(fd); return ret; } @@ -956,6 +955,25 @@ u8 rand_u8(void) return (u8)(rand_u32()); } +/* + * Parse a boolean value from an environment variable. + * + * As long as the environment variable is not set to "0", "n" or "\0", + * it would return true. + */ +bool get_env_bool(const char *env_name) +{ + char *env_value_str; + + env_value_str = getenv(env_name); + if (!env_value_str) + return false; + if (env_value_str[0] == '0' || env_value_str[0] == 'n' || + env_value_str[0] == 0) + return false; + return true; +} + void btrfs_config_init(void) { bconf.output_format = CMD_FORMAT_TEXT; @@ -1178,7 +1196,11 @@ static int btrfs_get_string_for_multiple_profiles(int fd, char **data_ret, */ char *btrfs_test_for_multiple_profiles(int fd) { - char *data, *metadata, *system, *mixed, *types; + char *data = NULL; + char *metadata = NULL; + char *system = NULL; + char *mixed = NULL; + char *types = NULL; btrfs_get_string_for_multiple_profiles(fd, &data, &metadata, &mixed, &system, &types); @@ -1293,9 +1315,9 @@ int check_running_fs_exclop(int fd, enum exclusive_operation start, bool enqueue sysfs_fd = sysfs_open_fsid_file(fd, "exclusive_operation"); if (sysfs_fd < 0) { - if (errno == ENOENT) + if (sysfs_fd == -ENOENT) return 0; - return -errno; + return sysfs_fd; } exclop = get_fs_exclop(fd); @@ -1320,34 +1342,58 @@ int check_running_fs_exclop(int fd, enum exclusive_operation start, bool enqueue get_fs_exclop_name(exclop)); ret = 1; goto out; + } else { + pr_verbose(LOG_DEFAULT, "Waiting for another exclusive operation '%s' to finish ...", + get_fs_exclop_name(exclop)); + fflush(stdout); } + /* + * The sysfs file descriptor needs to be reopened and all data read + * before each select(). + */ while (exclop > 0) { fd_set fds; struct timeval tv = { .tv_sec = 60, .tv_usec = 0 }; + char tmp[1024]; + close(sysfs_fd); + sysfs_fd = sysfs_open_fsid_file(fd, "exclusive_operation"); + if (sysfs_fd < 0) + return sysfs_fd; FD_ZERO(&fds); FD_SET(sysfs_fd, &fds); + ret = read(sysfs_fd, tmp, sizeof(tmp)); ret = select(sysfs_fd + 1, NULL, NULL, &fds, &tv); if (ret < 0) { ret = -errno; break; } if (ret > 0) { + close(sysfs_fd); + sysfs_fd = sysfs_open_fsid_file(fd, "exclusive_operation"); + if (sysfs_fd < 0) + return sysfs_fd; + + FD_ZERO(&fds); + FD_SET(sysfs_fd, &fds); + + ret = read(sysfs_fd, tmp, sizeof(tmp)); /* * Notified before the timeout, check again before * returning. In case there are more operations * waiting, we want to reduce the chances to race so * reuse the remaining time to randomize the order. */ - tv.tv_sec /= 2; + tv.tv_sec = (tv.tv_sec % 10) + 1; ret = select(sysfs_fd + 1, NULL, NULL, &fds, &tv); exclop = get_fs_exclop(fd); if (exclop <= 0) ret = 0; } } + pr_verbose(LOG_DEFAULT, " done\n"); out: close(sysfs_fd); diff --git a/src/btrfs/common/utils.h b/src/btrfs/common/utils.h index e267814b..56d00ed8 100644 --- a/src/btrfs/common/utils.h +++ b/src/btrfs/common/utils.h @@ -22,6 +22,7 @@ #include "kerncompat.h" #include #include +#include #include "kernel-lib/list.h" #include "kernel-shared/volumes.h" #include "common/fsfeatures.h" @@ -40,6 +41,21 @@ enum exclusive_operation { BTRFS_EXCLOP_UNKNOWN = -1, }; +static inline u32 btrfs_type_to_imode(u8 type) +{ + static u32 imode_by_btrfs_type[] = { + [BTRFS_FT_REG_FILE] = S_IFREG, + [BTRFS_FT_DIR] = S_IFDIR, + [BTRFS_FT_CHRDEV] = S_IFCHR, + [BTRFS_FT_BLKDEV] = S_IFBLK, + [BTRFS_FT_FIFO] = S_IFIFO, + [BTRFS_FT_SOCK] = S_IFSOCK, + [BTRFS_FT_SYMLINK] = S_IFLNK, + }; + + return imode_by_btrfs_type[(type)]; +} + /* 2 for "0x", 2 for each byte, plus nul */ #define BTRFS_CSUM_STRING_LEN (2 + 2 * BTRFS_CSUM_SIZE + 1) void btrfs_format_csum(u16 csum_type, const u8 *data, char *output); @@ -117,6 +133,8 @@ u64 rand_u64(void); unsigned int rand_range(unsigned int upper); void init_rand_seed(u64 seed); +bool get_env_bool(const char *env_name); + char *btrfs_test_for_multiple_profiles(int fd); int btrfs_warn_multiple_profiles(int fd); void btrfs_warn_experimental(const char *str); diff --git a/src/btrfs/crypto/hash.c b/src/btrfs/crypto/hash.c index f18dbcb6..debe9341 100644 --- a/src/btrfs/crypto/hash.c +++ b/src/btrfs/crypto/hash.c @@ -180,3 +180,111 @@ int hash_blake2b(const u8 *buf, size_t len, u8 *out) } #endif + +#if CRYPTOPROVIDER_BOTAN == 1 + +#include + +void hash_init_accel(void) +{ + crc32c_init_accel(); +} + +int hash_sha256(const u8 *buf, size_t len, u8 *out) +{ + botan_hash_t hash; + static bool initialized = false; + int ret; + + if (!initialized) { + ret = botan_hash_init(&hash, "SHA-256", 0); + if (ret < 0) { + fprintf(stderr, "HASH: cannot instantiate sha256, error %d\n", ret); + exit(1); + } + initialized = true; + } else { + botan_hash_clear(hash); + } + botan_hash_update(hash, buf, len); + botan_hash_final(hash, out); + /* botan_hash_destroy(hash); */ + return 0; +} + +int hash_blake2b(const u8 *buf, size_t len, u8 *out) +{ + botan_hash_t hash; + static bool initialized = false; + int ret; + + if (!initialized) { + ret = botan_hash_init(&hash, "BLAKE2b(256)", 0); + if (ret < 0) { + fprintf(stderr, "HASH: cannot instantiate sha256, error %d\n", ret); + exit(1); + } + initialized = true; + } else { + botan_hash_clear(hash); + } + botan_hash_update(hash, buf, len); + botan_hash_final(hash, out); + /* botan_hash_destroy(hash); */ + return 0; +} + +#endif + +#if CRYPTOPROVIDER_OPENSSL == 1 + +#include +#include + +void hash_init_accel(void) +{ + crc32c_init_accel(); +} + +int hash_sha256(const u8 *buf, size_t len, u8 *out) +{ + EVP_MD_CTX *ctx = NULL; + + if (!ctx) { + ctx = EVP_MD_CTX_new(); + if (!ctx) { + fprintf(stderr, "HASH: cannot instantiate sha256\n"); + exit(1); + } + } + EVP_DigestInit(ctx, EVP_sha256()); + EVP_DigestUpdate(ctx, buf, len); + EVP_DigestFinal(ctx, out, NULL); + /* EVP_MD_CTX_free(ctx); */ + return 0; +} + +int hash_blake2b(const u8 *buf, size_t len, u8 *out) +{ + EVP_MD_CTX *ctx = NULL; + size_t digest_size = 256 / 8; + const OSSL_PARAM params[] = { + OSSL_PARAM_size_t("size", &digest_size), + OSSL_PARAM_END + }; + + if (!ctx) { + ctx = EVP_MD_CTX_new(); + if (!ctx) { + fprintf(stderr, "HASH: cannot instantiate sha256\n"); + exit(1); + } + } + EVP_DigestInit_ex2(ctx, EVP_blake2b512(), params); + EVP_DigestUpdate(ctx, buf, len); + EVP_DigestFinal(ctx, out, NULL); + /* EVP_MD_CTX_free(ctx); */ + return 0; +} + +#endif diff --git a/src/btrfs/include/kerncompat.h b/src/btrfs/include/kerncompat.h index 18b474f6..3f981bf3 100644 --- a/src/btrfs/include/kerncompat.h +++ b/src/btrfs/include/kerncompat.h @@ -73,7 +73,7 @@ #define BITS_PER_BYTE 8 #define BITS_PER_LONG (__SIZEOF_LONG__ * BITS_PER_BYTE) #define __GFP_BITS_SHIFT 20 -#define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1)) +#define __GFP_BITS_MASK ((int)((1U << __GFP_BITS_SHIFT) - 1)) #define __GFP_DMA32 0 #define __GFP_HIGHMEM 0 #define GFP_KERNEL 0 diff --git a/src/btrfs/kernel-shared/accessors.c b/src/btrfs/kernel-shared/accessors.c index e2ad55db..967e2088 100644 --- a/src/btrfs/kernel-shared/accessors.c +++ b/src/btrfs/kernel-shared/accessors.c @@ -28,7 +28,7 @@ static bool check_setget_bounds(const struct extent_buffer *eb, /* * MODIFIED: - * - We don't have eb->pages. + * - We don't have eb->folios */ void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb) { @@ -39,7 +39,7 @@ void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *e /* * MODIFIED: - * - We don't have eb->pages, simply wrap the set/get helpers. + * - We don't have eb->folios, simply wrap the set/get helpers. */ /* @@ -61,7 +61,7 @@ void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *e * an offset into the extent buffer page array, cast to a specific type. This * gives us all the type checking. * - * The extent buffer pages stored in the array pages do not form a contiguous + * The extent buffer pages stored in the array folios may not form a contiguous * phyusical range, but the API functions assume the linear offset to the range * from 0 to metadata node size. */ diff --git a/src/btrfs/kernel-shared/accessors.h b/src/btrfs/kernel-shared/accessors.h index b4637065..b17c675c 100644 --- a/src/btrfs/kernel-shared/accessors.h +++ b/src/btrfs/kernel-shared/accessors.h @@ -98,7 +98,7 @@ static inline void btrfs_set_token_##name(struct btrfs_map_token *token,\ /* * MODIFIED: - * - We have eb->data, not eb->pages[0] + * - We have eb->data, not eb->folios[0] */ #define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ static inline u##bits btrfs_##name(const struct extent_buffer *eb) \ @@ -126,10 +126,8 @@ static inline void btrfs_set_##name(type *s, u##bits val) \ static inline u64 btrfs_device_total_bytes(const struct extent_buffer *eb, struct btrfs_dev_item *s) { - _static_assert(sizeof(u64) == - sizeof(((struct btrfs_dev_item *)0))->total_bytes); - return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item, - total_bytes)); + _static_assert(sizeof(u64) == sizeof(((struct btrfs_dev_item *)0))->total_bytes); + return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes)); } /* @@ -140,8 +138,7 @@ static inline void btrfs_set_device_total_bytes(const struct extent_buffer *eb, struct btrfs_dev_item *s, u64 val) { - _static_assert(sizeof(u64) == - sizeof(((struct btrfs_dev_item *)0))->total_bytes); + _static_assert(sizeof(u64) == sizeof(((struct btrfs_dev_item *)0))->total_bytes); btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val); } @@ -257,7 +254,7 @@ static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb, struct btrfs_chunk *c, int nr, u64 val) { - btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val); + btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val); } /* struct btrfs_block_group_item */ @@ -278,36 +275,6 @@ BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info, extent_count, 32); BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32); -/* struct btrfs_stripe_extent */ -BTRFS_SETGET_FUNCS(stripe_extent_encoding, struct btrfs_stripe_extent, encoding, 8); -BTRFS_SETGET_FUNCS(raid_stride_devid, struct btrfs_raid_stride, devid, 64); -BTRFS_SETGET_FUNCS(raid_stride_offset, struct btrfs_raid_stride, offset, 64); - -static inline struct btrfs_raid_stride *btrfs_raid_stride_nr( - struct btrfs_stripe_extent *dps, - int nr) -{ - unsigned long offset = (unsigned long)dps; - - offset += offsetof(struct btrfs_stripe_extent, strides); - offset += nr * sizeof(struct btrfs_raid_stride); - return (struct btrfs_raid_stride *)offset; -} - -static inline u64 btrfs_raid_stride_devid_nr(struct extent_buffer *eb, - struct btrfs_stripe_extent *dps, - int nr) -{ - return btrfs_raid_stride_devid(eb, btrfs_raid_stride_nr(dps, nr)); -} - -static inline u64 btrfs_raid_stride_offset_nr(struct extent_buffer *eb, - struct btrfs_stripe_extent *dps, - int nr) -{ - return btrfs_raid_stride_offset(eb, btrfs_raid_stride_nr(dps, nr)); -} - /* struct btrfs_inode_ref */ BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64); @@ -355,6 +322,38 @@ BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64); BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32); +BTRFS_SETGET_FUNCS(stripe_extent_encoding, struct btrfs_stripe_extent, encoding, 8); +BTRFS_SETGET_FUNCS(raid_stride_devid, struct btrfs_raid_stride, devid, 64); +BTRFS_SETGET_FUNCS(raid_stride_offset, struct btrfs_raid_stride, offset, 64); +BTRFS_SETGET_STACK_FUNCS(stack_stripe_extent_encoding, + struct btrfs_stripe_extent, encoding, 8); +BTRFS_SETGET_STACK_FUNCS(stack_raid_stride_devid, struct btrfs_raid_stride, devid, 64); + +static inline struct btrfs_raid_stride *btrfs_raid_stride_nr( + struct btrfs_stripe_extent *dps, + int nr) +{ + unsigned long offset = (unsigned long)dps; + + offset += offsetof(struct btrfs_stripe_extent, strides); + offset += nr * sizeof(struct btrfs_raid_stride); + return (struct btrfs_raid_stride *)offset; +} + +static inline u64 btrfs_raid_stride_devid_nr(struct extent_buffer *eb, + struct btrfs_stripe_extent *dps, + int nr) +{ + return btrfs_raid_stride_devid(eb, btrfs_raid_stride_nr(dps, nr)); +} + +static inline u64 btrfs_raid_stride_offset_nr(struct extent_buffer *eb, + struct btrfs_stripe_extent *dps, + int nr) +{ + return btrfs_raid_stride_offset(eb, btrfs_raid_stride_nr(dps, nr)); +} + /* struct btrfs_dev_extent */ BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, chunk_tree, 64); BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent, @@ -399,6 +398,9 @@ BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref, count, 3 BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref, count, 32); +BTRFS_SETGET_FUNCS(extent_owner_ref_root_id, struct btrfs_extent_owner_ref, + root_id, 64); + BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref, type, 8); BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref, @@ -420,8 +422,6 @@ static inline u32 btrfs_extent_inline_ref_size(int type) return 0; } -BTRFS_SETGET_FUNCS(extent_owner_ref_root_id, struct btrfs_extent_owner_ref, root_id, 64); - /* struct btrfs_node */ BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); @@ -670,17 +670,17 @@ static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb, static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu, const struct btrfs_disk_key *disk) { - cpu->offset = le64_to_cpu(disk->offset); - cpu->type = disk->type; cpu->objectid = le64_to_cpu(disk->objectid); + cpu->type = disk->type; + cpu->offset = le64_to_cpu(disk->offset); } static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk, const struct btrfs_key *cpu) { - disk->offset = cpu_to_le64(cpu->offset); - disk->type = cpu->type; disk->objectid = cpu_to_le64(cpu->objectid); + disk->type = cpu->type; + disk->offset = cpu_to_le64(cpu->offset); } static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb, diff --git a/src/btrfs/kernel-shared/compression.h b/src/btrfs/kernel-shared/compression.h index e3f58dd6..788ab75d 100644 --- a/src/btrfs/kernel-shared/compression.h +++ b/src/btrfs/kernel-shared/compression.h @@ -7,8 +7,10 @@ #define BTRFS_COMPRESSION_H #include "kerncompat.h" +#include "kernel-lib/sizes.h" struct btrfs_inode; +struct btrfs_ordered_extent; struct address_space; struct inode; struct bio; @@ -27,12 +29,16 @@ struct btrfs_bio { }; /* Maximum length of compressed data stored on disk */ #define BTRFS_MAX_COMPRESSED (SZ_128K) +#define BTRFS_MAX_COMPRESSED_PAGES (BTRFS_MAX_COMPRESSED / PAGE_SIZE) +_static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0); /* Maximum size of data before compression */ #define BTRFS_MAX_UNCOMPRESSED (SZ_128K) #define BTRFS_ZLIB_DEFAULT_LEVEL 3 +struct page; + struct compressed_bio { /* Number of compressed pages in the array */ unsigned int nr_pages; @@ -88,17 +94,18 @@ int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page, int btrfs_decompress_buf2page(const char *buf, u32 buf_len, struct compressed_bio *cb, u32 decompressed); -void btrfs_submit_compressed_write(struct btrfs_inode *inode, u64 start, - unsigned int len, u64 disk_start, - unsigned int compressed_len, +void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered, struct page **compressed_pages, unsigned int nr_pages, blk_opf_t write_flags, bool writeback); -void btrfs_submit_compressed_read(struct btrfs_bio *bbio, int mirror_num); +void btrfs_submit_compressed_read(struct btrfs_bio *bbio); unsigned int btrfs_compress_str2level(unsigned int type, const char *str); +struct page *btrfs_alloc_compr_page(void); +void btrfs_free_compr_page(struct page *page); + enum btrfs_compression_type { BTRFS_COMPRESS_NONE = 0, BTRFS_COMPRESS_ZLIB = 1, @@ -146,7 +153,7 @@ int zlib_compress_pages(struct list_head *ws, struct address_space *mapping, unsigned long *total_in, unsigned long *total_out); int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int zlib_decompress(struct list_head *ws, const u8 *data_in, - struct page *dest_page, unsigned long start_byte, size_t srclen, + struct page *dest_page, unsigned long dest_pgoff, size_t srclen, size_t destlen); struct list_head *zlib_alloc_workspace(unsigned int level); void zlib_free_workspace(struct list_head *ws); @@ -157,7 +164,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping, unsigned long *total_in, unsigned long *total_out); int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int lzo_decompress(struct list_head *ws, const u8 *data_in, - struct page *dest_page, unsigned long start_byte, size_t srclen, + struct page *dest_page, unsigned long dest_pgoff, size_t srclen, size_t destlen); struct list_head *lzo_alloc_workspace(unsigned int level); void lzo_free_workspace(struct list_head *ws); diff --git a/src/btrfs/kernel-shared/ctree.c b/src/btrfs/kernel-shared/ctree.c index 6bf9233b..b9229450 100644 --- a/src/btrfs/kernel-shared/ctree.c +++ b/src/btrfs/kernel-shared/ctree.c @@ -232,9 +232,9 @@ noinline void btrfs_release_path(struct btrfs_path *p) * cause could be a bug, eg. due to ENOSPC, and not for common errors that are * caused by external factors. */ -bool __cold abort_should_print_stack(int errno) +bool __cold abort_should_print_stack(int error) { - switch (errno) { + switch (error) { case -EIO: case -EROFS: case -ENOMEM: @@ -1250,8 +1250,8 @@ int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path, struct extent_buffer *eb; struct btrfs_path *path; - key.type = key_type; key.objectid = iobjectid; + key.type = key_type; key.offset = ioff; if (found_path == NULL) { diff --git a/src/btrfs/kernel-shared/ctree.h b/src/btrfs/kernel-shared/ctree.h index bcf11d87..444d206e 100644 --- a/src/btrfs/kernel-shared/ctree.h +++ b/src/btrfs/kernel-shared/ctree.h @@ -404,6 +404,15 @@ struct btrfs_fs_info { u32 sectorsize; u32 stripesize; u32 leaf_data_size; + + /* + * For open_ctree_fs_info() to hold the initial fd until close. + * + * For writeable open_ctree_fs_info() call, we should not close + * the fd until the fs_info is properly closed, or it will trigger + * udev scan while our fs is not properly initialized. + */ + int initial_fd; u16 csum_type; u16 csum_size; @@ -1210,7 +1219,7 @@ static inline int is_fstree(u64 rootid) return 0; } -void btrfs_uuid_to_key(const u8 *uuid, struct btrfs_key *key); +void btrfs_uuid_to_key(const u8 *uuid, u8 type, struct btrfs_key *key); /* inode.c */ int check_dir_conflict(struct btrfs_root *root, char *name, int namelen, diff --git a/src/btrfs/kernel-shared/delayed-ref.h b/src/btrfs/kernel-shared/delayed-ref.h index bb3a771a..95bf62ab 100644 --- a/src/btrfs/kernel-shared/delayed-ref.h +++ b/src/btrfs/kernel-shared/delayed-ref.h @@ -32,10 +32,16 @@ struct btrfs_trans_handle; struct btrfs_block_rsv; /* these are the possible values of struct btrfs_delayed_ref_node->action */ -#define BTRFS_ADD_DELAYED_REF 1 /* add one backref to the tree */ -#define BTRFS_DROP_DELAYED_REF 2 /* delete one backref from the tree */ -#define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */ -#define BTRFS_UPDATE_DELAYED_HEAD 4 /* not changing ref count on head ref */ +enum btrfs_delayed_ref_action { + /* Add one backref to the tree */ + BTRFS_ADD_DELAYED_REF = 1, + /* Delete one backref from the tree */ + BTRFS_DROP_DELAYED_REF, + /* Record a full extent allocation */ + BTRFS_ADD_DELAYED_EXTENT, + /* Not changing ref count on head ref */ + BTRFS_UPDATE_DELAYED_HEAD, +} __attribute__ ((__packed__)); struct btrfs_delayed_ref_node { struct rb_node ref_node; @@ -210,7 +216,7 @@ enum btrfs_ref_type { BTRFS_REF_DATA, BTRFS_REF_METADATA, BTRFS_REF_LAST, -}; +} __attribute__((__packed__)); struct btrfs_data_ref { /* For EXTENT_DATA_REF */ @@ -250,7 +256,7 @@ struct btrfs_tree_ref { struct btrfs_ref { enum btrfs_ref_type type; - int action; + enum btrfs_delayed_ref_action action; /* * Whether this extent should go through qgroup record. diff --git a/src/btrfs/kernel-shared/dir-item.c b/src/btrfs/kernel-shared/dir-item.c index 2251de40..4c62597b 100644 --- a/src/btrfs/kernel-shared/dir-item.c +++ b/src/btrfs/kernel-shared/dir-item.c @@ -229,7 +229,6 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, key.objectid = dir; key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); diff --git a/src/btrfs/kernel-shared/disk-io.c b/src/btrfs/kernel-shared/disk-io.c index c0533192..295bd50a 100644 --- a/src/btrfs/kernel-shared/disk-io.c +++ b/src/btrfs/kernel-shared/disk-io.c @@ -673,28 +673,28 @@ struct btrfs_root *btrfs_read_fs_root_no_cache(struct btrfs_fs_info *fs_info, return root; } -static int btrfs_global_roots_compare_keys(struct rb_node *node, - void *data) +static int btrfs_global_roots_compare_keys(const struct rb_node *node, + const void *data) { - struct btrfs_key *key = (struct btrfs_key *)data; - struct btrfs_root *root; + const struct btrfs_key *key = (struct btrfs_key *)data; + const struct btrfs_root *root; root = rb_entry(node, struct btrfs_root, rb_node); return btrfs_comp_cpu_keys(key, &root->root_key); } -static int btrfs_global_roots_compare(struct rb_node *node1, - struct rb_node *node2) +static int btrfs_global_roots_compare(const struct rb_node *node1, + const struct rb_node *node2) { - struct btrfs_root *root = rb_entry(node2, struct btrfs_root, rb_node); + const struct btrfs_root *root = rb_entry(node2, struct btrfs_root, rb_node); return btrfs_global_roots_compare_keys(node1, &root->root_key); } -static int btrfs_fs_roots_compare_objectids(struct rb_node *node, - void *data) +static int btrfs_fs_roots_compare_objectids(const struct rb_node *node, + const void *data) { - u64 objectid = *((u64 *)data); - struct btrfs_root *root; + u64 objectid = *((const u64 *)data); + const struct btrfs_root *root; root = rb_entry(node, struct btrfs_root, rb_node); if (objectid > root->objectid) @@ -705,12 +705,12 @@ static int btrfs_fs_roots_compare_objectids(struct rb_node *node, return 0; } -int btrfs_fs_roots_compare_roots(struct rb_node *node1, struct rb_node *node2) +int btrfs_fs_roots_compare_roots(const struct rb_node *node1, const struct rb_node *node2) { - struct btrfs_root *root; + const struct btrfs_root *root; root = rb_entry(node2, struct btrfs_root, rb_node); - return btrfs_fs_roots_compare_objectids(node1, (void *)&root->objectid); + return btrfs_fs_roots_compare_objectids(node1, &root->objectid); } int btrfs_global_root_insert(struct btrfs_fs_info *fs_info, @@ -913,6 +913,7 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr) fs_info->metadata_alloc_profile = (u64)-1; fs_info->system_alloc_profile = fs_info->metadata_alloc_profile; fs_info->nr_global_roots = 1; + fs_info->initial_fd = -1; return fs_info; @@ -1690,7 +1691,10 @@ struct btrfs_fs_info *open_ctree_fs_info(struct open_ctree_args *oca) return NULL; } info = __open_ctree_fd(fp, oca); - close(fp); + if (info) + info->initial_fd = fp; + else + close(fp); return info; } @@ -2297,6 +2301,8 @@ int close_ctree_fs_info(struct btrfs_fs_info *fs_info) btrfs_release_all_roots(fs_info); ret = btrfs_close_devices(fs_info->fs_devices); + if (fs_info->initial_fd >= 0) + close(fs_info->initial_fd); btrfs_cleanup_all_caches(fs_info); btrfs_free_fs_info(fs_info); if (!err) diff --git a/src/btrfs/kernel-shared/disk-io.h b/src/btrfs/kernel-shared/disk-io.h index 68cdf5b0..9f848635 100644 --- a/src/btrfs/kernel-shared/disk-io.h +++ b/src/btrfs/kernel-shared/disk-io.h @@ -128,19 +128,19 @@ enum btrfs_open_ctree_flags { enum btrfs_read_sb_flags { SBREAD_DEFAULT = 0, /* Reading superblock during recovery */ - SBREAD_RECOVER = (1 << 0), + SBREAD_RECOVER = (1U << 0), /* * Read superblock with the fake signature, cannot be used with * SBREAD_RECOVER */ - SBREAD_TEMPORARY = (1 << 1), + SBREAD_TEMPORARY = (1U << 1), /* * Equivalent of OPEN_CTREE_IGNORE_FSID_MISMATCH, allow to read * superblock that has mismatched sb::fsid and sb::dev_item.fsid */ - SBREAD_IGNORE_FSID_MISMATCH = (1 << 2), + SBREAD_IGNORE_FSID_MISMATCH = (1U << 2), }; /* @@ -237,7 +237,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); int write_tree_block(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct extent_buffer *eb); -int btrfs_fs_roots_compare_roots(struct rb_node *node1, struct rb_node *node2); +int btrfs_fs_roots_compare_roots(const struct rb_node *node1, const struct rb_node *node2); struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info, struct btrfs_key *key); diff --git a/src/btrfs/kernel-shared/extent-tree.c b/src/btrfs/kernel-shared/extent-tree.c index c2ccb8aa..af04b9ea 100644 --- a/src/btrfs/kernel-shared/extent-tree.c +++ b/src/btrfs/kernel-shared/extent-tree.c @@ -123,8 +123,8 @@ static int cache_block_group(struct btrfs_root *root, path->reada = READA_FORWARD; last = max_t(u64, block_group->start, BTRFS_SUPER_INFO_OFFSET); key.objectid = last; - key.offset = 0; key.type = 0; + key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) @@ -1325,11 +1325,11 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, return -ENOMEM; key.objectid = bytenr; - key.offset = offset; if (metadata) key.type = BTRFS_METADATA_ITEM_KEY; else key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = offset; again: ret = btrfs_search_slot(trans, extent_root, &key, path, 0, 0); @@ -1409,11 +1409,11 @@ int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, key.objectid = bytenr; if (skinny_metadata) { - key.offset = btrfs_header_level(eb); key.type = BTRFS_METADATA_ITEM_KEY; + key.offset = btrfs_header_level(eb); } else { - key.offset = fs_info->nodesize; key.type = BTRFS_EXTENT_ITEM_KEY; + key.offset = fs_info->nodesize; } again: @@ -2420,12 +2420,11 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, ins.objectid = node->bytenr; if (skinny_metadata) { - ins.offset = ref->level; ins.type = BTRFS_METADATA_ITEM_KEY; + ins.offset = ref->level; } else { - ins.offset = node->num_bytes; ins.type = BTRFS_EXTENT_ITEM_KEY; - + ins.offset = node->num_bytes; size += sizeof(struct btrfs_tree_block_info); } @@ -3217,8 +3216,8 @@ static int remove_block_group_item(struct btrfs_trans_handle *trans, int ret = 0; key.objectid = block_group->start; - key.offset = block_group->length; key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; + key.offset = block_group->length; /* * If we're doing convert and the bg is beyond our last converted bg, @@ -3348,8 +3347,8 @@ static int free_system_chunk_item(struct btrfs_super_block *super, sizeof(*disk_key); if (key->objectid == cpu_key.objectid && - key->offset == cpu_key.offset && - key->type == cpu_key.type) { + key->type == cpu_key.type && + key->offset == cpu_key.offset) { memmove(ptr + cur, ptr + cur + chunk_len, array_size - cur - chunk_len); array_size -= chunk_len; @@ -3376,8 +3375,8 @@ static int free_chunk_item(struct btrfs_trans_handle *trans, int ret; key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.offset = bytenr; key.type = BTRFS_CHUNK_ITEM_KEY; + key.offset = bytenr; path = btrfs_alloc_path(); if (!path) diff --git a/src/btrfs/kernel-shared/extent_io.c b/src/btrfs/kernel-shared/extent_io.c index ee19430d..e62ca63c 100644 --- a/src/btrfs/kernel-shared/extent_io.c +++ b/src/btrfs/kernel-shared/extent_io.c @@ -339,10 +339,9 @@ static int read_raid56(struct btrfs_fs_info *fs_info, void *buf, u64 logical, ASSERT(len <= BTRFS_STRIPE_LEN); pointers = calloc(num_stripes, sizeof(void *)); - if (!pointers) { - ret = -ENOMEM; - goto out; - } + if (!pointers) + return -ENOMEM; + /* Allocate memory for the full stripe */ for (i = 0; i < num_stripes; i++) { pointers[i] = kmalloc(BTRFS_STRIPE_LEN, GFP_KERNEL); diff --git a/src/btrfs/kernel-shared/extent_io.h b/src/btrfs/kernel-shared/extent_io.h index 0885b941..99f6765a 100644 --- a/src/btrfs/kernel-shared/extent_io.h +++ b/src/btrfs/kernel-shared/extent_io.h @@ -41,7 +41,7 @@ * single word in a bitmap may straddle two pages in the extent buffer. */ #define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) -#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) +#define BYTE_MASK ((1U << BITS_PER_BYTE) - 1) #define BITMAP_FIRST_BYTE_MASK(start) \ ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) #define BITMAP_LAST_BYTE_MASK(nbits) \ diff --git a/src/btrfs/kernel-shared/file-item.c b/src/btrfs/kernel-shared/file-item.c index 34d8059e..d2da56e1 100644 --- a/src/btrfs/kernel-shared/file-item.c +++ b/src/btrfs/kernel-shared/file-item.c @@ -57,8 +57,8 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, return -ENOMEM; file_key.objectid = objectid; - file_key.offset = pos; file_key.type = BTRFS_EXTENT_DATA_KEY; + file_key.offset = pos; ret = btrfs_insert_empty_item(trans, root, path, &file_key, sizeof(*item)); @@ -102,8 +102,8 @@ int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, return -ENOMEM; key.objectid = objectid; - key.offset = offset; key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = offset; datasize = btrfs_file_extent_calc_inline_size(size); ret = btrfs_insert_empty_item(trans, root, path, &key, datasize); @@ -146,8 +146,8 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans, int csums_in_item; file_key.objectid = csum_objectid; - file_key.offset = bytenr; file_key.type = BTRFS_EXTENT_CSUM_KEY; + file_key.offset = bytenr; ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); if (ret < 0) goto fail; @@ -207,8 +207,8 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 logical, return -ENOMEM; file_key.objectid = csum_objectid; - file_key.offset = logical; file_key.type = BTRFS_EXTENT_CSUM_KEY; + file_key.offset = logical; item = btrfs_lookup_csum(trans, root, path, logical, csum_objectid, csum_type, 1); @@ -406,8 +406,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, while (1) { key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - key.offset = end_byte - 1; key.type = BTRFS_EXTENT_CSUM_KEY; + key.offset = end_byte - 1; ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) { diff --git a/src/btrfs/kernel-shared/file-item.h b/src/btrfs/kernel-shared/file-item.h index d6d9aece..0df8f4df 100644 --- a/src/btrfs/kernel-shared/file-item.h +++ b/src/btrfs/kernel-shared/file-item.h @@ -25,12 +25,11 @@ struct list_head; static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info) { - return BTRFS_MAX_ITEM_SIZE(info) - - BTRFS_FILE_EXTENT_INLINE_DATA_START; + return BTRFS_MAX_ITEM_SIZE(info) - BTRFS_FILE_EXTENT_INLINE_DATA_START; } /* - * Returns the number of bytes used by the item on disk, minus the size of any + * Return the number of bytes used by the item on disk, minus the size of any * extent headers. If a file is compressed on disk, this is the compressed * size. */ diff --git a/src/btrfs/kernel-shared/free-space-cache.c b/src/btrfs/kernel-shared/free-space-cache.c index c2d5d258..d80fe570 100644 --- a/src/btrfs/kernel-shared/free-space-cache.c +++ b/src/btrfs/kernel-shared/free-space-cache.c @@ -306,8 +306,8 @@ static int __load_free_space_cache(struct btrfs_root *root, INIT_LIST_HEAD(&bitmaps); key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.offset = offset; key.type = 0; + key.offset = offset; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) { diff --git a/src/btrfs/kernel-shared/free-space-tree.c b/src/btrfs/kernel-shared/free-space-tree.c index e31854ce..93806ca0 100644 --- a/src/btrfs/kernel-shared/free-space-tree.c +++ b/src/btrfs/kernel-shared/free-space-tree.c @@ -178,9 +178,10 @@ static int add_new_free_space_info(struct btrfs_trans_handle *trans, return ret; } -static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize) +static inline u32 free_space_bitmap_size(const struct btrfs_fs_info *fs_info, + u64 size) { - return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE); + return DIV_ROUND_UP((u32)div_u64(size, fs_info->sectorsize), BITS_PER_BYTE); } static unsigned long *alloc_bitmap(u32 bitmap_size) @@ -241,8 +242,7 @@ static int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, int done = 0, nr; int ret; - bitmap_size = free_space_bitmap_size(block_group->length, - fs_info->sectorsize); + bitmap_size = free_space_bitmap_size(fs_info, block_group->length); bitmap = alloc_bitmap(bitmap_size); if (!bitmap) { ret = -ENOMEM; @@ -331,8 +331,7 @@ static int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, u32 data_size; extent_size = min(end - i, bitmap_range); - data_size = free_space_bitmap_size(extent_size, - fs_info->sectorsize); + data_size = free_space_bitmap_size(fs_info, extent_size); key.objectid = i; key.type = BTRFS_FREE_SPACE_BITMAP_KEY; @@ -379,8 +378,7 @@ static int convert_free_space_to_extents(struct btrfs_trans_handle *trans, int done = 0, nr; int ret; - bitmap_size = free_space_bitmap_size(block_group->start, - fs_info->sectorsize); + bitmap_size = free_space_bitmap_size(fs_info, block_group->length); bitmap = alloc_bitmap(bitmap_size); if (!bitmap) { ret = -ENOMEM; @@ -423,8 +421,8 @@ static int convert_free_space_to_extents(struct btrfs_trans_handle *trans, fs_info->sectorsize * BITS_PER_BYTE); bitmap_cursor = ((char *)bitmap) + bitmap_pos; - data_size = free_space_bitmap_size(found_key.offset, - fs_info->sectorsize); + data_size = free_space_bitmap_size(fs_info, + found_key.offset); ptr = btrfs_item_ptr_offset(leaf, path->slots[0] - 1); read_extent_buffer(leaf, bitmap_cursor, ptr, diff --git a/src/btrfs/kernel-shared/free-space-tree.h b/src/btrfs/kernel-shared/free-space-tree.h index a93ebe21..ec0539c4 100644 --- a/src/btrfs/kernel-shared/free-space-tree.h +++ b/src/btrfs/kernel-shared/free-space-tree.h @@ -26,6 +26,11 @@ struct btrfs_block_group; struct btrfs_fs_info; struct btrfs_trans_handle; +/* + * The default size for new free space bitmap items. The last bitmap in a block + * group may be truncated, and none of the free space tree code assumes that + * existing bitmaps are this size. + */ #define BTRFS_FREE_SPACE_BITMAP_SIZE 256 #define BTRFS_FREE_SPACE_BITMAP_BITS (BTRFS_FREE_SPACE_BITMAP_SIZE * BITS_PER_BYTE) diff --git a/src/btrfs/kernel-shared/inode-item.c b/src/btrfs/kernel-shared/inode-item.c index 260d86b7..34fe5bff 100644 --- a/src/btrfs/kernel-shared/inode-item.c +++ b/src/btrfs/kernel-shared/inode-item.c @@ -29,10 +29,9 @@ struct btrfs_trans_handle; -static int find_name_in_backref(struct btrfs_path *path, const char * name, - int name_len, struct btrfs_inode_ref **ref_ret) +static int find_name_in_backref(struct extent_buffer *leaf, int slot, const char * name, + int name_len, struct btrfs_inode_ref **ref_ret) { - struct extent_buffer *leaf; struct btrfs_inode_ref *ref; unsigned long ptr; unsigned long name_ptr; @@ -40,9 +39,8 @@ static int find_name_in_backref(struct btrfs_path *path, const char * name, u32 cur_offset = 0; int len; - leaf = path->nodes[0]; - item_size = btrfs_item_size(leaf, path->slots[0]); - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); + item_size = btrfs_item_size(leaf, slot); + ptr = btrfs_item_ptr_offset(leaf, slot); while (cur_offset < item_size) { ref = (struct btrfs_inode_ref *)(ptr + cur_offset); len = btrfs_inode_ref_name_len(leaf, ref); @@ -71,8 +69,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, int ins_len = name_len + sizeof(*ref); key.objectid = inode_objectid; - key.offset = ref_objectid; key.type = BTRFS_INODE_REF_KEY; + key.offset = ref_objectid; path = btrfs_alloc_path(); if (!path) @@ -83,7 +81,7 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, if (ret == -EEXIST) { u32 old_size; - if (find_name_in_backref(path, name, name_len, &ref)) + if (find_name_in_backref(path->nodes[0], path->slots[0], name, name_len, &ref)) goto out; old_size = btrfs_item_size(path->nodes[0], path->slots[0]); @@ -182,7 +180,7 @@ struct btrfs_inode_ref *btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans, if (ret) goto out; - find_name_in_backref(path, name, namelen, &ret_inode_ref); + find_name_in_backref(path->nodes[0], path->slots[0], name, namelen, &ret_inode_ref); out: if (ret < 0) return ERR_PTR(ret); @@ -190,23 +188,20 @@ struct btrfs_inode_ref *btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans, return ret_inode_ref; } -static int btrfs_find_name_in_ext_backref(struct btrfs_path *path, - u64 parent_ino, const char *name, int namelen, - struct btrfs_inode_extref **extref_ret) +static int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, + int slot, u64 parent_ino, + const char *name, int namelen, + struct btrfs_inode_extref **extref_ret) { - struct extent_buffer *node; struct btrfs_inode_extref *extref; unsigned long ptr; unsigned long name_ptr; u32 item_size; u32 cur_offset = 0; int ref_name_len; - int slot; - node = path->nodes[0]; - slot = path->slots[0]; - item_size = btrfs_item_size(node, slot); - ptr = btrfs_item_ptr_offset(node, slot); + item_size = btrfs_item_size(leaf, slot); + ptr = btrfs_item_ptr_offset(leaf, slot); /* * Search all extended backrefs in this item. We're only looking @@ -217,11 +212,11 @@ static int btrfs_find_name_in_ext_backref(struct btrfs_path *path, while (cur_offset < item_size) { extref = (struct btrfs_inode_extref *) (ptr + cur_offset); name_ptr = (unsigned long)(&extref->name); - ref_name_len = btrfs_inode_extref_name_len(node, extref); + ref_name_len = btrfs_inode_extref_name_len(leaf, extref); if (ref_name_len == namelen && - btrfs_inode_extref_parent(node, extref) == parent_ino && - (memcmp_extent_buffer(node, name, name_ptr, namelen) == 0)) + btrfs_inode_extref_parent(leaf, extref) == parent_ino && + (memcmp_extent_buffer(leaf, name, name_ptr, namelen) == 0)) { if (extref_ret) *extref_ret = extref; @@ -253,7 +248,8 @@ struct btrfs_inode_extref *btrfs_lookup_inode_extref(struct btrfs_trans_handle return ERR_PTR(ret); if (ret > 0) return NULL; - if (!btrfs_find_name_in_ext_backref(path, parent_ino, name, + if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], + parent_ino, name, namelen, &extref)) return NULL; @@ -294,7 +290,7 @@ int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, * Sanity check - did we find the right item for this name? This * should always succeed so error here will make the FS readonly. */ - if (!btrfs_find_name_in_ext_backref(path, ref_objectid, + if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], ref_objectid, name, name_len, &extref)) { ret = -ENOENT; goto out; @@ -356,14 +352,14 @@ int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, ret = btrfs_insert_empty_item(trans, root, path, &key, ins_len); if (ret == -EEXIST) { - if (btrfs_find_name_in_ext_backref(path, ref_objectid, + if (btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0], + ref_objectid, name, name_len, NULL)) goto out; btrfs_extend_item(path, ins_len); ret = 0; } - if (ret < 0) goto out; @@ -382,7 +378,6 @@ int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, out: btrfs_free_path(path); - return ret; } @@ -403,8 +398,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, int del_len = name_len + sizeof(*ref); key.objectid = ino; - key.offset = parent_ino; key.type = BTRFS_INODE_REF_KEY; + key.offset = parent_ino; path = btrfs_alloc_path(); if (!path) @@ -418,7 +413,7 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, } else if (ret < 0) { goto out; } - if (!find_name_in_backref(path, name, name_len, &ref)) { + if (!find_name_in_backref(path->nodes[0], path->slots[0], name, name_len, &ref)) { ret = -ENOENT; search_ext_refs = 1; goto out; diff --git a/src/btrfs/kernel-shared/messages.c b/src/btrfs/kernel-shared/messages.c index d2e96d58..1853ad71 100644 --- a/src/btrfs/kernel-shared/messages.c +++ b/src/btrfs/kernel-shared/messages.c @@ -10,14 +10,13 @@ #ifdef CONFIG_PRINTK #define STATE_STRING_PREFACE ": state " -#define STATE_STRING_BUF_LEN (sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT) +#define STATE_STRING_BUF_LEN (sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT + 1) /* * Characters to print to indicate error conditions or uncommon filesystem state. * RO is not an error. */ static const char fs_state_chars[] = { - [BTRFS_FS_STATE_ERROR] = 'E', [BTRFS_FS_STATE_REMOUNTING] = 'M', [BTRFS_FS_STATE_RO] = 0, [BTRFS_FS_STATE_TRANS_ABORTED] = 'A', @@ -37,6 +36,11 @@ static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf) memcpy(curr, STATE_STRING_PREFACE, sizeof(STATE_STRING_PREFACE)); curr += sizeof(STATE_STRING_PREFACE) - 1; + if (BTRFS_FS_ERROR(info)) { + *curr++ = 'E'; + states_printed = true; + } + for_each_set_bit(bit, &fs_state, sizeof(fs_state)) { WARN_ON_ONCE(bit >= BTRFS_FS_STATE_COUNT); if ((bit < BTRFS_FS_STATE_COUNT) && fs_state_chars[bit]) { @@ -106,8 +110,8 @@ const char * __attribute_const__ btrfs_decode_error(int error) } /* - * __btrfs_handle_fs_error decodes expected errors from the caller and - * invokes the appropriate error response. + * Decodes expected errors from the caller and invokes the appropriate error + * response. */ __cold void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, @@ -121,7 +125,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function #ifdef CONFIG_PRINTK_INDEX printk_index_subsys_emit( - "BTRFS: error (device %s%s) in %s:%d: error=%d %s", KERN_CRIT, fmt); + "BTRFS: error (device %s%s) in %s:%d: errno=%d %s", KERN_CRIT, fmt); #endif /* @@ -145,7 +149,7 @@ void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function sb->s_id, statestr, function, line, error, errstr, PV_VAL(vaf)); va_end(args); } else { - pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s\n", + pr_crit("BTRFS: error (device %s%s) in %s:%d: errno=%d %s\n", sb->s_id, statestr, function, line, error, errstr); } #endif @@ -265,12 +269,6 @@ void __cold btrfs_assertfail(const char *expr, const char *file, int line) } #endif -void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info) -{ - btrfs_err(fs_info, -"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel"); -} - #if BITS_PER_LONG == 32 && defined(__KERNEL__) void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info) { diff --git a/src/btrfs/kernel-shared/messages.h b/src/btrfs/kernel-shared/messages.h index 0ae398c5..532346da 100644 --- a/src/btrfs/kernel-shared/messages.h +++ b/src/btrfs/kernel-shared/messages.h @@ -9,11 +9,16 @@ struct btrfs_fs_info; +/* + * We want to be able to override this in btrfs-progs. + */ #ifdef __KERNEL__ + static inline __printf(2, 3) __cold void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) { } + #endif #ifdef CONFIG_PRINTK diff --git a/src/btrfs/kernel-shared/misc.h b/src/btrfs/kernel-shared/misc.h index 99c4951b..3c9c5ed6 100644 --- a/src/btrfs/kernel-shared/misc.h +++ b/src/btrfs/kernel-shared/misc.h @@ -140,4 +140,24 @@ static inline struct rb_node *rb_simple_insert(struct rb_root *root, u64 bytenr, return NULL; } +static inline bool bitmap_test_range_all_set(const unsigned long *addr, + unsigned long start, + unsigned long nbits) +{ + unsigned long found_zero; + + found_zero = find_next_zero_bit(addr, start + nbits, start); + return (found_zero == start + nbits); +} + +static inline bool bitmap_test_range_all_zero(const unsigned long *addr, + unsigned long start, + unsigned long nbits) +{ + unsigned long found_set; + + found_set = find_next_bit(addr, start + nbits, start); + return (found_set == start + nbits); +} + #endif diff --git a/src/btrfs/kernel-shared/print-tree.c b/src/btrfs/kernel-shared/print-tree.c index 6294c129..a3673771 100644 --- a/src/btrfs/kernel-shared/print-tree.c +++ b/src/btrfs/kernel-shared/print-tree.c @@ -1742,8 +1742,6 @@ void btrfs_print_tree(struct extent_buffer *eb, unsigned int mode) const bool follow = (mode & BTRFS_PRINT_TREE_FOLLOW); unsigned int traverse = BTRFS_PRINT_TREE_DEFAULT; - if (!eb) - return; /* BFS is default and takes precedence if both are set */ if (mode & BTRFS_PRINT_TREE_DFS) traverse = BTRFS_PRINT_TREE_DFS; diff --git a/src/btrfs/kernel-shared/print-tree.h b/src/btrfs/kernel-shared/print-tree.h index d857e1da..3c4cee90 100644 --- a/src/btrfs/kernel-shared/print-tree.h +++ b/src/btrfs/kernel-shared/print-tree.h @@ -30,15 +30,15 @@ struct extent_buffer; enum { /* Depth-first search, nodes and leaves can be interleaved */ - BTRFS_PRINT_TREE_DFS = (1 << 0), + BTRFS_PRINT_TREE_DFS = (1U << 0), /* Breadth-first search, first nodes, then leaves */ - BTRFS_PRINT_TREE_BFS = (1 << 1), + BTRFS_PRINT_TREE_BFS = (1U << 1), /* Follow to child nodes */ - BTRFS_PRINT_TREE_FOLLOW = (1 << 2), + BTRFS_PRINT_TREE_FOLLOW = (1U << 2), /* Print checksum of node/leaf */ - BTRFS_PRINT_TREE_CSUM_HEADERS = (1 << 3), + BTRFS_PRINT_TREE_CSUM_HEADERS = (1U << 3), /* Print checksums in checksum items */ - BTRFS_PRINT_TREE_CSUM_ITEMS = (1 << 4), + BTRFS_PRINT_TREE_CSUM_ITEMS = (1U << 4), BTRFS_PRINT_TREE_DEFAULT = BTRFS_PRINT_TREE_BFS, }; diff --git a/src/btrfs/kernel-shared/root-tree.c b/src/btrfs/kernel-shared/root-tree.c index 33f9e469..dd2636ec 100644 --- a/src/btrfs/kernel-shared/root-tree.c +++ b/src/btrfs/kernel-shared/root-tree.c @@ -21,10 +21,12 @@ #include #include "kernel-lib/bitops.h" #include "kernel-shared/accessors.h" +#include "kernel-shared/messages.h" #include "kernel-shared/extent_io.h" #include "kernel-shared/uapi/btrfs_tree.h" #include "kernel-shared/ctree.h" #include "kernel-shared/disk-io.h" +#include "kernel-shared/transaction.h" int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct btrfs_root_item *item, struct btrfs_key *key) @@ -74,6 +76,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_key *key, struct btrfs_root_item *item) { + struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_path *path; struct extent_buffer *l; int ret; @@ -88,7 +91,17 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root ret = btrfs_search_slot(trans, root, key, path, 0, 1); if (ret < 0) goto out; - BUG_ON(ret != 0); + + if (ret > 0) { + btrfs_crit(fs_info, + "unable to find root key (%llu %u %llu) in tree %llu", + key->objectid, key->type, key->offset, + root->root_key.objectid); + ret = -EUCLEAN; + btrfs_abort_transaction(trans, ret); + goto out; + } + l = path->nodes[0]; slot = path->slots[0]; ptr = btrfs_item_ptr_offset(l, slot); @@ -104,17 +117,20 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root ret = btrfs_search_slot(trans, root, key, path, -1, 1); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } ret = btrfs_del_item(trans, root, path); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } btrfs_release_path(path); ret = btrfs_insert_empty_item(trans, root, path, key, sizeof(*item)); if (ret < 0) { + btrfs_abort_transaction(trans, ret); goto out; } l = path->nodes[0]; diff --git a/src/btrfs/kernel-shared/transaction.h b/src/btrfs/kernel-shared/transaction.h index ca3bc9ce..d8539edc 100644 --- a/src/btrfs/kernel-shared/transaction.h +++ b/src/btrfs/kernel-shared/transaction.h @@ -34,6 +34,7 @@ struct btrfs_root; enum btrfs_trans_state { TRANS_STATE_RUNNING, + TRANS_STATE_COMMIT_PREP, TRANS_STATE_COMMIT_START, TRANS_STATE_COMMIT_DOING, TRANS_STATE_UNBLOCKED, @@ -113,9 +114,6 @@ struct btrfs_transaction { */ atomic_t pending_ordered; wait_queue_head_t pending_wait; - - spinlock_t releasing_ebs_lock; - struct list_head releasing_ebs; }; enum { @@ -175,7 +173,7 @@ struct btrfs_pending_snapshot { struct list_head list; }; -bool __cold abort_should_print_stack(int errno); +bool __cold abort_should_print_stack(int error); void btrfs_abort_transaction(struct btrfs_trans_handle *trans, int error); int btrfs_end_transaction(struct btrfs_trans_handle *trans); @@ -215,7 +213,7 @@ void btrfs_add_dropped_root(struct btrfs_trans_handle *trans, void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans); void __cold __btrfs_abort_transaction(struct btrfs_trans_handle *trans, const char *function, - unsigned int line, int errno, bool first_hit); + unsigned int line, int error, bool first_hit); int __init btrfs_transaction_init(void); void __cold btrfs_transaction_exit(void); diff --git a/src/btrfs/kernel-shared/tree-checker.c b/src/btrfs/kernel-shared/tree-checker.c index 00315679..8770392b 100644 --- a/src/btrfs/kernel-shared/tree-checker.c +++ b/src/btrfs/kernel-shared/tree-checker.c @@ -33,6 +33,7 @@ #include "kernel-shared/accessors.h" #include "kernel-shared/file-item.h" #include "kernel-shared/extent_io.h" +#include "kernel-shared/print-tree.h" #include "kernel-shared/uapi/btrfs.h" #include "kernel-shared/uapi/btrfs_tree.h" #include "common/internal.h" @@ -95,6 +96,8 @@ static void generic_err(const struct extent_buffer *eb, int slot, btrfs_header_level(eb) == 0 ? "leaf" : "node", btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)eb, 0); } /* @@ -123,6 +126,8 @@ static void file_extent_err(const struct extent_buffer *eb, int slot, btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, key.objectid, key.offset, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)eb, 0); } /* @@ -183,6 +188,8 @@ static void dir_item_err(const struct extent_buffer *eb, int slot, btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, key.objectid, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)eb, 0); } /* @@ -477,6 +484,20 @@ static int check_root_key(struct extent_buffer *leaf, struct btrfs_key *key, btrfs_item_key_to_cpu(leaf, &item_key, slot); is_root_item = (item_key.type == BTRFS_ROOT_ITEM_KEY); + /* + * Bad rootid for reloc trees. + * + * Reloc trees are only for subvolume trees, other trees only need + * to be COWed to be relocated. + */ + if (unlikely(is_root_item && key->objectid == BTRFS_TREE_RELOC_OBJECTID && + !is_fstree(key->offset))) { + generic_err(leaf, slot, + "invalid reloc tree for root %lld, root id is not a subvolume tree", + key->offset); + return -EUCLEAN; + } + /* No such tree id */ if (unlikely(key->objectid == 0)) { if (is_root_item) @@ -669,6 +690,8 @@ static void block_group_err(const struct extent_buffer *eb, int slot, btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, key.objectid, key.offset, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)eb, 0); } static int check_block_group_item(struct extent_buffer *leaf, @@ -800,6 +823,8 @@ static void chunk_err(const struct extent_buffer *leaf, BTRFS_CHUNK_TREE_OBJECTID, leaf->start, slot, logical, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)leaf, 0); } /* @@ -1025,6 +1050,8 @@ static void dev_item_err(const struct extent_buffer *eb, int slot, btrfs_header_owner(eb), btrfs_header_bytenr(eb), slot, key.objectid, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)eb, 0); } static int check_dev_item(struct extent_buffer *leaf, @@ -1279,6 +1306,8 @@ static void extent_err(const struct extent_buffer *eb, int slot, btrfs_header_level(eb) == 0 ? "leaf" : "node", eb->start, slot, bytenr, len, &vaf); va_end(args); + + btrfs_print_tree((struct extent_buffer *)eb, 0); } static int check_extent_item(struct extent_buffer *leaf, @@ -1291,6 +1320,8 @@ static int check_extent_item(struct extent_buffer *leaf, unsigned long ptr; /* Current pointer inside inline refs */ unsigned long end; /* Extent item end */ const u32 item_size = btrfs_item_size(leaf, slot); + u8 last_type = 0; + u64 last_seq = U64_MAX; u64 flags; u64 generation; u64 total_refs; /* Total refs in btrfs_extent_item */ @@ -1337,6 +1368,18 @@ static int check_extent_item(struct extent_buffer *leaf, * 2.2) Ref type specific data * Either using btrfs_extent_inline_ref::offset, or specific * data structure. + * + * All above inline items should follow the order: + * + * - All btrfs_extent_inline_ref::type should be in an ascending + * order + * + * - Within the same type, the items should follow a descending + * order by their sequence number. The sequence number is + * determined by: + * * btrfs_extent_inline_ref::offset for all types other than + * EXTENT_DATA_REF + * * hash_extent_data_ref() for EXTENT_DATA_REF */ if (unlikely(item_size < sizeof(*ei))) { extent_err(leaf, slot, @@ -1418,6 +1461,7 @@ static int check_extent_item(struct extent_buffer *leaf, struct btrfs_extent_inline_ref *iref; struct btrfs_extent_data_ref *dref; struct btrfs_shared_data_ref *sref; + u64 seq; u64 dref_offset; u64 inline_offset; u8 inline_type; @@ -1431,10 +1475,11 @@ static int check_extent_item(struct extent_buffer *leaf, iref = (struct btrfs_extent_inline_ref *)ptr; inline_type = btrfs_extent_inline_ref_type(leaf, iref); inline_offset = btrfs_extent_inline_ref_offset(leaf, iref); + seq = inline_offset; if (unlikely(ptr + btrfs_extent_inline_ref_size(inline_type) > end)) { extent_err(leaf, slot, "inline ref item overflows extent item, ptr %lu iref size %u end %lu", - ptr, inline_type, end); + ptr, btrfs_extent_inline_ref_size(inline_type), end); return -EUCLEAN; } @@ -1461,6 +1506,10 @@ static int check_extent_item(struct extent_buffer *leaf, case BTRFS_EXTENT_DATA_REF_KEY: dref = (struct btrfs_extent_data_ref *)(&iref->offset); dref_offset = btrfs_extent_data_ref_offset(leaf, dref); + seq = hash_extent_data_ref( + btrfs_extent_data_ref_root(leaf, dref), + btrfs_extent_data_ref_objectid(leaf, dref), + btrfs_extent_data_ref_offset(leaf, dref)); if (unlikely(!IS_ALIGNED(dref_offset, fs_info->sectorsize))) { extent_err(leaf, slot, @@ -1490,6 +1539,24 @@ static int check_extent_item(struct extent_buffer *leaf, inline_type); return -EUCLEAN; } + if (inline_type < last_type) { + extent_err(leaf, slot, + "inline ref out-of-order: has type %u, prev type %u", + inline_type, last_type); + return -EUCLEAN; + } + /* Type changed, allow the sequence starts from U64_MAX again. */ + if (inline_type > last_type) + last_seq = U64_MAX; + if (seq > last_seq) { + extent_err(leaf, slot, +"inline ref out-of-order: has type %u offset %llu seq 0x%llx, prev type %u seq 0x%llx", + inline_type, inline_offset, seq, + last_type, last_seq); + return -EUCLEAN; + } + last_type = inline_type; + last_seq = seq; ptr += btrfs_extent_inline_ref_size(inline_type); } /* No padding is allowed */ @@ -1651,6 +1718,44 @@ static int check_inode_ref(struct extent_buffer *leaf, return 0; } +static int check_raid_stripe_extent(const struct extent_buffer *leaf, + const struct btrfs_key *key, int slot) +{ + struct btrfs_stripe_extent *stripe_extent = + btrfs_item_ptr(leaf, slot, struct btrfs_stripe_extent); + + if (unlikely(!IS_ALIGNED(key->objectid, leaf->fs_info->sectorsize))) { + generic_err(leaf, slot, +"invalid key objectid for raid stripe extent, have %llu expect aligned to %u", + key->objectid, leaf->fs_info->sectorsize); + return -EUCLEAN; + } + + if (unlikely(!btrfs_fs_incompat(leaf->fs_info, RAID_STRIPE_TREE))) { + generic_err(leaf, slot, + "RAID_STRIPE_EXTENT present but RAID_STRIPE_TREE incompat bit unset"); + return -EUCLEAN; + } + + switch (btrfs_stripe_extent_encoding(leaf, stripe_extent)) { + case BTRFS_STRIPE_RAID0: + case BTRFS_STRIPE_RAID1: + case BTRFS_STRIPE_DUP: + case BTRFS_STRIPE_RAID10: + case BTRFS_STRIPE_RAID5: + case BTRFS_STRIPE_RAID6: + case BTRFS_STRIPE_RAID1C3: + case BTRFS_STRIPE_RAID1C4: + break; + default: + generic_err(leaf, slot, "invalid raid stripe encoding %u", + btrfs_stripe_extent_encoding(leaf, stripe_extent)); + return -EUCLEAN; + } + + return 0; +} + /* * Common point to switch the item-specific validation. */ @@ -1660,8 +1765,8 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf, struct btrfs_key *prev_key) { struct btrfs_fs_info *fs_info = leaf->fs_info; - struct btrfs_chunk *chunk; int ret = 0; + struct btrfs_chunk *chunk; if (fs_info->skip_leaf_item_checks) return 0; @@ -1709,6 +1814,9 @@ static enum btrfs_tree_block_status check_leaf_item(struct extent_buffer *leaf, case BTRFS_EXTENT_DATA_REF_KEY: ret = check_extent_data_ref(leaf, key, slot); break; + case BTRFS_RAID_STRIPE_KEY: + ret = check_raid_stripe_extent(leaf, key, slot); + break; } if (ret) diff --git a/src/btrfs/kernel-shared/tree-checker.h b/src/btrfs/kernel-shared/tree-checker.h index e03c5e5d..795ea524 100644 --- a/src/btrfs/kernel-shared/tree-checker.h +++ b/src/btrfs/kernel-shared/tree-checker.h @@ -12,6 +12,7 @@ #include "kernel-shared/uapi/btrfs_tree.h" struct extent_buffer; +struct btrfs_chunk; /* All the extra info needed to verify the parentness of a tree block. */ struct btrfs_tree_parent_check { @@ -24,7 +25,7 @@ struct btrfs_tree_parent_check { /* * Expected transid, can be 0 to skip the check, but such skip - * should only be utlized for backref walk related code. + * should only be utilized for backref walk related code. */ u64 transid; diff --git a/src/btrfs/kernel-shared/uapi/btrfs.h b/src/btrfs/kernel-shared/uapi/btrfs.h index 34e84b89..e5e62eac 100644 --- a/src/btrfs/kernel-shared/uapi/btrfs.h +++ b/src/btrfs/kernel-shared/uapi/btrfs.h @@ -287,12 +287,12 @@ _static_assert(sizeof(struct btrfs_ioctl_dev_info_args) == 4096); */ /* Request information about checksum type and size */ -#define BTRFS_FS_INFO_FLAG_CSUM_INFO (1 << 0) +#define BTRFS_FS_INFO_FLAG_CSUM_INFO (1U << 0) /* Request information about filesystem generation */ -#define BTRFS_FS_INFO_FLAG_GENERATION (1 << 1) +#define BTRFS_FS_INFO_FLAG_GENERATION (1U << 1) /* Request information about filesystem metadata UUID */ -#define BTRFS_FS_INFO_FLAG_METADATA_UUID (1 << 2) +#define BTRFS_FS_INFO_FLAG_METADATA_UUID (1U << 2) struct btrfs_ioctl_fs_info_args { __u64 max_id; /* out */ diff --git a/src/btrfs/kernel-shared/ulist.c b/src/btrfs/kernel-shared/ulist.c index eba58bbc..9e2f494e 100644 --- a/src/btrfs/kernel-shared/ulist.c +++ b/src/btrfs/kernel-shared/ulist.c @@ -238,7 +238,8 @@ int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, } /* - * ulist_del - delete one node from ulist + * Delete one node from ulist. + * * @ulist: ulist to remove node from * @val: value to delete * @aux: aux to delete diff --git a/src/btrfs/kernel-shared/uuid-tree.c b/src/btrfs/kernel-shared/uuid-tree.c index 018499a0..766cd31e 100644 --- a/src/btrfs/kernel-shared/uuid-tree.c +++ b/src/btrfs/kernel-shared/uuid-tree.c @@ -27,16 +27,18 @@ #include "kernel-shared/uapi/btrfs.h" #include "kernel-shared/uapi/btrfs_tree.h" #include "kernel-shared/ctree.h" +#include "kernel-shared/messages.h" #include "kernel-shared/transaction.h" #include "common/messages.h" #include "common/utils.h" -void btrfs_uuid_to_key(const u8 *uuid, struct btrfs_key *key) +void btrfs_uuid_to_key(const u8 *uuid, u8 type, struct btrfs_key *key) { u64 tmp; tmp = get_unaligned_le64(uuid); put_unaligned_64(tmp, &key->objectid); + key->type = type; tmp = get_unaligned_le64(uuid + sizeof(u64)); put_unaligned_64(tmp, &key->offset); } @@ -56,16 +58,15 @@ static int btrfs_uuid_tree_lookup_any(int fd, const u8 *uuid, u8 type, __le64 lesubid; struct btrfs_key key; - key.type = type; - btrfs_uuid_to_key(uuid, &key); + btrfs_uuid_to_key(uuid, type, &key); memset(&search_arg, 0, sizeof(search_arg)); search_arg.key.tree_id = BTRFS_UUID_TREE_OBJECTID; search_arg.key.min_objectid = key.objectid; - search_arg.key.max_objectid = key.objectid; search_arg.key.min_type = type; - search_arg.key.max_type = type; search_arg.key.min_offset = key.offset; + search_arg.key.max_objectid = key.objectid; + search_arg.key.max_type = type; search_arg.key.max_offset = key.offset; search_arg.key.max_transid = (u64)-1; search_arg.key.nr_items = 1; @@ -117,7 +118,7 @@ int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid, } int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, - u64 subid) + u64 subid) { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *uuid_root = fs_info->uuid_root; @@ -137,8 +138,7 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, goto out; } - btrfs_uuid_to_key(uuid, &key); - key.type = type; + btrfs_uuid_to_key(uuid, type, &key); path = btrfs_alloc_path(); if (!path) { @@ -148,7 +148,8 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1); if (ret < 0) { - warning("error %d while searching for uuid item!", ret); + btrfs_warn(fs_info, "error %d while searching for uuid item!", + ret); goto out; } if (ret > 0) { @@ -161,7 +162,8 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, u8 *uuid, u8 type, offset = btrfs_item_ptr_offset(eb, slot); item_size = btrfs_item_size(eb, slot); if (!IS_ALIGNED(item_size, sizeof(u64))) { - warning("uuid item with illegal size %u!", item_size); + btrfs_warn(fs_info, "uuid item with illegal size %lu!", + (unsigned long)item_size); ret = -ENOENT; goto out; } diff --git a/src/btrfs/kernel-shared/volumes.c b/src/btrfs/kernel-shared/volumes.c index a9da39dc..b21231ef 100644 --- a/src/btrfs/kernel-shared/volumes.c +++ b/src/btrfs/kernel-shared/volumes.c @@ -871,8 +871,8 @@ static int find_free_dev_extent_start(struct btrfs_device *device, path->reada = READA_FORWARD; key.objectid = device->devid; - key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; + key.offset = search_start; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) @@ -1006,8 +1006,8 @@ int btrfs_insert_dev_extent(struct btrfs_trans_handle *trans, return -ENOMEM; key.objectid = device->devid; - key.offset = start; key.type = BTRFS_DEV_EXTENT_KEY; + key.offset = start; ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*extent)); if (ret < 0) @@ -1062,8 +1062,8 @@ static int find_next_chunk(struct btrfs_fs_info *fs_info, u64 *offset) return -ENOMEM; key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.offset = (u64)-1; key.type = BTRFS_CHUNK_ITEM_KEY; + key.offset = (u64)-1; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) @@ -1302,8 +1302,8 @@ static int btrfs_device_avail_bytes(struct btrfs_trans_handle *trans, return -ENOMEM; key.objectid = device->devid; - key.offset = search_start; key.type = BTRFS_DEV_EXTENT_KEY; + key.offset = search_start; path->reada = READA_FORWARD; ret = btrfs_search_slot(trans, root, &key, path, 0, 0); @@ -2663,8 +2663,8 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) * item - BTRFS_FIRST_CHUNK_TREE_OBJECTID). */ key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.offset = 0; key.type = 0; + key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto error; diff --git a/src/btrfs/kernel-shared/zoned.c b/src/btrfs/kernel-shared/zoned.c index 9c40e4ef..fb1e1388 100644 --- a/src/btrfs/kernel-shared/zoned.c +++ b/src/btrfs/kernel-shared/zoned.c @@ -34,7 +34,7 @@ #include "common/device-utils.h" #include "common/extent-cache.h" #include "common/internal.h" -#include "common/parse-utils.h" +#include "common/string-utils.h" #include "common/messages.h" #include "mkfs/common.h" @@ -102,7 +102,7 @@ u64 zone_size(const char *file) tmp = bconf_param_value("zone-size"); if (tmp) { - size = parse_size_from_string(tmp); + size = arg_strtou64_with_suffix(tmp); if (!is_power_of_2(size) || size < BTRFS_MIN_ZONE_SIZE || size > BTRFS_MAX_ZONE_SIZE) { error("invalid emulated zone size %llu", size); diff --git a/src/btrfs/libbtrfs/ctree.h b/src/btrfs/libbtrfs/ctree.h index ea2a680e..0e9c5bcd 100644 --- a/src/btrfs/libbtrfs/ctree.h +++ b/src/btrfs/libbtrfs/ctree.h @@ -1581,18 +1581,18 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info) /* * Inode flags */ -#define BTRFS_INODE_NODATASUM (1 << 0) -#define BTRFS_INODE_NODATACOW (1 << 1) -#define BTRFS_INODE_READONLY (1 << 2) -#define BTRFS_INODE_NOCOMPRESS (1 << 3) -#define BTRFS_INODE_PREALLOC (1 << 4) -#define BTRFS_INODE_SYNC (1 << 5) -#define BTRFS_INODE_IMMUTABLE (1 << 6) -#define BTRFS_INODE_APPEND (1 << 7) -#define BTRFS_INODE_NODUMP (1 << 8) -#define BTRFS_INODE_NOATIME (1 << 9) -#define BTRFS_INODE_DIRSYNC (1 << 10) -#define BTRFS_INODE_COMPRESS (1 << 11) +#define BTRFS_INODE_NODATASUM (1U << 0) +#define BTRFS_INODE_NODATACOW (1U << 1) +#define BTRFS_INODE_READONLY (1U << 2) +#define BTRFS_INODE_NOCOMPRESS (1U << 3) +#define BTRFS_INODE_PREALLOC (1U << 4) +#define BTRFS_INODE_SYNC (1U << 5) +#define BTRFS_INODE_IMMUTABLE (1U << 6) +#define BTRFS_INODE_APPEND (1U << 7) +#define BTRFS_INODE_NODUMP (1U << 8) +#define BTRFS_INODE_NOATIME (1U << 9) +#define BTRFS_INODE_DIRSYNC (1U << 10) +#define BTRFS_INODE_COMPRESS (1U << 11) void read_extent_buffer(const struct extent_buffer *eb, void *dst, unsigned long start, unsigned long len); diff --git a/src/btrfs/libbtrfs/kerncompat.h b/src/btrfs/libbtrfs/kerncompat.h index a8ba07f0..3f384d8a 100644 --- a/src/btrfs/libbtrfs/kerncompat.h +++ b/src/btrfs/libbtrfs/kerncompat.h @@ -72,7 +72,7 @@ #define BITS_PER_BYTE 8 #define BITS_PER_LONG (__SIZEOF_LONG__ * BITS_PER_BYTE) #define __GFP_BITS_SHIFT 20 -#define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1)) +#define __GFP_BITS_MASK ((int)((1U << __GFP_BITS_SHIFT) - 1)) #define GFP_KERNEL 0 #define GFP_NOFS 0 #define __read_mostly diff --git a/src/btrfs/libbtrfs/version.h b/src/btrfs/libbtrfs/version.h index 58e0ded5..ef496e78 100644 --- a/src/btrfs/libbtrfs/version.h +++ b/src/btrfs/libbtrfs/version.h @@ -9,6 +9,6 @@ BTRFS_LIB_MINOR * 100 + \ BTRFS_LIB_PATCHLEVEL ) -#define BTRFS_BUILD_VERSION "Btrfs v6.6.2" +#define BTRFS_BUILD_VERSION "Btrfs v6.8.1" #endif diff --git a/src/btrfs/libbtrfsutil/btrfs.h b/src/btrfs/libbtrfsutil/btrfs.h index d997cb2c..86f5b4e9 100644 --- a/src/btrfs/libbtrfsutil/btrfs.h +++ b/src/btrfs/libbtrfsutil/btrfs.h @@ -34,6 +34,7 @@ struct btrfs_ioctl_vol_args { }; #define BTRFS_DEVICE_PATH_NAME_MAX 1024 +#define BTRFS_SUBVOL_NAME_MAX 4039 #define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3) #define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4) @@ -108,8 +109,6 @@ struct btrfs_ioctl_qgroup_limit_args { */ #define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) - -#define BTRFS_SUBVOL_NAME_MAX 4039 struct btrfs_ioctl_vol_args_v2 { __s64 fd; __u64 transid; @@ -238,6 +237,18 @@ struct btrfs_ioctl_dev_info_args { __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */ }; +/* + * Retrieve information about the filesystem + */ + +/* Request information about checksum type and size */ +#define BTRFS_FS_INFO_FLAG_CSUM_INFO (1U << 0) + +/* Request information about filesystem generation */ +#define BTRFS_FS_INFO_FLAG_GENERATION (1U << 1) +/* Request information about filesystem metadata UUID */ +#define BTRFS_FS_INFO_FLAG_METADATA_UUID (1U << 2) + struct btrfs_ioctl_fs_info_args { __u64 max_id; /* out */ __u64 num_devices; /* out */ @@ -245,8 +256,13 @@ struct btrfs_ioctl_fs_info_args { __u32 nodesize; /* out */ __u32 sectorsize; /* out */ __u32 clone_alignment; /* out */ - __u32 reserved32; - __u64 reserved[122]; /* pad to 1k */ + /* See BTRFS_FS_INFO_FLAG_* */ + __u16 csum_type; /* out */ + __u16 csum_size; /* out */ + __u64 flags; /* in/out */ + __u64 generation; /* out */ + __u8 metadata_uuid[BTRFS_FSID_SIZE]; /* out */ + __u8 reserved[944]; /* pad to 1k */ }; /* @@ -266,6 +282,13 @@ struct btrfs_ioctl_fs_info_args { * first mount when booting older kernel versions. */ #define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) +#define BTRFS_FEATURE_COMPAT_RO_VERITY (1ULL << 2) + +/* + * Put all block group items into a dedicated block group tree, greatly + * reducing mount time for large filesystem due to better locality. + */ +#define BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE (1ULL << 3) #define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) #define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) @@ -283,9 +306,12 @@ struct btrfs_ioctl_fs_info_args { #define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) -#define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10) +#define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10) #define BTRFS_FEATURE_INCOMPAT_RAID1C34 (1ULL << 11) #define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12) +#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13) +#define BTRFS_FEATURE_INCOMPAT_RAID_STRIPE_TREE (1ULL << 14) +#define BTRFS_FEATURE_INCOMPAT_SIMPLE_QUOTA (1ULL << 16) struct btrfs_ioctl_feature_flags { __u64 compat_flags; @@ -296,6 +322,7 @@ struct btrfs_ioctl_feature_flags { /* balance control ioctl modes */ #define BTRFS_BALANCE_CTL_PAUSE 1 #define BTRFS_BALANCE_CTL_CANCEL 2 +#define BTRFS_BALANCE_CTL_RESUME 3 /* * this is packed, because it should be exactly the same as its disk @@ -303,6 +330,12 @@ struct btrfs_ioctl_feature_flags { */ struct btrfs_balance_args { __u64 profiles; + + /* + * usage filter + * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N' + * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max + */ union { __u64 usage; struct { @@ -519,7 +552,7 @@ struct btrfs_ioctl_search_header { __u64 offset; __u32 type; __u32 len; -}; +} __attribute__ ((__may_alias__)); #define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) /* @@ -532,6 +565,10 @@ struct btrfs_ioctl_search_args { char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; }; +/* + * Extended version of TREE_SEARCH ioctl that can return more than 4k of bytes. + * The allocated size of the buffer is set in buf_size. + */ struct btrfs_ioctl_search_args_v2 { struct btrfs_ioctl_search_key key; /* in/out - search parameters */ __u64 buf_size; /* in - size of buffer @@ -541,9 +578,9 @@ struct btrfs_ioctl_search_args_v2 { }; struct btrfs_ioctl_clone_range_args { - __s64 src_fd; - __u64 src_offset, src_length; - __u64 dest_offset; + __s64 src_fd; + __u64 src_offset, src_length; + __u64 dest_offset; }; /* @@ -642,8 +679,8 @@ struct btrfs_ioctl_ino_path_args { struct btrfs_ioctl_logical_ino_args { __u64 logical; /* in */ __u64 size; /* in */ - __u64 reserved[3]; - __u64 flags; /* in */ + __u64 reserved[3]; /* must be 0 for now */ + __u64 flags; /* in, v2 only */ /* struct btrfs_data_container *inodes; out */ __u64 inodes; }; @@ -652,7 +689,7 @@ struct btrfs_ioctl_logical_ino_args { * 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) enum btrfs_dev_stat_values { /* disk I/O failure stats */ @@ -684,12 +721,19 @@ struct btrfs_ioctl_get_dev_stats { /* out values: */ __u64 values[BTRFS_DEV_STAT_VALUES_MAX]; - __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ + /* + * This pads the struct to 1032 bytes. It was originally meant to pad to + * 1024 bytes, but when adding the flags field, the padding calculation + * was not adjusted. + */ + __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; }; +/* Command values for btrfs_ioctl_quota_ctl_args::cmd. */ #define BTRFS_QUOTA_CTL_ENABLE 1 #define BTRFS_QUOTA_CTL_DISABLE 2 #define BTRFS_QUOTA_CTL_RESCAN__NOTUSED 3 +#define BTRFS_QUOTA_CTL_ENABLE_SIMPLE_QUOTA 4 struct btrfs_ioctl_quota_ctl_args { __u64 cmd; __u64 status; @@ -746,18 +790,33 @@ struct btrfs_ioctl_received_subvol_args { */ #define BTRFS_SEND_FLAG_OMIT_END_CMD 0x4 +/* + * Read the protocol version in the structure + */ +#define BTRFS_SEND_FLAG_VERSION 0x8 + +/* + * Send compressed data using the ENCODED_WRITE command instead of decompressing + * the data and sending it with the WRITE command. This requires protocol + * version >= 2. + */ +#define BTRFS_SEND_FLAG_COMPRESSED 0x10 + #define BTRFS_SEND_FLAG_MASK \ (BTRFS_SEND_FLAG_NO_FILE_DATA | \ BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \ - BTRFS_SEND_FLAG_OMIT_END_CMD) + BTRFS_SEND_FLAG_OMIT_END_CMD | \ + BTRFS_SEND_FLAG_VERSION | \ + BTRFS_SEND_FLAG_COMPRESSED) struct btrfs_ioctl_send_args { __s64 send_fd; /* in */ __u64 clone_sources_count; /* in */ - __u64 *clone_sources; /* in */ + __u64 *clone_sources; /* in */ __u64 parent_root; /* in */ __u64 flags; /* in */ - __u64 reserved[4]; /* in */ + __u32 version; /* in */ + __u8 reserved[28]; /* in */ }; /* @@ -858,6 +917,8 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args) #define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \ struct btrfs_ioctl_vol_args) +#define BTRFS_IOC_FORGET_DEV _IOW(BTRFS_IOCTL_MAGIC, 5, \ + struct btrfs_ioctl_vol_args) /* * Removed in kernel since 4.17: * BTRFS_IOC_TRANS_START _IO(BTRFS_IOCTL_MAGIC, 6) @@ -875,18 +936,18 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args) #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ - struct btrfs_ioctl_clone_range_args) + struct btrfs_ioctl_clone_range_args) #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ - struct btrfs_ioctl_vol_args) + struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \ struct btrfs_ioctl_defrag_range_args) #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ struct btrfs_ioctl_search_args) #define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \ - struct btrfs_ioctl_search_args_v2) + struct btrfs_ioctl_search_args_v2) #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ struct btrfs_ioctl_ino_lookup_args) #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) @@ -955,7 +1016,7 @@ enum btrfs_err_code { #define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \ struct btrfs_ioctl_vol_args_v2) #define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \ - struct btrfs_ioctl_logical_ino_args) + struct btrfs_ioctl_logical_ino_args) #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ struct btrfs_ioctl_get_subvol_info_args) #define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ diff --git a/src/btrfs/libbtrfsutil/btrfs_tree.h b/src/btrfs/libbtrfsutil/btrfs_tree.h index 5e1609e0..d6261ba2 100644 --- a/src/btrfs/libbtrfsutil/btrfs_tree.h +++ b/src/btrfs/libbtrfsutil/btrfs_tree.h @@ -48,9 +48,12 @@ /* tracks free space in block groups. */ #define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL -/* hold the block group items. */ +/* Holds the block group items for extent tree v2. */ #define BTRFS_BLOCK_GROUP_TREE_OBJECTID 11ULL +/* Holds raid stripe entries */ +#define BTRFS_RAID_STRIPE_TREE_OBJECTID 12ULL + /* device stats in the device tree */ #define BTRFS_DEV_STATS_OBJECTID 0ULL @@ -84,6 +87,7 @@ */ #define BTRFS_FREE_INO_OBJECTID -12ULL +#define BTRFS_CSUM_CHANGE_OBJECTID -13ULL /* dummy objectid represents multiple objectids */ #define BTRFS_MULTIPLE_OBJECTIDS -255ULL @@ -116,12 +120,37 @@ #define BTRFS_INODE_REF_KEY 12 #define BTRFS_INODE_EXTREF_KEY 13 #define BTRFS_XATTR_ITEM_KEY 24 + +/* + * fs verity items are stored under two different key types on disk. + * The descriptor items: + * [ inode objectid, BTRFS_VERITY_DESC_ITEM_KEY, offset ] + * + * At offset 0, we store a btrfs_verity_descriptor_item which tracks the size + * of the descriptor item and some extra data for encryption. + * Starting at offset 1, these hold the generic fs verity descriptor. The + * latter are opaque to btrfs, we just read and write them as a blob for the + * higher level verity code. The most common descriptor size is 256 bytes. + * + * The merkle tree items: + * [ inode objectid, BTRFS_VERITY_MERKLE_ITEM_KEY, offset ] + * + * These also start at offset 0, and correspond to the merkle tree bytes. When + * fsverity asks for page 0 of the merkle tree, we pull up one page starting at + * offset 0 for this key type. These are also opaque to btrfs, we're blindly + * storing whatever fsverity sends down. + */ +#define BTRFS_VERITY_DESC_ITEM_KEY 36 +#define BTRFS_VERITY_MERKLE_ITEM_KEY 37 + #define BTRFS_ORPHAN_ITEM_KEY 48 /* reserve 2-15 close to the inode for later flexibility */ /* * dir items are the name -> inode pointers in a directory. There is one - * for every name in a directory. + * for every name in a directory. BTRFS_DIR_LOG_ITEM_KEY is no longer used + * but it's still defined here for documentation purposes and to help avoid + * having its numerical value reused in the future. */ #define BTRFS_DIR_LOG_ITEM_KEY 60 #define BTRFS_DIR_LOG_INDEX_KEY 72 @@ -169,6 +198,9 @@ */ #define BTRFS_METADATA_ITEM_KEY 169 +/* Extent owner, used by squota. */ +#define BTRFS_EXTENT_OWNER_REF_KEY 172 + #define BTRFS_TREE_BLOCK_REF_KEY 176 #define BTRFS_EXTENT_DATA_REF_KEY 178 @@ -310,6 +342,8 @@ * * Used by: * struct btrfs_dir_item.type + * + * Values 0..7 must match common file type values in fs_types.h. */ #define BTRFS_FT_UNKNOWN 0 #define BTRFS_FT_REG_FILE 1 @@ -321,6 +355,8 @@ #define BTRFS_FT_SYMLINK 7 #define BTRFS_FT_XATTR 8 #define BTRFS_FT_MAX 9 +/* Directory contains encrypted data */ +#define BTRFS_FT_ENCRYPTED 0x80 /* * The key defines the order in the tree, and so it also defines (optimal) @@ -459,6 +495,9 @@ struct btrfs_free_space_header { #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) +#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) +#define BTRFS_SUPER_FLAG_CHANGING_FSID (1ULL << 35) +#define BTRFS_SUPER_FLAG_CHANGING_FSID_V2 (1ULL << 36) /* @@ -507,20 +546,16 @@ struct btrfs_shared_data_ref { __le32 count; } __attribute__ ((__packed__)); +/* Extent owner, used by squota. */ +struct btrfs_extent_owner_ref { + __le64 root_id; +} __attribute__ ((__packed__)); + struct btrfs_extent_inline_ref { __u8 type; __le64 offset; } __attribute__ ((__packed__)); -/* old style backrefs item */ -struct btrfs_extent_ref_v0 { - __le64 root; - __le64 generation; - __le64 objectid; - __le32 count; -} __attribute__ ((__packed__)); - - /* dev extents record free space on individual devices. The owner * field points back to the chunk allocation mapping tree that allocated * the extent. The chunk tree uuid field is a way to double check the owner @@ -762,14 +797,14 @@ struct btrfs_file_extent_item { __u8 encryption; __le16 other_encoding; /* spare for later use */ - /* are we __inline__ data or a real extent? */ + /* are we inline data or a real extent? */ __u8 type; /* * disk space consumed by the extent, checksum blocks are included * in these numbers * - * At this offset in the structure, the __inline__ extent data start. + * At this offset in the structure, the inline extent data start. */ __le64 disk_bytenr; __le64 disk_num_bytes; @@ -831,8 +866,8 @@ struct btrfs_dev_replace_item { #define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) #define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) #define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) -#define BTRFS_BLOCK_GROUP_RAID1C3 (1ULL << 9) -#define BTRFS_BLOCK_GROUP_RAID1C4 (1ULL << 10) +#define BTRFS_BLOCK_GROUP_RAID1C3 (1ULL << 9) +#define BTRFS_BLOCK_GROUP_RAID1C4 (1ULL << 10) #define BTRFS_BLOCK_GROUP_RESERVED (BTRFS_AVAIL_ALLOC_BIT_SINGLE | \ BTRFS_SPACE_INFO_GLOBAL_RSV) @@ -855,15 +890,19 @@ enum btrfs_raid_types { #define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ BTRFS_BLOCK_GROUP_RAID1 | \ - BTRFS_BLOCK_GROUP_RAID5 | \ - BTRFS_BLOCK_GROUP_RAID6 | \ BTRFS_BLOCK_GROUP_RAID1C3 | \ BTRFS_BLOCK_GROUP_RAID1C4 | \ + BTRFS_BLOCK_GROUP_RAID5 | \ + BTRFS_BLOCK_GROUP_RAID6 | \ BTRFS_BLOCK_GROUP_DUP | \ BTRFS_BLOCK_GROUP_RAID10) #define BTRFS_BLOCK_GROUP_RAID56_MASK (BTRFS_BLOCK_GROUP_RAID5 | \ BTRFS_BLOCK_GROUP_RAID6) +#define BTRFS_BLOCK_GROUP_RAID1_MASK (BTRFS_BLOCK_GROUP_RAID1 | \ + BTRFS_BLOCK_GROUP_RAID1C3 | \ + BTRFS_BLOCK_GROUP_RAID1C4) + /* * We need a bit for restriper to be able to tell when chunks of type * SINGLE are available. This "extended" profile format is used in @@ -910,7 +949,7 @@ struct btrfs_free_space_info { #define BTRFS_QGROUP_LEVEL_SHIFT 48 static __inline__ __u16 btrfs_qgroup_level(__u64 qgroupid) { - return qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT; + return (__u16)(qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT); } /* @@ -930,6 +969,18 @@ static __inline__ __u16 btrfs_qgroup_level(__u64 qgroupid) */ #define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT (1ULL << 2) +/* + * Whether or not this filesystem is using simple quotas. Not exactly the + * incompat bit, because we support using simple quotas, disabling it, then + * going back to full qgroup quotas. + */ +#define BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE (1ULL << 3) + +#define BTRFS_QGROUP_STATUS_FLAGS_MASK (BTRFS_QGROUP_STATUS_FLAG_ON | \ + BTRFS_QGROUP_STATUS_FLAG_RESCAN | \ + BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT | \ + BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE) + #define BTRFS_QGROUP_STATUS_VERSION 1 struct btrfs_qgroup_status_item { @@ -950,6 +1001,12 @@ struct btrfs_qgroup_status_item { * of the scan. It contains a logical address */ __le64 rescan; + + /* + * (Added in 6.7.) Used by simple quotas to ignore old extent + * deletions. Present when incompat flag SIMPLE_QUOTA is set. + */ + __le64 enable_gen; } __attribute__ ((__packed__)); struct btrfs_qgroup_info_item { @@ -971,4 +1028,16 @@ struct btrfs_qgroup_limit_item { __le64 rsv_excl; } __attribute__ ((__packed__)); +struct btrfs_verity_descriptor_item { + /* Size of the verity descriptor in bytes */ + __le64 size; + /* + * When we implement support for fscrypt, we will need to encrypt the + * Merkle tree for encrypted verity files. These 128 bits are for the + * eventual storage of an fscrypt initialization vector. + */ + __le64 reserved[2]; + __u8 encryption; +} __attribute__ ((__packed__)); + #endif /* _BTRFS_CTREE_H_ */ diff --git a/src/btrfs/libbtrfsutil/btrfsutil.h b/src/btrfs/libbtrfsutil/btrfsutil.h index e55502f1..0f53a552 100644 --- a/src/btrfs/libbtrfsutil/btrfsutil.h +++ b/src/btrfs/libbtrfsutil/btrfsutil.h @@ -26,13 +26,15 @@ #include #define BTRFS_UTIL_VERSION_MAJOR 1 -#define BTRFS_UTIL_VERSION_MINOR 2 +#define BTRFS_UTIL_VERSION_MINOR 3 #define BTRFS_UTIL_VERSION_PATCH 0 #ifdef __cplusplus extern "C" { #endif +#define LIBBTRFSUTIL_ALIAS(orig) + /** * enum btrfs_util_error - libbtrfsutil error codes. * @@ -78,50 +80,91 @@ enum btrfs_util_error { */ const char *btrfs_util_strerror(enum btrfs_util_error err); +/** + * btrfs_util_sync() - Alias of btrfs_fs_util_sync(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_sync(const char *path); + /** * btrfs_util_sync() - Force a sync on a specific Btrfs filesystem. * @path: Path on a Btrfs filesystem. * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_sync(const char *path); +enum btrfs_util_error btrfs_util_fs_sync(const char *path) +LIBBTRFSUTIL_ALIAS(btrfs_util_sync); + /** - * btrfs_util_sync_fd() - See btrfs_util_sync(). + * btrfs_util_sync_fd() - Alias of btrfs_util_fs_sync_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_sync_fd(int fd); /** - * btrfs_util_start_sync() - Start a sync on a specific Btrfs filesystem but + * btrfs_util_fs_sync_fd() - See btrfs_util_fs_sync(). + */ +enum btrfs_util_error btrfs_util_fs_sync_fd(int fd) +LIBBTRFSUTIL_ALIAS(btrfs_util_sync_fd); + +/** + * btrfs_util_start_sync() - Alias of btrfs_util_fs_start_sync(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_start_sync(const char *path, uint64_t *transid); + +/** + * btrfs_util_fs_start_sync() - Start a sync on a specific Btrfs filesystem but * don't wait for it. * @path: Path on a Btrfs filesystem. * @transid: Returned transaction ID which can be waited on with - * btrfs_util_wait_sync(). This can be %NULL. + * btrfs_util_fs_wait_sync(). This can be %NULL. * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_start_sync(const char *path, - uint64_t *transid); +enum btrfs_util_error btrfs_util_fs_start_sync(const char *path, uint64_t *transid) +LIBBTRFSUTIL_ALIAS(btrfs_util_start_sync); /** - * btrfs_util_start_sync_fd() - See btrfs_util_start_sync(). + * btrfs_util_start_sync_fd() - Alias of btrfs_util_fs_start_sync_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_start_sync_fd(int fd, uint64_t *transid); /** - * btrfs_util_wait_sync() - Wait for a transaction with a given ID to sync. + * btrfs_util_fs_start_sync_fd() - See btrfs_util_start_sync(). + */ +enum btrfs_util_error btrfs_util_fs_start_sync_fd(int fd, uint64_t *transid) +LIBBTRFSUTIL_ALIAS(btrfs_util_start_sync_fd); + +/** + * btrfs_util_wait_sync() - Alias of btrfs_util_fs_wait_sync(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_wait_sync(const char *path, uint64_t transid); + +/** + * btrfs_util_fs_wait_sync() - Wait for a transaction with a given ID to sync. * @path: Path on a Btrfs filesystem. * @transid: Transaction ID to wait for, or zero for the current transaction. * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_wait_sync(const char *path, uint64_t transid); +enum btrfs_util_error btrfs_util_fs_wait_sync(const char *path, uint64_t transid) +LIBBTRFSUTIL_ALIAS(btrfs_util_wait_sync); /** - * btrfs_util_wait_sync_fd() - See btrfs_util_wait_sync(). + * btrfs_util_wait_sync_fd() - Alias of btrfs_util_fs_wait_sync_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_wait_sync_fd(int fd, uint64_t transid); +/** + * btrfs_util_fs_wait_sync_fd() - See btrfs_util_fs_wait_sync(). + */ +enum btrfs_util_error btrfs_util_fs_wait_sync_fd(int fd, uint64_t transid) +LIBBTRFSUTIL_ALIAS(btrfs_util_wait_sync_fd); + +/** + * btrfs_util_is_subvolume() - Alias of btrfs_util_subvolume_is_valid(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_is_subvolume(const char *path); + /** * btrfs_util_is_subvolume() - Return whether a given path is a Btrfs subvolume. * @path: Path to check. @@ -131,7 +174,8 @@ enum btrfs_util_error btrfs_util_wait_sync_fd(int fd, uint64_t transid); * %BTRFS_UTIL_ERROR_NOT_SUBVOLUME if @path is not a subvolume, non-zero error * code on any other failure. */ -enum btrfs_util_error btrfs_util_is_subvolume(const char *path); +enum btrfs_util_error btrfs_util_subvolume_is_valid(const char *path) +LIBBTRFSUTIL_ALIAS(btrfs_util_is_subvolume); /** * btrfs_util_is_subvolume_fd() - See btrfs_util_is_subvolume(). @@ -139,22 +183,44 @@ enum btrfs_util_error btrfs_util_is_subvolume(const char *path); enum btrfs_util_error btrfs_util_is_subvolume_fd(int fd); /** - * btrfs_util_subvolume_id() - Get the ID of the subvolume containing a path. + * btrfs_util_subvolume_is_valid_fd() - See btrfs_util_subvolume_is_valid(). + */ +enum btrfs_util_error btrfs_util_subvolume_is_valid_fd(int fd) +LIBBTRFSUTIL_ALIAS(btrfs_util_is_subvolume_fd); + +/** + * btrfs_util_subvolume_id() - Alias of btrfs_util_subvolume_get_id(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_subvolume_id(const char *path, uint64_t *id_ret); + +/** + * btrfs_util_subvolume_get_id() - Get the ID of the subvolume containing a path. * @path: Path on a Btrfs filesystem. * @id_ret: Returned subvolume ID. * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_subvolume_id(const char *path, - uint64_t *id_ret); +enum btrfs_util_error btrfs_util_subvolume_get_id(const char *path, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_id); /** - * btrfs_util_subvolume_id_fd() - See btrfs_util_subvolume_id(). + * btrfs_util_subvolume_id_fd() - Alias of btrfs_util_subvolume_get_id_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_subvolume_id_fd(int fd, uint64_t *id_ret); /** - * btrfs_util_subvolume_path() - Get the path of the subvolume with a given ID + * btrfs_util_subvolume_get_id_fd() - See btrfs_util_subvolume_get_id(). + */ +enum btrfs_util_error btrfs_util_subvolume_get_id_fd(int fd, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_id_fd); + +/** + * btrfs_util_subvolume_path() - Alias of btrfs_util_subvolume_get_path(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_subvolume_path(const char *path, uint64_t id, char **path_ret); + +/** + * btrfs_util_subvolume_get_path() - Get the path of the subvolume with a given ID * relative to the filesystem root. * @path: Path on a Btrfs filesystem. * @id: ID of subvolume to set as the default. If zero is given, the subvolume @@ -165,14 +231,19 @@ enum btrfs_util_error btrfs_util_subvolume_id_fd(int fd, uint64_t *id_ret); * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_subvolume_path(const char *path, uint64_t id, - char **path_ret); +enum btrfs_util_error btrfs_util_subvolume_get_path(const char *path, uint64_t id, char **path_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_path); + +/** + * btrfs_util_subvolume_path_fd() - Alias of btrfs_util_subvolume_get_path_fd(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_subvolume_path_fd(int fd, uint64_t id, char **path_ret); /** - * btrfs_util_subvolume_path_fd() - See btrfs_util_subvolume_path(). + * btrfs_util_subvolume_get_path_fd() - See btrfs_util_subvolume_get_path(). */ -enum btrfs_util_error btrfs_util_subvolume_path_fd(int fd, uint64_t id, - char **path_ret); +enum btrfs_util_error btrfs_util_subvolume_get_path_fd(int fd, uint64_t id, char **path_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_path_fd); /** * struct btrfs_util_subvolume_info - Information about a Btrfs subvolume. @@ -260,6 +331,12 @@ struct btrfs_util_subvolume_info { struct timespec rtime; }; +/** + * btrfs_util_subvolume_info() - Alias of (), do not use in new code. + */ +enum btrfs_util_error btrfs_util_subvolume_info(const char *path, uint64_t id, + struct btrfs_util_subvolume_info *subvol); + /** * btrfs_util_subvolume_info() - Get information about a subvolume. * @path: Path in a Btrfs filesystem. This may be any path in the filesystem; it @@ -275,33 +352,56 @@ struct btrfs_util_subvolume_info { * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_subvolume_info(const char *path, uint64_t id, - struct btrfs_util_subvolume_info *subvol); +enum btrfs_util_error btrfs_util_subvolume_get_info(const char *path, uint64_t id, + struct btrfs_util_subvolume_info *subvol) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_info); /** - * btrfs_util_subvolume_info_fd() - See btrfs_util_subvolume_info(). + * btrfs_util_subvolume_info_fd() - Alias of btrfs_util_subvolume_get_info_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_subvolume_info_fd(int fd, uint64_t id, struct btrfs_util_subvolume_info *subvol); /** - * btrfs_util_get_subvolume_read_only() - Get whether a subvolume is read-only. + * btrfs_util_subvolume_get_info_fd() - See btrfs_util_subvolume_get_info(). + */ +enum btrfs_util_error btrfs_util_subvolume_get_info_fd(int fd, uint64_t id, + struct btrfs_util_subvolume_info *subvol) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_info_fd); + +/** + * btrfs_util_get_subvolume_read_only() - Alias of btrfs_util_subvolume_get_read_only(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_get_subvolume_read_only(const char *path, bool *ret); + +/** + * btrfs_util_subvolume_get_read_only() - Get whether a subvolume is read-only. * @path: Subvolume path. * @ret: Returned read-only flag. * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_get_subvolume_read_only(const char *path, - bool *ret); +enum btrfs_util_error btrfs_util_subvolume_get_read_only(const char *path, bool *ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_subvolume_read_only); /** - * btrfs_util_get_subvolume_read_only_fd() - See - * btrfs_util_get_subvolume_read_only(). + * btrfs_util_get_subvolume_read_only_fd() - Alias of btrfs_util_subvolume_get_read_only_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_get_subvolume_read_only_fd(int fd, bool *ret); /** - * btrfs_util_set_subvolume_read_only() - Set whether a subvolume is read-only. + * btrfs_util_subvolume_get_read_only_fd() - See btrfs_util_subvolume_get_read_only(). + */ +enum btrfs_util_error btrfs_util_subvolume_get_read_only_fd(int fd, bool *ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_subvolume_read_only_fd); + +/** + * btrfs_util_set_subvolume_read_only() - Alias of btrfs_util_subvolume_set_read_only(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_set_subvolume_read_only(const char *path, bool read_only); + +/** + * btrfs_util_subvolume_set_read_only() - Set whether a subvolume is read-only. * @path: Subvolume path. * @read_only: New value of read-only flag. * @@ -309,18 +409,27 @@ enum btrfs_util_error btrfs_util_get_subvolume_read_only_fd(int fd, bool *ret); * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_set_subvolume_read_only(const char *path, - bool read_only); +enum btrfs_util_error btrfs_util_subvolume_set_read_only(const char *path, bool read_only) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_subvolume_read_only); /** - * btrfs_util_set_subvolume_read_only_fd() - See - * btrfs_util_set_subvolume_read_only(). + * btrfs_util_set_subvolume_read_only_fd() - Alias of btrfs_util_subvolume_set_read_only_fd(), do not use in new code. */ -enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, - bool read_only); +enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, bool read_only); /** - * btrfs_util_get_default_subvolume() - Get the default subvolume for a + * btrfs_util_subvolume_set_read_only_fd() - See btrfs_util_subvolume_set_read_only(). + */ +enum btrfs_util_error btrfs_util_subvolume_set_read_only_fd(int fd, bool read_only) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_subvolume_read_only_fd); + +/** + * btrfs_util_get_default_subvolume() - Alias of btrfs_util_subvolume_get_default(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_get_default_subvolume(const char *path, uint64_t *id_ret); + +/** + * btrfs_util_subvolume_get_default() - Get the default subvolume for a * filesystem. * @path: Path on a Btrfs filesystem. * @id_ret: Returned subvolume ID. @@ -329,18 +438,28 @@ enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_get_default_subvolume(const char *path, - uint64_t *id_ret); +enum btrfs_util_error btrfs_util_subvolume_get_default(const char *path, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_default_subvolume); /** * btrfs_util_get_default_subvolume_fd() - See * btrfs_util_get_default_subvolume(). */ -enum btrfs_util_error btrfs_util_get_default_subvolume_fd(int fd, - uint64_t *id_ret); +enum btrfs_util_error btrfs_util_get_default_subvolume_fd(int fd, uint64_t *id_ret); + +/** + * btrfs_util__subvolume_get_default_fd() - See btrfs_util_subvolume_get_default(). + */ +enum btrfs_util_error btrfs_util_subvolume_get_default_fd(int fd, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_default_subvolume_fd); + +/** + * btrfs_util_set_default_subvolume() - Alias of btrfs_util_set_default_subvolume(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_set_default_subvolume(const char *path, uint64_t id); /** - * btrfs_util_set_default_subvolume() - Set the default subvolume for a + * btrfs_util_subvolume_set_default() - Set the default subvolume for a * filesystem. * @path: Path in a Btrfs filesystem. This may be any path in the filesystem; it * does not have to refer to a subvolume unless @id is zero. @@ -351,19 +470,32 @@ enum btrfs_util_error btrfs_util_get_default_subvolume_fd(int fd, * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_set_default_subvolume(const char *path, - uint64_t id); +enum btrfs_util_error btrfs_util_subvolume_set_default(const char *path, uint64_t id) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_default_subvolume); /** - * btrfs_util_set_default_subvolume_fd() - See - * btrfs_util_set_default_subvolume(). + * btrfs_util_set_default_subvolume_fd() - Alias of btrfs_util_subvolume_set_default_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_set_default_subvolume_fd(int fd, uint64_t id); +/** + * btrfs_util_subvolume_set_default_fd() - See + * btrfs_util_subvolume_set_default(). + */ +enum btrfs_util_error btrfs_util_subvolume_set_default_fd(int fd, uint64_t id) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_default_subvolume_fd); + struct btrfs_util_qgroup_inherit; /** - * btrfs_util_create_subvolume() - Create a new subvolume. + * btrfs_util_create_subvolume() - Alias of btrfs_util_subvolume_create(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_create_subvolume(const char *path, int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit); + +/** + * btrfs_util_subvolume_create() - Create a new subvolume. * @path: Where to create the subvolume. * @flags: Must be zero. * @unused: No longer used (since 5.15) @@ -371,12 +503,22 @@ struct btrfs_util_qgroup_inherit; * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_create_subvolume(const char *path, int flags, +enum btrfs_util_error btrfs_util_subvolume_create(const char *path, int flags, uint64_t *unused, - struct btrfs_util_qgroup_inherit *qgroup_inherit); + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume); /** - * btrfs_util_create_subvolume_fd() - Create a new subvolume given its parent + * btrfs_util_create_subvolume_fd() - Alias of btrfs_util_subvolume_create_fd(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_create_subvolume_fd(int parent_fd, + const char *name, + int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit); + +/** + * btrfs_util_subvolume_create_fd() - Create a new subvolume given its parent * and name. * @parent_fd: File descriptor of the parent directory where the subvolume * should be created. @@ -387,11 +529,12 @@ enum btrfs_util_error btrfs_util_create_subvolume(const char *path, int flags, * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_create_subvolume_fd(int parent_fd, +enum btrfs_util_error btrfs_util_subvolume_create_fd(int parent_fd, const char *name, int flags, uint64_t *unused, - struct btrfs_util_qgroup_inherit *qgroup_inherit); + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume_fd); /** * BTRFS_UTIL_CREATE_SNAPSHOT_RECURSIVE - Also snapshot subvolumes beneath the @@ -402,31 +545,40 @@ enum btrfs_util_error btrfs_util_create_subvolume_fd(int parent_fd, * %BTRFS_UTIL_CREATE_SNAPSHOT_READ_ONLY. It requires appropriate privilege * (CAP_SYS_ADMIN). */ -#define BTRFS_UTIL_CREATE_SNAPSHOT_RECURSIVE (1 << 0) +#define BTRFS_UTIL_CREATE_SNAPSHOT_RECURSIVE (1U << 0) /** * BTRFS_UTIL_CREATE_SNAPSHOT_READ_ONLY - Create a read-only snapshot. */ -#define BTRFS_UTIL_CREATE_SNAPSHOT_READ_ONLY (1 << 1) -#define BTRFS_UTIL_CREATE_SNAPSHOT_MASK ((1 << 2) - 1) +#define BTRFS_UTIL_CREATE_SNAPSHOT_READ_ONLY (1U << 1) +#define BTRFS_UTIL_CREATE_SNAPSHOT_MASK ((1U << 2) - 1) /** - * btrfs_util_create_snapshot() - Create a new snapshot from a source subvolume + * btrfs_util_create_snapshot() - Alias of btrfs_util_snapshot_snapshot(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_create_snapshot(const char *source, + const char *path, int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit); + +/** + * btrfs_util_subvolume_snapshot() - Create a new snapshot from a source subvolume * path. * @source: Path of the existing subvolume to snapshot. * @path: Where to create the snapshot. * @flags: Bitmask of BTRFS_UTIL_CREATE_SNAPSHOT_* flags. - * @unused: See btrfs_util_create_subvolume(). + * @unused: See btrfs_util_create_subvAlias of (), do not use in new code.olume(). * @qgroup_inherit: See btrfs_util_create_subvolume(). * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_create_snapshot(const char *source, - const char *path, int flags, - uint64_t *unused, - struct btrfs_util_qgroup_inherit *qgroup_inherit); +enum btrfs_util_error btrfs_util_subvolume_snapshot(const char *source, + const char *path, int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_snapshot); /** - * btrfs_util_create_snapshot_fd() - See btrfs_util_create_snapshot(). + * btrfs_util_create_snapshot_fd() - Alias of btrfs_util_subvolume_snapshot_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_create_snapshot_fd(int fd, const char *path, int flags, @@ -434,15 +586,16 @@ enum btrfs_util_error btrfs_util_create_snapshot_fd(int fd, const char *path, struct btrfs_util_qgroup_inherit *qgroup_inherit); /** - * btrfs_util_create_snapshot_fd2() - Create a new snapshot from a source - * subvolume file descriptor and a target parent file descriptor and name. - * @fd: File descriptor of the existing subvolume to snapshot. - * @parent_fd: File descriptor of the parent directory where the snapshot should - * be created. - * @name: Name of the snapshot to create. - * @flags: See btrfs_util_create_snapshot(). - * @unused: See btrfs_util_create_snapshot(). - * @qgroup_inherit: See btrfs_util_create_snapshot(). + * btrfs_util_subvolume_snapshot_fd() - See btrfs_util_subvolume_snapshot(). + */ +enum btrfs_util_error btrfs_util_subvolume_snapshot_fd(int fd, const char *path, + int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_snapshot_fd); + +/** + * btrfs_util_create_snapshot_fd2() -Alias of btrfs_util_subvolume_snapshot_fd2(), do not use in new code. */ enum btrfs_util_error btrfs_util_create_snapshot_fd2(int fd, int parent_fd, const char *name, @@ -450,6 +603,24 @@ enum btrfs_util_error btrfs_util_create_snapshot_fd2(int fd, int parent_fd, uint64_t *unused, struct btrfs_util_qgroup_inherit *qgroup_inherit); +/** + * btrfs_util_subvolume_snapshot_fd2() - Create a new snapshot from a source + * subvolume file descriptor and a target parent file descriptor and name. + * @fd: File descriptor of the existing subvolume to snapshot. + * @parent_fd: File descriptor of the parent directory where the snapshot should + * be created. + * @name: Name of the snapshot to create. + * @flags: See btrfs_util_subvolume_snapshot(). + * @unused: See btrfs_util_subvolume_snapshot(). + * @qgroup_inherit: See btrfs_util_subvolume_snapshot(). + */ +enum btrfs_util_error btrfs_util_subvolume_snapshot_fd2(int fd, int parent_fd, + const char *name, + int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_snapshot_fd2); + /** * BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE - Delete subvolumes beneath the given * subvolume before attempting to delete the given subvolume. @@ -458,11 +629,16 @@ enum btrfs_util_error btrfs_util_create_snapshot_fd2(int fd, int parent_fd, * error. Note that this is currently implemented in userspace non-atomically. * It requires appropriate privilege (CAP_SYS_ADMIN). */ -#define BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE (1 << 0) -#define BTRFS_UTIL_DELETE_SUBVOLUME_MASK ((1 << 1) - 1) +#define BTRFS_UTIL_DELETE_SUBVOLUME_RECURSIVE (1U << 0) +#define BTRFS_UTIL_DELETE_SUBVOLUME_MASK ((1U << 1) - 1) /** - * btrfs_util_delete_subvolume() - Delete a subvolume or snapshot. + * btrfs_util_delete_subvolume() - Alias of btrfs_util_subvolume_delete(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_delete_subvolume(const char *path, int flags); + +/** + * btrfs_util_subvolume_delete() - Delete a subvolume or snapshot. * @path: Path of the subvolume to delete. * @flags: Bitmask of BTRFS_UTIL_DELETE_SUBVOLUME_* flags. * @@ -475,31 +651,45 @@ enum btrfs_util_error btrfs_util_create_snapshot_fd2(int fd, int parent_fd, * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_delete_subvolume(const char *path, int flags); +enum btrfs_util_error btrfs_util_subvolume_delete(const char *path, int flags) +LIBBTRFSUTIL_ALIAS(btrfs_util_delete_subvolume); /** - * btrfs_util_delete_subvolume_fd() - Delete a subvolume or snapshot given its + * btrfs_util_delete_subvolume_fd() - Alias of (), do not use in new code. + */ +enum btrfs_util_error btrfs_util_delete_subvolume_fd(int parent_fd, + const char *name, + int flags); + +/** + * btrfs_util_subvolume_delete_fd() - Delete a subvolume or snapshot given its * parent and name. * @parent_fd: File descriptor of the subvolume's parent directory. * @name: Name of the subvolume. - * @flags: See btrfs_util_delete_subvolume(). + * @flags: See btrfs_util_subvolume_delete(). * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_delete_subvolume_fd(int parent_fd, +enum btrfs_util_error btrfs_util_subvolume_delete_fd(int parent_fd, const char *name, - int flags); + int flags) +LIBBTRFSUTIL_ALIAS(btrfs_util_delete_subvolume_fd); /** - * btrfs_util_delete_subvolume_by_id_fd() - Delete a subvolume or snapshot using + * btrfs_util_delete_subvolume_by_id_fd() -Alias of btrfs_util_subvolume_delete_by_id_fd(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_delete_subvolume_by_id_fd(int fd, uint64_t subvolid); + +/** + * btrfs_util_subvolume_delete_by_id_fd() - Delete a subvolume or snapshot using * subvolume id. * @fd: File descriptor of the subvolume's parent directory. * @subvolid: Subvolume id of the subvolume or snapshot to be deleted. * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_delete_subvolume_by_id_fd(int fd, - uint64_t subvolid); +enum btrfs_util_error btrfs_util_subvolume_delete_by_id_fd(int fd, uint64_t subvolid) +LIBBTRFSUTIL_ALIAS(btrfs_util_delete_subvolume_by_id_fd); struct btrfs_util_subvolume_iterator; @@ -508,11 +698,19 @@ struct btrfs_util_subvolume_iterator; * behavior is pre-order, e.g., foo will be yielded before foo/bar. If this flag * is specified, foo/bar will be yielded before foo. */ -#define BTRFS_UTIL_SUBVOLUME_ITERATOR_POST_ORDER (1 << 0) -#define BTRFS_UTIL_SUBVOLUME_ITERATOR_MASK ((1 << 1) - 1) +#define BTRFS_UTIL_SUBVOLUME_ITERATOR_POST_ORDER (1U << 0) +#define BTRFS_UTIL_SUBVOLUME_ITERATOR_MASK ((1U << 1) - 1) + +/** + * btrfs_util_create_subvolume_iterator() - Alias of btrfs_util_subvolume_iter_create(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_create_subvolume_iterator(const char *path, + uint64_t top, + int flags, + struct btrfs_util_subvolume_iterator **ret); /** - * btrfs_util_create_subvolume_iterator() - Create an iterator over subvolumes + * btrfs_util_subvolume_iter_create() - Create an iterator over subvolumes * in a Btrfs filesystem. * @path: Path in a Btrfs filesystem. This may be any path in the filesystem; it * does not have to refer to a subvolume unless @top is zero. @@ -530,18 +728,18 @@ struct btrfs_util_subvolume_iterator; * skipped. * * The returned iterator must be freed with - * btrfs_util_destroy_subvolume_iterator(). + * btrfs_util_subvolume_iter_destroy(). * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_create_subvolume_iterator(const char *path, - uint64_t top, - int flags, - struct btrfs_util_subvolume_iterator **ret); +enum btrfs_util_error btrfs_util_subvolume_iter_create(const char *path, + uint64_t top, + int flags, + struct btrfs_util_subvolume_iterator **ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume_iterator); /** - * btrfs_util_create_subvolume_iterator_fd() - See - * btrfs_util_create_subvolume_iterator(). + * btrfs_util_create_subvolume_iterator_fd() - Alias of btrfs_util_subvolume_iter_create_fd(), do not use in new code. */ enum btrfs_util_error btrfs_util_create_subvolume_iterator_fd(int fd, uint64_t top, @@ -549,14 +747,34 @@ enum btrfs_util_error btrfs_util_create_subvolume_iterator_fd(int fd, struct btrfs_util_subvolume_iterator **ret); /** - * btrfs_util_destroy_subvolume_iterator() - Destroy a subvolume iterator - * previously created by btrfs_util_create_subvolume_iterator(). - * @iter: Iterator to destroy. + * btrfs_util_subvolume_iter_create_fd() - See btrfs_util_subvolume_iter_create(). + */ +enum btrfs_util_error btrfs_util_subvolume_iter_create_fd(int fd, + uint64_t top, + int flags, + struct btrfs_util_subvolume_iterator **ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume_iterator_fd); + +/** + * btrfs_util_destroy_subvolume_iterator() - Alias of btrfs_util_subvolume_iter_destroy(), do not use in new code. */ void btrfs_util_destroy_subvolume_iterator(struct btrfs_util_subvolume_iterator *iter); /** - * btrfs_util_subvolume_iterator_fd() - Get the file descriptor associated with + * btrfs_util_subvolume_iter_destroy() - Destroy a subvolume iterator + * previously created by btrfs_util_subvolume_iter_create(). + * @iter: Iterator to destroy. + */ +void btrfs_util_subvolume_iter_destroy(struct btrfs_util_subvolume_iterator *iter) +LIBBTRFSUTIL_ALIAS(btrfs_util_destroy_subvolume_iterator); + +/** + * btrfs_util_subvolume_iterator_fd() -Alias of btrfs_util_subvolume_iterator_get_fd(), do not use in new code. + */ +int btrfs_util_subvolume_iterator_fd(const struct btrfs_util_subvolume_iterator *iter); + +/** + * btrfs_util_subvolume_iterator_get_fd() - Get the file descriptor associated with * a subvolume iterator. * @iter: Iterator to get. * @@ -566,10 +784,18 @@ void btrfs_util_destroy_subvolume_iterator(struct btrfs_util_subvolume_iterator * * Return: File descriptor. */ -int btrfs_util_subvolume_iterator_fd(const struct btrfs_util_subvolume_iterator *iter); +int btrfs_util_subvolume_iterator_get_fd(const struct btrfs_util_subvolume_iterator *iter) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_iterator_fd); + +/** + * btrfs_util_subvolume_iterator_next() - Alias of btrfs_util_subvolume_iter_next(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_subvolume_iterator_next(struct btrfs_util_subvolume_iterator *iter, + char **path_ret, + uint64_t *id_ret); /** - * btrfs_util_subvolume_iterator_next() - Get the next subvolume from a + * btrfs_util_subvolume_iter_next() - Get the next subvolume from a * subvolume iterator. * @iter: Subvolume iterator. * @path_ret: Returned subvolume path, relative to the subvolume ID used to @@ -583,31 +809,45 @@ int btrfs_util_subvolume_iterator_fd(const struct btrfs_util_subvolume_iterator * Return: %BTRFS_UTIL_OK on success, %BTRFS_UTIL_ERROR_STOP_ITERATION if there * are no more subvolumes, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_subvolume_iterator_next(struct btrfs_util_subvolume_iterator *iter, - char **path_ret, - uint64_t *id_ret); +enum btrfs_util_error btrfs_util_subvolume_iter_next(struct btrfs_util_subvolume_iterator *iter, + char **path_ret, + uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_iterator_next); /** - * btrfs_util_subvolume_iterator_next_info() - Get information about the next + * btrfs_util_subvolume_iterator_next_info() - Alias of btrfs_util_subvolume_iter_next_info(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_subvolume_iterator_next_info(struct btrfs_util_subvolume_iterator *iter, + char **path_ret, + struct btrfs_util_subvolume_info *subvol); + +/** + * btrfs_util_subvolume_iter_next_info() - Get information about the next * subvolume for a subvolume iterator. * @iter: Subvolume iterator. - * @path_ret: See btrfs_util_subvolume_iterator_next(). + * @path_ret: See btrfs_util_subvolume_iter_next(). * @subvol: Returned subvolume information. * * This convenience function basically combines - * btrfs_util_subvolume_iterator_next() and btrfs_util_subvolume_info(). + * btrfs_util_subvolume_iter_next() and btrfs_util_subvolume_info(). * * This requires appropriate privilege (CAP_SYS_ADMIN) for kernels < 4.18. See * btrfs_util_create_subvolume_iterator(). * - * Return: See btrfs_util_subvolume_iterator_next(). + * Return: See btrfs_util_subvolume_iter_next(). */ -enum btrfs_util_error btrfs_util_subvolume_iterator_next_info(struct btrfs_util_subvolume_iterator *iter, - char **path_ret, - struct btrfs_util_subvolume_info *subvol); +enum btrfs_util_error btrfs_util_subvolume_iter_next_info(struct btrfs_util_subvolume_iterator *iter, + char **path_ret, + struct btrfs_util_subvolume_info *subvol) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_iterator_next_info); + +/** + * btrfs_util_deleted_subvolumes() - Alias of btrfs_util_subvolume_list_deleted(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_deleted_subvolumes(const char *path, uint64_t **ids, size_t *n); /** - * btrfs_util_deleted_subvolumes() - Get a list of subvolume which have been + * btrfs_util_subvolume_list_deleted() - Get a list of subvolume which have been * deleted but not yet cleaned up. * @path: Path on a Btrfs filesystem. * @ids: Returned array of subvolume IDs. @@ -617,36 +857,51 @@ enum btrfs_util_error btrfs_util_subvolume_iterator_next_info(struct btrfs_util_ * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_deleted_subvolumes(const char *path, - uint64_t **ids, - size_t *n); +enum btrfs_util_error btrfs_util_subvolume_list_deleted(const char *path, uint64_t **ids, size_t *n) +LIBBTRFSUTIL_ALIAS(btrfs_util_deleted_subvolumes); /** - * btrfs_util_deleted_subvolumes_fd() - See btrfs_util_deleted_subvolumes(). + * btrfs_util_deleted_subvolumes_fd() - See btrfs_util_subvolume_list_deleted(). */ -enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd, uint64_t **ids, - size_t *n); +enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd, uint64_t **ids, size_t *n); /** - * btrfs_util_create_qgroup_inherit() - Create a qgroup inheritance specifier + * btrfs_util_subvolume_list_deleted_fd() - See btrfs_util_subvolume_list_deleted(). + */ +enum btrfs_util_error btrfs_util_subvolume_list_deleted_fd(int fd, uint64_t **ids, size_t *n) +LIBBTRFSUTIL_ALIAS(btrfs_util_deleted_subvolumes_fd); + +/** + * btrfs_util_create_qgroup_inherit() - Alias of btrfs_util_qgroup_inherit_create(), do not use in new code. + */ +enum btrfs_util_error btrfs_util_create_qgroup_inherit(int flags, struct btrfs_util_qgroup_inherit **ret); + +/** + * btrfs_util_qgroup_inherit_create() - Create a qgroup inheritance specifier * for btrfs_util_create_subvolume() or btrfs_util_create_snapshot(). * @flags: Must be zero. * @ret: Returned qgroup inheritance specifier. * * The returned structure must be freed with - * btrfs_util_destroy_qgroup_inherit(). + * btrfs_util_qgroup_inherit_destroy(). * * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure. */ -enum btrfs_util_error btrfs_util_create_qgroup_inherit(int flags, - struct btrfs_util_qgroup_inherit **ret); +enum btrfs_util_error btrfs_util_qgroup_inherit_create(int flags, struct btrfs_util_qgroup_inherit **ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_qgroup_inherit); /** - * btrfs_util_destroy_qgroup_inherit() - Destroy a qgroup inheritance specifier + * btrfs_util_destroy_qgroup_inherit() - Alias of btrfs_util_qgroup_inherit_destroy(), do not use in new code. + */ +void btrfs_util_destroy_qgroup_inherit(struct btrfs_util_qgroup_inherit *inherit); + +/** + * btrfs_util_qgroup_inherit_destroy() - Destroy a qgroup inheritance specifier * previously created with btrfs_util_create_qgroup_inherit(). * @inherit: Specifier to destroy. */ -void btrfs_util_destroy_qgroup_inherit(struct btrfs_util_qgroup_inherit *inherit); +void btrfs_util_qgroup_inherit_destroy(struct btrfs_util_qgroup_inherit *inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_destroy_qgroup_inherit); /** * btrfs_util_qgroup_inherit_add_group() - Add inheritance from a qgroup to a @@ -669,6 +924,8 @@ enum btrfs_util_error btrfs_util_qgroup_inherit_add_group(struct btrfs_util_qgro void btrfs_util_qgroup_inherit_get_groups(const struct btrfs_util_qgroup_inherit *inherit, const uint64_t **groups, size_t *n); +#undef LIBBTRFSUTIL_ALIAS + #ifdef __cplusplus } #endif diff --git a/src/btrfs/libbtrfsutil/btrfsutil_internal.h b/src/btrfs/libbtrfsutil/btrfsutil_internal.h index fbe4a6e5..8325c621 100644 --- a/src/btrfs/libbtrfsutil/btrfsutil_internal.h +++ b/src/btrfs/libbtrfsutil/btrfsutil_internal.h @@ -30,6 +30,7 @@ #include "btrfs_tree.h" #define PUBLIC __attribute__((visibility("default"))) +#define LIBBTRFSUTIL_ALIAS(orig) __attribute__((alias(#orig))) #define le16_to_cpu __le16_to_cpu #define le32_to_cpu __le32_to_cpu diff --git a/src/btrfs/libbtrfsutil/qgroup.c b/src/btrfs/libbtrfsutil/qgroup.c index c518cb63..38b3d067 100644 --- a/src/btrfs/libbtrfsutil/qgroup.c +++ b/src/btrfs/libbtrfsutil/qgroup.c @@ -46,11 +46,15 @@ PUBLIC enum btrfs_util_error btrfs_util_create_qgroup_inherit(int flags, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_qgroup_inherit_create(int flags, struct btrfs_util_qgroup_inherit **ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_qgroup_inherit); PUBLIC void btrfs_util_destroy_qgroup_inherit(struct btrfs_util_qgroup_inherit *inherit) { free(inherit); } +PUBLIC void btrfs_util_qgroup_inherit_destroy(struct btrfs_util_qgroup_inherit *inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_destroy_qgroup_inherit); PUBLIC enum btrfs_util_error btrfs_util_qgroup_inherit_add_group(struct btrfs_util_qgroup_inherit **inherit, uint64_t qgroupid) diff --git a/src/btrfs/libbtrfsutil/subvolume.c b/src/btrfs/libbtrfsutil/subvolume.c index d6efd5c1..cc3cca5f 100644 --- a/src/btrfs/libbtrfsutil/subvolume.c +++ b/src/btrfs/libbtrfsutil/subvolume.c @@ -70,6 +70,8 @@ PUBLIC enum btrfs_util_error btrfs_util_is_subvolume(const char *path) return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_is_valid(const char *path) +LIBBTRFSUTIL_ALIAS(btrfs_util_is_subvolume); PUBLIC enum btrfs_util_error btrfs_util_is_subvolume_fd(int fd) { @@ -97,6 +99,8 @@ PUBLIC enum btrfs_util_error btrfs_util_is_subvolume_fd(int fd) return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_is_valid_fd(int fd) +LIBBTRFSUTIL_ALIAS(btrfs_util_is_subvolume_fd); PUBLIC enum btrfs_util_error btrfs_util_subvolume_id(const char *path, uint64_t *id_ret) @@ -112,6 +116,8 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_id(const char *path, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_id(const char *path, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_id); PUBLIC enum btrfs_util_error btrfs_util_subvolume_id_fd(int fd, uint64_t *id_ret) @@ -130,6 +136,8 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_id_fd(int fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_id_fd(int fd, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_id_fd); PUBLIC enum btrfs_util_error btrfs_util_subvolume_path(const char *path, uint64_t id, @@ -146,6 +154,8 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_path(const char *path, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_path(const char *path, uint64_t id, char **path_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_path); PUBLIC enum btrfs_util_error btrfs_util_subvolume_path_fd(int fd, uint64_t id, char **path_ret) @@ -255,6 +265,8 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_path_fd(int fd, uint64_t id, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_path_fd(int fd, uint64_t id, char **path_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_path_fd); static void copy_timespec(struct timespec *timespec, const struct btrfs_timespec *btrfs_timespec) @@ -298,6 +310,9 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_info(const char *path, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_info(const char *path, uint64_t id, + struct btrfs_util_subvolume_info *subvol) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_info); static enum btrfs_util_error get_subvolume_info_privileged(int fd, uint64_t id, struct btrfs_util_subvolume_info *subvol) @@ -452,6 +467,9 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_info_fd(int fd, uint64_t id, return get_subvolume_info_privileged(fd, id, subvol); } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_info_fd(int fd, uint64_t id, + struct btrfs_util_subvolume_info *subvol) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_info_fd); PUBLIC enum btrfs_util_error btrfs_util_get_subvolume_read_only_fd(int fd, bool *read_only_ret) @@ -466,6 +484,8 @@ PUBLIC enum btrfs_util_error btrfs_util_get_subvolume_read_only_fd(int fd, *read_only_ret = flags & BTRFS_SUBVOL_RDONLY; return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_read_only_fd(int fd, bool *ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_subvolume_read_only_fd); PUBLIC enum btrfs_util_error btrfs_util_get_subvolume_read_only(const char *path, bool *ret) @@ -481,6 +501,8 @@ PUBLIC enum btrfs_util_error btrfs_util_get_subvolume_read_only(const char *path SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_read_only(const char *path, bool *ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_subvolume_read_only); PUBLIC enum btrfs_util_error btrfs_util_set_subvolume_read_only(const char *path, bool read_only) @@ -496,6 +518,8 @@ PUBLIC enum btrfs_util_error btrfs_util_set_subvolume_read_only(const char *path SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_set_read_only(const char *path, bool read_only) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_subvolume_read_only); PUBLIC enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, bool read_only) @@ -518,6 +542,8 @@ PUBLIC enum btrfs_util_error btrfs_util_set_subvolume_read_only_fd(int fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_set_read_only_fd(int fd, bool read_only) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_subvolume_read_only_fd); PUBLIC enum btrfs_util_error btrfs_util_get_default_subvolume(const char *path, uint64_t *id_ret) @@ -533,6 +559,8 @@ PUBLIC enum btrfs_util_error btrfs_util_get_default_subvolume(const char *path, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_default(const char *path, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_default_subvolume); PUBLIC enum btrfs_util_error btrfs_util_get_default_subvolume_fd(int fd, uint64_t *id_ret) @@ -593,6 +621,8 @@ PUBLIC enum btrfs_util_error btrfs_util_get_default_subvolume_fd(int fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_get_default_fd(int fd, uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_get_default_subvolume_fd); PUBLIC enum btrfs_util_error btrfs_util_set_default_subvolume(const char *path, uint64_t id) @@ -608,6 +638,8 @@ PUBLIC enum btrfs_util_error btrfs_util_set_default_subvolume(const char *path, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_set_default(const char *path, uint64_t id) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_default_subvolume); PUBLIC enum btrfs_util_error btrfs_util_set_default_subvolume_fd(int fd, uint64_t id) @@ -631,6 +663,8 @@ PUBLIC enum btrfs_util_error btrfs_util_set_default_subvolume_fd(int fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_set_default_fd(int fd, uint64_t id) +LIBBTRFSUTIL_ALIAS(btrfs_util_set_default_subvolume_fd); static enum btrfs_util_error openat_parent_and_name(int dirfd, const char *path, char *name, size_t name_len, @@ -701,6 +735,10 @@ PUBLIC enum btrfs_util_error btrfs_util_create_subvolume(const char *path, SAVE_ERRNO_AND_CLOSE(parent_fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_create(const char *path, int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume); PUBLIC enum btrfs_util_error btrfs_util_create_subvolume_fd(int parent_fd, const char *name, @@ -739,8 +777,14 @@ PUBLIC enum btrfs_util_error btrfs_util_create_subvolume_fd(int parent_fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_create_fd(int parent_fd, + const char *name, + int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume_fd); -#define BTRFS_UTIL_SUBVOLUME_ITERATOR_CLOSE_FD (1 << 30) +#define BTRFS_UTIL_SUBVOLUME_ITERATOR_CLOSE_FD (1U << 30) struct search_stack_entry { union { @@ -949,6 +993,11 @@ PUBLIC enum btrfs_util_error btrfs_util_create_subvolume_iterator(const char *pa return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_iter_create(const char *path, + uint64_t top, + int flags, + struct btrfs_util_subvolume_iterator **ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume_iterator); PUBLIC enum btrfs_util_error btrfs_util_create_subvolume_iterator_fd(int fd, uint64_t top, @@ -1016,6 +1065,11 @@ PUBLIC enum btrfs_util_error btrfs_util_create_subvolume_iterator_fd(int fd, free(iter); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_iter_create_fd(int fd, + uint64_t top, + int flags, + struct btrfs_util_subvolume_iterator **ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_subvolume_iterator_fd); static enum btrfs_util_error snapshot_subvolume_children(int fd, int parent_fd, const char *name) @@ -1101,6 +1155,11 @@ PUBLIC enum btrfs_util_error btrfs_util_create_snapshot(const char *source, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_snapshot(const char *source, + const char *path, int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_snapshot); PUBLIC enum btrfs_util_error btrfs_util_create_snapshot_fd(int fd, const char *path, @@ -1122,6 +1181,11 @@ PUBLIC enum btrfs_util_error btrfs_util_create_snapshot_fd(int fd, SAVE_ERRNO_AND_CLOSE(parent_fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_snapshot_fd(int fd, const char *path, + int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_snapshot_fd); PUBLIC enum btrfs_util_error btrfs_util_create_snapshot_fd2(int fd, int parent_fd, @@ -1172,6 +1236,12 @@ PUBLIC enum btrfs_util_error btrfs_util_create_snapshot_fd2(int fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_snapshot_fd2(int fd, int parent_fd, + const char *name, + int flags, + uint64_t *unused, + struct btrfs_util_qgroup_inherit *qgroup_inherit) +LIBBTRFSUTIL_ALIAS(btrfs_util_create_snapshot_fd2); static enum btrfs_util_error delete_subvolume_children(int parent_fd, const char *name) @@ -1239,6 +1309,8 @@ PUBLIC enum btrfs_util_error btrfs_util_delete_subvolume(const char *path, SAVE_ERRNO_AND_CLOSE(parent_fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_delete(const char *path, int flags) +LIBBTRFSUTIL_ALIAS(btrfs_util_delete_subvolume); PUBLIC enum btrfs_util_error btrfs_util_delete_subvolume_fd(int parent_fd, const char *name, @@ -1274,6 +1346,10 @@ PUBLIC enum btrfs_util_error btrfs_util_delete_subvolume_fd(int parent_fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_delete_fd(int parent_fd, + const char *name, + int flags) +LIBBTRFSUTIL_ALIAS(btrfs_util_delete_subvolume_fd); PUBLIC enum btrfs_util_error btrfs_util_delete_subvolume_by_id_fd(int parent_fd, uint64_t subvolid) @@ -1290,6 +1366,8 @@ PUBLIC enum btrfs_util_error btrfs_util_delete_subvolume_by_id_fd(int parent_fd, return BTRFS_UTIL_OK; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_delete_by_id_fd(int fd, uint64_t subvolid) +LIBBTRFSUTIL_ALIAS(btrfs_util_delete_subvolume_by_id_fd); PUBLIC void btrfs_util_destroy_subvolume_iterator(struct btrfs_util_subvolume_iterator *iter) { @@ -1303,11 +1381,15 @@ PUBLIC void btrfs_util_destroy_subvolume_iterator(struct btrfs_util_subvolume_it free(iter); } } +PUBLIC void btrfs_util_subvolume_iter_destroy(struct btrfs_util_subvolume_iterator *iter) +LIBBTRFSUTIL_ALIAS(btrfs_util_destroy_subvolume_iterator); PUBLIC int btrfs_util_subvolume_iterator_fd(const struct btrfs_util_subvolume_iterator *iter) { return iter->fd; } +PUBLIC int btrfs_util_subvolume_iterator_get_fd(const struct btrfs_util_subvolume_iterator *iter) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_iterator_fd); static enum btrfs_util_error build_subvol_path(struct btrfs_util_subvolume_iterator *iter, const char *name, size_t name_len, @@ -1586,6 +1668,10 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_iterator_next(struct btrfs_uti id_ret); } } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_iter_next(struct btrfs_util_subvolume_iterator *iter, + char **path_ret, + uint64_t *id_ret) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_iterator_next); PUBLIC enum btrfs_util_error btrfs_util_subvolume_iterator_next_info(struct btrfs_util_subvolume_iterator *iter, char **path_ret, @@ -1603,6 +1689,10 @@ PUBLIC enum btrfs_util_error btrfs_util_subvolume_iterator_next_info(struct btrf else return btrfs_util_subvolume_info_fd(iter->cur_fd, 0, subvol); } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_iter_next_info(struct btrfs_util_subvolume_iterator *iter, + char **path_ret, + struct btrfs_util_subvolume_info *subvol) +LIBBTRFSUTIL_ALIAS(btrfs_util_subvolume_iterator_next_info); PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes(const char *path, uint64_t **ids, @@ -1619,6 +1709,8 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes(const char *path, SAVE_ERRNO_AND_CLOSE(fd); return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_list_deleted(const char *path, uint64_t **ids, size_t *n) +LIBBTRFSUTIL_ALIAS(btrfs_util_deleted_subvolumes); PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd, uint64_t **ids, @@ -1647,6 +1739,7 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd, *n = 0; for (;;) { const struct btrfs_ioctl_search_header *header; + struct btrfs_util_subvolume_info subvol; if (items_pos >= search.key.nr_items) { search.key.nr_items = 4096; @@ -1668,7 +1761,7 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd, * The orphan item might be for a free space cache inode, so * check if there's a matching root item. */ - err = btrfs_util_subvolume_info_fd(fd, header->offset, NULL); + err = btrfs_util_subvolume_info_fd(fd, header->offset, &subvol); if (!err) { if (*n >= capacity) { size_t new_capacity; @@ -1704,3 +1797,5 @@ PUBLIC enum btrfs_util_error btrfs_util_deleted_subvolumes_fd(int fd, } return err; } +PUBLIC enum btrfs_util_error btrfs_util_subvolume_list_deleted_fd(int fd, uint64_t **ids, size_t *n) +LIBBTRFSUTIL_ALIAS(btrfs_util_deleted_subvolumes_fd); diff --git a/src/version.h b/src/version.h index a384c391..16aebaca 100644 --- a/src/version.h +++ b/src/version.h @@ -3,5 +3,5 @@ * WHETHER THEY ARE BUILT BY OTHERS OR DURING DEVELOPMENT OR FOR THE * OFFICIAL PARTCLONE RELEASES. */ -#define git_version "c7a22fea1e6786fbe4ee2f01982590d6817689f9" +#define git_version "d67a0d03902fde65962102746b1fa09bf4496033"