diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-13 18:10:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-04-13 18:10:16 -0400 |
commit | 0fdfe5ad2802e747460bf48eb2eb0ca3d3f3af42 (patch) | |
tree | 1358c7920438e090605695f6fb8e7989eb3f8998 | |
parent | 44d2d371d250b44cbe40f8d47e329c97668d7594 (diff) | |
parent | 0df5dd4aae211edeeeb84f7f84f6d093406d7c22 (diff) |
Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6:
NFSv4: fix delegated locking
NFS: Ensure that the WRITE and COMMIT RPC calls are always uninterruptible
NFS: Fix a race with the new commit code
NFS: Ensure that writeback_single_inode() calls write_inode() when syncing
NFS: Fix the mode calculation in nfs_find_open_context
NFSv4: Fall back to ordinary lookup if nfs4_atomic_open() returns EISDIR
-rw-r--r-- | fs/nfs/client.c | 3 | ||||
-rw-r--r-- | fs/nfs/dir.c | 2 | ||||
-rw-r--r-- | fs/nfs/inode.c | 8 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 4 | ||||
-rw-r--r-- | fs/nfs/write.c | 44 | ||||
-rw-r--r-- | include/linux/nfs_fs_sb.h | 1 |
6 files changed, 39 insertions, 23 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 2a3d352c0bff..a8766c4ef2e0 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -1294,7 +1294,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1294 | 1294 | ||
1295 | /* Initialise the client representation from the mount data */ | 1295 | /* Initialise the client representation from the mount data */ |
1296 | server->flags = data->flags; | 1296 | server->flags = data->flags; |
1297 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | 1297 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR| |
1298 | NFS_CAP_POSIX_LOCK; | ||
1298 | server->options = data->options; | 1299 | server->options = data->options; |
1299 | 1300 | ||
1300 | /* Get a client record */ | 1301 | /* Get a client record */ |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index c6f2750648f4..be46f26c9a56 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1025,12 +1025,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1025 | res = NULL; | 1025 | res = NULL; |
1026 | goto out; | 1026 | goto out; |
1027 | /* This turned out not to be a regular file */ | 1027 | /* This turned out not to be a regular file */ |
1028 | case -EISDIR: | ||
1028 | case -ENOTDIR: | 1029 | case -ENOTDIR: |
1029 | goto no_open; | 1030 | goto no_open; |
1030 | case -ELOOP: | 1031 | case -ELOOP: |
1031 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1032 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
1032 | goto no_open; | 1033 | goto no_open; |
1033 | /* case -EISDIR: */ | ||
1034 | /* case -EINVAL: */ | 1034 | /* case -EINVAL: */ |
1035 | default: | 1035 | default: |
1036 | goto out; | 1036 | goto out; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 737128f777f3..50a56edca0b5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -623,10 +623,10 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
623 | list_for_each_entry(pos, &nfsi->open_files, list) { | 623 | list_for_each_entry(pos, &nfsi->open_files, list) { |
624 | if (cred != NULL && pos->cred != cred) | 624 | if (cred != NULL && pos->cred != cred) |
625 | continue; | 625 | continue; |
626 | if ((pos->mode & mode) == mode) { | 626 | if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) |
627 | ctx = get_nfs_open_context(pos); | 627 | continue; |
628 | break; | 628 | ctx = get_nfs_open_context(pos); |
629 | } | 629 | break; |
630 | } | 630 | } |
631 | spin_unlock(&inode->i_lock); | 631 | spin_unlock(&inode->i_lock); |
632 | return ctx; | 632 | return ctx; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index fe0cd9eb1d4d..638067007c65 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1523,6 +1523,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
1524 | } else | 1524 | } else |
1525 | nfs_refresh_inode(dir, o_res->dir_attr); | 1525 | nfs_refresh_inode(dir, o_res->dir_attr); |
1526 | if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0) | ||
1527 | server->caps &= ~NFS_CAP_POSIX_LOCK; | ||
1526 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1528 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
1527 | status = _nfs4_proc_open_confirm(data); | 1529 | status = _nfs4_proc_open_confirm(data); |
1528 | if (status != 0) | 1530 | if (status != 0) |
@@ -1664,7 +1666,7 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1664 | status = PTR_ERR(state); | 1666 | status = PTR_ERR(state); |
1665 | if (IS_ERR(state)) | 1667 | if (IS_ERR(state)) |
1666 | goto err_opendata_put; | 1668 | goto err_opendata_put; |
1667 | if ((opendata->o_res.rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) != 0) | 1669 | if (server->caps & NFS_CAP_POSIX_LOCK) |
1668 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | 1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); |
1669 | nfs4_opendata_put(opendata); | 1671 | nfs4_opendata_put(opendata); |
1670 | nfs4_put_state_owner(sp); | 1672 | nfs4_put_state_owner(sp); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 53ff70e23993..de38d63aa920 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -201,6 +201,7 @@ static int nfs_set_page_writeback(struct page *page) | |||
201 | struct inode *inode = page->mapping->host; | 201 | struct inode *inode = page->mapping->host; |
202 | struct nfs_server *nfss = NFS_SERVER(inode); | 202 | struct nfs_server *nfss = NFS_SERVER(inode); |
203 | 203 | ||
204 | page_cache_get(page); | ||
204 | if (atomic_long_inc_return(&nfss->writeback) > | 205 | if (atomic_long_inc_return(&nfss->writeback) > |
205 | NFS_CONGESTION_ON_THRESH) { | 206 | NFS_CONGESTION_ON_THRESH) { |
206 | set_bdi_congested(&nfss->backing_dev_info, | 207 | set_bdi_congested(&nfss->backing_dev_info, |
@@ -216,6 +217,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
216 | struct nfs_server *nfss = NFS_SERVER(inode); | 217 | struct nfs_server *nfss = NFS_SERVER(inode); |
217 | 218 | ||
218 | end_page_writeback(page); | 219 | end_page_writeback(page); |
220 | page_cache_release(page); | ||
219 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 221 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
221 | } | 223 | } |
@@ -421,6 +423,7 @@ static void | |||
421 | nfs_mark_request_dirty(struct nfs_page *req) | 423 | nfs_mark_request_dirty(struct nfs_page *req) |
422 | { | 424 | { |
423 | __set_page_dirty_nobuffers(req->wb_page); | 425 | __set_page_dirty_nobuffers(req->wb_page); |
426 | __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC); | ||
424 | } | 427 | } |
425 | 428 | ||
426 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 429 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -660,9 +663,11 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
660 | req = nfs_setup_write_request(ctx, page, offset, count); | 663 | req = nfs_setup_write_request(ctx, page, offset, count); |
661 | if (IS_ERR(req)) | 664 | if (IS_ERR(req)) |
662 | return PTR_ERR(req); | 665 | return PTR_ERR(req); |
666 | nfs_mark_request_dirty(req); | ||
663 | /* Update file length */ | 667 | /* Update file length */ |
664 | nfs_grow_file(page, offset, count); | 668 | nfs_grow_file(page, offset, count); |
665 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 669 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
670 | nfs_mark_request_dirty(req); | ||
666 | nfs_clear_page_tag_locked(req); | 671 | nfs_clear_page_tag_locked(req); |
667 | return 0; | 672 | return 0; |
668 | } | 673 | } |
@@ -739,8 +744,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
739 | status = nfs_writepage_setup(ctx, page, offset, count); | 744 | status = nfs_writepage_setup(ctx, page, offset, count); |
740 | if (status < 0) | 745 | if (status < 0) |
741 | nfs_set_pageerror(page); | 746 | nfs_set_pageerror(page); |
742 | else | ||
743 | __set_page_dirty_nobuffers(page); | ||
744 | 747 | ||
745 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", | 748 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", |
746 | status, (long long)i_size_read(inode)); | 749 | status, (long long)i_size_read(inode)); |
@@ -749,13 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
749 | 752 | ||
750 | static void nfs_writepage_release(struct nfs_page *req) | 753 | static void nfs_writepage_release(struct nfs_page *req) |
751 | { | 754 | { |
755 | struct page *page = req->wb_page; | ||
752 | 756 | ||
753 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 757 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) |
754 | nfs_end_page_writeback(req->wb_page); | ||
755 | nfs_inode_remove_request(req); | 758 | nfs_inode_remove_request(req); |
756 | } else | ||
757 | nfs_end_page_writeback(req->wb_page); | ||
758 | nfs_clear_page_tag_locked(req); | 759 | nfs_clear_page_tag_locked(req); |
760 | nfs_end_page_writeback(page); | ||
759 | } | 761 | } |
760 | 762 | ||
761 | static int flush_task_priority(int how) | 763 | static int flush_task_priority(int how) |
@@ -779,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
779 | int how) | 781 | int how) |
780 | { | 782 | { |
781 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 783 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
782 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
783 | int priority = flush_task_priority(how); | 784 | int priority = flush_task_priority(how); |
784 | struct rpc_task *task; | 785 | struct rpc_task *task; |
785 | struct rpc_message msg = { | 786 | struct rpc_message msg = { |
@@ -794,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
794 | .callback_ops = call_ops, | 795 | .callback_ops = call_ops, |
795 | .callback_data = data, | 796 | .callback_data = data, |
796 | .workqueue = nfsiod_workqueue, | 797 | .workqueue = nfsiod_workqueue, |
797 | .flags = flags, | 798 | .flags = RPC_TASK_ASYNC, |
798 | .priority = priority, | 799 | .priority = priority, |
799 | }; | 800 | }; |
801 | int ret = 0; | ||
800 | 802 | ||
801 | /* Set up the RPC argument and reply structs | 803 | /* Set up the RPC argument and reply structs |
802 | * NB: take care not to mess about with data->commit et al. */ | 804 | * NB: take care not to mess about with data->commit et al. */ |
@@ -835,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
835 | (unsigned long long)data->args.offset); | 837 | (unsigned long long)data->args.offset); |
836 | 838 | ||
837 | task = rpc_run_task(&task_setup_data); | 839 | task = rpc_run_task(&task_setup_data); |
838 | if (IS_ERR(task)) | 840 | if (IS_ERR(task)) { |
839 | return PTR_ERR(task); | 841 | ret = PTR_ERR(task); |
842 | goto out; | ||
843 | } | ||
844 | if (how & FLUSH_SYNC) { | ||
845 | ret = rpc_wait_for_completion_task(task); | ||
846 | if (ret == 0) | ||
847 | ret = task->tk_status; | ||
848 | } | ||
840 | rpc_put_task(task); | 849 | rpc_put_task(task); |
841 | return 0; | 850 | out: |
851 | return ret; | ||
842 | } | 852 | } |
843 | 853 | ||
844 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 854 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
@@ -847,9 +857,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
847 | */ | 857 | */ |
848 | static void nfs_redirty_request(struct nfs_page *req) | 858 | static void nfs_redirty_request(struct nfs_page *req) |
849 | { | 859 | { |
860 | struct page *page = req->wb_page; | ||
861 | |||
850 | nfs_mark_request_dirty(req); | 862 | nfs_mark_request_dirty(req); |
851 | nfs_end_page_writeback(req->wb_page); | ||
852 | nfs_clear_page_tag_locked(req); | 863 | nfs_clear_page_tag_locked(req); |
864 | nfs_end_page_writeback(page); | ||
853 | } | 865 | } |
854 | 866 | ||
855 | /* | 867 | /* |
@@ -1084,16 +1096,15 @@ static void nfs_writeback_release_full(void *calldata) | |||
1084 | if (nfs_write_need_commit(data)) { | 1096 | if (nfs_write_need_commit(data)) { |
1085 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1097 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
1086 | nfs_mark_request_commit(req); | 1098 | nfs_mark_request_commit(req); |
1087 | nfs_end_page_writeback(page); | ||
1088 | dprintk(" marked for commit\n"); | 1099 | dprintk(" marked for commit\n"); |
1089 | goto next; | 1100 | goto next; |
1090 | } | 1101 | } |
1091 | dprintk(" OK\n"); | 1102 | dprintk(" OK\n"); |
1092 | remove_request: | 1103 | remove_request: |
1093 | nfs_end_page_writeback(page); | ||
1094 | nfs_inode_remove_request(req); | 1104 | nfs_inode_remove_request(req); |
1095 | next: | 1105 | next: |
1096 | nfs_clear_page_tag_locked(req); | 1106 | nfs_clear_page_tag_locked(req); |
1107 | nfs_end_page_writeback(page); | ||
1097 | } | 1108 | } |
1098 | nfs_writedata_release(calldata); | 1109 | nfs_writedata_release(calldata); |
1099 | } | 1110 | } |
@@ -1207,7 +1218,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1207 | { | 1218 | { |
1208 | struct nfs_page *first = nfs_list_entry(head->next); | 1219 | struct nfs_page *first = nfs_list_entry(head->next); |
1209 | struct inode *inode = first->wb_context->path.dentry->d_inode; | 1220 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
1210 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
1211 | int priority = flush_task_priority(how); | 1221 | int priority = flush_task_priority(how); |
1212 | struct rpc_task *task; | 1222 | struct rpc_task *task; |
1213 | struct rpc_message msg = { | 1223 | struct rpc_message msg = { |
@@ -1222,7 +1232,7 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1222 | .callback_ops = &nfs_commit_ops, | 1232 | .callback_ops = &nfs_commit_ops, |
1223 | .callback_data = data, | 1233 | .callback_data = data, |
1224 | .workqueue = nfsiod_workqueue, | 1234 | .workqueue = nfsiod_workqueue, |
1225 | .flags = flags, | 1235 | .flags = RPC_TASK_ASYNC, |
1226 | .priority = priority, | 1236 | .priority = priority, |
1227 | }; | 1237 | }; |
1228 | 1238 | ||
@@ -1252,6 +1262,8 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1252 | task = rpc_run_task(&task_setup_data); | 1262 | task = rpc_run_task(&task_setup_data); |
1253 | if (IS_ERR(task)) | 1263 | if (IS_ERR(task)) |
1254 | return PTR_ERR(task); | 1264 | return PTR_ERR(task); |
1265 | if (how & FLUSH_SYNC) | ||
1266 | rpc_wait_for_completion_task(task); | ||
1255 | rpc_put_task(task); | 1267 | rpc_put_task(task); |
1256 | return 0; | 1268 | return 0; |
1257 | } | 1269 | } |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 717a5e54eb1d..e82957acea56 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
@@ -176,6 +176,7 @@ struct nfs_server { | |||
176 | #define NFS_CAP_ATIME (1U << 11) | 176 | #define NFS_CAP_ATIME (1U << 11) |
177 | #define NFS_CAP_CTIME (1U << 12) | 177 | #define NFS_CAP_CTIME (1U << 12) |
178 | #define NFS_CAP_MTIME (1U << 13) | 178 | #define NFS_CAP_MTIME (1U << 13) |
179 | #define NFS_CAP_POSIX_LOCK (1U << 14) | ||
179 | 180 | ||
180 | 181 | ||
181 | /* maximum number of slots to use */ | 182 | /* maximum number of slots to use */ |