kernel - Implement vm.swap_info_array sysctl
authorMatthew Dillon <dillon@apollo.backplane.com>
Wed, 18 Aug 2010 00:43:02 +0000 (17:43 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 18 Aug 2010 00:43:02 +0000 (17:43 -0700)
* Track swap usage on a per-device basis

* Implement the vm.swap_info_array sysctl to retrieve the array.

sys/sys/conf.h
sys/vm/swap_pager.c
sys/vm/swap_pager.h
sys/vm/vm_param.h
sys/vm/vm_swap.c

index d690433..2571221 100644 (file)
@@ -178,10 +178,12 @@ void ldisc_deregister (int);
 struct swdevt {
        udev_t  sw_dev;                 /* For quasibogus swapdev reporting */
        int     sw_flags;
-       int     sw_nblks;
+       int     sw_nblks;               /* Number of swap blocks on device */
+       int     sw_nused;               /* swap blocks used on device */
        struct  vnode *sw_vp;
        struct cdev *sw_device;
 };
+
 #define        SW_FREED        0x01
 #define        SW_SEQUENTIAL   0x02
 #define        sw_freed        sw_flags        /* XXX compat */
index fa5004c..dad5e4d 100644 (file)
@@ -490,7 +490,7 @@ swp_pager_getswapspace(vm_object_t object, int npages)
                        swap_pager_almost_full = 1;
                }
        } else {
-               vm_swap_size -= npages;
+               swapacctspace(blk, -npages);
                if (object->type == OBJT_SWAP)
                        vm_swap_anon_use += npages;
                else
@@ -519,7 +519,7 @@ static __inline void
 swp_pager_freeswapspace(vm_object_t object, swblk_t blk, int npages)
 {
        blist_free(swapblist, blk, npages);
-       vm_swap_size += npages;
+       swapacctspace(blk, npages);
        if (object->type == OBJT_SWAP)
                vm_swap_anon_use -= npages;
        else
index ab28cd0..a5543dc 100644 (file)
@@ -109,6 +109,8 @@ void swap_pager_swap_init (void);
 void swap_pager_newswap (void);
 int swap_pager_reserve (vm_object_t, vm_pindex_t, vm_size_t);
 
+void swapacctspace(swblk_t base, swblk_t count);
+
 /*
  * newswap functions
  */
index ce0ee0d..e5cbddc 100644 (file)
 }
 
 /*
+ * Structure for swap device statistics
+ */
+#define XSWDEV_VERSION  1
+
+struct xswdev {
+       size_t  xsw_size;
+       int     xsw_version;
+       int     xsw_flags;
+       dev_t   xsw_dev;
+       size_t  xsw_blksize;
+       size_t  xsw_nblks;
+       size_t  xsw_used;
+};
+
+/*
  *     Return values from the VM routines.
  */
 #define        KERN_SUCCESS            0
index 6e3c532..e666098 100644 (file)
@@ -46,6 +46,7 @@
 #include <sys/proc.h>
 #include <sys/priv.h>
 #include <sys/nlookup.h>
+#include <sys/sysctl.h>
 #include <sys/dmap.h>          /* XXX */
 #include <sys/vnode.h>
 #include <sys/fcntl.h>
@@ -59,6 +60,7 @@
 #include <vm/vm_extern.h>
 #include <vm/swap_pager.h>
 #include <vm/vm_zone.h>
+#include <vm/vm_param.h>
 
 #include <sys/thread2.h>
 #include <sys/mplock2.h>
@@ -338,7 +340,7 @@ swaponvp(struct thread *td, struct vnode *vp, u_quad_t nblks)
        sp->sw_dev = dev2udev(dev);
        sp->sw_device = dev;
        sp->sw_flags |= SW_FREED;
-       sp->sw_nblks = (swblk_t)nblks;
+       sp->sw_nused = 0;
 
        /*
         * nblks, nswap, and dmmax are PAGE_SIZE'd parameters now, not
@@ -346,6 +348,7 @@ swaponvp(struct thread *td, struct vnode *vp, u_quad_t nblks)
         * size of the swap bitmap, taking into account the stripe size.
         */
        aligned_nblks = (swblk_t)((nblks + (dmmax - 1)) & ~(u_long)(dmmax - 1));
+       sp->sw_nblks = aligned_nblks;
 
        if (aligned_nblks * nswdev > nswap)
                nswap = aligned_nblks * nswdev;
@@ -355,8 +358,8 @@ swaponvp(struct thread *td, struct vnode *vp, u_quad_t nblks)
        else
                blist_resize(&swapblist, nswap, 0);
 
-       for (dvbase = dmmax; dvbase < nblks; dvbase += dmmax) {
-               blk = min(nblks - dvbase, dmmax);
+       for (dvbase = dmmax; dvbase < aligned_nblks; dvbase += dmmax) {
+               blk = min(aligned_nblks - dvbase, dmmax);
                vsbase = index * dmmax + dvbase * nswdev;
                blist_free(swapblist, vsbase, blk);
                vm_swap_size += blk;
@@ -367,3 +370,57 @@ swaponvp(struct thread *td, struct vnode *vp, u_quad_t nblks)
        mtx_unlock(&swap_mtx);
        return (0);
 }
+
+/*
+ * Account for swap space in individual swdevt's.  The caller ensures
+ * that the provided range falls into a single swdevt.
+ *
+ * +count      space freed
+ * -count      space allocated
+ */
+void
+swapacctspace(swblk_t base, swblk_t count)
+{
+       int index;
+       int seg;
+
+       vm_swap_size += count;
+       seg = base / dmmax;
+       index = seg % nswdev;
+       swdevt[index].sw_nused -= count;
+}
+
+/*
+ * Retrieve swap info
+ */
+static int
+sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS)
+{
+       struct xswdev xs;
+       struct swdevt *sp;
+       int     error;
+       int     n;
+
+       error = 0;
+       for (n = 0; n < nswdev; ++n) {
+               sp = &swdevt[n];
+
+               xs.xsw_size = sizeof(xs);
+               xs.xsw_version = XSWDEV_VERSION;
+               xs.xsw_blksize = PAGE_SIZE;
+               xs.xsw_dev = sp->sw_dev;
+               xs.xsw_flags = sp->sw_flags;
+               xs.xsw_nblks = sp->sw_nblks;
+               xs.xsw_used = sp->sw_nused;
+
+               error = SYSCTL_OUT(req, &xs, sizeof(xs));
+               if (error)
+                       break;
+       }
+       return (error);
+}
+
+SYSCTL_INT(_vm, OID_AUTO, nswapdev, CTLFLAG_RD, &nswdev, 0,
+          "Number of swap devices");
+SYSCTL_NODE(_vm, OID_AUTO, swap_info_array, CTLFLAG_RD, sysctl_vm_swap_info,
+           "Swap statistics by device");