Annotation of prex/usr/server/fs/fifofs/fifo_vnops.c, Revision 1.1.1.1
1.1 nbrk 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 <prex/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: char *fn_name; /* name (null-terminated) */
56: cond_t fn_rcond; /* cv for read */
57: cond_t fn_wcond; /* cv for write */
58: mutex_t fn_rmtx; /* mutex for read */
59: mutex_t fn_wmtx; /* mutex for write */
60: int fn_readers; /* reader count */
61: int fn_writers; /* writer count */
62: int fn_start; /* start offset of buffer data */
63: int fn_size; /* siez of buffer data */
64: char *fn_buf; /* pointer to buffer */
65: };
66:
67: #define fifo_mount ((vfsop_mount_t)vfs_nullop)
68: #define fifo_unmount ((vfsop_umount_t)vfs_nullop)
69: #define fifo_sync ((vfsop_sync_t)vfs_nullop)
70: #define fifo_vget ((vfsop_vget_t)vfs_nullop)
71: #define fifo_statfs ((vfsop_statfs_t)vfs_nullop)
72:
73: static int fifo_open (vnode_t, int);
74: static int fifo_close (vnode_t, file_t);
75: static int fifo_read (vnode_t, file_t, void *, size_t, size_t *);
76: static int fifo_write (vnode_t, file_t, void *, size_t, size_t *);
77: #define fifo_seek ((vnop_seek_t)vop_nullop)
78: static int fifo_ioctl (vnode_t, file_t, u_long, void *);
79: #define fifo_fsync ((vnop_fsync_t)vop_nullop)
80: static int fifo_readdir (vnode_t, file_t, struct dirent *);
81: static int fifo_lookup (vnode_t, char *, vnode_t);
82: static int fifo_create (vnode_t, char *, mode_t);
83: static int fifo_remove (vnode_t, vnode_t, char *);
84: #define fifo_rename ((vnop_rename_t)vop_einval)
85: #define fifo_mkdir ((vnop_mkdir_t)vop_einval)
86: #define fifo_rmdir ((vnop_rmdir_t)vop_einval)
87: #define fifo_getattr ((vnop_getattr_t)vop_nullop)
88: #define fifo_setattr ((vnop_setattr_t)vop_nullop)
89: #define fifo_inactive ((vnop_inactive_t)vop_nullop)
90: #define fifo_truncate ((vnop_truncate_t)vop_nullop)
91:
92: static void wait_reader(vnode_t);
93: static void wakeup_reader(vnode_t);
94: static void wait_writer(vnode_t);
95: static void wakeup_writer(vnode_t);
96:
97: #if CONFIG_FS_THREADS > 1
98: static mutex_t fifo_lock = MUTEX_INITIALIZER;
99: #endif
100:
101: static struct list fifo_head;
102:
103: /*
104: * vnode operations
105: */
106: struct vnops fifofs_vnops = {
107: fifo_open, /* open */
108: fifo_close, /* close */
109: fifo_read, /* read */
110: fifo_write, /* write */
111: fifo_seek, /* seek */
112: fifo_ioctl, /* ioctl */
113: fifo_fsync, /* fsync */
114: fifo_readdir, /* readdir */
115: fifo_lookup, /* lookup */
116: fifo_create, /* create */
117: fifo_remove, /* remove */
118: fifo_rename, /* remame */
119: fifo_mkdir, /* mkdir */
120: fifo_rmdir, /* rmdir */
121: fifo_getattr, /* getattr */
122: fifo_setattr, /* setattr */
123: fifo_inactive, /* inactive */
124: fifo_truncate, /* truncate */
125: };
126:
127: /*
128: * File system operations
129: */
130: struct vfsops fifofs_vfsops = {
131: fifo_mount, /* mount */
132: fifo_unmount, /* unmount */
133: fifo_sync, /* sync */
134: fifo_vget, /* vget */
135: fifo_statfs, /* statfs */
136: &fifofs_vnops, /* vnops */
137: };
138:
139: static int
140: fifo_open(vnode_t vp, int flags)
141: {
142: struct fifo_node *np = vp->v_data;
143:
144: DPRINTF(("fifo_open: path=%s\n", vp->v_path));
145:
146: if (!strcmp(vp->v_path, "/")) /* root ? */
147: return 0;
148:
149: /*
150: * Unblock all threads who are waiting in open().
151: */
152: if (flags & FREAD) {
153: if (np->fn_readers == 0 && np->fn_writers > 0)
154: wakeup_writer(vp);
155: np->fn_readers++;
156: }
157: if (flags & FWRITE) {
158: if (np->fn_writers == 0 && np->fn_readers > 0)
159: wakeup_reader(vp);
160: np->fn_writers++;
161: }
162:
163: /*
164: * If no-one opens FIFO at the other side, wait for open().
165: */
166: if (flags & FREAD) {
167: if (flags & O_NONBLOCK) {
168: } else {
169: while (np->fn_writers == 0)
170: wait_writer(vp);
171: }
172: }
173: if (flags & FWRITE) {
174: if (flags & O_NONBLOCK) {
175: if (np->fn_readers == 0)
176: return ENXIO;
177: } else {
178: while (np->fn_readers == 0)
179: wait_reader(vp);
180: }
181: }
182: return 0;
183: }
184:
185: static int
186: fifo_close(vnode_t vp, file_t fp)
187: {
188: struct fifo_node *np = vp->v_data;
189:
190: DPRINTF(("fifo_close: fp=%x\n", fp));
191:
192: if (np == NULL)
193: return 0;
194:
195: if (fp->f_flags & FREAD) {
196: np->fn_readers--;
197: if (np->fn_readers == 0)
198: wakeup_writer(vp);
199: }
200: if (fp->f_flags & FWRITE) {
201: np->fn_writers--;
202: if (np->fn_writers == 0)
203: wakeup_reader(vp);
204: }
205: if (vp->v_refcnt > 1)
206: return 0;
207:
208: return 0;
209: }
210:
211: static int
212: fifo_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
213: {
214: struct fifo_node *np = vp->v_data;
215: char *p = buf;
216: int pos, nbytes;
217:
218: DPRINTF(("fifo_read\n"));
219:
220: /*
221: * If nothing in the pipe, wait.
222: */
223: while (np->fn_size == 0) {
224: /*
225: * No data and no writer, then EOF
226: */
227: if (np->fn_writers == 0) {
228: *result = 0;
229: return 0;
230: }
231: /*
232: * wait for data
233: */
234: wait_writer(vp);
235: }
236: /*
237: * Read
238: */
239: nbytes = (np->fn_size < size) ? np->fn_size : size;
240: np->fn_size -= nbytes;
241: *result = nbytes;
242: pos = np->fn_start;
243: while (nbytes > 0) {
244: *p++ = np->fn_buf[pos];
245: if (++pos > PIPE_BUF)
246: pos = 0;
247: nbytes--;
248: }
249: np->fn_start = pos;
250:
251: wakeup_writer(vp);
252: return 0;
253: }
254:
255: static int
256: fifo_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
257: {
258: struct fifo_node *np = vp->v_data;
259: char *p = buf;
260: int pos, nfree, nbytes;
261:
262: DPRINTF(("fifo_write\n"));
263:
264: again:
265: /*
266: * If the pipe is full,
267: * wait for reads to deplete
268: * and truncate it.
269: */
270: while (np->fn_size >= PIPE_BUF)
271: wait_reader(vp);
272:
273: /*
274: * Write
275: */
276: nfree = PIPE_BUF - np->fn_size;
277: nbytes = (nfree < size) ? nfree : size;
278:
279: pos = np->fn_start + np->fn_size;
280: if (pos >= PIPE_BUF)
281: pos -= PIPE_BUF;
282: np->fn_size += nbytes;
283: size -= nbytes;
284: while (nbytes > 0) {
285: np->fn_buf[pos] = *p++;
286: if (++pos > PIPE_BUF)
287: pos = 0;
288: nbytes--;
289: }
290:
291: wakeup_reader(vp);
292:
293: if (size > 0)
294: goto again;
295:
296: *result = size;
297: return 0;
298: }
299:
300: static int
301: fifo_ioctl(vnode_t vp, file_t fp, u_long cmd, void *arg)
302: {
303: DPRINTF(("fifo_ioctl\n"));
304: return EINVAL;
305: }
306:
307: static int
308: fifo_lookup(vnode_t dvp, char *name, vnode_t vp)
309: {
310: list_t head, n;
311: struct fifo_node *np = NULL;
312: int found;
313:
314: DPRINTF(("fifo_lookup: %s\n", name));
315:
316: if (*name == '\0')
317: return ENOENT;
318:
319: mutex_lock(&fifo_lock);
320:
321: found = 0;
322: head = &fifo_head;
323: for (n = list_first(head); n != head; n = list_next(n)) {
324: np = list_entry(n, struct fifo_node, fn_link);
325: if (strcmp(name, np->fn_name) == 0) {
326: found = 1;
327: break;
328: }
329: }
330: if (found == 0) {
331: mutex_unlock(&fifo_lock);
332: return ENOENT;
333: }
334: vp->v_data = np;
335: vp->v_mode = ALLPERMS;
336: vp->v_type = VFIFO;
337: vp->v_size = 0;
338:
339: mutex_unlock(&fifo_lock);
340: return 0;
341: }
342:
343: static int
344: fifo_create(vnode_t dvp, char *name, mode_t mode)
345: {
346: struct fifo_node *np;
347:
348: DPRINTF(("create %s in %s\n", name, dvp->v_path));
349:
350: #if 0
351: if (!S_ISFIFO(mode))
352: return EINVAL;
353: #endif
354:
355: if ((np = malloc(sizeof(struct fifo_node))) == NULL)
356: return ENOMEM;
357:
358: if ((np->fn_buf = malloc(PIPE_BUF)) == NULL) {
359: free(np);
360: return ENOMEM;
361: }
362: np->fn_name = malloc(strlen(name) + 1);
363: if (np->fn_name == NULL) {
364: free(np->fn_buf);
365: free(np);
366: return ENOMEM;
367: }
368:
369: strcpy(np->fn_name, name);
370: mutex_init(&np->fn_rmtx);
371: mutex_init(&np->fn_wmtx);
372: cond_init(&np->fn_rcond);
373: cond_init(&np->fn_wcond);
374: np->fn_readers = 0;
375: np->fn_writers = 0;
376: np->fn_start = 0;
377: np->fn_size = 0;
378:
379: mutex_lock(&fifo_lock);
380: list_insert(&fifo_head, &np->fn_link);
381: mutex_unlock(&fifo_lock);
382: return 0;
383: }
384:
385: static int
386: fifo_remove(vnode_t dvp, vnode_t vp, char *name)
387: {
388: struct fifo_node *np = vp->v_data;
389:
390: DPRINTF(("remove %s in %s\n", name, dvp->v_path));
391:
392: mutex_lock(&fifo_lock);
393: list_remove(&np->fn_link);
394: mutex_unlock(&fifo_lock);
395:
396: free(np->fn_name);
397: free(np->fn_buf);
398: free(np);
399:
400: vp->v_data = NULL;
401: return 0;
402: }
403:
404: /*
405: * @vp: vnode of the directory.
406: */
407: static int
408: fifo_readdir(vnode_t vp, file_t fp, struct dirent *dir)
409: {
410: struct fifo_node *np;
411: list_t head, n;
412: int i;
413:
414: mutex_lock(&fifo_lock);
415:
416: if (fp->f_offset == 0) {
417: dir->d_type = DT_DIR;
418: strcpy((char *)&dir->d_name, ".");
419: } else if (fp->f_offset == 1) {
420: dir->d_type = DT_DIR;
421: strcpy((char *)&dir->d_name, "..");
422: } else {
423: i = 0;
424: np = NULL;
425: head = &fifo_head;
426: for (n = list_first(head); n != head; n = list_next(n)) {
427: if (i == (fp->f_offset - 2)) {
428: np = list_entry(n, struct fifo_node, fn_link);
429: break;
430: }
431: }
432: if (np == NULL) {
433: mutex_unlock(&fifo_lock);
434: return ENOENT;
435: }
436: dir->d_type = DT_FIFO;
437: strcpy((char *)&dir->d_name, np->fn_name);
438: }
439: dir->d_fileno = fp->f_offset;
440: dir->d_namlen = strlen(dir->d_name);
441:
442: fp->f_offset++;
443:
444: mutex_unlock(&fifo_lock);
445: return 0;
446: }
447:
448: int
449: fifofs_init(void)
450: {
451: list_init(&fifo_head);
452: return 0;
453: }
454:
455:
456: static void
457: wait_reader(vnode_t vp)
458: {
459: struct fifo_node *np = vp->v_data;
460:
461: DPRINTF(("wait_reader: %x\n", np));
462: vn_unlock(vp);
463: mutex_lock(&np->fn_rmtx);
464: cond_wait(&np->fn_rcond, &np->fn_rmtx);
465: mutex_unlock(&np->fn_rmtx);
466: vn_lock(vp);
467: }
468:
469: static void
470: wakeup_writer(vnode_t vp)
471: {
472: struct fifo_node *np = vp->v_data;
473:
474: DPRINTF(("wakeup_writer: %x\n", np));
475: cond_broadcast(&np->fn_rcond);
476: }
477:
478: static void
479: wait_writer(vnode_t vp)
480: {
481: struct fifo_node *np = vp->v_data;
482:
483: DPRINTF(("wait_writer: %x\n", np));
484: vn_unlock(vp);
485: mutex_lock(&np->fn_wmtx);
486: cond_wait(&np->fn_wcond, &np->fn_wmtx);
487: mutex_unlock(&np->fn_wmtx);
488: vn_lock(vp);
489: }
490:
491: static void
492: wakeup_reader(vnode_t vp)
493: {
494: struct fifo_node *np = vp->v_data;
495:
496: DPRINTF(("wakeup_reader: %x\n", np));
497: cond_broadcast(&np->fn_wcond);
498: }
CVSweb