Commit fa476ac6 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] final ->d_parent fixes

OK, here's ->d_parent stuff unrelated to printk.  Looking into printk
right now...
parent 5e37545c
...@@ -257,12 +257,18 @@ static int ...@@ -257,12 +257,18 @@ static int
__ncp_lookup_validate(struct dentry * dentry, int flags) __ncp_lookup_validate(struct dentry * dentry, int flags)
{ {
struct ncp_server *server; struct ncp_server *server;
struct inode *dir = dentry->d_parent->d_inode; struct dentry *parent;
struct inode *dir;
struct ncp_entry_info finfo; struct ncp_entry_info finfo;
int res, val = 0, len = dentry->d_name.len + 1; int res, val = 0, len = dentry->d_name.len + 1;
__u8 __name[len]; __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; goto finished;
server = NCP_SERVER(dir); server = NCP_SERVER(dir);
...@@ -313,6 +319,7 @@ __ncp_lookup_validate(struct dentry * dentry, int flags) ...@@ -313,6 +319,7 @@ __ncp_lookup_validate(struct dentry * dentry, int flags)
finished: finished:
DDPRINTK("ncp_lookup_validate: result=%d\n", val); DDPRINTK("ncp_lookup_validate: result=%d\n", val);
dput(parent);
return val; return val;
} }
......
...@@ -467,12 +467,16 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) ...@@ -467,12 +467,16 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
{ {
struct inode *dir; struct inode *dir;
struct inode *inode; struct inode *inode;
struct dentry *parent;
int error; int error;
struct nfs_fh fhandle; struct nfs_fh fhandle;
struct nfs_fattr fattr; struct nfs_fattr fattr;
read_lock(&dparent_lock);
parent = dget(dentry->d_parent);
read_unlock(&dparent_lock);
lock_kernel(); lock_kernel();
dir = dentry->d_parent->d_inode; dir = parent->d_inode;
inode = dentry->d_inode; inode = dentry->d_inode;
if (!inode) { if (!inode) {
...@@ -508,6 +512,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) ...@@ -508,6 +512,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
nfs_renew_times(dentry); nfs_renew_times(dentry);
out_valid: out_valid:
unlock_kernel(); unlock_kernel();
dput(parent);
return 1; return 1;
out_bad: out_bad:
NFS_CACHEINV(dir); NFS_CACHEINV(dir);
...@@ -521,6 +526,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags) ...@@ -521,6 +526,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
} }
d_drop(dentry); d_drop(dentry);
unlock_kernel(); unlock_kernel();
dput(parent);
return 0; return 0;
} }
......
...@@ -112,11 +112,15 @@ exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry) ...@@ -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 *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p; struct list_head *p;
spin_lock(&dcache_lock);
list_for_each(p, head) { list_for_each(p, head) {
svc_export *exp = list_entry(p, svc_export, ex_hash); 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; return exp;
}
} }
spin_unlock(&dcache_lock);
return NULL; return NULL;
} }
...@@ -132,12 +136,16 @@ exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry) ...@@ -132,12 +136,16 @@ exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry)
struct list_head *p; struct list_head *p;
struct dentry *ndentry; struct dentry *ndentry;
spin_lock(&dcache_lock);
list_for_each(p, head) { list_for_each(p, head) {
svc_export *exp = list_entry(p, svc_export, ex_hash); svc_export *exp = list_entry(p, svc_export, ex_hash);
ndentry = exp->ex_dentry; 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; return exp;
}
} }
spin_unlock(&dcache_lock);
return NULL; return NULL;
} }
......
...@@ -699,10 +699,12 @@ encode_entry(struct readdir_cd *cd, const char *name, ...@@ -699,10 +699,12 @@ encode_entry(struct readdir_cd *cd, const char *name,
fh_init(&fh, NFS3_FHSIZE); fh_init(&fh, NFS3_FHSIZE);
if (isdotent(name, namlen)) { if (isdotent(name, namlen)) {
dchild = dparent; if (namlen == 2) {
if (namlen == 2) read_lock(&dparent_lock);
dchild = dchild->d_parent; dchild = dget(dparent->d_parent);
dchild = dget(dchild); read_unlock(&dparent_lock);
} else
dchild = dget(dparent);
} else } else
dchild = lookup_one_len(name, dparent,namlen); dchild = lookup_one_len(name, dparent,namlen);
if (IS_ERR(dchild)) if (IS_ERR(dchild))
......
...@@ -477,6 +477,11 @@ find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int fhtype, int ne ...@@ -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 /* Something wrong. We need to drop the whole dentry->result path
* whatever it was * 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; struct dentry *d;
for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent) for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent)
d_drop(d); d_drop(d);
...@@ -610,7 +615,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -610,7 +615,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
dentry = dget(exp->ex_dentry); dentry = dget(exp->ex_dentry);
break; break;
default: 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, datap, data_left, fh->fh_fileid_type,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
} }
...@@ -619,7 +624,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -619,7 +624,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
tfh[0] = fh->ofh_ino; tfh[0] = fh->ofh_ino;
tfh[1] = fh->ofh_generation; tfh[1] = fh->ofh_generation;
tfh[2] = fh->ofh_dirino; 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, tfh, 3, fh->ofh_dirino?2:1,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
} }
...@@ -676,11 +681,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -676,11 +681,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
if (exp->ex_dentry != dentry) { if (exp->ex_dentry != dentry) {
struct dentry *tdentry = dentry; struct dentry *tdentry = dentry;
spin_lock(&dcache_lock);
do { do {
tdentry = tdentry->d_parent; tdentry = tdentry->d_parent;
if (exp->ex_dentry == tdentry) if (exp->ex_dentry == tdentry)
break; break;
/* executable only by root and we can't be root */ /* executable only by root and we can't be root */
/*
* FIXME: permissions check is not that simple
*/
if (current->fsuid if (current->fsuid
&& (exp->ex_flags & NFSEXP_ROOTSQUASH) && (exp->ex_flags & NFSEXP_ROOTSQUASH)
&& !(tdentry->d_inode->i_uid && !(tdentry->d_inode->i_uid
...@@ -700,8 +709,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -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", printk("nfsd Security: %s/%s bad export.\n",
dentry->d_parent->d_name.name, dentry->d_parent->d_name.name,
dentry->d_name.name); dentry->d_name.name);
spin_unlock(&dcache_lock);
goto out; goto out;
} }
spin_unlock(&dcache_lock);
} }
} }
...@@ -729,7 +740,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) ...@@ -729,7 +740,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
inline int _fh_update(struct dentry *dentry, struct svc_export *exp, inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
__u32 *datap, int *maxsize) __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) { if (dentry == exp->ex_dentry) {
*maxsize = 0; *maxsize = 0;
...@@ -806,7 +817,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st ...@@ -806,7 +817,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
if (ref_fh && if (ref_fh &&
ref_fh->fh_handle.fh_version == 0xca && 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 */ /* old style filehandle please */
memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
fhp->fh_handle.fh_size = NFS_FHSIZE; fhp->fh_handle.fh_size = NFS_FHSIZE;
......
...@@ -114,29 +114,33 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, ...@@ -114,29 +114,33 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
if (isdotent(name, len)) { if (isdotent(name, len)) {
if (len==1) if (len==1)
dentry = dget(dparent); dentry = dget(dparent);
else if (dparent != exp->ex_dentry) else if (dparent != exp->ex_dentry) {
read_lock(&dparent_lock);
dentry = dget(dparent->d_parent); 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 / */ dentry = dget(dparent); /* .. == . just like at / */
else { else {
/* checking mountpoint crossing is very different when stepping up */ /* checking mountpoint crossing is very different when stepping up */
struct svc_export *exp2 = NULL; struct svc_export *exp2 = NULL;
struct dentry *dp; struct dentry *dp, *old;
struct vfsmount *mnt = mntget(exp->ex_mnt); struct vfsmount *mnt = mntget(exp->ex_mnt);
dentry = dget(dparent); dentry = dget(dparent);
while(follow_up(&mnt, &dentry)) while(follow_up(&mnt, &dentry))
; ;
dp = dget(dentry->d_parent); old = dentry;
dput(dentry); read_lock(&dparent_lock);
dentry = dp; dp = dentry->d_parent;
for ( ; !exp2 && dp->d_parent != dp; dp=dp->d_parent) for ( ; !exp2 && dp->d_parent != dp; dp=dp->d_parent)
exp2 = exp_get_by_name(exp->ex_client, mnt, dp); exp2 = exp_get_by_name(exp->ex_client, mnt, dp);
if (!exp2) { if (!exp2) {
dput(dentry);
dentry = dget(dparent); dentry = dget(dparent);
} else { } else {
dget(dentry->d_parent);
exp = exp2; exp = exp2;
} }
read_unlock(&dparent_lock);
dput(old);
mntput(mnt); mntput(mnt);
} }
} else { } else {
......
...@@ -224,7 +224,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d ...@@ -224,7 +224,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if ( cfi.fileCharacteristics & FILE_PARENT ) 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; flen = 2;
memcpy(fname, "..", flen); memcpy(fname, "..", flen);
dt_type = DT_DIR; dt_type = DT_DIR;
......
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