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: Sage Weil <sage@newdream.net>
This commit is contained in:
Родитель
1b7facc41b
Коммит
1cd3935bed
|
@ -128,7 +128,8 @@ more:
|
|||
dentry = list_entry(p, struct dentry, d_u.d_child);
|
||||
di = ceph_dentry(dentry);
|
||||
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);
|
||||
if (p == &parent->d_subdirs) {
|
||||
fi->at_end = 1;
|
||||
|
@ -571,7 +572,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
|||
!is_root_ceph_dentry(dir, dentry) &&
|
||||
(ci->i_ceph_flags & CEPH_I_COMPLETE) &&
|
||||
(__ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1))) {
|
||||
di->offset = ci->i_max_offset++;
|
||||
spin_unlock(&dir->i_lock);
|
||||
dout(" dir %p complete, -ENOENT\n", dir);
|
||||
d_add(dentry, NULL);
|
||||
|
@ -984,8 +984,9 @@ static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
{
|
||||
struct inode *dir = dentry->d_parent->d_inode;
|
||||
|
||||
dout("d_revalidate %p '%.*s' inode %p\n", dentry,
|
||||
dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
|
||||
dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
|
||||
dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
|
||||
ceph_dentry(dentry)->offset);
|
||||
|
||||
/* always trust cached snapped dentries, snapdir dentry */
|
||||
if (ceph_snap(dir) != CEPH_NOSNAP) {
|
||||
|
@ -1177,8 +1178,8 @@ void ceph_dentry_lru_touch(struct dentry *dn)
|
|||
struct ceph_dentry_info *di = ceph_dentry(dn);
|
||||
struct ceph_mds_client *mdsc;
|
||||
|
||||
dout("dentry_lru_touch %p %p '%.*s'\n", di, dn,
|
||||
dn->d_name.len, dn->d_name.name);
|
||||
dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
|
||||
dn->d_name.len, dn->d_name.name, di->offset);
|
||||
if (di) {
|
||||
mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
|
||||
spin_lock(&mdsc->dentry_lru_lock);
|
||||
|
|
|
@ -803,50 +803,6 @@ out_unlock:
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* splice a dentry to an inode.
|
||||
* caller must hold directory i_mutex for this to be safe.
|
||||
*
|
||||
* we will only rehash the resulting dentry if @prehash is
|
||||
* true; @prehash will be set to false (for the benefit of
|
||||
* the caller) if we fail.
|
||||
*/
|
||||
static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
|
||||
bool *prehash)
|
||||
{
|
||||
struct dentry *realdn;
|
||||
|
||||
/* dn must be unhashed */
|
||||
if (!d_unhashed(dn))
|
||||
d_drop(dn);
|
||||
realdn = d_materialise_unique(dn, in);
|
||||
if (IS_ERR(realdn)) {
|
||||
pr_err("splice_dentry error %p inode %p ino %llx.%llx\n",
|
||||
dn, in, ceph_vinop(in));
|
||||
if (prehash)
|
||||
*prehash = false; /* don't rehash on error */
|
||||
dn = realdn; /* note realdn contains the error */
|
||||
goto out;
|
||||
} else if (realdn) {
|
||||
dout("dn %p (%d) spliced with %p (%d) "
|
||||
"inode %p ino %llx.%llx\n",
|
||||
dn, atomic_read(&dn->d_count),
|
||||
realdn, atomic_read(&realdn->d_count),
|
||||
realdn->d_inode, ceph_vinop(realdn->d_inode));
|
||||
dput(dn);
|
||||
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);
|
||||
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.
|
||||
|
@ -878,6 +834,52 @@ static void ceph_set_dentry_offset(struct dentry *dn)
|
|||
spin_unlock(&dcache_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* splice a dentry to an inode.
|
||||
* caller must hold directory i_mutex for this to be safe.
|
||||
*
|
||||
* we will only rehash the resulting dentry if @prehash is
|
||||
* true; @prehash will be set to false (for the benefit of
|
||||
* the caller) if we fail.
|
||||
*/
|
||||
static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
|
||||
bool *prehash)
|
||||
{
|
||||
struct dentry *realdn;
|
||||
|
||||
BUG_ON(dn->d_inode);
|
||||
|
||||
/* dn must be unhashed */
|
||||
if (!d_unhashed(dn))
|
||||
d_drop(dn);
|
||||
realdn = d_materialise_unique(dn, in);
|
||||
if (IS_ERR(realdn)) {
|
||||
pr_err("splice_dentry error %p inode %p ino %llx.%llx\n",
|
||||
dn, in, ceph_vinop(in));
|
||||
if (prehash)
|
||||
*prehash = false; /* don't rehash on error */
|
||||
dn = realdn; /* note realdn contains the error */
|
||||
goto out;
|
||||
} else if (realdn) {
|
||||
dout("dn %p (%d) spliced with %p (%d) "
|
||||
"inode %p ino %llx.%llx\n",
|
||||
dn, atomic_read(&dn->d_count),
|
||||
realdn, atomic_read(&realdn->d_count),
|
||||
realdn->d_inode, ceph_vinop(realdn->d_inode));
|
||||
dput(dn);
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
|
Загрузка…
Ссылка в новой задаче