NFS中pageuptodate的分析

PG_uptodate标志含义一直不是很明确。

很多地方会set次标志

1.从磁盘读取到页

2.从用户态拷贝的页缓存

3.把脏页刷到磁盘

4.初始化一个空页

清楚此标志只有读取或者下刷失败时候。



SetPageUptodate()

1.bl_done_with_rpage(struct page *page, const int ok)
{
    if (ok) {
        ClearPagePnfsErr(page);
        SetPageUptodate(page);
    } else {
        ClearPageUptodate(page);
        SetPageError(page);
        SetPagePnfsErr(page);
    }
    /* Page is unlocked via rpc_release.  Should really be done here. */
}

当页被正确读出时,设置叶已经被更新。

2bl_write_end(struct inode *inode, struct page *page, loff_t pos,
         unsigned count, unsigned copied, struct pnfs_fsdata *fsdata)
{
    dprintk("%s enter, %u@%lld, %i\n", __func__, count, pos,
        fsdata ? fsdata->ok_to_use_pnfs : -1);
    print_page(page);
    if (fsdata) {
        if (fsdata->ok_to_use_pnfs) {
            dprintk("%s using pnfs\n", __func__);
            SetPageUptodate(page);
        }
    }
    return 0;
}
当页被正确刷到磁盘后,也会更新。

3. static void nfs_readpage_from_fscache_complete(struct page *page,
                           void *context,
                           int error)
{
    dfprintk(FSCACHE,
         "NFS: readpage_from_fscache_complete (0x%p/0x%p/%d)\n",
         page, context, error);

    /* if the read completes with an error, we just unlock the page and let
     * the VM reissue the readpage */
    if (!error) {
        SetPageUptodate(page);
        unlock_page(page);
    } else {
        error = nfs_readpage_async(context, page->mapping->host, page);
        if (error)
            unlock_page(page);
    }
}

需要了解FScache是个什么东东

4.

static void nfs_readpage_release_partial(void *calldata)
{
    struct nfs_read_data *data = calldata;
    struct nfs_page *req = data->req;
    struct page *page = req->wb_page;
    int status = data->task.tk_status;

    if (status < 0)
        SetPageError(page);

    if (atomic_dec_and_test(&req->wb_complete)) {
        if (!PageError(page))
            SetPageUptodate(page);
        nfs_readpage_release(req);
    }
    nfs_readdata_release(calldata);
}

这个是当页从磁盘读出后,par的回调函数执行的,但在1中已经设置了,此处岂不重复设置了么?

同理,static void nfs_readpage_release_full(void *calldata)中也会更新页标志。

_______________________________________________________________________________

_______________________________________________________________________________

清除uptodate的标志只有一个地方:

bl_done_with_rpage(struct page *page, const int ok)
{
    if (ok) {
        ClearPagePnfsErr(page);
        SetPageUptodate(page);
    } else {
        ClearPageUptodate(page);
        SetPageError(page);
        SetPagePnfsErr(page);
    }
    /* Page is unlocked via rpc_release.  Should really be done here. */
}

这说明uptodate这个标志位包含的信息其实并不是很丰富。

_______________________________________________________________________________

_______________________________________________________________________________

检测uptodate

1.static int nfs_want_read_modify_write(struct file *file, struct page *page,
            loff_t pos, unsigned len)
{
    unsigned int pglen = nfs_page_length(page);
    unsigned int offset = pos & (PAGE_CACHE_SIZE - 1);
    unsigned int end = offset + len;

    if ((file->f_mode & FMODE_READ) &&    /* open for read? */
        !PageUptodate(page) &&        /* Uptodate? */
        !PagePrivate(page) &&        /* i/o request already? */
        pglen &&                /* valid bytes of file? */
        (end < pglen || offset))        /* replace all valid bytes? */
        return 1;
    return 0;
}
这个函数用来判断:当需要写的时候,* Decide whether a read/modify/write cycle may be more efficient
 * then a modify/write/read cycle when writing to a page in the
 * page cache.
 *


2.if (!PageUptodate(page)) {
        unsigned pglen = nfs_page_length(page);
        unsigned end = offset + len;

        if (pglen == 0) {
            zero_user_segments(page, 0, offset,
                    end, PAGE_CACHE_SIZE);
            SetPageUptodate(page);
        } else if (end >= pglen) {
            zero_user_segment(page, end, PAGE_CACHE_SIZE);
            if (offset == 0)
                SetPageUptodate(page);
        } else
            zero_user_segment(page, pglen, PAGE_CACHE_SIZE);
    }

这是在nfs_write_end中调用的,很可能的原因是:在bl driver层中,只修改了完整的页的标志,对于写了一半的页并没有处理。

PS:user_segment是什么意思i?


3. static void nfs_readpage_release(struct nfs_page *req)
{
    struct inode *d_inode = req->wb_context->path.dentry->d_inode;

    if (PageUptodate(req->wb_page))
        nfs_readpage_to_fscache(d_inode, req->wb_page, 0);

    unlock_page(req->wb_page);

    dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
            req->wb_context->path.dentry->d_inode->i_sb->s_id,
            (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
            req->wb_bytes,
            (long long)req_offset(req));
    nfs_clear_request(req);
    nfs_release_request(req);
}

此处是当完成从磁盘到页的读操作后(完成bio后)的回调函数。

PS:fscache是什么?




4. int nfs_readpage(struct file *file, struct page *page)
{
    struct nfs_open_context *ctx;
    struct inode *inode = page->mapping->host;
    int        error;

    dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
        page, PAGE_CACHE_SIZE, page->index);
    nfs_inc_stats(inode, NFSIOS_VFSREADPAGE);
    nfs_add_stats(inode, NFSIOS_READPAGES, 1);

    error = nfs_wb_page(inode, page);

if (PageUptodate(page))        goto out_unlock;

此处比较重要:在读一个页之前,先看是否有写请求在页上,若有则先刷到磁盘。若下刷成功,则uptodata标志会被置位(前面已经有代码),通过判断uptodate标志位则不需要再去读磁盘,直接返回即可。


5. /*
 * If the page cache is marked as unsafe or invalid, then we can't rely on
 * the PageUptodate() flag. In this case, we will need to turn off
 * write optimisations that depend on the page contents being correct.
 */
static int nfs_write_pageuptodate(struct page *page, struct inode *inode)
{
    return PageUptodate(page) &&
        !(NFS_I(inode)->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA));
}








  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值