resource 资源分配

简介: resource 资源分配

资源管理

先掌握用于管理资源的数据结构和函数:

数据结构

Linux提供通用的构架,用于在内存中构建数据结构。这些结构描述了系统中可用的资源,使得内核代码能够管理和分配资源。具中关键的数据结构resource源码如下:

//树数据结构定义
struct resource {
  resource_size_t start;
  resource_size_t end;//start end指定一般性区域,通常表示某个地址空间的一个区域
  const char *name;//存储一个字符串,以便给资源赋予一个有意义的名称,资源名称实际与内核无关 proc文件系统z2
  unsigned long flags;//用于描述资源及其当前状态
  struct resource *parent, *sibling, *child;
};

用于连接parent,child,sibling成员规则如下:

  • 每个子结点只有一个父结点
  • 一个父结点可以有任意数目的子结点
  • 同一个父结点的所有子结点,会迕接到兄弟结点链表上面。

在内存中表示数据结构时,我们必须要注意几个问题:

  1. 尽管每个子结点都有一个指针指向父结点,但父结点只有一个指针指向第一个子结点。所有其它子结点都通过兄弟结点链表访问
  2. 指向父结点的指针同样可以为NULL。

请求和释放资源

为确保可靠地配詈资源(无论何种类型),内核必须提供一种机制来分配和释放资源。一旦资源已经分配,则不能由任何其他驱动程序使用。

请求资源

内核提供了_request_resource函数,用于请求一个资源区域。

request_resource->request_resource_conflict->__request_resource

/* Return the conflict entry if you can't request it */
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
  resource_size_t start = new->start;
  resource_size_t end = new->end;
  struct resource *tmp, **p;
  if (end < start)
    return root;
  if (start < root->start)
    return root;
  if (end > root->end)
    return root;
  p = &root->child;
  for (;;) {
    tmp = *p;
    if (!tmp || tmp->start > end) {
      new->sibling = tmp;
      *p = new;
      new->parent = root;
      return NULL;
    }
    p = &tmp->sibling;
    if (tmp->end < start)
      continue;
    return tmp;
  }
}

该函数用于分配个reqeust实例,在此函数当中也会进行检查(起始地址大于结束地址,请求无法使用),则放弃操作。request_resource这个函数负责必要的锁操作,主要工作还是由__request_resource。

request_resource

/**
 * request_resource - request and reserve an I/O or memory resource
 * @root: root resource descriptor
 * @new: resource descriptor desired by caller
 *
 * Returns 0 for success, negative error code on error.
 */
int request_resource(struct resource *root, struct resource *new)
{
  struct resource *conflict;
  conflict = request_resource_conflict(root, new);
  return conflict ? -EBUSY : 0;
}

request_resource_conflict

struct resource *request_resource_conflict(struct resource *root, struct resource *new)
{
  struct resource *conflict;
  write_lock(&resource_lock);
  conflict = __request_resource(root, new);
  write_unlock(&resource_lock);
  return conflict;
}

__request_resource它连接扫描现存的资源,将新资源添加到正确的位置,或发现与已经分配区域的冲突。完成所有操作之后,需要遍历兄中弟结点的链表。如果所需的资源区域是空闲的,则插入新的resource实例,这样就可以完成资源分析。如果区域不是空闲的,则分配失败。

在扫描特定父结点的子结点时,只会在一个层次上扫描兄弟结点链表。内核不会扫描更底层子结点的链表。

释放资源

调用release_resource函数释放使用中的资源源码如下:

release_resource

int release_resource(struct resource *old)
{
  int retval;
  write_lock(&resource_lock);
  retval = __release_resource(old);
  write_unlock(&resource_lock);
  return retval;
}

__release_resource

static int __release_resource(struct resource *old)
{
  struct resource *tmp, **p;
  p = &old->parent->child;
  for (;;) {
    tmp = *p;
    if (!tmp)
      break;
    if (tmp == old) {
      *p = tmp->sibling;
      old->parent = NULL;
      return 0;
    }
    p = &tmp->sibling;
  }
  return -EINVAL;
}

I/O内存

资源、管理还有一个很重要的方面是I/O内存的分配方式,因为在所有平台上都是与外设通信的主要方法(IA一32除外,其中I/O端口更为重要)。I/O内存不仅包括与扩展设备通信自接使用的内存区域,还包括系统中可用的物理内存和ROM存储器,以及包含在资源列表中的内存(可以使用proc文件系统中的iomem文件,显示所有的I/O内存)。

所有分配的I/O内存地址,它们都要通过一棵资源树管理,树的根结点是全局内核变量iomem_resource。

用I/O内存时,分配内存区域并不是所需唯一操作。主要取决于总线系统和处理器类型,可能必需拓展设备的地址空间映射到内核地址空间之后,才可以访问此设备(称为软件I/O映射)。这是通过使用ioremap内核函数适当设备系统页表而实现的。同样也可以使用体系结构当中的iounmap函数解除映射操作。

将一个物理地址映射到处理器的虚扌以地址空间中,使得内核可以使用该地址,就设备驱动程序而言,意味着拓展总线的地址空间映射到CPU的地址空间中,使得能够用普通内存访问函数来操作总线/设备。

I/O端口

I/O端口是一种与设和总线通信的流行方法,特别是在IA一32平台上。类似于I/O内存,按良好范例编写的驱动程序在访问所需的区域之前,相应的区域必须已经注册。糟糕的是,处理无法检查注册是否经完成。

kernel/resource.c中的ioport_resource充当资源树的根节点。proc文件系统中的ioports文件可以显示已经分配的端口地址。

ioport_resource

struct resource ioport_resource = {
  .name = "PCI IO",
  .start  = 0,
  .end  = IO_SPACE_LIMIT,
  .flags  = IORESOURCE_IO,
};


目录
打赏
0
0
0
0
4
分享
相关文章
通过springboot框架创建对象(一)
在Spring Boot中,对象创建依赖于Spring框架的核心特性——控制反转(IoC)和依赖注入(DI)。IoC将对象的创建和管理交由Spring应用上下文负责,开发者只需定义依赖关系。DI通过构造函数、setter方法或字段注入实现依赖对象的传递。Spring Boot的自动配置机制基于类路径和配置文件,自动为应用程序配置Spring容器,简化开发过程。Bean的生命周期包括定义扫描、实例化、依赖注入、初始化和销毁回调,均由Spring容器管理。这些特性提高了开发效率并简化了代码维护。
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用(二)
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用
223 0
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
1905 1
PCIe初始化枚举和资源分配流程分析
本文主要是对PCIe的初始化枚举、资源分配流程进行分析,代码对应的是alikernel-4.19,平台是arm64 ## 1. PCIe architecture ### 1.1 pcie的拓扑结构 在分析PCIe初始化枚举流程之前,先描述下pcie的拓扑结构。 如下图所示: ![11.png](https://ata2-img.oss-cn-zhangjiakou.aliyuncs
8092 1
PCIe初始化枚举和资源分配流程分析
一文读懂RDMA: Remote Direct Memory Access(远程直接内存访问)
该文档详细介绍了RDMA(远程直接内存访问)技术的基本原理、主要特点及其编程接口。RDMA通过硬件直接在应用程序间搬移数据,绕过操作系统协议栈,显著提升网络通信效率,尤其适用于高性能计算和大数据处理等场景。文档还提供了RDMA编程接口的概述及示例代码,帮助开发者更好地理解和应用这一技术。
在Linux中,什么是虚拟化?并且列出常见的虚拟化技术。
在Linux中,什么是虚拟化?并且列出常见的虚拟化技术。
SpringBoot使用接口下载图片的写法
在Spring Boot中实现图片下载功能涉及定义一个REST接口来发送图片文件。首先,创建`ImageController`类,并在其中定义`downloadImage`方法,该方法使用`@GetMapping`注解来处理HTTP GET请求。方法内部,通过`Files.readAllBytes`读取图片文件到字节数组,再将该数组封装成`ByteArrayResource`。接着,设置`HttpHeaders`以指定文件名为`image.jpg`并配置为附件下载。
456 0
CMake深度解析:掌握add_custom_command,精通Makefile生成规则(三)
CMake深度解析:掌握add_custom_command,精通Makefile生成规则
2696 2
Linux模块文件编译到内核与独立编译成.ko文件的方法
Linux模块文件编译到内核与独立编译成.ko文件的方法
3280 0
Linux系统中驱动之设备树的platform驱动实现
Linux系统中驱动之设备树的platform驱动实现
393 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问