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