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
This commit is contained in:
David van Moolenbroek 2014-11-10 14:54:06 +00:00
parent f1abbce725
commit 31b6611abf
6 changed files with 189 additions and 14 deletions

View file

@ -2,7 +2,7 @@
.include <bsd.own.mk> .include <bsd.own.mk>
PROG= procfs 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
CPPFLAGS+= -I${NETBSDSRCDIR}/minix/fs CPPFLAGS+= -I${NETBSDSRCDIR}/minix/fs

View file

@ -49,7 +49,7 @@ construct_tree(struct inode * dir, struct file * files)
static void static void
init_hook(void) init_hook(void)
{ {
static int first_time = 1; static int first_time = TRUE;
struct inode *root; struct inode *root;
if (first_time) { if (first_time) {
@ -57,7 +57,9 @@ init_hook(void)
construct_tree(root, root_files); construct_tree(root, root_files);
first_time = 0; service_init();
first_time = FALSE;
} }
} }

View file

@ -10,6 +10,12 @@ ssize_t buf_result(void);
/* cpuinfo.c */ /* cpuinfo.c */
void root_cpuinfo(void); 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 */ /* tree.c */
int init_tree(void); int init_tree(void);
int lookup_hook(struct inode *parent, char *name, cbdata_t cbdata); 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, ssize_t read_hook(struct inode *inode, char *ptr, size_t len, off_t off,
cbdata_t cbdata); cbdata_t cbdata);
int rdlink_hook(struct inode *inode, char *ptr, size_t max, cbdata_t cbdata); int rdlink_hook(struct inode *inode, char *ptr, size_t max, cbdata_t cbdata);
void out_of_inodes(void);
/* util.c */ /* util.c */
int procfs_getloadavg(struct load *loadavg, int nelem); int procfs_getloadavg(struct load *loadavg, int nelem);

145
minix/fs/procfs/service.c Normal file
View file

@ -0,0 +1,145 @@
/* 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);
}

View file

@ -185,7 +185,7 @@ init_tree(void)
* If the NR_INODES value is not below the *crucial* minimum, the symptom of * 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. * this case will be an incomplete listing of the main proc directory.
*/ */
static void void
out_of_inodes(void) out_of_inodes(void)
{ {
static int warned = FALSE; 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() will take care of this case.
*/ */
construct_pid_entries(parent, name); construct_pid_entries(parent, name);
else
/* TODO: skip updating the main tables in this case. */
service_lookup(parent, now);
return OK; return OK;
} }
@ -473,6 +476,8 @@ getdents_hook(struct inode * node, cbdata_t __unused cbdata)
construct_pid_dirs(); construct_pid_dirs();
} else if (dir_is_pid(node)) } else if (dir_is_pid(node))
construct_pid_entries(node, NULL /*name*/); construct_pid_entries(node, NULL /*name*/);
else
service_getdents(node);
return OK; return OK;
} }
@ -485,13 +490,20 @@ ssize_t
read_hook(struct inode * node, char * ptr, size_t len, off_t off, read_hook(struct inode * node, char * ptr, size_t len, off_t off,
cbdata_t cbdata) cbdata_t cbdata)
{ {
struct inode *parent;
buf_init(ptr, len, off); buf_init(ptr, len, off);
/* Populate the buffer with the proper content. */ /* Populate the buffer with the proper content. */
if (get_inode_index(node) != NO_INDEX) if (get_inode_index(node) != NO_INDEX) {
pid_read(node); parent = get_parent_inode(node);
else
/* 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)(); ((void (*)(void))cbdata)();
return buf_result(); return buf_result();

View file

@ -10,12 +10,18 @@ struct load {
/* /*
* ProcFS supports two groups of files: dynamic files, which are created within * ProcFS supports two groups of files: dynamic files, which are created within
* process-specific (PID) directories, and static files, which are global. For * process-specific (PID) directories and the service directory, and static
* both, the following structure is used to construct the files. * 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 * For dynamic service files, no indirection infrastructure is present. Each
* (although partial support for symbolic links is already present), and the * service gets one flat file, named after its label, and generating the
* 'data' field must be filled with a pointer to a function of the type: * 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) * void (*)(int slot)
* *
@ -51,7 +57,7 @@ struct load {
* of the process associated with that dynamic directory, for the purpose of * of the process associated with that dynamic directory, for the purpose of
* comparing old and new PIDs after updating process tables (without having * comparing old and new PIDs after updating process tables (without having
* to atoi() the directory's name). * 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 * 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 * 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. * 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. * getdents() results, where for example the same file shows up twice.
* VTreeFS currently does not distinguish between indexed and deletable files * VTreeFS currently does not distinguish between indexed and deletable files
* and hence, all dynamic files must be indexed so as to be deletable anyway. * 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), * - Static directories have no index (they are not and must not be deletable),
* and although their cbdata is their associated 'data' field from their * and although their cbdata is their associated 'data' field from their
* "struct file" entries, their cbdata value is currently not relied on * "struct file" entries, their cbdata value is currently not relied on
* anywhere. Then again, as of writing, there are no static directories at * 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 * - 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, * also their 'data' field from the "struct file" entry creating the file,
* and this is used to actually call the callback function directly. * and this is used to actually call the callback function directly.