summaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/export.c13
-rw-r--r--fs/nfsd/nfscache.c13
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/nfsfh.c16
-rw-r--r--fs/nfsd/nfsproc.c4
-rw-r--r--fs/nfsd/nfssvc.c12
-rw-r--r--fs/nfsd/vfs.c150
7 files changed, 102 insertions, 107 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index dee52dd8a..df2532048 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -9,8 +9,6 @@
* creates a client control block and adds it to the hash
* table. Then, you call NFSCTL_EXPORT for each fs.
*
- * You cannot currently read the export information from the
- * kernel. It would be nice to have a /proc file though.
*
* Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
*/
@@ -388,12 +386,10 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
err = -EPERM;
if (path) {
- err = 0;
- if (path_init(path, LOOKUP_POSITIVE, &nd))
- err = path_walk(path, &nd);
- if (err) {
+ if (path_init(path, LOOKUP_POSITIVE, &nd) &&
+ path_walk(path, &nd)) {
printk("nfsd: exp_rootfh path not found %s", path);
- return -EPERM;
+ return err;
}
dev = nd.dentry->d_inode->i_dev;
ino = nd.dentry->d_inode->i_ino;
@@ -438,7 +434,8 @@ exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
fh_put(&fh);
out:
- path_release(&nd);
+ if (path)
+ path_release(&nd);
return err;
}
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 357a297f6..f5795583b 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -174,8 +174,9 @@ int
nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
{
struct svc_cacherep *rh, *rp;
- struct svc_client *clp = rqstp->rq_client;
u32 xid = rqstp->rq_xid,
+ proto = rqstp->rq_prot,
+ vers = rqstp->rq_vers,
proc = rqstp->rq_proc;
unsigned long age;
@@ -189,7 +190,9 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
while ((rp = rp->c_hash_next) != rh) {
if (rp->c_state != RC_UNUSED &&
xid == rp->c_xid && proc == rp->c_proc &&
- exp_checkaddr(clp, rp->c_client)) {
+ proto == rp->c_prot && vers == rp->c_vers &&
+ time_before(jiffies, rp->c_timestamp + 120*HZ) &&
+ memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, rqstp->rq_addrlen)==0) {
nfsdstats.rchits++;
goto found_entry;
}
@@ -226,7 +229,11 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
rp->c_state = RC_INPROG;
rp->c_xid = xid;
rp->c_proc = proc;
- rp->c_client = rqstp->rq_addr.sin_addr;
+ rp->c_addr = rqstp->rq_addr;
+ rp->c_prot = proto;
+ rp->c_vers = vers;
+ rp->c_timestamp = jiffies;
+
hash_refile(rp);
/* release any buffer */
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c4e456185..913cbf5f8 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -5,7 +5,6 @@
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
-#define NFS_GETFH_NEW
#include <linux/config.h>
#include <linux/module.h>
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 85a98c874..78f399bd3 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -495,17 +495,15 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
- if (!fhp->fh_dverified) {
+ if (!fhp->fh_dentry) {
kdev_t xdev;
ino_t xino;
__u32 *datap=NULL;
int data_left = fh->fh_size/4;
int nfsdev;
error = nfserr_stale;
-#if CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
error = nfserr_badhandle;
-#endif
if (fh->fh_version == 1) {
datap = fh->fh_auth;
@@ -562,10 +560,8 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
* Look up the dentry using the NFS file handle.
*/
error = nfserr_stale;
-#if CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
error = nfserr_badhandle;
-#endif
if (fh->fh_version == 1) {
/* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
@@ -611,7 +607,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
fhp->fh_dentry = dentry;
fhp->fh_export = exp;
- fhp->fh_dverified = 1;
nfsd_nr_verified++;
} else {
/* just rechecking permissions
@@ -731,7 +726,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
parent->d_name.name, dentry->d_name.name,
(inode ? inode->i_ino : 0));
- if (fhp->fh_dverified || fhp->fh_locked || fhp->fh_dentry) {
+ if (fhp->fh_locked || fhp->fh_dentry) {
printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
parent->d_name.name, dentry->d_name.name);
}
@@ -757,8 +752,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4;
- /* We stuck it there, we know it's good. */
- fhp->fh_dverified = 1;
nfsd_nr_verified++;
if (fhp->fh_handle.fh_fileid_type == 255)
return nfserr_opnotsupp;
@@ -775,7 +768,7 @@ fh_update(struct svc_fh *fhp)
struct dentry *dentry;
__u32 *datap;
- if (!fhp->fh_dverified)
+ if (!fhp->fh_dentry)
goto out_bad;
dentry = fhp->fh_dentry;
@@ -811,10 +804,9 @@ void
fh_put(struct svc_fh *fhp)
{
struct dentry * dentry = fhp->fh_dentry;
- if (fhp->fh_dverified) {
+ if (dentry) {
fh_unlock(fhp);
fhp->fh_dentry = NULL;
- fhp->fh_dverified = 0;
dput(dentry);
nfsd_nr_put++;
}
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 763970736..b5057d57b 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -239,7 +239,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
* whether the file exists or not. Time to bail ...
*/
nfserr = nfserr_acces;
- if (!newfhp->fh_dverified) {
+ if (!newfhp->fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_create: file handle not verified\n");
goto out_unlock;
@@ -415,7 +415,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
dprintk("nfsd: MKDIR %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
- if (resp->fh.fh_dverified) {
+ if (resp->fh.fh_dentry) {
printk(KERN_WARNING
"nfsd_proc_mkdir: response already verified??\n");
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index fb3b32f8d..9a4d12a7d 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -275,7 +275,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
/* Encode result.
* For NFSv2, additional info is never returned in case of an error.
*/
-#ifdef CONFIG_NFSD_V3
if (!(nfserr && rqstp->rq_vers == 2)) {
xdr = proc->pc_encode;
if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
@@ -286,17 +285,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
return 1;
}
}
-#else
- xdr = proc->pc_encode;
- if (!nfserr && xdr
- && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
- /* Failed to encode result. Release cache entry */
- dprintk("nfsd: failed to encode result!\n");
- nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
- *statp = rpc_system_err;
- return 1;
- }
-#endif /* CONFIG_NFSD_V3 */
/* Store reply in cache. */
nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 40f1ab85a..7a144d707 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -165,6 +165,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dentry = mounts;
} else
dput(mounts);
+ mntput(mnt);
}
}
/*
@@ -253,8 +254,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
goto out_nfserr;
err = locks_verify_truncate(inode, NULL, iap->ia_size);
- if (err)
+ if (err) {
+ put_write_access(inode);
goto out_nfserr;
+ }
DQUOT_INIT(inode);
}
@@ -314,11 +317,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap)
if (err)
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export))
- write_inode_now(inode);
+ write_inode_now(inode, 0);
err = 0;
-
- /* Don't unlock inode; the nfssvc_release functions are supposed
- * to do this. */
out:
return err;
@@ -413,7 +413,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access)
out:
return error;
}
-#endif
+#endif /* CONFIG_NFSD_V3 */
@@ -512,7 +512,7 @@ nfsd_sync(struct file *filp)
{
dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
down(&filp->f_dentry->d_inode->i_sem);
- filp->f_op->fsync(filp, filp->f_dentry);
+ filp->f_op->fsync(filp, filp->f_dentry, 0);
up(&filp->f_dentry->d_inode->i_sem);
}
@@ -520,10 +520,10 @@ void
nfsd_sync_dir(struct dentry *dp)
{
struct inode *inode = dp->d_inode;
- int (*fsync) (struct file *, struct dentry *);
+ int (*fsync) (struct file *, struct dentry *, int);
if (inode->i_fop && (fsync = inode->i_fop->fsync)) {
- fsync(NULL, dp);
+ fsync(NULL, dp, 0);
}
}
@@ -598,7 +598,6 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
oldfs = get_fs(); set_fs(KERNEL_DS);
err = file.f_op->read(&file, buf, *count, &file.f_pos);
set_fs(oldfs);
- nfsdstats.io_read += *count;
/* Write back readahead params */
if (ra != NULL) {
@@ -614,6 +613,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
}
if (err >= 0) {
+ nfsdstats.io_read += err;
*count = err;
err = 0;
} else
@@ -665,19 +665,16 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
* When gathered writes have been configured for this volume,
* flushing the data to disk is handled separately below.
*/
-#ifdef CONFIG_NFSD_V3
+
if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */
stable = 2;
*stablep = 2; /* FILE_SYNC */
}
+
if (!EX_ISSYNC(exp))
stable = 0;
if (stable && !EX_WGATHER(exp))
file.f_flags |= O_SYNC;
-#else
- if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
- file.f_flags |= O_SYNC;
-#endif /* CONFIG_NFSD_V3 */
file.f_pos = offset; /* set write offset */
@@ -692,7 +689,8 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
#else
err = file.f_op->write(&file, buf, cnt, &file.f_pos);
#endif
- nfsdstats.io_write += cnt;
+ if (err >= 0)
+ nfsdstats.io_write += cnt;
set_fs(oldfs);
/* clear setuid/setgid flag after write */
@@ -734,7 +732,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
#else
dprintk("nfsd: write defer %d\n", current->pid);
/* FIXME: Olaf commented this out [gam3] */
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((HZ+99)/100);
+ current->state = TASK_RUNNING;
dprintk("nfsd: write resume %d\n", current->pid);
#endif
}
@@ -743,7 +743,9 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
dprintk("nfsd: write sync %d\n", current->pid);
nfsd_sync(&file);
}
+#if 0
wake_up(&inode->i_wait);
+#endif
last_ino = inode->i_ino;
last_dev = inode->i_dev;
}
@@ -762,11 +764,12 @@ out:
#ifdef CONFIG_NFSD_V3
/*
- * Commit all pendig writes to stable storage.
- * Strictly speaking, we could sync just indicated the file region here,
+ * Commit all pending writes to stable storage.
+ * Strictly speaking, we could sync just the indicated file region here,
* but there's currently no way we can ask the VFS to do so.
*
- * We lock the file to make sure we return full WCC data to the client.
+ * Unfortunately we cannot lock the file to make sure we return full WCC
+ * data to the client, as locking happens lower down in the filesystem.
*/
int
nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -828,7 +831,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* Check whether the response file handle has been verified yet.
* If it has, the parent directory should already be locked.
*/
- if (!resfhp->fh_dverified) {
+ if (!resfhp->fh_dentry) {
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
fh_lock(fhp);
dchild = lookup_one(fname, dentry);
@@ -891,7 +894,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (EX_ISSYNC(fhp->fh_export)) {
nfsd_sync_dir(dentry);
- write_inode_now(dchild->d_inode);
+ write_inode_now(dchild->d_inode, 0);
}
@@ -928,6 +931,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct dentry *dentry, *dchild;
struct inode *dirp;
int err;
+ __u32 v_mtime=0, v_atime=0;
+ int v_mode=0;
err = nfserr_perm;
if (!flen)
@@ -963,6 +968,19 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (err)
goto out;
+ if (createmode == NFS3_CREATE_EXCLUSIVE) {
+ /* while the verifier would fit in mtime+atime,
+ * solaris7 gets confused (bugid 4218508) if these have
+ * the high bit set, so we use the mode as well
+ */
+ v_mtime = verifier[0]&0x7fffffff;
+ v_atime = verifier[1]&0x7fffffff;
+ v_mode = S_IFREG
+ | ((verifier[0]&0x80000000) >> (32-7)) /* u+x */
+ | ((verifier[1]&0x80000000) >> (32-9)) /* u+r */
+ ;
+ }
+
if (dchild->d_inode) {
err = 0;
@@ -976,10 +994,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
break;
case NFS3_CREATE_EXCLUSIVE:
- if ( dchild->d_inode->i_mtime == verifier[0]
- && dchild->d_inode->i_atime == verifier[1]
- && dchild->d_inode->i_mode == S_IFREG
- && dchild->d_inode->i_size == 0 )
+ if ( dchild->d_inode->i_mtime == v_mtime
+ && dchild->d_inode->i_atime == v_atime
+ && dchild->d_inode->i_mode == v_mode
+ && dchild->d_inode->i_size == 0 )
break;
/* fallthru */
case NFS3_CREATE_GUARDED:
@@ -1005,19 +1023,23 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out;
if (createmode == NFS3_CREATE_EXCLUSIVE) {
- /* Cram the verifier into atime/mtime */
- iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET;
- iap->ia_mtime = verifier[0];
- iap->ia_atime = verifier[1];
+ /* Cram the verifier into atime/mtime/mode */
+ iap->ia_valid = ATTR_MTIME|ATTR_ATIME
+ | ATTR_MTIME_SET|ATTR_ATIME_SET
+ | ATTR_MODE;
+ iap->ia_mtime = v_mtime;
+ iap->ia_atime = v_atime;
+ iap->ia_mode = v_mode;
}
- /* Set file attributes. Mode has already been set and
- * setting uid/gid works only for root. Irix appears to
- * send along the gid when it tries to implement setgid
- * directories via NFS. Clear out all that cruft.
+ /* Set file attributes.
+ * Mode has already been set but we might need to reset it
+ * for CREATE_EXCLUSIVE
+ * Irix appears to send along the gid when it tries to
+ * implement setgid directories via NFS. Clear out all that cruft.
*/
set_attr:
- if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+ if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0)
err = nfsd_setattr(rqstp, resfhp, iap);
out:
@@ -1118,7 +1140,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
| S_IFLNK;
err = notify_change(dnew, iap);
if (!err && EX_ISSYNC(fhp->fh_export))
- write_inode_now(dentry->d_inode);
+ write_inode_now(dentry->d_inode, 0);
}
}
} else
@@ -1178,7 +1200,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
if (!err) {
if (EX_ISSYNC(ffhp->fh_export)) {
nfsd_sync_dir(ddir);
- write_inode_now(dest);
+ write_inode_now(dest, 0);
}
} else {
if (err == -EXDEV && rqstp->rq_vers == 2)
@@ -1230,7 +1252,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
goto out;
+ /* cannot use fh_lock as we need deadlock protective ordering
+ * so do it by hand */
double_down(&tdir->i_sem, &fdir->i_sem);
+ ffhp->fh_locked = tfhp->fh_locked = 1;
+ fill_pre_wcc(ffhp);
+ fill_pre_wcc(tfhp);
+
odentry = lookup_one(fname, fdentry);
err = PTR_ERR(odentry);
if (IS_ERR(odentry))
@@ -1245,39 +1273,31 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (IS_ERR(ndentry))
goto out_dput_old;
-#ifdef CONFIG_NFSD_V3
- /* Fill in the pre-op attr for the wcc data for both
- * tdir and fdir
- */
- fill_pre_wcc(ffhp);
- fill_pre_wcc(tfhp);
-#endif /* CONFIG_NFSD_V3 */
err = vfs_rename(fdir, odentry, tdir, ndentry);
if (!err && EX_ISSYNC(tfhp->fh_export)) {
nfsd_sync_dir(tdentry);
nfsd_sync_dir(fdentry);
}
-#ifdef CONFIG_NFSD_V3
- /* Fill in the post-op attr for the wcc data for both
- * tdir and fdir
- */
- fill_post_wcc(ffhp);
- fill_post_wcc(tfhp);
-#endif /* CONFIG_NFSD_V3 */
- double_up(&tdir->i_sem, &fdir->i_sem);
dput(ndentry);
-out_dput_old:
+ out_dput_old:
dput(odentry);
+ out_nfserr:
if (err)
- goto out_nfserr;
+ err = nfserrno(err);
+
+ /* we cannot reply on fh_unlock on the two filehandles,
+ * as that would do the wrong thing if the two directories
+ * were the same, so again we do it by hand
+ */
+ fill_post_wcc(ffhp);
+ fill_post_wcc(tfhp);
+ double_up(&tdir->i_sem, &fdir->i_sem);
+ ffhp->fh_locked = tfhp->fh_locked = 0;
+
out:
return err;
-
-out_nfserr:
- err = nfserrno(err);
- goto out;
}
/*
@@ -1320,17 +1340,13 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
err = vfs_rmdir(dirp, rdentry);
}
- fh_unlock(fhp);
-
dput(rdentry);
if (err)
goto out_nfserr;
- if (EX_ISSYNC(fhp->fh_export)) {
- down(&dentry->d_inode->i_sem);
+ if (EX_ISSYNC(fhp->fh_export))
nfsd_sync_dir(dentry);
- up(&dentry->d_inode->i_sem);
- }
+
out:
return err;
@@ -1353,13 +1369,11 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
struct file file;
struct readdir_cd cd;
- err = 0;
- if (offset > ~(u32) 0)
- goto out;
-
err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
if (err)
goto out;
+ if (offset > ~(u32) 0)
+ goto out_close;
err = nfserr_notdir;
if (!file.f_op->readdir)
@@ -1402,11 +1416,9 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
eof = !cd.eob;
if (cd.offset) {
-#ifdef CONFIG_NFSD_V3
if (rqstp->rq_vers == 3)
(void)xdr_encode_hyper(cd.offset, file.f_pos);
else
-#endif /* CONFIG_NFSD_V3 */
*cd.offset = htonl(file.f_pos);
}