Commit 1cd3935b authored by Sage Weil's avatar Sage Weil

ceph: set dn offset when spliced

We want to assign an offset when the dentry goes from null to linked, which
is always done by splice_dentry().  Notably, we should NOT assign an
offset when a dentry is first created and is still null.

BUG if we try to splice a non-null dentry (we shouldn't).
Signed-off-by: default avatarSage Weil <sage@newdream.net>
parent 1b7facc4
...@@ -128,7 +128,8 @@ static int __dcache_readdir(struct file *filp, ...@@ -128,7 +128,8 @@ static int __dcache_readdir(struct file *filp,
dentry = list_entry(p, struct dentry, d_u.d_child); dentry = list_entry(p, struct dentry, d_u.d_child);
di = ceph_dentry(dentry); di = ceph_dentry(dentry);
while (1) { while (1) {
dout(" p %p/%p d_subdirs %p/%p\n", p->prev, p->next, dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
d_unhashed(dentry) ? "!hashed" : "hashed",
parent->d_subdirs.prev, parent->d_subdirs.next); parent->d_subdirs.prev, parent->d_subdirs.next);
if (p == &parent->d_subdirs) { if (p == &parent->d_subdirs) {
fi->at_end = 1; fi->at_end = 1;
...@@ -571,7 +572,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry, ...@@ -571,7 +572,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
!is_root_ceph_dentry(dir, dentry) && !is_root_ceph_dentry(dir, dentry) &&
(ci->i_ceph_flags & CEPH_I_COMPLETE) && (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
(__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) { (__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
di->offset = ci->i_max_offset++;
spin_unlock(&dir->i_lock); spin_unlock(&dir->i_lock);
dout(" dir %p complete, -ENOENT\n", dir); dout(" dir %p complete, -ENOENT\n", dir);
d_add(dentry, NULL); d_add(dentry, NULL);
...@@ -984,8 +984,9 @@ static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -984,8 +984,9 @@ static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
struct inode *dir = dentry->d_parent->d_inode; struct inode *dir = dentry->d_parent->d_inode;
dout("d_revalidate %p '%.*s' inode %p\n", dentry, dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
dentry->d_name.len, dentry->d_name.name, dentry->d_inode); dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
ceph_dentry(dentry)->offset);
/* always trust cached snapped dentries, snapdir dentry */ /* always trust cached snapped dentries, snapdir dentry */
if (ceph_snap(dir) != CEPH_NOSNAP) { if (ceph_snap(dir) != CEPH_NOSNAP) {
...@@ -1177,8 +1178,8 @@ void ceph_dentry_lru_touch(struct dentry *dn) ...@@ -1177,8 +1178,8 @@ void ceph_dentry_lru_touch(struct dentry *dn)
struct ceph_dentry_info *di = ceph_dentry(dn); struct ceph_dentry_info *di = ceph_dentry(dn);
struct ceph_mds_client *mdsc; struct ceph_mds_client *mdsc;
dout("dentry_lru_touch %p %p '%.*s'\n", di, dn, dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
dn->d_name.len, dn->d_name.name); dn->d_name.len, dn->d_name.name, di->offset);
if (di) { if (di) {
mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc; mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
spin_lock(&mdsc->dentry_lru_lock); spin_lock(&mdsc->dentry_lru_lock);
......
...@@ -803,6 +803,37 @@ static void update_dentry_lease(struct dentry *dentry, ...@@ -803,6 +803,37 @@ static void update_dentry_lease(struct dentry *dentry,
return; 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. * splice a dentry to an inode.
* caller must hold directory i_mutex for this to be safe. * 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, ...@@ -816,6 +847,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
{ {
struct dentry *realdn; struct dentry *realdn;
BUG_ON(dn->d_inode);
/* dn must be unhashed */ /* dn must be unhashed */
if (!d_unhashed(dn)) if (!d_unhashed(dn))
d_drop(dn); d_drop(dn);
...@@ -837,47 +870,16 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, ...@@ -837,47 +870,16 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
dn = realdn; dn = realdn;
} else { } else {
BUG_ON(!ceph_dentry(dn)); BUG_ON(!ceph_dentry(dn));
dout("dn %p attached to %p ino %llx.%llx\n", dout("dn %p attached to %p ino %llx.%llx\n",
dn, dn->d_inode, ceph_vinop(dn->d_inode)); dn, dn->d_inode, ceph_vinop(dn->d_inode));
} }
if ((!prehash || *prehash) && d_unhashed(dn)) if ((!prehash || *prehash) && d_unhashed(dn))
d_rehash(dn); d_rehash(dn);
ceph_set_dentry_offset(dn);
out: out:
return dn; 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 * Incorporate results into the local cache. This is either just
* one inode, or a directory, dentry, and possibly linked-to inode (e.g., * 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, ...@@ -1030,6 +1032,9 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
ceph_invalidate_dentry_lease(dn); ceph_invalidate_dentry_lease(dn);
/* take overwritten dentry's readdir offset */ /* 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(req->r_old_dentry)->offset =
ceph_dentry(dn)->offset; ceph_dentry(dn)->offset;
...@@ -1074,7 +1079,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, ...@@ -1074,7 +1079,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
goto done; goto done;
} }
req->r_dentry = dn; /* may have spliced */ req->r_dentry = dn; /* may have spliced */
ceph_set_dentry_offset(dn);
igrab(in); igrab(in);
} else if (ceph_ino(in) == vino.ino && } else if (ceph_ino(in) == vino.ino &&
ceph_snap(in) == vino.snap) { ceph_snap(in) == vino.snap) {
...@@ -1117,7 +1121,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, ...@@ -1117,7 +1121,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
err = PTR_ERR(dn); err = PTR_ERR(dn);
goto done; goto done;
} }
ceph_set_dentry_offset(dn);
req->r_dentry = dn; /* may have spliced */ req->r_dentry = dn; /* may have spliced */
igrab(in); igrab(in);
rinfo->head->is_dentry = 1; /* fool notrace handlers */ rinfo->head->is_dentry = 1; /* fool notrace handlers */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment