对于现代操作系统,虚拟文件系统是一个几乎无处不见的功能,因此,要探究现代操作系统的运行机制,对其进行讨论是必然的。
本文使用的是Linux 2.6.x.x ,这是一个变革性的版本,无论是内存管理,进程管理,文件管理还是设备管理都出现了开天辟地的变化,因此,以这个版本进行探究是很有必要的。
引流:现代操作系统的内存管理原理:以Linux2.6.x.x为例
虚拟文件系统概述
root@huawei linux-version
Filesystem 1K-blocks Used Available Use% Mounted on
udev 1967860 0 1967860 0% /dev
tmpfs 402568 1580 400988 1% /run
/dev/vda1 41020640 26749836 12157372 69% /
tmpfs 2012832 0 2012832 0% /dev/shm
tmpfs 5120 4 5116 1% /run/lock
tmpfs 2012832 0 2012832 0% /sys/fs/cgroup
tmpfs 402564 40 402524 1% /run/user/122
tmpfs 402564 0 402564 0% /run/user/0
如上,tmpfs ,是一种基于内存的虚拟文件系统,虚拟的意思就是文件系统里的文件不对应硬盘上任何文件。(有一种说法叫做逻辑文件系统)
传统上,文件系统用于在块设备上持久存储系统,但也可以使用文件系统来组织、提供或交换并不存储在块设备上的信息,这些信息可以由内核动态生成。(从这句话来看普通文件系统和proc 这些貌似是对等的关系,那么暂且把他们叫做逻辑文件系统吧)
常见的如proc 、tmpfs 和sysfs
此处要注意逻辑文件系统和文件系统,磁盘文件系统和内存文件系统的区别 特定虚拟文件系统只是一个中间层,有如下几种:
proc :操作系统本身和应用程序之间的通信提供了一个安全的接口devfs :在2.6内核以前使用devfs 来提供一种类似于文件的方法来管理位于/dev 目录下的所有设备sysfs :sysfs 文件系统把连接在系统上的设备和总线组织成为一个分级的文件,用户空间的程序同样可以利用这些信息,以实现和内核的交互,一般来说是替代devfs 的。sysfs 文件系统是当前系统上实际设备树的一个直观反映,它是通过kobject 子系统来建立这个信息的,当一个kobject 被创建的时候,对应的文件和目录也就被创建了。tmpfs :Linux 特有的文件系统,标准挂载点是/dev/shm ,默认大小是实际内存的一半。tmpfs 可以使用物理内存,也可以使用swap 交换空间。是一种普遍的对文件整理的虚拟文件系统。优点:临时性;快速读写和动态收缩
具体的文件系统如:minix 、ext3 、ext4 等 磁盘文件系统:文件系统在磁盘中,速度较慢 内存文件系统:文件系统在内存中,速度更快
文件系统类型:基于磁盘的文件系统Disk-based Filesystem 、虚拟文件系统Virtual Filesystem 在内核中生成,是一种使用户应用程序与用户通信的方法和网络文件系统Network Filesystem 是基于磁盘的文件系统和虚拟文件系统之间的折中。
VFS 不仅为文件系统提供了方法和抽象,还支持文件系统中对象(或文件)的统一视图。
inode 的成员有以下几类:
- 描述文件状态的元数据。例如,访问权限或上次修改的日期。
- 保存实际文件内容的数据段
- 该目录项的数据所在inode的编号
- 文件或目录的名称
下面是查找/usr/bin/emacs 的过程
万物皆文件 大多数内核导出、用户程序使用的函数都可以通过VFS 定义的文件接口访问。以下是使用文件作为其主要通信手段的一部分内核子系统:字符和块设备;进程之间的管道;用于所有网络协议的套接字;用于交互式输入和输出的终端;
VFS 由两部分组成:文件和文件系统
struct inode {
struct hlist_node i_hash;
struct list_head i_list;
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
atomic_t i_count;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
unsigned long i_version;
loff_t i_size;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
unsigned int i_blkbits;
blkcnt_t i_blocks;
unsigned short i_bytes;
umode_t i_mode;
spinlock_t i_lock;
struct mutex i_mutex;
struct rw_semaphore i_alloc_sem;
const struct inode_operations *i_op;
const struct file_operations *i_fop;
struct super_block *i_sb;
struct file_lock *i_flock;
struct address_space *i_mapping;
struct address_space i_data;
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
};
int i_cindex;
__u32 i_generation;
#ifdef CONFIG_DNOTIFY
unsigned long i_dnotify_mask;
struct dnotify_struct *i_dnotify;
#endif
#ifdef CONFIG_INOTIFY
struct list_head inotify_watches;
struct mutex inotify_mutex;
#endif
unsigned long i_state;
unsigned long dirtied_when;
unsigned int i_flags;
atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
void *i_private;
};
对于iNode 的操作,使用i_op 成员进行指定
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
int (*link) (struct dentry *,struct inode *,struct dentry *);
int (*unlink) (struct inode *,struct dentry *);
int (*symlink) (struct inode *,struct dentry *,const char *);
int (*mkdir) (struct inode *,struct dentry *,int);
int (*rmdir) (struct inode *,struct dentry *);
int (*mknod) (struct inode *,struct dentry *,int,dev_t);
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
int (*readlink) (struct dentry *, char __user *,int);
void * (*follow_link) (struct dentry *, struct nameidata *);
void (*put_link) (struct dentry *, struct nameidata *, void *);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, struct nameidata *);
int (*setattr) (struct dentry *, struct iattr *);
int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
void (*truncate_range)(struct inode *, loff_t, loff_t);
long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len);
};
而对于如proc 这种的文件系统,其管理对象是进程task_struct
struct task_struct {
int link_count, total_link_count;
struct fs_struct *fs;
struct files_struct *files;
struct nsproxy *nsproxy;
};
files 包含当前进程的各个文件描述符
struct files_struct {
atomic_t count;
struct fdtable *fdt;
struct fdtable fdtab;
spinlock_t file_lock ____cacheline_aligned_in_smp;
int next_fd;
struct embedded_fd_set close_on_exec_init;
struct embedded_fd_set open_fds_init;
struct file * fd_array[NR_OPEN_DEFAULT];
};
struct embedded_fd_set {
unsigned long fds_bits[1];
};
默认情况下,内核允许每个进程打开 NR_OPEN_DEFAULT 个文件。允许打开文件的初始数目是32。64位系统可以同时处理64个文件
#define BITS_PER_LONG 32
#define NR_OPEN_DEFAULT BITS_PER_LONG
而对于
struct fdtable {
unsigned int max_fds;
struct file ** fd;
fd_set *close_on_exec;
fd_set *open_fds;
struct rcu_head rcu;
struct fdtable *next;
};
其他暂不做概述
proc
proc 是一种逻辑文件系统,其信息不能从块设备读取,只有在读取文件内容时,才动态生成相应的信息。
使用proc 文件系统,可以获得有关内核各子系统的信息(例如,内存利用率、附接的外设,等等),也可以在不重新编译内核源代码的情况下修改内核的行为,或重启系统。
与之相关联的是系统控制机制sysctl system control mechanism 。通常,进程数据文件系统procfs 装在在/proc ,它的缩写是proc FS ,即因此得名。
尽管proc 文件系统的容量依系统而不同,其中仍然包含了许多深层嵌套的目录、文件、链接。但这些信息可以分为以下几大类:内存管理、系统进程的特征数据、文件系统、设备驱动程序、系统总线、电源管理、终端和系统控制参数。
对于某些进程的信息,可以在`/proc`下查看
root@huawei 2194
/usr/libexec/at-spi-bus-launcher
root@huawei 2194
/proc/2194
一般性系统信息
root@huawei /proc
cpu 12211193 7303 2174437 538380117 370471 0 21859 0 0 0
cpu0 6128342 3721 1085295 269120499 127141 0 7760 0 0 0
cpu1 6082850 3582 1089142 269259618 243329 0 14099 0 0 0
intr 1278733850 0 9 0 0 2566 0 3 0 0 0 277238 28 15 0 0 0 0 0 0 0 0 0 0 0 0 27 0 4839272 5689436 0 4780 5813 0 18799006 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 2490275942
btime 1663128233
processes 8110805
procs_running 1
procs_blocked 0
softirq 903628053 0 295168408 202239 20129044 18142070 0 22983 280585352 13555 289364402
数据结构
proc 中的每个数据项都由proc_dir_entry 来表示
struct proc_dir_entry {
unsigned int low_ino;
unsigned short namelen;
const char *name;
mode_t mode;
nlink_t nlink;
uid_t uid;
gid_t gid;
loff_t size;
const struct inode_operations *proc_iops;
const struct file_operations *proc_fops;
get_info_t *get_info;
struct module *owner;
struct proc_dir_entry *next, *parent, *subdir;
void *data;
read_proc_t *read_proc;
write_proc_t *write_proc;
atomic_t count;
int pde_users;
spinlock_t pde_unload_lock;
struct completion *pde_unload_completion;
shadow_proc_t *shadow_proc;
};
内核提供了一个数据结构proc_inode ,支持以面向inode 的方式来查看proc 文件系统的数据项。
union proc_op {
int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
int (*proc_read)(struct task_struct *task, char *page);
};
struct proc_inode {
struct pid *pid;
int fd;
union proc_op op;
struct proc_dir_entry *pde;
struct inode vfs_inode;
};
换言之,在关联到proc 文件系统的每个inode 结构实例之前,内存中都有一些额外的数据属于对应的proc_inode 实例,根据inode 信息,可使用container_of 机制获得proc_inode
static inline struct proc_inode *PROC_I(const struct inode *inode)
{
return container_of(inode, struct proc_inode, vfs_inode);
}
初始化和装载
装载proc 文件系统
/proc 的装载几乎与非虚拟文件系统是等同的。唯一的区别在于,将一个适宜的关键字(通常是proc 或none )指定为数据源,而不使用设备文件
进程相关信息
输出与系统进程相关的信息,是proc 文件系统最初设计的主要任务之一
系统控制信息
可以在运行时通过系统控制修改内核行为。控制参数从用户空间传输到内核,无须重启机器。操纵内核行为的传统方法是sysctl 系统调用
sysfs
sysfs 是一个向用户空间导出内核对象的文件系统,它不仅提供了察看内核内部数据结构的能力,由于系统的所有设备和总线都是通过kobject 组织的,所以sysfs 提供了系统的硬件拓扑的一种表示。
struct kobject 数据结构
kobject 包含在一个层次化的组织中。最重要的一点是,它们可以有一个父对象,可以包含到一个kset 中。这决定了kobject 出现在sysfs 层次结构中的位置:如果存在父对象,那么需要在父对象对应的目录中新建一项。否则,将其放置到kobject 所在的kset 所属的kobject 对应的目录中- 每个
kobject 在sysfs 中都表示为一个目录。出现在该目录中的文件是对象的属性。用于导出和设置属性的操作由对象所属的子系统提供 - 总线、设备、驱动程序和类是使用
kobject 机制的主要内核对象,因而也占据了sysfs 中几乎所有的数据项
每个sysfs_dirent 都表示一个sysfs 节点
struct sysfs_dirent {
atomic_t s_count;
atomic_t s_active;
struct sysfs_dirent *s_parent;
struct sysfs_dirent *s_sibling;
const char *s_name;
union {
struct sysfs_elem_dir s_dir;
struct sysfs_elem_symlink s_symlink;
struct sysfs_elem_attr s_attr;
struct sysfs_elem_bin_attr s_bin_attr;
};
unsigned int s_flags;
ino_t s_ino;
umode_t s_mode;
struct iattr *s_iattr;
};
内核对象
内核中很多地方都需要跟踪记录C 语言中结构的实例。尽管这些对象的用法大不相同,但各个不同子系统的某些操作非常类似,例如引用计数。这导致了代码复制。由于这是个糟糕的问题,因此在内核版本2.5的开发期间,内核采用了一般性的方法来管理内核对象
一般性的内核对象机制可用于执行下列对象操作:
- 引用计数;
- 管理对象链表(集合);
- 集合加锁;
- 将对象属性导出到用户空间(通过
sysfs 文件系统)。
struct kobject {
const char * k_name;
struct kref kref;
struct list_head entry;
struct kobject * parent;
struct kset * kset;
struct kobj_type * ktype;
struct sysfs_dirent * sd;
wait_queue_head_t poll;
};
引用计数
struct kref {
atomic_t refcount;
};
void kref_init(struct kref *kref);
void kref_get(struct kref *kref);
int kref_put(struct kref *kref, void (*release) (struct kref *kref));
对象集合:在很多情况下,必须将不同的内核对象归类到集合中,例如,所有字符设备集合,或所有基于PCI 的设备集合
struct kset {
struct kobj_type *ktype;
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops *uevent_ops;
};
extern void kset_init(struct kset * k);
extern int __must_check kset_add(struct kset * k);
extern int __must_check kset_register(struct kset * k);
extern void kset_unregister(struct kset * k);
udev和devfs的区别
在2.6内核以前一直使用的是devfs ,evfs 挂载于/dev 目录下,提供了一种类似于文件的方法来管理位于/dev目录下的所有设备,我们知道/dev 目录下的每一个文件都对应的是一个设备,至于当前该设备存在与否先且不论,而且这些特殊文件是位于根文件系统上的,在制作文件系统的时候我们就已经建立了这些设备文件,因此通过操作这些特殊文件,可以实现与内核进行交互。
但是devfs 也有一些缺点,如
- 不确定的设备映射,有时一个设备映射的设备文件可能不同,例如我的U盘可能对应
sda 有可能对应sdb ; - 没有足够的主/辅设备号,当设备过多的时候,显然这会成为一个问题;
/dev 目录下文件太多而且不能表示当前系统上的实际设备;- 命名不够灵活,不能任意指定
因此,正因为上述的问题,udev 横空出世:udev官网源码
在linux2.6 内核以后,引入了一个新的文件系统sysfs ,它挂载于/sys 目录下,跟devfs一样它也是一个虚拟文件系统,也是用来对系统的设备进行管理的
root@huawei /sys
Filesystem 1K-blocks Used Available Use% Mounted on
sysfs 0 0 0 - /sys
它把实际连接到系统上的设备和总线组织成一个分级的文件,用户空间的程序同样可以利用这些信息以实现和内核的交互,该文件系统是当前系统上实际设备树的一个直观反应。
它是通过kobject 子系统来建立这个信息的,当一个kobject被创建的时候,对应的文件和目录也就被创建了,位于/sys 下的相关目录下,既然每个设备在sysfs 中都有唯一对应的目录,那么也就可以被用户空间读写了。
用户空间的工具udev 就是利用了sysfs 提供的信息来实现所有devfs的功能的。
udev 优点:
-
动态管理:当设备添加/删除时,udev 的守护进程侦听到来自内核的uevent ,以此添加或者删除/dev 下的设备文件,所以,udev 只为 已经连接的设备产生设备文件,而不会在/dev/ 下产生大量虚无的设备文件.在发生热插拔时,设备的变化的相关信息会输出到内核的/sys (sysfs文 件系统),udev 利用sysfs 的信息来进行相应的设备节点的管理 -
自定义命名规则:通过规则文件,udev 在/dev/ 下为所有的设备定义了内核设备名称,比如/dev/sda,/dev/hda,/dev /fd (这些都是驱动层定义的设备名)等等。由于udev 是在用户空间运行,Linux 用户可以自己定义规则文件,产生标识性强的设备文件,比如/dev /boot_disk,/dev/root_disk,/dev/color_printer 等等 -
设定设备的权限和所有者/组。同样在规则文件中,可以自己定义设备相关的权限和所有者/组
root@huawei tun
/sys/dev/char/10:1/subsystem/tun
root@huawei tun
dev power subsystem uevent
root@huawei tun
10:200
root@huawei tun
MAJOR=10
MINOR=200
DEVNAME=net/tun
Cgroup
最后,我还想在此提一下Cgroup ,在查看文件系统列表中可以看到Cgroup 是占了内核中文件系统的半壁江山的,谈fs 不谈它貌似有点说不过去。
cgroup 0 0 0 - /sys/fs/cgroup/cpu,cpuacct
cgroup 0 0 0 - /sys/fs/cgroup/devices
cgroup 0 0 0 - /sys/fs/cgroup/blkio
cgroup 0 0 0 - /sys/fs/cgroup/freezer
cgroup 0 0 0 - /sys/fs/cgroup/memory
cgroup 0 0 0 - /sys/fs/cgroup/net_cls,net_prio
cgroup 0 0 0 - /sys/fs/cgroup/rdma
cgroup 0 0 0 - /sys/fs/cgroup/cpuset
cgroup 0 0 0 - /sys/fs/cgroup/perf_event
cgroup 0 0 0 - /sys/fs/cgroup/pids
cgroup 0 0 0 - /sys/fs/cgroup/hugetlb
查看Cgroup 数据结构
struct cgroup {
unsigned long flags;
atomic_t count;
struct list_head sibling;
struct list_head children;
struct cgroup *parent;
struct dentry *dentry;
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
struct cgroupfs_root *root;
struct cgroup *top_cgroup;
struct list_head css_sets;
struct list_head release_list;
};
每个子系统都有自己的资源控制统计信息结构
struct cgroup_subsys_state {
struct cgroup *cgroup;
atomic_t refcnt;
unsigned long flags;
};
struct mem_cgroup {
struct cgroup_subsys_state css;
struct res_counter res;
struct mem_cgroup_lru_info info;
int prev_priority;
struct mem_cgroup_stat stat;
};
图例来自:cgroup图示 Cgroup 系统图例 由于一个进程可以同时添加到不同的 cgroup 中(前提是这些 cgroup 属于不同的 层级)进行资源控制,而这些 cgroup 附加了不同的资源控制 子系统。所以需要使用一个结构把这些 子系统 的资源控制统计信息收集起来,方便进程通过 子系统ID 快速查找到对应的 子系统 资源控制统计信息,而css_set 结构体就是用来做这件事情
struct css_set {
struct kref ref;
struct list_head list;
struct list_head tasks;
struct list_head cg_links;
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
};
CGroup 通过 cgroup_subsys 结构操作各个子系统,每个 子系统 都要实现一个这样的结构,
struct cgroup_subsys {
struct cgroup_subsys_state *(*create)(struct cgroup_subsys *ss,
struct cgroup *cgrp);
void (*pre_destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
void (*destroy)(struct cgroup_subsys *ss, struct cgroup *cgrp);
int (*can_attach)(struct cgroup_subsys *ss,
struct cgroup *cgrp, struct task_struct *tsk);
void (*attach)(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct cgroup *old_cgrp, struct task_struct *tsk);
void (*fork)(struct cgroup_subsys *ss, struct task_struct *task);
void (*exit)(struct cgroup_subsys *ss, struct task_struct *task);
int (*populate)(struct cgroup_subsys *ss,
struct cgroup *cgrp);
void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp);
void (*bind)(struct cgroup_subsys *ss, struct cgroup *root);
int subsys_id;
int active;
int disabled;
int early_init;
const char *name;
struct cgroupfs_root *root;
struct list_head sibling;
void *private;
};
内存子系统定义了一个名为 mem_cgroup_subsys 的 cgroup_subsys 结构
struct cgroup_subsys mem_cgroup_subsys = {
.name = "memory",
.subsys_id = mem_cgroup_subsys_id,
.create = mem_cgroup_create,
.pre_destroy = mem_cgroup_pre_destroy,
.destroy = mem_cgroup_destroy,
.populate = mem_cgroup_populate,
.attach = mem_cgroup_move_task,
.early_init = 0,
};
另外Linux 内核还定义了一个 cgroup_subsys 结构的数组 subsys ,用于保存所有 子系统 的 cgroup_subsys 结构
static struct cgroup_subsys *subsys[]
#ifdef CONFIG_CPUSETS
SUBSYS(cpuset)
#endif
#ifdef CONFIG_CGROUP_DEBUG
SUBSYS(debug)
#endif
#ifdef CONFIG_CGROUP_NS
SUBSYS(ns)
#endif
#ifdef CONFIG_FAIR_CGROUP_SCHED
SUBSYS(cpu_cgroup)
#endif
#ifdef CONFIG_CGROUP_CPUACCT
SUBSYS(cpuacct)
#endif
内存限制
root@huawei memory
cgroup.clone_children memory.failcnt memory.kmem.slabinfo memory.kmem.usage_in_bytes memory.oom_control memory.usage_in_bytes tasks
cgroup.event_control memory.force_empty memory.kmem.tcp.failcnt memory.limit_in_bytes memory.pressure_level memory.use_hierarchy user.slice
cgroup.procs memory.kmem.failcnt memory.kmem.tcp.limit_in_bytes memory.max_usage_in_bytes memory.soft_limit_in_bytes notify_on_release
cgroup.sane_behavior memory.kmem.limit_in_bytes memory.kmem.tcp.max_usage_in_bytes memory.move_charge_at_immigrate memory.stat release_agent
docker memory.kmem.max_usage_in_bytes memory.kmem.tcp.usage_in_bytes memory.numa_stat memory.swappiness system.slice
root@huawei memory
/sys/fs/cgroup/memory
root@huawei memory
9223372036854771712
root@huawei memory
1 2 3 4 6 9 10 112 13
处理器占用限制
root@huawei cpu
cgroup.clone_children cpuacct.stat cpuacct.usage_percpu cpuacct.usage_sys cpu.cfs_quota_us docker system.slice
cgroup.procs cpuacct.usage cpuacct.usage_percpu_sys cpuacct.usage_user cpu.shares notify_on_release tasks
cgroup.sane_behavior cpuacct.usage_all cpuacct.usage_percpu_user cpu.cfs_period_us cpu.stat release_agent user.slice
root@huawei cpu
user 12278762
system 2208080
root@huawei cpu
154089159888977
root@huawei cpu
nr_periods 0
nr_throttled 0
throttled_time 0
root@huawei cpu
1 2 3 4 6 9 10 11 12 13
最后,想在这里记录一个难点 tty0 :当前虚拟终端的别名 tty1-ttyn :tty1-6 是文本型控制台(虚拟终端),tty7 是x-window 图形控制台.(图形终端) ttyS0 :串口终端 console :控制台终端(计算机显示器) pts :伪终端
谁与争锋?我辈当先!
|