안녕하세요! 질문이 있어서 이렇게 글을 써봅니다.
밑에 BCM5358(MIPS계열) 커널 포팅 관련하여 글 올렸었데요.
디버깅을 진행하던 도중 slab에 관하여 궁금한게 있습니다.
지금 현재 Kernel Panic이 발생하는데 Call Trace를 보면 kmem_cache_alloc 함수가 호출된 것을 확인할수 있습니다.
그래서 kmem_cache_alloc 함수에 디버그 코드를 넣고 부팅을 시켜보니 메모리를 초기화한 이후에 kmem_cache_alloc 함수를
호출한걸 보면 slab으로 메모리 영역을 할당한걸로 보입니다.
현재는 kernel_init( )함수에서 do_basic_setup( ) 함수에서 멈춥니다. 추측하건데 메모리 영역 할당에 뭔가 문제가 생긴걸로 보이는데요.
메모리 관련 초기 설정에서 뭔가 잘못되면 위와 같은 증상이 생길수 있는지 궁금합니다.
고수님들의 많은 답변 부탁드려요~
댓글 9
-
최형호
2013.10.18 15:22
-
꽃의비밀
2013.10.18 16:25
친절한 답변 감사드립니다^^ 기본적인 정보를 언급하지 않았네요 ㅎㅎ
커널 소스는 2.6.32.27 이며, 아래의 소스는 init/main.c 에 start_kernel( ) 입니다.
proc_caches_init(); buffer_init(); key_init(); security_init(); //vfs_caches_init(totalram_pages); // DEBUG by JANG (2013-10-10) radix_tree_init(); #if 1 // debug by jang(2013-10-15) signals_init(); // debug by jang (2013-10-15) /* rootfs populating might need page-writeback */ page_writeback_init(); #ifdef CONFIG_PROC_FS proc_root_init(); // 여기서 멈춥니다. #endif cgroup_init(); cpuset_init(); taskstats_init_early(); delayacct_init();
proc_root_init( )에서 현재 멈추고 kernel panic이 발생합니다.
void __init proc_root_init(void) { int err; proc_init_inodecache(); err = register_filesystem(&proc_fs_type); if (err) return; proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); err = PTR_ERR(proc_mnt); if (IS_ERR(proc_mnt)) { unregister_filesystem(&proc_fs_type); return; } proc_symlink("mounts", NULL, "self/mounts"); proc_net_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); #endif proc_mkdir("fs", NULL); proc_mkdir("driver", NULL); proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) /* just give it a mountpoint */ proc_mkdir("openprom", NULL); #endif proc_tty_init(); #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); #endif proc_mkdir("bus", NULL); proc_sys_init(); }
위는 proc_root_init( ) 함수 입니다.INIT DEBUG MESSAGE small13-1!!!! [DEBUG] kmem_cache_alloc...... [DEBUG] kmem_cache_alloc...... [DEBUG] kmem_cache_alloc...... CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 800b6388, ra == 800b6334 Oops[#1]: Cpu 0 $ 0 : 00000000 11000000 00000000 003fffff $ 4 : 00000000 000080d0 8038b014 803d6958 $ 8 : 00000000 00000000 6b205d47 5f6d656d $12 : 68636163 00000000 00000000 6c615f65 $16 : 000080d0 11000001 00000000 00000000 $20 : 803d6958 80863424 8038b014 80430000 $24 : 00000002 801ce914 $28 : 803ce000 803cfef0 00000000 800b6334 Hi : 2a1482c2 Lo : b42e1b60 epc : 800b6388 kmem_cache_alloc+0x84/0x114 Not tainted ra : 800b6334 kmem_cache_alloc+0x30/0x114 Status: 11000002 KERNEL EXL Cause : 40808008 BadVA : 00000000 PrId : 00019749 (MIPS 74Kc) Modules linked in: Process swapper (pid: 0, threadinfo=803ce000, task=803d0600, tls=00000000) *HwTLS: 7ffbbdfd Stack : 838018a0 00000000 000000d0 0000004c 8038b014 80423f98 803daef0 00400000 800db520 00000088 83801900 00000088 803cff2c 803cff28 8038b014 80423f98 803daef0 00400000 803d6958 80863424 80760000 80863418 800bd92c 80863424 8038b014 803daef0 80420000 800d9398 8038af8c 80863424 803e0000 80423f98 80420000 80420000 80863320 803fc134 80412004 80423f98 803cff9c 80423f98 ... Call Trace: [<800b6388>] kmem_cache_alloc+0x84/0x114 [<800db520>] alloc_vfsmnt+0x3c/0x19c [<800bd92c>] vfs_kern_mount+0x38/0x100 [<803fc134>] proc_root_init+0x40/0xec [<803f1c78>] start_kernel+0x3e8/0x4d8 Code: 00000040 00000040 000000c0 <8e650000> 8ca20000 1040001c 2442ffff 00021880 00651821 Disabling lock debugging due to kernel taint Kernel panic - not syncing: Attempted to kill the idle task!
현재 상황은 위와 같습니다. proc_root_init( )을 주석처리 하면 kernel_init( )까지 진행되고 커널 패닉이 발생합니다.
-
주피터
2013.10.18 22:38
init/main.c 의 7줄에
//vfs_caches_init(totalram_pages); // DEBUG by JANG (2013-10-10)
가 주석처리 되어 있는데,
이게 주석 처리 되어 있어서 cache memory 가 초기화 되지 못해서,
그 후에 memory allocation 이 안 되는거라 생각이 듭니다.
주석처리한 부분을 주석 처리 하지 않고,
다른 방법으로 문제를 해결 해야 했으면 어떨가 하는 생각이 드네요.
-
꽃의비밀
2013.10.21 09:32
친절한 답변 감사합니다^^
주석 처리를 해제하고 부팅을 시켜보니 PCI 버스 초기화 하는 부분에서 에러(커널패닉)가 나네요.
아마 드라이버 로딩을 하다가 뭔가 문제가 있는거 같습니다.
NET: Registered protocol family 16 bio: create slab <bio-0> at 0 vgaarb: loaded SCSI subsystem initialized PCI: no core PCI: no core CPU 0 Unable to handle kernel paging request at virtual address 00000020, epc == 801a72bc, ra == 801a72ac Oops[#1]: Cpu 0 $ 0 : 00000000 11000000 83848280 83806c08 $ 4 : 83848380 00000000 00000000 00000000 $ 8 : 00000000 80005530 00004347 80350b80 $12 : 00000000 00000000 00000001 00000000 $16 : 838b6800 83848280 00000000 803d3a58 $20 : 00000000 00000000 00000000 00000000 $24 : 00000008 801ce904 $28 : 83818000 83819e48 00000000 801a72ac Hi : 00000000 Lo : 68dbc000 epc : 801a72bc pci_create_bus+0x5c/0x220 Not tainted ra : 801a72ac pci_create_bus+0x4c/0x220 Status: 11000003 KERNEL EXL IE Cause : 40808008 BadVA : 00000020 PrId : 00019749 (MIPS 74Kc) Modules linked in: Process swapper (pid: 1, threadinfo=83818000, task=83817b68, tls=00000000) Stack : 80439a28 ffffffff ffffffff 80420000 11000001 80420000 80340000 80420000 803f3210 00000001 80007760 80039f18 80400ad8 804200dc 11000001 80420000 11000001 803f32e4 8040080c 80400800 00000000 11000001 8041fde0 804200dc 8000c7fc 8000c7fc 80340000 8041fd50 80340000 00000000 00000000 00000000 00000000 80039f18 8041fde0 804200dc 80340000 8041fd50 80340000 00000000 ... Call Trace: [<801a72bc>] pci_create_bus+0x5c/0x220 [<80007760>] pci_scan_bus_parented+0x14/0x3c [<803f32e4>] pcibios_init+0xd4/0x138 [<8000c7fc>] do_one_initcall+0x3c/0x210 [<803f1814>] kernel_init+0x1b0/0x24c [<800171e0>] kernel_thread_helper+0x10/0x18 Code: 00408821 ae130068 ae12006c <8e440020> 0c06b452 02802821 14400029 3c13803e 0c002d11 Disabling lock debugging due to kernel taint Kernel panic - not syncing: Attempted to kill init!
드라이버 로딩 부분을 한번 살펴봐야 겠네요 ㅎㅎ좋은 정보 감사드립니다.
-
최형호
2013.10.21 13:44
안녕하세요.
커널 패닉에서 아래 부분이 pci_create_bus 의 몇번째 라인인지 해당 코드와 함께 붙여주시면 좀더 확인하기가 편할 것 같습니다.
[<801a72bc>] pci_create_bus+0x5c/0x220
행복한 하루되세요.
-
꽃의비밀
2013.10.23 09:51
친절한 답변 정말 감사합니다.^^
위의 커널패닉 문제는 해결하였습니다. 도움주신 덕분에 무난히 해결을 하게 되었습니다.
gdb를 사용하여 커널 패닉 발생 부분을 발견할수 있다는 걸 알았네요 ㅎㅎ. 많은 도움이 되었습니다.
간단하게 히스토리를 얘기하면
위의 call stack에서 pci_create_bus( ) 내에 pci_domain_nr( )함수 호출시 패닉이 발생했던거였습니다.
위 함수를 통해 domain number를 얻어오는데, 커널소스를 보니 함수 define 부분이 중복되는 부분이 있네요.
일단 부팅이 급선무여서 강제적으로 상수값으로 넣어줬습니다. (추후 디버깅 할예정.. 심각한 버그 유발 가능성 생각함 ㅋ)
그러니 문제없이 PCI 버스를 검색하고 초기화 합니다.
향후 커널 디버깅시 최형호님의 방법으로 진행하면 훨씬 수월할듯 합니다. 친절한 답변 감사드립니다.
근데.... 여기서 끝이 아니네요 ㅎ 부팅의 길은 멀기만 합니다.
파일시스템을 정상적으로 마운트 하지 못하는 문제가 발생하는데요.
Nand Flash에 squash 파일시스템을 사용합니다. 근데 희안하게 FAT로 마운트를 하려는게 보이네요..
아래는 커널 로그입니다.
앞부분 생략....
The first offset=200000, 2nd offset=1400000 Boot partition size = 524288(0x80000) lookup_nflash_rootfs_offset: offset = 0x200000 nflash: squash filesystem with lzma found at block 28 2nd offset 1400000 lookup_nflash_rootfs_offset: offset = 0x1400000 nflash: squash filesystem with lzma found at block 174 Creating 6 MTD partitions on "nflash": 0x000000000000-0x000000080000 : "boot" 0x000000080000-0x000000200000 : "nvram" 0x000000200000-0x000001400000 : "linux" 0x0000003930e0-0x000001400000 : "rootfs" 0x000001400000-0x000002600000 : "linux2" 0x0000015c1eb4-0x000002600000 : "rootfs2" Creating 1 MTD partitions on "brcmnand": 0x000002600000-0x000007f00000 : "brcmnand" PPP generic driver version 2.4.2 NET: Registered protocol family 24 Netlink kernel socket create failed GACT probability on Mirror/redirect action on netem: version 1.2 u32 classifier Performance counters on input device check on Actions configured Netfilter messages via NETLINK v0.30. nf_conntrack version 0.5.0 (946 buckets, 3784 max) ctnetlink v0.93: registering with nfnetlink. ip_tables: (C) 2000-2006 Netfilter Core Team TCP cubic registered NET: Registered protocol family 17 802.1Q VLAN Support v1.8 Ben Greear <greearb@candelatech.com> All bugs added by David S. Miller <davem@redhat.com> [DEBUG] do_basic_setup --- 7 do_basic_setup, 890!!!! INIT DEBUG MESSAGE haha2 kernel_init, 988!!!! FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive! FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive! List of all partitions: 1f00 512 mtdblock0 (driver?) 1f01 1536 mtdblock1 (driver?) 1f02 18432 mtdblock2 (driver?) 1f03 16819 mtdblock3 (driver?) 1f04 18432 mtdblock4 (driver?) 1f05 16632 mtdblock5 (driver?) 1f06 91136 mtdblock6 (driver?) No filesystem could mount root, tried: squashfs vfat msdos fuseblk Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,5)
위와 같은 증상인데요.. FAT로 왜 read하는지는 분석중입니다.
감사합니다.
추후 포팅이 완료되면 간단하게 히스토리 공유할 예정입니다.^^
-
꽃의비밀
2013.10.24 09:22
추가 질문 사항입니다. 루트 파일 시스템 마운트 관련하여 디버깅 하던 도중에 다음과 같은 현상이 발생합니다.
file_system_type 구조체에 파일시스템 정보를 등록을 하고 do_mount( ) 함수를 호출하여 마운트를 하는걸로 보이는데..
희안하게 file_system_type 구조체에서 get_sb( ) 함수를 호출하는데 이 함수를 타지 않더군요. 그래서 error 를 발생시켜서
제대로 파일시스템을 마운트 하지 못하는 상태입니다.
get_sb( )내에 printk써서 제대로 타지 않는것을 확인하였습니다.
즉 함수포인터를 제대로 호출을 하지 못하고 있네요...
어디 부분을 확인해 봐야 할까요...?
조언 부탁드립니다.
-
최형호
2013.10.22 17:19
아....
제가 너무 간략하게 답글을 달았나 보군요. 죄송합니다.
문제가 되는 바이너리를 빌드한 커널 코드가 있을텐데요.
해당 소스의 루트에 보시면 vmlinux가 생성이 되어있을 것입니다.
그러면 gdb 를 이용해서 아래와 같이 정확한 라인을 구할 수 있습니다.
(문제 발생이후 추가 수정을 하지 않았다면은요...)
예를 들어 0xc0486596 가 어느 소스의 어느 라인인지 보고 싶을 때 아래와 같이 하면 됩니다.
(아래는 제 환경에서 한 것이니 참고만 하세요.)
$ gdb vmlinux
(gdb) l *0xc0486596
0xc0486596 is in start_kernel (init/main.c:648).
643 *
644 *******************************************************************************/
645 setup_arch(&command_line);
646 mm_init_owner(&init_mm, &init_task);
647 mm_init_cpumask(&init_mm);
648 setup_command_line(command_line);
649 setup_nr_cpu_ids();
650 setup_per_cpu_areas();
651 smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
652
(gdb)
"l *주소" 이런식으로 gdb에 명령을 입력하면 위의 빨간색으로 된 문장처럼 해당 주소에 해당하는 파일명과 라인을 알수있습니다.
이 방법을 이용하면 커널 패닉이 발생한 곳을 정확히 얻을 수 있습니다.
현재 커널 패닉이 아래와 같은데 앞부분을 보면 문제 발생 주소가 보입니다.
call stack의 마지막 부분의 (제일 윗부분) 주소가 0x801a72bc 와 같습니다.
[<801a72bc>] pci_create_bus+0x5c/0x220
[<80007760>] pci_scan_bus_parented+0x14/0x3c
[<803f32e4>] pcibios_init+0xd4/0x138
[<8000c7fc>] do_one_initcall+0x3c/0x210
[<803f1814>] kernel_init+0x1b0/0x24c
[<800171e0>] kernel_thread_helper+0x10/0x18
그러므로 "l *0x801a72bc" 라는 명령으로 (앞에는 i 가 아니고 소문자 L 입니다.) 문제 발생 파일명과 라인을 알수있습니다.
좀더 정확한 분석을 위해 단수히 파일명과 라인이 아니라
"disas/m 0x801a72bc" 명령을 실행해서 0x801a72bc 부근의 어셈및 소스를 복사해서 보여주면 좋을 것 같습니다.
두서없이 내용이 길었는데요.
요약하면 gdb를 이용하여 아래 정보를 알려주시면 된다는 것입니다.
1. l *0x801a72bc 를 통해 파일명 및 라인
2. disas/m 0x801a72bc 으로 소스및 어셈코드
아마 2번만 해주셔도 분석에 많은 도움이 될 것으로 생각됩니다.
행복한 하루되세요.
-
꽃의비밀
2013.10.22 13:59
안녕하세요! 답이 늦었습니다.^^
BCM5358에서 PCI버스를 쓰는지 여부를 확인할수가 없는데.. PCI버스를 써야 되더라구요. (flash 사용시..)
관련코드 첨부합니다.
struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { int error; struct pci_bus *b; struct device *dev; b = pci_alloc_bus(); #if 1 // DEBUG BY JANG (2013-10-22) printk(KERN_CRIT "[DEBUG] return.... n"); //return b; #endif if (!b) return NULL; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev){ kfree(b); return NULL; } printk(KERN_CRIT "[DEBUG] return....1 n"); b->sysdata = sysdata; b->ops = ops; if (pci_find_bus(pci_domain_nr(b), bus)) { /* If we already got to this bus through a different bridge, ignore it */ pr_debug("PCI: Bus %04x:%02x already knownn", pci_domain_nr(b), bus); goto err_out; } printk(KERN_CRIT "[DEBUG] return....2 n"); down_write(&pci_bus_sem); list_add_tail(&b->node, &pci_root_buses); up_write(&pci_bus_sem); printk(KERN_CRIT "[DEBUG] return....3 n"); dev->parent = parent; dev->release = pci_release_bus_bridge_dev; dev_set_name(dev, "pci%04x:%02x", pci_domain_nr(b), bus); error = device_register(dev); if (error) goto dev_reg_err; b->bridge = get_device(dev); if (!parent) set_dev_node(b->bridge, pcibus_to_node(b)); b->dev.class = &pcibus_class; b->dev.parent = b->bridge; dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus); error = device_register(&b->dev); if (error) goto class_dev_reg_err; error = device_create_file(&b->dev, &dev_attr_cpuaffinity); if (error) goto dev_create_file_err; /* Create legacy_io and legacy_mem files for this bus */ pci_create_legacy_files(b); b->number = b->secondary = bus; b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; return b; dev_create_file_err: device_unregister(&b->dev); class_dev_reg_err: device_unregister(dev); dev_reg_err: down_write(&pci_bus_sem); list_del(&b->node); up_write(&pci_bus_sem); err_out: kfree(dev); kfree(b); return NULL; }
printk를 써서 어디서 멈추는지 대략 확인해본 결과 pci_find_bus( )에서 멈추고 커널패닉이 발생하는거 같습니다.알기가 어렵네요 ㅎㅎ
.
안녕하세요.
주제넘다 하지 마시고 들어주셨으면 감사하겠습니다.
진짜 고수라도 아마 님께서 말씀하신 것만으로 문제를 분석하는 것은 하늘에 별따기 입니다.
아마 계속 글을 올리셔도 아마 원하는 답변을 얻기 쉽지 않으실겁니다.
패닉도 그렇고 락업도 그렇고 수백 수천가지 이상의 원인으로 발생할수있기 때문에 이런부분이 문제가 같다고 말하기 어려운 것입니다.
커널 패닉이 났으면 로그 정보라도 붙여주시고 해당 코드들도 남겨주셔야 그나마 분석이 될까 합니다.
패닉시 보여지는 콜스택도 생성된 vmlinux 마다 함수의 주소도 달라지기 때문에 해당 함수의 내용과 패닉위치등도 보여주시는게 좋습니다.
디버깅을 위한 많은 방법들이 있겠지만 제가 주로 사용하는 방법을 언급하자면,
- 의심되는 부분에 로그 넣어보기
- gdb 혹은 trace32 같은 디버깅 전문 툴 사용하기
타겟에 serial port가 있다면 kgdb를 그리 어렵지 않게 연결해서 문제가 되는 부분을 찾으실 수 있을 것 같습니다.
다만 gdb 사용법이 익숙치 않으면 어려울수도 있습니다.