Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Viro <viro@math.psu.edu>2002-02-24 22:09:16 -0800
committerLinus Torvalds <torvalds@penguin.transmeta.com>2002-02-24 22:09:16 -0800
commitfa476ac69516ef31ea054121bdf0cefd394fc15f (patch)
tree91228e22cb2c35c496d539b68b00b09c717a90a2
parent5e37545cf526580b165d3805652f241324a850ac (diff)
[PATCH] final ->d_parent fixes
OK, here's ->d_parent stuff unrelated to printk. Looking into printk right now...
-rw-r--r--fs/ncpfs/dir.c11
-rw-r--r--fs/nfs/dir.c8
-rw-r--r--fs/nfsd/export.c12
-rw-r--r--fs/nfsd/nfs3xdr.c10
-rw-r--r--fs/nfsd/nfsfh.c19
-rw-r--r--fs/nfsd/vfs.c18
-rw-r--r--fs/udf/dir.c2
7 files changed, 59 insertions, 21 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 61dd8ff82f77..feb133caae26 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -257,12 +257,18 @@ static int
__ncp_lookup_validate(struct dentry * dentry, int flags)
{
struct ncp_server *server;
- struct inode *dir = dentry->d_parent->d_inode;
+ struct dentry *parent;
+ struct inode *dir;
struct ncp_entry_info finfo;
int res, val = 0, len = dentry->d_name.len + 1;
__u8 __name[len];
- if (!dentry->d_inode || !dir)
+ read_lock(&dparent_lock);
+ parent = dget(dentry->d_parent);
+ read_unlock(&dparent_lock);
+ dir = parent->d_inode;
+
+ if (!dentry->d_inode)
goto finished;
server = NCP_SERVER(dir);
@@ -313,6 +319,7 @@ __ncp_lookup_validate(struct dentry * dentry, int flags)
finished:
DDPRINTK("ncp_lookup_validate: result=%d\n", val);
+ dput(parent);
return val;
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 4aa917a0f86a..55fddf9d1149 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -467,12 +467,16 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{
struct inode *dir;
struct inode *inode;
+ struct dentry *parent;
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
+ read_lock(&dparent_lock);
+ parent = dget(dentry->d_parent);
+ read_unlock(&dparent_lock);
lock_kernel();
- dir = dentry->d_parent->d_inode;
+ dir = parent->d_inode;
inode = dentry->d_inode;
if (!inode) {
@@ -508,6 +512,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
nfs_renew_times(dentry);
out_valid:
unlock_kernel();
+ dput(parent);
return 1;
out_bad:
NFS_CACHEINV(dir);
@@ -521,6 +526,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
}
d_drop(dentry);
unlock_kernel();
+ dput(parent);
return 0;
}
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 346d961bb297..6961ba4011fa 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -112,11 +112,15 @@ exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry)
struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p;
+ 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))
+ if (is_subdir(dentry, exp->ex_dentry)) {
+ spin_unlock(&dcache_lock);
return exp;
+ }
}
+ spin_unlock(&dcache_lock);
return NULL;
}
@@ -132,12 +136,16 @@ exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry)
struct list_head *p;
struct dentry *ndentry;
+ spin_lock(&dcache_lock);
list_for_each(p, head) {
svc_export *exp = list_entry(p, svc_export, ex_hash);
ndentry = exp->ex_dentry;
- if (ndentry && is_subdir(ndentry->d_parent, dentry))
+ if (ndentry && is_subdir(ndentry->d_parent, dentry)) {
+ spin_unlock(&dcache_lock);
return exp;
+ }
}
+ spin_unlock(&dcache_lock);
return NULL;
}
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 710132891d6e..b60c4f504dcb 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -699,10 +699,12 @@ encode_entry(struct readdir_cd *cd, const char *name,
fh_init(&fh, NFS3_FHSIZE);
if (isdotent(name, namlen)) {
- dchild = dparent;
- if (namlen == 2)
- dchild = dchild->d_parent;
- dchild = dget(dchild);
+ if (namlen == 2) {
+ read_lock(&dparent_lock);
+ dchild = dget(dparent->d_parent);
+ read_unlock(&dparent_lock);
+ } else
+ dchild = dget(dparent);
} else
dchild = lookup_one_len(name, dparent,namlen);
if (IS_ERR(dchild))
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index eaa328f37eae..301c167f97a6 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -477,6 +477,11 @@ find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int fhtype, int ne
/* Something wrong. We need to drop the whole dentry->result path
* whatever it was
*/
+ /*
+ * FIXME: the loop below will do Bad Things(tm) if
+ * dentry (or one of its ancestors) become attached
+ * to the tree (e.g. due to VFAT-style alias handling)
+ */
struct dentry *d;
for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent)
d_drop(d);
@@ -610,7 +615,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
dentry = dget(exp->ex_dentry);
break;
default:
- dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+ dentry = find_fh_dentry(exp->ex_dentry->d_sb,
datap, data_left, fh->fh_fileid_type,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
}
@@ -619,7 +624,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
tfh[0] = fh->ofh_ino;
tfh[1] = fh->ofh_generation;
tfh[2] = fh->ofh_dirino;
- dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+ dentry = find_fh_dentry(exp->ex_dentry->d_sb,
tfh, 3, fh->ofh_dirino?2:1,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
}
@@ -676,11 +681,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
if (exp->ex_dentry != dentry) {
struct dentry *tdentry = dentry;
+ spin_lock(&dcache_lock);
do {
tdentry = tdentry->d_parent;
if (exp->ex_dentry == tdentry)
break;
/* executable only by root and we can't be root */
+ /*
+ * FIXME: permissions check is not that simple
+ */
if (current->fsuid
&& (exp->ex_flags & NFSEXP_ROOTSQUASH)
&& !(tdentry->d_inode->i_uid
@@ -700,8 +709,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
printk("nfsd Security: %s/%s bad export.\n",
dentry->d_parent->d_name.name,
dentry->d_name.name);
+ spin_unlock(&dcache_lock);
goto out;
}
+ spin_unlock(&dcache_lock);
}
}
@@ -729,7 +740,7 @@ out:
inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
__u32 *datap, int *maxsize)
{
- struct super_block *sb = dentry->d_inode->i_sb;
+ struct super_block *sb = dentry->d_sb;
if (dentry == exp->ex_dentry) {
*maxsize = 0;
@@ -806,7 +817,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
if (ref_fh &&
ref_fh->fh_handle.fh_version == 0xca &&
- parent->d_inode->i_sb->s_op->dentry_to_fh == NULL) {
+ dentry->d_sb->s_op->dentry_to_fh == NULL) {
/* old style filehandle please */
memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
fhp->fh_handle.fh_size = NFS_FHSIZE;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 92852049f121..2ff38d02efd2 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -114,29 +114,33 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (isdotent(name, len)) {
if (len==1)
dentry = dget(dparent);
- else if (dparent != exp->ex_dentry)
+ else if (dparent != exp->ex_dentry) {
+ read_lock(&dparent_lock);
dentry = dget(dparent->d_parent);
- else if (!EX_CROSSMNT(exp))
+ read_unlock(&dparent_lock);
+ } else if (!EX_CROSSMNT(exp))
dentry = dget(dparent); /* .. == . just like at / */
else {
/* checking mountpoint crossing is very different when stepping up */
struct svc_export *exp2 = NULL;
- struct dentry *dp;
+ struct dentry *dp, *old;
struct vfsmount *mnt = mntget(exp->ex_mnt);
dentry = dget(dparent);
while(follow_up(&mnt, &dentry))
;
- dp = dget(dentry->d_parent);
- dput(dentry);
- dentry = dp;
+ 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);
if (!exp2) {
- dput(dentry);
dentry = dget(dparent);
} else {
+ dget(dentry->d_parent);
exp = exp2;
}
+ read_unlock(&dparent_lock);
+ dput(old);
mntput(mnt);
}
} else {
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index f1dd42b3c63a..91a6b64f0d1f 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -224,7 +224,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if ( cfi.fileCharacteristics & FILE_PARENT )
{
- iblock = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(filp->f_dentry->d_parent->d_inode), 0);
+ iblock = parent_ino(filp->f_dentry);
flen = 2;
memcpy(fname, "..", flen);
dt_type = DT_DIR;