Date: Wed, 13 Mar 2013 22:27:50 +0100 From: Pawel Jakub Dawidek <pjd@FreeBSD.org> To: John Baldwin <jhb@freebsd.org> Cc: Dirk Engling <erdgeist@erdgeist.org>, freebsd-current@freebsd.org Subject: Re: pidfile_open incorrectly returns EAGAIN when pidfile is locked Message-ID: <20130313212750.GC1372@garage.freebsd.pl> In-Reply-To: <201303131118.36811.jhb@freebsd.org> References: <513F8D20.2050707@erdgeist.org> <201303131118.36811.jhb@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--ncSAzJYg3Aa9+CRW
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Wed, Mar 13, 2013 at 11:18:36AM -0400, John Baldwin wrote:
> On Tuesday, March 12, 2013 4:16:32 pm Dirk Engling wrote:
> > While debugging my own daemon I noticed that pidfile_open does not
> > perform the appropriate checks for a running daemon if the caller does
> > not provide a pidptr to pidfile_open
> >=20
> > fd =3D flopen(pfh->pf_path,
> > O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
> >=20
> > fails when another daemon holds the lock and flopen sets errno to
> > EAGAIN, the check 4 lines below in
> >=20
> > if (errno =3D=3D EWOULDBLOCK && pidptr !=3D NULL) {
> >=20
> > means that the pidfile_read is never executed.
> >=20
> > This results in my second daemon receiving an EAGAIN which clearly was
> > meant to report a race condition between two daemons starting at the
> > same time and the first one not yet finishing pidfile_write.
> >=20
> > The expected behavior would be to set errno to EEXIST, even if no pidptr
> > was passed.
>=20
> Yes, I think it should actually perform the same logic even if pidptr is
> NULL of waiting for the other daemon to finish starting up. Something li=
ke
> this:
>=20
> Index: lib/libutil/pidfile.c
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- pidfile.c (revision 248162)
> +++ pidfile.c (working copy)
> @@ -100,6 +100,7 @@ pidfile_open(const char *path, mode_t mode, pid_t
> struct stat sb;
> int error, fd, len, count;
> struct timespec rqtp;
> + pid_t dummy;
> =20
> pfh =3D malloc(sizeof(*pfh));
> if (pfh =3D=3D NULL)
> @@ -126,7 +127,9 @@ pidfile_open(const char *path, mode_t mode, pid_t
> fd =3D flopen(pfh->pf_path,
> O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NONBLOCK, mode);
> if (fd =3D=3D -1) {
> - if (errno =3D=3D EWOULDBLOCK && pidptr !=3D NULL) {
> + if (errno =3D=3D EWOULDBLOCK) {
> + if (pidptr =3D=3D NULL)
> + pidptr =3D &dummy;
> count =3D 20;
> rqtp.tv_sec =3D 0;
> rqtp.tv_nsec =3D 5000000;
I agree EEXIST should be returned, but I don't like reading existing
pidfile (including waiting for the other process to write its PID) just
to throw read PID away.
How about this patch?
http://people.freebsd.org/~pjd/patches/pidfile.c.patch
--=20
Pawel Jakub Dawidek http://www.wheelsystems.com
FreeBSD committer http://www.FreeBSD.org
Am I Evil? Yes, I Am! http://tupytaj.pl
--ncSAzJYg3Aa9+CRW
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.19 (FreeBSD)
iEYEARECAAYFAlFA71YACgkQForvXbEpPzRVuACeNxSf6DagXiOt8Dv5/qaT4vbN
/RwAmwaTqTGScNqfgQIk7yOcPuJoNRsp
=OQHV
-----END PGP SIGNATURE-----
--ncSAzJYg3Aa9+CRW--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130313212750.GC1372>
