From: Josh Durgin <josh.durgin@inktank.com>
To: Alex Elder <elder@inktank.com>
Cc: "ceph-devel@vger.kernel.org" <ceph-devel@vger.kernel.org>
Subject: Re: [PATCH] rbd: simplify __rbd_init_snaps_header()
Date: Tue, 07 Aug 2012 16:27:30 -0700 [thread overview]
Message-ID: <5021A462.2030603@inktank.com> (raw)
In-Reply-To: <502002D4.6070701@inktank.com>
On 08/06/2012 10:45 AM, Alex Elder wrote:
> The purpose of __rbd_init_snaps_header() is to compare a new
> snapshot context with an rbd device's list of existing snapshots.
> It updates the list by adding any new snapshots or removing any
> that are not present in the new snapshot context.
>
> The code as written is a little confusing, because it traverses both
> the existing snapshot list and the set of snapshots in the snapshot
> context in reverse. This was done based on an assumption about
> snapshots that is not true--namely that a duplicate snapshot name
> could cause an error in intepreting things if they were not
> processed in ascending order.
>
> These precautions are not necessary, because:
> - all snapshots are uniquely identified by their snapshot id
> - a new snapshot cannot be created if the rbd device has another
> snapshot with the same name
> (It is furthermore not currently possible to rename a snapshot.)
>
> This patch re-implements __rbd_init_snaps_header() so it passes
> through both the existing snapshot list and the entries in the
> snapshot context in forward order. It still does the same thing
> as before, but I find the logic considerably easier to understand.
>
> By going forward through the names in the snapshot context, there
> is no longer a need for the rbd_prev_snap_name() helper function.
>
> Signed-off-by: Alex Elder <elder@inktank.com>
This is more readable to me as well, but a few nits below. Other than
those, Reviewed-by: Josh Durgin <josh.durgin@inktank.com>
> ---
> drivers/block/rbd.c | 166
> +++++++++++++++++++++++++++-------------------------
> 1 file changed, 88 insertions(+), 78 deletions(-)
>
> Index: b/drivers/block/rbd.c
> ===================================================================
> --- a/drivers/block/rbd.c
> +++ b/drivers/block/rbd.c
> @@ -2066,98 +2066,108 @@ err:
> return ERR_PTR(ret);
> }
>
> +/* These might otherwise belong in <linux/list.h> */
> +
> +/* Return the next list entry, or a null pointer if there are no more */
> +
> +#define list_next_entry(list, head, type, member) \
> + (list_is_last(list, head) ? NULL : list_entry(list, type, member))
> +
This isn't used in this patch, is it used later?
> /*
> - * search for the previous snap in a null delimited string list
> + * Insert a new entry before the given next one in the list. Adjust
> + * the list header if appropriate.
> */
> -const char *rbd_prev_snap_name(const char *name, const char *start)
> +static inline void list_insert(struct list_head *new,
> + struct list_head *next,
> + struct list_head *head)
It looks like list_add_tail(new, next) does what we need in the one
place that uses this.
> {
> - if (name < start + 2)
> - return NULL;
> + struct list_head *prev = next->prev;
>
> - name -= 2;
> - while (*name) {
> - if (name == start)
> - return start;
> - name--;
> - }
> - return name + 1;
> + new->prev = prev;
> + prev->next = new;
> + new->next = next;
> + next->prev = new;
> + if (next == head)
> + head->next = new;
> }
>
> /*
> - * compare the old list of snapshots that we have to what's in the header
> - * and update it accordingly. Note that the header holds the snapshots
> - * in a reverse order (from newest to oldest) and we need to go from
> - * older to new so that we don't get a duplicate snap name when
> - * doing the process (e.g., removed snapshot and recreated a new
> - * one with the same name.
> + * Scan the rbd device's current snapshot list and compare it to the
> + * newly-received snapshot context. Remove any existing snapshots
> + * not present in the new snapshot context. Add a new snapshot for
> + * any snaphots in the snapshot context not in the current list.
> + * And verify there are no changes to snapshots we already know
> + * about.
> + *
> + * Assumes the snapshots in the snapshot context are sorted by
> + * snapshot id, highest id first. (Snapshots in the rbd_dev's list
> + * are also maintained in that order.)
> */
> static int __rbd_init_snaps_header(struct rbd_device *rbd_dev)
> {
> - const char *name, *first_name;
> - int i = rbd_dev->header.total_snaps;
> - struct rbd_snap *snap, *old_snap = NULL;
> - struct list_head *p, *n;
> -
> - first_name = rbd_dev->header.snap_names;
> - name = first_name + rbd_dev->header.snap_names_len;
> -
> - list_for_each_prev_safe(p, n, &rbd_dev->snaps) {
> - u64 cur_id;
> -
> - old_snap = list_entry(p, struct rbd_snap, node);
> -
> - if (i)
> - cur_id = rbd_dev->header.snapc->snaps[i - 1];
> -
> - if (!i || old_snap->id < cur_id) {
> - /*
> - * old_snap->id was skipped, thus was
> - * removed. If this rbd_dev is mapped to
> - * the removed snapshot, record that it no
> - * longer exists, to prevent further I/O.
> - */
> - if (rbd_dev->snap_id == old_snap->id)
> + struct ceph_snap_context * const snapc = rbd_dev->header.snapc;
Putting the const after the type looks odd to me, especially when it's
the opposite on the next line.
> + const u32 snap_count = snapc->num_snaps;
> + char *snap_name = rbd_dev->header.snap_names;
> + struct list_head * const head = &rbd_dev->snaps;
same here
> + struct list_head *links = head->next;
> + u32 index = 0;
> +
> + while (index < snap_count || links != head) {
> + u64 snap_id;
> + struct rbd_snap *snap;
> +
> + snap_id = index < snap_count ? snapc->snaps[index]
> + : CEPH_NOSNAP;
> + snap = links != head ? list_entry(links, struct rbd_snap, node)
> + : NULL;
> + BUG_ON(snap && snap->id == CEPH_NOSNAP);
> +
> + if (snap_id == CEPH_NOSNAP || (snap && snap->id > snap_id)) {
> + struct list_head *next = links->next;
> +
> + /* Existing snapshot not in the new snap context */
> +
> + if (rbd_dev->snap_id == snap->id)
> rbd_dev->snap_exists = false;
> - __rbd_remove_snap_dev(old_snap);
> - continue;
> - }
> - if (old_snap->id == cur_id) {
> - /* we have this snapshot already */
> - i--;
> - name = rbd_prev_snap_name(name, first_name);
> + __rbd_remove_snap_dev(snap);
> +
> + /* Done with this list entry; advance */
> +
> + links = next;
This could just be links = links->next like you have later.
> continue;
> }
> - for (; i > 0;
> - i--, name = rbd_prev_snap_name(name, first_name)) {
> - if (!name) {
> - WARN_ON(1);
> - return -EINVAL;
> - }
> - cur_id = rbd_dev->header.snapc->snaps[i];
> - /* snapshot removal? handle it above */
> - if (cur_id >= old_snap->id)
> - break;
> - /* a new snapshot */
> - snap = __rbd_add_snap_dev(rbd_dev, i - 1, name);
> - if (IS_ERR(snap))
> - return PTR_ERR(snap);
> -
> - /* note that we add it backward so using n and not p */
> - list_add(&snap->node, n);
> - p = &snap->node;
> - }
> - }
> - /* we're done going over the old snap list, just add what's left */
> - for (; i > 0; i--) {
> - name = rbd_prev_snap_name(name, first_name);
> - if (!name) {
> - WARN_ON(1);
> - return -EINVAL;
> +
> + if (!snap || (snap_id != CEPH_NOSNAP && snap->id < snap_id)) {
> + struct rbd_snap *new_snap;
> +
> + /* We haven't seen this snapshot before */
> +
> + new_snap = __rbd_add_snap_dev(rbd_dev, index,
> + snap_name);
> + if (IS_ERR(new_snap))
> + return PTR_ERR(new_snap);
> +
> + /* New goes before existing, or at end of list */
> +
> + if (snap)
> + list_insert(&new_snap->node, &snap->node, head);
> + else
> + list_add(&new_snap->node, head);
> + } else {
> + /* Already have this one */
> +
> + BUG_ON(snap->size != rbd_dev->header.snap_sizes[index]);
> + BUG_ON(strcmp(snap_name, snap->name));
> +
> + /* Done with this list entry; advance */
> +
> + links = links->next;
> }
> - snap = __rbd_add_snap_dev(rbd_dev, i - 1, name);
> - if (IS_ERR(snap))
> - return PTR_ERR(snap);
> - list_add(&snap->node, &rbd_dev->snaps);
> +
> + /* Advance to the next entry in the snapshot context */
> +
> + index++;
> + snap_name += strlen(snap_name) + 1;
> }
>
> return 0;
next prev parent reply other threads:[~2012-08-07 23:27 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-06 17:45 [PATCH] rbd: simplify __rbd_init_snaps_header() Alex Elder
2012-08-07 23:27 ` Josh Durgin [this message]
2012-08-08 1:03 ` Alex Elder
2012-08-08 1:27 ` Alex Elder
2012-08-08 1:29 ` Josh Durgin
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=5021A462.2030603@inktank.com \
--to=josh.durgin@inktank.com \
--cc=ceph-devel@vger.kernel.org \
--cc=elder@inktank.com \
/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