Explorar o código

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>
Yan, Zheng %!s(int64=9) %!d(string=hai) anos
pai
achega
a4b7431f39
Modificáronse 1 ficheiros con 23 adicións e 5 borrados
  1. 23 5
      fs/ceph/inode.c

+ 23 - 5
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);
 	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,
 static int ceph_fill_fragtree(struct inode *inode,
 			      struct ceph_frag_tree_head *fragtree,
 			      struct ceph_frag_tree_head *fragtree,
 			      struct ceph_mds_reply_dirfrag *dirinfo)
 			      struct ceph_mds_reply_dirfrag *dirinfo)
 {
 {
 	struct ceph_inode_info *ci = ceph_inode(inode);
 	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;
 	struct rb_node *rb_node;
 	int i;
 	int i;
 	u32 id, nsplits;
 	u32 id, nsplits;
@@ -362,8 +371,12 @@ static int ceph_fill_fragtree(struct inode *inode,
 				break;
 				break;
 			}
 			}
 			rb_node = rb_next(rb_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);
+			}
 			frag = NULL;
 			frag = NULL;
 		}
 		}
 		if (!frag) {
 		if (!frag) {
@@ -373,12 +386,17 @@ static int ceph_fill_fragtree(struct inode *inode,
 		}
 		}
 		frag->split_by = le32_to_cpu(fragtree->splits[i].by);
 		frag->split_by = le32_to_cpu(fragtree->splits[i].by);
 		dout(" frag %x split by %d\n", frag->frag, frag->split_by);
 		dout(" frag %x split by %d\n", frag->frag, frag->split_by);
+		prev_frag = frag;
 	}
 	}
 	while (rb_node) {
 	while (rb_node) {
 		frag = rb_entry(rb_node, struct ceph_inode_frag, node);
 		frag = rb_entry(rb_node, struct ceph_inode_frag, node);
 		rb_node = rb_next(rb_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:
 out_unlock:
 	mutex_unlock(&ci->i_fragtree_mutex);
 	mutex_unlock(&ci->i_fragtree_mutex);