From owner-freebsd-arch Sun Jul 14 2:16:58 2002 Delivered-To: freebsd-arch@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id CD3E737B400 for ; Sun, 14 Jul 2002 02:16:55 -0700 (PDT) Received: from gw.catspoiler.org (217-ip-163.nccn.net [209.79.217.163]) by mx1.FreeBSD.org (Postfix) with ESMTP id 1D8D443E3B for ; Sun, 14 Jul 2002 02:16:50 -0700 (PDT) (envelope-from dl-freebsd@catspoiler.org) Received: from mousie.catspoiler.org (mousie.catspoiler.org [192.168.101.2]) by gw.catspoiler.org (8.12.5/8.12.5) with ESMTP id g6E9Ghwr020552 for ; Sun, 14 Jul 2002 02:16:47 -0700 (PDT) (envelope-from dl-freebsd@catspoiler.org) Message-Id: <200207140916.g6E9Ghwr020552@gw.catspoiler.org> Date: Sun, 14 Jul 2002 02:16:43 -0700 (PDT) From: Don Lewis Subject: wiring the sysctl output buffer To: arch@FreeBSD.org MIME-Version: 1.0 Content-Type: TEXT/plain; charset=us-ascii Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG A number of places in the kernel call SYSCTL_OUT() while holding locks. The problem is that SYSCTL_OUT() can block while it wires down the "old" buffer in user space. If the data is small, such as an integer value, the best solution may be to copy the data and defer calling SYSCTL_OUT() until after the locks are released. This extra copy could be wasteful if the data is large, and it may be cumbersome if the data size is not known ahead of time, since determining the data size may be expensive. The data size could also potentially change between the time the size is calculatated and the time when the data is copied to the temporary buffer if the locks must be released so that MALLOC() can be called to allocate the buffer. I think the best solution to this problem is to add a sysctl system API to prewire the output buffer that can be called before grabbing the locks. Doing so allows the existing code to operate properly with only minimal changes. Here's a patch that implements this new API and illustrates how it can be used to fix the kern.function_list sysctl, which wants to call SYSCTL_OUT() multiple times while walking a locked data structure. I think this is the best fix, though I'd like some feedback on whether this is the best API. Index: sys/sysctl.h =================================================================== RCS file: /home/ncvs/src/sys/sys/sysctl.h,v retrieving revision 1.105 diff -u -r1.105 sysctl.h --- sys/sysctl.h 16 May 2002 21:28:26 -0000 1.105 +++ sys/sysctl.h 14 Jul 2002 07:57:29 -0000 @@ -595,6 +595,7 @@ size_t *retval); int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, int *nindx, struct sysctl_req *req); +void sysctl_wire_old_buffer(struct sysctl_req *req); #else /* !_KERNEL */ #include Index: kern/kern_sysctl.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_sysctl.c,v retrieving revision 1.126 diff -u -r1.126 kern_sysctl.c --- kern/kern_sysctl.c 29 Jun 2002 02:00:01 -0000 1.126 +++ kern/kern_sysctl.c 14 Jul 2002 07:57:50 -0000 @@ -990,6 +990,18 @@ return (error); } +/* + * Lock the user space destination buffer. + */ +void +sysctl_wire_old_buffer(struct sysctl_req *req) +{ + if (req->lock == 1 && req->oldptr && req->oldfunc == sysctl_old_user) { + vslock(req->oldptr, req->oldlen); + req->lock = 2; + } +} + int sysctl_find_oid(int *name, u_int namelen, struct sysctl_oid **noid, int *nindx, struct sysctl_req *req) Index: kern/kern_linker.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_linker.c,v retrieving revision 1.91 diff -u -r1.91 kern_linker.c --- kern/kern_linker.c 7 Jul 2002 22:35:47 -0000 1.91 +++ kern/kern_linker.c 14 Jul 2002 07:58:38 -0000 @@ -1794,6 +1794,7 @@ linker_file_t lf; int error; + sysctl_wire_old_buffer(req); mtx_lock(&kld_mtx); TAILQ_FOREACH(lf, &linker_files, link) { error = LINKER_EACH_FUNCTION_NAME(lf, To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-arch" in the body of the message