mirror of
https://github.com/drasko/codezero.git
synced 2026-01-13 19:33:15 +01:00
sys_readdir and root vnode fixes.
Changes towards successfully filling dirent structures for sys_readdir and creating a root vnode for the filesystem.
This commit is contained in:
@@ -1,18 +1,6 @@
|
||||
#ifndef __FS0_MM_H__
|
||||
#define __FS0_MM_H__
|
||||
|
||||
/*
|
||||
* Describes the in-memory representation of a file. This is used to track
|
||||
* file content, i.e. file pages by mm0, this is a temporary mock up until
|
||||
* fs0 and mm0 are wired together.
|
||||
*/
|
||||
struct vm_file {
|
||||
unsigned long vnum;
|
||||
unsigned long length;
|
||||
|
||||
/* This is the cache of physical pages that this file has in memory. */
|
||||
struct list_head page_cache_list;
|
||||
struct vm_pager *pager;
|
||||
};
|
||||
|
||||
#endif /* __FS0_MM_H__ */
|
||||
|
||||
@@ -48,6 +48,7 @@ struct vnode_ops {
|
||||
vnode_op_t create;
|
||||
struct vnode *(*lookup)(struct vnode *root, char *path);
|
||||
int (*readdir)(struct vnode *v);
|
||||
int (*filldir)(struct vnode *v);
|
||||
vnode_op_t link;
|
||||
vnode_op_t unlink;
|
||||
int (*mkdir)(struct vnode *parent, char *name);
|
||||
@@ -91,8 +92,9 @@ struct dentry {
|
||||
};
|
||||
|
||||
/*
|
||||
* Buffer to keep directory content. This is the only vnode content
|
||||
* that fs0 maintains. All other file data is in mm0 page cache.
|
||||
* Buffer that maintains directory content for a directory vnode. This is the
|
||||
* only vnode content that fs0 maintains. All other file data is in mm0 page
|
||||
* cache.
|
||||
*/
|
||||
struct dirbuf {
|
||||
unsigned long npages;
|
||||
@@ -100,6 +102,15 @@ struct dirbuf {
|
||||
u8 *buffer;
|
||||
};
|
||||
|
||||
/* Posix-style dirent format used by userspace. Returned by sys_readdir() */
|
||||
#define DIRENT_NAME_MAX 32
|
||||
struct dirent {
|
||||
u32 inum; /* Inode number */
|
||||
u32 offset; /* Dentry offset in its buffer */
|
||||
u32 rlength; /* Record length */
|
||||
u8 name[DIRENT_NAME_MAX]; /* Name string */
|
||||
};
|
||||
|
||||
struct vnode {
|
||||
unsigned long vnum; /* Filesystem-wide unique vnode id */
|
||||
int refcnt; /* Reference counter */
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#define MEMFS_MAGIC 0xB
|
||||
#define MEMFS_NAME "memfs"
|
||||
#define MEMFS_NAME_SIZE 8
|
||||
|
||||
struct memfs_inode {
|
||||
u32 inum; /* Inode number */
|
||||
u32 mode; /* File permissions */
|
||||
@@ -64,7 +65,7 @@ struct memfs_superblock {
|
||||
u32 blocksize; /* Filesystem block size */
|
||||
u64 fmaxblocks; /* Maximum number of blocks per file */
|
||||
u64 fssize; /* Total size of filesystem */
|
||||
struct memfs_inode *root; /* The root of this superblock */
|
||||
unsigned long root_vnum; /* The root vnum of this superblock */
|
||||
struct list_head inode_cache_list; /* Chain of alloc caches */
|
||||
struct list_head block_cache_list; /* Chain of alloc caches */
|
||||
struct id_pool *ipool; /* Index pool for inodes */
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
#include INC_GLUE(memory.h)
|
||||
#include <stdio.h>
|
||||
|
||||
/* List of all in-memory files. */
|
||||
struct list_head vm_file_list;
|
||||
|
||||
/*
|
||||
* This reads contents of a file in pages, calling the fs-specific file read function to read-in
|
||||
* those pages' contents.
|
||||
|
||||
@@ -49,8 +49,6 @@ void vfs_register_filesystems(void)
|
||||
memfs_register_fstype(&fs_type_list);
|
||||
}
|
||||
|
||||
extern struct list_head vm_file_list;
|
||||
|
||||
/*
|
||||
* Filesystem initialisation.
|
||||
*/
|
||||
|
||||
@@ -66,12 +66,6 @@ int memfs_format_filesystem(void *buffer)
|
||||
INIT_LIST_HEAD(&sb->inode_cache_list);
|
||||
memfs_init_caches(sb);
|
||||
|
||||
/* We allocate and fix a root inode so the sb is ready for mount */
|
||||
sb->root = memfs_create_inode(sb);
|
||||
|
||||
/* Some early-init code relies on root having inode number 0 */
|
||||
BUG_ON(sb->root->inum != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -115,6 +109,50 @@ struct file_system_type memfs_fstype = {
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialise root inode as a directory, as in the mknod() call
|
||||
* but differently since root is parentless and is the parent of itself.
|
||||
*/
|
||||
int memfs_init_rootdir(struct superblock *sb)
|
||||
{
|
||||
struct memfs_superblock *msb = sb->fs_super;
|
||||
struct dentry *d;
|
||||
struct vnode *v;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Create the root vnode. Since this is memfs, root vnode is
|
||||
* not read-in but dynamically created here. We expect this
|
||||
* first vnode to have vnum = 0.
|
||||
*/
|
||||
v = sb->root = vfs_sb->ops->alloc_vnode(vfs_sb);
|
||||
msb->root_vnum = vfs_sb->root->vnum;
|
||||
BUG_ON(msb->root_vnum != 0);
|
||||
|
||||
/* Initialise fields */
|
||||
vfs_set_type(v, S_IFDIR);
|
||||
|
||||
/* Allocate a new vfs dentry */
|
||||
if (!(d = vfs_alloc_dentry()))
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialise it. NOTE: On root, parent is itself */
|
||||
strncpy(d->name, "/", VFS_DNAME_MAX);
|
||||
d->ops = generic_dentry_operations;
|
||||
d->parent = d;
|
||||
d->vnode = v;
|
||||
|
||||
/* Associate dentry with its vnode */
|
||||
list_add(&d->vref, &d->vnode->dentries);
|
||||
|
||||
/* Associate dentry with its parent */
|
||||
list_add(&d->child, &parent->children);
|
||||
|
||||
/* Add both vnode and dentry to their flat caches */
|
||||
list_add(&d->cache_list, &dentry_cache);
|
||||
list_add(&v->cache_list, &vnode_cache);
|
||||
}
|
||||
|
||||
/* Copies fs-specific superblock into generic vfs superblock */
|
||||
struct superblock *memfs_fill_superblock(struct memfs_superblock *sb,
|
||||
struct superblock *vfs_sb)
|
||||
@@ -125,11 +163,8 @@ struct superblock *memfs_fill_superblock(struct memfs_superblock *sb,
|
||||
vfs_sb->fssize = sb->fssize;
|
||||
vfs_sb->blocksize = sb->blocksize;
|
||||
|
||||
/*
|
||||
* Create the first vnode. Since this is memfs, root vnode is
|
||||
* not read-in but dynamically created here.
|
||||
*/
|
||||
vfs_sb->ops->alloc_vnode(vfs_sb);
|
||||
/* We initialise the root vnode as the root directory */
|
||||
memfs_init_rootdir(vfs_sb);
|
||||
|
||||
return vfs_sb;
|
||||
}
|
||||
|
||||
@@ -204,6 +204,7 @@ int memfs_write_vnode(struct superblock *sb, struct vnode *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Creates ordinary files and directories at the moment. In the future,
|
||||
* other file types will be added.
|
||||
@@ -247,6 +248,8 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode)
|
||||
/* Get the next directory entry available on the parent vnode */
|
||||
if (v->dirbuf.npages * PAGE_SIZE <= v->size)
|
||||
return -ENOSPC;
|
||||
|
||||
/* Fill in the new entry to parent directory entry */
|
||||
memfsd = (struct memfs_dentry *)&v->dirbuf.buffer[v->size];
|
||||
memfsd->offset = v->size;
|
||||
memfsd->rlength = sizeof(*memfsd);
|
||||
@@ -254,8 +257,7 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode)
|
||||
strncpy((char *)memfsd->name, dirname, MEMFS_DNAME_MAX);
|
||||
memfsd->name[MEMFS_DNAME_MAX - 1] = '\0';
|
||||
|
||||
BUG(); /* FIXME: Fix this issue. */
|
||||
/* Write the updated directory buffer back to disk */
|
||||
/* Write the updated directory buffer back to disk block */
|
||||
v->fops.write(v, 0, 1, v->dirbuf.buffer);
|
||||
|
||||
/* Update parent vnode */
|
||||
@@ -269,6 +271,7 @@ int memfs_vnode_mknod(struct vnode *v, char *dirname, unsigned int mode)
|
||||
newd->ops = generic_dentry_operations;
|
||||
newd->parent = parent;
|
||||
newd->vnode = newv;
|
||||
strncpy(newd->name, dirname, VFS_DNAME_MAX);
|
||||
|
||||
/* Associate dentry with its vnode */
|
||||
list_add(&newd->vref, &newd->vnode->dentries);
|
||||
@@ -374,8 +377,33 @@ int memfs_vnode_readdir(struct vnode *v)
|
||||
}
|
||||
|
||||
|
||||
int memfs_vnode_filldir(void *usrbuf, struct vnode *v, int count)
|
||||
{
|
||||
int size;
|
||||
|
||||
/* Bytes to read, minimum of vnode size and count requested */
|
||||
nbytes = (v->size <= count) ? v->size : count;
|
||||
|
||||
/* Read the dir content from fs, if haven't done so yet */
|
||||
if ((err = v->ops.readdir(v)) < 0)
|
||||
return err;
|
||||
|
||||
/* Do we have those bytes at hand? */
|
||||
if (v->dirbuf.buffer && (v->dirbuf.npages * PAGE_SIZE) >= nbytes) {
|
||||
/*
|
||||
* Memfs does a direct copy since memfs dirent format
|
||||
* is the same as generic dirent format.
|
||||
*/
|
||||
memcpy(buf, v->dirbuf.buffer, nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct vnode_ops memfs_vnode_operations = {
|
||||
.readdir = memfs_vnode_readdir,
|
||||
.filldir = memfs_vnode_filldir,
|
||||
.mknod = memfs_vnode_mknod,
|
||||
};
|
||||
|
||||
|
||||
@@ -226,17 +226,33 @@ int pager_sys_write(l4id_t sender, unsigned long vnum, unsigned long f_offset,
|
||||
* the names . and ..
|
||||
*/
|
||||
|
||||
int fill_dirent(void *buf, unsigned long vnum, int offset, char *name)
|
||||
{
|
||||
struct dirent *d = buf;
|
||||
|
||||
d->inum = (unsigned int)vnum;
|
||||
d->offset = offset;
|
||||
d->rlength = sizeof(struct dirent);
|
||||
strncpy(d->name, name, DIRENT_NAME_MAX);
|
||||
|
||||
return d->rlength;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads @count bytes of posix struct dirents into @buf. This implements
|
||||
* the raw dirent read syscall upon which readdir() etc. posix calls
|
||||
* can be built in userspace.
|
||||
*
|
||||
* FIXME: Ensure buf is in shared utcb, and count does not exceed it.
|
||||
*/
|
||||
int sys_readdir(l4id_t sender, int fd, void *buf, int count)
|
||||
{
|
||||
struct dentry *d = list_entry(v->dentries.next, struct dentry, vref);
|
||||
int dirent_size = sizeof(struct dirent);
|
||||
int total = 0, nbytes = 0;
|
||||
unsigned long vnum;
|
||||
struct vnode *v;
|
||||
struct tcb *t;
|
||||
unsigned long nbytes;
|
||||
int err;
|
||||
|
||||
/* Get the task */
|
||||
@@ -257,20 +273,30 @@ int sys_readdir(l4id_t sender, int fd, void *buf, int count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read the whole content from fs, if haven't done so yet */
|
||||
if ((err = v->ops.readdir(v)) < 0) {
|
||||
l4_ipc_return(err);
|
||||
/* Write pseudo-entries . and .. to user buffer */
|
||||
if (count < dirent_size)
|
||||
return 0;
|
||||
|
||||
fill_dirent(buf, v->vnum, nbytes, ".");
|
||||
nbytes += dirent_size;
|
||||
buf += dirent_size;
|
||||
count -= dirent_size;
|
||||
|
||||
if (count < dirent_size)
|
||||
return 0;
|
||||
|
||||
fill_dirent(buf, d->parent->vnode->vnum, nbytes, "..");
|
||||
nbytes += dirent_size;
|
||||
buf += dirent_size;
|
||||
count -= dirent_size;
|
||||
|
||||
/* Copy fs-specific dir to buf in struct dirent format */
|
||||
if ((total = v->ops.filldir(buf, v, count)) < 0) {
|
||||
l4_ipc_return(total);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bytes to read, minimum of vnode size and count requested */
|
||||
nbytes = (v->size <= count) ? v->size : count;
|
||||
|
||||
/* Do we have those bytes at hand? */
|
||||
if (v->dirbuf.buffer && (v->dirbuf.npages * PAGE_SIZE) >= nbytes) {
|
||||
memcpy(buf, v->dirbuf.buffer, nbytes);
|
||||
l4_ipc_return(nbytes);
|
||||
}
|
||||
nbytes += total;
|
||||
l4_ipc_return(nbytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
#include <vfs.h>
|
||||
#include <task.h>
|
||||
|
||||
struct list_head vnode_cache;
|
||||
struct list_head dentry_cache;
|
||||
LIST_HEAD(vnode_cache);
|
||||
LIST_HEAD(dentry_cache);
|
||||
|
||||
/*
|
||||
* /
|
||||
@@ -59,7 +59,7 @@ struct vnode *vfs_lookup_byvnum(struct superblock *sb, unsigned long vnum)
|
||||
*/
|
||||
struct vnode *vfs_lookup_bypath(struct tcb *task, char *path)
|
||||
{
|
||||
struct vnode *vnstart;
|
||||
struct vnode *vstart;
|
||||
|
||||
/* Is it the root or current directory? If so, we already got it. */
|
||||
if (!strcmp(path, "/"))
|
||||
@@ -76,13 +76,15 @@ struct vnode *vfs_lookup_bypath(struct tcb *task, char *path)
|
||||
/*
|
||||
* This does vfs cache + fs lookup.
|
||||
*/
|
||||
return generic_vnode_lookup(vnstart, path);
|
||||
return generic_vnode_lookup(vstart, path);
|
||||
}
|
||||
|
||||
int vfs_mount_root(struct superblock *sb)
|
||||
{
|
||||
/* Lookup the root vnode of this superblock.
|
||||
* The root superblock has vnode number 0. */
|
||||
/*
|
||||
* Lookup the root vnode of this superblock.
|
||||
* The root superblock has vnode number 0.
|
||||
*/
|
||||
vfs_root.pivot = vfs_lookup_byvnum(sb, 0);
|
||||
vfs_root.sb = sb;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user