Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/fs/fifofs/fifo_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fifo_open
  2. fifo_close
  3. fifo_read
  4. fifo_write
  5. fifo_ioctl
  6. fifo_lookup
  7. fifo_create
  8. cleanup_fifo
  9. fifo_remove
  10. fifo_readdir
  11. fifofs_init
  12. wait_reader
  13. wakeup_writer
  14. wait_writer
  15. wakeup_reader

   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] */