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