[BACK]Return to kern_exec.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / kern

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/kern/kern_exec.c between version 1.332.2.4 and 1.332.2.5

version 1.332.2.4, 2012/04/05 21:33:38 version 1.332.2.5, 2012/04/29 23:05:04
Line 237  struct execve_data {
Line 237  struct execve_data {
  */   */
 struct spawn_exec_data {  struct spawn_exec_data {
         struct execve_data      sed_exec;          struct execve_data      sed_exec;
         size_t                  sed_actions_len;          struct posix_spawn_file_actions
         struct posix_spawn_file_actions_entry  
                                 *sed_actions;                                  *sed_actions;
         struct posix_spawnattr  *sed_attrs;          struct posix_spawnattr  *sed_attrs;
         struct proc             *sed_parent;          struct proc             *sed_parent;
         kcondvar_t              sed_cv_child_ready;          kcondvar_t              sed_cv_child_ready;
         kmutex_t                sed_mtx_child;          kmutex_t                sed_mtx_child;
         int                     sed_error;          int                     sed_error;
           volatile uint32_t       sed_refcnt;
 };  };
   
 static void *  static void *
Line 842  execve_loadvm(struct lwp *l, const char 
Line 842  execve_loadvm(struct lwp *l, const char 
         return error;          return error;
 }  }
   
   static void
   execve_free_data(struct execve_data *data)
   {
   
           /* free the vmspace-creation commands, and release their references */
           kill_vmcmds(&data->ed_pack.ep_vmcmds);
           /* kill any opened file descriptor, if necessary */
           if (data->ed_pack.ep_flags & EXEC_HASFD) {
                   data->ed_pack.ep_flags &= ~EXEC_HASFD;
                   fd_close(data->ed_pack.ep_fd);
           }
   
           /* close and put the exec'd file */
           vn_lock(data->ed_pack.ep_vp, LK_EXCLUSIVE | LK_RETRY);
           VOP_CLOSE(data->ed_pack.ep_vp, FREAD, curlwp->l_cred);
           vput(data->ed_pack.ep_vp);
           pool_put(&exec_pool, data->ed_argp);
   
           kmem_free(data->ed_pack.ep_hdr, data->ed_pack.ep_hdrlen);
           if (data->ed_pack.ep_emul_root != NULL)
                   vrele(data->ed_pack.ep_emul_root);
           if (data->ed_pack.ep_interp != NULL)
                   vrele(data->ed_pack.ep_interp);
   
           pathbuf_stringcopy_put(data->ed_pathbuf, data->ed_pathstring);
           pathbuf_destroy(data->ed_pathbuf);
           PNBUF_PUT(data->ed_resolvedpathbuf);
   }
   
 static int  static int
 execve_runproc(struct lwp *l, struct execve_data * restrict data)  execve_runproc(struct lwp *l, struct execve_data * restrict data,
           bool no_local_exec_lock, bool is_spawn)
 {  {
         int error = 0;          int error = 0;
         struct proc             *p;          struct proc             *p;
Line 856  execve_runproc(struct lwp *l, struct exe
Line 886  execve_runproc(struct lwp *l, struct exe
         struct vmspace          *vm;          struct vmspace          *vm;
         ksiginfo_t              ksi;          ksiginfo_t              ksi;
         ksiginfoq_t             kq;          ksiginfoq_t             kq;
         bool                    proc_is_new;  
   
         KASSERT(rw_lock_held(&exec_lock));          /*
            * In case of a posix_spawn operation, the child doing the exec
            * might not hold the reader lock on exec_lock, but the parent
            * will do this instead.
            */
           KASSERT(no_local_exec_lock || rw_lock_held(&exec_lock));
         KASSERT(data != NULL);          KASSERT(data != NULL);
         if (data == NULL)          if (data == NULL)
                 return (EINVAL);                  return (EINVAL);
   
         p = l->l_proc;          p = l->l_proc;
         proc_is_new = p->p_vmspace == NULL;          if (no_local_exec_lock)
                   KASSERT(is_spawn);
   
         base_vcp = NULL;          base_vcp = NULL;
   
Line 893  execve_runproc(struct lwp *l, struct exe
Line 928  execve_runproc(struct lwp *l, struct exe
          * for remapping.  Note that this might replace the current           * for remapping.  Note that this might replace the current
          * vmspace with another!           * vmspace with another!
          */           */
         uvmspace_exec(l, data->ed_pack.ep_vm_minaddr, data->ed_pack.ep_vm_maxaddr);          if (is_spawn)
                   uvmspace_spawn(l, data->ed_pack.ep_vm_minaddr,
                       data->ed_pack.ep_vm_maxaddr);
           else
                   uvmspace_exec(l, data->ed_pack.ep_vm_minaddr,
                       data->ed_pack.ep_vm_maxaddr);
   
         /* record proc's vnode, for use by procfs and others */          /* record proc's vnode, for use by procfs and others */
         if (p->p_textvp)          if (p->p_textvp)
Line 1318  execve_runproc(struct lwp *l, struct exe
Line 1358  execve_runproc(struct lwp *l, struct exe
   
         /* Allow new references from the debugger/procfs. */          /* Allow new references from the debugger/procfs. */
         rw_exit(&p->p_reflock);          rw_exit(&p->p_reflock);
         rw_exit(&exec_lock);          if (!no_local_exec_lock)
                   rw_exit(&exec_lock);
   
         mutex_enter(proc_lock);          mutex_enter(proc_lock);
   
Line 1360  execve_runproc(struct lwp *l, struct exe
Line 1401  execve_runproc(struct lwp *l, struct exe
  exec_abort:   exec_abort:
         SDT_PROBE(proc,,,exec_failure, error, 0, 0, 0, 0);          SDT_PROBE(proc,,,exec_failure, error, 0, 0, 0, 0);
         rw_exit(&p->p_reflock);          rw_exit(&p->p_reflock);
         rw_exit(&exec_lock);          if (!no_local_exec_lock)
                   rw_exit(&exec_lock);
   
         pathbuf_stringcopy_put(data->ed_pathbuf, data->ed_pathstring);          pathbuf_stringcopy_put(data->ed_pathbuf, data->ed_pathstring);
         pathbuf_destroy(data->ed_pathbuf);          pathbuf_destroy(data->ed_pathbuf);
Line 1373  execve_runproc(struct lwp *l, struct exe
Line 1415  execve_runproc(struct lwp *l, struct exe
          */           */
         uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS,          uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS,
                 VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS);                  VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS);
   
         exec_free_emul_arg(&data->ed_pack);          exec_free_emul_arg(&data->ed_pack);
         pool_put(&exec_pool, data->ed_argp);          pool_put(&exec_pool, data->ed_argp);
         kmem_free(data->ed_pack.ep_hdr, data->ed_pack.ep_hdrlen);          kmem_free(data->ed_pack.ep_hdr, data->ed_pack.ep_hdrlen);
Line 1382  execve_runproc(struct lwp *l, struct exe
Line 1425  execve_runproc(struct lwp *l, struct exe
                 vrele(data->ed_pack.ep_interp);                  vrele(data->ed_pack.ep_interp);
   
         /* Acquire the sched-state mutex (exit1() will release it). */          /* Acquire the sched-state mutex (exit1() will release it). */
         if (!proc_is_new) {          if (!is_spawn) {
                 mutex_enter(p->p_lock);                  mutex_enter(p->p_lock);
                 exit1(l, W_EXITCODE(error, SIGABRT));                  exit1(l, W_EXITCODE(error, SIGABRT));
         }          }
   
         /* NOTREACHED */          return error;
         return 0;  
 }  }
   
 int  int
Line 1401  execve1(struct lwp *l, const char *path,
Line 1443  execve1(struct lwp *l, const char *path,
         error = execve_loadvm(l, path, args, envs, fetch_element, &data);          error = execve_loadvm(l, path, args, envs, fetch_element, &data);
         if (error)          if (error)
                 return error;                  return error;
         error = execve_runproc(l, &data);          error = execve_runproc(l, &data, false, false);
         return error;          return error;
 }  }
   
Line 1729  exec_sigcode_map(struct proc *p, const s
Line 1771  exec_sigcode_map(struct proc *p, const s
 }  }
   
 /*  /*
    * Release a refcount on spawn_exec_data and destroy memory, if this
    * was the last one.
    */
   static void
   spawn_exec_data_release(struct spawn_exec_data *data)
   {
           if (atomic_dec_32_nv(&data->sed_refcnt) != 0)
                   return;
   
           cv_destroy(&data->sed_cv_child_ready);
           mutex_destroy(&data->sed_mtx_child);
   
           if (data->sed_actions)
                   posix_spawn_fa_free(data->sed_actions,
                       data->sed_actions->len);
           if (data->sed_attrs)
                   kmem_free(data->sed_attrs,
                       sizeof(*data->sed_attrs));
           kmem_free(data, sizeof(*data));
   }
   
   /*
  * A child lwp of a posix_spawn operation starts here and ends up in   * A child lwp of a posix_spawn operation starts here and ends up in
  * cpu_spawn_return, dealing with all filedescriptor and scheduler   * cpu_spawn_return, dealing with all filedescriptor and scheduler
  * manipulations in between.   * manipulations in between.
    * The parent waits for the child, as it is not clear wether the child
    * will be able to aquire its own exec_lock. If it can, the parent can
    * be released early and continue running in parallel. If not (or if the
    * magic debug flag is passed in the scheduler attribute struct), the
    * child rides on the parent's exec lock untill it is ready to return to
    * to userland - and only then releases the parent. This method loses
    * concurrency, but improves error reporting.
  */   */
 static void  static void
 spawn_return(void *arg)  spawn_return(void *arg)
Line 1741  spawn_return(void *arg)
Line 1812  spawn_return(void *arg)
         int error, newfd;          int error, newfd;
         size_t i;          size_t i;
         const struct posix_spawn_file_actions_entry *fae;          const struct posix_spawn_file_actions_entry *fae;
           pid_t ppid;
         register_t retval;          register_t retval;
         bool have_reflock;          bool have_reflock;
           bool parent_is_waiting = true;
         /* we have been created non-preemptable */  
         KASSERT(l->l_nopreempt == 1);  
   
         /*          /*
          * The following actions may block, so we need a temporary           * Check if we can release parent early.
          * vmspace - borrow the kernel one           * We either need to have no sed_attrs, or sed_attrs does not
          */           * have POSIX_SPAWN_RETURNERROR or one of the flags, that require
         l->l_proc->p_vmspace = proc0.p_vmspace;           * safe access to the parent proc (passed in sed_parent).
         pmap_activate(l);           * We then try to get the exec_lock, and only if that works, we can
         KPREEMPT_ENABLE(l);           * release the parent here already.
            */
           ppid = spawn_data->sed_parent->p_pid;
           if ((!spawn_data->sed_attrs
               || (spawn_data->sed_attrs->sa_flags
                   & (POSIX_SPAWN_RETURNERROR|POSIX_SPAWN_SETPGROUP)) == 0)
               && rw_tryenter(&exec_lock, RW_READER)) {
                   parent_is_waiting = false;
                   mutex_enter(&spawn_data->sed_mtx_child);
                   cv_signal(&spawn_data->sed_cv_child_ready);
                   mutex_exit(&spawn_data->sed_mtx_child);
           }
   
         /* don't allow debugger access yet */          /* don't allow debugger access yet */
         rw_enter(&l->l_proc->p_reflock, RW_WRITER);          rw_enter(&l->l_proc->p_reflock, RW_WRITER);
Line 1762  spawn_return(void *arg)
Line 1843  spawn_return(void *arg)
         error = 0;          error = 0;
         /* handle posix_spawn_file_actions */          /* handle posix_spawn_file_actions */
         if (spawn_data->sed_actions != NULL) {          if (spawn_data->sed_actions != NULL) {
                 for (i = 0; i < spawn_data->sed_actions_len; i++) {                  for (i = 0; i < spawn_data->sed_actions->len; i++) {
                         fae = &spawn_data->sed_actions[i];                          fae = &spawn_data->sed_actions->fae[i];
                         switch (fae->fae_action) {                          switch (fae->fae_action) {
                         case FAE_OPEN:                          case FAE_OPEN:
                                 if (fd_getfile(fae->fae_fildes) != NULL) {                                  if (fd_getfile(fae->fae_fildes) != NULL) {
Line 1832  spawn_return(void *arg)
Line 1913  spawn_return(void *arg)
                             &spawn_data->sed_attrs->sa_schedparam);                              &spawn_data->sed_attrs->sa_schedparam);
                 else if (spawn_data->sed_attrs->sa_flags                  else if (spawn_data->sed_attrs->sa_flags
                     & POSIX_SPAWN_SETSCHEDPARAM) {                      & POSIX_SPAWN_SETSCHEDPARAM) {
                         error = do_sched_setparam(spawn_data->sed_parent->p_pid, 0,                          error = do_sched_setparam(ppid, 0,
                             SCHED_NONE, &spawn_data->sed_attrs->sa_schedparam);                              SCHED_NONE, &spawn_data->sed_attrs->sa_schedparam);
                 }                  }
                 if (error)                  if (error)
Line 1872  spawn_return(void *arg)
Line 1953  spawn_return(void *arg)
                 }                  }
         }          }
   
         /* stop using kernel vmspace */  
         KPREEMPT_DISABLE(l);  
         pmap_deactivate(l);  
         l->l_proc->p_vmspace = NULL;  
   
         /* now do the real exec */          /* now do the real exec */
         rw_enter(&exec_lock, RW_READER);          error = execve_runproc(l, &spawn_data->sed_exec, parent_is_waiting,
         error = execve_runproc(l, &spawn_data->sed_exec);              true);
         have_reflock = false;          have_reflock = false;
         if (error == EJUSTRETURN)          if (error == EJUSTRETURN)
                 error = 0;                  error = 0;
         else if (error)          else if (error)
                 goto report_error;                  goto report_error;
   
         /* we now have our own vmspace */          if (parent_is_waiting) {
         KPREEMPT_ENABLE(l);                  mutex_enter(&spawn_data->sed_mtx_child);
         KASSERT(l->l_nopreempt == 0);                  cv_signal(&spawn_data->sed_cv_child_ready);
                   mutex_exit(&spawn_data->sed_mtx_child);
           }
   
         /* done, signal parent */          /* release our refcount on the data */
         mutex_enter(&spawn_data->sed_mtx_child);          spawn_exec_data_release(spawn_data);
         cv_signal(&spawn_data->sed_cv_child_ready);  
         mutex_exit(&spawn_data->sed_mtx_child);  
   
         /* and finaly: leave to userland for the first time */          /* and finaly: leave to userland for the first time */
         cpu_spawn_return(l);          cpu_spawn_return(l);
Line 1902  spawn_return(void *arg)
Line 1978  spawn_return(void *arg)
         return;          return;
   
  report_error:   report_error:
         if (have_reflock)          if (have_reflock) {
                   /*
                    * We have not passed through execve_runproc(),
                    * which would have released the p_reflock and also
                    * taken ownership of the sed_exec part of spawn_data,
                    * so release/free both here.
                    */
                 rw_exit(&l->l_proc->p_reflock);                  rw_exit(&l->l_proc->p_reflock);
                   execve_free_data(&spawn_data->sed_exec);
           }
   
         /* stop using kernel vmspace (if we haven't already) */          if (parent_is_waiting) {
         if (l->l_proc->p_vmspace) {                  /* pass error to parent */
                 KPREEMPT_DISABLE(l);                  mutex_enter(&spawn_data->sed_mtx_child);
                 pmap_deactivate(l);                  spawn_data->sed_error = error;
                 l->l_proc->p_vmspace = NULL;                  cv_signal(&spawn_data->sed_cv_child_ready);
                 /* do not enable preemption without vmspace */                  mutex_exit(&spawn_data->sed_mtx_child);
           } else {
                   rw_exit(&exec_lock);
         }          }
   
         /*          /* release our refcount on the data */
          * Set error value for parent to pick up (and take over ownership          spawn_exec_data_release(spawn_data);
          * of spawn_data again), signal parent and exit this process.  
          */          /* done, exit */
         mutex_enter(&spawn_data->sed_mtx_child);  
         spawn_data->sed_error = error;  
         cv_signal(&spawn_data->sed_cv_child_ready);  
         mutex_exit(&spawn_data->sed_mtx_child);  
         mutex_enter(l->l_proc->p_lock);          mutex_enter(l->l_proc->p_lock);
         exit1(l, W_EXITCODE(error, SIGABRT));          /*
            * Posix explicitly asks for an exit code of 127 if we report
            * errors from the child process - so, unfortunately, there
            * is no way to report a more exact error code.
            * A NetBSD specific workaround is POSIX_SPAWN_RETURNERROR as
            * flag bit in the attrp argument to posix_spawn(2), see above.
            */
           exit1(l, W_EXITCODE(127, 0));
 }  }
   
 static void  void
 posix_spawn_fa_free(struct posix_spawn_file_actions *fa, size_t len)  posix_spawn_fa_free(struct posix_spawn_file_actions *fa, size_t len)
 {  {
   
Line 1935  posix_spawn_fa_free(struct posix_spawn_f
Line 2024  posix_spawn_fa_free(struct posix_spawn_f
                         continue;                          continue;
                 kmem_free(fae->fae_path, strlen(fae->fae_path) + 1);                  kmem_free(fae->fae_path, strlen(fae->fae_path) + 1);
         }          }
         if (fa->len)          if (fa->len > 0)
                 kmem_free(fa->fae, sizeof(*fa->fae) * fa->len);                  kmem_free(fa->fae, sizeof(*fa->fae) * fa->len);
         kmem_free(fa, sizeof(*fa));          kmem_free(fa, sizeof(*fa));
 }  }
Line 1958  posix_spawn_fa_alloc(struct posix_spawn_
Line 2047  posix_spawn_fa_alloc(struct posix_spawn_
                 goto out;                  goto out;
         }          }
   
         if (fa->len == 0)          if (fa->len == 0) {
                   kmem_free(fa, sizeof(*fa));
                 return 0;                  return 0;
           }
   
           fa->size = fa->len;
         size_t fal = fa->len * sizeof(*fae);          size_t fal = fa->len * sizeof(*fae);
         fae = fa->fae;          fae = fa->fae;
         fa->fae = kmem_alloc(fal, KM_SLEEP);          fa->fae = kmem_alloc(fal, KM_SLEEP);
Line 1980  posix_spawn_fa_alloc(struct posix_spawn_
Line 2072  posix_spawn_fa_alloc(struct posix_spawn_
                 memcpy(fae->fae_path, pbuf, fal);                  memcpy(fae->fae_path, pbuf, fal);
         }          }
         PNBUF_PUT(pbuf);          PNBUF_PUT(pbuf);
   
         *fap = fa;          *fap = fa;
         return 0;          return 0;
 out:  out:
Line 1990  out:
Line 2083  out:
 }  }
   
 int  int
 sys_posix_spawn(struct lwp *l1, const struct sys_posix_spawn_args *uap,  check_posix_spawn(struct lwp *l1)
     register_t *retval)  
 {  {
         /* {          int error, tnprocs, count;
                 syscallarg(pid_t *) pid;  
                 syscallarg(const char *) path;  
                 syscallarg(const struct posix_spawn_file_actions *) file_actions;  
                 syscallarg(const struct posix_spawnattr *) attrp;  
                 syscallarg(char *const *) argv;  
                 syscallarg(char *const *) envp;  
         } */  
   
         struct proc *p1, *p2;  
         struct plimit *p1_lim;  
         struct lwp *l2;  
         int error = 0, tnprocs, count;  
         struct posix_spawn_file_actions *fa = NULL;  
         struct posix_spawnattr *sa = NULL;  
         struct spawn_exec_data *spawn_data;  
         uid_t uid;          uid_t uid;
         vaddr_t uaddr;          struct proc *p1;
         pid_t pid;  
         bool have_exec_lock = false;  
   
         p1 = l1->l_proc;          p1 = l1->l_proc;
         uid = kauth_cred_getuid(l1->l_cred);          uid = kauth_cred_getuid(l1->l_cred);
Line 2030  sys_posix_spawn(struct lwp *l1, const st
Line 2105  sys_posix_spawn(struct lwp *l1, const st
   
         if (error) {          if (error) {
                 atomic_dec_uint(&nprocs);                  atomic_dec_uint(&nprocs);
                 *retval = EAGAIN;                  return EAGAIN;
                 return 0;  
         }          }
   
         /*          /*
Line 2042  sys_posix_spawn(struct lwp *l1, const st
Line 2116  sys_posix_spawn(struct lwp *l1, const st
              p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS),               p1, KAUTH_ARG(KAUTH_REQ_PROCESS_RLIMIT_BYPASS),
              &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) != 0 &&               &p1->p_rlimit[RLIMIT_NPROC], KAUTH_ARG(RLIMIT_NPROC)) != 0 &&
             __predict_false(count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur)) {              __predict_false(count > p1->p_rlimit[RLIMIT_NPROC].rlim_cur)) {
                 error = EAGAIN;                  (void)chgproccnt(uid, -1);
                 goto error_exit;                  atomic_dec_uint(&nprocs);
                   return EAGAIN;
         }          }
   
         /* copy in file_actions struct */          return 0;
         if (SCARG(uap, file_actions) != NULL) {  }
                 error = posix_spawn_fa_alloc(&fa, SCARG(uap, file_actions));  
                 if (error)  
                         goto error_exit;  
         }  
   
         /* copyin posix_spawnattr struct */  int
         if (SCARG(uap, attrp) != NULL) {  do_posix_spawn(struct lwp *l1, pid_t *pid_res, bool *child_ok, const char *path,
                 sa = kmem_alloc(sizeof(*sa), KM_SLEEP);          struct posix_spawn_file_actions *fa,
                 error = copyin(SCARG(uap, attrp), sa, sizeof(*sa));          struct posix_spawnattr *sa,
                 if (error)          char *const *argv, char *const *envp,
                         goto error_exit;          execve_fetch_element_t fetch)
         }  {
   
           struct proc *p1, *p2;
           struct lwp *l2;
           int error;
           struct spawn_exec_data *spawn_data;
           vaddr_t uaddr;
           pid_t pid;
           bool have_exec_lock = false;
   
           p1 = l1->l_proc;
   
           /* Allocate and init spawn_data */
           spawn_data = kmem_zalloc(sizeof(*spawn_data), KM_SLEEP);
           spawn_data->sed_refcnt = 1; /* only parent so far */
           cv_init(&spawn_data->sed_cv_child_ready, "pspawn");
           mutex_init(&spawn_data->sed_mtx_child, MUTEX_DEFAULT, IPL_NONE);
           mutex_enter(&spawn_data->sed_mtx_child);
   
         /*          /*
          * Do the first part of the exec now, collect state           * Do the first part of the exec now, collect state
          * in spawn_data.           * in spawn_data.
          */           */
         spawn_data = kmem_zalloc(sizeof(*spawn_data), KM_SLEEP);          error = execve_loadvm(l1, path, argv,
         error = execve_loadvm(l1, SCARG(uap, path), SCARG(uap, argv),              envp, fetch, &spawn_data->sed_exec);
             SCARG(uap, envp), execve_fetch_element, &spawn_data->sed_exec);  
         if (error == EJUSTRETURN)          if (error == EJUSTRETURN)
                 error = 0;                  error = 0;
         else if (error)          else if (error)
Line 2087  sys_posix_spawn(struct lwp *l1, const st
Line 2174  sys_posix_spawn(struct lwp *l1, const st
         }          }
   
         /*          /*
          * Allocate new proc. Leave it's p_vmspace NULL for now.           * Allocate new proc. Borrow proc0 vmspace for it, we will
            * replace it with its own before returning to userland
            * in the child.
          * This is a point of no return, we will have to go through           * This is a point of no return, we will have to go through
          * the child proc to properly clean it up past this point.           * the child proc to properly clean it up past this point.
          */           */
Line 2103  sys_posix_spawn(struct lwp *l1, const st
Line 2192  sys_posix_spawn(struct lwp *l1, const st
             (unsigned) ((char *)&p2->p_endzero - (char *)&p2->p_startzero));              (unsigned) ((char *)&p2->p_endzero - (char *)&p2->p_startzero));
         memcpy(&p2->p_startcopy, &p1->p_startcopy,          memcpy(&p2->p_startcopy, &p1->p_startcopy,
             (unsigned) ((char *)&p2->p_endcopy - (char *)&p2->p_startcopy));              (unsigned) ((char *)&p2->p_endcopy - (char *)&p2->p_startcopy));
         p2->p_vmspace = NULL;          p2->p_vmspace = proc0.p_vmspace;
   
         CIRCLEQ_INIT(&p2->p_sigpend.sp_info);          CIRCLEQ_INIT(&p2->p_sigpend.sp_info);
   
Line 2145  sys_posix_spawn(struct lwp *l1, const st
Line 2234  sys_posix_spawn(struct lwp *l1, const st
          * Note: p_limit (rlimit stuff) is copy-on-write, so normally           * Note: p_limit (rlimit stuff) is copy-on-write, so normally
          * we just need increase pl_refcnt.           * we just need increase pl_refcnt.
          */           */
         p1_lim = p1->p_limit;          if (!p1->p_limit->pl_writeable) {
         if (!p1_lim->pl_writeable) {                  lim_addref(p1->p_limit);
                 lim_addref(p1_lim);                  p2->p_limit = p1->p_limit;
                 p2->p_limit = p1_lim;  
         } else {          } else {
                 p2->p_limit = lim_copy(p1->p_limit);                  p2->p_limit = lim_copy(p1->p_limit);
         }          }
Line 2200  sys_posix_spawn(struct lwp *l1, const st
Line 2288  sys_posix_spawn(struct lwp *l1, const st
         /*          /*
          * Prepare remaining parts of spawn data           * Prepare remaining parts of spawn data
          */           */
         if (fa && fa->len) {          spawn_data->sed_actions = fa;
                 spawn_data->sed_actions_len = fa->len;          spawn_data->sed_attrs = sa;
                 spawn_data->sed_actions = fa->fae;  
         }  
         if (sa)  
                 spawn_data->sed_attrs = sa;  
   
         spawn_data->sed_parent = p1;          spawn_data->sed_parent = p1;
         cv_init(&spawn_data->sed_cv_child_ready, "pspawn");  
         mutex_init(&spawn_data->sed_mtx_child, MUTEX_DEFAULT, IPL_NONE);  
         mutex_enter(&spawn_data->sed_mtx_child);  
   
         /* create LWP */          /* create LWP */
         lwp_create(l1, p2, uaddr, 0, NULL, 0, spawn_return, spawn_data,          lwp_create(l1, p2, uaddr, 0, NULL, 0, spawn_return, spawn_data,
Line 2241  sys_posix_spawn(struct lwp *l1, const st
Line 2322  sys_posix_spawn(struct lwp *l1, const st
                 kauth_cred_free(ocred);                  kauth_cred_free(ocred);
         }          }
   
           *child_ok = true;
           spawn_data->sed_refcnt = 2;     /* child gets it as well */
   #if 0
         l2->l_nopreempt = 1; /* start it non-preemptable */          l2->l_nopreempt = 1; /* start it non-preemptable */
   #endif
   
         /*          /*
          * It's now safe for the scheduler and other processes to see the           * It's now safe for the scheduler and other processes to see the
Line 2283  sys_posix_spawn(struct lwp *l1, const st
Line 2368  sys_posix_spawn(struct lwp *l1, const st
         mutex_exit(proc_lock);          mutex_exit(proc_lock);
   
         cv_wait(&spawn_data->sed_cv_child_ready, &spawn_data->sed_mtx_child);          cv_wait(&spawn_data->sed_cv_child_ready, &spawn_data->sed_mtx_child);
         mutex_exit(&spawn_data->sed_mtx_child);  
         error = spawn_data->sed_error;          error = spawn_data->sed_error;
           mutex_exit(&spawn_data->sed_mtx_child);
           spawn_exec_data_release(spawn_data);
   
         rw_exit(&p1->p_reflock);          rw_exit(&p1->p_reflock);
         rw_exit(&exec_lock);          rw_exit(&exec_lock);
         have_exec_lock = false;          have_exec_lock = false;
   
         if (fa)          *pid_res = pid;
                 posix_spawn_fa_free(fa, fa->len);          return error;
   
    error_exit:
           if (have_exec_lock) {
                   execve_free_data(&spawn_data->sed_exec);
                   rw_exit(&p1->p_reflock);
                   rw_exit(&exec_lock);
           }
           mutex_exit(&spawn_data->sed_mtx_child);
           spawn_exec_data_release(spawn_data);
   
           return error;
   }
   
   int
   sys_posix_spawn(struct lwp *l1, const struct sys_posix_spawn_args *uap,
       register_t *retval)
   {
           /* {
                   syscallarg(pid_t *) pid;
                   syscallarg(const char *) path;
                   syscallarg(const struct posix_spawn_file_actions *) file_actions;
                   syscallarg(const struct posix_spawnattr *) attrp;
                   syscallarg(char *const *) argv;
                   syscallarg(char *const *) envp;
           } */
   
         if (sa)          int error;
                 kmem_free(sa, sizeof(*sa));          struct posix_spawn_file_actions *fa = NULL;
           struct posix_spawnattr *sa = NULL;
           pid_t pid;
           bool child_ok = false;
   
         cv_destroy(&spawn_data->sed_cv_child_ready);          error = check_posix_spawn(l1);
         mutex_destroy(&spawn_data->sed_mtx_child);          if (error) {
                   *retval = error;
                   return 0;
           }
   
         kmem_free(spawn_data, sizeof(*spawn_data));          /* copy in file_actions struct */
           if (SCARG(uap, file_actions) != NULL) {
                   error = posix_spawn_fa_alloc(&fa, SCARG(uap, file_actions));
                   if (error)
                           goto error_exit;
           }
   
           /* copyin posix_spawnattr struct */
           if (SCARG(uap, attrp) != NULL) {
                   sa = kmem_alloc(sizeof(*sa), KM_SLEEP);
                   error = copyin(SCARG(uap, attrp), sa, sizeof(*sa));
                   if (error)
                           goto error_exit;
           }
   
           /*
            * Do the spawn
            */
           error = do_posix_spawn(l1, &pid, &child_ok, SCARG(uap, path), fa, sa,
               SCARG(uap, argv), SCARG(uap, envp), execve_fetch_element);
           if (error)
                   goto error_exit;
   
         if (error == 0 && SCARG(uap, pid) != NULL)          if (error == 0 && SCARG(uap, pid) != NULL)
                 error = copyout(&pid, SCARG(uap, pid), sizeof(pid));                  error = copyout(&pid, SCARG(uap, pid), sizeof(pid));
Line 2308  sys_posix_spawn(struct lwp *l1, const st
Line 2446  sys_posix_spawn(struct lwp *l1, const st
         return 0;          return 0;
   
  error_exit:   error_exit:
         if (have_exec_lock)          if (!child_ok) {
                 rw_exit(&exec_lock);                  (void)chgproccnt(kauth_cred_getuid(l1->l_cred), -1);
                   atomic_dec_uint(&nprocs);
         if (fa)  
                 posix_spawn_fa_free(fa, fa->len);  
   
         if (sa)  
                 kmem_free(sa, sizeof(*sa));  
   
         (void)chgproccnt(uid, -1);                  if (sa)
         atomic_dec_uint(&nprocs);                          kmem_free(sa, sizeof(*sa));
                   if (fa)
                           posix_spawn_fa_free(fa, fa->len);
           }
   
         *retval = error;          *retval = error;
         return 0;          return 0;

Legend:
Removed from v.1.332.2.4  
changed lines
  Added in v.1.332.2.5

CVSweb <webmaster@jp.NetBSD.org>