diff options
Diffstat (limited to 'fs/nfsd')
-rw-r--r-- | fs/nfsd/export.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfscache.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 16 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 12 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 150 |
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); } |