Date: Wed, 21 Nov 2001 14:00:02 -0800 (PST) From: Maxim Konovalov <maxim@macomnet.ru> To: freebsd-bugs@FreeBSD.org Subject: Re: bin/24955:/usr/bin/tail -F in 4.1+ doesn't work if file inode changes (works in 4.0) Message-ID: <200111212200.fALM02O99854@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/24955; it has been noted by GNATS.
From: Maxim Konovalov <maxim@macomnet.ru>
To: Ian Dowse <iedowse@maths.tcd.ie>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: bin/24955:/usr/bin/tail -F in 4.1+ doesn't work if file inode
changes (works in 4.0)
Date: Thu, 22 Nov 2001 00:50:37 +0300 (MSK)
Hello Ian,
On Mon, 19 Nov 2001, Ian Dowse wrote:
> In message <20011119214750.L60209-100000@news1.macomnet.ru>, Maxim Konovalov wr
> ites:
> >
> >What about this one:
>
> Looks better, but unless I'm mistaken it introduces 250ms polling
> even when -F is not specified; this would undo the benefit of using
> kqueue in the first place.
>
> How about something like the modified version below? It only polls
> in the -F case (with a longer 1s interval), and it separates the
> choice of sleep vs kqueue from the stat calls necessary for -F.
> We always use kqueue if supported, but in the -F case, the kqueue
> timeout is set to 1 second. By keeping `kq' open, this patch also
> allows switching back to kqueue, for example if a symlink is changed
> so that the path moves from an NFS to a UFS filesystem.
>
> Note that the EVFILT_VNODE filter could probably be removed, since
> it is no longer needed to notice when the file is renamed or deleted.
Looks OK for me except one minor problem, see below
> Ian
>
> Index: forward.c
> ===================================================================
> RCS file: /dump/FreeBSD-CVS/src/usr.bin/tail/forward.c,v
> retrieving revision 1.27
> diff -u -r1.27 forward.c
> --- forward.c 1 Sep 2001 22:22:44 -0000 1.27
> +++ forward.c 19 Nov 2001 22:34:00 -0000
> @@ -94,10 +94,11 @@
> off_t off;
> struct stat *sbp;
> {
> - int ch, kq = -1;
> + int ch, n, kq = -1;
> int action = USE_SLEEP;
> struct kevent ev[2];
> struct stat sb2;
> + struct timespec ts;
>
> switch(style) {
> case FBYTES:
> @@ -193,9 +194,10 @@
> clearerr(fp);
>
> switch (action) {
> - case ADD_EVENTS: {
> - int n = 0;
> - struct timespec ts = { 0, 0 };
> + case ADD_EVENTS:
> + n = 0;
> + ts.tv_sec = 0;
> + ts.tv_nsec = 0;
>
> if (Fflag && fileno(fp) != STDIN_FILENO) {
> EV_SET(&ev[n], fileno(fp), EVFILT_VNODE,
> @@ -208,24 +210,27 @@
> n++;
>
> if (kevent(kq, ev, n, NULL, 0, &ts) < 0) {
> - close(kq);
> - kq = -1;
> action = USE_SLEEP;
> } else {
> action = USE_KQUEUE;
> }
> break;
> - }
>
> case USE_KQUEUE:
> - if (kevent(kq, NULL, 0, ev, 1, NULL) < 0)
> + ts.tv_sec = 1;
> + ts.tv_nsec = 0;
> + /*
> + * In the -F case we set a timeout to ensure that
> + * we re-stat the file at least once every second.
> + */
> + n = kevent(kq, NULL, 0, ev, 1, Fflag ? &ts : NULL);
> + if (n < 0)
> err(1, "kevent");
> -
> - if (ev->filter == EVFILT_VNODE) {
> - /* file was rotated, wait until it reappears */
> - action = USE_SLEEP;
> - } else if (ev->data < 0) {
> - /* file shrank, reposition to end */
> + if (n == 0) {
> + /* timeout */
> + break;
> + } else if (ev->filter == EVFILT_READ && ev->data < 0) {
> + /* file shrank, reposition to end */
> if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
> ierr();
> return;
> @@ -236,9 +241,11 @@
> case USE_SLEEP:
> (void) usleep(250000);
> clearerr(fp);
+ if (kq != -1)
+ action = ADD_EVENTS;
It will help to break USE_SLEEP cycle when you remove symlink to fname
and recreate it again. Of course it will break automatically when new
data arrives but it may never happen.
> + break;
> + }
>
> - if (Fflag && fileno(fp) != STDIN_FILENO &&
> - stat(fname, &sb2) != -1) {
> + if (Fflag && fileno(fp) != STDIN_FILENO) {
> + if (stat(fname, &sb2) != -1) {
> if (sb2.st_ino != sbp->st_ino ||
> sb2.st_dev != sbp->st_dev ||
> sb2.st_rdev != sbp->st_rdev ||
> @@ -246,16 +253,15 @@
> fp = freopen(fname, "r", fp);
> if (fp == NULL) {
> ierr();
> - break;
> - }
> - *sbp = sb2;
> - if (kq != -1)
> + } else {
> + *sbp = sb2;
> action = ADD_EVENTS;
> - } else if (kq != -1) {
> - action = USE_KQUEUE;
> + }
> }
> + } else {
> + /* file was rotated, wait until it reappears */
> + action = USE_SLEEP;
> }
> - break;
> }
> }
> }
>
>
There is still an issue when fname is renamed. Our tail will continue
read data from the renamed file in USE_SLEEP cycle until a new fname
appear. The old tail (RELENG_4_0_0_RELEASE f.e.) works in the same
way. Imho it is not a correct behaviour but I am not quite sure.
--
Maxim Konovalov, MAcomnet, Internet-Intranet Dept., system engineer
phone: +7 (095) 796-9079, mailto: maxim@macomnet.ru
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200111212200.fALM02O99854>
