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
__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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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))
......
......@@ -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 @@ 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,
__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;
......
......@@ -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 {
......
......@@ -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;
......
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