layout commit 代码阅读

客户端在关闭文件之前进行flush操作时,会进行数据和元数据的提交操作,但由于带外时已将数据写回,因此并无脏页需要进行数据commit。这时仅进行元数据即layout commit操作即可。文件关闭后同样需要进行layout return工作。


static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
{
    int ret;

    ret = nfs_writepages(mapping, wbc);  //完成脏页下刷的工作
    if (ret < 0)
        goto out;
    ret = nfs_sync_mapping_wait(mapping, wbc, how); //刷完之后,完成commit的工作。
    if (ret < 0)
        goto out;
    return 0;
out:
    __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
    return ret;

}





long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how)
{
    struct inode *inode = mapping->host;
    pgoff_t idx_start, idx_end;
    unsigned int npages = 0;
    LIST_HEAD(head);
    int nocommit = how & FLUSH_NOCOMMIT;
    long pages, ret;

    /* FIXME */
    if (wbc->range_cyclic)
        idx_start = 0;
    else {
        idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
        idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
        if (idx_end > idx_start) {
            pgoff_t l_npages = 1 + idx_end - idx_start;
            npages = l_npages;
            if (sizeof(npages) != sizeof(l_npages) &&
                    (pgoff_t)npages != l_npages)
                npages = 0;
        }
    }
    how &= ~FLUSH_NOCOMMIT;
    spin_lock(&inode->i_lock);
    do {
        ret = nfs_wait_on_requests_locked(inode, idx_start, npages);
//等待磁盘IO
        if (ret != 0)
            continue;
        if (nocommit)
            break;
        pages = nfs_scan_commit(inode, &head, idx_start, npages);//检查是否设置了
        if (pages == 0)
            break;
        if (how & FLUSH_INVALIDATE) {
            spin_unlock(&inode->i_lock);
            nfs_cancel_commit_list(&head);
            ret = pages;
            spin_lock(&inode->i_lock);
            continue;
        }
        pages += nfs_scan_commit(inode, &head, 0, 0);
        spin_unlock(&inode->i_lock);
#ifdef CONFIG_PNFS
        pnfs_update_layout_commit(inode, &head, idx_start, npages);
#endif /* CONFIG_PNFS */
        ret = nfs_commit_list(inode, &head, how);
        spin_lock(&inode->i_lock);

    } while (ret >= 0);
    spin_unlock(&inode->i_lock);
#ifdef CONFIG_PNFS
    if (how == 0 && ret == 0 && NFS_I(inode)->layoutcommit_ctx) {
        dprintk("%s calling layoutcommit\n", __func__);
        ret = pnfs_layoutcommit_inode(inode, 1);
    }
#endif /* CONFIG_PNFS */
    return ret;
}


nfs_scan_commit(inode, &head, idx_start, npages);//检查是否设置了NFS_PAGE_TAG_COMMIT

而在bio完成的回调函数里,nfs_writeback_done_full,会有用 nfs_need_commit()函数检测,

由于在bio回调函数中设置了data->commit_verif 的值为NFS_FILE_SYNC 则nfs_need_commit()判断失败。

即跳出上述函数的while循环,直接进入pnfs_layoutcommit_inode(inode, 1);其中1  表示sync.


commit过程中,从inode中找到last_write_end和lash_write_begin 即最新的写完成的范围(在把用户态数据刷到脏页完成后修改,也就是说很可能和脏页刷到磁盘成功与否没有太大关系)

其中NFS层主要是逻辑偏移和长度,layout driver层主要是具体的segment 处理








你可能感兴趣的:(layout commit 代码阅读)