|
@@ -803,6 +803,37 @@ out_unlock:
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Set dentry's directory position based on the current dir's max, and
|
|
|
+ * order it in d_subdirs, so that dcache_readdir behaves.
|
|
|
+ */
|
|
|
+static void ceph_set_dentry_offset(struct dentry *dn)
|
|
|
+{
|
|
|
+ struct dentry *dir = dn->d_parent;
|
|
|
+ struct inode *inode = dn->d_parent->d_inode;
|
|
|
+ struct ceph_dentry_info *di;
|
|
|
+
|
|
|
+ BUG_ON(!inode);
|
|
|
+
|
|
|
+ di = ceph_dentry(dn);
|
|
|
+
|
|
|
+ spin_lock(&inode->i_lock);
|
|
|
+ if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) {
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ di->offset = ceph_inode(inode)->i_max_offset++;
|
|
|
+ spin_unlock(&inode->i_lock);
|
|
|
+
|
|
|
+ spin_lock(&dcache_lock);
|
|
|
+ spin_lock(&dn->d_lock);
|
|
|
+ list_move_tail(&dir->d_subdirs, &dn->d_u.d_child);
|
|
|
+ dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
|
|
|
+ dn->d_u.d_child.prev, dn->d_u.d_child.next);
|
|
|
+ spin_unlock(&dn->d_lock);
|
|
|
+ spin_unlock(&dcache_lock);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* splice a dentry to an inode.
|
|
|
* caller must hold directory i_mutex for this to be safe.
|
|
@@ -816,6 +847,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
|
|
|
{
|
|
|
struct dentry *realdn;
|
|
|
|
|
|
+ BUG_ON(dn->d_inode);
|
|
|
+
|
|
|
/* dn must be unhashed */
|
|
|
if (!d_unhashed(dn))
|
|
|
d_drop(dn);
|
|
@@ -837,47 +870,16 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
|
|
|
dn = realdn;
|
|
|
} else {
|
|
|
BUG_ON(!ceph_dentry(dn));
|
|
|
-
|
|
|
dout("dn %p attached to %p ino %llx.%llx\n",
|
|
|
dn, dn->d_inode, ceph_vinop(dn->d_inode));
|
|
|
}
|
|
|
if ((!prehash || *prehash) && d_unhashed(dn))
|
|
|
d_rehash(dn);
|
|
|
+ ceph_set_dentry_offset(dn);
|
|
|
out:
|
|
|
return dn;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Set dentry's directory position based on the current dir's max, and
|
|
|
- * order it in d_subdirs, so that dcache_readdir behaves.
|
|
|
- */
|
|
|
-static void ceph_set_dentry_offset(struct dentry *dn)
|
|
|
-{
|
|
|
- struct dentry *dir = dn->d_parent;
|
|
|
- struct inode *inode = dn->d_parent->d_inode;
|
|
|
- struct ceph_dentry_info *di;
|
|
|
-
|
|
|
- BUG_ON(!inode);
|
|
|
-
|
|
|
- di = ceph_dentry(dn);
|
|
|
-
|
|
|
- spin_lock(&inode->i_lock);
|
|
|
- if ((ceph_inode(inode)->i_ceph_flags & CEPH_I_COMPLETE) == 0) {
|
|
|
- spin_unlock(&inode->i_lock);
|
|
|
- return;
|
|
|
- }
|
|
|
- di->offset = ceph_inode(inode)->i_max_offset++;
|
|
|
- spin_unlock(&inode->i_lock);
|
|
|
-
|
|
|
- spin_lock(&dcache_lock);
|
|
|
- spin_lock(&dn->d_lock);
|
|
|
- list_move_tail(&dir->d_subdirs, &dn->d_u.d_child);
|
|
|
- dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset,
|
|
|
- dn->d_u.d_child.prev, dn->d_u.d_child.next);
|
|
|
- spin_unlock(&dn->d_lock);
|
|
|
- spin_unlock(&dcache_lock);
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Incorporate results into the local cache. This is either just
|
|
|
* one inode, or a directory, dentry, and possibly linked-to inode (e.g.,
|
|
@@ -1030,6 +1032,9 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
|
|
|
ceph_invalidate_dentry_lease(dn);
|
|
|
|
|
|
/* take overwritten dentry's readdir offset */
|
|
|
+ dout("dn %p gets %p offset %lld (old offset %lld)\n",
|
|
|
+ req->r_old_dentry, dn, ceph_dentry(dn)->offset,
|
|
|
+ ceph_dentry(req->r_old_dentry)->offset);
|
|
|
ceph_dentry(req->r_old_dentry)->offset =
|
|
|
ceph_dentry(dn)->offset;
|
|
|
|
|
@@ -1074,7 +1079,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
|
|
|
goto done;
|
|
|
}
|
|
|
req->r_dentry = dn; /* may have spliced */
|
|
|
- ceph_set_dentry_offset(dn);
|
|
|
igrab(in);
|
|
|
} else if (ceph_ino(in) == vino.ino &&
|
|
|
ceph_snap(in) == vino.snap) {
|
|
@@ -1117,7 +1121,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
|
|
|
err = PTR_ERR(dn);
|
|
|
goto done;
|
|
|
}
|
|
|
- ceph_set_dentry_offset(dn);
|
|
|
req->r_dentry = dn; /* may have spliced */
|
|
|
igrab(in);
|
|
|
rinfo->head->is_dentry = 1; /* fool notrace handlers */
|