scoutos / prex-0.9.0 / usr / server / fs / fifofs / fifo_vnops.c @ 03e9c04a
History | View | Annotate | Download (11 KB)
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 |
} |