Monday, July 5, 2010

Ever seen a grown man naked?

Greetings everyone,

I've published a simple code which, however, targets some 'not so easy'
problems in vfs/reiserfs.

Like deadlock:

[  573.405720]
[  573.405722] =======================================================
[  573.405728] [ INFO: possible circular locking dependency detected ]
[  573.405732] 2.6.35-rc3-dbg-git6-00502-g94feaba-dirty #65
[  573.405735] -------------------------------------------------------
[  573.405739] a.out/7287 is trying to acquire lock:
[  573.405742]  (&sb->s_type->i_mutex_key#10){+.+.+.}, at: [] reiserfs_file_release+0x11d/0x344
[  573.405758]
[  573.405759] but task is already holding lock:
[  573.405762]  (&mm->mmap_sem){++++++}, at: [] sys_mmap_pgoff+0xa4/0xe7
[  573.405772]
[  573.405773] which lock already depends on the new lock.
[  573.405774]
[  573.405777]
[  573.405778] the existing dependency chain (in reverse order) is:
[  573.405781]
[  573.405782] -> #1 (&mm->mmap_sem){++++++}:
[  573.405789]        [] lock_acquire+0x59/0x70
[  573.405797]        [] might_fault+0x53/0x70
[  573.405803]        [] copy_to_user+0x30/0x48
[  573.405809]        [] filldir64+0x95/0xc9
[  573.405815]        [] reiserfs_readdir_dentry+0x35d/0x4d9
[  573.405821]        [] reiserfs_readdir+0x12/0x17
[  573.405827]        [] vfs_readdir+0x6d/0x92
[  573.405831]        [] sys_getdents64+0x63/0xa2
[  573.405836]        [] sysenter_do_call+0x12/0x32
[  573.405843]
[  573.405843] -> #0 (&sb->s_type->i_mutex_key#10){+.+.+.}:
[  573.405851]        [] __lock_acquire+0x96d/0xbe1
[  573.405857]        [] lock_acquire+0x59/0x70
[  573.405862]        [] __mutex_lock_common+0x39/0x36b
[  573.405869]        [] mutex_lock_nested+0x12/0x15
[  573.405874]        [] reiserfs_file_release+0x11d/0x344
[  573.405880]        [] fput+0xe0/0x16a
[  573.405886]        [] remove_vma+0x28/0x47
[  573.405892]        [] do_munmap+0x1e8/0x200
[  573.405897]        [] mmap_region+0x6b/0x372
[  573.405902]        [] do_mmap_pgoff+0x23c/0x282
[  573.405908]        [] sys_mmap_pgoff+0xbd/0xe7
[  573.405913]        [] sysenter_do_call+0x12/0x32
[  573.405919]
[  573.405920] other info that might help us debug this:
[  573.405921]
[  573.405925] 1 lock held by a.out/7287:
[  573.405928]  #0:  (&mm->mmap_sem){++++++}, at: [] sys_mmap_pgoff+0xa4/0xe7
[  573.405937]
[  573.405938] stack backtrace:
[  573.405942] Pid: 7287, comm: a.out Not tainted 2.6.35-rc3-dbg-git6-00502-g94feaba-dirty #65
[  573.405946] Call Trace:
[  573.405951]  [] ? printk+0xf/0x11
[  573.405957]  [] print_circular_bug+0x8a/0x96
[  573.405962]  [] __lock_acquire+0x96d/0xbe1
[  573.405969]  [] ? mark_lock+0x26/0x1b3
[  573.405975]  [] lock_acquire+0x59/0x70
[  573.405980]  [] ? reiserfs_file_release+0x11d/0x344
[  573.405986]  [] __mutex_lock_common+0x39/0x36b
[  573.405991]  [] ? reiserfs_file_release+0x11d/0x344
[  573.405997]  [] mutex_lock_nested+0x12/0x15
[  573.406003]  [] ? reiserfs_file_release+0x11d/0x344
[  573.406008]  [] reiserfs_file_release+0x11d/0x344
[  573.406014]  [] ? fput+0x90/0x16a
[  573.406019]  [] fput+0xe0/0x16a
[  573.406024]  [] remove_vma+0x28/0x47
[  573.406030]  [] ? arch_unmap_area_topdown+0x0/0x18
[  573.406035]  [] do_munmap+0x1e8/0x200
[  573.406040]  [] mmap_region+0x6b/0x372
[  573.406046]  [] do_mmap_pgoff+0x23c/0x282
[  573.406052]  [] sys_mmap_pgoff+0xbd/0xe7
[  573.406058]  [] sysenter_do_call+0x12/0x32



Error causing RO remount:
[  202.300464] REISERFS error (device sda9): vs-2100 add_save_link:
search_by_key ([-1 7812832 0x1 IND]) returned 1
[  202.300473] REISERFS (device sda9): Remounting filesystem read-only
[  202.301603] ------------[ cut here ]------------
[  202.301615] WARNING: at fs/reiserfs/journal.c:3436
journal_end+0x5b/0xaf()
[  202.301689] Pid: 5055, comm: a.out Not tainted
2.6.35-rc3-dbg-git6-00502-g94feaba-dirty #65
[  202.301693] Call Trace:
[  202.301701]  [] warn_slowpath_common+0x65/0x7a
[  202.301707]  [] ? journal_end+0x5b/0xaf
[  202.301712]  [] warn_slowpath_null+0xf/0x13
[  202.301718]  [] journal_end+0x5b/0xaf
[  202.301725]  [] reiserfs_truncate_file+0x19f/0x233
[  202.301733]  [] reiserfs_vfs_truncate_file+0xd/0xf
[  202.301738]  [] vmtruncate+0x23/0x29
[  202.301745]  [] inode_setattr+0x47/0x68
[  202.301751]  [] reiserfs_setattr+0x242/0x297
[  202.301758]  [] ? down_write+0x22/0x2a
[  202.301764]  [] notify_change+0x15c/0x26b
[  202.301770]  [] do_truncate+0x64/0x7d
[  202.301776]  [] ? _raw_spin_unlock+0x33/0x3f
[  202.301783]  [] do_last+0x450/0x459
[  202.301789]  [] do_filp_open+0x1c0/0x41a
[  202.301798]  [] ? get_parent_ip+0xb/0x31
[  202.301804]  [] ? sub_preempt_count+0x7c/0x89
[  202.301810]  [] ? alloc_fd+0xb4/0xbf
[  202.301816]  [] do_sys_open+0x48/0xdf
[  202.301821]  [] sys_open+0x1e/0x26
[  202.301827]  [] sysenter_do_call+0x12/0x32
[  202.301833] ---[ end trace c4e3312bdadd2dc5 ]---


And even OOps...

Al Viro wrote:
> OK...  See 22093b8f3d387f77 in vfs-2.6.git for-next (should
> propagate to git.kernel.org shortly).  That ought to deal with
> this crap, assuming I hadn't fucked up somewhere...


YAY!

/*
 * 2010, Sergey Senozhatsky. GPLv2
 *
*/

[..]


int main()
{
    char buf[4096];
    int i = 0;
    /* we don't really care */
    for (; i < 4096; i++)
        buf[i] = (i + 65) % 255;

    for (i = 0; i < 10; i++) {

        int pid = fork();
        if (pid > 0 ) {
            printf("parent...");
        } else if (pid == 0) {
           
            printf("child...\n");
            int fd = open("conftest.mmap", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0600);
            if (fd > 0) {
                printf("OPEN ok %d\n", fd);
                if (write(fd, buf, 4096) < 0)
                    printf("WRITE error\n");
                else
                    printf("WRITE ok\n");
               
                close(fd);
            } else {
                printf("OPEN error\n");
            }
           
            fd = open("conftest.mmap", O_RDWR|O_LARGEFILE);
            if (fd > 0) {
                printf("OPEN conftest.mmap %d\n", fd);
               
                void *map = mmap((void*)0xb78a8000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, fd, 0);
                if (map == MAP_FAILED) {
                    printf("MMAP failed\n");
                    close(fd);
                    goto out;
                } else {
                    printf("MMAP ok\n");
                }
               
                if (read(fd, buf, 4096) < 0)
                    printf("READ failed\n");
                else
                    printf("READ ok\n");

                close(fd);
                munmap(map, 4096);
            } else {
                printf("Error: can't open conftest.mmap\n");
            }
           
        out:
            fd = open(".", O_RDONLY|O_LARGEFILE);
            if (fd > 0) {
                printf("OPEN . ok %d... closing\n", fd);
                close(fd);
            } else {
                printf("OPEN error\n");
            }
           
            struct stat _stat;
            if (fstatat(AT_FDCWD, "conftest.mmap", &_stat, AT_SYMLINK_NOFOLLOW) < 0)
                printf("FSTATAT error\n");
            else
                printf("FSTATAT ok\n");
           
            if (unlinkat(AT_FDCWD, "conftest.mmap", 0) < 0)
                printf("UNLINKAT error\n");
            else
                printf("UNLINKAT ok\n");

            /*
             * Yep...
             * return 0;
             */
        } else {
            printf("FORK error\n");
        }
    }
   
    return 0;
}

No comments:

Post a Comment