From: David van Moolenbroek Date: Mon, 10 Nov 2014 14:54:06 +0000 (+0000) Subject: procfs: add /proc/service directory X-Git-Url: http://zhaoyanbai.com/repos/?a=commitdiff_plain;h=31b6611abf2e94d3c0c0e282031f253dd63c282b;p=minix.git procfs: add /proc/service directory This directory is filled dynamically with regular files, one for each service that RS knows about, named after its label. Its contents are still subject to (heavy) change, but currently expose the service's endpoint and number of restarts so far. Change-Id: Ie58c824bcb6382c8da7a714e59fee87329970b4b --- diff --git a/minix/fs/procfs/Makefile b/minix/fs/procfs/Makefile index af2afdc1d..8fb44e97b 100644 --- a/minix/fs/procfs/Makefile +++ b/minix/fs/procfs/Makefile @@ -2,7 +2,7 @@ .include PROG= procfs -SRCS= buf.c cpuinfo.c main.c pid.c root.c tree.c util.c +SRCS= buf.c cpuinfo.c main.c pid.c root.c service.c tree.c util.c CPPFLAGS+= -I${NETBSDSRCDIR}/minix CPPFLAGS+= -I${NETBSDSRCDIR}/minix/fs diff --git a/minix/fs/procfs/main.c b/minix/fs/procfs/main.c index c488486ad..6ad523500 100644 --- a/minix/fs/procfs/main.c +++ b/minix/fs/procfs/main.c @@ -49,7 +49,7 @@ construct_tree(struct inode * dir, struct file * files) static void init_hook(void) { - static int first_time = 1; + static int first_time = TRUE; struct inode *root; if (first_time) { @@ -57,7 +57,9 @@ init_hook(void) construct_tree(root, root_files); - first_time = 0; + service_init(); + + first_time = FALSE; } } diff --git a/minix/fs/procfs/proto.h b/minix/fs/procfs/proto.h index 3d6eb9a14..c9dcde0f5 100644 --- a/minix/fs/procfs/proto.h +++ b/minix/fs/procfs/proto.h @@ -10,6 +10,12 @@ ssize_t buf_result(void); /* cpuinfo.c */ void root_cpuinfo(void); +/* service.c */ +void service_init(void); +void service_lookup(struct inode *parent, clock_t now); +void service_getdents(struct inode *node); +void service_read(struct inode *node); + /* tree.c */ int init_tree(void); int lookup_hook(struct inode *parent, char *name, cbdata_t cbdata); @@ -17,6 +23,7 @@ int getdents_hook(struct inode *inode, cbdata_t cbdata); ssize_t read_hook(struct inode *inode, char *ptr, size_t len, off_t off, cbdata_t cbdata); int rdlink_hook(struct inode *inode, char *ptr, size_t max, cbdata_t cbdata); +void out_of_inodes(void); /* util.c */ int procfs_getloadavg(struct load *loadavg, int nelem); diff --git a/minix/fs/procfs/service.c b/minix/fs/procfs/service.c new file mode 100644 index 000000000..2982b10db --- /dev/null +++ b/minix/fs/procfs/service.c @@ -0,0 +1,145 @@ +/* ProcFS - service.c - the service subdirectory */ + +#include "inc.h" + +#include +#include "rs/const.h" +#include "rs/type.h" + +static struct rprocpub rprocpub[NR_SYS_PROCS]; +static struct rproc rproc[NR_SYS_PROCS]; + +static struct inode *service_node; + +/* + * Initialize the service directory. + */ +void +service_init(void) +{ + struct inode *root, *node; + struct inode_stat stat; + + root = get_root_inode(); + + memset(&stat, 0, sizeof(stat)); + stat.mode = DIR_ALL_MODE; + stat.uid = SUPER_USER; + stat.gid = SUPER_USER; + + service_node = add_inode(root, "service", NO_INDEX, &stat, + NR_SYS_PROCS, NULL); + + if (service_node == NULL) + panic("unable to create service node"); +} + +/* + * Update the contents of the service directory, by first updating the RS + * tables and then updating the directory contents. + */ +void +service_update(void) +{ + struct inode *node; + struct inode_stat stat; + index_t slot; + + /* There is not much we can do if either of these calls fails. */ + (void)getsysinfo(RS_PROC_NR, SI_PROCPUB_TAB, rprocpub, + sizeof(rprocpub)); + (void)getsysinfo(RS_PROC_NR, SI_PROC_TAB, rproc, sizeof(rproc)); + + /* + * As with PIDs, we make two passes. Delete first, then add. This + * prevents problems in the hypothetical case that between updates, one + * slot ends up with the label name of a previous, different slot. + */ + for (slot = 0; slot < NR_SYS_PROCS; slot++) { + if ((node = get_inode_by_index(service_node, slot)) == NULL) + continue; + + /* + * If the slot is no longer in use, or the label name does not + * match, the node must be deleted. + */ + if (!(rproc[slot].r_flags & RS_IN_USE) || + strcmp(get_inode_name(node), rprocpub[slot].label)) + delete_inode(node); + } + + memset(&stat, 0, sizeof(stat)); + stat.mode = REG_ALL_MODE; + stat.uid = SUPER_USER; + stat.gid = SUPER_USER; + + for (slot = 0; slot < NR_SYS_PROCS; slot++) { + if (!(rproc[slot].r_flags & RS_IN_USE) || + get_inode_by_index(service_node, slot) != NULL) + continue; + + node = add_inode(service_node, rprocpub[slot].label, slot, + &stat, (index_t)0, (cbdata_t)slot); + + if (node == NULL) + out_of_inodes(); + } +} + +/* + * A lookup request is being performed. If it is in the service directory, + * update the tables. We do this lazily, to reduce overhead. + */ +void +service_lookup(struct inode * parent, clock_t now) +{ + static clock_t last_update = 0; + + if (parent != service_node) + return; + + if (last_update != now) { + service_update(); + + last_update = now; + } +} + +/* + * A getdents request is being performed. If it is in the service directory, + * update the tables. + */ +void +service_getdents(struct inode * node) +{ + + if (node != service_node) + return; + + service_update(); +} + +/* + * A read request is being performed. If it is on a file in the service + * directory, process the read request. We rely on the fact that any read + * call will have been preceded by a lookup, so its table entry has been + * updated very recently. + */ +void +service_read(struct inode * node) +{ + struct inode *parent; + index_t slot; + struct rprocpub *rpub; + struct rproc *rp; + + if (get_parent_inode(node) != service_node) + return; + + slot = get_inode_index(node); + rpub = &rprocpub[slot]; + rp = &rproc[slot]; + + /* TODO: add a large number of other fields! */ + buf_printf("%d %d\n", rpub->endpoint, rp->r_restarts); +} diff --git a/minix/fs/procfs/tree.c b/minix/fs/procfs/tree.c index db3387f68..cb977d328 100644 --- a/minix/fs/procfs/tree.c +++ b/minix/fs/procfs/tree.c @@ -185,7 +185,7 @@ init_tree(void) * If the NR_INODES value is not below the *crucial* minimum, the symptom of * this case will be an incomplete listing of the main proc directory. */ -static void +void out_of_inodes(void) { static int warned = FALSE; @@ -454,6 +454,9 @@ lookup_hook(struct inode * parent, char * name, cbdata_t __unused cbdata) * construct_pid_entries() will take care of this case. */ construct_pid_entries(parent, name); + else + /* TODO: skip updating the main tables in this case. */ + service_lookup(parent, now); return OK; } @@ -473,6 +476,8 @@ getdents_hook(struct inode * node, cbdata_t __unused cbdata) construct_pid_dirs(); } else if (dir_is_pid(node)) construct_pid_entries(node, NULL /*name*/); + else + service_getdents(node); return OK; } @@ -485,13 +490,20 @@ ssize_t read_hook(struct inode * node, char * ptr, size_t len, off_t off, cbdata_t cbdata) { + struct inode *parent; buf_init(ptr, len, off); /* Populate the buffer with the proper content. */ - if (get_inode_index(node) != NO_INDEX) - pid_read(node); - else + if (get_inode_index(node) != NO_INDEX) { + parent = get_parent_inode(node); + + /* The PID directories are indexed; service/ is not. */ + if (get_inode_index(parent) != NO_INDEX) + pid_read(node); + else + service_read(node); + } else ((void (*)(void))cbdata)(); return buf_result(); diff --git a/minix/fs/procfs/type.h b/minix/fs/procfs/type.h index 3ae5fe329..a2782d49d 100644 --- a/minix/fs/procfs/type.h +++ b/minix/fs/procfs/type.h @@ -10,12 +10,18 @@ struct load { /* * ProcFS supports two groups of files: dynamic files, which are created within - * process-specific (PID) directories, and static files, which are global. For - * both, the following structure is used to construct the files. + * process-specific (PID) directories and the service directory, and static + * files, which are global. For both, the following structure is used to + * construct the files. * - * For dynamic files, the rules are simple: only regular files are supported - * (although partial support for symbolic links is already present), and the - * 'data' field must be filled with a pointer to a function of the type: + * For dynamic service files, no indirection infrastructure is present. Each + * service gets one flat file, named after its label, and generating the + * contents of this flat file is all handled within the service module. They + * are not relevant to the rest of this comment. + * + * For dynamic PID files, the rules are simple: only regular files are + * supported (although partial support for symbolic links is already present), + * and the 'data' field must be filled with a pointer to a function of type: * * void (*)(int slot) * @@ -51,7 +57,7 @@ struct load { * of the process associated with that dynamic directory, for the purpose of * comparing old and new PIDs after updating process tables (without having * to atoi() the directory's name). - * - Dynamic files are always in such a dynamic directory. Their index is the + * - Dynamic files in a dynamic directory are PID files. Their index is the * array index into the "struct file" array of pid files (pid_files[]). They * are indexed at all because they may be deleted at any time due to inode * shortages, independently of other dynamic files in the same directory. @@ -59,11 +65,14 @@ struct load { * getdents() results, where for example the same file shows up twice. * VTreeFS currently does not distinguish between indexed and deletable files * and hence, all dynamic files must be indexed so as to be deletable anyway. + * - Dynamic files in a static directory are currently always service files. + * Their index is the slot number in process tables, for the same reasons as + * above. They have no meaningful cbdata value. * - Static directories have no index (they are not and must not be deletable), * and although their cbdata is their associated 'data' field from their * "struct file" entries, their cbdata value is currently not relied on * anywhere. Then again, as of writing, there are no static directories at - * all. + * all, except the service directory, which is an exception case. * - Static files have no index either (for the same reason). Their cbdata is * also their 'data' field from the "struct file" entry creating the file, * and this is used to actually call the callback function directly.