Commit acb977dc authored by Linus Torvalds's avatar Linus Torvalds

Merge home.transmeta.com:/home/torvalds/v2.5/knfsd

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 222099f6 c0d68f59
......@@ -430,12 +430,13 @@ struct dentry *fat_fh_to_dentry(struct super_block *sb, __u32 *fh,
struct dentry *result;
if (fhtype != 3)
return NULL;
return ERR_PTR(-ESTALE);
if (len < 5)
return NULL;
if (parent)
return NULL; /* We cannot find the parent,
return ERR_PTR(-ESTALE);
/* We cannot find the parent,
It better just *be* there */
if (parent)
return ERR_PTR(-ESTALE);
inode = iget(sb, fh[0]);
if (!inode || is_bad_inode(inode) ||
......
......@@ -3,7 +3,7 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* table of configured filesystems
* nfsservctl system-call when nfsd is not compiled in.
*/
#include <linux/config.h>
......@@ -14,28 +14,28 @@
#include <linux/nfsd/interface.h>
#include <linux/linkage.h>
#if defined(CONFIG_NFSD_MODULE)
struct nfsd_linkage *nfsd_linkage = NULL;
#if ! defined(CONFIG_NFSD)
struct nfsd_linkage *nfsd_linkage;
long
asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp)
{
int ret = -ENOSYS;
#if defined(CONFIG_MODULES)
lock_kernel();
if (nfsd_linkage ||
(request_module ("nfsd") == 0 && nfsd_linkage))
(request_module ("nfsd") == 0 && nfsd_linkage)) {
__MOD_INC_USE_COUNT(nfsd_linkage->owner);
unlock_kernel();
ret = nfsd_linkage->do_nfsservctl(cmd, argp, resp);
__MOD_DEC_USE_COUNT(nfsd_linkage->owner);
} else
unlock_kernel();
#endif
return ret;
}
EXPORT_SYMBOL(nfsd_linkage);
#elif ! defined (CONFIG_NFSD)
asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp)
{
return -ENOSYS;
}
#endif /* CONFIG_NFSD */
......@@ -59,7 +59,6 @@ struct svc_clnthash {
};
static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX];
static svc_client * clients;
static int initialized;
static int hash_lock;
static int want_lock;
......@@ -73,18 +72,17 @@ svc_export *
exp_get(svc_client *clp, kdev_t dev, ino_t ino)
{
struct list_head *head, *p;
svc_export *exp = NULL;
if (!clp)
return NULL;
head = &clp->cl_export[EXPORT_HASH(dev)];
list_for_each(p, head) {
exp = list_entry(p, svc_export, ex_hash);
svc_export *exp = list_entry(p, svc_export, ex_hash);
if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev))
break;
}
return exp;
}
return NULL;
}
svc_export *
......@@ -92,18 +90,17 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry)
{
struct list_head *head, *p;
int hash = EXPORT_HASH(mnt->mnt_sb->s_dev);
svc_export *exp = NULL;
if (!clp)
return NULL;
head = &clp->cl_export[hash];
list_for_each(p, head) {
exp = list_entry(p, svc_export, ex_hash);
svc_export *exp = list_entry(p, svc_export, ex_hash);
if (exp->ex_dentry == dentry && exp->ex_mnt == mnt)
break;
}
return exp;
return NULL;
}
/*
......@@ -114,14 +111,13 @@ exp_parent(svc_client *clp, struct super_block *sb, struct dentry *dentry)
{
struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p;
svc_export *exp = NULL;
list_for_each(p, head) {
exp = list_entry(p, svc_export, ex_hash);
svc_export *exp = list_entry(p, svc_export, ex_hash);
if (is_subdir(dentry, exp->ex_dentry))
break;
}
return exp;
}
return NULL;
}
/*
......@@ -134,16 +130,15 @@ exp_child(svc_client *clp, struct super_block *sb, struct dentry *dentry)
{
struct list_head *head = &clp->cl_export[EXPORT_HASH(sb->s_dev)];
struct list_head *p;
svc_export *exp = NULL;
struct dentry *ndentry;
list_for_each(p, head) {
exp = list_entry(p, svc_export, ex_hash);
svc_export *exp = list_entry(p, svc_export, ex_hash);
ndentry = exp->ex_dentry;
if (ndentry && is_subdir(ndentry->d_parent, dentry))
break;
}
return exp;
}
return NULL;
}
/* Update parent pointers of all exports */
......@@ -477,9 +472,6 @@ exp_getclient(struct sockaddr_in *sin)
struct svc_clnthash **hp, **head, *tmp;
unsigned long addr = sin->sin_addr.s_addr;
if (!initialized)
return NULL;
head = &clnt_hash[CLIENT_HASH(addr)];
for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
......@@ -552,9 +544,10 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
if (p == (void *)1)
clp = clients;
else if (exp->ex_list.next == &exp->ex_client->cl_list)
else if (exp->ex_list.next == &exp->ex_client->cl_list) {
clp = exp->ex_client->cl_next;
else {
*pos += 1LL<<32;
} else {
++*pos;
return list_entry(exp->ex_list.next, svc_export, ex_list);
}
......@@ -875,13 +868,11 @@ nfsd_export_init(void)
int i;
dprintk("nfsd: initializing export module.\n");
if (initialized)
return;
for (i = 0; i < CLIENT_HASHMAX; i++)
clnt_hash[i] = NULL;
clients = NULL;
initialized = 1;
}
/*
......@@ -893,8 +884,7 @@ nfsd_export_shutdown(void)
int i;
dprintk("nfsd: shutting down export module.\n");
if (!initialized)
return;
if (exp_writelock() < 0) {
printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
return;
......
......@@ -339,7 +339,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
|| (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV)
|| argp->minor > 0xFF)
RETURN_STATUS(nfserr_inval);
rdev = ((argp->major) << 8) | (argp->minor);
rdev = MKDEV(argp->major, argp->minor);
} else
if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
RETURN_STATUS(nfserr_inval);
......
......@@ -44,8 +44,6 @@ static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
#endif
static int initialized;
extern struct seq_operations nfs_exports_op;
static int exports_open(struct inode *inode, struct file *file)
{
......@@ -68,20 +66,6 @@ void proc_export_init(void)
entry->proc_fops = &exports_operations;
}
/*
* Initialize nfsd
*/
static void
nfsd_init(void)
{
nfsd_stat_init(); /* Statistics */
nfsd_cache_init(); /* RPC reply cache */
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
proc_export_init();
initialized = 1;
}
static inline int
nfsctl_svc(struct nfsctl_svc *data)
{
......@@ -203,10 +187,8 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
int err;
int argsize, respsize;
MOD_INC_USE_COUNT;
lock_kernel ();
if (!initialized)
nfsd_init();
err = -EPERM;
if (!capable(CAP_SYS_ADMIN)) {
goto done;
......@@ -276,38 +258,47 @@ asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
kfree(res);
unlock_kernel ();
MOD_DEC_USE_COUNT;
return err;
}
#ifdef MODULE
/* New-style module support since 2.1.18 */
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
MODULE_LICENSE("GPL");
#ifdef MODULE
struct nfsd_linkage nfsd_linkage_s = {
do_nfsservctl: handle_sys_nfsservctl,
owner: THIS_MODULE,
};
#endif
/*
* Initialize the module
*/
int
init_module(void)
static int __init
nfsd_init(void)
{
printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
#ifdef MODULE
nfsd_linkage = &nfsd_linkage_s;
#endif
nfsd_stat_init(); /* Statistics */
nfsd_cache_init(); /* RPC reply cache */
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
proc_export_init();
return 0;
}
/*
* Clean up the mess before unloading the module
*/
void
cleanup_module(void)
static void __exit
nfsd_exit(void)
{
#ifdef MODULE
nfsd_linkage = NULL;
#endif
nfsd_export_shutdown();
nfsd_cache_shutdown();
remove_proc_entry("fs/nfs/exports", NULL);
......@@ -315,4 +306,6 @@ cleanup_module(void)
nfsd_stat_shutdown();
nfsd_lockd_shutdown();
}
#endif
module_init(nfsd_init);
module_exit(nfsd_exit);
......@@ -209,36 +209,37 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
err = inode_change_ok(inode, iap);
/* could be a "touch" (utimes) request where the user is not the owner but does
* have write permission. In this case the user should be allowed to set
* both times to the current time. We could just assume any such SETATTR
* is intended to set the times to "now", but we do a couple of simple tests
* to increase our confidence.
/* NFSv2 does not differentiate between "set-[ac]time-to-now"
* which only requires access, and "set-[ac]time-to-X" which
* requires ownership.
* So if it looks like it might be "set both to the same time which
* is close to now", and if inode_change_ok fails, then we
* convert to "set to now" instead of "set to explicit time"
*
* We only call inode_change_ok as the last test as technically
* it is not an interface that we should be using. It is only
* valid if the filesystem does not define it's own i_op->setattr.
*/
#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
#define MAX_TOUCH_TIME_ERROR (30*60)
if (err
&& (iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
&& iap->ia_mtime == iap->ia_atime
) {
/* looks good. now just make sure time is in the right ballpark.
* solaris, at least, doesn't seem to care what the time request is
/* Looks probable. Now just make sure time is in the right ballpark.
* Solaris, at least, doesn't seem to care what the time request is.
* We require it be within 30 minutes of now.
*/
time_t delta = iap->ia_atime - CURRENT_TIME;
if (delta<0) delta = -delta;
if (delta < MAX_TOUCH_TIME_ERROR) {
if (delta < MAX_TOUCH_TIME_ERROR &&
inode_change_ok(inode, iap) != 0) {
/* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME
* this will cause notify_change to set these times to "now"
*/
iap->ia_valid &= ~BOTH_TIME_SET;
err = inode_change_ok(inode, iap);
}
}
if (err)
goto out_nfserr;
/* The size case is special. It changes the file as well as the attributes. */
if (iap->ia_valid & ATTR_SIZE) {
if (iap->ia_size < inode->i_size) {
......@@ -511,24 +512,33 @@ nfsd_close(struct file *filp)
* As this calls fsync (not fdatasync) there is no need for a write_inode
* after it.
*/
inline void nfsd_dosync(struct file *filp, struct dentry *dp,
struct file_operations *fop)
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
filemap_fdatasync(inode->i_mapping);
if (fop && (fsync = fop->fsync))
fsync(filp, dp, 0);
filemap_fdatawait(inode->i_mapping);
}
void
nfsd_sync(struct file *filp)
{
struct inode *inode = filp->f_dentry->d_inode;
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, 0);
up(&filp->f_dentry->d_inode->i_sem);
down(&inode->i_sem);
nfsd_dosync(filp, filp->f_dentry, filp->f_op);
up(&inode->i_sem);
}
void
nfsd_sync_dir(struct dentry *dp)
{
struct inode *inode = dp->d_inode;
int (*fsync) (struct file *, struct dentry *, int);
if (inode->i_fop && (fsync = inode->i_fop->fsync)) {
fsync(NULL, dp, 0);
}
nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
}
/*
......@@ -1382,7 +1392,6 @@ int
nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
encode_dent_fn func, u32 *buffer, int *countp, u32 *verf)
{
struct inode *inode;
u32 *p;
int oldlen, eof, err;
struct file file;
......@@ -1394,9 +1403,6 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
if (offset > ~(u32) 0)
goto out_close;
err = nfserr_notdir;
if (!file.f_op->readdir)
goto out_close;
file.f_pos = offset;
/* Set up the readdir context */
......@@ -1411,25 +1417,16 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
* readdir() is not guaranteed to fill up the entire buffer, but
* may choose to do less.
*/
inode = file.f_dentry->d_inode;
down(&inode->i_sem);
while (1) {
do {
oldlen = cd.buflen;
/*
dprintk("nfsd: f_op->readdir(%s/%ld @ %d) buflen = %d (%d)\n",
file.f_inode->i_sb->s_id, file.f_inode->i_ino,
(int) file.f_pos, (int) oldlen, (int) cd.buflen);
*/
err = file.f_op->readdir(&file, &cd, (filldir_t) func);
err = vfs_readdir(&file, (filldir_t) func, &cd);
if (err < 0)
goto out_nfserr;
if (oldlen == cd.buflen)
break;
if (cd.eob)
break;
}
up(&inode->i_sem);
} while (oldlen != cd.buflen && !cd.eob);
/* If we didn't fill the buffer completely, we're at EOF */
eof = !cd.eob;
......@@ -1456,7 +1453,6 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
return err;
out_nfserr:
up(&inode->i_sem);
err = nfserrno(err);
goto out_close;
}
......
......@@ -16,6 +16,7 @@
extern struct nfsd_linkage {
long (*do_nfsservctl)(int cmd, void *argp, void *resp);
struct module *owner;
} * nfsd_linkage;
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment