Commit 37dbeea3 authored by Neil Brown's avatar Neil Brown Committed by David S. Miller

[PATCH] kNFSd 12: Change exp_parent to talk directory tree, not hash table.

Currently get_parent (needed to find the exportpoint
above a given dentry) walks the hash table of export points
checking each with is_subdir.  Now it walks up the d_parent
link checking each for membership in the hashtable.

nfsd_lookup currently does that walk too (when crossing
a mountpoint backwards) so the code gets unified.

This approach makes more sense as we move towards a cache
for export information that can be filled on demand.
It also assumes less about the hash table (which will change).
parent 04146816
......@@ -35,8 +35,6 @@
typedef struct svc_client svc_client;
typedef struct svc_export svc_export;
static svc_export * exp_parent(svc_client *clp, struct super_block *sb,
struct dentry *dentry);
static void exp_unexport_all(svc_client *clp);
static void exp_do_unexport(svc_export *unexp);
static svc_client * exp_getclientbyname(char *name);
......@@ -124,24 +122,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
}
/*
* Find the export entry for a given dentry. <gam3@acm.org>
* Find the export entry for a given dentry.
*/
static svc_export *
exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry)
struct svc_export *
exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
{
struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p;
svc_export *exp;
spin_lock(&dcache_lock);
list_for_each(p, head) {
svc_export *exp = list_entry(p, svc_export, ex_hash);
if (is_subdir(dentry, exp->ex_dentry)) {
spin_unlock(&dcache_lock);
return exp;
}
read_lock(&dparent_lock);
exp = exp_get_by_name(clp, mnt, dentry);
while (exp == NULL && dentry != dentry->d_parent) {
dentry = dentry->d_parent;
exp = exp_get_by_name(clp, mnt, dentry);
}
spin_unlock(&dcache_lock);
return NULL;
read_unlock(&dparent_lock);
return exp;
}
/*
......@@ -415,7 +410,7 @@ exp_rootfh(struct svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
path, nd.dentry, clp->cl_ident,
inode->i_sb->s_id, inode->i_ino);
exp = exp_parent(clp, inode->i_sb, nd.dentry);
exp = exp_parent(clp, nd.mnt, nd.dentry);
if (!exp) {
dprintk("nfsd: exp_rootfh export not found.\n");
goto out;
......
......@@ -119,24 +119,24 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
else {
/* checking mountpoint crossing is very different when stepping up */
struct svc_export *exp2 = NULL;
struct dentry *dp, *old;
struct dentry *dp;
struct vfsmount *mnt = mntget(exp->ex_mnt);
dentry = dget(dparent);
while(follow_up(&mnt, &dentry))
;
old = dentry;
read_lock(&dparent_lock);
dp = dentry->d_parent;
for ( ; !exp2 && dp->d_parent != dp; dp=dp->d_parent)
exp2 = exp_get_by_name(exp->ex_client, mnt, dp);
dp = dget(dentry->d_parent);
read_unlock(&dparent_lock);
dput(dentry);
dentry = dp;
exp2 = exp_parent(exp->ex_client, mnt, dentry);
if (!exp2) {
dput(dentry);
dentry = dget(dparent);
} else {
dget(dentry->d_parent);
exp = exp2;
}
read_unlock(&dparent_lock);
dput(old);
mntput(mnt);
}
} else {
......
......@@ -91,6 +91,8 @@ struct svc_export * exp_get_fsid(struct svc_client *clp, int fsid);
struct svc_export * exp_get_by_name(struct svc_client *clp,
struct vfsmount *mnt,
struct dentry *dentry);
struct svc_export * exp_parent(struct svc_client *clp, struct vfsmount *mnt,
struct dentry *dentry);
int exp_rootfh(struct svc_client *,
char *path, struct knfsd_fh *, int maxsize);
int nfserrno(int errno);
......
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