diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index b39b37f80913..1dda78db6a73 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/nfs_mount.h> | 20 | #include <linux/nfs_mount.h> |
21 | #include <linux/nfs_page.h> | 21 | #include <linux/nfs_page.h> |
22 | #include <linux/backing-dev.h> | 22 | #include <linux/backing-dev.h> |
23 | #include <linux/export.h> | ||
23 | 24 | ||
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | 26 | ||
@@ -390,7 +391,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
390 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); | 391 | error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req); |
391 | BUG_ON(error); | 392 | BUG_ON(error); |
392 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) | 393 | if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE)) |
393 | nfsi->change_attr++; | 394 | inode->i_version++; |
394 | set_bit(PG_MAPPED, &req->wb_flags); | 395 | set_bit(PG_MAPPED, &req->wb_flags); |
395 | SetPagePrivate(req->wb_page); | 396 | SetPagePrivate(req->wb_page); |
396 | set_page_private(req->wb_page, (unsigned long)req); | 397 | set_page_private(req->wb_page, (unsigned long)req); |
@@ -428,7 +429,6 @@ static void | |||
428 | nfs_mark_request_dirty(struct nfs_page *req) | 429 | nfs_mark_request_dirty(struct nfs_page *req) |
429 | { | 430 | { |
430 | __set_page_dirty_nobuffers(req->wb_page); | 431 | __set_page_dirty_nobuffers(req->wb_page); |
431 | __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC); | ||
432 | } | 432 | } |
433 | 433 | ||
434 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 434 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -762,6 +762,8 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
762 | status = nfs_writepage_setup(ctx, page, offset, count); | 762 | status = nfs_writepage_setup(ctx, page, offset, count); |
763 | if (status < 0) | 763 | if (status < 0) |
764 | nfs_set_pageerror(page); | 764 | nfs_set_pageerror(page); |
765 | else | ||
766 | __set_page_dirty_nobuffers(page); | ||
765 | 767 | ||
766 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", | 768 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", |
767 | status, (long long)i_size_read(inode)); | 769 | status, (long long)i_size_read(inode)); |
@@ -958,7 +960,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head | |||
958 | if (!data) | 960 | if (!data) |
959 | goto out_bad; | 961 | goto out_bad; |
960 | data->pagevec[0] = page; | 962 | data->pagevec[0] = page; |
961 | nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags); | 963 | nfs_write_rpcsetup(req, data, len, offset, desc->pg_ioflags); |
962 | list_add(&data->list, res); | 964 | list_add(&data->list, res); |
963 | requests++; | 965 | requests++; |
964 | nbytes -= len; | 966 | nbytes -= len; |
@@ -1010,7 +1012,6 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r | |||
1010 | req = nfs_list_entry(head->next); | 1012 | req = nfs_list_entry(head->next); |
1011 | nfs_list_remove_request(req); | 1013 | nfs_list_remove_request(req); |
1012 | nfs_list_add_request(req, &data->pages); | 1014 | nfs_list_add_request(req, &data->pages); |
1013 | ClearPageError(req->wb_page); | ||
1014 | *pages++ = req->wb_page; | 1015 | *pages++ = req->wb_page; |
1015 | } | 1016 | } |
1016 | req = nfs_list_entry(data->pages.next); | 1017 | req = nfs_list_entry(data->pages.next); |
@@ -1165,7 +1166,13 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
1165 | static void nfs_writeback_release_full(void *calldata) | 1166 | static void nfs_writeback_release_full(void *calldata) |
1166 | { | 1167 | { |
1167 | struct nfs_write_data *data = calldata; | 1168 | struct nfs_write_data *data = calldata; |
1168 | int status = data->task.tk_status; | 1169 | int ret, status = data->task.tk_status; |
1170 | struct nfs_pageio_descriptor pgio; | ||
1171 | |||
1172 | if (data->pnfs_error) { | ||
1173 | nfs_pageio_init_write_mds(&pgio, data->inode, FLUSH_STABLE); | ||
1174 | pgio.pg_recoalesce = 1; | ||
1175 | } | ||
1169 | 1176 | ||
1170 | /* Update attributes as result of writeback. */ | 1177 | /* Update attributes as result of writeback. */ |
1171 | while (!list_empty(&data->pages)) { | 1178 | while (!list_empty(&data->pages)) { |
@@ -1181,6 +1188,11 @@ static void nfs_writeback_release_full(void *calldata) | |||
1181 | req->wb_bytes, | 1188 | req->wb_bytes, |
1182 | (long long)req_offset(req)); | 1189 | (long long)req_offset(req)); |
1183 | 1190 | ||
1191 | if (data->pnfs_error) { | ||
1192 | dprintk(", pnfs error = %d\n", data->pnfs_error); | ||
1193 | goto next; | ||
1194 | } | ||
1195 | |||
1184 | if (status < 0) { | 1196 | if (status < 0) { |
1185 | nfs_set_pageerror(page); | 1197 | nfs_set_pageerror(page); |
1186 | nfs_context_set_write_error(req->wb_context, status); | 1198 | nfs_context_set_write_error(req->wb_context, status); |
@@ -1200,7 +1212,19 @@ remove_request: | |||
1200 | next: | 1212 | next: |
1201 | nfs_clear_page_tag_locked(req); | 1213 | nfs_clear_page_tag_locked(req); |
1202 | nfs_end_page_writeback(page); | 1214 | nfs_end_page_writeback(page); |
1215 | if (data->pnfs_error) { | ||
1216 | lock_page(page); | ||
1217 | nfs_pageio_cond_complete(&pgio, page->index); | ||
1218 | ret = nfs_page_async_flush(&pgio, page, 0); | ||
1219 | if (ret) { | ||
1220 | nfs_set_pageerror(page); | ||
1221 | dprintk("rewrite to MDS error = %d\n", ret); | ||
1222 | } | ||
1223 | unlock_page(page); | ||
1224 | } | ||
1203 | } | 1225 | } |
1226 | if (data->pnfs_error) | ||
1227 | nfs_pageio_complete(&pgio); | ||
1204 | nfs_writedata_release(calldata); | 1228 | nfs_writedata_release(calldata); |
1205 | } | 1229 | } |
1206 | 1230 | ||
@@ -1220,7 +1244,6 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1220 | { | 1244 | { |
1221 | struct nfs_writeargs *argp = &data->args; | 1245 | struct nfs_writeargs *argp = &data->args; |
1222 | struct nfs_writeres *resp = &data->res; | 1246 | struct nfs_writeres *resp = &data->res; |
1223 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
1224 | int status; | 1247 | int status; |
1225 | 1248 | ||
1226 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1249 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
@@ -1254,7 +1277,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1254 | if (time_before(complain, jiffies)) { | 1277 | if (time_before(complain, jiffies)) { |
1255 | dprintk("NFS: faulty NFS server %s:" | 1278 | dprintk("NFS: faulty NFS server %s:" |
1256 | " (committed = %d) != (stable = %d)\n", | 1279 | " (committed = %d) != (stable = %d)\n", |
1257 | server->nfs_client->cl_hostname, | 1280 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, |
1258 | resp->verf->committed, argp->stable); | 1281 | resp->verf->committed, argp->stable); |
1259 | complain = jiffies + 300 * HZ; | 1282 | complain = jiffies + 300 * HZ; |
1260 | } | 1283 | } |
@@ -1281,7 +1304,7 @@ void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1281 | */ | 1304 | */ |
1282 | argp->stable = NFS_FILE_SYNC; | 1305 | argp->stable = NFS_FILE_SYNC; |
1283 | } | 1306 | } |
1284 | nfs_restart_rpc(task, server->nfs_client); | 1307 | rpc_restart_call_prepare(task); |
1285 | return; | 1308 | return; |
1286 | } | 1309 | } |
1287 | if (time_before(complain, jiffies)) { | 1310 | if (time_before(complain, jiffies)) { |
@@ -1553,6 +1576,10 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr | |||
1553 | int flags = FLUSH_SYNC; | 1576 | int flags = FLUSH_SYNC; |
1554 | int ret = 0; | 1577 | int ret = 0; |
1555 | 1578 | ||
1579 | /* no commits means nothing needs to be done */ | ||
1580 | if (!nfsi->ncommit) | ||
1581 | return ret; | ||
1582 | |||
1556 | if (wbc->sync_mode == WB_SYNC_NONE) { | 1583 | if (wbc->sync_mode == WB_SYNC_NONE) { |
1557 | /* Don't commit yet if this is a non-blocking flush and there | 1584 | /* Don't commit yet if this is a non-blocking flush and there |
1558 | * are a lot of outstanding writes for this mapping. | 1585 | * are a lot of outstanding writes for this mapping. |
@@ -1686,34 +1713,20 @@ out_error: | |||
1686 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | 1713 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, |
1687 | struct page *page) | 1714 | struct page *page) |
1688 | { | 1715 | { |
1689 | struct nfs_page *req; | 1716 | /* |
1690 | int ret; | 1717 | * If PagePrivate is set, then the page is currently associated with |
1718 | * an in-progress read or write request. Don't try to migrate it. | ||
1719 | * | ||
1720 | * FIXME: we could do this in principle, but we'll need a way to ensure | ||
1721 | * that we can safely release the inode reference while holding | ||
1722 | * the page lock. | ||
1723 | */ | ||
1724 | if (PagePrivate(page)) | ||
1725 | return -EBUSY; | ||
1691 | 1726 | ||
1692 | nfs_fscache_release_page(page, GFP_KERNEL); | 1727 | nfs_fscache_release_page(page, GFP_KERNEL); |
1693 | 1728 | ||
1694 | req = nfs_find_and_lock_request(page, false); | 1729 | return migrate_page(mapping, newpage, page); |
1695 | ret = PTR_ERR(req); | ||
1696 | if (IS_ERR(req)) | ||
1697 | goto out; | ||
1698 | |||
1699 | ret = migrate_page(mapping, newpage, page); | ||
1700 | if (!req) | ||
1701 | goto out; | ||
1702 | if (ret) | ||
1703 | goto out_unlock; | ||
1704 | page_cache_get(newpage); | ||
1705 | spin_lock(&mapping->host->i_lock); | ||
1706 | req->wb_page = newpage; | ||
1707 | SetPagePrivate(newpage); | ||
1708 | set_page_private(newpage, (unsigned long)req); | ||
1709 | ClearPagePrivate(page); | ||
1710 | set_page_private(page, 0); | ||
1711 | spin_unlock(&mapping->host->i_lock); | ||
1712 | page_cache_release(page); | ||
1713 | out_unlock: | ||
1714 | nfs_clear_page_tag_locked(req); | ||
1715 | out: | ||
1716 | return ret; | ||
1717 | } | 1730 | } |
1718 | #endif | 1731 | #endif |
1719 | 1732 | ||