diff options
Diffstat (limited to 'fs/afs/write.c')
-rw-r--r-- | fs/afs/write.c | 98 |
1 files changed, 55 insertions, 43 deletions
diff --git a/fs/afs/write.c b/fs/afs/write.c index e669f2fae873..8bcab95f1127 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -314,6 +314,46 @@ static void afs_redirty_pages(struct writeback_control *wbc, } /* + * completion of write to server + */ +static void afs_pages_written_back(struct afs_vnode *vnode, + pgoff_t first, pgoff_t last) +{ + struct pagevec pv; + unsigned long priv; + unsigned count, loop; + + _enter("{%llx:%llu},{%lx-%lx}", + vnode->fid.vid, vnode->fid.vnode, first, last); + + pagevec_init(&pv); + + do { + _debug("done %lx-%lx", first, last); + + count = last - first + 1; + if (count > PAGEVEC_SIZE) + count = PAGEVEC_SIZE; + pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, + first, count, pv.pages); + ASSERTCMP(pv.nr, ==, count); + + for (loop = 0; loop < count; loop++) { + priv = page_private(pv.pages[loop]); + trace_afs_page_dirty(vnode, tracepoint_string("clear"), + pv.pages[loop]->index, priv); + set_page_private(pv.pages[loop], 0); + end_page_writeback(pv.pages[loop]); + } + first += count; + __pagevec_release(&pv); + } while (first <= last); + + afs_prune_wb_keys(vnode); + _leave(""); +} + +/* * write to a file */ static int afs_store_data(struct address_space *mapping, @@ -322,6 +362,7 @@ static int afs_store_data(struct address_space *mapping, { struct afs_vnode *vnode = AFS_FS_I(mapping->host); struct afs_fs_cursor fc; + struct afs_status_cb *scb; struct afs_wb_key *wbk = NULL; struct list_head *p; int ret = -ENOKEY, ret2; @@ -333,6 +374,10 @@ static int afs_store_data(struct address_space *mapping, vnode->fid.unique, first, last, offset, to); + scb = kzalloc(sizeof(struct afs_status_cb), GFP_NOFS); + if (!scb) + return -ENOMEM; + spin_lock(&vnode->wb_lock); p = vnode->wb_keys.next; @@ -351,6 +396,7 @@ try_next_key: spin_unlock(&vnode->wb_lock); afs_put_wb_key(wbk); + kfree(scb); _leave(" = %d [no keys]", ret); return ret; @@ -362,13 +408,18 @@ found_key: ret = -ERESTARTSYS; if (afs_begin_vnode_operation(&fc, vnode, wbk->key, false)) { + afs_dataversion_t data_version = vnode->status.data_version + 1; + while (afs_select_fileserver(&fc)) { fc.cb_break = afs_calc_vnode_cb_break(vnode); - afs_fs_store_data(&fc, mapping, first, last, offset, to); + afs_fs_store_data(&fc, mapping, first, last, offset, to, scb); } - afs_check_for_remote_deletion(&fc, fc.vnode); - afs_vnode_commit_status(&fc, vnode, fc.cb_break); + afs_check_for_remote_deletion(&fc, vnode); + afs_vnode_commit_status(&fc, vnode, fc.cb_break, + &data_version, scb); + if (fc.ac.error == 0) + afs_pages_written_back(vnode, first, last); ret = afs_end_vnode_operation(&fc); } @@ -393,6 +444,7 @@ found_key: } afs_put_wb_key(wbk); + kfree(scb); _leave(" = %d", ret); return ret; } @@ -679,46 +731,6 @@ int afs_writepages(struct address_space *mapping, } /* - * completion of write to server - */ -void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) -{ - struct pagevec pv; - unsigned long priv; - unsigned count, loop; - pgoff_t first = call->first, last = call->last; - - _enter("{%llx:%llu},{%lx-%lx}", - vnode->fid.vid, vnode->fid.vnode, first, last); - - pagevec_init(&pv); - - do { - _debug("done %lx-%lx", first, last); - - count = last - first + 1; - if (count > PAGEVEC_SIZE) - count = PAGEVEC_SIZE; - pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, - first, count, pv.pages); - ASSERTCMP(pv.nr, ==, count); - - for (loop = 0; loop < count; loop++) { - priv = page_private(pv.pages[loop]); - trace_afs_page_dirty(vnode, tracepoint_string("clear"), - pv.pages[loop]->index, priv); - set_page_private(pv.pages[loop], 0); - end_page_writeback(pv.pages[loop]); - } - first += count; - __pagevec_release(&pv); - } while (first <= last); - - afs_prune_wb_keys(vnode); - _leave(""); -} - -/* * write to an AFS file */ ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from) |