Date: Wed, 10 Jan 2001 15:03:42 +0100 (CET) From: Andre Albsmeier <andre.albsmeier@mchp.siemens.de> To: FreeBSD-gnats-submit@freebsd.org Subject: kern/24223: "tail -f file" is a CPU hog when file is on an NFS volume Message-ID: <200101101403.f0AE3gc13210@curry.mchp.siemens.de>
next in thread | raw e-mail | index | archive | help
>Number: 24223
>Category: kern
>Synopsis: "tail -f file" is a CPU hog when file is on an NFS volume
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Wed Jan 10 06:10:01 PST 2001
>Closed-Date:
>Last-Modified:
>Originator: Andre Albsmeier
>Release: FreeBSD 4.2-STABLE i386
>Organization:
>Environment:
FreeBSD 4.2-STABLE with a nfs mounted volume from another FreeBSD 4.2-STABLE
server.
>Description:
If "tail -f file" is executed for a file which resides on an NFS mounted
volume it consumes all CPU time.
>How-To-Repeat:
mount some-server:/filesystem /mnt
cat blah > /mnt/file
tail -f /mnt/file
run top in another window
>Fix:
unknown. tail spins around in the code segment below (forward.c).
The switch statement is called repeatedly with action == USE_KQUEUE.
for (;;) {
while ((ch = getc(fp)) != EOF)
if (putchar(ch) == EOF)
oerr();
if (ferror(fp)) {
ierr();
return;
}
(void)fflush(stdout);
if (! fflag)
break;
clearerr(fp);
switch (action) {
case ADD_EVENTS: {
int n = 0;
struct timespec ts = { 0, 0 };
if (Fflag && fileno(fp) != STDIN_FILENO) {
ev[n].ident = fileno(fp);
ev[n].filter = EVFILT_VNODE;
ev[n].flags = EV_ADD | EV_ENABLE | EV_CLEAR;
ev[n].fflags = NOTE_DELETE | NOTE_RENAME;
n++;
}
ev[n].ident = fileno(fp);
ev[n].filter = EVFILT_READ;
ev[n].flags = EV_ADD | EV_ENABLE;
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)
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 (fseek(fp, 0L, SEEK_END) == -1) {
ierr();
return;
}
}
break;
case USE_SLEEP:
(void) usleep(250000);
clearerr(fp);
if (Fflag && fileno(fp) != STDIN_FILENO &&
stat(fname, &sb2) != -1) {
if (sb2.st_ino != sbp->st_ino ||
sb2.st_dev != sbp->st_dev ||
sb2.st_rdev != sbp->st_rdev ||
sb2.st_nlink == 0) {
fp = freopen(fname, "r", fp);
if (fp == NULL) {
ierr();
break;
}
*sbp = sb2;
if (kq != -1)
action = ADD_EVENTS;
}
}
break;
}
}
}
/*
* rlines -- display the last offset lines of the file.
*/
static void
rlines(fp, off, sbp)
FILE *fp;
long off;
struct stat *sbp;
{
register off_t size;
register char *p;
char *start;
if (!(size = sbp->st_size))
return;
if (size > SIZE_T_MAX) {
errno = EFBIG;
ierr();
return;
}
if ((start = mmap(NULL, (size_t)size,
PROT_READ, MAP_SHARED, fileno(fp), (off_t)0)) == MAP_FAILED) {
ierr();
return;
}
/* Last char is special, ignore whether newline or not. */
for (p = start + size - 1; --size;)
if (*--p == '\n' && !--off) {
++p;
break;
}
/* Set the file pointer to reflect the length displayed. */
size = sbp->st_size - size;
WR(p, size);
if (fseek(fp, (long)sbp->st_size, SEEK_SET) == -1) {
ierr();
return;
}
if (munmap(start, (size_t)sbp->st_size)) {
ierr();
return;
}
}
>Release-Note:
>Audit-Trail:
>Unformatted:
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?200101101403.f0AE3gc13210>
