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:
Bahadir Balban
2008-04-12 17:57:45 +01:00
parent 5e0ec2db85
commit d7b06b5304
9 changed files with 138 additions and 52 deletions

View File

@@ -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__ */

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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.

View File

@@ -49,8 +49,6 @@ void vfs_register_filesystems(void)
memfs_register_fstype(&fs_type_list);
}
extern struct list_head vm_file_list;
/*
* Filesystem initialisation.
*/

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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;