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.