diff options
Diffstat (limited to 'fs/nfs')
37 files changed, 1943 insertions, 1029 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 2a77bc25d5af..a43d07e7b924 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -90,13 +90,12 @@ config ROOT_NFS | |||
90 | If you want your system to mount its root file system via NFS, | 90 | If you want your system to mount its root file system via NFS, |
91 | choose Y here. This is common practice for managing systems | 91 | choose Y here. This is common practice for managing systems |
92 | without local permanent storage. For details, read | 92 | without local permanent storage. For details, read |
93 | <file:Documentation/filesystems/nfsroot.txt>. | 93 | <file:Documentation/filesystems/nfs/nfsroot.txt>. |
94 | 94 | ||
95 | Most people say N here. | 95 | Most people say N here. |
96 | 96 | ||
97 | config NFS_FSCACHE | 97 | config NFS_FSCACHE |
98 | bool "Provide NFS client caching support (EXPERIMENTAL)" | 98 | bool "Provide NFS client caching support" |
99 | depends on EXPERIMENTAL | ||
100 | depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y | 99 | depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y |
101 | help | 100 | help |
102 | Say Y here if you want NFS data to be cached locally on disc through | 101 | Say Y here if you want NFS data to be cached locally on disc through |
diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c index b4ffd0146ea6..84690319e625 100644 --- a/fs/nfs/cache_lib.c +++ b/fs/nfs/cache_lib.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/namei.h> | 12 | #include <linux/namei.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/sunrpc/cache.h> | 14 | #include <linux/sunrpc/cache.h> |
14 | #include <linux/sunrpc/rpc_pipe_fs.h> | 15 | #include <linux/sunrpc/rpc_pipe_fs.h> |
15 | 16 | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 293fa0528a6e..36dfdae95123 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -78,11 +78,6 @@ nfs4_callback_svc(void *vrqstp) | |||
78 | 78 | ||
79 | set_freezable(); | 79 | set_freezable(); |
80 | 80 | ||
81 | /* | ||
82 | * FIXME: do we really need to run this under the BKL? If so, please | ||
83 | * add a comment about what it's intended to protect. | ||
84 | */ | ||
85 | lock_kernel(); | ||
86 | while (!kthread_should_stop()) { | 81 | while (!kthread_should_stop()) { |
87 | /* | 82 | /* |
88 | * Listen for a request on the socket | 83 | * Listen for a request on the socket |
@@ -104,7 +99,6 @@ nfs4_callback_svc(void *vrqstp) | |||
104 | preverr = err; | 99 | preverr = err; |
105 | svc_process(rqstp); | 100 | svc_process(rqstp); |
106 | } | 101 | } |
107 | unlock_kernel(); | ||
108 | return 0; | 102 | return 0; |
109 | } | 103 | } |
110 | 104 | ||
@@ -124,7 +118,6 @@ nfs4_callback_up(struct svc_serv *serv) | |||
124 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 118 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
125 | nfs_callback_tcpport, PF_INET); | 119 | nfs_callback_tcpport, PF_INET); |
126 | 120 | ||
127 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
128 | ret = svc_create_xprt(serv, "tcp", PF_INET6, | 121 | ret = svc_create_xprt(serv, "tcp", PF_INET6, |
129 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 122 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
130 | if (ret > 0) { | 123 | if (ret > 0) { |
@@ -135,7 +128,6 @@ nfs4_callback_up(struct svc_serv *serv) | |||
135 | ret = 0; | 128 | ret = 0; |
136 | else | 129 | else |
137 | goto out_err; | 130 | goto out_err; |
138 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | ||
139 | 131 | ||
140 | return svc_prepare_thread(serv, &serv->sv_pools[0]); | 132 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
141 | 133 | ||
@@ -160,11 +152,6 @@ nfs41_callback_svc(void *vrqstp) | |||
160 | 152 | ||
161 | set_freezable(); | 153 | set_freezable(); |
162 | 154 | ||
163 | /* | ||
164 | * FIXME: do we really need to run this under the BKL? If so, please | ||
165 | * add a comment about what it's intended to protect. | ||
166 | */ | ||
167 | lock_kernel(); | ||
168 | while (!kthread_should_stop()) { | 155 | while (!kthread_should_stop()) { |
169 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | 156 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); |
170 | spin_lock_bh(&serv->sv_cb_lock); | 157 | spin_lock_bh(&serv->sv_cb_lock); |
@@ -183,7 +170,6 @@ nfs41_callback_svc(void *vrqstp) | |||
183 | } | 170 | } |
184 | finish_wait(&serv->sv_cb_waitq, &wq); | 171 | finish_wait(&serv->sv_cb_waitq, &wq); |
185 | } | 172 | } |
186 | unlock_kernel(); | ||
187 | return 0; | 173 | return 0; |
188 | } | 174 | } |
189 | 175 | ||
@@ -397,6 +383,7 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp) | |||
397 | */ | 383 | */ |
398 | static struct svc_version *nfs4_callback_version[] = { | 384 | static struct svc_version *nfs4_callback_version[] = { |
399 | [1] = &nfs4_callback_version1, | 385 | [1] = &nfs4_callback_version1, |
386 | [4] = &nfs4_callback_version4, | ||
400 | }; | 387 | }; |
401 | 388 | ||
402 | static struct svc_stat nfs4_callback_stats; | 389 | static struct svc_stat nfs4_callback_stats; |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index 07baa8254ca1..85a7cfd1b8dd 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -106,6 +106,27 @@ struct cb_sequenceres { | |||
106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | 106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, |
107 | struct cb_sequenceres *res); | 107 | struct cb_sequenceres *res); |
108 | 108 | ||
109 | extern int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, | ||
110 | const nfs4_stateid *stateid); | ||
111 | |||
112 | #define RCA4_TYPE_MASK_RDATA_DLG 0 | ||
113 | #define RCA4_TYPE_MASK_WDATA_DLG 1 | ||
114 | |||
115 | struct cb_recallanyargs { | ||
116 | struct sockaddr *craa_addr; | ||
117 | uint32_t craa_objs_to_keep; | ||
118 | uint32_t craa_type_mask; | ||
119 | }; | ||
120 | |||
121 | extern unsigned nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy); | ||
122 | |||
123 | struct cb_recallslotargs { | ||
124 | struct sockaddr *crsa_addr; | ||
125 | uint32_t crsa_target_max_slots; | ||
126 | }; | ||
127 | extern unsigned nfs4_callback_recallslot(struct cb_recallslotargs *args, | ||
128 | void *dummy); | ||
129 | |||
109 | #endif /* CONFIG_NFS_V4_1 */ | 130 | #endif /* CONFIG_NFS_V4_1 */ |
110 | 131 | ||
111 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 132 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
@@ -114,8 +135,9 @@ extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | |||
114 | #ifdef CONFIG_NFS_V4 | 135 | #ifdef CONFIG_NFS_V4 |
115 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); | 136 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
116 | extern void nfs_callback_down(int minorversion); | 137 | extern void nfs_callback_down(int minorversion); |
138 | extern int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, | ||
139 | const nfs4_stateid *stateid); | ||
117 | #endif /* CONFIG_NFS_V4 */ | 140 | #endif /* CONFIG_NFS_V4 */ |
118 | |||
119 | /* | 141 | /* |
120 | * nfs41: Callbacks are expected to not cause substantial latency, | 142 | * nfs41: Callbacks are expected to not cause substantial latency, |
121 | * so we limit their concurrency to 1 by setting up the maximum number | 143 | * so we limit their concurrency to 1 by setting up the maximum number |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index b7da1f54da68..a08770a7e857 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -7,6 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | #include <linux/nfs4.h> | 8 | #include <linux/nfs4.h> |
9 | #include <linux/nfs_fs.h> | 9 | #include <linux/nfs_fs.h> |
10 | #include <linux/slab.h> | ||
10 | #include "nfs4_fs.h" | 11 | #include "nfs4_fs.h" |
11 | #include "callback.h" | 12 | #include "callback.h" |
12 | #include "delegation.h" | 13 | #include "delegation.h" |
@@ -61,6 +62,16 @@ out: | |||
61 | return res->status; | 62 | return res->status; |
62 | } | 63 | } |
63 | 64 | ||
65 | static int (*nfs_validate_delegation_stateid(struct nfs_client *clp))(struct nfs_delegation *, const nfs4_stateid *) | ||
66 | { | ||
67 | #if defined(CONFIG_NFS_V4_1) | ||
68 | if (clp->cl_minorversion > 0) | ||
69 | return nfs41_validate_delegation_stateid; | ||
70 | #endif | ||
71 | return nfs4_validate_delegation_stateid; | ||
72 | } | ||
73 | |||
74 | |||
64 | __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | 75 | __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) |
65 | { | 76 | { |
66 | struct nfs_client *clp; | 77 | struct nfs_client *clp; |
@@ -81,7 +92,8 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy) | |||
81 | inode = nfs_delegation_find_inode(clp, &args->fh); | 92 | inode = nfs_delegation_find_inode(clp, &args->fh); |
82 | if (inode != NULL) { | 93 | if (inode != NULL) { |
83 | /* Set up a helper thread to actually return the delegation */ | 94 | /* Set up a helper thread to actually return the delegation */ |
84 | switch(nfs_async_inode_return_delegation(inode, &args->stateid)) { | 95 | switch (nfs_async_inode_return_delegation(inode, &args->stateid, |
96 | nfs_validate_delegation_stateid(clp))) { | ||
85 | case 0: | 97 | case 0: |
86 | res = 0; | 98 | res = 0; |
87 | break; | 99 | break; |
@@ -102,51 +114,79 @@ out: | |||
102 | return res; | 114 | return res; |
103 | } | 115 | } |
104 | 116 | ||
117 | int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) | ||
118 | { | ||
119 | if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, | ||
120 | sizeof(delegation->stateid.data)) != 0) | ||
121 | return 0; | ||
122 | return 1; | ||
123 | } | ||
124 | |||
105 | #if defined(CONFIG_NFS_V4_1) | 125 | #if defined(CONFIG_NFS_V4_1) |
106 | 126 | ||
127 | int nfs41_validate_delegation_stateid(struct nfs_delegation *delegation, const nfs4_stateid *stateid) | ||
128 | { | ||
129 | if (delegation == NULL) | ||
130 | return 0; | ||
131 | |||
132 | /* seqid is 4-bytes long */ | ||
133 | if (((u32 *) &stateid->data)[0] != 0) | ||
134 | return 0; | ||
135 | if (memcmp(&delegation->stateid.data[4], &stateid->data[4], | ||
136 | sizeof(stateid->data)-4)) | ||
137 | return 0; | ||
138 | |||
139 | return 1; | ||
140 | } | ||
141 | |||
107 | /* | 142 | /* |
108 | * Validate the sequenceID sent by the server. | 143 | * Validate the sequenceID sent by the server. |
109 | * Return success if the sequenceID is one more than what we last saw on | 144 | * Return success if the sequenceID is one more than what we last saw on |
110 | * this slot, accounting for wraparound. Increments the slot's sequence. | 145 | * this slot, accounting for wraparound. Increments the slot's sequence. |
111 | * | 146 | * |
112 | * We don't yet implement a duplicate request cache, so at this time | 147 | * We don't yet implement a duplicate request cache, instead we set the |
113 | * we will log replays, and process them as if we had not seen them before, | 148 | * back channel ca_maxresponsesize_cached to zero. This is OK for now |
114 | * but we don't bump the sequence in the slot. Not too worried about it, | ||
115 | * since we only currently implement idempotent callbacks anyway. | 149 | * since we only currently implement idempotent callbacks anyway. |
116 | * | 150 | * |
117 | * We have a single slot backchannel at this time, so we don't bother | 151 | * We have a single slot backchannel at this time, so we don't bother |
118 | * checking the used_slots bit array on the table. The lower layer guarantees | 152 | * checking the used_slots bit array on the table. The lower layer guarantees |
119 | * a single outstanding callback request at a time. | 153 | * a single outstanding callback request at a time. |
120 | */ | 154 | */ |
121 | static int | 155 | static __be32 |
122 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | 156 | validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) |
123 | { | 157 | { |
124 | struct nfs4_slot *slot; | 158 | struct nfs4_slot *slot; |
125 | 159 | ||
126 | dprintk("%s enter. slotid %d seqid %d\n", | 160 | dprintk("%s enter. slotid %d seqid %d\n", |
127 | __func__, slotid, seqid); | 161 | __func__, args->csa_slotid, args->csa_sequenceid); |
128 | 162 | ||
129 | if (slotid > NFS41_BC_MAX_CALLBACKS) | 163 | if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS) |
130 | return htonl(NFS4ERR_BADSLOT); | 164 | return htonl(NFS4ERR_BADSLOT); |
131 | 165 | ||
132 | slot = tbl->slots + slotid; | 166 | slot = tbl->slots + args->csa_slotid; |
133 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | 167 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); |
134 | 168 | ||
135 | /* Normal */ | 169 | /* Normal */ |
136 | if (likely(seqid == slot->seq_nr + 1)) { | 170 | if (likely(args->csa_sequenceid == slot->seq_nr + 1)) { |
137 | slot->seq_nr++; | 171 | slot->seq_nr++; |
138 | return htonl(NFS4_OK); | 172 | return htonl(NFS4_OK); |
139 | } | 173 | } |
140 | 174 | ||
141 | /* Replay */ | 175 | /* Replay */ |
142 | if (seqid == slot->seq_nr) { | 176 | if (args->csa_sequenceid == slot->seq_nr) { |
143 | dprintk("%s seqid %d is a replay - no DRC available\n", | 177 | dprintk("%s seqid %d is a replay\n", |
144 | __func__, seqid); | 178 | __func__, args->csa_sequenceid); |
145 | return htonl(NFS4_OK); | 179 | /* Signal process_op to set this error on next op */ |
180 | if (args->csa_cachethis == 0) | ||
181 | return htonl(NFS4ERR_RETRY_UNCACHED_REP); | ||
182 | |||
183 | /* The ca_maxresponsesize_cached is 0 with no DRC */ | ||
184 | else if (args->csa_cachethis == 1) | ||
185 | return htonl(NFS4ERR_REP_TOO_BIG_TO_CACHE); | ||
146 | } | 186 | } |
147 | 187 | ||
148 | /* Wraparound */ | 188 | /* Wraparound */ |
149 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | 189 | if (args->csa_sequenceid == 1 && (slot->seq_nr + 1) == 0) { |
150 | slot->seq_nr = 1; | 190 | slot->seq_nr = 1; |
151 | return htonl(NFS4_OK); | 191 | return htonl(NFS4_OK); |
152 | } | 192 | } |
@@ -191,27 +231,87 @@ validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | |||
191 | return NULL; | 231 | return NULL; |
192 | } | 232 | } |
193 | 233 | ||
194 | /* FIXME: referring calls should be processed */ | 234 | /* |
195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | 235 | * For each referring call triple, check the session's slot table for |
236 | * a match. If the slot is in use and the sequence numbers match, the | ||
237 | * client is still waiting for a response to the original request. | ||
238 | */ | ||
239 | static bool referring_call_exists(struct nfs_client *clp, | ||
240 | uint32_t nrclists, | ||
241 | struct referring_call_list *rclists) | ||
242 | { | ||
243 | bool status = 0; | ||
244 | int i, j; | ||
245 | struct nfs4_session *session; | ||
246 | struct nfs4_slot_table *tbl; | ||
247 | struct referring_call_list *rclist; | ||
248 | struct referring_call *ref; | ||
249 | |||
250 | /* | ||
251 | * XXX When client trunking is implemented, this becomes | ||
252 | * a session lookup from within the loop | ||
253 | */ | ||
254 | session = clp->cl_session; | ||
255 | tbl = &session->fc_slot_table; | ||
256 | |||
257 | for (i = 0; i < nrclists; i++) { | ||
258 | rclist = &rclists[i]; | ||
259 | if (memcmp(session->sess_id.data, | ||
260 | rclist->rcl_sessionid.data, | ||
261 | NFS4_MAX_SESSIONID_LEN) != 0) | ||
262 | continue; | ||
263 | |||
264 | for (j = 0; j < rclist->rcl_nrefcalls; j++) { | ||
265 | ref = &rclist->rcl_refcalls[j]; | ||
266 | |||
267 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u " | ||
268 | "slotid %u\n", __func__, | ||
269 | ((u32 *)&rclist->rcl_sessionid.data)[0], | ||
270 | ((u32 *)&rclist->rcl_sessionid.data)[1], | ||
271 | ((u32 *)&rclist->rcl_sessionid.data)[2], | ||
272 | ((u32 *)&rclist->rcl_sessionid.data)[3], | ||
273 | ref->rc_sequenceid, ref->rc_slotid); | ||
274 | |||
275 | spin_lock(&tbl->slot_tbl_lock); | ||
276 | status = (test_bit(ref->rc_slotid, tbl->used_slots) && | ||
277 | tbl->slots[ref->rc_slotid].seq_nr == | ||
278 | ref->rc_sequenceid); | ||
279 | spin_unlock(&tbl->slot_tbl_lock); | ||
280 | if (status) | ||
281 | goto out; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | out: | ||
286 | return status; | ||
287 | } | ||
288 | |||
289 | __be32 nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
196 | struct cb_sequenceres *res) | 290 | struct cb_sequenceres *res) |
197 | { | 291 | { |
198 | struct nfs_client *clp; | 292 | struct nfs_client *clp; |
199 | int i, status; | 293 | int i; |
200 | 294 | __be32 status; | |
201 | for (i = 0; i < args->csa_nrclists; i++) | ||
202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
203 | kfree(args->csa_rclists); | ||
204 | 295 | ||
205 | status = htonl(NFS4ERR_BADSESSION); | 296 | status = htonl(NFS4ERR_BADSESSION); |
206 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | 297 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); |
207 | if (clp == NULL) | 298 | if (clp == NULL) |
208 | goto out; | 299 | goto out; |
209 | 300 | ||
210 | status = validate_seqid(&clp->cl_session->bc_slot_table, | 301 | status = validate_seqid(&clp->cl_session->bc_slot_table, args); |
211 | args->csa_slotid, args->csa_sequenceid); | ||
212 | if (status) | 302 | if (status) |
213 | goto out_putclient; | 303 | goto out_putclient; |
214 | 304 | ||
305 | /* | ||
306 | * Check for pending referring calls. If a match is found, a | ||
307 | * related callback was received before the response to the original | ||
308 | * call. | ||
309 | */ | ||
310 | if (referring_call_exists(clp, args->csa_nrclists, args->csa_rclists)) { | ||
311 | status = htonl(NFS4ERR_DELAY); | ||
312 | goto out_putclient; | ||
313 | } | ||
314 | |||
215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | 315 | memcpy(&res->csr_sessionid, &args->csa_sessionid, |
216 | sizeof(res->csr_sessionid)); | 316 | sizeof(res->csr_sessionid)); |
217 | res->csr_sequenceid = args->csa_sequenceid; | 317 | res->csr_sequenceid = args->csa_sequenceid; |
@@ -222,9 +322,81 @@ unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | |||
222 | out_putclient: | 322 | out_putclient: |
223 | nfs_put_client(clp); | 323 | nfs_put_client(clp); |
224 | out: | 324 | out: |
325 | for (i = 0; i < args->csa_nrclists; i++) | ||
326 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
327 | kfree(args->csa_rclists); | ||
328 | |||
329 | if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) | ||
330 | res->csr_status = 0; | ||
331 | else | ||
332 | res->csr_status = status; | ||
333 | dprintk("%s: exit with status = %d res->csr_status %d\n", __func__, | ||
334 | ntohl(status), ntohl(res->csr_status)); | ||
335 | return status; | ||
336 | } | ||
337 | |||
338 | __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy) | ||
339 | { | ||
340 | struct nfs_client *clp; | ||
341 | __be32 status; | ||
342 | fmode_t flags = 0; | ||
343 | |||
344 | status = htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
345 | clp = nfs_find_client(args->craa_addr, 4); | ||
346 | if (clp == NULL) | ||
347 | goto out; | ||
348 | |||
349 | dprintk("NFS: RECALL_ANY callback request from %s\n", | ||
350 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | ||
351 | |||
352 | if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *) | ||
353 | &args->craa_type_mask)) | ||
354 | flags = FMODE_READ; | ||
355 | if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *) | ||
356 | &args->craa_type_mask)) | ||
357 | flags |= FMODE_WRITE; | ||
358 | |||
359 | if (flags) | ||
360 | nfs_expire_all_delegation_types(clp, flags); | ||
361 | status = htonl(NFS4_OK); | ||
362 | out: | ||
225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | 363 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); |
226 | res->csr_status = status; | 364 | return status; |
227 | return res->csr_status; | ||
228 | } | 365 | } |
229 | 366 | ||
367 | /* Reduce the fore channel's max_slots to the target value */ | ||
368 | __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy) | ||
369 | { | ||
370 | struct nfs_client *clp; | ||
371 | struct nfs4_slot_table *fc_tbl; | ||
372 | __be32 status; | ||
373 | |||
374 | status = htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
375 | clp = nfs_find_client(args->crsa_addr, 4); | ||
376 | if (clp == NULL) | ||
377 | goto out; | ||
378 | |||
379 | dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", | ||
380 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR), | ||
381 | args->crsa_target_max_slots); | ||
382 | |||
383 | fc_tbl = &clp->cl_session->fc_slot_table; | ||
384 | |||
385 | status = htonl(NFS4ERR_BAD_HIGH_SLOT); | ||
386 | if (args->crsa_target_max_slots > fc_tbl->max_slots || | ||
387 | args->crsa_target_max_slots < 1) | ||
388 | goto out_putclient; | ||
389 | |||
390 | status = htonl(NFS4_OK); | ||
391 | if (args->crsa_target_max_slots == fc_tbl->max_slots) | ||
392 | goto out_putclient; | ||
393 | |||
394 | fc_tbl->target_max_slots = args->crsa_target_max_slots; | ||
395 | nfs41_handle_recall_slot(clp); | ||
396 | out_putclient: | ||
397 | nfs_put_client(clp); /* balance nfs_find_client */ | ||
398 | out: | ||
399 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
400 | return status; | ||
401 | } | ||
230 | #endif /* CONFIG_NFS_V4_1 */ | 402 | #endif /* CONFIG_NFS_V4_1 */ |
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index 76b0aa0f73bf..05af212f0edf 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/sunrpc/svc.h> | 9 | #include <linux/sunrpc/svc.h> |
10 | #include <linux/nfs4.h> | 10 | #include <linux/nfs4.h> |
11 | #include <linux/nfs_fs.h> | 11 | #include <linux/nfs_fs.h> |
12 | #include <linux/slab.h> | ||
12 | #include "nfs4_fs.h" | 13 | #include "nfs4_fs.h" |
13 | #include "callback.h" | 14 | #include "callback.h" |
14 | 15 | ||
@@ -23,10 +24,15 @@ | |||
23 | #if defined(CONFIG_NFS_V4_1) | 24 | #if defined(CONFIG_NFS_V4_1) |
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | 25 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ |
25 | 4 + 1 + 3) | 26 | 4 + 1 + 3) |
27 | #define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
28 | #define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | ||
26 | #endif /* CONFIG_NFS_V4_1 */ | 29 | #endif /* CONFIG_NFS_V4_1 */ |
27 | 30 | ||
28 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 31 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
29 | 32 | ||
33 | /* Internal error code */ | ||
34 | #define NFS4ERR_RESOURCE_HDR 11050 | ||
35 | |||
30 | typedef __be32 (*callback_process_op_t)(void *, void *); | 36 | typedef __be32 (*callback_process_op_t)(void *, void *); |
31 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); | 37 | typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *); |
32 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); | 38 | typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *); |
@@ -172,7 +178,7 @@ static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) | |||
172 | __be32 *p; | 178 | __be32 *p; |
173 | p = read_buf(xdr, 4); | 179 | p = read_buf(xdr, 4); |
174 | if (unlikely(p == NULL)) | 180 | if (unlikely(p == NULL)) |
175 | return htonl(NFS4ERR_RESOURCE); | 181 | return htonl(NFS4ERR_RESOURCE_HDR); |
176 | *op = ntohl(*p); | 182 | *op = ntohl(*p); |
177 | return 0; | 183 | return 0; |
178 | } | 184 | } |
@@ -214,10 +220,10 @@ out: | |||
214 | 220 | ||
215 | #if defined(CONFIG_NFS_V4_1) | 221 | #if defined(CONFIG_NFS_V4_1) |
216 | 222 | ||
217 | static unsigned decode_sessionid(struct xdr_stream *xdr, | 223 | static __be32 decode_sessionid(struct xdr_stream *xdr, |
218 | struct nfs4_sessionid *sid) | 224 | struct nfs4_sessionid *sid) |
219 | { | 225 | { |
220 | uint32_t *p; | 226 | __be32 *p; |
221 | int len = NFS4_MAX_SESSIONID_LEN; | 227 | int len = NFS4_MAX_SESSIONID_LEN; |
222 | 228 | ||
223 | p = read_buf(xdr, len); | 229 | p = read_buf(xdr, len); |
@@ -228,12 +234,12 @@ static unsigned decode_sessionid(struct xdr_stream *xdr, | |||
228 | return 0; | 234 | return 0; |
229 | } | 235 | } |
230 | 236 | ||
231 | static unsigned decode_rc_list(struct xdr_stream *xdr, | 237 | static __be32 decode_rc_list(struct xdr_stream *xdr, |
232 | struct referring_call_list *rc_list) | 238 | struct referring_call_list *rc_list) |
233 | { | 239 | { |
234 | uint32_t *p; | 240 | __be32 *p; |
235 | int i; | 241 | int i; |
236 | unsigned status; | 242 | __be32 status; |
237 | 243 | ||
238 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | 244 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); |
239 | if (status) | 245 | if (status) |
@@ -266,13 +272,13 @@ out: | |||
266 | return status; | 272 | return status; |
267 | } | 273 | } |
268 | 274 | ||
269 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | 275 | static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, |
270 | struct xdr_stream *xdr, | 276 | struct xdr_stream *xdr, |
271 | struct cb_sequenceargs *args) | 277 | struct cb_sequenceargs *args) |
272 | { | 278 | { |
273 | uint32_t *p; | 279 | __be32 *p; |
274 | int i; | 280 | int i; |
275 | unsigned status; | 281 | __be32 status; |
276 | 282 | ||
277 | status = decode_sessionid(xdr, &args->csa_sessionid); | 283 | status = decode_sessionid(xdr, &args->csa_sessionid); |
278 | if (status) | 284 | if (status) |
@@ -326,6 +332,39 @@ out_free: | |||
326 | goto out; | 332 | goto out; |
327 | } | 333 | } |
328 | 334 | ||
335 | static __be32 decode_recallany_args(struct svc_rqst *rqstp, | ||
336 | struct xdr_stream *xdr, | ||
337 | struct cb_recallanyargs *args) | ||
338 | { | ||
339 | __be32 *p; | ||
340 | |||
341 | args->craa_addr = svc_addr(rqstp); | ||
342 | p = read_buf(xdr, 4); | ||
343 | if (unlikely(p == NULL)) | ||
344 | return htonl(NFS4ERR_BADXDR); | ||
345 | args->craa_objs_to_keep = ntohl(*p++); | ||
346 | p = read_buf(xdr, 4); | ||
347 | if (unlikely(p == NULL)) | ||
348 | return htonl(NFS4ERR_BADXDR); | ||
349 | args->craa_type_mask = ntohl(*p); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static __be32 decode_recallslot_args(struct svc_rqst *rqstp, | ||
355 | struct xdr_stream *xdr, | ||
356 | struct cb_recallslotargs *args) | ||
357 | { | ||
358 | __be32 *p; | ||
359 | |||
360 | args->crsa_addr = svc_addr(rqstp); | ||
361 | p = read_buf(xdr, 4); | ||
362 | if (unlikely(p == NULL)) | ||
363 | return htonl(NFS4ERR_BADXDR); | ||
364 | args->crsa_target_max_slots = ntohl(*p++); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
329 | #endif /* CONFIG_NFS_V4_1 */ | 368 | #endif /* CONFIG_NFS_V4_1 */ |
330 | 369 | ||
331 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 370 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
@@ -445,7 +484,7 @@ static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) | |||
445 | 484 | ||
446 | p = xdr_reserve_space(xdr, 8); | 485 | p = xdr_reserve_space(xdr, 8); |
447 | if (unlikely(p == NULL)) | 486 | if (unlikely(p == NULL)) |
448 | return htonl(NFS4ERR_RESOURCE); | 487 | return htonl(NFS4ERR_RESOURCE_HDR); |
449 | *p++ = htonl(op); | 488 | *p++ = htonl(op); |
450 | *p = res; | 489 | *p = res; |
451 | return 0; | 490 | return 0; |
@@ -479,10 +518,10 @@ out: | |||
479 | 518 | ||
480 | #if defined(CONFIG_NFS_V4_1) | 519 | #if defined(CONFIG_NFS_V4_1) |
481 | 520 | ||
482 | static unsigned encode_sessionid(struct xdr_stream *xdr, | 521 | static __be32 encode_sessionid(struct xdr_stream *xdr, |
483 | const struct nfs4_sessionid *sid) | 522 | const struct nfs4_sessionid *sid) |
484 | { | 523 | { |
485 | uint32_t *p; | 524 | __be32 *p; |
486 | int len = NFS4_MAX_SESSIONID_LEN; | 525 | int len = NFS4_MAX_SESSIONID_LEN; |
487 | 526 | ||
488 | p = xdr_reserve_space(xdr, len); | 527 | p = xdr_reserve_space(xdr, len); |
@@ -493,11 +532,11 @@ static unsigned encode_sessionid(struct xdr_stream *xdr, | |||
493 | return 0; | 532 | return 0; |
494 | } | 533 | } |
495 | 534 | ||
496 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | 535 | static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp, |
497 | struct xdr_stream *xdr, | 536 | struct xdr_stream *xdr, |
498 | const struct cb_sequenceres *res) | 537 | const struct cb_sequenceres *res) |
499 | { | 538 | { |
500 | uint32_t *p; | 539 | __be32 *p; |
501 | unsigned status = res->csr_status; | 540 | unsigned status = res->csr_status; |
502 | 541 | ||
503 | if (unlikely(status != 0)) | 542 | if (unlikely(status != 0)) |
@@ -533,6 +572,8 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
533 | case OP_CB_GETATTR: | 572 | case OP_CB_GETATTR: |
534 | case OP_CB_RECALL: | 573 | case OP_CB_RECALL: |
535 | case OP_CB_SEQUENCE: | 574 | case OP_CB_SEQUENCE: |
575 | case OP_CB_RECALL_ANY: | ||
576 | case OP_CB_RECALL_SLOT: | ||
536 | *op = &callback_ops[op_nr]; | 577 | *op = &callback_ops[op_nr]; |
537 | break; | 578 | break; |
538 | 579 | ||
@@ -540,9 +581,7 @@ preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | |||
540 | case OP_CB_NOTIFY_DEVICEID: | 581 | case OP_CB_NOTIFY_DEVICEID: |
541 | case OP_CB_NOTIFY: | 582 | case OP_CB_NOTIFY: |
542 | case OP_CB_PUSH_DELEG: | 583 | case OP_CB_PUSH_DELEG: |
543 | case OP_CB_RECALL_ANY: | ||
544 | case OP_CB_RECALLABLE_OBJ_AVAIL: | 584 | case OP_CB_RECALLABLE_OBJ_AVAIL: |
545 | case OP_CB_RECALL_SLOT: | ||
546 | case OP_CB_WANTS_CANCELLED: | 585 | case OP_CB_WANTS_CANCELLED: |
547 | case OP_CB_NOTIFY_LOCK: | 586 | case OP_CB_NOTIFY_LOCK: |
548 | return htonl(NFS4ERR_NOTSUPP); | 587 | return htonl(NFS4ERR_NOTSUPP); |
@@ -582,20 +621,18 @@ preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | |||
582 | static __be32 process_op(uint32_t minorversion, int nop, | 621 | static __be32 process_op(uint32_t minorversion, int nop, |
583 | struct svc_rqst *rqstp, | 622 | struct svc_rqst *rqstp, |
584 | struct xdr_stream *xdr_in, void *argp, | 623 | struct xdr_stream *xdr_in, void *argp, |
585 | struct xdr_stream *xdr_out, void *resp) | 624 | struct xdr_stream *xdr_out, void *resp, int* drc_status) |
586 | { | 625 | { |
587 | struct callback_op *op = &callback_ops[0]; | 626 | struct callback_op *op = &callback_ops[0]; |
588 | unsigned int op_nr = OP_CB_ILLEGAL; | 627 | unsigned int op_nr; |
589 | __be32 status; | 628 | __be32 status; |
590 | long maxlen; | 629 | long maxlen; |
591 | __be32 res; | 630 | __be32 res; |
592 | 631 | ||
593 | dprintk("%s: start\n", __func__); | 632 | dprintk("%s: start\n", __func__); |
594 | status = decode_op_hdr(xdr_in, &op_nr); | 633 | status = decode_op_hdr(xdr_in, &op_nr); |
595 | if (unlikely(status)) { | 634 | if (unlikely(status)) |
596 | status = htonl(NFS4ERR_OP_ILLEGAL); | 635 | return status; |
597 | goto out; | ||
598 | } | ||
599 | 636 | ||
600 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | 637 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", |
601 | __func__, minorversion, nop, op_nr); | 638 | __func__, minorversion, nop, op_nr); |
@@ -604,19 +641,32 @@ static __be32 process_op(uint32_t minorversion, int nop, | |||
604 | preprocess_nfs4_op(op_nr, &op); | 641 | preprocess_nfs4_op(op_nr, &op); |
605 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | 642 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) |
606 | op_nr = OP_CB_ILLEGAL; | 643 | op_nr = OP_CB_ILLEGAL; |
607 | out: | 644 | if (status) |
645 | goto encode_hdr; | ||
646 | |||
647 | if (*drc_status) { | ||
648 | status = *drc_status; | ||
649 | goto encode_hdr; | ||
650 | } | ||
651 | |||
608 | maxlen = xdr_out->end - xdr_out->p; | 652 | maxlen = xdr_out->end - xdr_out->p; |
609 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 653 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
610 | if (likely(status == 0 && op->decode_args != NULL)) | 654 | status = op->decode_args(rqstp, xdr_in, argp); |
611 | status = op->decode_args(rqstp, xdr_in, argp); | 655 | if (likely(status == 0)) |
612 | if (likely(status == 0 && op->process_op != NULL)) | ||
613 | status = op->process_op(argp, resp); | 656 | status = op->process_op(argp, resp); |
614 | } else | 657 | } else |
615 | status = htonl(NFS4ERR_RESOURCE); | 658 | status = htonl(NFS4ERR_RESOURCE); |
616 | 659 | ||
660 | /* Only set by OP_CB_SEQUENCE processing */ | ||
661 | if (status == htonl(NFS4ERR_RETRY_UNCACHED_REP)) { | ||
662 | *drc_status = status; | ||
663 | status = 0; | ||
664 | } | ||
665 | |||
666 | encode_hdr: | ||
617 | res = encode_op_hdr(xdr_out, op_nr, status); | 667 | res = encode_op_hdr(xdr_out, op_nr, status); |
618 | if (status == 0) | 668 | if (unlikely(res)) |
619 | status = res; | 669 | return res; |
620 | if (op->encode_res != NULL && status == 0) | 670 | if (op->encode_res != NULL && status == 0) |
621 | status = op->encode_res(rqstp, xdr_out, resp); | 671 | status = op->encode_res(rqstp, xdr_out, resp); |
622 | dprintk("%s: done, status = %d\n", __func__, ntohl(status)); | 672 | dprintk("%s: done, status = %d\n", __func__, ntohl(status)); |
@@ -632,7 +682,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
632 | struct cb_compound_hdr_res hdr_res = { NULL }; | 682 | struct cb_compound_hdr_res hdr_res = { NULL }; |
633 | struct xdr_stream xdr_in, xdr_out; | 683 | struct xdr_stream xdr_in, xdr_out; |
634 | __be32 *p; | 684 | __be32 *p; |
635 | __be32 status; | 685 | __be32 status, drc_status = 0; |
636 | unsigned int nops = 0; | 686 | unsigned int nops = 0; |
637 | 687 | ||
638 | dprintk("%s: start\n", __func__); | 688 | dprintk("%s: start\n", __func__); |
@@ -652,11 +702,18 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
652 | return rpc_system_err; | 702 | return rpc_system_err; |
653 | 703 | ||
654 | while (status == 0 && nops != hdr_arg.nops) { | 704 | while (status == 0 && nops != hdr_arg.nops) { |
655 | status = process_op(hdr_arg.minorversion, nops, | 705 | status = process_op(hdr_arg.minorversion, nops, rqstp, |
656 | rqstp, &xdr_in, argp, &xdr_out, resp); | 706 | &xdr_in, argp, &xdr_out, resp, &drc_status); |
657 | nops++; | 707 | nops++; |
658 | } | 708 | } |
659 | 709 | ||
710 | /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return | ||
711 | * resource error in cb_compound status without returning op */ | ||
712 | if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) { | ||
713 | status = htonl(NFS4ERR_RESOURCE); | ||
714 | nops--; | ||
715 | } | ||
716 | |||
660 | *hdr_res.status = status; | 717 | *hdr_res.status = status; |
661 | *hdr_res.nops = htonl(nops); | 718 | *hdr_res.nops = htonl(nops); |
662 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); | 719 | dprintk("%s: done, status = %u\n", __func__, ntohl(status)); |
@@ -688,6 +745,16 @@ static struct callback_op callback_ops[] = { | |||
688 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, | 745 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, |
689 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, | 746 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, |
690 | }, | 747 | }, |
748 | [OP_CB_RECALL_ANY] = { | ||
749 | .process_op = (callback_process_op_t)nfs4_callback_recallany, | ||
750 | .decode_args = (callback_decode_arg_t)decode_recallany_args, | ||
751 | .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, | ||
752 | }, | ||
753 | [OP_CB_RECALL_SLOT] = { | ||
754 | .process_op = (callback_process_op_t)nfs4_callback_recallslot, | ||
755 | .decode_args = (callback_decode_arg_t)decode_recallslot_args, | ||
756 | .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ, | ||
757 | }, | ||
691 | #endif /* CONFIG_NFS_V4_1 */ | 758 | #endif /* CONFIG_NFS_V4_1 */ |
692 | }; | 759 | }; |
693 | 760 | ||
@@ -716,5 +783,13 @@ struct svc_version nfs4_callback_version1 = { | |||
716 | .vs_proc = nfs4_callback_procedures1, | 783 | .vs_proc = nfs4_callback_procedures1, |
717 | .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, | 784 | .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, |
718 | .vs_dispatch = NULL, | 785 | .vs_dispatch = NULL, |
786 | .vs_hidden = 1, | ||
719 | }; | 787 | }; |
720 | 788 | ||
789 | struct svc_version nfs4_callback_version4 = { | ||
790 | .vs_vers = 4, | ||
791 | .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), | ||
792 | .vs_proc = nfs4_callback_procedures1, | ||
793 | .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, | ||
794 | .vs_dispatch = NULL, | ||
795 | }; | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 99ea196f071f..acc9c4943b84 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
36 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <linux/slab.h> | ||
38 | #include <net/ipv6.h> | 39 | #include <net/ipv6.h> |
39 | #include <linux/nfs_xdr.h> | 40 | #include <linux/nfs_xdr.h> |
40 | #include <linux/sunrpc/bc_xprt.h> | 41 | #include <linux/sunrpc/bc_xprt.h> |
@@ -164,30 +165,7 @@ error_0: | |||
164 | return ERR_PTR(err); | 165 | return ERR_PTR(err); |
165 | } | 166 | } |
166 | 167 | ||
167 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
168 | { | ||
169 | #ifdef CONFIG_NFS_V4 | 168 | #ifdef CONFIG_NFS_V4 |
170 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
171 | nfs4_kill_renewd(clp); | ||
172 | BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners)); | ||
173 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
174 | nfs_idmap_delete(clp); | ||
175 | |||
176 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
177 | #endif | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Destroy the NFS4 callback service | ||
182 | */ | ||
183 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
184 | { | ||
185 | #ifdef CONFIG_NFS_V4 | ||
186 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
187 | nfs_callback_down(clp->cl_minorversion); | ||
188 | #endif /* CONFIG_NFS_V4 */ | ||
189 | } | ||
190 | |||
191 | /* | 169 | /* |
192 | * Clears/puts all minor version specific parts from an nfs_client struct | 170 | * Clears/puts all minor version specific parts from an nfs_client struct |
193 | * reverting it to minorversion 0. | 171 | * reverting it to minorversion 0. |
@@ -202,9 +180,33 @@ static void nfs4_clear_client_minor_version(struct nfs_client *clp) | |||
202 | 180 | ||
203 | clp->cl_call_sync = _nfs4_call_sync; | 181 | clp->cl_call_sync = _nfs4_call_sync; |
204 | #endif /* CONFIG_NFS_V4_1 */ | 182 | #endif /* CONFIG_NFS_V4_1 */ |
183 | } | ||
205 | 184 | ||
185 | /* | ||
186 | * Destroy the NFS4 callback service | ||
187 | */ | ||
188 | static void nfs4_destroy_callback(struct nfs_client *clp) | ||
189 | { | ||
190 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
191 | nfs_callback_down(clp->cl_minorversion); | ||
192 | } | ||
193 | |||
194 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
195 | { | ||
196 | if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) | ||
197 | nfs4_kill_renewd(clp); | ||
198 | nfs4_clear_client_minor_version(clp); | ||
206 | nfs4_destroy_callback(clp); | 199 | nfs4_destroy_callback(clp); |
200 | if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) | ||
201 | nfs_idmap_delete(clp); | ||
202 | |||
203 | rpc_destroy_wait_queue(&clp->cl_rpcwaitq); | ||
204 | } | ||
205 | #else | ||
206 | static void nfs4_shutdown_client(struct nfs_client *clp) | ||
207 | { | ||
207 | } | 208 | } |
209 | #endif /* CONFIG_NFS_V4 */ | ||
208 | 210 | ||
209 | /* | 211 | /* |
210 | * Destroy a shared client record | 212 | * Destroy a shared client record |
@@ -213,7 +215,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
213 | { | 215 | { |
214 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 216 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
215 | 217 | ||
216 | nfs4_clear_client_minor_version(clp); | ||
217 | nfs4_shutdown_client(clp); | 218 | nfs4_shutdown_client(clp); |
218 | 219 | ||
219 | nfs_fscache_release_client_cookie(clp); | 220 | nfs_fscache_release_client_cookie(clp); |
@@ -965,6 +966,8 @@ out_error: | |||
965 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) | 966 | static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) |
966 | { | 967 | { |
967 | target->flags = source->flags; | 968 | target->flags = source->flags; |
969 | target->rsize = source->rsize; | ||
970 | target->wsize = source->wsize; | ||
968 | target->acregmin = source->acregmin; | 971 | target->acregmin = source->acregmin; |
969 | target->acregmax = source->acregmax; | 972 | target->acregmax = source->acregmax; |
970 | target->acdirmin = source->acdirmin; | 973 | target->acdirmin = source->acdirmin; |
@@ -1260,10 +1263,20 @@ error: | |||
1260 | static void nfs4_session_set_rwsize(struct nfs_server *server) | 1263 | static void nfs4_session_set_rwsize(struct nfs_server *server) |
1261 | { | 1264 | { |
1262 | #ifdef CONFIG_NFS_V4_1 | 1265 | #ifdef CONFIG_NFS_V4_1 |
1266 | struct nfs4_session *sess; | ||
1267 | u32 server_resp_sz; | ||
1268 | u32 server_rqst_sz; | ||
1269 | |||
1263 | if (!nfs4_has_session(server->nfs_client)) | 1270 | if (!nfs4_has_session(server->nfs_client)) |
1264 | return; | 1271 | return; |
1265 | server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | 1272 | sess = server->nfs_client->cl_session; |
1266 | server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; | 1273 | server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead; |
1274 | server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead; | ||
1275 | |||
1276 | if (server->rsize > server_resp_sz) | ||
1277 | server->rsize = server_resp_sz; | ||
1278 | if (server->wsize > server_rqst_sz) | ||
1279 | server->wsize = server_rqst_sz; | ||
1267 | #endif /* CONFIG_NFS_V4_1 */ | 1280 | #endif /* CONFIG_NFS_V4_1 */ |
1268 | } | 1281 | } |
1269 | 1282 | ||
@@ -1283,7 +1296,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1283 | 1296 | ||
1284 | /* Initialise the client representation from the mount data */ | 1297 | /* Initialise the client representation from the mount data */ |
1285 | server->flags = data->flags; | 1298 | server->flags = data->flags; |
1286 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR; | 1299 | server->caps |= NFS_CAP_ATOMIC_OPEN|NFS_CAP_CHANGE_ATTR| |
1300 | NFS_CAP_POSIX_LOCK; | ||
1287 | server->options = data->options; | 1301 | server->options = data->options; |
1288 | 1302 | ||
1289 | /* Get a client record */ | 1303 | /* Get a client record */ |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 6dd48a4405b4..ea61d26e7871 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/kthread.h> | 10 | #include <linux/kthread.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/smp_lock.h> | 14 | #include <linux/smp_lock.h> |
14 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
15 | 16 | ||
@@ -23,6 +24,8 @@ | |||
23 | 24 | ||
24 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) | 25 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) |
25 | { | 26 | { |
27 | if (delegation->cred) | ||
28 | put_rpccred(delegation->cred); | ||
26 | kfree(delegation); | 29 | kfree(delegation); |
27 | } | 30 | } |
28 | 31 | ||
@@ -35,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head) | |||
35 | 38 | ||
36 | static void nfs_free_delegation(struct nfs_delegation *delegation) | 39 | static void nfs_free_delegation(struct nfs_delegation *delegation) |
37 | { | 40 | { |
38 | struct rpc_cred *cred; | ||
39 | |||
40 | cred = rcu_dereference(delegation->cred); | ||
41 | rcu_assign_pointer(delegation->cred, NULL); | ||
42 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | 41 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); |
43 | if (cred) | ||
44 | put_rpccred(cred); | ||
45 | } | 42 | } |
46 | 43 | ||
47 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | 44 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) |
@@ -92,7 +89,7 @@ out: | |||
92 | return status; | 89 | return status; |
93 | } | 90 | } |
94 | 91 | ||
95 | static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) | 92 | static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid) |
96 | { | 93 | { |
97 | struct nfs_inode *nfsi = NFS_I(inode); | 94 | struct nfs_inode *nfsi = NFS_I(inode); |
98 | struct nfs_open_context *ctx; | 95 | struct nfs_open_context *ctx; |
@@ -116,10 +113,11 @@ again: | |||
116 | err = nfs_delegation_claim_locks(ctx, state); | 113 | err = nfs_delegation_claim_locks(ctx, state); |
117 | put_nfs_open_context(ctx); | 114 | put_nfs_open_context(ctx); |
118 | if (err != 0) | 115 | if (err != 0) |
119 | return; | 116 | return err; |
120 | goto again; | 117 | goto again; |
121 | } | 118 | } |
122 | spin_unlock(&inode->i_lock); | 119 | spin_unlock(&inode->i_lock); |
120 | return 0; | ||
123 | } | 121 | } |
124 | 122 | ||
125 | /* | 123 | /* |
@@ -127,21 +125,35 @@ again: | |||
127 | */ | 125 | */ |
128 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) | 126 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res) |
129 | { | 127 | { |
130 | struct nfs_delegation *delegation = NFS_I(inode)->delegation; | 128 | struct nfs_delegation *delegation; |
131 | struct rpc_cred *oldcred; | 129 | struct rpc_cred *oldcred = NULL; |
132 | 130 | ||
133 | if (delegation == NULL) | 131 | rcu_read_lock(); |
134 | return; | 132 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
135 | memcpy(delegation->stateid.data, res->delegation.data, | 133 | if (delegation != NULL) { |
136 | sizeof(delegation->stateid.data)); | 134 | spin_lock(&delegation->lock); |
137 | delegation->type = res->delegation_type; | 135 | if (delegation->inode != NULL) { |
138 | delegation->maxsize = res->maxsize; | 136 | memcpy(delegation->stateid.data, res->delegation.data, |
139 | oldcred = delegation->cred; | 137 | sizeof(delegation->stateid.data)); |
140 | delegation->cred = get_rpccred(cred); | 138 | delegation->type = res->delegation_type; |
141 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); | 139 | delegation->maxsize = res->maxsize; |
142 | NFS_I(inode)->delegation_state = delegation->type; | 140 | oldcred = delegation->cred; |
143 | smp_wmb(); | 141 | delegation->cred = get_rpccred(cred); |
144 | put_rpccred(oldcred); | 142 | clear_bit(NFS_DELEGATION_NEED_RECLAIM, |
143 | &delegation->flags); | ||
144 | NFS_I(inode)->delegation_state = delegation->type; | ||
145 | spin_unlock(&delegation->lock); | ||
146 | put_rpccred(oldcred); | ||
147 | rcu_read_unlock(); | ||
148 | } else { | ||
149 | /* We appear to have raced with a delegation return. */ | ||
150 | spin_unlock(&delegation->lock); | ||
151 | rcu_read_unlock(); | ||
152 | nfs_inode_set_delegation(inode, cred, res); | ||
153 | } | ||
154 | } else { | ||
155 | rcu_read_unlock(); | ||
156 | } | ||
145 | } | 157 | } |
146 | 158 | ||
147 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) | 159 | static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) |
@@ -164,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation | |||
164 | return inode; | 176 | return inode; |
165 | } | 177 | } |
166 | 178 | ||
167 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | 179 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, |
180 | const nfs4_stateid *stateid, | ||
181 | struct nfs_client *clp) | ||
168 | { | 182 | { |
169 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | 183 | struct nfs_delegation *delegation = |
184 | rcu_dereference_protected(nfsi->delegation, | ||
185 | lockdep_is_held(&clp->cl_lock)); | ||
170 | 186 | ||
171 | if (delegation == NULL) | 187 | if (delegation == NULL) |
172 | goto nomatch; | 188 | goto nomatch; |
@@ -193,7 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
193 | { | 209 | { |
194 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 210 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
195 | struct nfs_inode *nfsi = NFS_I(inode); | 211 | struct nfs_inode *nfsi = NFS_I(inode); |
196 | struct nfs_delegation *delegation; | 212 | struct nfs_delegation *delegation, *old_delegation; |
197 | struct nfs_delegation *freeme = NULL; | 213 | struct nfs_delegation *freeme = NULL; |
198 | int status = 0; | 214 | int status = 0; |
199 | 215 | ||
@@ -211,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
211 | spin_lock_init(&delegation->lock); | 227 | spin_lock_init(&delegation->lock); |
212 | 228 | ||
213 | spin_lock(&clp->cl_lock); | 229 | spin_lock(&clp->cl_lock); |
214 | if (rcu_dereference(nfsi->delegation) != NULL) { | 230 | old_delegation = rcu_dereference_protected(nfsi->delegation, |
215 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, | 231 | lockdep_is_held(&clp->cl_lock)); |
216 | sizeof(delegation->stateid)) == 0 && | 232 | if (old_delegation != NULL) { |
217 | delegation->type == nfsi->delegation->type) { | 233 | if (memcmp(&delegation->stateid, &old_delegation->stateid, |
234 | sizeof(old_delegation->stateid)) == 0 && | ||
235 | delegation->type == old_delegation->type) { | ||
218 | goto out; | 236 | goto out; |
219 | } | 237 | } |
220 | /* | 238 | /* |
@@ -224,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
224 | dfprintk(FILE, "%s: server %s handed out " | 242 | dfprintk(FILE, "%s: server %s handed out " |
225 | "a duplicate delegation!\n", | 243 | "a duplicate delegation!\n", |
226 | __func__, clp->cl_hostname); | 244 | __func__, clp->cl_hostname); |
227 | if (delegation->type <= nfsi->delegation->type) { | 245 | if (delegation->type <= old_delegation->type) { |
228 | freeme = delegation; | 246 | freeme = delegation; |
229 | delegation = NULL; | 247 | delegation = NULL; |
230 | goto out; | 248 | goto out; |
231 | } | 249 | } |
232 | freeme = nfs_detach_delegation_locked(nfsi, NULL); | 250 | freeme = nfs_detach_delegation_locked(nfsi, NULL, clp); |
233 | } | 251 | } |
234 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | 252 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); |
235 | nfsi->delegation_state = delegation->type; | 253 | nfsi->delegation_state = delegation->type; |
@@ -261,30 +279,34 @@ static void nfs_msync_inode(struct inode *inode) | |||
261 | /* | 279 | /* |
262 | * Basic procedure for returning a delegation to the server | 280 | * Basic procedure for returning a delegation to the server |
263 | */ | 281 | */ |
264 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation) | 282 | static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync) |
265 | { | 283 | { |
266 | struct nfs_inode *nfsi = NFS_I(inode); | 284 | struct nfs_inode *nfsi = NFS_I(inode); |
285 | int err; | ||
267 | 286 | ||
268 | nfs_msync_inode(inode); | ||
269 | /* | 287 | /* |
270 | * Guard against new delegated open/lock/unlock calls and against | 288 | * Guard against new delegated open/lock/unlock calls and against |
271 | * state recovery | 289 | * state recovery |
272 | */ | 290 | */ |
273 | down_write(&nfsi->rwsem); | 291 | down_write(&nfsi->rwsem); |
274 | nfs_delegation_claim_opens(inode, &delegation->stateid); | 292 | err = nfs_delegation_claim_opens(inode, &delegation->stateid); |
275 | up_write(&nfsi->rwsem); | 293 | up_write(&nfsi->rwsem); |
276 | nfs_msync_inode(inode); | 294 | if (err) |
295 | goto out; | ||
277 | 296 | ||
278 | return nfs_do_return_delegation(inode, delegation, 1); | 297 | err = nfs_do_return_delegation(inode, delegation, issync); |
298 | out: | ||
299 | return err; | ||
279 | } | 300 | } |
280 | 301 | ||
281 | /* | 302 | /* |
282 | * Return all delegations that have been marked for return | 303 | * Return all delegations that have been marked for return |
283 | */ | 304 | */ |
284 | void nfs_client_return_marked_delegations(struct nfs_client *clp) | 305 | int nfs_client_return_marked_delegations(struct nfs_client *clp) |
285 | { | 306 | { |
286 | struct nfs_delegation *delegation; | 307 | struct nfs_delegation *delegation; |
287 | struct inode *inode; | 308 | struct inode *inode; |
309 | int err = 0; | ||
288 | 310 | ||
289 | restart: | 311 | restart: |
290 | rcu_read_lock(); | 312 | rcu_read_lock(); |
@@ -295,15 +317,21 @@ restart: | |||
295 | if (inode == NULL) | 317 | if (inode == NULL) |
296 | continue; | 318 | continue; |
297 | spin_lock(&clp->cl_lock); | 319 | spin_lock(&clp->cl_lock); |
298 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 320 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); |
299 | spin_unlock(&clp->cl_lock); | 321 | spin_unlock(&clp->cl_lock); |
300 | rcu_read_unlock(); | 322 | rcu_read_unlock(); |
301 | if (delegation != NULL) | 323 | if (delegation != NULL) { |
302 | __nfs_inode_return_delegation(inode, delegation); | 324 | filemap_flush(inode->i_mapping); |
325 | err = __nfs_inode_return_delegation(inode, delegation, 0); | ||
326 | } | ||
303 | iput(inode); | 327 | iput(inode); |
304 | goto restart; | 328 | if (!err) |
329 | goto restart; | ||
330 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | ||
331 | return err; | ||
305 | } | 332 | } |
306 | rcu_read_unlock(); | 333 | rcu_read_unlock(); |
334 | return 0; | ||
307 | } | 335 | } |
308 | 336 | ||
309 | /* | 337 | /* |
@@ -318,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) | |||
318 | struct nfs_inode *nfsi = NFS_I(inode); | 346 | struct nfs_inode *nfsi = NFS_I(inode); |
319 | struct nfs_delegation *delegation; | 347 | struct nfs_delegation *delegation; |
320 | 348 | ||
321 | if (rcu_dereference(nfsi->delegation) != NULL) { | 349 | if (rcu_access_pointer(nfsi->delegation) != NULL) { |
322 | spin_lock(&clp->cl_lock); | 350 | spin_lock(&clp->cl_lock); |
323 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 351 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
324 | spin_unlock(&clp->cl_lock); | 352 | spin_unlock(&clp->cl_lock); |
325 | if (delegation != NULL) | 353 | if (delegation != NULL) |
326 | nfs_do_return_delegation(inode, delegation, 0); | 354 | nfs_do_return_delegation(inode, delegation, 0); |
@@ -334,12 +362,14 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
334 | struct nfs_delegation *delegation; | 362 | struct nfs_delegation *delegation; |
335 | int err = 0; | 363 | int err = 0; |
336 | 364 | ||
337 | if (rcu_dereference(nfsi->delegation) != NULL) { | 365 | if (rcu_access_pointer(nfsi->delegation) != NULL) { |
338 | spin_lock(&clp->cl_lock); | 366 | spin_lock(&clp->cl_lock); |
339 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 367 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
340 | spin_unlock(&clp->cl_lock); | 368 | spin_unlock(&clp->cl_lock); |
341 | if (delegation != NULL) | 369 | if (delegation != NULL) { |
342 | err = __nfs_inode_return_delegation(inode, delegation); | 370 | nfs_msync_inode(inode); |
371 | err = __nfs_inode_return_delegation(inode, delegation, 1); | ||
372 | } | ||
343 | } | 373 | } |
344 | return err; | 374 | return err; |
345 | } | 375 | } |
@@ -368,33 +398,47 @@ void nfs_super_return_all_delegations(struct super_block *sb) | |||
368 | spin_unlock(&delegation->lock); | 398 | spin_unlock(&delegation->lock); |
369 | } | 399 | } |
370 | rcu_read_unlock(); | 400 | rcu_read_unlock(); |
371 | nfs_client_return_marked_delegations(clp); | 401 | if (nfs_client_return_marked_delegations(clp) != 0) |
402 | nfs4_schedule_state_manager(clp); | ||
372 | } | 403 | } |
373 | 404 | ||
374 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) | 405 | static |
406 | void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp, fmode_t flags) | ||
375 | { | 407 | { |
376 | struct nfs_delegation *delegation; | 408 | struct nfs_delegation *delegation; |
377 | 409 | ||
378 | rcu_read_lock(); | 410 | rcu_read_lock(); |
379 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 411 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
380 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | 412 | if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) |
381 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | 413 | continue; |
414 | if (delegation->type & flags) | ||
415 | nfs_mark_return_delegation(clp, delegation); | ||
382 | } | 416 | } |
383 | rcu_read_unlock(); | 417 | rcu_read_unlock(); |
384 | } | 418 | } |
385 | 419 | ||
420 | static void nfs_client_mark_return_all_delegations(struct nfs_client *clp) | ||
421 | { | ||
422 | nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | ||
423 | } | ||
424 | |||
386 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) | 425 | static void nfs_delegation_run_state_manager(struct nfs_client *clp) |
387 | { | 426 | { |
388 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) | 427 | if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) |
389 | nfs4_schedule_state_manager(clp); | 428 | nfs4_schedule_state_manager(clp); |
390 | } | 429 | } |
391 | 430 | ||
392 | void nfs_expire_all_delegations(struct nfs_client *clp) | 431 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags) |
393 | { | 432 | { |
394 | nfs_client_mark_return_all_delegations(clp); | 433 | nfs_client_mark_return_all_delegation_types(clp, flags); |
395 | nfs_delegation_run_state_manager(clp); | 434 | nfs_delegation_run_state_manager(clp); |
396 | } | 435 | } |
397 | 436 | ||
437 | void nfs_expire_all_delegations(struct nfs_client *clp) | ||
438 | { | ||
439 | nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE); | ||
440 | } | ||
441 | |||
398 | /* | 442 | /* |
399 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. | 443 | * Return all delegations following an NFS4ERR_CB_PATH_DOWN error. |
400 | */ | 444 | */ |
@@ -413,8 +457,7 @@ static void nfs_client_mark_return_unreferenced_delegations(struct nfs_client *c | |||
413 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 457 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
414 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) | 458 | if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) |
415 | continue; | 459 | continue; |
416 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | 460 | nfs_mark_return_delegation(clp, delegation); |
417 | set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); | ||
418 | } | 461 | } |
419 | rcu_read_unlock(); | 462 | rcu_read_unlock(); |
420 | } | 463 | } |
@@ -428,18 +471,21 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) | |||
428 | /* | 471 | /* |
429 | * Asynchronous delegation recall! | 472 | * Asynchronous delegation recall! |
430 | */ | 473 | */ |
431 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) | 474 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, |
475 | int (*validate_stateid)(struct nfs_delegation *delegation, | ||
476 | const nfs4_stateid *stateid)) | ||
432 | { | 477 | { |
433 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 478 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
434 | struct nfs_delegation *delegation; | 479 | struct nfs_delegation *delegation; |
435 | 480 | ||
436 | rcu_read_lock(); | 481 | rcu_read_lock(); |
437 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 482 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
438 | if (delegation == NULL || memcmp(delegation->stateid.data, stateid->data, | 483 | |
439 | sizeof(delegation->stateid.data)) != 0) { | 484 | if (!validate_stateid(delegation, stateid)) { |
440 | rcu_read_unlock(); | 485 | rcu_read_unlock(); |
441 | return -ENOENT; | 486 | return -ENOENT; |
442 | } | 487 | } |
488 | |||
443 | nfs_mark_return_delegation(clp, delegation); | 489 | nfs_mark_return_delegation(clp, delegation); |
444 | rcu_read_unlock(); | 490 | rcu_read_unlock(); |
445 | nfs_delegation_run_state_manager(clp); | 491 | nfs_delegation_run_state_manager(clp); |
@@ -496,7 +542,7 @@ restart: | |||
496 | if (inode == NULL) | 542 | if (inode == NULL) |
497 | continue; | 543 | continue; |
498 | spin_lock(&clp->cl_lock); | 544 | spin_lock(&clp->cl_lock); |
499 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 545 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); |
500 | spin_unlock(&clp->cl_lock); | 546 | spin_unlock(&clp->cl_lock); |
501 | rcu_read_unlock(); | 547 | rcu_read_unlock(); |
502 | if (delegation != NULL) | 548 | if (delegation != NULL) |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 09f383795174..69e7b8140122 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -34,15 +34,18 @@ enum { | |||
34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 35 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
36 | int nfs_inode_return_delegation(struct inode *inode); | 36 | int nfs_inode_return_delegation(struct inode *inode); |
37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid); | 37 | int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid, |
38 | int (*validate_stateid)(struct nfs_delegation *delegation, | ||
39 | const nfs4_stateid *stateid)); | ||
38 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 40 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
39 | 41 | ||
40 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 42 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
41 | void nfs_super_return_all_delegations(struct super_block *sb); | 43 | void nfs_super_return_all_delegations(struct super_block *sb); |
42 | void nfs_expire_all_delegations(struct nfs_client *clp); | 44 | void nfs_expire_all_delegations(struct nfs_client *clp); |
45 | void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags); | ||
43 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); | 46 | void nfs_expire_unreferenced_delegations(struct nfs_client *clp); |
44 | void nfs_handle_cb_pathdown(struct nfs_client *clp); | 47 | void nfs_handle_cb_pathdown(struct nfs_client *clp); |
45 | void nfs_client_return_marked_delegations(struct nfs_client *clp); | 48 | int nfs_client_return_marked_delegations(struct nfs_client *clp); |
46 | 49 | ||
47 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); | 50 | void nfs_delegation_mark_reclaim(struct nfs_client *clp); |
48 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); | 51 | void nfs_delegation_reap_unclaimed(struct nfs_client *clp); |
@@ -68,4 +71,10 @@ static inline int nfs_inode_return_delegation(struct inode *inode) | |||
68 | } | 71 | } |
69 | #endif | 72 | #endif |
70 | 73 | ||
74 | static inline int nfs_have_delegated_attributes(struct inode *inode) | ||
75 | { | ||
76 | return nfs_have_delegation(inode, FMODE_READ) && | ||
77 | !(NFS_I(inode)->cache_validity & NFS_INO_REVAL_FORCED); | ||
78 | } | ||
79 | |||
71 | #endif | 80 | #endif |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 7cb298525eef..a7bb5c694aa3 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -560,7 +560,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
560 | desc->entry = &my_entry; | 560 | desc->entry = &my_entry; |
561 | 561 | ||
562 | nfs_block_sillyrename(dentry); | 562 | nfs_block_sillyrename(dentry); |
563 | res = nfs_revalidate_mapping_nolock(inode, filp->f_mapping); | 563 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
564 | if (res < 0) | 564 | if (res < 0) |
565 | goto out; | 565 | goto out; |
566 | 566 | ||
@@ -837,6 +837,8 @@ out_zap_parent: | |||
837 | /* If we have submounts, don't unhash ! */ | 837 | /* If we have submounts, don't unhash ! */ |
838 | if (have_submounts(dentry)) | 838 | if (have_submounts(dentry)) |
839 | goto out_valid; | 839 | goto out_valid; |
840 | if (dentry->d_flags & DCACHE_DISCONNECTED) | ||
841 | goto out_valid; | ||
840 | shrink_dcache_parent(dentry); | 842 | shrink_dcache_parent(dentry); |
841 | } | 843 | } |
842 | d_drop(dentry); | 844 | d_drop(dentry); |
@@ -1025,12 +1027,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1025 | res = NULL; | 1027 | res = NULL; |
1026 | goto out; | 1028 | goto out; |
1027 | /* This turned out not to be a regular file */ | 1029 | /* This turned out not to be a regular file */ |
1030 | case -EISDIR: | ||
1028 | case -ENOTDIR: | 1031 | case -ENOTDIR: |
1029 | goto no_open; | 1032 | goto no_open; |
1030 | case -ELOOP: | 1033 | case -ELOOP: |
1031 | if (!(nd->intent.open.flags & O_NOFOLLOW)) | 1034 | if (!(nd->intent.open.flags & O_NOFOLLOW)) |
1032 | goto no_open; | 1035 | goto no_open; |
1033 | /* case -EISDIR: */ | ||
1034 | /* case -EINVAL: */ | 1036 | /* case -EINVAL: */ |
1035 | default: | 1037 | default: |
1036 | goto out; | 1038 | goto out; |
@@ -1050,7 +1052,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1050 | struct inode *dir; | 1052 | struct inode *dir; |
1051 | int openflags, ret = 0; | 1053 | int openflags, ret = 0; |
1052 | 1054 | ||
1053 | if (!is_atomic_open(nd)) | 1055 | if (!is_atomic_open(nd) || d_mountpoint(dentry)) |
1054 | goto no_open; | 1056 | goto no_open; |
1055 | parent = dget_parent(dentry); | 1057 | parent = dget_parent(dentry); |
1056 | dir = parent->d_inode; | 1058 | dir = parent->d_inode; |
@@ -1579,55 +1581,47 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1579 | struct dentry *dentry = NULL, *rehash = NULL; | 1581 | struct dentry *dentry = NULL, *rehash = NULL; |
1580 | int error = -EBUSY; | 1582 | int error = -EBUSY; |
1581 | 1583 | ||
1582 | /* | ||
1583 | * To prevent any new references to the target during the rename, | ||
1584 | * we unhash the dentry and free the inode in advance. | ||
1585 | */ | ||
1586 | if (!d_unhashed(new_dentry)) { | ||
1587 | d_drop(new_dentry); | ||
1588 | rehash = new_dentry; | ||
1589 | } | ||
1590 | |||
1591 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", | 1584 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", |
1592 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1585 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1593 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, | 1586 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, |
1594 | atomic_read(&new_dentry->d_count)); | 1587 | atomic_read(&new_dentry->d_count)); |
1595 | 1588 | ||
1596 | /* | 1589 | /* |
1597 | * First check whether the target is busy ... we can't | 1590 | * For non-directories, check whether the target is busy and if so, |
1598 | * safely do _any_ rename if the target is in use. | 1591 | * make a copy of the dentry and then do a silly-rename. If the |
1599 | * | 1592 | * silly-rename succeeds, the copied dentry is hashed and becomes |
1600 | * For files, make a copy of the dentry and then do a | 1593 | * the new target. |
1601 | * silly-rename. If the silly-rename succeeds, the | ||
1602 | * copied dentry is hashed and becomes the new target. | ||
1603 | */ | 1594 | */ |
1604 | if (!new_inode) | 1595 | if (new_inode && !S_ISDIR(new_inode->i_mode)) { |
1605 | goto go_ahead; | 1596 | /* |
1606 | if (S_ISDIR(new_inode->i_mode)) { | 1597 | * To prevent any new references to the target during the |
1607 | error = -EISDIR; | 1598 | * rename, we unhash the dentry in advance. |
1608 | if (!S_ISDIR(old_inode->i_mode)) | 1599 | */ |
1609 | goto out; | 1600 | if (!d_unhashed(new_dentry)) { |
1610 | } else if (atomic_read(&new_dentry->d_count) > 2) { | 1601 | d_drop(new_dentry); |
1611 | int err; | 1602 | rehash = new_dentry; |
1612 | /* copy the target dentry's name */ | 1603 | } |
1613 | dentry = d_alloc(new_dentry->d_parent, | 1604 | |
1614 | &new_dentry->d_name); | 1605 | if (atomic_read(&new_dentry->d_count) > 2) { |
1615 | if (!dentry) | 1606 | int err; |
1616 | goto out; | 1607 | |
1608 | /* copy the target dentry's name */ | ||
1609 | dentry = d_alloc(new_dentry->d_parent, | ||
1610 | &new_dentry->d_name); | ||
1611 | if (!dentry) | ||
1612 | goto out; | ||
1617 | 1613 | ||
1618 | /* silly-rename the existing target ... */ | 1614 | /* silly-rename the existing target ... */ |
1619 | err = nfs_sillyrename(new_dir, new_dentry); | 1615 | err = nfs_sillyrename(new_dir, new_dentry); |
1620 | if (!err) { | 1616 | if (err) |
1621 | new_dentry = rehash = dentry; | 1617 | goto out; |
1618 | |||
1619 | new_dentry = dentry; | ||
1620 | rehash = NULL; | ||
1622 | new_inode = NULL; | 1621 | new_inode = NULL; |
1623 | /* instantiate the replacement target */ | 1622 | } |
1624 | d_instantiate(new_dentry, NULL); | ||
1625 | } else if (atomic_read(&new_dentry->d_count) > 1) | ||
1626 | /* dentry still busy? */ | ||
1627 | goto out; | ||
1628 | } | 1623 | } |
1629 | 1624 | ||
1630 | go_ahead: | ||
1631 | /* | 1625 | /* |
1632 | * ... prune child dentries and writebacks if needed. | 1626 | * ... prune child dentries and writebacks if needed. |
1633 | */ | 1627 | */ |
@@ -1797,7 +1791,7 @@ static int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, str | |||
1797 | cache = nfs_access_search_rbtree(inode, cred); | 1791 | cache = nfs_access_search_rbtree(inode, cred); |
1798 | if (cache == NULL) | 1792 | if (cache == NULL) |
1799 | goto out; | 1793 | goto out; |
1800 | if (!nfs_have_delegation(inode, FMODE_READ) && | 1794 | if (!nfs_have_delegated_attributes(inode) && |
1801 | !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) | 1795 | !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) |
1802 | goto out_stale; | 1796 | goto out_stale; |
1803 | res->jiffies = cache->jiffies; | 1797 | res->jiffies = cache->jiffies; |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index e1d415e97849..ad4cd31d6050 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/file.h> | 44 | #include <linux/file.h> |
45 | #include <linux/pagemap.h> | 45 | #include <linux/pagemap.h> |
46 | #include <linux/kref.h> | 46 | #include <linux/kref.h> |
47 | #include <linux/slab.h> | ||
47 | 48 | ||
48 | #include <linux/nfs_fs.h> | 49 | #include <linux/nfs_fs.h> |
49 | #include <linux/nfs_page.h> | 50 | #include <linux/nfs_page.h> |
@@ -342,6 +343,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq, | |||
342 | data->res.fattr = &data->fattr; | 343 | data->res.fattr = &data->fattr; |
343 | data->res.eof = 0; | 344 | data->res.eof = 0; |
344 | data->res.count = bytes; | 345 | data->res.count = bytes; |
346 | nfs_fattr_init(&data->fattr); | ||
345 | msg.rpc_argp = &data->args; | 347 | msg.rpc_argp = &data->args; |
346 | msg.rpc_resp = &data->res; | 348 | msg.rpc_resp = &data->res; |
347 | 349 | ||
@@ -575,6 +577,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | |||
575 | data->res.count = 0; | 577 | data->res.count = 0; |
576 | data->res.fattr = &data->fattr; | 578 | data->res.fattr = &data->fattr; |
577 | data->res.verf = &data->verf; | 579 | data->res.verf = &data->verf; |
580 | nfs_fattr_init(&data->fattr); | ||
578 | 581 | ||
579 | NFS_PROTO(data->inode)->commit_setup(data, &msg); | 582 | NFS_PROTO(data->inode)->commit_setup(data, &msg); |
580 | 583 | ||
@@ -766,6 +769,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq, | |||
766 | data->res.fattr = &data->fattr; | 769 | data->res.fattr = &data->fattr; |
767 | data->res.count = bytes; | 770 | data->res.count = bytes; |
768 | data->res.verf = &data->verf; | 771 | data->res.verf = &data->verf; |
772 | nfs_fattr_init(&data->fattr); | ||
769 | 773 | ||
770 | task_setup_data.task = &data->task; | 774 | task_setup_data.task = &data->task; |
771 | task_setup_data.callback_data = data; | 775 | task_setup_data.callback_data = data; |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index f4d54ba97cc6..76fd235d0024 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/hash.h> | 9 | #include <linux/hash.h> |
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/kmod.h> | 11 | #include <linux/kmod.h> |
12 | #include <linux/slab.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/socket.h> | 14 | #include <linux/socket.h> |
14 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
@@ -36,6 +37,19 @@ struct nfs_dns_ent { | |||
36 | }; | 37 | }; |
37 | 38 | ||
38 | 39 | ||
40 | static void nfs_dns_ent_update(struct cache_head *cnew, | ||
41 | struct cache_head *ckey) | ||
42 | { | ||
43 | struct nfs_dns_ent *new; | ||
44 | struct nfs_dns_ent *key; | ||
45 | |||
46 | new = container_of(cnew, struct nfs_dns_ent, h); | ||
47 | key = container_of(ckey, struct nfs_dns_ent, h); | ||
48 | |||
49 | memcpy(&new->addr, &key->addr, key->addrlen); | ||
50 | new->addrlen = key->addrlen; | ||
51 | } | ||
52 | |||
39 | static void nfs_dns_ent_init(struct cache_head *cnew, | 53 | static void nfs_dns_ent_init(struct cache_head *cnew, |
40 | struct cache_head *ckey) | 54 | struct cache_head *ckey) |
41 | { | 55 | { |
@@ -49,8 +63,7 @@ static void nfs_dns_ent_init(struct cache_head *cnew, | |||
49 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); | 63 | new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); |
50 | if (new->hostname) { | 64 | if (new->hostname) { |
51 | new->namelen = key->namelen; | 65 | new->namelen = key->namelen; |
52 | memcpy(&new->addr, &key->addr, key->addrlen); | 66 | nfs_dns_ent_update(cnew, ckey); |
53 | new->addrlen = key->addrlen; | ||
54 | } else { | 67 | } else { |
55 | new->namelen = 0; | 68 | new->namelen = 0; |
56 | new->addrlen = 0; | 69 | new->addrlen = 0; |
@@ -146,7 +159,7 @@ static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, | |||
146 | return 0; | 159 | return 0; |
147 | } | 160 | } |
148 | 161 | ||
149 | struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, | 162 | static struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, |
150 | struct nfs_dns_ent *key) | 163 | struct nfs_dns_ent *key) |
151 | { | 164 | { |
152 | struct cache_head *ch; | 165 | struct cache_head *ch; |
@@ -159,7 +172,7 @@ struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, | |||
159 | return container_of(ch, struct nfs_dns_ent, h); | 172 | return container_of(ch, struct nfs_dns_ent, h); |
160 | } | 173 | } |
161 | 174 | ||
162 | struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, | 175 | static struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, |
163 | struct nfs_dns_ent *new, | 176 | struct nfs_dns_ent *new, |
164 | struct nfs_dns_ent *key) | 177 | struct nfs_dns_ent *key) |
165 | { | 178 | { |
@@ -234,7 +247,7 @@ static struct cache_detail nfs_dns_resolve = { | |||
234 | .cache_show = nfs_dns_show, | 247 | .cache_show = nfs_dns_show, |
235 | .match = nfs_dns_match, | 248 | .match = nfs_dns_match, |
236 | .init = nfs_dns_ent_init, | 249 | .init = nfs_dns_ent_init, |
237 | .update = nfs_dns_ent_init, | 250 | .update = nfs_dns_ent_update, |
238 | .alloc = nfs_dns_ent_alloc, | 251 | .alloc = nfs_dns_ent_alloc, |
239 | }; | 252 | }; |
240 | 253 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f5fdd39e037a..8d965bddb87e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -24,9 +24,9 @@ | |||
24 | #include <linux/nfs_fs.h> | 24 | #include <linux/nfs_fs.h> |
25 | #include <linux/nfs_mount.h> | 25 | #include <linux/nfs_mount.h> |
26 | #include <linux/mm.h> | 26 | #include <linux/mm.h> |
27 | #include <linux/slab.h> | ||
28 | #include <linux/pagemap.h> | 27 | #include <linux/pagemap.h> |
29 | #include <linux/aio.h> | 28 | #include <linux/aio.h> |
29 | #include <linux/gfp.h> | ||
30 | 30 | ||
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | #include <asm/system.h> | 32 | #include <asm/system.h> |
@@ -123,11 +123,11 @@ nfs_file_open(struct inode *inode, struct file *filp) | |||
123 | filp->f_path.dentry->d_parent->d_name.name, | 123 | filp->f_path.dentry->d_parent->d_name.name, |
124 | filp->f_path.dentry->d_name.name); | 124 | filp->f_path.dentry->d_name.name); |
125 | 125 | ||
126 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | ||
126 | res = nfs_check_flags(filp->f_flags); | 127 | res = nfs_check_flags(filp->f_flags); |
127 | if (res) | 128 | if (res) |
128 | return res; | 129 | return res; |
129 | 130 | ||
130 | nfs_inc_stats(inode, NFSIOS_VFSOPEN); | ||
131 | res = nfs_open(inode, filp); | 131 | res = nfs_open(inode, filp); |
132 | return res; | 132 | return res; |
133 | } | 133 | } |
@@ -237,9 +237,9 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
237 | dentry->d_parent->d_name.name, | 237 | dentry->d_parent->d_name.name, |
238 | dentry->d_name.name); | 238 | dentry->d_name.name); |
239 | 239 | ||
240 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); | ||
240 | if ((file->f_mode & FMODE_WRITE) == 0) | 241 | if ((file->f_mode & FMODE_WRITE) == 0) |
241 | return 0; | 242 | return 0; |
242 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); | ||
243 | 243 | ||
244 | /* Flush writes to the server and return any errors */ | 244 | /* Flush writes to the server and return any errors */ |
245 | return nfs_do_fsync(ctx, inode); | 245 | return nfs_do_fsync(ctx, inode); |
@@ -262,9 +262,11 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
262 | (unsigned long) count, (unsigned long) pos); | 262 | (unsigned long) count, (unsigned long) pos); |
263 | 263 | ||
264 | result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); | 264 | result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping); |
265 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count); | 265 | if (!result) { |
266 | if (!result) | ||
267 | result = generic_file_aio_read(iocb, iov, nr_segs, pos); | 266 | result = generic_file_aio_read(iocb, iov, nr_segs, pos); |
267 | if (result > 0) | ||
268 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, result); | ||
269 | } | ||
268 | return result; | 270 | return result; |
269 | } | 271 | } |
270 | 272 | ||
@@ -282,8 +284,11 @@ nfs_file_splice_read(struct file *filp, loff_t *ppos, | |||
282 | (unsigned long) count, (unsigned long long) *ppos); | 284 | (unsigned long) count, (unsigned long long) *ppos); |
283 | 285 | ||
284 | res = nfs_revalidate_mapping(inode, filp->f_mapping); | 286 | res = nfs_revalidate_mapping(inode, filp->f_mapping); |
285 | if (!res) | 287 | if (!res) { |
286 | res = generic_file_splice_read(filp, ppos, pipe, count, flags); | 288 | res = generic_file_splice_read(filp, ppos, pipe, count, flags); |
289 | if (res > 0) | ||
290 | nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, res); | ||
291 | } | ||
287 | return res; | 292 | return res; |
288 | } | 293 | } |
289 | 294 | ||
@@ -486,6 +491,9 @@ static int nfs_release_page(struct page *page, gfp_t gfp) | |||
486 | { | 491 | { |
487 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); | 492 | dfprintk(PAGECACHE, "NFS: release_page(%p)\n", page); |
488 | 493 | ||
494 | /* Only do I/O if gfp is a superset of GFP_KERNEL */ | ||
495 | if ((gfp & GFP_KERNEL) == GFP_KERNEL) | ||
496 | nfs_wb_page(page->mapping->host, page); | ||
489 | /* If PagePrivate() is set, then the page is not freeable */ | 497 | /* If PagePrivate() is set, then the page is not freeable */ |
490 | if (PagePrivate(page)) | 498 | if (PagePrivate(page)) |
491 | return 0; | 499 | return 0; |
@@ -581,7 +589,7 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode) | |||
581 | { | 589 | { |
582 | struct nfs_open_context *ctx; | 590 | struct nfs_open_context *ctx; |
583 | 591 | ||
584 | if (IS_SYNC(inode) || (filp->f_flags & O_SYNC)) | 592 | if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC)) |
585 | return 1; | 593 | return 1; |
586 | ctx = nfs_file_open_context(filp); | 594 | ctx = nfs_file_open_context(filp); |
587 | if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) | 595 | if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) |
@@ -594,6 +602,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
594 | { | 602 | { |
595 | struct dentry * dentry = iocb->ki_filp->f_path.dentry; | 603 | struct dentry * dentry = iocb->ki_filp->f_path.dentry; |
596 | struct inode * inode = dentry->d_inode; | 604 | struct inode * inode = dentry->d_inode; |
605 | unsigned long written = 0; | ||
597 | ssize_t result; | 606 | ssize_t result; |
598 | size_t count = iov_length(iov, nr_segs); | 607 | size_t count = iov_length(iov, nr_segs); |
599 | 608 | ||
@@ -620,14 +629,18 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
620 | if (!count) | 629 | if (!count) |
621 | goto out; | 630 | goto out; |
622 | 631 | ||
623 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
624 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); | 632 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); |
625 | /* Return error values for O_SYNC and IS_SYNC() */ | 633 | if (result > 0) |
634 | written = result; | ||
635 | |||
636 | /* Return error values for O_DSYNC and IS_SYNC() */ | ||
626 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { | 637 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
627 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); | 638 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); |
628 | if (err < 0) | 639 | if (err < 0) |
629 | result = err; | 640 | result = err; |
630 | } | 641 | } |
642 | if (result > 0) | ||
643 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); | ||
631 | out: | 644 | out: |
632 | return result; | 645 | return result; |
633 | 646 | ||
@@ -642,6 +655,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
642 | { | 655 | { |
643 | struct dentry *dentry = filp->f_path.dentry; | 656 | struct dentry *dentry = filp->f_path.dentry; |
644 | struct inode *inode = dentry->d_inode; | 657 | struct inode *inode = dentry->d_inode; |
658 | unsigned long written = 0; | ||
645 | ssize_t ret; | 659 | ssize_t ret; |
646 | 660 | ||
647 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", | 661 | dprintk("NFS splice_write(%s/%s, %lu@%llu)\n", |
@@ -652,14 +666,17 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
652 | * The combination of splice and an O_APPEND destination is disallowed. | 666 | * The combination of splice and an O_APPEND destination is disallowed. |
653 | */ | 667 | */ |
654 | 668 | ||
655 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | ||
656 | |||
657 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); | 669 | ret = generic_file_splice_write(pipe, filp, ppos, count, flags); |
670 | if (ret > 0) | ||
671 | written = ret; | ||
672 | |||
658 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | 673 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { |
659 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | 674 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); |
660 | if (err < 0) | 675 | if (err < 0) |
661 | ret = err; | 676 | ret = err; |
662 | } | 677 | } |
678 | if (ret > 0) | ||
679 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, written); | ||
663 | return ret; | 680 | return ret; |
664 | } | 681 | } |
665 | 682 | ||
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index fa588006588d..a6b16ed93229 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/nfs_fs_sb.h> | 17 | #include <linux/nfs_fs_sb.h> |
18 | #include <linux/in6.h> | 18 | #include <linux/in6.h> |
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/slab.h> | ||
20 | 21 | ||
21 | #include "internal.h" | 22 | #include "internal.h" |
22 | #include "iostat.h" | 23 | #include "iostat.h" |
@@ -354,12 +355,11 @@ void nfs_fscache_reset_inode_cookie(struct inode *inode) | |||
354 | */ | 355 | */ |
355 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) | 356 | int nfs_fscache_release_page(struct page *page, gfp_t gfp) |
356 | { | 357 | { |
357 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | ||
358 | struct fscache_cookie *cookie = nfsi->fscache; | ||
359 | |||
360 | BUG_ON(!cookie); | ||
361 | |||
362 | if (PageFsCache(page)) { | 358 | if (PageFsCache(page)) { |
359 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | ||
360 | struct fscache_cookie *cookie = nfsi->fscache; | ||
361 | |||
362 | BUG_ON(!cookie); | ||
363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", | 363 | dfprintk(FSCACHE, "NFS: fscache releasepage (0x%p/0x%p/0x%p)\n", |
364 | cookie, page, nfsi); | 364 | cookie, page, nfsi); |
365 | 365 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index faa091865ad0..50a56edca0b5 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/vfs.h> | 36 | #include <linux/vfs.h> |
37 | #include <linux/inet.h> | 37 | #include <linux/inet.h> |
38 | #include <linux/nfs_xdr.h> | 38 | #include <linux/nfs_xdr.h> |
39 | #include <linux/slab.h> | ||
39 | 40 | ||
40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
@@ -97,22 +98,6 @@ u64 nfs_compat_user_ino64(u64 fileid) | |||
97 | return ino; | 98 | return ino; |
98 | } | 99 | } |
99 | 100 | ||
100 | int nfs_write_inode(struct inode *inode, int sync) | ||
101 | { | ||
102 | int ret; | ||
103 | |||
104 | if (sync) { | ||
105 | ret = filemap_fdatawait(inode->i_mapping); | ||
106 | if (ret == 0) | ||
107 | ret = nfs_commit_inode(inode, FLUSH_SYNC); | ||
108 | } else | ||
109 | ret = nfs_commit_inode(inode, 0); | ||
110 | if (ret >= 0) | ||
111 | return 0; | ||
112 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | void nfs_clear_inode(struct inode *inode) | 101 | void nfs_clear_inode(struct inode *inode) |
117 | { | 102 | { |
118 | /* | 103 | /* |
@@ -130,16 +115,12 @@ void nfs_clear_inode(struct inode *inode) | |||
130 | */ | 115 | */ |
131 | int nfs_sync_mapping(struct address_space *mapping) | 116 | int nfs_sync_mapping(struct address_space *mapping) |
132 | { | 117 | { |
133 | int ret; | 118 | int ret = 0; |
134 | 119 | ||
135 | if (mapping->nrpages == 0) | 120 | if (mapping->nrpages != 0) { |
136 | return 0; | 121 | unmap_mapping_range(mapping, 0, 0, 0); |
137 | unmap_mapping_range(mapping, 0, 0, 0); | 122 | ret = nfs_wb_all(mapping->host); |
138 | ret = filemap_write_and_wait(mapping); | 123 | } |
139 | if (ret != 0) | ||
140 | goto out; | ||
141 | ret = nfs_wb_all(mapping->host); | ||
142 | out: | ||
143 | return ret; | 124 | return ret; |
144 | } | 125 | } |
145 | 126 | ||
@@ -511,17 +492,11 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
511 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; | 492 | int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME; |
512 | int err; | 493 | int err; |
513 | 494 | ||
514 | /* | 495 | /* Flush out writes to the server in order to update c/mtime. */ |
515 | * Flush out writes to the server in order to update c/mtime. | ||
516 | * | ||
517 | * Hold the i_mutex to suspend application writes temporarily; | ||
518 | * this prevents long-running writing applications from blocking | ||
519 | * nfs_wb_nocommit. | ||
520 | */ | ||
521 | if (S_ISREG(inode->i_mode)) { | 496 | if (S_ISREG(inode->i_mode)) { |
522 | mutex_lock(&inode->i_mutex); | 497 | err = filemap_write_and_wait(inode->i_mapping); |
523 | nfs_wb_nocommit(inode); | 498 | if (err) |
524 | mutex_unlock(&inode->i_mutex); | 499 | goto out; |
525 | } | 500 | } |
526 | 501 | ||
527 | /* | 502 | /* |
@@ -545,6 +520,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
545 | generic_fillattr(inode, stat); | 520 | generic_fillattr(inode, stat); |
546 | stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); | 521 | stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode)); |
547 | } | 522 | } |
523 | out: | ||
548 | return err; | 524 | return err; |
549 | } | 525 | } |
550 | 526 | ||
@@ -574,14 +550,14 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) | |||
574 | nfs_revalidate_inode(server, inode); | 550 | nfs_revalidate_inode(server, inode); |
575 | } | 551 | } |
576 | 552 | ||
577 | static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred) | 553 | static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred) |
578 | { | 554 | { |
579 | struct nfs_open_context *ctx; | 555 | struct nfs_open_context *ctx; |
580 | 556 | ||
581 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); | 557 | ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); |
582 | if (ctx != NULL) { | 558 | if (ctx != NULL) { |
583 | ctx->path.dentry = dget(dentry); | 559 | ctx->path = *path; |
584 | ctx->path.mnt = mntget(mnt); | 560 | path_get(&ctx->path); |
585 | ctx->cred = get_rpccred(cred); | 561 | ctx->cred = get_rpccred(cred); |
586 | ctx->state = NULL; | 562 | ctx->state = NULL; |
587 | ctx->lockowner = current->files; | 563 | ctx->lockowner = current->files; |
@@ -620,11 +596,6 @@ void put_nfs_open_context(struct nfs_open_context *ctx) | |||
620 | __put_nfs_open_context(ctx, 0); | 596 | __put_nfs_open_context(ctx, 0); |
621 | } | 597 | } |
622 | 598 | ||
623 | static void put_nfs_open_context_sync(struct nfs_open_context *ctx) | ||
624 | { | ||
625 | __put_nfs_open_context(ctx, 1); | ||
626 | } | ||
627 | |||
628 | /* | 599 | /* |
629 | * Ensure that mmap has a recent RPC credential for use when writing out | 600 | * Ensure that mmap has a recent RPC credential for use when writing out |
630 | * shared pages | 601 | * shared pages |
@@ -652,10 +623,10 @@ struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_c | |||
652 | list_for_each_entry(pos, &nfsi->open_files, list) { | 623 | list_for_each_entry(pos, &nfsi->open_files, list) { |
653 | if (cred != NULL && pos->cred != cred) | 624 | if (cred != NULL && pos->cred != cred) |
654 | continue; | 625 | continue; |
655 | if ((pos->mode & mode) == mode) { | 626 | if ((pos->mode & (FMODE_READ|FMODE_WRITE)) != mode) |
656 | ctx = get_nfs_open_context(pos); | 627 | continue; |
657 | break; | 628 | ctx = get_nfs_open_context(pos); |
658 | } | 629 | break; |
659 | } | 630 | } |
660 | spin_unlock(&inode->i_lock); | 631 | spin_unlock(&inode->i_lock); |
661 | return ctx; | 632 | return ctx; |
@@ -671,7 +642,7 @@ static void nfs_file_clear_open_context(struct file *filp) | |||
671 | spin_lock(&inode->i_lock); | 642 | spin_lock(&inode->i_lock); |
672 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); | 643 | list_move_tail(&ctx->list, &NFS_I(inode)->open_files); |
673 | spin_unlock(&inode->i_lock); | 644 | spin_unlock(&inode->i_lock); |
674 | put_nfs_open_context_sync(ctx); | 645 | __put_nfs_open_context(ctx, filp->f_flags & O_DIRECT ? 0 : 1); |
675 | } | 646 | } |
676 | } | 647 | } |
677 | 648 | ||
@@ -686,7 +657,7 @@ int nfs_open(struct inode *inode, struct file *filp) | |||
686 | cred = rpc_lookup_cred(); | 657 | cred = rpc_lookup_cred(); |
687 | if (IS_ERR(cred)) | 658 | if (IS_ERR(cred)) |
688 | return PTR_ERR(cred); | 659 | return PTR_ERR(cred); |
689 | ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); | 660 | ctx = alloc_nfs_open_context(&filp->f_path, cred); |
690 | put_rpccred(cred); | 661 | put_rpccred(cred); |
691 | if (ctx == NULL) | 662 | if (ctx == NULL) |
692 | return -ENOMEM; | 663 | return -ENOMEM; |
@@ -759,7 +730,7 @@ int nfs_attribute_timeout(struct inode *inode) | |||
759 | { | 730 | { |
760 | struct nfs_inode *nfsi = NFS_I(inode); | 731 | struct nfs_inode *nfsi = NFS_I(inode); |
761 | 732 | ||
762 | if (nfs_have_delegation(inode, FMODE_READ)) | 733 | if (nfs_have_delegated_attributes(inode)) |
763 | return 0; | 734 | return 0; |
764 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); | 735 | return !time_in_range_open(jiffies, nfsi->read_cache_jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo); |
765 | } | 736 | } |
@@ -779,7 +750,7 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
779 | return __nfs_revalidate_inode(server, inode); | 750 | return __nfs_revalidate_inode(server, inode); |
780 | } | 751 | } |
781 | 752 | ||
782 | static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_space *mapping) | 753 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) |
783 | { | 754 | { |
784 | struct nfs_inode *nfsi = NFS_I(inode); | 755 | struct nfs_inode *nfsi = NFS_I(inode); |
785 | 756 | ||
@@ -800,49 +771,10 @@ static int nfs_invalidate_mapping_nolock(struct inode *inode, struct address_spa | |||
800 | return 0; | 771 | return 0; |
801 | } | 772 | } |
802 | 773 | ||
803 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) | ||
804 | { | ||
805 | int ret = 0; | ||
806 | |||
807 | mutex_lock(&inode->i_mutex); | ||
808 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_DATA) { | ||
809 | ret = nfs_sync_mapping(mapping); | ||
810 | if (ret == 0) | ||
811 | ret = nfs_invalidate_mapping_nolock(inode, mapping); | ||
812 | } | ||
813 | mutex_unlock(&inode->i_mutex); | ||
814 | return ret; | ||
815 | } | ||
816 | |||
817 | /** | ||
818 | * nfs_revalidate_mapping_nolock - Revalidate the pagecache | ||
819 | * @inode - pointer to host inode | ||
820 | * @mapping - pointer to mapping | ||
821 | */ | ||
822 | int nfs_revalidate_mapping_nolock(struct inode *inode, struct address_space *mapping) | ||
823 | { | ||
824 | struct nfs_inode *nfsi = NFS_I(inode); | ||
825 | int ret = 0; | ||
826 | |||
827 | if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE) | ||
828 | || nfs_attribute_timeout(inode) || NFS_STALE(inode)) { | ||
829 | ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
830 | if (ret < 0) | ||
831 | goto out; | ||
832 | } | ||
833 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
834 | ret = nfs_invalidate_mapping_nolock(inode, mapping); | ||
835 | out: | ||
836 | return ret; | ||
837 | } | ||
838 | |||
839 | /** | 774 | /** |
840 | * nfs_revalidate_mapping - Revalidate the pagecache | 775 | * nfs_revalidate_mapping - Revalidate the pagecache |
841 | * @inode - pointer to host inode | 776 | * @inode - pointer to host inode |
842 | * @mapping - pointer to mapping | 777 | * @mapping - pointer to mapping |
843 | * | ||
844 | * This version of the function will take the inode->i_mutex and attempt to | ||
845 | * flush out all dirty data if it needs to invalidate the page cache. | ||
846 | */ | 778 | */ |
847 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) | 779 | int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping) |
848 | { | 780 | { |
@@ -1261,8 +1193,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1261 | 1193 | ||
1262 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { | 1194 | if (fattr->valid & NFS_ATTR_FATTR_MODE) { |
1263 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { | 1195 | if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)) { |
1196 | umode_t newmode = inode->i_mode & S_IFMT; | ||
1197 | newmode |= fattr->mode & S_IALLUGO; | ||
1198 | inode->i_mode = newmode; | ||
1264 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; | 1199 | invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; |
1265 | inode->i_mode = fattr->mode; | ||
1266 | } | 1200 | } |
1267 | } else if (server->caps & NFS_CAP_MODE) | 1201 | } else if (server->caps & NFS_CAP_MODE) |
1268 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR | 1202 | invalid |= save_cache_validity & (NFS_INO_INVALID_ATTR |
@@ -1418,6 +1352,7 @@ static void init_once(void *foo) | |||
1418 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); | 1352 | INIT_LIST_HEAD(&nfsi->access_cache_inode_lru); |
1419 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); | 1353 | INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); |
1420 | nfsi->npages = 0; | 1354 | nfsi->npages = 0; |
1355 | nfsi->ncommit = 0; | ||
1421 | atomic_set(&nfsi->silly_count, 1); | 1356 | atomic_set(&nfsi->silly_count, 1); |
1422 | INIT_HLIST_HEAD(&nfsi->silly_list); | 1357 | INIT_HLIST_HEAD(&nfsi->silly_list); |
1423 | init_waitqueue_head(&nfsi->waitqueue); | 1358 | init_waitqueue_head(&nfsi->waitqueue); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e21b1bb9972f..11f82f03c5de 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -30,6 +30,15 @@ static inline int nfs4_has_session(const struct nfs_client *clp) | |||
30 | return 0; | 30 | return 0; |
31 | } | 31 | } |
32 | 32 | ||
33 | static inline int nfs4_has_persistent_session(const struct nfs_client *clp) | ||
34 | { | ||
35 | #ifdef CONFIG_NFS_V4_1 | ||
36 | if (nfs4_has_session(clp)) | ||
37 | return (clp->cl_session->flags & SESSION4_PERSIST); | ||
38 | #endif /* CONFIG_NFS_V4_1 */ | ||
39 | return 0; | ||
40 | } | ||
41 | |||
33 | struct nfs_clone_mount { | 42 | struct nfs_clone_mount { |
34 | const struct super_block *sb; | 43 | const struct super_block *sb; |
35 | const struct dentry *dentry; | 44 | const struct dentry *dentry; |
@@ -156,6 +165,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | |||
156 | 165 | ||
157 | /* callback_xdr.c */ | 166 | /* callback_xdr.c */ |
158 | extern struct svc_version nfs4_callback_version1; | 167 | extern struct svc_version nfs4_callback_version1; |
168 | extern struct svc_version nfs4_callback_version4; | ||
159 | 169 | ||
160 | /* pagelist.c */ | 170 | /* pagelist.c */ |
161 | extern int __init nfs_init_nfspagecache(void); | 171 | extern int __init nfs_init_nfspagecache(void); |
@@ -177,24 +187,14 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
177 | extern struct rpc_procinfo nfs3_procedures[]; | 187 | extern struct rpc_procinfo nfs3_procedures[]; |
178 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 188 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
179 | 189 | ||
180 | /* nfs4proc.c */ | ||
181 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
182 | const struct nfs_client *clp) | ||
183 | { | ||
184 | #ifdef CONFIG_NFS_V4_1 | ||
185 | if (nfs4_has_session(clp) && | ||
186 | test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
187 | rpc_restart_call_prepare(task); | ||
188 | return; | ||
189 | } | ||
190 | #endif /* CONFIG_NFS_V4_1 */ | ||
191 | rpc_restart_call(task); | ||
192 | } | ||
193 | |||
194 | /* nfs4xdr.c */ | 190 | /* nfs4xdr.c */ |
195 | #ifdef CONFIG_NFS_V4 | 191 | #ifdef CONFIG_NFS_V4 |
196 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 192 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
197 | #endif | 193 | #endif |
194 | #ifdef CONFIG_NFS_V4_1 | ||
195 | extern const u32 nfs41_maxread_overhead; | ||
196 | extern const u32 nfs41_maxwrite_overhead; | ||
197 | #endif | ||
198 | 198 | ||
199 | /* nfs4proc.c */ | 199 | /* nfs4proc.c */ |
200 | #ifdef CONFIG_NFS_V4 | 200 | #ifdef CONFIG_NFS_V4 |
@@ -211,7 +211,7 @@ extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask); | |||
211 | extern struct workqueue_struct *nfsiod_workqueue; | 211 | extern struct workqueue_struct *nfsiod_workqueue; |
212 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 212 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
213 | extern void nfs_destroy_inode(struct inode *); | 213 | extern void nfs_destroy_inode(struct inode *); |
214 | extern int nfs_write_inode(struct inode *,int); | 214 | extern int nfs_write_inode(struct inode *, struct writeback_control *); |
215 | extern void nfs_clear_inode(struct inode *); | 215 | extern void nfs_clear_inode(struct inode *); |
216 | #ifdef CONFIG_NFS_V4 | 216 | #ifdef CONFIG_NFS_V4 |
217 | extern void nfs4_clear_inode(struct inode *); | 217 | extern void nfs4_clear_inode(struct inode *); |
@@ -273,20 +273,6 @@ extern int _nfs4_call_sync_session(struct nfs_server *server, | |||
273 | struct nfs4_sequence_res *res, | 273 | struct nfs4_sequence_res *res, |
274 | int cache_reply); | 274 | int cache_reply); |
275 | 275 | ||
276 | #ifdef CONFIG_NFS_V4_1 | ||
277 | extern void nfs41_sequence_free_slot(const struct nfs_client *, | ||
278 | struct nfs4_sequence_res *res); | ||
279 | #endif /* CONFIG_NFS_V4_1 */ | ||
280 | |||
281 | static inline void nfs4_sequence_free_slot(const struct nfs_client *clp, | ||
282 | struct nfs4_sequence_res *res) | ||
283 | { | ||
284 | #ifdef CONFIG_NFS_V4_1 | ||
285 | if (nfs4_has_session(clp)) | ||
286 | nfs41_sequence_free_slot(clp, res); | ||
287 | #endif /* CONFIG_NFS_V4_1 */ | ||
288 | } | ||
289 | |||
290 | /* | 276 | /* |
291 | * Determine the device name as a string | 277 | * Determine the device name as a string |
292 | */ | 278 | */ |
@@ -380,3 +366,15 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len) | |||
380 | return ((unsigned long)len + (unsigned long)base + | 366 | return ((unsigned long)len + (unsigned long)base + |
381 | PAGE_SIZE - 1) >> PAGE_SHIFT; | 367 | PAGE_SIZE - 1) >> PAGE_SHIFT; |
382 | } | 368 | } |
369 | |||
370 | /* | ||
371 | * Helper for restarting RPC calls in the possible presence of NFSv4.1 | ||
372 | * sessions. | ||
373 | */ | ||
374 | static inline void nfs_restart_rpc(struct rpc_task *task, const struct nfs_client *clp) | ||
375 | { | ||
376 | if (nfs4_has_session(clp)) | ||
377 | rpc_restart_call_prepare(task); | ||
378 | else | ||
379 | rpc_restart_call(task); | ||
380 | } | ||
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h index ceda50aad73c..1d8d5c813b01 100644 --- a/fs/nfs/iostat.h +++ b/fs/nfs/iostat.h | |||
@@ -25,13 +25,7 @@ struct nfs_iostats { | |||
25 | static inline void nfs_inc_server_stats(const struct nfs_server *server, | 25 | static inline void nfs_inc_server_stats(const struct nfs_server *server, |
26 | enum nfs_stat_eventcounters stat) | 26 | enum nfs_stat_eventcounters stat) |
27 | { | 27 | { |
28 | struct nfs_iostats *iostats; | 28 | this_cpu_inc(server->io_stats->events[stat]); |
29 | int cpu; | ||
30 | |||
31 | cpu = get_cpu(); | ||
32 | iostats = per_cpu_ptr(server->io_stats, cpu); | ||
33 | iostats->events[stat]++; | ||
34 | put_cpu(); | ||
35 | } | 29 | } |
36 | 30 | ||
37 | static inline void nfs_inc_stats(const struct inode *inode, | 31 | static inline void nfs_inc_stats(const struct inode *inode, |
@@ -44,13 +38,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server, | |||
44 | enum nfs_stat_bytecounters stat, | 38 | enum nfs_stat_bytecounters stat, |
45 | unsigned long addend) | 39 | unsigned long addend) |
46 | { | 40 | { |
47 | struct nfs_iostats *iostats; | 41 | this_cpu_add(server->io_stats->bytes[stat], addend); |
48 | int cpu; | ||
49 | |||
50 | cpu = get_cpu(); | ||
51 | iostats = per_cpu_ptr(server->io_stats, cpu); | ||
52 | iostats->bytes[stat] += addend; | ||
53 | put_cpu(); | ||
54 | } | 42 | } |
55 | 43 | ||
56 | static inline void nfs_add_stats(const struct inode *inode, | 44 | static inline void nfs_add_stats(const struct inode *inode, |
@@ -65,22 +53,16 @@ static inline void nfs_add_fscache_stats(struct inode *inode, | |||
65 | enum nfs_stat_fscachecounters stat, | 53 | enum nfs_stat_fscachecounters stat, |
66 | unsigned long addend) | 54 | unsigned long addend) |
67 | { | 55 | { |
68 | struct nfs_iostats *iostats; | 56 | this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend); |
69 | int cpu; | ||
70 | |||
71 | cpu = get_cpu(); | ||
72 | iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu); | ||
73 | iostats->fscache[stat] += addend; | ||
74 | put_cpu(); | ||
75 | } | 57 | } |
76 | #endif | 58 | #endif |
77 | 59 | ||
78 | static inline struct nfs_iostats *nfs_alloc_iostats(void) | 60 | static inline struct nfs_iostats __percpu *nfs_alloc_iostats(void) |
79 | { | 61 | { |
80 | return alloc_percpu(struct nfs_iostats); | 62 | return alloc_percpu(struct nfs_iostats); |
81 | } | 63 | } |
82 | 64 | ||
83 | static inline void nfs_free_iostats(struct nfs_iostats *stats) | 65 | static inline void nfs_free_iostats(struct nfs_iostats __percpu *stats) |
84 | { | 66 | { |
85 | if (stats != NULL) | 67 | if (stats != NULL) |
86 | free_percpu(stats); | 68 | free_percpu(stats); |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index 0adefc40cc89..59047f8d7d72 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -120,7 +120,7 @@ static struct { | |||
120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, | 120 | { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, |
121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, | 121 | { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, |
122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, | 122 | { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, |
123 | { .status = MNT3ERR_SERVERFAULT, .errno = -ESERVERFAULT, }, | 123 | { .status = MNT3ERR_SERVERFAULT, .errno = -EREMOTEIO, }, |
124 | }; | 124 | }; |
125 | 125 | ||
126 | struct mountres { | 126 | struct mountres { |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 40c766782891..7888cf36022d 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/dcache.h> | 10 | #include <linux/dcache.h> |
11 | #include <linux/gfp.h> | ||
11 | #include <linux/mount.h> | 12 | #include <linux/mount.h> |
12 | #include <linux/namei.h> | 13 | #include <linux/namei.h> |
13 | #include <linux/nfs_fs.h> | 14 | #include <linux/nfs_fs.h> |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 5e078b222b4e..81cf14257916 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/param.h> | 12 | #include <linux/param.h> |
13 | #include <linux/time.h> | 13 | #include <linux/time.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/slab.h> | ||
16 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
17 | #include <linux/string.h> | 16 | #include <linux/string.h> |
18 | #include <linux/in.h> | 17 | #include <linux/in.h> |
@@ -699,7 +698,7 @@ static struct { | |||
699 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, | 698 | { NFSERR_BAD_COOKIE, -EBADCOOKIE }, |
700 | { NFSERR_NOTSUPP, -ENOTSUPP }, | 699 | { NFSERR_NOTSUPP, -ENOTSUPP }, |
701 | { NFSERR_TOOSMALL, -ETOOSMALL }, | 700 | { NFSERR_TOOSMALL, -ETOOSMALL }, |
702 | { NFSERR_SERVERFAULT, -ESERVERFAULT }, | 701 | { NFSERR_SERVERFAULT, -EREMOTEIO }, |
703 | { NFSERR_BADTYPE, -EBADTYPE }, | 702 | { NFSERR_BADTYPE, -EBADTYPE }, |
704 | { NFSERR_JUKEBOX, -EJUKEBOX }, | 703 | { NFSERR_JUKEBOX, -EJUKEBOX }, |
705 | { -1, -EIO } | 704 | { -1, -EIO } |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index bac60515a4b3..d150ae0c5ecd 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <linux/fs.h> | 1 | #include <linux/fs.h> |
2 | #include <linux/gfp.h> | ||
2 | #include <linux/nfs.h> | 3 | #include <linux/nfs.h> |
3 | #include <linux/nfs3.h> | 4 | #include <linux/nfs3.h> |
4 | #include <linux/nfs_fs.h> | 5 | #include <linux/nfs_fs.h> |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 3f8881d1a050..e701002694e5 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
12 | #include <linux/sunrpc/clnt.h> | 12 | #include <linux/sunrpc/clnt.h> |
13 | #include <linux/slab.h> | ||
13 | #include <linux/nfs.h> | 14 | #include <linux/nfs.h> |
14 | #include <linux/nfs3.h> | 15 | #include <linux/nfs3.h> |
15 | #include <linux/nfs_fs.h> | 16 | #include <linux/nfs_fs.h> |
@@ -22,14 +23,14 @@ | |||
22 | 23 | ||
23 | #define NFSDBG_FACILITY NFSDBG_PROC | 24 | #define NFSDBG_FACILITY NFSDBG_PROC |
24 | 25 | ||
25 | /* A wrapper to handle the EJUKEBOX error message */ | 26 | /* A wrapper to handle the EJUKEBOX and EKEYEXPIRED error messages */ |
26 | static int | 27 | static int |
27 | nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | 28 | nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) |
28 | { | 29 | { |
29 | int res; | 30 | int res; |
30 | do { | 31 | do { |
31 | res = rpc_call_sync(clnt, msg, flags); | 32 | res = rpc_call_sync(clnt, msg, flags); |
32 | if (res != -EJUKEBOX) | 33 | if (res != -EJUKEBOX && res != -EKEYEXPIRED) |
33 | break; | 34 | break; |
34 | schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); | 35 | schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); |
35 | res = -ERESTARTSYS; | 36 | res = -ERESTARTSYS; |
@@ -42,9 +43,10 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | |||
42 | static int | 43 | static int |
43 | nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) | 44 | nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) |
44 | { | 45 | { |
45 | if (task->tk_status != -EJUKEBOX) | 46 | if (task->tk_status != -EJUKEBOX && task->tk_status != -EKEYEXPIRED) |
46 | return 0; | 47 | return 0; |
47 | nfs_inc_stats(inode, NFSIOS_DELAY); | 48 | if (task->tk_status == -EJUKEBOX) |
49 | nfs_inc_stats(inode, NFSIOS_DELAY); | ||
48 | task->tk_status = 0; | 50 | task->tk_status = 0; |
49 | rpc_restart_call(task); | 51 | rpc_restart_call(task); |
50 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); | 52 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); |
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c index 5fe5492fbd29..56a86f6ac8b5 100644 --- a/fs/nfs/nfs3xdr.c +++ b/fs/nfs/nfs3xdr.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/param.h> | 9 | #include <linux/param.h> |
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/mm.h> | 11 | #include <linux/mm.h> |
12 | #include <linux/slab.h> | ||
13 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
14 | #include <linux/string.h> | 13 | #include <linux/string.h> |
15 | #include <linux/in.h> | 14 | #include <linux/in.h> |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 6ea07a3c75d4..a187200a7aac 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -44,7 +44,9 @@ enum nfs4_client_state { | |||
44 | NFS4CLNT_RECLAIM_REBOOT, | 44 | NFS4CLNT_RECLAIM_REBOOT, |
45 | NFS4CLNT_RECLAIM_NOGRACE, | 45 | NFS4CLNT_RECLAIM_NOGRACE, |
46 | NFS4CLNT_DELEGRETURN, | 46 | NFS4CLNT_DELEGRETURN, |
47 | NFS4CLNT_SESSION_SETUP, | 47 | NFS4CLNT_SESSION_RESET, |
48 | NFS4CLNT_SESSION_DRAINING, | ||
49 | NFS4CLNT_RECALL_SLOT, | ||
48 | }; | 50 | }; |
49 | 51 | ||
50 | /* | 52 | /* |
@@ -107,6 +109,10 @@ enum { | |||
107 | NFS_OWNER_RECLAIM_NOGRACE | 109 | NFS_OWNER_RECLAIM_NOGRACE |
108 | }; | 110 | }; |
109 | 111 | ||
112 | #define NFS_LOCK_NEW 0 | ||
113 | #define NFS_LOCK_RECLAIM 1 | ||
114 | #define NFS_LOCK_EXPIRED 2 | ||
115 | |||
110 | /* | 116 | /* |
111 | * struct nfs4_state maintains the client-side state for a given | 117 | * struct nfs4_state maintains the client-side state for a given |
112 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). | 118 | * (state_owner,inode) tuple (OPEN) or state_owner (LOCK). |
@@ -141,6 +147,7 @@ enum { | |||
141 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ | 147 | NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */ |
142 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ | 148 | NFS_STATE_RECLAIM_REBOOT, /* OPEN stateid server rebooted */ |
143 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ | 149 | NFS_STATE_RECLAIM_NOGRACE, /* OPEN stateid needs to recover state */ |
150 | NFS_STATE_POSIX_LOCKS, /* Posix locks are supported */ | ||
144 | }; | 151 | }; |
145 | 152 | ||
146 | struct nfs4_state { | 153 | struct nfs4_state { |
@@ -180,6 +187,7 @@ struct nfs4_state_recovery_ops { | |||
180 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 187 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
181 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | 188 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); |
182 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | 189 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); |
190 | int (*reclaim_complete)(struct nfs_client *); | ||
183 | }; | 191 | }; |
184 | 192 | ||
185 | struct nfs4_state_maintenance_ops { | 193 | struct nfs4_state_maintenance_ops { |
@@ -200,9 +208,11 @@ extern ssize_t nfs4_listxattr(struct dentry *, char *, size_t); | |||
200 | /* nfs4proc.c */ | 208 | /* nfs4proc.c */ |
201 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); | 209 | extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *); |
202 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 210 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
211 | extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred); | ||
203 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 212 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
204 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 213 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
205 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | 214 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); |
215 | extern int nfs41_init_clientid(struct nfs_client *, struct rpc_cred *); | ||
206 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 216 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
207 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 217 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
208 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 218 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -218,9 +228,11 @@ extern int nfs4_setup_sequence(struct nfs_client *clp, | |||
218 | int cache_reply, struct rpc_task *task); | 228 | int cache_reply, struct rpc_task *task); |
219 | extern void nfs4_destroy_session(struct nfs4_session *session); | 229 | extern void nfs4_destroy_session(struct nfs4_session *session); |
220 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | 230 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); |
221 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | 231 | extern int nfs4_proc_create_session(struct nfs_client *); |
222 | extern int nfs4_proc_destroy_session(struct nfs4_session *); | 232 | extern int nfs4_proc_destroy_session(struct nfs4_session *); |
223 | extern int nfs4_init_session(struct nfs_server *server); | 233 | extern int nfs4_init_session(struct nfs_server *server); |
234 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | ||
235 | struct nfs_fsinfo *fsinfo); | ||
224 | #else /* CONFIG_NFS_v4_1 */ | 236 | #else /* CONFIG_NFS_v4_1 */ |
225 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | 237 | static inline int nfs4_setup_sequence(struct nfs_client *clp, |
226 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | 238 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, |
@@ -267,6 +279,9 @@ extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t); | |||
267 | extern void nfs4_schedule_state_recovery(struct nfs_client *); | 279 | extern void nfs4_schedule_state_recovery(struct nfs_client *); |
268 | extern void nfs4_schedule_state_manager(struct nfs_client *); | 280 | extern void nfs4_schedule_state_manager(struct nfs_client *); |
269 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); | 281 | extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state); |
282 | extern int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state); | ||
283 | extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); | ||
284 | extern void nfs41_handle_recall_slot(struct nfs_client *clp); | ||
270 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); | 285 | extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); |
271 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); | 286 | extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); |
272 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); | 287 | extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t); |
@@ -275,6 +290,7 @@ extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter); | |||
275 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); | 290 | extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task); |
276 | extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); | 291 | extern void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid); |
277 | extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); | 292 | extern void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid); |
293 | extern void nfs_release_seqid(struct nfs_seqid *seqid); | ||
278 | extern void nfs_free_seqid(struct nfs_seqid *seqid); | 294 | extern void nfs_free_seqid(struct nfs_seqid *seqid); |
279 | 295 | ||
280 | extern const nfs4_stateid zero_stateid; | 296 | extern const nfs4_stateid zero_stateid; |
@@ -287,6 +303,7 @@ struct nfs4_mount_data; | |||
287 | 303 | ||
288 | /* callback_xdr.c */ | 304 | /* callback_xdr.c */ |
289 | extern struct svc_version nfs4_callback_version1; | 305 | extern struct svc_version nfs4_callback_version1; |
306 | extern struct svc_version nfs4_callback_version4; | ||
290 | 307 | ||
291 | #else | 308 | #else |
292 | 309 | ||
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index fa3408f20112..f071d12c613b 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/namei.h> | 12 | #include <linux/namei.h> |
13 | #include <linux/nfs_fs.h> | 13 | #include <linux/nfs_fs.h> |
14 | #include <linux/slab.h> | ||
14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
15 | #include <linux/sunrpc/clnt.h> | 16 | #include <linux/sunrpc/clnt.h> |
16 | #include <linux/vfs.h> | 17 | #include <linux/vfs.h> |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 741a562177fc..071fcedd517c 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <linux/errno.h> | 40 | #include <linux/errno.h> |
41 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/slab.h> | ||
42 | #include <linux/sunrpc/clnt.h> | 43 | #include <linux/sunrpc/clnt.h> |
43 | #include <linux/nfs.h> | 44 | #include <linux/nfs.h> |
44 | #include <linux/nfs4.h> | 45 | #include <linux/nfs4.h> |
@@ -64,6 +65,7 @@ | |||
64 | 65 | ||
65 | struct nfs4_opendata; | 66 | struct nfs4_opendata; |
66 | static int _nfs4_proc_open(struct nfs4_opendata *data); | 67 | static int _nfs4_proc_open(struct nfs4_opendata *data); |
68 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data); | ||
67 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); | 69 | static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); |
68 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); | 70 | static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *); |
69 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); | 71 | static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr); |
@@ -248,19 +250,15 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
248 | if (state == NULL) | 250 | if (state == NULL) |
249 | break; | 251 | break; |
250 | nfs4_state_mark_reclaim_nograce(clp, state); | 252 | nfs4_state_mark_reclaim_nograce(clp, state); |
251 | case -NFS4ERR_STALE_CLIENTID: | 253 | goto do_state_recovery; |
252 | case -NFS4ERR_STALE_STATEID: | 254 | case -NFS4ERR_STALE_STATEID: |
253 | case -NFS4ERR_EXPIRED: | 255 | if (state == NULL) |
254 | nfs4_schedule_state_recovery(clp); | ||
255 | ret = nfs4_wait_clnt_recover(clp); | ||
256 | if (ret == 0) | ||
257 | exception->retry = 1; | ||
258 | #if !defined(CONFIG_NFS_V4_1) | ||
259 | break; | ||
260 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
261 | if (!nfs4_has_session(server->nfs_client)) | ||
262 | break; | 256 | break; |
263 | /* FALLTHROUGH */ | 257 | nfs4_state_mark_reclaim_reboot(clp, state); |
258 | case -NFS4ERR_STALE_CLIENTID: | ||
259 | case -NFS4ERR_EXPIRED: | ||
260 | goto do_state_recovery; | ||
261 | #if defined(CONFIG_NFS_V4_1) | ||
264 | case -NFS4ERR_BADSESSION: | 262 | case -NFS4ERR_BADSESSION: |
265 | case -NFS4ERR_BADSLOT: | 263 | case -NFS4ERR_BADSLOT: |
266 | case -NFS4ERR_BAD_HIGH_SLOT: | 264 | case -NFS4ERR_BAD_HIGH_SLOT: |
@@ -270,13 +268,21 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
270 | case -NFS4ERR_SEQ_MISORDERED: | 268 | case -NFS4ERR_SEQ_MISORDERED: |
271 | dprintk("%s ERROR: %d Reset session\n", __func__, | 269 | dprintk("%s ERROR: %d Reset session\n", __func__, |
272 | errorcode); | 270 | errorcode); |
273 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 271 | nfs4_schedule_state_recovery(clp); |
274 | exception->retry = 1; | 272 | exception->retry = 1; |
275 | /* FALLTHROUGH */ | 273 | break; |
276 | #endif /* !defined(CONFIG_NFS_V4_1) */ | 274 | #endif /* defined(CONFIG_NFS_V4_1) */ |
277 | case -NFS4ERR_FILE_OPEN: | 275 | case -NFS4ERR_FILE_OPEN: |
276 | if (exception->timeout > HZ) { | ||
277 | /* We have retried a decent amount, time to | ||
278 | * fail | ||
279 | */ | ||
280 | ret = -EBUSY; | ||
281 | break; | ||
282 | } | ||
278 | case -NFS4ERR_GRACE: | 283 | case -NFS4ERR_GRACE: |
279 | case -NFS4ERR_DELAY: | 284 | case -NFS4ERR_DELAY: |
285 | case -EKEYEXPIRED: | ||
280 | ret = nfs4_delay(server->client, &exception->timeout); | 286 | ret = nfs4_delay(server->client, &exception->timeout); |
281 | if (ret != 0) | 287 | if (ret != 0) |
282 | break; | 288 | break; |
@@ -285,6 +291,12 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
285 | } | 291 | } |
286 | /* We failed to handle the error */ | 292 | /* We failed to handle the error */ |
287 | return nfs4_map_errors(ret); | 293 | return nfs4_map_errors(ret); |
294 | do_state_recovery: | ||
295 | nfs4_schedule_state_recovery(clp); | ||
296 | ret = nfs4_wait_clnt_recover(clp); | ||
297 | if (ret == 0) | ||
298 | exception->retry = 1; | ||
299 | return ret; | ||
288 | } | 300 | } |
289 | 301 | ||
290 | 302 | ||
@@ -311,48 +323,67 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
311 | * so we need to scan down from highest_used_slotid to 0 looking for the now | 323 | * so we need to scan down from highest_used_slotid to 0 looking for the now |
312 | * highest slotid in use. | 324 | * highest slotid in use. |
313 | * If none found, highest_used_slotid is set to -1. | 325 | * If none found, highest_used_slotid is set to -1. |
326 | * | ||
327 | * Must be called while holding tbl->slot_tbl_lock | ||
314 | */ | 328 | */ |
315 | static void | 329 | static void |
316 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | 330 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) |
317 | { | 331 | { |
318 | int slotid = free_slotid; | 332 | int slotid = free_slotid; |
319 | 333 | ||
320 | spin_lock(&tbl->slot_tbl_lock); | ||
321 | /* clear used bit in bitmap */ | 334 | /* clear used bit in bitmap */ |
322 | __clear_bit(slotid, tbl->used_slots); | 335 | __clear_bit(slotid, tbl->used_slots); |
323 | 336 | ||
324 | /* update highest_used_slotid when it is freed */ | 337 | /* update highest_used_slotid when it is freed */ |
325 | if (slotid == tbl->highest_used_slotid) { | 338 | if (slotid == tbl->highest_used_slotid) { |
326 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | 339 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); |
327 | if (slotid >= 0 && slotid < tbl->max_slots) | 340 | if (slotid < tbl->max_slots) |
328 | tbl->highest_used_slotid = slotid; | 341 | tbl->highest_used_slotid = slotid; |
329 | else | 342 | else |
330 | tbl->highest_used_slotid = -1; | 343 | tbl->highest_used_slotid = -1; |
331 | } | 344 | } |
332 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
333 | spin_unlock(&tbl->slot_tbl_lock); | ||
334 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | 345 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, |
335 | free_slotid, tbl->highest_used_slotid); | 346 | free_slotid, tbl->highest_used_slotid); |
336 | } | 347 | } |
337 | 348 | ||
338 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | 349 | /* |
339 | struct nfs4_sequence_res *res) | 350 | * Signal state manager thread if session is drained |
351 | */ | ||
352 | static void nfs41_check_drain_session_complete(struct nfs4_session *ses) | ||
340 | { | 353 | { |
341 | struct nfs4_slot_table *tbl; | 354 | struct rpc_task *task; |
342 | 355 | ||
343 | if (!nfs4_has_session(clp)) { | 356 | if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) { |
344 | dprintk("%s: No session\n", __func__); | 357 | task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq); |
358 | if (task) | ||
359 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
345 | return; | 360 | return; |
346 | } | 361 | } |
362 | |||
363 | if (ses->fc_slot_table.highest_used_slotid != -1) | ||
364 | return; | ||
365 | |||
366 | dprintk("%s COMPLETE: Session Drained\n", __func__); | ||
367 | complete(&ses->complete); | ||
368 | } | ||
369 | |||
370 | static void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
371 | struct nfs4_sequence_res *res) | ||
372 | { | ||
373 | struct nfs4_slot_table *tbl; | ||
374 | |||
347 | tbl = &clp->cl_session->fc_slot_table; | 375 | tbl = &clp->cl_session->fc_slot_table; |
348 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | 376 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { |
349 | dprintk("%s: No slot\n", __func__); | ||
350 | /* just wake up the next guy waiting since | 377 | /* just wake up the next guy waiting since |
351 | * we may have not consumed a slot after all */ | 378 | * we may have not consumed a slot after all */ |
352 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | 379 | dprintk("%s: No slot\n", __func__); |
353 | return; | 380 | return; |
354 | } | 381 | } |
382 | |||
383 | spin_lock(&tbl->slot_tbl_lock); | ||
355 | nfs4_free_slot(tbl, res->sr_slotid); | 384 | nfs4_free_slot(tbl, res->sr_slotid); |
385 | nfs41_check_drain_session_complete(clp->cl_session); | ||
386 | spin_unlock(&tbl->slot_tbl_lock); | ||
356 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 387 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
357 | } | 388 | } |
358 | 389 | ||
@@ -377,10 +408,10 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
377 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | 408 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) |
378 | goto out; | 409 | goto out; |
379 | 410 | ||
380 | tbl = &clp->cl_session->fc_slot_table; | 411 | /* Check the SEQUENCE operation status */ |
381 | slot = tbl->slots + res->sr_slotid; | ||
382 | |||
383 | if (res->sr_status == 0) { | 412 | if (res->sr_status == 0) { |
413 | tbl = &clp->cl_session->fc_slot_table; | ||
414 | slot = tbl->slots + res->sr_slotid; | ||
384 | /* Update the slot's sequence and clientid lease timer */ | 415 | /* Update the slot's sequence and clientid lease timer */ |
385 | ++slot->seq_nr; | 416 | ++slot->seq_nr; |
386 | timestamp = res->sr_renewal_time; | 417 | timestamp = res->sr_renewal_time; |
@@ -388,7 +419,9 @@ static void nfs41_sequence_done(struct nfs_client *clp, | |||
388 | if (time_before(clp->cl_last_renewal, timestamp)) | 419 | if (time_before(clp->cl_last_renewal, timestamp)) |
389 | clp->cl_last_renewal = timestamp; | 420 | clp->cl_last_renewal = timestamp; |
390 | spin_unlock(&clp->cl_lock); | 421 | spin_unlock(&clp->cl_lock); |
391 | return; | 422 | /* Check sequence flags */ |
423 | if (atomic_read(&clp->cl_count) > 1) | ||
424 | nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags); | ||
392 | } | 425 | } |
393 | out: | 426 | out: |
394 | /* The session may be reset by one of the error handlers. */ | 427 | /* The session may be reset by one of the error handlers. */ |
@@ -407,7 +440,7 @@ out: | |||
407 | * Note: must be called with under the slot_tbl_lock. | 440 | * Note: must be called with under the slot_tbl_lock. |
408 | */ | 441 | */ |
409 | static u8 | 442 | static u8 |
410 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | 443 | nfs4_find_slot(struct nfs4_slot_table *tbl) |
411 | { | 444 | { |
412 | int slotid; | 445 | int slotid; |
413 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | 446 | u8 ret_id = NFS4_MAX_SLOT_TABLE; |
@@ -429,24 +462,6 @@ out: | |||
429 | return ret_id; | 462 | return ret_id; |
430 | } | 463 | } |
431 | 464 | ||
432 | static int nfs4_recover_session(struct nfs4_session *session) | ||
433 | { | ||
434 | struct nfs_client *clp = session->clp; | ||
435 | unsigned int loop; | ||
436 | int ret; | ||
437 | |||
438 | for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) { | ||
439 | ret = nfs4_wait_clnt_recover(clp); | ||
440 | if (ret != 0) | ||
441 | break; | ||
442 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
443 | break; | ||
444 | nfs4_schedule_state_manager(clp); | ||
445 | ret = -EIO; | ||
446 | } | ||
447 | return ret; | ||
448 | } | ||
449 | |||
450 | static int nfs41_setup_sequence(struct nfs4_session *session, | 465 | static int nfs41_setup_sequence(struct nfs4_session *session, |
451 | struct nfs4_sequence_args *args, | 466 | struct nfs4_sequence_args *args, |
452 | struct nfs4_sequence_res *res, | 467 | struct nfs4_sequence_res *res, |
@@ -455,7 +470,6 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
455 | { | 470 | { |
456 | struct nfs4_slot *slot; | 471 | struct nfs4_slot *slot; |
457 | struct nfs4_slot_table *tbl; | 472 | struct nfs4_slot_table *tbl; |
458 | int status = 0; | ||
459 | u8 slotid; | 473 | u8 slotid; |
460 | 474 | ||
461 | dprintk("--> %s\n", __func__); | 475 | dprintk("--> %s\n", __func__); |
@@ -468,24 +482,27 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
468 | tbl = &session->fc_slot_table; | 482 | tbl = &session->fc_slot_table; |
469 | 483 | ||
470 | spin_lock(&tbl->slot_tbl_lock); | 484 | spin_lock(&tbl->slot_tbl_lock); |
471 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | 485 | if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) && |
472 | if (tbl->highest_used_slotid != -1) { | 486 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
473 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 487 | /* |
474 | spin_unlock(&tbl->slot_tbl_lock); | 488 | * The state manager will wait until the slot table is empty. |
475 | dprintk("<-- %s: Session reset: draining\n", __func__); | 489 | * Schedule the reset thread |
476 | return -EAGAIN; | 490 | */ |
477 | } | 491 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
492 | spin_unlock(&tbl->slot_tbl_lock); | ||
493 | dprintk("%s Schedule Session Reset\n", __func__); | ||
494 | return -EAGAIN; | ||
495 | } | ||
478 | 496 | ||
479 | /* The slot table is empty; start the reset thread */ | 497 | if (!rpc_queue_empty(&tbl->slot_tbl_waitq) && |
480 | dprintk("%s Session Reset\n", __func__); | 498 | !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) { |
499 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
481 | spin_unlock(&tbl->slot_tbl_lock); | 500 | spin_unlock(&tbl->slot_tbl_lock); |
482 | status = nfs4_recover_session(session); | 501 | dprintk("%s enforce FIFO order\n", __func__); |
483 | if (status) | 502 | return -EAGAIN; |
484 | return status; | ||
485 | spin_lock(&tbl->slot_tbl_lock); | ||
486 | } | 503 | } |
487 | 504 | ||
488 | slotid = nfs4_find_slot(tbl, task); | 505 | slotid = nfs4_find_slot(tbl); |
489 | if (slotid == NFS4_MAX_SLOT_TABLE) { | 506 | if (slotid == NFS4_MAX_SLOT_TABLE) { |
490 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | 507 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); |
491 | spin_unlock(&tbl->slot_tbl_lock); | 508 | spin_unlock(&tbl->slot_tbl_lock); |
@@ -494,6 +511,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
494 | } | 511 | } |
495 | spin_unlock(&tbl->slot_tbl_lock); | 512 | spin_unlock(&tbl->slot_tbl_lock); |
496 | 513 | ||
514 | rpc_task_set_priority(task, RPC_PRIORITY_NORMAL); | ||
497 | slot = tbl->slots + slotid; | 515 | slot = tbl->slots + slotid; |
498 | args->sa_session = session; | 516 | args->sa_session = session; |
499 | args->sa_slotid = slotid; | 517 | args->sa_slotid = slotid; |
@@ -527,7 +545,7 @@ int nfs4_setup_sequence(struct nfs_client *clp, | |||
527 | goto out; | 545 | goto out; |
528 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | 546 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, |
529 | task); | 547 | task); |
530 | if (ret != -EAGAIN) { | 548 | if (ret && ret != -EAGAIN) { |
531 | /* terminate rpc task */ | 549 | /* terminate rpc task */ |
532 | task->tk_status = ret; | 550 | task->tk_status = ret; |
533 | task->tk_action = NULL; | 551 | task->tk_action = NULL; |
@@ -556,12 +574,17 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | |||
556 | rpc_call_start(task); | 574 | rpc_call_start(task); |
557 | } | 575 | } |
558 | 576 | ||
577 | static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata) | ||
578 | { | ||
579 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
580 | nfs41_call_sync_prepare(task, calldata); | ||
581 | } | ||
582 | |||
559 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | 583 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) |
560 | { | 584 | { |
561 | struct nfs41_call_sync_data *data = calldata; | 585 | struct nfs41_call_sync_data *data = calldata; |
562 | 586 | ||
563 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | 587 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); |
564 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
565 | } | 588 | } |
566 | 589 | ||
567 | struct rpc_call_ops nfs41_call_sync_ops = { | 590 | struct rpc_call_ops nfs41_call_sync_ops = { |
@@ -569,12 +592,18 @@ struct rpc_call_ops nfs41_call_sync_ops = { | |||
569 | .rpc_call_done = nfs41_call_sync_done, | 592 | .rpc_call_done = nfs41_call_sync_done, |
570 | }; | 593 | }; |
571 | 594 | ||
595 | struct rpc_call_ops nfs41_call_priv_sync_ops = { | ||
596 | .rpc_call_prepare = nfs41_call_priv_sync_prepare, | ||
597 | .rpc_call_done = nfs41_call_sync_done, | ||
598 | }; | ||
599 | |||
572 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | 600 | static int nfs4_call_sync_sequence(struct nfs_client *clp, |
573 | struct rpc_clnt *clnt, | 601 | struct rpc_clnt *clnt, |
574 | struct rpc_message *msg, | 602 | struct rpc_message *msg, |
575 | struct nfs4_sequence_args *args, | 603 | struct nfs4_sequence_args *args, |
576 | struct nfs4_sequence_res *res, | 604 | struct nfs4_sequence_res *res, |
577 | int cache_reply) | 605 | int cache_reply, |
606 | int privileged) | ||
578 | { | 607 | { |
579 | int ret; | 608 | int ret; |
580 | struct rpc_task *task; | 609 | struct rpc_task *task; |
@@ -592,6 +621,8 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp, | |||
592 | }; | 621 | }; |
593 | 622 | ||
594 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 623 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
624 | if (privileged) | ||
625 | task_setup.callback_ops = &nfs41_call_priv_sync_ops; | ||
595 | task = rpc_run_task(&task_setup); | 626 | task = rpc_run_task(&task_setup); |
596 | if (IS_ERR(task)) | 627 | if (IS_ERR(task)) |
597 | ret = PTR_ERR(task); | 628 | ret = PTR_ERR(task); |
@@ -609,7 +640,7 @@ int _nfs4_call_sync_session(struct nfs_server *server, | |||
609 | int cache_reply) | 640 | int cache_reply) |
610 | { | 641 | { |
611 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | 642 | return nfs4_call_sync_sequence(server->nfs_client, server->client, |
612 | msg, args, res, cache_reply); | 643 | msg, args, res, cache_reply, 0); |
613 | } | 644 | } |
614 | 645 | ||
615 | #endif /* CONFIG_NFS_V4_1 */ | 646 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -637,15 +668,6 @@ static void nfs4_sequence_done(const struct nfs_server *server, | |||
637 | #endif /* CONFIG_NFS_V4_1 */ | 668 | #endif /* CONFIG_NFS_V4_1 */ |
638 | } | 669 | } |
639 | 670 | ||
640 | /* no restart, therefore free slot here */ | ||
641 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
642 | struct nfs4_sequence_res *res, | ||
643 | int rpc_status) | ||
644 | { | ||
645 | nfs4_sequence_done(server, res, rpc_status); | ||
646 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
647 | } | ||
648 | |||
649 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 671 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
650 | { | 672 | { |
651 | struct nfs_inode *nfsi = NFS_I(dir); | 673 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -705,8 +727,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
705 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); | 727 | p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); |
706 | if (p->o_arg.seqid == NULL) | 728 | if (p->o_arg.seqid == NULL) |
707 | goto err_free; | 729 | goto err_free; |
708 | p->path.mnt = mntget(path->mnt); | 730 | path_get(path); |
709 | p->path.dentry = dget(path->dentry); | 731 | p->path = *path; |
710 | p->dir = parent; | 732 | p->dir = parent; |
711 | p->owner = sp; | 733 | p->owner = sp; |
712 | atomic_inc(&sp->so_count); | 734 | atomic_inc(&sp->so_count); |
@@ -720,9 +742,15 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
720 | p->o_arg.bitmask = server->attr_bitmask; | 742 | p->o_arg.bitmask = server->attr_bitmask; |
721 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 743 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
722 | if (flags & O_EXCL) { | 744 | if (flags & O_EXCL) { |
723 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 745 | if (nfs4_has_persistent_session(server->nfs_client)) { |
724 | s[0] = jiffies; | 746 | /* GUARDED */ |
725 | s[1] = current->pid; | 747 | p->o_arg.u.attrs = &p->attrs; |
748 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | ||
749 | } else { /* EXCLUSIVE4_1 */ | ||
750 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | ||
751 | s[0] = jiffies; | ||
752 | s[1] = current->pid; | ||
753 | } | ||
726 | } else if (flags & O_CREAT) { | 754 | } else if (flags & O_CREAT) { |
727 | p->o_arg.u.attrs = &p->attrs; | 755 | p->o_arg.u.attrs = &p->attrs; |
728 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); | 756 | memcpy(&p->attrs, attrs, sizeof(p->attrs)); |
@@ -776,13 +804,16 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode | |||
776 | goto out; | 804 | goto out; |
777 | switch (mode & (FMODE_READ|FMODE_WRITE)) { | 805 | switch (mode & (FMODE_READ|FMODE_WRITE)) { |
778 | case FMODE_READ: | 806 | case FMODE_READ: |
779 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0; | 807 | ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 |
808 | && state->n_rdonly != 0; | ||
780 | break; | 809 | break; |
781 | case FMODE_WRITE: | 810 | case FMODE_WRITE: |
782 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0; | 811 | ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0 |
812 | && state->n_wronly != 0; | ||
783 | break; | 813 | break; |
784 | case FMODE_READ|FMODE_WRITE: | 814 | case FMODE_READ|FMODE_WRITE: |
785 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0; | 815 | ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0 |
816 | && state->n_rdwr != 0; | ||
786 | } | 817 | } |
787 | out: | 818 | out: |
788 | return ret; | 819 | return ret; |
@@ -1047,7 +1078,7 @@ static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmod | |||
1047 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); | 1078 | memset(&opendata->o_res, 0, sizeof(opendata->o_res)); |
1048 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); | 1079 | memset(&opendata->c_res, 0, sizeof(opendata->c_res)); |
1049 | nfs4_init_opendata_res(opendata); | 1080 | nfs4_init_opendata_res(opendata); |
1050 | ret = _nfs4_proc_open(opendata); | 1081 | ret = _nfs4_recover_proc_open(opendata); |
1051 | if (ret != 0) | 1082 | if (ret != 0) |
1052 | return ret; | 1083 | return ret; |
1053 | newstate = nfs4_opendata_to_nfs4_state(opendata); | 1084 | newstate = nfs4_opendata_to_nfs4_state(opendata); |
@@ -1135,7 +1166,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state | |||
1135 | int err; | 1166 | int err; |
1136 | do { | 1167 | do { |
1137 | err = _nfs4_do_open_reclaim(ctx, state); | 1168 | err = _nfs4_do_open_reclaim(ctx, state); |
1138 | if (err != -NFS4ERR_DELAY) | 1169 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
1139 | break; | 1170 | break; |
1140 | nfs4_handle_exception(server, err, &exception); | 1171 | nfs4_handle_exception(server, err, &exception); |
1141 | } while (exception.retry); | 1172 | } while (exception.retry); |
@@ -1183,6 +1214,14 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state | |||
1183 | case -ENOENT: | 1214 | case -ENOENT: |
1184 | case -ESTALE: | 1215 | case -ESTALE: |
1185 | goto out; | 1216 | goto out; |
1217 | case -NFS4ERR_BADSESSION: | ||
1218 | case -NFS4ERR_BADSLOT: | ||
1219 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1220 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1221 | case -NFS4ERR_DEADSESSION: | ||
1222 | nfs4_schedule_state_recovery( | ||
1223 | server->nfs_client); | ||
1224 | goto out; | ||
1186 | case -NFS4ERR_STALE_CLIENTID: | 1225 | case -NFS4ERR_STALE_CLIENTID: |
1187 | case -NFS4ERR_STALE_STATEID: | 1226 | case -NFS4ERR_STALE_STATEID: |
1188 | case -NFS4ERR_EXPIRED: | 1227 | case -NFS4ERR_EXPIRED: |
@@ -1330,14 +1369,20 @@ out_no_action: | |||
1330 | 1369 | ||
1331 | } | 1370 | } |
1332 | 1371 | ||
1372 | static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata) | ||
1373 | { | ||
1374 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
1375 | nfs4_open_prepare(task, calldata); | ||
1376 | } | ||
1377 | |||
1333 | static void nfs4_open_done(struct rpc_task *task, void *calldata) | 1378 | static void nfs4_open_done(struct rpc_task *task, void *calldata) |
1334 | { | 1379 | { |
1335 | struct nfs4_opendata *data = calldata; | 1380 | struct nfs4_opendata *data = calldata; |
1336 | 1381 | ||
1337 | data->rpc_status = task->tk_status; | 1382 | data->rpc_status = task->tk_status; |
1338 | 1383 | ||
1339 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | 1384 | nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res, |
1340 | task->tk_status); | 1385 | task->tk_status); |
1341 | 1386 | ||
1342 | if (RPC_ASSASSINATED(task)) | 1387 | if (RPC_ASSASSINATED(task)) |
1343 | return; | 1388 | return; |
@@ -1388,10 +1433,13 @@ static const struct rpc_call_ops nfs4_open_ops = { | |||
1388 | .rpc_release = nfs4_open_release, | 1433 | .rpc_release = nfs4_open_release, |
1389 | }; | 1434 | }; |
1390 | 1435 | ||
1391 | /* | 1436 | static const struct rpc_call_ops nfs4_recover_open_ops = { |
1392 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | 1437 | .rpc_call_prepare = nfs4_recover_open_prepare, |
1393 | */ | 1438 | .rpc_call_done = nfs4_open_done, |
1394 | static int _nfs4_proc_open(struct nfs4_opendata *data) | 1439 | .rpc_release = nfs4_open_release, |
1440 | }; | ||
1441 | |||
1442 | static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) | ||
1395 | { | 1443 | { |
1396 | struct inode *dir = data->dir->d_inode; | 1444 | struct inode *dir = data->dir->d_inode; |
1397 | struct nfs_server *server = NFS_SERVER(dir); | 1445 | struct nfs_server *server = NFS_SERVER(dir); |
@@ -1418,27 +1466,65 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) | |||
1418 | data->rpc_done = 0; | 1466 | data->rpc_done = 0; |
1419 | data->rpc_status = 0; | 1467 | data->rpc_status = 0; |
1420 | data->cancelled = 0; | 1468 | data->cancelled = 0; |
1469 | if (isrecover) | ||
1470 | task_setup_data.callback_ops = &nfs4_recover_open_ops; | ||
1421 | task = rpc_run_task(&task_setup_data); | 1471 | task = rpc_run_task(&task_setup_data); |
1422 | if (IS_ERR(task)) | 1472 | if (IS_ERR(task)) |
1423 | return PTR_ERR(task); | 1473 | return PTR_ERR(task); |
1424 | status = nfs4_wait_for_completion_rpc_task(task); | 1474 | status = nfs4_wait_for_completion_rpc_task(task); |
1425 | if (status != 0) { | 1475 | if (status != 0) { |
1426 | data->cancelled = 1; | 1476 | data->cancelled = 1; |
1427 | smp_wmb(); | 1477 | smp_wmb(); |
1428 | } else | 1478 | } else |
1429 | status = data->rpc_status; | 1479 | status = data->rpc_status; |
1430 | rpc_put_task(task); | 1480 | rpc_put_task(task); |
1481 | |||
1482 | return status; | ||
1483 | } | ||
1484 | |||
1485 | static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | ||
1486 | { | ||
1487 | struct inode *dir = data->dir->d_inode; | ||
1488 | struct nfs_openres *o_res = &data->o_res; | ||
1489 | int status; | ||
1490 | |||
1491 | status = nfs4_run_open_task(data, 1); | ||
1431 | if (status != 0 || !data->rpc_done) | 1492 | if (status != 0 || !data->rpc_done) |
1432 | return status; | 1493 | return status; |
1433 | 1494 | ||
1434 | if (o_res->fh.size == 0) | 1495 | nfs_refresh_inode(dir, o_res->dir_attr); |
1435 | _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); | 1496 | |
1497 | if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | ||
1498 | status = _nfs4_proc_open_confirm(data); | ||
1499 | if (status != 0) | ||
1500 | return status; | ||
1501 | } | ||
1502 | |||
1503 | return status; | ||
1504 | } | ||
1505 | |||
1506 | /* | ||
1507 | * Note: On error, nfs4_proc_open will free the struct nfs4_opendata | ||
1508 | */ | ||
1509 | static int _nfs4_proc_open(struct nfs4_opendata *data) | ||
1510 | { | ||
1511 | struct inode *dir = data->dir->d_inode; | ||
1512 | struct nfs_server *server = NFS_SERVER(dir); | ||
1513 | struct nfs_openargs *o_arg = &data->o_arg; | ||
1514 | struct nfs_openres *o_res = &data->o_res; | ||
1515 | int status; | ||
1516 | |||
1517 | status = nfs4_run_open_task(data, 0); | ||
1518 | if (status != 0 || !data->rpc_done) | ||
1519 | return status; | ||
1436 | 1520 | ||
1437 | if (o_arg->open_flags & O_CREAT) { | 1521 | if (o_arg->open_flags & O_CREAT) { |
1438 | update_changeattr(dir, &o_res->cinfo); | 1522 | update_changeattr(dir, &o_res->cinfo); |
1439 | nfs_post_op_update_inode(dir, o_res->dir_attr); | 1523 | nfs_post_op_update_inode(dir, o_res->dir_attr); |
1440 | } else | 1524 | } else |
1441 | 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; | ||
1442 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { | 1528 | if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) { |
1443 | status = _nfs4_proc_open_confirm(data); | 1529 | status = _nfs4_proc_open_confirm(data); |
1444 | if (status != 0) | 1530 | if (status != 0) |
@@ -1488,7 +1574,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s | |||
1488 | return ret; | 1574 | return ret; |
1489 | } | 1575 | } |
1490 | 1576 | ||
1491 | static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) | 1577 | static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) |
1492 | { | 1578 | { |
1493 | struct nfs_server *server = NFS_SERVER(state->inode); | 1579 | struct nfs_server *server = NFS_SERVER(state->inode); |
1494 | struct nfs4_exception exception = { }; | 1580 | struct nfs4_exception exception = { }; |
@@ -1496,10 +1582,17 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4 | |||
1496 | 1582 | ||
1497 | do { | 1583 | do { |
1498 | err = _nfs4_open_expired(ctx, state); | 1584 | err = _nfs4_open_expired(ctx, state); |
1499 | if (err != -NFS4ERR_DELAY) | 1585 | switch (err) { |
1500 | break; | 1586 | default: |
1501 | nfs4_handle_exception(server, err, &exception); | 1587 | goto out; |
1588 | case -NFS4ERR_GRACE: | ||
1589 | case -NFS4ERR_DELAY: | ||
1590 | case -EKEYEXPIRED: | ||
1591 | nfs4_handle_exception(server, err, &exception); | ||
1592 | err = 0; | ||
1593 | } | ||
1502 | } while (exception.retry); | 1594 | } while (exception.retry); |
1595 | out: | ||
1503 | return err; | 1596 | return err; |
1504 | } | 1597 | } |
1505 | 1598 | ||
@@ -1573,6 +1666,8 @@ static int _nfs4_do_open(struct inode *dir, struct path *path, fmode_t fmode, in | |||
1573 | status = PTR_ERR(state); | 1666 | status = PTR_ERR(state); |
1574 | if (IS_ERR(state)) | 1667 | if (IS_ERR(state)) |
1575 | goto err_opendata_put; | 1668 | goto err_opendata_put; |
1669 | if (server->caps & NFS_CAP_POSIX_LOCK) | ||
1670 | set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); | ||
1576 | nfs4_opendata_put(opendata); | 1671 | nfs4_opendata_put(opendata); |
1577 | nfs4_put_state_owner(sp); | 1672 | nfs4_put_state_owner(sp); |
1578 | *res = state; | 1673 | *res = state; |
@@ -1712,6 +1807,18 @@ static void nfs4_free_closedata(void *data) | |||
1712 | kfree(calldata); | 1807 | kfree(calldata); |
1713 | } | 1808 | } |
1714 | 1809 | ||
1810 | static void nfs4_close_clear_stateid_flags(struct nfs4_state *state, | ||
1811 | fmode_t fmode) | ||
1812 | { | ||
1813 | spin_lock(&state->owner->so_lock); | ||
1814 | if (!(fmode & FMODE_READ)) | ||
1815 | clear_bit(NFS_O_RDONLY_STATE, &state->flags); | ||
1816 | if (!(fmode & FMODE_WRITE)) | ||
1817 | clear_bit(NFS_O_WRONLY_STATE, &state->flags); | ||
1818 | clear_bit(NFS_O_RDWR_STATE, &state->flags); | ||
1819 | spin_unlock(&state->owner->so_lock); | ||
1820 | } | ||
1821 | |||
1715 | static void nfs4_close_done(struct rpc_task *task, void *data) | 1822 | static void nfs4_close_done(struct rpc_task *task, void *data) |
1716 | { | 1823 | { |
1717 | struct nfs4_closedata *calldata = data; | 1824 | struct nfs4_closedata *calldata = data; |
@@ -1728,6 +1835,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1728 | case 0: | 1835 | case 0: |
1729 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); | 1836 | nfs_set_open_stateid(state, &calldata->res.stateid, 0); |
1730 | renew_lease(server, calldata->timestamp); | 1837 | renew_lease(server, calldata->timestamp); |
1838 | nfs4_close_clear_stateid_flags(state, | ||
1839 | calldata->arg.fmode); | ||
1731 | break; | 1840 | break; |
1732 | case -NFS4ERR_STALE_STATEID: | 1841 | case -NFS4ERR_STALE_STATEID: |
1733 | case -NFS4ERR_OLD_STATEID: | 1842 | case -NFS4ERR_OLD_STATEID: |
@@ -1736,12 +1845,10 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1736 | if (calldata->arg.fmode == 0) | 1845 | if (calldata->arg.fmode == 0) |
1737 | break; | 1846 | break; |
1738 | default: | 1847 | default: |
1739 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1848 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) |
1740 | nfs4_restart_rpc(task, server->nfs_client); | 1849 | rpc_restart_call_prepare(task); |
1741 | return; | ||
1742 | } | ||
1743 | } | 1850 | } |
1744 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | 1851 | nfs_release_seqid(calldata->arg.seqid); |
1745 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1852 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1746 | } | 1853 | } |
1747 | 1854 | ||
@@ -1749,38 +1856,39 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1749 | { | 1856 | { |
1750 | struct nfs4_closedata *calldata = data; | 1857 | struct nfs4_closedata *calldata = data; |
1751 | struct nfs4_state *state = calldata->state; | 1858 | struct nfs4_state *state = calldata->state; |
1752 | int clear_rd, clear_wr, clear_rdwr; | 1859 | int call_close = 0; |
1753 | 1860 | ||
1754 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) | 1861 | if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0) |
1755 | return; | 1862 | return; |
1756 | 1863 | ||
1757 | clear_rd = clear_wr = clear_rdwr = 0; | 1864 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; |
1865 | calldata->arg.fmode = FMODE_READ|FMODE_WRITE; | ||
1758 | spin_lock(&state->owner->so_lock); | 1866 | spin_lock(&state->owner->so_lock); |
1759 | /* Calculate the change in open mode */ | 1867 | /* Calculate the change in open mode */ |
1760 | if (state->n_rdwr == 0) { | 1868 | if (state->n_rdwr == 0) { |
1761 | if (state->n_rdonly == 0) { | 1869 | if (state->n_rdonly == 0) { |
1762 | clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags); | 1870 | call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags); |
1763 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1871 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); |
1872 | calldata->arg.fmode &= ~FMODE_READ; | ||
1764 | } | 1873 | } |
1765 | if (state->n_wronly == 0) { | 1874 | if (state->n_wronly == 0) { |
1766 | clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags); | 1875 | call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags); |
1767 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1876 | call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags); |
1877 | calldata->arg.fmode &= ~FMODE_WRITE; | ||
1768 | } | 1878 | } |
1769 | } | 1879 | } |
1770 | spin_unlock(&state->owner->so_lock); | 1880 | spin_unlock(&state->owner->so_lock); |
1771 | if (!clear_rd && !clear_wr && !clear_rdwr) { | 1881 | |
1882 | if (!call_close) { | ||
1772 | /* Note: exit _without_ calling nfs4_close_done */ | 1883 | /* Note: exit _without_ calling nfs4_close_done */ |
1773 | task->tk_action = NULL; | 1884 | task->tk_action = NULL; |
1774 | return; | 1885 | return; |
1775 | } | 1886 | } |
1887 | |||
1888 | if (calldata->arg.fmode == 0) | ||
1889 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; | ||
1890 | |||
1776 | nfs_fattr_init(calldata->res.fattr); | 1891 | nfs_fattr_init(calldata->res.fattr); |
1777 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) { | ||
1778 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1779 | calldata->arg.fmode = FMODE_READ; | ||
1780 | } else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) { | ||
1781 | task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE]; | ||
1782 | calldata->arg.fmode = FMODE_WRITE; | ||
1783 | } | ||
1784 | calldata->timestamp = jiffies; | 1892 | calldata->timestamp = jiffies; |
1785 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | 1893 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, |
1786 | &calldata->arg.seq_args, &calldata->res.seq_res, | 1894 | &calldata->arg.seq_args, &calldata->res.seq_res, |
@@ -1832,8 +1940,6 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1832 | calldata->state = state; | 1940 | calldata->state = state; |
1833 | calldata->arg.fh = NFS_FH(state->inode); | 1941 | calldata->arg.fh = NFS_FH(state->inode); |
1834 | calldata->arg.stateid = &state->open_stateid; | 1942 | calldata->arg.stateid = &state->open_stateid; |
1835 | if (nfs4_has_session(server->nfs_client)) | ||
1836 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1837 | /* Serialization for the sequence id */ | 1943 | /* Serialization for the sequence id */ |
1838 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1944 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1839 | if (calldata->arg.seqid == NULL) | 1945 | if (calldata->arg.seqid == NULL) |
@@ -1844,8 +1950,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1844 | calldata->res.seqid = calldata->arg.seqid; | 1950 | calldata->res.seqid = calldata->arg.seqid; |
1845 | calldata->res.server = server; | 1951 | calldata->res.server = server; |
1846 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | 1952 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; |
1847 | calldata->path.mnt = mntget(path->mnt); | 1953 | path_get(path); |
1848 | calldata->path.dentry = dget(path->dentry); | 1954 | calldata->path = *path; |
1849 | 1955 | ||
1850 | msg.rpc_argp = &calldata->arg, | 1956 | msg.rpc_argp = &calldata->arg, |
1851 | msg.rpc_resp = &calldata->res, | 1957 | msg.rpc_resp = &calldata->res, |
@@ -1964,8 +2070,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st | |||
1964 | case -EDQUOT: | 2070 | case -EDQUOT: |
1965 | case -ENOSPC: | 2071 | case -ENOSPC: |
1966 | case -EROFS: | 2072 | case -EROFS: |
1967 | lookup_instantiate_filp(nd, (struct dentry *)state, NULL); | 2073 | return PTR_ERR(state); |
1968 | return 1; | ||
1969 | default: | 2074 | default: |
1970 | goto out_drop; | 2075 | goto out_drop; |
1971 | } | 2076 | } |
@@ -1981,7 +2086,7 @@ out_drop: | |||
1981 | return 0; | 2086 | return 0; |
1982 | } | 2087 | } |
1983 | 2088 | ||
1984 | void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | 2089 | static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) |
1985 | { | 2090 | { |
1986 | if (ctx->state == NULL) | 2091 | if (ctx->state == NULL) |
1987 | return; | 2092 | return; |
@@ -2532,7 +2637,6 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2532 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | 2637 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); |
2533 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2638 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2534 | return 0; | 2639 | return 0; |
2535 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2536 | update_changeattr(dir, &res->cinfo); | 2640 | update_changeattr(dir, &res->cinfo); |
2537 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2641 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2538 | return 1; | 2642 | return 1; |
@@ -2971,11 +3075,10 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2971 | 3075 | ||
2972 | dprintk("--> %s\n", __func__); | 3076 | dprintk("--> %s\n", __func__); |
2973 | 3077 | ||
2974 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2975 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | 3078 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); |
2976 | 3079 | ||
2977 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 3080 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2978 | nfs4_restart_rpc(task, server->nfs_client); | 3081 | nfs_restart_rpc(task, server->nfs_client); |
2979 | return -EAGAIN; | 3082 | return -EAGAIN; |
2980 | } | 3083 | } |
2981 | 3084 | ||
@@ -2995,12 +3098,11 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2995 | { | 3098 | { |
2996 | struct inode *inode = data->inode; | 3099 | struct inode *inode = data->inode; |
2997 | 3100 | ||
2998 | /* slot is freed in nfs_writeback_done */ | ||
2999 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3101 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3000 | task->tk_status); | 3102 | task->tk_status); |
3001 | 3103 | ||
3002 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 3104 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
3003 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3105 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3004 | return -EAGAIN; | 3106 | return -EAGAIN; |
3005 | } | 3107 | } |
3006 | if (task->tk_status >= 0) { | 3108 | if (task->tk_status >= 0) { |
@@ -3028,11 +3130,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
3028 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | 3130 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, |
3029 | task->tk_status); | 3131 | task->tk_status); |
3030 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3132 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
3031 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); | 3133 | nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
3032 | return -EAGAIN; | 3134 | return -EAGAIN; |
3033 | } | 3135 | } |
3034 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3035 | &data->res.seq_res); | ||
3036 | nfs_refresh_inode(inode, data->res.fattr); | 3136 | nfs_refresh_inode(inode, data->res.fattr); |
3037 | return 0; | 3137 | return 0; |
3038 | } | 3138 | } |
@@ -3050,10 +3150,19 @@ static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_messa | |||
3050 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special | 3150 | * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special |
3051 | * standalone procedure for queueing an asynchronous RENEW. | 3151 | * standalone procedure for queueing an asynchronous RENEW. |
3052 | */ | 3152 | */ |
3153 | static void nfs4_renew_release(void *data) | ||
3154 | { | ||
3155 | struct nfs_client *clp = data; | ||
3156 | |||
3157 | if (atomic_read(&clp->cl_count) > 1) | ||
3158 | nfs4_schedule_state_renewal(clp); | ||
3159 | nfs_put_client(clp); | ||
3160 | } | ||
3161 | |||
3053 | static void nfs4_renew_done(struct rpc_task *task, void *data) | 3162 | static void nfs4_renew_done(struct rpc_task *task, void *data) |
3054 | { | 3163 | { |
3055 | struct nfs_client *clp = (struct nfs_client *)task->tk_msg.rpc_argp; | 3164 | struct nfs_client *clp = data; |
3056 | unsigned long timestamp = (unsigned long)data; | 3165 | unsigned long timestamp = task->tk_start; |
3057 | 3166 | ||
3058 | if (task->tk_status < 0) { | 3167 | if (task->tk_status < 0) { |
3059 | /* Unless we're shutting down, schedule state recovery! */ | 3168 | /* Unless we're shutting down, schedule state recovery! */ |
@@ -3069,6 +3178,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
3069 | 3178 | ||
3070 | static const struct rpc_call_ops nfs4_renew_ops = { | 3179 | static const struct rpc_call_ops nfs4_renew_ops = { |
3071 | .rpc_call_done = nfs4_renew_done, | 3180 | .rpc_call_done = nfs4_renew_done, |
3181 | .rpc_release = nfs4_renew_release, | ||
3072 | }; | 3182 | }; |
3073 | 3183 | ||
3074 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3184 | int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3079,8 +3189,10 @@ int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred) | |||
3079 | .rpc_cred = cred, | 3189 | .rpc_cred = cred, |
3080 | }; | 3190 | }; |
3081 | 3191 | ||
3192 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
3193 | return -EIO; | ||
3082 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | 3194 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, |
3083 | &nfs4_renew_ops, (void *)jiffies); | 3195 | &nfs4_renew_ops, clp); |
3084 | } | 3196 | } |
3085 | 3197 | ||
3086 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) | 3198 | int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred) |
@@ -3331,15 +3443,14 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3331 | if (state == NULL) | 3443 | if (state == NULL) |
3332 | break; | 3444 | break; |
3333 | nfs4_state_mark_reclaim_nograce(clp, state); | 3445 | nfs4_state_mark_reclaim_nograce(clp, state); |
3334 | case -NFS4ERR_STALE_CLIENTID: | 3446 | goto do_state_recovery; |
3335 | case -NFS4ERR_STALE_STATEID: | 3447 | case -NFS4ERR_STALE_STATEID: |
3448 | if (state == NULL) | ||
3449 | break; | ||
3450 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
3451 | case -NFS4ERR_STALE_CLIENTID: | ||
3336 | case -NFS4ERR_EXPIRED: | 3452 | case -NFS4ERR_EXPIRED: |
3337 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | 3453 | goto do_state_recovery; |
3338 | nfs4_schedule_state_recovery(clp); | ||
3339 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3340 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3341 | task->tk_status = 0; | ||
3342 | return -EAGAIN; | ||
3343 | #if defined(CONFIG_NFS_V4_1) | 3454 | #if defined(CONFIG_NFS_V4_1) |
3344 | case -NFS4ERR_BADSESSION: | 3455 | case -NFS4ERR_BADSESSION: |
3345 | case -NFS4ERR_BADSLOT: | 3456 | case -NFS4ERR_BADSLOT: |
@@ -3350,7 +3461,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3350 | case -NFS4ERR_SEQ_MISORDERED: | 3461 | case -NFS4ERR_SEQ_MISORDERED: |
3351 | dprintk("%s ERROR %d, Reset session\n", __func__, | 3462 | dprintk("%s ERROR %d, Reset session\n", __func__, |
3352 | task->tk_status); | 3463 | task->tk_status); |
3353 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 3464 | nfs4_schedule_state_recovery(clp); |
3354 | task->tk_status = 0; | 3465 | task->tk_status = 0; |
3355 | return -EAGAIN; | 3466 | return -EAGAIN; |
3356 | #endif /* CONFIG_NFS_V4_1 */ | 3467 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -3358,6 +3469,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3358 | if (server) | 3469 | if (server) |
3359 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3470 | nfs_inc_server_stats(server, NFSIOS_DELAY); |
3360 | case -NFS4ERR_GRACE: | 3471 | case -NFS4ERR_GRACE: |
3472 | case -EKEYEXPIRED: | ||
3361 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3473 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
3362 | task->tk_status = 0; | 3474 | task->tk_status = 0; |
3363 | return -EAGAIN; | 3475 | return -EAGAIN; |
@@ -3367,6 +3479,13 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
3367 | } | 3479 | } |
3368 | task->tk_status = nfs4_map_errors(task->tk_status); | 3480 | task->tk_status = nfs4_map_errors(task->tk_status); |
3369 | return 0; | 3481 | return 0; |
3482 | do_state_recovery: | ||
3483 | rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL); | ||
3484 | nfs4_schedule_state_recovery(clp); | ||
3485 | if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0) | ||
3486 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | ||
3487 | task->tk_status = 0; | ||
3488 | return -EAGAIN; | ||
3370 | } | 3489 | } |
3371 | 3490 | ||
3372 | static int | 3491 | static int |
@@ -3463,6 +3582,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp, struct rpc_cred *cred) | |||
3463 | case -NFS4ERR_RESOURCE: | 3582 | case -NFS4ERR_RESOURCE: |
3464 | /* The IBM lawyers misread another document! */ | 3583 | /* The IBM lawyers misread another document! */ |
3465 | case -NFS4ERR_DELAY: | 3584 | case -NFS4ERR_DELAY: |
3585 | case -EKEYEXPIRED: | ||
3466 | err = nfs4_delay(clp->cl_rpcclient, &timeout); | 3586 | err = nfs4_delay(clp->cl_rpcclient, &timeout); |
3467 | } | 3587 | } |
3468 | } while (err == 0); | 3588 | } while (err == 0); |
@@ -3483,12 +3603,23 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
3483 | { | 3603 | { |
3484 | struct nfs4_delegreturndata *data = calldata; | 3604 | struct nfs4_delegreturndata *data = calldata; |
3485 | 3605 | ||
3486 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | 3606 | nfs4_sequence_done(data->res.server, &data->res.seq_res, |
3487 | task->tk_status); | 3607 | task->tk_status); |
3488 | 3608 | ||
3489 | data->rpc_status = task->tk_status; | 3609 | switch (task->tk_status) { |
3490 | if (data->rpc_status == 0) | 3610 | case -NFS4ERR_STALE_STATEID: |
3611 | case -NFS4ERR_EXPIRED: | ||
3612 | case 0: | ||
3491 | renew_lease(data->res.server, data->timestamp); | 3613 | renew_lease(data->res.server, data->timestamp); |
3614 | break; | ||
3615 | default: | ||
3616 | if (nfs4_async_handle_error(task, data->res.server, NULL) == | ||
3617 | -EAGAIN) { | ||
3618 | nfs_restart_rpc(task, data->res.server->nfs_client); | ||
3619 | return; | ||
3620 | } | ||
3621 | } | ||
3622 | data->rpc_status = task->tk_status; | ||
3492 | } | 3623 | } |
3493 | 3624 | ||
3494 | static void nfs4_delegreturn_release(void *calldata) | 3625 | static void nfs4_delegreturn_release(void *calldata) |
@@ -3741,11 +3872,9 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3741 | break; | 3872 | break; |
3742 | default: | 3873 | default: |
3743 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3874 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3744 | nfs4_restart_rpc(task, | 3875 | nfs_restart_rpc(task, |
3745 | calldata->server->nfs_client); | 3876 | calldata->server->nfs_client); |
3746 | } | 3877 | } |
3747 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3748 | &calldata->res.seq_res); | ||
3749 | } | 3878 | } |
3750 | 3879 | ||
3751 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3880 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3921,14 +4050,20 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3921 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 4050 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3922 | } | 4051 | } |
3923 | 4052 | ||
4053 | static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata) | ||
4054 | { | ||
4055 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
4056 | nfs4_lock_prepare(task, calldata); | ||
4057 | } | ||
4058 | |||
3924 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) | 4059 | static void nfs4_lock_done(struct rpc_task *task, void *calldata) |
3925 | { | 4060 | { |
3926 | struct nfs4_lockdata *data = calldata; | 4061 | struct nfs4_lockdata *data = calldata; |
3927 | 4062 | ||
3928 | dprintk("%s: begin!\n", __func__); | 4063 | dprintk("%s: begin!\n", __func__); |
3929 | 4064 | ||
3930 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | 4065 | nfs4_sequence_done(data->server, &data->res.seq_res, |
3931 | task->tk_status); | 4066 | task->tk_status); |
3932 | 4067 | ||
3933 | data->rpc_status = task->tk_status; | 4068 | data->rpc_status = task->tk_status; |
3934 | if (RPC_ASSASSINATED(task)) | 4069 | if (RPC_ASSASSINATED(task)) |
@@ -3976,7 +4111,35 @@ static const struct rpc_call_ops nfs4_lock_ops = { | |||
3976 | .rpc_release = nfs4_lock_release, | 4111 | .rpc_release = nfs4_lock_release, |
3977 | }; | 4112 | }; |
3978 | 4113 | ||
3979 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int reclaim) | 4114 | static const struct rpc_call_ops nfs4_recover_lock_ops = { |
4115 | .rpc_call_prepare = nfs4_recover_lock_prepare, | ||
4116 | .rpc_call_done = nfs4_lock_done, | ||
4117 | .rpc_release = nfs4_lock_release, | ||
4118 | }; | ||
4119 | |||
4120 | static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error) | ||
4121 | { | ||
4122 | struct nfs_client *clp = server->nfs_client; | ||
4123 | struct nfs4_state *state = lsp->ls_state; | ||
4124 | |||
4125 | switch (error) { | ||
4126 | case -NFS4ERR_ADMIN_REVOKED: | ||
4127 | case -NFS4ERR_BAD_STATEID: | ||
4128 | case -NFS4ERR_EXPIRED: | ||
4129 | if (new_lock_owner != 0 || | ||
4130 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4131 | nfs4_state_mark_reclaim_nograce(clp, state); | ||
4132 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4133 | break; | ||
4134 | case -NFS4ERR_STALE_STATEID: | ||
4135 | if (new_lock_owner != 0 || | ||
4136 | (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) | ||
4137 | nfs4_state_mark_reclaim_reboot(clp, state); | ||
4138 | lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED; | ||
4139 | }; | ||
4140 | } | ||
4141 | |||
4142 | static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type) | ||
3980 | { | 4143 | { |
3981 | struct nfs4_lockdata *data; | 4144 | struct nfs4_lockdata *data; |
3982 | struct rpc_task *task; | 4145 | struct rpc_task *task; |
@@ -4000,8 +4163,11 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4000 | return -ENOMEM; | 4163 | return -ENOMEM; |
4001 | if (IS_SETLKW(cmd)) | 4164 | if (IS_SETLKW(cmd)) |
4002 | data->arg.block = 1; | 4165 | data->arg.block = 1; |
4003 | if (reclaim != 0) | 4166 | if (recovery_type > NFS_LOCK_NEW) { |
4004 | data->arg.reclaim = 1; | 4167 | if (recovery_type == NFS_LOCK_RECLAIM) |
4168 | data->arg.reclaim = NFS_LOCK_RECLAIM; | ||
4169 | task_setup_data.callback_ops = &nfs4_recover_lock_ops; | ||
4170 | } | ||
4005 | msg.rpc_argp = &data->arg, | 4171 | msg.rpc_argp = &data->arg, |
4006 | msg.rpc_resp = &data->res, | 4172 | msg.rpc_resp = &data->res, |
4007 | task_setup_data.callback_data = data; | 4173 | task_setup_data.callback_data = data; |
@@ -4011,6 +4177,9 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f | |||
4011 | ret = nfs4_wait_for_completion_rpc_task(task); | 4177 | ret = nfs4_wait_for_completion_rpc_task(task); |
4012 | if (ret == 0) { | 4178 | if (ret == 0) { |
4013 | ret = data->rpc_status; | 4179 | ret = data->rpc_status; |
4180 | if (ret) | ||
4181 | nfs4_handle_setlk_error(data->server, data->lsp, | ||
4182 | data->arg.new_lock_owner, ret); | ||
4014 | } else | 4183 | } else |
4015 | data->cancelled = 1; | 4184 | data->cancelled = 1; |
4016 | rpc_put_task(task); | 4185 | rpc_put_task(task); |
@@ -4028,8 +4197,8 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request | |||
4028 | /* Cache the lock if possible... */ | 4197 | /* Cache the lock if possible... */ |
4029 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4198 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4030 | return 0; | 4199 | return 0; |
4031 | err = _nfs4_do_setlk(state, F_SETLK, request, 1); | 4200 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM); |
4032 | if (err != -NFS4ERR_DELAY) | 4201 | if (err != -NFS4ERR_DELAY && err != -EKEYEXPIRED) |
4033 | break; | 4202 | break; |
4034 | nfs4_handle_exception(server, err, &exception); | 4203 | nfs4_handle_exception(server, err, &exception); |
4035 | } while (exception.retry); | 4204 | } while (exception.retry); |
@@ -4048,11 +4217,18 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
4048 | do { | 4217 | do { |
4049 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) | 4218 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) |
4050 | return 0; | 4219 | return 0; |
4051 | err = _nfs4_do_setlk(state, F_SETLK, request, 0); | 4220 | err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED); |
4052 | if (err != -NFS4ERR_DELAY) | 4221 | switch (err) { |
4053 | break; | 4222 | default: |
4054 | nfs4_handle_exception(server, err, &exception); | 4223 | goto out; |
4224 | case -NFS4ERR_GRACE: | ||
4225 | case -NFS4ERR_DELAY: | ||
4226 | case -EKEYEXPIRED: | ||
4227 | nfs4_handle_exception(server, err, &exception); | ||
4228 | err = 0; | ||
4229 | } | ||
4055 | } while (exception.retry); | 4230 | } while (exception.retry); |
4231 | out: | ||
4056 | return err; | 4232 | return err; |
4057 | } | 4233 | } |
4058 | 4234 | ||
@@ -4060,8 +4236,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4060 | { | 4236 | { |
4061 | struct nfs_inode *nfsi = NFS_I(state->inode); | 4237 | struct nfs_inode *nfsi = NFS_I(state->inode); |
4062 | unsigned char fl_flags = request->fl_flags; | 4238 | unsigned char fl_flags = request->fl_flags; |
4063 | int status; | 4239 | int status = -ENOLCK; |
4064 | 4240 | ||
4241 | if ((fl_flags & FL_POSIX) && | ||
4242 | !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags)) | ||
4243 | goto out; | ||
4065 | /* Is this a delegated open? */ | 4244 | /* Is this a delegated open? */ |
4066 | status = nfs4_set_lock_state(state, request); | 4245 | status = nfs4_set_lock_state(state, request); |
4067 | if (status != 0) | 4246 | if (status != 0) |
@@ -4078,7 +4257,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock | |||
4078 | status = do_vfs_lock(request->fl_file, request); | 4257 | status = do_vfs_lock(request->fl_file, request); |
4079 | goto out_unlock; | 4258 | goto out_unlock; |
4080 | } | 4259 | } |
4081 | status = _nfs4_do_setlk(state, cmd, request, 0); | 4260 | status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW); |
4082 | if (status != 0) | 4261 | if (status != 0) |
4083 | goto out_unlock; | 4262 | goto out_unlock; |
4084 | /* Note: we always want to sleep here! */ | 4263 | /* Note: we always want to sleep here! */ |
@@ -4161,7 +4340,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4161 | if (err != 0) | 4340 | if (err != 0) |
4162 | goto out; | 4341 | goto out; |
4163 | do { | 4342 | do { |
4164 | err = _nfs4_do_setlk(state, F_SETLK, fl, 0); | 4343 | err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW); |
4165 | switch (err) { | 4344 | switch (err) { |
4166 | default: | 4345 | default: |
4167 | printk(KERN_ERR "%s: unhandled error %d.\n", | 4346 | printk(KERN_ERR "%s: unhandled error %d.\n", |
@@ -4172,6 +4351,11 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4172 | case -NFS4ERR_EXPIRED: | 4351 | case -NFS4ERR_EXPIRED: |
4173 | case -NFS4ERR_STALE_CLIENTID: | 4352 | case -NFS4ERR_STALE_CLIENTID: |
4174 | case -NFS4ERR_STALE_STATEID: | 4353 | case -NFS4ERR_STALE_STATEID: |
4354 | case -NFS4ERR_BADSESSION: | ||
4355 | case -NFS4ERR_BADSLOT: | ||
4356 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
4357 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
4358 | case -NFS4ERR_DEADSESSION: | ||
4175 | nfs4_schedule_state_recovery(server->nfs_client); | 4359 | nfs4_schedule_state_recovery(server->nfs_client); |
4176 | goto out; | 4360 | goto out; |
4177 | case -ERESTARTSYS: | 4361 | case -ERESTARTSYS: |
@@ -4191,6 +4375,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) | |||
4191 | err = 0; | 4375 | err = 0; |
4192 | goto out; | 4376 | goto out; |
4193 | case -NFS4ERR_DELAY: | 4377 | case -NFS4ERR_DELAY: |
4378 | case -EKEYEXPIRED: | ||
4194 | break; | 4379 | break; |
4195 | } | 4380 | } |
4196 | err = nfs4_handle_exception(server, err, &exception); | 4381 | err = nfs4_handle_exception(server, err, &exception); |
@@ -4296,7 +4481,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4296 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | 4481 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore |
4297 | * be in some phase of session reset. | 4482 | * be in some phase of session reset. |
4298 | */ | 4483 | */ |
4299 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | 4484 | int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) |
4300 | { | 4485 | { |
4301 | nfs4_verifier verifier; | 4486 | nfs4_verifier verifier; |
4302 | struct nfs41_exchange_id_args args = { | 4487 | struct nfs41_exchange_id_args args = { |
@@ -4318,6 +4503,9 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4318 | dprintk("--> %s\n", __func__); | 4503 | dprintk("--> %s\n", __func__); |
4319 | BUG_ON(clp == NULL); | 4504 | BUG_ON(clp == NULL); |
4320 | 4505 | ||
4506 | /* Remove server-only flags */ | ||
4507 | args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R; | ||
4508 | |||
4321 | p = (u32 *)verifier.data; | 4509 | p = (u32 *)verifier.data; |
4322 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | 4510 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); |
4323 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | 4511 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); |
@@ -4333,7 +4521,7 @@ static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | |||
4333 | 4521 | ||
4334 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | 4522 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); |
4335 | 4523 | ||
4336 | if (status != NFS4ERR_CLID_INUSE) | 4524 | if (status != -NFS4ERR_CLID_INUSE) |
4337 | break; | 4525 | break; |
4338 | 4526 | ||
4339 | if (signalled()) | 4527 | if (signalled()) |
@@ -4361,11 +4549,12 @@ static void nfs4_get_lease_time_prepare(struct rpc_task *task, | |||
4361 | (struct nfs4_get_lease_time_data *)calldata; | 4549 | (struct nfs4_get_lease_time_data *)calldata; |
4362 | 4550 | ||
4363 | dprintk("--> %s\n", __func__); | 4551 | dprintk("--> %s\n", __func__); |
4552 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
4364 | /* just setup sequence, do not trigger session recovery | 4553 | /* just setup sequence, do not trigger session recovery |
4365 | since we're invoked within one */ | 4554 | since we're invoked within one */ |
4366 | ret = nfs41_setup_sequence(data->clp->cl_session, | 4555 | ret = nfs41_setup_sequence(data->clp->cl_session, |
4367 | &data->args->la_seq_args, | 4556 | &data->args->la_seq_args, |
4368 | &data->res->lr_seq_res, 0, task); | 4557 | &data->res->lr_seq_res, 0, task); |
4369 | 4558 | ||
4370 | BUG_ON(ret == -EAGAIN); | 4559 | BUG_ON(ret == -EAGAIN); |
4371 | rpc_call_start(task); | 4560 | rpc_call_start(task); |
@@ -4386,13 +4575,13 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | |||
4386 | switch (task->tk_status) { | 4575 | switch (task->tk_status) { |
4387 | case -NFS4ERR_DELAY: | 4576 | case -NFS4ERR_DELAY: |
4388 | case -NFS4ERR_GRACE: | 4577 | case -NFS4ERR_GRACE: |
4578 | case -EKEYEXPIRED: | ||
4389 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | 4579 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); |
4390 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | 4580 | rpc_delay(task, NFS4_POLL_RETRY_MIN); |
4391 | task->tk_status = 0; | 4581 | task->tk_status = 0; |
4392 | nfs4_restart_rpc(task, data->clp); | 4582 | nfs_restart_rpc(task, data->clp); |
4393 | return; | 4583 | return; |
4394 | } | 4584 | } |
4395 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4396 | dprintk("<-- %s\n", __func__); | 4585 | dprintk("<-- %s\n", __func__); |
4397 | } | 4586 | } |
4398 | 4587 | ||
@@ -4444,28 +4633,33 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | |||
4444 | /* | 4633 | /* |
4445 | * Reset a slot table | 4634 | * Reset a slot table |
4446 | */ | 4635 | */ |
4447 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | 4636 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs, |
4448 | int old_max_slots, int ivalue) | 4637 | int ivalue) |
4449 | { | 4638 | { |
4639 | struct nfs4_slot *new = NULL; | ||
4450 | int i; | 4640 | int i; |
4451 | int ret = 0; | 4641 | int ret = 0; |
4452 | 4642 | ||
4453 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | 4643 | dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__, |
4644 | max_reqs, tbl->max_slots); | ||
4454 | 4645 | ||
4455 | /* | 4646 | /* Does the newly negotiated max_reqs match the existing slot table? */ |
4456 | * Until we have dynamic slot table adjustment, insist | 4647 | if (max_reqs != tbl->max_slots) { |
4457 | * upon the same slot table size | 4648 | ret = -ENOMEM; |
4458 | */ | 4649 | new = kmalloc(max_reqs * sizeof(struct nfs4_slot), |
4459 | if (max_slots != old_max_slots) { | 4650 | GFP_KERNEL); |
4460 | dprintk("%s reset slot table does't match old\n", | 4651 | if (!new) |
4461 | __func__); | 4652 | goto out; |
4462 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | 4653 | ret = 0; |
4463 | goto out; | 4654 | kfree(tbl->slots); |
4464 | } | 4655 | } |
4465 | spin_lock(&tbl->slot_tbl_lock); | 4656 | spin_lock(&tbl->slot_tbl_lock); |
4466 | for (i = 0; i < max_slots; ++i) | 4657 | if (new) { |
4658 | tbl->slots = new; | ||
4659 | tbl->max_slots = max_reqs; | ||
4660 | } | ||
4661 | for (i = 0; i < tbl->max_slots; ++i) | ||
4467 | tbl->slots[i].seq_nr = ivalue; | 4662 | tbl->slots[i].seq_nr = ivalue; |
4468 | tbl->highest_used_slotid = -1; | ||
4469 | spin_unlock(&tbl->slot_tbl_lock); | 4663 | spin_unlock(&tbl->slot_tbl_lock); |
4470 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | 4664 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, |
4471 | tbl, tbl->slots, tbl->max_slots); | 4665 | tbl, tbl->slots, tbl->max_slots); |
@@ -4482,16 +4676,12 @@ static int nfs4_reset_slot_tables(struct nfs4_session *session) | |||
4482 | int status; | 4676 | int status; |
4483 | 4677 | ||
4484 | status = nfs4_reset_slot_table(&session->fc_slot_table, | 4678 | status = nfs4_reset_slot_table(&session->fc_slot_table, |
4485 | session->fc_attrs.max_reqs, | 4679 | session->fc_attrs.max_reqs, 1); |
4486 | session->fc_slot_table.max_slots, | ||
4487 | 1); | ||
4488 | if (status) | 4680 | if (status) |
4489 | return status; | 4681 | return status; |
4490 | 4682 | ||
4491 | status = nfs4_reset_slot_table(&session->bc_slot_table, | 4683 | status = nfs4_reset_slot_table(&session->bc_slot_table, |
4492 | session->bc_attrs.max_reqs, | 4684 | session->bc_attrs.max_reqs, 0); |
4493 | session->bc_slot_table.max_slots, | ||
4494 | 0); | ||
4495 | return status; | 4685 | return status; |
4496 | } | 4686 | } |
4497 | 4687 | ||
@@ -4515,7 +4705,6 @@ static void nfs4_destroy_slot_tables(struct nfs4_session *session) | |||
4515 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | 4705 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, |
4516 | int max_slots, int ivalue) | 4706 | int max_slots, int ivalue) |
4517 | { | 4707 | { |
4518 | int i; | ||
4519 | struct nfs4_slot *slot; | 4708 | struct nfs4_slot *slot; |
4520 | int ret = -ENOMEM; | 4709 | int ret = -ENOMEM; |
4521 | 4710 | ||
@@ -4526,18 +4715,9 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4526 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | 4715 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); |
4527 | if (!slot) | 4716 | if (!slot) |
4528 | goto out; | 4717 | goto out; |
4529 | for (i = 0; i < max_slots; ++i) | ||
4530 | slot[i].seq_nr = ivalue; | ||
4531 | ret = 0; | 4718 | ret = 0; |
4532 | 4719 | ||
4533 | spin_lock(&tbl->slot_tbl_lock); | 4720 | spin_lock(&tbl->slot_tbl_lock); |
4534 | if (tbl->slots != NULL) { | ||
4535 | spin_unlock(&tbl->slot_tbl_lock); | ||
4536 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4537 | __func__, tbl, tbl->slots); | ||
4538 | WARN_ON(1); | ||
4539 | goto out_free; | ||
4540 | } | ||
4541 | tbl->max_slots = max_slots; | 4721 | tbl->max_slots = max_slots; |
4542 | tbl->slots = slot; | 4722 | tbl->slots = slot; |
4543 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | 4723 | tbl->highest_used_slotid = -1; /* no slot is currently used */ |
@@ -4547,10 +4727,6 @@ static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | |||
4547 | out: | 4727 | out: |
4548 | dprintk("<-- %s: return %d\n", __func__, ret); | 4728 | dprintk("<-- %s: return %d\n", __func__, ret); |
4549 | return ret; | 4729 | return ret; |
4550 | |||
4551 | out_free: | ||
4552 | kfree(slot); | ||
4553 | goto out; | ||
4554 | } | 4730 | } |
4555 | 4731 | ||
4556 | /* | 4732 | /* |
@@ -4558,17 +4734,24 @@ out_free: | |||
4558 | */ | 4734 | */ |
4559 | static int nfs4_init_slot_tables(struct nfs4_session *session) | 4735 | static int nfs4_init_slot_tables(struct nfs4_session *session) |
4560 | { | 4736 | { |
4561 | int status; | 4737 | struct nfs4_slot_table *tbl; |
4738 | int status = 0; | ||
4562 | 4739 | ||
4563 | status = nfs4_init_slot_table(&session->fc_slot_table, | 4740 | tbl = &session->fc_slot_table; |
4564 | session->fc_attrs.max_reqs, 1); | 4741 | if (tbl->slots == NULL) { |
4565 | if (status) | 4742 | status = nfs4_init_slot_table(tbl, |
4566 | return status; | 4743 | session->fc_attrs.max_reqs, 1); |
4744 | if (status) | ||
4745 | return status; | ||
4746 | } | ||
4567 | 4747 | ||
4568 | status = nfs4_init_slot_table(&session->bc_slot_table, | 4748 | tbl = &session->bc_slot_table; |
4569 | session->bc_attrs.max_reqs, 0); | 4749 | if (tbl->slots == NULL) { |
4570 | if (status) | 4750 | status = nfs4_init_slot_table(tbl, |
4571 | nfs4_destroy_slot_tables(session); | 4751 | session->bc_attrs.max_reqs, 0); |
4752 | if (status) | ||
4753 | nfs4_destroy_slot_tables(session); | ||
4754 | } | ||
4572 | 4755 | ||
4573 | return status; | 4756 | return status; |
4574 | } | 4757 | } |
@@ -4582,7 +4765,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4582 | if (!session) | 4765 | if (!session) |
4583 | return NULL; | 4766 | return NULL; |
4584 | 4767 | ||
4585 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4586 | /* | 4768 | /* |
4587 | * The create session reply races with the server back | 4769 | * The create session reply races with the server back |
4588 | * channel probe. Mark the client NFS_CS_SESSION_INITING | 4770 | * channel probe. Mark the client NFS_CS_SESSION_INITING |
@@ -4590,12 +4772,15 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
4590 | * nfs_client struct | 4772 | * nfs_client struct |
4591 | */ | 4773 | */ |
4592 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | 4774 | clp->cl_cons_state = NFS_CS_SESSION_INITING; |
4775 | init_completion(&session->complete); | ||
4593 | 4776 | ||
4594 | tbl = &session->fc_slot_table; | 4777 | tbl = &session->fc_slot_table; |
4778 | tbl->highest_used_slotid = -1; | ||
4595 | spin_lock_init(&tbl->slot_tbl_lock); | 4779 | spin_lock_init(&tbl->slot_tbl_lock); |
4596 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | 4780 | rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); |
4597 | 4781 | ||
4598 | tbl = &session->bc_slot_table; | 4782 | tbl = &session->bc_slot_table; |
4783 | tbl->highest_used_slotid = -1; | ||
4599 | spin_lock_init(&tbl->slot_tbl_lock); | 4784 | spin_lock_init(&tbl->slot_tbl_lock); |
4600 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | 4785 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); |
4601 | 4786 | ||
@@ -4637,16 +4822,14 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
4637 | args->fc_attrs.headerpadsz = 0; | 4822 | args->fc_attrs.headerpadsz = 0; |
4638 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | 4823 | args->fc_attrs.max_rqst_sz = mxrqst_sz; |
4639 | args->fc_attrs.max_resp_sz = mxresp_sz; | 4824 | args->fc_attrs.max_resp_sz = mxresp_sz; |
4640 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4641 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | 4825 | args->fc_attrs.max_ops = NFS4_MAX_OPS; |
4642 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | 4826 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; |
4643 | 4827 | ||
4644 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | 4828 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " |
4645 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | 4829 | "max_ops=%u max_reqs=%u\n", |
4646 | __func__, | 4830 | __func__, |
4647 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | 4831 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, |
4648 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | 4832 | args->fc_attrs.max_ops, args->fc_attrs.max_reqs); |
4649 | args->fc_attrs.max_reqs); | ||
4650 | 4833 | ||
4651 | /* Back channel attributes */ | 4834 | /* Back channel attributes */ |
4652 | args->bc_attrs.headerpadsz = 0; | 4835 | args->bc_attrs.headerpadsz = 0; |
@@ -4747,11 +4930,10 @@ static int _nfs4_proc_create_session(struct nfs_client *clp) | |||
4747 | * It is the responsibility of the caller to verify the session is | 4930 | * It is the responsibility of the caller to verify the session is |
4748 | * expired before calling this routine. | 4931 | * expired before calling this routine. |
4749 | */ | 4932 | */ |
4750 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | 4933 | int nfs4_proc_create_session(struct nfs_client *clp) |
4751 | { | 4934 | { |
4752 | int status; | 4935 | int status; |
4753 | unsigned *ptr; | 4936 | unsigned *ptr; |
4754 | struct nfs_fsinfo fsinfo; | ||
4755 | struct nfs4_session *session = clp->cl_session; | 4937 | struct nfs4_session *session = clp->cl_session; |
4756 | 4938 | ||
4757 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | 4939 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); |
@@ -4760,35 +4942,19 @@ int nfs4_proc_create_session(struct nfs_client *clp, int reset) | |||
4760 | if (status) | 4942 | if (status) |
4761 | goto out; | 4943 | goto out; |
4762 | 4944 | ||
4763 | /* Init or reset the fore channel */ | 4945 | /* Init and reset the fore channel */ |
4764 | if (reset) | 4946 | status = nfs4_init_slot_tables(session); |
4765 | status = nfs4_reset_slot_tables(session); | 4947 | dprintk("slot table initialization returned %d\n", status); |
4766 | else | 4948 | if (status) |
4767 | status = nfs4_init_slot_tables(session); | 4949 | goto out; |
4768 | dprintk("fore channel slot table initialization returned %d\n", status); | 4950 | status = nfs4_reset_slot_tables(session); |
4951 | dprintk("slot table reset returned %d\n", status); | ||
4769 | if (status) | 4952 | if (status) |
4770 | goto out; | 4953 | goto out; |
4771 | 4954 | ||
4772 | ptr = (unsigned *)&session->sess_id.data[0]; | 4955 | ptr = (unsigned *)&session->sess_id.data[0]; |
4773 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | 4956 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, |
4774 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | 4957 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); |
4775 | |||
4776 | if (reset) | ||
4777 | /* Lease time is aleady set */ | ||
4778 | goto out; | ||
4779 | |||
4780 | /* Get the lease time */ | ||
4781 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4782 | if (status == 0) { | ||
4783 | /* Update lease time and schedule renewal */ | ||
4784 | spin_lock(&clp->cl_lock); | ||
4785 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4786 | clp->cl_last_renewal = jiffies; | ||
4787 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4788 | spin_unlock(&clp->cl_lock); | ||
4789 | |||
4790 | nfs4_schedule_state_renewal(clp); | ||
4791 | } | ||
4792 | out: | 4958 | out: |
4793 | dprintk("<-- %s\n", __func__); | 4959 | dprintk("<-- %s\n", __func__); |
4794 | return status; | 4960 | return status; |
@@ -4827,13 +4993,24 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
4827 | int nfs4_init_session(struct nfs_server *server) | 4993 | int nfs4_init_session(struct nfs_server *server) |
4828 | { | 4994 | { |
4829 | struct nfs_client *clp = server->nfs_client; | 4995 | struct nfs_client *clp = server->nfs_client; |
4996 | struct nfs4_session *session; | ||
4997 | unsigned int rsize, wsize; | ||
4830 | int ret; | 4998 | int ret; |
4831 | 4999 | ||
4832 | if (!nfs4_has_session(clp)) | 5000 | if (!nfs4_has_session(clp)) |
4833 | return 0; | 5001 | return 0; |
4834 | 5002 | ||
4835 | clp->cl_session->fc_attrs.max_rqst_sz = server->wsize; | 5003 | rsize = server->rsize; |
4836 | clp->cl_session->fc_attrs.max_resp_sz = server->rsize; | 5004 | if (rsize == 0) |
5005 | rsize = NFS_MAX_FILE_IO_SIZE; | ||
5006 | wsize = server->wsize; | ||
5007 | if (wsize == 0) | ||
5008 | wsize = NFS_MAX_FILE_IO_SIZE; | ||
5009 | |||
5010 | session = clp->cl_session; | ||
5011 | session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead; | ||
5012 | session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead; | ||
5013 | |||
4837 | ret = nfs4_recover_expired_lease(server); | 5014 | ret = nfs4_recover_expired_lease(server); |
4838 | if (!ret) | 5015 | if (!ret) |
4839 | ret = nfs4_check_client_ready(clp); | 5016 | ret = nfs4_check_client_ready(clp); |
@@ -4858,10 +5035,19 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | |||
4858 | args.sa_cache_this = 0; | 5035 | args.sa_cache_this = 0; |
4859 | 5036 | ||
4860 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | 5037 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, |
4861 | &res, 0); | 5038 | &res, args.sa_cache_this, 1); |
5039 | } | ||
5040 | |||
5041 | static void nfs41_sequence_release(void *data) | ||
5042 | { | ||
5043 | struct nfs_client *clp = (struct nfs_client *)data; | ||
5044 | |||
5045 | if (atomic_read(&clp->cl_count) > 1) | ||
5046 | nfs4_schedule_state_renewal(clp); | ||
5047 | nfs_put_client(clp); | ||
4862 | } | 5048 | } |
4863 | 5049 | ||
4864 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | 5050 | static void nfs41_sequence_call_done(struct rpc_task *task, void *data) |
4865 | { | 5051 | { |
4866 | struct nfs_client *clp = (struct nfs_client *)data; | 5052 | struct nfs_client *clp = (struct nfs_client *)data; |
4867 | 5053 | ||
@@ -4869,16 +5055,17 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data) | |||
4869 | 5055 | ||
4870 | if (task->tk_status < 0) { | 5056 | if (task->tk_status < 0) { |
4871 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | 5057 | dprintk("%s ERROR %d\n", __func__, task->tk_status); |
5058 | if (atomic_read(&clp->cl_count) == 1) | ||
5059 | goto out; | ||
4872 | 5060 | ||
4873 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | 5061 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) |
4874 | == -EAGAIN) { | 5062 | == -EAGAIN) { |
4875 | nfs4_restart_rpc(task, clp); | 5063 | nfs_restart_rpc(task, clp); |
4876 | return; | 5064 | return; |
4877 | } | 5065 | } |
4878 | } | 5066 | } |
4879 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4880 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | 5067 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); |
4881 | 5068 | out: | |
4882 | kfree(task->tk_msg.rpc_argp); | 5069 | kfree(task->tk_msg.rpc_argp); |
4883 | kfree(task->tk_msg.rpc_resp); | 5070 | kfree(task->tk_msg.rpc_resp); |
4884 | 5071 | ||
@@ -4903,6 +5090,7 @@ static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | |||
4903 | static const struct rpc_call_ops nfs41_sequence_ops = { | 5090 | static const struct rpc_call_ops nfs41_sequence_ops = { |
4904 | .rpc_call_done = nfs41_sequence_call_done, | 5091 | .rpc_call_done = nfs41_sequence_call_done, |
4905 | .rpc_call_prepare = nfs41_sequence_prepare, | 5092 | .rpc_call_prepare = nfs41_sequence_prepare, |
5093 | .rpc_release = nfs41_sequence_release, | ||
4906 | }; | 5094 | }; |
4907 | 5095 | ||
4908 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | 5096 | static int nfs41_proc_async_sequence(struct nfs_client *clp, |
@@ -4915,12 +5103,14 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
4915 | .rpc_cred = cred, | 5103 | .rpc_cred = cred, |
4916 | }; | 5104 | }; |
4917 | 5105 | ||
5106 | if (!atomic_inc_not_zero(&clp->cl_count)) | ||
5107 | return -EIO; | ||
4918 | args = kzalloc(sizeof(*args), GFP_KERNEL); | 5108 | args = kzalloc(sizeof(*args), GFP_KERNEL); |
4919 | if (!args) | ||
4920 | return -ENOMEM; | ||
4921 | res = kzalloc(sizeof(*res), GFP_KERNEL); | 5109 | res = kzalloc(sizeof(*res), GFP_KERNEL); |
4922 | if (!res) { | 5110 | if (!args || !res) { |
4923 | kfree(args); | 5111 | kfree(args); |
5112 | kfree(res); | ||
5113 | nfs_put_client(clp); | ||
4924 | return -ENOMEM; | 5114 | return -ENOMEM; |
4925 | } | 5115 | } |
4926 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | 5116 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; |
@@ -4931,6 +5121,113 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, | |||
4931 | &nfs41_sequence_ops, (void *)clp); | 5121 | &nfs41_sequence_ops, (void *)clp); |
4932 | } | 5122 | } |
4933 | 5123 | ||
5124 | struct nfs4_reclaim_complete_data { | ||
5125 | struct nfs_client *clp; | ||
5126 | struct nfs41_reclaim_complete_args arg; | ||
5127 | struct nfs41_reclaim_complete_res res; | ||
5128 | }; | ||
5129 | |||
5130 | static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data) | ||
5131 | { | ||
5132 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5133 | |||
5134 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
5135 | if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args, | ||
5136 | &calldata->res.seq_res, 0, task)) | ||
5137 | return; | ||
5138 | |||
5139 | rpc_call_start(task); | ||
5140 | } | ||
5141 | |||
5142 | static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data) | ||
5143 | { | ||
5144 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5145 | struct nfs_client *clp = calldata->clp; | ||
5146 | struct nfs4_sequence_res *res = &calldata->res.seq_res; | ||
5147 | |||
5148 | dprintk("--> %s\n", __func__); | ||
5149 | nfs41_sequence_done(clp, res, task->tk_status); | ||
5150 | switch (task->tk_status) { | ||
5151 | case 0: | ||
5152 | case -NFS4ERR_COMPLETE_ALREADY: | ||
5153 | break; | ||
5154 | case -NFS4ERR_BADSESSION: | ||
5155 | case -NFS4ERR_DEADSESSION: | ||
5156 | /* | ||
5157 | * Handle the session error, but do not retry the operation, as | ||
5158 | * we have no way of telling whether the clientid had to be | ||
5159 | * reset before we got our reply. If reset, a new wave of | ||
5160 | * reclaim operations will follow, containing their own reclaim | ||
5161 | * complete. We don't want our retry to get on the way of | ||
5162 | * recovery by incorrectly indicating to the server that we're | ||
5163 | * done reclaiming state since the process had to be restarted. | ||
5164 | */ | ||
5165 | _nfs4_async_handle_error(task, NULL, clp, NULL); | ||
5166 | break; | ||
5167 | default: | ||
5168 | if (_nfs4_async_handle_error( | ||
5169 | task, NULL, clp, NULL) == -EAGAIN) { | ||
5170 | rpc_restart_call_prepare(task); | ||
5171 | return; | ||
5172 | } | ||
5173 | } | ||
5174 | |||
5175 | dprintk("<-- %s\n", __func__); | ||
5176 | } | ||
5177 | |||
5178 | static void nfs4_free_reclaim_complete_data(void *data) | ||
5179 | { | ||
5180 | struct nfs4_reclaim_complete_data *calldata = data; | ||
5181 | |||
5182 | kfree(calldata); | ||
5183 | } | ||
5184 | |||
5185 | static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = { | ||
5186 | .rpc_call_prepare = nfs4_reclaim_complete_prepare, | ||
5187 | .rpc_call_done = nfs4_reclaim_complete_done, | ||
5188 | .rpc_release = nfs4_free_reclaim_complete_data, | ||
5189 | }; | ||
5190 | |||
5191 | /* | ||
5192 | * Issue a global reclaim complete. | ||
5193 | */ | ||
5194 | static int nfs41_proc_reclaim_complete(struct nfs_client *clp) | ||
5195 | { | ||
5196 | struct nfs4_reclaim_complete_data *calldata; | ||
5197 | struct rpc_task *task; | ||
5198 | struct rpc_message msg = { | ||
5199 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE], | ||
5200 | }; | ||
5201 | struct rpc_task_setup task_setup_data = { | ||
5202 | .rpc_client = clp->cl_rpcclient, | ||
5203 | .rpc_message = &msg, | ||
5204 | .callback_ops = &nfs4_reclaim_complete_call_ops, | ||
5205 | .flags = RPC_TASK_ASYNC, | ||
5206 | }; | ||
5207 | int status = -ENOMEM; | ||
5208 | |||
5209 | dprintk("--> %s\n", __func__); | ||
5210 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); | ||
5211 | if (calldata == NULL) | ||
5212 | goto out; | ||
5213 | calldata->clp = clp; | ||
5214 | calldata->arg.one_fs = 0; | ||
5215 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
5216 | |||
5217 | msg.rpc_argp = &calldata->arg; | ||
5218 | msg.rpc_resp = &calldata->res; | ||
5219 | task_setup_data.callback_data = calldata; | ||
5220 | task = rpc_run_task(&task_setup_data); | ||
5221 | if (IS_ERR(task)) { | ||
5222 | status = PTR_ERR(task); | ||
5223 | goto out; | ||
5224 | } | ||
5225 | rpc_put_task(task); | ||
5226 | return 0; | ||
5227 | out: | ||
5228 | dprintk("<-- %s status=%d\n", __func__, status); | ||
5229 | return status; | ||
5230 | } | ||
4934 | #endif /* CONFIG_NFS_V4_1 */ | 5231 | #endif /* CONFIG_NFS_V4_1 */ |
4935 | 5232 | ||
4936 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5233 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -4948,8 +5245,9 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | |||
4948 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 5245 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
4949 | .recover_open = nfs4_open_reclaim, | 5246 | .recover_open = nfs4_open_reclaim, |
4950 | .recover_lock = nfs4_lock_reclaim, | 5247 | .recover_lock = nfs4_lock_reclaim, |
4951 | .establish_clid = nfs4_proc_exchange_id, | 5248 | .establish_clid = nfs41_init_clientid, |
4952 | .get_clid_cred = nfs4_get_exchange_id_cred, | 5249 | .get_clid_cred = nfs4_get_exchange_id_cred, |
5250 | .reclaim_complete = nfs41_proc_reclaim_complete, | ||
4953 | }; | 5251 | }; |
4954 | #endif /* CONFIG_NFS_V4_1 */ | 5252 | #endif /* CONFIG_NFS_V4_1 */ |
4955 | 5253 | ||
@@ -4968,7 +5266,7 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | |||
4968 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 5266 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
4969 | .recover_open = nfs4_open_expired, | 5267 | .recover_open = nfs4_open_expired, |
4970 | .recover_lock = nfs4_lock_expired, | 5268 | .recover_lock = nfs4_lock_expired, |
4971 | .establish_clid = nfs4_proc_exchange_id, | 5269 | .establish_clid = nfs41_init_clientid, |
4972 | .get_clid_cred = nfs4_get_exchange_id_cred, | 5270 | .get_clid_cred = nfs4_get_exchange_id_cred, |
4973 | }; | 5271 | }; |
4974 | #endif /* CONFIG_NFS_V4_1 */ | 5272 | #endif /* CONFIG_NFS_V4_1 */ |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index 0156c01c212c..d87f10327b72 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -36,11 +36,6 @@ | |||
36 | * as an rpc_task, not a real kernel thread, so it always runs in rpciod's | 36 | * as an rpc_task, not a real kernel thread, so it always runs in rpciod's |
37 | * context. There is one renewd per nfs_server. | 37 | * context. There is one renewd per nfs_server. |
38 | * | 38 | * |
39 | * TODO: If the send queue gets backlogged (e.g., if the server goes down), | ||
40 | * we will keep filling the queue with periodic RENEW requests. We need a | ||
41 | * mechanism for ensuring that if renewd successfully sends off a request, | ||
42 | * then it only wakes up when the request is finished. Maybe use the | ||
43 | * child task framework of the RPC layer? | ||
44 | */ | 39 | */ |
45 | 40 | ||
46 | #include <linux/mm.h> | 41 | #include <linux/mm.h> |
@@ -63,7 +58,7 @@ nfs4_renew_state(struct work_struct *work) | |||
63 | struct nfs_client *clp = | 58 | struct nfs_client *clp = |
64 | container_of(work, struct nfs_client, cl_renewd.work); | 59 | container_of(work, struct nfs_client, cl_renewd.work); |
65 | struct rpc_cred *cred; | 60 | struct rpc_cred *cred; |
66 | long lease, timeout; | 61 | long lease; |
67 | unsigned long last, now; | 62 | unsigned long last, now; |
68 | 63 | ||
69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | 64 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; |
@@ -75,7 +70,6 @@ nfs4_renew_state(struct work_struct *work) | |||
75 | lease = clp->cl_lease_time; | 70 | lease = clp->cl_lease_time; |
76 | last = clp->cl_last_renewal; | 71 | last = clp->cl_last_renewal; |
77 | now = jiffies; | 72 | now = jiffies; |
78 | timeout = (2 * lease) / 3 + (long)last - (long)now; | ||
79 | /* Are we close to a lease timeout? */ | 73 | /* Are we close to a lease timeout? */ |
80 | if (time_after(now, last + lease/3)) { | 74 | if (time_after(now, last + lease/3)) { |
81 | cred = ops->get_state_renewal_cred_locked(clp); | 75 | cred = ops->get_state_renewal_cred_locked(clp); |
@@ -90,19 +84,15 @@ nfs4_renew_state(struct work_struct *work) | |||
90 | /* Queue an asynchronous RENEW. */ | 84 | /* Queue an asynchronous RENEW. */ |
91 | ops->sched_state_renewal(clp, cred); | 85 | ops->sched_state_renewal(clp, cred); |
92 | put_rpccred(cred); | 86 | put_rpccred(cred); |
87 | goto out_exp; | ||
93 | } | 88 | } |
94 | timeout = (2 * lease) / 3; | 89 | } else { |
95 | spin_lock(&clp->cl_lock); | ||
96 | } else | ||
97 | dprintk("%s: failed to call renewd. Reason: lease not expired \n", | 90 | dprintk("%s: failed to call renewd. Reason: lease not expired \n", |
98 | __func__); | 91 | __func__); |
99 | if (timeout < 5 * HZ) /* safeguard */ | 92 | spin_unlock(&clp->cl_lock); |
100 | timeout = 5 * HZ; | 93 | } |
101 | dprintk("%s: requeueing work. Lease period = %ld\n", | 94 | nfs4_schedule_state_renewal(clp); |
102 | __func__, (timeout + HZ - 1) / HZ); | 95 | out_exp: |
103 | cancel_delayed_work(&clp->cl_renewd); | ||
104 | schedule_delayed_work(&clp->cl_renewd, timeout); | ||
105 | spin_unlock(&clp->cl_lock); | ||
106 | nfs_expire_unreferenced_delegations(clp); | 96 | nfs_expire_unreferenced_delegations(clp); |
107 | out: | 97 | out: |
108 | dprintk("%s: done\n", __func__); | 98 | dprintk("%s: done\n", __func__); |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 2ef4fecf3984..6c5ed51f105e 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -116,6 +116,79 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
116 | 116 | ||
117 | #if defined(CONFIG_NFS_V4_1) | 117 | #if defined(CONFIG_NFS_V4_1) |
118 | 118 | ||
119 | static int nfs41_setup_state_renewal(struct nfs_client *clp) | ||
120 | { | ||
121 | int status; | ||
122 | struct nfs_fsinfo fsinfo; | ||
123 | |||
124 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
125 | if (status == 0) { | ||
126 | /* Update lease time and schedule renewal */ | ||
127 | spin_lock(&clp->cl_lock); | ||
128 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
129 | clp->cl_last_renewal = jiffies; | ||
130 | spin_unlock(&clp->cl_lock); | ||
131 | |||
132 | nfs4_schedule_state_renewal(clp); | ||
133 | } | ||
134 | |||
135 | return status; | ||
136 | } | ||
137 | |||
138 | static void nfs4_end_drain_session(struct nfs_client *clp) | ||
139 | { | ||
140 | struct nfs4_session *ses = clp->cl_session; | ||
141 | int max_slots; | ||
142 | |||
143 | if (test_and_clear_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) { | ||
144 | spin_lock(&ses->fc_slot_table.slot_tbl_lock); | ||
145 | max_slots = ses->fc_slot_table.max_slots; | ||
146 | while (max_slots--) { | ||
147 | struct rpc_task *task; | ||
148 | |||
149 | task = rpc_wake_up_next(&ses->fc_slot_table. | ||
150 | slot_tbl_waitq); | ||
151 | if (!task) | ||
152 | break; | ||
153 | rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED); | ||
154 | } | ||
155 | spin_unlock(&ses->fc_slot_table.slot_tbl_lock); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | static int nfs4_begin_drain_session(struct nfs_client *clp) | ||
160 | { | ||
161 | struct nfs4_session *ses = clp->cl_session; | ||
162 | struct nfs4_slot_table *tbl = &ses->fc_slot_table; | ||
163 | |||
164 | spin_lock(&tbl->slot_tbl_lock); | ||
165 | set_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state); | ||
166 | if (tbl->highest_used_slotid != -1) { | ||
167 | INIT_COMPLETION(ses->complete); | ||
168 | spin_unlock(&tbl->slot_tbl_lock); | ||
169 | return wait_for_completion_interruptible(&ses->complete); | ||
170 | } | ||
171 | spin_unlock(&tbl->slot_tbl_lock); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) | ||
176 | { | ||
177 | int status; | ||
178 | |||
179 | nfs4_begin_drain_session(clp); | ||
180 | status = nfs4_proc_exchange_id(clp, cred); | ||
181 | if (status != 0) | ||
182 | goto out; | ||
183 | status = nfs4_proc_create_session(clp); | ||
184 | if (status != 0) | ||
185 | goto out; | ||
186 | nfs41_setup_state_renewal(clp); | ||
187 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
188 | out: | ||
189 | return status; | ||
190 | } | ||
191 | |||
119 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | 192 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) |
120 | { | 193 | { |
121 | struct rpc_cred *cred; | 194 | struct rpc_cred *cred; |
@@ -693,16 +766,21 @@ struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter) | |||
693 | return new; | 766 | return new; |
694 | } | 767 | } |
695 | 768 | ||
696 | void nfs_free_seqid(struct nfs_seqid *seqid) | 769 | void nfs_release_seqid(struct nfs_seqid *seqid) |
697 | { | 770 | { |
698 | if (!list_empty(&seqid->list)) { | 771 | if (!list_empty(&seqid->list)) { |
699 | struct rpc_sequence *sequence = seqid->sequence->sequence; | 772 | struct rpc_sequence *sequence = seqid->sequence->sequence; |
700 | 773 | ||
701 | spin_lock(&sequence->lock); | 774 | spin_lock(&sequence->lock); |
702 | list_del(&seqid->list); | 775 | list_del_init(&seqid->list); |
703 | spin_unlock(&sequence->lock); | 776 | spin_unlock(&sequence->lock); |
704 | rpc_wake_up(&sequence->wait); | 777 | rpc_wake_up(&sequence->wait); |
705 | } | 778 | } |
779 | } | ||
780 | |||
781 | void nfs_free_seqid(struct nfs_seqid *seqid) | ||
782 | { | ||
783 | nfs_release_seqid(seqid); | ||
706 | kfree(seqid); | 784 | kfree(seqid); |
707 | } | 785 | } |
708 | 786 | ||
@@ -823,7 +901,7 @@ void nfs4_schedule_state_recovery(struct nfs_client *clp) | |||
823 | nfs4_schedule_state_manager(clp); | 901 | nfs4_schedule_state_manager(clp); |
824 | } | 902 | } |
825 | 903 | ||
826 | static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) | 904 | int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state) |
827 | { | 905 | { |
828 | 906 | ||
829 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); | 907 | set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags); |
@@ -877,6 +955,10 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_ | |||
877 | case -NFS4ERR_EXPIRED: | 955 | case -NFS4ERR_EXPIRED: |
878 | case -NFS4ERR_NO_GRACE: | 956 | case -NFS4ERR_NO_GRACE: |
879 | case -NFS4ERR_STALE_CLIENTID: | 957 | case -NFS4ERR_STALE_CLIENTID: |
958 | case -NFS4ERR_BADSESSION: | ||
959 | case -NFS4ERR_BADSLOT: | ||
960 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
961 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
880 | goto out; | 962 | goto out; |
881 | default: | 963 | default: |
882 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", | 964 | printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n", |
@@ -959,6 +1041,10 @@ restart: | |||
959 | case -NFS4ERR_NO_GRACE: | 1041 | case -NFS4ERR_NO_GRACE: |
960 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); | 1042 | nfs4_state_mark_reclaim_nograce(sp->so_client, state); |
961 | case -NFS4ERR_STALE_CLIENTID: | 1043 | case -NFS4ERR_STALE_CLIENTID: |
1044 | case -NFS4ERR_BADSESSION: | ||
1045 | case -NFS4ERR_BADSLOT: | ||
1046 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1047 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
962 | goto out_err; | 1048 | goto out_err; |
963 | } | 1049 | } |
964 | nfs4_put_open_state(state); | 1050 | nfs4_put_open_state(state); |
@@ -1011,6 +1097,14 @@ static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp) | |||
1011 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot); | 1097 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot); |
1012 | } | 1098 | } |
1013 | 1099 | ||
1100 | static void nfs4_reclaim_complete(struct nfs_client *clp, | ||
1101 | const struct nfs4_state_recovery_ops *ops) | ||
1102 | { | ||
1103 | /* Notify the server we're done reclaiming our state */ | ||
1104 | if (ops->reclaim_complete) | ||
1105 | (void)ops->reclaim_complete(clp); | ||
1106 | } | ||
1107 | |||
1014 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | 1108 | static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) |
1015 | { | 1109 | { |
1016 | struct nfs4_state_owner *sp; | 1110 | struct nfs4_state_owner *sp; |
@@ -1020,6 +1114,9 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) | |||
1020 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1114 | if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
1021 | return; | 1115 | return; |
1022 | 1116 | ||
1117 | nfs4_reclaim_complete(clp, | ||
1118 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
1119 | |||
1023 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { | 1120 | for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) { |
1024 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); | 1121 | sp = rb_entry(pos, struct nfs4_state_owner, so_client_node); |
1025 | spin_lock(&sp->so_lock); | 1122 | spin_lock(&sp->so_lock); |
@@ -1046,25 +1143,25 @@ static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp) | |||
1046 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); | 1143 | nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce); |
1047 | } | 1144 | } |
1048 | 1145 | ||
1049 | static void nfs4_state_end_reclaim_nograce(struct nfs_client *clp) | 1146 | static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) |
1050 | { | ||
1051 | clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | ||
1052 | } | ||
1053 | |||
1054 | static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | ||
1055 | { | 1147 | { |
1056 | switch (error) { | 1148 | switch (error) { |
1057 | case -NFS4ERR_CB_PATH_DOWN: | 1149 | case -NFS4ERR_CB_PATH_DOWN: |
1058 | nfs_handle_cb_pathdown(clp); | 1150 | nfs_handle_cb_pathdown(clp); |
1059 | break; | 1151 | return 0; |
1152 | case -NFS4ERR_NO_GRACE: | ||
1153 | nfs4_state_end_reclaim_reboot(clp); | ||
1154 | return 0; | ||
1060 | case -NFS4ERR_STALE_CLIENTID: | 1155 | case -NFS4ERR_STALE_CLIENTID: |
1061 | case -NFS4ERR_LEASE_MOVED: | 1156 | case -NFS4ERR_LEASE_MOVED: |
1062 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1157 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1158 | nfs4_state_end_reclaim_reboot(clp); | ||
1063 | nfs4_state_start_reclaim_reboot(clp); | 1159 | nfs4_state_start_reclaim_reboot(clp); |
1064 | break; | 1160 | break; |
1065 | case -NFS4ERR_EXPIRED: | 1161 | case -NFS4ERR_EXPIRED: |
1066 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1162 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1067 | nfs4_state_start_reclaim_nograce(clp); | 1163 | nfs4_state_start_reclaim_nograce(clp); |
1164 | break; | ||
1068 | case -NFS4ERR_BADSESSION: | 1165 | case -NFS4ERR_BADSESSION: |
1069 | case -NFS4ERR_BADSLOT: | 1166 | case -NFS4ERR_BADSLOT: |
1070 | case -NFS4ERR_BAD_HIGH_SLOT: | 1167 | case -NFS4ERR_BAD_HIGH_SLOT: |
@@ -1072,8 +1169,11 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1072 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | 1169 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: |
1073 | case -NFS4ERR_SEQ_FALSE_RETRY: | 1170 | case -NFS4ERR_SEQ_FALSE_RETRY: |
1074 | case -NFS4ERR_SEQ_MISORDERED: | 1171 | case -NFS4ERR_SEQ_MISORDERED: |
1075 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 1172 | set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); |
1173 | /* Zero session reset errors */ | ||
1174 | return 0; | ||
1076 | } | 1175 | } |
1176 | return error; | ||
1077 | } | 1177 | } |
1078 | 1178 | ||
1079 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) | 1179 | static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) |
@@ -1093,8 +1193,7 @@ restart: | |||
1093 | if (status < 0) { | 1193 | if (status < 0) { |
1094 | set_bit(ops->owner_flag_bit, &sp->so_flags); | 1194 | set_bit(ops->owner_flag_bit, &sp->so_flags); |
1095 | nfs4_put_state_owner(sp); | 1195 | nfs4_put_state_owner(sp); |
1096 | nfs4_recovery_handle_error(clp, status); | 1196 | return nfs4_recovery_handle_error(clp, status); |
1097 | return status; | ||
1098 | } | 1197 | } |
1099 | nfs4_put_state_owner(sp); | 1198 | nfs4_put_state_owner(sp); |
1100 | goto restart; | 1199 | goto restart; |
@@ -1124,8 +1223,7 @@ static int nfs4_check_lease(struct nfs_client *clp) | |||
1124 | status = ops->renew_lease(clp, cred); | 1223 | status = ops->renew_lease(clp, cred); |
1125 | put_rpccred(cred); | 1224 | put_rpccred(cred); |
1126 | out: | 1225 | out: |
1127 | nfs4_recovery_handle_error(clp, status); | 1226 | return nfs4_recovery_handle_error(clp, status); |
1128 | return status; | ||
1129 | } | 1227 | } |
1130 | 1228 | ||
1131 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1229 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
@@ -1151,55 +1249,127 @@ static int nfs4_reclaim_lease(struct nfs_client *clp) | |||
1151 | } | 1249 | } |
1152 | 1250 | ||
1153 | #ifdef CONFIG_NFS_V4_1 | 1251 | #ifdef CONFIG_NFS_V4_1 |
1154 | static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err) | 1252 | void nfs41_handle_recall_slot(struct nfs_client *clp) |
1155 | { | 1253 | { |
1156 | switch (err) { | 1254 | set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); |
1157 | case -NFS4ERR_STALE_CLIENTID: | 1255 | nfs4_schedule_state_recovery(clp); |
1158 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1256 | } |
1159 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 1257 | |
1258 | static void nfs4_reset_all_state(struct nfs_client *clp) | ||
1259 | { | ||
1260 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { | ||
1261 | clp->cl_boot_time = CURRENT_TIME; | ||
1262 | nfs4_state_start_reclaim_nograce(clp); | ||
1263 | nfs4_schedule_state_recovery(clp); | ||
1160 | } | 1264 | } |
1161 | } | 1265 | } |
1162 | 1266 | ||
1267 | static void nfs41_handle_server_reboot(struct nfs_client *clp) | ||
1268 | { | ||
1269 | if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) { | ||
1270 | nfs4_state_start_reclaim_reboot(clp); | ||
1271 | nfs4_schedule_state_recovery(clp); | ||
1272 | } | ||
1273 | } | ||
1274 | |||
1275 | static void nfs41_handle_state_revoked(struct nfs_client *clp) | ||
1276 | { | ||
1277 | /* Temporary */ | ||
1278 | nfs4_reset_all_state(clp); | ||
1279 | } | ||
1280 | |||
1281 | static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp) | ||
1282 | { | ||
1283 | /* This will need to handle layouts too */ | ||
1284 | nfs_expire_all_delegations(clp); | ||
1285 | } | ||
1286 | |||
1287 | static void nfs41_handle_cb_path_down(struct nfs_client *clp) | ||
1288 | { | ||
1289 | nfs_expire_all_delegations(clp); | ||
1290 | if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0) | ||
1291 | nfs4_schedule_state_recovery(clp); | ||
1292 | } | ||
1293 | |||
1294 | void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) | ||
1295 | { | ||
1296 | if (!flags) | ||
1297 | return; | ||
1298 | else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) | ||
1299 | nfs41_handle_server_reboot(clp); | ||
1300 | else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | | ||
1301 | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | | ||
1302 | SEQ4_STATUS_ADMIN_STATE_REVOKED | | ||
1303 | SEQ4_STATUS_LEASE_MOVED)) | ||
1304 | nfs41_handle_state_revoked(clp); | ||
1305 | else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) | ||
1306 | nfs41_handle_recallable_state_revoked(clp); | ||
1307 | else if (flags & (SEQ4_STATUS_CB_PATH_DOWN | | ||
1308 | SEQ4_STATUS_BACKCHANNEL_FAULT | | ||
1309 | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) | ||
1310 | nfs41_handle_cb_path_down(clp); | ||
1311 | } | ||
1312 | |||
1163 | static int nfs4_reset_session(struct nfs_client *clp) | 1313 | static int nfs4_reset_session(struct nfs_client *clp) |
1164 | { | 1314 | { |
1165 | int status; | 1315 | int status; |
1166 | 1316 | ||
1317 | nfs4_begin_drain_session(clp); | ||
1167 | status = nfs4_proc_destroy_session(clp->cl_session); | 1318 | status = nfs4_proc_destroy_session(clp->cl_session); |
1168 | if (status && status != -NFS4ERR_BADSESSION && | 1319 | if (status && status != -NFS4ERR_BADSESSION && |
1169 | status != -NFS4ERR_DEADSESSION) { | 1320 | status != -NFS4ERR_DEADSESSION) { |
1170 | nfs4_session_recovery_handle_error(clp, status); | 1321 | status = nfs4_recovery_handle_error(clp, status); |
1171 | goto out; | 1322 | goto out; |
1172 | } | 1323 | } |
1173 | 1324 | ||
1174 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | 1325 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); |
1175 | status = nfs4_proc_create_session(clp, 1); | 1326 | status = nfs4_proc_create_session(clp); |
1176 | if (status) | 1327 | if (status) { |
1177 | nfs4_session_recovery_handle_error(clp, status); | 1328 | status = nfs4_recovery_handle_error(clp, status); |
1178 | /* fall through*/ | 1329 | goto out; |
1330 | } | ||
1331 | /* create_session negotiated new slot table */ | ||
1332 | clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state); | ||
1333 | |||
1334 | /* Let the state manager reestablish state */ | ||
1335 | if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | ||
1336 | nfs41_setup_state_renewal(clp); | ||
1179 | out: | 1337 | out: |
1180 | /* Wake up the next rpc task even on error */ | ||
1181 | rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq); | ||
1182 | return status; | 1338 | return status; |
1183 | } | 1339 | } |
1184 | 1340 | ||
1185 | static int nfs4_initialize_session(struct nfs_client *clp) | 1341 | static int nfs4_recall_slot(struct nfs_client *clp) |
1186 | { | 1342 | { |
1187 | int status; | 1343 | struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table; |
1344 | struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs; | ||
1345 | struct nfs4_slot *new, *old; | ||
1346 | int i; | ||
1347 | |||
1348 | nfs4_begin_drain_session(clp); | ||
1349 | new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot), | ||
1350 | GFP_KERNEL); | ||
1351 | if (!new) | ||
1352 | return -ENOMEM; | ||
1188 | 1353 | ||
1189 | status = nfs4_proc_create_session(clp, 0); | 1354 | spin_lock(&fc_tbl->slot_tbl_lock); |
1190 | if (!status) { | 1355 | for (i = 0; i < fc_tbl->target_max_slots; i++) |
1191 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1356 | new[i].seq_nr = fc_tbl->slots[i].seq_nr; |
1192 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | 1357 | old = fc_tbl->slots; |
1193 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1358 | fc_tbl->slots = new; |
1194 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | 1359 | fc_tbl->max_slots = fc_tbl->target_max_slots; |
1195 | } else { | 1360 | fc_tbl->target_max_slots = 0; |
1196 | nfs_mark_client_ready(clp, status); | 1361 | fc_attrs->max_reqs = fc_tbl->max_slots; |
1197 | } | 1362 | spin_unlock(&fc_tbl->slot_tbl_lock); |
1198 | return status; | 1363 | |
1364 | kfree(old); | ||
1365 | nfs4_end_drain_session(clp); | ||
1366 | return 0; | ||
1199 | } | 1367 | } |
1368 | |||
1200 | #else /* CONFIG_NFS_V4_1 */ | 1369 | #else /* CONFIG_NFS_V4_1 */ |
1201 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | 1370 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } |
1202 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | 1371 | static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; } |
1372 | static int nfs4_recall_slot(struct nfs_client *clp) { return 0; } | ||
1203 | #endif /* CONFIG_NFS_V4_1 */ | 1373 | #endif /* CONFIG_NFS_V4_1 */ |
1204 | 1374 | ||
1205 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | 1375 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors |
@@ -1212,6 +1382,7 @@ static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | |||
1212 | case -NFS4ERR_DELAY: | 1382 | case -NFS4ERR_DELAY: |
1213 | case -NFS4ERR_CLID_INUSE: | 1383 | case -NFS4ERR_CLID_INUSE: |
1214 | case -EAGAIN: | 1384 | case -EAGAIN: |
1385 | case -EKEYEXPIRED: | ||
1215 | break; | 1386 | break; |
1216 | 1387 | ||
1217 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | 1388 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery |
@@ -1234,7 +1405,8 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1234 | status = nfs4_reclaim_lease(clp); | 1405 | status = nfs4_reclaim_lease(clp); |
1235 | if (status) { | 1406 | if (status) { |
1236 | nfs4_set_lease_expired(clp, status); | 1407 | nfs4_set_lease_expired(clp, status); |
1237 | if (status == -EAGAIN) | 1408 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, |
1409 | &clp->cl_state)) | ||
1238 | continue; | 1410 | continue; |
1239 | if (clp->cl_cons_state == | 1411 | if (clp->cl_cons_state == |
1240 | NFS_CS_SESSION_INITING) | 1412 | NFS_CS_SESSION_INITING) |
@@ -1242,61 +1414,67 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1242 | goto out_error; | 1414 | goto out_error; |
1243 | } | 1415 | } |
1244 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1416 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
1417 | set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); | ||
1245 | } | 1418 | } |
1246 | 1419 | ||
1247 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { | 1420 | if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { |
1248 | status = nfs4_check_lease(clp); | 1421 | status = nfs4_check_lease(clp); |
1249 | if (status != 0) | 1422 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1250 | continue; | 1423 | continue; |
1424 | if (status < 0 && status != -NFS4ERR_CB_PATH_DOWN) | ||
1425 | goto out_error; | ||
1251 | } | 1426 | } |
1427 | |||
1252 | /* Initialize or reset the session */ | 1428 | /* Initialize or reset the session */ |
1253 | if (test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state) | 1429 | if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) |
1254 | && nfs4_has_session(clp)) { | 1430 | && nfs4_has_session(clp)) { |
1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | 1431 | status = nfs4_reset_session(clp); |
1256 | status = nfs4_initialize_session(clp); | 1432 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1257 | else | 1433 | continue; |
1258 | status = nfs4_reset_session(clp); | 1434 | if (status < 0) |
1259 | if (status) { | ||
1260 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
1261 | continue; | ||
1262 | goto out_error; | 1435 | goto out_error; |
1263 | } | ||
1264 | } | 1436 | } |
1437 | |||
1265 | /* First recover reboot state... */ | 1438 | /* First recover reboot state... */ |
1266 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1439 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1267 | status = nfs4_do_reclaim(clp, | 1440 | status = nfs4_do_reclaim(clp, |
1268 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | 1441 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); |
1269 | if (status == -NFS4ERR_STALE_CLIENTID) | 1442 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
1270 | continue; | 1443 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)) |
1271 | if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
1272 | continue; | 1444 | continue; |
1273 | nfs4_state_end_reclaim_reboot(clp); | 1445 | nfs4_state_end_reclaim_reboot(clp); |
1274 | continue; | 1446 | if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) |
1447 | continue; | ||
1448 | if (status < 0) | ||
1449 | goto out_error; | ||
1275 | } | 1450 | } |
1276 | 1451 | ||
1277 | /* Now recover expired state... */ | 1452 | /* Now recover expired state... */ |
1278 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1453 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1279 | status = nfs4_do_reclaim(clp, | 1454 | status = nfs4_do_reclaim(clp, |
1280 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | 1455 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); |
1281 | if (status < 0) { | 1456 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) || |
1282 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | 1457 | test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) || |
1283 | if (status == -NFS4ERR_STALE_CLIENTID) | 1458 | test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) |
1284 | continue; | 1459 | continue; |
1285 | if (status == -NFS4ERR_EXPIRED) | 1460 | if (status < 0) |
1286 | continue; | ||
1287 | if (test_bit(NFS4CLNT_SESSION_SETUP, | ||
1288 | &clp->cl_state)) | ||
1289 | continue; | ||
1290 | goto out_error; | 1461 | goto out_error; |
1291 | } else | ||
1292 | nfs4_state_end_reclaim_nograce(clp); | ||
1293 | continue; | ||
1294 | } | 1462 | } |
1295 | 1463 | ||
1464 | nfs4_end_drain_session(clp); | ||
1296 | if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { | 1465 | if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) { |
1297 | nfs_client_return_marked_delegations(clp); | 1466 | nfs_client_return_marked_delegations(clp); |
1298 | continue; | 1467 | continue; |
1299 | } | 1468 | } |
1469 | /* Recall session slots */ | ||
1470 | if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state) | ||
1471 | && nfs4_has_session(clp)) { | ||
1472 | status = nfs4_recall_slot(clp); | ||
1473 | if (status < 0) | ||
1474 | goto out_error; | ||
1475 | continue; | ||
1476 | } | ||
1477 | |||
1300 | 1478 | ||
1301 | nfs4_clear_state_manager_bit(clp); | 1479 | nfs4_clear_state_manager_bit(clp); |
1302 | /* Did we race with an attempt to give us more work? */ | 1480 | /* Did we race with an attempt to give us more work? */ |
@@ -1309,8 +1487,7 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1309 | out_error: | 1487 | out_error: |
1310 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" | 1488 | printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s" |
1311 | " with error %d\n", clp->cl_hostname, -status); | 1489 | " with error %d\n", clp->cl_hostname, -status); |
1312 | if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) | 1490 | nfs4_end_drain_session(clp); |
1313 | nfs4_state_end_reclaim_reboot(clp); | ||
1314 | nfs4_clear_state_manager_bit(clp); | 1491 | nfs4_clear_state_manager_bit(clp); |
1315 | } | 1492 | } |
1316 | 1493 | ||
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 20b4e30e6c82..38f3b582e7c2 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/param.h> | 38 | #include <linux/param.h> |
39 | #include <linux/time.h> | 39 | #include <linux/time.h> |
40 | #include <linux/mm.h> | 40 | #include <linux/mm.h> |
41 | #include <linux/slab.h> | ||
42 | #include <linux/errno.h> | 41 | #include <linux/errno.h> |
43 | #include <linux/string.h> | 42 | #include <linux/string.h> |
44 | #include <linux/in.h> | 43 | #include <linux/in.h> |
@@ -46,11 +45,13 @@ | |||
46 | #include <linux/proc_fs.h> | 45 | #include <linux/proc_fs.h> |
47 | #include <linux/kdev_t.h> | 46 | #include <linux/kdev_t.h> |
48 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
48 | #include <linux/sunrpc/msg_prot.h> | ||
49 | #include <linux/nfs.h> | 49 | #include <linux/nfs.h> |
50 | #include <linux/nfs4.h> | 50 | #include <linux/nfs4.h> |
51 | #include <linux/nfs_fs.h> | 51 | #include <linux/nfs_fs.h> |
52 | #include <linux/nfs_idmap.h> | 52 | #include <linux/nfs_idmap.h> |
53 | #include "nfs4_fs.h" | 53 | #include "nfs4_fs.h" |
54 | #include "internal.h" | ||
54 | 55 | ||
55 | #define NFSDBG_FACILITY NFSDBG_XDR | 56 | #define NFSDBG_FACILITY NFSDBG_XDR |
56 | 57 | ||
@@ -134,7 +135,7 @@ static int nfs4_stat_to_errno(int); | |||
134 | #define decode_lookup_maxsz (op_decode_hdr_maxsz) | 135 | #define decode_lookup_maxsz (op_decode_hdr_maxsz) |
135 | #define encode_share_access_maxsz \ | 136 | #define encode_share_access_maxsz \ |
136 | (2) | 137 | (2) |
137 | #define encode_createmode_maxsz (1 + encode_attrs_maxsz) | 138 | #define encode_createmode_maxsz (1 + encode_attrs_maxsz + encode_verifier_maxsz) |
138 | #define encode_opentype_maxsz (1 + encode_createmode_maxsz) | 139 | #define encode_opentype_maxsz (1 + encode_createmode_maxsz) |
139 | #define encode_claim_null_maxsz (1 + nfs4_name_maxsz) | 140 | #define encode_claim_null_maxsz (1 + nfs4_name_maxsz) |
140 | #define encode_open_maxsz (op_encode_hdr_maxsz + \ | 141 | #define encode_open_maxsz (op_encode_hdr_maxsz + \ |
@@ -299,6 +300,8 @@ static int nfs4_stat_to_errno(int); | |||
299 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) | 300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) |
300 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | 301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ |
301 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | 302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) |
303 | #define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4) | ||
304 | #define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4) | ||
302 | #else /* CONFIG_NFS_V4_1 */ | 305 | #else /* CONFIG_NFS_V4_1 */ |
303 | #define encode_sequence_maxsz 0 | 306 | #define encode_sequence_maxsz 0 |
304 | #define decode_sequence_maxsz 0 | 307 | #define decode_sequence_maxsz 0 |
@@ -676,6 +679,25 @@ static int nfs4_stat_to_errno(int); | |||
676 | decode_sequence_maxsz + \ | 679 | decode_sequence_maxsz + \ |
677 | decode_putrootfh_maxsz + \ | 680 | decode_putrootfh_maxsz + \ |
678 | decode_fsinfo_maxsz) | 681 | decode_fsinfo_maxsz) |
682 | #define NFS4_enc_reclaim_complete_sz (compound_encode_hdr_maxsz + \ | ||
683 | encode_sequence_maxsz + \ | ||
684 | encode_reclaim_complete_maxsz) | ||
685 | #define NFS4_dec_reclaim_complete_sz (compound_decode_hdr_maxsz + \ | ||
686 | decode_sequence_maxsz + \ | ||
687 | decode_reclaim_complete_maxsz) | ||
688 | |||
689 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | ||
690 | compound_encode_hdr_maxsz + | ||
691 | encode_sequence_maxsz + | ||
692 | encode_putfh_maxsz + | ||
693 | encode_getattr_maxsz) * | ||
694 | XDR_UNIT); | ||
695 | |||
696 | const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | ||
697 | compound_decode_hdr_maxsz + | ||
698 | decode_sequence_maxsz + | ||
699 | decode_putfh_maxsz) * | ||
700 | XDR_UNIT); | ||
679 | #endif /* CONFIG_NFS_V4_1 */ | 701 | #endif /* CONFIG_NFS_V4_1 */ |
680 | 702 | ||
681 | static const umode_t nfs_type2fmt[] = { | 703 | static const umode_t nfs_type2fmt[] = { |
@@ -1140,6 +1162,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |||
1140 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) | 1162 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) |
1141 | { | 1163 | { |
1142 | __be32 *p; | 1164 | __be32 *p; |
1165 | struct nfs_client *clp; | ||
1143 | 1166 | ||
1144 | p = reserve_space(xdr, 4); | 1167 | p = reserve_space(xdr, 4); |
1145 | switch(arg->open_flags & O_EXCL) { | 1168 | switch(arg->open_flags & O_EXCL) { |
@@ -1148,8 +1171,23 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op | |||
1148 | encode_attrs(xdr, arg->u.attrs, arg->server); | 1171 | encode_attrs(xdr, arg->u.attrs, arg->server); |
1149 | break; | 1172 | break; |
1150 | default: | 1173 | default: |
1151 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); | 1174 | clp = arg->server->nfs_client; |
1152 | encode_nfs4_verifier(xdr, &arg->u.verifier); | 1175 | if (clp->cl_minorversion > 0) { |
1176 | if (nfs4_has_persistent_session(clp)) { | ||
1177 | *p = cpu_to_be32(NFS4_CREATE_GUARDED); | ||
1178 | encode_attrs(xdr, arg->u.attrs, arg->server); | ||
1179 | } else { | ||
1180 | struct iattr dummy; | ||
1181 | |||
1182 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); | ||
1183 | encode_nfs4_verifier(xdr, &arg->u.verifier); | ||
1184 | dummy.ia_valid = 0; | ||
1185 | encode_attrs(xdr, &dummy, arg->server); | ||
1186 | } | ||
1187 | } else { | ||
1188 | *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); | ||
1189 | encode_nfs4_verifier(xdr, &arg->u.verifier); | ||
1190 | } | ||
1153 | } | 1191 | } |
1154 | } | 1192 | } |
1155 | 1193 | ||
@@ -1539,6 +1577,14 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
1539 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | 1577 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; |
1540 | uint32_t len; | 1578 | uint32_t len; |
1541 | struct nfs_client *clp = args->client; | 1579 | struct nfs_client *clp = args->client; |
1580 | u32 max_resp_sz_cached; | ||
1581 | |||
1582 | /* | ||
1583 | * Assumes OPEN is the biggest non-idempotent compound. | ||
1584 | * 2 is the verifier. | ||
1585 | */ | ||
1586 | max_resp_sz_cached = (NFS4_dec_open_sz + RPC_REPHDRSIZE + | ||
1587 | RPC_MAX_AUTH_SIZE + 2) * XDR_UNIT; | ||
1542 | 1588 | ||
1543 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | 1589 | len = scnprintf(machine_name, sizeof(machine_name), "%s", |
1544 | clp->cl_ipaddr); | 1590 | clp->cl_ipaddr); |
@@ -1553,7 +1599,7 @@ static void encode_create_session(struct xdr_stream *xdr, | |||
1553 | *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ | 1599 | *p++ = cpu_to_be32(args->fc_attrs.headerpadsz); /* header padding size */ |
1554 | *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ | 1600 | *p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz); /* max req size */ |
1555 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */ | 1601 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz); /* max resp size */ |
1556 | *p++ = cpu_to_be32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | 1602 | *p++ = cpu_to_be32(max_resp_sz_cached); /* Max resp sz cached */ |
1557 | *p++ = cpu_to_be32(args->fc_attrs.max_ops); /* max operations */ | 1603 | *p++ = cpu_to_be32(args->fc_attrs.max_ops); /* max operations */ |
1558 | *p++ = cpu_to_be32(args->fc_attrs.max_reqs); /* max requests */ | 1604 | *p++ = cpu_to_be32(args->fc_attrs.max_reqs); /* max requests */ |
1559 | *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ | 1605 | *p++ = cpu_to_be32(0); /* rdmachannel_attrs */ |
@@ -1592,6 +1638,19 @@ static void encode_destroy_session(struct xdr_stream *xdr, | |||
1592 | hdr->nops++; | 1638 | hdr->nops++; |
1593 | hdr->replen += decode_destroy_session_maxsz; | 1639 | hdr->replen += decode_destroy_session_maxsz; |
1594 | } | 1640 | } |
1641 | |||
1642 | static void encode_reclaim_complete(struct xdr_stream *xdr, | ||
1643 | struct nfs41_reclaim_complete_args *args, | ||
1644 | struct compound_hdr *hdr) | ||
1645 | { | ||
1646 | __be32 *p; | ||
1647 | |||
1648 | p = reserve_space(xdr, 8); | ||
1649 | *p++ = cpu_to_be32(OP_RECLAIM_COMPLETE); | ||
1650 | *p++ = cpu_to_be32(args->one_fs); | ||
1651 | hdr->nops++; | ||
1652 | hdr->replen += decode_reclaim_complete_maxsz; | ||
1653 | } | ||
1595 | #endif /* CONFIG_NFS_V4_1 */ | 1654 | #endif /* CONFIG_NFS_V4_1 */ |
1596 | 1655 | ||
1597 | static void encode_sequence(struct xdr_stream *xdr, | 1656 | static void encode_sequence(struct xdr_stream *xdr, |
@@ -2096,7 +2155,7 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
2096 | encode_compound_hdr(&xdr, req, &hdr); | 2155 | encode_compound_hdr(&xdr, req, &hdr); |
2097 | encode_sequence(&xdr, &args->seq_args, &hdr); | 2156 | encode_sequence(&xdr, &args->seq_args, &hdr); |
2098 | encode_putfh(&xdr, args->fh, &hdr); | 2157 | encode_putfh(&xdr, args->fh, &hdr); |
2099 | replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1; | 2158 | replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1; |
2100 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2159 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
2101 | 2160 | ||
2102 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, | 2161 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
@@ -2420,6 +2479,26 @@ static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | |||
2420 | encode_nops(&hdr); | 2479 | encode_nops(&hdr); |
2421 | return 0; | 2480 | return 0; |
2422 | } | 2481 | } |
2482 | |||
2483 | /* | ||
2484 | * a RECLAIM_COMPLETE request | ||
2485 | */ | ||
2486 | static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p, | ||
2487 | struct nfs41_reclaim_complete_args *args) | ||
2488 | { | ||
2489 | struct xdr_stream xdr; | ||
2490 | struct compound_hdr hdr = { | ||
2491 | .minorversion = nfs4_xdr_minorversion(&args->seq_args) | ||
2492 | }; | ||
2493 | |||
2494 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2495 | encode_compound_hdr(&xdr, req, &hdr); | ||
2496 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2497 | encode_reclaim_complete(&xdr, args, &hdr); | ||
2498 | encode_nops(&hdr); | ||
2499 | return 0; | ||
2500 | } | ||
2501 | |||
2423 | #endif /* CONFIG_NFS_V4_1 */ | 2502 | #endif /* CONFIG_NFS_V4_1 */ |
2424 | 2503 | ||
2425 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 2504 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
@@ -4528,6 +4607,11 @@ static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | |||
4528 | { | 4607 | { |
4529 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); | 4608 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); |
4530 | } | 4609 | } |
4610 | |||
4611 | static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy) | ||
4612 | { | ||
4613 | return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE); | ||
4614 | } | ||
4531 | #endif /* CONFIG_NFS_V4_1 */ | 4615 | #endif /* CONFIG_NFS_V4_1 */ |
4532 | 4616 | ||
4533 | static int decode_sequence(struct xdr_stream *xdr, | 4617 | static int decode_sequence(struct xdr_stream *xdr, |
@@ -4554,7 +4638,7 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4554 | * If the server returns different values for sessionID, slotID or | 4638 | * If the server returns different values for sessionID, slotID or |
4555 | * sequence number, the server is looney tunes. | 4639 | * sequence number, the server is looney tunes. |
4556 | */ | 4640 | */ |
4557 | status = -ESERVERFAULT; | 4641 | status = -EREMOTEIO; |
4558 | 4642 | ||
4559 | if (memcmp(id.data, res->sr_session->sess_id.data, | 4643 | if (memcmp(id.data, res->sr_session->sess_id.data, |
4560 | NFS4_MAX_SESSIONID_LEN)) { | 4644 | NFS4_MAX_SESSIONID_LEN)) { |
@@ -4583,8 +4667,8 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4583 | dummy = be32_to_cpup(p++); | 4667 | dummy = be32_to_cpup(p++); |
4584 | /* target highest slot id - currently not processed */ | 4668 | /* target highest slot id - currently not processed */ |
4585 | dummy = be32_to_cpup(p++); | 4669 | dummy = be32_to_cpup(p++); |
4586 | /* result flags - currently not processed */ | 4670 | /* result flags */ |
4587 | dummy = be32_to_cpup(p); | 4671 | res->sr_status_flags = be32_to_cpup(p); |
4588 | status = 0; | 4672 | status = 0; |
4589 | out_err: | 4673 | out_err: |
4590 | res->sr_status = status; | 4674 | res->sr_status = status; |
@@ -5309,7 +5393,7 @@ out: | |||
5309 | } | 5393 | } |
5310 | 5394 | ||
5311 | /* | 5395 | /* |
5312 | * FSINFO request | 5396 | * Decode FSINFO response |
5313 | */ | 5397 | */ |
5314 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, | 5398 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, |
5315 | struct nfs4_fsinfo_res *res) | 5399 | struct nfs4_fsinfo_res *res) |
@@ -5330,7 +5414,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, | |||
5330 | } | 5414 | } |
5331 | 5415 | ||
5332 | /* | 5416 | /* |
5333 | * PATHCONF request | 5417 | * Decode PATHCONF response |
5334 | */ | 5418 | */ |
5335 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, | 5419 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, |
5336 | struct nfs4_pathconf_res *res) | 5420 | struct nfs4_pathconf_res *res) |
@@ -5351,7 +5435,7 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, | |||
5351 | } | 5435 | } |
5352 | 5436 | ||
5353 | /* | 5437 | /* |
5354 | * STATFS request | 5438 | * Decode STATFS response |
5355 | */ | 5439 | */ |
5356 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, | 5440 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, |
5357 | struct nfs4_statfs_res *res) | 5441 | struct nfs4_statfs_res *res) |
@@ -5372,7 +5456,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, | |||
5372 | } | 5456 | } |
5373 | 5457 | ||
5374 | /* | 5458 | /* |
5375 | * GETATTR_BITMAP request | 5459 | * Decode GETATTR_BITMAP response |
5376 | */ | 5460 | */ |
5377 | static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res) | 5461 | static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res) |
5378 | { | 5462 | { |
@@ -5411,7 +5495,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy) | |||
5411 | } | 5495 | } |
5412 | 5496 | ||
5413 | /* | 5497 | /* |
5414 | * a SETCLIENTID request | 5498 | * Decode SETCLIENTID response |
5415 | */ | 5499 | */ |
5416 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | 5500 | static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, |
5417 | struct nfs_client *clp) | 5501 | struct nfs_client *clp) |
@@ -5428,7 +5512,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p, | |||
5428 | } | 5512 | } |
5429 | 5513 | ||
5430 | /* | 5514 | /* |
5431 | * a SETCLIENTID_CONFIRM request | 5515 | * Decode SETCLIENTID_CONFIRM response |
5432 | */ | 5516 | */ |
5433 | static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) | 5517 | static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) |
5434 | { | 5518 | { |
@@ -5448,7 +5532,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
5448 | } | 5532 | } |
5449 | 5533 | ||
5450 | /* | 5534 | /* |
5451 | * DELEGRETURN request | 5535 | * Decode DELEGRETURN response |
5452 | */ | 5536 | */ |
5453 | static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res) | 5537 | static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res) |
5454 | { | 5538 | { |
@@ -5467,6 +5551,8 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
5467 | if (status != 0) | 5551 | if (status != 0) |
5468 | goto out; | 5552 | goto out; |
5469 | status = decode_delegreturn(&xdr); | 5553 | status = decode_delegreturn(&xdr); |
5554 | if (status != 0) | ||
5555 | goto out; | ||
5470 | decode_getfattr(&xdr, res->fattr, res->server, | 5556 | decode_getfattr(&xdr, res->fattr, res->server, |
5471 | !RPC_IS_ASYNC(rqstp->rq_task)); | 5557 | !RPC_IS_ASYNC(rqstp->rq_task)); |
5472 | out: | 5558 | out: |
@@ -5474,7 +5560,7 @@ out: | |||
5474 | } | 5560 | } |
5475 | 5561 | ||
5476 | /* | 5562 | /* |
5477 | * FS_LOCATIONS request | 5563 | * Decode FS_LOCATIONS response |
5478 | */ | 5564 | */ |
5479 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, | 5565 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, |
5480 | struct nfs4_fs_locations_res *res) | 5566 | struct nfs4_fs_locations_res *res) |
@@ -5504,7 +5590,7 @@ out: | |||
5504 | 5590 | ||
5505 | #if defined(CONFIG_NFS_V4_1) | 5591 | #if defined(CONFIG_NFS_V4_1) |
5506 | /* | 5592 | /* |
5507 | * EXCHANGE_ID request | 5593 | * Decode EXCHANGE_ID response |
5508 | */ | 5594 | */ |
5509 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | 5595 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, |
5510 | void *res) | 5596 | void *res) |
@@ -5521,7 +5607,7 @@ static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | |||
5521 | } | 5607 | } |
5522 | 5608 | ||
5523 | /* | 5609 | /* |
5524 | * a CREATE_SESSION request | 5610 | * Decode CREATE_SESSION response |
5525 | */ | 5611 | */ |
5526 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | 5612 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, |
5527 | struct nfs41_create_session_res *res) | 5613 | struct nfs41_create_session_res *res) |
@@ -5538,7 +5624,7 @@ static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | |||
5538 | } | 5624 | } |
5539 | 5625 | ||
5540 | /* | 5626 | /* |
5541 | * a DESTROY_SESSION request | 5627 | * Decode DESTROY_SESSION response |
5542 | */ | 5628 | */ |
5543 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | 5629 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, |
5544 | void *dummy) | 5630 | void *dummy) |
@@ -5555,7 +5641,7 @@ static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | |||
5555 | } | 5641 | } |
5556 | 5642 | ||
5557 | /* | 5643 | /* |
5558 | * a SEQUENCE request | 5644 | * Decode SEQUENCE response |
5559 | */ | 5645 | */ |
5560 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | 5646 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, |
5561 | struct nfs4_sequence_res *res) | 5647 | struct nfs4_sequence_res *res) |
@@ -5572,7 +5658,7 @@ static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | |||
5572 | } | 5658 | } |
5573 | 5659 | ||
5574 | /* | 5660 | /* |
5575 | * a GET_LEASE_TIME request | 5661 | * Decode GET_LEASE_TIME response |
5576 | */ | 5662 | */ |
5577 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | 5663 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, |
5578 | struct nfs4_get_lease_time_res *res) | 5664 | struct nfs4_get_lease_time_res *res) |
@@ -5591,6 +5677,25 @@ static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | |||
5591 | status = decode_fsinfo(&xdr, res->lr_fsinfo); | 5677 | status = decode_fsinfo(&xdr, res->lr_fsinfo); |
5592 | return status; | 5678 | return status; |
5593 | } | 5679 | } |
5680 | |||
5681 | /* | ||
5682 | * Decode RECLAIM_COMPLETE response | ||
5683 | */ | ||
5684 | static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p, | ||
5685 | struct nfs41_reclaim_complete_res *res) | ||
5686 | { | ||
5687 | struct xdr_stream xdr; | ||
5688 | struct compound_hdr hdr; | ||
5689 | int status; | ||
5690 | |||
5691 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5692 | status = decode_compound_hdr(&xdr, &hdr); | ||
5693 | if (!status) | ||
5694 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5695 | if (!status) | ||
5696 | status = decode_reclaim_complete(&xdr, (void *)NULL); | ||
5697 | return status; | ||
5698 | } | ||
5594 | #endif /* CONFIG_NFS_V4_1 */ | 5699 | #endif /* CONFIG_NFS_V4_1 */ |
5595 | 5700 | ||
5596 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5701 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
@@ -5678,7 +5783,7 @@ static struct { | |||
5678 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, | 5783 | { NFS4ERR_BAD_COOKIE, -EBADCOOKIE }, |
5679 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, | 5784 | { NFS4ERR_NOTSUPP, -ENOTSUPP }, |
5680 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, | 5785 | { NFS4ERR_TOOSMALL, -ETOOSMALL }, |
5681 | { NFS4ERR_SERVERFAULT, -ESERVERFAULT }, | 5786 | { NFS4ERR_SERVERFAULT, -EREMOTEIO }, |
5682 | { NFS4ERR_BADTYPE, -EBADTYPE }, | 5787 | { NFS4ERR_BADTYPE, -EBADTYPE }, |
5683 | { NFS4ERR_LOCKED, -EAGAIN }, | 5788 | { NFS4ERR_LOCKED, -EAGAIN }, |
5684 | { NFS4ERR_SYMLINK, -ELOOP }, | 5789 | { NFS4ERR_SYMLINK, -ELOOP }, |
@@ -5705,7 +5810,7 @@ nfs4_stat_to_errno(int stat) | |||
5705 | } | 5810 | } |
5706 | if (stat <= 10000 || stat > 10100) { | 5811 | if (stat <= 10000 || stat > 10100) { |
5707 | /* The server is looney tunes. */ | 5812 | /* The server is looney tunes. */ |
5708 | return -ESERVERFAULT; | 5813 | return -EREMOTEIO; |
5709 | } | 5814 | } |
5710 | /* If we cannot translate the error, the recovery routines should | 5815 | /* If we cannot translate the error, the recovery routines should |
5711 | * handle it. | 5816 | * handle it. |
@@ -5767,6 +5872,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
5767 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | 5872 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), |
5768 | PROC(SEQUENCE, enc_sequence, dec_sequence), | 5873 | PROC(SEQUENCE, enc_sequence, dec_sequence), |
5769 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | 5874 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), |
5875 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), | ||
5770 | #endif /* CONFIG_NFS_V4_1 */ | 5876 | #endif /* CONFIG_NFS_V4_1 */ |
5771 | }; | 5877 | }; |
5772 | 5878 | ||
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index e2975939126a..29d9d36cd5f4 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -112,12 +112,10 @@ void nfs_unlock_request(struct nfs_page *req) | |||
112 | */ | 112 | */ |
113 | int nfs_set_page_tag_locked(struct nfs_page *req) | 113 | int nfs_set_page_tag_locked(struct nfs_page *req) |
114 | { | 114 | { |
115 | struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode); | ||
116 | |||
117 | if (!nfs_lock_request_dontget(req)) | 115 | if (!nfs_lock_request_dontget(req)) |
118 | return 0; | 116 | return 0; |
119 | if (req->wb_page != NULL) | 117 | if (req->wb_page != NULL) |
120 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 118 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
121 | return 1; | 119 | return 1; |
122 | } | 120 | } |
123 | 121 | ||
@@ -126,10 +124,10 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
126 | */ | 124 | */ |
127 | void nfs_clear_page_tag_locked(struct nfs_page *req) | 125 | void nfs_clear_page_tag_locked(struct nfs_page *req) |
128 | { | 126 | { |
129 | struct inode *inode = req->wb_context->path.dentry->d_inode; | ||
130 | struct nfs_inode *nfsi = NFS_I(inode); | ||
131 | |||
132 | if (req->wb_page != NULL) { | 127 | if (req->wb_page != NULL) { |
128 | struct inode *inode = req->wb_context->path.dentry->d_inode; | ||
129 | struct nfs_inode *nfsi = NFS_I(inode); | ||
130 | |||
133 | spin_lock(&inode->i_lock); | 131 | spin_lock(&inode->i_lock); |
134 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 132 | radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
135 | nfs_unlock_request(req); | 133 | nfs_unlock_request(req); |
@@ -142,16 +140,22 @@ void nfs_clear_page_tag_locked(struct nfs_page *req) | |||
142 | * nfs_clear_request - Free up all resources allocated to the request | 140 | * nfs_clear_request - Free up all resources allocated to the request |
143 | * @req: | 141 | * @req: |
144 | * | 142 | * |
145 | * Release page resources associated with a write request after it | 143 | * Release page and open context resources associated with a read/write |
146 | * has completed. | 144 | * request after it has completed. |
147 | */ | 145 | */ |
148 | void nfs_clear_request(struct nfs_page *req) | 146 | void nfs_clear_request(struct nfs_page *req) |
149 | { | 147 | { |
150 | struct page *page = req->wb_page; | 148 | struct page *page = req->wb_page; |
149 | struct nfs_open_context *ctx = req->wb_context; | ||
150 | |||
151 | if (page != NULL) { | 151 | if (page != NULL) { |
152 | page_cache_release(page); | 152 | page_cache_release(page); |
153 | req->wb_page = NULL; | 153 | req->wb_page = NULL; |
154 | } | 154 | } |
155 | if (ctx != NULL) { | ||
156 | put_nfs_open_context(ctx); | ||
157 | req->wb_context = NULL; | ||
158 | } | ||
155 | } | 159 | } |
156 | 160 | ||
157 | 161 | ||
@@ -165,9 +169,8 @@ static void nfs_free_request(struct kref *kref) | |||
165 | { | 169 | { |
166 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); | 170 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); |
167 | 171 | ||
168 | /* Release struct file or cached credential */ | 172 | /* Release struct file and open context */ |
169 | nfs_clear_request(req); | 173 | nfs_clear_request(req); |
170 | put_nfs_open_context(req->wb_context); | ||
171 | nfs_page_free(req); | 174 | nfs_page_free(req); |
172 | } | 175 | } |
173 | 176 | ||
@@ -176,6 +179,12 @@ void nfs_release_request(struct nfs_page *req) | |||
176 | kref_put(&req->wb_kref, nfs_free_request); | 179 | kref_put(&req->wb_kref, nfs_free_request); |
177 | } | 180 | } |
178 | 181 | ||
182 | static int nfs_wait_bit_uninterruptible(void *word) | ||
183 | { | ||
184 | io_schedule(); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
179 | /** | 188 | /** |
180 | * nfs_wait_on_request - Wait for a request to complete. | 189 | * nfs_wait_on_request - Wait for a request to complete. |
181 | * @req: request to wait upon. | 190 | * @req: request to wait upon. |
@@ -186,14 +195,9 @@ void nfs_release_request(struct nfs_page *req) | |||
186 | int | 195 | int |
187 | nfs_wait_on_request(struct nfs_page *req) | 196 | nfs_wait_on_request(struct nfs_page *req) |
188 | { | 197 | { |
189 | int ret = 0; | 198 | return wait_on_bit(&req->wb_flags, PG_BUSY, |
190 | 199 | nfs_wait_bit_uninterruptible, | |
191 | if (!test_bit(PG_BUSY, &req->wb_flags)) | 200 | TASK_UNINTERRUPTIBLE); |
192 | goto out; | ||
193 | ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY, | ||
194 | nfs_wait_bit_killable, TASK_KILLABLE); | ||
195 | out: | ||
196 | return ret; | ||
197 | } | 201 | } |
198 | 202 | ||
199 | /** | 203 | /** |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ef583854d8d0..0288be80444f 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
@@ -29,7 +29,6 @@ | |||
29 | 29 | ||
30 | #include <linux/types.h> | 30 | #include <linux/types.h> |
31 | #include <linux/param.h> | 31 | #include <linux/param.h> |
32 | #include <linux/slab.h> | ||
33 | #include <linux/time.h> | 32 | #include <linux/time.h> |
34 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
35 | #include <linux/errno.h> | 34 | #include <linux/errno.h> |
@@ -47,6 +46,39 @@ | |||
47 | #define NFSDBG_FACILITY NFSDBG_PROC | 46 | #define NFSDBG_FACILITY NFSDBG_PROC |
48 | 47 | ||
49 | /* | 48 | /* |
49 | * wrapper to handle the -EKEYEXPIRED error message. This should generally | ||
50 | * only happen if using krb5 auth and a user's TGT expires. NFSv2 doesn't | ||
51 | * support the NFSERR_JUKEBOX error code, but we handle this situation in the | ||
52 | * same way that we handle that error with NFSv3. | ||
53 | */ | ||
54 | static int | ||
55 | nfs_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) | ||
56 | { | ||
57 | int res; | ||
58 | do { | ||
59 | res = rpc_call_sync(clnt, msg, flags); | ||
60 | if (res != -EKEYEXPIRED) | ||
61 | break; | ||
62 | schedule_timeout_killable(NFS_JUKEBOX_RETRY_TIME); | ||
63 | res = -ERESTARTSYS; | ||
64 | } while (!fatal_signal_pending(current)); | ||
65 | return res; | ||
66 | } | ||
67 | |||
68 | #define rpc_call_sync(clnt, msg, flags) nfs_rpc_wrapper(clnt, msg, flags) | ||
69 | |||
70 | static int | ||
71 | nfs_async_handle_expired_key(struct rpc_task *task) | ||
72 | { | ||
73 | if (task->tk_status != -EKEYEXPIRED) | ||
74 | return 0; | ||
75 | task->tk_status = 0; | ||
76 | rpc_restart_call(task); | ||
77 | rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); | ||
78 | return 1; | ||
79 | } | ||
80 | |||
81 | /* | ||
50 | * Bare-bones access to getattr: this is for nfs_read_super. | 82 | * Bare-bones access to getattr: this is for nfs_read_super. |
51 | */ | 83 | */ |
52 | static int | 84 | static int |
@@ -307,6 +339,8 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir) | |||
307 | 339 | ||
308 | static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) | 340 | static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) |
309 | { | 341 | { |
342 | if (nfs_async_handle_expired_key(task)) | ||
343 | return 0; | ||
310 | nfs_mark_for_revalidate(dir); | 344 | nfs_mark_for_revalidate(dir); |
311 | return 1; | 345 | return 1; |
312 | } | 346 | } |
@@ -560,6 +594,9 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
560 | 594 | ||
561 | static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) | 595 | static int nfs_read_done(struct rpc_task *task, struct nfs_read_data *data) |
562 | { | 596 | { |
597 | if (nfs_async_handle_expired_key(task)) | ||
598 | return -EAGAIN; | ||
599 | |||
563 | nfs_invalidate_atime(data->inode); | 600 | nfs_invalidate_atime(data->inode); |
564 | if (task->tk_status >= 0) { | 601 | if (task->tk_status >= 0) { |
565 | nfs_refresh_inode(data->inode, data->res.fattr); | 602 | nfs_refresh_inode(data->inode, data->res.fattr); |
@@ -579,6 +616,9 @@ static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message * | |||
579 | 616 | ||
580 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) | 617 | static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data) |
581 | { | 618 | { |
619 | if (nfs_async_handle_expired_key(task)) | ||
620 | return -EAGAIN; | ||
621 | |||
582 | if (task->tk_status >= 0) | 622 | if (task->tk_status >= 0) |
583 | nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); | 623 | nfs_post_op_update_inode_force_wcc(data->inode, data->res.fattr); |
584 | return 0; | 624 | return 0; |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 12c9e66d3f1d..db9b360ae19d 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -356,25 +356,19 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
356 | struct nfs_readres *resp = &data->res; | 356 | struct nfs_readres *resp = &data->res; |
357 | 357 | ||
358 | if (resp->eof || resp->count == argp->count) | 358 | if (resp->eof || resp->count == argp->count) |
359 | goto out; | 359 | return; |
360 | 360 | ||
361 | /* This is a short read! */ | 361 | /* This is a short read! */ |
362 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 362 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
363 | /* Has the server at least made some progress? */ | 363 | /* Has the server at least made some progress? */ |
364 | if (resp->count == 0) | 364 | if (resp->count == 0) |
365 | goto out; | 365 | return; |
366 | 366 | ||
367 | /* Yes, so retry the read at the end of the data */ | 367 | /* Yes, so retry the read at the end of the data */ |
368 | argp->offset += resp->count; | 368 | argp->offset += resp->count; |
369 | argp->pgbase += resp->count; | 369 | argp->pgbase += resp->count; |
370 | argp->count -= resp->count; | 370 | argp->count -= resp->count; |
371 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); | 371 | nfs_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); |
372 | return; | ||
373 | out: | ||
374 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | ||
375 | &data->res.seq_res); | ||
376 | return; | ||
377 | |||
378 | } | 372 | } |
379 | 373 | ||
380 | /* | 374 | /* |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 90be551b80c1..b4148fc00f9f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
49 | #include <linux/inet.h> | 49 | #include <linux/inet.h> |
50 | #include <linux/in6.h> | 50 | #include <linux/in6.h> |
51 | #include <linux/slab.h> | ||
51 | #include <net/ipv6.h> | 52 | #include <net/ipv6.h> |
52 | #include <linux/netdevice.h> | 53 | #include <linux/netdevice.h> |
53 | #include <linux/nfs_xdr.h> | 54 | #include <linux/nfs_xdr.h> |
@@ -175,14 +176,16 @@ static const match_table_t nfs_mount_option_tokens = { | |||
175 | }; | 176 | }; |
176 | 177 | ||
177 | enum { | 178 | enum { |
178 | Opt_xprt_udp, Opt_xprt_tcp, Opt_xprt_rdma, | 179 | Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma, |
179 | 180 | ||
180 | Opt_xprt_err | 181 | Opt_xprt_err |
181 | }; | 182 | }; |
182 | 183 | ||
183 | static const match_table_t nfs_xprt_protocol_tokens = { | 184 | static const match_table_t nfs_xprt_protocol_tokens = { |
184 | { Opt_xprt_udp, "udp" }, | 185 | { Opt_xprt_udp, "udp" }, |
186 | { Opt_xprt_udp6, "udp6" }, | ||
185 | { Opt_xprt_tcp, "tcp" }, | 187 | { Opt_xprt_tcp, "tcp" }, |
188 | { Opt_xprt_tcp6, "tcp6" }, | ||
186 | { Opt_xprt_rdma, "rdma" }, | 189 | { Opt_xprt_rdma, "rdma" }, |
187 | 190 | ||
188 | { Opt_xprt_err, NULL } | 191 | { Opt_xprt_err, NULL } |
@@ -241,6 +244,7 @@ static int nfs_show_stats(struct seq_file *, struct vfsmount *); | |||
241 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); | 244 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); |
242 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, | 245 | static int nfs_xdev_get_sb(struct file_system_type *fs_type, |
243 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 246 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); |
247 | static void nfs_put_super(struct super_block *); | ||
244 | static void nfs_kill_super(struct super_block *); | 248 | static void nfs_kill_super(struct super_block *); |
245 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | 249 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); |
246 | 250 | ||
@@ -264,6 +268,7 @@ static const struct super_operations nfs_sops = { | |||
264 | .alloc_inode = nfs_alloc_inode, | 268 | .alloc_inode = nfs_alloc_inode, |
265 | .destroy_inode = nfs_destroy_inode, | 269 | .destroy_inode = nfs_destroy_inode, |
266 | .write_inode = nfs_write_inode, | 270 | .write_inode = nfs_write_inode, |
271 | .put_super = nfs_put_super, | ||
267 | .statfs = nfs_statfs, | 272 | .statfs = nfs_statfs, |
268 | .clear_inode = nfs_clear_inode, | 273 | .clear_inode = nfs_clear_inode, |
269 | .umount_begin = nfs_umount_begin, | 274 | .umount_begin = nfs_umount_begin, |
@@ -333,6 +338,7 @@ static const struct super_operations nfs4_sops = { | |||
333 | .alloc_inode = nfs_alloc_inode, | 338 | .alloc_inode = nfs_alloc_inode, |
334 | .destroy_inode = nfs_destroy_inode, | 339 | .destroy_inode = nfs_destroy_inode, |
335 | .write_inode = nfs_write_inode, | 340 | .write_inode = nfs_write_inode, |
341 | .put_super = nfs_put_super, | ||
336 | .statfs = nfs_statfs, | 342 | .statfs = nfs_statfs, |
337 | .clear_inode = nfs4_clear_inode, | 343 | .clear_inode = nfs4_clear_inode, |
338 | .umount_begin = nfs_umount_begin, | 344 | .umount_begin = nfs_umount_begin, |
@@ -492,6 +498,45 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour) | |||
492 | return sec_flavours[i].str; | 498 | return sec_flavours[i].str; |
493 | } | 499 | } |
494 | 500 | ||
501 | static void nfs_show_mountd_netid(struct seq_file *m, struct nfs_server *nfss, | ||
502 | int showdefaults) | ||
503 | { | ||
504 | struct sockaddr *sap = (struct sockaddr *) &nfss->mountd_address; | ||
505 | |||
506 | seq_printf(m, ",mountproto="); | ||
507 | switch (sap->sa_family) { | ||
508 | case AF_INET: | ||
509 | switch (nfss->mountd_protocol) { | ||
510 | case IPPROTO_UDP: | ||
511 | seq_printf(m, RPCBIND_NETID_UDP); | ||
512 | break; | ||
513 | case IPPROTO_TCP: | ||
514 | seq_printf(m, RPCBIND_NETID_TCP); | ||
515 | break; | ||
516 | default: | ||
517 | if (showdefaults) | ||
518 | seq_printf(m, "auto"); | ||
519 | } | ||
520 | break; | ||
521 | case AF_INET6: | ||
522 | switch (nfss->mountd_protocol) { | ||
523 | case IPPROTO_UDP: | ||
524 | seq_printf(m, RPCBIND_NETID_UDP6); | ||
525 | break; | ||
526 | case IPPROTO_TCP: | ||
527 | seq_printf(m, RPCBIND_NETID_TCP6); | ||
528 | break; | ||
529 | default: | ||
530 | if (showdefaults) | ||
531 | seq_printf(m, "auto"); | ||
532 | } | ||
533 | break; | ||
534 | default: | ||
535 | if (showdefaults) | ||
536 | seq_printf(m, "auto"); | ||
537 | } | ||
538 | } | ||
539 | |||
495 | static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | 540 | static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, |
496 | int showdefaults) | 541 | int showdefaults) |
497 | { | 542 | { |
@@ -505,7 +550,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
505 | } | 550 | } |
506 | case AF_INET6: { | 551 | case AF_INET6: { |
507 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; | 552 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; |
508 | seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr); | 553 | seq_printf(m, ",mountaddr=%pI6c", &sin6->sin6_addr); |
509 | break; | 554 | break; |
510 | } | 555 | } |
511 | default: | 556 | default: |
@@ -518,17 +563,7 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, | |||
518 | if (nfss->mountd_port || showdefaults) | 563 | if (nfss->mountd_port || showdefaults) |
519 | seq_printf(m, ",mountport=%u", nfss->mountd_port); | 564 | seq_printf(m, ",mountport=%u", nfss->mountd_port); |
520 | 565 | ||
521 | switch (nfss->mountd_protocol) { | 566 | nfs_show_mountd_netid(m, nfss, showdefaults); |
522 | case IPPROTO_UDP: | ||
523 | seq_printf(m, ",mountproto=udp"); | ||
524 | break; | ||
525 | case IPPROTO_TCP: | ||
526 | seq_printf(m, ",mountproto=tcp"); | ||
527 | break; | ||
528 | default: | ||
529 | if (showdefaults) | ||
530 | seq_printf(m, ",mountproto=auto"); | ||
531 | } | ||
532 | } | 567 | } |
533 | 568 | ||
534 | /* | 569 | /* |
@@ -578,7 +613,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
578 | seq_puts(m, nfs_infop->nostr); | 613 | seq_puts(m, nfs_infop->nostr); |
579 | } | 614 | } |
580 | seq_printf(m, ",proto=%s", | 615 | seq_printf(m, ",proto=%s", |
581 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_PROTO)); | 616 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); |
582 | if (version == 4) { | 617 | if (version == 4) { |
583 | if (nfss->port != NFS_PORT) | 618 | if (nfss->port != NFS_PORT) |
584 | seq_printf(m, ",port=%u", nfss->port); | 619 | seq_printf(m, ",port=%u", nfss->port); |
@@ -714,8 +749,6 @@ static void nfs_umount_begin(struct super_block *sb) | |||
714 | struct nfs_server *server; | 749 | struct nfs_server *server; |
715 | struct rpc_clnt *rpc; | 750 | struct rpc_clnt *rpc; |
716 | 751 | ||
717 | lock_kernel(); | ||
718 | |||
719 | server = NFS_SB(sb); | 752 | server = NFS_SB(sb); |
720 | /* -EIO all pending I/O */ | 753 | /* -EIO all pending I/O */ |
721 | rpc = server->client_acl; | 754 | rpc = server->client_acl; |
@@ -724,8 +757,6 @@ static void nfs_umount_begin(struct super_block *sb) | |||
724 | rpc = server->client; | 757 | rpc = server->client; |
725 | if (!IS_ERR(rpc)) | 758 | if (!IS_ERR(rpc)) |
726 | rpc_killall_tasks(rpc); | 759 | rpc_killall_tasks(rpc); |
727 | |||
728 | unlock_kernel(); | ||
729 | } | 760 | } |
730 | 761 | ||
731 | static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version) | 762 | static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version) |
@@ -734,8 +765,6 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve | |||
734 | 765 | ||
735 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 766 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
736 | if (data) { | 767 | if (data) { |
737 | data->rsize = NFS_MAX_FILE_IO_SIZE; | ||
738 | data->wsize = NFS_MAX_FILE_IO_SIZE; | ||
739 | data->acregmin = NFS_DEF_ACREGMIN; | 768 | data->acregmin = NFS_DEF_ACREGMIN; |
740 | data->acregmax = NFS_DEF_ACREGMAX; | 769 | data->acregmax = NFS_DEF_ACREGMAX; |
741 | data->acdirmin = NFS_DEF_ACDIRMIN; | 770 | data->acdirmin = NFS_DEF_ACDIRMIN; |
@@ -887,6 +916,8 @@ static int nfs_parse_mount_options(char *raw, | |||
887 | { | 916 | { |
888 | char *p, *string, *secdata; | 917 | char *p, *string, *secdata; |
889 | int rc, sloppy = 0, invalid_option = 0; | 918 | int rc, sloppy = 0, invalid_option = 0; |
919 | unsigned short protofamily = AF_UNSPEC; | ||
920 | unsigned short mountfamily = AF_UNSPEC; | ||
890 | 921 | ||
891 | if (!raw) { | 922 | if (!raw) { |
892 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 923 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -1232,12 +1263,17 @@ static int nfs_parse_mount_options(char *raw, | |||
1232 | token = match_token(string, | 1263 | token = match_token(string, |
1233 | nfs_xprt_protocol_tokens, args); | 1264 | nfs_xprt_protocol_tokens, args); |
1234 | 1265 | ||
1266 | protofamily = AF_INET; | ||
1235 | switch (token) { | 1267 | switch (token) { |
1268 | case Opt_xprt_udp6: | ||
1269 | protofamily = AF_INET6; | ||
1236 | case Opt_xprt_udp: | 1270 | case Opt_xprt_udp: |
1237 | mnt->flags &= ~NFS_MOUNT_TCP; | 1271 | mnt->flags &= ~NFS_MOUNT_TCP; |
1238 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1272 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
1239 | kfree(string); | 1273 | kfree(string); |
1240 | break; | 1274 | break; |
1275 | case Opt_xprt_tcp6: | ||
1276 | protofamily = AF_INET6; | ||
1241 | case Opt_xprt_tcp: | 1277 | case Opt_xprt_tcp: |
1242 | mnt->flags |= NFS_MOUNT_TCP; | 1278 | mnt->flags |= NFS_MOUNT_TCP; |
1243 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; | 1279 | mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP; |
@@ -1265,10 +1301,15 @@ static int nfs_parse_mount_options(char *raw, | |||
1265 | nfs_xprt_protocol_tokens, args); | 1301 | nfs_xprt_protocol_tokens, args); |
1266 | kfree(string); | 1302 | kfree(string); |
1267 | 1303 | ||
1304 | mountfamily = AF_INET; | ||
1268 | switch (token) { | 1305 | switch (token) { |
1306 | case Opt_xprt_udp6: | ||
1307 | mountfamily = AF_INET6; | ||
1269 | case Opt_xprt_udp: | 1308 | case Opt_xprt_udp: |
1270 | mnt->mount_server.protocol = XPRT_TRANSPORT_UDP; | 1309 | mnt->mount_server.protocol = XPRT_TRANSPORT_UDP; |
1271 | break; | 1310 | break; |
1311 | case Opt_xprt_tcp6: | ||
1312 | mountfamily = AF_INET6; | ||
1272 | case Opt_xprt_tcp: | 1313 | case Opt_xprt_tcp: |
1273 | mnt->mount_server.protocol = XPRT_TRANSPORT_TCP; | 1314 | mnt->mount_server.protocol = XPRT_TRANSPORT_TCP; |
1274 | break; | 1315 | break; |
@@ -1367,8 +1408,33 @@ static int nfs_parse_mount_options(char *raw, | |||
1367 | if (!sloppy && invalid_option) | 1408 | if (!sloppy && invalid_option) |
1368 | return 0; | 1409 | return 0; |
1369 | 1410 | ||
1411 | /* | ||
1412 | * verify that any proto=/mountproto= options match the address | ||
1413 | * familiies in the addr=/mountaddr= options. | ||
1414 | */ | ||
1415 | if (protofamily != AF_UNSPEC && | ||
1416 | protofamily != mnt->nfs_server.address.ss_family) | ||
1417 | goto out_proto_mismatch; | ||
1418 | |||
1419 | if (mountfamily != AF_UNSPEC) { | ||
1420 | if (mnt->mount_server.addrlen) { | ||
1421 | if (mountfamily != mnt->mount_server.address.ss_family) | ||
1422 | goto out_mountproto_mismatch; | ||
1423 | } else { | ||
1424 | if (mountfamily != mnt->nfs_server.address.ss_family) | ||
1425 | goto out_mountproto_mismatch; | ||
1426 | } | ||
1427 | } | ||
1428 | |||
1370 | return 1; | 1429 | return 1; |
1371 | 1430 | ||
1431 | out_mountproto_mismatch: | ||
1432 | printk(KERN_INFO "NFS: mount server address does not match mountproto= " | ||
1433 | "option\n"); | ||
1434 | return 0; | ||
1435 | out_proto_mismatch: | ||
1436 | printk(KERN_INFO "NFS: server address does not match proto= option\n"); | ||
1437 | return 0; | ||
1372 | out_invalid_address: | 1438 | out_invalid_address: |
1373 | printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); | 1439 | printk(KERN_INFO "NFS: bad IP address specified: %s\n", p); |
1374 | return 0; | 1440 | return 0; |
@@ -1881,7 +1947,6 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
1881 | if (data == NULL) | 1947 | if (data == NULL) |
1882 | return -ENOMEM; | 1948 | return -ENOMEM; |
1883 | 1949 | ||
1884 | lock_kernel(); | ||
1885 | /* fill out struct with values from existing mount */ | 1950 | /* fill out struct with values from existing mount */ |
1886 | data->flags = nfss->flags; | 1951 | data->flags = nfss->flags; |
1887 | data->rsize = nfss->rsize; | 1952 | data->rsize = nfss->rsize; |
@@ -1907,7 +1972,6 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
1907 | error = nfs_compare_remount_data(nfss, data); | 1972 | error = nfs_compare_remount_data(nfss, data); |
1908 | out: | 1973 | out: |
1909 | kfree(data); | 1974 | kfree(data); |
1910 | unlock_kernel(); | ||
1911 | return error; | 1975 | return error; |
1912 | } | 1976 | } |
1913 | 1977 | ||
@@ -2123,6 +2187,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2123 | if (data->version == 4) { | 2187 | if (data->version == 4) { |
2124 | error = nfs4_try_mount(flags, dev_name, data, mnt); | 2188 | error = nfs4_try_mount(flags, dev_name, data, mnt); |
2125 | kfree(data->client_address); | 2189 | kfree(data->client_address); |
2190 | kfree(data->nfs_server.export_path); | ||
2126 | goto out; | 2191 | goto out; |
2127 | } | 2192 | } |
2128 | #endif /* CONFIG_NFS_V4 */ | 2193 | #endif /* CONFIG_NFS_V4 */ |
@@ -2151,7 +2216,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
2151 | } else { | 2216 | } else { |
2152 | error = nfs_bdi_register(server); | 2217 | error = nfs_bdi_register(server); |
2153 | if (error) | 2218 | if (error) |
2154 | goto error_splat_super; | 2219 | goto error_splat_bdi; |
2155 | } | 2220 | } |
2156 | 2221 | ||
2157 | if (!s->s_root) { | 2222 | if (!s->s_root) { |
@@ -2193,11 +2258,25 @@ out_err_nosb: | |||
2193 | error_splat_root: | 2258 | error_splat_root: |
2194 | dput(mntroot); | 2259 | dput(mntroot); |
2195 | error_splat_super: | 2260 | error_splat_super: |
2261 | if (server && !s->s_root) | ||
2262 | bdi_unregister(&server->backing_dev_info); | ||
2263 | error_splat_bdi: | ||
2196 | deactivate_locked_super(s); | 2264 | deactivate_locked_super(s); |
2197 | goto out; | 2265 | goto out; |
2198 | } | 2266 | } |
2199 | 2267 | ||
2200 | /* | 2268 | /* |
2269 | * Ensure that we unregister the bdi before kill_anon_super | ||
2270 | * releases the device name | ||
2271 | */ | ||
2272 | static void nfs_put_super(struct super_block *s) | ||
2273 | { | ||
2274 | struct nfs_server *server = NFS_SB(s); | ||
2275 | |||
2276 | bdi_unregister(&server->backing_dev_info); | ||
2277 | } | ||
2278 | |||
2279 | /* | ||
2201 | * Destroy an NFS2/3 superblock | 2280 | * Destroy an NFS2/3 superblock |
2202 | */ | 2281 | */ |
2203 | static void nfs_kill_super(struct super_block *s) | 2282 | static void nfs_kill_super(struct super_block *s) |
@@ -2205,7 +2284,6 @@ static void nfs_kill_super(struct super_block *s) | |||
2205 | struct nfs_server *server = NFS_SB(s); | 2284 | struct nfs_server *server = NFS_SB(s); |
2206 | 2285 | ||
2207 | kill_anon_super(s); | 2286 | kill_anon_super(s); |
2208 | bdi_unregister(&server->backing_dev_info); | ||
2209 | nfs_fscache_release_super_cookie(s); | 2287 | nfs_fscache_release_super_cookie(s); |
2210 | nfs_free_server(server); | 2288 | nfs_free_server(server); |
2211 | } | 2289 | } |
@@ -2253,7 +2331,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
2253 | } else { | 2331 | } else { |
2254 | error = nfs_bdi_register(server); | 2332 | error = nfs_bdi_register(server); |
2255 | if (error) | 2333 | if (error) |
2256 | goto error_splat_super; | 2334 | goto error_splat_bdi; |
2257 | } | 2335 | } |
2258 | 2336 | ||
2259 | if (!s->s_root) { | 2337 | if (!s->s_root) { |
@@ -2290,6 +2368,9 @@ out_err_noserver: | |||
2290 | return error; | 2368 | return error; |
2291 | 2369 | ||
2292 | error_splat_super: | 2370 | error_splat_super: |
2371 | if (server && !s->s_root) | ||
2372 | bdi_unregister(&server->backing_dev_info); | ||
2373 | error_splat_bdi: | ||
2293 | deactivate_locked_super(s); | 2374 | deactivate_locked_super(s); |
2294 | dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); | 2375 | dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error); |
2295 | return error; | 2376 | return error; |
@@ -2505,7 +2586,7 @@ static int nfs4_remote_get_sb(struct file_system_type *fs_type, | |||
2505 | } else { | 2586 | } else { |
2506 | error = nfs_bdi_register(server); | 2587 | error = nfs_bdi_register(server); |
2507 | if (error) | 2588 | if (error) |
2508 | goto error_splat_super; | 2589 | goto error_splat_bdi; |
2509 | } | 2590 | } |
2510 | 2591 | ||
2511 | if (!s->s_root) { | 2592 | if (!s->s_root) { |
@@ -2543,6 +2624,9 @@ out_free: | |||
2543 | error_splat_root: | 2624 | error_splat_root: |
2544 | dput(mntroot); | 2625 | dput(mntroot); |
2545 | error_splat_super: | 2626 | error_splat_super: |
2627 | if (server && !s->s_root) | ||
2628 | bdi_unregister(&server->backing_dev_info); | ||
2629 | error_splat_bdi: | ||
2546 | deactivate_locked_super(s); | 2630 | deactivate_locked_super(s); |
2547 | goto out; | 2631 | goto out; |
2548 | } | 2632 | } |
@@ -2574,7 +2658,7 @@ static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | |||
2574 | devname = nfs_path(path->mnt->mnt_devname, | 2658 | devname = nfs_path(path->mnt->mnt_devname, |
2575 | path->mnt->mnt_root, path->dentry, | 2659 | path->mnt->mnt_root, path->dentry, |
2576 | page, PAGE_SIZE); | 2660 | page, PAGE_SIZE); |
2577 | if (devname == NULL) | 2661 | if (IS_ERR(devname)) |
2578 | goto out_freepage; | 2662 | goto out_freepage; |
2579 | tmp = kstrdup(devname, GFP_KERNEL); | 2663 | tmp = kstrdup(devname, GFP_KERNEL); |
2580 | if (tmp == NULL) | 2664 | if (tmp == NULL) |
@@ -2738,7 +2822,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
2738 | } else { | 2822 | } else { |
2739 | error = nfs_bdi_register(server); | 2823 | error = nfs_bdi_register(server); |
2740 | if (error) | 2824 | if (error) |
2741 | goto error_splat_super; | 2825 | goto error_splat_bdi; |
2742 | } | 2826 | } |
2743 | 2827 | ||
2744 | if (!s->s_root) { | 2828 | if (!s->s_root) { |
@@ -2774,6 +2858,9 @@ out_err_noserver: | |||
2774 | return error; | 2858 | return error; |
2775 | 2859 | ||
2776 | error_splat_super: | 2860 | error_splat_super: |
2861 | if (server && !s->s_root) | ||
2862 | bdi_unregister(&server->backing_dev_info); | ||
2863 | error_splat_bdi: | ||
2777 | deactivate_locked_super(s); | 2864 | deactivate_locked_super(s); |
2778 | dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); | 2865 | dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error); |
2779 | return error; | 2866 | return error; |
@@ -2820,7 +2907,7 @@ static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type, | |||
2820 | } else { | 2907 | } else { |
2821 | error = nfs_bdi_register(server); | 2908 | error = nfs_bdi_register(server); |
2822 | if (error) | 2909 | if (error) |
2823 | goto error_splat_super; | 2910 | goto error_splat_bdi; |
2824 | } | 2911 | } |
2825 | 2912 | ||
2826 | if (!s->s_root) { | 2913 | if (!s->s_root) { |
@@ -2856,6 +2943,9 @@ out_err_noserver: | |||
2856 | return error; | 2943 | return error; |
2857 | 2944 | ||
2858 | error_splat_super: | 2945 | error_splat_super: |
2946 | if (server && !s->s_root) | ||
2947 | bdi_unregister(&server->backing_dev_info); | ||
2948 | error_splat_bdi: | ||
2859 | deactivate_locked_super(s); | 2949 | deactivate_locked_super(s); |
2860 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); | 2950 | dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error); |
2861 | return error; | 2951 | return error; |
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 412738dbfbc7..05c9e02f4153 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
20 | #include <linux/stat.h> | 20 | #include <linux/stat.h> |
21 | #include <linux/mm.h> | 21 | #include <linux/mm.h> |
22 | #include <linux/slab.h> | ||
23 | #include <linux/string.h> | 22 | #include <linux/string.h> |
24 | #include <linux/namei.h> | 23 | #include <linux/namei.h> |
25 | 24 | ||
@@ -50,7 +49,7 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
50 | struct page *page; | 49 | struct page *page; |
51 | void *err; | 50 | void *err; |
52 | 51 | ||
53 | err = ERR_PTR(nfs_revalidate_mapping_nolock(inode, inode->i_mapping)); | 52 | err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping)); |
54 | if (err) | 53 | if (err) |
55 | goto read_failed; | 54 | goto read_failed; |
56 | page = read_cache_page(&inode->i_data, 0, | 55 | page = read_cache_page(&inode->i_data, 0, |
diff --git a/fs/nfs/sysctl.c b/fs/nfs/sysctl.c index b62481dabae9..ad4d2e787b20 100644 --- a/fs/nfs/sysctl.c +++ b/fs/nfs/sysctl.c | |||
@@ -15,70 +15,64 @@ | |||
15 | 15 | ||
16 | #include "callback.h" | 16 | #include "callback.h" |
17 | 17 | ||
18 | #ifdef CONFIG_NFS_V4 | ||
18 | static const int nfs_set_port_min = 0; | 19 | static const int nfs_set_port_min = 0; |
19 | static const int nfs_set_port_max = 65535; | 20 | static const int nfs_set_port_max = 65535; |
21 | #endif | ||
20 | static struct ctl_table_header *nfs_callback_sysctl_table; | 22 | static struct ctl_table_header *nfs_callback_sysctl_table; |
21 | 23 | ||
22 | static ctl_table nfs_cb_sysctls[] = { | 24 | static ctl_table nfs_cb_sysctls[] = { |
23 | #ifdef CONFIG_NFS_V4 | 25 | #ifdef CONFIG_NFS_V4 |
24 | { | 26 | { |
25 | .ctl_name = CTL_UNNUMBERED, | ||
26 | .procname = "nfs_callback_tcpport", | 27 | .procname = "nfs_callback_tcpport", |
27 | .data = &nfs_callback_set_tcpport, | 28 | .data = &nfs_callback_set_tcpport, |
28 | .maxlen = sizeof(int), | 29 | .maxlen = sizeof(int), |
29 | .mode = 0644, | 30 | .mode = 0644, |
30 | .proc_handler = &proc_dointvec_minmax, | 31 | .proc_handler = proc_dointvec_minmax, |
31 | .extra1 = (int *)&nfs_set_port_min, | 32 | .extra1 = (int *)&nfs_set_port_min, |
32 | .extra2 = (int *)&nfs_set_port_max, | 33 | .extra2 = (int *)&nfs_set_port_max, |
33 | }, | 34 | }, |
34 | { | 35 | { |
35 | .ctl_name = CTL_UNNUMBERED, | ||
36 | .procname = "idmap_cache_timeout", | 36 | .procname = "idmap_cache_timeout", |
37 | .data = &nfs_idmap_cache_timeout, | 37 | .data = &nfs_idmap_cache_timeout, |
38 | .maxlen = sizeof(int), | 38 | .maxlen = sizeof(int), |
39 | .mode = 0644, | 39 | .mode = 0644, |
40 | .proc_handler = &proc_dointvec_jiffies, | 40 | .proc_handler = proc_dointvec_jiffies, |
41 | .strategy = &sysctl_jiffies, | ||
42 | }, | 41 | }, |
43 | #endif | 42 | #endif |
44 | { | 43 | { |
45 | .ctl_name = CTL_UNNUMBERED, | ||
46 | .procname = "nfs_mountpoint_timeout", | 44 | .procname = "nfs_mountpoint_timeout", |
47 | .data = &nfs_mountpoint_expiry_timeout, | 45 | .data = &nfs_mountpoint_expiry_timeout, |
48 | .maxlen = sizeof(nfs_mountpoint_expiry_timeout), | 46 | .maxlen = sizeof(nfs_mountpoint_expiry_timeout), |
49 | .mode = 0644, | 47 | .mode = 0644, |
50 | .proc_handler = &proc_dointvec_jiffies, | 48 | .proc_handler = proc_dointvec_jiffies, |
51 | .strategy = &sysctl_jiffies, | ||
52 | }, | 49 | }, |
53 | { | 50 | { |
54 | .ctl_name = CTL_UNNUMBERED, | ||
55 | .procname = "nfs_congestion_kb", | 51 | .procname = "nfs_congestion_kb", |
56 | .data = &nfs_congestion_kb, | 52 | .data = &nfs_congestion_kb, |
57 | .maxlen = sizeof(nfs_congestion_kb), | 53 | .maxlen = sizeof(nfs_congestion_kb), |
58 | .mode = 0644, | 54 | .mode = 0644, |
59 | .proc_handler = &proc_dointvec, | 55 | .proc_handler = proc_dointvec, |
60 | }, | 56 | }, |
61 | { .ctl_name = 0 } | 57 | { } |
62 | }; | 58 | }; |
63 | 59 | ||
64 | static ctl_table nfs_cb_sysctl_dir[] = { | 60 | static ctl_table nfs_cb_sysctl_dir[] = { |
65 | { | 61 | { |
66 | .ctl_name = CTL_UNNUMBERED, | ||
67 | .procname = "nfs", | 62 | .procname = "nfs", |
68 | .mode = 0555, | 63 | .mode = 0555, |
69 | .child = nfs_cb_sysctls, | 64 | .child = nfs_cb_sysctls, |
70 | }, | 65 | }, |
71 | { .ctl_name = 0 } | 66 | { } |
72 | }; | 67 | }; |
73 | 68 | ||
74 | static ctl_table nfs_cb_sysctl_root[] = { | 69 | static ctl_table nfs_cb_sysctl_root[] = { |
75 | { | 70 | { |
76 | .ctl_name = CTL_FS, | ||
77 | .procname = "fs", | 71 | .procname = "fs", |
78 | .mode = 0555, | 72 | .mode = 0555, |
79 | .child = nfs_cb_sysctl_dir, | 73 | .child = nfs_cb_sysctl_dir, |
80 | }, | 74 | }, |
81 | { .ctl_name = 0 } | 75 | { } |
82 | }; | 76 | }; |
83 | 77 | ||
84 | int nfs_register_sysctl(void) | 78 | int nfs_register_sysctl(void) |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 1064c91ae810..6da3d3ff6edd 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -83,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
83 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
84 | 84 | ||
85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); | 86 | nfs_restart_rpc(task, NFS_SERVER(dir)->nfs_client); |
87 | } | 87 | } |
88 | 88 | ||
89 | /** | 89 | /** |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 53eb26c16b50..3aea3ca98ab7 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -178,7 +178,7 @@ static int wb_priority(struct writeback_control *wbc) | |||
178 | { | 178 | { |
179 | if (wbc->for_reclaim) | 179 | if (wbc->for_reclaim) |
180 | return FLUSH_HIGHPRI | FLUSH_STABLE; | 180 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
181 | if (wbc->for_kupdate) | 181 | if (wbc->for_kupdate || wbc->for_background) |
182 | return FLUSH_LOWPRI; | 182 | return FLUSH_LOWPRI; |
183 | return 0; | 183 | return 0; |
184 | } | 184 | } |
@@ -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) |
@@ -438,6 +441,7 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
438 | radix_tree_tag_set(&nfsi->nfs_page_tree, | 441 | radix_tree_tag_set(&nfsi->nfs_page_tree, |
439 | req->wb_index, | 442 | req->wb_index, |
440 | NFS_PAGE_TAG_COMMIT); | 443 | NFS_PAGE_TAG_COMMIT); |
444 | nfsi->ncommit++; | ||
441 | spin_unlock(&inode->i_lock); | 445 | spin_unlock(&inode->i_lock); |
442 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 446 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
443 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); | 447 | inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); |
@@ -501,57 +505,6 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
501 | } | 505 | } |
502 | #endif | 506 | #endif |
503 | 507 | ||
504 | /* | ||
505 | * Wait for a request to complete. | ||
506 | * | ||
507 | * Interruptible by fatal signals only. | ||
508 | */ | ||
509 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) | ||
510 | { | ||
511 | struct nfs_inode *nfsi = NFS_I(inode); | ||
512 | struct nfs_page *req; | ||
513 | pgoff_t idx_end, next; | ||
514 | unsigned int res = 0; | ||
515 | int error; | ||
516 | |||
517 | if (npages == 0) | ||
518 | idx_end = ~0; | ||
519 | else | ||
520 | idx_end = idx_start + npages - 1; | ||
521 | |||
522 | next = idx_start; | ||
523 | while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_LOCKED)) { | ||
524 | if (req->wb_index > idx_end) | ||
525 | break; | ||
526 | |||
527 | next = req->wb_index + 1; | ||
528 | BUG_ON(!NFS_WBACK_BUSY(req)); | ||
529 | |||
530 | kref_get(&req->wb_kref); | ||
531 | spin_unlock(&inode->i_lock); | ||
532 | error = nfs_wait_on_request(req); | ||
533 | nfs_release_request(req); | ||
534 | spin_lock(&inode->i_lock); | ||
535 | if (error < 0) | ||
536 | return error; | ||
537 | res++; | ||
538 | } | ||
539 | return res; | ||
540 | } | ||
541 | |||
542 | static void nfs_cancel_commit_list(struct list_head *head) | ||
543 | { | ||
544 | struct nfs_page *req; | ||
545 | |||
546 | while(!list_empty(head)) { | ||
547 | req = nfs_list_entry(head->next); | ||
548 | nfs_list_remove_request(req); | ||
549 | nfs_clear_request_commit(req); | ||
550 | nfs_inode_remove_request(req); | ||
551 | nfs_unlock_request(req); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 508 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
556 | static int | 509 | static int |
557 | nfs_need_commit(struct nfs_inode *nfsi) | 510 | nfs_need_commit(struct nfs_inode *nfsi) |
@@ -573,11 +526,17 @@ static int | |||
573 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) | 526 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
574 | { | 527 | { |
575 | struct nfs_inode *nfsi = NFS_I(inode); | 528 | struct nfs_inode *nfsi = NFS_I(inode); |
529 | int ret; | ||
576 | 530 | ||
577 | if (!nfs_need_commit(nfsi)) | 531 | if (!nfs_need_commit(nfsi)) |
578 | return 0; | 532 | return 0; |
579 | 533 | ||
580 | return nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); | 534 | ret = nfs_scan_list(nfsi, dst, idx_start, npages, NFS_PAGE_TAG_COMMIT); |
535 | if (ret > 0) | ||
536 | nfsi->ncommit -= ret; | ||
537 | if (nfs_need_commit(NFS_I(inode))) | ||
538 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
539 | return ret; | ||
581 | } | 540 | } |
582 | #else | 541 | #else |
583 | static inline int nfs_need_commit(struct nfs_inode *nfsi) | 542 | static inline int nfs_need_commit(struct nfs_inode *nfsi) |
@@ -642,9 +601,10 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
642 | spin_lock(&inode->i_lock); | 601 | spin_lock(&inode->i_lock); |
643 | } | 602 | } |
644 | 603 | ||
645 | if (nfs_clear_request_commit(req)) | 604 | if (nfs_clear_request_commit(req) && |
646 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, | 605 | radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, |
647 | req->wb_index, NFS_PAGE_TAG_COMMIT); | 606 | req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) |
607 | NFS_I(inode)->ncommit--; | ||
648 | 608 | ||
649 | /* Okay, the request matches. Update the region */ | 609 | /* Okay, the request matches. Update the region */ |
650 | if (offset < req->wb_offset) { | 610 | if (offset < req->wb_offset) { |
@@ -703,9 +663,11 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
703 | req = nfs_setup_write_request(ctx, page, offset, count); | 663 | req = nfs_setup_write_request(ctx, page, offset, count); |
704 | if (IS_ERR(req)) | 664 | if (IS_ERR(req)) |
705 | return PTR_ERR(req); | 665 | return PTR_ERR(req); |
666 | nfs_mark_request_dirty(req); | ||
706 | /* Update file length */ | 667 | /* Update file length */ |
707 | nfs_grow_file(page, offset, count); | 668 | nfs_grow_file(page, offset, count); |
708 | 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); | ||
709 | nfs_clear_page_tag_locked(req); | 671 | nfs_clear_page_tag_locked(req); |
710 | return 0; | 672 | return 0; |
711 | } | 673 | } |
@@ -774,7 +736,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
774 | */ | 736 | */ |
775 | if (nfs_write_pageuptodate(page, inode) && | 737 | if (nfs_write_pageuptodate(page, inode) && |
776 | inode->i_flock == NULL && | 738 | inode->i_flock == NULL && |
777 | !(file->f_flags & O_SYNC)) { | 739 | !(file->f_flags & O_DSYNC)) { |
778 | count = max(count + offset, nfs_page_length(page)); | 740 | count = max(count + offset, nfs_page_length(page)); |
779 | offset = 0; | 741 | offset = 0; |
780 | } | 742 | } |
@@ -782,8 +744,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
782 | status = nfs_writepage_setup(ctx, page, offset, count); | 744 | status = nfs_writepage_setup(ctx, page, offset, count); |
783 | if (status < 0) | 745 | if (status < 0) |
784 | nfs_set_pageerror(page); | 746 | nfs_set_pageerror(page); |
785 | else | ||
786 | __set_page_dirty_nobuffers(page); | ||
787 | 747 | ||
788 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", | 748 | dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", |
789 | status, (long long)i_size_read(inode)); | 749 | status, (long long)i_size_read(inode)); |
@@ -792,13 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
792 | 752 | ||
793 | static void nfs_writepage_release(struct nfs_page *req) | 753 | static void nfs_writepage_release(struct nfs_page *req) |
794 | { | 754 | { |
755 | struct page *page = req->wb_page; | ||
795 | 756 | ||
796 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 757 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) |
797 | nfs_end_page_writeback(req->wb_page); | ||
798 | nfs_inode_remove_request(req); | 758 | nfs_inode_remove_request(req); |
799 | } else | ||
800 | nfs_end_page_writeback(req->wb_page); | ||
801 | nfs_clear_page_tag_locked(req); | 759 | nfs_clear_page_tag_locked(req); |
760 | nfs_end_page_writeback(page); | ||
802 | } | 761 | } |
803 | 762 | ||
804 | static int flush_task_priority(int how) | 763 | static int flush_task_priority(int how) |
@@ -822,7 +781,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
822 | int how) | 781 | int how) |
823 | { | 782 | { |
824 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 783 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
825 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
826 | int priority = flush_task_priority(how); | 784 | int priority = flush_task_priority(how); |
827 | struct rpc_task *task; | 785 | struct rpc_task *task; |
828 | struct rpc_message msg = { | 786 | struct rpc_message msg = { |
@@ -837,9 +795,10 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
837 | .callback_ops = call_ops, | 795 | .callback_ops = call_ops, |
838 | .callback_data = data, | 796 | .callback_data = data, |
839 | .workqueue = nfsiod_workqueue, | 797 | .workqueue = nfsiod_workqueue, |
840 | .flags = flags, | 798 | .flags = RPC_TASK_ASYNC, |
841 | .priority = priority, | 799 | .priority = priority, |
842 | }; | 800 | }; |
801 | int ret = 0; | ||
843 | 802 | ||
844 | /* Set up the RPC argument and reply structs | 803 | /* Set up the RPC argument and reply structs |
845 | * 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. */ |
@@ -878,10 +837,18 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
878 | (unsigned long long)data->args.offset); | 837 | (unsigned long long)data->args.offset); |
879 | 838 | ||
880 | task = rpc_run_task(&task_setup_data); | 839 | task = rpc_run_task(&task_setup_data); |
881 | if (IS_ERR(task)) | 840 | if (IS_ERR(task)) { |
882 | 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 | } | ||
883 | rpc_put_task(task); | 849 | rpc_put_task(task); |
884 | return 0; | 850 | out: |
851 | return ret; | ||
885 | } | 852 | } |
886 | 853 | ||
887 | /* 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 |
@@ -890,9 +857,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
890 | */ | 857 | */ |
891 | static void nfs_redirty_request(struct nfs_page *req) | 858 | static void nfs_redirty_request(struct nfs_page *req) |
892 | { | 859 | { |
860 | struct page *page = req->wb_page; | ||
861 | |||
893 | nfs_mark_request_dirty(req); | 862 | nfs_mark_request_dirty(req); |
894 | nfs_end_page_writeback(req->wb_page); | ||
895 | nfs_clear_page_tag_locked(req); | 863 | nfs_clear_page_tag_locked(req); |
864 | nfs_end_page_writeback(page); | ||
896 | } | 865 | } |
897 | 866 | ||
898 | /* | 867 | /* |
@@ -1127,16 +1096,15 @@ static void nfs_writeback_release_full(void *calldata) | |||
1127 | if (nfs_write_need_commit(data)) { | 1096 | if (nfs_write_need_commit(data)) { |
1128 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1097 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
1129 | nfs_mark_request_commit(req); | 1098 | nfs_mark_request_commit(req); |
1130 | nfs_end_page_writeback(page); | ||
1131 | dprintk(" marked for commit\n"); | 1099 | dprintk(" marked for commit\n"); |
1132 | goto next; | 1100 | goto next; |
1133 | } | 1101 | } |
1134 | dprintk(" OK\n"); | 1102 | dprintk(" OK\n"); |
1135 | remove_request: | 1103 | remove_request: |
1136 | nfs_end_page_writeback(page); | ||
1137 | nfs_inode_remove_request(req); | 1104 | nfs_inode_remove_request(req); |
1138 | next: | 1105 | next: |
1139 | nfs_clear_page_tag_locked(req); | 1106 | nfs_clear_page_tag_locked(req); |
1107 | nfs_end_page_writeback(page); | ||
1140 | } | 1108 | } |
1141 | nfs_writedata_release(calldata); | 1109 | nfs_writedata_release(calldata); |
1142 | } | 1110 | } |
@@ -1216,7 +1184,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1216 | */ | 1184 | */ |
1217 | argp->stable = NFS_FILE_SYNC; | 1185 | argp->stable = NFS_FILE_SYNC; |
1218 | } | 1186 | } |
1219 | nfs4_restart_rpc(task, server->nfs_client); | 1187 | nfs_restart_rpc(task, server->nfs_client); |
1220 | return -EAGAIN; | 1188 | return -EAGAIN; |
1221 | } | 1189 | } |
1222 | if (time_before(complain, jiffies)) { | 1190 | if (time_before(complain, jiffies)) { |
@@ -1228,13 +1196,31 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1228 | /* Can't do anything about it except throw an error. */ | 1196 | /* Can't do anything about it except throw an error. */ |
1229 | task->tk_status = -EIO; | 1197 | task->tk_status = -EIO; |
1230 | } | 1198 | } |
1231 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
1232 | return 0; | 1199 | return 0; |
1233 | } | 1200 | } |
1234 | 1201 | ||
1235 | 1202 | ||
1236 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1203 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1237 | void nfs_commitdata_release(void *data) | 1204 | static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait) |
1205 | { | ||
1206 | if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags)) | ||
1207 | return 1; | ||
1208 | if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags, | ||
1209 | NFS_INO_COMMIT, nfs_wait_bit_killable, | ||
1210 | TASK_KILLABLE)) | ||
1211 | return 1; | ||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static void nfs_commit_clear_lock(struct nfs_inode *nfsi) | ||
1216 | { | ||
1217 | clear_bit(NFS_INO_COMMIT, &nfsi->flags); | ||
1218 | smp_mb__after_clear_bit(); | ||
1219 | wake_up_bit(&nfsi->flags, NFS_INO_COMMIT); | ||
1220 | } | ||
1221 | |||
1222 | |||
1223 | static void nfs_commitdata_release(void *data) | ||
1238 | { | 1224 | { |
1239 | struct nfs_write_data *wdata = data; | 1225 | struct nfs_write_data *wdata = data; |
1240 | 1226 | ||
@@ -1251,7 +1237,6 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1251 | { | 1237 | { |
1252 | struct nfs_page *first = nfs_list_entry(head->next); | 1238 | struct nfs_page *first = nfs_list_entry(head->next); |
1253 | struct inode *inode = first->wb_context->path.dentry->d_inode; | 1239 | struct inode *inode = first->wb_context->path.dentry->d_inode; |
1254 | int flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
1255 | int priority = flush_task_priority(how); | 1240 | int priority = flush_task_priority(how); |
1256 | struct rpc_task *task; | 1241 | struct rpc_task *task; |
1257 | struct rpc_message msg = { | 1242 | struct rpc_message msg = { |
@@ -1266,7 +1251,7 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1266 | .callback_ops = &nfs_commit_ops, | 1251 | .callback_ops = &nfs_commit_ops, |
1267 | .callback_data = data, | 1252 | .callback_data = data, |
1268 | .workqueue = nfsiod_workqueue, | 1253 | .workqueue = nfsiod_workqueue, |
1269 | .flags = flags, | 1254 | .flags = RPC_TASK_ASYNC, |
1270 | .priority = priority, | 1255 | .priority = priority, |
1271 | }; | 1256 | }; |
1272 | 1257 | ||
@@ -1326,6 +1311,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1326 | BDI_RECLAIMABLE); | 1311 | BDI_RECLAIMABLE); |
1327 | nfs_clear_page_tag_locked(req); | 1312 | nfs_clear_page_tag_locked(req); |
1328 | } | 1313 | } |
1314 | nfs_commit_clear_lock(NFS_I(inode)); | ||
1329 | return -ENOMEM; | 1315 | return -ENOMEM; |
1330 | } | 1316 | } |
1331 | 1317 | ||
@@ -1381,6 +1367,7 @@ static void nfs_commit_release(void *calldata) | |||
1381 | next: | 1367 | next: |
1382 | nfs_clear_page_tag_locked(req); | 1368 | nfs_clear_page_tag_locked(req); |
1383 | } | 1369 | } |
1370 | nfs_commit_clear_lock(NFS_I(data->inode)); | ||
1384 | nfs_commitdata_release(calldata); | 1371 | nfs_commitdata_release(calldata); |
1385 | } | 1372 | } |
1386 | 1373 | ||
@@ -1392,11 +1379,14 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
1392 | .rpc_release = nfs_commit_release, | 1379 | .rpc_release = nfs_commit_release, |
1393 | }; | 1380 | }; |
1394 | 1381 | ||
1395 | int nfs_commit_inode(struct inode *inode, int how) | 1382 | static int nfs_commit_inode(struct inode *inode, int how) |
1396 | { | 1383 | { |
1397 | LIST_HEAD(head); | 1384 | LIST_HEAD(head); |
1398 | int res; | 1385 | int may_wait = how & FLUSH_SYNC; |
1386 | int res = 0; | ||
1399 | 1387 | ||
1388 | if (!nfs_commit_set_lock(NFS_I(inode), may_wait)) | ||
1389 | goto out; | ||
1400 | spin_lock(&inode->i_lock); | 1390 | spin_lock(&inode->i_lock); |
1401 | res = nfs_scan_commit(inode, &head, 0, 0); | 1391 | res = nfs_scan_commit(inode, &head, 0, 0); |
1402 | spin_unlock(&inode->i_lock); | 1392 | spin_unlock(&inode->i_lock); |
@@ -1404,95 +1394,60 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1404 | int error = nfs_commit_list(inode, &head, how); | 1394 | int error = nfs_commit_list(inode, &head, how); |
1405 | if (error < 0) | 1395 | if (error < 0) |
1406 | return error; | 1396 | return error; |
1407 | } | 1397 | if (may_wait) |
1398 | wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT, | ||
1399 | nfs_wait_bit_killable, | ||
1400 | TASK_KILLABLE); | ||
1401 | } else | ||
1402 | nfs_commit_clear_lock(NFS_I(inode)); | ||
1403 | out: | ||
1408 | return res; | 1404 | return res; |
1409 | } | 1405 | } |
1410 | #else | ||
1411 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) | ||
1412 | { | ||
1413 | return 0; | ||
1414 | } | ||
1415 | #endif | ||
1416 | 1406 | ||
1417 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) | 1407 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) |
1418 | { | 1408 | { |
1419 | struct inode *inode = mapping->host; | 1409 | struct nfs_inode *nfsi = NFS_I(inode); |
1420 | pgoff_t idx_start, idx_end; | 1410 | int flags = FLUSH_SYNC; |
1421 | unsigned int npages = 0; | 1411 | int ret = 0; |
1422 | LIST_HEAD(head); | 1412 | |
1423 | int nocommit = how & FLUSH_NOCOMMIT; | 1413 | /* Don't commit yet if this is a non-blocking flush and there are |
1424 | long pages, ret; | 1414 | * lots of outstanding writes for this mapping. |
1425 | 1415 | */ | |
1426 | /* FIXME */ | 1416 | if (wbc->sync_mode == WB_SYNC_NONE && |
1427 | if (wbc->range_cyclic) | 1417 | nfsi->ncommit <= (nfsi->npages >> 1)) |
1428 | idx_start = 0; | 1418 | goto out_mark_dirty; |
1429 | else { | 1419 | |
1430 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | 1420 | if (wbc->nonblocking || wbc->for_background) |
1431 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | 1421 | flags = 0; |
1432 | if (idx_end > idx_start) { | 1422 | ret = nfs_commit_inode(inode, flags); |
1433 | pgoff_t l_npages = 1 + idx_end - idx_start; | 1423 | if (ret >= 0) { |
1434 | npages = l_npages; | 1424 | if (wbc->sync_mode == WB_SYNC_NONE) { |
1435 | if (sizeof(npages) != sizeof(l_npages) && | 1425 | if (ret < wbc->nr_to_write) |
1436 | (pgoff_t)npages != l_npages) | 1426 | wbc->nr_to_write -= ret; |
1437 | npages = 0; | 1427 | else |
1428 | wbc->nr_to_write = 0; | ||
1438 | } | 1429 | } |
1430 | return 0; | ||
1439 | } | 1431 | } |
1440 | how &= ~FLUSH_NOCOMMIT; | 1432 | out_mark_dirty: |
1441 | spin_lock(&inode->i_lock); | 1433 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
1442 | do { | ||
1443 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | ||
1444 | if (ret != 0) | ||
1445 | continue; | ||
1446 | if (nocommit) | ||
1447 | break; | ||
1448 | pages = nfs_scan_commit(inode, &head, idx_start, npages); | ||
1449 | if (pages == 0) | ||
1450 | break; | ||
1451 | if (how & FLUSH_INVALIDATE) { | ||
1452 | spin_unlock(&inode->i_lock); | ||
1453 | nfs_cancel_commit_list(&head); | ||
1454 | ret = pages; | ||
1455 | spin_lock(&inode->i_lock); | ||
1456 | continue; | ||
1457 | } | ||
1458 | pages += nfs_scan_commit(inode, &head, 0, 0); | ||
1459 | spin_unlock(&inode->i_lock); | ||
1460 | ret = nfs_commit_list(inode, &head, how); | ||
1461 | spin_lock(&inode->i_lock); | ||
1462 | |||
1463 | } while (ret >= 0); | ||
1464 | spin_unlock(&inode->i_lock); | ||
1465 | return ret; | 1434 | return ret; |
1466 | } | 1435 | } |
1467 | 1436 | #else | |
1468 | static int __nfs_write_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) | 1437 | static int nfs_commit_inode(struct inode *inode, int how) |
1469 | { | 1438 | { |
1470 | int ret; | ||
1471 | |||
1472 | ret = nfs_writepages(mapping, wbc); | ||
1473 | if (ret < 0) | ||
1474 | goto out; | ||
1475 | ret = nfs_sync_mapping_wait(mapping, wbc, how); | ||
1476 | if (ret < 0) | ||
1477 | goto out; | ||
1478 | return 0; | 1439 | return 0; |
1479 | out: | ||
1480 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
1481 | return ret; | ||
1482 | } | 1440 | } |
1483 | 1441 | ||
1484 | /* Two pass sync: first using WB_SYNC_NONE, then WB_SYNC_ALL */ | 1442 | static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_control *wbc) |
1485 | static int nfs_write_mapping(struct address_space *mapping, int how) | ||
1486 | { | 1443 | { |
1487 | struct writeback_control wbc = { | 1444 | return 0; |
1488 | .bdi = mapping->backing_dev_info, | 1445 | } |
1489 | .sync_mode = WB_SYNC_ALL, | 1446 | #endif |
1490 | .nr_to_write = LONG_MAX, | ||
1491 | .range_start = 0, | ||
1492 | .range_end = LLONG_MAX, | ||
1493 | }; | ||
1494 | 1447 | ||
1495 | return __nfs_write_mapping(mapping, &wbc, how); | 1448 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1449 | { | ||
1450 | return nfs_commit_unstable_pages(inode, wbc); | ||
1496 | } | 1451 | } |
1497 | 1452 | ||
1498 | /* | 1453 | /* |
@@ -1500,37 +1455,27 @@ static int nfs_write_mapping(struct address_space *mapping, int how) | |||
1500 | */ | 1455 | */ |
1501 | int nfs_wb_all(struct inode *inode) | 1456 | int nfs_wb_all(struct inode *inode) |
1502 | { | 1457 | { |
1503 | return nfs_write_mapping(inode->i_mapping, 0); | 1458 | struct writeback_control wbc = { |
1504 | } | 1459 | .sync_mode = WB_SYNC_ALL, |
1460 | .nr_to_write = LONG_MAX, | ||
1461 | .range_start = 0, | ||
1462 | .range_end = LLONG_MAX, | ||
1463 | }; | ||
1505 | 1464 | ||
1506 | int nfs_wb_nocommit(struct inode *inode) | 1465 | return sync_inode(inode, &wbc); |
1507 | { | ||
1508 | return nfs_write_mapping(inode->i_mapping, FLUSH_NOCOMMIT); | ||
1509 | } | 1466 | } |
1510 | 1467 | ||
1511 | int nfs_wb_page_cancel(struct inode *inode, struct page *page) | 1468 | int nfs_wb_page_cancel(struct inode *inode, struct page *page) |
1512 | { | 1469 | { |
1513 | struct nfs_page *req; | 1470 | struct nfs_page *req; |
1514 | loff_t range_start = page_offset(page); | ||
1515 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | ||
1516 | struct writeback_control wbc = { | ||
1517 | .bdi = page->mapping->backing_dev_info, | ||
1518 | .sync_mode = WB_SYNC_ALL, | ||
1519 | .nr_to_write = LONG_MAX, | ||
1520 | .range_start = range_start, | ||
1521 | .range_end = range_end, | ||
1522 | }; | ||
1523 | int ret = 0; | 1471 | int ret = 0; |
1524 | 1472 | ||
1525 | BUG_ON(!PageLocked(page)); | 1473 | BUG_ON(!PageLocked(page)); |
1526 | for (;;) { | 1474 | for (;;) { |
1475 | wait_on_page_writeback(page); | ||
1527 | req = nfs_page_find_request(page); | 1476 | req = nfs_page_find_request(page); |
1528 | if (req == NULL) | 1477 | if (req == NULL) |
1529 | goto out; | ||
1530 | if (test_bit(PG_CLEAN, &req->wb_flags)) { | ||
1531 | nfs_release_request(req); | ||
1532 | break; | 1478 | break; |
1533 | } | ||
1534 | if (nfs_lock_request_dontget(req)) { | 1479 | if (nfs_lock_request_dontget(req)) { |
1535 | nfs_inode_remove_request(req); | 1480 | nfs_inode_remove_request(req); |
1536 | /* | 1481 | /* |
@@ -1542,55 +1487,44 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page) | |||
1542 | break; | 1487 | break; |
1543 | } | 1488 | } |
1544 | ret = nfs_wait_on_request(req); | 1489 | ret = nfs_wait_on_request(req); |
1490 | nfs_release_request(req); | ||
1545 | if (ret < 0) | 1491 | if (ret < 0) |
1546 | goto out; | 1492 | break; |
1547 | } | 1493 | } |
1548 | if (!PagePrivate(page)) | ||
1549 | return 0; | ||
1550 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, FLUSH_INVALIDATE); | ||
1551 | out: | ||
1552 | return ret; | 1494 | return ret; |
1553 | } | 1495 | } |
1554 | 1496 | ||
1555 | static int nfs_wb_page_priority(struct inode *inode, struct page *page, | 1497 | /* |
1556 | int how) | 1498 | * Write back all requests on one page - we do this before reading it. |
1499 | */ | ||
1500 | int nfs_wb_page(struct inode *inode, struct page *page) | ||
1557 | { | 1501 | { |
1558 | loff_t range_start = page_offset(page); | 1502 | loff_t range_start = page_offset(page); |
1559 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); | 1503 | loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1); |
1560 | struct writeback_control wbc = { | 1504 | struct writeback_control wbc = { |
1561 | .bdi = page->mapping->backing_dev_info, | ||
1562 | .sync_mode = WB_SYNC_ALL, | 1505 | .sync_mode = WB_SYNC_ALL, |
1563 | .nr_to_write = LONG_MAX, | 1506 | .nr_to_write = 0, |
1564 | .range_start = range_start, | 1507 | .range_start = range_start, |
1565 | .range_end = range_end, | 1508 | .range_end = range_end, |
1566 | }; | 1509 | }; |
1567 | int ret; | 1510 | int ret; |
1568 | 1511 | ||
1569 | do { | 1512 | while(PagePrivate(page)) { |
1513 | wait_on_page_writeback(page); | ||
1570 | if (clear_page_dirty_for_io(page)) { | 1514 | if (clear_page_dirty_for_io(page)) { |
1571 | ret = nfs_writepage_locked(page, &wbc); | 1515 | ret = nfs_writepage_locked(page, &wbc); |
1572 | if (ret < 0) | 1516 | if (ret < 0) |
1573 | goto out_error; | 1517 | goto out_error; |
1574 | } else if (!PagePrivate(page)) | 1518 | } |
1575 | break; | 1519 | ret = sync_inode(inode, &wbc); |
1576 | ret = nfs_sync_mapping_wait(page->mapping, &wbc, how); | ||
1577 | if (ret < 0) | 1520 | if (ret < 0) |
1578 | goto out_error; | 1521 | goto out_error; |
1579 | } while (PagePrivate(page)); | 1522 | } |
1580 | return 0; | 1523 | return 0; |
1581 | out_error: | 1524 | out_error: |
1582 | __mark_inode_dirty(inode, I_DIRTY_PAGES); | ||
1583 | return ret; | 1525 | return ret; |
1584 | } | 1526 | } |
1585 | 1527 | ||
1586 | /* | ||
1587 | * Write back all requests on one page - we do this before reading it. | ||
1588 | */ | ||
1589 | int nfs_wb_page(struct inode *inode, struct page* page) | ||
1590 | { | ||
1591 | return nfs_wb_page_priority(inode, page, FLUSH_STABLE); | ||
1592 | } | ||
1593 | |||
1594 | #ifdef CONFIG_MIGRATION | 1528 | #ifdef CONFIG_MIGRATION |
1595 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | 1529 | int nfs_migrate_page(struct address_space *mapping, struct page *newpage, |
1596 | struct page *page) | 1530 | struct page *page) |
@@ -1598,8 +1532,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
1598 | struct nfs_page *req; | 1532 | struct nfs_page *req; |
1599 | int ret; | 1533 | int ret; |
1600 | 1534 | ||
1601 | if (PageFsCache(page)) | 1535 | nfs_fscache_release_page(page, GFP_KERNEL); |
1602 | nfs_fscache_release_page(page, GFP_KERNEL); | ||
1603 | 1536 | ||
1604 | req = nfs_find_and_lock_request(page); | 1537 | req = nfs_find_and_lock_request(page); |
1605 | ret = PTR_ERR(req); | 1538 | ret = PTR_ERR(req); |
@@ -1612,15 +1545,16 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
1612 | if (ret) | 1545 | if (ret) |
1613 | goto out_unlock; | 1546 | goto out_unlock; |
1614 | page_cache_get(newpage); | 1547 | page_cache_get(newpage); |
1548 | spin_lock(&mapping->host->i_lock); | ||
1615 | req->wb_page = newpage; | 1549 | req->wb_page = newpage; |
1616 | SetPagePrivate(newpage); | 1550 | SetPagePrivate(newpage); |
1617 | set_page_private(newpage, page_private(page)); | 1551 | set_page_private(newpage, (unsigned long)req); |
1618 | ClearPagePrivate(page); | 1552 | ClearPagePrivate(page); |
1619 | set_page_private(page, 0); | 1553 | set_page_private(page, 0); |
1554 | spin_unlock(&mapping->host->i_lock); | ||
1620 | page_cache_release(page); | 1555 | page_cache_release(page); |
1621 | out_unlock: | 1556 | out_unlock: |
1622 | nfs_clear_page_tag_locked(req); | 1557 | nfs_clear_page_tag_locked(req); |
1623 | nfs_release_request(req); | ||
1624 | out: | 1558 | out: |
1625 | return ret; | 1559 | return ret; |
1626 | } | 1560 | } |