1 1.65 thorpej /* $NetBSD: coda_psdev.c,v 1.65 2024/05/17 23:57:46 thorpej Exp $ */ 2 1.2 rvb 3 1.1 rvb /* 4 1.27 perry * 5 1.2 rvb * Coda: an Experimental Distributed File System 6 1.2 rvb * Release 3.1 7 1.27 perry * 8 1.2 rvb * Copyright (c) 1987-1998 Carnegie Mellon University 9 1.2 rvb * All Rights Reserved 10 1.27 perry * 11 1.2 rvb * Permission to use, copy, modify and distribute this software and its 12 1.2 rvb * documentation is hereby granted, provided that both the copyright 13 1.2 rvb * notice and this permission notice appear in all copies of the 14 1.2 rvb * software, derivative works or modified versions, and any portions 15 1.2 rvb * thereof, and that both notices appear in supporting documentation, and 16 1.2 rvb * that credit is given to Carnegie Mellon University in all documents 17 1.2 rvb * and publicity pertaining to direct or indirect use of this code or its 18 1.2 rvb * derivatives. 19 1.27 perry * 20 1.2 rvb * CODA IS AN EXPERIMENTAL SOFTWARE SYSTEM AND IS KNOWN TO HAVE BUGS, 21 1.2 rvb * SOME OF WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON ALLOWS 22 1.2 rvb * FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON 23 1.2 rvb * DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER 24 1.2 rvb * RESULTING DIRECTLY OR INDIRECTLY FROM THE USE OF THIS SOFTWARE OR OF 25 1.2 rvb * ANY DERIVATIVE WORK. 26 1.27 perry * 27 1.2 rvb * Carnegie Mellon encourages users of this software to return any 28 1.2 rvb * improvements or extensions that they make, and to grant Carnegie 29 1.2 rvb * Mellon the rights to redistribute these changes without encumbrance. 30 1.27 perry * 31 1.27 perry * @(#) coda/coda_psdev.c,v 1.1.1.1 1998/08/29 21:26:45 rvb Exp $ 32 1.2 rvb */ 33 1.1 rvb 34 1.27 perry /* 35 1.1 rvb * Mach Operating System 36 1.1 rvb * Copyright (c) 1989 Carnegie-Mellon University 37 1.1 rvb * All rights reserved. The CMU software License Agreement specifies 38 1.1 rvb * the terms and conditions for use and redistribution. 39 1.1 rvb */ 40 1.1 rvb 41 1.1 rvb /* 42 1.1 rvb * This code was written for the Coda file system at Carnegie Mellon 43 1.1 rvb * University. Contributers include David Steere, James Kistler, and 44 1.1 rvb * M. Satyanarayanan. */ 45 1.1 rvb 46 1.24 jdolecek /* These routines define the pseudo device for communication between 47 1.27 perry * Coda's Venus and Minicache in Mach 2.6. They used to be in cfs_subr.c, 48 1.27 perry * but I moved them to make it easier to port the Minicache without 49 1.1 rvb * porting coda. -- DCS 10/12/94 50 1.24 jdolecek * 51 1.24 jdolecek * Following code depends on file-system CODA. 52 1.1 rvb */ 53 1.1 rvb 54 1.1 rvb /* These routines are the device entry points for Venus. */ 55 1.18 lukem 56 1.18 lukem #include <sys/cdefs.h> 57 1.65 thorpej __KERNEL_RCSID(0, "$NetBSD: coda_psdev.c,v 1.65 2024/05/17 23:57:46 thorpej Exp $"); 58 1.1 rvb 59 1.3 rvb extern int coda_nc_initialized; /* Set if cache has been initialized */ 60 1.1 rvb 61 1.1 rvb #include <sys/param.h> 62 1.1 rvb #include <sys/systm.h> 63 1.1 rvb #include <sys/kernel.h> 64 1.1 rvb #include <sys/proc.h> 65 1.1 rvb #include <sys/mount.h> 66 1.1 rvb #include <sys/file.h> 67 1.1 rvb #include <sys/ioctl.h> 68 1.1 rvb #include <sys/poll.h> 69 1.1 rvb #include <sys/select.h> 70 1.20 gehenna #include <sys/conf.h> 71 1.45 ad #include <sys/atomic.h> 72 1.48 christos #include <sys/module.h> 73 1.1 rvb 74 1.4 rvb #include <coda/coda.h> 75 1.4 rvb #include <coda/cnode.h> 76 1.4 rvb #include <coda/coda_namecache.h> 77 1.4 rvb #include <coda/coda_io.h> 78 1.1 rvb 79 1.56 christos #include "ioconf.h" 80 1.56 christos 81 1.2 rvb #define CTL_C 82 1.2 rvb 83 1.3 rvb int coda_psdev_print_entry = 0; 84 1.8 rvb static 85 1.8 rvb int outstanding_upcalls = 0; 86 1.8 rvb int coda_call_sleep = PZERO - 1; 87 1.8 rvb #ifdef CTL_C 88 1.8 rvb int coda_pcatch = PCATCH; 89 1.8 rvb #else 90 1.8 rvb #endif 91 1.3 rvb 92 1.48 christos int coda_kernel_version = CODA_KERNEL_VERSION; 93 1.48 christos 94 1.19 perry #define ENTRY if(coda_psdev_print_entry) myprintf(("Entered %s\n",__func__)) 95 1.1 rvb 96 1.20 gehenna dev_type_open(vc_nb_open); 97 1.20 gehenna dev_type_close(vc_nb_close); 98 1.20 gehenna dev_type_read(vc_nb_read); 99 1.20 gehenna dev_type_write(vc_nb_write); 100 1.20 gehenna dev_type_ioctl(vc_nb_ioctl); 101 1.20 gehenna dev_type_poll(vc_nb_poll); 102 1.21 jdolecek dev_type_kqfilter(vc_nb_kqfilter); 103 1.20 gehenna 104 1.20 gehenna const struct cdevsw vcoda_cdevsw = { 105 1.52 dholland .d_open = vc_nb_open, 106 1.52 dholland .d_close = vc_nb_close, 107 1.52 dholland .d_read = vc_nb_read, 108 1.52 dholland .d_write = vc_nb_write, 109 1.52 dholland .d_ioctl = vc_nb_ioctl, 110 1.52 dholland .d_stop = nostop, 111 1.52 dholland .d_tty = notty, 112 1.52 dholland .d_poll = vc_nb_poll, 113 1.52 dholland .d_mmap = nommap, 114 1.52 dholland .d_kqfilter = vc_nb_kqfilter, 115 1.53 dholland .d_discard = nodiscard, 116 1.52 dholland .d_flag = D_OTHER, 117 1.20 gehenna }; 118 1.1 rvb 119 1.1 rvb struct vmsg { 120 1.41 plunky TAILQ_ENTRY(vmsg) vm_chain; 121 1.36 christos void * vm_data; 122 1.1 rvb u_short vm_flags; 123 1.1 rvb u_short vm_inSize; /* Size is at most 5000 bytes */ 124 1.1 rvb u_short vm_outSize; 125 1.1 rvb u_short vm_opcode; /* copied from data to save ptr lookup */ 126 1.1 rvb int vm_unique; 127 1.36 christos void * vm_sleep; /* Not used by Mach. */ 128 1.1 rvb }; 129 1.1 rvb 130 1.48 christos struct coda_mntinfo coda_mnttbl[NVCODA]; 131 1.48 christos 132 1.1 rvb #define VM_READ 1 133 1.1 rvb #define VM_WRITE 2 134 1.1 rvb #define VM_INTR 4 135 1.1 rvb 136 1.3 rvb /* vcodaattach: do nothing */ 137 1.1 rvb void 138 1.34 christos vcodaattach(int n) 139 1.1 rvb { 140 1.1 rvb } 141 1.1 rvb 142 1.27 perry /* 143 1.1 rvb * These functions are written for NetBSD. 144 1.1 rvb */ 145 1.27 perry int 146 1.34 christos vc_nb_open(dev_t dev, int flag, int mode, 147 1.34 christos struct lwp *l) 148 1.1 rvb { 149 1.13 augustss struct vcomm *vcp; 150 1.27 perry 151 1.1 rvb ENTRY; 152 1.1 rvb 153 1.47 christos if (minor(dev) >= NVCODA) 154 1.1 rvb return(ENXIO); 155 1.27 perry 156 1.3 rvb if (!coda_nc_initialized) 157 1.3 rvb coda_nc_init(); 158 1.27 perry 159 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 160 1.1 rvb if (VC_OPEN(vcp)) 161 1.1 rvb return(EBUSY); 162 1.27 perry 163 1.39 rmind selinit(&vcp->vc_selproc); 164 1.41 plunky TAILQ_INIT(&vcp->vc_requests); 165 1.41 plunky TAILQ_INIT(&vcp->vc_replies); 166 1.1 rvb MARK_VC_OPEN(vcp); 167 1.27 perry 168 1.3 rvb coda_mnttbl[minor(dev)].mi_vfsp = NULL; 169 1.3 rvb coda_mnttbl[minor(dev)].mi_rootvp = NULL; 170 1.1 rvb 171 1.1 rvb return(0); 172 1.1 rvb } 173 1.1 rvb 174 1.27 perry int 175 1.34 christos vc_nb_close(dev_t dev, int flag, int mode, struct lwp *l) 176 1.1 rvb { 177 1.13 augustss struct vcomm *vcp; 178 1.41 plunky struct vmsg *vmp; 179 1.3 rvb struct coda_mntinfo *mi; 180 1.1 rvb int err; 181 1.27 perry 182 1.1 rvb ENTRY; 183 1.1 rvb 184 1.47 christos if (minor(dev) >= NVCODA) 185 1.1 rvb return(ENXIO); 186 1.1 rvb 187 1.3 rvb mi = &coda_mnttbl[minor(dev)]; 188 1.1 rvb vcp = &(mi->mi_vcomm); 189 1.27 perry 190 1.1 rvb if (!VC_OPEN(vcp)) 191 1.1 rvb panic("vcclose: not open"); 192 1.27 perry 193 1.1 rvb /* prevent future operations on this vfs from succeeding by auto- 194 1.1 rvb * unmounting any vfs mounted via this device. This frees user or 195 1.1 rvb * sysadm from having to remember where all mount points are located. 196 1.1 rvb * Put this before WAKEUPs to avoid queuing new messages between 197 1.1 rvb * the WAKEUP and the unmount (which can happen if we're unlucky) 198 1.1 rvb */ 199 1.8 rvb if (!mi->mi_rootvp) { 200 1.8 rvb /* just a simple open/close w no mount */ 201 1.8 rvb MARK_VC_CLOSED(vcp); 202 1.8 rvb return 0; 203 1.1 rvb } 204 1.8 rvb 205 1.8 rvb /* Let unmount know this is for real */ 206 1.8 rvb VTOC(mi->mi_rootvp)->c_flags |= C_UNMOUNTING; 207 1.8 rvb coda_unmounting(mi->mi_vfsp); 208 1.27 perry 209 1.1 rvb /* Wakeup clients so they can return. */ 210 1.41 plunky while ((vmp = TAILQ_FIRST(&vcp->vc_requests)) != NULL) { 211 1.41 plunky TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain); 212 1.41 plunky 213 1.1 rvb /* Free signal request messages and don't wakeup cause 214 1.1 rvb no one is waiting. */ 215 1.3 rvb if (vmp->vm_opcode == CODA_SIGNAL) { 216 1.40 plunky CODA_FREE(vmp->vm_data, VC_IN_NO_DATA); 217 1.40 plunky CODA_FREE(vmp, sizeof(struct vmsg)); 218 1.1 rvb continue; 219 1.1 rvb } 220 1.27 perry outstanding_upcalls++; 221 1.1 rvb wakeup(&vmp->vm_sleep); 222 1.1 rvb } 223 1.8 rvb 224 1.41 plunky while ((vmp = TAILQ_FIRST(&vcp->vc_replies)) != NULL) { 225 1.41 plunky TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain); 226 1.41 plunky 227 1.27 perry outstanding_upcalls++; 228 1.1 rvb wakeup(&vmp->vm_sleep); 229 1.1 rvb } 230 1.8 rvb 231 1.1 rvb MARK_VC_CLOSED(vcp); 232 1.8 rvb 233 1.8 rvb if (outstanding_upcalls) { 234 1.8 rvb #ifdef CODA_VERBOSE 235 1.8 rvb printf("presleep: outstanding_upcalls = %d\n", outstanding_upcalls); 236 1.8 rvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 237 1.8 rvb printf("postsleep: outstanding_upcalls = %d\n", outstanding_upcalls); 238 1.8 rvb #else 239 1.8 rvb (void) tsleep(&outstanding_upcalls, coda_call_sleep, "coda_umount", 0); 240 1.8 rvb #endif 241 1.8 rvb } 242 1.8 rvb 243 1.31 christos err = dounmount(mi->mi_vfsp, flag, l); 244 1.8 rvb if (err) 245 1.47 christos myprintf(("Error %d unmounting vfs in vcclose(%llu)\n", 246 1.47 christos err, (unsigned long long)minor(dev))); 247 1.39 rmind seldestroy(&vcp->vc_selproc); 248 1.1 rvb return 0; 249 1.1 rvb } 250 1.1 rvb 251 1.27 perry int 252 1.34 christos vc_nb_read(dev_t dev, struct uio *uiop, int flag) 253 1.1 rvb { 254 1.13 augustss struct vcomm * vcp; 255 1.13 augustss struct vmsg *vmp; 256 1.1 rvb int error = 0; 257 1.27 perry 258 1.1 rvb ENTRY; 259 1.1 rvb 260 1.47 christos if (minor(dev) >= NVCODA) 261 1.1 rvb return(ENXIO); 262 1.27 perry 263 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 264 1.41 plunky 265 1.1 rvb /* Get message at head of request queue. */ 266 1.41 plunky vmp = TAILQ_FIRST(&vcp->vc_requests); 267 1.41 plunky if (vmp == NULL) 268 1.1 rvb return(0); /* Nothing to read */ 269 1.27 perry 270 1.1 rvb /* Move the input args into userspace */ 271 1.1 rvb uiop->uio_rw = UIO_READ; 272 1.1 rvb error = uiomove(vmp->vm_data, vmp->vm_inSize, uiop); 273 1.1 rvb if (error) { 274 1.1 rvb myprintf(("vcread: error (%d) on uiomove\n", error)); 275 1.1 rvb error = EINVAL; 276 1.1 rvb } 277 1.1 rvb 278 1.41 plunky TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain); 279 1.27 perry 280 1.1 rvb /* If request was a signal, free up the message and don't 281 1.1 rvb enqueue it in the reply queue. */ 282 1.3 rvb if (vmp->vm_opcode == CODA_SIGNAL) { 283 1.3 rvb if (codadebug) 284 1.27 perry myprintf(("vcread: signal msg (%d, %d)\n", 285 1.1 rvb vmp->vm_opcode, vmp->vm_unique)); 286 1.40 plunky CODA_FREE(vmp->vm_data, VC_IN_NO_DATA); 287 1.40 plunky CODA_FREE(vmp, sizeof(struct vmsg)); 288 1.1 rvb return(error); 289 1.1 rvb } 290 1.27 perry 291 1.1 rvb vmp->vm_flags |= VM_READ; 292 1.41 plunky TAILQ_INSERT_TAIL(&vcp->vc_replies, vmp, vm_chain); 293 1.27 perry 294 1.1 rvb return(error); 295 1.1 rvb } 296 1.1 rvb 297 1.1 rvb int 298 1.34 christos vc_nb_write(dev_t dev, struct uio *uiop, int flag) 299 1.1 rvb { 300 1.13 augustss struct vcomm * vcp; 301 1.13 augustss struct vmsg *vmp; 302 1.3 rvb struct coda_out_hdr *out; 303 1.1 rvb u_long seq; 304 1.1 rvb u_long opcode; 305 1.28 christos int tbuf[2]; 306 1.1 rvb int error = 0; 307 1.1 rvb 308 1.1 rvb ENTRY; 309 1.1 rvb 310 1.47 christos if (minor(dev) >= NVCODA) 311 1.1 rvb return(ENXIO); 312 1.27 perry 313 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 314 1.27 perry 315 1.62 andvar /* Peek at the opcode, unique without transferring the data. */ 316 1.1 rvb uiop->uio_rw = UIO_WRITE; 317 1.40 plunky error = uiomove(tbuf, sizeof(int) * 2, uiop); 318 1.1 rvb if (error) { 319 1.1 rvb myprintf(("vcwrite: error (%d) on uiomove\n", error)); 320 1.1 rvb return(EINVAL); 321 1.1 rvb } 322 1.27 perry 323 1.28 christos opcode = tbuf[0]; 324 1.28 christos seq = tbuf[1]; 325 1.27 perry 326 1.3 rvb if (codadebug) 327 1.1 rvb myprintf(("vcwrite got a call for %ld.%ld\n", opcode, seq)); 328 1.27 perry 329 1.1 rvb if (DOWNCALL(opcode)) { 330 1.1 rvb union outputArgs pbuf; 331 1.27 perry 332 1.1 rvb /* get the rest of the data. */ 333 1.1 rvb uiop->uio_rw = UIO_WRITE; 334 1.40 plunky error = uiomove(&pbuf.coda_purgeuser.oh.result, sizeof(pbuf) - (sizeof(int)*2), uiop); 335 1.1 rvb if (error) { 336 1.27 perry myprintf(("vcwrite: error (%d) on uiomove (Op %ld seq %ld)\n", 337 1.1 rvb error, opcode, seq)); 338 1.1 rvb return(EINVAL); 339 1.1 rvb } 340 1.27 perry 341 1.1 rvb return handleDownCall(opcode, &pbuf); 342 1.1 rvb } 343 1.27 perry 344 1.1 rvb /* Look for the message on the (waiting for) reply queue. */ 345 1.41 plunky TAILQ_FOREACH(vmp, &vcp->vc_replies, vm_chain) { 346 1.1 rvb if (vmp->vm_unique == seq) break; 347 1.1 rvb } 348 1.27 perry 349 1.41 plunky if (vmp == NULL) { 350 1.3 rvb if (codadebug) 351 1.1 rvb myprintf(("vcwrite: msg (%ld, %ld) not found\n", opcode, seq)); 352 1.27 perry 353 1.1 rvb return(ESRCH); 354 1.41 plunky } 355 1.27 perry 356 1.1 rvb /* Remove the message from the reply queue */ 357 1.41 plunky TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain); 358 1.27 perry 359 1.1 rvb /* move data into response buffer. */ 360 1.3 rvb out = (struct coda_out_hdr *)vmp->vm_data; 361 1.1 rvb /* Don't need to copy opcode and uniquifier. */ 362 1.27 perry 363 1.1 rvb /* get the rest of the data. */ 364 1.1 rvb if (vmp->vm_outSize < uiop->uio_resid) { 365 1.11 matt myprintf(("vcwrite: more data than asked for (%d < %lu)\n", 366 1.11 matt vmp->vm_outSize, (unsigned long) uiop->uio_resid)); 367 1.1 rvb wakeup(&vmp->vm_sleep); /* Notify caller of the error. */ 368 1.1 rvb return(EINVAL); 369 1.27 perry } 370 1.27 perry 371 1.28 christos tbuf[0] = uiop->uio_resid; /* Save this value. */ 372 1.1 rvb uiop->uio_rw = UIO_WRITE; 373 1.40 plunky error = uiomove(&out->result, vmp->vm_outSize - (sizeof(int) * 2), uiop); 374 1.1 rvb if (error) { 375 1.27 perry myprintf(("vcwrite: error (%d) on uiomove (op %ld seq %ld)\n", 376 1.1 rvb error, opcode, seq)); 377 1.1 rvb return(EINVAL); 378 1.1 rvb } 379 1.27 perry 380 1.1 rvb /* I don't think these are used, but just in case. */ 381 1.1 rvb /* XXX - aren't these two already correct? -bnoble */ 382 1.1 rvb out->opcode = opcode; 383 1.1 rvb out->unique = seq; 384 1.28 christos vmp->vm_outSize = tbuf[0]; /* Amount of data transferred? */ 385 1.1 rvb vmp->vm_flags |= VM_WRITE; 386 1.1 rvb wakeup(&vmp->vm_sleep); 387 1.27 perry 388 1.1 rvb return(0); 389 1.1 rvb } 390 1.1 rvb 391 1.1 rvb int 392 1.36 christos vc_nb_ioctl(dev_t dev, u_long cmd, void *addr, int flag, 393 1.34 christos struct lwp *l) 394 1.1 rvb { 395 1.1 rvb ENTRY; 396 1.1 rvb 397 1.57 msaitoh switch (cmd) { 398 1.3 rvb case CODARESIZE: { 399 1.3 rvb struct coda_resize *data = (struct coda_resize *)addr; 400 1.3 rvb return(coda_nc_resize(data->hashsize, data->heapsize, IS_DOWNCALL)); 401 1.1 rvb break; 402 1.1 rvb } 403 1.3 rvb case CODASTATS: 404 1.3 rvb if (coda_nc_use) { 405 1.3 rvb coda_nc_gather_stats(); 406 1.1 rvb return(0); 407 1.1 rvb } else { 408 1.1 rvb return(ENODEV); 409 1.1 rvb } 410 1.1 rvb break; 411 1.3 rvb case CODAPRINT: 412 1.3 rvb if (coda_nc_use) { 413 1.3 rvb print_coda_nc(); 414 1.1 rvb return(0); 415 1.1 rvb } else { 416 1.1 rvb return(ENODEV); 417 1.1 rvb } 418 1.1 rvb break; 419 1.9 rvb case CIOC_KERNEL_VERSION: 420 1.9 rvb switch (*(u_int *)addr) { 421 1.9 rvb case 0: 422 1.9 rvb *(u_int *)addr = coda_kernel_version; 423 1.9 rvb return 0; 424 1.9 rvb break; 425 1.9 rvb case 1: 426 1.9 rvb case 2: 427 1.9 rvb if (coda_kernel_version != *(u_int *)addr) 428 1.9 rvb return ENOENT; 429 1.9 rvb else 430 1.9 rvb return 0; 431 1.9 rvb default: 432 1.9 rvb return ENOENT; 433 1.9 rvb } 434 1.9 rvb break; 435 1.1 rvb default : 436 1.1 rvb return(EINVAL); 437 1.1 rvb break; 438 1.1 rvb } 439 1.1 rvb } 440 1.1 rvb 441 1.1 rvb int 442 1.31 christos vc_nb_poll(dev_t dev, int events, struct lwp *l) 443 1.1 rvb { 444 1.13 augustss struct vcomm *vcp; 445 1.1 rvb int event_msk = 0; 446 1.1 rvb 447 1.1 rvb ENTRY; 448 1.27 perry 449 1.47 christos if (minor(dev) >= NVCODA) 450 1.1 rvb return(ENXIO); 451 1.27 perry 452 1.3 rvb vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 453 1.27 perry 454 1.1 rvb event_msk = events & (POLLIN|POLLRDNORM); 455 1.1 rvb if (!event_msk) 456 1.1 rvb return(0); 457 1.27 perry 458 1.41 plunky if (!TAILQ_EMPTY(&vcp->vc_requests)) 459 1.1 rvb return(events & (POLLIN|POLLRDNORM)); 460 1.1 rvb 461 1.31 christos selrecord(l, &(vcp->vc_selproc)); 462 1.27 perry 463 1.1 rvb return(0); 464 1.1 rvb } 465 1.1 rvb 466 1.21 jdolecek static void 467 1.21 jdolecek filt_vc_nb_detach(struct knote *kn) 468 1.21 jdolecek { 469 1.21 jdolecek struct vcomm *vcp = kn->kn_hook; 470 1.21 jdolecek 471 1.59 thorpej selremove_knote(&vcp->vc_selproc, kn); 472 1.21 jdolecek } 473 1.21 jdolecek 474 1.21 jdolecek static int 475 1.34 christos filt_vc_nb_read(struct knote *kn, long hint) 476 1.21 jdolecek { 477 1.27 perry struct vcomm *vcp = kn->kn_hook; 478 1.21 jdolecek struct vmsg *vmp; 479 1.21 jdolecek 480 1.41 plunky vmp = TAILQ_FIRST(&vcp->vc_requests); 481 1.41 plunky if (vmp == NULL) 482 1.21 jdolecek return (0); 483 1.21 jdolecek 484 1.21 jdolecek kn->kn_data = vmp->vm_inSize; 485 1.21 jdolecek return (1); 486 1.21 jdolecek } 487 1.21 jdolecek 488 1.58 maya static const struct filterops vc_nb_read_filtops = { 489 1.60 thorpej .f_flags = FILTEROP_ISFD, 490 1.58 maya .f_attach = NULL, 491 1.58 maya .f_detach = filt_vc_nb_detach, 492 1.58 maya .f_event = filt_vc_nb_read, 493 1.58 maya }; 494 1.21 jdolecek 495 1.21 jdolecek int 496 1.21 jdolecek vc_nb_kqfilter(dev_t dev, struct knote *kn) 497 1.21 jdolecek { 498 1.21 jdolecek struct vcomm *vcp; 499 1.21 jdolecek 500 1.21 jdolecek ENTRY; 501 1.27 perry 502 1.47 christos if (minor(dev) >= NVCODA) 503 1.21 jdolecek return(ENXIO); 504 1.27 perry 505 1.21 jdolecek vcp = &coda_mnttbl[minor(dev)].mi_vcomm; 506 1.21 jdolecek 507 1.21 jdolecek switch (kn->kn_filter) { 508 1.21 jdolecek case EVFILT_READ: 509 1.21 jdolecek kn->kn_fop = &vc_nb_read_filtops; 510 1.21 jdolecek break; 511 1.21 jdolecek 512 1.21 jdolecek default: 513 1.37 pooka return (EINVAL); 514 1.21 jdolecek } 515 1.21 jdolecek 516 1.21 jdolecek kn->kn_hook = vcp; 517 1.21 jdolecek 518 1.59 thorpej selrecord_knote(&vcp->vc_selproc, kn); 519 1.21 jdolecek 520 1.21 jdolecek return (0); 521 1.21 jdolecek } 522 1.21 jdolecek 523 1.1 rvb /* 524 1.1 rvb * Statistics 525 1.1 rvb */ 526 1.3 rvb struct coda_clstat coda_clstat; 527 1.1 rvb 528 1.27 perry /* 529 1.23 wiz * Key question: whether to sleep interruptably or uninterruptably when 530 1.1 rvb * waiting for Venus. The former seems better (cause you can ^C a 531 1.1 rvb * job), but then GNU-EMACS completion breaks. Use tsleep with no 532 1.1 rvb * timeout, and no longjmp happens. But, when sleeping 533 1.1 rvb * "uninterruptibly", we don't get told if it returns abnormally 534 1.27 perry * (e.g. kill -9). 535 1.1 rvb */ 536 1.1 rvb 537 1.1 rvb int 538 1.30 xtraeme coda_call(struct coda_mntinfo *mntinfo, int inSize, int *outSize, 539 1.36 christos void *buffer) 540 1.1 rvb { 541 1.1 rvb struct vcomm *vcp; 542 1.1 rvb struct vmsg *vmp; 543 1.1 rvb int error; 544 1.1 rvb #ifdef CTL_C 545 1.31 christos struct lwp *l = curlwp; 546 1.31 christos struct proc *p = l->l_proc; 547 1.4 rvb sigset_t psig_omask; 548 1.1 rvb int i; 549 1.35 ad psig_omask = l->l_sigmask; /* XXXSA */ 550 1.1 rvb #endif 551 1.1 rvb if (mntinfo == NULL) { 552 1.1 rvb /* Unlikely, but could be a race condition with a dying warden */ 553 1.1 rvb return ENODEV; 554 1.1 rvb } 555 1.1 rvb 556 1.1 rvb vcp = &(mntinfo->mi_vcomm); 557 1.27 perry 558 1.3 rvb coda_clstat.ncalls++; 559 1.3 rvb coda_clstat.reqs[((struct coda_in_hdr *)buffer)->opcode]++; 560 1.1 rvb 561 1.1 rvb if (!VC_OPEN(vcp)) 562 1.1 rvb return(ENODEV); 563 1.1 rvb 564 1.3 rvb CODA_ALLOC(vmp,struct vmsg *,sizeof(struct vmsg)); 565 1.1 rvb /* Format the request message. */ 566 1.1 rvb vmp->vm_data = buffer; 567 1.1 rvb vmp->vm_flags = 0; 568 1.1 rvb vmp->vm_inSize = inSize; 569 1.27 perry vmp->vm_outSize 570 1.1 rvb = *outSize ? *outSize : inSize; /* |buffer| >= inSize */ 571 1.3 rvb vmp->vm_opcode = ((struct coda_in_hdr *)buffer)->opcode; 572 1.1 rvb vmp->vm_unique = ++vcp->vc_seq; 573 1.3 rvb if (codadebug) 574 1.27 perry myprintf(("Doing a call for %d.%d\n", 575 1.1 rvb vmp->vm_opcode, vmp->vm_unique)); 576 1.27 perry 577 1.1 rvb /* Fill in the common input args. */ 578 1.3 rvb ((struct coda_in_hdr *)buffer)->unique = vmp->vm_unique; 579 1.1 rvb 580 1.1 rvb /* Append msg to request queue and poke Venus. */ 581 1.41 plunky TAILQ_INSERT_TAIL(&vcp->vc_requests, vmp, vm_chain); 582 1.39 rmind selnotify(&(vcp->vc_selproc), 0, 0); 583 1.1 rvb 584 1.1 rvb /* We can be interrupted while we wait for Venus to process 585 1.1 rvb * our request. If the interrupt occurs before Venus has read 586 1.1 rvb * the request, we dequeue and return. If it occurs after the 587 1.1 rvb * read but before the reply, we dequeue, send a signal 588 1.1 rvb * message, and return. If it occurs after the reply we ignore 589 1.1 rvb * it. In no case do we want to restart the syscall. If it 590 1.1 rvb * was interrupted by a venus shutdown (vcclose), return 591 1.1 rvb * ENODEV. */ 592 1.1 rvb 593 1.1 rvb /* Ignore return, We have to check anyway */ 594 1.1 rvb #ifdef CTL_C 595 1.3 rvb /* This is work in progress. Setting coda_pcatch lets tsleep reawaken 596 1.1 rvb on a ^c or ^z. The problem is that emacs sets certain interrupts 597 1.1 rvb as SA_RESTART. This means that we should exit sleep handle the 598 1.1 rvb "signal" and then go to sleep again. Mostly this is done by letting 599 1.27 perry the syscall complete and be restarted. We are not idempotent and 600 1.1 rvb can not do this. A better solution is necessary. 601 1.1 rvb */ 602 1.1 rvb i = 0; 603 1.1 rvb do { 604 1.3 rvb error = tsleep(&vmp->vm_sleep, (coda_call_sleep|coda_pcatch), "coda_call", hz*2); 605 1.1 rvb if (error == 0) 606 1.1 rvb break; 607 1.43 ad mutex_enter(p->p_lock); 608 1.35 ad if (error == EWOULDBLOCK) { 609 1.7 rvb #ifdef CODA_VERBOSE 610 1.3 rvb printf("coda_call: tsleep TIMEOUT %d sec\n", 2+2*i); 611 1.5 rvb #endif 612 1.35 ad } else if (sigispending(l, SIGIO)) { 613 1.35 ad sigaddset(&l->l_sigmask, SIGIO); 614 1.7 rvb #ifdef CODA_VERBOSE 615 1.3 rvb printf("coda_call: tsleep returns %d SIGIO, cnt %d\n", error, i); 616 1.5 rvb #endif 617 1.35 ad } else if (sigispending(l, SIGALRM)) { 618 1.35 ad sigaddset(&l->l_sigmask, SIGALRM); 619 1.8 rvb #ifdef CODA_VERBOSE 620 1.8 rvb printf("coda_call: tsleep returns %d SIGALRM, cnt %d\n", error, i); 621 1.8 rvb #endif 622 1.1 rvb } else { 623 1.4 rvb sigset_t tmp; 624 1.35 ad tmp = p->p_sigpend.sp_set; /* array assignment */ 625 1.35 ad sigminusset(&l->l_sigmask, &tmp); 626 1.4 rvb 627 1.7 rvb #ifdef CODA_VERBOSE 628 1.3 rvb printf("coda_call: tsleep returns %d, cnt %d\n", error, i); 629 1.4 rvb printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x, mask %x.%x.%x.%x\n", 630 1.35 ad p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1], 631 1.35 ad p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3], 632 1.35 ad l->l_sigmask.__bits[0], l->l_sigmask.__bits[1], 633 1.35 ad l->l_sigmask.__bits[2], l->l_sigmask.__bits[3], 634 1.4 rvb tmp.__bits[0], tmp.__bits[1], tmp.__bits[2], tmp.__bits[3]); 635 1.5 rvb #endif 636 1.43 ad mutex_exit(p->p_lock); 637 1.1 rvb break; 638 1.5 rvb #ifdef notyet 639 1.35 ad sigminusset(&l->l_sigmask, &p->p_sigpend.sp_set); 640 1.27 perry printf("coda_call: siglist = %x.%x.%x.%x, sigmask = %x.%x.%x.%x\n", 641 1.35 ad p->p_sigpend.sp_set.__bits[0], p->p_sigpend.sp_set.__bits[1], 642 1.35 ad p->p_sigpend.sp_set.__bits[2], p->p_sigpend.sp_set.__bits[3], 643 1.35 ad l->l_sigmask.__bits[0], l->l_sigmask.__bits[1], 644 1.35 ad l->l_sigmask.__bits[2], l->l_sigmask.__bits[3]); 645 1.5 rvb #endif 646 1.1 rvb } 647 1.43 ad mutex_exit(p->p_lock); 648 1.8 rvb } while (error && i++ < 128 && VC_OPEN(vcp)); 649 1.35 ad l->l_sigmask = psig_omask; /* XXXSA */ 650 1.1 rvb #else 651 1.3 rvb (void) tsleep(&vmp->vm_sleep, coda_call_sleep, "coda_call", 0); 652 1.1 rvb #endif 653 1.1 rvb if (VC_OPEN(vcp)) { /* Venus is still alive */ 654 1.1 rvb /* Op went through, interrupt or not... */ 655 1.1 rvb if (vmp->vm_flags & VM_WRITE) { 656 1.1 rvb error = 0; 657 1.1 rvb *outSize = vmp->vm_outSize; 658 1.1 rvb } 659 1.1 rvb 660 1.27 perry else if (!(vmp->vm_flags & VM_READ)) { 661 1.1 rvb /* Interrupted before venus read it. */ 662 1.7 rvb #ifdef CODA_VERBOSE 663 1.7 rvb if (1) 664 1.7 rvb #else 665 1.5 rvb if (codadebug) 666 1.5 rvb #endif 667 1.1 rvb myprintf(("interrupted before read: op = %d.%d, flags = %x\n", 668 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 669 1.41 plunky 670 1.41 plunky TAILQ_REMOVE(&vcp->vc_requests, vmp, vm_chain); 671 1.1 rvb error = EINTR; 672 1.1 rvb } 673 1.27 perry 674 1.27 perry else { 675 1.1 rvb /* (!(vmp->vm_flags & VM_WRITE)) means interrupted after 676 1.1 rvb upcall started */ 677 1.1 rvb /* Interrupted after start of upcall, send venus a signal */ 678 1.3 rvb struct coda_in_hdr *dog; 679 1.1 rvb struct vmsg *svmp; 680 1.27 perry 681 1.7 rvb #ifdef CODA_VERBOSE 682 1.7 rvb if (1) 683 1.7 rvb #else 684 1.5 rvb if (codadebug) 685 1.5 rvb #endif 686 1.1 rvb myprintf(("Sending Venus a signal: op = %d.%d, flags = %x\n", 687 1.1 rvb vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 688 1.27 perry 689 1.41 plunky TAILQ_REMOVE(&vcp->vc_replies, vmp, vm_chain); 690 1.1 rvb error = EINTR; 691 1.27 perry 692 1.3 rvb CODA_ALLOC(svmp, struct vmsg *, sizeof (struct vmsg)); 693 1.1 rvb 694 1.3 rvb CODA_ALLOC((svmp->vm_data), char *, sizeof (struct coda_in_hdr)); 695 1.3 rvb dog = (struct coda_in_hdr *)svmp->vm_data; 696 1.27 perry 697 1.1 rvb svmp->vm_flags = 0; 698 1.3 rvb dog->opcode = svmp->vm_opcode = CODA_SIGNAL; 699 1.1 rvb dog->unique = svmp->vm_unique = vmp->vm_unique; 700 1.3 rvb svmp->vm_inSize = sizeof (struct coda_in_hdr); 701 1.3 rvb /*??? rvb */ svmp->vm_outSize = sizeof (struct coda_in_hdr); 702 1.27 perry 703 1.3 rvb if (codadebug) 704 1.64 andvar myprintf(("coda_call: enqueuing signal msg (%d, %d)\n", 705 1.1 rvb svmp->vm_opcode, svmp->vm_unique)); 706 1.27 perry 707 1.42 plunky /* insert at head of queue */ 708 1.42 plunky TAILQ_INSERT_HEAD(&vcp->vc_requests, svmp, vm_chain); 709 1.39 rmind selnotify(&(vcp->vc_selproc), 0, 0); 710 1.1 rvb } 711 1.1 rvb } 712 1.1 rvb 713 1.1 rvb else { /* If venus died (!VC_OPEN(vcp)) */ 714 1.63 rin if (codadebug) { 715 1.63 rin myprintf(("vcclose woke op %d.%d flags %d\n", 716 1.63 rin vmp->vm_opcode, vmp->vm_unique, vmp->vm_flags)); 717 1.63 rin } 718 1.27 perry 719 1.1 rvb error = ENODEV; 720 1.1 rvb } 721 1.1 rvb 722 1.3 rvb CODA_FREE(vmp, sizeof(struct vmsg)); 723 1.8 rvb 724 1.8 rvb if (outstanding_upcalls > 0 && (--outstanding_upcalls == 0)) 725 1.8 rvb wakeup(&outstanding_upcalls); 726 1.1 rvb 727 1.1 rvb if (!error) 728 1.3 rvb error = ((struct coda_out_hdr *)buffer)->result; 729 1.1 rvb return(error); 730 1.1 rvb } 731 1.4 rvb 732 1.48 christos MODULE(MODULE_CLASS_DRIVER, vcoda, NULL); 733 1.48 christos 734 1.48 christos static int 735 1.48 christos vcoda_modcmd(modcmd_t cmd, void *arg) 736 1.48 christos { 737 1.50 christos int error = 0; 738 1.48 christos 739 1.48 christos switch (cmd) { 740 1.48 christos case MODULE_CMD_INIT: 741 1.48 christos #ifdef _MODULE 742 1.51 riz { 743 1.50 christos int cmajor, dmajor; 744 1.48 christos vcodaattach(NVCODA); 745 1.48 christos 746 1.50 christos dmajor = cmajor = -1; 747 1.48 christos return devsw_attach("vcoda", NULL, &dmajor, 748 1.48 christos &vcoda_cdevsw, &cmajor); 749 1.51 riz } 750 1.48 christos #endif 751 1.48 christos break; 752 1.48 christos 753 1.48 christos case MODULE_CMD_FINI: 754 1.48 christos #ifdef _MODULE 755 1.48 christos { 756 1.48 christos for (size_t i = 0; i < NVCODA; i++) { 757 1.48 christos struct vcomm *vcp = &coda_mnttbl[i].mi_vcomm; 758 1.48 christos if (VC_OPEN(vcp)) 759 1.48 christos return EBUSY; 760 1.48 christos } 761 1.61 riastrad devsw_detach(NULL, &vcoda_cdevsw); 762 1.48 christos } 763 1.48 christos #endif 764 1.48 christos break; 765 1.48 christos 766 1.48 christos case MODULE_CMD_STAT: 767 1.48 christos return ENOTTY; 768 1.48 christos 769 1.48 christos default: 770 1.48 christos return ENOTTY; 771 1.48 christos } 772 1.48 christos return error; 773 1.48 christos } 774