proc 파일 시스템 프로그래밍

sangchu의 이미지

지금 proc 파일시스템에 대한 프로그래밍을 하고 있는데, 희한한 부분이 있어서 질문드립니다.
read_num을 생성한 파일시스템의 read_proc으로 등록시켰는데,
읽기를 수행하면 read_num 안의 printk("excute read_num")이 세번이 찍히네요.
세번을 호출한 일이 없는데 어찌 된일인지?

그리고 모듈 프로그래밍할 때 디버깅은 어떻게 하나요? gdb나 strace를 사용할 수 있는건가요?

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <net/arp.h>
#include <linux/types.h>
 
#define MODULE_ON	1
#define MODULE_OFF	0
 
static int num = MODULE_OFF;
static char buf[4*sizeof "123"];
 
char * inet_ntoa(struct in_addr ina)
{
    unsigned char *ucp = (unsigned char *)&ina;
 
    sprintf(buf, "%d.%d.%d.%d",
        ucp[0] & 0xff,
        ucp[1] & 0xff,
        ucp[2] & 0xff,
        ucp[3] & 0xff);
    return buf;
}
 
static int my_protocol_rcv(struct sk_buff *skb, struct net_device *dev,
                          struct packet_type *pt, struct net_device *orig_dev)
{
        unsigned char *p;
        int i;
        struct iphdr ipheader;
        struct in_addr in;
 
 
        if(skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK)
        {
                kfree_skb(skb);
                return 1;
        }
 
        printk("[Network]\n");
        //printk("\n");
 
        p = skb_network_header(skb);
 
        memcpy(&ipheader, p, sizeof(ipheader));
        in.s_addr = ipheader.saddr;
 
        printk("src ip : %s\n", inet_ntoa(in));
 
        in.s_addr = ipheader.daddr;
 
        printk("dst ip : %s\n", inet_ntoa(in));
 
        p = skb_mac_header(skb);
        printk("[MAC]\n");
        printk("dst mac : ");
        for(i=0; i<6; i++)
                printk("%x:", p[i]);
        printk("\n");
 
        printk("src mac : ");
        for(; i<12; i++)
                printk("%x:", p[i]);
        printk("\n");
        printk("\n");
 
        kfree_skb(skb);
        return 1;
}
 
static struct packet_type my_packet_type = {
        .type = __constant_htons(ETH_P_ALL),
        .func = my_protocol_rcv,
};
 
static int read_num(char * buffer, char ** start, off_t offset, int length)
{
	int size = sprintf(buffer, "goodday %d\n", num);
 
	*start = buffer + offset;
 
	size -= offset;
 
	printk("excute read_num\n");
 
	if(size>0)
	{
		if(size > length)
	      	return length;
		else
	      	return size;
	}
	else
	{
		if(size > length)
			return length;
		else
        		return 0;
        }
}
 
static int write_num(struct file * file, const char * buffer,
                        unsigned long count, void * data)
{
    int val = 0;
    char buf[16];
    char * endp;
 
    if(count > sizeof(buf))
        return -EINVAL;
 
    if(copy_from_user(buf, buffer, count))
        return -EFAULT;
 
    val = simple_strtoul(buf, &endp, 10);
 
    if(*endp != '\n')
        return -EINVAL;
 
    num = val;
 
	// here dev_add_pack
	if(val == MODULE_ON)
	    dev_add_pack(&my_packet_type);
	else if(val == MODULE_OFF)
        dev_remove_pack(&my_packet_type);
	else
		printk("dev_add_pack : 0 , dev_remove_pack : 1\n");
 
    return count;
}
 
static int num_init(void)
{
    struct proc_dir_entry * proc_dir_juhee;
    struct proc_dir_entry * proc_wr_num;
 
    proc_dir_juhee = proc_mkdir("juhee", 0);
 
    if(!proc_dir_juhee)
    {
        printk(KERN_ERR "cannot create /proc/juhee\n");
        return -ENOMEM;
    }
 
    proc_wr_num = create_proc_entry("num", 0, proc_dir_juhee);
 
    if(!proc_wr_num)
    {
        printk(KERN_ERR "cannot create /proc/juhee\n");
        remove_proc_entry("juhee", 0);
        return -ENOMEM;
    }
 
    proc_wr_num->read_proc = read_num;
    proc_wr_num->write_proc = write_num;
    proc_wr_num->data = num;
 
    return 0;
}
 
static void num_exit(void)
{
    remove_proc_entry("juhee/num", 0);
    remove_proc_entry("juhee", 0);
}
 
module_init(num_init);
module_exit(num_exit);
 
MODULE_LICENSE("GPL");

mithrandir의 이미지

코드를 코드블럭으로 감싸주시고 indentation도 넣어주세요. 이대로는 보기가 어려워서 대답할 마음도 가실겁니다;;
저는 커널 디버깅은 보통 printk;;; 로 합니다. 요새는 커널 유틸이 좋아져서 디버거 연결시키는 기능도 분명 있으리라 봅니다. 혹은 qemu나 bochs 등을 통해서 실행하고, gdb를 연결하는 것도 방법이겠지요.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

lacovnk의 이미지

제가 code lang='c'로 감쌌습니다.

mithrandir의 이미지

혹시 커널버전 몇을 사용하시나요?
제가 찾아본 커널들은 proc_read_entry에 해당하는 프로토타입이

proc_read_entry (
    char            *page,
    char            **start,
    off_t           off,
    int             count,
    int             *eof,
    void            *data);

처럼 되어서, 전부 읽었다면 *eof = 1 을 설정하게 되어있더군요.
계속 읽었다면 아마 저부분이 문제가 아닐까 합니다.

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

언제나 삽질 - http://tisphie.net/typo/
프로그래밍 언어 개발 - http://langdev.net

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.