nfs_writedata_free(wdata);
}
+static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
+{
+ ctx->error = error;
+ smp_wmb();
+ set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
+}
+
static struct nfs_page *nfs_page_find_request_locked(struct page *page)
{
struct nfs_page *req = NULL;
return 0;
}
-/*
- * Write an mmapped page to the server.
- */
-static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
{
- struct nfs_pageio_descriptor mypgio, *pgio;
struct inode *inode = page->mapping->host;
- int err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
- if (wbc->for_writepages)
- pgio = wbc->fs_private;
- else {
- nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc));
- pgio = &mypgio;
- }
-
nfs_pageio_cond_complete(pgio, page->index);
+ return nfs_page_async_flush(pgio, page);
+}
- err = nfs_page_async_flush(pgio, page);
+/*
+ * Write an mmapped page to the server.
+ */
+static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
+{
+ struct nfs_pageio_descriptor pgio;
+ int err;
- if (!wbc->for_writepages)
- nfs_pageio_complete(pgio);
- return err;
+ nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc));
+ err = nfs_do_writepage(page, wbc, &pgio);
+ nfs_pageio_complete(&pgio);
+ if (err < 0)
+ return err;
+ if (pgio.pg_error < 0)
+ return pgio.pg_error;
+ return 0;
}
int nfs_writepage(struct page *page, struct writeback_control *wbc)
{
- int err;
+ int ret;
- err = nfs_writepage_locked(page, wbc);
+ ret = nfs_writepage_locked(page, wbc);
unlock_page(page);
- return err;
+ return ret;
+}
+
+static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data)
+{
+ int ret;
+
+ ret = nfs_do_writepage(page, wbc, data);
+ unlock_page(page);
+ return ret;
}
int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
- wbc->fs_private = &pgio;
- err = generic_writepages(mapping, wbc);
+ err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio);
nfs_pageio_complete(&pgio);
- if (err)
+ if (err < 0)
return err;
- if (pgio.pg_error)
+ if (pgio.pg_error < 0)
return pgio.pg_error;
return 0;
}
int nfs_flush_incompatible(struct file *file, struct page *page)
{
- struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct nfs_page *req;
int do_flush, status;
/*
int nfs_updatepage(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
- struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = page->mapping->host;
int status = 0;
if (task->tk_status < 0) {
nfs_set_pageerror(page);
- req->wb_context->error = task->tk_status;
+ nfs_context_set_write_error(req->wb_context, task->tk_status);
dprintk(", error = %d\n", task->tk_status);
goto out;
}
if (task->tk_status < 0) {
nfs_set_pageerror(page);
- req->wb_context->error = task->tk_status;
+ nfs_context_set_write_error(req->wb_context, task->tk_status);
dprintk(", error = %d\n", task->tk_status);
goto remove_request;
}
req->wb_bytes,
(long long)req_offset(req));
if (task->tk_status < 0) {
- req->wb_context->error = task->tk_status;
+ nfs_context_set_write_error(req->wb_context, task->tk_status);
nfs_inode_remove_request(req);
dprintk(", error = %d\n", task->tk_status);
goto next;
return ret;
}
-/*
- * flush the inode to disk.
- */
-int nfs_wb_all(struct inode *inode)
+static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
{
- struct address_space *mapping = inode->i_mapping;
- struct writeback_control wbc = {
- .bdi = mapping->backing_dev_info,
- .sync_mode = WB_SYNC_ALL,
- .nr_to_write = LONG_MAX,
- .for_writepages = 1,
- .range_cyclic = 1,
- };
int ret;
- ret = nfs_writepages(mapping, &wbc);
+ ret = nfs_writepages(mapping, wbc);
if (ret < 0)
goto out;
- ret = nfs_sync_mapping_wait(mapping, &wbc, 0);
- if (ret >= 0)
- return 0;
+ ret = nfs_sync_mapping_wait(mapping, wbc, how);
+ if (ret < 0)
+ goto out;
+ return 0;
out:
__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
return ret;
}
-int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, loff_t range_end, int how)
+/* Two pass sync: first using WB_SYNC_NONE, then WB_SYNC_ALL */
+static int nfs_write_mapping(struct address_space *mapping, int how)
{
struct writeback_control wbc = {
.bdi = mapping->backing_dev_info,
- .sync_mode = WB_SYNC_ALL,
+ .sync_mode = WB_SYNC_NONE,
.nr_to_write = LONG_MAX,
- .range_start = range_start,
- .range_end = range_end,
.for_writepages = 1,
+ .range_cyclic = 1,
};
int ret;
- ret = nfs_writepages(mapping, &wbc);
+ ret = __nfs_write_mapping(mapping, &wbc, how);
if (ret < 0)
- goto out;
- ret = nfs_sync_mapping_wait(mapping, &wbc, how);
- if (ret >= 0)
- return 0;
-out:
- __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
- return ret;
+ return ret;
+ wbc.sync_mode = WB_SYNC_ALL;
+ return __nfs_write_mapping(mapping, &wbc, how);
+}
+
+/*
+ * flush the inode to disk.
+ */
+int nfs_wb_all(struct inode *inode)
+{
+ return nfs_write_mapping(inode->i_mapping, 0);
+}
+
+int nfs_wb_nocommit(struct inode *inode)
+{
+ return nfs_write_mapping(inode->i_mapping, FLUSH_NOCOMMIT);
}
int nfs_wb_page_cancel(struct inode *inode, struct page *page)