diff --git a/executer/kernel/mcctrl/Makefile.in b/executer/kernel/mcctrl/Makefile.in index 8d14448e..02d94d54 100644 --- a/executer/kernel/mcctrl/Makefile.in +++ b/executer/kernel/mcctrl/Makefile.in @@ -9,7 +9,7 @@ obj-m += mcctrl.o ccflags-y := -I$(IHK_BASE)/linux/include -I$(IHK_BASE)/ikc/include -I$(IHK_BASE)/include -I$(src)/../../include -mcmodel=kernel -mno-red-zone -DMCEXEC_PATH=\"$(BINDIR)/mcexec\" -mcctrl-y := driver.o control.o ikc.o syscall.o procfs.o binfmt_mcexec.o +mcctrl-y := driver.o control.o ikc.o syscall.o procfs.o binfmt_mcexec.o sysfs.o KBUILD_EXTRA_SYMBOLS = @abs_builddir@/../../../../ihk/linux/core/Module.symvers diff --git a/executer/kernel/mcctrl/driver.c b/executer/kernel/mcctrl/driver.c index 5d088487..de8c84b2 100644 --- a/executer/kernel/mcctrl/driver.c +++ b/executer/kernel/mcctrl/driver.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "mcctrl.h" #define OS_MAX_MINOR 64 @@ -137,6 +138,7 @@ static void __exit mcctrl_exit(void) printk("mcctrl: unregistered.\n"); for(i = 0; i < OS_MAX_MINOR; i++){ if(os[i]){ + sysfsm_cleanup(os[i]); ihk_os_unregister_user_call_handlers(os[i], mcctrl_uc + i); destroy_ikc_channels(os[i]); procfs_exit(i); diff --git a/executer/kernel/mcctrl/ikc.c b/executer/kernel/mcctrl/ikc.c index 92aee2fd..719cd57d 100644 --- a/executer/kernel/mcctrl/ikc.c +++ b/executer/kernel/mcctrl/ikc.c @@ -84,6 +84,26 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, case SCD_MSG_SEND_SIGNAL: sig_done(pisp->arg, pisp->err); break; + + case SCD_MSG_SYSFS_REQ_CREATE: + case SCD_MSG_SYSFS_REQ_MKDIR: + case SCD_MSG_SYSFS_REQ_SYMLINK: + case SCD_MSG_SYSFS_REQ_LOOKUP: + case SCD_MSG_SYSFS_REQ_UNLINK: + case SCD_MSG_SYSFS_REQ_SETUP: + case SCD_MSG_SYSFS_RESP_SHOW: + case SCD_MSG_SYSFS_RESP_STORE: + case SCD_MSG_SYSFS_RESP_RELEASE: + sysfsm_packet_handler(__os, pisp->msg, pisp->err, + pisp->sysfs_arg1, pisp->sysfs_arg2); + break; + + default: + printk(KERN_ERR "mcctrl:syscall_packet_handler:" + "unknown message (%d.%d.%d.%d.%d.%#lx)\n", + pisp->msg, pisp->ref, pisp->osnum, pisp->pid, + pisp->err, pisp->arg); + break; } return 0; } diff --git a/executer/kernel/mcctrl/mcctrl.h b/executer/kernel/mcctrl/mcctrl.h index 35e52a1b..8a4f4c6b 100644 --- a/executer/kernel/mcctrl/mcctrl.h +++ b/executer/kernel/mcctrl/mcctrl.h @@ -33,10 +33,12 @@ #define HEADER_MCCTRL_H #include +#include #include #include #include #include +#include #define SCD_MSG_PREPARE_PROCESS 0x1 #define SCD_MSG_PREPARE_PROCESS_ACKED 0x2 @@ -57,6 +59,27 @@ #define SCD_MSG_DEBUG_LOG 0x20 +#define SCD_MSG_SYSFS_REQ_CREATE 0x30 +/* #define SCD_MSG_SYSFS_RESP_CREATE 0x31 */ +#define SCD_MSG_SYSFS_REQ_MKDIR 0x32 +/* #define SCD_MSG_SYSFS_RESP_MKDIR 0x33 */ +#define SCD_MSG_SYSFS_REQ_SYMLINK 0x34 +/* #define SCD_MSG_SYSFS_RESP_SYMLINK 0x35 */ +#define SCD_MSG_SYSFS_REQ_LOOKUP 0x36 +/* #define SCD_MSG_SYSFS_RESP_LOOKUP 0x37 */ +#define SCD_MSG_SYSFS_REQ_UNLINK 0x38 +/* #define SCD_MSG_SYSFS_RESP_UNLINK 0x39 */ +#define SCD_MSG_SYSFS_REQ_SHOW 0x3a +#define SCD_MSG_SYSFS_RESP_SHOW 0x3b +#define SCD_MSG_SYSFS_REQ_STORE 0x3c +#define SCD_MSG_SYSFS_RESP_STORE 0x3d +#define SCD_MSG_SYSFS_REQ_RELEASE 0x3e +#define SCD_MSG_SYSFS_RESP_RELEASE 0x3f +#define SCD_MSG_SYSFS_REQ_SETUP 0x40 +#define SCD_MSG_SYSFS_RESP_SETUP 0x41 +/* #define SCD_MSG_SYSFS_REQ_CLEANUP 0x42 */ +/* #define SCD_MSG_SYSFS_RESP_CLEANUP 0x43 */ + #define DMA_PIN_SHIFT 21 #define DO_USER_MODE @@ -70,11 +93,24 @@ struct coretable { struct ikc_scd_packet { int msg; - int ref; - int osnum; - int pid; int err; - unsigned long arg; + union { + /* for traditional SCD_MSG_* */ + struct { + int ref; + int osnum; + int pid; + int padding; + unsigned long arg; + }; + + /* for SCD_MSG_SYSFS_* */ + struct { + long sysfs_arg1; + long sysfs_arg2; + long sysfs_arg3; + }; + }; }; struct mcctrl_priv { @@ -128,6 +164,31 @@ struct mcctrl_per_proc_data { unsigned long rpgtable; /* per process, not per OS */ }; +struct sysfsm_req { + int busy; + int padding; + long lresult; + wait_queue_head_t wq; +}; + +struct sysfsm_data { + size_t sysfs_bufsize; + void *sysfs_buf; + long sysfs_buf_rpa; + long sysfs_buf_pa; + struct kobject *sysfs_kobj; + struct sysfsm_node *sysfs_root; + struct semaphore sysfs_tree_sem; + struct semaphore sysfs_io_sem; + struct sysfsm_req sysfs_req; + ihk_os_t sysfs_os; +}; + +static inline int sysfs_inited(struct sysfsm_data *sdp) +{ + return !!(sdp->sysfs_buf); +} /* sysfs_inited() */ + struct mcctrl_usrdata { struct ihk_ikc_listen_param listen_param; struct ihk_ikc_listen_param listen_param2; @@ -146,6 +207,7 @@ struct mcctrl_usrdata { struct list_head per_proc_list; ihk_spinlock_t per_proc_list_lock; void **keys; + struct sysfsm_data sysfsm_data; }; struct mcctrl_signal { @@ -188,4 +250,8 @@ struct procfs_file { char fname[PROCFS_NAME_MAX]; /* procfs filename (request) */ }; +/* sysfs.c */ +void sysfsm_cleanup(ihk_os_t os); +void sysfsm_packet_handler(void *os, int msg, int err, long arg1, long arg2); + #endif diff --git a/executer/kernel/mcctrl/sysfs.c b/executer/kernel/mcctrl/sysfs.c new file mode 100644 index 00000000..8df2535b --- /dev/null +++ b/executer/kernel/mcctrl/sysfs.c @@ -0,0 +1,1634 @@ +/** + * \file sysfs.c + * License details are found in the file LICENSE. + * \brief + * sysfs framework, IHK-Master side + * \author Gou Nakamura \par + * Copyright (C) 2015 RIKEN AICS + */ +/* + * HISTORY: + */ + +#include +#include +#include +#include "mcctrl.h" +#include "sysfs_msg.h" + +#define dprintk(...) do { if (0) printk(KERN_DEBUG __VA_ARGS__); } while (0) +#define wprintk(...) do { if (1) printk(KERN_WARNING __VA_ARGS__); } while (0) +#define eprintk(...) do { if (1) printk(KERN_ERR __VA_ARGS__); } while (0) + +enum { + /* sysfsm_node.type */ + SNT_FILE = 1, + SNT_DIR = 2, + SNT_LINK = 3, +}; + +struct sysfsm_node { + int8_t type; + int8_t padding[7]; + char *name; + struct sysfsm_node *parent; + struct sysfsm_data *sdp; + struct list_head chain; + union { + /* SNT_DIR */ + struct { + struct kobject kobj; + struct list_head children; + }; + + /* SNT_FILE */ + struct { + struct attribute attr; + long client_ops; + long client_instance; + }; + }; +}; /* struct sysfsm_node */ + +struct sysfs_work { + void *os; + int msg; + int err; + long arg1; + long arg2; + struct work_struct work; +}; /* struct sysfs_work */ + +static struct sysfs_ops the_ops; +static struct kobj_type the_ktype; + +static ssize_t +sysfsm_show(struct kobject *kobj, struct attribute *attr, char *buf) +{ + int error; + struct semaphore *held_sem = NULL; + struct ikc_scd_packet packet; + struct sysfsm_node *np; + ssize_t ssize = -EIO; + struct sysfsm_data *sdp; + struct sysfsm_req *req; + + dprintk("mcctrl:sysfsm_show(%s,%s,%p)\n", kobj->name, attr->name, buf); + + np = container_of(attr, struct sysfsm_node, attr); + sdp = np->sdp; + req = &sdp->sysfs_req; + + if (!sysfs_inited(sdp)) { + /* emulate EOF */ + error = 0; + ssize = 0; + eprintk("mcctrl:sysfsm_show:not initialized. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_io_sem); + if (error) { + eprintk("mcctrl:sysfsm_show:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_io_sem; + + /* for the case that last wait_event_interruptible() was interrupted */ + error = wait_event_interruptible(req->wq, !req->busy); + if (error) { + eprintk("mcctrl:sysfsm_show:wait_event_interruptible0 failed. %d\n", + error); + error = -EINTR; + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_SHOW; + packet.sysfs_arg1 = (long)np; + packet.sysfs_arg2 = (long)np->client_ops; + packet.sysfs_arg3 = (long)np->client_instance; + + req->busy = 1; +#define SYSFS_MCK_CPU 0 + error = mcctrl_ikc_send(sdp->sysfs_os, SYSFS_MCK_CPU, &packet); + if (error) { + eprintk("mcctrl:sysfsm_show:mcctrl_ikc_send failed. %d\n", + error); + goto out; + } + + error = wait_event_interruptible(req->wq, !req->busy); + if (error) { + eprintk("mcctrl:sysfsm_show:wait_event_interruptible failed. %d\n", + error); + error = -EINTR; + goto out; + } + + ssize = req->lresult; + if (ssize < 0) { + error = ssize; + eprintk("mcctrl:sysfsm_show:SCD_MSG_SYSFS_REQ_SHOW failed. %d\n", + error); + goto out; + } + + if (ssize > 0) { + memcpy(buf, sdp->sysfs_buf, ssize); + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + if (error) { + eprintk("mcctrl:sysfsm_show(%s,%s,%p): %d\n", + kobj->name, attr->name, buf, error); + ssize = error; + } + dprintk("mcctrl:sysfsm_show(%s,%s,%p): %ld %d\n", + kobj->name, attr->name, buf, ssize, error); + return ssize; +} /* sysfsm_show() */ + +static ssize_t +sysfsm_store(struct kobject *kobj, struct attribute *attr, const char *buf, + size_t bufsize) +{ + int error; + struct semaphore *held_sem = NULL; + struct ikc_scd_packet packet; + struct sysfsm_node *np; + ssize_t ssize = -EIO; + struct sysfsm_data *sdp; + struct sysfsm_req *req; + + dprintk("mcctrl:sysfsm_store(%s,%s,%p,%ld)\n", + kobj->name, attr->name, buf, bufsize); + + np = container_of(attr, struct sysfsm_node, attr); + sdp = np->sdp; + req = &sdp->sysfs_req; + + if (!sysfs_inited(sdp)) { + /* emulate EOF */ + error = -ENOSPC; + eprintk("mcctrl:sysfsm_store:not initialized. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_io_sem); + if (error) { + eprintk("mcctrl:sysfsm_store:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_io_sem; + + /* for the case that last wait_event_interruptible() was interrupted */ + error = wait_event_interruptible(req->wq, !req->busy); + if (error) { + eprintk("mcctrl:sysfsm_store:wait_event_interruptible0 failed. %d\n", + error); + error = -EINTR; + goto out; + } + + if (bufsize > sdp->sysfs_bufsize) { + error = -ENOSPC; + eprintk("mcctrl:sysfsm_store:too large size %#lx. %d\n", + bufsize, error); + goto out; + } + + memcpy(sdp->sysfs_buf, buf, bufsize); + + packet.msg = SCD_MSG_SYSFS_REQ_STORE; + packet.sysfs_arg1 = (long)np; + packet.sysfs_arg2 = (long)np->client_ops; + packet.sysfs_arg3 = (long)np->client_instance; + packet.err = bufsize; + + req->busy = 1; +#define SYSFS_MCK_CPU 0 + error = mcctrl_ikc_send(sdp->sysfs_os, SYSFS_MCK_CPU, &packet); + if (error) { + eprintk("mcctrl:sysfsm_store:mcctrl_ikc_send failed. %d\n", + error); + goto out; + } + + error = wait_event_interruptible(req->wq, !req->busy); + if (error) { + eprintk("mcctrl:sysfsm_store:wait_event_interruptible failed. %d\n", + error); + error = -EINTR; + goto out; + } + + ssize = req->lresult; + if (ssize < 0) { + error = ssize; + eprintk("mcctrl:sysfsm_store:SCD_MSG_SYSFS_REQ_STORE failed. %d\n", + error); + goto out; + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + if (error) { + eprintk("mcctrl:sysfsm_store(%s,%s,%p,%ld): %d\n", + kobj->name, attr->name, buf, bufsize, error); + ssize = error; + } + dprintk("mcctrl:sysfsm_store(%s,%s,%p,%ld): %ld %d\n", + kobj->name, attr->name, buf, bufsize, ssize, error); + return ssize; +} /* sysfsm_store() */ + +static int +release_i(struct sysfsm_node *np) +{ + int error; + struct semaphore *held_sem = NULL; + struct sysfsm_data *sdp; + struct ikc_scd_packet packet; + struct sysfsm_req *req; + + BUG_ON(!np); + dprintk("mcctrl:release_i(%p %s)\n", np, np->name); + + sdp = np->sdp; + req = &sdp->sysfs_req; + + if ((np->type == SNT_FILE) + && (np->client_ops || np->client_instance) + && sysfs_inited(sdp)) { + error = down_interruptible(&sdp->sysfs_io_sem); + if (error) { + eprintk("mcctrl:release_i:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_io_sem; + + /* for the case that last wait_event_interruptible() was interrupted */ + error = wait_event_interruptible(req->wq, !req->busy); + if (error) { + eprintk("mcctrl:release_i:wait_event_interruptible0 failed. %d\n", + error); + error = -EINTR; + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_RELEASE; + packet.sysfs_arg1 = (long)np; + packet.sysfs_arg2 = np->client_ops; + packet.sysfs_arg3 = np->client_instance; + + req->busy = 1; +#define SYSFS_MCK_CPU 0 + error = mcctrl_ikc_send(sdp->sysfs_os, SYSFS_MCK_CPU, &packet); + if (error) { + eprintk("mcctrl:release_i:mcctrl_ikc_send failed. %d\n", + error); + goto out; + } + + error = wait_event_interruptible(req->wq, !req->busy); + if (error) { + eprintk("mcctrl:release_i:wait_event_interruptible failed. %d\n", + error); + error = -EINTR; + goto out; + } + } + + kfree(np->name); + kfree(np); + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + if (error) { + eprintk("mcctrl:release_i(%p %s): %d\n", np, np->name, error); + } + dprintk("mcctrl:release_i(%p): %d\n", np, error); + return error; +} /* release_i() */ + +static void +sysfsm_release(struct kobject *kobj) +{ + int error; + struct sysfsm_node *np = container_of(kobj, struct sysfsm_node, kobj); + + dprintk("mcctrl:sysfsm_release(%p %s)\n", kobj, kobj->name); + + error = release_i(np); + if (error) { + eprintk("mcctrl:sysfsm_release:release_i failed. %d\n", error); + goto out; + } + + error = 0; +out: + if (error) { + eprintk("mcctrl:sysfsm_release(%p %s): %d\n", + kobj, kobj->name, error); + } + dprintk("mcctrl:sysfsm_release(%p): %d\n", kobj, error); + return; +} /* sysfsm_release() */ + +static struct sysfsm_node * +lookup_i(struct sysfsm_node *dirp, const char *name) +{ + int error; + struct sysfsm_node *np; + + BUG_ON(!dirp); + BUG_ON(!name); + dprintk("mcctrl:lookup_i(%s,%s)\n", dirp->name, name); + + if (dirp->type != SNT_DIR) { + error = -ENOTDIR; + eprintk("mcctrl:lookup_i:not a directory. %d\n", error); + goto out; + } + + if (name[0] == '\0') { + error = -ENOENT; + eprintk("mcctrl:lookup_i:null component. %d\n", error); + goto out; + } + + list_for_each_entry(np, &dirp->children, chain) { + if (!strcmp(np->name, name)) { + /* found */ + error = 0; + goto out; + } + } + + /* this is usual when called from create_i(), mkdir_i() and symlink_i(). */ +#define ENOENT_NOMSG 1 + error = ENOENT_NOMSG; +out: + if (error) { + if (error < 0) { + eprintk("mcctrl:lookup_i(%s,%s): %d\n", + dirp->name, name, error); + } + else if (error == ENOENT_NOMSG) { + error = -ENOENT; + } + np = ERR_PTR(error); + } + dprintk("mcctrl:lookup_i(%s,%s): %p %d\n", + dirp->name, name, np, error); + return np; +} /* lookup_i() */ + +static struct sysfsm_node * +create_i(struct sysfsm_node *parent, const char *name, mode_t mode, + long client_ops, long client_instance) +{ + int error; + struct sysfsm_node *np = NULL; + struct sysfsm_data *sdp; + + BUG_ON(!parent); + BUG_ON(!name); + dprintk("mcctrl:create_i(%s,%s,%#o,%#lx,%#lx)\n", + parent->name, name, mode, client_ops, client_instance); + + sdp = parent->sdp; + + if (parent == sdp->sysfs_root) { + error = -EPERM; + eprintk("mcctrl:create_i:root dir. %d\n", error); + goto out; + } + + if (parent->type != SNT_DIR) { + error = -ENOTDIR; + eprintk("mcctrl:create_i:not a directory. %d\n", error); + goto out; + } + + if (name[0] == '\0') { + error = -EINVAL; + eprintk("mcctrl:create_i:null filename. %d\n", error); + goto out; + } + + np = lookup_i(parent, name); + if (!IS_ERR(np)) { + error = -EEXIST; + eprintk("mcctrl:create_i:already exist. %d\n", error); + np = NULL; + goto out; + } + + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) { + error = -ENOMEM; + eprintk("mcctrl:create_i:kzalloc failed. %d\n", error); + goto out; + } + + np->type = SNT_FILE; + np->name = kstrdup(name, GFP_KERNEL); + np->parent = parent; + np->sdp = sdp; + INIT_LIST_HEAD(&np->chain); + np->attr.name = np->name; + np->attr.mode = mode; + np->client_ops = client_ops; + np->client_instance = client_instance; + + if (!np->name) { + error = -ENOMEM; + eprintk("mcctrl:create_i:kstrdup failed. %d\n", error); + goto out; + } + + error = sysfs_create_file(&parent->kobj, &np->attr); + if (error) { + eprintk("mcctrl:create_i:sysfs_create_file failed. %d\n", + error); + goto out; + } + + list_add(&np->chain, &parent->children); + + error = 0; +out: + if (error) { + if (np) { + kfree(np->name); + kfree(np); + } + np = ERR_PTR(error); + eprintk("mcctrl:create_i(%s,%s,%#o,%#lx,%#lx) : %d\n", + parent->name, name, mode, client_ops, + client_instance, error); + } + dprintk("mcctrl:create_i(%s,%s,%#o,%#lx,%#lx) : %p %d\n", + parent->name, name, mode, client_ops, client_instance, + np, error); + return np; +} /* create_i() */ + +static struct sysfsm_node * +mkdir_i(struct sysfsm_node *parent, const char *name) +{ + int error; + struct sysfsm_node *np = NULL; + struct kobject *parent_kobj; + struct sysfsm_data *sdp; + + BUG_ON(!parent); + BUG_ON(!name); + dprintk("mcctrl:mkdir_i(%s,%s)\n", parent->name, name); + + sdp = parent->sdp; + + if ((parent == sdp->sysfs_root) && strcmp(name, "sys")) { + error = -EPERM; + eprintk("mcctrl:mkdir_i:root dir. %d\n", error); + goto out; + } + + if (parent->type != SNT_DIR) { + error = -ENOTDIR; + eprintk("mcctrl:mkdir_i:not a directory. %d\n", error); + goto out; + } + + if (name[0] == '\0') { + error = -EINVAL; + eprintk("mcctrl:mkdir_i:null dirname. %d\n", error); + goto out; + } + + np = lookup_i(parent, name); + if (!IS_ERR(np)) { + error = -EEXIST; + eprintk("mcctrl:mkdir_i:already exist. %d\n", error); + np = NULL; + goto out; + } + + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) { + error = -ENOMEM; + eprintk("mcctrl:mkdir_i:kzalloc failed. %d\n", error); + goto out; + } + + np->type = SNT_DIR; + np->name = kstrdup(name, GFP_KERNEL); + np->parent = parent; + np->sdp = sdp; + INIT_LIST_HEAD(&np->chain); + INIT_LIST_HEAD(&np->children); + + if (!np->name) { + error = -ENOMEM; + eprintk("mcctrl:mkdir_i:kstrdup failed. %d\n", error); + goto out; + } + + parent_kobj = &parent->kobj; + if (parent == sdp->sysfs_root) { + parent_kobj = sdp->sysfs_kobj; + } + + error = kobject_init_and_add(&np->kobj, &the_ktype, parent_kobj, + np->name); + if (error) { + eprintk("mcctrl:mkdir_i:kobject_init_and_add failed. %d\n", + error); + goto out; + } + + list_add(&np->chain, &parent->children); + + error = 0; +out: + if (error) { + if (np) { + kfree(np->name); + kfree(np); + } + np = ERR_PTR(error); + eprintk("mcctrl:mkdir_i(%s,%s): %d\n", + parent->name, name, error); + } + dprintk("mcctrl:mkdir_i(%s,%s): %p %d\n", + parent->name, name, np, error); + return np; +} /* mkdir_i() */ + +static struct sysfsm_node * +symlink_i(struct sysfsm_node *target, struct sysfsm_node *parent, + const char *name) +{ + int error; + struct sysfsm_node *np = NULL; + struct sysfsm_data *sdp; + + BUG_ON(!target); + BUG_ON(!parent); + BUG_ON(!name); + dprintk("mcctrl:symlink_i(%s,%s,%s)\n", + target->name, parent->name, name); + + sdp = parent->sdp; + + if (target->type != SNT_DIR) { + error = -EINVAL; + eprintk("mcctrl:symlink_i:target isn't a directory. %d\n", + error); + goto out; + } + + if (parent == sdp->sysfs_root) { + error = -EPERM; + eprintk("mcctrl:symlink_i:root directory. %d\n", error); + goto out; + } + + if (parent->type != SNT_DIR) { + error = -ENOTDIR; + eprintk("mcctrl:symlink_i:parent isn't a directory. %d\n", + error); + goto out; + } + + if (name[0] == '\0') { + error = -EINVAL; + eprintk("mcctrl:symlink_i:null linkname. %d\n", error); + goto out; + } + + np = lookup_i(parent, name); + if (!IS_ERR(np)) { + error = -EEXIST; + eprintk("mcctrl:symlink_i:already exist. %d\n", error); + np = NULL; + goto out; + } + + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) { + error = -ENOMEM; + eprintk("mcctrl:symlink_i:kzalloc failed. %d\n", error); + goto out; + } + + np->type = SNT_LINK; + np->name = kstrdup(name, GFP_KERNEL); + np->parent = parent; + np->sdp = sdp; + INIT_LIST_HEAD(&np->chain); + + if (!np->name) { + error = -ENOMEM; + eprintk("mcctrl:symlink_i:kstrdup failed. %d\n", error); + goto out; + } + + error = sysfs_create_link(&parent->kobj, &target->kobj, name); + if (error) { + eprintk("mcctrl:symlink_i:sysfs_create_link failed. %d\n", + error); + goto out; + } + + list_add(&np->chain, &parent->children); + + error = 0; +out: + if (error) { + if (np) { + kfree(np->name); + kfree(np); + } + np = ERR_PTR(error); + eprintk("mcctrl:symlink_i(%s,%s,%s): %d\n", + target->name, parent->name, name, error); + } + dprintk("mcctrl:symlink_i(%s,%s,%s): %p %d\n", + target->name, parent->name, name, np, error); + return np; +} /* symlink_i() */ + +static int +unlink_i(struct sysfsm_node *np) +{ + int error; + struct sysfsm_data *sdp; + + BUG_ON(!np); + dprintk("mcctrl:unlink_i(%s)\n", np->name); + + sdp = np->sdp; + + if ((np == sdp->sysfs_root) || (np->parent == sdp->sysfs_root)) { + error = -EPERM; + eprintk("mcctrl:unlink_i:protected directory. %d\n", error); + goto out; + } + + if ((np->type == SNT_DIR) && !list_empty(&np->children)) { + /* this is usual when called from cleanup_ancestor() */ + error = -ENOTEMPTY; + dprintk("mcctrl:unlink_i:not empty dir. %d\n", error); + goto out; + } + + list_del(&np->chain); + if (np->type == SNT_FILE) { + sysfs_remove_file(&np->parent->kobj, &np->attr); + } + else if (np->type == SNT_DIR) { + if (np->parent != np) { + kobject_del(&np->kobj); + error = 0; + goto out; + } + } + else if (np->type == SNT_LINK) { + sysfs_remove_link(&np->parent->kobj, np->name); + } + else { + BUG(); + } + + error = release_i(np); + if (error) { + eprintk("mcctrl:unlink_i:release_i failed. %d\n", error); + goto out; + } + + error = 0; +out: + if (error) { + eprintk("mcctrl:unlink_i(%s): %d\n", np->name, error); + } + dprintk("mcctrl:unlink_i(%s): %d\n", (!error)?NULL:np->name, error); + return error; +} /* unlink_i() */ + +static int +remove(struct sysfsm_node *target) +{ + int error; + struct sysfsm_node *np; + struct sysfsm_node *next_np; + + BUG_ON(!target); + dprintk("mcctrl:remove(%s)\n", target->name); + + for (np = target; np; np = next_np) { + while ((np->type == SNT_DIR) && !list_empty(&np->children)) { + np = list_first_entry(&np->children, + struct sysfsm_node, chain); + } + + next_np = np->parent; + if (np == target) { + next_np = NULL; + } + + error = unlink_i(np); + if (error) { + eprintk("mcctrl:remove:unlink_i(%s) failed. %d\n", + np->name, error); + goto out; + } + } + + error = 0; +out: + if (error) { + eprintk("mcctrl:remove(%s): %d\n", target->name, error); + } + dprintk("mcctrl:remove(%s): %d\n", (!error)?NULL:target->name, error); + return error; +} /* remove() */ + +static struct sysfsm_node * +lookup(struct sysfsm_node *from, char *path) +{ + int error; + struct sysfsm_node *dirp; + struct sysfsm_node *np; + char *p; + char *name; + + BUG_ON(!from); + BUG_ON(!path); + dprintk("mcctrl:lookup(%s,%s)\n", from->name, path); + + dirp = from; + np = from; + p = path; + while (!!(name = strsep(&p, "/"))) { + if (!*name) { + continue; + } + + np = lookup_i(dirp, name); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:lookup:lookup_i(%s,%s) failed. %d\n", + dirp->name, name, error); + goto out; + } + dirp = np; + } + + error = 0; +out: + if (error) { + np = ERR_PTR(error); + eprintk("mcctrl:lookup(%s,%s): %d\n", from->name, path, error); + } + dprintk("mcctrl:lookup(%s,%s): %p %d\n", from->name, path, np, error); + return np; +} /* lookup() */ + +static struct sysfsm_node * +dig(struct sysfsm_node *from, char *path) +{ + int error; + struct sysfsm_node *dirp; + char *p; + char *name; + struct sysfsm_node *np; + + BUG_ON(!from); + BUG_ON(!path); + dprintk("mcctrl:dig(%s,%s)\n", from->name, path); + + dirp = from; + p = path; + while (!!(name = strsep(&p, "/"))) { + if (!*name) { + continue; + } + + np = lookup_i(dirp, name); + if (IS_ERR(np)) { + error = PTR_ERR(np); + if (error != -ENOENT) { + eprintk("mcctrl:dig:lookup_i(%s,%s) failed. %d\n", + dirp->name, name, error); + goto out; + } + + np = mkdir_i(dirp, name); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:dig:mkdir_i(%s,%s) failed. %d\n", + dirp->name, name, error); + goto out; + } + } + dirp = np; + } + + if (dirp->type != SNT_DIR) { + error = -ENOTDIR; + eprintk("mcctrl:dig:%s:not a directory. %d\n", + dirp->name, error); + goto out; + } + + error = 0; +out: + if (error) { + dirp = ERR_PTR(error); + eprintk("mcctrl:dig(%s): %d\n", from->name, error); + } + dprintk("mcctrl:dig(%s): %p %d\n", from->name, dirp, error); + return dirp; +} /* dig() */ + +static void +cleanup_ancestor(struct sysfsm_node *target) +{ + int error; + struct sysfsm_node *np; + struct sysfsm_node *next_np; + + BUG_ON(!target); + dprintk("mcctrl:cleanup_ancestor(%p {%s})\n", target, target->name); + + error = 0; + for (np = target; !error; np = next_np) { + next_np = np->parent; + error = unlink_i(np); + } + + dprintk("mcctrl:cleanup_ancestor(%p):\n", target); + return; +} /* cleanup_ancestor() */ + +static struct sysfsm_node * +sysfsm_create(struct sysfsm_data *sdp, const char *path0, mode_t mode, + long client_ops, long client_instance) +{ + int error; + char *path = NULL; + struct semaphore *held_sem = NULL; + struct sysfsm_node *dirp; + char *name; + struct sysfsm_node *np = ERR_PTR(-EIO); + + BUG_ON(!sdp); + dprintk("mcctrl:sysfsm_create(%p,%s,%#o,%#lx,%#lx)\n", + sdp, path0, mode, client_ops, client_instance); + + path = kstrdup(path0, GFP_KERNEL); + if (!path) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_create:kstrdup failed. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_tree_sem); + if (error) { + eprintk("mcctrl:sysfsm_create:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_tree_sem; + + dirp = sdp->sysfs_root; + name = strrchr(path, '/'); + if (!name) { + name = path; + } + else { + *name = '\0'; + ++name; + + dirp = dig(dirp, path); + if (IS_ERR(dirp)) { + error = PTR_ERR(dirp); + eprintk("mcctrl:sysfsm_create:dig failed. %d\n", + error); + goto out; + } + } + + np = create_i(dirp, name, mode, client_ops, client_instance); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:sysfsm_create:create_i(%s,%s) failed. %d\n", + dirp->name, name, error); + goto out; + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + kfree(path); + if (error) { + np = ERR_PTR(error); + eprintk("mcctrl:sysfsm_create(%p,%s,%#o,%#lx,%#lx): %d\n", + sdp, path0, mode, client_ops, client_instance, + error); + } + dprintk("mcctrl:sysfsm_create(%p,%s,%#o,%#lx,%#lx): %p %d\n", + sdp, path0, mode, client_ops, client_instance, np, + error); + return np; +} /* sysfsm_create() */ + +struct sysfsm_node * +sysfsm_mkdir(struct sysfsm_data *sdp, const char *path0) +{ + int error; + char *path = NULL; + struct semaphore *held_sem = NULL; + struct sysfsm_node *dirp; + char *name; + struct sysfsm_node *np = ERR_PTR(-EIO); + + BUG_ON(!sdp); + dprintk("mcctrl:sysfsm_mkdir(%p,%s)\n", sdp, path0); + + path = kstrdup(path0, GFP_KERNEL); + if (!path) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_mkdir:kstrdup failed. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_tree_sem); + if (error) { + eprintk("mcctrl:sysfsm_mkdir:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_tree_sem; + + dirp = sdp->sysfs_root; + name = strrchr(path, '/'); + if (!name) { + name = path; + } + else { + *name = '\0'; + ++name; + + dirp = dig(dirp, path); + if (IS_ERR(dirp)) { + error = PTR_ERR(dirp); + eprintk("mcctrl:sysfsm_mkdir:dig failed. %d\n", error); + goto out; + } + } + + np = mkdir_i(dirp, name); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:sysfsm_mkdir:mkdir_i failed. %d\n", error); + goto out; + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + kfree(path); + if (error) { + np = ERR_PTR(error); + eprintk("mcctrl:sysfsm_mkdir(%p,%s): %d\n", sdp, path0, error); + } + dprintk("mcctrl:sysfsm_mkdir(%p,%s): %p %d\n", sdp, path0, np, error); + return np; +} /* sysfsm_mkdir() */ + +struct sysfsm_node * +sysfsm_symlink(struct sysfsm_data *sdp, struct sysfsm_node *target, + const char *path0) +{ + int error; + char *path = NULL; + struct semaphore *held_sem = NULL; + char *name; + struct sysfsm_node *dirp; + struct sysfsm_node *np = ERR_PTR(-EIO); + + BUG_ON(!sdp); + BUG_ON(!target); + dprintk("mcctrl:sysfsm_symlink(%p,%s,%s)\n", sdp, target->name, path0); + + path = kstrdup(path0, GFP_KERNEL); + if (!path) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_symlink:kstrdup failed. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_tree_sem); + if (error) { + eprintk("mcctrl:sysfsm_symlink:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_tree_sem; + + dirp = sdp->sysfs_root; + name = strrchr(path, '/'); + if (!name) { + name = path; + } + else { + *name = '\0'; + ++name; + + dirp = dig(dirp, path); + if (IS_ERR(dirp)) { + error = PTR_ERR(dirp); + eprintk("mcctrl:sysfsm_symlink:dig failed. %d\n", + error); + goto out; + } + } + + np = symlink_i(target, dirp, name); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:sysfsm_symlink:symlink_i(%s,%s,%s) failed. %d\n", + target->name, dirp->name, name, error); + goto out; + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + kfree(path); + if (error) { + np = ERR_PTR(error); + eprintk("mcctrl:sysfsm_symlink(%p,%s,%s): %d\n", + sdp, target->name, path0, error); + } + dprintk("mcctrl:sysfsm_symlink(%p,%s,%s): %p %d\n", + sdp, target->name, path0, np, error); + return np; +} /* sysfsm_symlink() */ + +static struct sysfsm_node * +sysfsm_lookup(struct sysfsm_data *sdp, const char *path0) +{ + int error; + char *path = NULL; + struct semaphore *held_sem = NULL; + struct sysfsm_node *np; + + BUG_ON(!sdp); + dprintk("mcctrl:sysfsm_lookup(%p,%s)\n", sdp, path0); + + path = kstrdup(path0, GFP_KERNEL); + if (!path) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_lookup:kstrdup failed. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_tree_sem); + if (error) { + eprintk("mcctrl:sysfsm_lookup:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_tree_sem; + + np = lookup(sdp->sysfs_root, path); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:sysfsm_lookup:lookup failed. %d\n", error); + goto out; + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + kfree(path); + if (error) { + np = ERR_PTR(error); + eprintk("mcctrl:sysfsm_lookup(%p,%s): %d\n", + sdp, path0, error); + } + dprintk("mcctrl:sysfsm_lookup(%p,%s): %p %d\n", sdp, path0, np, error); + return np; +} /* sysfsm_lookup() */ + +static int +sysfsm_unlink(struct sysfsm_data *sdp, const char *path0, int flags) +{ + int error; + char *path = NULL; + struct semaphore *held_sem = NULL; + struct sysfsm_node *dirp; + struct sysfsm_node *np; + + BUG_ON(!sdp); + dprintk("mcctrl:sysfsm_unlink(%p,%s,%#x)\n", sdp, path0, flags); + + path = kstrdup(path0, GFP_KERNEL); + if (!path) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_unlink:kstrdup failed. %d\n", error); + goto out; + } + + error = down_interruptible(&sdp->sysfs_tree_sem); + if (error) { + eprintk("mcctrl:sysfsm_unlink:down failed. %d\n", error); + goto out; + } + held_sem = &sdp->sysfs_tree_sem; + + np = lookup(sdp->sysfs_root, path); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:sysfsm_unlink:lookup failed. %d\n", error); + goto out; + } + + dirp = np->parent; + + error = remove(np); + if (error) { + eprintk("mcctrl:sysfsm_unlink:remove failed. %d\n", error); + goto out; + } + + if (!flags & SYSFS_UNLINK_KEEP_ANCESTOR) { + cleanup_ancestor(dirp); + } + + error = 0; +out: + if (held_sem) { + up(held_sem); + } + kfree(path); + if (error) { + eprintk("mcctrl:sysfsm_unlink(%p,%s,%#x): %d\n", + sdp, path0, flags, error); + } + dprintk("mcctrl:sysfsm_unlink(%p,%s,%#x): %d\n", + sdp, path0, flags, error); + return error; +} /* sysfsm_unlink() */ + +void +sysfsm_cleanup(ihk_os_t os) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + struct sysfsm_data *sdp = &udp->sysfsm_data; + struct sysfsm_node *np; + + dprintk("mcctrl:sysfsm_cleanup(%p)\n", os); + + if (sdp->sysfs_buf) { + ihk_device_unmap_virtual(dev, sdp->sysfs_buf, + sdp->sysfs_bufsize); + ihk_device_unmap_memory(dev, sdp->sysfs_buf_pa, + sdp->sysfs_bufsize); + sdp->sysfs_buf = NULL; + sdp->sysfs_buf_pa = 0; + sdp->sysfs_buf_rpa = 0; + } + + np = sdp->sysfs_root; + sdp->sysfs_root = NULL; + + if (np) { + error = remove(np); + if (error) { + wprintk("mcctrl:sysfsm_cleanup:remove failed. %d\n", + error); + /* through */ + } + } + + dprintk("mcctrl:sysfsm_cleanup(%p):\n", os); + return; +} /* sysfsm_cleanup() */ + +int +sysfsm_setup(ihk_os_t os, void *buf, long buf_pa, size_t bufsize) +{ + int error; + struct device *dev = ihk_os_get_linux_device(os); + struct sysfsm_node *np = NULL; + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + struct sysfsm_data *sdp = &udp->sysfsm_data; + struct sysfsm_req *req = &sdp->sysfs_req; + + dprintk("mcctrl:sysfsm_setup(%p)\n", os); + + req->busy = 0; + init_waitqueue_head(&req->wq); + + np = kzalloc(sizeof(*np), GFP_KERNEL); + if (!np) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_setup:kzalloc failed. %d\n", error); + goto out; + } + + np->type = SNT_DIR; + np->name = kstrdup("(the_root)", GFP_KERNEL); + np->parent = np; + np->sdp = sdp; + INIT_LIST_HEAD(&np->chain); + INIT_LIST_HEAD(&np->children); + + if (!np->name) { + error = -ENOMEM; + eprintk("mcctrl:sysfsm_setup:kstrdup failed. %d\n", error); + goto out; + } + + sdp->sysfs_os = os; + sdp->sysfs_kobj = &dev->kobj; + sema_init(&sdp->sysfs_io_sem, 1); + sema_init(&sdp->sysfs_tree_sem, 1); + + sdp->sysfs_root = np; + np = NULL; + + np = mkdir_i(sdp->sysfs_root, "sys"); + if (IS_ERR(np)) { + error = PTR_ERR(np); + eprintk("mcctrl:sysfsm_setup:mkdir_i failed. %d\n", error); + goto out; + } + + sdp->sysfs_bufsize = bufsize; + sdp->sysfs_buf_pa = buf_pa; + wmb(); + sdp->sysfs_buf = buf; + + error = 0; +out: + if (error) { + if (np) { + kfree(np->name); + kfree(np); + } + sysfsm_cleanup(os); + eprintk("mcctrl:sysfsm_setup(%p): %d\n", os, error); + } + dprintk("mcctrl:sysfsm_setup(%p): %d\n", os, error); + return error; +} /* sysfsm_setup() */ + +static void +sysfsm_req_setup(void *os, long param_rpa) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + long param_pa; + struct sysfs_req_setup_param *param; + long buf_pa; + void *buf; + + param_pa = ihk_device_map_memory(dev, param_rpa, sizeof(*param)); + param = ihk_device_map_virtual(dev, param_pa, sizeof(*param), NULL, 0); + + buf_pa = ihk_device_map_memory(dev, param->buf_rpa, param->bufsize); + buf = ihk_device_map_virtual(dev, buf_pa, param->bufsize, NULL, 0); + + error = sysfsm_setup(os, buf, buf_pa, param->bufsize); + + param->error = error; + wmb(); + param->busy = 0; + + if (error) { + ihk_device_unmap_virtual(dev, buf, param->bufsize); + ihk_device_unmap_memory(dev, buf_pa, param->bufsize); + } + ihk_device_unmap_virtual(dev, param, sizeof(*param)); + ihk_device_unmap_memory(dev, param_pa, sizeof(*param)); + return; +} /* sysfsm_req_setup() */ + +static void +sysfsm_req_create(void *os, long param_rpa) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + long param_pa; + struct sysfs_req_create_param *param; + struct sysfsm_node *np; + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + + param_pa = ihk_device_map_memory(dev, param_rpa, sizeof(*param)); + param = ihk_device_map_virtual(dev, param_pa, sizeof(*param), NULL, 0); + + np = sysfsm_create(&udp->sysfsm_data, param->path, param->mode, + param->client_ops, param->client_instance); + if (IS_ERR(np)) { + error = PTR_ERR(np); + goto out; + } + + error = 0; + +out: + param->error = error; + wmb(); + param->busy = 0; + + ihk_device_unmap_virtual(dev, param, sizeof(*param)); + ihk_device_unmap_memory(dev, param_pa, sizeof(*param)); + return; +} /* sysfsm_req_create() */ + +static void +sysfsm_req_mkdir(void *os, long param_rpa) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + long param_pa; + struct sysfs_req_mkdir_param *param; + struct sysfsm_node *np; + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + + param_pa = ihk_device_map_memory(dev, param_rpa, sizeof(*param)); + param = ihk_device_map_virtual(dev, param_pa, sizeof(*param), NULL, 0); + + np = sysfsm_mkdir(&udp->sysfsm_data, param->path); + if (IS_ERR(np)) { + error = PTR_ERR(np); + goto out; + } + + error = 0; + param->handle = (long)np; + +out: + param->error = error; + wmb(); + param->busy = 0; + + ihk_device_unmap_virtual(dev, param, sizeof(*param)); + ihk_device_unmap_memory(dev, param_pa, sizeof(*param)); + return; +} /* sysfsm_req_mkdir() */ + +static void +sysfsm_req_symlink(void *os, long param_rpa) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + long param_pa; + struct sysfs_req_symlink_param *param; + struct sysfsm_node *np; + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + + param_pa = ihk_device_map_memory(dev, param_rpa, sizeof(*param)); + param = ihk_device_map_virtual(dev, param_pa, sizeof(*param), NULL, 0); + + np = sysfsm_symlink(&udp->sysfsm_data, (void *)param->target, + param->path); + if (IS_ERR(np)) { + error = PTR_ERR(np); + goto out; + } + + error = 0; +out: + param->error = error; + wmb(); + param->busy = 0; + + ihk_device_unmap_virtual(dev, param, sizeof(*param)); + ihk_device_unmap_memory(dev, param_pa, sizeof(*param)); + return; +} /* sysfsm_req_symlink() */ + +static void +sysfsm_req_lookup(void *os, long param_rpa) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + long param_pa; + struct sysfs_req_lookup_param *param; + struct sysfsm_node *np; + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + + param_pa = ihk_device_map_memory(dev, param_rpa, sizeof(*param)); + param = ihk_device_map_virtual(dev, param_pa, sizeof(*param), NULL, 0); + + np = sysfsm_lookup(&udp->sysfsm_data, param->path); + if (IS_ERR(np)) { + error = PTR_ERR(np); + goto out; + } + + error = 0; + param->handle = (long)np; + +out: + param->error = error; + wmb(); + param->busy = 0; + + ihk_device_unmap_virtual(dev, param, sizeof(*param)); + ihk_device_unmap_memory(dev, param_pa, sizeof(*param)); + return; +} /* sysfsm_req_lookup() */ + +static void +sysfsm_req_unlink(void *os, long param_rpa) +{ + int error; + ihk_device_t dev = ihk_os_to_dev(os); + long param_pa; + struct sysfs_req_unlink_param *param; + struct mcctrl_usrdata *udp = ihk_host_os_get_usrdata(os); + + param_pa = ihk_device_map_memory(dev, param_rpa, sizeof(*param)); + param = ihk_device_map_virtual(dev, param_pa, sizeof(*param), NULL, 0); + + error = sysfsm_unlink(&udp->sysfsm_data, param->path, param->flags); + if (error) { + goto out; + } + + error = 0; +out: + param->error = error; + wmb(); + param->busy = 0; + + ihk_device_unmap_virtual(dev, param, sizeof(*param)); + ihk_device_unmap_memory(dev, param_pa, sizeof(*param)); + return; +} /* sysfsm_req_unlink() */ + +static void +sysfsm_resp_show(void *os, struct sysfsm_node *np, ssize_t ssize) +{ + struct sysfsm_data *sdp = np->sdp; + struct sysfsm_req *req = &sdp->sysfs_req; + + dprintk("mcctrl:sysfsm_resp_show(%p,%s,%ld)\n", os, np->name, ssize); + + req->lresult = ssize; + wmb(); + req->busy = 0; + wake_up(&req->wq); + + dprintk("mcctrl:sysfsm_resp_show(%p,%s,%ld):\n", os, np->name, ssize); + return; +} /* sysfsm_resp_show() */ + +static void +sysfsm_resp_store(void *os, struct sysfsm_node *np, ssize_t ssize) +{ + struct sysfsm_data *sdp = np->sdp; + struct sysfsm_req *req = &sdp->sysfs_req; + + dprintk("mcctrl:sysfsm_resp_store(%p,%s,%ld)\n", os, np->name, ssize); + + req->lresult = ssize; + wmb(); + req->busy = 0; + wake_up(&req->wq); + + dprintk("mcctrl:sysfsm_resp_store(%p,%s,%ld):\n", os, np->name, ssize); + return; +} /* sysfsm_resp_store() */ + +static void +sysfsm_resp_release(void *os, struct sysfsm_node *np, int error) +{ + struct sysfsm_data *sdp = np->sdp; + struct sysfsm_req *req = &sdp->sysfs_req; + + dprintk("mcctrl:sysfsm_resp_release(%p,%p %s,%d)\n", + os, np, np->name, error); + + req->lresult = error; + wmb(); + req->busy = 0; + wake_up(&req->wq); + + dprintk("mcctrl:sysfsm_resp_release(%p,%p,%d):\n", os, np, error); + return; +} /* sysfsm_resp_release() */ + +static void +sysfsm_work_main(struct work_struct *work0) +{ + struct sysfs_work *work = container_of(work0, struct sysfs_work, work); + + switch (work->msg) { + case SCD_MSG_SYSFS_REQ_SETUP: + sysfsm_req_setup(work->os, work->arg1); + break; + + case SCD_MSG_SYSFS_REQ_CREATE: + sysfsm_req_create(work->os, work->arg1); + break; + + case SCD_MSG_SYSFS_REQ_MKDIR: + sysfsm_req_mkdir(work->os, work->arg1); + break; + + case SCD_MSG_SYSFS_REQ_SYMLINK: + sysfsm_req_symlink(work->os, work->arg1); + break; + + case SCD_MSG_SYSFS_REQ_LOOKUP: + sysfsm_req_lookup(work->os, work->arg1); + break; + + case SCD_MSG_SYSFS_REQ_UNLINK: + sysfsm_req_unlink(work->os, work->arg1); + break; + + case SCD_MSG_SYSFS_RESP_SHOW: + sysfsm_resp_show(work->os, (void *)work->arg1, + work->arg2); + break; + + case SCD_MSG_SYSFS_RESP_STORE: + sysfsm_resp_store(work->os, (void *)work->arg1, + work->arg2); + break; + + case SCD_MSG_SYSFS_RESP_RELEASE: + sysfsm_resp_release(work->os, (void *)work->arg1, + work->err); + break; + + default: + wprintk("mcctrl:sysfsm_work_main:unknown work (%d,%p,%#lx,%#lx)\n", + work->msg, work->os, work->arg1, work->arg2); + break; + + } + + kfree(work); + return; +} /* sysfsm_work_main() */ + +void +sysfsm_packet_handler(void *os, int msg, int err, long arg1, long arg2) +{ + struct sysfs_work *work = NULL; + + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + eprintk("mcctrl:sysfsm_packet_handler:kzalloc failed\n"); + return; + } + + work->os = os; + work->msg = msg; + work->err = err; + work->arg1 = arg1; + work->arg2 = arg2; + INIT_WORK(&work->work, &sysfsm_work_main); + + schedule_work(&work->work); + return; +} /* sysfsm_packet_handler() */ + +static struct sysfs_ops the_ops = { + .show = &sysfsm_show, + .store = &sysfsm_store, +}; + +static struct kobj_type the_ktype = { + .sysfs_ops = &the_ops, + .release = &sysfsm_release, +}; + +/**** End of File ****/ diff --git a/executer/kernel/mcctrl/sysfs_msg.h b/executer/kernel/mcctrl/sysfs_msg.h new file mode 100644 index 00000000..22761585 --- /dev/null +++ b/executer/kernel/mcctrl/sysfs_msg.h @@ -0,0 +1,76 @@ +/** + * \file sysfs_msg.h + * License details are found in the file LICENSE. + * \brief + * message declarations for sysfs framework + * \author Gou Nakamura \par + * Copyright (C) 2015 RIKEN AICS + */ +/* + * HISTORY: + */ + +#ifndef MCKERNEL_SYSFS_MSG_H +#define MCKERNEL_SYSFS_MSG_H + +#define SYSFS_PATH_MAX 1024 + +struct sysfs_req_create_param { + int mode; + int error; + long client_ops; + long client_instance; + char path[SYSFS_PATH_MAX]; + int padding; + int busy; +}; /* struct sysfs_req_create_param */ + +struct sysfs_req_mkdir_param { + int error; + int padding; + long handle; + char path[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_mkdir_param */ + +struct sysfs_req_symlink_param { + int error; + int padding; + long target; + char path[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_symlink_param */ + +struct sysfs_req_lookup_param { + int error; + int padding; + long handle; + char path[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_lookup_param */ + +/* for sysfs_req_unlink_param.flags */ +#define SYSFS_UNLINK_KEEP_ANCESTOR 0x01 + +struct sysfs_req_unlink_param { + int flags; + int error; + char path[SYSFS_PATH_MAX]; + int padding; + int busy; +}; /* struct sysfs_req_unlink_param */ + +struct sysfs_req_setup_param { + int error; + int padding; + long buf_rpa; + long bufsize; + char padding3[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_setup_param */ + +#endif /* MCKERNEL_SYSFS_MSG_H */ diff --git a/kernel/Makefile.build.in b/kernel/Makefile.build.in index ca0f9a10..9aac2e26 100644 --- a/kernel/Makefile.build.in +++ b/kernel/Makefile.build.in @@ -3,7 +3,7 @@ SRC=$(VPATH) IHKDIR=$(IHKBASE)/$(TARGETDIR) OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o OBJS += process.o copy.o waitq.o futex.o timer.o plist.o fileobj.o shmobj.o -OBJS += zeroobj.o procfs.o devobj.o +OBJS += zeroobj.o procfs.o devobj.o sysfs.o DEPSRCS=$(wildcard $(SRC)/*.c) CFLAGS += -I$(SRC)/include -mcmodel=kernel -D__KERNEL__ -g diff --git a/kernel/host.c b/kernel/host.c index 93d6d1c5..15578980 100644 --- a/kernel/host.c +++ b/kernel/host.c @@ -30,6 +30,7 @@ #include #include #include +#include //#define DEBUG_PRINT_HOST @@ -607,6 +608,22 @@ static int syscall_packet_handler(struct ihk_ikc_channel_desc *c, dkprintf("SCD_MSG_DEBUG_LOG code=%lx\n", packet->arg); debug_log(packet->arg); return 0; + + case SCD_MSG_SYSFS_REQ_SHOW: + case SCD_MSG_SYSFS_REQ_STORE: + case SCD_MSG_SYSFS_REQ_RELEASE: + sysfss_packet_handler(c, packet->msg, packet->err, + packet->sysfs_arg1, packet->sysfs_arg2, + packet->sysfs_arg3); + return 0; + + default: + kprintf("syscall_pakcet_handler:unknown message " + "(%d.%d.%d.%d.%d.%#lx)\n", + packet->msg, packet->ref, packet->osnum, + packet->pid, packet->err, packet->arg); + return 0; + } return 0; } diff --git a/kernel/include/syscall.h b/kernel/include/syscall.h index eb70283c..5c3822d2 100644 --- a/kernel/include/syscall.h +++ b/kernel/include/syscall.h @@ -46,6 +46,27 @@ #define SCD_MSG_DEBUG_LOG 0x20 +#define SCD_MSG_SYSFS_REQ_CREATE 0x30 +/* #define SCD_MSG_SYSFS_RESP_CREATE 0x31 */ +#define SCD_MSG_SYSFS_REQ_MKDIR 0x32 +/* #define SCD_MSG_SYSFS_RESP_MKDIR 0x33 */ +#define SCD_MSG_SYSFS_REQ_SYMLINK 0x34 +/* #define SCD_MSG_SYSFS_RESP_SYMLINK 0x35 */ +#define SCD_MSG_SYSFS_REQ_LOOKUP 0x36 +/* #define SCD_MSG_SYSFS_RESP_LOOKUP 0x37 */ +#define SCD_MSG_SYSFS_REQ_UNLINK 0x38 +/* #define SCD_MSG_SYSFS_RESP_UNLINK 0x39 */ +#define SCD_MSG_SYSFS_REQ_SHOW 0x3a +#define SCD_MSG_SYSFS_RESP_SHOW 0x3b +#define SCD_MSG_SYSFS_REQ_STORE 0x3c +#define SCD_MSG_SYSFS_RESP_STORE 0x3d +#define SCD_MSG_SYSFS_REQ_RELEASE 0x3e +#define SCD_MSG_SYSFS_RESP_RELEASE 0x3f +#define SCD_MSG_SYSFS_REQ_SETUP 0x40 +#define SCD_MSG_SYSFS_RESP_SETUP 0x41 +/* #define SCD_MSG_SYSFS_REQ_CLEANUP 0x42 */ +/* #define SCD_MSG_SYSFS_RESP_CLEANUP 0x43 */ + #define ARCH_SET_GS 0x1001 #define ARCH_SET_FS 0x1002 #define ARCH_GET_FS 0x1003 @@ -94,13 +115,27 @@ struct user_desc { unsigned int useable:1; unsigned int lm:1; }; + struct ikc_scd_packet { int msg; - int ref; - int osnum; - int pid; int err; - unsigned long arg; + union { + /* for traditional SCD_MSG_* */ + struct { + int ref; + int osnum; + int pid; + int padding; + unsigned long arg; + }; + + /* for SCD_MSG_SYSFS_* */ + struct { + long sysfs_arg1; + long sysfs_arg2; + long sysfs_arg3; + }; + }; }; struct program_image_section { diff --git a/kernel/include/sysfs.h b/kernel/include/sysfs.h new file mode 100644 index 00000000..cf4e39a3 --- /dev/null +++ b/kernel/include/sysfs.h @@ -0,0 +1,48 @@ +/** + * \file sysfs.h + * License details are found in the file LICENSE. + * \brief + * sysfs framework API definitions + * \author Gou Nakamura \par + * Copyright (C) 2015 RIKEN AICS + */ +/* + * HISTORY: + */ + +#ifndef MCKERNEL_SYSFS_H +#define MCKERNEL_SYSFS_H + +#define SYSFS_PATH_MAX 1024 + +/* for sysfs_unlinkf() */ +#define SYSFS_UNLINK_KEEP_ANCESTOR 0x01 + + +struct sysfs_ops { + ssize_t (*show)(struct sysfs_ops *ops, void *instance, void *buf, + size_t bufsize); + ssize_t (*store)(struct sysfs_ops *ops, void *instance, void *buf, + size_t bufsize); + void (*release)(struct sysfs_ops *ops, void *instance); +}; + +struct sysfs_handle { + long handle; +}; +typedef struct sysfs_handle sysfs_handle_t; + + +extern int sysfs_createf(struct sysfs_ops *ops, void *instance, int mode, + const char *fmt, ...); +extern int sysfs_mkdirf(sysfs_handle_t *dirhp, const char *fmt, ...); +extern int sysfs_symlinkf(sysfs_handle_t targeth, const char *fmt, ...); +extern int sysfs_lookupf(sysfs_handle_t *objhp, const char *fmt, ...); +extern int sysfs_unlinkf(int flags, const char *fmt, ...); + +extern void sysfs_init(void); +struct ihk_ikc_channel_desc; +extern void sysfss_packet_handler(struct ihk_ikc_channel_desc *ch, int msg, + int error, long arg1, long arg2, long arg3); + +#endif /* MCKERNEL_SYSFS_H */ diff --git a/kernel/include/sysfs_msg.h b/kernel/include/sysfs_msg.h new file mode 100644 index 00000000..22761585 --- /dev/null +++ b/kernel/include/sysfs_msg.h @@ -0,0 +1,76 @@ +/** + * \file sysfs_msg.h + * License details are found in the file LICENSE. + * \brief + * message declarations for sysfs framework + * \author Gou Nakamura \par + * Copyright (C) 2015 RIKEN AICS + */ +/* + * HISTORY: + */ + +#ifndef MCKERNEL_SYSFS_MSG_H +#define MCKERNEL_SYSFS_MSG_H + +#define SYSFS_PATH_MAX 1024 + +struct sysfs_req_create_param { + int mode; + int error; + long client_ops; + long client_instance; + char path[SYSFS_PATH_MAX]; + int padding; + int busy; +}; /* struct sysfs_req_create_param */ + +struct sysfs_req_mkdir_param { + int error; + int padding; + long handle; + char path[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_mkdir_param */ + +struct sysfs_req_symlink_param { + int error; + int padding; + long target; + char path[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_symlink_param */ + +struct sysfs_req_lookup_param { + int error; + int padding; + long handle; + char path[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_lookup_param */ + +/* for sysfs_req_unlink_param.flags */ +#define SYSFS_UNLINK_KEEP_ANCESTOR 0x01 + +struct sysfs_req_unlink_param { + int flags; + int error; + char path[SYSFS_PATH_MAX]; + int padding; + int busy; +}; /* struct sysfs_req_unlink_param */ + +struct sysfs_req_setup_param { + int error; + int padding; + long buf_rpa; + long bufsize; + char padding3[SYSFS_PATH_MAX]; + int padding2; + int busy; +}; /* struct sysfs_req_setup_param */ + +#endif /* MCKERNEL_SYSFS_MSG_H */ diff --git a/kernel/init.c b/kernel/init.c index ffca7a37..82cd6a61 100644 --- a/kernel/init.c +++ b/kernel/init.c @@ -30,6 +30,7 @@ #include #include #include +#include //#define IOCTL_FUNC_EXTENSION #ifdef IOCTL_FUNC_EXTENSION @@ -278,6 +279,7 @@ static void post_init(void) ap_start(); create_os_procfs_files(); + sysfs_init(); } #ifdef DCFA_RUN extern void user_main(); diff --git a/kernel/sysfs.c b/kernel/sysfs.c new file mode 100644 index 00000000..6a352f72 --- /dev/null +++ b/kernel/sysfs.c @@ -0,0 +1,617 @@ +/** + * \file sysfs.c + * License details are found in the file LICENSE. + * \brief + * sysfs framework, IHK-Slave side + * \author Gou Nakamura \par + * Copyright (C) 2015 RIKEN AICS + */ +/* + * HISTORY: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define dkprintf(...) do { if (0) kprintf(__VA_ARGS__); } while (0) +#define ekprintf(...) do { if (1) kprintf(__VA_ARGS__); } while (0) + +static size_t sysfs_data_bufsize; +static void *sysfs_data_buf; + +int +sysfs_createf(struct sysfs_ops *ops, void *instance, int mode, + const char *fmt, ...) +{ + int error; + va_list ap; + ssize_t n; + struct sysfs_req_create_param *param = NULL; + struct ikc_scd_packet packet; + + dkprintf("sysfs_createf(%p,%p,%#o,%s,...)\n", + ops, instance, mode, fmt); + + param = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!param) { + error = -ENOMEM; + ekprintf("sysfs_createf:allocate_pages failed. %d\n", error); + goto out; + } + + param->client_ops = (long)ops; + param->client_instance = (long)instance; + param->mode = mode; + param->busy = 1; + + va_start(ap, fmt); + n = vsnprintf(param->path, sizeof(param->path), fmt, ap); + va_end(ap); + if (n >= sizeof(param->path)) { + error = -ENAMETOOLONG; + ekprintf("sysfs_createf:vsnprintf failed. %d\n", error); + goto out; + } + dkprintf("sysfs_createf:path %s\n", param->path); + if (param->path[0] != '/') { + error = -ENOENT; + ekprintf("sysfs_createf:not an absolute path. %d\n", error); + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_CREATE; + packet.sysfs_arg1 = virt_to_phys(param); + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfs_createf:ihk_ikc_send failed. %d\n", error); + goto out; + } + + while (param->busy) { + cpu_pause(); + } + rmb(); + + error = param->error; + if (error) { + ekprintf("sysfs_createf:SCD_MSG_SYSFS_REQ_CREATE failed. %d\n", + error); + goto out; + } + + error = 0; +out: + if (param) { + free_pages(param, 1); + } + if (error) { + ekprintf("sysfs_createf(%p,%p,%#o,%s,...): %d\n", + ops, instance, mode, fmt, error); + } + dkprintf("sysfs_createf(%p,%p,%#o,%s,...): %d\n", + ops, instance, mode, fmt, error); + return error; +} /* sysfs_createf() */ + +int +sysfs_mkdirf(sysfs_handle_t *dirhp, const char *fmt, ...) +{ + int error; + struct sysfs_req_mkdir_param *param = NULL; + struct ikc_scd_packet packet; + va_list ap; + int n; + + dkprintf("sysfs_mkdirf(%p,%s,...)\n", dirhp, fmt); + + param = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!param) { + error = -ENOMEM; + ekprintf("sysfs_mkdirf:allocate_pages failed. %d\n", error); + goto out; + } + + param->busy = 1; + + va_start(ap, fmt); + n = vsnprintf(param->path, sizeof(param->path), fmt, ap); + va_end(ap); + if (n >= sizeof(param->path)) { + error = -ENAMETOOLONG; + ekprintf("sysfs_mkdirf:vsnprintf failed. %d\n", error); + goto out; + } + dkprintf("sysfs_mkdirf:path %s\n", param->path); + if (param->path[0] != '/') { + error = -ENOENT; + ekprintf("sysfs_mkdirf:not an absolute path. %d\n", error); + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_MKDIR; + packet.sysfs_arg1 = virt_to_phys(param); + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfs_mkdirf:ihk_ikc_send failed. %d\n", error); + goto out; + } + + while (param->busy) { + cpu_pause(); + } + rmb(); + + error = param->error; + if (error) { + ekprintf("sysfs_mkdirf:SCD_MSG_SYSFS_REQ_MKDIR failed. %d\n", + error); + goto out; + } + + error = 0; + if (dirhp) { + dirhp->handle = param->handle; + } + +out: + if (param) { + free_pages(param, 1); + } + if (error) { + ekprintf("sysfs_mkdirf(%p,%s,...): %d\n", dirhp, fmt, error); + } + dkprintf("sysfs_mkdirf(%p,%s,...): %d %#lx\n", dirhp, fmt, error, + (dirhp)?dirhp->handle:0); + return error; +} /* sysfs_mkdirf() */ + +int +sysfs_symlinkf(sysfs_handle_t targeth, const char *fmt, ...) +{ + int error; + struct sysfs_req_symlink_param *param = NULL; + struct ikc_scd_packet packet; + va_list ap; + int n; + + dkprintf("sysfs_symlinkf(%#lx,%s,...)\n", targeth.handle, fmt); + + param = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!param) { + error = -ENOMEM; + ekprintf("sysfs_symlinkf:allocate_pages failed. %d\n", error); + goto out; + } + + param->target = targeth.handle; + param->busy = 1; + + va_start(ap, fmt); + n = vsnprintf(param->path, sizeof(param->path), fmt, ap); + va_end(ap); + if (n >= sizeof(param->path)) { + error = -ENAMETOOLONG; + ekprintf("sysfs_symlinkf:vsnprintf failed. %d\n", error); + goto out; + } + dkprintf("sysfs_symlinkf:path %s\n", param->path); + if (param->path[0] != '/') { + error = -ENOENT; + ekprintf("sysfs_symlinkf:not an absolute path. %d\n", error); + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_SYMLINK; + packet.sysfs_arg1 = virt_to_phys(param); + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfs_symlinkf:ihk_ikc_send failed. %d\n", error); + goto out; + } + + while (param->busy) { + cpu_pause(); + } + rmb(); + + error = param->error; + if (error) { + ekprintf("sysfs_symlinkf:" + "SCD_MSG_SYSFS_REQ_SYMLINK failed. %d\n", + error); + goto out; + } + + error = 0; +out: + if (param) { + free_pages(param, 1); + } + if (error) { + ekprintf("sysfs_symlinkf(%#lx,%s,...): %d\n", + targeth.handle, fmt, error); + } + dkprintf("sysfs_symlinkf(%#lx,%s,...): %d\n", + targeth.handle, fmt, error); + return error; +} /* sysfs_symlinkf() */ + +int +sysfs_lookupf(sysfs_handle_t *objhp, const char *fmt, ...) +{ + int error; + struct sysfs_req_lookup_param *param = NULL; + struct ikc_scd_packet packet; + va_list ap; + int n; + + dkprintf("sysfs_lookupf(%p,%s,...)\n", objhp, fmt); + + param = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!param) { + error = -ENOMEM; + ekprintf("sysfs_lookupf:allocate_pages failed. %d\n", error); + goto out; + } + + param->busy = 1; + + va_start(ap, fmt); + n = vsnprintf(param->path, sizeof(param->path), fmt, ap); + va_end(ap); + if (n >= sizeof(param->path)) { + error = -ENAMETOOLONG; + ekprintf("sysfs_lookupf:vsnprintf failed. %d\n", error); + goto out; + } + dkprintf("sysfs_lookupf:path %s\n", param->path); + if (param->path[0] != '/') { + error = -ENOENT; + ekprintf("sysfs_lookupf:not an absolute path. %d\n", error); + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_LOOKUP; + packet.sysfs_arg1 = virt_to_phys(param); + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfs_lookupf:ihk_ikc_send failed. %d\n", error); + goto out; + } + + while (param->busy) { + cpu_pause(); + } + rmb(); + + error = param->error; + if (error) { + ekprintf("sysfs_lookupf:SCD_MSG_SYSFS_REQ_LOOKUP failed. %d\n", + error); + goto out; + } + + error = 0; + if (objhp) { + objhp->handle = param->handle; + } + +out: + if (param) { + free_pages(param, 1); + } + if (error) { + ekprintf("sysfs_lookupf(%p,%s,...): %d\n", objhp, fmt, error); + } + dkprintf("sysfs_lookupf(%p,%s,...): %d %#lx\n", objhp, fmt, error, + (objhp)?objhp->handle:0); + return error; +} /* sysfs_lookupf() */ + +int +sysfs_unlinkf(int flags, const char *fmt, ...) +{ + int error; + struct sysfs_req_unlink_param *param = NULL; + struct ikc_scd_packet packet; + va_list ap; + int n; + + dkprintf("sysfs_unlinkf(%#x,%s,...)\n", flags, fmt); + + param = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!param) { + error = -ENOMEM; + ekprintf("sysfs_unlinkf:allocate_pages failed. %d\n", error); + goto out; + } + + param->flags = flags; + param->busy = 1; + + va_start(ap, fmt); + n = vsnprintf(param->path, sizeof(param->path), fmt, ap); + va_end(ap); + if (n >= sizeof(param->path)) { + error = -ENAMETOOLONG; + ekprintf("sysfs_unlinkf:vsnprintf failed. %d\n", error); + goto out; + } + dkprintf("sysfs_unlinkf:path %s\n", param->path); + if (param->path[0] != '/') { + error = -ENOENT; + ekprintf("sysfs_unlinkf:not an absolute path. %d\n", error); + goto out; + } + + packet.msg = SCD_MSG_SYSFS_REQ_UNLINK; + packet.sysfs_arg1 = virt_to_phys(param); + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfs_unlinkf:ihk_ikc_send failed. %d\n", error); + goto out; + } + + while (param->busy) { + cpu_pause(); + } + rmb(); + + error = param->error; + if (error) { + ekprintf("sysfs_unlinkf:SCD_MSG_SYSFS_REQ_UNLINK failed. %d\n", + error); + goto out; + } + + error = 0; +out: + if (param) { + free_pages(param, 1); + } + if (error) { + ekprintf("sysfs_unlinkf(%#x,%s,...): %d\n", flags, fmt, error); + } + dkprintf("sysfs_unlinkf(%#x,%s,...): %d\n", flags, fmt, error); + return error; +} /* sysfs_unlinkf() */ + +static void +sysfss_req_show(long nodeh, struct sysfs_ops *ops, void *instance) +{ + int error; + ssize_t ssize; + struct ikc_scd_packet packet; + + dkprintf("sysfss_req_show(%#lx,%p,%p)\n", nodeh, ops, instance); + + ssize = -EIO; + if (ops->show) { + ssize = (*ops->show)(ops, instance, sysfs_data_buf, + sysfs_data_bufsize); + if (ssize < 0) { + ekprintf("sysfss_req_show:->show failed. %ld\n", + ssize); + /* through */ + } + } + + error = 0; + if (ssize < 0) { + error = ssize; + } + + packet.msg = SCD_MSG_SYSFS_RESP_SHOW; + packet.err = error; + packet.sysfs_arg1 = nodeh; + packet.sysfs_arg2 = ssize; + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfss_req_show:ihk_ikc_send failed. %d\n", error); + /* through */ + } + + if (error || packet.err) { + ekprintf("sysfss_req_show(%#lx,%p,%p): %d %d\n", + nodeh, ops, instance, error, packet.err); + } + dkprintf("sysfss_req_show(%#lx,%p,%p): %d %d %ld\n", + nodeh, ops, instance, error, packet.err, ssize); + return; +} /* sysfss_req_show() */ + +static void +sysfss_req_store(long nodeh, struct sysfs_ops *ops, void *instance, + size_t size) +{ + int error; + ssize_t ssize; + struct ikc_scd_packet packet; + + dkprintf("sysfss_req_store(%#lx,%p,%p,%d)\n", + nodeh, ops, instance, size); + + ssize = -EIO; + if (ops->store) { + ssize = (*ops->store)(ops, instance, sysfs_data_buf, size); + if (ssize < 0) { + ekprintf("sysfss_req_store:->store failed. %ld\n", + ssize); + /* through */ + } + } + + error = 0; + if (ssize < 0) { + error = ssize; + } + + packet.msg = SCD_MSG_SYSFS_RESP_STORE; + packet.err = error; + packet.sysfs_arg1 = nodeh; + packet.sysfs_arg2 = ssize; + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfss_req_store:ihk_ikc_send failed. %d\n", error); + /* through */ + } + + if (error || packet.err) { + ekprintf("sysfss_req_store(%#lx,%p,%p,%d): %d %d\n", + nodeh, ops, instance, size, error, packet.err); + } + dkprintf("sysfss_req_store(%#lx,%p,%p,%d): %d %d %ld\n", + nodeh, ops, instance, size, error, packet.err, ssize); + return; +} /* sysfss_req_store() */ + +static void +sysfss_req_release(long nodeh, struct sysfs_ops *ops, void *instance) +{ + int error; + struct ikc_scd_packet packet; + + dkprintf("sysfss_req_release(%#lx,%p,%p)\n", nodeh, ops, instance); + + if (ops->release) { + (*ops->release)(ops, instance); + } + + packet.msg = SCD_MSG_SYSFS_RESP_RELEASE; + packet.err = 0; + packet.sysfs_arg1 = nodeh; + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfss_req_release:ihk_ikc_send failed. %d\n", + error); + /* through */ + } + + if (error || packet.err) { + ekprintf("sysfss_req_release(%#lx,%p,%p): %d %d\n", + nodeh, ops, instance, error, packet.err); + } + dkprintf("sysfss_req_release(%#lx,%p,%p): %d %d\n", + nodeh, ops, instance, error, packet.err); + return; +} /* sysfss_req_release() */ + +void +sysfss_packet_handler(struct ihk_ikc_channel_desc *ch, int msg, int error, + long arg1, long arg2, long arg3) +{ + switch (msg) { + case SCD_MSG_SYSFS_REQ_SHOW: + sysfss_req_show(arg1, (void *)arg2, (void *)arg3); + break; + + case SCD_MSG_SYSFS_REQ_STORE: + sysfss_req_store(arg1, (void *)arg2, (void *)arg3, error); + break; + + case SCD_MSG_SYSFS_REQ_RELEASE: + sysfss_req_release(arg1, (void *)arg2, (void *)arg3); + break; + + default: + kprintf("sysfss_packet_handler:unknown message. msg %d" + " error %d arg1 %#lx arg2 %#lx arg3 %#lx\n", + msg, error, arg1, arg2, arg3); + break; + + } + return; +} /* sysfss_packet_handler() */ + +void +sysfs_init(void) +{ + int error; + struct sysfs_req_setup_param *param = NULL; + struct ikc_scd_packet packet; + + dkprintf("sysfs_init()\n"); + + if ((sizeof(struct sysfs_req_create_param) > PAGE_SIZE) + || (sizeof(struct sysfs_req_mkdir_param) > PAGE_SIZE) + || (sizeof(struct sysfs_req_symlink_param) > PAGE_SIZE) + || (sizeof(struct sysfs_req_lookup_param) > PAGE_SIZE) + || (sizeof(struct sysfs_req_unlink_param) > PAGE_SIZE) + || (sizeof(struct sysfs_req_setup_param) > PAGE_SIZE)) { + panic("struct sysfs_*_req_param too large"); + } + + sysfs_data_bufsize = PAGE_SIZE; + sysfs_data_buf = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!sysfs_data_buf) { + error = -ENOMEM; + ekprintf("sysfs_init:allocate_pages(buf) failed. %d\n", error); + goto out; + } + + param = allocate_pages(1, IHK_MC_AP_NOWAIT); + if (!param) { + error = -ENOMEM; + ekprintf("sysfs_init:allocate_pages(param) failed. %d\n", + error); + goto out; + } + + param->busy = 1; + param->buf_rpa = virt_to_phys(sysfs_data_buf); + param->bufsize = PAGE_SIZE; + + packet.msg = SCD_MSG_SYSFS_REQ_SETUP; + packet.sysfs_arg1 = virt_to_phys(param); + + error = ihk_ikc_send(cpu_local_var(syscall_channel), &packet, 0); + if (error) { + ekprintf("sysfs_init:ihk_ikc_send failed. %d\n", error); + goto out; + } + + while (param->busy) { + cpu_pause(); + } + rmb(); + + error = param->error; + if (error) { + ekprintf("sysfs_init:SCD_MSG_SYSFS_REQ_SETUP failed. %d\n", + error); + goto out; + } + + error = 0; +out: + if (param) { + free_pages(param, 1); + } + if (error) { + ekprintf("sysfs_init(): %d\n", error); + panic("sysfs_init"); + } + dkprintf("sysfs_init():\n"); + return; +} /* sysfs_init() */ + +/**** End of File ****/ diff --git a/lib/include/vsprintf.h b/lib/include/vsprintf.h new file mode 100644 index 00000000..2363c534 --- /dev/null +++ b/lib/include/vsprintf.h @@ -0,0 +1,22 @@ +/** + * \file vsprintf.h + * License details are found in the file LICENSE. + * \brief + * declare printf() like functions + * \author Gou Nakamura \par + * Copyright (C) 2015 RIKEN AICS + */ +/* + * HISTORY + */ + +#ifndef VSPRINTF_H +#define VSPRINTF_H + +#include +#include + +extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); +extern int snprintf(char *buf, size_t size, const char *fmt, ...); + +#endif