Nucleus
Barry New list iteration in VFS f97b909 (3 years, 3 months ago)
diff --git a/vfs/direntry.c b/vfs/direntry.c
index 7a0b559..de7f02a 100644
--- a/vfs/direntry.c
+++ b/vfs/direntry.c
@@ -6,12 +6,6 @@
#include <nucleus/object.h>
#include <nucleus/vfs.h>
-/* Information for find callback */
-struct FindData {
- const char *name;
- DirEntry *result;
-};
-
static void direntry_delete(Object *);
/* Directory Entry object type */
@@ -41,32 +35,21 @@ direntry_delete(Object *obj)
put(entry->inode);
}
-/* Callback for finding a directory entry by name */
-static int
-compare_direntry_name(void *addr, void *data)
-{
- DirEntry *entry = addr;
- struct FindData *find = data;
- uint32_t hash = name_hash(find->name);
- if (__builtin_expect(!(entry->hash), 0))
- entry->hash = name_hash(entry->name);
- if (entry->hash != hash)
- return 0;
- if (strcmp(entry->name, find->name))
- return 0;
- find->result = get(entry);
- return 1;
-}
-
/* Find a Directory Entry by name in a list */
DirEntry *
find_direntry(ObjectList *list, const char *name)
{
- struct FindData data = {
- .name = name,
- .result = NULL,
- };
- iterate(list, compare_direntry_name, &data);
- return data.result;
+ DirEntry *entry;
+ uint32_t hash = name_hash(name);
+ foreach (list, entry) {
+ if (__builtin_expect(!(entry->hash), 0))
+ entry->hash = name_hash(entry->name);
+ if (entry->hash != hash)
+ continue;
+ if (strcmp(entry->name, name))
+ continue;
+ break;
+ }
+ return entry;
}
diff --git a/vfs/file.c b/vfs/file.c
index f73c8e1..0d0f31d 100644
--- a/vfs/file.c
+++ b/vfs/file.c
@@ -7,17 +7,21 @@
* generic version.
*/
+#include <string.h>
+#include <sys/stat.h>
#include <errno.h>
#include <nucleus/object.h>
#include <nucleus/vfs.h>
static void file_delete(Object *);
+static void file_copy(Object *, Object *);
/* File object type */
ObjectType fileType = {
.name = "FILE",
.size = sizeof(File),
.delete = file_delete,
+ .copy = file_copy,
};
/* Destroy a file */
@@ -31,6 +35,20 @@ file_delete(Object *obj)
destroy_list(file->path);
}
+/* Copy a file */
+static void
+file_copy(Object *a, Object *b)
+{
+ File *parent = (void *) a, *child = (void *) b;
+ if (parent->inode)
+ child->inode = copy(parent->inode);
+ child->flags = parent->flags;
+ child->pos = parent->pos;
+ child->ops = parent->ops;
+ if (parent->path)
+ child->path = copy_list(parent->path);
+}
+
/* Open a file */
int
file_open(File *file)
@@ -45,10 +63,43 @@ size_t
file_read(File *file, char *buf, size_t size)
{
size_t count = 0;
- if (!file->ops || !file->ops->read)
- return count;
- count = file->ops->read(file, buf, size, file->pos);
+ lock(file);
+ /* Irregular files cannot be cached */
+ if (!S_ISREG(file->inode->mode)) {
+ if (file->ops && file->ops->read)
+ count = file->ops->read(file, buf, size, file->pos);
+ goto end;
+ }
+
+ if (file->pos > file->inode->size)
+ goto end;
+ if (file->pos + size > file->inode->size)
+ size = file->inode->size - file->pos;
+
+ /* Read with cache */
+ Page *page;
+ char *data;
+ uint16_t min, indent = file->pos % PAGE_SIZE;
+ while (size) {
+ min = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+ page = find_page(file->inode->pages,
+ file->pos + (count % PAGE_SIZE));
+ if (page) {
+ /* Cache hit */
+ data = map_page(page);
+ memcpy(buf + count, data + indent, min);
+ } else if (file->ops && file->ops->read) {
+ /* Cache miss */
+ file->ops->read(file, buf + count, min,
+ file->pos + count);
+ }
+ indent = 0;
+ size -= min;
+ count += min;
+ }
+end:
file->pos += count;
+ unlock(file);
return count;
}
@@ -57,9 +108,52 @@ size_t
file_write(File *file, char *buf, size_t size)
{
size_t count = 0;
- if (!file->ops || !file->ops->write)
- return count;
- count = file->ops->write(file, buf, size, file->pos);
+ lock(file);
+ /* Irregular files cannot be cached */
+ if (!S_ISREG(file->inode->mode)) {
+ if (file->ops && file->ops->write)
+ count = file->ops->write(file, buf, size, file->pos);
+ goto end;
+ }
+
+ if (file->pos + size > file->inode->size)
+ file->inode->size = size + file->pos;
+
+ /* Write with cache */
+ Page *page;
+ char *data;
+ uint16_t min, indent = file->pos % PAGE_SIZE;
+ while (size) {
+ min = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+ page = find_page(file->inode->pages,
+ file->pos + (count % PAGE_SIZE));
+ if (page) {
+ /* Cache hit */
+ data = map_page(page);
+ memcpy(data + indent, buf + count, min);
+ } else if (file->ops && file->ops->write) {
+ /* Cache miss */
+ file->ops->read(file, buf + count, min,
+ file->pos + count);
+ }
+ indent = 0;
+ size -= min;
+ count += min;
+ }
+end:
file->pos += count;
+ unlock(file);
return count;
}
+
+/* Map a file into memory */
+void
+file_mmap(File *file, void *addr, size_t len, off_t offset)
+{
+ if (!file->ops)
+ return;
+ if (file->ops->mmap)
+ file->ops->mmap(file, addr, len, offset);
+ else if (S_ISREG(file->inode->mode))
+ file->ops->read(file, addr, len, offset);
+}
diff --git a/vfs/fstype.c b/vfs/fstype.c
index 9043ba4..f157a71 100644
--- a/vfs/fstype.c
+++ b/vfs/fstype.c
@@ -16,31 +16,12 @@ struct FSType {
Inode *(*mount)(FSType *, int, const char *, void *);
};
-/* Find callback data */
-struct FindData {
- const char *name;
- FSType *result;
-};
-
/* File System Type object type */
ObjectType fstypeType = {
.name = "FILE SYSTEM TYPE",
.size = sizeof(FSType),
};
-/* Callback for finding a file system type */
-static int
-compare_fstype_name(void *object, void *data)
-{
- FSType *type = object;
- struct FindData *find = data;
- if (!strcmp(type->name, find->name)) {
- find->result = type;
- return 1;
- }
- return 0;
-}
-
/* Create a new file system type */
void
register_fstype(const char *name, mount_callback_t mount)
@@ -55,13 +36,13 @@ int
mount_fstype(const char *name, int flags, const char *src, void *data,
Inode **root)
{
- struct FindData find = {
- .name = name,
- .result = NULL,
- };
- iterate(fstypeType.objects, compare_fstype_name, &find);
- if (!find.result)
+ FSType *type;
+ foreach (fstypeType.objects, type) {
+ if (!strcmp(type->name, name))
+ break;
+ }
+ if (!type)
return -ENODEV;
- *root = find.result->mount(find.result, flags, src, data);
+ *root = type->mount(type, flags, src, data);
return 0;
}
diff --git a/vfs/inode.c b/vfs/inode.c
index 3f760e7..03c301d 100644
--- a/vfs/inode.c
+++ b/vfs/inode.c
@@ -17,6 +17,7 @@
static void inode_new(Object *);
static void inode_delete(Object *);
+static void inode_copy(Object *, Object *);
/* Inode object type */
ObjectType inodeType = {
@@ -24,6 +25,7 @@ ObjectType inodeType = {
.size = sizeof(Inode),
.new = inode_new,
.delete = inode_delete,
+ .copy = inode_copy,
};
/* Create a new Inode */
@@ -51,6 +53,28 @@ inode_delete(Object *obj)
destroy_list(inode->pages);
}
+/* Copy an Inode */
+static void
+inode_copy(Object *a, Object *b)
+{
+ Inode *parent = (void *) a, *child = (void *) b;
+ child->ino = parent->ino;
+ child->uid = parent->uid;
+ child->gid = parent->gid;
+ child->mode = parent->mode;
+ child->nlink = parent->nlink;
+ child->size = parent->size;
+ child->dev = parent->dev;
+ child->ops = parent->ops;
+ child->fileOps = parent->fileOps;
+ if (parent->super)
+ child->super = get(parent->super);
+ if (parent->dirEntries)
+ child->dirEntries = copy_list(parent->dirEntries);
+ if (parent->pages)
+ child->pages = copy_list(parent->pages);
+}
+
/* Check if a process has permission to access an inode */
int
permission(Inode *inode, int mask)
diff --git a/vfs/superblock.c b/vfs/superblock.c
index 4d90e3d..41f35b3 100644
--- a/vfs/superblock.c
+++ b/vfs/superblock.c
@@ -9,31 +9,12 @@
#include <sys/types.h>
#include <nucleus/vfs.h>
-/* Data for find callback */
-struct FindData {
- ino_t ino;
- Inode *result;
-};
-
/* Super Block object type */
ObjectType superBlockType = {
.name = "SUPER BLOCK",
.size = sizeof(SuperBlock),
};
-/* Find an Inode by ino value */
-static int
-compare_inode_ino(void *addr, void *data)
-{
- Inode *inode = addr;
- struct FindData *find = data;
- if (find->ino == inode->ino){
- find->result = get(inode);
- return 1;
- }
- return 0;
-}
-
/* Allocate an Inode */
Inode *
super_alloc_inode(SuperBlock *sb)
@@ -48,10 +29,9 @@ Inode *
super_find_inode(SuperBlock *sb, ino_t ino)
{
Inode *inode;
- struct FindData find = {
- .ino = ino,
- .result = NULL,
- };
- iterate(sb->inodes, compare_inode_ino, &find);
- return find.result;
+ foreach (sb->inodes, inode) {
+ if (inode->ino == ino)
+ break;
+ }
+ return inode;
}