Project

General

Profile

Statistics
| Branch: | Revision:

root / prex-0.9.0 / usr / server / fs / ramfs / ramfs_vnops.c @ 03e9c04a

History | View | Annotate | Download (11.3 KB)

1 03e9c04a Brad Neuman
/*
2
 * Copyright (c) 2006-2007, 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
 * rmafs_vnops.c - vnode operations for RAM file system.
32
 */
33
34
#include <sys/prex.h>
35
36
#include <sys/stat.h>
37
#include <sys/vnode.h>
38
#include <sys/file.h>
39
#include <sys/mount.h>
40
#include <sys/dirent.h>
41
#include <sys/param.h>
42
43
#include <errno.h>
44
#include <string.h>
45
#include <stdlib.h>
46
#include <fcntl.h>
47
48
#include "ramfs.h"
49
50
#define ramfs_open        ((vnop_open_t)vop_nullop)
51
#define ramfs_close        ((vnop_close_t)vop_nullop)
52
static int ramfs_read        (vnode_t, file_t, void *, size_t, size_t *);
53
static int ramfs_write        (vnode_t, file_t, void *, size_t, size_t *);
54
#define ramfs_seek        ((vnop_seek_t)vop_nullop)
55
#define ramfs_ioctl        ((vnop_ioctl_t)vop_einval)
56
#define ramfs_fsync        ((vnop_fsync_t)vop_nullop)
57
static int ramfs_readdir(vnode_t, file_t, struct dirent *);
58
static int ramfs_lookup        (vnode_t, char *, vnode_t);
59
static int ramfs_create        (vnode_t, char *, mode_t);
60
static int ramfs_remove        (vnode_t, vnode_t, char *);
61
static int ramfs_rename        (vnode_t, vnode_t, char *, vnode_t, vnode_t, char *);
62
static int ramfs_mkdir        (vnode_t, char *, mode_t);
63
static int ramfs_rmdir        (vnode_t, vnode_t, char *);
64
#define ramfs_getattr        ((vnop_getattr_t)vop_nullop)
65
#define ramfs_setattr        ((vnop_setattr_t)vop_nullop)
66
#define ramfs_inactive        ((vnop_inactive_t)vop_nullop)
67
static int ramfs_truncate(vnode_t, off_t);
68
69
70
#if CONFIG_FS_THREADS > 1
71
static mutex_t ramfs_lock = MUTEX_INITIALIZER;
72
#endif
73
74
/*
75
 * vnode operations
76
 */
77
struct vnops ramfs_vnops = {
78
        ramfs_open,                /* open */
79
        ramfs_close,                /* close */
80
        ramfs_read,                /* read */
81
        ramfs_write,                /* write */
82
        ramfs_seek,                /* seek */
83
        ramfs_ioctl,                /* ioctl */
84
        ramfs_fsync,                /* fsync */
85
        ramfs_readdir,                /* readdir */
86
        ramfs_lookup,                /* lookup */
87
        ramfs_create,                /* create */
88
        ramfs_remove,                /* remove */
89
        ramfs_rename,                /* remame */
90
        ramfs_mkdir,                /* mkdir */
91
        ramfs_rmdir,                /* rmdir */
92
        ramfs_getattr,                /* getattr */
93
        ramfs_setattr,                /* setattr */
94
        ramfs_inactive,                /* inactive */
95
        ramfs_truncate,                /* truncate */
96
};
97
98
struct ramfs_node *
99
ramfs_allocate_node(char *name, int type)
100
{
101
        struct ramfs_node *np;
102
103
        np = malloc(sizeof(struct ramfs_node));
104
        if (np == NULL)
105
                return NULL;
106
        memset(np, 0, sizeof(struct ramfs_node));
107
108
        np->rn_namelen = strlen(name);
109
        np->rn_name = malloc(np->rn_namelen + 1);
110
        if (np->rn_name == NULL) {
111
                free(np);
112
                return NULL;
113
        }
114
        strlcpy(np->rn_name, name, np->rn_namelen + 1);
115
        np->rn_type = type;
116
        return np;
117
}
118
119
void
120
ramfs_free_node(struct ramfs_node *np)
121
{
122
123
        free(np->rn_name);
124
        free(np);
125
}
126
127
static struct ramfs_node *
128
ramfs_add_node(struct ramfs_node *dnp, char *name, int type)
129
{
130
        struct ramfs_node *np, *prev;
131
132
        np = ramfs_allocate_node(name, type);
133
        if (np == NULL)
134
                return NULL;
135
136
        mutex_lock(&ramfs_lock);
137
138
        /* Link to the directory list */
139
        if (dnp->rn_child == NULL) {
140
                dnp->rn_child = np;
141
        } else {
142
                prev = dnp->rn_child;
143
                while (prev->rn_next != NULL)
144
                        prev = prev->rn_next;
145
                prev->rn_next = np;
146
        }
147
        mutex_unlock(&ramfs_lock);
148
        return np;
149
}
150
151
static int
152
ramfs_remove_node(struct ramfs_node *dnp, struct ramfs_node *np)
153
{
154
        struct ramfs_node *prev;
155
156
        if (dnp->rn_child == NULL)
157
                return EBUSY;
158
159
        mutex_lock(&ramfs_lock);
160
161
        /* Unlink from the directory list */
162
        if (dnp->rn_child == np) {
163
                dnp->rn_child = np->rn_next;
164
        } else {
165
                for (prev = dnp->rn_child; prev->rn_next != np;
166
                     prev = prev->rn_next) {
167
                        if (prev->rn_next == NULL) {
168
                                mutex_unlock(&ramfs_lock);
169
                                return ENOENT;
170
                        }
171
                }
172
                prev->rn_next = np->rn_next;
173
        }
174
        ramfs_free_node(np);
175
176
        mutex_unlock(&ramfs_lock);
177
        return 0;
178
}
179
180
static int
181
ramfs_rename_node(struct ramfs_node *np, char *name)
182
{
183
        size_t len;
184
        char *tmp;
185
186
        len = strlen(name);
187
        if (len <= np->rn_namelen) {
188
                /* Reuse current name buffer */
189
                strlcpy(np->rn_name, name, sizeof(np->rn_name));
190
        } else {
191
                /* Expand name buffer */
192
                tmp = malloc(len + 1);
193
                if (tmp == NULL)
194
                        return ENOMEM;
195
                strlcpy(tmp, name, len + 1);
196
                free(np->rn_name);
197
                np->rn_name = tmp;
198
        }
199
        np->rn_namelen = len;
200
        return 0;
201
}
202
203
static int
204
ramfs_lookup(vnode_t dvp, char *name, vnode_t vp)
205
{
206
        struct ramfs_node *np, *dnp;
207
        size_t len;
208
        int found;
209
210
        if (*name == '\0')
211
                return ENOENT;
212
213
        mutex_lock(&ramfs_lock);
214
215
        len = strlen(name);
216
        dnp = dvp->v_data;
217
        found = 0;
218
        for (np = dnp->rn_child; np != NULL; np = np->rn_next) {
219
                if (np->rn_namelen == len &&
220
                    memcmp(name, np->rn_name, len) == 0) {
221
                        found = 1;
222
                        break;
223
                }
224
        }
225
        if (found == 0) {
226
                mutex_unlock(&ramfs_lock);
227
                return ENOENT;
228
        }
229
        vp->v_data = np;
230
        vp->v_mode = ALLPERMS;
231
        vp->v_type = np->rn_type;
232
        vp->v_size = np->rn_size;
233
234
        mutex_unlock(&ramfs_lock);
235
        return 0;
236
}
237
238
static int
239
ramfs_mkdir(vnode_t dvp, char *name, mode_t mode)
240
{
241
        struct ramfs_node *np;
242
243
        DPRINTF(("mkdir %s\n", name));
244
        if (!S_ISDIR(mode))
245
                return EINVAL;
246
247
        np = ramfs_add_node(dvp->v_data, name, VDIR);
248
        if (np == NULL)
249
                return ENOMEM;
250
        np->rn_size = 0;
251
        return 0;
252
}
253
254
/* Remove a directory */
255
static int
256
ramfs_rmdir(vnode_t dvp, vnode_t vp, char *name)
257
{
258
259
        return ramfs_remove_node(dvp->v_data, vp->v_data);
260
}
261
262
/* Remove a file */
263
static int
264
ramfs_remove(vnode_t dvp, vnode_t vp, char *name)
265
{
266
        struct ramfs_node *np;
267
        int error;
268
269
        DPRINTF(("remove %s in %s\n", name, dvp->v_path));
270
        error = ramfs_remove_node(dvp->v_data, vp->v_data);
271
        if (error)
272
                return error;
273
274
        np = vp->v_data;
275
        if (np->rn_buf != NULL)
276
                vm_free(task_self(), np->rn_buf);
277
        return 0;
278
}
279
280
/* Truncate file */
281
static int
282
ramfs_truncate(vnode_t vp, off_t length)
283
{
284
        struct ramfs_node *np;
285
        void *new_buf;
286
        size_t new_size;
287
        task_t task;
288
289
        DPRINTF(("truncate %s length=%d\n", vp->v_path, length));
290
        np = vp->v_data;
291
292
        if (length == 0) {
293
                if (np->rn_buf != NULL) {
294
                        vm_free(task_self(), np->rn_buf);
295
                        np->rn_buf = NULL;
296
                        np->rn_bufsize = 0;
297
                }
298
        } else if (length > np->rn_bufsize) {
299
                task = task_self();
300
                new_size = round_page(length);
301
                if (vm_allocate(task, &new_buf, new_size, 1))
302
                        return EIO;
303
                if (np->rn_size != 0) {
304
                        memcpy(new_buf, np->rn_buf, vp->v_size);
305
                        vm_free(task, np->rn_buf);
306
                }
307
                np->rn_buf = new_buf;
308
                np->rn_bufsize = new_size;
309
        }
310
        np->rn_size = length;
311
        vp->v_size = length;
312
        return 0;
313
}
314
315
/*
316
 * Create empty file.
317
 */
318
static int
319
ramfs_create(vnode_t dvp, char *name, mode_t mode)
320
{
321
        struct ramfs_node *np;
322
323
        DPRINTF(("create %s in %s\n", name, dvp->v_path));
324
        if (!S_ISREG(mode))
325
                return EINVAL;
326
327
        np = ramfs_add_node(dvp->v_data, name, VREG);
328
        if (np == NULL)
329
                return ENOMEM;
330
        return 0;
331
}
332
333
static int
334
ramfs_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
335
{
336
        struct ramfs_node *np;
337
        off_t off;
338
339
        *result = 0;
340
        if (vp->v_type == VDIR)
341
                return EISDIR;
342
        if (vp->v_type != VREG)
343
                return EINVAL;
344
345
        off = fp->f_offset;
346
        if (off >= (off_t)vp->v_size)
347
                return 0;
348
349
        if (vp->v_size - off < size)
350
                size = vp->v_size - off;
351
352
        np = vp->v_data;
353
        memcpy(buf, np->rn_buf + off, size);
354
355
        fp->f_offset += size;
356
        *result = size;
357
        return 0;
358
}
359
360
static int
361
ramfs_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
362
{
363
        struct ramfs_node *np;
364
        off_t file_pos, end_pos;
365
        void *new_buf;
366
        size_t new_size;
367
        task_t task;
368
369
        *result = 0;
370
        if (vp->v_type == VDIR)
371
                return EISDIR;
372
        if (vp->v_type != VREG)
373
                return EINVAL;
374
375
        np = vp->v_data;
376
        /* Check if the file position exceeds the end of file. */
377
        end_pos = vp->v_size;
378
        file_pos = (fp->f_flags & O_APPEND) ? end_pos : fp->f_offset;
379
        if (file_pos + size > (size_t)end_pos) {
380
                /* Expand the file size before writing to it */
381
                end_pos = file_pos + size;
382
                if (end_pos > (off_t)np->rn_bufsize) {
383
                        task = task_self();
384
                        /*
385
                         * We allocate the data buffer in page boundary.
386
                         * So that we can reduce the memory allocation unless
387
                         * the file size exceeds next page boundary.
388
                         * This will prevent the memory fragmentation by
389
                         * many malloc/free calls.
390
                         */
391
                        new_size = round_page(end_pos);
392
                        if (vm_allocate(task, &new_buf, new_size, 1))
393
                                return EIO;
394
                        if (np->rn_size != 0) {
395
                                memcpy(new_buf, np->rn_buf, vp->v_size);
396
                                vm_free(task, np->rn_buf);
397
                        }
398
                        np->rn_buf = new_buf;
399
                        np->rn_bufsize = new_size;
400
                }
401
                np->rn_size = end_pos;
402
                vp->v_size = end_pos;
403
        }
404
        memcpy(np->rn_buf + file_pos, buf, size);
405
        fp->f_offset += size;
406
        *result = size;
407
        return 0;
408
}
409
410
static int
411
ramfs_rename(vnode_t dvp1, vnode_t vp1, char *name1,
412
             vnode_t dvp2, vnode_t vp2, char *name2)
413
{
414
        struct ramfs_node *np, *old_np;
415
        int error;
416
417
        if (vp2) {
418
                /* Remove destination file, first */
419
                error = ramfs_remove_node(dvp2->v_data, vp2->v_data);
420
                if (error)
421
                        return error;
422
        }
423
        /* Same directory ? */
424
        if (dvp1 == dvp2) {
425
                /* Change the name of existing file */
426
                error = ramfs_rename_node(vp1->v_data, name2);
427
                if (error)
428
                        return error;
429
        } else {
430
                /* Create new file or directory */
431
                old_np = vp1->v_data;
432
                np = ramfs_add_node(dvp2->v_data, name2, VREG);
433
                if (np == NULL)
434
                        return ENOMEM;
435
436
                if (vp1->v_type == VREG) {
437
                        /* Copy file data */
438
                        np->rn_buf = old_np->rn_buf;
439
                        np->rn_size = old_np->rn_size;
440
                        np->rn_bufsize = old_np->rn_bufsize;
441
                }
442
                /* Remove source file */
443
                ramfs_remove_node(dvp1->v_data, vp1->v_data);
444
        }
445
        return 0;
446
}
447
448
/*
449
 * @vp: vnode of the directory.
450
 */
451
static int
452
ramfs_readdir(vnode_t vp, file_t fp, struct dirent *dir)
453
{
454
        struct ramfs_node *np, *dnp;
455
        int i;
456
457
        mutex_lock(&ramfs_lock);
458
459
        if (fp->f_offset == 0) {
460
                dir->d_type = DT_DIR;
461
                strlcpy((char *)&dir->d_name, ".", sizeof(dir->d_name));
462
        } else if (fp->f_offset == 1) {
463
                dir->d_type = DT_DIR;
464
                strlcpy((char *)&dir->d_name, "..", sizeof(dir->d_name));
465
        } else {
466
                dnp = vp->v_data;
467
                np = dnp->rn_child;
468
                if (np == NULL) {
469
                        mutex_unlock(&ramfs_lock);
470
                        return ENOENT;
471
                }
472
473
                for (i = 0; i != (fp->f_offset - 2); i++) {
474
                        np = np->rn_next;
475
                        if (np == NULL) {
476
                                mutex_unlock(&ramfs_lock);
477
                                return ENOENT;
478
                        }
479
                }
480
                if (np->rn_type == VDIR)
481
                        dir->d_type = DT_DIR;
482
                else
483
                        dir->d_type = DT_REG;
484
                strlcpy((char *)&dir->d_name, np->rn_name,
485
                        sizeof(dir->d_name));
486
        }
487
        dir->d_fileno = (uint32_t)fp->f_offset;
488
        dir->d_namlen = (uint16_t)strlen(dir->d_name);
489
490
        fp->f_offset++;
491
492
        mutex_unlock(&ramfs_lock);
493
        return 0;
494
}
495
496
int
497
ramfs_init(void)
498
{
499
        return 0;
500
}