diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 89 |
1 files changed, 45 insertions, 44 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 3107908e5f3..9449b683550 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -89,24 +89,38 @@ static mempool_t *nfs_commit_mempool; | |||
89 | 89 | ||
90 | static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); | 90 | static DECLARE_WAIT_QUEUE_HEAD(nfs_write_congestion); |
91 | 91 | ||
92 | static inline struct nfs_write_data *nfs_commit_alloc(void) | 92 | static inline struct nfs_write_data *nfs_commit_alloc(unsigned int pagecount) |
93 | { | 93 | { |
94 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); | 94 | struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, SLAB_NOFS); |
95 | |||
95 | if (p) { | 96 | if (p) { |
96 | memset(p, 0, sizeof(*p)); | 97 | memset(p, 0, sizeof(*p)); |
97 | INIT_LIST_HEAD(&p->pages); | 98 | INIT_LIST_HEAD(&p->pages); |
99 | if (pagecount < NFS_PAGEVEC_SIZE) | ||
100 | p->pagevec = &p->page_array[0]; | ||
101 | else { | ||
102 | size_t size = ++pagecount * sizeof(struct page *); | ||
103 | p->pagevec = kmalloc(size, GFP_NOFS); | ||
104 | if (p->pagevec) { | ||
105 | memset(p->pagevec, 0, size); | ||
106 | } else { | ||
107 | mempool_free(p, nfs_commit_mempool); | ||
108 | p = NULL; | ||
109 | } | ||
110 | } | ||
98 | } | 111 | } |
99 | return p; | 112 | return p; |
100 | } | 113 | } |
101 | 114 | ||
102 | static inline void nfs_commit_free(struct nfs_write_data *p) | 115 | static inline void nfs_commit_free(struct nfs_write_data *p) |
103 | { | 116 | { |
117 | if (p && (p->pagevec != &p->page_array[0])) | ||
118 | kfree(p->pagevec); | ||
104 | mempool_free(p, nfs_commit_mempool); | 119 | mempool_free(p, nfs_commit_mempool); |
105 | } | 120 | } |
106 | 121 | ||
107 | static void nfs_writedata_release(struct rpc_task *task) | 122 | void nfs_writedata_release(void *wdata) |
108 | { | 123 | { |
109 | struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; | ||
110 | nfs_writedata_free(wdata); | 124 | nfs_writedata_free(wdata); |
111 | } | 125 | } |
112 | 126 | ||
@@ -168,7 +182,7 @@ static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | |||
168 | int result, written = 0; | 182 | int result, written = 0; |
169 | struct nfs_write_data *wdata; | 183 | struct nfs_write_data *wdata; |
170 | 184 | ||
171 | wdata = nfs_writedata_alloc(); | 185 | wdata = nfs_writedata_alloc(1); |
172 | if (!wdata) | 186 | if (!wdata) |
173 | return -ENOMEM; | 187 | return -ENOMEM; |
174 | 188 | ||
@@ -232,19 +246,16 @@ static int nfs_writepage_async(struct nfs_open_context *ctx, | |||
232 | unsigned int offset, unsigned int count) | 246 | unsigned int offset, unsigned int count) |
233 | { | 247 | { |
234 | struct nfs_page *req; | 248 | struct nfs_page *req; |
235 | int status; | ||
236 | 249 | ||
237 | req = nfs_update_request(ctx, inode, page, offset, count); | 250 | req = nfs_update_request(ctx, inode, page, offset, count); |
238 | status = (IS_ERR(req)) ? PTR_ERR(req) : 0; | 251 | if (IS_ERR(req)) |
239 | if (status < 0) | 252 | return PTR_ERR(req); |
240 | goto out; | ||
241 | /* Update file length */ | 253 | /* Update file length */ |
242 | nfs_grow_file(page, offset, count); | 254 | nfs_grow_file(page, offset, count); |
243 | /* Set the PG_uptodate flag? */ | 255 | /* Set the PG_uptodate flag? */ |
244 | nfs_mark_uptodate(page, offset, count); | 256 | nfs_mark_uptodate(page, offset, count); |
245 | nfs_unlock_request(req); | 257 | nfs_unlock_request(req); |
246 | out: | 258 | return 0; |
247 | return status; | ||
248 | } | 259 | } |
249 | 260 | ||
250 | static int wb_priority(struct writeback_control *wbc) | 261 | static int wb_priority(struct writeback_control *wbc) |
@@ -304,11 +315,8 @@ do_it: | |||
304 | lock_kernel(); | 315 | lock_kernel(); |
305 | if (!IS_SYNC(inode) && inode_referenced) { | 316 | if (!IS_SYNC(inode) && inode_referenced) { |
306 | err = nfs_writepage_async(ctx, inode, page, 0, offset); | 317 | err = nfs_writepage_async(ctx, inode, page, 0, offset); |
307 | if (err >= 0) { | 318 | if (!wbc->for_writepages) |
308 | err = 0; | 319 | nfs_flush_inode(inode, 0, 0, wb_priority(wbc)); |
309 | if (wbc->for_reclaim) | ||
310 | nfs_flush_inode(inode, 0, 0, FLUSH_STABLE); | ||
311 | } | ||
312 | } else { | 320 | } else { |
313 | err = nfs_writepage_sync(ctx, inode, page, 0, | 321 | err = nfs_writepage_sync(ctx, inode, page, 0, |
314 | offset, priority); | 322 | offset, priority); |
@@ -877,9 +885,6 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
877 | 885 | ||
878 | data->task.tk_priority = flush_task_priority(how); | 886 | data->task.tk_priority = flush_task_priority(how); |
879 | data->task.tk_cookie = (unsigned long)inode; | 887 | data->task.tk_cookie = (unsigned long)inode; |
880 | data->task.tk_calldata = data; | ||
881 | /* Release requests */ | ||
882 | data->task.tk_release = nfs_writedata_release; | ||
883 | 888 | ||
884 | dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", | 889 | dprintk("NFS: %4d initiated write call (req %s/%Ld, %u bytes @ offset %Lu)\n", |
885 | data->task.tk_pid, | 890 | data->task.tk_pid, |
@@ -919,7 +924,7 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) | |||
919 | 924 | ||
920 | nbytes = req->wb_bytes; | 925 | nbytes = req->wb_bytes; |
921 | for (;;) { | 926 | for (;;) { |
922 | data = nfs_writedata_alloc(); | 927 | data = nfs_writedata_alloc(1); |
923 | if (!data) | 928 | if (!data) |
924 | goto out_bad; | 929 | goto out_bad; |
925 | list_add(&data->pages, &list); | 930 | list_add(&data->pages, &list); |
@@ -983,7 +988,7 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
983 | if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) | 988 | if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) |
984 | return nfs_flush_multi(head, inode, how); | 989 | return nfs_flush_multi(head, inode, how); |
985 | 990 | ||
986 | data = nfs_writedata_alloc(); | 991 | data = nfs_writedata_alloc(NFS_SERVER(inode)->wpages); |
987 | if (!data) | 992 | if (!data) |
988 | goto out_bad; | 993 | goto out_bad; |
989 | 994 | ||
@@ -1137,9 +1142,9 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1137 | /* | 1142 | /* |
1138 | * This function is called when the WRITE call is complete. | 1143 | * This function is called when the WRITE call is complete. |
1139 | */ | 1144 | */ |
1140 | void nfs_writeback_done(struct rpc_task *task) | 1145 | void nfs_writeback_done(struct rpc_task *task, void *calldata) |
1141 | { | 1146 | { |
1142 | struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; | 1147 | struct nfs_write_data *data = calldata; |
1143 | struct nfs_writeargs *argp = &data->args; | 1148 | struct nfs_writeargs *argp = &data->args; |
1144 | struct nfs_writeres *resp = &data->res; | 1149 | struct nfs_writeres *resp = &data->res; |
1145 | 1150 | ||
@@ -1206,9 +1211,8 @@ void nfs_writeback_done(struct rpc_task *task) | |||
1206 | 1211 | ||
1207 | 1212 | ||
1208 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1213 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1209 | static void nfs_commit_release(struct rpc_task *task) | 1214 | void nfs_commit_release(void *wdata) |
1210 | { | 1215 | { |
1211 | struct nfs_write_data *wdata = (struct nfs_write_data *)task->tk_calldata; | ||
1212 | nfs_commit_free(wdata); | 1216 | nfs_commit_free(wdata); |
1213 | } | 1217 | } |
1214 | 1218 | ||
@@ -1244,9 +1248,6 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1244 | 1248 | ||
1245 | data->task.tk_priority = flush_task_priority(how); | 1249 | data->task.tk_priority = flush_task_priority(how); |
1246 | data->task.tk_cookie = (unsigned long)inode; | 1250 | data->task.tk_cookie = (unsigned long)inode; |
1247 | data->task.tk_calldata = data; | ||
1248 | /* Release requests */ | ||
1249 | data->task.tk_release = nfs_commit_release; | ||
1250 | 1251 | ||
1251 | dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); | 1252 | dprintk("NFS: %4d initiated commit call\n", data->task.tk_pid); |
1252 | } | 1253 | } |
@@ -1255,12 +1256,12 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1255 | * Commit dirty pages | 1256 | * Commit dirty pages |
1256 | */ | 1257 | */ |
1257 | static int | 1258 | static int |
1258 | nfs_commit_list(struct list_head *head, int how) | 1259 | nfs_commit_list(struct inode *inode, struct list_head *head, int how) |
1259 | { | 1260 | { |
1260 | struct nfs_write_data *data; | 1261 | struct nfs_write_data *data; |
1261 | struct nfs_page *req; | 1262 | struct nfs_page *req; |
1262 | 1263 | ||
1263 | data = nfs_commit_alloc(); | 1264 | data = nfs_commit_alloc(NFS_SERVER(inode)->wpages); |
1264 | 1265 | ||
1265 | if (!data) | 1266 | if (!data) |
1266 | goto out_bad; | 1267 | goto out_bad; |
@@ -1283,10 +1284,9 @@ nfs_commit_list(struct list_head *head, int how) | |||
1283 | /* | 1284 | /* |
1284 | * COMMIT call returned | 1285 | * COMMIT call returned |
1285 | */ | 1286 | */ |
1286 | void | 1287 | void nfs_commit_done(struct rpc_task *task, void *calldata) |
1287 | nfs_commit_done(struct rpc_task *task) | ||
1288 | { | 1288 | { |
1289 | struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; | 1289 | struct nfs_write_data *data = calldata; |
1290 | struct nfs_page *req; | 1290 | struct nfs_page *req; |
1291 | int res = 0; | 1291 | int res = 0; |
1292 | 1292 | ||
@@ -1366,7 +1366,7 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1366 | res = nfs_scan_commit(inode, &head, 0, 0); | 1366 | res = nfs_scan_commit(inode, &head, 0, 0); |
1367 | spin_unlock(&nfsi->req_lock); | 1367 | spin_unlock(&nfsi->req_lock); |
1368 | if (res) { | 1368 | if (res) { |
1369 | error = nfs_commit_list(&head, how); | 1369 | error = nfs_commit_list(inode, &head, how); |
1370 | if (error < 0) | 1370 | if (error < 0) |
1371 | return error; | 1371 | return error; |
1372 | } | 1372 | } |
@@ -1377,22 +1377,23 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1377 | int nfs_sync_inode(struct inode *inode, unsigned long idx_start, | 1377 | int nfs_sync_inode(struct inode *inode, unsigned long idx_start, |
1378 | unsigned int npages, int how) | 1378 | unsigned int npages, int how) |
1379 | { | 1379 | { |
1380 | int error, | 1380 | int nocommit = how & FLUSH_NOCOMMIT; |
1381 | wait; | 1381 | int wait = how & FLUSH_WAIT; |
1382 | int error; | ||
1382 | 1383 | ||
1383 | wait = how & FLUSH_WAIT; | 1384 | how &= ~(FLUSH_WAIT|FLUSH_NOCOMMIT); |
1384 | how &= ~FLUSH_WAIT; | ||
1385 | 1385 | ||
1386 | do { | 1386 | do { |
1387 | error = 0; | 1387 | if (wait) { |
1388 | if (wait) | ||
1389 | error = nfs_wait_on_requests(inode, idx_start, npages); | 1388 | error = nfs_wait_on_requests(inode, idx_start, npages); |
1390 | if (error == 0) | 1389 | if (error != 0) |
1391 | error = nfs_flush_inode(inode, idx_start, npages, how); | 1390 | continue; |
1392 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1391 | } |
1393 | if (error == 0) | 1392 | error = nfs_flush_inode(inode, idx_start, npages, how); |
1393 | if (error != 0) | ||
1394 | continue; | ||
1395 | if (!nocommit) | ||
1394 | error = nfs_commit_inode(inode, how); | 1396 | error = nfs_commit_inode(inode, how); |
1395 | #endif | ||
1396 | } while (error > 0); | 1397 | } while (error > 0); |
1397 | return error; | 1398 | return error; |
1398 | } | 1399 | } |