ktrace: fix a race between writes and close
It was possible that termination of ktrace session occured during some record write, in which case write occured after the close of the vnode. Use ktr_io_params refcounting to avoid this situation, by taking the reference on the structure instead of vnode. Reviewed by: markj Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D30400
This commit is contained in:
parent
48235c377f
commit
fc369a353b
@ -1257,7 +1257,7 @@ ktrsetchildren(struct thread *td, struct proc *top, int ops, int facs,
|
|||||||
static void
|
static void
|
||||||
ktr_writerequest(struct thread *td, struct ktr_request *req)
|
ktr_writerequest(struct thread *td, struct ktr_request *req)
|
||||||
{
|
{
|
||||||
struct ktr_io_params *kiop;
|
struct ktr_io_params *kiop, *kiop1;
|
||||||
struct ktr_header *kth;
|
struct ktr_header *kth;
|
||||||
struct vnode *vp;
|
struct vnode *vp;
|
||||||
struct proc *p;
|
struct proc *p;
|
||||||
@ -1272,14 +1272,10 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
p = td->td_proc;
|
p = td->td_proc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We hold the vnode and credential for use in I/O in case ktrace is
|
* We reference the kiop for use in I/O in case ktrace is
|
||||||
* disabled on the process as we write out the request.
|
* disabled on the process as we write out the request.
|
||||||
*
|
|
||||||
* XXXRW: This is not ideal: we could end up performing a write after
|
|
||||||
* the vnode has been closed.
|
|
||||||
*/
|
*/
|
||||||
mtx_lock(&ktrace_mtx);
|
mtx_lock(&ktrace_mtx);
|
||||||
|
|
||||||
kiop = p->p_ktrioparms;
|
kiop = p->p_ktrioparms;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1291,13 +1287,12 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ktr_io_params_ref(kiop);
|
||||||
vp = kiop->vp;
|
vp = kiop->vp;
|
||||||
cred = kiop->cr;
|
cred = kiop->cr;
|
||||||
lim = kiop->lim;
|
lim = kiop->lim;
|
||||||
|
|
||||||
vrefact(vp);
|
|
||||||
KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
|
KASSERT(cred != NULL, ("ktr_writerequest: cred == NULL"));
|
||||||
crhold(cred);
|
|
||||||
mtx_unlock(&ktrace_mtx);
|
mtx_unlock(&ktrace_mtx);
|
||||||
|
|
||||||
kth = &req->ktr_header;
|
kth = &req->ktr_header;
|
||||||
@ -1339,9 +1334,11 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
|
error = VOP_WRITE(vp, &auio, IO_UNIT | IO_APPEND, cred);
|
||||||
VOP_UNLOCK(vp);
|
VOP_UNLOCK(vp);
|
||||||
vn_finished_write(mp);
|
vn_finished_write(mp);
|
||||||
crfree(cred);
|
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
vrele(vp);
|
mtx_lock(&ktrace_mtx);
|
||||||
|
kiop = ktr_io_params_rele(kiop);
|
||||||
|
mtx_unlock(&ktrace_mtx);
|
||||||
|
ktr_io_params_free(kiop);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1354,12 +1351,15 @@ ktr_writerequest(struct thread *td, struct ktr_request *req)
|
|||||||
"ktrace write failed, errno %d, tracing stopped for pid %d\n",
|
"ktrace write failed, errno %d, tracing stopped for pid %d\n",
|
||||||
error, p->p_pid);
|
error, p->p_pid);
|
||||||
|
|
||||||
|
kiop1 = NULL;
|
||||||
PROC_LOCK(p);
|
PROC_LOCK(p);
|
||||||
mtx_lock(&ktrace_mtx);
|
mtx_lock(&ktrace_mtx);
|
||||||
if (p->p_ktrioparms != NULL && p->p_ktrioparms->vp == vp)
|
if (p->p_ktrioparms != NULL && p->p_ktrioparms->vp == vp)
|
||||||
kiop = ktr_freeproc(p);
|
kiop1 = ktr_freeproc(p);
|
||||||
|
kiop = ktr_io_params_rele(kiop);
|
||||||
mtx_unlock(&ktrace_mtx);
|
mtx_unlock(&ktrace_mtx);
|
||||||
PROC_UNLOCK(p);
|
PROC_UNLOCK(p);
|
||||||
|
ktr_io_params_free(kiop1);
|
||||||
ktr_io_params_free(kiop);
|
ktr_io_params_free(kiop);
|
||||||
vrele(vp);
|
vrele(vp);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user