linux内核函数出错的返回值

1. 函数返回指针

内核中的函数通常以返回指针的形式来传递调用函数后执行的结果,返回值指针有三种结果:

  1. 调用成功则返回一个有效指针
  2. 调用失败返回NULL,例如malloc、kmalloc、vmalloc
  3. 调用失败返回错误信息指针(无效指针)

内核中通过这个错误指针来传递有关错误的信息。

2. 如何通过错误信息指针来返回错误信息

在linux中虚拟内存空间的分配,0~3G是给用户空间的,而3G~4G是给linux内核的,而0xFFFFF000就位于linux内核的虚拟内存空间范围内,内核返回的指针(ptr)通常指向页的边界(4KB),也ptr指向的空间不会在(0xFFFFF000~0xFFFFFFFF)区间(因为小于一页),即:ptr & 0XFFF == 0;而一般内核出错代码返回值是一个负数,在 -1000~0之间,转变成unsigned long型,刚好在(0xFFFFF000~0xFFFFFFFF)区间。所以就可以用(unsigned long)ptr > (unsigned long)-1000L来判断内核函数的返回值是一个有效的指针,还是一个出错代码。

3. 出错代码返回指针在(-1000,0)区间

  1. include/uapi/asm-generic/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
    
  2. include/uapi/asm-generic/errno.h文件中如下:

    /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
    #ifndef _ASM_GENERIC_ERRNO_H
    #define _ASM_GENERIC_ERRNO_H
    
    #include <asm-generic/errno-base.h>
    
    #define EDEADLK         35      /* Resource deadlock would occur */
    #define ENAMETOOLONG    36      /* File name too long */
    #define ENOLCK          37      /* No record locks available */
    
    /*
     * This error code is special: arch syscall entry code will return
     * -ENOSYS if users try to call a syscall that doesn't exist.  To keep
     * failures of syscalls that really do exist distinguishable from
     * failures due to attempts to use a nonexistent syscall, syscall
     * implementations should refrain from returning -ENOSYS.
     */
    #define ENOSYS          38      /* Invalid system call number */
    
    #define ENOTEMPTY       39      /* Directory not empty */
    #define ELOOP           40      /* Too many symbolic links encountered */
    #define EWOULDBLOCK     EAGAIN  /* Operation would block */
    #define ENOMSG          42      /* No message of desired type */
    #define EIDRM           43      /* Identifier removed */
    #define ECHRNG          44      /* Channel number out of range */
    #define EL2NSYNC        45      /* Level 2 not synchronized */
    #define EL3HLT          46      /* Level 3 halted */
    #define EL3RST          47      /* Level 3 reset */
    #define ELNRNG          48      /* Link number out of range */
    #define EUNATCH         49      /* Protocol driver not attached */
    #define ENOCSI          50      /* No CSI structure available */
    #define EL2HLT          51      /* Level 2 halted */
    #define EBADE           52      /* Invalid exchange */
    #define EBADR           53      /* Invalid request descriptor */
    #define EXFULL          54      /* Exchange full */
    #define ENOANO          55      /* No anode */
    #define EBADRQC         56      /* Invalid request code */
    #define EBADSLT         57      /* Invalid slot */
    
    #define EDEADLOCK       EDEADLK
    
    #define EBFONT          59      /* Bad font file format */
    #define ENOSTR          60      /* Device not a stream */
    #define ENODATA         61      /* No data available */
    #define ETIME           62      /* Timer expired */
    #define ENOSR           63      /* Out of streams resources */
    #define ENONET          64      /* Machine is not on the network */
    #define ENOPKG          65      /* Package not installed */
    #define EREMOTE         66      /* Object is remote */
    #define ENOLINK         67      /* Link has been severed */
    #define EADV            68      /* Advertise error */
    #define ESRMNT          69      /* Srmount error */
    #define ECOMM           70      /* Communication error on send */
    #define EPROTO          71      /* Protocol error */
    #define EMULTIHOP       72      /* Multihop attempted */
    #define EDOTDOT         73      /* RFS specific error */
    #define EBADMSG         74      /* Not a data message */
    #define EOVERFLOW       75      /* Value too large for defined data type */
    #define ENOTUNIQ        76      /* Name not unique on network */
    #define EBADFD          77      /* File descriptor in bad state */
    #define EREMCHG         78      /* Remote address changed */
    #define ELIBACC         79      /* Can not access a needed shared library */
    #define ELIBBAD         80      /* Accessing a corrupted shared library */
    #define ELIBSCN         81      /* .lib section in a.out corrupted */
    #define ELIBMAX         82      /* Attempting to link in too many shared libraries */
    #define ELIBEXEC        83      /* Cannot exec a shared library directly */
    #define EILSEQ          84      /* Illegal byte sequence */
    #define ERESTART        85      /* Interrupted system call should be restarted */
    #define ESTRPIPE        86      /* Streams pipe error */
    #define EUSERS          87      /* Too many users */
    #define ENOTSOCK        88      /* Socket operation on non-socket */
    #define EDESTADDRREQ    89      /* Destination address required */
    #define EMSGSIZE        90      /* Message too long */
    #define EPROTOTYPE      91      /* Protocol wrong type for socket */
    #define ENOPROTOOPT     92      /* Protocol not available */
    #define EPROTONOSUPPORT 93      /* Protocol not supported */
    #define ESOCKTNOSUPPORT 94      /* Socket type not supported */
    #define EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
    #define EPFNOSUPPORT    96      /* Protocol family not supported */
    #define EAFNOSUPPORT    97      /* Address family not supported by protocol */
    #define EADDRINUSE      98      /* Address already in use */
    #define EADDRNOTAVAIL   99      /* Cannot assign requested address */
    #define ENETDOWN        100     /* Network is down */
    #define ENETUNREACH     101     /* Network is unreachable */
    #define ENETRESET       102     /* Network dropped connection because of reset */
    #define ECONNABORTED    103     /* Software caused connection abort */
    #define ECONNRESET      104     /* Connection reset by peer */
    #define ENOBUFS         105     /* No buffer space available */
    #define EISCONN         106     /* Transport endpoint is already connected */
    #define ENOTCONN        107     /* Transport endpoint is not connected */
    #define ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
    #define ETOOMANYREFS    109     /* Too many references: cannot splice */
    #define ETIMEDOUT       110     /* Connection timed out */
    #define ECONNREFUSED    111     /* Connection refused */
    #define EHOSTDOWN       112     /* Host is down */
    #define EHOSTUNREACH    113     /* No route to host */
    #define EALREADY        114     /* Operation already in progress */
    #define EINPROGRESS     115     /* Operation now in progress */
    #define ESTALE          116     /* Stale file handle */
    #define EUCLEAN         117     /* Structure needs cleaning */
    #define ENOTNAM         118     /* Not a XENIX named type file */
    #define ENAVAIL         119     /* No XENIX semaphores available */
    #define EISNAM          120     /* Is a named type file */
    #define EREMOTEIO       121     /* Remote I/O error */
    #define EDQUOT          122     /* Quota exceeded */
    
    #define ENOMEDIUM       123     /* No medium found */
    #define EMEDIUMTYPE     124     /* Wrong medium type */
    #define ECANCELED       125     /* Operation Canceled */
    #define ENOKEY          126     /* Required key not available */
    #define EKEYEXPIRED     127     /* Key has expired */
    #define EKEYREVOKED     128     /* Key has been revoked */
    #define EKEYREJECTED    129     /* Key was rejected by service */
    
    /* for robust mutexes */
    #define EOWNERDEAD      130     /* Owner died */
    #define ENOTRECOVERABLE 131     /* State not recoverable */
    
    #define ERFKILL         132     /* Operation not possible due to RF-kill */
    
    #define EHWPOISON       133     /* Memory page has hardware error */
    
    #endif
    
  3. ./include/linux/errno.h文件中

    /* SPDX-License-Identifier: GPL-2.0 */
    #ifndef _LINUX_ERRNO_H
    #define _LINUX_ERRNO_H
    
    #include <uapi/linux/errno.h>
    
    
    /*
     * These should never be seen by user programs.  To return one of ERESTART*
     * codes, signal_pending() MUST be set.  Note that ptrace can observe these
     * at syscall exit tracing, but they will never be left for the debugged user
     * process to see.
     */
    #define ERESTARTSYS     512
    #define ERESTARTNOINTR  513
    #define ERESTARTNOHAND  514     /* restart if no handler.. */
    #define ENOIOCTLCMD     515     /* No ioctl command */
    #define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */
    #define EPROBE_DEFER    517     /* Driver requests probe retry */
    #define EOPENSTALE      518     /* open found a stale dentry */
    #define ENOPARAM        519     /* Parameter not supported */
    
    /* Defined for the NFSv3 protocol */
    #define EBADHANDLE      521     /* Illegal NFS file handle */
    #define ENOTSYNC        522     /* Update synchronization mismatch */
    #define EBADCOOKIE      523     /* Cookie is stale */
    #define ENOTSUPP        524     /* Operation is not supported */
    #define ETOOSMALL       525     /* Buffer or request is too small */
    #define ESERVERFAULT    526     /* An untranslatable error occurred */
    #define EBADTYPE        527     /* Type not supported by server */
    #define EJUKEBOX        528     /* Request initiated, but will not complete before timeout */
    #define EIOCBQUEUED     529     /* iocb queued, will get completion event */
    #define ERECALLCONFLICT 530     /* conflict with recalled state */
    #define ENOGRACE        531     /* NFS file lock reclaim refused */
    
    #endif
    

有上述的宏定义可知,其返回都是在(0~1000)之间,如果加上个负号,就像 return -ENOMEM;那么其返回值就在(~1000,0)之间,这就是为什么return返回值要加负号的原因,也是为什么内核函数返回的都是一个负数的原因。

4. 错误的判断和错误原因的打印

4.1 错误的判断

错误的判断是通过函数IS_ERR(const void *ptr)来判定的
该函数的在include\linux\err.h

static inline bool __must_check IS_ERR(__force const void *ptr)
{
        return IS_ERR_VALUE((unsigned long)ptr);
}

该函数只需传递一个参数:错误指针ptr,然后调用IS_ERR_VALUE((unsigned long)ptr)
该函数也是在该文件中被宏定义:

#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)

MAX_ERRNO被宏定义为4095,转换为(unsigned long)-MAX_ERRNO后为0xFFFFF000,该段代码的含义就是如果x在(0xFFFFF000~0xFFFFFFFF)区间,函数就返回一个真值,判断为假。

4.2 错误信息的返回

错误信息的打印是通过函数PTR_ERR(const void *ptr)返回的

static inline long __must_check PTR_ERR(__force const void *ptr)
{
        return (long) ptr;
}

refer to

  1. 为什么linux内核函数出现错误,返回值是一个负数
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值