added a lot of printk output to ease writing of emulator
[linux-2.4.21-pre4.git] / fs / nfsd / nfsctl.c
1 /*
2  * linux/fs/nfsd/nfsctl.c
3  *
4  * Syscall interface to knfsd.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #include <linux/config.h>
10 #include <linux/module.h>
11 #include <linux/version.h>
12
13 #include <linux/linkage.h>
14 #include <linux/sched.h>
15 #include <linux/errno.h>
16 #include <linux/fs.h>
17 #include <linux/fcntl.h>
18 #include <linux/net.h>
19 #include <linux/in.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/init.h>
25
26 #include <linux/nfs.h>
27 #include <linux/sunrpc/svc.h>
28 #include <linux/nfsd/nfsd.h>
29 #include <linux/nfsd/cache.h>
30 #include <linux/nfsd/xdr.h>
31 #include <linux/nfsd/syscall.h>
32
33 #include <asm/uaccess.h>
34 #include <linux/smp.h>
35 #include <linux/smp_lock.h>
36 #include <linux/init.h>
37
38 static int      nfsctl_svc(struct nfsctl_svc *data);
39 static int      nfsctl_addclient(struct nfsctl_client *data);
40 static int      nfsctl_delclient(struct nfsctl_client *data);
41 static int      nfsctl_export(struct nfsctl_export *data);
42 static int      nfsctl_unexport(struct nfsctl_export *data);
43 static int      nfsctl_getfh(struct nfsctl_fhparm *, __u8 *);
44 static int      nfsctl_getfd(struct nfsctl_fdparm *, __u8 *);
45 static int      nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *);
46 #ifdef notyet
47 static int      nfsctl_ugidupdate(struct nfsctl_ugidmap *data);
48 #endif
49
50 extern struct seq_operations nfs_exports_op;
51 static int exports_open(struct inode *inode, struct file *file)
52 {
53         return seq_open(file, &nfs_exports_op);
54 }
55 static struct file_operations exports_operations = {
56         open:           exports_open,
57         read:           seq_read,
58         llseek:         seq_lseek,
59         release:        seq_release,
60 };
61
62 void proc_export_init(void)
63 {
64         struct proc_dir_entry *entry;
65         if (!proc_mkdir("fs/nfs", 0))
66                 return;
67         entry = create_proc_entry("fs/nfs/exports", 0, NULL);
68         if (entry)
69                 entry->proc_fops =  &exports_operations;
70 }
71
72 static inline int
73 nfsctl_svc(struct nfsctl_svc *data)
74 {
75         return nfsd_svc(data->svc_port, data->svc_nthreads);
76 }
77
78 static inline int
79 nfsctl_addclient(struct nfsctl_client *data)
80 {
81         return exp_addclient(data);
82 }
83
84 static inline int
85 nfsctl_delclient(struct nfsctl_client *data)
86 {
87         return exp_delclient(data);
88 }
89
90 static inline int
91 nfsctl_export(struct nfsctl_export *data)
92 {
93         return exp_export(data);
94 }
95
96 static inline int
97 nfsctl_unexport(struct nfsctl_export *data)
98 {
99         return exp_unexport(data);
100 }
101
102 #ifdef notyet
103 static inline int
104 nfsctl_ugidupdate(nfs_ugidmap *data)
105 {
106         return -EINVAL;
107 }
108 #endif
109
110 static inline int
111 nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res)
112 {
113         struct sockaddr_in      *sin;
114         struct svc_client       *clp;
115         int                     err = 0;
116
117         if (data->gd_addr.sa_family != AF_INET)
118                 return -EPROTONOSUPPORT;
119         sin = (struct sockaddr_in *)&data->gd_addr;
120         if (data->gd_maxlen > NFS3_FHSIZE)
121                 data->gd_maxlen = NFS3_FHSIZE;
122         exp_readlock();
123         if (!(clp = exp_getclient(sin)))
124                 err = -EPERM;
125         else
126                 err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
127         exp_unlock();
128         return err;
129 }
130
131 static inline int
132 nfsctl_getfd(struct nfsctl_fdparm *data, __u8 *res)
133 {
134         struct sockaddr_in      *sin;
135         struct svc_client       *clp;
136         int                     err = 0;
137         struct  knfsd_fh        fh;
138
139         if (data->gd_addr.sa_family != AF_INET)
140                 return -EPROTONOSUPPORT;
141         if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
142                 return -EINVAL;
143         sin = (struct sockaddr_in *)&data->gd_addr;
144
145         exp_readlock();
146         if (!(clp = exp_getclient(sin)))
147                 err = -EPERM;
148         else
149                 err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
150         exp_unlock();
151
152         if (err == 0) {
153                 if (fh.fh_size > NFS_FHSIZE)
154                         err = -EINVAL;
155                 else {
156                         memset(res,0, NFS_FHSIZE);
157                         memcpy(res, &fh.fh_base, fh.fh_size);
158                 }
159         }
160
161         return err;
162 }
163
164 static inline int
165 nfsctl_getfh(struct nfsctl_fhparm *data, __u8 *res)
166 {
167         struct sockaddr_in      *sin;
168         struct svc_client       *clp;
169         int                     err = 0;
170         struct knfsd_fh         fh;
171
172         if (data->gf_addr.sa_family != AF_INET)
173                 return -EPROTONOSUPPORT;
174         if (data->gf_version < 2 || data->gf_version > NFSSVC_MAXVERS)
175                 return -EINVAL;
176         sin = (struct sockaddr_in *)&data->gf_addr;
177
178         exp_readlock();
179         if (!(clp = exp_getclient(sin)))
180                 err = -EPERM;
181         else
182                 err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, &fh, NFS_FHSIZE);
183         exp_unlock();
184
185         if (err == 0) {
186                 if (fh.fh_size > NFS_FHSIZE)
187                         err = -EINVAL;
188                 else {
189                         memset(res,0, NFS_FHSIZE);
190                         memcpy(res, &fh.fh_base, fh.fh_size);
191                 }
192         }
193
194         return err;
195 }
196
197 #ifdef CONFIG_NFSD
198 #define handle_sys_nfsservctl sys_nfsservctl
199 #endif
200
201 static struct {
202         int argsize, respsize;
203 }  sizes[] = {
204         /* NFSCTL_SVC        */ { sizeof(struct nfsctl_svc), 0 },
205         /* NFSCTL_ADDCLIENT  */ { sizeof(struct nfsctl_client), 0},
206         /* NFSCTL_DELCLIENT  */ { sizeof(struct nfsctl_client), 0},
207         /* NFSCTL_EXPORT     */ { sizeof(struct nfsctl_export), 0},
208         /* NFSCTL_UNEXPORT   */ { sizeof(struct nfsctl_export), 0},
209         /* NFSCTL_UGIDUPDATE */ { sizeof(struct nfsctl_uidmap), 0},
210         /* NFSCTL_GETFH      */ { sizeof(struct nfsctl_fhparm), NFS_FHSIZE},
211         /* NFSCTL_GETFD      */ { sizeof(struct nfsctl_fdparm), NFS_FHSIZE},
212         /* NFSCTL_GETFS      */ { sizeof(struct nfsctl_fsparm), sizeof(struct knfsd_fh)},
213 };
214 #define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1)
215
216 long
217 asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
218 {
219         struct nfsctl_arg *     argp = opaque_argp;
220         union nfsctl_res *      resp = opaque_resp;
221         struct nfsctl_arg *     arg = NULL;
222         union nfsctl_res *      res = NULL;
223         int                     err;
224         int                     argsize, respsize;
225
226         lock_kernel ();
227
228         err = -EPERM;
229         if (!capable(CAP_SYS_ADMIN)) {
230                 goto done;
231         }
232         err = -EINVAL;
233         if (cmd<0 || cmd > CMD_MAX)
234                 goto done;
235         err = -EFAULT;
236         argsize = sizes[cmd].argsize + (int)&((struct nfsctl_arg *)0)->u;
237         respsize = sizes[cmd].respsize; /* maximum */
238         if (!access_ok(VERIFY_READ, argp, argsize)
239          || (resp && !access_ok(VERIFY_WRITE, resp, respsize))) {
240                 goto done;
241         }
242         err = -ENOMEM;  /* ??? */
243         if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
244             (resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
245                 goto done;
246         }
247
248         err = -EINVAL;
249         copy_from_user(arg, argp, argsize);
250         if (arg->ca_version != NFSCTL_VERSION) {
251                 printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
252                 goto done;
253         }
254
255         switch(cmd) {
256         case NFSCTL_SVC:
257                 err = nfsctl_svc(&arg->ca_svc);
258                 break;
259         case NFSCTL_ADDCLIENT:
260                 err = nfsctl_addclient(&arg->ca_client);
261                 break;
262         case NFSCTL_DELCLIENT:
263                 err = nfsctl_delclient(&arg->ca_client);
264                 break;
265         case NFSCTL_EXPORT:
266                 err = nfsctl_export(&arg->ca_export);
267                 break;
268         case NFSCTL_UNEXPORT:
269                 err = nfsctl_unexport(&arg->ca_export);
270                 break;
271 #ifdef notyet
272         case NFSCTL_UGIDUPDATE:
273                 err = nfsctl_ugidupdate(&arg->ca_umap);
274                 break;
275 #endif
276         case NFSCTL_GETFH:
277                 err = nfsctl_getfh(&arg->ca_getfh, res->cr_getfh);
278                 break;
279         case NFSCTL_GETFD:
280                 err = nfsctl_getfd(&arg->ca_getfd, res->cr_getfh);
281                 break;
282         case NFSCTL_GETFS:
283                 err = nfsctl_getfs(&arg->ca_getfs, &res->cr_getfs);
284                 respsize = res->cr_getfs.fh_size+ (int)&((struct knfsd_fh*)0)->fh_base;
285                 break;
286         default:
287                 err = -EINVAL;
288         }
289
290         if (!err && resp && respsize)
291                 copy_to_user(resp, res, respsize);
292
293 done:
294         if (arg)
295                 kfree(arg);
296         if (res)
297                 kfree(res);
298
299         unlock_kernel ();
300         return err;
301 }
302
303 EXPORT_NO_SYMBOLS;
304 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
305 MODULE_LICENSE("GPL");
306
307 #ifdef MODULE
308 struct nfsd_linkage nfsd_linkage_s = {
309         do_nfsservctl: handle_sys_nfsservctl,
310         owner: THIS_MODULE,
311 };
312 #endif
313
314 /*
315  * Initialize the module
316  */
317 static int __init
318 nfsd_init(void)
319 {
320         printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
321 #ifdef MODULE
322         nfsd_linkage = &nfsd_linkage_s;
323 #endif
324         nfsd_stat_init();       /* Statistics */
325         nfsd_cache_init();      /* RPC reply cache */
326         nfsd_export_init();     /* Exports table */
327         nfsd_lockd_init();      /* lockd->nfsd callbacks */
328         proc_export_init();
329         return 0;
330 }
331
332 /*
333  * Clean up the mess before unloading the module
334  */
335 static void __exit
336 nfsd_exit(void)
337 {
338 #ifdef MODULE
339         nfsd_linkage = NULL;
340 #endif
341         nfsd_export_shutdown();
342         nfsd_cache_shutdown();
343         remove_proc_entry("fs/nfs/exports", NULL);
344         remove_proc_entry("fs/nfs", NULL);
345         nfsd_stat_shutdown();
346         nfsd_lockd_shutdown();
347 }
348
349 module_init(nfsd_init);
350 module_exit(nfsd_exit);