Linux内核学习轨迹第六部:VFS四大核心对象:super_block/inode/dentry/file(第二节)

Linux Swap 子系统:架构、内存管理与虚拟化 Swap Linux Swap机制通过将不活跃内存页移至磁盘或压缩内存,扩展系统有效内存容量,缓解内存压力。传统架构中,逻辑Swap槽与物理存储绑定,导致资源浪费,尤其在使用Zswap等压缩技术时。为此,Vswap与Xswap提出虚拟化方案:前者以XArray实现灵活映射,支持多后端迁移;后者采用稀疏映射,简化管理但容量固定。二者在架构设计、资源记账与动态扩展上各有权衡,反映了内核开发中对性能、可维护性与灵活性的深层考量。 阅读详情

2. VFS四大核心对象:super_block/inode/dentry/file全解析

四大核心对象是VFS的基石,它们分别描述了文件系统的不同维度,从静态的文件系统结构,到动态的进程文件交互,形成了完整的文件管理体系。本章节基于Linux 6.6内核源码(定义在include/linux/fs.h),完整拆解每个对象的核心字段、生命周期、相互关联关系。

2.1 超级块:struct super_block

struct super_block是一个已挂载的文件系统实例的全局描述符,对应磁盘上的文件系统超级块,存储了文件系统的类型、块大小、魔数、根目录、操作函数集、挂载参数等全局信息,是整个文件系统的「根」。

每个已挂载的文件系统,在内核中都有且仅有一个super_block实例,比如系统挂载了/(ext4)、/boot(vfat)、/proc(procfs),就会有三个对应的super_block实例。

2.1.1 核心字段拆解

struct super_block {
    // 超级块的链表节点,所有已挂载的super_block都链接到全局super_blocks链表
    struct list_head s_list;
    // 设备标识符,块设备的设备号,伪文件系统为0
    dev_t s_dev;
    // 文件系统的块大小,单位字节
    unsigned long s_blocksize;
    // 块大小的位掩码,用于快速计算
    unsigned char s_blocksize_bits;
    // 文件系统的魔数,用于识别文件系统类型,比如ext4的魔数是0xEF53
    unsigned long s_magic;
    // 超级块的标志位,比如MS_RDONLY(只读挂载)、MS_NOSUID(禁止suid)
    unsigned long s_flags;
    // 挂载的次数,用于共享挂载
    int s_count;
    // 超级块的读写信号量,保护超级块的修改
    struct rw_semaphore s_umount;
    // 超级块的自旋锁
    spinlock_t s_lock;

    // 超级块操作函数集,文件系统级别的操作接口
    const struct super_operations *s_op;
    // 该文件系统的类型描述符,对应file_system_type结构体
    struct file_system_type *s_type;
    // 该超级块对应的挂载实例
    struct vfsmount *s_vfsmnt;
    // 文件系统的根目录dentry
    struct dentry *s_root;

    // inode相关字段
    // 该文件系统的所有inode的哈希表
    struct hlist_head *s_inodes;
    // 该文件系统的inode数量统计
    atomic_long_t s_inodes_count;
    // 正在使用的inode数量
    atomic_long_t s_active_inodes;
    // 脏inode链表,需要同步到磁盘的inode
    struct list_head s_inodes_dirty;
    // inode的LRU链表,用于inode缓存回收
    struct list_head s_inodes_lru;

    // 目录项缓存相关字段
    // 目录项缓存的收缩函数
    int (*s_shrink)(struct super_block *sb, struct shrink_control *sc);
    // 文件系统的最大链接数
    unsigned int s_max_links;
    // 时间戳的粒度,比如ext4是1纳秒
    u32 s_time_gran;

    // 具体文件系统的私有数据,比如ext4的ext4_sb_info
    void *s_fs_info;

    // 挂载命名空间相关
    struct user_namespace *s_user_ns;
    // 安全相关的钩子函数
    struct security_hook_heads *s_security;
} __randomize_layout;

2.1.2 核心字段深度解析

1.s_op:超级块操作函数集

定义了文件系统级别的操作接口,具体文件系统必须实现这套接口,核心函数包括
struct super_operations {
    // 分配一个新的inode
    struct inode *(*alloc_inode)(struct super_block *sb);
    // 释放inode
    void (*destroy_inode)(struct inode *inode);
    // 把inode的元数据同步到磁盘
    void (*write_inode)(struct inode *inode, struct writeback_control *wbc);
    // 丢弃inode
    void (*evict_inode)(struct inode *inode);
    // 把文件系统的所有脏数据同步到磁盘
    int (*sync_fs)(struct super_block *sb, int wait);
    // 冻结文件系统,用于快照
    int (*freeze_super)(struct super_block *sb);
    // 解冻文件系统
    int (*thaw_super)(struct super_block *sb);
    // umount时调用,释放超级块
    void (*put_super)(struct super_block *sb);
    // 统计文件系统的磁盘使用情况
    int (*statfs)(struct dentry *dentry, struct kstatfs *buf);
};
比如ext4文件系统,会实现自己的ext4_sops超级块操作函数集,处理ext4格式的inode分配、同步、磁盘统计等逻辑。

2.s_root:文件系统的根目录dentry

指向该文件系统根目录的dentry实例,是路径解析的起点,挂载文件系统时,内核会读取文件系统的根目录inode,创建对应的dentry,赋值给s_root。

3.s_fs_info:文件系统私有数据

这是VFS为具体文件系统提供的私有数据指针,具体文件系统可以把自己的超级块私有信息存储在这里,比如ext4的struct ext4_sb_info、xfs的struct xfs_mount,VFS层不会修改这个指针,完全由具体文件系统管理。

4.s_inodes/s_inodes_lru/s_inodes_dirty

管理该文件系统的所有inode,包括inode的哈希表(用于快速查找inode)、LRU链表(用于inode缓存回收)、脏inode链表(用于同步到磁盘),是inode生命周期管理的核心结构。

2.1.3 生命周期

  1. 创建:mount系统调用挂载文件系统时,内核调用具体文件系统的fill_super函数,读取磁盘上的超级块,创建并初始化super_block实例,加入全局super_blocks链表;
  2. 使用:文件系统挂载期间,super_block实例一直存在,用于管理该文件系统的所有inode、dentry、挂载参数;
  3. 销毁:umount系统调用卸载文件系统时,内核会等待所有的inode释放,调用super_operations的put_super函数,释放super_block实例,从全局链表中移除。

2.2 索引节点:struct inode

struct inode(Index Node,索引节点)是VFS中最核心的对象,它描述了一个文件的元数据和物理存储信息,包括文件的权限、所有者、大小、创建/修改/访问时间、块指针、扩展属性等。
核心认知纠正:inode是文件的唯一标识,和文件名无关。文件名只是dentry中的一个字符串,一个inode可以对应多个文件名(硬链接),每个硬链接对应一个dentry,指向同一个inode。
每个文件(包括目录、设备文件、管道、socket)在内核中都有且仅有一个inode实例,无论是磁盘文件系统的inode(持久化到磁盘),还是内存文件系统的inode(仅存在于内存),都由VFS统一管理。

2.2.1 核心字段拆解

struct inode {
    // inode的哈希表节点,用于快速查找
    struct hlist_node i_hash;
    // inode的链表节点,用于链接到super_block的inode链表
    struct list_head i_list;
    // inode的LRU链表节点,用于缓存回收
    struct list_head i_lru;
    // 脏inode链表节点,用于同步到磁盘
    struct list_head i_io_list;
    // 该inode所属的超级块
    struct super_block *i_sb;

    // inode号,文件系统内唯一,是文件的唯一标识
    ino_t i_ino;
    // 硬链接计数,有多少个硬链接指向这个inode,为0时释放inode
    unsigned int i_nlink;
    // 文件的UID/GID
    kuid_t i_uid;
    kgid_t i_gid;
    // 文件的类型和权限,S_IFREG(普通文件)/S_IFDIR(目录)/S_IFCHR(字符设备)等
    umode_t i_mode;
    // 文件的标志位,比如S_IMMUTABLE(不可修改)
    unsigned int i_flags;
    // 文件的锁
    struct rw_semaphore i_rwsem;
    // 自旋锁
    spinlock_t i_lock;

    // 文件的大小,单位字节
    loff_t i_size;
    // 文件的块数量
    blkcnt_t i_blocks;
    // 文件的块大小
    unsigned int i_blkbits;

    // 时间戳
    struct timespec64 i_atime; // 最后访问时间
    struct timespec64 i_mtime; // 最后修改时间
    struct timespec64 i_ctime; // 最后元数据修改时间
    struct timespec64 i_btime; // 文件创建时间

    // 操作函数集
    // inode操作函数集,元数据相关操作
    const struct inode_operations *i_op;
    // 文件操作函数集,IO相关操作,打开文件时会赋值给file->f_op
    const struct file_operations *i_fop;

    // 页缓存相关
    // 该文件的页缓存address_space,管理文件的所有缓存页
    struct address_space *i_mapping;
    struct address_space i_data; // 内嵌的address_space,普通文件直接使用

    // 设备相关,设备文件的设备号
    dev_t i_rdev;

    // 引用计数,有多少个地方引用了这个inode,为0时可以回收
    refcount_t i_count;
    // 脏页标记,inode的元数据是否被修改
    unsigned long i_state;

    // 安全相关
    struct security_hook_heads *i_security;
    // 私有数据,具体文件系统使用,比如ext4的ext4_inode_info
    void *i_private;
} __randomize_layout;

2.2.2 核心字段深度解析

   1.i_ino与i_nlink

  • i_ino:inode号,在同一个文件系统内是唯一的,是文件的唯一标识,ls -i命令可以查看文件的inode号;
  • i_nlink:硬链接计数,每创建一个硬链接,这个值加1,每删除一个硬链接,这个值减1,当值为0时,inode会被释放,对应的磁盘空间会被回收。

   2.i_op:inode操作函数集

定义了文件元数据相关的操作接口,是目录、文件创建/删除、硬链接/软链接、权限修改的核心入口,核心函数包括:
struct inode_operations {
    // 创建一个新文件
    int (*create)(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl);
    // 创建一个硬链接
    int (*link)(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry);
    // 删除一个文件/硬链接
    int (*unlink)(struct inode *dir, struct dentry *dentry);
    // 创建一个软链接
    int (*symlink)(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, const char *symname);
    // 创建一个目录
    int (*mkdir)(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode);
    // 删除一个目录
    int (*rmdir)(struct inode *dir, struct dentry *dentry);
    // 重命名文件/目录
    int (*rename)(struct mnt_idmap *idmap, struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags);
    // 读取软链接的目标路径
    const char *(*get_link)(struct dentry *dentry, struct inode *inode, struct delayed_call *done);
    // 修改文件的权限
    int (*setattr)(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *attr);
    // 获取文件的属性
    int (*getattr)(struct mnt_idmap *idmap, const struct path *path, struct kstat *stat, u32 request_mask, unsigned int query_flags);
};
比如,我们调用mkdir()创建目录,最终会调用父目录inode的i_op->mkdir函数;调用unlink()删除文件,最终会调用父目录inode的i_op->unlink函数。

1.i_fop:文件操作函数集

定义了文件打开后的IO操作接口,进程调用open()打开文件时,内核会把inode的i_fop赋值给file实例的f_op,后续的read()/write()等操作,都会调用file->f_op对应的函数。
比如ext4的普通文件inode,i_fop指向ext4_file_operations,实现了ext4的read/write逻辑;字符设备的inode,i_fop指向设备驱动的file_operations,实现设备的IO逻辑。

2.i_mapping:页缓存address_space

指向该文件的页缓存地址空间,管理文件的所有缓存页,是VFS和页缓存层的桥梁。我们在内存管理章节已经详细拆解过address_space,文件的read/write操作,都会通过这个字段访问页缓存。

3.i_mode:文件类型与权限

这个字段分为两部分:高4位是文件类型,低12位是文件权限。
  • 常见文件类型:S_IFREG(普通文件)、S_IFDIR(目录)、S_IFLNK(软链接)、S_IFCHR(字符设备)、S_IFBLK(块设备)、S_IFIFO(管道)、S_IFSOCK(socket);
  • 权限位:低9位是UGO的读/写/执行权限,高3位是SUID/SGID/Sticky位

2.2.3 生命周期

  1. 创建:创建文件/目录/设备时,内核调用super_block的s_op->alloc_inode函数,分配inode实例,初始化inode号、权限、所有者、时间戳等信息,加入到super_block的inode哈希表和链表中;
  2. 使用:文件被访问、打开、修改期间,inode的引用计数i_count会增加,保证inode不会被回收;
  3. 脏数据同步:inode的元数据被修改后,会被标记为脏,加入到super_block的脏inode链表中,内核的回写线程会定期把脏inode同步到磁盘;
  4. 释放:当硬链接计数i_nlink为0,且引用计数i_count为0时,内核会调用s_op->evict_inode函数,释放inode对应的磁盘空间,回收inode实例。

2.3 目录项:struct dentry

struct dentry(Directory Entry,目录项)是路径解析的核心,它描述了文件的名称、目录层级关系、与inode的关联。简单来说,inode描述文件的「是什么」,dentry描述文件的「在哪里」。
dentry是内存中的对象,不会持久化到磁盘(磁盘上的目录项存储在目录文件的数据块中),内核会把经常访问的dentry缓存起来,形成目录项缓存(dcache),避免每次路径解析都要从磁盘读取目录项,极大提升路径解析的性能。

2.3.1 核心字段拆解

struct dentry {
    // 目录项的引用计数
    refcount_t d_count;
    // 目录项的标志位,比如DCACHE_UNHASHED(未哈希)、DCACHE_MOUNTED(挂载点)
    unsigned int d_flags;
    // 自旋锁
    spinlock_t d_lock;

    // 目录项的名称
    struct qstr d_name;
    // 父目录的dentry,根目录的d_parent指向自己
    struct dentry *d_parent;
    // 该dentry对应的inode,为NULL表示负dentry
    struct inode *d_inode;
    // 该dentry所属的超级块
    struct super_block *d_sb;

    // 子目录项的哈希表,用于快速查找子目录/文件
    struct hlist_head d_child;
    // 子目录项的链表,用于遍历该目录下的所有子项
    struct list_head d_subdirs;
    // 兄弟目录项的链表节点,链接到父目录的d_subdirs链表
    struct list_head d_child_list;

    // 目录项的LRU链表节点,用于dcache回收
    struct list_head d_lru;
    // 目录项操作函数集
    const struct dentry_operations *d_op;

    // 挂载相关,该dentry作为挂载点时,指向对应的vfsmount实例
    struct vfsmount *d_mount;
    // 目录项的完整路径名缓存
    char *d_iname;
} __randomize_layout;

2.3.2 核心字段深度解析

1.d_name与d_parent

  • d_name:目录项的名称,是一个struct qstr结构体,包含名称字符串、长度、哈希值,哈希值用于快速查找子目录项;
  • d_parent:指向父目录的dentry,形成了完整的目录层级树,根目录的d_parent指向自己。

2.d_inode:关联的inode

指向该目录项对应的inode实例,一个inode可以对应多个dentry(硬链接),每个硬链接对应一个dentry,都指向同一个inode。
  • 负dentry(Negative Dentry):如果d_inode为NULL,这个dentry就是负dentry,对应一个不存在的文件。内核会缓存负dentry,当用户频繁访问一个不存在的文件时,不需要每次都遍历磁盘目录,直接通过负dentry返回ENOENT错误,极大提升性能。

3.d_subdirs与d_child

  • d_subdirs:该目录下所有子目录项的链表头,遍历目录时,就是遍历这个链表;
  • d_child:子目录项的哈希表头,根据文件名的哈希值,可以在O(1)时间复杂度内找到对应的子目录项,是路径解析的核心优化。

4.d_op:目录项操作函数集

定义了目录项的操作接口,用于路径解析、哈希比较、dentry释放等,核心函数包括:
struct dentry_operations {
    // 比较两个文件名是否相同,用于路径解析
    int (*d_compare)(const struct dentry *dentry, unsigned int len, const char *str, const struct qstr *name);
    // 计算文件名的哈希值
    int (*d_hash)(const struct dentry *dentry, struct qstr *name);
    // dentry被释放时调用
    void (*d_release)(struct dentry *dentry);
    // 路径解析时,判断dentry是否有效
    int (*d_revalidate)(struct dentry *dentry, unsigned int flags);
};
比如网络文件系统NFS,会实现自己的d_revalidate函数,每次访问dentry时,验证远端服务器上的文件是否存在,保证缓存的一致性。

2.3.3 生命周期与dcache

  1. 创建:路径解析时,如果对应的dentry不在dcache中,内核会创建新的dentry实例,初始化名称、父目录、关联的inode,加入到父目录的子项哈希表和链表中,同时加入dcache的全局哈希表;
  2. 缓存:dentry被释放后,不会立即销毁,而是加入到dcache的LRU链表中,缓存起来,后续再次访问时,可以直接从LRU链表中取出复用,避免重新创建;
  3. 回收:当系统内存不足时,内核会调用dcache的收缩函数,回收LRU链表中最久未使用的dentry,释放内存;
  4. 销毁:当dentry的引用计数为0,且被从LRU链表中移除时,内核会销毁dentry实例,释放内存。
dcache的核心价值:路径解析是文件操作中最频繁的操作之一,比如打开/usr/bin/ls,需要解析/、usr、bin、ls四个目录项,如果每次都要从磁盘读取,性能会极差。dcache把经常访问的dentry缓存到内存中,路径解析的性能提升了几个数量级。

2.4 打开的文件实例:struct file

struct file是进程打开一个文件后,内核创建的动态实例,描述了进程与文件的交互上下文,包括文件的打开模式、当前读写偏移、操作函数集、私有数据等。
核心认知纠正:inode是文件的静态描述,全局唯一;file是进程打开文件的动态实例,每个进程每次打开同一个文件,都会创建一个新的file实例。比如两个进程同时打开同一个文件,会有两个独立的file实例,各自有自己的读写偏移,但是共享同一个inode。
file实例是用户态文件描述符(fd)的底层载体,用户态拿到的fd,本质是进程文件描述符表中的索引,对应内核中的一个file实例。

2.4.1 核心字段拆解

struct file {
    // 文件的引用计数
    refcount_t f_count;
    // 文件的打开模式,O_RDONLY/O_WRONLY/O_RDWR/O_APPEND/O_NONBLOCK等
    unsigned int f_mode;
    // 文件的打开标志,open()系统调用的flags参数
    unsigned int f_flags;
    // 文件的当前读写偏移,lseek()修改的就是这个值
    loff_t f_pos;
    // 保护f_pos的自旋锁
    spinlock_t f_pos_lock;

    // 该文件对应的inode
    struct inode *f_inode;
    // 该文件对应的路径信息,包括dentry和vfsmount
    struct path f_path;
    #define f_dentry f_path.dentry
    #define f_vfsmnt f_path.mnt

    // 文件操作函数集,open()时从inode->i_fop复制过来
    const struct file_operations *f_op;

    // 所属的进程文件描述符表
    struct files_struct *f_files;
    // 对应的文件描述符fd
    unsigned int f_fd;

    // 异步IO相关
    struct fown_struct f_owner;
    // 事件通知相关,poll/select/epoll使用
    struct epoll_event f_epoll;
    // 私有数据,文件系统/驱动使用,比如ext4的私有数据、设备驱动的私有数据
    void *private_data;

    // 安全相关
    struct security_hook_heads *f_security;
    // 预读相关,文件的预读状态
    struct file_ra_state f_ra;
} __randomize_layout;
2.4.2 核心字段深度解析

1.f_path:文件的路径信息

是一个struct path结构体,包含两个字段:
  • dentry:指向该文件的dentry实例;
  • mnt:指向该文件所在的挂载实例struct vfsmount。这个字段是文件操作的核心,通过它可以找到对应的dentry、inode、super_block,完成所有的文件操作。

2.f_op:文件操作函数集

这是IO操作的核心入口,open()系统调用时,内核会把inode的i_fop复制到这里,后续的read()/write()/mmap()/fsync()等系统调用,都会调用这个函数集对应的函数。
核心函数包括:
struct file_operations {
    // 打开文件时调用
    int (*open)(struct inode *inode, struct file *filp);
    // 读文件
    ssize_t (*read)(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
    // 写文件
    ssize_t (*write)(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
    // 新的异步IO读写接口,替代传统的read/write
    ssize_t (*read_iter)(struct kiocb *iocb, struct iov_iter *to);
    ssize_t (*write_iter)(struct kiocb *iocb, struct iov_iter *from);
    // 调整文件读写偏移
    loff_t (*llseek)(struct file *filp, loff_t offset, int whence);
    // 内存映射
    int (*mmap)(struct file *filp, struct vm_area_struct *vma);
    // 同步文件数据到磁盘
    int (*fsync)(struct file *filp, loff_t start, loff_t end, int datasync);
    // 轮询文件事件,poll/select/epoll使用
    __poll_t (*poll)(struct file *filp, struct poll_table_struct *wait);
    // 控制文件,ioctl系统调用
    long (*unlocked_ioctl)(struct file *filp, unsigned int cmd, unsigned long arg);
    // 关闭文件时调用
    int (*release)(struct inode *inode, struct file *filp);
    // 刷新文件的脏页
    int (*flush)(struct file *filp, fl_owner_t id);
};
这是VFS最核心的操作函数集,所有的文件IO操作最终都会落到这里,不同的文件系统、设备驱动、socket,都会实现自己的file_operations函数集,接入VFS的统一接口。

3f_pos:文件当前读写偏移

记录了文件的当前读写位置,每次read()/write()操作后,这个值会自动增加对应的字节数;lseek()系统调用可以直接修改这个值,实现随机读写。
  • 核心细节:每个file实例有独立的f_pos,多个进程同时打开同一个文件,各自的读写偏移互不影响;如果多个进程共享同一个file实例(比如fork之后父子进程共享打开的文件),则共享同一个f_pos,读写会相互影响。

4.f_flags与f_mode

  • f_flags:保存了open()系统调用的flags参数,比如O_NONBLOCK(非阻塞IO)、O_APPEND(追加写)、O_DIRECT(直接IO)、O_SYNC(同步写),内核会根据这些标志位,调整IO操作的行为;
  • f_mode:文件的访问模式,比如FMODE_READ/FMODE_WRITE/FMODE_EXEC,是权限检查的核心依据。

5.private_data:私有数据指针

这是VFS为文件系统、设备驱动提供的私有数据指针,用于存储打开文件的上下文信息,比如设备驱动的硬件状态、文件系统的会话信息、socket的网络连接状态等,VFS层不会修改这个指针,完全由具体的实现管理。

2.4.3 生命周期

  1. 创建:open()系统调用时,内核完成路径解析、权限检查后,分配file实例,初始化f_path、f_op、f_flags、f_mode、f_pos等字段,调用f_op->open函数,完成文件的打开操作,然后把file实例加入到进程的文件描述符表中,返回对应的fd给用户态;
  2. 使用:进程通过fd调用read()/write()/lseek()/mmap()等系统调用时,内核通过fd找到对应的file实例,调用f_op对应的函数,完成IO操作;
  3. 引用计数管理:每次dup()、fork()都会增加file实例的引用计数f_count,每次close()都会减少引用计数;
  4. 销毁:当引用计数f_count为0时,内核调用f_op->release函数,完成文件的关闭操作,释放file实例,从进程的文件描述符表中移除。

2.5 四大核心对象的关联关系

我们用一个简单的例子,梳理四大核心对象的关联关系:进程打开/data/test.txt文件
  1. super_block:对应/data分区挂载的ext4文件系统实例,是整个文件系统的根;
  2. inode:对应test.txt文件的元数据,inode号唯一,存储了文件的权限、大小、块指针等信息;
  3. dentry:对应test.txt的目录项,名称是test.txt,父目录是data的dentry,指向test.txt的inode;
  4. file:进程打开文件时创建的实例,指向test.txt的dentry和inode,有独立的读写偏移,f_op指向ext4的文件操作函数集,对应进程的fd。
关联关系的核心链路:
进程fd → struct file → struct dentry → struct inode → struct super_block → 具体文件系统实现

WRF-Chem新手避坑指南:从chem_opt到emiss_opt,那些手册里没明说的参数配置实战 本文为WRF-Chem新手提供从chem_opt到emiss_opt的参数配置实战指南,解析官方文档中未明确的常见陷阱与解决方案。通过华北重霾案例,详细讲解化学机制选择、排放源配置及特殊参数组合的注意事项,帮助用户避开常见错误,提升模拟效率。 阅读详情

相关推荐

使用TensorFlow搭建FNN(全连接神经网络)的基本步骤

提示:转载请注明出处,若本文无意侵犯到您的合法权益,请及时与作者联系。 目录 一、定义神经网络的输入输出 二、搭建神经网络 1、定义一个神经层中的权重 2、定义一个神经层中的阈值 3、定义一个神经层中的激活函数 4、组合神经层为神经网络 三、搭建损失函数和优化器 1、搭建损失函数 首先介绍第一个函数这其中用到的共同的函数为 2、定义优化器 四、训练神经网络 全连接神经网络的网络结构如下: 一、定义神经网络的输入输出 神经网络最擅长的工作就是模拟非线性函数,即一个复杂的高..

qq_41959920的博客 4070

Linux内核学习轨迹第六部:VFS的设计思想与整体架构(第一节)

很多工程师对VFS的理解停留在「文件操作的封装」表层,却不理解四大核心对象的生命周期、挂载的底层实现、目录项缓存的工作机制、IO全链路的内核流转,最终在遇到实际问题时手足无措。:无论底层是什么资源,VFS都把它抽象为一个file实例,对应一套file_operations操作函数集,用户态通过统一的POSIX接口操作,VFS层把接口调用转发给对应的操作函数,最终实现对底层资源的访问,这就是「一切皆文件」的底层逻辑。为避免内容过长导致异常,本章节先完成前3个核心模块的完整拆解,后续模块可按需继续补充。

新时代农民工 723

SQLSTATE58030

在优化一条SQL的时候遇到了执行错误 gtlions =# select t1.telnumber,t2.ua,t2.url,t1.apply_name,t2.apply_name from tb1 t1 gtlions -# left outer join tb2 t2 on t1.sid = t2.ipsid gtlions-# where t1.sum_date=20141128 a

Gtlions Tracker 3659

理解 Linux 动态库加载:LD_LIBRARY_PATH

flyfish

二分掌柜的 334

【LVGL】从HTML到LVGL:嵌入式UI的设计迁移与落地实践

嵌入式UI迁移实践:从HTML到LVGL 本文介绍了将HTML/CSS设计的UI原型迁移到嵌入式系统(LVGL)的完整流程,重点涉及"HTML→Figma→LVGL"的三步转换方法。具体内容包括: 设计迁移流程:通过Figma作为中间桥梁,将HTML原型转化为标准设计资产,再适配到LVGL库; 工具与参数准备:详细列出了设计迁移所需的工具链和需要提取的核心设计参数; Figma还原步骤:分组件讲解如何在Figma中1:1还原HTML设计,包括标题栏、压力显示区、图表区等核心组件; LVG

ymlmail的博客 1971

Kolla 容器化 高可用OpenStack 部署与 Ceph 集群集成

本文介绍了 Kolla 项目在容器化 OpenStack 部署和管理方面的应用,以及与 Ceph 集群的集成。Kolla 项目通过容器技术提供了一种简化和自动化的 OpenStack 部署方法,同时实现了易于升级和回滚的特点。本文还探讨了 Kolla 在实现零宕机升级方面的进展,并分析了其对 OpenStack 用户和社区的重要意义。

we22635的博客 2702

Linux-iostat命令详解

Linux命令学习记录

m0xin的博客 100

别再到处找了!2024最新银河麒麟V10全版本(飞腾/龙芯/兆芯)官方下载与安装保姆级教程

本文提供2024年银河麒麟V10操作系统全版本(飞腾/龙芯/兆芯)的官方下载与安装保姆级教程,涵盖版本选择、镜像获取、启动盘制作及安装优化等关键步骤,助您高效部署国产操作系统。

weixin_26846533的博客 482

Linux 服务器性能排查手册(2026):CPU、内存、磁盘IO、网络四大瓶颈定位

iptables 四表五链模型、firewalld zone 信任级别、云安全组与主机防火墙的关系与优先级,避坑改了防火墙把自己挡在服务器外面的翻车事故。

2502_91473995的博客 293

Synopsys SCL许可证服务器搭建详解:从安装到生成.dat文件

本文详细解析了Synopsys SCL许可证服务器的完整搭建流程,从系统环境准备、SCL安装到生成.dat文件。重点阐述了如何正确获取HOST ID、配置License文件以及调试常见故障,为数字芯片设计工程师提供了一套从零到一的实战避坑指南,确保EDA工具链稳定运行。

weixin_29306011的博客 610

2023华为od机试【最小循环子数组】C++

2023华为od机试【最小循环子数组】C++ 给定一个由若干整数组成的数组nums,请检查数组是否是由某个子数组重复循环拼接而成,请输出这个最小的子数组。

MISAYAONE的博客 2185

【Linux】APT 本地 deb 安装与 `-f` 参数总结笔记

apt install ./xx.deb 可自动解析并安装依赖,无需 -f;-f 仅用于修复已损坏的依赖状态,非首次安装时必需。apt install -f 可单独运行,修复 broken dependencies。两者职责不同:前者是安装与依赖解决,后者是故障修复。完全离线时需提前准备依赖包或本地源。

hknaruto的专栏 210

【知识分享】高速印刷电路板(PCB)寄生参数计算指南

对于高速PCB设计而言,寄生参数一直是令人讨厌的问题,它们会悄悄潜入PCB并在电路中造成严重的破坏,具体来说,它们是渗透到高速电路中的隐藏杂散电容器和电感器,包括由封装引线和长走线形成的电感器、PCB焊盘对金属平面形成的电容器、走线之间形成的电容器等等。

一只豌豆象的博客 1780

Linux rm 误删文件恢复实操教程

Linux使用rm删除文件时,并不会直接抹除磁盘上的数据,只是移除文件索引,让系统不再识别这块空间。只要没有写入新数据,原有扇区内容就会保留。新文件写入才有可能覆盖这些区域,一旦覆盖就很难找回。恢复的本质就是扫描磁盘,找到这些还存在、但索引丢失的数据条目,再把它们导出保存到其他分区。越早停止写入,恢复成功的概率越高。

海天数据恢复-winhex数据恢复教程 226

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Windows/Linux下强实时运动控制内核(二):基于Qt的Delta机械手的开发应用

强实时运动控制内核MotionRT750下Qt开发Delta机械手的完整开发流程。

weixin_57350300的博客 241

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Linux sudo

如果输出 → 无 sudo 权限 如果输出 → 拥有全部 sudo 权限 辅助验证命令 ⚠️ 注意:在 wheel 组 ≠ 一定能 sudo,必须 开启 Ubuntu/Debian: ✅ 重要:修改组之后,用户要重新登录才生效! 或者执行 临时生效 看到这行(没有 #注释)才生效: 方式 2:visudo 直接单独给用户授权(精细化权限) 找到 ,下面添加一行: 自带语法校验,写错会告警,不要直接 vim 改 ,写错直接 sudo 炸掉! 想免密 su

fengliyang_的博客 178

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Linux epoll 一篇讲透:从 select/poll 到红黑树、LT/ET,再到完整 TCP 服务器

一万个客户端已经连上服务器,眼下只有十个客户端发来了数据。服务器怎样把时间花在这十个连接上?理解这个问题,就抓住了 epoll 的主线。接下来,我们沿着“为什么需要它 → 接口怎么用 → 内核如何实现 → LT/ET 怎么写 → 完整服务器怎么运行”的顺序,把知识连起来。**阅读基础:**了解socketbindlistenaccept的基本用途即可。本文示例面向 Linux,服务器使用 C++17,实验脚本使用 Python 3。

2601_94861874的博客 134

Linux 网络基础详解:IP、子网、路由与 ip、ss 命令实战

建库建表、增删改查、连接查询(内连左连右连)、聚合函数、权限控制 GRANT/REVOKE,每条命令配可运行示例,零基础也能跟着敲会 SQL 基础。

2502_91473995的博客 611

Linux、Shell、MySQL 测试卷逐题细讲(下篇:MySQL)

本文为Linux、Shell、MySQL测试卷下半段MySQL部分逐题讲解,包含填空、选择与SQL分析三类题型。填空题覆盖COUNT、HAVING、DISTINCT、事务、约束、索引等核心语法;选择题辨析存储过程、索引类型、ACID、存储引擎、用户管理等考点。SQL大题围绕员工、部门、职位、地点四张关联表,考察多表连接、分组聚合、自连接、相关子查询、NULL处理等高频写法,标注LEFT JOIN统计计数、NULL判断、子查询别名等易错坑点,同时梳理试卷OCR识别带来的干扰问题,重点提示SQL实操中的常见失误

dongziwen1的博客 181

深入浅出聊聊 Linux 的 PageCache 与系统极致性能

本文深入浅出解析了 Linux PageCache 的核心机制,揭示其如何通过“延迟写、预读读”提升系统性能。以监控告警为切入点,阐明 free -h 中 buff/cache 并非真正占用,真正可用内存由 available 决定。结合 Kafka、Elasticsearch、MySQL 等实战场景,说明中间件如何依赖 PageCache 实现极致性能。强调不可手动清理缓存,并建议合理调优脏页参数,避免卡顿。最终指出:内存满≠危机,而是系统高效运行的体现。

小小默:进无止境 299

Linux 下 OpenCode 接入自定义大模型 API 教程:以 DeepSeek-V4.1-Flash-1017 为例

本文介绍在Linux下通过Python脚本配置OpenCode接入自定义大模型API(以DeepSeek-V4.1-Flash-1017为例),实现永久化、非侵入式配置。通过修改~/.config/opencode/opencode.json文件,添加OpenAI兼容服务商BLSC,注册模型并设置APIKey。支持命令行测试、默认模型设定及安全权限控制,操作简单且不影响原有配置。适用于各类支持OpenAI接口的自定义模型服务,提升开发灵活性与安全性。

qq_15060477的博客 122

【Linux 命令实战(06):Linux 文件权限管理,掌握 chmod、chown、chgrp】

chmod:修改文件和目录权限。chown:修改文件所有者,也可以修改所属用户组。chgrp:修改文件所属用户组。r:读取。w:写入。x:执行,对于目录则表示进入和访问能力。ugo:分别代表所有者、所属组和其他用户。我认为,权限管理最重要的不是记住755644这些数字,而是先弄清楚谁需要访问文件、需要执行什么操作,再给出恰当的权限。尤其是在测试服务器和生产服务器上,不要为了图方便直接使用chmod 777。权限开放得越大,并不代表问题解决得越好。

一些微不足道的见解、希望能帮助各位 301

【Linux 命令实战(02):文件与目录操作,掌握 pwd、ls、cd 三个核心命令】

命令作用cd /进入根目录cd ~进入当前用户家目录cd返回当前用户家目录cd …返回上一级目录cd …/…返回上两级目录cd -返回上一次所在目录进入指定目录命令核心用途常用参数pwd查看当前目录-L、-Pls查看文件和目录cd切换目录…、~、-Linux 文件系统的基本结构。绝对路径与相对路径的区别。Tab 自动补全。Shell 通配符。使用&&组合命令。这篇文章主要解决的是如何在 Linux 文件系统中快速定位目录。

一些微不足道的见解、希望能帮助各位 194

Linux篇(五)

本文系统梳理了Linux常用终端快捷键、软件包管理(yum/apt)、服务管理(systemctl)、软链接(ln)、时间与IP配置、域名解析、固定IP设置及网络命令(ping/wget/curl),涵盖日常运维核心操作,助力高效管理Linux环境。

wykyzdq的博客 17

Linux Day29——HTTP与网络排障

*实测**:`traceroute -n -m 8 8.8.8.8` 的输出:第 1 跳 `172.17.144.1`(本机网关)、第 2 跳 `10.32.0.1`、第 3 跳 `10.50.255.253`、第 4 跳 `* * *`、第 5 跳 `221.226.71.193`、第 6 跳 `* * *`、第 7、8 跳有地址但夹着星号。`ping` 和 `traceroute` 都靠它。**实测**:`ss -lta` 看到三行 `domain`,加 `-n` 后变成 `53`。

2503_94114317的博客 152

Linux的渲染与显示系统链路

Linux渲染与显示链路核心为DRM/KMS + EGL直连模式,绕过传统X11/Wayland中间层,实现低延迟、高效率的直接帧提交。相比X11的粗粒度权限控制与Wayland的合成开销,该方案链路短、资源消耗低,但仅支持单进程独占显示,缺乏窗口管理与系统级兜底。EGL作为跨平台桥梁,连接OpenGL ES与原生显示系统,通过Display、Surface、Context三要素构建渲染环境。内核层DRM管理GPU资源,KMS配置显示模式,用户态GDM负责登录会话,共同构成从硬件到应用的完整图形栈。

微小的鱼的博客 297
上一篇: Linux内核学习轨迹第六部:VFS的设计思想与整体架构(第一节)
下一篇: Linux内核学习轨迹第六部:文件系统的注册、挂载与卸载全流程(第三节)
WythePlus
博客等级 码龄11年 397粉丝 300原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值