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>
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

View file

@ -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;
}
}

View file

@ -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);

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
* 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();

View file

@ -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.