Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / usr / server / fs / vfs / vfs_vnode.c @ 03e9c04a

History | View | Annotate | Download (9.34 KB)

1 03e9c04a Brad Neuman
/*
2
 * Copyright (c) 2005-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
 * vfs_vnode.c - vnode service
32
 */
33
34
#include <sys/prex.h>
35
#include <sys/list.h>
36
#include <sys/vnode.h>
37
#include <sys/mount.h>
38
39
#include <limits.h>
40
#include <unistd.h>
41
#include <string.h>
42
#include <stdlib.h>
43
#include <stdio.h>
44
#include <errno.h>
45
46
#include "vfs.h"
47
48
/*
49
 * Memo:
50
 *
51
 * Function   Ref count Lock
52
 * ---------- --------- ----------
53
 * vn_lock     *        Lock
54
 * vn_unlock   *        Unlock
55
 * vget        1        Lock
56
 * vput       -1        Unlock
57
 * vref       +1        *
58
 * vrele      -1        *
59
 */
60
61
#define VNODE_BUCKETS 32                /* size of vnode hash table */
62
63
/*
64
 * vnode table.
65
 * All active (opened) vnodes are stored on this hash table.
66
 * They can be accessed by its path name.
67
 */
68
static struct list vnode_table[VNODE_BUCKETS];
69
70
/*
71
 * Global lock to access all vnodes and vnode table.
72
 * If a vnode is already locked, there is no need to
73
 * lock this global lock to access internal data.
74
 */
75
#if CONFIG_FS_THREADS > 1
76
static mutex_t vnode_lock = MUTEX_INITIALIZER;
77
#define VNODE_LOCK()        mutex_lock(&vnode_lock)
78
#define VNODE_UNLOCK()        mutex_unlock(&vnode_lock)
79
#else
80
#define VNODE_LOCK()
81
#define VNODE_UNLOCK()
82
#endif
83
84
85
/*
86
 * Get the hash value from the mount point and path name.
87
 */
88
static u_int
89
vn_hash(mount_t mp, char *path)
90
{
91
        u_int val = 0;
92
93
        if (path) {
94
                while (*path)
95
                        val = ((val << 5) + val) + *path++;
96
        }
97
        return (val ^ (u_int)mp) & (VNODE_BUCKETS - 1);
98
}
99
100
/*
101
 * Returns locked vnode for specified mount point and path.
102
 * vn_lock() will increment the reference count of vnode.
103
 */
104
vnode_t
105
vn_lookup(mount_t mp, char *path)
106
{
107
        list_t head, n;
108
        vnode_t vp;
109
110
        VNODE_LOCK();
111
        head = &vnode_table[vn_hash(mp, path)];
112
        for (n = list_first(head); n != head; n = list_next(n)) {
113
                vp = list_entry(n, struct vnode, v_link);
114
                if (vp->v_mount == mp &&
115
                    !strncmp(vp->v_path, path, PATH_MAX)) {
116
                        vp->v_refcnt++;
117
                        VNODE_UNLOCK();
118
                        mutex_lock(&vp->v_lock);
119
                        vp->v_nrlocks++;
120
                        return vp;
121
                }
122
        }
123
        VNODE_UNLOCK();
124
        return NULL;                /* not found */
125
}
126
127
/*
128
 * Lock vnode
129
 */
130
void
131
vn_lock(vnode_t vp)
132
{
133
        ASSERT(vp);
134
        ASSERT(vp->v_refcnt > 0);
135
136
        mutex_lock(&vp->v_lock);
137
        vp->v_nrlocks++;
138
        DPRINTF(VFSDB_VNODE, ("vn_lock:   %s\n", vp->v_path));
139
}
140
141
/*
142
 * Unlock vnode
143
 */
144
void
145
vn_unlock(vnode_t vp)
146
{
147
        ASSERT(vp);
148
        ASSERT(vp->v_refcnt > 0);
149
        ASSERT(vp->v_nrlocks > 0);
150
151
        DPRINTF(VFSDB_VNODE, ("vn_unlock: %s\n", vp->v_path));
152
        vp->v_nrlocks--;
153
        mutex_unlock(&vp->v_lock);
154
}
155
156
/*
157
 * Allocate new vnode for specified path.
158
 * Increment its reference count and lock it.
159
 */
160
vnode_t
161
vget(mount_t mp, char *path)
162
{
163
        vnode_t vp;
164
        int error;
165
        size_t len;
166
167
        DPRINTF(VFSDB_VNODE, ("vget: %s\n", path));
168
169
        if (!(vp = malloc(sizeof(struct vnode))))
170
                return NULL;
171
        memset(vp, 0, sizeof(struct vnode));
172
173
        len = strlen(path) + 1;
174
        if (!(vp->v_path = malloc(len))) {
175
                free(vp);
176
                return NULL;
177
        }
178
        vp->v_mount = mp;
179
        vp->v_refcnt = 1;
180
        vp->v_op = mp->m_op->vfs_vnops;
181
        strlcpy(vp->v_path, path, len);
182
        mutex_init(&vp->v_lock);
183
        vp->v_nrlocks = 0;
184
185
        /*
186
         * Request to allocate fs specific data for vnode.
187
         */
188
        if ((error = VFS_VGET(mp, vp)) != 0) {
189
                mutex_destroy(&vp->v_lock);
190
                free(vp->v_path);
191
                free(vp);
192
                return NULL;
193
        }
194
        vfs_busy(vp->v_mount);
195
        mutex_lock(&vp->v_lock);
196
        vp->v_nrlocks++;
197
198
        VNODE_LOCK();
199
        list_insert(&vnode_table[vn_hash(mp, path)], &vp->v_link);
200
        VNODE_UNLOCK();
201
        return vp;
202
}
203
204
/*
205
 * Unlock vnode and decrement its reference count.
206
 */
207
void
208
vput(vnode_t vp)
209
{
210
        ASSERT(vp);
211
        ASSERT(vp->v_nrlocks > 0);
212
        ASSERT(vp->v_refcnt > 0);
213
        DPRINTF(VFSDB_VNODE, ("vput: ref=%d %s\n", vp->v_refcnt,
214
                              vp->v_path));
215
216
        vp->v_refcnt--;
217
        if (vp->v_refcnt > 0) {
218
                vn_unlock(vp);
219
                return;
220
        }
221
        VNODE_LOCK();
222
        list_remove(&vp->v_link);
223
        VNODE_UNLOCK();
224
225
        /*
226
         * Deallocate fs specific vnode data
227
         */
228
        VOP_INACTIVE(vp);
229
        vfs_unbusy(vp->v_mount);
230
        vp->v_nrlocks--;
231
        ASSERT(vp->v_nrlocks == 0);
232
        mutex_unlock(&vp->v_lock);
233
        mutex_destroy(&vp->v_lock);
234
        free(vp->v_path);
235
        free(vp);
236
}
237
238
/*
239
 * Increment the reference count on an active vnode.
240
 */
241
void
242
vref(vnode_t vp)
243
{
244
        ASSERT(vp);
245
        ASSERT(vp->v_refcnt > 0);        /* Need vget */
246
247
        VNODE_LOCK();
248
        DPRINTF(VFSDB_VNODE, ("vref: ref=%d %s\n", vp->v_refcnt,
249
                              vp->v_path));
250
        vp->v_refcnt++;
251
        VNODE_UNLOCK();
252
}
253
254
/*
255
 * Decrement the reference count of the vnode.
256
 * Any code in the system which is using vnode should call vrele()
257
 * when it is finished with the vnode.
258
 * If count drops to zero, call inactive routine and return to freelist.
259
 */
260
void
261
vrele(vnode_t vp)
262
{
263
        ASSERT(vp);
264
        ASSERT(vp->v_refcnt > 0);
265
266
        VNODE_LOCK();
267
        DPRINTF(VFSDB_VNODE, ("vrele: ref=%d %s\n", vp->v_refcnt,
268
                              vp->v_path));
269
        vp->v_refcnt--;
270
        if (vp->v_refcnt > 0) {
271
                VNODE_UNLOCK();
272
                return;
273
        }
274
        list_remove(&vp->v_link);
275
        VNODE_UNLOCK();
276
277
        /*
278
         * Deallocate fs specific vnode data
279
         */
280
        VOP_INACTIVE(vp);
281
        vfs_unbusy(vp->v_mount);
282
        mutex_destroy(&vp->v_lock);
283
        free(vp->v_path);
284
        free(vp);
285
}
286
287
/*
288
 * vgone() is called when unlocked vnode is no longer valid.
289
 */
290
void
291
vgone(vnode_t vp)
292
{
293
        ASSERT(vp->v_nrlocks == 0);
294
295
        VNODE_LOCK();
296
        DPRINTF(VFSDB_VNODE, ("vgone: %s\n", vp->v_path));
297
        list_remove(&vp->v_link);
298
        vfs_unbusy(vp->v_mount);
299
        mutex_destroy(&vp->v_lock);
300
        free(vp->v_path);
301
        free(vp);
302
        VNODE_UNLOCK();
303
}
304
305
/*
306
 * Return reference count.
307
 */
308
int
309
vcount(vnode_t vp)
310
{
311
        int count;
312
313
        vn_lock(vp);
314
        count = vp->v_refcnt;
315
        vn_unlock(vp);
316
        return count;
317
}
318
319
/*
320
 * Remove all vnode in the vnode table for unmount.
321
 */
322
void
323
vflush(mount_t mp)
324
{
325
        int i;
326
        list_t head, n;
327
        vnode_t vp;
328
329
        VNODE_LOCK();
330
        for (i = 0; i < VNODE_BUCKETS; i++) {
331
                head = &vnode_table[i];
332
                for (n = list_first(head); n != head; n = list_next(n)) {
333
                        vp = list_entry(n, struct vnode, v_link);
334
                        if (vp->v_mount == mp) {
335
                                /* XXX: */
336
                        }
337
                }
338
        }
339
        VNODE_UNLOCK();
340
}
341
342
int
343
vn_stat(vnode_t vp, struct stat *st)
344
{
345
        mode_t mode;
346
347
        memset(st, 0, sizeof(struct stat));
348
349
        st->st_ino = (ino_t)vp;
350
        st->st_size = vp->v_size;
351
        mode = vp->v_mode;
352
        switch (vp->v_type) {
353
        case VREG:
354
                mode |= S_IFREG;
355
                break;
356
        case VDIR:
357
                mode |= S_IFDIR;
358
                break;
359
        case VBLK:
360
                mode |= S_IFBLK;
361
                break;
362
        case VCHR:
363
                mode |= S_IFCHR;
364
                break;
365
        case VLNK:
366
                mode |= S_IFLNK;
367
                break;
368
        case VSOCK:
369
                mode |= S_IFSOCK;
370
                break;
371
        case VFIFO:
372
                mode |= S_IFIFO;
373
                break;
374
        default:
375
                return EBADF;
376
        };
377
        st->st_mode = mode;
378
        st->st_blksize = BSIZE;
379
        st->st_blocks = vp->v_size / S_BLKSIZE;
380
        st->st_uid = 0;
381
        st->st_gid = 0;
382
        if (vp->v_type == VCHR || vp->v_type == VBLK)
383
                st->st_rdev = (dev_t)vp->v_data;
384
385
        return 0;
386
}
387
388
/*
389
 * Chceck permission on vnode pointer.
390
 */
391
int
392
vn_access(vnode_t vp, int flags)
393
{
394
        int error = 0;
395
396
        if ((flags & VEXEC) && (vp->v_mode & 0111) == 0) {
397
                error = EACCES;
398
                goto out;
399
        }
400
        if ((flags & VREAD) && (vp->v_mode & 0444) == 0) {
401
                error = EACCES;
402
                goto out;
403
        }
404
        if (flags & VWRITE) {
405
                if (vp->v_mount->m_flags & MNT_RDONLY) {
406
                        error = EROFS;
407
                        goto out;
408
                }
409
                if ((vp->v_mode & 0222) == 0) {
410
                        error = EACCES;
411
                        goto out;
412
                }
413
        }
414
 out:
415
        return error;
416
}
417
418
#ifdef DEBUG_VFS
419
/*
420
 * Dump all all vnode.
421
 */
422
void
423
vnode_dump(void)
424
{
425
        int i;
426
        list_t head, n;
427
        vnode_t vp;
428
        mount_t mp;
429
        char type[][6] = { "VNON ", "VREG ", "VDIR ", "VBLK ", "VCHR ",
430
                           "VLNK ", "VSOCK", "VFIFO" };
431
432
        VNODE_LOCK();
433
        dprintf("Dump vnode\n");
434
        dprintf(" vnode    mount    type  refcnt blkno    path\n");
435
        dprintf(" -------- -------- ----- ------ -------- ------------------------------\n");
436
437
        for (i = 0; i < VNODE_BUCKETS; i++) {
438
                head = &vnode_table[i];
439
                for (n = list_first(head); n != head; n = list_next(n)) {
440
                        vp = list_entry(n, struct vnode, v_link);
441
                        mp = vp->v_mount;
442
443
                        dprintf(" %08x %08x %s %6d %8d %s%s\n", (u_int)vp,
444
                                (u_int)mp, type[vp->v_type], vp->v_refcnt,
445
                                (u_int)vp->v_blkno,
446
                                (strlen(mp->m_path) == 1) ? "\0" : mp->m_path,
447
                                vp->v_path);
448
                }
449
        }
450
        dprintf("\n");
451
        VNODE_UNLOCK();
452
}
453
#endif
454
455
int
456
vop_nullop(void)
457
{
458
459
        return 0;
460
}
461
462
int
463
vop_einval(void)
464
{
465
466
        return EINVAL;
467
}
468
469
/*
470
 * vnode_init() is called once (from vfs_init)
471
 * in initialization.
472
 */
473
void
474
vnode_init(void)
475
{
476
        int i;
477
478
        for (i = 0; i < VNODE_BUCKETS; i++)
479
                list_init(&vnode_table[i]);
480
}