summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/imgact_elf.c53
-rw-r--r--sys/kern/kern_exit.c8
-rw-r--r--sys/kern/subr_taskqueue.c23
3 files changed, 69 insertions, 15 deletions
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index df223bf..341c6f4 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -454,7 +454,7 @@ __elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
rv = vm_map_find(map, NULL, 0, &start, end - start, 0,
VMFS_NO_SPACE, prot | VM_PROT_WRITE, VM_PROT_ALL,
0);
- if (rv)
+ if (rv != KERN_SUCCESS)
return (rv);
if (object == NULL)
return (KERN_SUCCESS);
@@ -469,9 +469,8 @@ __elfN(map_insert)(vm_map_t map, vm_object_t object, vm_ooffset_t offset,
error = copyout((caddr_t)sf_buf_kva(sf) + off,
(caddr_t)start, sz);
vm_imgact_unmap_page(sf);
- if (error) {
+ if (error != 0)
return (KERN_FAILURE);
- }
offset += sz;
}
rv = KERN_SUCCESS;
@@ -1823,8 +1822,12 @@ typedef vm_offset_t elf_ps_strings_t;
static void
__elfN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep)
{
+ struct sbuf sbarg;
+ size_t len;
+ char *cp, *end;
struct proc *p;
elf_prpsinfo_t *psinfo;
+ int error;
p = (struct proc *)arg;
if (sb != NULL) {
@@ -1833,13 +1836,43 @@ __elfN(note_prpsinfo)(void *arg, struct sbuf *sb, size_t *sizep)
psinfo->pr_version = PRPSINFO_VERSION;
psinfo->pr_psinfosz = sizeof(elf_prpsinfo_t);
strlcpy(psinfo->pr_fname, p->p_comm, sizeof(psinfo->pr_fname));
- /*
- * XXX - We don't fill in the command line arguments properly
- * yet.
- */
- strlcpy(psinfo->pr_psargs, p->p_comm,
- sizeof(psinfo->pr_psargs));
-
+ PROC_LOCK(p);
+ if (p->p_args != NULL) {
+ len = sizeof(psinfo->pr_psargs) - 1;
+ if (len > p->p_args->ar_length)
+ len = p->p_args->ar_length;
+ memcpy(psinfo->pr_psargs, p->p_args->ar_args, len);
+ PROC_UNLOCK(p);
+ error = 0;
+ } else {
+ _PHOLD(p);
+ PROC_UNLOCK(p);
+ sbuf_new(&sbarg, psinfo->pr_psargs,
+ sizeof(psinfo->pr_psargs), SBUF_FIXEDLEN);
+ error = proc_getargv(curthread, p, &sbarg);
+ PRELE(p);
+ if (sbuf_finish(&sbarg) == 0)
+ len = sbuf_len(&sbarg) - 1;
+ else
+ len = sizeof(psinfo->pr_psargs) - 1;
+ sbuf_delete(&sbarg);
+ }
+ if (error || len == 0)
+ strlcpy(psinfo->pr_psargs, p->p_comm,
+ sizeof(psinfo->pr_psargs));
+ else {
+ KASSERT(len < sizeof(psinfo->pr_psargs),
+ ("len is too long: %zu vs %zu", len,
+ sizeof(psinfo->pr_psargs)));
+ cp = psinfo->pr_psargs;
+ end = cp + len - 1;
+ for (;;) {
+ cp = memchr(cp, '\0', end - cp);
+ if (cp == NULL)
+ break;
+ *cp = ' ';
+ }
+ }
sbuf_bcat(sb, psinfo, sizeof(*psinfo));
free(psinfo, M_TEMP);
}
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 125f210..3a20fb1 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -723,9 +723,9 @@ sys_wait4(struct thread *td, struct wait4_args *uap)
else
rup = NULL;
error = kern_wait(td, uap->pid, &status, uap->options, rup);
- if (uap->status != NULL && error == 0)
+ if (uap->status != NULL && error == 0 && td->td_retval[0] != 0)
error = copyout(&status, uap->status, sizeof(status));
- if (uap->rusage != NULL && error == 0)
+ if (uap->rusage != NULL && error == 0 && td->td_retval[0] != 0)
error = copyout(&ru, uap->rusage, sizeof(struct rusage));
return (error);
}
@@ -759,9 +759,9 @@ sys_wait6(struct thread *td, struct wait6_args *uap)
*/
error = kern_wait6(td, idtype, id, &status, uap->options, wrup, sip);
- if (uap->status != NULL && error == 0)
+ if (uap->status != NULL && error == 0 && td->td_retval[0] != 0)
error = copyout(&status, uap->status, sizeof(status));
- if (uap->wrusage != NULL && error == 0)
+ if (uap->wrusage != NULL && error == 0 && td->td_retval[0] != 0)
error = copyout(&wru, uap->wrusage, sizeof(wru));
if (uap->info != NULL && error == 0)
error = copyout(&si, uap->info, sizeof(si));
diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c
index 5a20148..d380b9c 100644
--- a/sys/kern/subr_taskqueue.c
+++ b/sys/kern/subr_taskqueue.c
@@ -81,6 +81,7 @@ struct taskqueue {
#define TQ_FLAGS_UNLOCKED_ENQUEUE (1 << 2)
#define DT_CALLOUT_ARMED (1 << 0)
+#define DT_DRAIN_IN_PROGRESS (1 << 1)
#define TQ_LOCK(tq) \
do { \
@@ -299,7 +300,11 @@ taskqueue_enqueue_timeout(struct taskqueue *queue,
KASSERT(!queue->tq_spin, ("Timeout for spin-queue"));
timeout_task->q = queue;
res = timeout_task->t.ta_pending;
- if (ticks == 0) {
+ if (timeout_task->f & DT_DRAIN_IN_PROGRESS) {
+ /* Do nothing */
+ TQ_UNLOCK(queue);
+ res = -1;
+ } else if (ticks == 0) {
taskqueue_enqueue_locked(queue, &timeout_task->t);
/* The lock is released inside. */
} else {
@@ -559,8 +564,24 @@ taskqueue_drain_timeout(struct taskqueue *queue,
struct timeout_task *timeout_task)
{
+ /*
+ * Set flag to prevent timer from re-starting during drain:
+ */
+ TQ_LOCK(queue);
+ KASSERT((timeout_task->f & DT_DRAIN_IN_PROGRESS) == 0,
+ ("Drain already in progress"));
+ timeout_task->f |= DT_DRAIN_IN_PROGRESS;
+ TQ_UNLOCK(queue);
+
callout_drain(&timeout_task->c);
taskqueue_drain(queue, &timeout_task->t);
+
+ /*
+ * Clear flag to allow timer to re-start:
+ */
+ TQ_LOCK(queue);
+ timeout_task->f &= ~DT_DRAIN_IN_PROGRESS;
+ TQ_UNLOCK(queue);
}
static void
OpenPOWER on IntegriCloud