Project

General

Profile

Statistics
| Branch: | Revision:

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
}