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

Kostik Belousov kostikbel at gmail.com
Sun Jul 31 19:30:26 UTC 2011


On Sun, Jul 31, 2011 at 06:56:51PM +0200, Robert Millan wrote:
> 2011/7/30 Kostik Belousov <kostikbel at gmail.com>:
> > 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.
> 
> Ok, I see that you fixed this by unifying those functions.
Rather, by gathering both pieces of information without dropping the
protection of sw_dev_mtx.

> 
> > 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.
> 
> You say you don't want to handle this, but AFAICT from the patch you
> already did.  Or did I miss something?
Since sw_dev_mtx is dropped and reacquired between each iteration of the
loop, some swap device may be removed meantime. At least, the output
will show the same device twice.

Hm, the swapoff/swapon routines are half-protected by the Giant, taking
the Giant around the loop prevents the swap device list changes.
> 
> > Should the swap device name be separated from 'unknown' word by
> > space or by tab ?
> 
> Linux' /proc/swaps prints spaces after the first column and tabs for
> the rest.  I think it's better to do the same just in case, but I
> don't think it's relevant either way.
Right, I added a comment to not have this broken by somebody in future.

> 
> > I updated your patch, hopefully fixing the issues. Do you have comments
> > or objections ?
> 
> No.  Thanks for fixing those problems.

Below is the hopefully final patch after Bruce Evans' comments incorporated.
If nobody speaks, I will send this to re tomorrow.

diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index 692c5a3..8832d3d 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -502,6 +502,33 @@ linprocfs_dostat(PFS_FILL_ARGS)
 	return (0);
 }
 
+static int
+linprocfs_doswaps(PFS_FILL_ARGS)
+{
+	struct xswdev xsw;
+	uintmax_t total, used;
+	int n;
+	char devname[SPECNAMELEN + 1];
+
+	sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
+	mtx_lock(&Giant);
+	for (n = 0; ; n++) {
+		if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
+			break;
+		total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
+		used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
+
+		/*
+		 * The space and not tab after the device name is on
+		 * purpose.  Linux does so.
+		 */
+		sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
+		    devname, total, used);
+	}
+	mtx_unlock(&Giant);
+	return (0);
+}
+
 /*
  * Filler function for proc/uptime
  */
@@ -1490,6 +1517,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..9a818e7 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -2365,35 +2365,53 @@ 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;
+		}
+		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);
 		}
-		n++;
+		error = 0;
+		break;
 	}
 	mtx_unlock(&sw_dev_mtx);
-	return (ENOENT);
+	return (error);
+}
+
+static int
+sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS)
+{
+	struct xswdev xs;
+	int error;
+
+	if (arg2 != 1)			/* name length */
+		return (EINVAL);
+	error = swap_dev_info(*(int *)arg1, &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..5c716d9 100644
--- a/sys/vm/swap_pager.h
+++ b/sys/vm/swap_pager.h
@@ -75,7 +75,8 @@ struct swdevt {
 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/20110731/2e1c9fec/attachment.pgp


More information about the freebsd-emulation mailing list