cgroup 内存管理之 tmpfs

本文内核代码版本:https://elixir.bootlin.com/linux/v4.14.281/source/mm/shmem.c

1. tmpfs 内存简介

tmpfs 文件系统是 pod 中常见的一种“存储”介质,也叫 ram disk,都是一个东西

tmpfs 的特殊的地方在于:

  1. 首先它是个文件系统
  2. 但是它的文件数据是完全存放在内存里面的,不在磁盘上

所以要讲 tmpfs 的话,就得把这两部分都讲清楚,一个是文件系统的实现,一个是底层“持久化”层内存的管理

通常应用程序之间会通过 tmpfs 文件系统来实现高效的数据共享

/dev/shm 就是一个最典型的 tmpfs 文件系统,是操作系统为了解决大多数程序数据共享而默认挂在的一个 tmpfs

2. tmpfs 文件系统的实现

我们知道 file 是linux内核最重要的设计,一切皆文件

除了普通的文件,平时我们接触到的,unix管道、socket、proc、cgroup 等等,都是基于文件的实现

为了实现灵活可扩展的文件系统架构,Linux设计了 virtual file system 抽象层,简称 vfs,对用户台程序屏蔽了所有具体的底层文件系统的实现细节,提供统一的文件系统接口

2.1. virtual file system 接口定义

https://www.kernel.org/doc/html/latest/filesystems/vfs.html

vfs 属于一个专题,我们这里不讲那么复杂,有时间可以专门展开讲

vfs 定义了文件系统实现最关键的2个接口:

  1. 一个是 struct file_operations:文件读写的接口
  2. 一个是 struct inode_operations:inode操作接口

inode_opertions 定义如下:

struct inode_operations {
    int (*create)(struct user_namespace*, struct inode*, struct dentry*, umode_t, bool);
    int (*symlink)(struct user_namespace*, struct inode*, struct dentry*, const char*);
    int (*mkdir)(struct user_namespace*, struct inode*, struct dentry*, umode_t);
    int (*rmdir)(struct inode*, struct dentry*); /* 省略一万字 */
};

是不是很熟悉?

file_operations 的定义如下:

struct file_operations {
    int (*open)(struct inode*, struct file*);
    loff_t (*llseek)(struct file*, loff_t, int);
    ssize_t (*read)(struct file*, char __user*, size_t, loff_t*);
    ssize_t (*write)(struct file*, const char __user*, size_t, loff_t*); /* 省略一万字 */
};

是不是也很熟悉?

内核 tmpfs 文件系统的源码:mm/shmem.c

tmpfs 其实并没有实现 vfs 中的所有接口,主要原因是因为由于绝大部分的 file system 底层实现其实都是一样的,没区别,所以内核为了简化文件系统的开发,把这些通用的实现都抽象出来,变成 generic_file_read/write 之类的通用实现

static const struct file_operations shmem_file_operations = { /* 普通文件的读、写、seek、fsync */ .mmap = shmem_mmap, .get_unmapped_area = shmem_get_unmapped_area, #ifdef CONFIG_TMPFS .llseek = shmem_file_llseek, .read_iter = shmem_file_read_iter, .write_iter = generic_file_write_iter, .fsync = noop_fsync, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, .fallocate = shmem_fallocate, #endif };
static const struct inode_operations shmem_inode_operations = { /* 这个是针对普通文件的 inode 操作 */ .getattr = shmem_getattr, .setattr = shmem_setattr, };
static const struct inode_operations shmem_dir_inode_operations = { /* 这个是针对目录的 inode 操作 */ #ifdef CONFIG_TMPFS .create = shmem_create, .lookup = simple_lookup, .link = shmem_link, .unlink = shmem_unlink, .symlink = shmem_symlink, .mkdir = shmem_mkdir, .rmdir = shmem_rmdir, .mknod = shmem_mknod, .rename = shmem_rename2, .tmpfile = shmem_tmpfile, #endif };