#include <linux/nfsd/nfsd.h>
#define NFSDDBG_FACILITY NFSDDBG_FH
-#define NFSD_PARANOIA 1
-/* #define NFSD_DEBUG_VERBOSE 1 */
static int nfsd_nr_verified;
* if not, require that we can walk up to exp->ex_dentry
* doing some checks on the 'x' bits
*/
-int nfsd_acceptable(void *expv, struct dentry *dentry)
+static int nfsd_acceptable(void *expv, struct dentry *dentry)
{
struct svc_export *exp = expv;
int rv;
return rv;
}
+/* Type check. The correct error return for type mismatches does not seem to be
+ * generally agreed upon. SunOS seems to use EISDIR if file isn't S_IFREG; a
+ * comment in the NFSv3 spec says this is incorrect (implementation notes for
+ * the write call).
+ */
+static inline __be32
+nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
+{
+ /* Type can be negative when creating hardlinks - not to a dir */
+ if (type > 0 && (mode & S_IFMT) != type) {
+ if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK)
+ return nfserr_symlink;
+ else if (type == S_IFDIR)
+ return nfserr_notdir;
+ else if ((mode & S_IFMT) == S_IFDIR)
+ return nfserr_isdir;
+ else
+ return nfserr_inval;
+ }
+ if (type < 0 && (mode & S_IFMT) == -type) {
+ if (rqstp->rq_vers == 4 && (mode & S_IFMT) == S_IFLNK)
+ return nfserr_symlink;
+ else if (type == -S_IFDIR)
+ return nfserr_isdir;
+ else
+ return nfserr_notdir;
+ }
+ return 0;
+}
/*
* Perform sanity checks on the dentry in a client's file handle.
* This is only called at the start of an nfsproc call, so fhp points to
* a svc_fh which is all 0 except for the over-the-wire file handle.
*/
-u32
+__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 dentry *dentry;
- struct inode *inode;
- u32 error = 0;
+ __be32 error = 0;
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
exp = exp_find(rqstp->rq_client, 0, tfh, &rqstp->rq_chandle);
}
- error = nfserr_dropit;
- if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
+ if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
+ || PTR_ERR(exp) == -ETIMEDOUT)) {
+ error = nfserrno(PTR_ERR(exp));
goto out;
+ }
error = nfserr_stale;
if (!exp || IS_ERR(exp))
error = nfserr_perm;
if (!rqstp->rq_secure && EX_SECURE(exp)) {
printk(KERN_WARNING
- "nfsd: request from insecure port (%08x:%d)!\n",
- ntohl(rqstp->rq_addr.sin_addr.s_addr),
+ "nfsd: request from insecure port (%u.%u.%u.%u:%d)!\n",
+ NIPQUAD(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port));
goto out;
}
/* Set user creds for this exportpoint */
- error = nfsd_setuser(rqstp, exp);
- if (error) {
- error = nfserrno(error);
+ error = nfserrno(nfsd_setuser(rqstp, exp));
+ if (error)
goto out;
- }
/*
* Look up the dentry using the NFS file handle.
dentry = dget(exp->ex_dentry);
else {
struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
- dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb,
- datap, data_left,
- fileid_type,
- nfsd_acceptable, exp);
+ dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb,
+ datap, data_left,
+ fileid_type,
+ nfsd_acceptable, exp);
}
if (dentry == NULL)
goto out;
error = nfserrno(PTR_ERR(dentry));
goto out;
}
-#ifdef NFSD_PARANOIA
+
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);
}
-#endif
fhp->fh_dentry = dentry;
fhp->fh_export = exp;
dprintk("nfsd: fh_verify - just checking\n");
dentry = fhp->fh_dentry;
exp = fhp->fh_export;
+ /* Set user creds for this exportpoint; necessary even
+ * in the "just checking" case because this may be a
+ * filehandle that was created by fh_compose, and that
+ * is about to be used in another nfsv4 compound
+ * operation */
+ error = nfserrno(nfsd_setuser(rqstp, exp));
+ if (error)
+ goto out;
}
cache_get(&exp->h);
- inode = dentry->d_inode;
-
-
- /* Type check. The correct error return for type mismatches
- * does not seem to be generally agreed upon. SunOS seems to
- * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
- * spec says this is incorrect (implementation notes for the
- * write call).
- */
- /* Type can be negative when creating hardlinks - not to a dir */
- if (type > 0 && (inode->i_mode & S_IFMT) != type) {
- if (rqstp->rq_vers == 4 && (inode->i_mode & S_IFMT) == S_IFLNK)
- error = nfserr_symlink;
- else if (type == S_IFDIR)
- error = nfserr_notdir;
- else if ((inode->i_mode & S_IFMT) == S_IFDIR)
- error = nfserr_isdir;
- else
- error = nfserr_inval;
- goto out;
- }
- if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
- if (rqstp->rq_vers == 4 && (inode->i_mode & S_IFMT) == S_IFLNK)
- error = nfserr_symlink;
- else if (type == -S_IFDIR)
- error = nfserr_isdir;
- else
- error = nfserr_notdir;
+ error = nfsd_mode_check(rqstp, dentry->d_inode->i_mode, type);
+ if (error)
goto out;
- }
/* Finally, check access permissions. */
error = nfsd_permission(exp, dentry, access);
-#ifdef NFSD_PARANOIA_EXTREME
if (error) {
- printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
- dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
+ dprintk("fh_verify: %s/%s permission failure, "
+ "acc=%x, error=%d\n",
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name,
+ access, ntohl(error));
}
-#endif
out:
if (exp && !IS_ERR(exp))
exp_put(exp);
* an inode. In this case a call to fh_update should be made
* before the fh goes out on the wire ...
*/
-inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
- __u32 *datap, int *maxsize)
+static inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
+ __u32 *datap, int *maxsize)
{
struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
/*
* for composing old style file handles
*/
-inline void _fh_update_old(struct dentry *dentry, struct svc_export *exp,
- struct knfsd_fh *fh)
+static inline void _fh_update_old(struct dentry *dentry,
+ struct svc_export *exp,
+ struct knfsd_fh *fh)
{
fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino);
fh->ofh_generation = dentry->d_inode->i_generation;
fh->ofh_dirino = 0;
}
-int
+__be32
fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh)
{
/* ref_fh is a reference file handle.
- * if it is non-null, then we should compose a filehandle which is
- * of the same version, where possible.
+ * if it is non-null and for the same filesystem, then we should compose
+ * a filehandle which is of the same version, where possible.
* Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
* Then create a 32byte filehandle using nfs_fhbase_old
*
parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0));
- if (ref_fh) {
+ if (ref_fh && ref_fh->fh_export == exp) {
ref_fh_version = ref_fh->fh_handle.fh_version;
if (ref_fh_version == 0xca)
ref_fh_fsid_type = 0;
ref_fh_fsid_type = ref_fh->fh_handle.fh_fsid_type;
if (ref_fh_fsid_type > 3)
ref_fh_fsid_type = 0;
- }
- /* make sure ref_fh type works for given export */
- if (ref_fh_fsid_type == 1 &&
- !(exp->ex_flags & NFSEXP_FSID)) {
- /* if we don't have an fsid, we cannot provide one... */
- ref_fh_fsid_type = 0;
- }
+
+ /* make sure ref_fh type works for given export */
+ if (ref_fh_fsid_type == 1 &&
+ !(exp->ex_flags & NFSEXP_FSID)) {
+ /* if we don't have an fsid, we cannot provide one... */
+ ref_fh_fsid_type = 0;
+ }
+ } else if (exp->ex_flags & NFSEXP_FSID)
+ ref_fh_fsid_type = 1;
+
if (!old_valid_dev(ex_dev) && ref_fh_fsid_type == 0) {
/* for newer device numbers, we must use a newer fsid format */
ref_fh_version = 1;
* Update file handle information after changing a dentry.
* This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
*/
-int
+__be32
fh_update(struct svc_fh *fhp)
{
struct dentry *dentry;
} else {
int size;
if (fhp->fh_handle.fh_fileid_type != 0)
- goto out_uptodate;
+ goto out;
datap = fhp->fh_handle.fh_auth+
fhp->fh_handle.fh_size/4 -1;
size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
printk(KERN_ERR "fh_update: %s/%s still negative!\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
goto out;
-out_uptodate:
- printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
- dentry->d_parent->d_name.name, dentry->d_name.name);
- goto out;
}
/*
nfsd_nr_put++;
}
if (exp) {
- svc_export_put(&exp->h, &svc_export_cache);
+ cache_put(&exp->h, &svc_export_cache);
fhp->fh_export = NULL;
}
return;