diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 112 |
1 files changed, 66 insertions, 46 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 89527a487ed7..522efff3e2c5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -196,7 +196,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
196 | } | 196 | } |
197 | /* Update file length */ | 197 | /* Update file length */ |
198 | nfs_grow_file(page, offset, count); | 198 | nfs_grow_file(page, offset, count); |
199 | nfs_unlock_request(req); | 199 | nfs_clear_page_tag_locked(req); |
200 | return 0; | 200 | return 0; |
201 | } | 201 | } |
202 | 202 | ||
@@ -252,7 +252,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
252 | struct page *page) | 252 | struct page *page) |
253 | { | 253 | { |
254 | struct inode *inode = page->mapping->host; | 254 | struct inode *inode = page->mapping->host; |
255 | struct nfs_inode *nfsi = NFS_I(inode); | ||
256 | struct nfs_page *req; | 255 | struct nfs_page *req; |
257 | int ret; | 256 | int ret; |
258 | 257 | ||
@@ -263,10 +262,10 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
263 | spin_unlock(&inode->i_lock); | 262 | spin_unlock(&inode->i_lock); |
264 | return 0; | 263 | return 0; |
265 | } | 264 | } |
266 | if (nfs_lock_request_dontget(req)) | 265 | if (nfs_set_page_tag_locked(req)) |
267 | break; | 266 | break; |
268 | /* Note: If we hold the page lock, as is the case in nfs_writepage, | 267 | /* Note: If we hold the page lock, as is the case in nfs_writepage, |
269 | * then the call to nfs_lock_request_dontget() will always | 268 | * then the call to nfs_set_page_tag_locked() will always |
270 | * succeed provided that someone hasn't already marked the | 269 | * succeed provided that someone hasn't already marked the |
271 | * request as dirty (in which case we don't care). | 270 | * request as dirty (in which case we don't care). |
272 | */ | 271 | */ |
@@ -280,7 +279,7 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
280 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { | 279 | if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) { |
281 | /* This request is marked for commit */ | 280 | /* This request is marked for commit */ |
282 | spin_unlock(&inode->i_lock); | 281 | spin_unlock(&inode->i_lock); |
283 | nfs_unlock_request(req); | 282 | nfs_clear_page_tag_locked(req); |
284 | nfs_pageio_complete(pgio); | 283 | nfs_pageio_complete(pgio); |
285 | return 0; | 284 | return 0; |
286 | } | 285 | } |
@@ -288,8 +287,6 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, | |||
288 | spin_unlock(&inode->i_lock); | 287 | spin_unlock(&inode->i_lock); |
289 | BUG(); | 288 | BUG(); |
290 | } | 289 | } |
291 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | ||
292 | NFS_PAGE_TAG_LOCKED); | ||
293 | spin_unlock(&inode->i_lock); | 290 | spin_unlock(&inode->i_lock); |
294 | nfs_pageio_add_request(pgio, req); | 291 | nfs_pageio_add_request(pgio, req); |
295 | return 0; | 292 | return 0; |
@@ -381,6 +378,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
381 | set_page_private(req->wb_page, (unsigned long)req); | 378 | set_page_private(req->wb_page, (unsigned long)req); |
382 | nfsi->npages++; | 379 | nfsi->npages++; |
383 | kref_get(&req->wb_kref); | 380 | kref_get(&req->wb_kref); |
381 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | ||
384 | return 0; | 382 | return 0; |
385 | } | 383 | } |
386 | 384 | ||
@@ -490,7 +488,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
490 | /* | 488 | /* |
491 | * Wait for a request to complete. | 489 | * Wait for a request to complete. |
492 | * | 490 | * |
493 | * Interruptible by signals only if mounted with intr flag. | 491 | * Interruptible by fatal signals only. |
494 | */ | 492 | */ |
495 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) | 493 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) |
496 | { | 494 | { |
@@ -596,7 +594,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
596 | spin_lock(&inode->i_lock); | 594 | spin_lock(&inode->i_lock); |
597 | req = nfs_page_find_request_locked(page); | 595 | req = nfs_page_find_request_locked(page); |
598 | if (req) { | 596 | if (req) { |
599 | if (!nfs_lock_request_dontget(req)) { | 597 | if (!nfs_set_page_tag_locked(req)) { |
600 | int error; | 598 | int error; |
601 | 599 | ||
602 | spin_unlock(&inode->i_lock); | 600 | spin_unlock(&inode->i_lock); |
@@ -646,7 +644,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
646 | || req->wb_page != page | 644 | || req->wb_page != page |
647 | || !nfs_dirty_request(req) | 645 | || !nfs_dirty_request(req) |
648 | || offset > rqend || end < req->wb_offset) { | 646 | || offset > rqend || end < req->wb_offset) { |
649 | nfs_unlock_request(req); | 647 | nfs_clear_page_tag_locked(req); |
650 | return ERR_PTR(-EBUSY); | 648 | return ERR_PTR(-EBUSY); |
651 | } | 649 | } |
652 | 650 | ||
@@ -755,7 +753,7 @@ static void nfs_writepage_release(struct nfs_page *req) | |||
755 | nfs_clear_page_tag_locked(req); | 753 | nfs_clear_page_tag_locked(req); |
756 | } | 754 | } |
757 | 755 | ||
758 | static inline int flush_task_priority(int how) | 756 | static int flush_task_priority(int how) |
759 | { | 757 | { |
760 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { | 758 | switch (how & (FLUSH_HIGHPRI|FLUSH_LOWPRI)) { |
761 | case FLUSH_HIGHPRI: | 759 | case FLUSH_HIGHPRI: |
@@ -775,15 +773,31 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
775 | unsigned int count, unsigned int offset, | 773 | unsigned int count, unsigned int offset, |
776 | int how) | 774 | int how) |
777 | { | 775 | { |
778 | struct inode *inode; | 776 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
779 | int flags; | 777 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
778 | int priority = flush_task_priority(how); | ||
779 | struct rpc_task *task; | ||
780 | struct rpc_message msg = { | ||
781 | .rpc_argp = &data->args, | ||
782 | .rpc_resp = &data->res, | ||
783 | .rpc_cred = req->wb_context->cred, | ||
784 | }; | ||
785 | struct rpc_task_setup task_setup_data = { | ||
786 | .rpc_client = NFS_CLIENT(inode), | ||
787 | .task = &data->task, | ||
788 | .rpc_message = &msg, | ||
789 | .callback_ops = call_ops, | ||
790 | .callback_data = data, | ||
791 | .flags = flags, | ||
792 | .priority = priority, | ||
793 | }; | ||
780 | 794 | ||
781 | /* Set up the RPC argument and reply structs | 795 | /* Set up the RPC argument and reply structs |
782 | * NB: take care not to mess about with data->commit et al. */ | 796 | * NB: take care not to mess about with data->commit et al. */ |
783 | 797 | ||
784 | data->req = req; | 798 | data->req = req; |
785 | data->inode = inode = req->wb_context->path.dentry->d_inode; | 799 | data->inode = inode = req->wb_context->path.dentry->d_inode; |
786 | data->cred = req->wb_context->cred; | 800 | data->cred = msg.rpc_cred; |
787 | 801 | ||
788 | data->args.fh = NFS_FH(inode); | 802 | data->args.fh = NFS_FH(inode); |
789 | data->args.offset = req_offset(req) + offset; | 803 | data->args.offset = req_offset(req) + offset; |
@@ -791,6 +805,12 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
791 | data->args.pages = data->pagevec; | 805 | data->args.pages = data->pagevec; |
792 | data->args.count = count; | 806 | data->args.count = count; |
793 | data->args.context = req->wb_context; | 807 | data->args.context = req->wb_context; |
808 | data->args.stable = NFS_UNSTABLE; | ||
809 | if (how & FLUSH_STABLE) { | ||
810 | data->args.stable = NFS_DATA_SYNC; | ||
811 | if (!NFS_I(inode)->ncommit) | ||
812 | data->args.stable = NFS_FILE_SYNC; | ||
813 | } | ||
794 | 814 | ||
795 | data->res.fattr = &data->fattr; | 815 | data->res.fattr = &data->fattr; |
796 | data->res.count = count; | 816 | data->res.count = count; |
@@ -798,12 +818,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
798 | nfs_fattr_init(&data->fattr); | 818 | nfs_fattr_init(&data->fattr); |
799 | 819 | ||
800 | /* Set up the initial task struct. */ | 820 | /* Set up the initial task struct. */ |
801 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 821 | NFS_PROTO(inode)->write_setup(data, &msg); |
802 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
803 | NFS_PROTO(inode)->write_setup(data, how); | ||
804 | |||
805 | data->task.tk_priority = flush_task_priority(how); | ||
806 | data->task.tk_cookie = (unsigned long)inode; | ||
807 | 822 | ||
808 | dprintk("NFS: %5u initiated write call " | 823 | dprintk("NFS: %5u initiated write call " |
809 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", | 824 | "(req %s/%Ld, %u bytes @ offset %Lu)\n", |
@@ -812,16 +827,10 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
812 | (long long)NFS_FILEID(inode), | 827 | (long long)NFS_FILEID(inode), |
813 | count, | 828 | count, |
814 | (unsigned long long)data->args.offset); | 829 | (unsigned long long)data->args.offset); |
815 | } | ||
816 | |||
817 | static void nfs_execute_write(struct nfs_write_data *data) | ||
818 | { | ||
819 | struct rpc_clnt *clnt = NFS_CLIENT(data->inode); | ||
820 | sigset_t oldset; | ||
821 | 830 | ||
822 | rpc_clnt_sigmask(clnt, &oldset); | 831 | task = rpc_run_task(&task_setup_data); |
823 | rpc_execute(&data->task); | 832 | if (!IS_ERR(task)) |
824 | rpc_clnt_sigunmask(clnt, &oldset); | 833 | rpc_put_task(task); |
825 | } | 834 | } |
826 | 835 | ||
827 | /* | 836 | /* |
@@ -868,7 +877,6 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
868 | wsize, offset, how); | 877 | wsize, offset, how); |
869 | offset += wsize; | 878 | offset += wsize; |
870 | nbytes -= wsize; | 879 | nbytes -= wsize; |
871 | nfs_execute_write(data); | ||
872 | } while (nbytes != 0); | 880 | } while (nbytes != 0); |
873 | 881 | ||
874 | return 0; | 882 | return 0; |
@@ -916,7 +924,6 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
916 | /* Set up the argument struct */ | 924 | /* Set up the argument struct */ |
917 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 925 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
918 | 926 | ||
919 | nfs_execute_write(data); | ||
920 | return 0; | 927 | return 0; |
921 | out_bad: | 928 | out_bad: |
922 | while (!list_empty(head)) { | 929 | while (!list_empty(head)) { |
@@ -932,7 +939,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
932 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 939 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
933 | struct inode *inode, int ioflags) | 940 | struct inode *inode, int ioflags) |
934 | { | 941 | { |
935 | int wsize = NFS_SERVER(inode)->wsize; | 942 | size_t wsize = NFS_SERVER(inode)->wsize; |
936 | 943 | ||
937 | if (wsize < PAGE_CACHE_SIZE) | 944 | if (wsize < PAGE_CACHE_SIZE) |
938 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); | 945 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); |
@@ -1146,19 +1153,33 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1146 | struct nfs_write_data *data, | 1153 | struct nfs_write_data *data, |
1147 | int how) | 1154 | int how) |
1148 | { | 1155 | { |
1149 | struct nfs_page *first; | 1156 | struct nfs_page *first = nfs_list_entry(head->next); |
1150 | struct inode *inode; | 1157 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
1151 | int flags; | 1158 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; |
1159 | int priority = flush_task_priority(how); | ||
1160 | struct rpc_task *task; | ||
1161 | struct rpc_message msg = { | ||
1162 | .rpc_argp = &data->args, | ||
1163 | .rpc_resp = &data->res, | ||
1164 | .rpc_cred = first->wb_context->cred, | ||
1165 | }; | ||
1166 | struct rpc_task_setup task_setup_data = { | ||
1167 | .task = &data->task, | ||
1168 | .rpc_client = NFS_CLIENT(inode), | ||
1169 | .rpc_message = &msg, | ||
1170 | .callback_ops = &nfs_commit_ops, | ||
1171 | .callback_data = data, | ||
1172 | .flags = flags, | ||
1173 | .priority = priority, | ||
1174 | }; | ||
1152 | 1175 | ||
1153 | /* Set up the RPC argument and reply structs | 1176 | /* Set up the RPC argument and reply structs |
1154 | * NB: take care not to mess about with data->commit et al. */ | 1177 | * NB: take care not to mess about with data->commit et al. */ |
1155 | 1178 | ||
1156 | list_splice_init(head, &data->pages); | 1179 | list_splice_init(head, &data->pages); |
1157 | first = nfs_list_entry(data->pages.next); | ||
1158 | inode = first->wb_context->path.dentry->d_inode; | ||
1159 | 1180 | ||
1160 | data->inode = inode; | 1181 | data->inode = inode; |
1161 | data->cred = first->wb_context->cred; | 1182 | data->cred = msg.rpc_cred; |
1162 | 1183 | ||
1163 | data->args.fh = NFS_FH(data->inode); | 1184 | data->args.fh = NFS_FH(data->inode); |
1164 | /* Note: we always request a commit of the entire inode */ | 1185 | /* Note: we always request a commit of the entire inode */ |
@@ -1170,14 +1191,13 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1170 | nfs_fattr_init(&data->fattr); | 1191 | nfs_fattr_init(&data->fattr); |
1171 | 1192 | ||
1172 | /* Set up the initial task struct. */ | 1193 | /* Set up the initial task struct. */ |
1173 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | 1194 | NFS_PROTO(inode)->commit_setup(data, &msg); |
1174 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | ||
1175 | NFS_PROTO(inode)->commit_setup(data, how); | ||
1176 | 1195 | ||
1177 | data->task.tk_priority = flush_task_priority(how); | ||
1178 | data->task.tk_cookie = (unsigned long)inode; | ||
1179 | |||
1180 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); | 1196 | dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid); |
1197 | |||
1198 | task = rpc_run_task(&task_setup_data); | ||
1199 | if (!IS_ERR(task)) | ||
1200 | rpc_put_task(task); | ||
1181 | } | 1201 | } |
1182 | 1202 | ||
1183 | /* | 1203 | /* |
@@ -1197,7 +1217,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1197 | /* Set up the argument struct */ | 1217 | /* Set up the argument struct */ |
1198 | nfs_commit_rpcsetup(head, data, how); | 1218 | nfs_commit_rpcsetup(head, data, how); |
1199 | 1219 | ||
1200 | nfs_execute_write(data); | ||
1201 | return 0; | 1220 | return 0; |
1202 | out_bad: | 1221 | out_bad: |
1203 | while (!list_empty(head)) { | 1222 | while (!list_empty(head)) { |
@@ -1436,7 +1455,8 @@ out: | |||
1436 | return ret; | 1455 | return ret; |
1437 | } | 1456 | } |
1438 | 1457 | ||
1439 | int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | 1458 | static int nfs_wb_page_priority(struct inode *inode, struct page *page, |
1459 | int how) | ||
1440 | { | 1460 | { |
1441 | loff_t range_start = page_offset(page); | 1461 | loff_t range_start = page_offset(page); |
1442 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | 1462 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); |