Linux-2.3.3 and a short hiatus..
[davej-history.git] / fs / nfsd / nfsctl.c
blobfd7a5b227a636c5c268851634526a286d769fb19
1 /*
2 * linux/fs/nfsd/nfsctl.c
4 * Syscall interface to knfsd.
6 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7 */
8 #define NFS_GETFH_NEW
10 #include <linux/config.h>
11 #include <linux/module.h>
12 #include <linux/version.h>
14 #include <linux/linkage.h>
15 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/fs.h>
18 #include <linux/fcntl.h>
19 #include <linux/net.h>
20 #include <linux/in.h>
21 #include <linux/version.h>
22 #include <linux/unistd.h>
23 #include <linux/malloc.h>
24 #include <linux/proc_fs.h>
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>
33 #if LINUX_VERSION_CODE >= 0x020100
34 #include <asm/uaccess.h>
35 #else
36 # define copy_from_user memcpy_fromfs
37 # define copy_to_user memcpy_tofs
38 # define access_ok !verify_area
39 #endif
40 #include <linux/smp.h>
41 #include <linux/smp_lock.h>
43 extern void nfsd_fh_init(void);
44 extern long sys_call_table[];
46 static int nfsctl_svc(struct nfsctl_svc *data);
47 static int nfsctl_addclient(struct nfsctl_client *data);
48 static int nfsctl_delclient(struct nfsctl_client *data);
49 static int nfsctl_export(struct nfsctl_export *data);
50 static int nfsctl_unexport(struct nfsctl_export *data);
51 static int nfsctl_getfh(struct nfsctl_fhparm *, struct knfs_fh *);
52 static int nfsctl_getfd(struct nfsctl_fdparm *, struct knfs_fh *);
53 /* static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); */
55 static int initialized = 0;
57 int exp_procfs_exports(char *buffer, char **start, off_t offset,
58 int length, int *eof, void *data);
60 void proc_export_init(void)
62 struct proc_dir_entry *nfs_export_ent = NULL;
64 if (!(nfs_export_ent = create_proc_entry("fs/nfs", S_IFDIR, 0)))
65 return;
66 if (!(nfs_export_ent = create_proc_entry("fs/nfs/exports", 0, 0)))
67 return;
68 nfs_export_ent->read_proc = exp_procfs_exports;
73 * Initialize nfsd
75 static void
76 nfsd_init(void)
78 nfsd_xdr_init(); /* XDR */
79 nfsd_stat_init(); /* Statistics */
80 nfsd_cache_init(); /* RPC reply cache */
81 nfsd_export_init(); /* Exports table */
82 nfsd_lockd_init(); /* lockd->nfsd callbacks */
83 nfsd_fh_init(); /* FH table */
84 proc_export_init();
85 initialized = 1;
88 static inline int
89 nfsctl_svc(struct nfsctl_svc *data)
91 return nfsd_svc(data->svc_port, data->svc_nthreads);
94 static inline int
95 nfsctl_addclient(struct nfsctl_client *data)
97 return exp_addclient(data);
100 static inline int
101 nfsctl_delclient(struct nfsctl_client *data)
103 return exp_delclient(data);
106 static inline int
107 nfsctl_export(struct nfsctl_export *data)
109 return exp_export(data);
112 static inline int
113 nfsctl_unexport(struct nfsctl_export *data)
115 return exp_unexport(data);
118 #ifdef notyet
119 static inline int
120 nfsctl_ugidupdate(nfs_ugidmap *data)
122 return -EINVAL;
124 #endif
126 static inline int
127 nfsctl_getfd(struct nfsctl_fdparm *data, struct knfs_fh *res)
129 struct sockaddr_in *sin;
130 struct svc_client *clp;
131 int err = 0;
133 if (data->gd_addr.sa_family != AF_INET)
134 return -EPROTONOSUPPORT;
135 if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
136 return -EINVAL;
137 sin = (struct sockaddr_in *)&data->gd_addr;
139 exp_readlock();
140 if (!(clp = exp_getclient(sin)))
141 err = -EPERM;
142 else
143 err = exp_rootfh(clp, 0, 0, data->gd_path, res);
144 exp_unlock();
146 return err;
149 static inline int
150 nfsctl_getfh(struct nfsctl_fhparm *data, struct knfs_fh *res)
152 struct sockaddr_in *sin;
153 struct svc_client *clp;
154 int err = 0;
156 if (data->gf_addr.sa_family != AF_INET)
157 return -EPROTONOSUPPORT;
158 if (data->gf_version < 2 || data->gf_version > NFSSVC_MAXVERS)
159 return -EINVAL;
160 sin = (struct sockaddr_in *)&data->gf_addr;
162 exp_readlock();
163 if (!(clp = exp_getclient(sin)))
164 err = -EPERM;
165 else
166 err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, res);
167 exp_unlock();
169 return err;
172 #ifdef CONFIG_NFSD
173 #define handle_sys_nfsservctl sys_nfsservctl
174 #endif
177 asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp)
179 struct nfsctl_arg * argp = opaque_argp;
180 union nfsctl_res * resp = opaque_resp;
181 struct nfsctl_arg * arg = NULL;
182 union nfsctl_res * res = NULL;
183 int err;
185 MOD_INC_USE_COUNT;
186 lock_kernel ();
187 if (!initialized)
188 nfsd_init();
189 err = -EPERM;
190 if (!capable(CAP_SYS_ADMIN)) {
191 goto done;
193 err = -EFAULT;
194 if (!access_ok(VERIFY_READ, argp, sizeof(*argp))
195 || (resp && !access_ok(VERIFY_WRITE, resp, sizeof(*resp)))) {
196 goto done;
199 err = -ENOMEM; /* ??? */
200 if (!(arg = kmalloc(sizeof(*arg), GFP_USER)) ||
201 (resp && !(res = kmalloc(sizeof(*res), GFP_USER)))) {
202 goto done;
205 err = -EINVAL;
206 copy_from_user(arg, argp, sizeof(*argp));
207 if (arg->ca_version != NFSCTL_VERSION) {
208 printk(KERN_WARNING "nfsd: incompatible version in syscall.\n");
209 goto done;
212 switch(cmd) {
213 case NFSCTL_SVC:
214 err = nfsctl_svc(&arg->ca_svc);
215 break;
216 case NFSCTL_ADDCLIENT:
217 err = nfsctl_addclient(&arg->ca_client);
218 break;
219 case NFSCTL_DELCLIENT:
220 err = nfsctl_delclient(&arg->ca_client);
221 break;
222 case NFSCTL_EXPORT:
223 err = nfsctl_export(&arg->ca_export);
224 break;
225 case NFSCTL_UNEXPORT:
226 err = nfsctl_unexport(&arg->ca_export);
227 break;
228 #ifdef notyet
229 case NFSCTL_UGIDUPDATE:
230 err = nfsctl_ugidupdate(&arg->ca_umap);
231 break;
232 #endif
233 case NFSCTL_GETFH:
234 err = nfsctl_getfh(&arg->ca_getfh, &res->cr_getfh);
235 break;
236 case NFSCTL_GETFD:
237 err = nfsctl_getfd(&arg->ca_getfd, &res->cr_getfh);
238 break;
239 default:
240 err = -EINVAL;
243 if (!err && resp)
244 copy_to_user(resp, res, sizeof(*resp));
246 done:
247 if (arg)
248 kfree(arg);
249 if (res)
250 kfree(res);
252 unlock_kernel ();
253 MOD_DEC_USE_COUNT;
254 return err;
257 #ifdef MODULE
258 /* New-style module support since 2.1.18 */
259 #if LINUX_VERSION_CODE >= 131346
260 EXPORT_NO_SYMBOLS;
261 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
262 #endif
264 extern int (*do_nfsservctl)(int, void *, void *);
267 * This is called as the fill_inode function when an inode
268 * is going into (fill = 1) or out of service (fill = 0).
270 * We use it here to make sure the module can't be unloaded
271 * while a /proc inode is in use.
273 void nfsd_modcount(struct inode *inode, int fill)
275 if (fill)
276 MOD_INC_USE_COUNT;
277 else
278 MOD_DEC_USE_COUNT;
282 * Initialize the module
285 init_module(void)
287 printk("Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
288 do_nfsservctl = handle_sys_nfsservctl;
289 return 0;
293 * Clean up the mess before unloading the module
295 void
296 cleanup_module(void)
298 if (MOD_IN_USE) {
299 printk("nfsd: nfsd busy, remove delayed\n");
300 return;
302 do_nfsservctl = NULL;
303 nfsd_export_shutdown();
304 nfsd_cache_shutdown();
305 nfsd_fh_free();
306 remove_proc_entry("fs/nfs/exports", NULL);
307 remove_proc_entry("fs/nfs", NULL);
308 nfsd_stat_shutdown();
309 nfsd_lockd_shutdown();
311 #endif