Skip site navigation (1)Skip section navigation (2)
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>