内核中判断返回指针是否错误方法

本文介绍了Linux内核中如何通过指针值判断错误发生的方法,利用内核地址空间的最后一段保留区域作为错误指针,通过宏IS_ERR和IS_ERR_OR_NULL进行检查。

内核中判断返回指针是否错误的方法:使用IS_ERR或者IS_ERR_OR_NULL

参考include/linux/err.h

#define MAX_ERRNO  4095

 

#ifndef __ASSEMBLY__

 

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

 

static inline void * __must_check ERR_PTR(long error)

{

       return (void *) error;

}

 

static inline long __must_check PTR_ERR(const void *ptr)

{

       return (long) ptr;

}

 

static inline long __must_check IS_ERR(const void *ptr)

{

       return IS_ERR_VALUE((unsigned long)ptr);

}

 

static inline long __must_check IS_ERR_OR_NULL(const void *ptr)

{

       return !ptr || IS_ERR_VALUE((unsigned long)ptr);

}

 

内核空间是一个有限的空间,而在这有限的空间中,其最后一个page是专门保留的,也就是说一般人不可能用到内核空间最后一个page的指针.换句话说,你在写设备驱动程序的过程中,涉及到的任何一个指针,必然有三种情况,一种是有效指针,一种是NULL,空指针,一种是错误指针,或者说无效指针.而所谓的错误指针就是指其已经到达了最后一个page.比如对于32bit的系统来说,内核空间最高地址0xffffffff,那么最后一个page就是指的0xfffff000~0xffffffff(假设4k一个page).这段地址是被保留的,一般人不得越雷池半步,如果你发现你的一个指针指向这个范围中的某个地址,那么你的代码肯定出错了。

这里不仅不是浪费一个page,反而是充分利用资源,把一个东西当两个东西来用.

宏MAX_ERRNO(定义为4095)是最大错误号,Linux内核中,出错有多种可能.关于Linux内核中的错误,我们看一下include/asm-generic/errno-base.h文件:

#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

 

最常见的几个是-EBUSY,-EINVAL,-ENODEV,-EPIPE,-EAGAIN,-ENOMEM.这些是每个体系结构里都有的,另外各个体系结构也都定义了自己的一些错误代码.这些东西当然也都是宏,实际上对应的是一些数字,这个数字就叫做错误号.而对于Linux内核来说,不管任何体系结构,最多最多,错误号不会超过4095.而4095又正好是比4k小1,即4096减1.而我们知道一个page可能是4k,也可能是更多,比如8k,但至少它也是4k,所以留出一个page出来就可以让我们把内核空间的指针来记录错误了.

 

转自:http://blog.youkuaiyun.com/adaptiver/article/details/8660217

<think>好的,我现在需要解决用户的问题:如何在Linux内核驱动代码中判断/dev下的块设备是否存在。首先,我需要明确用户的需求。用户可能是在开发内核模块时,需要检查某个块设备是否已经被正确创建,比如在初始化代码中确认设备节点是否存在,以便进行后续操作或错误处理。 首先,我应该回忆Linux内核中设备管理的相关知识。用户空间的/dev目录下的设备节点通常是由udev或mdev根据内核中的设备信息动态创建的。但在内核层面,驱动代码并不直接与用户空间的设备文件交互,而是通过设备号(主设备号和次设备号)来管理设备。因此,判断块设备是否存在应该是指在内核中该块设备是否已经注册。 接下来,我需要考虑在内核中如何检查一个块设备是否已经存在。可能的思路是通过设备号来查找对应的设备结构体。Linux内核中使用struct block_device来表示块设备,而设备号由主设备号和次设备号组成。因此,可以通过设备号来查找对应的block_device结构体是否存在。 然后,我需要找到内核提供的相关函数。可能涉及到的函数包括bdget(),这个函数通过设备号获取对应的block_device结构体。如果设备存在,bdget()会返回对应的结构体指针,否则返回NULL。但需要注意,bdget()会增加结构体的引用计数,使用完后需要调用bdput()来减少引用计数。 不过,另一个可能的函数是blkdev_get_by_dev(),这个函数用于通过设备号打开块设备,返回block_device结构体,同时会检查设备是否存在。但使用时需要注意其参数,比如需要指定打开模式和错误处理。 此外,可能还有其他方法,比如遍历所有已注册的块设备,但这种方法效率可能不高,尤其是在系统中有大量块设备的情况下。因此,使用设备号查找应该是更直接的方法。 接下来,我需要验证这些思路的正确性。例如,假设驱动代码中已经知道设备的主次设备号,可以调用bdget_disk()或者直接使用bdget()来获取block_device。如果返回指针不为NULL,说明设备存在,否则不存在。但需要注意的是,即使设备存在,可能已经被卸载,这时候是否需要进一步检查或者是否在设备注册时已经有相应的机制? 另外,还需要考虑内核版本的问题,不同版本的内核函数可能有所变化。例如,某些函数可能在较新的内核中被弃用,或者参数发生了变化。因此,需要查阅当前内核版本的文档或源码确认函数的正确用法。 可能的步骤总结如下: 1. 获取目标块设备的主设备号和次设备号。 2. 使用内核函数如bdget()根据设备号获取block_device结构体。 3. 检查返回是否为NULL,以判断设备是否存在。 4. 如果存在,使用完后释放引用计数。 另外,用户提到的是/dev下的块设备,但内核中更关注的是设备是否注册,而不是用户空间是否有对应的节点。因此,正确的方法应基于内核内部的设备注册状态,而不是用户空间的文件存在与否。 可能的代码示例: dev_t dev = MKDEV(major, minor); struct block_device *bdev = bdget(dev); if (bdev) { // 设备存在 bdput(bdev); } else { // 设备不存在 } 但需要确认bdget()在设备不存在时是否返回NULL。查阅内核源码,bdget()会尝试从inode缓存中查找对应的block_device,如果不存在则返回NULL。因此,这种方法应该是可行的。 另外,可能还需要考虑设备是否已经被打开或者处于活动状态,但根据问题需求,仅需判断是否存在,所以bdget()足够。 总结,正确的方法是通过设备号使用bdget()来检查block_device是否存在,从而判断块设备是否已注册在内核中。</think>在Linux内核驱动代码中,判断块设备是否存在需通过内核层面的设备注册状态,而非直接检查用户空间的`/dev`节点。以下是具体方法: --- ### **步骤 1:获取设备号** 块设备由**主设备号(major)**和**次设备号(minor)**唯一标识。通常需要预先知道目标设备的设备号,例如通过`MKDEV`宏生成: ```c dev_t dev = MKDEV(major, minor); ``` --- ### **步骤 2:通过设备号查找块设备** 使用内核函数`bdget()`,其作用是通过设备号获取对应的`struct block_device`对象: ```c struct block_device *bdev = bdget(dev); ``` - **返回值分析**: - 若`bdev`非`NULL`:设备已在内核注册。 - 若`bdev`为`NULL`:设备未注册或未初始化。 --- ### **步骤 3:释放引用计数** 若`bdget()`成功返回`bdev`,需调用`bdput()`减少引用计数,避免内存泄漏: ```c if (bdev) { // 设备存在的逻辑 bdput(bdev); } else { // 设备不存在的逻辑 } ``` --- ### **完整代码示例** ```c #include <linux/fs.h> #include <linux/blkdev.h> int check_block_device_exist(dev_t dev) { struct block_device *bdev = bdget(dev); if (bdev) { bdput(bdev); return 1; // 设备存在 } return 0; // 设备不存在 } ``` --- ### **关键函数说明** 1. **`bdget(dev_t dev)`** - **功能**:通过设备号查找块设备,返回`struct block_device`指针。 - **注意**:此函数会增加引用计数,需手动调用`bdput()`释放。 2. **`bdput(struct block_device *bdev)`** - **功能**:减少`block_device`的引用计数,当计数归零时释放资源。 --- ### **补充说明** - **内核与用户空间的区别**:内核不直接管理`/dev`下的文件,而是通过设备号判断块设备是否注册。用户空间的设备节点由`udev`/`mdev`自动创建。 - **设备状态验证**:若需进一步验证设备是否可用(如已挂载),需结合`blkdev_get_by_dev()`等函数检查设备状态。 --- 通过上述方法,可在内核驱动代码中可靠判断块设备是否存在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值