Minimal working vfs refactor
This commit is contained in:
+6
-5
@@ -59,19 +59,20 @@ OBJS+=$(O)/sys/debug.o \
|
||||
$(O)/sys/net/arp.o \
|
||||
$(O)/sys/net/in.o \
|
||||
$(O)/sys/net/netdev.o \
|
||||
$(O)/sys/vfs/pseudo.o \
|
||||
$(O)/sys/vfs/ext2/ext2.o \
|
||||
$(O)/sys/vfs/ext2/ext2blk.o \
|
||||
$(O)/sys/vfs/tar.o \
|
||||
$(O)/sys/blk/ram.o \
|
||||
$(O)/sys/reboot.o \
|
||||
$(O)/sys/random.o
|
||||
|
||||
# $(O)/sys/vfs/pseudo.o \
|
||||
# \
|
||||
$(O)/sys/tty.o \
|
||||
$(O)/sys/vfs/pty.o \
|
||||
$(O)/sys/vfs/ext2/ext2alloc.o \
|
||||
$(O)/sys/vfs/ext2/ext2blk.o \
|
||||
$(O)/sys/vfs/ext2/ext2.o \
|
||||
$(O)/sys/vfs/ext2/ext2dir.o \
|
||||
$(O)/sys/vfs/ext2/ext2vnop.o \
|
||||
$(O)/sys/vfs/tar.o \
|
||||
$(O)/sys/blk/ram.o \
|
||||
|
||||
ifeq ($(VESA_ENABLE),1)
|
||||
OBJS+=$(O)/sys/psf.o \
|
||||
|
||||
+21
-15
@@ -1,12 +1,15 @@
|
||||
#pragma once
|
||||
#include "sys/types.h"
|
||||
|
||||
struct vnode;
|
||||
|
||||
// TODO: something like device name alias
|
||||
// for example, /dev/root aliased to
|
||||
// /dev/ramN or /dev/sdXN
|
||||
enum dev_class {
|
||||
DEV_CLASS_BLOCK,
|
||||
DEV_CLASS_CHAR
|
||||
DEV_CLASS_BLOCK = 1,
|
||||
DEV_CLASS_CHAR = 2,
|
||||
DEV_CLASS_ANY = 255
|
||||
};
|
||||
|
||||
#define DEV_BLOCK_SDx 1
|
||||
@@ -17,19 +20,22 @@ enum dev_class {
|
||||
|
||||
#define DEV_CHAR_TTY 1
|
||||
|
||||
struct dev_entry {
|
||||
char dev_name[64];
|
||||
int dev_add(enum dev_class cls, int subcls, void *dev, const char *name);
|
||||
int dev_find(enum dev_class cls, const char *name, struct vnode **dev_node);
|
||||
|
||||
enum dev_class dev_class;
|
||||
uint16_t dev_subclass;
|
||||
uint16_t dev_number;
|
||||
//struct dev_entry {
|
||||
// char dev_name[64];
|
||||
//
|
||||
// enum dev_class dev_class;
|
||||
// uint16_t dev_subclass;
|
||||
// uint16_t dev_number;
|
||||
//
|
||||
// void *dev;
|
||||
// struct dev_entry *cdr;
|
||||
//};
|
||||
|
||||
void *dev;
|
||||
struct dev_entry *cdr;
|
||||
};
|
||||
//struct dev_entry *dev_iter(void);
|
||||
|
||||
struct dev_entry *dev_iter(void);
|
||||
|
||||
int dev_alloc_name(enum dev_class cls, uint16_t subclass, char *name);
|
||||
int dev_by_name(struct dev_entry **ent, const char *name);
|
||||
void dev_entry_add(struct dev_entry *ent);
|
||||
//int dev_alloc_name(enum dev_class cls, uint16_t subclass, char *name);
|
||||
//int dev_by_name(struct dev_entry **ent, const char *name);
|
||||
//void dev_entry_add(struct dev_entry *ent);
|
||||
|
||||
+15
-15
@@ -124,24 +124,24 @@ void ext2_class_init(void);
|
||||
enum vnode_type ext2_inode_type(struct ext2_inode *i);
|
||||
|
||||
// Implemented in ext2blk.c
|
||||
int ext2_write_superblock(fs_t *ext2);
|
||||
int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf);
|
||||
int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf);
|
||||
int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, void *buf);
|
||||
int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, const void *buf);
|
||||
int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino);
|
||||
int ext2_write_inode(fs_t *ext2, const struct ext2_inode *inode, uint32_t ino);
|
||||
int ext2_write_superblock(struct fs *ext2);
|
||||
int ext2_read_block(struct fs *ext2, uint32_t block_no, void *buf);
|
||||
int ext2_write_block(struct fs *ext2, uint32_t block_no, const void *buf);
|
||||
int ext2_read_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, void *buf);
|
||||
int ext2_write_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, const void *buf);
|
||||
int ext2_read_inode(struct fs *ext2, struct ext2_inode *inode, uint32_t ino);
|
||||
int ext2_write_inode(struct fs *ext2, const struct ext2_inode *inode, uint32_t ino);
|
||||
|
||||
// Implemented in ext2alloc.c
|
||||
int ext2_alloc_block(fs_t *ext2, uint32_t *block_no);
|
||||
int ext2_free_block(fs_t *ext2, uint32_t block_no);
|
||||
int ext2_inode_alloc_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index);
|
||||
int ext2_free_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index);
|
||||
int ext2_free_inode(fs_t *ext2, uint32_t ino);
|
||||
int ext2_alloc_inode(fs_t *ext2, uint32_t *ino);
|
||||
int ext2_alloc_block(struct fs *ext2, uint32_t *block_no);
|
||||
int ext2_free_block(struct fs *ext2, uint32_t block_no);
|
||||
int ext2_inode_alloc_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index);
|
||||
int ext2_free_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t ino, uint32_t index);
|
||||
int ext2_free_inode(struct fs *ext2, uint32_t ino);
|
||||
int ext2_alloc_inode(struct fs *ext2, uint32_t *ino);
|
||||
|
||||
// Implemented in ext2dir.c
|
||||
int ext2_dir_add_inode(fs_t *ext2, struct vnode *dir, const char *name, uint32_t ino);
|
||||
int ext2_dir_remove_inode(fs_t *ext2, struct vnode *dir, const char *name, uint32_t ino);
|
||||
int ext2_dir_add_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino);
|
||||
int ext2_dir_remove_inode(struct fs *ext2, struct vnode *dir, const char *name, uint32_t ino);
|
||||
|
||||
extern struct vnode_operations ext2_vnode_ops;
|
||||
|
||||
+4
-7
@@ -3,15 +3,15 @@
|
||||
#include "sys/blk.h"
|
||||
|
||||
struct statvfs;
|
||||
struct vfs_node;
|
||||
|
||||
struct fs_class {
|
||||
char name[64];
|
||||
|
||||
int opt;
|
||||
|
||||
struct vnode *(*get_root) (fs_t *fs);
|
||||
int (*mount) (struct fs *fs, const char *opt);
|
||||
struct vnode *(*get_root) (struct fs *fs);
|
||||
int (*init) (struct fs *fs, const char *opt);
|
||||
int (*mount) (struct fs *fs);
|
||||
int (*umount) (struct fs *fs);
|
||||
int (*statvfs) (struct fs *fs, struct statvfs *st);
|
||||
};
|
||||
@@ -19,9 +19,6 @@ struct fs_class {
|
||||
// The actual filesystem instance,
|
||||
// one per each mount
|
||||
struct fs {
|
||||
// Mount details here
|
||||
struct vnode *mnt_at;
|
||||
|
||||
// Block device on which the filesystem resides
|
||||
struct blkdev *blk;
|
||||
|
||||
@@ -31,7 +28,7 @@ struct fs {
|
||||
struct fs_class *cls;
|
||||
};
|
||||
|
||||
struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, struct vnode *mnt_at);
|
||||
struct fs *fs_create(struct fs_class *cls, struct blkdev *blk);
|
||||
void fs_release(struct fs *fs);
|
||||
struct fs_class *fs_class_by_name(const char *name);
|
||||
int fs_class_register(struct fs_class *cls);
|
||||
|
||||
+26
-29
@@ -10,62 +10,48 @@
|
||||
|
||||
#define NODE_MAXLEN 256
|
||||
|
||||
// Means the node has no physical storage and resides only
|
||||
// in memory
|
||||
#define VN_MEMORY (1 << 0)
|
||||
|
||||
struct ofile;
|
||||
struct vfs_ioctx;
|
||||
struct vnode;
|
||||
typedef struct fs fs_t;
|
||||
struct fs;
|
||||
|
||||
enum vnode_type {
|
||||
VN_REG,
|
||||
VN_DIR,
|
||||
VN_BLK,
|
||||
VN_CHR,
|
||||
// VN_LNK
|
||||
VN_UNK,
|
||||
};
|
||||
|
||||
struct vnode_operations {
|
||||
// File tree traversal, node instance operations
|
||||
int (*find) (struct vnode *node, const char *path, struct vnode **res);
|
||||
void (*destroy) (struct vnode *node);
|
||||
|
||||
// Symlink
|
||||
// int (*readlink) (struct vnode *node, char *path);
|
||||
// int (*symlink) (struct vnode *at, struct vfs_ioctx *ctx, const char *name, const char *dst);
|
||||
|
||||
// File entry operations
|
||||
int (*access) (struct vnode *node, uid_t *uid, gid_t *gid, mode_t *mode);
|
||||
int (*creat) (struct vnode *node, struct vfs_ioctx *ctx, const char *name, mode_t mode, int opt, struct vnode **res);
|
||||
int (*mkdir) (struct vnode *at, const char *name, mode_t mode);
|
||||
int (*unlink) (struct vnode *at, struct vnode *vn, const char *name);
|
||||
int (*stat) (struct vnode *node, struct stat *st);
|
||||
int (*chmod) (struct vnode *node, mode_t mode);
|
||||
int (*chown) (struct vnode *node, uid_t uid, gid_t gid);
|
||||
|
||||
// Directory access
|
||||
int (*opendir) (struct vnode *node, int opt);
|
||||
int (*readdir) (struct ofile *fd);
|
||||
|
||||
// File access
|
||||
int (*open) (struct vnode *node, int opt);
|
||||
int (*open) (struct ofile *fd);
|
||||
void (*close) (struct ofile *fd);
|
||||
|
||||
ssize_t (*read) (struct ofile *fd, void *buf, size_t count);
|
||||
ssize_t (*write) (struct ofile *fd, const void *buf, size_t count);
|
||||
int (*truncate) (struct ofile *fd, size_t length);
|
||||
};
|
||||
|
||||
struct vnode {
|
||||
enum vnode_type type;
|
||||
|
||||
char name[NODE_MAXLEN];
|
||||
uint32_t flags;
|
||||
|
||||
struct vnode *first_child;
|
||||
struct vnode *next_child;
|
||||
struct vnode *parent;
|
||||
|
||||
uint32_t refcount;
|
||||
uint32_t open_count;
|
||||
uint64_t ino;
|
||||
|
||||
fs_t *fs;
|
||||
gid_t gid;
|
||||
uid_t uid;
|
||||
|
||||
struct fs *fs;
|
||||
void *fs_data;
|
||||
/*
|
||||
* (struct blkdev *) if type == VN_BLK
|
||||
@@ -76,4 +62,15 @@ struct vnode {
|
||||
struct vnode_operations *op;
|
||||
};
|
||||
|
||||
struct vnode *vnode_create(const char *name);
|
||||
// Node itself
|
||||
struct vnode *vnode_create(enum vnode_type t, const char *name);
|
||||
|
||||
// Tree manipulation
|
||||
void vnode_attach(struct vnode *parent, struct vnode *child);
|
||||
void vnode_detach(struct vnode *node);
|
||||
|
||||
// Tree traversal
|
||||
void vnode_dump_tree(int level, struct vnode *node, int depth);
|
||||
int vnode_lookup_child(struct vnode *of, const char *name, struct vnode **child);
|
||||
int vnode_lookup_tree(struct vnode *at, const char *rel_path, struct vnode **child);
|
||||
|
||||
|
||||
+24
-15
@@ -62,26 +62,35 @@ static ssize_t ahci_blk_write(struct blkdev *blk, const void *buf, size_t off, s
|
||||
}
|
||||
|
||||
static int ahci_add_port_dev(struct ahci_port_registers *port) {
|
||||
void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry));
|
||||
_assert(ent);
|
||||
|
||||
// Create a new device
|
||||
// XXX: Replace kmalloc with dev_blk_create
|
||||
struct blkdev *blk = kmalloc(sizeof(struct blkdev));
|
||||
blk->dev_data = port;
|
||||
blk->read = ahci_blk_read;
|
||||
blk->write = ahci_blk_write;
|
||||
|
||||
ent->dev = blk;
|
||||
ent->dev_class = DEV_CLASS_BLOCK;
|
||||
ent->dev_subclass = DEV_BLOCK_SDx;
|
||||
if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev_entry_add(ent);
|
||||
|
||||
return 0;
|
||||
return dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_SDx, blk, NULL);
|
||||
}
|
||||
// //void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
// //struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
// //struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry));
|
||||
// //_assert(ent);
|
||||
//
|
||||
// //blk->dev_data = port;
|
||||
// //blk->read = ahci_blk_read;
|
||||
// //blk->write = ahci_blk_write;
|
||||
//
|
||||
// //ent->dev = blk;
|
||||
// //ent->dev_class = DEV_CLASS_BLOCK;
|
||||
// //ent->dev_subclass = DEV_BLOCK_SDx;
|
||||
// //if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) {
|
||||
// // return -1;
|
||||
// //}
|
||||
//
|
||||
// //dev_entry_add(ent);
|
||||
//
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
uint32_t ahci_irq(void *ctx) {
|
||||
struct ahci_registers *controller = ctx;
|
||||
|
||||
+28
-28
@@ -287,39 +287,39 @@ int ide_ata_read_pio(struct ide_device *dev, void *buf, size_t nsect, uint64_t l
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ide_blk_read(struct blkdev *blk, void *buf, size_t off, size_t count) {
|
||||
_assert(blk && blk->dev_data);
|
||||
_assert(!(off & 511));
|
||||
_assert(!(count & 511));
|
||||
|
||||
size_t nsect = count / 512;
|
||||
size_t lba = off / 512;
|
||||
|
||||
// XXX: DMA fucks up for some reason, investigate that
|
||||
ide_ata_read_pio((struct ide_device *) blk->dev_data, buf, nsect, lba);
|
||||
|
||||
return count;
|
||||
}
|
||||
//static ssize_t ide_blk_read(struct blkdev *blk, void *buf, size_t off, size_t count) {
|
||||
// _assert(blk && blk->dev_data);
|
||||
// _assert(!(off & 511));
|
||||
// _assert(!(count & 511));
|
||||
//
|
||||
// size_t nsect = count / 512;
|
||||
// size_t lba = off / 512;
|
||||
//
|
||||
// // XXX: DMA fucks up for some reason, investigate that
|
||||
// ide_ata_read_pio((struct ide_device *) blk->dev_data, buf, nsect, lba);
|
||||
//
|
||||
// return count;
|
||||
//}
|
||||
|
||||
static int ide_add_ata_dev(struct ide_device *dev) {
|
||||
void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry));
|
||||
_assert(ent);
|
||||
//void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
//struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
//struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry));
|
||||
//_assert(ent);
|
||||
|
||||
blk->dev_data = dev;
|
||||
blk->write = NULL;
|
||||
blk->read = ide_blk_read;
|
||||
//blk->write = ahci_blk_write;
|
||||
//blk->dev_data = dev;
|
||||
//blk->write = NULL;
|
||||
//blk->read = ide_blk_read;
|
||||
////blk->write = ahci_blk_write;
|
||||
|
||||
ent->dev = blk;
|
||||
ent->dev_class = DEV_CLASS_BLOCK;
|
||||
ent->dev_subclass = DEV_BLOCK_HDx;
|
||||
if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) {
|
||||
return -1;
|
||||
}
|
||||
//ent->dev = blk;
|
||||
//ent->dev_class = DEV_CLASS_BLOCK;
|
||||
//ent->dev_subclass = DEV_BLOCK_HDx;
|
||||
//if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) {
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
dev_entry_add(ent);
|
||||
//dev_entry_add(ent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+5
-2
@@ -50,6 +50,9 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
amd64_gdt_init();
|
||||
amd64_idt_init();
|
||||
amd64_mm_init(data);
|
||||
// XXX: HEAP IS ONLY AVAILABLE AT THIS POINT
|
||||
extern void pseudo_init();
|
||||
pseudo_init();
|
||||
amd64_acpi_init();
|
||||
#if defined(VESA_ENABLE)
|
||||
amd64_vesa_init(multiboot_info);
|
||||
@@ -64,8 +67,8 @@ void kernel_main(struct amd64_loader_data *data) {
|
||||
//tty_init();
|
||||
if (data->initrd_ptr) {
|
||||
// Create ram0 block device
|
||||
//ramblk_init(MM_VIRTUALIZE(data->initrd_ptr), data->initrd_len);
|
||||
//tarfs_init();
|
||||
ramblk_init(MM_VIRTUALIZE(data->initrd_ptr), data->initrd_len);
|
||||
tarfs_init();
|
||||
}
|
||||
|
||||
// Initial random seed
|
||||
|
||||
+46
-2
@@ -75,10 +75,54 @@ void init_func(void *arg) {
|
||||
// Mount rootfs if available
|
||||
//struct blkdev *root_blk = blk_by_name("ram0");
|
||||
struct vfs_ioctx ioctx = {0};
|
||||
struct ofile fd;
|
||||
struct stat st;
|
||||
int res;
|
||||
//ext2_class_init();
|
||||
|
||||
ext2_class_init();
|
||||
|
||||
struct fs_class *tarfs_class = fs_class_by_name("ustar");
|
||||
_assert(tarfs_class);
|
||||
|
||||
// Find _ramblk0
|
||||
struct vnode *ramblk0;
|
||||
if ((res = dev_find(DEV_CLASS_BLOCK, "ram0", &ramblk0)) != 0) {
|
||||
panic("Failed to find root device\n");
|
||||
}
|
||||
|
||||
kinfo("Found root device: %s\n", ramblk0->name);
|
||||
|
||||
// Create a filesystem instance at this device
|
||||
struct fs *fs_instance = fs_create(tarfs_class, ramblk0->dev);
|
||||
_assert(fs_instance);
|
||||
|
||||
// Get tarfs root node
|
||||
struct vnode *root_node = tarfs_class->get_root(fs_instance);
|
||||
_assert(root_node);
|
||||
|
||||
vnode_dump_tree(DEBUG_INFO, root_node, 0);
|
||||
|
||||
// Find some file in rootfs
|
||||
struct vnode *etc_file_txt;
|
||||
_assert(vnode_lookup_tree(root_node, "etc/file.txt", &etc_file_txt) == 0);
|
||||
_assert(etc_file_txt);
|
||||
|
||||
// Open it
|
||||
_assert(etc_file_txt->op);
|
||||
_assert(etc_file_txt->op->read);
|
||||
|
||||
struct ofile fd = {
|
||||
.vnode = etc_file_txt,
|
||||
.pos = 0,
|
||||
};
|
||||
|
||||
char buf[512];
|
||||
ssize_t bread;
|
||||
_assert((bread = etc_file_txt->op->read(&fd, buf, sizeof(buf))) > 0);
|
||||
|
||||
buf[bread] = 0;
|
||||
kdebug("\n%s\n", buf);
|
||||
|
||||
kinfo("Done\n");
|
||||
|
||||
//if (root_blk) {
|
||||
// if ((res = vfs_mount(&ioctx, "/", root_blk, "ustar", NULL)) != 0) {
|
||||
|
||||
@@ -28,217 +28,3 @@ ssize_t blk_write(struct blkdev *blk, const void *buf, size_t off, size_t lim) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
const char GUID_EMPTY[16] = {0};
|
||||
|
||||
// TODO: guess this would better be in blk_part.c or something like that
|
||||
struct mbr {
|
||||
char bootstrap[440];
|
||||
uint32_t uuid;
|
||||
uint16_t opt;
|
||||
struct mbr_entry {
|
||||
uint8_t attr;
|
||||
uint8_t chs_start[3];
|
||||
uint8_t type;
|
||||
uint8_t chs_end[3];
|
||||
uint32_t lba_start;
|
||||
uint32_t nsectors;
|
||||
} __attribute__((packed)) entries[4];
|
||||
uint16_t sign;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct gpt_header {
|
||||
char signature[8];
|
||||
uint32_t revision;
|
||||
uint32_t header_size;
|
||||
uint32_t header_crc32;
|
||||
uint32_t __res0;
|
||||
uint64_t my_lba;
|
||||
uint64_t alt_lba;
|
||||
uint64_t first_lba;
|
||||
uint64_t last_lba;
|
||||
char disk_guid[16];
|
||||
uint64_t partition_entry_lba;
|
||||
uint32_t partition_count;
|
||||
uint32_t partition_entry_size;
|
||||
uint32_t partition_array_crc32;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct gpt_part_entry {
|
||||
char type_guid[16];
|
||||
char part_guid[16];
|
||||
uint64_t start_lba;
|
||||
uint64_t end_lba;
|
||||
uint64_t attr;
|
||||
char part_name[72];
|
||||
};
|
||||
|
||||
struct blk_part {
|
||||
struct blkdev *device;
|
||||
uint64_t lba_start;
|
||||
uint64_t lba_size;
|
||||
};
|
||||
|
||||
int blk_mount_auto(struct vnode *at, struct blkdev *blk, const char *opt) {
|
||||
int res;
|
||||
|
||||
//if ((res = vfs_mount_internal(at, blk, "ext2", opt)) == 0) {
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t blk_part_write(struct blkdev *dev, const void *buf, size_t off, size_t count) {
|
||||
struct blk_part *part = (struct blk_part *) dev->dev_data;
|
||||
size_t part_size_bytes = part->lba_size * 512;
|
||||
size_t part_off_bytes = part->lba_start * 512;
|
||||
|
||||
if (off >= part_size_bytes) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t l = MIN(part_size_bytes - off, count);
|
||||
|
||||
return blk_write(part->device, buf, off + part_off_bytes, l);
|
||||
}
|
||||
|
||||
static ssize_t blk_part_read(struct blkdev *dev, void *buf, size_t off, size_t count) {
|
||||
struct blk_part *part = (struct blk_part *) dev->dev_data;
|
||||
size_t part_size_bytes = part->lba_size * 512;
|
||||
size_t part_off_bytes = part->lba_start * 512;
|
||||
|
||||
if (off >= part_size_bytes) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t l = MIN(part_size_bytes - off, count);
|
||||
|
||||
return blk_read(part->device, buf, off + part_off_bytes, l);
|
||||
}
|
||||
|
||||
static int blk_enumerate_mbr(struct blkdev *dev, uint8_t *head) {
|
||||
kdebug("Enumerating MBR partitions\n");
|
||||
struct mbr *mbr = (struct mbr *) head;
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
if (mbr->entries[i].chs_start[1] && mbr->entries[i].nsectors) {
|
||||
kdebug("Partition %u: Start %u, End %u, %u Sectors (%S), Type 0x%02x\n",
|
||||
i,
|
||||
mbr->entries[i].lba_start,
|
||||
mbr->entries[i].lba_start + mbr->entries[i].nsectors,
|
||||
mbr->entries[i].nsectors,
|
||||
mbr->entries[i].nsectors * 512,
|
||||
mbr->entries[i].type);
|
||||
|
||||
struct blk_part *part = (struct blk_part *) kmalloc(sizeof(struct blk_part));
|
||||
part->device = dev;
|
||||
part->lba_start = mbr->entries[i].lba_start;
|
||||
part->lba_size = mbr->entries[i].nsectors * 512;
|
||||
|
||||
void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry));
|
||||
_assert(ent);
|
||||
|
||||
blk->dev_data = part;
|
||||
blk->read = blk_part_read;
|
||||
blk->write = blk_part_write;
|
||||
blk->ent_parent = dev->ent;
|
||||
|
||||
ent->dev = blk;
|
||||
ent->dev_class = DEV_CLASS_BLOCK;
|
||||
ent->dev_subclass = DEV_BLOCK_PART;
|
||||
// XXX: This is ugly
|
||||
strcpy(ent->dev_name, dev->ent->dev_name);
|
||||
char digit[2] = { '1' + i, 0 };
|
||||
strcat(ent->dev_name, digit);
|
||||
|
||||
dev_entry_add(ent);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blk_enumerate_gpt(struct blkdev *dev, uint8_t *head) {
|
||||
// LBA1 - GPT header
|
||||
struct gpt_header *hdr = (struct gpt_header *) &head[512];
|
||||
// Read a single block for partition table entries
|
||||
char buf[512];
|
||||
|
||||
_assert(blk_read(dev, buf, hdr->partition_entry_lba * 512, 512) >= 0);
|
||||
|
||||
size_t offset = 0;
|
||||
size_t part_n = 0;
|
||||
for (size_t i = 0; i < hdr->partition_count; ++i) {
|
||||
struct gpt_part_entry *ent = (struct gpt_part_entry *) &buf[offset];
|
||||
|
||||
if (strncmp(ent->type_guid, GUID_EMPTY, 16)) {
|
||||
// Maybe some known filesystem here, ignore partition type guid
|
||||
|
||||
struct blk_part *part = (struct blk_part *) kmalloc(sizeof(struct blk_part));
|
||||
part->device = dev;
|
||||
part->lba_start = ent->start_lba;
|
||||
part->lba_size = ent->end_lba - ent->start_lba;
|
||||
|
||||
void *buf = kmalloc(sizeof(struct blkdev) + sizeof(struct dev_entry));
|
||||
struct dev_entry *ent = (struct dev_entry *) buf;
|
||||
struct blkdev *blk = (struct blkdev *) ((uintptr_t) buf + sizeof(struct dev_entry));
|
||||
_assert(ent);
|
||||
|
||||
blk->dev_data = part;
|
||||
blk->read = blk_part_read;
|
||||
blk->write = blk_part_write;
|
||||
blk->ent_parent = dev->ent;
|
||||
|
||||
ent->dev = blk;
|
||||
ent->dev_class = DEV_CLASS_BLOCK;
|
||||
ent->dev_subclass = DEV_BLOCK_PART;
|
||||
// XXX: This is ugly
|
||||
strcpy(ent->dev_name, dev->ent->dev_name);
|
||||
char digit[2] = { '1' + part_n++, 0 };
|
||||
strcat(ent->dev_name, digit);
|
||||
|
||||
dev_entry_add(ent);
|
||||
}
|
||||
|
||||
offset += hdr->partition_entry_size;
|
||||
if (offset >= 512) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//struct blkdev *blk_by_name(const char *name) {
|
||||
// struct dev_entry *it = dev_iter();
|
||||
//
|
||||
// for (; it; it = it->cdr) {
|
||||
// if (!strcmp(it->dev_name, name)) {
|
||||
// return (struct blkdev *) it->dev;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return NULL;
|
||||
//}
|
||||
|
||||
int blk_enumerate_partitions(struct blkdev *dev) {
|
||||
kdebug("Enumerating partitions of %s\n", dev->ent->dev_name);
|
||||
// TODO: handle stuff where block size is not 512
|
||||
uint8_t buf[1024];
|
||||
|
||||
_assert(blk_read(dev, buf, 0, 1024) >= 0);
|
||||
|
||||
if (!strncmp((const char *) (buf + 512), "EFI PART", 8)) {
|
||||
// Found GPT
|
||||
return blk_enumerate_gpt(dev, buf);
|
||||
} else if (buf[510] == 0x55 && buf[511] == 0xAA) {
|
||||
// Found MBR
|
||||
return blk_enumerate_mbr(dev, buf);
|
||||
}
|
||||
|
||||
// No partition table - just a plain block device
|
||||
return 0;
|
||||
}
|
||||
|
||||
+12
-11
@@ -32,15 +32,16 @@ void ramblk_init(uintptr_t at, size_t len) {
|
||||
ram_priv.begin = at;
|
||||
ram_priv.lim = len;
|
||||
|
||||
struct dev_entry *ent = (struct dev_entry *) kmalloc(sizeof(struct dev_entry));
|
||||
_assert(ent);
|
||||
|
||||
ent->dev = ramblk0;
|
||||
ent->dev_class = DEV_CLASS_BLOCK;
|
||||
ent->dev_subclass = DEV_BLOCK_RAM;
|
||||
if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) {
|
||||
panic("Failed to allocate a name for ram device\n");
|
||||
}
|
||||
|
||||
dev_entry_add(ent);
|
||||
dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_RAM, &_ramblk0, "ram0");
|
||||
// struct dev_entry *ent = (struct dev_entry *) kmalloc(sizeof(struct dev_entry));
|
||||
// _assert(ent);
|
||||
//
|
||||
// ent->dev = ramblk0;
|
||||
// ent->dev_class = DEV_CLASS_BLOCK;
|
||||
// ent->dev_subclass = DEV_BLOCK_RAM;
|
||||
// if (dev_alloc_name(ent->dev_class, ent->dev_subclass, ent->dev_name) != 0) {
|
||||
// panic("Failed to allocate a name for ram device\n");
|
||||
// }
|
||||
//
|
||||
// dev_entry_add(ent);
|
||||
}
|
||||
|
||||
@@ -10,63 +10,69 @@
|
||||
#include "sys/fs/fs.h"
|
||||
#include "sys/attr.h"
|
||||
#include "sys/heap.h"
|
||||
#include "sys/errno.h"
|
||||
|
||||
static struct vnode *devfs_root = NULL;
|
||||
|
||||
static uint64_t dev_scsi_bitmap = 0;
|
||||
static uint64_t dev_ide_bitmap = 0;
|
||||
static int dev_ram_count = 0;
|
||||
static uint64_t dev_count = 0;
|
||||
|
||||
static int dev_alloc_block_name(uint16_t subclass, char *name) {
|
||||
if (subclass == DEV_BLOCK_RAM) {
|
||||
strcpy(name, "ram");
|
||||
name[3] = dev_ram_count++ + '0';
|
||||
name[4] = 0;
|
||||
return 0;
|
||||
int dev_add(enum dev_class cls, int subcls, void *dev, const char *name) {
|
||||
char node_name[5];
|
||||
struct vnode *node;
|
||||
|
||||
if (!name) {
|
||||
// TODO: generate proper names for device nodes
|
||||
node_name[4] = 0;
|
||||
node_name[3] = '0' + ++dev_count;
|
||||
node_name[0] = 'd';
|
||||
node_name[1] = 'e';
|
||||
node_name[2] = 'v';
|
||||
name = node_name;
|
||||
}
|
||||
if (subclass == DEV_BLOCK_SDx || subclass == DEV_BLOCK_HDx) {
|
||||
uint64_t *bmp = subclass == DEV_BLOCK_SDx ? &dev_scsi_bitmap : &dev_ide_bitmap;
|
||||
name[1] = 'd';
|
||||
name[0] = subclass == DEV_BLOCK_SDx ? 's' : 'h';
|
||||
|
||||
for (size_t i = 0; i < 64; ++i) {
|
||||
if (!(*bmp & (1ULL << i))) {
|
||||
*bmp |= 1ULL << i;
|
||||
name[2] = 'a' + i;
|
||||
name[3] = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// Create a filesystem node for the device
|
||||
node = vnode_create(cls == DEV_CLASS_BLOCK ? VN_BLK : VN_CHR, name);
|
||||
node->dev = dev;
|
||||
|
||||
// Use inode number to store full device class:subclass
|
||||
node->ino = ((uint32_t) cls) | ((uint64_t) subcls << 32);
|
||||
|
||||
// If root does not yet exist, make one
|
||||
if (!devfs_root) {
|
||||
devfs_root = vnode_create(VN_DIR, NULL);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dev_alloc_name(enum dev_class cls, uint16_t subclass, char *name) {
|
||||
switch (cls) {
|
||||
case DEV_CLASS_BLOCK:
|
||||
return dev_alloc_block_name(subclass, name);
|
||||
default:
|
||||
panic("Not implemented\n");
|
||||
}
|
||||
}
|
||||
// TODO: some devices are located in subdirs
|
||||
vnode_attach(devfs_root, node);
|
||||
|
||||
static int dev_post_add(struct dev_entry *ent) {
|
||||
if (ent->dev_class == DEV_CLASS_BLOCK) {
|
||||
struct blkdev *blk = (struct blkdev *) ent->dev;
|
||||
kinfo("Created device node: %s\n", node->name);
|
||||
|
||||
blk->ent = ent;
|
||||
|
||||
if (ent->dev_subclass < DEV_BLOCK_PART) {
|
||||
if (blk_enumerate_partitions((struct blkdev *) ent->dev) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Self-test
|
||||
struct vnode *test_node = NULL;
|
||||
_assert(vnode_lookup_child(devfs_root, name, &test_node) == 0);
|
||||
_assert(test_node == node);
|
||||
_assert(vnode_lookup_tree(devfs_root, name, &test_node) == 0);
|
||||
_assert(test_node == node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dev_entry_add(struct dev_entry *ent) {
|
||||
// For example: enumerate partitions on block devices
|
||||
_assert(dev_post_add(ent) == 0);
|
||||
int dev_find(enum dev_class cls, const char *name, struct vnode **node) {
|
||||
_assert(node);
|
||||
int res;
|
||||
if (!devfs_root) {
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((res = vnode_lookup_tree(devfs_root, name, node)) != 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (cls == DEV_CLASS_BLOCK && (*node)->type != VN_BLK) {
|
||||
return -ENODEV;
|
||||
}
|
||||
if (cls == DEV_CLASS_CHAR && (*node)->type != VN_CHR) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+27
-23
@@ -12,8 +12,8 @@ enum vnode_type ext2_inode_type(struct ext2_inode *i) {
|
||||
return VN_DIR;
|
||||
case EXT2_TYPE_REG:
|
||||
return VN_REG;
|
||||
case EXT2_TYPE_LNK:
|
||||
return VN_LNK;
|
||||
//case EXT2_TYPE_LNK:
|
||||
// return VN_LNK;
|
||||
default:
|
||||
// fprintf(stderr, "Unknown file type: %x\n", v);
|
||||
// abort();
|
||||
@@ -22,9 +22,9 @@ enum vnode_type ext2_inode_type(struct ext2_inode *i) {
|
||||
}
|
||||
}
|
||||
|
||||
static int ext2_fs_mount(fs_t *fs, const char *opt) {
|
||||
static int ext2_fs_init(struct fs *fs, const char *opt) {
|
||||
int res;
|
||||
kdebug("ext2_fs_mount()\n");
|
||||
kdebug("ext2_fs_init()\n");
|
||||
struct ext2_extsb *sb;
|
||||
// ext2's private data is its superblock structure
|
||||
sb = (struct ext2_extsb *) kmalloc(EXT2_SBSIZ);
|
||||
@@ -84,7 +84,7 @@ static int ext2_fs_mount(fs_t *fs, const char *opt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext2_fs_umount(fs_t *fs) {
|
||||
static int ext2_fs_umount(struct fs *fs) {
|
||||
struct ext2_extsb *sb = (struct ext2_extsb *) fs->fs_private;
|
||||
// Free block group descriptor table
|
||||
kfree(sb->block_group_descriptor_table);
|
||||
@@ -93,29 +93,32 @@ static int ext2_fs_umount(fs_t *fs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vnode_t *ext2_fs_get_root(fs_t *fs) {
|
||||
struct ext2_extsb *sb = fs->fs_private;
|
||||
kdebug("ext2_fs_get_root()\n");
|
||||
static struct vnode *ext2_fs_get_root(struct fs *fs) {
|
||||
// TODO: make sure get_root is only called once per filesystem
|
||||
//struct ext2_extsb *sb = fs->fs_private;
|
||||
//kdebug("ext2_fs_get_root()\n");
|
||||
|
||||
struct ext2_inode *inode = (struct ext2_inode *) kmalloc(sb->inode_struct_size);
|
||||
// Read root inode (2)
|
||||
if (ext2_read_inode(fs, inode, EXT2_ROOTINO) != 0) {
|
||||
kfree(inode);
|
||||
return NULL;
|
||||
}
|
||||
//struct ext2_inode *inode = (struct ext2_inode *) kmalloc(sb->inode_struct_size);
|
||||
//// Read root inode (2)
|
||||
//if (ext2_read_inode(fs, inode, EXT2_ROOTINO) != 0) {
|
||||
// kfree(inode);
|
||||
// return NULL;
|
||||
//}
|
||||
|
||||
vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t));
|
||||
//vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t));
|
||||
|
||||
res->fs = fs;
|
||||
res->fs_data = inode;
|
||||
res->fs_number = EXT2_ROOTINO;
|
||||
res->op = &ext2_vnode_ops;
|
||||
res->type = ext2_inode_type(inode);
|
||||
//res->fs = fs;
|
||||
//res->fs_data = inode;
|
||||
//res->fs_number = EXT2_ROOTINO;
|
||||
//res->op = &ext2_vnode_ops;
|
||||
//res->type = ext2_inode_type(inode);
|
||||
|
||||
return res;
|
||||
//return res;
|
||||
panic("ext2 get root\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ext2_fs_statvfs(fs_t *fs, struct statvfs *st) {
|
||||
static int ext2_fs_statvfs(struct fs *fs, struct statvfs *st) {
|
||||
struct ext2_extsb *sb = fs->fs_private;
|
||||
|
||||
st->f_blocks = sb->sb.block_count;
|
||||
@@ -141,7 +144,8 @@ static int ext2_fs_statvfs(fs_t *fs, struct statvfs *st) {
|
||||
static struct fs_class ext2_class = {
|
||||
.name = "ext2",
|
||||
.get_root = ext2_fs_get_root,
|
||||
.mount = ext2_fs_mount,
|
||||
.init = ext2_fs_init,
|
||||
.mount = NULL,
|
||||
.umount = ext2_fs_umount,
|
||||
.statvfs = ext2_fs_statvfs
|
||||
};
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
#define ext2_super(e) ((struct ext2_extsb *) (e)->fs_private)
|
||||
|
||||
int ext2_write_superblock(fs_t *ext2) {
|
||||
int ext2_write_superblock(struct fs *ext2) {
|
||||
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
|
||||
return blk_write(ext2->blk, sb, EXT2_SBOFF, EXT2_SBSIZ);
|
||||
}
|
||||
|
||||
int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf) {
|
||||
int ext2_read_block(struct fs *ext2, uint32_t block_no, void *buf) {
|
||||
if (!block_no) {
|
||||
return -1;
|
||||
}
|
||||
@@ -26,7 +26,7 @@ int ext2_read_block(fs_t *ext2, uint32_t block_no, void *buf) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf) {
|
||||
int ext2_write_block(struct fs *ext2, uint32_t block_no, const void *buf) {
|
||||
if (!block_no) {
|
||||
return -1;
|
||||
}
|
||||
@@ -41,7 +41,7 @@ int ext2_write_block(fs_t *ext2, uint32_t block_no, const void *buf) {
|
||||
return res;
|
||||
}
|
||||
|
||||
int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, const void *buf) {
|
||||
int ext2_write_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, const void *buf) {
|
||||
if (index < 12) {
|
||||
uint32_t block_number = inode->direct_blocks[index];
|
||||
return ext2_write_block(ext2, block_number, buf);
|
||||
@@ -52,7 +52,7 @@ int ext2_write_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index,
|
||||
}
|
||||
}
|
||||
|
||||
int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index, void *buf) {
|
||||
int ext2_read_inode_block(struct fs *ext2, struct ext2_inode *inode, uint32_t index, void *buf) {
|
||||
if (index < 12) {
|
||||
// Use direct ptrs
|
||||
uint32_t block_number = inode->direct_blocks[index];
|
||||
@@ -76,7 +76,7 @@ int ext2_read_inode_block(fs_t *ext2, struct ext2_inode *inode, uint32_t index,
|
||||
}
|
||||
}
|
||||
|
||||
int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino) {
|
||||
int ext2_read_inode(struct fs *ext2, struct ext2_inode *inode, uint32_t ino) {
|
||||
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
|
||||
//printf("ext2_read_inode %d\n", ino);
|
||||
char inode_block_buffer[sb->block_size];
|
||||
@@ -104,7 +104,7 @@ int ext2_read_inode(fs_t *ext2, struct ext2_inode *inode, uint32_t ino) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_write_inode(fs_t *ext2, const struct ext2_inode *inode, uint32_t ino) {
|
||||
int ext2_write_inode(struct fs *ext2, const struct ext2_inode *inode, uint32_t ino) {
|
||||
struct ext2_extsb *sb = (struct ext2_extsb *) ext2->fs_private;
|
||||
//printf("ext2_read_inode %d\n", ino);
|
||||
char inode_block_buffer[sb->block_size];
|
||||
|
||||
+24
-5
@@ -1,5 +1,6 @@
|
||||
#include "sys/string.h"
|
||||
#include "sys/fs/fs.h"
|
||||
#include "sys/debug.h"
|
||||
#include "sys/errno.h"
|
||||
|
||||
// #include <stddef.h>
|
||||
@@ -9,16 +10,34 @@
|
||||
static struct fs_class *fses[10] = { NULL };
|
||||
static struct fs mounts[10];
|
||||
|
||||
struct fs *fs_create(struct fs_class *cls, struct blkdev *blk, struct vnode *at) {
|
||||
struct fs *fs_create(struct fs_class *cls, struct blkdev *blk) {
|
||||
struct fs *fs = NULL;
|
||||
// XXX: I hate heap allocations, but why not use one?
|
||||
for (size_t i = 0; i < 10; ++i) {
|
||||
if (mounts[i].cls == NULL) {
|
||||
mounts[i].cls = cls;
|
||||
mounts[i].blk= blk;
|
||||
mounts[i].mnt_at = at;
|
||||
return &mounts[i];
|
||||
mounts[i].blk = blk;
|
||||
fs = &mounts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
if (!fs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Try to initialize filesystem instance at device
|
||||
if (cls->init) {
|
||||
if (cls->init(fs, NULL) != 0) {
|
||||
fs->cls = NULL;
|
||||
kerror("%s init failed\n", cls->name);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
kwarn("%s provides no init function\n", cls->name);
|
||||
}
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
struct fs_class *fs_class_by_name(const char *name) {
|
||||
|
||||
+196
-2
@@ -1,20 +1,52 @@
|
||||
#include "sys/fs/node.h"
|
||||
#include "sys/fs/vfs.h"
|
||||
#include "sys/fs/fs.h"
|
||||
#include "sys/errno.h"
|
||||
|
||||
#include "sys/debug.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/heap.h"
|
||||
#include "sys/panic.h"
|
||||
#include "sys/string.h"
|
||||
#include "sys/heap.h"
|
||||
|
||||
struct vnode *vnode_create(const char *name) {
|
||||
static const char *path_element(const char *path, char *element) {
|
||||
const char *sep = strchr(path, '/');
|
||||
if (!sep) {
|
||||
strcpy(element, path);
|
||||
return NULL;
|
||||
} else {
|
||||
_assert(sep - path < NODE_MAXLEN);
|
||||
strncpy(element, path, sep - path);
|
||||
element[sep - path] = 0;
|
||||
|
||||
while (*sep == '/') {
|
||||
++sep;
|
||||
}
|
||||
if (!*sep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sep;
|
||||
}
|
||||
}
|
||||
|
||||
struct vnode *vnode_create(enum vnode_type t, const char *name) {
|
||||
struct vnode *node = (struct vnode *) kmalloc(sizeof(struct vnode));
|
||||
_assert(node);
|
||||
|
||||
node->type = t;
|
||||
node->flags = 0;
|
||||
|
||||
node->parent = NULL;
|
||||
node->first_child = NULL;
|
||||
node->next_child = NULL;
|
||||
|
||||
node->fs = NULL;
|
||||
node->fs_data = NULL;
|
||||
|
||||
node->op = NULL;
|
||||
node->dev = NULL;
|
||||
|
||||
if (name) {
|
||||
_assert(strlen(name) < NODE_MAXLEN);
|
||||
strcpy(node->name, name);
|
||||
@@ -24,3 +56,165 @@ struct vnode *vnode_create(const char *name) {
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void vnode_attach(struct vnode *parent, struct vnode *child) {
|
||||
_assert(parent);
|
||||
_assert(child);
|
||||
_assert(!child->parent);
|
||||
|
||||
child->parent = parent;
|
||||
child->next_child = parent->first_child;
|
||||
parent->first_child = child;
|
||||
}
|
||||
|
||||
void vnode_detach(struct vnode *node) {
|
||||
_assert(node);
|
||||
|
||||
struct vnode *parent = node->parent;
|
||||
node->parent = NULL;
|
||||
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node == parent->first_child) {
|
||||
parent->first_child = node->next_child;
|
||||
node->next_child = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (struct vnode *ch = parent->first_child; ch; ch = ch->next_child) {
|
||||
if (ch->next_child == node) {
|
||||
ch->next_child = node->next_child;
|
||||
node->next_child = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
panic("Parent has no link to its child node\n");
|
||||
}
|
||||
|
||||
// Only dumps cached nodes in filesystem tree
|
||||
void vnode_dump_tree(int level, struct vnode *node, int depth) {
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
debugs(level, " ");
|
||||
}
|
||||
switch (node->type) {
|
||||
case VN_DIR:
|
||||
debugs(level, "\033[33m");
|
||||
break;
|
||||
case VN_REG:
|
||||
debugs(level, "\033[1m");
|
||||
break;
|
||||
case VN_BLK:
|
||||
case VN_CHR:
|
||||
debugs(level, "\033[32m");
|
||||
break;
|
||||
default:
|
||||
debugs(level, "\033[41m");
|
||||
break;
|
||||
}
|
||||
|
||||
if (node->name[0]) {
|
||||
debugs(level, node->name);
|
||||
} else {
|
||||
debugs(level, "[root]");
|
||||
}
|
||||
debugs(level, "\033[0m");
|
||||
|
||||
if (node->first_child) {
|
||||
debugs(level, " {\n");
|
||||
|
||||
for (struct vnode *ch = node->first_child; ch; ch = ch->next_child) {
|
||||
vnode_dump_tree(level, ch, depth + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
debugs(level, " ");
|
||||
}
|
||||
debugs(level, "}\n");
|
||||
} else {
|
||||
debugc(level, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Only looks up in-memory nodes, does not perform any operations to fetch
|
||||
// the nodes from storage
|
||||
// NOTE: Resolution of .. and . is performed when resolving paths, as a node can
|
||||
// have multiple parents (roots of filesystems mounted at different locations)
|
||||
int vnode_lookup_child(struct vnode *of, const char *name, struct vnode **child) {
|
||||
_assert(of);
|
||||
_assert(child);
|
||||
_assert(name);
|
||||
_assert(strlen(name) < NODE_MAXLEN);
|
||||
|
||||
for (struct vnode *ch = of->first_child; ch; ch = ch->next_child) {
|
||||
if (!strcmp(ch->name, name)) {
|
||||
*child = ch;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int vnode_lookup_tree(struct vnode *at, const char *path, struct vnode **child) {
|
||||
char name[NODE_MAXLEN];
|
||||
const char *child_path;
|
||||
struct vnode *node;
|
||||
int err;
|
||||
|
||||
_assert(at);
|
||||
_assert(child);
|
||||
|
||||
if (!path || !*path) {
|
||||
*child = at;
|
||||
kdebug("empty hit-final %s\n", at->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The paths are always assumed to be relative
|
||||
while (*path == '/') {
|
||||
++path;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
child_path = path_element(path, name);
|
||||
|
||||
if (!strcmp(name, ".")) {
|
||||
// Refers to this node
|
||||
kdebug(". hit %s\n", at->name);
|
||||
continue;
|
||||
} else if (!strcmp(name, "..")) {
|
||||
// Refers to node's parent
|
||||
// And this won't work for filesystem mountpoints:
|
||||
// Path like a/mnt/.. would still resolve the same point as
|
||||
// a/mnt
|
||||
struct vnode *parent = at->parent;
|
||||
if (!parent) {
|
||||
parent = at;
|
||||
}
|
||||
kdebug(".. hit %s\n", parent->name);
|
||||
return vnode_lookup_tree(parent, child_path, child);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: lookup_or_load
|
||||
if ((err = vnode_lookup_child(at, name, &node)) != 0) {
|
||||
kdebug("miss %s\n", name);
|
||||
return err;
|
||||
}
|
||||
|
||||
_assert(node);
|
||||
|
||||
if (!child_path) {
|
||||
kdebug("hit-final %s\n", name);
|
||||
*child = node;
|
||||
return 0;
|
||||
} else {
|
||||
kdebug("hit %s\n", name);
|
||||
return vnode_lookup_tree(node, child_path, child);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-22
@@ -31,34 +31,16 @@ static struct blkdev _dev_null = {
|
||||
.write = pseudo_write,
|
||||
.read = pseudo_read
|
||||
};
|
||||
static struct dev_entry _ent_null = {
|
||||
.dev = &_dev_null,
|
||||
.dev_class = DEV_CLASS_BLOCK,
|
||||
.dev_subclass = DEV_BLOCK_PSEUDO,
|
||||
.dev_name = "null"
|
||||
};
|
||||
static struct blkdev _dev_zero = {
|
||||
.dev_data = (void *) DEV_ZERO,
|
||||
.write = pseudo_write,
|
||||
.read = pseudo_read
|
||||
};
|
||||
static struct dev_entry _ent_zero = {
|
||||
.dev = &_dev_zero,
|
||||
.dev_class = DEV_CLASS_BLOCK,
|
||||
.dev_subclass = DEV_BLOCK_PSEUDO,
|
||||
.dev_name = "zero"
|
||||
};
|
||||
static struct blkdev _dev_urandom = {
|
||||
.dev_data = (void *) DEV_URANDOM,
|
||||
.write = pseudo_write,
|
||||
.read = pseudo_read
|
||||
};
|
||||
static struct dev_entry _ent_urandom = {
|
||||
.dev = &_dev_urandom,
|
||||
.dev_class = DEV_CLASS_BLOCK,
|
||||
.dev_subclass = DEV_BLOCK_PSEUDO,
|
||||
.dev_name = "urandom"
|
||||
};
|
||||
|
||||
static ssize_t pseudo_write(struct blkdev *dev, const void *buf, size_t pos, size_t lim) {
|
||||
switch ((uint64_t) dev->dev_data) {
|
||||
@@ -87,8 +69,10 @@ static ssize_t pseudo_read(struct blkdev *dev, void *buf, size_t pos, size_t lim
|
||||
}
|
||||
}
|
||||
|
||||
static __init void pseudo_init(void) {
|
||||
dev_entry_add(&_ent_null);
|
||||
dev_entry_add(&_ent_zero);
|
||||
dev_entry_add(&_ent_urandom);
|
||||
// XXX: This is called before heap init, fucked up?
|
||||
void pseudo_init(void) {
|
||||
// FIXME: They're actually character devices
|
||||
dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_PSEUDO, &_dev_null, "null");
|
||||
dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_PSEUDO, &_dev_zero, "zero");
|
||||
dev_add(DEV_CLASS_BLOCK, DEV_BLOCK_PSEUDO, &_dev_urandom, "urandom");
|
||||
}
|
||||
|
||||
+84
-193
@@ -20,23 +20,15 @@ struct tar {
|
||||
};
|
||||
|
||||
struct tarfs_vnode_attr {
|
||||
uint32_t type_perm;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
size_t block;
|
||||
size_t first_block;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static int tarfs_vnode_access(vnode_t *vn, uid_t *uid, gid_t *gid, mode_t *mode);
|
||||
static int tarfs_vnode_stat(vnode_t *vn, struct stat *st);
|
||||
static int tarfs_vnode_open(vnode_t *vn, int opt);
|
||||
static ssize_t tarfs_vnode_read(struct ofile *fd, void *buf, size_t count);
|
||||
|
||||
static struct vnode_operations _tarfs_vnode_op = {
|
||||
.access = tarfs_vnode_access,
|
||||
.stat = tarfs_vnode_stat,
|
||||
.open = tarfs_vnode_open,
|
||||
.read = tarfs_vnode_read
|
||||
.read = tarfs_vnode_read,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t tarfs_octal(const char *buf, size_t lim) {
|
||||
@@ -52,66 +44,64 @@ static ssize_t tarfs_octal(const char *buf, size_t lim) {
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char *tarfs_path_element(char *dst, const char *src) {
|
||||
const char *sep = strchr(src, '/');
|
||||
static const char *path_element(const char *path, char *element) {
|
||||
const char *sep = strchr(path, '/');
|
||||
if (!sep) {
|
||||
strcpy(dst, src);
|
||||
strcpy(element, path);
|
||||
return NULL;
|
||||
} else {
|
||||
strncpy(dst, src, sep - src);
|
||||
dst[sep - src] = 0;
|
||||
_assert(sep - path < NODE_MAXLEN);
|
||||
strncpy(element, path, sep - path);
|
||||
element[sep - path] = 0;
|
||||
|
||||
while (*sep == '/') {
|
||||
++sep;
|
||||
}
|
||||
if (!*sep) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sep;
|
||||
}
|
||||
}
|
||||
|
||||
static int tarfs_node_add(struct vfs_node *at, struct vfs_node **res, const char *name) {
|
||||
// Try to find the node
|
||||
for (struct vfs_node *child = at->child; child; child = child->cdr) {
|
||||
if (!strcmp(child->name, name)) {
|
||||
*res = child;
|
||||
// Already exists
|
||||
return 0;
|
||||
}
|
||||
static int tarfs_mapper_create_node(struct vnode *at, struct vnode **res, const char *name, int dir) {
|
||||
_assert(at->type == VN_DIR); // Can only attach child to a directory
|
||||
|
||||
if (vnode_lookup_child(at, name, res) == 0) {
|
||||
// Already exists
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Else we need to insert it
|
||||
struct vfs_node *node_new = (struct vfs_node *) kmalloc(sizeof(struct vfs_node));
|
||||
strcpy(node_new->name, name);
|
||||
node_new->ismount = 0;
|
||||
node_new->parent = at;
|
||||
node_new->child = NULL;
|
||||
node_new->cdr = at->child;
|
||||
node_new->real_vnode = NULL;
|
||||
node_new->vnode = NULL;
|
||||
at->child = node_new;
|
||||
struct vnode *node_new = vnode_create(dir ? VN_DIR : VN_REG, name);
|
||||
node_new->flags |= VN_MEMORY;
|
||||
node_new->op = &_tarfs_vnode_op;
|
||||
|
||||
vnode_attach(at, node_new);
|
||||
*res = node_new;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tarfs_mapper_create_path(struct vfs_node *root, struct vfs_node **res, const char *path, int isdir) {
|
||||
char path_element[256];
|
||||
const char *remaining = path;
|
||||
struct vfs_node *node = root;
|
||||
struct vfs_node *new_node;
|
||||
static int tarfs_mapper_create_path(struct vnode *root, const char *path, struct vnode **res, int dir) {
|
||||
char name[NODE_MAXLEN];
|
||||
const char *child_path = path;
|
||||
struct vnode *node = root;
|
||||
struct vnode *new_node;
|
||||
int err;
|
||||
|
||||
kdebug("Add path %s\n", path);
|
||||
while (1) {
|
||||
remaining = tarfs_path_element(path_element, remaining);
|
||||
|
||||
if (tarfs_node_add(node, &new_node, path_element) < 0) {
|
||||
panic("Failed\n");
|
||||
while (1) {
|
||||
child_path = path_element(child_path, name);
|
||||
|
||||
if ((err = tarfs_mapper_create_node(node, &new_node, name, dir)) != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
node = new_node;
|
||||
|
||||
if (!remaining) {
|
||||
if (!child_path) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -121,74 +111,34 @@ static int tarfs_mapper_create_path(struct vfs_node *root, struct vfs_node **res
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vnode_t *tarfs_create_vnode(fs_t *fs, struct vfs_node *node, struct tar *hdr, size_t off) {
|
||||
if (hdr) {
|
||||
struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) kmalloc(sizeof(struct tarfs_vnode_attr));
|
||||
attr->block = off + 512;
|
||||
attr->gid = tarfs_octal(hdr->gid, 8);
|
||||
attr->uid = tarfs_octal(hdr->uid, 8);
|
||||
attr->type_perm = tarfs_octal(hdr->mode, 8);
|
||||
|
||||
if (!(hdr->typeflag[0] == '\0' || hdr->typeflag[0] == '0')) {
|
||||
attr->type_perm |= (1 << 16);
|
||||
attr->size = 0;
|
||||
} else {
|
||||
attr->size = tarfs_octal(hdr->size, 12);
|
||||
}
|
||||
|
||||
vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t));
|
||||
res->tree_node = node;
|
||||
res->fs = fs;
|
||||
res->fs_data = attr;
|
||||
res->refcount = 0;
|
||||
res->op = &_tarfs_vnode_op;
|
||||
res->type = (attr->type_perm & (1 << 16)) ? VN_DIR : VN_REG;
|
||||
|
||||
return res;
|
||||
} else {
|
||||
|
||||
vnode_t *res = (vnode_t *) kmalloc(sizeof(vnode_t));
|
||||
res->tree_node = node;
|
||||
res->fs = fs;
|
||||
res->fs_data = NULL;
|
||||
res->refcount = 0;
|
||||
res->op = &_tarfs_vnode_op;
|
||||
res->type = VN_DIR;
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
static int tarfs_node_mapper(fs_t *tar, struct vfs_node **root) {
|
||||
kdebug("tar: node mapper\n");
|
||||
char block_buffer[512];
|
||||
static int tar_init(struct fs *tar, const char *opt) {
|
||||
char block[512];
|
||||
size_t off = 0;
|
||||
int was0 = 0;
|
||||
int prev_zero = 0;
|
||||
ssize_t res;
|
||||
|
||||
struct vfs_node *_root = (struct vfs_node *) kmalloc(sizeof(struct vfs_node));
|
||||
_root->child = NULL;
|
||||
_root->cdr = NULL;
|
||||
_root->ismount = 0;
|
||||
_root->parent = NULL;
|
||||
_root->real_vnode = NULL;
|
||||
_root->vnode = NULL;
|
||||
struct vfs_node *curr_node;
|
||||
// Create filesystem root node
|
||||
struct vnode *tar_root = vnode_create(VN_DIR, NULL);
|
||||
tar->fs_private = tar_root;
|
||||
tar_root->fs = tar;
|
||||
|
||||
struct vnode *node;
|
||||
|
||||
while (1) {
|
||||
if (blk_read(tar->blk, block_buffer, off, 512) < 0) {
|
||||
return -EIO;
|
||||
if ((res = blk_read(tar->blk, block, off, 512)) < 0) {
|
||||
return res;
|
||||
}
|
||||
struct tar *hdr = (struct tar *) block_buffer;
|
||||
|
||||
if (hdr->filename[0] == 0) {
|
||||
if (was0) {
|
||||
// End of archive
|
||||
struct tar *hdr = (struct tar *) block;
|
||||
|
||||
if (!hdr->filename[0]) {
|
||||
if (prev_zero) {
|
||||
break;
|
||||
} else {
|
||||
was0 = 1;
|
||||
off += 512;
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_zero = 1;
|
||||
off += 512;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t node_size = 0;
|
||||
@@ -199,117 +149,58 @@ static int tarfs_node_mapper(fs_t *tar, struct vfs_node **root) {
|
||||
isdir = 0;
|
||||
}
|
||||
|
||||
kdebug("Node %c:%s:%S\n", isdir ? 'd' : '-', hdr->filename, node_size);
|
||||
if ((res = tarfs_mapper_create_path(tar_root, hdr->filename, &node, isdir)) < 0) {
|
||||
return res;
|
||||
}
|
||||
_assert(node);
|
||||
|
||||
tarfs_mapper_create_path(_root, &curr_node, hdr->filename, isdir);
|
||||
_assert(curr_node);
|
||||
vnode_t *vnode = tarfs_create_vnode(tar, curr_node, hdr, off);
|
||||
_assert(vnode);
|
||||
curr_node->vnode = vnode;
|
||||
// Initialize the vnode
|
||||
node->uid = 0;
|
||||
node->gid = 0;
|
||||
|
||||
struct tarfs_vnode_attr *attr = kmalloc(sizeof(struct tarfs_vnode_attr));
|
||||
_assert(attr);
|
||||
node->fs_data = attr;
|
||||
node->fs = tar;
|
||||
|
||||
attr->first_block = off + 512;
|
||||
attr->size = node_size;
|
||||
|
||||
off += 512 + ((node_size + 0x1FF) & ~0x1FF);
|
||||
}
|
||||
|
||||
// Make a vnode for root
|
||||
vnode_t *vnode = tarfs_create_vnode(tar, _root, NULL, 0);
|
||||
_root->vnode = vnode;
|
||||
|
||||
*root = _root;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vnode *tar_get_root(struct fs *tar) {
|
||||
return tar->fs_private;
|
||||
}
|
||||
|
||||
static struct fs_class _tarfs = {
|
||||
.name = "ustar",
|
||||
.opt = FS_NODE_MAPPER,
|
||||
.mapper = tarfs_node_mapper
|
||||
.opt = 0,
|
||||
.init = tar_init,
|
||||
.get_root = tar_get_root
|
||||
};
|
||||
|
||||
// Vnode operations
|
||||
|
||||
static int tarfs_vnode_access(vnode_t *vn, uid_t *uid, gid_t *gid, mode_t *mode) {
|
||||
_assert(vn && uid && gid && mode);
|
||||
|
||||
if (!vn->fs_data) {
|
||||
*uid = 0;
|
||||
*gid = 0;
|
||||
*mode = S_IFDIR | 0755;
|
||||
} else {
|
||||
struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) vn->fs_data;
|
||||
*uid = attr->uid;
|
||||
*gid = attr->gid;
|
||||
*mode = (attr->type_perm & 0x1FF) | ((attr->type_perm & (1 << 16)) ? S_IFDIR : S_IFREG);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tarfs_vnode_stat(vnode_t *vn, struct stat *st) {
|
||||
_assert(vn && st);
|
||||
if (!vn->fs_data) {
|
||||
// Root node
|
||||
st->st_atime = 0;
|
||||
st->st_ctime = 0;
|
||||
st->st_mtime = 0;
|
||||
st->st_dev = 0;
|
||||
st->st_rdev = 0;
|
||||
|
||||
st->st_gid = 0;
|
||||
st->st_uid = 0;
|
||||
st->st_mode = S_IFDIR | 0755;
|
||||
|
||||
st->st_ino = 0;
|
||||
st->st_nlink = 1;
|
||||
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = 0;
|
||||
st->st_size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) vn->fs_data;
|
||||
|
||||
st->st_atime = 0;
|
||||
st->st_mtime = 0;
|
||||
st->st_ctime = 0;
|
||||
st->st_dev = 0;
|
||||
st->st_rdev = 0;
|
||||
|
||||
st->st_gid = attr->gid;
|
||||
st->st_uid = attr->uid;
|
||||
st->st_mode = (attr->type_perm & 0x1FF) | ((attr->type_perm & (1 << 16)) ? S_IFDIR : S_IFREG);
|
||||
|
||||
st->st_ino = (attr->block / 512) - 1;
|
||||
st->st_nlink = 1;
|
||||
|
||||
st->st_blksize = 512;
|
||||
st->st_blocks = (attr->size + 511) & ~511;
|
||||
st->st_size = attr->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tarfs_vnode_open(vnode_t *vnode, int opt) {
|
||||
if ((opt & O_ACCMODE) != O_RDONLY) {
|
||||
return -EROFS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
static ssize_t tarfs_vnode_read(struct ofile *fd, void *buf, size_t count) {
|
||||
_assert(fd && buf && fd->vnode);
|
||||
vnode_t *vn = fd->vnode;
|
||||
_assert(fd);
|
||||
_assert(buf);
|
||||
_assert(fd->vnode);
|
||||
struct vnode *vn = fd->vnode;
|
||||
_assert(vn->fs_data);
|
||||
struct tarfs_vnode_attr *attr = (struct tarfs_vnode_attr *) vn->fs_data;
|
||||
_assert(vn->fs && vn->fs->blk);
|
||||
struct tarfs_vnode_attr *attr = vn->fs_data;
|
||||
|
||||
if (fd->pos >= attr->size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t can = MIN(attr->size - fd->pos, count);
|
||||
// TODO: do it properly with block buffer
|
||||
blk_read(vn->fs->blk, buf, fd->pos + attr->block, can);
|
||||
// TODO: size is not block-size aligned, may fuck up
|
||||
blk_read(vn->fs->blk, buf, fd->pos + attr->first_block, can);
|
||||
|
||||
return can;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user