Date: Tue, 6 Feb 2007 15:37:53 -0500 From: John Baldwin <jhb@freebsd.org> To: arch@freebsd.org Subject: Restoring crash dump ability for kvm_getswapinfo(3) Message-ID: <200702061537.54056.jhb@freebsd.org>
next in thread | raw e-mail | index | archive | help
The patch below fixes kvm_getswapinfo(3) (and thus pstat -T/pstat -s/swapinfo) on crash dumps. The one ugliness in it is that since 'struct swdevt' was moved into swap_pager.c, there is no longer a header that I can include to get it (used to be in vm/swap_pager.h) so I have a copy of the structure in kvm_getswapinfo.c. I'd prefer to move the structures back into vm/swap_pager.h. Index: kvm_getswapinfo.c =================================================================== RCS file: /usr/cvs/src/lib/libkvm/kvm_getswapinfo.c,v retrieving revision 1.26 diff -u -r1.26 kvm_getswapinfo.c --- kvm_getswapinfo.c 31 Jul 2004 18:49:53 -0000 1.26 +++ kvm_getswapinfo.c 6 Feb 2007 20:31:09 -0000 @@ -49,18 +49,59 @@ #include "kvm_private.h" -#define NL_SWAPBLIST 0 -#define NL_SWDEVT 1 -#define NL_NSWDEV 2 -#define NL_DMMAX 3 +/* Grrr, this is hidden in swap_pager.c now, how annoying. */ +typedef int32_t swblk_t; + +struct buf; +struct blist; + +struct swdevt; +typedef void sw_strategy_t(struct buf *bp, struct swdevt *sw); +typedef void sw_close_t(struct thread *td, struct swdevt *sw); + +struct swdevt { + int sw_flags; + int sw_nblks; + int sw_used; + dev_t sw_dev; + struct vnode *sw_vp; + void *sw_id; + swblk_t sw_first; + swblk_t sw_end; + struct blist *sw_blist; + TAILQ_ENTRY(swdevt) sw_list; + sw_strategy_t *sw_strategy; + sw_close_t *sw_close; +}; + +static struct nlist kvm_swap_nl[] = { + { "_swtailq" }, /* list of swap devices and sizes */ + { "_dmmax" }, /* maximum size of a swap block */ + { NULL } +}; + +#define NL_SWTAILQ 0 +#define NL_DMMAX 1 static int kvm_swap_nl_cached = 0; static int unswdev; /* number of found swap dev's */ static int dmmax; +static int kvm_getswapinfo_kvm(kvm_t *, struct kvm_swap *, int, int); static int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int); +static int nlist_init(kvm_t *); static int getsysctl(kvm_t *, char *, void *, size_t); +#define KREAD(kd, addr, obj) \ + (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) +#define KGET(idx, var) \ + KGET2(kvm_swap_nl[(idx)].n_value, var, kvm_swap_nl[(idx)].n_name) +#define KGET2(addr, var, msg) \ + if (KREAD(kd, (u_long)(addr), (var))) { \ + _kvm_err(kd, kd->program, "cannot read %s", msg); \ + return (-1); \ + } + #define GETSWDEVNAME(dev, str, flags) \ if (dev == NODEV) { \ strlcpy(str, "[NFS swap]", sizeof(str)); \ @@ -91,8 +132,50 @@ if (ISALIVE(kd)) { return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags); } else { - return -1; + return kvm_getswapinfo_kvm(kd, swap_ary, swap_max, flags); + } +} + +int +kvm_getswapinfo_kvm( + kvm_t *kd, + struct kvm_swap *swap_ary, + int swap_max, + int flags +) { + int i, ttl; + TAILQ_HEAD(, swdevt) swtailq; + struct swdevt *sp, swinfo; + struct kvm_swap tot; + + if (!nlist_init(kd)) + return (-1); + + bzero(&tot, sizeof(tot)); + KGET(NL_SWTAILQ, &swtailq); + sp = TAILQ_FIRST(&swtailq); + for (i = 0; sp != NULL; i++) { + KGET2(sp, &swinfo, "swinfo"); + ttl = swinfo.sw_nblks - dmmax; + if (i < swap_max - 1) { + bzero(&swap_ary[i], sizeof(swap_ary[i])); + swap_ary[i].ksw_total = ttl; + swap_ary[i].ksw_used = swinfo.sw_used; + swap_ary[i].ksw_flags = swinfo.sw_flags; + GETSWDEVNAME(swinfo.sw_dev, swap_ary[i].ksw_devname, + flags); + } + tot.ksw_total += ttl; + tot.ksw_used += swinfo.sw_used; + sp = TAILQ_NEXT(&swinfo, sw_list); } + + if (i >= swap_max) + i = swap_max - 1; + if (i >= 0) + swap_ary[i] = tot; + + return(i); } #define GETSYSCTL(kd, name, var) \ @@ -168,6 +251,36 @@ } static int +nlist_init(kvm_t *kd) +{ + TAILQ_HEAD(, swdevt) swtailq; + struct swdevt *sp, swinfo; + + if (kvm_swap_nl_cached) + return (1); + + if (kvm_nlist(kd, kvm_swap_nl) < 0) + return (0); + + /* Required entries */ + if (kvm_swap_nl[NL_SWTAILQ].n_value == 0) { + _kvm_err(kd, kd->program, "unable to find swtailq"); + return (0); + } + + if (kvm_swap_nl[NL_DMMAX].n_value == 0) { + _kvm_err(kd, kd->program, "unable to find dmmax"); + return (0); + } + + /* Get globals, type of swap */ + KGET(NL_DMMAX, &dmmax); + + kvm_swap_nl_cached = 1; + return (1); +} + +static int getsysctl ( kvm_t *kd, char *name, -- John Baldwin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200702061537.54056.jhb>