kernel: Add a number of missing crit_exit, lwkt_reltoken, rel_mplock, etc.
[dragonfly.git] / sys / dev / misc / sysvipc / sysvipc.c
1 /*
2  * Copyright (c) 2013 Larisa Grigore  <larisagrigore@gmail.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in
13  *    the documentation and/or other materials provided with the
14  *    distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/sysmsg.h>
34 #include <sys/sysproto.h>
35 #include <sys/proc.h>
36 #include <sys/conf.h>
37 #include <sys/malloc.h>
38 #include <sys/ctype.h>
39 #include <sys/mman.h>
40 #include <sys/device.h>
41 #include <sys/fcntl.h>
42 #include <machine/varargs.h>
43 #include <sys/module.h>
44 #include <sys/proc.h>
45 #include <sys/file.h>
46 #include <sys/filedesc.h>
47 #include <sys/queue.h>
48 #include <sys/spinlock2.h>
49
50 #include <sys/sysvipc.h>
51 #include <sys/shm.h>
52
53 #include <vm/vm.h>
54 #include <vm/vm_pager.h>
55 #include <vm/vm_param.h>
56 #include <vm/vm_map.h>
57
58 static cdev_t           sysvipc_dev;
59 static d_open_t         sysvipc_dev_open;
60 static d_close_t        sysvipc_dev_close;
61 //static d_read_t               sysvipc_dev_read;
62 //static d_write_t      sysvipc_dev_write;
63 static d_ioctl_t        sysvipc_dev_ioctl;
64 static d_kqfilter_t     sysvipc_dev_kqfilter;
65
66 static struct dev_ops sysvipc_dev_ops = {
67         { "sysv", 0, 0 },
68         .d_open =       sysvipc_dev_open,
69         .d_close =      sysvipc_dev_close,
70         .d_ioctl =      sysvipc_dev_ioctl,
71         .d_kqfilter =   sysvipc_dev_kqfilter,
72 };
73
74 struct sysvipc_req {
75         struct proc                     *proc;
76         int                             fd[2];
77         TAILQ_ENTRY(sysvipc_req)        req_link;
78 };
79
80 TAILQ_HEAD(_req_list, sysvipc_req);
81
82 struct sysvipc_softc {
83         cdev_t                  sysvipc_dev;
84         struct kqinfo           sysvipc_rkq;
85         int                     opened;
86         struct _req_list        consumed_list;
87         struct _req_list        req_list;
88         struct lock             consumed_mtx;
89         struct lock             req_mtx;
90         struct thread           *sysvipc_daemon_thread;
91 };
92
93 static int
94 sysvipc_register(cdev_t dev)
95 {
96         struct sysvipc_softc *sysv;
97         
98         if (dev->si_drv1 != NULL)
99                 return (EEXIST);
100
101         kprintf("aloc sysv\n");
102         dev->si_drv1 = sysv = (struct sysvipc_softc *)
103                 kmalloc(sizeof(*sysv), M_TEMP,
104                                 M_ZERO | M_WAITOK);
105         sysv->sysvipc_dev = dev;
106         TAILQ_INIT(&sysv->req_list);
107         TAILQ_INIT(&sysv->consumed_list);
108         lockinit(&sysv->req_mtx, "sysvlkr", 0, LK_CANRECURSE);
109         lockinit(&sysv->consumed_mtx, "sysvlkc", 0, LK_CANRECURSE);
110         sysv->sysvipc_daemon_thread = curthread;
111
112         return 0;
113 }
114
115 static int
116 sysvipc_unregister(cdev_t dev)
117 {
118         struct sysvipc_softc *sysv = dev->si_drv1;
119
120         kfree(sysv, M_TEMP);
121         dev->si_drv1 = NULL;
122
123         return 0;
124 }
125
126 /*
127  * dev stuff
128  */
129 static int
130 sysvipc_dev_open(struct dev_open_args *ap)
131 {
132         return 0;
133 }
134
135 static int
136 sysvipc_dev_close(struct dev_close_args *ap)
137 {
138         return 0;
139 }
140
141 static void filt_sysvipc_detach(struct knote *);
142 static int filt_sysvipc_read(struct knote *, long);
143
144 static struct filterops sysvipc_read_filtops =
145         { FILTEROP_ISFD, NULL, filt_sysvipc_detach, filt_sysvipc_read };
146
147 static int
148 sysvipc_dev_kqfilter(struct dev_kqfilter_args *ap)
149 {
150         cdev_t dev = ap->a_head.a_dev;
151         struct knote *kn = ap->a_kn;
152         struct sysvipc_softc *sysv = dev->si_drv1;
153         struct klist *list;
154
155         if(sysv==NULL){
156                 kprintf("error read\n");
157                 return -1;
158         }
159         kprintf("kqfilter\n");
160
161         sysv = dev->si_drv1;
162         list = &sysv->sysvipc_rkq.ki_note;
163         ap->a_result =0;
164
165         switch(kn->kn_filter) {
166         case EVFILT_READ:
167                 kprintf("event read\n");
168                 kn->kn_fop = &sysvipc_read_filtops;
169                 kn->kn_hook = (void *)sysv;
170                 break;
171         default:
172                 ap->a_result = EOPNOTSUPP;
173                 return(0);
174         }
175
176         knote_insert(list, kn);
177         return(0);
178
179 }
180
181 /* TODO: kernel panic at line 181. it is called after unregister_daemon.*/
182 static void
183 filt_sysvipc_detach(struct knote *kn)
184 {
185         /*kprintf("detach\n");
186         if(!kn)
187                 return;
188         kprintf("detach 1\n");
189
190         struct sysvipc_softc * sysv =
191                 (struct sysvipc_softc *)kn->kn_hook;
192
193         if(!sysv)
194                 return;
195         kprintf("detach 2\n");
196
197         knote_remove(&sysv->sysvipc_rkq.ki_note, kn);
198         kprintf("end detach\n");
199 */
200 }
201
202 static int
203 filt_sysvipc_read(struct knote *kn, long hint)
204 {
205         struct sysvipc_softc * sysv =
206                 (struct sysvipc_softc *)kn->kn_hook;
207         int ready = 0;
208
209         //TODO what type of lock should I use?!?!
210         lockmgr(&sysv->req_mtx, LK_EXCLUSIVE);
211         ready = !(TAILQ_EMPTY(&sysv->req_list));
212         lockmgr(&sysv->req_mtx, LK_RELEASE);
213         return (ready);
214 }
215
216 static int
217 sysvipc_install_fd(struct proc *p_from, struct proc *p_to, int fd)
218 {
219         struct filedesc *fdp_from = p_from->p_fd;
220         struct filedesc *fdp_to = p_to->p_fd;
221         
222         struct file *fp;
223         int error, newfd;
224         int flags;
225
226         /*
227          * Get the file corresponding to fd from the process p_from.
228          */
229         spin_lock(&fdp_from->fd_spin);
230         if ((unsigned)fd >= fdp_from->fd_nfiles || fdp_from->fd_files[fd].fp == NULL) {
231                 spin_unlock(&fdp_from->fd_spin);
232                 return (EBADF);
233         }
234
235         fp = fdp_from->fd_files[fd].fp;
236         flags = fdp_from->fd_files[fd].fileflags;
237         fhold(fp);      /* MPSAFE - can be called with a spinlock held */
238         spin_unlock(&fdp_from->fd_spin);
239
240         /*
241          * Reserve a fd in the process p_to.
242          */
243         error = fdalloc(p_to, 1, &newfd);
244         if (error) {
245                 fdrop(fp);
246                 return (error);
247         }
248
249         /*
250          * Set fd for the fp file.
251          */
252         fsetfd(fdp_to, fp, newfd);
253         fdp_to->fd_files[newfd].fileflags = flags;
254         fdrop(fp);
255
256         return (newfd);
257 }
258
259 static struct sysvipc_req*
260 sysvipc_find_req(struct _req_list *list,
261                 struct lock *req_mtx, pid_t pid)
262 {
263         struct sysvipc_req *reqtmp;
264         lockmgr(req_mtx, LK_EXCLUSIVE);
265         TAILQ_FOREACH(reqtmp, list, req_link) {
266                 if(reqtmp->proc->p_pid == pid) {
267                         lockmgr(req_mtx, LK_RELEASE);
268                         return reqtmp;
269                 }
270         }
271         lockmgr(req_mtx, LK_RELEASE);
272         return NULL;
273 }
274
275 static int
276 get_proc_shm_cred(struct proc *p, struct ipc_perm *perm)
277 {
278         struct ucred *cred;
279
280         cred = p->p_ucred;
281         perm->cuid = perm->uid = cred->cr_uid;
282         perm->cgid = perm->gid = cred->cr_gid;
283
284         return 1;
285 }
286
287 static int
288 sysvipc_dev_ioctl(struct dev_ioctl_args *ap)
289 {
290         int error;
291         struct client *cl;
292         struct proc *proc_to, *proc_from;
293         struct sysvipc_req *req;
294         cdev_t dev = ap->a_head.a_dev;
295         struct sysvipc_softc *sysv = dev->si_drv1;
296         struct client_shm_data *client_data;
297
298         error = 0;
299
300         switch(ap->a_cmd) {
301         case REGISTER_DAEMON:
302                 kprintf("[driver] register daemon\n");
303                 sysvipc_register(dev);
304                 break;
305         case UNREGISTER_DAEMON:
306                 sysvipc_unregister(dev);
307                 break;
308         case INSTALL_PIPE:
309                 kprintf("[driver] install pipe\n");
310
311                 if(curthread != sysv->sysvipc_daemon_thread)
312                         return (EPERM);
313
314                 cl = (struct client *)ap->a_data;
315
316                 //kprintf("sysv ipc pid = %d fd 0 = %d fd 1 = %d!\n",
317                 //cl->pid, cl->fd[0], cl->fd[1]);
318
319                 if(cl->pid <= 0)
320                         return (EINVAL);
321
322                 proc_from = curthread->td_proc;
323                 proc_to = pfind(cl->pid);
324
325                 /* Find the request associated with the client. */
326                 req = sysvipc_find_req(&sysv->consumed_list,
327                                 &sysv->consumed_mtx, cl->pid);
328                 if(!req)
329                         return (EINVAL);
330
331                 /* Install for the client two file descriptors. 
332                  * The first one is used for read and the second one for
333                  * write purpose.
334                  */
335                 req->fd[0] = sysvipc_install_fd(proc_from,
336                                 proc_to, cl->fd[0]);
337                 req->fd[1] = sysvipc_install_fd(proc_from,
338                                 proc_to, cl->fd[1]);
339                 PRELE(proc_to);
340
341                 /* Wakeup the client. */
342                 wakeup(req);
343
344                 break;
345         case REGISTER_TO_DAEMON:
346
347                 if(sysv == NULL)
348                         return (EEXIST);
349
350                 if(curthread == sysv->sysvipc_daemon_thread)
351                         return (EPERM);
352
353                 kprintf("[driver] register to daemon\n");
354                 cl = (struct client *)ap->a_data;
355
356                 /* Allocate a struture for the request. */
357                 req = (struct sysvipc_req*)kmalloc( sizeof(*req),
358                                 M_TEMP, M_ZERO | M_WAITOK);
359
360                 req->proc = curthread->td_proc;
361
362                 /* Add the request to the list used read be daemon. */
363                 lockmgr(&sysv->req_mtx, LK_EXCLUSIVE);
364                 TAILQ_INSERT_HEAD(&sysv->req_list, req, req_link);
365                 lockmgr(&sysv->req_mtx, LK_RELEASE);
366
367                 /* Wake up daemon to process the request. */
368                 wakeup(sysv);
369                 KNOTE(&sysv->sysvipc_rkq.ki_note, 0);
370
371                 /* Wait so that the daemon processes the request and
372                  * installs the two new file descriptors.
373                  */
374                 tsleep(req, 0, "regist", 0);
375
376                 //kprintf("client wake up %d %d\n", req->fd[0], req->fd[1]);
377                 cl->fd[0] = req->fd[0];
378                 cl->fd[1] = req->fd[1];
379
380                 /* Remove the request from the list of consumed requests. */
381                 lockmgr(&sysv->consumed_mtx, LK_EXCLUSIVE);
382                 TAILQ_REMOVE(&sysv->consumed_list, req, req_link);
383                 lockmgr(&sysv->consumed_mtx, LK_RELEASE);
384
385                 kfree(req, M_TEMP);
386                 break;
387         case CONSUME_REQUEST:
388                 if(curthread != sysv->sysvipc_daemon_thread)
389                         return (EPERM);
390
391                 /* Wait for new requests. */
392                 lockmgr(&sysv->req_mtx, LK_EXCLUSIVE);
393                 while(TAILQ_EMPTY(&sysv->req_list))
394                         lksleep(sysv, &sysv->req_mtx, 0, "sysv", 0);
395                 kprintf("wake up to consume request\n");
396
397                 /* Remove the request from the req_list and add it to the
398                  * list of consumed requests.
399                  */
400                 req = TAILQ_LAST( &sysv->req_list, _req_list);
401                 if(!req) {
402                         lockmgr(&sysv->req_mtx, LK_RELEASE);
403                         return (EINVAL);
404                 }
405                 TAILQ_REMOVE(&sysv->req_list, req, req_link);
406                 lockmgr(&sysv->req_mtx, LK_RELEASE);
407
408                 lockmgr(&sysv->consumed_mtx, LK_EXCLUSIVE);
409                 TAILQ_INSERT_HEAD(&sysv->consumed_list, req, req_link);
410                 kprintf("pid received = %d\n", req->proc->p_pid);
411                 *(pid_t *)ap->a_data = req->proc->p_pid;
412                 lockmgr(&sysv->consumed_mtx, LK_RELEASE);
413
414                 break;
415         case INSTALL_FD:
416                 if(curthread != sysv->sysvipc_daemon_thread)
417                         return (EPERM);
418
419                 kprintf("[driver] install fd\n");
420                 client_data = (struct client_shm_data *)ap->a_data;
421
422                 /* Get process structure. */
423                 proc_from = curthread->td_proc;
424                 proc_to = pfind(client_data->pid);
425
426                 /* Get client's credentials. */
427                 //get_proc_shm_cred(proc_to, &client_data->shm_perm);
428
429                 /* Install for the client the file descriptor. */
430                 client_data->fd = sysvipc_install_fd(proc_from,
431                                 proc_to, client_data->fd);
432
433                 PRELE(proc_to);
434
435                 break;
436         default:
437                 break;
438         }
439
440         return(error);
441 }
442
443
444 static int
445 sysvipc_modevent(module_t mod, int type, void *unused)
446 {
447         struct sysvipc_softc *sysv;
448
449         switch (type) {
450         case MOD_LOAD:
451                 sysvipc_dev = make_dev(&sysvipc_dev_ops,
452                     0,
453                     UID_ROOT,
454                     GID_WHEEL,
455                     0600,
456                     "sysvipc");
457
458                 kprintf("sysv ipc driver ready!\n");
459                 return 0;
460
461         case MOD_UNLOAD:
462                 sysv = sysvipc_dev->si_drv1;
463                 if(sysv != NULL)
464                         sysvipc_unregister(sysvipc_dev);
465                 destroy_dev(sysvipc_dev);
466                 kprintf("sysv ipc driver unloaded.\n");
467                 return 0;
468         }
469
470         return EINVAL;
471 }
472
473 static moduledata_t sysvipc_mod = {
474         "tessysvipc",
475         sysvipc_modevent,
476         0
477 };
478
479 DECLARE_MODULE(sysvipc, sysvipc_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
480 MODULE_VERSION(sysvipc, 1);