Fixes for i/o during coredumping:

- Do not dump into system files.
- Do not acquire write reference to the mount point where img.core is
  written, in the coredump().  The vn_rdwr() calls from ELF imgact
  request the write ref from vn_rdwr().  Recursive acqusition of the
  write ref deadlocks with the unmount.
- Instead, take the range lock for the whole core file.  This prevents
  parallel dumping from two processes executing the same image,
  converting the useless interleaved dump into sequential dumping,
  with second core overwriting the first.

Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2014-10-04 18:35:00 +00:00
parent e3d6feceb1
commit 539c9eef12
2 changed files with 15 additions and 22 deletions

View File

@ -1112,8 +1112,8 @@ core_output(struct vnode *vp, void *base, size_t len, off_t offset,
#endif
} else {
error = vn_rdwr_inchunks(UIO_WRITE, vp, base, len, offset,
UIO_USERSPACE, IO_UNIT | IO_DIRECT, active_cred, file_cred,
NULL, td);
UIO_USERSPACE, IO_UNIT | IO_DIRECT | IO_RANGELOCKED,
active_cred, file_cred, NULL, td);
}
return (error);
}
@ -1160,8 +1160,8 @@ sbuf_drain_core_output(void *arg, const char *data, int len)
#endif
error = vn_rdwr_inchunks(UIO_WRITE, p->vp,
__DECONST(void *, data), len, p->offset, UIO_SYSSPACE,
IO_UNIT | IO_DIRECT, p->active_cred, p->file_cred, NULL,
p->td);
IO_UNIT | IO_DIRECT | IO_RANGELOCKED, p->active_cred,
p->file_cred, NULL, p->td);
if (locked)
PROC_LOCK(p->td->td_proc);
if (error != 0)

View File

@ -3214,8 +3214,8 @@ coredump(struct thread *td)
struct flock lf;
struct vattr vattr;
int error, error1, locked;
struct mount *mp;
char *name; /* name of corefile */
void *rl_cookie;
off_t limit;
int compress;
@ -3248,39 +3248,33 @@ coredump(struct thread *td)
}
PROC_UNLOCK(p);
restart:
error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td, compress,
&vp, &name);
if (error != 0)
return (error);
/* Don't dump to non-regular files or files with links. */
/*
* Don't dump to non-regular files or files with links.
* Do not dump into system files.
*/
if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 ||
vattr.va_nlink != 1) {
vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0) {
VOP_UNLOCK(vp, 0);
error = EFAULT;
goto close;
}
VOP_UNLOCK(vp, 0);
/* Postpone other writers, including core dumps of other processes. */
rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX);
lf.l_whence = SEEK_SET;
lf.l_start = 0;
lf.l_len = 0;
lf.l_type = F_WRLCK;
locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0);
if (vn_start_write(vp, &mp, V_NOWAIT) != 0) {
lf.l_type = F_UNLCK;
if (locked)
VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK);
if ((error = vn_close(vp, FWRITE, cred, td)) != 0)
goto out;
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
goto out;
free(name, M_TEMP);
goto restart;
}
VATTR_NULL(&vattr);
vattr.va_size = 0;
if (set_core_nodump_flag)
@ -3288,7 +3282,6 @@ restart:
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
VOP_SETATTR(vp, &vattr, cred);
VOP_UNLOCK(vp, 0);
vn_finished_write(mp);
PROC_LOCK(p);
p->p_acflag |= ACORE;
PROC_UNLOCK(p);
@ -3304,11 +3297,11 @@ restart:
lf.l_type = F_UNLCK;
VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK);
}
vn_rangelock_unlock(vp, rl_cookie);
close:
error1 = vn_close(vp, FWRITE, cred, td);
if (error == 0)
error = error1;
out:
#ifdef AUDIT
audit_proc_coredump(td, name, error);
#endif