#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct vfs_volume_table volume_table; static struct vfs_volume* vfs_find_volume (const char* volume) { struct hash_node_link* found_link = NULL; size_t volume_len = strlen_null (volume); uint32_t hash = hash_fnv32 (volume, volume_len); spin_lock (&volume_table.lock); hash_find (&volume_table, volume, volume_len, hash, lengthof (volume_table.volume_buckets), volume_buckets, struct vfs_volume, volume_table_link, key, found_link); spin_unlock (&volume_table.lock); if (found_link == NULL) return NULL; return hash_entry (found_link, struct vfs_volume, volume_table_link); } int vfs_create_volume (const char* key, int fs_type, struct device* back_device, bool format) { if (strlen_null (key) > VOLUME_MAX) return -ST_OOB_ERROR; struct vfs_volume* volume = malloc (sizeof (*volume)); if (volume == NULL) return -ST_OOM_ERROR; memset (volume, 0, sizeof (*volume)); memcpy (volume->key, key, strlen_null (key)); volume->fs_type = fs_type; volume->back_device = back_device; volume->lock = SPIN_LOCK_INIT; switch (volume->fs_type) { case VFS_TARFS: volume->driver_ops.mount = &tarfs_mount; volume->driver_ops.format = &tarfs_format; volume->driver_ops.describe = &tarfs_describe; volume->driver_ops.read_file = &tarfs_read_file; volume->driver_ops.write_file = &tarfs_write_file; volume->driver_ops.read_dir_entry = &tarfs_read_dir_entry; volume->driver_ops.create_file = &tarfs_create_file; break; case VFS_FAT16: volume->driver_ops.mount = &fatfs_mount; volume->driver_ops.format = &fatfs16_format; volume->driver_ops.describe = &fatfs_describe; volume->driver_ops.read_file = &fatfs_read_file; volume->driver_ops.write_file = &fatfs_write_file; volume->driver_ops.read_dir_entry = &fatfs_read_dir_entry; volume->driver_ops.create_file = &fatfs_create_file; break; case VFS_FAT32: volume->driver_ops.mount = &fatfs_mount; volume->driver_ops.format = &fatfs32_format; volume->driver_ops.describe = &fatfs_describe; volume->driver_ops.read_file = &fatfs_read_file; volume->driver_ops.write_file = &fatfs_write_file; volume->driver_ops.read_dir_entry = &fatfs_read_dir_entry; volume->driver_ops.create_file = &fatfs_create_file; break; default: free (volume); return -ST_MOUNT_ERROR; } int ret = volume->driver_ops.mount (volume, format); if (ret < 0) { free (volume); return ret; } uint32_t mp_hash = hash_fnv32 (volume->key, strlen_null (volume->key)); spin_lock (&volume_table.lock); hash_insert (&volume_table, &volume->volume_table_link, mp_hash, lengthof (volume_table.volume_buckets), volume_buckets); spin_unlock (&volume_table.lock); return ST_OK; } int vfs_volume_open (struct proc* proc, const char* volume_name, struct reschedule_ctx* rctx) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (!volume->locked) { volume->locked = true; volume->owner = proc; spin_unlock (&volume->lock); return ST_OK; } else { if (proc == VFS_KERNEL) { spin_unlock (&volume->lock); return -ST_TRY_AGAIN; } else { proc_sq_suspend (proc, &volume->sq, &volume->lock, rctx); return ST_OK; } } } int vfs_volume_close (struct proc* proc, const char* volume_name, struct reschedule_ctx* rctx) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_lock (&volume->sq.lock); struct list_node_link* node = volume->sq.proc_list; if (node) { struct proc_sq_entry* sq_entry = list_entry (node, struct proc_sq_entry, sq_link); struct proc* resumed_proc = sq_entry->proc; volume->owner = resumed_proc; volume->locked = true; spin_unlock (&volume->sq.lock); spin_unlock (&volume->lock); proc_sq_resume (resumed_proc, sq_entry, rctx); return ST_OK; } volume->locked = false; volume->owner = NULL; spin_unlock (&volume->sq.lock); spin_unlock (&volume->lock); return ST_OK; } int vfs_format (struct proc* proc, const char* volume_name) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_unlock (&volume->lock); return volume->driver_ops.format (volume); } int vfs_read_file (struct proc* proc, const char* volume_name, const char* path, uint8_t* buffer, size_t off, size_t size) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_unlock (&volume->lock); return volume->driver_ops.read_file (volume, path, buffer, off, size); } int vfs_write_file (struct proc* proc, const char* volume_name, const char* path, uint8_t* buffer, size_t off, size_t size) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_unlock (&volume->lock); return volume->driver_ops.write_file (volume, path, buffer, off, size); } int vfs_create_file (struct proc* proc, const char* volume_name, const char* path) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_unlock (&volume->lock); return volume->driver_ops.create_file (volume, path); } int vfs_describe (struct proc* proc, const char* volume_name, const char* path, struct desc* desc) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_unlock (&volume->lock); return volume->driver_ops.describe (volume, path, desc); } int vfs_read_dir_entry (struct proc* proc, const char* volume_name, const char* path, struct dir_entry* entry, size_t entry_num) { struct vfs_volume* volume = vfs_find_volume (volume_name); if (volume == NULL) return -ST_NOT_FOUND; spin_lock (&volume->lock); if (volume->locked && volume->owner != proc) { spin_unlock (&volume->lock); return -ST_PERMISSION_ERROR; } spin_unlock (&volume->lock); return volume->driver_ops.read_dir_entry (volume, path, entry, entry_num); } void vfs_init (void) { memset (&volume_table, 0, sizeof (volume_table)); volume_table.lock = SPIN_LOCK_INIT; } void vfs_translate (size_t fs_block, size_t fs_block_count, size_t fs_block_size, size_t device_sector_size, size_t* out_phys_sector, size_t* out_sector_count) { size_t ratio = fs_block_size / device_sector_size; if (out_phys_sector != NULL) *out_phys_sector = fs_block * ratio; if (out_sector_count != NULL) *out_sector_count = fs_block_count * ratio; }