mirror of
https://github.com/kdave/btrfs-progs
synced 2024-12-25 15:42:23 +00:00
Revert "libbtrfs: remove the support for fs without uuid tree"
This reverts commit 83ab92512e
.
The commit removed some old code that seemed to be unused but this
actually broke snapper. Revert the changes completely to the v6.3 ABI
level.
Link: https://bugzilla.opensuse.org/show_bug.cgi?id=1212217
Issue: #672
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
7a0da24f52
commit
f9b0da8e78
@ -199,6 +199,73 @@ static int btrfs_read_root_item(int mnt_fd, u64 root_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
|
||||
static struct rb_node *tree_insert(struct rb_root *root,
|
||||
struct subvol_info *si,
|
||||
enum subvol_search_type type)
|
||||
{
|
||||
struct rb_node **p = &root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct subvol_info *entry;
|
||||
__s64 comp;
|
||||
|
||||
while (*p) {
|
||||
parent = *p;
|
||||
if (type == subvol_search_by_received_uuid) {
|
||||
entry = rb_entry(parent, struct subvol_info,
|
||||
rb_received_node);
|
||||
|
||||
comp = memcmp(entry->received_uuid, si->received_uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
if (!comp) {
|
||||
if (entry->stransid < si->stransid)
|
||||
comp = -1;
|
||||
else if (entry->stransid > si->stransid)
|
||||
comp = 1;
|
||||
else
|
||||
comp = 0;
|
||||
}
|
||||
} else if (type == subvol_search_by_uuid) {
|
||||
entry = rb_entry(parent, struct subvol_info,
|
||||
rb_local_node);
|
||||
comp = memcmp(entry->uuid, si->uuid, BTRFS_UUID_SIZE);
|
||||
} else if (type == subvol_search_by_root_id) {
|
||||
entry = rb_entry(parent, struct subvol_info,
|
||||
rb_root_id_node);
|
||||
comp = entry->root_id - si->root_id;
|
||||
} else if (type == subvol_search_by_path) {
|
||||
entry = rb_entry(parent, struct subvol_info,
|
||||
rb_path_node);
|
||||
comp = strcmp(entry->path, si->path);
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (comp < 0)
|
||||
p = &(*p)->rb_left;
|
||||
else if (comp > 0)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return parent;
|
||||
}
|
||||
|
||||
if (type == subvol_search_by_received_uuid) {
|
||||
rb_link_node(&si->rb_received_node, parent, p);
|
||||
rb_insert_color(&si->rb_received_node, root);
|
||||
} else if (type == subvol_search_by_uuid) {
|
||||
rb_link_node(&si->rb_local_node, parent, p);
|
||||
rb_insert_color(&si->rb_local_node, root);
|
||||
} else if (type == subvol_search_by_root_id) {
|
||||
rb_link_node(&si->rb_root_id_node, parent, p);
|
||||
rb_insert_color(&si->rb_root_id_node, root);
|
||||
} else if (type == subvol_search_by_path) {
|
||||
rb_link_node(&si->rb_path_node, parent, p);
|
||||
rb_insert_color(&si->rb_path_node, root);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id)
|
||||
{
|
||||
if (path_len < 1)
|
||||
@ -297,6 +364,116 @@ static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
|
||||
static int count_bytes(void *buf, int len, char b)
|
||||
{
|
||||
int cnt = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (((char *)buf)[i] == b)
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
void subvol_uuid_search_add(struct subvol_uuid_search *s,
|
||||
struct subvol_info *si);
|
||||
void subvol_uuid_search_add(struct subvol_uuid_search *s,
|
||||
struct subvol_info *si)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
tree_insert(&s->root_id_subvols, si, subvol_search_by_root_id);
|
||||
tree_insert(&s->path_subvols, si, subvol_search_by_path);
|
||||
|
||||
cnt = count_bytes(si->uuid, BTRFS_UUID_SIZE, 0);
|
||||
if (cnt != BTRFS_UUID_SIZE)
|
||||
tree_insert(&s->local_subvols, si, subvol_search_by_uuid);
|
||||
cnt = count_bytes(si->received_uuid, BTRFS_UUID_SIZE, 0);
|
||||
if (cnt != BTRFS_UUID_SIZE)
|
||||
tree_insert(&s->received_subvols, si,
|
||||
subvol_search_by_received_uuid);
|
||||
}
|
||||
|
||||
static struct subvol_info *tree_search(struct rb_root *root,
|
||||
u64 root_id, const u8 *uuid,
|
||||
u64 stransid, const char *path,
|
||||
enum subvol_search_type type)
|
||||
{
|
||||
struct rb_node *n = root->rb_node;
|
||||
struct subvol_info *entry;
|
||||
__s64 comp;
|
||||
|
||||
while (n) {
|
||||
if (type == subvol_search_by_received_uuid) {
|
||||
entry = rb_entry(n, struct subvol_info,
|
||||
rb_received_node);
|
||||
comp = memcmp(entry->received_uuid, uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
if (!comp) {
|
||||
if (entry->stransid < stransid)
|
||||
comp = -1;
|
||||
else if (entry->stransid > stransid)
|
||||
comp = 1;
|
||||
else
|
||||
comp = 0;
|
||||
}
|
||||
} else if (type == subvol_search_by_uuid) {
|
||||
entry = rb_entry(n, struct subvol_info, rb_local_node);
|
||||
comp = memcmp(entry->uuid, uuid, BTRFS_UUID_SIZE);
|
||||
} else if (type == subvol_search_by_root_id) {
|
||||
entry = rb_entry(n, struct subvol_info,
|
||||
rb_root_id_node);
|
||||
comp = entry->root_id - root_id;
|
||||
} else if (type == subvol_search_by_path) {
|
||||
entry = rb_entry(n, struct subvol_info, rb_path_node);
|
||||
comp = strcmp(entry->path, path);
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
if (comp < 0)
|
||||
n = n->rb_left;
|
||||
else if (comp > 0)
|
||||
n = n->rb_right;
|
||||
else
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function will be only called if kernel doesn't support uuid tree.
|
||||
*/
|
||||
static struct subvol_info *subvol_uuid_search_old(struct subvol_uuid_search *s,
|
||||
u64 root_id, const u8 *uuid, u64 transid,
|
||||
const char *path,
|
||||
enum subvol_search_type type)
|
||||
{
|
||||
struct rb_root *root;
|
||||
if (type == subvol_search_by_received_uuid)
|
||||
root = &s->received_subvols;
|
||||
else if (type == subvol_search_by_uuid)
|
||||
root = &s->local_subvols;
|
||||
else if (type == subvol_search_by_root_id)
|
||||
root = &s->root_id_subvols;
|
||||
else if (type == subvol_search_by_path)
|
||||
root = &s->path_subvols;
|
||||
else
|
||||
return NULL;
|
||||
return tree_search(root, root_id, uuid, transid, path, type);
|
||||
}
|
||||
#else
|
||||
void subvol_uuid_search_add(struct subvol_uuid_search *s,
|
||||
struct subvol_info *si)
|
||||
{
|
||||
if (si) {
|
||||
free(si->path);
|
||||
free(si);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct subvol_info *subvol_uuid_search2(struct subvol_uuid_search *s,
|
||||
u64 root_id, const u8 *uuid, u64 transid,
|
||||
const char *path,
|
||||
@ -394,6 +571,11 @@ static struct subvol_info *subvol_uuid_search2(struct subvol_uuid_search *s,
|
||||
struct btrfs_root_item root_item;
|
||||
struct subvol_info *info = NULL;
|
||||
|
||||
#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
|
||||
if (!s->uuid_tree_existed)
|
||||
return subvol_uuid_search_old(s, root_id, uuid, transid,
|
||||
path, type);
|
||||
#endif
|
||||
switch (type) {
|
||||
case subvol_search_by_received_uuid:
|
||||
ret = btrfs_uuid_tree_lookup_any(s->mnt_fd, uuid,
|
||||
@ -461,9 +643,219 @@ out:
|
||||
return info;
|
||||
}
|
||||
|
||||
#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
|
||||
static int is_uuid_tree_supported(int fd)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_ioctl_search_args args;
|
||||
struct btrfs_ioctl_search_key *sk = &args.key;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
|
||||
|
||||
sk->min_objectid = BTRFS_UUID_TREE_OBJECTID;
|
||||
sk->max_objectid = BTRFS_UUID_TREE_OBJECTID;
|
||||
sk->max_type = BTRFS_ROOT_ITEM_KEY;
|
||||
sk->min_type = BTRFS_ROOT_ITEM_KEY;
|
||||
sk->max_offset = (u64)-1;
|
||||
sk->max_transid = (u64)-1;
|
||||
sk->nr_items = 1;
|
||||
|
||||
ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* the ioctl returns the number of item it found in nr_items */
|
||||
if (sk->nr_items == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function is mainly used to read all root items
|
||||
* it will be only used when we use older kernel which uuid
|
||||
* tree is not supported yet
|
||||
*/
|
||||
int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_ioctl_search_args args;
|
||||
struct btrfs_ioctl_search_key *sk = &args.key;
|
||||
struct btrfs_ioctl_search_header *sh;
|
||||
struct btrfs_root_item *root_item_ptr;
|
||||
struct btrfs_root_item root_item = {};
|
||||
struct subvol_info *si = NULL;
|
||||
int root_item_valid = 0;
|
||||
unsigned long off = 0;
|
||||
int i;
|
||||
|
||||
s->mnt_fd = mnt_fd;
|
||||
|
||||
s->root_id_subvols = RB_ROOT;
|
||||
s->local_subvols = RB_ROOT;
|
||||
s->received_subvols = RB_ROOT;
|
||||
s->path_subvols = RB_ROOT;
|
||||
|
||||
ret = is_uuid_tree_supported(mnt_fd);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr,
|
||||
"ERROR: check if we support uuid tree fails - %m\n");
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
/* uuid tree is supported */
|
||||
s->uuid_tree_existed = 1;
|
||||
return 0;
|
||||
}
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
|
||||
|
||||
sk->max_objectid = (u64)-1;
|
||||
sk->max_offset = (u64)-1;
|
||||
sk->max_transid = (u64)-1;
|
||||
sk->min_type = BTRFS_ROOT_ITEM_KEY;
|
||||
sk->max_type = BTRFS_ROOT_BACKREF_KEY;
|
||||
sk->nr_items = 4096;
|
||||
|
||||
while (1) {
|
||||
ret = ioctl(mnt_fd, BTRFS_IOC_TREE_SEARCH, &args);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "ERROR: can't perform the search - %m\n");
|
||||
return ret;
|
||||
}
|
||||
if (sk->nr_items == 0)
|
||||
break;
|
||||
|
||||
off = 0;
|
||||
|
||||
for (i = 0; i < sk->nr_items; i++) {
|
||||
sh = (struct btrfs_ioctl_search_header *)(args.buf +
|
||||
off);
|
||||
off += sizeof(*sh);
|
||||
|
||||
if ((btrfs_search_header_objectid(sh) != 5 &&
|
||||
btrfs_search_header_objectid(sh)
|
||||
< BTRFS_FIRST_FREE_OBJECTID) ||
|
||||
btrfs_search_header_objectid(sh)
|
||||
> BTRFS_LAST_FREE_OBJECTID) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (btrfs_search_header_type(sh)
|
||||
== BTRFS_ROOT_ITEM_KEY) {
|
||||
/* older kernels don't have uuids+times */
|
||||
if (btrfs_search_header_len(sh)
|
||||
< sizeof(root_item)) {
|
||||
root_item_valid = 0;
|
||||
goto skip;
|
||||
}
|
||||
root_item_ptr = (struct btrfs_root_item *)
|
||||
(args.buf + off);
|
||||
memcpy(&root_item, root_item_ptr,
|
||||
sizeof(root_item));
|
||||
root_item_valid = 1;
|
||||
} else if (btrfs_search_header_type(sh)
|
||||
== BTRFS_ROOT_BACKREF_KEY ||
|
||||
root_item_valid) {
|
||||
char path_buf[PATH_MAX];
|
||||
char *path;
|
||||
|
||||
if (!root_item_valid)
|
||||
goto skip;
|
||||
|
||||
ret = btrfs_subvolid_resolve(mnt_fd, path_buf,
|
||||
sizeof(path_buf),
|
||||
btrfs_search_header_objectid(sh));
|
||||
if (ret < 0) {
|
||||
errno = -ret;
|
||||
fprintf(stderr, "ERROR: unable to "
|
||||
"resolve path "
|
||||
"for root %llu: %m\n",
|
||||
btrfs_search_header_objectid(sh));
|
||||
goto out;
|
||||
}
|
||||
path = strdup(path_buf);
|
||||
|
||||
si = calloc(1, sizeof(*si));
|
||||
si->root_id = btrfs_search_header_objectid(sh);
|
||||
memcpy(si->uuid, root_item.uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
memcpy(si->parent_uuid, root_item.parent_uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
memcpy(si->received_uuid,
|
||||
root_item.received_uuid,
|
||||
BTRFS_UUID_SIZE);
|
||||
si->ctransid = btrfs_root_ctransid(&root_item);
|
||||
si->otransid = btrfs_root_otransid(&root_item);
|
||||
si->stransid = btrfs_root_stransid(&root_item);
|
||||
si->rtransid = btrfs_root_rtransid(&root_item);
|
||||
si->path = path;
|
||||
subvol_uuid_search_add(s, si);
|
||||
root_item_valid = 0;
|
||||
} else {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
skip:
|
||||
off += btrfs_search_header_len(sh);
|
||||
|
||||
/*
|
||||
* record the mins in sk so we can make sure the
|
||||
* next search doesn't repeat this root
|
||||
*/
|
||||
sk->min_objectid = btrfs_search_header_objectid(sh);
|
||||
sk->min_offset = btrfs_search_header_offset(sh);
|
||||
sk->min_type = btrfs_search_header_type(sh);
|
||||
}
|
||||
sk->nr_items = 4096;
|
||||
if (sk->min_offset < (u64)-1)
|
||||
sk->min_offset++;
|
||||
else if (sk->min_objectid < (u64)-1) {
|
||||
sk->min_objectid++;
|
||||
sk->min_offset = 0;
|
||||
sk->min_type = 0;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void subvol_uuid_search_finit(struct subvol_uuid_search *s);
|
||||
void subvol_uuid_search_finit(struct subvol_uuid_search *s)
|
||||
{
|
||||
struct rb_root *root = &s->root_id_subvols;
|
||||
struct rb_node *node;
|
||||
|
||||
if (!s->uuid_tree_existed)
|
||||
return;
|
||||
|
||||
while ((node = rb_first(root))) {
|
||||
struct subvol_info *entry =
|
||||
rb_entry(node, struct subvol_info, rb_root_id_node);
|
||||
|
||||
free(entry->path);
|
||||
rb_erase(node, root);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
s->root_id_subvols = RB_ROOT;
|
||||
s->local_subvols = RB_ROOT;
|
||||
s->received_subvols = RB_ROOT;
|
||||
s->path_subvols = RB_ROOT;
|
||||
}
|
||||
#else
|
||||
int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s)
|
||||
{
|
||||
s->mnt_fd = mnt_fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void subvol_uuid_search_finit(struct subvol_uuid_search *s)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
@ -35,6 +35,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compatibility code for kernels < 3.12; the UUID tree is not available there
|
||||
* and we have to do the slow search. This should be deprecated someday.
|
||||
*/
|
||||
#define BTRFS_COMPAT_SEND_NO_UUID_TREE 1
|
||||
|
||||
enum subvol_search_type {
|
||||
subvol_search_by_root_id,
|
||||
subvol_search_by_uuid,
|
||||
@ -43,6 +49,12 @@ enum subvol_search_type {
|
||||
};
|
||||
|
||||
struct subvol_info {
|
||||
#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
|
||||
struct rb_node rb_root_id_node;
|
||||
struct rb_node rb_local_node;
|
||||
struct rb_node rb_received_node;
|
||||
struct rb_node rb_path_node;
|
||||
#endif
|
||||
|
||||
u64 root_id;
|
||||
u8 uuid[BTRFS_UUID_SIZE];
|
||||
@ -58,6 +70,14 @@ struct subvol_info {
|
||||
|
||||
struct subvol_uuid_search {
|
||||
int mnt_fd;
|
||||
#ifdef BTRFS_COMPAT_SEND_NO_UUID_TREE
|
||||
int uuid_tree_existed;
|
||||
|
||||
struct rb_root root_id_subvols;
|
||||
struct rb_root local_subvols;
|
||||
struct rb_root received_subvols;
|
||||
struct rb_root path_subvols;
|
||||
#endif
|
||||
};
|
||||
|
||||
int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s);
|
||||
|
Loading…
Reference in New Issue
Block a user