From: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
To: Stefan Behrens <sbehrens@giantdisaster.de>
Cc: linux-btrfs@vger.kernel.org,
"dsterba@suse.cz Sterba" <dsterba@suse.cz>,
ablock84@googlemail.com
Subject: Re: [PATCH] Btrfs-progs: make send/receive compatible with older kernels
Date: Thu, 09 Jan 2014 19:56:20 +0800 [thread overview]
Message-ID: <52CE8E64.9000805@cn.fujitsu.com> (raw)
In-Reply-To: <52CE8CDC.6030408@giantdisaster.de>
Hi Stefan,
On 01/09/2014 07:49 PM, Stefan Behrens wrote:
> On Thu, 9 Jan 2014 18:52:38 +0800, Wang Shilong wrote:
>> Some users complaint that with latest btrfs-progs, they will
>> fail to use send/receive. The problem is new tool will try
>> to use uuid tree while it dosen't work on older kernel.
>>
>> Now we first check if we support uuid tree, if not we fall into
>> normal search as previous way.i copy most of codes from Alexander
>> Block's previous codes and did some adjustments to make it work.
>>
>> Signed-off-by: Alexander Block <ablock84@googlemail.com>
>> Signed-off-by: Wang Shilong <wangsl.fnst@cn.fujitsu.com>
>> ---
>> send-utils.c | 352 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>> send-utils.h | 11 ++
>> 2 files changed, 359 insertions(+), 4 deletions(-)
> I'd prefer a printf("Needs kernel 3.12 or better\n") if no UUID tree is
> found. The code that you add will never be tested by anyone and will
> become broken sooner or later.
>
> The new kernel is compatible to old progs and to new progs. But new
> progs require a new kernel and IMO this is normal. A printf is friendly
> enough in this case.
>
> IMHO maintaining compatibility in progs to old kernels should be limited
> to code that is small enough to not cost effort and problems in the future.
Firstly i'd say sorry about that i forgot cc you.
Yeah, both ways are ok for me, Let's wait to see what is other
people's opinions about this. ^_^
Thanks,
Wang
>
>
>> diff --git a/send-utils.c b/send-utils.c
>> index 874f8a5..1772d2c 100644
>> --- a/send-utils.c
>> +++ b/send-utils.c
>> @@ -159,6 +159,71 @@ static int btrfs_read_root_item(int mnt_fd, u64 root_id,
>> return 0;
>> }
>>
>> +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;
>> +}
>> +
>> int btrfs_subvolid_resolve(int fd, char *path, size_t path_len, u64 subvol_id)
>> {
>> if (path_len < 1)
>> @@ -255,13 +320,101 @@ static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len,
>> return 0;
>> }
>>
>> +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)
>> {
>> - if (si) {
>> - free(si->path);
>> - free(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 dosen'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);
>> }
>>
>> struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s,
>> @@ -273,6 +426,9 @@ struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s,
>> struct btrfs_root_item root_item;
>> struct subvol_info *info = NULL;
>>
>> + if (!s->uuid_tree_existed)
>> + return subvol_uuid_search_old(s, root_id, uuid, transid,
>> + path, type);
>> switch (type) {
>> case subvol_search_by_received_uuid:
>> ret = btrfs_lookup_uuid_received_subvol_item(s->mnt_fd, uuid,
>> @@ -325,15 +481,203 @@ out:
>> return info;
>> }
>>
>> +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;
>> + int e;
>> + char *path;
>> +
>> s->mnt_fd = mnt_fd;
>>
>> - return 0;
>> + 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- %s\n",
>> + strerror(errno));
>> + 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);
>> + e = errno;
>> + if (ret < 0) {
>> + fprintf(stderr, "ERROR: can't perform the search- %s\n",
>> + strerror(e));
>> + 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 ((sh->objectid != 5 &&
>> + sh->objectid < BTRFS_FIRST_FREE_OBJECTID) ||
>> + sh->objectid > BTRFS_LAST_FREE_OBJECTID)
>> + goto skip;
>> +
>> + if (sh->type == BTRFS_ROOT_ITEM_KEY) {
>> + /* older kernels don't have uuids+times */
>> + if (sh->len < 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 (sh->type == BTRFS_ROOT_BACKREF_KEY ||
>> + root_item_valid) {
>> + if (!root_item_valid)
>> + goto skip;
>> +
>> + path = btrfs_list_path_for_root(mnt_fd,
>> + sh->objectid);
>> + if (!path)
>> + path = strdup("");
>> + if (IS_ERR(path)) {
>> + ret = PTR_ERR(path);
>> + fprintf(stderr, "ERROR: unable to "
>> + "resolve path "
>> + "for root %llu\n",
>> + sh->objectid);
>> + goto out;
>> + }
>> +
>> + si = calloc(1, sizeof(*si));
>> + si->root_id = sh->objectid;
>> + 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 += sh->len;
>> +
>> + /*
>> + * record the mins in sk so we can make sure the
>> + * next search doesn't repeat this root
>> + */
>> + sk->min_objectid = sh->objectid;
>> + sk->min_offset = sh->offset;
>> + sk->min_type = sh->type;
>> + }
>> + 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)
>> {
>> + 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;
>> }
>>
>> char *path_cat(const char *p1, const char *p2)
>> diff --git a/send-utils.h b/send-utils.h
>> index ed1a40e..943b027 100644
>> --- a/send-utils.h
>> +++ b/send-utils.h
>> @@ -38,6 +38,11 @@ enum subvol_search_type {
>> };
>>
>> struct subvol_info {
>> + 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;
>> +
>> u64 root_id;
>> u8 uuid[BTRFS_UUID_SIZE];
>> u8 parent_uuid[BTRFS_UUID_SIZE];
>> @@ -52,6 +57,12 @@ struct subvol_info {
>>
>> struct subvol_uuid_search {
>> int mnt_fd;
>> + 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;
>> };
>>
>> int subvol_uuid_search_init(int mnt_fd, struct subvol_uuid_search *s);
>>
>
>
next prev parent reply other threads:[~2014-01-09 11:57 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-09 10:52 [PATCH] Btrfs-progs: make send/receive compatible with older kernels Wang Shilong
2014-01-09 11:49 ` Stefan Behrens
2014-01-09 11:56 ` Wang Shilong [this message]
2014-01-09 12:16 ` Hugo Mills
2014-01-09 14:52 ` Chris Mason
2014-01-14 15:27 ` David Sterba
2014-01-18 5:30 ` Wang Shilong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52CE8E64.9000805@cn.fujitsu.com \
--to=wangsl.fnst@cn.fujitsu.com \
--cc=ablock84@googlemail.com \
--cc=dsterba@suse.cz \
--cc=linux-btrfs@vger.kernel.org \
--cc=sbehrens@giantdisaster.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox