커널의 에러 코드 정의
리눅스 커널에서 사용되는 에러 코드들은 아래 파일들에 정의되어 있다.
- 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);
'임베디드 개발 > 리눅스 디바이스 드라이버' 카테고리의 다른 글
Linux Kernel ] Container_of (0) | 2025.02.06 |
---|---|
Device tree compiler 사용법 (0) | 2025.01.27 |
LDD ] PCIe 디바이스 드라이버 작성하기 - (2) (0) | 2025.01.15 |
VSCode에서 리눅스 커널 모듈 개발시 Intellisense Error 없애기 (0) | 2024.12.29 |
LDD ] PCIe 디바이스 드라이버 작성하기 - (1) (0) | 2024.12.25 |