|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/fs/fifofs/fifo_vnops.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
1 /* 2 * Copyright (c) 2008, Kohsuke Ohtani 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the author nor the names of any co-contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * fifofs - FIFO/pipe file system. 32 */ 33 34 #include <sys/prex.h> 35 #include <sys/stat.h> 36 #include <sys/vnode.h> 37 #include <sys/file.h> 38 #include <sys/mount.h> 39 #include <sys/syslog.h> 40 #include <sys/dirent.h> 41 #include <sys/list.h> 42 43 #include <ctype.h> 44 #include <unistd.h> 45 #include <errno.h> 46 #include <string.h> 47 #include <stdlib.h> 48 #include <limits.h> 49 #include <fcntl.h> 50 51 #include "fifo.h" 52 53 struct fifo_node { 54 struct list fn_link; 55 int fn_type; /* type: VFIFO or VPIPE */ 56 char *fn_name; /* name (null-terminated) */ 57 cond_t fn_rcond; /* cv for read */ 58 cond_t fn_wcond; /* cv for write */ 59 mutex_t fn_rmtx; /* mutex for read */ 60 mutex_t fn_wmtx; /* mutex for write */ 61 int fn_readers; /* reader count */ 62 int fn_writers; /* writer count */ 63 int fn_start; /* start offset of buffer data */ 64 int fn_size; /* size of buffer data */ 65 char *fn_buf; /* pointer to buffer */ 66 }; 67 68 #define fifo_mount ((vfsop_mount_t)vfs_nullop) 69 #define fifo_unmount ((vfsop_umount_t)vfs_nullop) 70 #define fifo_sync ((vfsop_sync_t)vfs_nullop) 71 #define fifo_vget ((vfsop_vget_t)vfs_nullop) 72 #define fifo_statfs ((vfsop_statfs_t)vfs_nullop) 73 74 static int fifo_open (vnode_t, int); 75 static int fifo_close (vnode_t, file_t); 76 static int fifo_read (vnode_t, file_t, void *, size_t, size_t *); 77 static int fifo_write (vnode_t, file_t, void *, size_t, size_t *); 78 #define fifo_seek ((vnop_seek_t)vop_nullop) 79 static int fifo_ioctl (vnode_t, file_t, u_long, void *); 80 #define fifo_fsync ((vnop_fsync_t)vop_nullop) 81 static int fifo_readdir (vnode_t, file_t, struct dirent *); 82 static int fifo_lookup (vnode_t, char *, vnode_t); 83 static int fifo_create (vnode_t, char *, mode_t); 84 static int fifo_remove (vnode_t, vnode_t, char *); 85 #define fifo_rename ((vnop_rename_t)vop_einval) 86 #define fifo_mkdir ((vnop_mkdir_t)vop_einval) 87 #define fifo_rmdir ((vnop_rmdir_t)vop_einval) 88 #define fifo_getattr ((vnop_getattr_t)vop_nullop) 89 #define fifo_setattr ((vnop_setattr_t)vop_nullop) 90 #define fifo_inactive ((vnop_inactive_t)vop_nullop) 91 #define fifo_truncate ((vnop_truncate_t)vop_nullop) 92 93 static void cleanup_fifo(vnode_t); 94 static void wait_reader(vnode_t); 95 static void wakeup_reader(vnode_t); 96 static void wait_writer(vnode_t); 97 static void wakeup_writer(vnode_t); 98 99 #if CONFIG_FS_THREADS > 1 100 static mutex_t fifo_lock = MUTEX_INITIALIZER; 101 #endif 102 103 static struct list fifo_head; 104 105 /* 106 * vnode operations 107 */ 108 struct vnops fifofs_vnops = { 109 fifo_open, /* open */ 110 fifo_close, /* close */ 111 fifo_read, /* read */ 112 fifo_write, /* write */ 113 fifo_seek, /* seek */ 114 fifo_ioctl, /* ioctl */ 115 fifo_fsync, /* fsync */ 116 fifo_readdir, /* readdir */ 117 fifo_lookup, /* lookup */ 118 fifo_create, /* create */ 119 fifo_remove, /* remove */ 120 fifo_rename, /* remame */ 121 fifo_mkdir, /* mkdir */ 122 fifo_rmdir, /* rmdir */ 123 fifo_getattr, /* getattr */ 124 fifo_setattr, /* setattr */ 125 fifo_inactive, /* inactive */ 126 fifo_truncate, /* truncate */ 127 }; 128 129 /* 130 * File system operations 131 */ 132 struct vfsops fifofs_vfsops = { 133 fifo_mount, /* mount */ 134 fifo_unmount, /* unmount */ 135 fifo_sync, /* sync */ 136 fifo_vget, /* vget */ 137 fifo_statfs, /* statfs */ 138 &fifofs_vnops, /* vnops */ 139 }; 140 141 static int 142 fifo_open(vnode_t vp, int flags) 143 { 144 struct fifo_node *np = vp->v_data; 145 146 DPRINTF(("fifo_open: path=%s\n", vp->v_path)); 147 148 if (!strcmp(vp->v_path, "/")) /* root ? */ 149 return 0; 150 151 /* 152 * Unblock all threads who are waiting in open(). 153 */ 154 if (flags & FREAD) { 155 if (np->fn_readers == 0 && np->fn_writers > 0) 156 wakeup_writer(vp); 157 np->fn_readers++; 158 } 159 if (flags & FWRITE) { 160 if (np->fn_writers == 0 && np->fn_readers > 0) 161 wakeup_reader(vp); 162 np->fn_writers++; 163 } 164 165 /* 166 * If no-one opens FIFO at the other side, wait for open(). 167 */ 168 if (flags & FREAD) { 169 if (flags & O_NONBLOCK) { 170 } else { 171 while (np->fn_writers == 0) 172 wait_writer(vp); 173 } 174 } 175 if (flags & FWRITE) { 176 if (flags & O_NONBLOCK) { 177 if (np->fn_readers == 0) 178 return ENXIO; 179 } else { 180 while (np->fn_readers == 0) 181 wait_reader(vp); 182 } 183 } 184 return 0; 185 } 186 187 static int 188 fifo_close(vnode_t vp, file_t fp) 189 { 190 struct fifo_node *np = vp->v_data; 191 192 DPRINTF(("fifo_close: fp=%x\n", fp)); 193 194 if (np == NULL) 195 return 0; 196 197 if (fp->f_flags & FREAD) { 198 np->fn_readers--; 199 if (np->fn_readers == 0) 200 wakeup_writer(vp); 201 } 202 if (fp->f_flags & FWRITE) { 203 np->fn_writers--; 204 if (np->fn_writers == 0) 205 wakeup_reader(vp); 206 } 207 if (vp->v_refcnt > 1) 208 return 0; 209 210 /* Clearn up pipe */ 211 if (!strncmp(np->fn_name, "pipe", 4)) { 212 DPRINTF(("fifo_close: remove pipe\n")); 213 cleanup_fifo(vp); 214 } 215 return 0; 216 } 217 218 static int 219 fifo_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) 220 { 221 struct fifo_node *np = vp->v_data; 222 char *p = buf; 223 u_int pos, nbytes; 224 225 DPRINTF(("fifo_read\n")); 226 227 /* 228 * If nothing in the pipe, wait. 229 */ 230 while (np->fn_size == 0) { 231 /* 232 * No data and no writer, then EOF 233 */ 234 if (np->fn_writers == 0) { 235 *result = 0; 236 return 0; 237 } 238 /* 239 * wait for data 240 */ 241 wait_writer(vp); 242 } 243 /* 244 * Read 245 */ 246 nbytes = (np->fn_size < size) ? np->fn_size : size; 247 np->fn_size -= nbytes; 248 *result = nbytes; 249 250 pos = np->fn_start; 251 while (nbytes > 0) { 252 *p++ = np->fn_buf[pos]; 253 if (++pos > PIPE_BUF) 254 pos = 0; 255 nbytes--; 256 } 257 np->fn_start = pos; 258 259 wakeup_writer(vp); 260 return 0; 261 } 262 263 static int 264 fifo_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result) 265 { 266 struct fifo_node *np = vp->v_data; 267 char *p = buf; 268 u_int pos, nfree, nbytes, count = 0; 269 270 DPRINTF(("fifo_write\n")); 271 272 again: 273 /* 274 * If the pipe is full, 275 * wait for reads to deplete 276 * and truncate it. 277 */ 278 while (np->fn_size >= PIPE_BUF) 279 wait_reader(vp); 280 281 /* 282 * Write 283 */ 284 nfree = PIPE_BUF - np->fn_size; 285 nbytes = (nfree < size) ? nfree : size; 286 287 pos = np->fn_start + np->fn_size; 288 if (pos >= PIPE_BUF) 289 pos -= PIPE_BUF; 290 np->fn_size += nbytes; 291 size -= nbytes; 292 while (nbytes > 0) { 293 np->fn_buf[pos] = *p++; 294 if (++pos > PIPE_BUF) 295 pos = 0; 296 nbytes--; 297 count++; 298 } 299 300 wakeup_reader(vp); 301 302 if (size > 0) 303 goto again; 304 305 *result = count; 306 return 0; 307 } 308 309 static int 310 fifo_ioctl(vnode_t vp, file_t fp, u_long cmd, void *arg) 311 { 312 DPRINTF(("fifo_ioctl\n")); 313 return EINVAL; 314 } 315 316 static int 317 fifo_lookup(vnode_t dvp, char *name, vnode_t vp) 318 { 319 list_t head, n; 320 struct fifo_node *np = NULL; 321 int found; 322 323 DPRINTF(("fifo_lookup: %s\n", name)); 324 325 if (*name == '\0') 326 return ENOENT; 327 328 mutex_lock(&fifo_lock); 329 330 found = 0; 331 head = &fifo_head; 332 for (n = list_first(head); n != head; n = list_next(n)) { 333 np = list_entry(n, struct fifo_node, fn_link); 334 if (strcmp(name, np->fn_name) == 0) { 335 found = 1; 336 break; 337 } 338 } 339 if (found == 0) { 340 mutex_unlock(&fifo_lock); 341 return ENOENT; 342 } 343 vp->v_data = np; 344 vp->v_mode = ALLPERMS; 345 vp->v_size = 0; 346 vp->v_type = VFIFO; 347 mutex_unlock(&fifo_lock); 348 return 0; 349 } 350 351 static int 352 fifo_create(vnode_t dvp, char *name, mode_t mode) 353 { 354 struct fifo_node *np; 355 size_t len; 356 357 DPRINTF(("create %s in %s\n", name, dvp->v_path)); 358 359 #if 0 360 if (!S_ISFIFO(mode)) 361 return EINVAL; 362 #endif 363 364 if ((np = malloc(sizeof(struct fifo_node))) == NULL) 365 return ENOMEM; 366 367 if ((np->fn_buf = malloc(PIPE_BUF)) == NULL) { 368 free(np); 369 return ENOMEM; 370 } 371 len = strlen(name) + 1; 372 np->fn_name = malloc(len); 373 if (np->fn_name == NULL) { 374 free(np->fn_buf); 375 free(np); 376 return ENOMEM; 377 } 378 379 strlcpy(np->fn_name, name, len); 380 mutex_init(&np->fn_rmtx); 381 mutex_init(&np->fn_wmtx); 382 cond_init(&np->fn_rcond); 383 cond_init(&np->fn_wcond); 384 np->fn_readers = 0; 385 np->fn_writers = 0; 386 np->fn_start = 0; 387 np->fn_size = 0; 388 389 mutex_lock(&fifo_lock); 390 list_insert(&fifo_head, &np->fn_link); 391 mutex_unlock(&fifo_lock); 392 return 0; 393 } 394 395 static void 396 cleanup_fifo(vnode_t vp) 397 { 398 struct fifo_node *np = vp->v_data; 399 400 mutex_lock(&fifo_lock); 401 list_remove(&np->fn_link); 402 mutex_unlock(&fifo_lock); 403 404 free(np->fn_name); 405 free(np->fn_buf); 406 free(np); 407 408 vp->v_data = NULL; 409 } 410 411 static int 412 fifo_remove(vnode_t dvp, vnode_t vp, char *name) 413 { 414 DPRINTF(("remove %s in %s\n", name, dvp->v_path)); 415 416 cleanup_fifo(vp); 417 return 0; 418 } 419 420 /* 421 * @vp: vnode of the directory. 422 */ 423 static int 424 fifo_readdir(vnode_t vp, file_t fp, struct dirent *dir) 425 { 426 struct fifo_node *np; 427 list_t head, n; 428 int i; 429 430 mutex_lock(&fifo_lock); 431 432 if (fp->f_offset == 0) { 433 dir->d_type = DT_DIR; 434 strlcpy((char *)&dir->d_name, ".", sizeof(dir->d_name)); 435 } else if (fp->f_offset == 1) { 436 dir->d_type = DT_DIR; 437 strlcpy((char *)&dir->d_name, "..", sizeof(dir->d_name)); 438 } else { 439 i = 0; 440 np = NULL; 441 head = &fifo_head; 442 for (n = list_first(head); n != head; n = list_next(n)) { 443 if (i == (fp->f_offset - 2)) { 444 np = list_entry(n, struct fifo_node, fn_link); 445 break; 446 } 447 } 448 if (np == NULL) { 449 mutex_unlock(&fifo_lock); 450 return ENOENT; 451 } 452 dir->d_type = DT_FIFO; 453 strlcpy((char *)&dir->d_name, np->fn_name, 454 sizeof(dir->d_name)); 455 } 456 dir->d_fileno = fp->f_offset; 457 dir->d_namlen = (uint16_t)strlen(dir->d_name); 458 459 fp->f_offset++; 460 461 mutex_unlock(&fifo_lock); 462 return 0; 463 } 464 465 int 466 fifofs_init(void) 467 { 468 list_init(&fifo_head); 469 return 0; 470 } 471 472 473 static void 474 wait_reader(vnode_t vp) 475 { 476 struct fifo_node *np = vp->v_data; 477 478 DPRINTF(("wait_reader: %x\n", np)); 479 vn_unlock(vp); 480 mutex_lock(&np->fn_rmtx); 481 cond_wait(&np->fn_rcond, &np->fn_rmtx); 482 mutex_unlock(&np->fn_rmtx); 483 vn_lock(vp); 484 } 485 486 static void 487 wakeup_writer(vnode_t vp) 488 { 489 struct fifo_node *np = vp->v_data; 490 491 DPRINTF(("wakeup_writer: %x\n", np)); 492 cond_broadcast(&np->fn_rcond); 493 } 494 495 static void 496 wait_writer(vnode_t vp) 497 { 498 struct fifo_node *np = vp->v_data; 499 500 DPRINTF(("wait_writer: %x\n", np)); 501 vn_unlock(vp); 502 mutex_lock(&np->fn_wmtx); 503 cond_wait(&np->fn_wcond, &np->fn_wmtx); 504 mutex_unlock(&np->fn_wmtx); 505 vn_lock(vp); 506 } 507 508 static void 509 wakeup_reader(vnode_t vp) 510 { 511 struct fifo_node *np = vp->v_data; 512 513 DPRINTF(("wakeup_reader: %x\n", np)); 514 cond_broadcast(&np->fn_wcond); 515 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |