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