kern/159281: [PATCH] Linux-like /proc/swaps for linprocfs

Kostik Belousov kostikbel at gmail.com
Sat Jul 30 17:32:48 UTC 2011


On Sat, Jul 30, 2011 at 01:06:48AM +0200, Robert Millan wrote:
> Hi Kostik,
> 
> 2011/7/29 Kostik Belousov <kostikbel at gmail.com>:
> > The patch is too hackish, IMHO.
> > I would prefer to have an exported kernel function that fills xswdev
> > by index, used both by vm_swap_info and linprocfs.
> >
> > For the device name, you would use sw_vp->v_rdev->si_name, see, for
> > instance, the following fragment in the swapoff_all():
> >                if (vn_isdisk(sp->sw_vp, NULL))
> >                        devname = sp->sw_vp->v_rdev->si_name;
> >                else
> >                        devname = "[file]";
> > This could be another function that returns swap information by index.
> 
> Here's a patch with the changes you requested.
> 

There are several issues in the patch that I see, not counting minor
stylistic bugs.

First, the sw_dev_mtx should be kept until all the data is read from
the xs. The locking there is somewhat vague, the original code was probably
correct because sysctl handler is not marked mpsafe, and all functions
changing the swtailq hold Giant.

Second, my proposal contains a flaw. Namely, if some swap device was removed
between calls to swap_info and swap_devname calls, we get mangled list.

The third problem, which is not fixed, and which I do not want to handle,
is that the swap devices list can be changed between calls to swap_devname(),
changing device indexes and thus making the output mangled.

Should the swap device name be separated from 'unknown' word by
space or by tab ?

I updated your patch, hopefully fixing the issues. Do you have comments
or objections ?

diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index 692c5a3..0733913 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -502,6 +502,30 @@ linprocfs_dostat(PFS_FILL_ARGS)
 	return (0);
 }
 
+static int
+linprocfs_doswaps(PFS_FILL_ARGS)
+{
+	struct xswdev xsw;
+	int n;
+	long long total, used;
+	char devname[SPECNAMELEN + 1];
+
+	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
+
+	for (n = 0; ; n++) {
+		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
+			break;
+
+		total = (long long)xsw.xsw_nblks * PAGE_SIZE / 1024;
+		used  = (long long)xsw.xsw_used * PAGE_SIZE / 1024;
+
+		sbuf_printf(sb, "/dev/%-34s unknown\t\t%lld\t%lld\t-1\n",
+		    devname, total, used);
+	}
+
+	return (0);
+}
+
 /*
  * Filler function for proc/uptime
  */
@@ -1490,6 +1514,8 @@ linprocfs_init(PFS_INIT_ARGS)
 	    NULL, NULL, NULL, 0);
 	pfs_create_file(root, "stat", &linprocfs_dostat,
 	    NULL, NULL, NULL, PFS_RD);
+	pfs_create_file(root, "swaps", &linprocfs_doswaps,
+	    NULL, NULL, NULL, PFS_RD);
 	pfs_create_file(root, "uptime", &linprocfs_douptime,
 	    NULL, NULL, NULL, PFS_RD);
 	pfs_create_file(root, "version", &linprocfs_doversion,
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index f421e4f..5929871 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -2365,35 +2365,58 @@ swap_pager_status(int *total, int *used)
 	mtx_unlock(&sw_dev_mtx);
 }
 
-static int
-sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS)
+int
+swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len)
 {
-	int	*name = (int *)arg1;
-	int	error, n;
-	struct xswdev xs;
 	struct swdevt *sp;
-
-	if (arg2 != 1) /* name length */
-		return (EINVAL);
+	char *tmp_devname;
+	int error, n;
 
 	n = 0;
+	error = ENOENT;
 	mtx_lock(&sw_dev_mtx);
 	TAILQ_FOREACH(sp, &swtailq, sw_list) {
-		if (n == *name) {
-			mtx_unlock(&sw_dev_mtx);
-			xs.xsw_version = XSWDEV_VERSION;
-			xs.xsw_dev = sp->sw_dev;
-			xs.xsw_flags = sp->sw_flags;
-			xs.xsw_nblks = sp->sw_nblks;
-			xs.xsw_used = sp->sw_used;
-
-			error = SYSCTL_OUT(req, &xs, sizeof(xs));
-			return (error);
+		if (n != name) {
+			n++;
+			continue;
 		}
-		n++;
+
+		xs->xsw_version = XSWDEV_VERSION;
+		xs->xsw_dev = sp->sw_dev;
+		xs->xsw_flags = sp->sw_flags;
+		xs->xsw_nblks = sp->sw_nblks;
+		xs->xsw_used = sp->sw_used;
+		if (devname != NULL) {
+			if (vn_isdisk(sp->sw_vp, NULL)) {
+				tmp_devname =
+					sp->sw_vp->v_rdev->si_name;
+			} else
+				tmp_devname = "[file]";
+			strncpy(devname, tmp_devname, len);
+		}
+		error = 0;
+		break;
 	}
 	mtx_unlock(&sw_dev_mtx);
-	return (ENOENT);
+	return (error);
+}
+
+static int
+sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS)
+{
+	int	*name = (int *)arg1;
+	int	error;
+	struct xswdev xs;
+
+	if (arg2 != 1) /* name length */
+		return (EINVAL);
+
+	error = swap_dev_info(*name, &xs, NULL, 0);
+	if (error != 0)
+		return (error);
+
+	error = SYSCTL_OUT(req, &xs, sizeof(xs));
+	return (error);
 }
 
 SYSCTL_INT(_vm, OID_AUTO, nswapdev, CTLFLAG_RD, &nswapdev, 0,
diff --git a/sys/vm/swap_pager.h b/sys/vm/swap_pager.h
index c3366e8..d7b0f5e 100644
--- a/sys/vm/swap_pager.h
+++ b/sys/vm/swap_pager.h
@@ -76,6 +76,8 @@ extern int swap_pager_full;
 extern int swap_pager_avail;
 
 struct swdevt;
+struct xswdev;
+int swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len);
 void swap_pager_copy(vm_object_t, vm_object_t, vm_pindex_t, int);
 void swap_pager_freespace(vm_object_t, vm_pindex_t, vm_size_t);
 void swap_pager_swap_init(void);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-emulation/attachments/20110730/39b418fd/attachment.pgp


More information about the freebsd-emulation mailing list