#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 (volume); uint32_t hash = hash_fnv32 (volume, strlen (volume)); 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, struct proc* proc, struct reschedule_ctx* rctx) { 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.describe = &tarfs_describe; volume->driver_ops.read = &tarfs_read; } break; default: { free (volume); return -ST_MOUNT_ERROR; } break; } int ret = volume->driver_ops.mount (volume, proc, rctx); if (ret < 0) { free (volume); return ret; } uint32_t mp_hash = hash_fnv32 (volume->key, strlen (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 = 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_read (struct proc* proc, const char* volume_name, const char* path, uint8_t* buffer, size_t off, size_t size, 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_unlock (&volume->lock); return volume->driver_ops.read (volume, path, buffer, off, size); } int vfs_describe (struct proc* proc, const char* volume_name, const char* path, struct desc* desc, 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_unlock (&volume->lock); return volume->driver_ops.describe (volume, path, desc); } void vfs_init (void) { memset (&volume_table, 0, sizeof (volume_table)); volume_table.lock = SPIN_LOCK_INIT; }