summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2016-05-04 06:05:10 +0300
committerIlya Dryomov <idryomov@gmail.com>2016-05-26 02:15:37 +0300
commita4b7431f39438f415cef1fa28502ec58016686f7 (patch)
tree432bd5da4924ea61b1fa0bcd862361e2f6343c29
parent421721195a68f46a8218c664154076b5b06f5f51 (diff)
downloadlinux-a4b7431f39438f415cef1fa28502ec58016686f7.tar.xz
ceph: keep leaf frag when updating fragtree
Nodes in i_fragtree are sorted according to ceph_compare_frag(). It means frag node in i_fragtree always follow its direct parent node. To check if a leaf node is valid, we just need to check if it's child of previous split node. Signed-off-by: Yan, Zheng <zyan@redhat.com>
-rw-r--r--fs/ceph/inode.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 562f57d15f46..09713f32ea88 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -310,12 +310,21 @@ static int frag_tree_split_cmp(const void *l, const void *r)
return ceph_frag_compare(ls->frag, rs->frag);
}
+static bool is_frag_child(u32 f, struct ceph_inode_frag *frag)
+{
+ if (!frag)
+ return f == ceph_frag_make(0, 0);
+ if (ceph_frag_bits(f) != ceph_frag_bits(frag->frag) + frag->split_by)
+ return false;
+ return ceph_frag_contains_value(frag->frag, ceph_frag_value(f));
+}
+
static int ceph_fill_fragtree(struct inode *inode,
struct ceph_frag_tree_head *fragtree,
struct ceph_mds_reply_dirfrag *dirinfo)
{
struct ceph_inode_info *ci = ceph_inode(inode);
- struct ceph_inode_frag *frag;
+ struct ceph_inode_frag *frag, *prev_frag = NULL;
struct rb_node *rb_node;
int i;
u32 id, nsplits;
@@ -362,8 +371,12 @@ static int ceph_fill_fragtree(struct inode *inode,
break;
}
rb_node = rb_next(rb_node);
- rb_erase(&frag->node, &ci->i_fragtree);
- kfree(frag);
+ /* delete stale split/leaf node */
+ if (frag->split_by > 0 ||
+ !is_frag_child(frag->frag, prev_frag)) {
+ rb_erase(&frag->node, &ci->i_fragtree);
+ kfree(frag);
+ }
frag = NULL;
}
if (!frag) {
@@ -373,12 +386,17 @@ static int ceph_fill_fragtree(struct inode *inode,
}
frag->split_by = le32_to_cpu(fragtree->splits[i].by);
dout(" frag %x split by %d\n", frag->frag, frag->split_by);
+ prev_frag = frag;
}
while (rb_node) {
frag = rb_entry(rb_node, struct ceph_inode_frag, node);
rb_node = rb_next(rb_node);
- rb_erase(&frag->node, &ci->i_fragtree);
- kfree(frag);
+ /* delete stale split/leaf node */
+ if (frag->split_by > 0 ||
+ !is_frag_child(frag->frag, prev_frag)) {
+ rb_erase(&frag->node, &ci->i_fragtree);
+ kfree(frag);
+ }
}
out_unlock:
mutex_unlock(&ci->i_fragtree_mutex);