Subject: Re: implementing closeall via a syscall
To: None <tech-kern@netbsd.org>
From: Matt Thomas <matt@3am-software.com>
List: tech-kern
Date: 01/04/2004 16:01:52
At 02:44 PM 1/4/2004, mouss wrote:
>I have implemented a syscall to close all descriptors from some value to 
>the max open, that is:
>         closem(k) will close descriptors k, k+1, ..., max_open_fd
>
>[rationale]
>dameons (and other apps) sometimes need to close almost all descriptors.
>The primary method to do this was to call close on fds from k to N, where 
>N is either a fixed value or the result of a function (SOPEN_MAX, 
>getrlimit, getdtablesize, ...). Unfortunately, this has two problems:
>         * a program may lower its limits while having a lot of fds open, 
> so the return value of getrlimit, sysconf, ... do not necessarily match 
> the number of open files inherited from a parent.
>         * there are too many useless syscalls
>
>An alternative is the use of /proc/ and close each open fd. This gets the 
>open fds right, but still consumes many syscalls. While this may be 
>acceptable, procfs is not necessarily the right place (kernfs maybe?).
>
>AIX has a F_CLOSEM cmd to fcntl to do just that. I originally intended to 
>implement this, but fcntl code checks that the fd arg is valid, which is 
>not relevant for the closem() function. Also, I got comments (a very long 
>time ago) that this would change the semantics of fcntl (which up so far 
>acts on a single fd and doesn't touch other fds), which seems a reasonable 
>counter-arg. Also, I'm not aware of any unix that followed the aix path, 
>so chances are this won't happen, so compatibility is not critical.

I'd prefer to follow prior art so i think the AIX fcntl FCLOSEM is 
preferrable to me.  It's not that hard to make fcntl to not check the fd 
for validity.

An alternative might be add an F_MAXFD to fcntl which would return the 
highest opened fd.

The following loop is wrong:

+       for (i=fdp->fd_lastfile; i>=fd; i--) {
+               fdrelease(p, i);
+       }

It should be:

         while (fdp->fd_lastfile >= fd)
                 fdrelease(p, fdp->fd_lastfile);


The changes to kern_descrip.c would look something life:

Index: kern_descrip.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_descrip.c,v
retrieving revision 1.121
diff -c -3 -p -r1.121 kern_descrip.c
*** kern_descrip.c      30 Nov 2003 18:16:45 -0000      1.121
--- kern_descrip.c      5 Jan 2004 00:01:23 -0000
*************** sys_fcntl(struct lwp *l, void *v, regist
*** 339,355 ****

         p = l->l_proc;
         fd = SCARG(uap, fd);
         fdp = p->p_fd;
         error = 0;
         flg = F_POSIX;

    restart:
         if ((fp = fd_getfile(fdp, fd)) == NULL)
                 return (EBADF);

         FILE_USE(fp);

-       cmd = SCARG(uap, cmd);
         if ((cmd & F_FSCTL)) {
                 error = fcntl_forfs(fd, p, cmd, SCARG(uap, arg));
                 goto out;
--- 339,366 ----

         p = l->l_proc;
         fd = SCARG(uap, fd);
+       cmd = SCARG(uap, cmd);
         fdp = p->p_fd;
         error = 0;
         flg = F_POSIX;

+       switch (cmd) {
+       case F_CLOSEM:
+               if (fd < 0)
+                       return (EBADF);
+               while (fdp->fd_lastfile >= fd)
+                       fdrelease(p, fdp->fd_lastfile);
+               return (0);
+       case F_MAXFD:
+               return (fdp->fd_lastfile);
+       }
+
    restart:
         if ((fp = fd_getfile(fdp, fd)) == NULL)
                 return (EBADF);

         FILE_USE(fp);

         if ((cmd & F_FSCTL)) {
                 error = fcntl_forfs(fd, p, cmd, SCARG(uap, arg));
                 goto out;

-- 
Matt Thomas                     email: matt@3am-software.com
3am Software Foundry              www: http://3am-software.com/bio/matt/
Cupertino, CA              disclaimer: I avow all knowledge of this message.