2 * linux/fs/nfsd/nfsctl.c
4 * Syscall interface to knfsd.
6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
9 #include <linux/config.h>
10 #include <linux/module.h>
12 #include <linux/linkage.h>
13 #include <linux/time.h>
14 #include <linux/errno.h>
16 #include <linux/fcntl.h>
17 #include <linux/net.h>
19 #include <linux/syscalls.h>
20 #include <linux/unistd.h>
21 #include <linux/slab.h>
22 #include <linux/proc_fs.h>
23 #include <linux/seq_file.h>
24 #include <linux/pagemap.h>
25 #include <linux/init.h>
27 #include <linux/nfs.h>
28 #include <linux/nfsd_idmap.h>
29 #include <linux/sunrpc/svc.h>
30 #include <linux/nfsd/nfsd.h>
31 #include <linux/nfsd/cache.h>
32 #include <linux/nfsd/xdr.h>
33 #include <linux/nfsd/syscall.h>
34 #include <linux/nfsd/interface.h>
36 #include <asm/uaccess.h>
39 * We have a single directory with 8 nodes in it.
56 * write() for these nodes.
58 static ssize_t write_svc(struct file *file, char *buf, size_t size);
59 static ssize_t write_add(struct file *file, char *buf, size_t size);
60 static ssize_t write_del(struct file *file, char *buf, size_t size);
61 static ssize_t write_export(struct file *file, char *buf, size_t size);
62 static ssize_t write_unexport(struct file *file, char *buf, size_t size);
63 static ssize_t write_getfd(struct file *file, char *buf, size_t size);
64 static ssize_t write_getfs(struct file *file, char *buf, size_t size);
65 static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
66 static ssize_t write_threads(struct file *file, char *buf, size_t size);
68 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
69 [NFSD_Svc] = write_svc,
70 [NFSD_Add] = write_add,
71 [NFSD_Del] = write_del,
72 [NFSD_Export] = write_export,
73 [NFSD_Unexport] = write_unexport,
74 [NFSD_Getfd] = write_getfd,
75 [NFSD_Getfs] = write_getfs,
76 [NFSD_Fh] = write_filehandle,
77 [NFSD_Threads] = write_threads,
80 /* an argresp is stored in an allocated page and holds the
81 * size of the argument or response, along with its content
89 * transaction based IO methods.
90 * The file expects a single write which triggers the transaction, and then
91 * possibly a read which collects the result - which is stored in a
94 static ssize_t TA_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
96 ino_t ino = file->f_dentry->d_inode->i_ino;
100 if (ino >= sizeof(write_op)/sizeof(write_op[0]) || !write_op[ino])
102 if (file->private_data)
103 return -EINVAL; /* only one write allowed per open */
104 if (size > PAGE_SIZE - sizeof(struct argresp))
107 ar = kmalloc(PAGE_SIZE, GFP_KERNEL);
111 down(&file->f_dentry->d_inode->i_sem);
112 if (file->private_data)
115 file->private_data = ar;
116 up(&file->f_dentry->d_inode->i_sem);
121 if (copy_from_user(ar->data, buf, size))
124 rv = write_op[ino](file, ar->data, size);
133 static ssize_t TA_read(struct file *file, char __user *buf, size_t size, loff_t *pos)
138 if (file->private_data == NULL)
139 rv = TA_write(file, buf, 0, pos);
143 ar = file->private_data;
146 if (*pos >= ar->size)
148 if (*pos + size > ar->size)
149 size = ar->size - *pos;
150 if (copy_to_user(buf, ar->data + *pos, size))
156 static int TA_open(struct inode *inode, struct file *file)
158 file->private_data = NULL;
162 static int TA_release(struct inode *inode, struct file *file)
164 void *p = file->private_data;
165 file->private_data = NULL;
170 static struct file_operations transaction_ops = {
174 .release = TA_release,
177 extern struct seq_operations nfs_exports_op;
178 static int exports_open(struct inode *inode, struct file *file)
180 return seq_open(file, &nfs_exports_op);
183 static struct file_operations exports_operations = {
184 .open = exports_open,
187 .release = seq_release,
190 /*----------------------------------------------------------------------------*/
192 * payload - write methods
193 * If the method has a response, the response should be put in buf,
194 * and the length returned. Otherwise return 0 or and -error.
197 static ssize_t write_svc(struct file *file, char *buf, size_t size)
199 struct nfsctl_svc *data;
200 if (size < sizeof(*data))
202 data = (struct nfsctl_svc*) buf;
203 return nfsd_svc(data->svc_port, data->svc_nthreads);
206 static ssize_t write_add(struct file *file, char *buf, size_t size)
208 struct nfsctl_client *data;
209 if (size < sizeof(*data))
211 data = (struct nfsctl_client *)buf;
212 return exp_addclient(data);
215 static ssize_t write_del(struct file *file, char *buf, size_t size)
217 struct nfsctl_client *data;
218 if (size < sizeof(*data))
220 data = (struct nfsctl_client *)buf;
221 return exp_delclient(data);
224 static ssize_t write_export(struct file *file, char *buf, size_t size)
226 struct nfsctl_export *data;
227 if (size < sizeof(*data))
229 data = (struct nfsctl_export*)buf;
230 return exp_export(data);
233 static ssize_t write_unexport(struct file *file, char *buf, size_t size)
235 struct nfsctl_export *data;
237 if (size < sizeof(*data))
239 data = (struct nfsctl_export*)buf;
240 return exp_unexport(data);
243 static ssize_t write_getfs(struct file *file, char *buf, size_t size)
245 struct nfsctl_fsparm *data;
246 struct sockaddr_in *sin;
247 struct auth_domain *clp;
249 struct knfsd_fh *res;
251 if (size < sizeof(*data))
253 data = (struct nfsctl_fsparm*)buf;
254 err = -EPROTONOSUPPORT;
255 if (data->gd_addr.sa_family != AF_INET)
257 sin = (struct sockaddr_in *)&data->gd_addr;
258 if (data->gd_maxlen > NFS3_FHSIZE)
259 data->gd_maxlen = NFS3_FHSIZE;
261 res = (struct knfsd_fh*)buf;
264 if (!(clp = auth_unix_lookup(sin->sin_addr)))
267 err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen);
268 auth_domain_put(clp);
272 err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base;
277 static ssize_t write_getfd(struct file *file, char *buf, size_t size)
279 struct nfsctl_fdparm *data;
280 struct sockaddr_in *sin;
281 struct auth_domain *clp;
286 if (size < sizeof(*data))
288 data = (struct nfsctl_fdparm*)buf;
289 err = -EPROTONOSUPPORT;
290 if (data->gd_addr.sa_family != AF_INET)
293 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
297 sin = (struct sockaddr_in *)&data->gd_addr;
299 if (!(clp = auth_unix_lookup(sin->sin_addr)))
302 err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE);
303 auth_domain_put(clp);
308 memset(res,0, NFS_FHSIZE);
309 memcpy(res, &fh.fh_base, fh.fh_size);
316 static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
319 * domain path maxsize
323 * qword quoting is used, so filehandle will be \x....
329 struct auth_domain *dom;
332 if (buf[size-1] != '\n')
337 len = qword_get(&mesg, dname, size);
338 if (len <= 0) return -EINVAL;
341 len = qword_get(&mesg, path, size);
342 if (len <= 0) return -EINVAL;
344 len = get_int(&mesg, &maxsize);
348 if (maxsize < NFS_FHSIZE)
350 if (maxsize > NFS3_FHSIZE)
351 maxsize = NFS3_FHSIZE;
353 if (qword_get(&mesg, mesg, size)>0)
356 /* we have all the words, they are in buf.. */
357 dom = unix_domain_find(dname);
361 len = exp_rootfh(dom, path, &fh, maxsize);
362 auth_domain_put(dom);
366 mesg = buf; len = PAGE_SIZE-sizeof(struct argresp);
367 qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size);
372 extern int nfsd_nrthreads(void);
374 static ssize_t write_threads(struct file *file, char *buf, size_t size)
376 /* if size > 0, look for a number of threads and call nfsd_svc
377 * then write out number of threads as reply
383 rv = get_int(&mesg, &newthreads);
388 rv = nfsd_svc(2049, newthreads);
392 sprintf(buf, "%d\n", nfsd_nrthreads());
396 /*----------------------------------------------------------------------------*/
398 * populating the filesystem.
401 static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
403 static struct tree_descr nfsd_files[] = {
404 [NFSD_Svc] = {".svc", &transaction_ops, S_IWUSR},
405 [NFSD_Add] = {".add", &transaction_ops, S_IWUSR},
406 [NFSD_Del] = {".del", &transaction_ops, S_IWUSR},
407 [NFSD_Export] = {".export", &transaction_ops, S_IWUSR},
408 [NFSD_Unexport] = {".unexport", &transaction_ops, S_IWUSR},
409 [NFSD_Getfd] = {".getfd", &transaction_ops, S_IWUSR|S_IRUSR},
410 [NFSD_Getfs] = {".getfs", &transaction_ops, S_IWUSR|S_IRUSR},
411 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
412 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
413 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
416 return simple_fill_super(sb, 0x6e667364, nfsd_files);
419 static struct super_block *nfsd_get_sb(struct file_system_type *fs_type,
420 int flags, const char *dev_name, void *data)
422 return get_sb_single(fs_type, flags, data, nfsd_fill_super);
425 static struct file_system_type nfsd_fs_type = {
426 .owner = THIS_MODULE,
428 .get_sb = nfsd_get_sb,
429 .kill_sb = kill_litter_super,
432 static int __init init_nfsd(void)
435 printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
437 nfsd_stat_init(); /* Statistics */
438 nfsd_cache_init(); /* RPC reply cache */
439 nfsd_export_init(); /* Exports table */
440 nfsd_lockd_init(); /* lockd->nfsd callbacks */
441 #ifdef CONFIG_NFSD_V4
442 nfsd_idmap_init(); /* Name to ID mapping */
443 #endif /* CONFIG_NFSD_V4 */
444 if (proc_mkdir("fs/nfs", 0)) {
445 struct proc_dir_entry *entry;
446 entry = create_proc_entry("fs/nfs/exports", 0, NULL);
448 entry->proc_fops = &exports_operations;
450 retval = register_filesystem(&nfsd_fs_type);
452 nfsd_export_shutdown();
453 nfsd_cache_shutdown();
454 remove_proc_entry("fs/nfs/exports", NULL);
455 remove_proc_entry("fs/nfs", NULL);
456 nfsd_stat_shutdown();
457 nfsd_lockd_shutdown();
462 static void __exit exit_nfsd(void)
464 nfsd_export_shutdown();
465 nfsd_cache_shutdown();
466 remove_proc_entry("fs/nfs/exports", NULL);
467 remove_proc_entry("fs/nfs", NULL);
468 nfsd_stat_shutdown();
469 nfsd_lockd_shutdown();
470 #ifdef CONFIG_NFSD_V4
471 nfsd_idmap_shutdown();
472 #endif /* CONFIG_NFSD_V4 */
473 unregister_filesystem(&nfsd_fs_type);
476 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
477 MODULE_LICENSE("GPL");
478 module_init(init_nfsd)
479 module_exit(exit_nfsd)