.include <bsd.own.mk>
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
static void
init_hook(void)
{
- static int first_time = 1;
+ static int first_time = TRUE;
struct inode *root;
if (first_time) {
construct_tree(root, root_files);
- first_time = 0;
+ service_init();
+
+ first_time = FALSE;
}
}
/* 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);
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);
--- /dev/null
+/* ProcFS - service.c - the service subdirectory */
+
+#include "inc.h"
+
+#include <minix/rs.h>
+#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);
+}
* 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;
* 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;
}
construct_pid_dirs();
} else if (dir_is_pid(node))
construct_pid_entries(node, NULL /*name*/);
+ else
+ service_getdents(node);
return OK;
}
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();
/*
* 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)
*
* 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.
* 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.