Date: Thu, 31 Oct 2013 06:36:42 +0000 (UTC) From: Gleb Smirnoff <glebius@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r257425 - in user/glebius/course/practical: . 01.readstat Message-ID: <201310310636.r9V6agJ2056745@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 :(
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310310636.r9V6agJ2056745>