Linux Kernel 4.x의 proc 파일 시스템 예제 코드

/**
 *      file    : proc.c
 *      brief   : procfs of kernel version 4.x
 *      author  : Jihoon Park (INSLAB)
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#define DIRECTORY	"ai_result"

#define FILE_PREDICT0	"prediction0"
#define FILE_PREDICT1	"prediction1"
#define FILE_NETSTAT0	"netstat0"
#define FILE_NETSTAT1	"netstat1"

#define FILE_MAX_SIZE	100

static struct proc_dir_entry *predict0_file, *predict1_file, *netstat0_file, *netstat1_file, *netstat_dir;

char file_value[4][FILE_MAX_SIZE];

/* proc file에 데이터를 쓰는 함수 */
static ssize_t write(struct file *file, const char *buf, size_t count, loff_t *pos)
{
    int len;
    int target_idx;
    char *file_name = file->f_path.dentry->d_iname;

    len = (count > FILE_MAX_SIZE) ? FILE_MAX_SIZE : count;

    if(!strcmp(file_name, "prediction0")) 	target_idx = 0;
    else if(!strcmp(file_name, "prediction1"))	target_idx = 1;
    else if(!strcmp(file_name, "netstat0"))	target_idx = 2;
    else if(!strcmp(file_name, "netstat1"))	target_idx = 3;
    
    if (raw_copy_from_user(file_value[target_idx], buf, len))    //write 실패시 error return
	    return -EFAULT; // address error
    file_value[target_idx][len] = 0x00;

    return len;
}
 
/* proc file을 읽을 경우 실행되는 함수 */
static int proc_show(struct seq_file *m, void *v) 
{
	char *file_name = m->file->f_path.dentry->d_iname;
	int target_idx;
	
	if(!strcmp(file_name, "prediction0"))		target_idx = 0;
    	else if(!strcmp(file_name, "prediction1"))	target_idx = 1;
    	else if(!strcmp(file_name, "netstat0"))		target_idx = 2;
    	else if(!strcmp(file_name, "netstat1"))		target_idx = 3;

    	seq_printf(m, "%s", file_value[target_idx]); // 출력 형식
    	return 0;
}
    
static int proc_open(struct inode *inode, struct  file *file)
{
	return single_open(file, proc_show, NULL);
}

// file_operations 구조체 초기화
// c99 버전부터 아래와 같은 방식으로 초기화 가능
static const struct file_operations proc_fops = { 
    .owner = THIS_MODULE,
     //파일을 열때 불려지는 함수
    .open = proc_open,
     // 파일을 읽을때 불려지는 함수
    .read = seq_read,
     // 파일을 쓸때 불려지는 함수
    .write = write,
    .llseek = seq_lseek,
    .release = single_release,
}; 

/* module 적재 함수 */
static int mod_procfs_init(void)
{
	int i;

	for(i=0; i<3; i++)
		strcpy(file_value[i], "0");
	
	netstat_dir = proc_mkdir(DIRECTORY, NULL);
	
	// procfs 파일 생성
	// 파일이름, 퍼미션, 디렉토리, file_operations 구조체
	predict0_file = proc_create(FILE_PREDICT0, 0646, netstat_dir, &proc_fops);
	predict1_file = proc_create(FILE_PREDICT1, 0646, netstat_dir, &proc_fops);
	netstat0_file = proc_create(FILE_NETSTAT0, 0646, netstat_dir, &proc_fops);
	netstat1_file = proc_create(FILE_NETSTAT1, 0646, netstat_dir, &proc_fops);

	if(predict0_file == NULL || predict1_file == NULL || netstat0_file == NULL || netstat1_file == NULL )
	{ 
		printk("netsat_file: error \n");
		return -EEXIST;
	}
	
	printk("%s\n", __FUNCTION__);
	
	return 0;
}

/* 모듈 제거 함수 */
static void mod_procfs_exit(void){
    remove_proc_entry(FILE_PREDICT0, netstat_dir);
    remove_proc_entry(FILE_PREDICT1, netstat_dir);
    remove_proc_entry(FILE_NETSTAT0, netstat_dir);
    remove_proc_entry(FILE_NETSTAT1, netstat_dir);
    remove_proc_entry(DIRECTORY, NULL);

    printk("%s\n", __FUNCTION__);
}
 
module_init(mod_procfs_init);
module_exit(mod_procfs_exit);


MODULE_LICENSE("INSLAB");

 

Linux Kernel 5.x의 proc 파일 시스템 예제 코드

/**
 *      file    : proc.c
 *      brief   : procfs of kernel version 5.x
 *      author  : Jihoon Park (INSLAB)
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/string.h>

#define DIRECTORY       "inslab"

#define FILE_RESULT0    "result0"
#define FILE_RESULT1    "result1"
#define FILE_NETSTAT0   "netstat0"
#define FILE_NETSTAT1   "netstat1"

#define FILE_MAX_SIZE   100

static struct proc_dir_entry *result0_file, *result1_file, *netstat0_file, *netstat1_file, *netstat_dir;

char file_value[4][FILE_MAX_SIZE];

/* proc file에 데이터를 쓰는 함수 */
static ssize_t write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
    int len;
    int target_idx;
    char *file_name = file->f_path.dentry->d_iname;

    len = (count > FILE_MAX_SIZE) ? FILE_MAX_SIZE : count;

    if(!strcmp(file_name, "result0"))           target_idx = 0;
    else if(!strcmp(file_name, "result1"))      target_idx = 1;
    else if(!strcmp(file_name, "netstat0"))     target_idx = 2;
    else if(!strcmp(file_name, "netstat1"))     target_idx = 3;

    if (raw_copy_from_user(file_value[target_idx], buf, len))    //write 실패시 error return
            return -EFAULT; // address error
    file_value[target_idx][len] = 0x00;

    return len;
}

/* proc file로부터 데이터를 읽는 함수 */
static ssize_t read(struct file *file, char __user *buff, size_t count, loff_t *pos)
{
        int len = 0;
        int target_idx = 0;
        char *file_name = file->f_path.dentry->d_iname;

        /* proc을 read하면 반복적으로 읽히는 현상이 발생한다.
         * 커널 버그인지는 잘 모르겠지만 반복 읽힘 문제를 해결하기
         * 위해 completed 변수로 반복을 제어하는 코드를 추가하였다.
         *
         * ref : https://github.com/ray326/hw1
         **/
        static int completed = 0;
        if (completed) {
                completed = 0;
                return 0;
        }
        completed = 1;

        if(!strcmp(file_name, "result0"))       target_idx = 0;
        else if(!strcmp(file_name, "result1"))  target_idx = 1;
        else if(!strcmp(file_name, "netstat0")) target_idx = 2;
        else if(!strcmp(file_name, "netstat1")) target_idx = 3;

        len = strlen(file_value[target_idx]);
        if (raw_copy_to_user(buff, file_value[target_idx], len))
                return -EFAULT;

        return len;
}



// proc_ops 구조체 초기화
static const struct proc_ops proc_fops = {
     // 파일을 읽을때 불려지는 함수
     .proc_read = read,
     // 파일을 쓸때 불려지는 함수
     .proc_write = write
};

/* module 적재 함수 */
static int mod_procfs_init(void)
{
        int i;

        for(i=0; i<4; i++)
                strcpy(file_value[i], "0\0");

        netstat_dir = proc_mkdir(DIRECTORY, NULL);

        // procfs 파일 생성
        // 파일이름, 퍼미션, 디렉토리, file_operations 구조체
        result0_file = proc_create(FILE_RESULT0, 0646, netstat_dir, &proc_fops);
        result1_file = proc_create(FILE_RESULT1, 0646, netstat_dir, &proc_fops);
        netstat0_file = proc_create(FILE_NETSTAT0, 0646, netstat_dir, &proc_fops);
        netstat1_file = proc_create(FILE_NETSTAT1, 0646, netstat_dir, &proc_fops);

        if(result0_file == NULL || result1_file == NULL || netstat0_file == NULL || netstat1_file == NULL )
        {
                printk("netsat_file: error \n");
                return -EEXIST;
        }

        printk("inslab_proc : %s\n", __FUNCTION__);

        return 0;
}

/* 모듈 제거 함수 */
static void mod_procfs_exit(void){
    remove_proc_entry(FILE_RESULT0, netstat_dir);
    remove_proc_entry(FILE_RESULT1, netstat_dir);
    remove_proc_entry(FILE_NETSTAT0, netstat_dir);
    remove_proc_entry(FILE_NETSTAT1, netstat_dir);
    remove_proc_entry(DIRECTORY, NULL);

    printk("inslab_proc : %s\n", __FUNCTION__);
}

module_init(mod_procfs_init);
module_exit(mod_procfs_exit);


MODULE_LICENSE("INSLAB");

 

약간의 설명

리눅스 4점대 커널 버전에서는 proc operation을 file_operations 구조체로 관리하였다.

하지만 5점대 커널 버전에서는 proc operation을 따로 proc_ops 구조체로 관리하고 있다.

따라서, 4점대에서 사용하던 proc 파일시스템 코드를 사용하지 못해 5점대에서는 위와 같이 업데이트 해주어야 한다.

 

Ref..

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기