Hi,

The following diff sets NOLOCK on dup(2) and dup2(2) syscalls. It is a
part of "unlock more syscalls".

All the hard work was already done by mpi@. My changes are mostly to add
few KASSERT() or comments in current code.

The key function for pipe creation is dopipe(). It creates 2 pipes
struct using pipecreate(), allocate descriptors and insert them (this
part is already KERNEL_LOCK safe).

The specific part are pipe_create() and error code which call pipeclose().

1. pipe_create()

pipe_create() do only initialization with safe code, or already take the
KERNEL_LOCK like for km_alloc() or km_free().

It also call pipespace() to initialize the buffer. I added some
KASSERT() inside it to make visible the expectation: the pipe should
be uninitialized (like when called from pipe_create() or locked (with
PIPE_LOCK, as the buffer will be freed and realloced).

While here, I also added a KASSERT() to stand the buffer is empty before
replacing it.


2. pipeclose()

In the general case, pipeclose() isn't safe to be called without KERNEL_LOCK:
- if the pipe is busy, it could call wakeup() and tsleep()
- if the pipe has peer, it could call pipeselwakeup() and wakeup()

But we are in dopipe(), so it is a special case:
- the pipe isn't used for now, so pipe_busy couldn't be set
- the error code paths possibility calling pipeclose() are before setting
  pipe_peer, so the pipe has not peer when called.

So I added a comment to say it is safe to call pipeclose() here.



And a side question: what is the purpose of `amountpipekva' variable ?
it is incremented/decremented to reflect the total size of all pipe
buffers in use, but it is used nowhere outside pipespace() for inc
and pipe_free_kmem() for dec. should be deleted or it is useful for
debugging (via ddb perhaps) ?



For testing, please regenerate syscalls after applying the diff, and
before compiling the kernel:

        $ cd /sys/kern && make syscalls


Comments or OK ?
-- 
Sebastien Marie



Index: kern/syscalls.master
===================================================================
RCS file: /cvs/src/sys/kern/syscalls.master,v
retrieving revision 1.192
diff -u -p -r1.192 syscalls.master
--- kern/syscalls.master        22 Jun 2019 06:49:14 -0000      1.192
+++ kern/syscalls.master        24 Jun 2019 10:26:14 -0000
@@ -216,7 +216,7 @@
                            socklen_t namelen); }
 99     STD             { int sys_getdents(int fd, void *buf, size_t buflen); }
 100    STD             { int sys_getpriority(int which, id_t who); }
-101    STD             { int sys_pipe2(int *fdp, int flags); }
+101    STD NOLOCK      { int sys_pipe2(int *fdp, int flags); }
 102    STD             { int sys_dup3(int from, int to, int flags); }
 103    STD             { int sys_sigreturn(struct sigcontext *sigcntxp); }
 104    STD             { int sys_bind(int s, const struct sockaddr *name, \
@@ -448,7 +448,7 @@
 260    UNIMPL
 261    UNIMPL
 262    UNIMPL
-263    STD             { int sys_pipe(int *fdp); }
+263    STD NOLOCK      { int sys_pipe(int *fdp); }
 264    STD             { int sys_fhopen(const fhandle_t *fhp, int flags); }
 265    UNIMPL
 266    UNIMPL
Index: kern/sys_pipe.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_pipe.c,v
retrieving revision 1.88
diff -u -p -r1.88 sys_pipe.c
--- kern/sys_pipe.c     22 Jun 2019 06:48:25 -0000      1.88
+++ kern/sys_pipe.c     24 Jun 2019 10:30:12 -0000
@@ -198,6 +198,7 @@ free3:
 free2:
        fdpunlock(fdp);
 free1:
+       /* fine without KERNEL_LOCK because just created */
        pipeclose(wpipe);
        pipeclose(rpipe);
        return (error);
@@ -214,12 +215,18 @@ pipespace(struct pipe *cpipe, u_int size
 {
        caddr_t buffer;
 
+       /* pipe should be uninitialized or locked */
+       KASSERT((cpipe->pipe_buffer.buffer == NULL) ||
+           (cpipe->pipe_state & PIPE_LOCK));
+
+       /* buffer should be empty */
+       KASSERT(cpipe->pipe_buffer.cnt == 0);
+
        KERNEL_LOCK();
        buffer = km_alloc(size, &kv_any, &kp_pageable, &kd_waitok);
        KERNEL_UNLOCK();
-       if (buffer == NULL) {
+       if (buffer == NULL)
                return (ENOMEM);
-       }
 
        /* free old resources if we are resizing */
        pipe_free_kmem(cpipe);
@@ -227,7 +234,6 @@ pipespace(struct pipe *cpipe, u_int size
        cpipe->pipe_buffer.size = size;
        cpipe->pipe_buffer.in = 0;
        cpipe->pipe_buffer.out = 0;
-       cpipe->pipe_buffer.cnt = 0;
 
        atomic_add_int(&amountpipekva, cpipe->pipe_buffer.size);
 
@@ -244,6 +250,8 @@ pipe_create(struct pipe *cpipe)
 
        /* so pipe_free_kmem() doesn't follow junk pointer */
        cpipe->pipe_buffer.buffer = NULL;
+       cpipe->pipe_buffer.cnt = 0;
+
        /*
         * protect so pipeclose() doesn't follow a junk pointer
         * if pipespace() fails.
@@ -303,6 +311,7 @@ pipeselwakeup(struct pipe *cpipe)
                selwakeup(&cpipe->pipe_sel);
        } else
                KNOTE(&cpipe->pipe_sel.si_note, 0);
+
        if (cpipe->pipe_state & PIPE_ASYNC)
                pgsigio(&cpipe->pipe_sigio, SIGIO, 0);
 }

Reply via email to