Subject: kern/9994: combination of ftruncate() and lseek() can cause LFS panic
To: None <gnats-bugs@gnats.netbsd.org>
From: IWAMOTO Toshihiro <iwamoto@sat.t.u-tokyo.ac.jp>
List: netbsd-bugs
Date: 04/27/2000 08:48:17
>Number:         9994
>Category:       kern
>Synopsis:       combination of ftruncate() and lseek() can cause LFS panic
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Apr 27 08:49:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator:     IWAMOTO Toshihiro
>Release:        today's -current
>Organization:

>Environment:
	
System: NetBSD miyuki.my.domain 1.4X NetBSD 1.4X (MASH) #45: Thu Apr 27 23:33:06 JST 2000 toshii@miyuki.my.domain:/usr/src/syssrc/sys/arch/i386/compile/MASH i386


>Description:
	Intense inode changes can cause inconsistency of LFS.
	Here is a ten-finger copy of a panic. This problem should not
	be related to recent fixes to PR #9926, as older versions of lfs_*.c
	also cause panics.

# cc test.c (the attached test program)
# ./a.out
lfs_inode: 32 frags released > 25 in inode 6
lfs_inode: 64 frags released > 63 in inode 6
lfs_inode: 40 frags released > 28 in inode 6
panic: lfs_truncate: frag count < 0 (144<244), ino 6

Stopped in a.out at     cpu_Debugger+0x4:       leave
db> tr
cpu_Debugger(...) at cpu_Debugger+0x4
panic(...) at panic+0x55
lfs_truncate(c7b5ce80) at lfs_truncate+0x1200
ufs_setattr(c7b5cebc,c7b5cf88,c797976c,c7b5cf80,c7b5cf88) at ufs_setattr+0x1d4
sys_ftruncate(c797976c,c7b5cf88,c7b5cf80,0,4ed7) at sys_ftruncate+0xfd
syscall() at syscall+0x1ed

>How-To-Repeat:
	Execute the following code. The system will panic in seconds.
	I didn't confirmed if any of read(), write() or usleep() can be
	omitted to invoke kernel panics.
	
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char** argv) {
    char hoge[8192], buf[8192];
    int fd, i, j, k;

    for(i=0; i<sizeof(hoge); i++)
        hoge[i] = (i / 7) & 0xff;

    sprintf(buf, "test.%d", getpid());
    unlink(buf);

    fd = open(buf, O_RDWR | O_CREAT, 0644);
    if (fd < 0) {
        perror("open");
        exit(1);
    }
    srandom(time(0));

    for(i=0; i<10000; i++) {
        j = random() % 3;
        k = random() & 0x3fffff;
        if (j != 2)
            if (lseek(fd, k, SEEK_SET) < 0) {
                perror("read");
                exit(1);
            }

        switch(j) {
        case 0:
            if (read(fd, buf, sizeof(buf)) < 0) {
                perror("read");
                exit(1);
            }
            break;
        case 1:
            if (write(fd, hoge, sizeof(hoge)) < 0) {
                perror("write");
                exit(1);
            }
            break;
        case 2:
            if (ftruncate(fd, k) < 0) {
                perror("write");
                exit(1);
            }
            break;
        }
        j = random() % 100*1000;
        usleep(j);
    }
    exit(0);
}
>Fix:
	
>Release-Note:
>Audit-Trail:
>Unformatted: