Ejemplo n.º 1
0
/* 
 * Called from nfsd_lookup and encode_dirent. Check if we have crossed 
 * a mount point.
 * Returns -EAGAIN or -ETIMEDOUT leaving *dpp and *expp unchanged,
 *  or nfs_ok having possibly changed *dpp and *expp
 */
int
nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, 
		        struct svc_export **expp)
{
	struct svc_export *exp = *expp, *exp2 = NULL;
	struct dentry *dentry = *dpp;
	struct vfsmount *mnt = mntget(exp->ex_path.mnt);
	struct dentry *mounts = dget(dentry);
	int err = 0;

	while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));

	exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
	if (IS_ERR(exp2)) {
		if (PTR_ERR(exp2) != -ENOENT)
			err = PTR_ERR(exp2);
		dput(mounts);
		mntput(mnt);
		goto out;
	}
	if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
		/* successfully crossed mount point */
		exp_put(exp);
		*expp = exp2;
		dput(dentry);
		*dpp = mounts;
	} else {
		exp_put(exp2);
		dput(mounts);
	}
	mntput(mnt);
out:
	return err;
}
Ejemplo n.º 2
0
__be32
nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
		   const char *name, unsigned int len,
		   struct svc_export **exp_ret, struct dentry **dentry_ret)
{
	struct svc_export	*exp;
	struct dentry		*dparent;
	struct dentry		*dentry;
	__be32			err;
	int			host_err;

	dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);

	/* Obtain dentry and export. */
	err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
	if (err)
		return err;

	dparent = fhp->fh_dentry;
	exp  = fhp->fh_export;
	exp_get(exp);

	/* Lookup the name, but don't follow links */
	if (isdotent(name, len)) {
		if (len==1)
			dentry = dget(dparent);
		else if (dparent != exp->ex_path.dentry)
			dentry = dget_parent(dparent);
		else if (!EX_NOHIDE(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 vfsmount *mnt = mntget(exp->ex_path.mnt);
			dentry = dget(dparent);
			while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry))
				;
			dp = dget_parent(dentry);
			dput(dentry);
			dentry = dp;

			exp2 = rqst_exp_parent(rqstp, mnt, dentry);
			if (PTR_ERR(exp2) == -ENOENT) {
				dput(dentry);
				dentry = dget(dparent);
			} else if (IS_ERR(exp2)) {
				host_err = PTR_ERR(exp2);
				dput(dentry);
				mntput(mnt);
				goto out_nfserr;
			} else {
				exp_put(exp);
				exp = exp2;
			}
			mntput(mnt);
		}
	} else {
		fh_lock(fhp);
		dentry = lookup_one_len(name, dparent, len);
		host_err = PTR_ERR(dentry);
		if (IS_ERR(dentry))
			goto out_nfserr;
		/*
		 * check if we have crossed a mount point ...
		 */
		if (d_mountpoint(dentry)) {
			if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
				dput(dentry);
				goto out_nfserr;
			}
		}
	}
	*dentry_ret = dentry;
	*exp_ret = exp;
	return 0;

out_nfserr:
	exp_put(exp);
	return nfserrno(host_err);
}
Ejemplo n.º 3
0
/*
 * Look up one component of a pathname.
 * N.B. After this call _both_ fhp and resfh need an fh_put
 *
 * If the lookup would cross a mountpoint, and the mounted filesystem
 * is exported to the client with NFSEXP_NOHIDE, then the lookup is
 * accepted as it stands and the mounted directory is
 * returned. Otherwise the covered directory is returned.
 * NOTE: this mountpoint crossing is not supported properly by all
 *   clients and is explicitly disallowed for NFSv3
 *      NeilBrown <*****@*****.**>
 */
int
nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
					int len, struct svc_fh *resfh)
{
	struct svc_export	*exp;
	struct dentry		*dparent;
	struct dentry		*dentry;
	int			err;

	dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);

	/* Obtain dentry and export. */
	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
	if (err)
		return err;

	dparent = fhp->fh_dentry;
	exp  = fhp->fh_export;
	exp_get(exp);

	err = nfserr_acces;

	/* Lookup the name, but don't follow links */
	if (isdotent(name, len)) {
		if (len==1)
			dentry = dget(dparent);
		else if (dparent != exp->ex_dentry) {
			dentry = dget_parent(dparent);
		} else  if (!EX_NOHIDE(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 vfsmount *mnt = mntget(exp->ex_mnt);
			dentry = dget(dparent);
			while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry))
				;
			dp = dget_parent(dentry);
			dput(dentry);
			dentry = dp;

			exp2 = exp_parent(exp->ex_client, mnt, dentry,
					  &rqstp->rq_chandle);
			if (IS_ERR(exp2)) {
				err = PTR_ERR(exp2);
				dput(dentry);
				mntput(mnt);
				goto out_nfserr;
			}
			if (!exp2) {
				dput(dentry);
				dentry = dget(dparent);
			} else {
				exp_put(exp);
				exp = exp2;
			}
			mntput(mnt);
		}
	} else {
		fh_lock(fhp);
		dentry = lookup_one_len(name, dparent, len);
		err = PTR_ERR(dentry);
		if (IS_ERR(dentry))
			goto out_nfserr;
		/*
		 * check if we have crossed a mount point ...
		 */
		if (d_mountpoint(dentry)) {
			if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
				dput(dentry);
				goto out_nfserr;
			}
		}
	}
	/*
	 * Note: we compose the file handle now, but as the
	 * dentry may be negative, it may need to be updated.
	 */
	err = fh_compose(resfh, exp, dentry, fhp);
	if (!err && !dentry->d_inode)
		err = nfserr_noent;
	dput(dentry);
out:
	exp_put(exp);
	return err;

out_nfserr:
	err = nfserrno(err);
	goto out;
}
Ejemplo n.º 4
0
/*
 * Look up one component of a pathname.
 * N.B. After this call _both_ fhp and resfh need an fh_put
 *
 * If the lookup would cross a mountpoint, and the mounted filesystem
 * is exported to the client with NFSEXP_NOHIDE, then the lookup is
 * accepted as it stands and the mounted directory is
 * returned. Otherwise the covered directory is returned.
 * NOTE: this mountpoint crossing is not supported properly by all
 *   clients and is explicitly disallowed for NFSv3
 *      NeilBrown <*****@*****.**>
 */
int
nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
					int len, struct svc_fh *resfh)
{
	struct svc_export	*exp;
	struct dentry		*dparent;
	struct dentry		*dentry;
	int			err;

	dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);

	/* Obtain dentry and export. */
	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_EXEC);
	if (err)
		goto out;

	dparent = fhp->fh_dentry;
	exp  = fhp->fh_export;

	err = nfserr_acces;

	/* Lookup the name, but don't follow links */
	if (isdotent(name, len)) {
		if (len==1)
			dentry = dget(dparent);
		else if (dparent != exp->ex_dentry)
			dentry = dget(dparent->d_parent);
		else if (!EX_NOHIDE(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 vfsmount *mnt = mntget(exp->ex_mnt);
			dentry = dget(dparent);
			while(follow_up(&mnt, &dentry))
				;
			dp = dget(dentry->d_parent);
			dput(dentry);
			dentry = dp;
			for ( ; exp2 == NULL && dp->d_parent != dp;
			      dp=dp->d_parent)
				exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
			if (exp2==NULL) {
				dput(dentry);
				dentry = dget(dparent);
			} else {
				exp = exp2;
			}
			mntput(mnt);
		}
	} else {
		fh_lock(fhp);
		dentry = lookup_one_len(name, dparent, len);
		err = PTR_ERR(dentry);
		if (IS_ERR(dentry))
			goto out_nfserr;
		/*
		 * check if we have crossed a mount point ...
		 */
		if (d_mountpoint(dentry)) {
			struct svc_export *exp2 = NULL;
			struct vfsmount *mnt = mntget(exp->ex_mnt);
			struct dentry *mounts = dget(dentry);
			while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts))
				;
			exp2 = exp_get(rqstp->rq_client,
				       mounts->d_inode->i_dev,
				       mounts->d_inode->i_ino);
			if (exp2 && EX_NOHIDE(exp2)) {
				/* successfully crossed mount point */
				exp = exp2;
				dput(dentry);
				dentry = mounts;
			} else
				dput(mounts);
			mntput(mnt);
		}
	}

	if (dentry->d_inode && dentry->d_inode->i_op &&
	    dentry->d_inode->i_op->revalidate &&
	    dentry->d_inode->i_op->revalidate(dentry))
		err = nfserr_noent;
	else
		err = fh_compose(resfh, exp, dentry, fhp);
	if (!err && !dentry->d_inode)
		err = nfserr_noent;
out:
	return err;

out_nfserr:
	err = nfserrno(err);
	goto out;
}