Linux内核文件系统-虚拟文件系统-地址空间

建议点击这里查看个人主页上的最新原文

点击这里在哔哩哔哩bilibili在线观看配套的教学视频

点击这里在哔哩哔哩bilibili在线观看配套的加餐视频(就是一些补充)

点击跳转到内核课程所有目录

一般的Linux书籍都是先讲解进程和内存相关的知识,但我想先讲解文件系统。第一,因为我就是做文件系统的,更擅长这一块,其他模块的内容我还要再去好好看看书,毕竟不能误人子弟嘛;第二,是因为文件系统模块更接近于用户态,是相对比较好理解的内容(当然想深入还是要下大功夫的),由文件系统入手比较适合初学者。

虚拟文件系统英文全称Virtual file system,缩写为VFS,又称为虚拟文件切换系统(virtual filesystem switch)。所有的文件系统都要先经过虚拟文件系统层,虚拟文件系统相当于制定了一套规则,如果你想写一个新的文件系统,只需要遵守这套规则就可以了。

VFS虽然是用C语言写的,但使用了面向对象的设计思路。

磁盘块可能不连续和动态变化的,文件访问需要将文件看作一个连续的字节流,这个矛盾的解决核心在于地址空间的引入。

// 可缓存、可映射对象的内容。
struct address_space {
        struct inode            *host;            // 拥有者,可以是 inode 或 block_device。
        struct xarray           i_pages;          // 缓存的页面。
        struct rw_semaphore     invalidate_lock;  // 在无效操作期间,保护页缓存内容与文件偏移->磁盘块映射之间的一致性。它还用于阻止通过内存映射修改页缓存内容。
        gfp_t                   gfp_mask;         // 用于分配页面的内存分配标志。
        atomic_t                i_mmap_writable;  // VM_SHARED 映射的数量。
#ifdef CONFIG_READ_ONLY_THP_FOR_FS
        /* thp 的数量,仅用于非 shmem 文件 */
        atomic_t                nr_thps;        // 页缓存中的 THP(非共享内存)数量。
#endif
        struct rb_root_cached   i_mmap;         // 私有和共享映射的树。
        unsigned long           nrpages;        // 页条目的数量,由 i_pages 锁保护。
        pgoff_t                 writeback_index;// 写回从这里开始。
        const struct address_space_operations *a_ops; // 方法。
        unsigned long           flags;          // 错误位和标志(AS_*)。
        struct rw_semaphore     i_mmap_rwsem;   // 保护 @i_mmap 和 @i_mmap_writable
        errseq_t                wb_err;         // 最近发生的错误。
        spinlock_t              private_lock;   // 供 address_space 的拥有者使用。
        struct list_head        private_list;   // 供 address_space 的拥有者使用。
        void                    *private_data;  // 供 address_space 的拥有者使用。
} __attribute__((aligned(sizeof(long)))) __randomize_layout;

地址空间操作:

struct address_space_operations {
        int (*writepage)(struct page *page, struct writeback_control *wbc); // 将文件在内存page中的更新到磁盘上
        int (*read_folio)(struct file *, struct folio *); // 从磁盘上读取文件的数据到内存page中

        /* 从此映射中回写一些脏页。 */
        int (*writepages)(struct address_space *, struct writeback_control *); // 将多个page更新到磁盘上

        /* 标记一个 folio 为脏页。如果此操作使其变脏,则返回 true */
        bool (*dirty_folio)(struct address_space *, struct folio *);

        void (*readahead)(struct readahead_control *);

        int (*write_begin)(struct file *, struct address_space *mapping, // 要求具体文件系统准备将数据写到文件
                                loff_t pos, unsigned len,
                                struct page **pagep, void **fsdata);
        int (*write_end)(struct file *, struct address_space *mapping,   // 完成数据复制之后调用,具体文件系统 unlock page,释放引用计数,更新 i_size
                                loff_t pos, unsigned len, unsigned copied,
                                struct page *page, void *fsdata);

        /* 不幸的是,FIBMAP 需要这个权宜之计。不要使用它 */
        sector_t (*bmap)(struct address_space *, sector_t); // 将文件中的逻辑块扇区编号映射为对应设备上的物理块扇区编号
        void (*invalidate_folio) (struct folio *, size_t offset, size_t len); // 使某个page部分或全部失效
        bool (*release_folio)(struct folio *, gfp_t); // 日志文件系统使用,释放page
        void (*free_folio)(struct folio *folio);
        ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter); // 绕过page cache
        /*
         * 将folio的内容移动到指定的目标,如果migrate_mode是MIGRATE_ASYNC,就不阻塞(异步)
         */
        int (*migrate_folio)(struct address_space *, struct folio *dst,
                        struct folio *src, enum migrate_mode);
        int (*launder_folio)(struct folio *); // 释放一个folio之前调用,回写dirty的folio
        bool (*is_partially_uptodate) (struct folio *, size_t from, // 判断是否最新
                        size_t count);
        void (*is_dirty_writeback) (struct folio *, bool *dirty, bool *wb);
        int (*error_remove_page)(struct address_space *, struct page *); // 被内存故障处理代码使用

        /* swapfile support */
        int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
                                sector_t *span);
        void (*swap_deactivate)(struct file *file);
        int (*swap_rw)(struct kiocb *iocb, struct iov_iter *iter);
};
### 关于ArcGIS License Server无法启动的解决方案 当遇到ArcGIS License Server无法启动的情况,可以从以下几个方面排查并解决问题: #### 1. **检查网络配置** 确保License Server所在的计算机能够被其他客户端正常访问。如果是在局域网环境中部署了ArcGIS Server Local,则需要确认该环境下的网络设置是否允许远程连接AO组件[^1]。 #### 2. **验证服务状态** 检查ArcGIS Server Object Manager (SOM) 的运行情况。通常情况下,在Host SOM机器上需将此服务更改为由本地系统账户登录,并重启相关服务来恢复其正常工作流程[^2]。 #### 3. **审查日志文件** 查看ArcGIS License Manager的日志记录,寻找任何可能指示错误原因的信息。这些日志可以帮助识别具体是什么阻止了许可服务器的成功初始化。 #### 4. **权限问题** 确认用于启动ArcGIS License Server的服务账号具有足够的权限执行所需操作。这包括但不限于读取/写入特定目录的权利以及与其他必要进程通信的能力。 #### 5. **软件版本兼容性** 保证所使用的ArcGIS产品及其依赖项之间存在良好的版本匹配度。不一致可能会导致意外行为完全失败激活license server的功能。 #### 示例代码片段:修改服务登录身份 以下是更改Windows服务登录凭据的一个简单PowerShell脚本例子: ```powershell $serviceName = "ArcGISServerObjectManager" $newUsername = ".\LocalSystemUser" # 替换为实际用户名 $newPassword = ConvertTo-SecureString "" -AsPlainText -Force Set-Service -Name $serviceName -StartupType Automatic New-ServiceCredential -ServiceName $serviceName -Account $newUsername -Password $newPassword Restart-Service -Name $serviceName ``` 上述脚本仅作为示范用途,请依据实际情况调整参数值后再实施。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值