Subject: UVM patch: sys_swapctl split
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 03/17/2002 19:27:19
After the recent dicsussions on the stackgap problem with swapctl(SWAP_STATS)
emulation for IRIX, I come to the following patch. I've got a few questions at
the end...

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/17 18:21:32
@@ -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,11 @@
 #endif
            ) {
-               sep = (struct swapent *)SCARG(uap, arg);
-               count = 0;
+               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));
+               uvm_swap_stats(SCARG(uap, cmd), (void *)sep, misc, retval);
+               error = copyout(sep, (void *)SCARG(uap, arg), len);
+               free(sep, M_TEMP);
 
-                               /* 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++;
-#if defined(COMPAT_13)
-                               if (SCARG(uap, cmd) == SWAP_OSTATS)
-                                       sep = (struct swapent *)
-                                           ((struct oswapent *)sep + 1);
-                               else
-#endif
-                                       sep++;
-                       }
-               }
-
-               UVMHIST_LOG(pdhist, "<- done SWAP_STATS", 0, 0, 0, 0);
-
-               *retval = count;
-               error = 0;
                goto out;
        }
@@ -716,4 +676,65 @@
        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 case.
+ */
+void
+uvm_swap_stats(cmd, sep, sec, retval)
+       int cmd;
+       void *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(&((struct swapent *)sep)->se_path,
+                                   sdp->swd_path, sdp->swd_pathlen);
+
+                       count++;
+#if defined(COMPAT_13)
+                       if (SCARG(uap, cmd) == SWAP_OSTATS)
+                               sep = (void *)((struct oswapent *)sep + 1);
+                       else
+#endif
+                               ((struct swapent *)sep)++;
+               }
+       }
+
+       UVMHIST_LOG(pdhist, "<- done SWAP_STATS", 0, 0, 0, 0);
+
+       *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/17 18:21:33
@@ -43,4 +43,5 @@
 void                   uvm_swap_free __P((int, int));
 void                   uvm_swap_markbad __P((int, int));
+void                   uvm_swap_stats __P((int, void *, int, register_t *));
 
 #endif /* _KERNEL */

There is one problem I have not been able to address yet: I started with 
void uvm_swap_stats __P((int, struct swapent *, int, register_t *));
but this makes an error at build time:


cat ../../../../arch/mips/mips/genassym.cf  |  sh ../../../../kern/genassym.sh
cc  -EB -G 0 -mno-abicalls -mno-half-pic -ffreestanding -g -DDEBUG_IRIX -O2
-Werror -Wall -Wno-main -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes
-Wno-uninitialized  -Dsgimips -I.  -I../../../../arch -I../../../.. -nostdinc
-DMIPS3_ENABLE_CLOCK_INTR -DSCSI_DELAY="5" -DMIPS3 -DPARANOIADIAG -DDEBUG
-DDIAGNOSTIC -DMAXUSERS=32 -D_KERNEL -D_KERNEL_OPT   > assym.h.tmp &&  mv -f
assym.h.tmp assym.h
cc1: warnings being treated as errors
In file included from ../../../../uvm/uvm.h:65,
                 from /tmp/332.c:11:
../../../../uvm/uvm_swap.h:45: warning: `struct swapent' declared inside
parameter list
../../../../uvm/uvm_swap.h:45: warning: its scope is only this definition or
declaration,
../../../../uvm/uvm_swap.h:45: warning: which is probably not what you want.


I had two solutions: adding an #include "sys/swap.h" in uvm/uvm_swap.h or
changing arg #2 type to void * in uvm_swap_stats() prototype. What is the
prefered way?

Also: should I UVMHIST_LOG the entry to uvm_swap_stats?

-- 
Emmanuel Dreyfus
manu@netbsd.org