Subject: Re: UVM patch: sys_swapctl split
To: enami tsugutomo <enami@sm.sony.co.jp>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 03/18/2002 09:16:31
> Does old 1.3 binary prepare `sizeof(struct swapent) * misc' bytes
> space?  I guess you should copyout up to the length just
> uvm_swap_stats() copied.

True, here is a hopefully last patch that will fix this.
I can't test a 1.3 swapctl binary: 1.3 did not exist on sgimips.

Index: uvm_swap.c
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_swap.c,v
retrieving revision 1.60
diff -U2 -r1.60 uvm_swap.c
--- uvm_swap.c  2002/03/09 07:28:20     1.60
+++ uvm_swap.c  2002/03/18 08:14:23
@@ -457,5 +457,5 @@
        char    userpath[PATH_MAX + 1];
        size_t  len;
-       int     count, error, misc;
+       int     error, misc;
        int     priority;
        UVMHIST_FUNC("sys_swapctl"); UVMHIST_CALLED(pdhist);
@@ -495,51 +495,17 @@
 #endif
            ) {
-               sep = (struct swapent *)SCARG(uap, arg);
-               count = 0;
+               misc = MIN(uvmexp.nswapdev, misc);
+               len = sizeof(struct swapent) * misc;
+               sep = (struct swapent *)malloc(len, M_TEMP, M_WAITOK);
 
-               LIST_FOREACH(spp, &swap_priority, spi_swappri) {
-                       for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev);
-                            sdp != (void *)&spp->spi_swapdev && misc-- > 0;
-                            sdp = CIRCLEQ_NEXT(sdp, swd_next)) {
-                               /*
-                                * backwards compatibility for system call.
-                                * note that we use 'struct oswapent' as an
-                                * overlay into both 'struct swapdev' and
-                                * the userland 'struct swapent', as we
-                                * want to retain backwards compatibility
-                                * with NetBSD 1.3.
-                                */
-                               sdp->swd_ose.ose_inuse =
-                                   btodb((u_int64_t)sdp->swd_npginuse <<
-                                   PAGE_SHIFT);
-                               error = copyout(&sdp->swd_ose, sep,
-                                               sizeof(struct oswapent));
-
-                               /* now copy out the path if necessary */
-#if defined(COMPAT_13)
-                               if (error == 0 && SCARG(uap, cmd) == SWAP_STATS)
-#else
-                               if (error == 0)
-#endif
-                                       error = copyout(sdp->swd_path,
-                                           &sep->se_path, sdp->swd_pathlen);
-
-                               if (error)
-                                       goto out;
-                               count++;
+               uvm_swap_stats(SCARG(uap, cmd), sep, misc, retval);
 #if defined(COMPAT_13)
-                               if (SCARG(uap, cmd) == SWAP_OSTATS)
-                                       sep = (struct swapent *)
-                                           ((struct oswapent *)sep + 1);
-                               else
+               if (SCARG(uap, cmd) == SWAP_OSTATS)
+                       len = sizeof(struct oswapent) * misc;
 #endif
-                                       sep++;
-                       }
-               }
+               error = copyout(sep, (void *)SCARG(uap, arg), len);
 
+               free(sep, M_TEMP);
                UVMHIST_LOG(pdhist, "<- done SWAP_STATS", 0, 0, 0, 0);
-
-               *retval = count;
-               error = 0;
                goto out;
        }
@@ -716,4 +682,64 @@
        UVMHIST_LOG(pdhist, "<- done!  error=%d", error, 0, 0, 0);
        return (error);
+}
+
+/* 
+ * swap_stats: implements swapctl(SWAP_STATS). The function is kept
+ * away from sys_swapctl() in order to allow COMPAT_* swapctl() 
+ * emulation to use it directly without going through sys_swapctl().
+ * The problem with using sys_swapctl() there is that it involves
+ * copying the swapent array to the stackgap, and this array's size
+ * is not known at build time. Hence it would not be possible to 
+ * ensure it would fit in the stackgap in any wase.
+ */
+void
+uvm_swap_stats(cmd, sep, sec, retval)
+       int cmd;
+       struct swapent *sep;
+       int sec;
+       register_t *retval;
+{
+       struct swappri *spp;
+       struct swapdev *sdp;
+       int count = 0;
+
+       LIST_FOREACH(spp, &swap_priority, spi_swappri) {
+               for (sdp = CIRCLEQ_FIRST(&spp->spi_swapdev);
+                    sdp != (void *)&spp->spi_swapdev && sec-- > 0;
+                    sdp = CIRCLEQ_NEXT(sdp, swd_next)) {
+                       /*
+                        * backwards compatibility for system call.
+                        * note that we use 'struct oswapent' as an
+                        * overlay into both 'struct swapdev' and
+                        * the userland 'struct swapent', as we
+                        * want to retain backwards compatibility
+                        * with NetBSD 1.3.
+                        */
+                       sdp->swd_ose.ose_inuse =
+                           btodb((u_int64_t)sdp->swd_npginuse <<
+                           PAGE_SHIFT);
+                       (void)memcpy(sep, &sdp->swd_ose, 
+                           sizeof(struct oswapent));
+                       
+                       /* now copy out the path if necessary */
+#if defined(COMPAT_13)
+                       if (SCARG(uap, cmd) == SWAP_STATS)
+#endif
+                               (void)memcpy(&sep->se_path, sdp->swd_path,
+                                   sdp->swd_pathlen);
+
+                       count++;
+#if defined(COMPAT_13)
+                       if (SCARG(uap, cmd) == SWAP_OSTATS)
+                               sep = (struct swapent *)
+                                   ((struct oswapent *)sep + 1);
+                       else
+#endif
+                               sep++;
+               }
+       }
+
+       *retval = count;
+       return;
 }
 
Index: uvm_swap.h
===================================================================
RCS file: /cvsroot/syssrc/sys/uvm/uvm_swap.h,v
retrieving revision 1.5
diff -U2 -r1.5 uvm_swap.h
--- uvm_swap.h  2000/01/11 06:57:51     1.5
+++ uvm_swap.h  2002/03/18 08:14:23
@@ -38,4 +38,6 @@
 #ifdef _KERNEL
 
+struct swapent;
+
 int                    uvm_swap_get __P((struct vm_page *, int, int));
 int                    uvm_swap_put __P((int, struct vm_page **, int, int));
@@ -43,4 +45,6 @@
 void                   uvm_swap_free __P((int, int));
 void                   uvm_swap_markbad __P((int, int));
+void                   uvm_swap_stats __P((int, struct swapent *,
+                           int, register_t *));
 
 #endif /* _KERNEL */
-- 
Emmanuel Dreyfus
manu@netbsd.org