OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [posix/] [mm0/] [fs/] [memfs/] [vnode.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Inode and vnode implementation.
3
 *
4
 * Copyright (C) 2008 Bahadir Balban
5
 */
6
#include <fs.h>
7
#include <vfs.h>
8
#include <memfs/memfs.h>
9
#include <memfs/file.h>
10
#include <l4/lib/list.h>
11
#include <l4/api/errno.h>
12
#include <l4/macros.h>
13
#include <malloc/malloc.h>
14
#include <stdio.h>
15
 
16
 
17
struct memfs_inode *memfs_alloc_inode(struct memfs_superblock *sb)
18
{
19
        struct mem_cache *cache;
20
        struct memfs_inode *i;
21
        void *free_block;
22
 
23
        /* Ask existing inode caches for a new inode */
24
        list_foreach_struct(cache, &sb->inode_cache_list, list) {
25
                if (cache->free)
26
                        if (!(i =  mem_cache_zalloc(cache)))
27
                                return PTR_ERR(-ENOSPC);
28
                        else
29
                                return i;
30
                else
31
                        continue;
32
        }
33
 
34
        /* Ask existing block caches for a new block */
35
        if (IS_ERR(free_block = memfs_alloc_block(sb)))
36
                return PTR_ERR(free_block);
37
 
38
        /* Initialise it as an inode cache */
39
        cache = mem_cache_init(free_block, sb->blocksize,
40
                               sizeof(struct memfs_inode), 0);
41
        list_insert(&cache->list, &sb->inode_cache_list);
42
 
43
        if (!(i =  mem_cache_zalloc(cache)))
44
                return PTR_ERR(-ENOSPC);
45
        else
46
                return i;
47
}
48
 
49
/*
50
 * O(n^2) complexity but its simple, yet it would only reveal on high numbers.
51
 */
52
int memfs_free_inode(struct memfs_superblock *sb, struct memfs_inode *i)
53
{
54
        struct mem_cache *c, *tmp;
55
 
56
        list_foreach_removable_struct(c, tmp, &sb->inode_cache_list, list) {
57
                /* Free it, if success */
58
                if (!mem_cache_free(c, i)) {
59
                        /* If cache completely emtpy */
60
                        if (mem_cache_is_empty(c)) {
61
                                /* Free the block, too. */
62
                                list_remove(&c->list);
63
                                memfs_free_block(sb, c);
64
                        }
65
                        return 0;
66
                }
67
        }
68
        return -EINVAL;
69
}
70
 
71
/* Allocates *and* initialises the inode */
72
struct memfs_inode *memfs_create_inode(struct memfs_superblock *sb)
73
{
74
        struct memfs_inode *i;
75
 
76
        /* Allocate the inode */
77
        if (PTR_ERR(i = memfs_alloc_inode(sb)) < 0)
78
                return i;
79
 
80
        /* Allocate a new inode number */
81
        if ((i->inum = id_new(sb->ipool)) < 0)
82
                return i;
83
 
84
        /* Put a reference to this inode in the inode table at this index */
85
        sb->inode[i->inum] = i;
86
 
87
        return i;
88
}
89
 
90
/* Deallocate the inode and any other closely relevant structure */
91
int memfs_destroy_inode(struct memfs_superblock *sb, struct memfs_inode *i)
92
{
93
        int inum = i->inum;
94
 
95
        /* Deallocate the inode */
96
        if (memfs_free_inode(sb, i) < 0)
97
                return -EINVAL;
98
 
99
        /* Deallocate the inode number */
100
        if (id_del(sb->ipool, inum) < 0)
101
                return -EINVAL;
102
 
103
        /* Clear the ref in inode table */
104
        sb->inode[inum] = 0;
105
 
106
        return 0;
107
}
108
 
109
/* Allocates both an inode and a vnode and associates the two together */
110
struct vnode *memfs_alloc_vnode(struct superblock *sb)
111
{
112
        struct memfs_inode *i;
113
        struct vnode *v;
114
 
115
        /* Get a (pseudo-disk) memfs inode */
116
        if (IS_ERR(i = memfs_create_inode(sb->fs_super)))
117
                return PTR_ERR(i);
118
 
119
        /* Get a vnode */
120
        if (!(v = vfs_alloc_vnode()))
121
                return PTR_ERR(-ENOMEM);
122
 
123
        /* Associate the two together */
124
        v->inode = i;
125
        v->vnum = i->inum | sb->fsidx;  /* Globalize by fsidx */
126
 
127
        /* Associate memfs-specific fields with vnode */
128
        v->ops = memfs_vnode_operations;
129
        v->fops = memfs_file_operations;
130
        v->sb = sb;
131
 
132
        /* Return the vnode */
133
        return v;
134
}
135
 
136
/* Frees the inode and the corresponding vnode */
137
int memfs_free_vnode(struct superblock *sb, struct vnode *v)
138
{
139
        struct memfs_inode *i = v->inode;
140
 
141
        BUG_ON(!i); /* Vnodes that come here must have valid inodes */
142
 
143
        /* Destroy on-disk inode */
144
        memfs_destroy_inode(sb->fs_super, i);
145
 
146
        /* Free vnode */
147
        vfs_free_vnode(v);
148
 
149
        return 0;
150
}
151
 
152
/*
153
 * Given a vnode with a valid vnum, this retrieves the corresponding
154
 * inode from the filesystem.
155
 */
156
struct memfs_inode *memfs_read_inode(struct superblock *sb, struct vnode *v)
157
{
158
        struct memfs_superblock *fssb = sb->fs_super;
159
 
160
        BUG_ON(!fssb->inode[v->vnum]);
161
 
162
        return fssb->inode[v->vnum];
163
}
164
 
165
/*
166
 * Given a preallocated vnode with a valid vnum, this reads the corresponding
167
 * inode from the filesystem and fills in the vnode's fields.
168
 */
169
int memfs_read_vnode(struct superblock *sb, struct vnode *v)
170
{
171
        struct memfs_inode *i = memfs_read_inode(sb, v);
172
 
173
        if (!i)
174
                return -EEXIST;
175
 
176
        /* Simply copy common fields */
177
        v->vnum = i->inum | sb->fsidx;
178
        v->size = i->size;
179
        v->mode = i->mode;
180
        v->owner = i->owner;
181
        v->atime = i->atime;
182
        v->mtime = i->mtime;
183
        v->ctime = i->ctime;
184
 
185
        return 0;
186
}
187
 
188
/* Writes a valid vnode's fields back to its fs-specific inode */
189
int memfs_write_vnode(struct superblock *sb, struct vnode *v)
190
{
191
        struct memfs_inode *i = v->inode;
192
 
193
        /* Vnodes that come here must have valid inodes */
194
        BUG_ON(!i);
195
 
196
        /* Simply copy common fields */
197
        i->inum = v->vnum & ~VFS_FSIDX_MASK;
198
        i->size = v->size;
199
        i->mode = v->mode;
200
        i->owner = v->owner;
201
        i->atime = v->atime;
202
        i->mtime = v->mtime;
203
        i->ctime = v->ctime;
204
 
205
        return 0;
206
}
207
 
208
 
209
/*
210
 * Creates ordinary files and directories at the moment. In the future,
211
 * other file types will be added. Returns the created node.
212
 */
213
struct vnode *memfs_vnode_mknod(struct vnode *v, const char *dirname,
214
                                unsigned int mode)
215
{
216
        struct dentry *d, *parent = link_to_struct(v->dentries.next,
217
                                               struct dentry, vref);
218
        struct memfs_dentry *memfsd;
219
        struct dentry *newd;
220
        struct vnode *newv;
221
        int err;
222
 
223
        /*
224
         * Precautions to prove that parent is the *only* dentry,
225
         * since directories can't have multiple dentries associated
226
         * with them.
227
         */
228
        BUG_ON(list_empty(&v->dentries));
229
        BUG_ON(parent->vref.next != &v->dentries);
230
        BUG_ON(!vfs_isdir(v));
231
 
232
        /* Populate the children */
233
        if ((err = v->ops.readdir(v)) < 0)
234
                return PTR_ERR(err);
235
 
236
        /* Check there's no existing child with same name */
237
        list_foreach_struct(d, &parent->children, child) {
238
                /* Does the name exist as a child? */
239
                if(d->ops.compare(d, dirname))
240
                        return PTR_ERR(-EEXIST);
241
        }
242
 
243
        /* Allocate a new vnode for the new directory */
244
        if (IS_ERR(newv = v->sb->ops->alloc_vnode(v->sb)))
245
                return newv;
246
 
247
        /* Initialise the vnode */
248
        vfs_set_type(newv, mode);
249
 
250
        /* Get the next directory entry available on the parent vnode */
251
        if (v->dirbuf.npages * PAGE_SIZE <= v->size)
252
                return PTR_ERR(-ENOSPC);
253
 
254
        /* Fill in the new entry to parent directory entry */
255
        memfsd = (struct memfs_dentry *)&v->dirbuf.buffer[v->size];
256
        memfsd->offset = v->size;
257
        memfsd->rlength = sizeof(*memfsd);
258
        memfsd->inum = ((struct memfs_inode *)newv->inode)->inum;
259
        strncpy((char *)memfsd->name, dirname, MEMFS_DNAME_MAX);
260
        memfsd->name[MEMFS_DNAME_MAX - 1] = '\0';
261
 
262
        /* Write the updated directory buffer back to disk block */
263
        if ((err = v->fops.write(v, 0, 1, v->dirbuf.buffer)) < 0)
264
                return PTR_ERR(err); /* FIXME: free all you allocated so far */
265
 
266
        /* Update parent vnode size */
267
        v->size += sizeof(*memfsd);
268
        v->sb->ops->write_vnode(v->sb, v);
269
 
270
        /* Allocate a new vfs dentry */
271
        if (!(newd = vfs_alloc_dentry()))
272
                return PTR_ERR(-ENOMEM);
273
 
274
        /* Initialise it */
275
        newd->ops = generic_dentry_operations;
276
        newd->parent = parent;
277
        newd->vnode = newv;
278
        strncpy(newd->name, dirname, VFS_DNAME_MAX);
279
 
280
        /* Associate dentry with its vnode */
281
        list_insert(&newd->vref, &newd->vnode->dentries);
282
 
283
        /* Associate dentry with its parent */
284
        list_insert(&newd->child, &parent->children);
285
 
286
        /* Add both vnode and dentry to their flat caches */
287
        list_insert(&newd->cache_list, &dentry_cache);
288
        list_insert(&newv->cache_list, &vnode_cache);
289
 
290
        return newv;
291
}
292
 
293
/*
294
 * Reads the vnode directory contents into vnode's buffer in a posix-compliant
295
 * struct dirent format.
296
 *
297
 * Reading the buffer, allocates and populates all dentries and their
298
 * corresponding vnodes that are the direct children of vnode v. This means
299
 * that by each call to readdir, the vfs layer increases its cache of filesystem
300
 * tree by one level beneath that directory.
301
 */
302
int memfs_vnode_readdir(struct vnode *v)
303
{
304
        int err;
305
        struct memfs_dentry *memfsd;
306
        struct dentry *parent = link_to_struct(v->dentries.next,
307
                                           struct dentry, vref);
308
 
309
        /*
310
         * Precautions to prove that parent is the *only* dentry,
311
         * since directories can't have multiple dentries associated
312
         * with them.
313
         */
314
        BUG_ON(parent->vref.next != &v->dentries);
315
        BUG_ON(!vfs_isdir(v));
316
 
317
        /* If a buffer is there, it means the directory is already read */
318
        if (v->dirbuf.buffer)
319
                return 0;
320
 
321
        /* This is as big as a page */
322
        if (IS_ERR(v->dirbuf.buffer = vfs_alloc_dirpage(v))) {
323
                printf("%s: Could not allocate dirbuf.\n", __FUNCTION__);
324
                return (int)v->dirbuf.buffer;
325
        }
326
        v->dirbuf.npages = 1;
327
 
328
        /*
329
         * Fail if vnode size is bigger than a page. Since this allocation
330
         * method is to be origaced, we can live with this limitation for now.
331
         */
332
        BUG_ON(v->size > PAGE_SIZE);
333
 
334
        /* Read memfsd contents into the buffer */
335
        if ((err = v->fops.read(v, 0, 1, v->dirbuf.buffer)))
336
                return err;
337
 
338
        memfsd = (struct memfs_dentry *)v->dirbuf.buffer;
339
 
340
        /* Read fs-specific directory entry into vnode and dentry caches. */
341
        for (int i = 0; i < (v->size / sizeof(struct memfs_dentry)); i++) {
342
                struct dentry *newd;
343
                struct vnode *newv;
344
 
345
                /* Allocate a vfs dentry */
346
                if (!(newd = vfs_alloc_dentry()))
347
                        return -ENOMEM;
348
 
349
                /* Initialise it */
350
                newd->ops = generic_dentry_operations;
351
                newd->parent = parent;
352
                list_insert(&newd->child, &parent->children);
353
 
354
                /*
355
                 * Lookup the vnode for dentry by its vnode number. We call
356
                 * vnode_lookup_byvnum instead of directly reading it because
357
                 * this dentry might just be a link to a vnode that's already
358
                 * in the vnode cache. If it's not there, the lookup function
359
                 * allocates and reads it for us as well.
360
                 */
361
                newv = newd->vnode = vfs_vnode_lookup_byvnum(v->sb, memfsd[i].inum);
362
                if (!newv) {
363
                        printf("Filesystem seems to be broken. Directory has"
364
                               "inode number: %d, but no such inode found.\n",
365
                                memfsd[i].inum);
366
                        BUG();
367
                }
368
 
369
                /* Assing this dentry as a name of its vnode */
370
                list_insert(&newd->vref, &newd->vnode->dentries);
371
 
372
                /* Increase link count */
373
                newv->links++;
374
 
375
                /* Copy fields into generic dentry */
376
                memcpy(newd->name, memfsd[i].name, MEMFS_DNAME_MAX);
377
 
378
                /* Add both vnode and dentry to their caches */
379
                list_insert(&newd->cache_list, &dentry_cache);
380
                list_insert(&newv->cache_list, &vnode_cache);
381
        }
382
 
383
        return 0;
384
}
385
 
386
/*
387
 * Copies fs-specific dirent data into user buffer in
388
 * generic struct dirent format.
389
 */
390
int memfs_vnode_filldir(void *userbuf, struct vnode *v, int count)
391
{
392
        int nbytes;
393
        int err;
394
 
395
        /* Bytes to read, minimum of vnode size and count requested */
396
        nbytes = (v->size <= count) ? v->size : count;
397
 
398
        /* Read the dir content from fs, if haven't done so yet */
399
        if ((err = v->ops.readdir(v)) < 0)
400
                return err;
401
 
402
        /* Do we have those bytes at hand? */
403
        if (v->dirbuf.buffer && (v->dirbuf.npages * PAGE_SIZE) >= nbytes) {
404
                /*
405
                 * Memfs does a direct copy since memfs dirent format
406
                 * is the same as generic dirent format.
407
                 */
408
                memcpy(userbuf, v->dirbuf.buffer, nbytes);
409
                return nbytes;
410
        }
411
        return 0;
412
}
413
 
414
struct vnode_ops memfs_vnode_operations = {
415
        .readdir = memfs_vnode_readdir,
416
        .filldir = memfs_vnode_filldir,
417
        .mknod = memfs_vnode_mknod,
418
        .lookup = generic_vnode_lookup,
419
};
420
 
421
struct superblock_ops memfs_superblock_operations = {
422
        .read_vnode = memfs_read_vnode,
423
        .write_vnode = memfs_write_vnode,
424
        .alloc_vnode = memfs_alloc_vnode,
425
        .free_vnode = memfs_free_vnode,
426
};
427
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.