본문 바로가기
임베디드 개발/리눅스 디바이스 드라이버

Linux Kernel ] Error Handling

by eteo 2025. 2. 3.

 

 

 

커널의 에러 코드 정의

 

리눅스 커널에서 사용되는 에러 코드들은 아래 파일들에 정의되어 있다.

- include/uapi/asm-generic/errno-base.h

- include/uapi/asm-generic/errno.h

 

errno-base.h 파일은 기본 에러 코드들을 정의하며, error.h 파일은 errno-base.h 파일을 포함하며 추가적으로 아키텍처나 환경에 따라 확장된 에러 코드를 제공한다.

 

errno-base.h

/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _ASM_GENERIC_ERRNO_BASE_H
#define _ASM_GENERIC_ERRNO_BASE_H

#define	EPERM		 1	/* Operation not permitted */
#define	ENOENT		 2	/* No such file or directory */
#define	ESRCH		 3	/* No such process */
#define	EINTR		 4	/* Interrupted system call */
#define	EIO		 5	/* I/O error */
#define	ENXIO		 6	/* No such device or address */
#define	E2BIG		 7	/* Argument list too long */
#define	ENOEXEC		 8	/* Exec format error */
#define	EBADF		 9	/* Bad file number */
#define	ECHILD		10	/* No child processes */
#define	EAGAIN		11	/* Try again */
#define	ENOMEM		12	/* Out of memory */
#define	EACCES		13	/* Permission denied */
#define	EFAULT		14	/* Bad address */
#define	ENOTBLK		15	/* Block device required */
#define	EBUSY		16	/* Device or resource busy */
#define	EEXIST		17	/* File exists */
#define	EXDEV		18	/* Cross-device link */
#define	ENODEV		19	/* No such device */
#define	ENOTDIR		20	/* Not a directory */
#define	EISDIR		21	/* Is a directory */
#define	EINVAL		22	/* Invalid argument */
#define	ENFILE		23	/* File table overflow */
#define	EMFILE		24	/* Too many open files */
#define	ENOTTY		25	/* Not a typewriter */
#define	ETXTBSY		26	/* Text file busy */
#define	EFBIG		27	/* File too large */
#define	ENOSPC		28	/* No space left on device */
#define	ESPIPE		29	/* Illegal seek */
#define	EROFS		30	/* Read-only file system */
#define	EMLINK		31	/* Too many links */
#define	EPIPE		32	/* Broken pipe */
#define	EDOM		33	/* Math argument out of domain of func */
#define	ERANGE		34	/* Math result not representable */

#endif

 

 

 

일반적인 에러 반환 방식

 

위 파일에는 에러 코드가 양수 값으로 정의되어 있는데 이는 POSIX 표준과의 호환성을 유지하기 위함이며, 리눅스 커널에서는 일반적으로 에러를 음수 값으로 반환한다.

 

예를 들어, 함수가 성공하면 양수 또는 0을 반환하고, 에러가 발생하면 음수 값으로 -EIO, -ENOMEM과 같은 특정 에러 코드를 반환한다.

 

 

 

 

포인터 반환 함수의 에러 처리

 

리눅스 커널에서는 함수가 포인터를 반환하는 경우가 매우 흔한데 이런 함수가 에러를 나타내야 할 때는 음수 에러 코드를 void * 타입으로 변환하여 리턴한다. 그 이유는 다음과 같다.

 

1. 기존 반환 타입과의 일관성을 유지한다.

2. 음수 값은 최상위 비트가 1인데, 리눅스에서 상위 주소 범위는 유효하지 않은 가상 메모리 주소로 예약되어 있어 유효한 포인터 값이 아님이 명확히 구별된다. 

 

포인터 반환 함수의 에러 처리를 위해 사용되는 주요 매크로는 다음과 같으며 /include/linux/err.h 파일에 정의되어 있다.

 

  • ERR_PTR : 음수 에러 코드를 포인터로 변환한다.
  • IS_ERR : 포인터가 에러를 나타내는 값인지 확인한다.
  • PTR_ERR : 포인터에서 원래의 음수 에러 코드를 추출한다.

 

void *example_function(int param) {
    if (param < 0) {        
    	// 에러가 있는 경우 음수 에러 코드를 void *로 변환하는 매크로 사용하여 반환
        return ERR_PTR(-EINVAL);
    }
    
    // 정상적인 경우 유효한 포인터 반환
    return (void *)0x12345678;
}

 

 

void *result = example_function(-1);

// 에러인지 확인하여 에러인 경우 에러 코드 출력
if (IS_ERR(result)) {
    long err = PTR_ERR(result);
    pr_err("Function failed with error: %ld\n", err);
    return;
}

pr_info("Function succeeded, result: %p\n", result);