ceph: don't assume frag tree splits in mds reply are sorted
authorYan, Zheng <zyan@redhat.com>
Tue, 3 May 2016 12:55:50 +0000 (20:55 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Wed, 25 May 2016 23:15:37 +0000 (01:15 +0200)
The algorithm that updates i_fragtree relies on that the frag tree
splits in mds reply are of the same order of i_fragtree. This is not
true because current MDS encodes frag tree splits in ascending order
of (unsigned)frag_t. But nodes in i_fragtree are sorted according to
ceph_frag_compare().

The fix is sort the frag tree splits first, then updates i_fragtree.

Signed-off-by: Yan, Zheng <zyan@redhat.com>
fs/ceph/inode.c

index 4889aaa72accb2c4d0ed752babff73ff0a95df9f..d91eb6b492593d214e96ab8481576ead864f76dc 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/vmalloc.h>
 #include <linux/posix_acl.h>
 #include <linux/random.h>
+#include <linux/sort.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -299,6 +300,13 @@ out:
        return err;
 }
 
+static int frag_tree_split_cmp(const void *l, const void *r)
+{
+       struct ceph_frag_tree_split *ls = (struct ceph_frag_tree_split*)l;
+       struct ceph_frag_tree_split *rs = (struct ceph_frag_tree_split*)r;
+       return ceph_frag_compare(ls->frag, rs->frag);
+}
+
 static int ceph_fill_fragtree(struct inode *inode,
                              struct ceph_frag_tree_head *fragtree,
                              struct ceph_mds_reply_dirfrag *dirinfo)
@@ -331,6 +339,11 @@ static int ceph_fill_fragtree(struct inode *inode,
        if (!update)
                goto out_unlock;
 
+       if (nsplits > 1) {
+               sort(fragtree->splits, nsplits, sizeof(fragtree->splits[0]),
+                    frag_tree_split_cmp, NULL);
+       }
+
        dout("fill_fragtree %llx.%llx\n", ceph_vinop(inode));
        rb_node = rb_first(&ci->i_fragtree);
        for (i = 0; i < nsplits; i++) {