当前位置: 首页 > news >正文

Linux 错误处理(字符设备基础三)

  在Linux字符设备驱动中,即使是最简单的注册字符设备,也存在注册失败的可能性,因此在之前编写的驱动代码中采用检查函数返回值的方式,确认函数是否成功执行

一、goto 语句

  在编写驱动程序时,驱动程序应该提供函数执行失败后处理的能力。如果驱动程序中函数执行失败了,必须取消掉所有失败前的注册,否则内核会处于一个不稳定的状态,因为它包含了不存在代码的内部指针。在处理 Linux 错误时,最好使用goto 语句,goto 语句的使用示例如下所示:

int init my_init_function(void)
{int err;err = register_this(ptr1, "skull");if (err)goto fail_this;err = register_that(ptr2, "skull");if (err)goto fail_that;err = register_those(ptr3, "skull");if (err)goto fail_those;return 0;fail_those:unregister_that(ptr2, "skull");fail_that:unregister_this(ptr1, "skull");fail_this:return err;
}

  在以上代码中试图注册 3 个虚构设备,goto 语句在失败情况下使用,对之前已经成功注册的设施进行注销。使用 goto 语句处理的时候,应该遵循“先进后出”的原则。

二、IS_ERR()

  对于任何一个指针来说,必然存在三种情况,一种是合法指针,一种是NULL(也就是空指针),一种是错误指针(也就是无效指针)。在 Linux 内核中,所谓的错误指针已经指向了内核空间的最后一页,例如,对于一个 64 位系统来说,内核空间最后地址为0xffffffffffffffff,那么最后一页的地址是 0xfffffffffffff000~0xffffffffffffffff,这段地址是被保留的,如果指针落在这段地址之内,说明是错误的无效指针。
  在 Linux 内核源码中实现了指针错误的处理机制,相关的函数接口主要有IS_ERR()、PTR_ERR()、ERR_PTR()等,其函数的源码在 include/linux/err.h 文件中,如下所示:

#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)static inline void * __must_check ERR_PTR(long error)
{return (void *) error;
}static inline long __must_check PTR_ERR(__force const void *ptr)
{return (long) ptr;
}static inline bool __must_check IS_ERR(__force const void *ptr)
{return IS_ERR_VALUE((unsigned long)ptr);
}static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr)
{return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr);
}

  如上所示,在 Linux 源码中 IS_ERR()函数其实就是判断指针是否出错,如果指针指向了内核空间的最后一页,就说明指针是一个无效指针,如果指针并不是落在内核空间的最后一页,就说明这指针是有效的。无效的指针能表示成一种负数的错误码,如果想知道这个指针是哪个错误码,使用 PTR_ERR 函数转化。0xfffffffffffff000~0xffffffffffffffff 这段地址和Linux错误码是一一对应的,内核错误码保存在 kernel\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

  对于IS_ERR()的使用,实例代码如下所示:

myclass = class_create(THIS_MODULE, "myclass");
if (IS_ERR(myclass)) 
{ret = PTR_ERR(myclass);goto fail;
}
mydevice = device_create(myclass, NULL, MKDEV(major, 0), NULL, "simple-device");
if (IS_ERR(mydevice)) 
{class_destroy(myclass);ret = PTR_ERR(mydevice);goto fail;
}

  在上述代码中,调用了 class_create()和 device_create()函数,必须使用IS_ERR()函数判断返回的指针是否是有效的,如果是无效的,需要调用 PTR_ERR()函数将无效指针转换为错误码,并进行错误码的返回。

http://www.lryc.cn/news/205001.html

相关文章:

  • STM32 PWM配置及呼吸灯
  • 华为云 CodeArts Snap 智能编程助手 PyCharm 插件安装与使用指南
  • SpringSecurity分布式安全框架
  • 高速下载b站视频的解决方案
  • Qt之彻底解决QSpinBox限定范围无效的问题
  • Ktor vs Spring Boot:哪个框架能帮助你构建更高性能的 Web 应用?
  • 【Ubuntu18.04】激光雷达与相机联合标定(Livox+HIKROBOT)(一)
  • hadoop伪分布式安装部署
  • 前端视角看 Docker : 加速开发和部署的利器
  • JVM相关的面试题
  • HTML、CSS和jQuery:实现图片折叠展开的效果
  • php简单后门实现及php连接数据库
  • IOS课程笔记[6] 基础控件
  • python爬虫入门(五)XPath使用
  • 【广州华锐互动】VR消防员模拟灭火:身临其境的火场救援
  • NFS性能瓶颈分析
  • Java中配置RabbitMQ基本步骤
  • Ingress典型配置
  • webpack中常见的Loader解决了什么问题?
  • 阿里7年经验之谈 —— 如何实现前端项目的自动化测试?
  • 动态开辟内存空间函数
  • nodejs+vue备忘记账系统-计算机毕业设计
  • 百度Comate代码助手SaaS版本:智慧编程,引领新潮
  • 数据与视图的完美契合:Vue响应式的交织魅力
  • Centos8 降低gcc版本至gcc-7.3
  • Qt之设置QLineEdit只能输入浮点数
  • Spark项目实战-卡口流量统计
  • kubernetesr进阶--Secret概述
  • 在 Python 中使用 Pillow 进行图像处理【2/4】
  • XTU-OJ 1171-coins