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>