资讯详情

NFS系统read调用过程(五)

然后解释这篇文章nfs_readpages()流程。在上一篇文章中,我们谈到了read_cache_pages()将缓存页添加到文件缓存中radix树中创建了每个缓存页面nfs_page然后链接这些缓存页面nfs_pageio_descriptor结构中。nfs_pageio_descriptor它包含多个缓存页缓存页和向服务器请求数据。接下来是调用nfs_pageio_descriptor中的函数向服务器请求数据了,这是通过函数nfs_pageio_complete()实现这个函数最终被调用nfs_pageio_descriptor结构中pg_ops字段中的函数pg_doio()在阅读操作中,这个函数是nfs_generic_pg_readpages()。

static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) {         struct nfs_read_header *rhdr;         struct nfs_pgio_header *hdr;         int ret;          // 步骤1   创建一个nfs_read_header结构         rhdr = nfs_readhdr_alloc();         if (!rhdr) {    // 创建rhdr失败了,无法处理desc中间的缓存页,这些缓存页需要释放                 desc->pg_completion_ops->error_cleanup(&desc->pg_list);                 return -ENOMEM;         }          // 步骤2   初始化hdr         hdr = &rhdr->header;            // 找到nfs_pgio_header结构         // 根据desc结构中的信息初始化hdr,向hdr中添加了nfs_page结构,         // 设置了hdr->completion_ops、inode、io_start、good_bytes         // nfs_readhdr_free用来释放nfs_read_header结构占用的内存         nfs_pgheader_init(desc, hdr, nfs_readhdr_free);         atomic_inc(&hdr->refcnt);       // 增加该结构的使用计数                  // 步骤3  将desc中间的缓存页转移到hdr中,设置READ要求的参数和返回值         ret = nfs_generic_pagein(desc, hdr);         if (ret == 0)                 // 步骤4   发起READ请求,向服务器请求数据。                 ret = nfs_do_multiple_reads(&hdr->rpc_list,                                             desc->pg_rpc_callops);          // 步骤5   READ请求执行完毕,完成一些工作         if (atomic_dec_and_test(&hdr->refcnt))                 hdr->completion_ops->completion(hdr);            return ret; }

虽然这个程序代码不长,但是内容很多,一篇文章可能讲不清楚。先说几个数据结构。前面提到过nfs_pageio_descriptor该结构包含多个缓存页面,客户端向服务器发送READ请用服务器端返回的数据填写缓存页面。如果nfs_pageio_descriptor结构中有很多数据,超过了RPC限制需要启动多个限制READ请求,每个READ请求使用数据结构nfs_read_data表示。

// 这是READ每个请求中使用的数据结构nfs_read_data结构对应一个READ请求。 struct nfs_read_data {         // nfs_pgio_header中保存了READ请求中的通用信息,多个相关的READ同一个请求可以共享nfs_pgio_header结构.         struct nfs_pgio_header  *header;         // 一个nfs_pgio_header多个结构包含在结构中nfs_read_data结构,每个nfs_read_data结构代表一个READ请求,         // 这些nfs_read_data构成链表,list指向链表中相邻元素.         struct list_head        list;           // 作为指针链接nfs_pgio_header结构中         struct rpc_task         task;           // 这是READ请求关联的RPC任务         struct nfs_fattr        fattr;  /* fattr storage */     // 文件的属性信息保存在这里         struct nfs_readargs args;   // 这是READ请求的参数         struct nfs_readres  res;    // 这是READ请求的返回值         // 这是时间戳,记录了READ请求的启动时间.         unsigned long           timestamp;      /* For lease renewal */         // 这是READ请求完成后调用函数         int (*read_done_cb) (struct rpc_task *task, struct nfs_read_data *data);         // 如果服务器获得的数据量小于要求的数据量,则在读取操作出错时使用的字段,         // 则设置这个值,再次发起READ请求,获取上次失败的数据。         __u64                   mds_offset;         // 这是从服务器获取的数据中填充缓存页面的缓存页面链表指针。         struct nfs_page_array   pages;      一些缓存页面指针保存在这里,指向这些缓存页面nfs_pgio_header结构中的pages         // 这是pNFS中和DS通信客户端         struct nfs_client       *ds_clp;        /* pNFS data server */ };

这些READ同一个要求处理nfs_pageio_descriptor结构中的数据与数据结构中的相同信息相同nfs_pgio_header表示,nfs_pageio_descriptor中所有的READ请求共享一个nfs_pgio_header结构中的信息。

// 这是一个I/O操作头的数据结构 struct nfs_pgio_header {         struct inode            *inode;         // 文件索引节点,本文件中的数据请求         struct rpc_cred         *cred;          // 用户信息         // 这是链表,链表中的数据结构是nfs_page,这是从nfs_pageio_descriptor在结构中转移.         struct list_head        pages;          // 应该存放在这里nfs_page结构         // 这是链表,存储在链表中nfs_read_data,每个nfs_read_data表示一个READ请求         struct list_head        rpc_list;         atomic_t                refcnt;         // 该结构的引用计数         // 这是链表pages第一个缓存页的指针         struct nfs_page         *req;           // nfs_page结构,这个结构对应一个缓存页         // 多个WRITE也可以在请求中共享nfs_pgio_header结构,verf是WRITE请求中使用的字段         struct nfs_writeverf    *verf;         // 这是文件的layout信息,供pNFS使用         structpnfs_layout_segment *lseg;
        // 这是请求的数据在文件中的起始位置
        loff_t                  io_start;
        // 这是RPC操作中使用的函数
        const struct rpc_call_ops *mds_ops;
        // 这是一个错误处理函数,出错后调用这个函数释放nfs_pgio_header占用的内存
        void (*release) (struct nfs_pgio_header *hdr);
        // 这是READ请求完毕后执行的一个函数
        const struct nfs_pgio_completion_ops *completion_ops;
        // 这是直接IO相关的数据结构
        struct nfs_direct_req   *dreq;
        spinlock_t              lock;           // 保护这个数据结构的自旋
        /* fields protected by lock */
        int                     pnfs_error;     // pNFS中的错误码
        int                     error;          /* merge with pnfs_error */
        // 实际读取的数据量
        unsigned long           good_bytes;     /* boundary of good data */
        unsigned long           flags;          // 一些标志位
};

如果nfs_pageio_descriptor结构中的数据比较少,只需要一个READ请求,那么就可以使用数据结构nfs_read_header。

struct nfs_read_header {
        struct nfs_pgio_header  header;         // 这是READ操作的通用信息
        struct nfs_read_data    rpc_data;       // 这是一次READ请求的信息
};

如果nfs_pageio_descriptor结构中的数据比较多,需要发起多次READ请求,那么就可以创建一个nfs_read_header结构和多个nfs_read_data结构。

现在可以讲解nfs_generic_pg_readpages的流程了。 (1)创建一个nfs_read_header结构。

(2)初始化其中的nfs_pgio_header结构。

(3)根据nfs_pageio_descriptor结构中的数据创建若干个nfs_read_data结构,将nfs_pageio_descriptor结构中的缓存页分配给每个nfs_read_data结构。

(4)初始化READ请求的参数和返回值,每个nfs_read_data结构发起一次READ请求。

(5)所有的nfs_read_data结构完毕后,执行一些收尾工作。

标签: 集成电路cc2520rhdr

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司