svn commit: r257425 - in user/glebius/course/practical: . 01.readstat

Gleb Smirnoff glebius at FreeBSD.org
Thu Oct 31 06:36:43 UTC 2013


Author: glebius
Date: Thu Oct 31 06:36:41 2013
New Revision: 257425
URL: http://svnweb.freebsd.org/changeset/base/257425

Log:
  Results of first practical session.

Added:
  user/glebius/course/practical/
  user/glebius/course/practical/01.readstat/
  user/glebius/course/practical/01.readstat/Makefile   (contents, props changed)
  user/glebius/course/practical/01.readstat/README
  user/glebius/course/practical/01.readstat/readstat1.c   (contents, props changed)
  user/glebius/course/practical/README

Added: user/glebius/course/practical/01.readstat/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/glebius/course/practical/01.readstat/Makefile	Thu Oct 31 06:36:41 2013	(r257425)
@@ -0,0 +1,4 @@
+KMOD=readstat
+SRCS=readstat.c
+
+.include <bsd.kmod.mk>

Added: user/glebius/course/practical/01.readstat/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/glebius/course/practical/01.readstat/README	Thu Oct 31 06:36:41 2013	(r257425)
@@ -0,0 +1,69 @@
+"readstat" does the following:
+
+1) Intercepts an important syscall. We used read(2) and this seems fine,
+   but we can use any widely used syscall.
+2) Accumulates statistics on which processes called the syscall and
+   with which arguments.
+
+The readstat1.c is the state that can be achieved during one academical
+hour (experimentally proved!).
+
+We start coding together with students, starting with 01.intro/module/module.c,
+and step by step enhance the code, discussing every step. For future lecturers
+I'd suggest to do the same and do not use my readstat1.c as reference,
+otherwise you can just type everything in too fast and not clear to students.
+
+Coding readstat1.c requires that students are familiar with the following:
+
+module(9)
+sysent vector (lection 02.entering_kernel)
+struct td, struct proc (lection 03.processes&threads)
+queue(3)
+tree(3)
+mutex(9)
+malloc(9)
+
+(1) Start with 01.intro/module/module.c, and make it simply intercept syscall.
+    At this step chances that students can code theirselves is pretty low, so
+    you have to do it yourself. You have to explain where did you get all the
+    symbol names and constants. Open kern/init_sysent.c, sys/sysproto.h, etc.
+    Run kgdb before and after module is loaded.
+    (kgdb) p sysent[3]
+
+(2) Include <tree.h> and initialize RB tree.
+
+(3) Discuss reentrability of syscall and whether the tree should be protected.
+    Now it is probably time to pass access to file to a student and watch(8)
+    her or him. Add static mutex, initialize/destroy it in module evhand.
+
+(4) Ask students on how can we obtain process name in interceptor. Let them
+    dictate you, or code theirselves. Ask/explain:
+    - Do we need any locking to read process name?
+    - Why do we strcpy() the name and not point to it from struct node?
+    - How do we use a libc function here?
+
+(4) Code RB find/insertion in the interceptor. We started with
+
+	if (RB_FIND) {
+
+	} else {
+		RB_INSERT()
+	}
+
+    But thanks to students who have read tree(3) quickly, we ended with
+    a more optimal code.
+
+(5) Now we do insert entries into tree and come to malloc(). Let's do not
+    initialize LIST(3) in nodes, just gather process names.
+    Ask/explain:
+    - Which wait flag to use with malloc() and why?
+    - Is there any ways to make interceptor more robust and not use M_NOWAIT.
+
+(6) Compile and run it.
+    (kgdb) p readstat
+    ... further kgdb investigation of tree ...
+
+(7) Initialize mutex and LIST in entry. Code interlocking between the tree lock
+    and a node lock. Gather stats.
+
+(8) Compile and run it. Traverse tree in kgdb.

Added: user/glebius/course/practical/01.readstat/readstat1.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/glebius/course/practical/01.readstat/readstat1.c	Thu Oct 31 06:36:41 2013	(r257425)
@@ -0,0 +1,115 @@
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/tree.h>
+
+#include <vm/uma.h>
+
+static struct mtx tree_mtx;
+static int (*original_read)(struct thread *, void *);
+
+struct elm {
+	LIST_ENTRY(elm) entry;
+	size_t size;
+	u_int count;
+};
+
+struct node {
+	RB_ENTRY(node) tree;
+	LIST_HEAD(,elm) elms;
+	struct mtx list_mtx;
+	char name[MAXCOMLEN+1];
+};
+
+static int
+node_compare(struct node *a, struct node *b)
+{
+
+	return (strcmp(a->name, b->name));
+}
+
+static RB_HEAD(head, node) readstat = RB_INITIALIZER(&readstat);
+static RB_PROTOTYPE(head, node, tree, node_compare);
+static RB_GENERATE(head, node, tree, node_compare);
+
+static MALLOC_DEFINE(M_LEAF, "rsnode", "read stat node");
+static MALLOC_DEFINE(M_ELM, "rselm", "read stat element");
+
+static int
+stat_read(struct thread *td, void *v)
+{
+	struct read_args *uap = (struct read_args *)v;
+	struct node *key, *node;
+	struct elm *elm, *elm0;
+
+	key = malloc(sizeof(*node), M_LEAF, M_WAITOK | M_ZERO);
+	mtx_init(&key->list_mtx, "list lock", NULL, MTX_DEF);
+	LIST_INIT(&key->elms);
+
+	elm0 = malloc(sizeof(*elm), M_ELM, M_WAITOK | M_ZERO);
+
+	strcpy(key->name, td->td_proc->p_comm);
+
+	mtx_lock(&tree_mtx);
+	node = RB_INSERT(head, &readstat, key);
+	if (node == NULL)
+		node = key;
+	mtx_lock(&node->list_mtx);
+	mtx_unlock(&tree_mtx);
+
+	if (node != key) {
+		mtx_destroy(&key->list_mtx);
+		free(key, M_LEAF);
+	}
+
+	LIST_FOREACH(elm, &node->elms, entry)
+		if (uap->nbyte == elm->size)
+			break;
+	if (elm == NULL) {
+		elm = elm0;
+		LIST_INSERT_HEAD(&node->elms, elm, entry);
+		elm->size = uap->nbyte;
+	} else
+		free(elm0, M_ELM);
+
+	elm->count++;
+
+	mtx_unlock(&node->list_mtx);
+
+	return (original_read(td, v));
+}
+
+static int
+readstat_load(module_t mod, int what, void *arg)
+{
+
+	switch (what) {
+	case MOD_LOAD:
+		mtx_init(&tree_mtx, "tree lock", NULL, MTX_DEF);
+		original_read = sysent[SYS_read].sy_call;
+		sysent[SYS_read].sy_call = stat_read;
+		break;
+	case MOD_UNLOAD:
+		sysent[SYS_read].sy_call = original_read;
+		mtx_destroy(&tree_mtx);
+		break;
+	}
+
+	return (0);
+}
+
+static moduledata_t mod_data= {
+	.name = "readstat",
+	.evhand = readstat_load,
+};
+
+MODULE_VERSION(readstat, 1);
+DECLARE_MODULE(readstat, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);

Added: user/glebius/course/practical/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/glebius/course/practical/README	Thu Oct 31 06:36:41 2013	(r257425)
@@ -0,0 +1,25 @@
+/* This README and all in underlying directories are just glebius' braindumps
+   that some day can be reformatted to a better notes. */
+
+All practical sessions require a shell box shared between lecturer and
+students. I use dedicated FreeBSD-CURRENT instance under bhyve. All
+students are provided shell and superuser there. Students are encouraged
+to run things on their own boxes or VMs, but shared shellbox is always
+available.
+
+Problems(bhyve):
+- It is impossible to share kernel debugger console to students, it requires
+  root on host. So only lecturer can work once VM goes into ddb.
+- Sometimes when VM enters ddb, the bhyve process exits.
+
+During entire practical session the beamer displays my terminal. I use
+Xterm running fullscreen w/o any widgets and using
+x11-fonts/inconsolata-lgc-ttf font. I encourage students to do some steps
+theirselves, in these cases I use watch(8) on students' tty to intercept
+it and make viewable by everyone on beamer.
+
+Problems:
+- If watch(8) a terminal that is bigger than yours, you got a mess on
+  screen (and on beamer, too!).
+- Modules should be build with DEBUG_FLAGS=-g knob, so that any kgdb
+  session display their symbols. This secret knowledge isn't documented :(


More information about the svn-src-user mailing list