puffs_msgif.c revision 1.68 1 /* $NetBSD: puffs_msgif.c,v 1.68 2008/01/31 08:23:04 tnn Exp $ */
2
3 /*
4 * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
5 *
6 * Development of this software was supported by the
7 * Google Summer of Code program and the Ulla Tuominen Foundation.
8 * The Google SoC project was mentored by Bill Studenmund.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.68 2008/01/31 08:23:04 tnn Exp $");
34
35 #include <sys/param.h>
36 #include <sys/atomic.h>
37 #include <sys/fstrans.h>
38 #include <sys/kmem.h>
39 #include <sys/kthread.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/mount.h>
43 #include <sys/namei.h>
44 #include <sys/proc.h>
45 #include <sys/vnode.h>
46
47 #include <dev/putter/putter_sys.h>
48
49 #include <fs/puffs/puffs_msgif.h>
50 #include <fs/puffs/puffs_sys.h>
51
52 #include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_mutex reference */
53
54 /*
55 * waitq data structures
56 */
57
58 /*
59 * While a request is going to userspace, park the caller within the
60 * kernel. This is the kernel counterpart of "struct puffs_req".
61 */
62 struct puffs_msgpark {
63 struct puffs_req *park_preq; /* req followed by buf */
64
65 size_t park_copylen; /* userspace copylength */
66 size_t park_maxlen; /* max size in comeback */
67
68 parkdone_fn park_done; /* "biodone" a'la puffs */
69 void *park_donearg;
70
71 int park_flags;
72 int park_refcount;
73
74 kcondvar_t park_cv;
75 kmutex_t park_mtx;
76
77 TAILQ_ENTRY(puffs_msgpark) park_entries;
78 };
79 #define PARKFLAG_WAITERGONE 0x01
80 #define PARKFLAG_DONE 0x02
81 #define PARKFLAG_ONQUEUE1 0x04
82 #define PARKFLAG_ONQUEUE2 0x08
83 #define PARKFLAG_CALL 0x10
84 #define PARKFLAG_WANTREPLY 0x20
85 #define PARKFLAG_HASERROR 0x40
86
87 static pool_cache_t parkpc;
88 #ifdef PUFFSDEBUG
89 static int totalpark;
90 #endif
91
92 static int
93 makepark(void *arg, void *obj, int flags)
94 {
95 struct puffs_msgpark *park = obj;
96
97 mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE);
98 cv_init(&park->park_cv, "puffsrpl");
99
100 return 0;
101 }
102
103 static void
104 nukepark(void *arg, void *obj)
105 {
106 struct puffs_msgpark *park = obj;
107
108 cv_destroy(&park->park_cv);
109 mutex_destroy(&park->park_mtx);
110 }
111
112 void
113 puffs_msgif_init()
114 {
115
116 parkpc = pool_cache_init(sizeof(struct puffs_msgpark), 0, 0, 0,
117 "puffprkl", NULL, IPL_NONE, makepark, nukepark, NULL);
118 }
119
120 void
121 puffs_msgif_destroy()
122 {
123
124 pool_cache_destroy(parkpc);
125 }
126
127 static int alloced;
128
129 static struct puffs_msgpark *
130 puffs_msgpark_alloc(int waitok)
131 {
132 struct puffs_msgpark *park;
133
134 park = pool_cache_get(parkpc, waitok ? PR_WAITOK : PR_NOWAIT);
135 if (park == NULL)
136 return park;
137
138 park->park_refcount = 1;
139 park->park_preq = NULL;
140 park->park_flags = PARKFLAG_WANTREPLY;
141
142 #ifdef PUFFSDEBUG
143 totalpark++;
144 #endif
145
146 return park;
147 }
148
149 static void
150 puffs_msgpark_reference(struct puffs_msgpark *park)
151 {
152
153 KASSERT(mutex_owned(&park->park_mtx));
154 park->park_refcount++;
155 }
156
157 /*
158 * Release reference to park structure.
159 */
160 static void
161 puffs_msgpark_release1(struct puffs_msgpark *park, int howmany)
162 {
163 struct puffs_req *preq = park->park_preq;
164 int refcnt;
165
166 KASSERT(mutex_owned(&park->park_mtx));
167 refcnt = park->park_refcount -= howmany;
168 mutex_exit(&park->park_mtx);
169
170 KASSERT(refcnt >= 0);
171
172 if (refcnt == 0) {
173 alloced--;
174 if (preq)
175 kmem_free(preq, park->park_maxlen);
176 pool_cache_put(parkpc, park);
177
178 #ifdef PUFFSDEBUG
179 totalpark--;
180 #endif
181 }
182 }
183 #define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1)
184
185 #ifdef PUFFSDEBUG
186 static void
187 parkdump(struct puffs_msgpark *park)
188 {
189
190 DPRINTF(("park %p, preq %p, id %" PRIu64 "\n"
191 "\tcopy %zu, max %zu - done: %p/%p\n"
192 "\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n",
193 park, park->park_preq, park->park_preq->preq_id,
194 park->park_copylen, park->park_maxlen,
195 park->park_done, park->park_donearg,
196 park->park_flags, park->park_refcount,
197 &park->park_cv, &park->park_mtx));
198 }
199
200 static void
201 parkqdump(struct puffs_wq *q, int dumpall)
202 {
203 struct puffs_msgpark *park;
204 int total = 0;
205
206 TAILQ_FOREACH(park, q, park_entries) {
207 if (dumpall)
208 parkdump(park);
209 total++;
210 }
211 DPRINTF(("puffs waitqueue at %p dumped, %d total\n", q, total));
212
213 }
214 #endif /* PUFFSDEBUG */
215
216 /*
217 * A word about locking in the park structures: the lock protects the
218 * fields of the *park* structure (not preq) and acts as an interlock
219 * in cv operations. The lock is always internal to this module and
220 * callers do not need to worry about it.
221 */
222
223 int
224 puffs_msgmem_alloc(size_t len, struct puffs_msgpark **ppark, void **mem,
225 int cansleep)
226 {
227 struct puffs_msgpark *park;
228 void *m;
229
230 m = kmem_zalloc(len, cansleep ? KM_SLEEP : KM_NOSLEEP);
231 if (m == NULL) {
232 KASSERT(cansleep == 0);
233 return ENOMEM;
234 }
235
236 park = puffs_msgpark_alloc(cansleep);
237 if (park == NULL) {
238 KASSERT(cansleep == 0);
239 kmem_free(m, len);
240 return ENOMEM;
241 }
242
243 park->park_preq = m;
244 park->park_maxlen = park->park_copylen = len;
245
246 *ppark = park;
247 *mem = m;
248
249 return 0;
250 }
251
252 void
253 puffs_msgmem_release(struct puffs_msgpark *park)
254 {
255
256 if (park == NULL)
257 return;
258
259 mutex_enter(&park->park_mtx);
260 puffs_msgpark_release(park);
261 }
262
263 void
264 puffs_msg_setfaf(struct puffs_msgpark *park)
265 {
266
267 KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
268 park->park_flags &= ~PARKFLAG_WANTREPLY;
269 }
270
271 void
272 puffs_msg_setdelta(struct puffs_msgpark *park, size_t delta)
273 {
274
275 KASSERT(delta < park->park_maxlen); /* "<=" wouldn't make sense */
276 park->park_copylen = park->park_maxlen - delta;
277 }
278
279 void
280 puffs_msg_setinfo(struct puffs_msgpark *park, int class, int type,
281 puffs_cookie_t ck)
282 {
283
284 park->park_preq->preq_opclass = PUFFSOP_OPCLASS(class);
285 park->park_preq->preq_optype = type;
286 park->park_preq->preq_cookie = ck;
287 }
288
289 void
290 puffs_msg_setcall(struct puffs_msgpark *park, parkdone_fn donefn, void *donearg)
291 {
292
293 KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
294 park->park_done = donefn;
295 park->park_donearg = donearg;
296 park->park_flags |= PARKFLAG_CALL;
297 }
298
299 /*
300 * kernel-user-kernel waitqueues
301 */
302
303 static uint64_t
304 puffs_getmsgid(struct puffs_mount *pmp)
305 {
306 uint64_t rv;
307
308 mutex_enter(&pmp->pmp_lock);
309 rv = pmp->pmp_nextmsgid++;
310 mutex_exit(&pmp->pmp_lock);
311
312 return rv;
313 }
314
315 /*
316 * A word about reference counting of parks. A reference must be taken
317 * when accessing a park and additionally when it is on a queue. So
318 * when taking it off a queue and releasing the access reference, the
319 * reference count is generally decremented by 2.
320 */
321
322 void
323 puffs_msg_enqueue(struct puffs_mount *pmp, struct puffs_msgpark *park)
324 {
325 struct lwp *l = curlwp;
326 struct mount *mp;
327 struct puffs_req *preq;
328
329 mp = PMPTOMP(pmp);
330 preq = park->park_preq;
331 preq->preq_buflen = park->park_maxlen;
332 KASSERT(preq->preq_id == 0
333 || (preq->preq_opclass & PUFFSOPFLAG_ISRESPONSE));
334
335 if ((park->park_flags & PARKFLAG_WANTREPLY) == 0)
336 preq->preq_opclass |= PUFFSOPFLAG_FAF;
337 else
338 preq->preq_id = puffs_getmsgid(pmp);
339
340 /* fill in caller information */
341 preq->preq_pid = l->l_proc->p_pid;
342 preq->preq_lid = l->l_lid;
343
344 /*
345 * To support cv_sig, yet another movie: check if there are signals
346 * pending and we are issueing a non-FAF. If so, return an error
347 * directly UNLESS we are issueing INACTIVE/RECLAIM. In that case,
348 * convert it to a FAF, fire off to the file server and return
349 * an error. Yes, this is bordering disgusting. Barfbags are on me.
350 */
351 if (__predict_false((park->park_flags & PARKFLAG_WANTREPLY)
352 && (park->park_flags & PARKFLAG_CALL) == 0
353 && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0))) {
354 park->park_flags |= PARKFLAG_HASERROR;
355 preq->preq_rv = EINTR;
356 if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN
357 && (preq->preq_optype == PUFFS_VN_INACTIVE
358 || preq->preq_optype == PUFFS_VN_RECLAIM)) {
359 park->park_preq->preq_opclass |= PUFFSOPFLAG_FAF;
360 park->park_flags &= ~PARKFLAG_WANTREPLY;
361 DPRINTF(("puffs_msg_enqueue: converted to FAF %p\n",
362 park));
363 } else {
364 return;
365 }
366 }
367
368 /*
369 * test for suspension lock.
370 *
371 * Note that we *DO NOT* keep the lock, since that might block
372 * lock acquiring PLUS it would give userlandia control over
373 * the lock. The operation queue enforces a strict ordering:
374 * when the fs server gets in the op stream, it knows things
375 * are in order. The kernel locks can't guarantee that for
376 * userspace, in any case.
377 *
378 * BUT: this presents a problem for ops which have a consistency
379 * clause based on more than one operation. Unfortunately such
380 * operations (read, write) do not reliably work yet.
381 *
382 * Ya, Ya, it's wrong wong wrong, me be fixink this someday.
383 *
384 * XXX: and there is one more problem. We sometimes need to
385 * take a lazy lock in case the fs is suspending and we are
386 * executing as the fs server context. This might happen
387 * e.g. in the case that the user server triggers a reclaim
388 * in the kernel while the fs is suspending. It's not a very
389 * likely event, but it needs to be fixed some day.
390 */
391
392 /*
393 * MOREXXX: once PUFFS_WCACHEINFO is enabled, we can't take
394 * the mutex here, since getpages() might be called locked.
395 */
396 fstrans_start(mp, FSTRANS_NORMAL);
397 mutex_enter(&pmp->pmp_lock);
398 fstrans_done(mp);
399
400 if (pmp->pmp_status != PUFFSTAT_RUNNING) {
401 mutex_exit(&pmp->pmp_lock);
402 park->park_flags |= PARKFLAG_HASERROR;
403 preq->preq_rv = ENXIO;
404 return;
405 }
406
407 #ifdef PUFFSDEBUG
408 parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1);
409 parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1);
410 #endif
411
412 /*
413 * Note: we don't need to lock park since we have the only
414 * reference to it at this point.
415 */
416 TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries);
417 park->park_flags |= PARKFLAG_ONQUEUE1;
418 pmp->pmp_msg_touser_count++;
419 park->park_refcount++;
420 mutex_exit(&pmp->pmp_lock);
421
422 cv_broadcast(&pmp->pmp_msg_waiter_cv);
423 putter_notify(pmp->pmp_pi);
424
425 DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, "
426 "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park,
427 preq->preq_opclass, preq->preq_optype, park->park_flags));
428 }
429
430 int
431 puffs_msg_wait(struct puffs_mount *pmp, struct puffs_msgpark *park)
432 {
433 struct puffs_req *preq = park->park_preq; /* XXX: hmmm */
434 struct mount *mp = PMPTOMP(pmp);
435 int error = 0;
436 int rv;
437
438 mutex_enter(&pmp->pmp_lock);
439 puffs_mp_reference(pmp);
440 mutex_exit(&pmp->pmp_lock);
441
442 mutex_enter(&park->park_mtx);
443 if ((park->park_flags & PARKFLAG_WANTREPLY) == 0
444 || (park->park_flags & PARKFLAG_CALL)) {
445 mutex_exit(&park->park_mtx);
446 rv = 0;
447 goto skipwait;
448 }
449
450 /* did the response beat us to the wait? */
451 if (__predict_false((park->park_flags & PARKFLAG_DONE)
452 || (park->park_flags & PARKFLAG_HASERROR))) {
453 rv = park->park_preq->preq_rv;
454 mutex_exit(&park->park_mtx);
455 goto skipwait;
456 }
457
458 error = cv_wait_sig(&park->park_cv, &park->park_mtx);
459 DPRINTF(("puffs_touser: waiter for %p woke up with %d\n",
460 park, error));
461 if (error) {
462 park->park_flags |= PARKFLAG_WAITERGONE;
463 if (park->park_flags & PARKFLAG_DONE) {
464 rv = preq->preq_rv;
465 mutex_exit(&park->park_mtx);
466 } else {
467 /*
468 * ok, we marked it as going away, but
469 * still need to do queue ops. take locks
470 * in correct order.
471 *
472 * We don't want to release our reference
473 * if it's on replywait queue to avoid error
474 * to file server. putop() code will DTRT.
475 */
476 mutex_exit(&park->park_mtx);
477 mutex_enter(&pmp->pmp_lock);
478 mutex_enter(&park->park_mtx);
479
480 /*
481 * Still on queue1? We can safely remove it
482 * without any consequences since the file
483 * server hasn't seen it. "else" we need to
484 * wait for the response and just ignore it
485 * to avoid signalling an incorrect error to
486 * the file server.
487 */
488 if (park->park_flags & PARKFLAG_ONQUEUE1) {
489 TAILQ_REMOVE(&pmp->pmp_msg_touser,
490 park, park_entries);
491 puffs_msgpark_release(park);
492 pmp->pmp_msg_touser_count--;
493 park->park_flags &= ~PARKFLAG_ONQUEUE1;
494 } else {
495 mutex_exit(&park->park_mtx);
496 }
497 mutex_exit(&pmp->pmp_lock);
498
499 rv = EINTR;
500 }
501 } else {
502 rv = preq->preq_rv;
503 mutex_exit(&park->park_mtx);
504 }
505
506 /*
507 * retake the lock and release. This makes sure (haha,
508 * I'm humorous) that we don't process the same vnode in
509 * multiple threads due to the locks hacks we have in
510 * puffs_lock(). In reality this is well protected by
511 * the biglock, but once that's gone, well, hopefully
512 * this will be fixed for real. (and when you read this
513 * comment in 2017 and subsequently barf, my condolences ;).
514 */
515 if (rv == 0 && !fstrans_is_owner(mp)) {
516 fstrans_start(mp, FSTRANS_NORMAL);
517 fstrans_done(mp);
518 }
519
520 skipwait:
521 mutex_enter(&pmp->pmp_lock);
522 puffs_mp_release(pmp);
523 mutex_exit(&pmp->pmp_lock);
524
525 return rv;
526 }
527
528 /*
529 * XXX: this suuuucks. Hopefully I'll get rid of this lossage once
530 * the whole setback-nonsense gets fixed.
531 */
532 int
533 puffs_msg_wait2(struct puffs_mount *pmp, struct puffs_msgpark *park,
534 struct puffs_node *pn1, struct puffs_node *pn2)
535 {
536 struct puffs_req *preq;
537 int rv;
538
539 rv = puffs_msg_wait(pmp, park);
540
541 preq = park->park_preq;
542 if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N1)
543 pn1->pn_stat |= PNODE_DOINACT;
544 if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N2)
545 pn2->pn_stat |= PNODE_DOINACT;
546
547 if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N1)
548 pn1->pn_stat |= PNODE_NOREFS;
549 if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N2)
550 pn2->pn_stat |= PNODE_NOREFS;
551
552 return rv;
553
554 }
555
556 /*
557 * XXX: lazy bum. please, for the love of foie gras, fix me.
558 * This should *NOT* depend on setfaf. Also "memcpy" could
559 * be done more nicely.
560 */
561 void
562 puffs_msg_sendresp(struct puffs_mount *pmp, struct puffs_req *origpreq, int rv)
563 {
564 struct puffs_msgpark *park;
565 struct puffs_req *preq;
566
567 puffs_msgmem_alloc(sizeof(struct puffs_req), &park, (void *)&preq, 1);
568 puffs_msg_setfaf(park); /* XXXXXX: avoids reqid override */
569
570 memcpy(preq, origpreq, sizeof(struct puffs_req));
571 preq->preq_rv = rv;
572 preq->preq_opclass |= PUFFSOPFLAG_ISRESPONSE;
573
574 puffs_msg_enqueue(pmp, park);
575 puffs_msgmem_release(park);
576 }
577
578 /*
579 * Get next request in the outgoing queue. "maxsize" controls the
580 * size the caller can accommodate and "nonblock" signals if this
581 * should block while waiting for input. Handles all locking internally.
582 */
583 int
584 puffs_msgif_getout(void *this, size_t maxsize, int nonblock,
585 uint8_t **data, size_t *dlen, void **parkptr)
586 {
587 struct puffs_mount *pmp = this;
588 struct puffs_msgpark *park;
589 struct puffs_req *preq;
590 int error;
591
592 error = 0;
593 mutex_enter(&pmp->pmp_lock);
594 puffs_mp_reference(pmp);
595 for (;;) {
596 /* RIP? */
597 if (pmp->pmp_status != PUFFSTAT_RUNNING) {
598 error = ENXIO;
599 break;
600 }
601
602 /* need platinum yendorian express card? */
603 if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) {
604 DPRINTF(("puffs_getout: no outgoing op, "));
605 if (nonblock) {
606 DPRINTF(("returning EWOULDBLOCK\n"));
607 error = EWOULDBLOCK;
608 break;
609 }
610 DPRINTF(("waiting ...\n"));
611
612 error = cv_wait_sig(&pmp->pmp_msg_waiter_cv,
613 &pmp->pmp_lock);
614 if (error)
615 break;
616 else
617 continue;
618 }
619
620 park = TAILQ_FIRST(&pmp->pmp_msg_touser);
621 if (park == NULL)
622 continue;
623
624 mutex_enter(&park->park_mtx);
625 puffs_msgpark_reference(park);
626
627 DPRINTF(("puffs_getout: found park at %p, ", park));
628
629 /* If it's a goner, don't process any furher */
630 if (park->park_flags & PARKFLAG_WAITERGONE) {
631 DPRINTF(("waitergone!\n"));
632 puffs_msgpark_release(park);
633 continue;
634 }
635 preq = park->park_preq;
636
637 #if 0
638 /* check size */
639 /*
640 * XXX: this check is not valid for now, we don't know
641 * the size of the caller's input buffer. i.e. this
642 * will most likely go away
643 */
644 if (maxsize < preq->preq_frhdr.pfr_len) {
645 DPRINTF(("buffer too small\n"));
646 puffs_msgpark_release(park);
647 error = E2BIG;
648 break;
649 }
650 #endif
651
652 DPRINTF(("returning\n"));
653
654 /*
655 * Ok, we found what we came for. Release it from the
656 * outgoing queue but do not unlock. We will unlock
657 * only after we "releaseout" it to avoid complications:
658 * otherwise it is (theoretically) possible for userland
659 * to race us into "put" before we have a change to put
660 * this baby on the receiving queue.
661 */
662 TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
663 KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
664 park->park_flags &= ~PARKFLAG_ONQUEUE1;
665 mutex_exit(&park->park_mtx);
666
667 pmp->pmp_msg_touser_count--;
668 KASSERT(pmp->pmp_msg_touser_count >= 0);
669
670 break;
671 }
672 puffs_mp_release(pmp);
673 mutex_exit(&pmp->pmp_lock);
674
675 if (error == 0) {
676 *data = (uint8_t *)preq;
677 preq->preq_pth.pth_framelen = park->park_copylen;
678 *dlen = preq->preq_pth.pth_framelen;
679 *parkptr = park;
680 }
681
682 return error;
683 }
684
685 /*
686 * Release outgoing structure. Now, depending on the success of the
687 * outgoing send, it is either going onto the result waiting queue
688 * or the death chamber.
689 */
690 void
691 puffs_msgif_releaseout(void *this, void *parkptr, int status)
692 {
693 struct puffs_mount *pmp = this;
694 struct puffs_msgpark *park = parkptr;
695
696 DPRINTF(("puffs_releaseout: returning park %p, errno %d: " ,
697 park, status));
698 mutex_enter(&pmp->pmp_lock);
699 mutex_enter(&park->park_mtx);
700 if (park->park_flags & PARKFLAG_WANTREPLY) {
701 if (status == 0) {
702 DPRINTF(("enqueue replywait\n"));
703 TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park,
704 park_entries);
705 park->park_flags |= PARKFLAG_ONQUEUE2;
706 } else {
707 DPRINTF(("error path!\n"));
708 park->park_preq->preq_rv = status;
709 park->park_flags |= PARKFLAG_DONE;
710 cv_signal(&park->park_cv);
711 }
712 puffs_msgpark_release(park);
713 } else {
714 DPRINTF(("release\n"));
715 puffs_msgpark_release1(park, 2);
716 }
717 mutex_exit(&pmp->pmp_lock);
718 }
719
720 size_t
721 puffs_msgif_waitcount(void *this)
722 {
723 struct puffs_mount *pmp = this;
724 size_t rv;
725
726 mutex_enter(&pmp->pmp_lock);
727 rv = pmp->pmp_msg_touser_count;
728 mutex_exit(&pmp->pmp_lock);
729
730 return rv;
731 }
732
733 /*
734 * XXX: locking with this one?
735 */
736 static void
737 puffsop_msg(void *this, struct puffs_req *preq)
738 {
739 struct puffs_mount *pmp = this;
740 struct putter_hdr *pth = &preq->preq_pth;
741 struct puffs_msgpark *park;
742 int wgone;
743
744 mutex_enter(&pmp->pmp_lock);
745
746 /* Locate waiter */
747 TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) {
748 if (park->park_preq->preq_id == preq->preq_id)
749 break;
750 }
751 if (park == NULL) {
752 DPRINTF(("puffsop_msg: no request: %" PRIu64 "\n",
753 preq->preq_id));
754 mutex_exit(&pmp->pmp_lock);
755 return; /* XXX send error */
756 }
757
758 mutex_enter(&park->park_mtx);
759 puffs_msgpark_reference(park);
760 if (pth->pth_framelen > park->park_maxlen) {
761 DPRINTF(("puffsop_msg: invalid buffer length: "
762 "%" PRIu64 " (req %" PRIu64 ", \n", pth->pth_framelen,
763 preq->preq_id));
764 park->park_preq->preq_rv = EPROTO;
765 cv_signal(&park->park_cv);
766 puffs_msgpark_release1(park, 2);
767 mutex_exit(&pmp->pmp_lock);
768 return; /* XXX: error */
769 }
770 wgone = park->park_flags & PARKFLAG_WAITERGONE;
771
772 KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
773 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
774 park->park_flags &= ~PARKFLAG_ONQUEUE2;
775 mutex_exit(&pmp->pmp_lock);
776
777 if (wgone) {
778 DPRINTF(("puffsop_msg: bad service - waiter gone for "
779 "park %p\n", park));
780 } else {
781 if (park->park_flags & PARKFLAG_CALL) {
782 DPRINTF(("puffsop_msg: call for %p, arg %p\n",
783 park->park_preq, park->park_donearg));
784 park->park_done(pmp, preq, park->park_donearg);
785 } else {
786 /* XXX: yes, I know */
787 memcpy(park->park_preq, preq, pth->pth_framelen);
788 }
789 }
790
791 if (!wgone) {
792 DPRINTF(("puffs_putop: flagging done for "
793 "park %p\n", park));
794 cv_signal(&park->park_cv);
795 }
796
797 park->park_flags |= PARKFLAG_DONE;
798 puffs_msgpark_release1(park, 2);
799 }
800
801 /*
802 * helpers
803 */
804 static void
805 dosuspendresume(void *arg)
806 {
807 struct puffs_mount *pmp = arg;
808 struct mount *mp;
809 int rv;
810
811 mp = PMPTOMP(pmp);
812 /*
813 * XXX? does this really do any good or is it just
814 * paranoid stupidity? or stupid paranoia?
815 */
816 if (mp->mnt_iflag & IMNT_UNMOUNT) {
817 printf("puffs dosuspendresume(): detected suspend on "
818 "unmounting fs\n");
819 goto out;
820 }
821
822 /* Do the dance. Allow only one concurrent suspend */
823 rv = vfs_suspend(PMPTOMP(pmp), 1);
824 if (rv == 0)
825 vfs_resume(PMPTOMP(pmp));
826
827 out:
828 mutex_enter(&pmp->pmp_lock);
829 KASSERT(pmp->pmp_suspend == 1);
830 pmp->pmp_suspend = 0;
831 puffs_mp_release(pmp);
832 mutex_exit(&pmp->pmp_lock);
833
834 kthread_exit(0);
835 }
836
837 static void
838 puffsop_suspend(struct puffs_mount *pmp)
839 {
840 int rv = 0;
841
842 mutex_enter(&pmp->pmp_lock);
843 if (pmp->pmp_suspend || pmp->pmp_status != PUFFSTAT_RUNNING) {
844 rv = EBUSY;
845 } else {
846 puffs_mp_reference(pmp);
847 pmp->pmp_suspend = 1;
848 }
849 mutex_exit(&pmp->pmp_lock);
850 if (rv)
851 return;
852 rv = kthread_create(PRI_NONE, 0, NULL, dosuspendresume,
853 pmp, NULL, "puffsusp");
854
855 /* XXX: "return" rv */
856 }
857
858 static void
859 puffsop_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
860 {
861 struct vnode *vp;
862 voff_t offlo, offhi;
863 int rv, flags = 0;
864
865 if (pf->pf_req.preq_pth.pth_framelen != sizeof(struct puffs_flush)) {
866 rv = EINVAL;
867 goto out;
868 }
869
870 /* XXX: slurry */
871 if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) {
872 cache_purgevfs(PMPTOMP(pmp));
873 rv = 0;
874 goto out;
875 }
876
877 /*
878 * Get vnode, don't lock it. Namecache is protected by its own lock
879 * and we have a reference to protect against premature harvesting.
880 *
881 * The node we want here might be locked and the op is in
882 * userspace waiting for us to complete ==> deadlock. Another
883 * reason we need to eventually bump locking to userspace, as we
884 * will need to lock the node if we wish to do flushes.
885 */
886 rv = puffs_cookie2vnode(pmp, pf->pf_cookie, 0, 0, &vp);
887 if (rv) {
888 if (rv == PUFFS_NOSUCHCOOKIE)
889 rv = ENOENT;
890 goto out;
891 }
892
893 switch (pf->pf_op) {
894 #if 0
895 /* not quite ready, yet */
896 case PUFFS_INVAL_NAMECACHE_NODE:
897 struct componentname *pf_cn;
898 char *name;
899 /* get comfortab^Wcomponentname */
900 pf_cn = kmem_alloc(componentname);
901 memset(pf_cn, 0, sizeof(struct componentname));
902 break;
903
904 #endif
905 case PUFFS_INVAL_NAMECACHE_DIR:
906 if (vp->v_type != VDIR) {
907 rv = EINVAL;
908 break;
909 }
910 cache_purge1(vp, NULL, PURGE_CHILDREN);
911 break;
912
913 case PUFFS_INVAL_PAGECACHE_NODE_RANGE:
914 flags = PGO_FREE;
915 /*FALLTHROUGH*/
916 case PUFFS_FLUSH_PAGECACHE_NODE_RANGE:
917 if (flags == 0)
918 flags = PGO_CLEANIT;
919
920 if (pf->pf_end > vp->v_size || vp->v_type != VREG) {
921 rv = EINVAL;
922 break;
923 }
924
925 offlo = trunc_page(pf->pf_start);
926 offhi = round_page(pf->pf_end);
927 if (offhi != 0 && offlo >= offhi) {
928 rv = EINVAL;
929 break;
930 }
931
932 mutex_enter(&vp->v_uobj.vmobjlock);
933 rv = VOP_PUTPAGES(vp, offlo, offhi, flags);
934 break;
935
936 default:
937 rv = EINVAL;
938 }
939
940 vrele(vp);
941
942 out:
943 puffs_msg_sendresp(pmp, &pf->pf_req, rv);
944 }
945
946 int
947 puffs_msgif_dispatch(void *this, struct putter_hdr *pth)
948 {
949 struct puffs_mount *pmp = this;
950 struct puffs_req *preq = (struct puffs_req *)pth;
951
952 /* XXX: need to send error to userspace */
953 if (pth->pth_framelen < sizeof(struct puffs_req)) {
954 puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */
955 return 0;
956 }
957
958 switch (PUFFSOP_OPCLASS(preq->preq_opclass)) {
959 case PUFFSOP_VN:
960 case PUFFSOP_VFS:
961 DPRINTF(("dispatch: vn/vfs message 0x%x\n", preq->preq_optype));
962 puffsop_msg(pmp, preq);
963 break;
964 case PUFFSOP_FLUSH:
965 DPRINTF(("dispatch: flush 0x%x\n", preq->preq_optype));
966 puffsop_flush(pmp, (struct puffs_flush *)preq);
967 break;
968 case PUFFSOP_SUSPEND:
969 DPRINTF(("dispatch: suspend\n"));
970 puffsop_suspend(pmp);
971 break;
972 default:
973 DPRINTF(("dispatch: invalid class 0x%x\n", preq->preq_opclass));
974 puffs_msg_sendresp(pmp, preq, EINVAL);
975 break;
976 }
977
978 return 0;
979 }
980
981 int
982 puffs_msgif_close(void *this)
983 {
984 struct puffs_mount *pmp = this;
985 struct mount *mp = PMPTOMP(pmp);
986 int rv;
987
988 mutex_enter(&pmp->pmp_lock);
989 puffs_mp_reference(pmp);
990
991 /*
992 * Free the waiting callers before proceeding any further.
993 * The syncer might be jogging around in this file system
994 * currently. If we allow it to go to the userspace of no
995 * return while trying to get the syncer lock, well ...
996 */
997 puffs_userdead(pmp);
998
999 /*
1000 * Make sure someone from puffs_unmount() isn't currently in
1001 * userspace. If we don't take this precautionary step,
1002 * they might notice that the mountpoint has disappeared
1003 * from under them once they return. Especially note that we
1004 * cannot simply test for an unmounter before calling
1005 * dounmount(), since it might be possible that that particular
1006 * invocation of unmount was called without MNT_FORCE. Here we
1007 * *must* make sure unmount succeeds. Also, restart is necessary
1008 * since pmp isn't locked. We might end up with PUTTER_DEAD after
1009 * restart and exit from there.
1010 */
1011 if (pmp->pmp_unmounting) {
1012 cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock);
1013 puffs_mp_release(pmp);
1014 mutex_exit(&pmp->pmp_lock);
1015 DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, "
1016 "restart\n", pmp));
1017 return ERESTART;
1018 }
1019
1020 /* Won't access pmp from here anymore */
1021 puffs_mp_release(pmp);
1022 mutex_exit(&pmp->pmp_lock);
1023
1024 /*
1025 * Detach from VFS. First do necessary XXX-dance (from
1026 * sys_unmount() & other callers of dounmount()
1027 *
1028 * XXX Freeze syncer. Must do this before locking the
1029 * mount point. See dounmount() for details.
1030 *
1031 * XXX2: take a reference to the mountpoint before starting to
1032 * wait for syncer_mutex. Otherwise the mointpoint can be
1033 * wiped out while we wait.
1034 */
1035 atomic_inc_uint((unsigned int*)&mp->mnt_refcnt);
1036 mutex_enter(&syncer_mutex);
1037 if (mp->mnt_iflag & IMNT_GONE) {
1038 mutex_exit(&syncer_mutex);
1039 vfs_destroy(mp);
1040 return 0;
1041 }
1042
1043 /*
1044 * microscopic race condition here (although not with the current
1045 * kernel), but can't really fix it without starting a crusade
1046 * against vfs_busy(), so let it be, let it be, let it be
1047 */
1048
1049 /*
1050 * The only way vfs_busy() will fail for us is if the filesystem
1051 * is already a goner.
1052 * XXX: skating on the thin ice of modern calling conventions ...
1053 */
1054 if (vfs_busy(mp, RW_WRITER, NULL)) {
1055 mutex_exit(&syncer_mutex);
1056 vfs_destroy(mp);
1057 return 0;
1058 }
1059
1060 /*
1061 * Once we have the mount point, unmount() can't interfere..
1062 * or at least in theory it shouldn't. dounmount() reentracy
1063 * might require some visiting at some point.
1064 */
1065 rv = dounmount(mp, MNT_FORCE, curlwp);
1066 KASSERT(rv == 0);
1067 vfs_destroy(mp);
1068
1069 return 0;
1070 }
1071
1072 /*
1073 * We're dead, kaput, RIP, slightly more than merely pining for the
1074 * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
1075 * our maker, ceased to be, etcetc. YASD. It's a dead FS!
1076 *
1077 * Caller must hold puffs mutex.
1078 */
1079 void
1080 puffs_userdead(struct puffs_mount *pmp)
1081 {
1082 struct puffs_msgpark *park, *park_next;
1083
1084 /*
1085 * Mark filesystem status as dying so that operations don't
1086 * attempt to march to userspace any longer.
1087 */
1088 pmp->pmp_status = PUFFSTAT_DYING;
1089
1090 /* signal waiters on REQUEST TO file server queue */
1091 for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) {
1092 uint8_t opclass;
1093
1094 mutex_enter(&park->park_mtx);
1095 puffs_msgpark_reference(park);
1096 park_next = TAILQ_NEXT(park, park_entries);
1097
1098 KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
1099 TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
1100 park->park_flags &= ~PARKFLAG_ONQUEUE1;
1101 pmp->pmp_msg_touser_count--;
1102
1103 /*
1104 * Even though waiters on QUEUE1 are removed in touser()
1105 * in case of WAITERGONE, it is still possible for us to
1106 * get raced here due to having to retake locks in said
1107 * touser(). In the race case simply "ignore" the item
1108 * on the queue and move on to the next one.
1109 */
1110 if (park->park_flags & PARKFLAG_WAITERGONE) {
1111 KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
1112 KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
1113 puffs_msgpark_release(park);
1114
1115 } else {
1116 opclass = park->park_preq->preq_opclass;
1117 park->park_preq->preq_rv = ENXIO;
1118
1119 if (park->park_flags & PARKFLAG_CALL) {
1120 park->park_done(pmp, park->park_preq,
1121 park->park_donearg);
1122 puffs_msgpark_release1(park, 2);
1123 } else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) {
1124 puffs_msgpark_release1(park, 2);
1125 } else {
1126 park->park_preq->preq_rv = ENXIO;
1127 cv_signal(&park->park_cv);
1128 puffs_msgpark_release(park);
1129 }
1130 }
1131 }
1132
1133 /* signal waiters on RESPONSE FROM file server queue */
1134 for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) {
1135 mutex_enter(&park->park_mtx);
1136 puffs_msgpark_reference(park);
1137 park_next = TAILQ_NEXT(park, park_entries);
1138
1139 KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
1140 KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
1141
1142 TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
1143 park->park_flags &= ~PARKFLAG_ONQUEUE2;
1144
1145 if (park->park_flags & PARKFLAG_WAITERGONE) {
1146 KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
1147 puffs_msgpark_release(park);
1148 } else {
1149 park->park_preq->preq_rv = ENXIO;
1150 if (park->park_flags & PARKFLAG_CALL) {
1151 park->park_done(pmp, park->park_preq,
1152 park->park_donearg);
1153 puffs_msgpark_release1(park, 2);
1154 } else {
1155 cv_signal(&park->park_cv);
1156 puffs_msgpark_release(park);
1157 }
1158 }
1159 }
1160
1161 cv_broadcast(&pmp->pmp_msg_waiter_cv);
1162 }
1163