Lichen Liu

与其感慨路难行,不如马上出发

  • 主页
所有文章 友链 关于我

Lichen Liu

与其感慨路难行,不如马上出发

  • 主页

/dev 下的null, zero, random等文件是怎么来的

2020-03-07

这些设备文件定义在 linux/drivers/char/mem.c 的devlist 中。就像文件名和结构体名描述的,它们是基于内存的字符设备。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static const struct memdev {
const char *name;
umode_t mode;
const struct file_operations *fops;
fmode_t fmode;
} devlist[] = {
#ifdef CONFIG_DEVMEM
[1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
#endif
#ifdef CONFIG_DEVKMEM
[2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
#endif
[3] = { "null", 0666, &null_fops, 0 },
#ifdef CONFIG_DEVPORT
[4] = { "port", 0, &port_fops, 0 },
#endif
[5] = { "zero", 0666, &zero_fops, 0 },
[7] = { "full", 0666, &full_fops, 0 },
[8] = { "random", 0666, &random_fops, 0 },
[9] = { "urandom", 0666, &urandom_fops, 0 },
#ifdef CONFIG_PRINTK
[11] = { "kmsg", 0644, &kmsg_fops, 0 },
#endif
};

文件系统初始化时,会调用chr_dev_init 函数,通过一个for 循环对devlist 中的这些设备进行初始化,并创建设备文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static int __init chr_dev_init(void)
{
int minor;

if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);

mem_class = class_create(THIS_MODULE, "mem");
if (IS_ERR(mem_class))
return PTR_ERR(mem_class);

mem_class->devnode = mem_devnode;
for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
if (!devlist[minor].name)
continue;

/*
* Create /dev/port?
*/
if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
continue;

device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
NULL, devlist[minor].name);
}

return tty_init();
}

device_create 函数在linux/drivers/base/core.c 中,它是一个包裹函数,负责将参数传入并调用device_create_vargs 再调用实际干活的device_create_groups_vargs.

device_create_groups_vargs先通过device_initialize 负责初始化一个空的设备的结构体dev,之后根据从device_create 传进来的参数填充数据,最后调用device_add 函数,传入刚刚填好数据的dev,在/sys/devices 目录下创建目录结构(例如/sys/devices/virtual/mem/null) ,并在/sys/class 下创建软链接(例如/sys/class/mem/null/),该目录下有设备的major:minor号,设备名称和权限等。

device_add 的最后,通过调用devtmpfs_create_node 函数,在devtmpfs,也就是/dev 目录下创建设备对应的文件(例如/dev/null)。

在/dev 下的设备文件创建完成后,就可以从用户态通过该文件对设备进行操作,不同的设备实现的fops 数量和方法也不同,其中null 和zero 的定义和实现都在 linux/drivers/char/mem.c 中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static const struct file_operations null_fops = {
.llseek = null_lseek,
.read = read_null,
.write = write_null,
.read_iter = read_iter_null,
.write_iter = write_iter_null,
.splice_write = splice_write_null,
};
static const struct file_operations zero_fops = {
.llseek = zero_lseek,
.write = write_zero,
.read_iter = read_iter_zero,
.write_iter = write_iter_zero,
.mmap = mmap_zero,
.get_unmapped_area = get_unmapped_area_zero,
#ifndef CONFIG_MMU
.mmap_capabilities = zero_mmap_capabilities,
#endif
};

其中部分方法还是zero 和null 共用的,例如zero_lseek 和null_lseek(设置到文件起始位置),write_null 和write_zero 等就是同一个函数实现(只返回个数字,但不发生实际写入):

1
2
3
4
5
6
7
8
9
10
11
#define zero_lseek	null_lseek
static loff_t null_lseek(struct file *file, loff_t offset, int orig)
{
return file->f_pos = 0;
}
#define write_zero write_null
static ssize_t write_null(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return count;
}

read_null 简单的返回一个0, 而read_iter_zero 则是通过memset 的方式向读buffer 写满0.

random 的实现在linux/drivers/char/random.c 中:

1
2
3
4
5
6
7
8
9
const struct file_operations random_fops = {
.read = random_read,
.write = random_write,
.poll = random_poll,
.unlocked_ioctl = random_ioctl,
.compat_ioctl = compat_ptr_ioctl,
.fasync = random_fasync,
.llseek = noop_llseek,
};

它的方法实现也比较复杂,有兴趣可以去研究一下。

  • Linux
  • Kernel

扫一扫,分享到微信

微信分享二维码
使用ct_state 实现出口放行防火墙
NUMA 内存策略 preferred 的效果
© 2023 Lichen Liu
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • Linux
  • golang
  • xml
  • omitempty
  • test
  • art
  • AWS
  • Kernel
  • bonding
  • sk_buff
  • kernel
  • libvirt
  • libvirt-go
  • numa
  • ping
  • arp
  • 输入法
  • ovs
  • font
  • manjaro
  • 坑
  • 北京
  • 旅游

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 北京周末

    2023-03-22

    #北京#旅游

  • manjaro kde 升级后中文字体变成方块

    2021-02-18

    #font#manjaro#坑

  • sk_buff 简介

    2020-10-26

    #Linux#sk_buff#kernel

  • 使用ct_state 实现出口放行防火墙

    2020-05-15

    #ovs

  • /dev 下的null, zero, random等文件是怎么来的

    2020-03-07

    #Linux#Kernel

  • NUMA 内存策略 preferred 的效果

    2020-02-20

    #Linux#numa

  • 在linux kernel 源码中搜索syscall 的实现

    2020-02-20

    #Linux

  • 一次ping 遇到Invalid argument 报错的问题

    2020-02-11

    #Linux#ping#arp

  • Linux 网络bond mode 4 的xmit_hash_policy layer3+4 到底是如何hash 的

    2020-01-10

    #Linux#bonding

  • golang xml 如何忽略空结构体

    2020-01-09

    #golang#xml#omitempty

  • libvirt-go 的一个坑

    2020-01-07

    #golang#libvirt#libvirt-go

  • 在AWS 的Amazon Linux 上下载源码

    2019-12-23

    #Linux#AWS#Kernel

  • 中文测试

    2019-12-23

    #test#输入法

  • Hello world

    2019-12-18

    #test#art

  • 肥叉烧
  • 安全大手子
  • 物理学博士
  • 一个愣头青
普通上班族,会一点Linux, 想学SDN