Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 92835
b: refs/heads/master
c: 03550fa
h: refs/heads/master
i:
  92833: aa750a0
  92831: 06cd3bf
v: v3
  • Loading branch information
J. Bruce Fields committed Apr 23, 2008
1 parent ddca0f8 commit ff12129
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 106 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: c3bb257d2d3a1a4e49372b9d74eaebe0fcf110dd
refs/heads/master: 03550fac06c4f0c39a1885d46015c28794413c82
228 changes: 123 additions & 105 deletions trunk/fs/nfsd/nfsfh.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,124 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
return nfserrno(nfsd_setuser(rqstp, exp));
}

/*
* Use the given filehandle to look up the corresponding export and
* dentry. On success, the results are used to set fh_export and
* fh_dentry.
*/
static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp)
{
struct knfsd_fh *fh = &fhp->fh_handle;
struct fid *fid = NULL, sfid;
struct svc_export *exp;
struct dentry *dentry;
int fileid_type;
int data_left = fh->fh_size/4;
__be32 error;

error = nfserr_stale;
if (rqstp->rq_vers > 2)
error = nfserr_badhandle;
if (rqstp->rq_vers == 4 && fh->fh_size == 0)
return nfserr_nofilehandle;

if (fh->fh_version == 1) {
int len;

if (--data_left < 0)
return error;
if (fh->fh_auth_type != 0)
return error;
len = key_len(fh->fh_fsid_type) / 4;
if (len == 0)
return error;
if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
/* deprecated, convert to type 3 */
len = key_len(FSID_ENCODE_DEV)/4;
fh->fh_fsid_type = FSID_ENCODE_DEV;
fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
fh->fh_fsid[1] = fh->fh_fsid[2];
}
data_left -= len;
if (data_left < 0)
return error;
exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_auth);
fid = (struct fid *)(fh->fh_auth + len);
} else {
__u32 tfh[2];
dev_t xdev;
ino_t xino;

if (fh->fh_size != NFS_FHSIZE)
return error;
/* assume old filehandle format */
xdev = old_decode_dev(fh->ofh_xdev);
xino = u32_to_ino_t(fh->ofh_xino);
mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
}

error = nfserr_stale;
if (PTR_ERR(exp) == -ENOENT)
return error;

if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));

error = nfsd_setuser_and_check_port(rqstp, exp);
if (error)
goto out;

/*
* Look up the dentry using the NFS file handle.
*/
error = nfserr_stale;
if (rqstp->rq_vers > 2)
error = nfserr_badhandle;

if (fh->fh_version != 1) {
sfid.i32.ino = fh->ofh_ino;
sfid.i32.gen = fh->ofh_generation;
sfid.i32.parent_ino = fh->ofh_dirino;
fid = &sfid;
data_left = 3;
if (fh->ofh_dirino == 0)
fileid_type = FILEID_INO32_GEN;
else
fileid_type = FILEID_INO32_GEN_PARENT;
} else
fileid_type = fh->fh_fileid_type;

if (fileid_type == FILEID_ROOT)
dentry = dget(exp->ex_path.dentry);
else {
dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
data_left, fileid_type,
nfsd_acceptable, exp);
}
if (dentry == NULL)
goto out;
if (IS_ERR(dentry)) {
if (PTR_ERR(dentry) != -EINVAL)
error = nfserrno(PTR_ERR(dentry));
goto out;
}

if (S_ISDIR(dentry->d_inode->i_mode) &&
(dentry->d_flags & DCACHE_DISCONNECTED)) {
printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
}

fhp->fh_dentry = dentry;
fhp->fh_export = exp;
nfsd_nr_verified++;
return 0;
out:
exp_put(exp);
return error;
}

/*
* Perform sanity checks on the dentry in a client's file handle.
*
Expand All @@ -124,115 +242,18 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp,
__be32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
{
struct knfsd_fh *fh = &fhp->fh_handle;
struct svc_export *exp = NULL;
struct svc_export *exp;
struct dentry *dentry;
__be32 error = 0;
__be32 error;

dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));

if (!fhp->fh_dentry) {
struct fid *fid = NULL, sfid;
int fileid_type;
int data_left = fh->fh_size/4;

error = nfserr_stale;
if (rqstp->rq_vers > 2)
error = nfserr_badhandle;
if (rqstp->rq_vers == 4 && fh->fh_size == 0)
return nfserr_nofilehandle;

if (fh->fh_version == 1) {
int len;
if (--data_left<0) goto out;
switch (fh->fh_auth_type) {
case 0: break;
default: goto out;
}
len = key_len(fh->fh_fsid_type) / 4;
if (len == 0) goto out;
if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
/* deprecated, convert to type 3 */
len = key_len(FSID_ENCODE_DEV)/4;
fh->fh_fsid_type = FSID_ENCODE_DEV;
fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl(fh->fh_fsid[0]), ntohl(fh->fh_fsid[1])));
fh->fh_fsid[1] = fh->fh_fsid[2];
}
if ((data_left -= len)<0) goto out;
exp = rqst_exp_find(rqstp, fh->fh_fsid_type,
fh->fh_auth);
fid = (struct fid *)(fh->fh_auth + len);
} else {
__u32 tfh[2];
dev_t xdev;
ino_t xino;
if (fh->fh_size != NFS_FHSIZE)
goto out;
/* assume old filehandle format */
xdev = old_decode_dev(fh->ofh_xdev);
xino = u32_to_ino_t(fh->ofh_xino);
mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
}

error = nfserr_stale;
if (PTR_ERR(exp) == -ENOENT)
goto out;

if (IS_ERR(exp)) {
error = nfserrno(PTR_ERR(exp));
goto out;
}

error = nfsd_setuser_and_check_port(rqstp, exp);
error = nfsd_set_fh_dentry(rqstp, fhp);
if (error)
goto out;

/*
* Look up the dentry using the NFS file handle.
*/
error = nfserr_stale;
if (rqstp->rq_vers > 2)
error = nfserr_badhandle;

if (fh->fh_version != 1) {
sfid.i32.ino = fh->ofh_ino;
sfid.i32.gen = fh->ofh_generation;
sfid.i32.parent_ino = fh->ofh_dirino;
fid = &sfid;
data_left = 3;
if (fh->ofh_dirino == 0)
fileid_type = FILEID_INO32_GEN;
else
fileid_type = FILEID_INO32_GEN_PARENT;
} else
fileid_type = fh->fh_fileid_type;

if (fileid_type == FILEID_ROOT)
dentry = dget(exp->ex_path.dentry);
else {
dentry = exportfs_decode_fh(exp->ex_path.mnt, fid,
data_left, fileid_type,
nfsd_acceptable, exp);
}
if (dentry == NULL)
goto out;
if (IS_ERR(dentry)) {
if (PTR_ERR(dentry) != -EINVAL)
error = nfserrno(PTR_ERR(dentry));
goto out;
}

if (S_ISDIR(dentry->d_inode->i_mode) &&
(dentry->d_flags & DCACHE_DISCONNECTED)) {
printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
}

fhp->fh_dentry = dentry;
fhp->fh_export = exp;
nfsd_nr_verified++;
cache_get(&exp->h);
dentry = fhp->fh_dentry;
exp = fhp->fh_export;
} else {
/*
* just rechecking permissions
Expand All @@ -242,7 +263,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
dprintk("nfsd: fh_verify - just checking\n");
dentry = fhp->fh_dentry;
exp = fhp->fh_export;
cache_get(&exp->h);
/*
* Set user creds for this exportpoint; necessary even
* in the "just checking" case because this may be a
Expand Down Expand Up @@ -281,8 +301,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
access, ntohl(error));
}
out:
if (exp && !IS_ERR(exp))
exp_put(exp);
if (error == nfserr_stale)
nfsdstats.fh_stale++;
return error;
Expand Down

0 comments on commit ff12129

Please sign in to comment.