From 577abf3bba2effcc6da24c42e8ca803eb3945e05 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Fri, 2 Jun 2023 19:34:33 +0100 Subject: [PATCH] obj: implement link objects --- include/socks/object.h | 13 +++- obj/link.c | 62 +++++++++++++++++++ obj/namespace.c | 132 ++++++++++++++++++++++++++++++++++++++--- obj/object.c | 15 ++++- 4 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 obj/link.c diff --git a/include/socks/object.h b/include/socks/object.h index 66b9384..f647e48 100644 --- a/include/socks/object.h +++ b/include/socks/object.h @@ -13,6 +13,7 @@ extern "C" { #define OBJECT_MAGIC 0xBADDCAFE #define OBJECT_NAME_MAX 64 +#define OBJECT_PATH_MAX 256 #define OBJECT_CAST(to_type, to_type_member, p) \ ((to_type *)((uintptr_t)p) - offsetof(to_type, to_type_member)) @@ -76,14 +77,17 @@ extern struct object_namespace *global_namespace(void); extern struct object_namespace *object_namespace_create(void); extern struct object *ns_header(struct object_namespace *ns); extern kern_status_t object_namespace_get_object(struct object_namespace *ns, const char *path, struct object **out); +extern kern_status_t object_namespace_create_link(struct object_namespace *ns, const char *linkpath, struct object *dest); extern kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj); extern kern_status_t object_unpublish(struct object_namespace *ns, struct object *obj); extern struct object *object_create(struct object_type *type); extern struct object *object_ref(struct object *obj); extern void object_deref(struct object *obj); -extern void object_lock(struct object *obj, unsigned long *flags); -extern void object_unlock(struct object *obj, unsigned long flags); +extern void object_lock(struct object *obj); +extern void object_unlock(struct object *obj); +extern void object_lock_irqsave(struct object *obj, unsigned long *flags); +extern void object_unlock_irqrestore(struct object *obj, unsigned long flags); static inline kern_status_t object_get(const char *path, struct object **out) { return object_namespace_get_object(global_namespace(), path, out); @@ -99,7 +103,12 @@ extern kern_status_t set_add_object(struct object *set, struct object *obj); extern kern_status_t set_remove_object(struct object *set, struct object *obj); extern bool object_is_set(struct object *obj); +extern struct object *link_create(const char *name, struct object *dest); +extern struct object *link_read_ptr(struct object *link); +extern bool object_is_link(struct object *obj); + extern void init_set_objects(void); +extern void init_link_objects(void); extern void init_global_namespace(void); #ifdef __cplusplus diff --git a/obj/link.c b/obj/link.c new file mode 100644 index 0000000..4f08381 --- /dev/null +++ b/obj/link.c @@ -0,0 +1,62 @@ +#include + +#define LINK_CAST(p) OBJECT_C_CAST(struct link, l_base, &link_type, p) + +struct link { + struct object l_base; + char l_name[OBJECT_NAME_MAX]; + struct object *l_dest; +}; + +static struct object_type link_type; + +static kern_status_t link_query_name(struct object *obj, char out[OBJECT_NAME_MAX]) +{ + struct link *link = LINK_CAST(obj); + strncpy(out, link->l_name, OBJECT_NAME_MAX - 1); + out[OBJECT_NAME_MAX - 1] = 0; + + return KERN_OK; +} + +static struct object_type link_type = { + .ob_name = "link", + .ob_size = sizeof(struct link), + .ob_header_offset = offsetof(struct link, l_base), + .ob_ops = { + .query_name = link_query_name, + }, +}; + +void init_link_objects(void) +{ + object_type_register(&link_type); +} + +struct object *link_create(const char *name, struct object *dest) +{ + struct object *link_obj = object_create(&link_type); + if (!link_obj) { + return NULL; + } + + struct link *link = LINK_CAST(link_obj); + + strncpy(link->l_name, name, sizeof link->l_name - 1); + link->l_name[sizeof link->l_name - 1] = 0; + + link->l_dest = object_ref(dest); + + return link_obj; +} + +struct object *link_read_ptr(struct object *link_obj) +{ + struct link *link = LINK_CAST(link_obj); + return link->l_dest; +} + +bool object_is_link(struct object *obj) +{ + return obj->ob_type == &link_type; +} diff --git a/obj/namespace.c b/obj/namespace.c index ce86730..d6df0c2 100644 --- a/obj/namespace.c +++ b/obj/namespace.c @@ -128,27 +128,143 @@ kern_status_t object_namespace_get_object(struct object_namespace *ns, const cha unsigned long flags; while (tok) { - object_lock(cur, &flags); + object_lock_irqsave(cur, &flags); struct object *next; kern_status_t status = object_get_child_named(cur, tok, &next); if (status != KERN_OK) { - object_unlock(cur, flags); + object_unlock_irqrestore(cur, flags); kfree(rpath); return status; } - object_unlock(cur, flags); + object_unlock_irqrestore(cur, flags); cur = next; tok = strtok_r(NULL, "/", &sp); + + object_lock_irqsave(cur, &flags); + if (!object_is_link(cur)) { + object_unlock_irqrestore(cur, flags); + continue; + } + + struct object *dest_obj; + dest_obj = link_read_ptr(cur); + object_unlock_irqrestore(cur, flags); + + if (!dest_obj) { + kfree(rpath); + /* TODO better error code for broken links */ + return KERN_INVALID_ARGUMENT; + } + + object_deref(cur); + cur = dest_obj; } kfree(rpath); - *out = object_ref(cur); + if (object_is_link(cur)) { + struct object *link_dest = link_read_ptr(cur); + object_deref(cur); + cur = object_ref(link_dest); + } + + *out = cur; return KERN_OK; } +kern_status_t object_namespace_create_link(struct object_namespace *ns, const char *linkpath, struct object *dest) +{ + if (*linkpath != '/') { + return KERN_INVALID_ARGUMENT; + } + + while (*linkpath == '/') { + linkpath++; + } + + size_t path_len = strlen(linkpath); + if (path_len == 0) { + return KERN_INVALID_ARGUMENT; + } + + size_t parts = 0; + char *rpath = kmalloc(path_len, 0); + if (!rpath) { + return KERN_NO_MEMORY; + } + + memcpy(rpath, linkpath, path_len); + cleanup_object_path(rpath, path_len, &parts); + + char *p = rpath + strlen(rpath) - 1; + while (*p != '/' && p >= rpath) { + p--; + } + + if (p == rpath) { + kfree(rpath); + return KERN_INVALID_ARGUMENT; + } + + *p = '\0'; + const char *linkname = p + 1; + + char *sp; + char *tok = strtok_r(rpath, "/", &sp); + struct object *cur = object_ref(ns->ns_root); + + unsigned long flags; + while (tok) { + object_lock_irqsave(cur, &flags); + + struct object *next; + kern_status_t status = object_get_child_named(cur, tok, &next); + if (status == KERN_NO_ENTRY) { + next = set_create(tok); + if (!next) { + object_unlock_irqrestore(cur, flags); + object_deref(cur); + kfree(rpath); + return KERN_NO_MEMORY; + } + + status = set_add_object(cur, next); + + object_unlock_irqrestore(cur, flags); + object_deref(cur); + } else { + object_unlock_irqrestore(cur, flags); + } + + if (status != KERN_OK) { + kfree(rpath); + return status; + } + + cur = next; + tok = strtok_r(NULL, "/", &sp); + } + + struct object *link = link_create(linkname, dest); + kfree(rpath); + + if (!link) { + object_deref(cur); + return KERN_NO_MEMORY; + } + + object_lock_irqsave(cur, &flags); + kern_status_t status = set_add_object(cur, link); + object_unlock_irqrestore(cur, flags); + + object_deref(cur); + object_deref(link); + + return status; +} + kern_status_t object_publish(struct object_namespace *ns, const char *path, struct object *obj) { if (*path != '/') { @@ -179,14 +295,14 @@ kern_status_t object_publish(struct object_namespace *ns, const char *path, stru unsigned long flags; while (tok) { - object_lock(cur, &flags); + object_lock_irqsave(cur, &flags); struct object *next; kern_status_t status = object_get_child_named(cur, tok, &next); if (status == KERN_NO_ENTRY) { next = set_create(tok); if (!next) { - object_unlock(cur, flags); + object_unlock_irqrestore(cur, flags); kfree(rpath); return KERN_NO_MEMORY; } @@ -195,12 +311,12 @@ kern_status_t object_publish(struct object_namespace *ns, const char *path, stru } if (status != KERN_OK) { - object_unlock(cur, flags); + object_unlock_irqrestore(cur, flags); kfree(rpath); return status; } - object_unlock(cur, flags); + object_unlock_irqrestore(cur, flags); cur = next; tok = strtok_r(NULL, "/", &sp); } diff --git a/obj/object.c b/obj/object.c index d8be0ab..efe58fb 100644 --- a/obj/object.c +++ b/obj/object.c @@ -10,6 +10,7 @@ static spin_lock_t object_types_lock = SPIN_LOCK_INIT; kern_status_t object_bootstrap(void) { init_set_objects(); + init_link_objects(); init_global_namespace(); return KERN_OK; } @@ -96,12 +97,22 @@ void object_deref(struct object *obj) vm_cache_free(&obj->ob_type->ob_cache, obj); } -void object_lock(struct object *obj, unsigned long *flags) +void object_lock(struct object *obj) +{ + spin_lock(&obj->ob_lock); +} + +void object_unlock(struct object *obj) +{ + spin_unlock(&obj->ob_lock); +} + +void object_lock_irqsave(struct object *obj, unsigned long *flags) { spin_lock_irqsave(&obj->ob_lock, flags); } -void object_unlock(struct object *obj, unsigned long flags) +void object_unlock_irqrestore(struct object *obj, unsigned long flags) { spin_unlock_irqrestore(&obj->ob_lock, flags); }