diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/Kconfig | 9 | ||||
-rw-r--r-- | fs/nfs/callback.c | 214 | ||||
-rw-r--r-- | fs/nfs/callback.h | 68 | ||||
-rw-r--r-- | fs/nfs/callback_proc.c | 127 | ||||
-rw-r--r-- | fs/nfs/callback_xdr.c | 280 | ||||
-rw-r--r-- | fs/nfs/client.c | 183 | ||||
-rw-r--r-- | fs/nfs/direct.c | 9 | ||||
-rw-r--r-- | fs/nfs/internal.h | 62 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 37 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 1287 | ||||
-rw-r--r-- | fs/nfs/nfs4renewd.c | 6 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 153 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 1072 | ||||
-rw-r--r-- | fs/nfs/read.c | 33 | ||||
-rw-r--r-- | fs/nfs/super.c | 14 | ||||
-rw-r--r-- | fs/nfs/unlink.c | 20 | ||||
-rw-r--r-- | fs/nfs/write.c | 31 |
17 files changed, 3308 insertions, 297 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index e67f3ec07736..5d6d6f415935 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -74,6 +74,15 @@ config NFS_V4 | |||
74 | 74 | ||
75 | If unsure, say N. | 75 | If unsure, say N. |
76 | 76 | ||
77 | config NFS_V4_1 | ||
78 | bool "NFS client support for NFSv4.1 (DEVELOPER ONLY)" | ||
79 | depends on NFS_V4 && EXPERIMENTAL | ||
80 | help | ||
81 | This option enables support for minor version 1 of the NFSv4 protocol | ||
82 | (draft-ietf-nfsv4-minorversion1) in the kernel's NFS client. | ||
83 | |||
84 | Unless you're an NFS developer, say N. | ||
85 | |||
77 | config ROOT_NFS | 86 | config ROOT_NFS |
78 | bool "Root file system on NFS" | 87 | bool "Root file system on NFS" |
79 | depends on NFS_FS=y && IP_PNP | 88 | depends on NFS_FS=y && IP_PNP |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 6e3bd42c21cd..7f604c7941fb 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -17,6 +17,9 @@ | |||
17 | #include <linux/freezer.h> | 17 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | 18 | #include <linux/kthread.h> |
19 | #include <linux/sunrpc/svcauth_gss.h> | 19 | #include <linux/sunrpc/svcauth_gss.h> |
20 | #if defined(CONFIG_NFS_V4_1) | ||
21 | #include <linux/sunrpc/bc_xprt.h> | ||
22 | #endif | ||
20 | 23 | ||
21 | #include <net/inet_sock.h> | 24 | #include <net/inet_sock.h> |
22 | 25 | ||
@@ -28,11 +31,12 @@ | |||
28 | 31 | ||
29 | struct nfs_callback_data { | 32 | struct nfs_callback_data { |
30 | unsigned int users; | 33 | unsigned int users; |
34 | struct svc_serv *serv; | ||
31 | struct svc_rqst *rqst; | 35 | struct svc_rqst *rqst; |
32 | struct task_struct *task; | 36 | struct task_struct *task; |
33 | }; | 37 | }; |
34 | 38 | ||
35 | static struct nfs_callback_data nfs_callback_info; | 39 | static struct nfs_callback_data nfs_callback_info[NFS4_MAX_MINOR_VERSION + 1]; |
36 | static DEFINE_MUTEX(nfs_callback_mutex); | 40 | static DEFINE_MUTEX(nfs_callback_mutex); |
37 | static struct svc_program nfs4_callback_program; | 41 | static struct svc_program nfs4_callback_program; |
38 | 42 | ||
@@ -56,10 +60,10 @@ module_param_call(callback_tcpport, param_set_port, param_get_int, | |||
56 | &nfs_callback_set_tcpport, 0644); | 60 | &nfs_callback_set_tcpport, 0644); |
57 | 61 | ||
58 | /* | 62 | /* |
59 | * This is the callback kernel thread. | 63 | * This is the NFSv4 callback kernel thread. |
60 | */ | 64 | */ |
61 | static int | 65 | static int |
62 | nfs_callback_svc(void *vrqstp) | 66 | nfs4_callback_svc(void *vrqstp) |
63 | { | 67 | { |
64 | int err, preverr = 0; | 68 | int err, preverr = 0; |
65 | struct svc_rqst *rqstp = vrqstp; | 69 | struct svc_rqst *rqstp = vrqstp; |
@@ -97,20 +101,12 @@ nfs_callback_svc(void *vrqstp) | |||
97 | } | 101 | } |
98 | 102 | ||
99 | /* | 103 | /* |
100 | * Bring up the callback thread if it is not already up. | 104 | * Prepare to bring up the NFSv4 callback service |
101 | */ | 105 | */ |
102 | int nfs_callback_up(void) | 106 | struct svc_rqst * |
107 | nfs4_callback_up(struct svc_serv *serv) | ||
103 | { | 108 | { |
104 | struct svc_serv *serv = NULL; | 109 | int ret; |
105 | int ret = 0; | ||
106 | |||
107 | mutex_lock(&nfs_callback_mutex); | ||
108 | if (nfs_callback_info.users++ || nfs_callback_info.task != NULL) | ||
109 | goto out; | ||
110 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
111 | ret = -ENOMEM; | ||
112 | if (!serv) | ||
113 | goto out_err; | ||
114 | 110 | ||
115 | ret = svc_create_xprt(serv, "tcp", PF_INET, | 111 | ret = svc_create_xprt(serv, "tcp", PF_INET, |
116 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 112 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
@@ -133,23 +129,168 @@ int nfs_callback_up(void) | |||
133 | goto out_err; | 129 | goto out_err; |
134 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ | 130 | #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ |
135 | 131 | ||
136 | nfs_callback_info.rqst = svc_prepare_thread(serv, &serv->sv_pools[0]); | 132 | return svc_prepare_thread(serv, &serv->sv_pools[0]); |
137 | if (IS_ERR(nfs_callback_info.rqst)) { | 133 | |
138 | ret = PTR_ERR(nfs_callback_info.rqst); | 134 | out_err: |
139 | nfs_callback_info.rqst = NULL; | 135 | if (ret == 0) |
136 | ret = -ENOMEM; | ||
137 | return ERR_PTR(ret); | ||
138 | } | ||
139 | |||
140 | #if defined(CONFIG_NFS_V4_1) | ||
141 | /* | ||
142 | * The callback service for NFSv4.1 callbacks | ||
143 | */ | ||
144 | static int | ||
145 | nfs41_callback_svc(void *vrqstp) | ||
146 | { | ||
147 | struct svc_rqst *rqstp = vrqstp; | ||
148 | struct svc_serv *serv = rqstp->rq_server; | ||
149 | struct rpc_rqst *req; | ||
150 | int error; | ||
151 | DEFINE_WAIT(wq); | ||
152 | |||
153 | set_freezable(); | ||
154 | |||
155 | /* | ||
156 | * FIXME: do we really need to run this under the BKL? If so, please | ||
157 | * add a comment about what it's intended to protect. | ||
158 | */ | ||
159 | lock_kernel(); | ||
160 | while (!kthread_should_stop()) { | ||
161 | prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); | ||
162 | spin_lock_bh(&serv->sv_cb_lock); | ||
163 | if (!list_empty(&serv->sv_cb_list)) { | ||
164 | req = list_first_entry(&serv->sv_cb_list, | ||
165 | struct rpc_rqst, rq_bc_list); | ||
166 | list_del(&req->rq_bc_list); | ||
167 | spin_unlock_bh(&serv->sv_cb_lock); | ||
168 | dprintk("Invoking bc_svc_process()\n"); | ||
169 | error = bc_svc_process(serv, req, rqstp); | ||
170 | dprintk("bc_svc_process() returned w/ error code= %d\n", | ||
171 | error); | ||
172 | } else { | ||
173 | spin_unlock_bh(&serv->sv_cb_lock); | ||
174 | schedule(); | ||
175 | } | ||
176 | finish_wait(&serv->sv_cb_waitq, &wq); | ||
177 | } | ||
178 | unlock_kernel(); | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Bring up the NFSv4.1 callback service | ||
184 | */ | ||
185 | struct svc_rqst * | ||
186 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | ||
187 | { | ||
188 | struct svc_xprt *bc_xprt; | ||
189 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | ||
190 | |||
191 | dprintk("--> %s\n", __func__); | ||
192 | /* Create a svc_sock for the service */ | ||
193 | bc_xprt = svc_sock_create(serv, xprt->prot); | ||
194 | if (!bc_xprt) | ||
195 | goto out; | ||
196 | |||
197 | /* | ||
198 | * Save the svc_serv in the transport so that it can | ||
199 | * be referenced when the session backchannel is initialized | ||
200 | */ | ||
201 | serv->bc_xprt = bc_xprt; | ||
202 | xprt->bc_serv = serv; | ||
203 | |||
204 | INIT_LIST_HEAD(&serv->sv_cb_list); | ||
205 | spin_lock_init(&serv->sv_cb_lock); | ||
206 | init_waitqueue_head(&serv->sv_cb_waitq); | ||
207 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | ||
208 | if (IS_ERR(rqstp)) | ||
209 | svc_sock_destroy(bc_xprt); | ||
210 | out: | ||
211 | dprintk("--> %s return %p\n", __func__, rqstp); | ||
212 | return rqstp; | ||
213 | } | ||
214 | |||
215 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
216 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
217 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
218 | { | ||
219 | if (minorversion) { | ||
220 | *rqstpp = nfs41_callback_up(serv, xprt); | ||
221 | *callback_svc = nfs41_callback_svc; | ||
222 | } | ||
223 | return minorversion; | ||
224 | } | ||
225 | |||
226 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
227 | struct nfs_callback_data *cb_info) | ||
228 | { | ||
229 | if (minorversion) | ||
230 | xprt->bc_serv = cb_info->serv; | ||
231 | } | ||
232 | #else | ||
233 | static inline int nfs_minorversion_callback_svc_setup(u32 minorversion, | ||
234 | struct svc_serv *serv, struct rpc_xprt *xprt, | ||
235 | struct svc_rqst **rqstpp, int (**callback_svc)(void *vrqstp)) | ||
236 | { | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt, | ||
241 | struct nfs_callback_data *cb_info) | ||
242 | { | ||
243 | } | ||
244 | #endif /* CONFIG_NFS_V4_1 */ | ||
245 | |||
246 | /* | ||
247 | * Bring up the callback thread if it is not already up. | ||
248 | */ | ||
249 | int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) | ||
250 | { | ||
251 | struct svc_serv *serv = NULL; | ||
252 | struct svc_rqst *rqstp; | ||
253 | int (*callback_svc)(void *vrqstp); | ||
254 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
255 | char svc_name[12]; | ||
256 | int ret = 0; | ||
257 | int minorversion_setup; | ||
258 | |||
259 | mutex_lock(&nfs_callback_mutex); | ||
260 | if (cb_info->users++ || cb_info->task != NULL) { | ||
261 | nfs_callback_bc_serv(minorversion, xprt, cb_info); | ||
262 | goto out; | ||
263 | } | ||
264 | serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL); | ||
265 | if (!serv) { | ||
266 | ret = -ENOMEM; | ||
267 | goto out_err; | ||
268 | } | ||
269 | |||
270 | minorversion_setup = nfs_minorversion_callback_svc_setup(minorversion, | ||
271 | serv, xprt, &rqstp, &callback_svc); | ||
272 | if (!minorversion_setup) { | ||
273 | /* v4.0 callback setup */ | ||
274 | rqstp = nfs4_callback_up(serv); | ||
275 | callback_svc = nfs4_callback_svc; | ||
276 | } | ||
277 | |||
278 | if (IS_ERR(rqstp)) { | ||
279 | ret = PTR_ERR(rqstp); | ||
140 | goto out_err; | 280 | goto out_err; |
141 | } | 281 | } |
142 | 282 | ||
143 | svc_sock_update_bufs(serv); | 283 | svc_sock_update_bufs(serv); |
144 | 284 | ||
145 | nfs_callback_info.task = kthread_run(nfs_callback_svc, | 285 | sprintf(svc_name, "nfsv4.%u-svc", minorversion); |
146 | nfs_callback_info.rqst, | 286 | cb_info->serv = serv; |
147 | "nfsv4-svc"); | 287 | cb_info->rqst = rqstp; |
148 | if (IS_ERR(nfs_callback_info.task)) { | 288 | cb_info->task = kthread_run(callback_svc, cb_info->rqst, svc_name); |
149 | ret = PTR_ERR(nfs_callback_info.task); | 289 | if (IS_ERR(cb_info->task)) { |
150 | svc_exit_thread(nfs_callback_info.rqst); | 290 | ret = PTR_ERR(cb_info->task); |
151 | nfs_callback_info.rqst = NULL; | 291 | svc_exit_thread(cb_info->rqst); |
152 | nfs_callback_info.task = NULL; | 292 | cb_info->rqst = NULL; |
293 | cb_info->task = NULL; | ||
153 | goto out_err; | 294 | goto out_err; |
154 | } | 295 | } |
155 | out: | 296 | out: |
@@ -166,22 +307,25 @@ out: | |||
166 | out_err: | 307 | out_err: |
167 | dprintk("NFS: Couldn't create callback socket or server thread; " | 308 | dprintk("NFS: Couldn't create callback socket or server thread; " |
168 | "err = %d\n", ret); | 309 | "err = %d\n", ret); |
169 | nfs_callback_info.users--; | 310 | cb_info->users--; |
170 | goto out; | 311 | goto out; |
171 | } | 312 | } |
172 | 313 | ||
173 | /* | 314 | /* |
174 | * Kill the callback thread if it's no longer being used. | 315 | * Kill the callback thread if it's no longer being used. |
175 | */ | 316 | */ |
176 | void nfs_callback_down(void) | 317 | void nfs_callback_down(int minorversion) |
177 | { | 318 | { |
319 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; | ||
320 | |||
178 | mutex_lock(&nfs_callback_mutex); | 321 | mutex_lock(&nfs_callback_mutex); |
179 | nfs_callback_info.users--; | 322 | cb_info->users--; |
180 | if (nfs_callback_info.users == 0 && nfs_callback_info.task != NULL) { | 323 | if (cb_info->users == 0 && cb_info->task != NULL) { |
181 | kthread_stop(nfs_callback_info.task); | 324 | kthread_stop(cb_info->task); |
182 | svc_exit_thread(nfs_callback_info.rqst); | 325 | svc_exit_thread(cb_info->rqst); |
183 | nfs_callback_info.rqst = NULL; | 326 | cb_info->serv = NULL; |
184 | nfs_callback_info.task = NULL; | 327 | cb_info->rqst = NULL; |
328 | cb_info->task = NULL; | ||
185 | } | 329 | } |
186 | mutex_unlock(&nfs_callback_mutex); | 330 | mutex_unlock(&nfs_callback_mutex); |
187 | } | 331 | } |
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h index e110e286a262..07baa8254ca1 100644 --- a/fs/nfs/callback.h +++ b/fs/nfs/callback.h | |||
@@ -20,13 +20,24 @@ enum nfs4_callback_procnum { | |||
20 | enum nfs4_callback_opnum { | 20 | enum nfs4_callback_opnum { |
21 | OP_CB_GETATTR = 3, | 21 | OP_CB_GETATTR = 3, |
22 | OP_CB_RECALL = 4, | 22 | OP_CB_RECALL = 4, |
23 | /* Callback operations new to NFSv4.1 */ | ||
24 | OP_CB_LAYOUTRECALL = 5, | ||
25 | OP_CB_NOTIFY = 6, | ||
26 | OP_CB_PUSH_DELEG = 7, | ||
27 | OP_CB_RECALL_ANY = 8, | ||
28 | OP_CB_RECALLABLE_OBJ_AVAIL = 9, | ||
29 | OP_CB_RECALL_SLOT = 10, | ||
30 | OP_CB_SEQUENCE = 11, | ||
31 | OP_CB_WANTS_CANCELLED = 12, | ||
32 | OP_CB_NOTIFY_LOCK = 13, | ||
33 | OP_CB_NOTIFY_DEVICEID = 14, | ||
23 | OP_CB_ILLEGAL = 10044, | 34 | OP_CB_ILLEGAL = 10044, |
24 | }; | 35 | }; |
25 | 36 | ||
26 | struct cb_compound_hdr_arg { | 37 | struct cb_compound_hdr_arg { |
27 | unsigned int taglen; | 38 | unsigned int taglen; |
28 | const char *tag; | 39 | const char *tag; |
29 | unsigned int callback_ident; | 40 | unsigned int minorversion; |
30 | unsigned nops; | 41 | unsigned nops; |
31 | }; | 42 | }; |
32 | 43 | ||
@@ -59,16 +70,59 @@ struct cb_recallargs { | |||
59 | uint32_t truncate; | 70 | uint32_t truncate; |
60 | }; | 71 | }; |
61 | 72 | ||
73 | #if defined(CONFIG_NFS_V4_1) | ||
74 | |||
75 | struct referring_call { | ||
76 | uint32_t rc_sequenceid; | ||
77 | uint32_t rc_slotid; | ||
78 | }; | ||
79 | |||
80 | struct referring_call_list { | ||
81 | struct nfs4_sessionid rcl_sessionid; | ||
82 | uint32_t rcl_nrefcalls; | ||
83 | struct referring_call *rcl_refcalls; | ||
84 | }; | ||
85 | |||
86 | struct cb_sequenceargs { | ||
87 | struct sockaddr *csa_addr; | ||
88 | struct nfs4_sessionid csa_sessionid; | ||
89 | uint32_t csa_sequenceid; | ||
90 | uint32_t csa_slotid; | ||
91 | uint32_t csa_highestslotid; | ||
92 | uint32_t csa_cachethis; | ||
93 | uint32_t csa_nrclists; | ||
94 | struct referring_call_list *csa_rclists; | ||
95 | }; | ||
96 | |||
97 | struct cb_sequenceres { | ||
98 | __be32 csr_status; | ||
99 | struct nfs4_sessionid csr_sessionid; | ||
100 | uint32_t csr_sequenceid; | ||
101 | uint32_t csr_slotid; | ||
102 | uint32_t csr_highestslotid; | ||
103 | uint32_t csr_target_highestslotid; | ||
104 | }; | ||
105 | |||
106 | extern unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
107 | struct cb_sequenceres *res); | ||
108 | |||
109 | #endif /* CONFIG_NFS_V4_1 */ | ||
110 | |||
62 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); | 111 | extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res); |
63 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); | 112 | extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy); |
64 | 113 | ||
65 | #ifdef CONFIG_NFS_V4 | 114 | #ifdef CONFIG_NFS_V4 |
66 | extern int nfs_callback_up(void); | 115 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
67 | extern void nfs_callback_down(void); | 116 | extern void nfs_callback_down(int minorversion); |
68 | #else | 117 | #endif /* CONFIG_NFS_V4 */ |
69 | #define nfs_callback_up() (0) | 118 | |
70 | #define nfs_callback_down() do {} while(0) | 119 | /* |
71 | #endif | 120 | * nfs41: Callbacks are expected to not cause substantial latency, |
121 | * so we limit their concurrency to 1 by setting up the maximum number | ||
122 | * of slots for the backchannel. | ||
123 | */ | ||
124 | #define NFS41_BC_MIN_CALLBACKS 1 | ||
125 | #define NFS41_BC_MAX_CALLBACKS 1 | ||
72 | 126 | ||
73 | extern unsigned int nfs_callback_set_tcpport; | 127 | extern unsigned int nfs_callback_set_tcpport; |
74 | extern unsigned short nfs_callback_tcpport; | 128 | extern unsigned short nfs_callback_tcpport; |
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index f7e83e23cf9f..b7da1f54da68 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -101,3 +101,130 @@ out: | |||
101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); | 101 | dprintk("%s: exit with status = %d\n", __func__, ntohl(res)); |
102 | return res; | 102 | return res; |
103 | } | 103 | } |
104 | |||
105 | #if defined(CONFIG_NFS_V4_1) | ||
106 | |||
107 | /* | ||
108 | * Validate the sequenceID sent by the server. | ||
109 | * 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. | ||
111 | * | ||
112 | * We don't yet implement a duplicate request cache, so at this time | ||
113 | * we will log replays, and process them as if we had not seen them before, | ||
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. | ||
116 | * | ||
117 | * 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 | ||
119 | * a single outstanding callback request at a time. | ||
120 | */ | ||
121 | static int | ||
122 | validate_seqid(struct nfs4_slot_table *tbl, u32 slotid, u32 seqid) | ||
123 | { | ||
124 | struct nfs4_slot *slot; | ||
125 | |||
126 | dprintk("%s enter. slotid %d seqid %d\n", | ||
127 | __func__, slotid, seqid); | ||
128 | |||
129 | if (slotid > NFS41_BC_MAX_CALLBACKS) | ||
130 | return htonl(NFS4ERR_BADSLOT); | ||
131 | |||
132 | slot = tbl->slots + slotid; | ||
133 | dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr); | ||
134 | |||
135 | /* Normal */ | ||
136 | if (likely(seqid == slot->seq_nr + 1)) { | ||
137 | slot->seq_nr++; | ||
138 | return htonl(NFS4_OK); | ||
139 | } | ||
140 | |||
141 | /* Replay */ | ||
142 | if (seqid == slot->seq_nr) { | ||
143 | dprintk("%s seqid %d is a replay - no DRC available\n", | ||
144 | __func__, seqid); | ||
145 | return htonl(NFS4_OK); | ||
146 | } | ||
147 | |||
148 | /* Wraparound */ | ||
149 | if (seqid == 1 && (slot->seq_nr + 1) == 0) { | ||
150 | slot->seq_nr = 1; | ||
151 | return htonl(NFS4_OK); | ||
152 | } | ||
153 | |||
154 | /* Misordered request */ | ||
155 | return htonl(NFS4ERR_SEQ_MISORDERED); | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Returns a pointer to a held 'struct nfs_client' that matches the server's | ||
160 | * address, major version number, and session ID. It is the caller's | ||
161 | * responsibility to release the returned reference. | ||
162 | * | ||
163 | * Returns NULL if there are no connections with sessions, or if no session | ||
164 | * matches the one of interest. | ||
165 | */ | ||
166 | static struct nfs_client *find_client_with_session( | ||
167 | const struct sockaddr *addr, u32 nfsversion, | ||
168 | struct nfs4_sessionid *sessionid) | ||
169 | { | ||
170 | struct nfs_client *clp; | ||
171 | |||
172 | clp = nfs_find_client(addr, 4); | ||
173 | if (clp == NULL) | ||
174 | return NULL; | ||
175 | |||
176 | do { | ||
177 | struct nfs_client *prev = clp; | ||
178 | |||
179 | if (clp->cl_session != NULL) { | ||
180 | if (memcmp(clp->cl_session->sess_id.data, | ||
181 | sessionid->data, | ||
182 | NFS4_MAX_SESSIONID_LEN) == 0) { | ||
183 | /* Returns a held reference to clp */ | ||
184 | return clp; | ||
185 | } | ||
186 | } | ||
187 | clp = nfs_find_client_next(prev); | ||
188 | nfs_put_client(prev); | ||
189 | } while (clp != NULL); | ||
190 | |||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* FIXME: referring calls should be processed */ | ||
195 | unsigned nfs4_callback_sequence(struct cb_sequenceargs *args, | ||
196 | struct cb_sequenceres *res) | ||
197 | { | ||
198 | struct nfs_client *clp; | ||
199 | int i, status; | ||
200 | |||
201 | for (i = 0; i < args->csa_nrclists; i++) | ||
202 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
203 | kfree(args->csa_rclists); | ||
204 | |||
205 | status = htonl(NFS4ERR_BADSESSION); | ||
206 | clp = find_client_with_session(args->csa_addr, 4, &args->csa_sessionid); | ||
207 | if (clp == NULL) | ||
208 | goto out; | ||
209 | |||
210 | status = validate_seqid(&clp->cl_session->bc_slot_table, | ||
211 | args->csa_slotid, args->csa_sequenceid); | ||
212 | if (status) | ||
213 | goto out_putclient; | ||
214 | |||
215 | memcpy(&res->csr_sessionid, &args->csa_sessionid, | ||
216 | sizeof(res->csr_sessionid)); | ||
217 | res->csr_sequenceid = args->csa_sequenceid; | ||
218 | res->csr_slotid = args->csa_slotid; | ||
219 | res->csr_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
220 | res->csr_target_highestslotid = NFS41_BC_MAX_CALLBACKS - 1; | ||
221 | |||
222 | out_putclient: | ||
223 | nfs_put_client(clp); | ||
224 | out: | ||
225 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
226 | res->csr_status = status; | ||
227 | return res->csr_status; | ||
228 | } | ||
229 | |||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index dd0ef34b5845..e5a2dac5f715 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c | |||
@@ -20,6 +20,11 @@ | |||
20 | 2 + 2 + 3 + 3) | 20 | 2 + 2 + 3 + 3) |
21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) | 21 | #define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) |
22 | 22 | ||
23 | #if defined(CONFIG_NFS_V4_1) | ||
24 | #define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ | ||
25 | 4 + 1 + 3) | ||
26 | #endif /* CONFIG_NFS_V4_1 */ | ||
27 | |||
23 | #define NFSDBG_FACILITY NFSDBG_CALLBACK | 28 | #define NFSDBG_FACILITY NFSDBG_CALLBACK |
24 | 29 | ||
25 | typedef __be32 (*callback_process_op_t)(void *, void *); | 30 | typedef __be32 (*callback_process_op_t)(void *, void *); |
@@ -132,7 +137,6 @@ static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) | |||
132 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) | 137 | static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) |
133 | { | 138 | { |
134 | __be32 *p; | 139 | __be32 *p; |
135 | unsigned int minor_version; | ||
136 | __be32 status; | 140 | __be32 status; |
137 | 141 | ||
138 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); | 142 | status = decode_string(xdr, &hdr->taglen, &hdr->tag); |
@@ -147,15 +151,19 @@ static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound | |||
147 | p = read_buf(xdr, 12); | 151 | p = read_buf(xdr, 12); |
148 | if (unlikely(p == NULL)) | 152 | if (unlikely(p == NULL)) |
149 | return htonl(NFS4ERR_RESOURCE); | 153 | return htonl(NFS4ERR_RESOURCE); |
150 | minor_version = ntohl(*p++); | 154 | hdr->minorversion = ntohl(*p++); |
151 | /* Check minor version is zero. */ | 155 | /* Check minor version is zero or one. */ |
152 | if (minor_version != 0) { | 156 | if (hdr->minorversion <= 1) { |
153 | printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n", | 157 | p++; /* skip callback_ident */ |
154 | __func__, minor_version); | 158 | } else { |
159 | printk(KERN_WARNING "%s: NFSv4 server callback with " | ||
160 | "illegal minor version %u!\n", | ||
161 | __func__, hdr->minorversion); | ||
155 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | 162 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); |
156 | } | 163 | } |
157 | hdr->callback_ident = ntohl(*p++); | ||
158 | hdr->nops = ntohl(*p); | 164 | hdr->nops = ntohl(*p); |
165 | dprintk("%s: minorversion %d nops %d\n", __func__, | ||
166 | hdr->minorversion, hdr->nops); | ||
159 | return 0; | 167 | return 0; |
160 | } | 168 | } |
161 | 169 | ||
@@ -204,6 +212,122 @@ out: | |||
204 | return status; | 212 | return status; |
205 | } | 213 | } |
206 | 214 | ||
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | |||
217 | static unsigned decode_sessionid(struct xdr_stream *xdr, | ||
218 | struct nfs4_sessionid *sid) | ||
219 | { | ||
220 | uint32_t *p; | ||
221 | int len = NFS4_MAX_SESSIONID_LEN; | ||
222 | |||
223 | p = read_buf(xdr, len); | ||
224 | if (unlikely(p == NULL)) | ||
225 | return htonl(NFS4ERR_RESOURCE);; | ||
226 | |||
227 | memcpy(sid->data, p, len); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static unsigned decode_rc_list(struct xdr_stream *xdr, | ||
232 | struct referring_call_list *rc_list) | ||
233 | { | ||
234 | uint32_t *p; | ||
235 | int i; | ||
236 | unsigned status; | ||
237 | |||
238 | status = decode_sessionid(xdr, &rc_list->rcl_sessionid); | ||
239 | if (status) | ||
240 | goto out; | ||
241 | |||
242 | status = htonl(NFS4ERR_RESOURCE); | ||
243 | p = read_buf(xdr, sizeof(uint32_t)); | ||
244 | if (unlikely(p == NULL)) | ||
245 | goto out; | ||
246 | |||
247 | rc_list->rcl_nrefcalls = ntohl(*p++); | ||
248 | if (rc_list->rcl_nrefcalls) { | ||
249 | p = read_buf(xdr, | ||
250 | rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); | ||
251 | if (unlikely(p == NULL)) | ||
252 | goto out; | ||
253 | rc_list->rcl_refcalls = kmalloc(rc_list->rcl_nrefcalls * | ||
254 | sizeof(*rc_list->rcl_refcalls), | ||
255 | GFP_KERNEL); | ||
256 | if (unlikely(rc_list->rcl_refcalls == NULL)) | ||
257 | goto out; | ||
258 | for (i = 0; i < rc_list->rcl_nrefcalls; i++) { | ||
259 | rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); | ||
260 | rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); | ||
261 | } | ||
262 | } | ||
263 | status = 0; | ||
264 | |||
265 | out: | ||
266 | return status; | ||
267 | } | ||
268 | |||
269 | static unsigned decode_cb_sequence_args(struct svc_rqst *rqstp, | ||
270 | struct xdr_stream *xdr, | ||
271 | struct cb_sequenceargs *args) | ||
272 | { | ||
273 | uint32_t *p; | ||
274 | int i; | ||
275 | unsigned status; | ||
276 | |||
277 | status = decode_sessionid(xdr, &args->csa_sessionid); | ||
278 | if (status) | ||
279 | goto out; | ||
280 | |||
281 | status = htonl(NFS4ERR_RESOURCE); | ||
282 | p = read_buf(xdr, 5 * sizeof(uint32_t)); | ||
283 | if (unlikely(p == NULL)) | ||
284 | goto out; | ||
285 | |||
286 | args->csa_addr = svc_addr(rqstp); | ||
287 | args->csa_sequenceid = ntohl(*p++); | ||
288 | args->csa_slotid = ntohl(*p++); | ||
289 | args->csa_highestslotid = ntohl(*p++); | ||
290 | args->csa_cachethis = ntohl(*p++); | ||
291 | args->csa_nrclists = ntohl(*p++); | ||
292 | args->csa_rclists = NULL; | ||
293 | if (args->csa_nrclists) { | ||
294 | args->csa_rclists = kmalloc(args->csa_nrclists * | ||
295 | sizeof(*args->csa_rclists), | ||
296 | GFP_KERNEL); | ||
297 | if (unlikely(args->csa_rclists == NULL)) | ||
298 | goto out; | ||
299 | |||
300 | for (i = 0; i < args->csa_nrclists; i++) { | ||
301 | status = decode_rc_list(xdr, &args->csa_rclists[i]); | ||
302 | if (status) | ||
303 | goto out_free; | ||
304 | } | ||
305 | } | ||
306 | status = 0; | ||
307 | |||
308 | dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u " | ||
309 | "highestslotid %u cachethis %d nrclists %u\n", | ||
310 | __func__, | ||
311 | ((u32 *)&args->csa_sessionid)[0], | ||
312 | ((u32 *)&args->csa_sessionid)[1], | ||
313 | ((u32 *)&args->csa_sessionid)[2], | ||
314 | ((u32 *)&args->csa_sessionid)[3], | ||
315 | args->csa_sequenceid, args->csa_slotid, | ||
316 | args->csa_highestslotid, args->csa_cachethis, | ||
317 | args->csa_nrclists); | ||
318 | out: | ||
319 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
320 | return status; | ||
321 | |||
322 | out_free: | ||
323 | for (i = 0; i < args->csa_nrclists; i++) | ||
324 | kfree(args->csa_rclists[i].rcl_refcalls); | ||
325 | kfree(args->csa_rclists); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | #endif /* CONFIG_NFS_V4_1 */ | ||
330 | |||
207 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) | 331 | static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) |
208 | { | 332 | { |
209 | __be32 *p; | 333 | __be32 *p; |
@@ -353,31 +477,134 @@ out: | |||
353 | return status; | 477 | return status; |
354 | } | 478 | } |
355 | 479 | ||
356 | static __be32 process_op(struct svc_rqst *rqstp, | 480 | #if defined(CONFIG_NFS_V4_1) |
481 | |||
482 | static unsigned encode_sessionid(struct xdr_stream *xdr, | ||
483 | const struct nfs4_sessionid *sid) | ||
484 | { | ||
485 | uint32_t *p; | ||
486 | int len = NFS4_MAX_SESSIONID_LEN; | ||
487 | |||
488 | p = xdr_reserve_space(xdr, len); | ||
489 | if (unlikely(p == NULL)) | ||
490 | return htonl(NFS4ERR_RESOURCE); | ||
491 | |||
492 | memcpy(p, sid, len); | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | static unsigned encode_cb_sequence_res(struct svc_rqst *rqstp, | ||
497 | struct xdr_stream *xdr, | ||
498 | const struct cb_sequenceres *res) | ||
499 | { | ||
500 | uint32_t *p; | ||
501 | unsigned status = res->csr_status; | ||
502 | |||
503 | if (unlikely(status != 0)) | ||
504 | goto out; | ||
505 | |||
506 | encode_sessionid(xdr, &res->csr_sessionid); | ||
507 | |||
508 | p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); | ||
509 | if (unlikely(p == NULL)) | ||
510 | return htonl(NFS4ERR_RESOURCE); | ||
511 | |||
512 | *p++ = htonl(res->csr_sequenceid); | ||
513 | *p++ = htonl(res->csr_slotid); | ||
514 | *p++ = htonl(res->csr_highestslotid); | ||
515 | *p++ = htonl(res->csr_target_highestslotid); | ||
516 | out: | ||
517 | dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); | ||
518 | return status; | ||
519 | } | ||
520 | |||
521 | static __be32 | ||
522 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
523 | { | ||
524 | if (op_nr == OP_CB_SEQUENCE) { | ||
525 | if (nop != 0) | ||
526 | return htonl(NFS4ERR_SEQUENCE_POS); | ||
527 | } else { | ||
528 | if (nop == 0) | ||
529 | return htonl(NFS4ERR_OP_NOT_IN_SESSION); | ||
530 | } | ||
531 | |||
532 | switch (op_nr) { | ||
533 | case OP_CB_GETATTR: | ||
534 | case OP_CB_RECALL: | ||
535 | case OP_CB_SEQUENCE: | ||
536 | *op = &callback_ops[op_nr]; | ||
537 | break; | ||
538 | |||
539 | case OP_CB_LAYOUTRECALL: | ||
540 | case OP_CB_NOTIFY_DEVICEID: | ||
541 | case OP_CB_NOTIFY: | ||
542 | case OP_CB_PUSH_DELEG: | ||
543 | case OP_CB_RECALL_ANY: | ||
544 | case OP_CB_RECALLABLE_OBJ_AVAIL: | ||
545 | case OP_CB_RECALL_SLOT: | ||
546 | case OP_CB_WANTS_CANCELLED: | ||
547 | case OP_CB_NOTIFY_LOCK: | ||
548 | return htonl(NFS4ERR_NOTSUPP); | ||
549 | |||
550 | default: | ||
551 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
552 | } | ||
553 | |||
554 | return htonl(NFS_OK); | ||
555 | } | ||
556 | |||
557 | #else /* CONFIG_NFS_V4_1 */ | ||
558 | |||
559 | static __be32 | ||
560 | preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) | ||
561 | { | ||
562 | return htonl(NFS4ERR_MINOR_VERS_MISMATCH); | ||
563 | } | ||
564 | |||
565 | #endif /* CONFIG_NFS_V4_1 */ | ||
566 | |||
567 | static __be32 | ||
568 | preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) | ||
569 | { | ||
570 | switch (op_nr) { | ||
571 | case OP_CB_GETATTR: | ||
572 | case OP_CB_RECALL: | ||
573 | *op = &callback_ops[op_nr]; | ||
574 | break; | ||
575 | default: | ||
576 | return htonl(NFS4ERR_OP_ILLEGAL); | ||
577 | } | ||
578 | |||
579 | return htonl(NFS_OK); | ||
580 | } | ||
581 | |||
582 | static __be32 process_op(uint32_t minorversion, int nop, | ||
583 | struct svc_rqst *rqstp, | ||
357 | struct xdr_stream *xdr_in, void *argp, | 584 | struct xdr_stream *xdr_in, void *argp, |
358 | struct xdr_stream *xdr_out, void *resp) | 585 | struct xdr_stream *xdr_out, void *resp) |
359 | { | 586 | { |
360 | struct callback_op *op = &callback_ops[0]; | 587 | struct callback_op *op = &callback_ops[0]; |
361 | unsigned int op_nr = OP_CB_ILLEGAL; | 588 | unsigned int op_nr = OP_CB_ILLEGAL; |
362 | __be32 status = 0; | 589 | __be32 status; |
363 | long maxlen; | 590 | long maxlen; |
364 | __be32 res; | 591 | __be32 res; |
365 | 592 | ||
366 | dprintk("%s: start\n", __func__); | 593 | dprintk("%s: start\n", __func__); |
367 | status = decode_op_hdr(xdr_in, &op_nr); | 594 | status = decode_op_hdr(xdr_in, &op_nr); |
368 | if (likely(status == 0)) { | 595 | if (unlikely(status)) { |
369 | switch (op_nr) { | 596 | status = htonl(NFS4ERR_OP_ILLEGAL); |
370 | case OP_CB_GETATTR: | 597 | goto out; |
371 | case OP_CB_RECALL: | ||
372 | op = &callback_ops[op_nr]; | ||
373 | break; | ||
374 | default: | ||
375 | op_nr = OP_CB_ILLEGAL; | ||
376 | op = &callback_ops[0]; | ||
377 | status = htonl(NFS4ERR_OP_ILLEGAL); | ||
378 | } | ||
379 | } | 598 | } |
380 | 599 | ||
600 | dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", | ||
601 | __func__, minorversion, nop, op_nr); | ||
602 | |||
603 | status = minorversion ? preprocess_nfs41_op(nop, op_nr, &op) : | ||
604 | preprocess_nfs4_op(op_nr, &op); | ||
605 | if (status == htonl(NFS4ERR_OP_ILLEGAL)) | ||
606 | op_nr = OP_CB_ILLEGAL; | ||
607 | out: | ||
381 | maxlen = xdr_out->end - xdr_out->p; | 608 | maxlen = xdr_out->end - xdr_out->p; |
382 | if (maxlen > 0 && maxlen < PAGE_SIZE) { | 609 | if (maxlen > 0 && maxlen < PAGE_SIZE) { |
383 | if (likely(status == 0 && op->decode_args != NULL)) | 610 | if (likely(status == 0 && op->decode_args != NULL)) |
@@ -425,7 +652,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r | |||
425 | return rpc_system_err; | 652 | return rpc_system_err; |
426 | 653 | ||
427 | while (status == 0 && nops != hdr_arg.nops) { | 654 | while (status == 0 && nops != hdr_arg.nops) { |
428 | status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp); | 655 | status = process_op(hdr_arg.minorversion, nops, |
656 | rqstp, &xdr_in, argp, &xdr_out, resp); | ||
429 | nops++; | 657 | nops++; |
430 | } | 658 | } |
431 | 659 | ||
@@ -452,7 +680,15 @@ static struct callback_op callback_ops[] = { | |||
452 | .process_op = (callback_process_op_t)nfs4_callback_recall, | 680 | .process_op = (callback_process_op_t)nfs4_callback_recall, |
453 | .decode_args = (callback_decode_arg_t)decode_recall_args, | 681 | .decode_args = (callback_decode_arg_t)decode_recall_args, |
454 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, | 682 | .res_maxsize = CB_OP_RECALL_RES_MAXSZ, |
455 | } | 683 | }, |
684 | #if defined(CONFIG_NFS_V4_1) | ||
685 | [OP_CB_SEQUENCE] = { | ||
686 | .process_op = (callback_process_op_t)nfs4_callback_sequence, | ||
687 | .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, | ||
688 | .encode_res = (callback_encode_res_t)encode_cb_sequence_res, | ||
689 | .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, | ||
690 | }, | ||
691 | #endif /* CONFIG_NFS_V4_1 */ | ||
456 | }; | 692 | }; |
457 | 693 | ||
458 | /* | 694 | /* |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 0e9a1f9743b0..c2d061675d80 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/in6.h> | 37 | #include <linux/in6.h> |
38 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
39 | #include <linux/nfs_xdr.h> | 39 | #include <linux/nfs_xdr.h> |
40 | #include <linux/sunrpc/bc_xprt.h> | ||
40 | 41 | ||
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
42 | 43 | ||
@@ -102,6 +103,7 @@ struct nfs_client_initdata { | |||
102 | size_t addrlen; | 103 | size_t addrlen; |
103 | const struct nfs_rpc_ops *rpc_ops; | 104 | const struct nfs_rpc_ops *rpc_ops; |
104 | int proto; | 105 | int proto; |
106 | u32 minorversion; | ||
105 | }; | 107 | }; |
106 | 108 | ||
107 | /* | 109 | /* |
@@ -121,13 +123,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
121 | 123 | ||
122 | clp->rpc_ops = cl_init->rpc_ops; | 124 | clp->rpc_ops = cl_init->rpc_ops; |
123 | 125 | ||
124 | if (cl_init->rpc_ops->version == 4) { | ||
125 | err = nfs_callback_up(); | ||
126 | if (err < 0) | ||
127 | goto error_2; | ||
128 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
129 | } | ||
130 | |||
131 | atomic_set(&clp->cl_count, 1); | 126 | atomic_set(&clp->cl_count, 1); |
132 | clp->cl_cons_state = NFS_CS_INITING; | 127 | clp->cl_cons_state = NFS_CS_INITING; |
133 | 128 | ||
@@ -138,7 +133,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
138 | err = -ENOMEM; | 133 | err = -ENOMEM; |
139 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); | 134 | clp->cl_hostname = kstrdup(cl_init->hostname, GFP_KERNEL); |
140 | if (!clp->cl_hostname) | 135 | if (!clp->cl_hostname) |
141 | goto error_3; | 136 | goto error_cleanup; |
142 | } | 137 | } |
143 | 138 | ||
144 | INIT_LIST_HEAD(&clp->cl_superblocks); | 139 | INIT_LIST_HEAD(&clp->cl_superblocks); |
@@ -153,6 +148,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
153 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); | 148 | rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); |
154 | clp->cl_boot_time = CURRENT_TIME; | 149 | clp->cl_boot_time = CURRENT_TIME; |
155 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; | 150 | clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; |
151 | clp->cl_minorversion = cl_init->minorversion; | ||
156 | #endif | 152 | #endif |
157 | cred = rpc_lookup_machine_cred(); | 153 | cred = rpc_lookup_machine_cred(); |
158 | if (!IS_ERR(cred)) | 154 | if (!IS_ERR(cred)) |
@@ -162,10 +158,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
162 | 158 | ||
163 | return clp; | 159 | return clp; |
164 | 160 | ||
165 | error_3: | 161 | error_cleanup: |
166 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
167 | nfs_callback_down(); | ||
168 | error_2: | ||
169 | kfree(clp); | 162 | kfree(clp); |
170 | error_0: | 163 | error_0: |
171 | return ERR_PTR(err); | 164 | return ERR_PTR(err); |
@@ -185,12 +178,42 @@ static void nfs4_shutdown_client(struct nfs_client *clp) | |||
185 | } | 178 | } |
186 | 179 | ||
187 | /* | 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 | /* | ||
192 | * Clears/puts all minor version specific parts from an nfs_client struct | ||
193 | * reverting it to minorversion 0. | ||
194 | */ | ||
195 | static void nfs4_clear_client_minor_version(struct nfs_client *clp) | ||
196 | { | ||
197 | #ifdef CONFIG_NFS_V4_1 | ||
198 | if (nfs4_has_session(clp)) { | ||
199 | nfs4_destroy_session(clp->cl_session); | ||
200 | clp->cl_session = NULL; | ||
201 | } | ||
202 | |||
203 | clp->cl_call_sync = _nfs4_call_sync; | ||
204 | #endif /* CONFIG_NFS_V4_1 */ | ||
205 | |||
206 | nfs4_destroy_callback(clp); | ||
207 | } | ||
208 | |||
209 | /* | ||
188 | * Destroy a shared client record | 210 | * Destroy a shared client record |
189 | */ | 211 | */ |
190 | static void nfs_free_client(struct nfs_client *clp) | 212 | static void nfs_free_client(struct nfs_client *clp) |
191 | { | 213 | { |
192 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); | 214 | dprintk("--> nfs_free_client(%u)\n", clp->rpc_ops->version); |
193 | 215 | ||
216 | nfs4_clear_client_minor_version(clp); | ||
194 | nfs4_shutdown_client(clp); | 217 | nfs4_shutdown_client(clp); |
195 | 218 | ||
196 | nfs_fscache_release_client_cookie(clp); | 219 | nfs_fscache_release_client_cookie(clp); |
@@ -199,9 +222,6 @@ static void nfs_free_client(struct nfs_client *clp) | |||
199 | if (!IS_ERR(clp->cl_rpcclient)) | 222 | if (!IS_ERR(clp->cl_rpcclient)) |
200 | rpc_shutdown_client(clp->cl_rpcclient); | 223 | rpc_shutdown_client(clp->cl_rpcclient); |
201 | 224 | ||
202 | if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | ||
203 | nfs_callback_down(); | ||
204 | |||
205 | if (clp->cl_machine_cred != NULL) | 225 | if (clp->cl_machine_cred != NULL) |
206 | put_rpccred(clp->cl_machine_cred); | 226 | put_rpccred(clp->cl_machine_cred); |
207 | 227 | ||
@@ -350,7 +370,8 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
350 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; | 370 | struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; |
351 | 371 | ||
352 | /* Don't match clients that failed to initialise properly */ | 372 | /* Don't match clients that failed to initialise properly */ |
353 | if (clp->cl_cons_state != NFS_CS_READY) | 373 | if (!(clp->cl_cons_state == NFS_CS_READY || |
374 | clp->cl_cons_state == NFS_CS_SESSION_INITING)) | ||
354 | continue; | 375 | continue; |
355 | 376 | ||
356 | /* Different NFS versions cannot share the same nfs_client */ | 377 | /* Different NFS versions cannot share the same nfs_client */ |
@@ -423,7 +444,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat | |||
423 | 444 | ||
424 | if (clp->cl_proto != data->proto) | 445 | if (clp->cl_proto != data->proto) |
425 | continue; | 446 | continue; |
426 | 447 | /* Match nfsv4 minorversion */ | |
448 | if (clp->cl_minorversion != data->minorversion) | ||
449 | continue; | ||
427 | /* Match the full socket address */ | 450 | /* Match the full socket address */ |
428 | if (!nfs_sockaddr_cmp(sap, clap)) | 451 | if (!nfs_sockaddr_cmp(sap, clap)) |
429 | continue; | 452 | continue; |
@@ -482,7 +505,7 @@ found_client: | |||
482 | nfs_free_client(new); | 505 | nfs_free_client(new); |
483 | 506 | ||
484 | error = wait_event_killable(nfs_client_active_wq, | 507 | error = wait_event_killable(nfs_client_active_wq, |
485 | clp->cl_cons_state != NFS_CS_INITING); | 508 | clp->cl_cons_state < NFS_CS_INITING); |
486 | if (error < 0) { | 509 | if (error < 0) { |
487 | nfs_put_client(clp); | 510 | nfs_put_client(clp); |
488 | return ERR_PTR(-ERESTARTSYS); | 511 | return ERR_PTR(-ERESTARTSYS); |
@@ -503,13 +526,29 @@ found_client: | |||
503 | /* | 526 | /* |
504 | * Mark a server as ready or failed | 527 | * Mark a server as ready or failed |
505 | */ | 528 | */ |
506 | static void nfs_mark_client_ready(struct nfs_client *clp, int state) | 529 | void nfs_mark_client_ready(struct nfs_client *clp, int state) |
507 | { | 530 | { |
508 | clp->cl_cons_state = state; | 531 | clp->cl_cons_state = state; |
509 | wake_up_all(&nfs_client_active_wq); | 532 | wake_up_all(&nfs_client_active_wq); |
510 | } | 533 | } |
511 | 534 | ||
512 | /* | 535 | /* |
536 | * With sessions, the client is not marked ready until after a | ||
537 | * successful EXCHANGE_ID and CREATE_SESSION. | ||
538 | * | ||
539 | * Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate | ||
540 | * other versions of NFS can be tried. | ||
541 | */ | ||
542 | int nfs4_check_client_ready(struct nfs_client *clp) | ||
543 | { | ||
544 | if (!nfs4_has_session(clp)) | ||
545 | return 0; | ||
546 | if (clp->cl_cons_state < NFS_CS_READY) | ||
547 | return -EPROTONOSUPPORT; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | /* | ||
513 | * Initialise the timeout values for a connection | 552 | * Initialise the timeout values for a connection |
514 | */ | 553 | */ |
515 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | 554 | static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, |
@@ -1054,6 +1093,61 @@ error: | |||
1054 | 1093 | ||
1055 | #ifdef CONFIG_NFS_V4 | 1094 | #ifdef CONFIG_NFS_V4 |
1056 | /* | 1095 | /* |
1096 | * Initialize the NFS4 callback service | ||
1097 | */ | ||
1098 | static int nfs4_init_callback(struct nfs_client *clp) | ||
1099 | { | ||
1100 | int error; | ||
1101 | |||
1102 | if (clp->rpc_ops->version == 4) { | ||
1103 | if (nfs4_has_session(clp)) { | ||
1104 | error = xprt_setup_backchannel( | ||
1105 | clp->cl_rpcclient->cl_xprt, | ||
1106 | NFS41_BC_MIN_CALLBACKS); | ||
1107 | if (error < 0) | ||
1108 | return error; | ||
1109 | } | ||
1110 | |||
1111 | error = nfs_callback_up(clp->cl_minorversion, | ||
1112 | clp->cl_rpcclient->cl_xprt); | ||
1113 | if (error < 0) { | ||
1114 | dprintk("%s: failed to start callback. Error = %d\n", | ||
1115 | __func__, error); | ||
1116 | return error; | ||
1117 | } | ||
1118 | __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); | ||
1119 | } | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * Initialize the minor version specific parts of an NFS4 client record | ||
1125 | */ | ||
1126 | static int nfs4_init_client_minor_version(struct nfs_client *clp) | ||
1127 | { | ||
1128 | clp->cl_call_sync = _nfs4_call_sync; | ||
1129 | |||
1130 | #if defined(CONFIG_NFS_V4_1) | ||
1131 | if (clp->cl_minorversion) { | ||
1132 | struct nfs4_session *session = NULL; | ||
1133 | /* | ||
1134 | * Create the session and mark it expired. | ||
1135 | * When a SEQUENCE operation encounters the expired session | ||
1136 | * it will do session recovery to initialize it. | ||
1137 | */ | ||
1138 | session = nfs4_alloc_session(clp); | ||
1139 | if (!session) | ||
1140 | return -ENOMEM; | ||
1141 | |||
1142 | clp->cl_session = session; | ||
1143 | clp->cl_call_sync = _nfs4_call_sync_session; | ||
1144 | } | ||
1145 | #endif /* CONFIG_NFS_V4_1 */ | ||
1146 | |||
1147 | return nfs4_init_callback(clp); | ||
1148 | } | ||
1149 | |||
1150 | /* | ||
1057 | * Initialise an NFS4 client record | 1151 | * Initialise an NFS4 client record |
1058 | */ | 1152 | */ |
1059 | static int nfs4_init_client(struct nfs_client *clp, | 1153 | static int nfs4_init_client(struct nfs_client *clp, |
@@ -1087,7 +1181,12 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
1087 | } | 1181 | } |
1088 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); | 1182 | __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); |
1089 | 1183 | ||
1090 | nfs_mark_client_ready(clp, NFS_CS_READY); | 1184 | error = nfs4_init_client_minor_version(clp); |
1185 | if (error < 0) | ||
1186 | goto error; | ||
1187 | |||
1188 | if (!nfs4_has_session(clp)) | ||
1189 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1091 | return 0; | 1190 | return 0; |
1092 | 1191 | ||
1093 | error: | 1192 | error: |
@@ -1105,7 +1204,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1105 | const size_t addrlen, | 1204 | const size_t addrlen, |
1106 | const char *ip_addr, | 1205 | const char *ip_addr, |
1107 | rpc_authflavor_t authflavour, | 1206 | rpc_authflavor_t authflavour, |
1108 | int proto, const struct rpc_timeout *timeparms) | 1207 | int proto, const struct rpc_timeout *timeparms, |
1208 | u32 minorversion) | ||
1109 | { | 1209 | { |
1110 | struct nfs_client_initdata cl_init = { | 1210 | struct nfs_client_initdata cl_init = { |
1111 | .hostname = hostname, | 1211 | .hostname = hostname, |
@@ -1113,6 +1213,7 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1113 | .addrlen = addrlen, | 1213 | .addrlen = addrlen, |
1114 | .rpc_ops = &nfs_v4_clientops, | 1214 | .rpc_ops = &nfs_v4_clientops, |
1115 | .proto = proto, | 1215 | .proto = proto, |
1216 | .minorversion = minorversion, | ||
1116 | }; | 1217 | }; |
1117 | struct nfs_client *clp; | 1218 | struct nfs_client *clp; |
1118 | int error; | 1219 | int error; |
@@ -1142,6 +1243,36 @@ error: | |||
1142 | } | 1243 | } |
1143 | 1244 | ||
1144 | /* | 1245 | /* |
1246 | * Initialize a session. | ||
1247 | * Note: save the mount rsize and wsize for create_server negotiation. | ||
1248 | */ | ||
1249 | static void nfs4_init_session(struct nfs_client *clp, | ||
1250 | unsigned int wsize, unsigned int rsize) | ||
1251 | { | ||
1252 | #if defined(CONFIG_NFS_V4_1) | ||
1253 | if (nfs4_has_session(clp)) { | ||
1254 | clp->cl_session->fc_attrs.max_rqst_sz = wsize; | ||
1255 | clp->cl_session->fc_attrs.max_resp_sz = rsize; | ||
1256 | } | ||
1257 | #endif /* CONFIG_NFS_V4_1 */ | ||
1258 | } | ||
1259 | |||
1260 | /* | ||
1261 | * Session has been established, and the client marked ready. | ||
1262 | * Set the mount rsize and wsize with negotiated fore channel | ||
1263 | * attributes which will be bound checked in nfs_server_set_fsinfo. | ||
1264 | */ | ||
1265 | static void nfs4_session_set_rwsize(struct nfs_server *server) | ||
1266 | { | ||
1267 | #ifdef CONFIG_NFS_V4_1 | ||
1268 | if (!nfs4_has_session(server->nfs_client)) | ||
1269 | return; | ||
1270 | server->rsize = server->nfs_client->cl_session->fc_attrs.max_resp_sz; | ||
1271 | server->wsize = server->nfs_client->cl_session->fc_attrs.max_rqst_sz; | ||
1272 | #endif /* CONFIG_NFS_V4_1 */ | ||
1273 | } | ||
1274 | |||
1275 | /* | ||
1145 | * Create a version 4 volume record | 1276 | * Create a version 4 volume record |
1146 | */ | 1277 | */ |
1147 | static int nfs4_init_server(struct nfs_server *server, | 1278 | static int nfs4_init_server(struct nfs_server *server, |
@@ -1168,7 +1299,8 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1168 | data->client_address, | 1299 | data->client_address, |
1169 | data->auth_flavors[0], | 1300 | data->auth_flavors[0], |
1170 | data->nfs_server.protocol, | 1301 | data->nfs_server.protocol, |
1171 | &timeparms); | 1302 | &timeparms, |
1303 | data->minorversion); | ||
1172 | if (error < 0) | 1304 | if (error < 0) |
1173 | goto error; | 1305 | goto error; |
1174 | 1306 | ||
@@ -1218,6 +1350,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1218 | BUG_ON(!server->nfs_client->rpc_ops); | 1350 | BUG_ON(!server->nfs_client->rpc_ops); |
1219 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); | 1351 | BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops); |
1220 | 1352 | ||
1353 | nfs4_init_session(server->nfs_client, server->wsize, server->rsize); | ||
1354 | |||
1221 | /* Probe the root fh to retrieve its FSID */ | 1355 | /* Probe the root fh to retrieve its FSID */ |
1222 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); | 1356 | error = nfs4_path_walk(server, mntfh, data->nfs_server.export_path); |
1223 | if (error < 0) | 1357 | if (error < 0) |
@@ -1228,6 +1362,8 @@ struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, | |||
1228 | (unsigned long long) server->fsid.minor); | 1362 | (unsigned long long) server->fsid.minor); |
1229 | dprintk("Mount FH: %d\n", mntfh->size); | 1363 | dprintk("Mount FH: %d\n", mntfh->size); |
1230 | 1364 | ||
1365 | nfs4_session_set_rwsize(server); | ||
1366 | |||
1231 | error = nfs_probe_fsinfo(server, mntfh, &fattr); | 1367 | error = nfs_probe_fsinfo(server, mntfh, &fattr); |
1232 | if (error < 0) | 1368 | if (error < 0) |
1233 | goto error; | 1369 | goto error; |
@@ -1286,7 +1422,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1286 | parent_client->cl_ipaddr, | 1422 | parent_client->cl_ipaddr, |
1287 | data->authflavor, | 1423 | data->authflavor, |
1288 | parent_server->client->cl_xprt->prot, | 1424 | parent_server->client->cl_xprt->prot, |
1289 | parent_server->client->cl_timeout); | 1425 | parent_server->client->cl_timeout, |
1426 | parent_client->cl_minorversion); | ||
1290 | if (error < 0) | 1427 | if (error < 0) |
1291 | goto error; | 1428 | goto error; |
1292 | 1429 | ||
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 08f6b040d289..489fc01a3204 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -259,6 +259,9 @@ static void nfs_direct_read_release(void *calldata) | |||
259 | } | 259 | } |
260 | 260 | ||
261 | static const struct rpc_call_ops nfs_read_direct_ops = { | 261 | static const struct rpc_call_ops nfs_read_direct_ops = { |
262 | #if defined(CONFIG_NFS_V4_1) | ||
263 | .rpc_call_prepare = nfs_read_prepare, | ||
264 | #endif /* CONFIG_NFS_V4_1 */ | ||
262 | .rpc_call_done = nfs_direct_read_result, | 265 | .rpc_call_done = nfs_direct_read_result, |
263 | .rpc_release = nfs_direct_read_release, | 266 | .rpc_release = nfs_direct_read_release, |
264 | }; | 267 | }; |
@@ -535,6 +538,9 @@ static void nfs_direct_commit_release(void *calldata) | |||
535 | } | 538 | } |
536 | 539 | ||
537 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 540 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
541 | #if defined(CONFIG_NFS_V4_1) | ||
542 | .rpc_call_prepare = nfs_write_prepare, | ||
543 | #endif /* CONFIG_NFS_V4_1 */ | ||
538 | .rpc_call_done = nfs_direct_commit_result, | 544 | .rpc_call_done = nfs_direct_commit_result, |
539 | .rpc_release = nfs_direct_commit_release, | 545 | .rpc_release = nfs_direct_commit_release, |
540 | }; | 546 | }; |
@@ -673,6 +679,9 @@ out_unlock: | |||
673 | } | 679 | } |
674 | 680 | ||
675 | static const struct rpc_call_ops nfs_write_direct_ops = { | 681 | static const struct rpc_call_ops nfs_write_direct_ops = { |
682 | #if defined(CONFIG_NFS_V4_1) | ||
683 | .rpc_call_prepare = nfs_write_prepare, | ||
684 | #endif /* CONFIG_NFS_V4_1 */ | ||
676 | .rpc_call_done = nfs_direct_write_result, | 685 | .rpc_call_done = nfs_direct_write_result, |
677 | .rpc_release = nfs_direct_write_release, | 686 | .rpc_release = nfs_direct_write_release, |
678 | }; | 687 | }; |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 10cf1110df48..7dd90a6769d0 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * NFS internal definitions | 2 | * NFS internal definitions |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include "nfs4_fs.h" | ||
5 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
6 | #include <linux/security.h> | 7 | #include <linux/security.h> |
7 | 8 | ||
@@ -17,6 +18,18 @@ struct nfs_string; | |||
17 | */ | 18 | */ |
18 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) | 19 | #define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) |
19 | 20 | ||
21 | /* | ||
22 | * Determine if sessions are in use. | ||
23 | */ | ||
24 | static inline int nfs4_has_session(const struct nfs_client *clp) | ||
25 | { | ||
26 | #ifdef CONFIG_NFS_V4_1 | ||
27 | if (clp->cl_session) | ||
28 | return 1; | ||
29 | #endif /* CONFIG_NFS_V4_1 */ | ||
30 | return 0; | ||
31 | } | ||
32 | |||
20 | struct nfs_clone_mount { | 33 | struct nfs_clone_mount { |
21 | const struct super_block *sb; | 34 | const struct super_block *sb; |
22 | const struct dentry *dentry; | 35 | const struct dentry *dentry; |
@@ -50,6 +63,7 @@ struct nfs_parsed_mount_data { | |||
50 | unsigned int auth_flavor_len; | 63 | unsigned int auth_flavor_len; |
51 | rpc_authflavor_t auth_flavors[1]; | 64 | rpc_authflavor_t auth_flavors[1]; |
52 | char *client_address; | 65 | char *client_address; |
66 | unsigned int minorversion; | ||
53 | char *fscache_uniq; | 67 | char *fscache_uniq; |
54 | 68 | ||
55 | struct { | 69 | struct { |
@@ -107,6 +121,8 @@ extern void nfs_free_server(struct nfs_server *server); | |||
107 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, | 121 | extern struct nfs_server *nfs_clone_server(struct nfs_server *, |
108 | struct nfs_fh *, | 122 | struct nfs_fh *, |
109 | struct nfs_fattr *); | 123 | struct nfs_fattr *); |
124 | extern void nfs_mark_client_ready(struct nfs_client *clp, int state); | ||
125 | extern int nfs4_check_client_ready(struct nfs_client *clp); | ||
110 | #ifdef CONFIG_PROC_FS | 126 | #ifdef CONFIG_PROC_FS |
111 | extern int __init nfs_fs_proc_init(void); | 127 | extern int __init nfs_fs_proc_init(void); |
112 | extern void nfs_fs_proc_exit(void); | 128 | extern void nfs_fs_proc_exit(void); |
@@ -154,6 +170,20 @@ extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int); | |||
154 | extern struct rpc_procinfo nfs3_procedures[]; | 170 | extern struct rpc_procinfo nfs3_procedures[]; |
155 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); | 171 | extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int); |
156 | 172 | ||
173 | /* nfs4proc.c */ | ||
174 | static inline void nfs4_restart_rpc(struct rpc_task *task, | ||
175 | const struct nfs_client *clp) | ||
176 | { | ||
177 | #ifdef CONFIG_NFS_V4_1 | ||
178 | if (nfs4_has_session(clp) && | ||
179 | test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
180 | rpc_restart_call_prepare(task); | ||
181 | return; | ||
182 | } | ||
183 | #endif /* CONFIG_NFS_V4_1 */ | ||
184 | rpc_restart_call(task); | ||
185 | } | ||
186 | |||
157 | /* nfs4xdr.c */ | 187 | /* nfs4xdr.c */ |
158 | #ifdef CONFIG_NFS_V4 | 188 | #ifdef CONFIG_NFS_V4 |
159 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); | 189 | extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus); |
@@ -213,6 +243,38 @@ extern int nfs4_path_walk(struct nfs_server *server, | |||
213 | const char *path); | 243 | const char *path); |
214 | #endif | 244 | #endif |
215 | 245 | ||
246 | /* read.c */ | ||
247 | extern void nfs_read_prepare(struct rpc_task *task, void *calldata); | ||
248 | |||
249 | /* write.c */ | ||
250 | extern void nfs_write_prepare(struct rpc_task *task, void *calldata); | ||
251 | |||
252 | /* nfs4proc.c */ | ||
253 | extern int _nfs4_call_sync(struct nfs_server *server, | ||
254 | struct rpc_message *msg, | ||
255 | struct nfs4_sequence_args *args, | ||
256 | struct nfs4_sequence_res *res, | ||
257 | int cache_reply); | ||
258 | extern int _nfs4_call_sync_session(struct nfs_server *server, | ||
259 | struct rpc_message *msg, | ||
260 | struct nfs4_sequence_args *args, | ||
261 | struct nfs4_sequence_res *res, | ||
262 | int cache_reply); | ||
263 | |||
264 | #ifdef CONFIG_NFS_V4_1 | ||
265 | extern void nfs41_sequence_free_slot(const struct nfs_client *, | ||
266 | struct nfs4_sequence_res *res); | ||
267 | #endif /* CONFIG_NFS_V4_1 */ | ||
268 | |||
269 | static inline void nfs4_sequence_free_slot(const struct nfs_client *clp, | ||
270 | struct nfs4_sequence_res *res) | ||
271 | { | ||
272 | #ifdef CONFIG_NFS_V4_1 | ||
273 | if (nfs4_has_session(clp)) | ||
274 | nfs41_sequence_free_slot(clp, res); | ||
275 | #endif /* CONFIG_NFS_V4_1 */ | ||
276 | } | ||
277 | |||
216 | /* | 278 | /* |
217 | * Determine the device name as a string | 279 | * Determine the device name as a string |
218 | */ | 280 | */ |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 84345deab26f..61bc3a32e1e2 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -44,6 +44,7 @@ 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 | }; | 48 | }; |
48 | 49 | ||
49 | /* | 50 | /* |
@@ -177,6 +178,14 @@ struct nfs4_state_recovery_ops { | |||
177 | int state_flag_bit; | 178 | int state_flag_bit; |
178 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); | 179 | int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *); |
179 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); | 180 | int (*recover_lock)(struct nfs4_state *, struct file_lock *); |
181 | int (*establish_clid)(struct nfs_client *, struct rpc_cred *); | ||
182 | struct rpc_cred * (*get_clid_cred)(struct nfs_client *); | ||
183 | }; | ||
184 | |||
185 | struct nfs4_state_maintenance_ops { | ||
186 | int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *); | ||
187 | struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *); | ||
188 | int (*renew_lease)(struct nfs_client *, struct rpc_cred *); | ||
180 | }; | 189 | }; |
181 | 190 | ||
182 | extern const struct dentry_operations nfs4_dentry_operations; | 191 | extern const struct dentry_operations nfs4_dentry_operations; |
@@ -193,6 +202,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc | |||
193 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); | 202 | extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); |
194 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); | 203 | extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); |
195 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); | 204 | extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); |
205 | extern int nfs4_init_clientid(struct nfs_client *, struct rpc_cred *); | ||
196 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); | 206 | extern int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait); |
197 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); | 207 | extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); |
198 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); | 208 | extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); |
@@ -200,8 +210,26 @@ extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fh | |||
200 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | 210 | extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, |
201 | struct nfs4_fs_locations *fs_locations, struct page *page); | 211 | struct nfs4_fs_locations *fs_locations, struct page *page); |
202 | 212 | ||
203 | extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops; | 213 | extern struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[]; |
204 | extern struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops; | 214 | extern struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[]; |
215 | #if defined(CONFIG_NFS_V4_1) | ||
216 | extern int nfs4_setup_sequence(struct nfs_client *clp, | ||
217 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
218 | int cache_reply, struct rpc_task *task); | ||
219 | extern void nfs4_destroy_session(struct nfs4_session *session); | ||
220 | extern struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp); | ||
221 | extern int nfs4_proc_create_session(struct nfs_client *, int reset); | ||
222 | extern int nfs4_proc_destroy_session(struct nfs4_session *); | ||
223 | #else /* CONFIG_NFS_v4_1 */ | ||
224 | static inline int nfs4_setup_sequence(struct nfs_client *clp, | ||
225 | struct nfs4_sequence_args *args, struct nfs4_sequence_res *res, | ||
226 | int cache_reply, struct rpc_task *task) | ||
227 | { | ||
228 | return 0; | ||
229 | } | ||
230 | #endif /* CONFIG_NFS_V4_1 */ | ||
231 | |||
232 | extern struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[]; | ||
205 | 233 | ||
206 | extern const u32 nfs4_fattr_bitmap[2]; | 234 | extern const u32 nfs4_fattr_bitmap[2]; |
207 | extern const u32 nfs4_statfs_bitmap[2]; | 235 | extern const u32 nfs4_statfs_bitmap[2]; |
@@ -216,7 +244,12 @@ extern void nfs4_kill_renewd(struct nfs_client *); | |||
216 | extern void nfs4_renew_state(struct work_struct *); | 244 | extern void nfs4_renew_state(struct work_struct *); |
217 | 245 | ||
218 | /* nfs4state.c */ | 246 | /* nfs4state.c */ |
247 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp); | ||
219 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); | 248 | struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp); |
249 | #if defined(CONFIG_NFS_V4_1) | ||
250 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp); | ||
251 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp); | ||
252 | #endif /* CONFIG_NFS_V4_1 */ | ||
220 | 253 | ||
221 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); | 254 | extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *); |
222 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); | 255 | extern void nfs4_put_state_owner(struct nfs4_state_owner *); |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 42e6a3b05498..7a750f061c26 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,11 +48,14 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 50 | #include <linux/mount.h> |
51 | #include <linux/module.h> | ||
52 | #include <linux/sunrpc/bc_xprt.h> | ||
51 | 53 | ||
52 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 55 | #include "delegation.h" |
54 | #include "internal.h" | 56 | #include "internal.h" |
55 | #include "iostat.h" | 57 | #include "iostat.h" |
58 | #include "callback.h" | ||
56 | 59 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 60 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 61 | ||
@@ -247,7 +250,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
247 | ret = nfs4_wait_clnt_recover(clp); | 250 | ret = nfs4_wait_clnt_recover(clp); |
248 | if (ret == 0) | 251 | if (ret == 0) |
249 | exception->retry = 1; | 252 | exception->retry = 1; |
253 | #if !defined(CONFIG_NFS_V4_1) | ||
250 | break; | 254 | break; |
255 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
256 | if (!nfs4_has_session(server->nfs_client)) | ||
257 | break; | ||
258 | /* FALLTHROUGH */ | ||
259 | case -NFS4ERR_BADSESSION: | ||
260 | case -NFS4ERR_BADSLOT: | ||
261 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
262 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
263 | case -NFS4ERR_DEADSESSION: | ||
264 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
265 | case -NFS4ERR_SEQ_MISORDERED: | ||
266 | dprintk("%s ERROR: %d Reset session\n", __func__, | ||
267 | errorcode); | ||
268 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
269 | exception->retry = 1; | ||
270 | /* FALLTHROUGH */ | ||
271 | #endif /* !defined(CONFIG_NFS_V4_1) */ | ||
251 | case -NFS4ERR_FILE_OPEN: | 272 | case -NFS4ERR_FILE_OPEN: |
252 | case -NFS4ERR_GRACE: | 273 | case -NFS4ERR_GRACE: |
253 | case -NFS4ERR_DELAY: | 274 | case -NFS4ERR_DELAY: |
@@ -271,6 +292,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
271 | spin_unlock(&clp->cl_lock); | 292 | spin_unlock(&clp->cl_lock); |
272 | } | 293 | } |
273 | 294 | ||
295 | #if defined(CONFIG_NFS_V4_1) | ||
296 | |||
297 | /* | ||
298 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
299 | * | ||
300 | * freeing a slot is trivially done by clearing its respective bit | ||
301 | * in the bitmap. | ||
302 | * If the freed slotid equals highest_used_slotid we want to update it | ||
303 | * so that the server would be able to size down the slot table if needed, | ||
304 | * otherwise we know that the highest_used_slotid is still in use. | ||
305 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
306 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
307 | * highest slotid in use. | ||
308 | * If none found, highest_used_slotid is set to -1. | ||
309 | */ | ||
310 | static void | ||
311 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | ||
312 | { | ||
313 | int slotid = free_slotid; | ||
314 | |||
315 | spin_lock(&tbl->slot_tbl_lock); | ||
316 | /* clear used bit in bitmap */ | ||
317 | __clear_bit(slotid, tbl->used_slots); | ||
318 | |||
319 | /* update highest_used_slotid when it is freed */ | ||
320 | if (slotid == tbl->highest_used_slotid) { | ||
321 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | ||
322 | if (slotid >= 0 && slotid < tbl->max_slots) | ||
323 | tbl->highest_used_slotid = slotid; | ||
324 | else | ||
325 | tbl->highest_used_slotid = -1; | ||
326 | } | ||
327 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
328 | spin_unlock(&tbl->slot_tbl_lock); | ||
329 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | ||
330 | free_slotid, tbl->highest_used_slotid); | ||
331 | } | ||
332 | |||
333 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
334 | struct nfs4_sequence_res *res) | ||
335 | { | ||
336 | struct nfs4_slot_table *tbl; | ||
337 | |||
338 | if (!nfs4_has_session(clp)) { | ||
339 | dprintk("%s: No session\n", __func__); | ||
340 | return; | ||
341 | } | ||
342 | tbl = &clp->cl_session->fc_slot_table; | ||
343 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | ||
344 | dprintk("%s: No slot\n", __func__); | ||
345 | /* just wake up the next guy waiting since | ||
346 | * we may have not consumed a slot after all */ | ||
347 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
348 | return; | ||
349 | } | ||
350 | nfs4_free_slot(tbl, res->sr_slotid); | ||
351 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
352 | } | ||
353 | |||
354 | static void nfs41_sequence_done(struct nfs_client *clp, | ||
355 | struct nfs4_sequence_res *res, | ||
356 | int rpc_status) | ||
357 | { | ||
358 | unsigned long timestamp; | ||
359 | struct nfs4_slot_table *tbl; | ||
360 | struct nfs4_slot *slot; | ||
361 | |||
362 | /* | ||
363 | * sr_status remains 1 if an RPC level error occurred. The server | ||
364 | * may or may not have processed the sequence operation.. | ||
365 | * Proceed as if the server received and processed the sequence | ||
366 | * operation. | ||
367 | */ | ||
368 | if (res->sr_status == 1) | ||
369 | res->sr_status = NFS_OK; | ||
370 | |||
371 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | ||
372 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | ||
373 | goto out; | ||
374 | |||
375 | tbl = &clp->cl_session->fc_slot_table; | ||
376 | slot = tbl->slots + res->sr_slotid; | ||
377 | |||
378 | if (res->sr_status == 0) { | ||
379 | /* Update the slot's sequence and clientid lease timer */ | ||
380 | ++slot->seq_nr; | ||
381 | timestamp = res->sr_renewal_time; | ||
382 | spin_lock(&clp->cl_lock); | ||
383 | if (time_before(clp->cl_last_renewal, timestamp)) | ||
384 | clp->cl_last_renewal = timestamp; | ||
385 | spin_unlock(&clp->cl_lock); | ||
386 | return; | ||
387 | } | ||
388 | out: | ||
389 | /* The session may be reset by one of the error handlers. */ | ||
390 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | ||
391 | nfs41_sequence_free_slot(clp, res); | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * nfs4_find_slot - efficiently look for a free slot | ||
396 | * | ||
397 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | ||
398 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
399 | * and respectively set up the sequence operation args. | ||
400 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | ||
401 | * | ||
402 | * Note: must be called with under the slot_tbl_lock. | ||
403 | */ | ||
404 | static u8 | ||
405 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | ||
406 | { | ||
407 | int slotid; | ||
408 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | ||
409 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
410 | |||
411 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | ||
412 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
413 | tbl->max_slots); | ||
414 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | ||
415 | if (slotid >= tbl->max_slots) | ||
416 | goto out; | ||
417 | __set_bit(slotid, tbl->used_slots); | ||
418 | if (slotid > tbl->highest_used_slotid) | ||
419 | tbl->highest_used_slotid = slotid; | ||
420 | ret_id = slotid; | ||
421 | out: | ||
422 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
423 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); | ||
424 | return ret_id; | ||
425 | } | ||
426 | |||
427 | static int nfs4_recover_session(struct nfs4_session *session) | ||
428 | { | ||
429 | struct nfs_client *clp = session->clp; | ||
430 | int ret; | ||
431 | |||
432 | for (;;) { | ||
433 | ret = nfs4_wait_clnt_recover(clp); | ||
434 | if (ret != 0) | ||
435 | return ret; | ||
436 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
437 | break; | ||
438 | nfs4_schedule_state_manager(clp); | ||
439 | } | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int nfs41_setup_sequence(struct nfs4_session *session, | ||
444 | struct nfs4_sequence_args *args, | ||
445 | struct nfs4_sequence_res *res, | ||
446 | int cache_reply, | ||
447 | struct rpc_task *task) | ||
448 | { | ||
449 | struct nfs4_slot *slot; | ||
450 | struct nfs4_slot_table *tbl; | ||
451 | int status = 0; | ||
452 | u8 slotid; | ||
453 | |||
454 | dprintk("--> %s\n", __func__); | ||
455 | /* slot already allocated? */ | ||
456 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | ||
457 | return 0; | ||
458 | |||
459 | memset(res, 0, sizeof(*res)); | ||
460 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
461 | tbl = &session->fc_slot_table; | ||
462 | |||
463 | spin_lock(&tbl->slot_tbl_lock); | ||
464 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | ||
465 | if (tbl->highest_used_slotid != -1) { | ||
466 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
467 | spin_unlock(&tbl->slot_tbl_lock); | ||
468 | dprintk("<-- %s: Session reset: draining\n", __func__); | ||
469 | return -EAGAIN; | ||
470 | } | ||
471 | |||
472 | /* The slot table is empty; start the reset thread */ | ||
473 | dprintk("%s Session Reset\n", __func__); | ||
474 | spin_unlock(&tbl->slot_tbl_lock); | ||
475 | status = nfs4_recover_session(session); | ||
476 | if (status) | ||
477 | return status; | ||
478 | spin_lock(&tbl->slot_tbl_lock); | ||
479 | } | ||
480 | |||
481 | slotid = nfs4_find_slot(tbl, task); | ||
482 | if (slotid == NFS4_MAX_SLOT_TABLE) { | ||
483 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
484 | spin_unlock(&tbl->slot_tbl_lock); | ||
485 | dprintk("<-- %s: no free slots\n", __func__); | ||
486 | return -EAGAIN; | ||
487 | } | ||
488 | spin_unlock(&tbl->slot_tbl_lock); | ||
489 | |||
490 | slot = tbl->slots + slotid; | ||
491 | args->sa_session = session; | ||
492 | args->sa_slotid = slotid; | ||
493 | args->sa_cache_this = cache_reply; | ||
494 | |||
495 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | ||
496 | |||
497 | res->sr_session = session; | ||
498 | res->sr_slotid = slotid; | ||
499 | res->sr_renewal_time = jiffies; | ||
500 | /* | ||
501 | * sr_status is only set in decode_sequence, and so will remain | ||
502 | * set to 1 if an rpc level failure occurs. | ||
503 | */ | ||
504 | res->sr_status = 1; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int nfs4_setup_sequence(struct nfs_client *clp, | ||
509 | struct nfs4_sequence_args *args, | ||
510 | struct nfs4_sequence_res *res, | ||
511 | int cache_reply, | ||
512 | struct rpc_task *task) | ||
513 | { | ||
514 | int ret = 0; | ||
515 | |||
516 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | ||
517 | __func__, clp, clp->cl_session, res->sr_slotid); | ||
518 | |||
519 | if (!nfs4_has_session(clp)) | ||
520 | goto out; | ||
521 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
522 | task); | ||
523 | if (ret != -EAGAIN) { | ||
524 | /* terminate rpc task */ | ||
525 | task->tk_status = ret; | ||
526 | task->tk_action = NULL; | ||
527 | } | ||
528 | out: | ||
529 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | struct nfs41_call_sync_data { | ||
534 | struct nfs_client *clp; | ||
535 | struct nfs4_sequence_args *seq_args; | ||
536 | struct nfs4_sequence_res *seq_res; | ||
537 | int cache_reply; | ||
538 | }; | ||
539 | |||
540 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | ||
541 | { | ||
542 | struct nfs41_call_sync_data *data = calldata; | ||
543 | |||
544 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | ||
545 | data->clp->cl_session); | ||
546 | if (nfs4_setup_sequence(data->clp, data->seq_args, | ||
547 | data->seq_res, data->cache_reply, task)) | ||
548 | return; | ||
549 | rpc_call_start(task); | ||
550 | } | ||
551 | |||
552 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | ||
553 | { | ||
554 | struct nfs41_call_sync_data *data = calldata; | ||
555 | |||
556 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | ||
557 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
558 | } | ||
559 | |||
560 | struct rpc_call_ops nfs41_call_sync_ops = { | ||
561 | .rpc_call_prepare = nfs41_call_sync_prepare, | ||
562 | .rpc_call_done = nfs41_call_sync_done, | ||
563 | }; | ||
564 | |||
565 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | ||
566 | struct rpc_clnt *clnt, | ||
567 | struct rpc_message *msg, | ||
568 | struct nfs4_sequence_args *args, | ||
569 | struct nfs4_sequence_res *res, | ||
570 | int cache_reply) | ||
571 | { | ||
572 | int ret; | ||
573 | struct rpc_task *task; | ||
574 | struct nfs41_call_sync_data data = { | ||
575 | .clp = clp, | ||
576 | .seq_args = args, | ||
577 | .seq_res = res, | ||
578 | .cache_reply = cache_reply, | ||
579 | }; | ||
580 | struct rpc_task_setup task_setup = { | ||
581 | .rpc_client = clnt, | ||
582 | .rpc_message = msg, | ||
583 | .callback_ops = &nfs41_call_sync_ops, | ||
584 | .callback_data = &data | ||
585 | }; | ||
586 | |||
587 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
588 | task = rpc_run_task(&task_setup); | ||
589 | if (IS_ERR(task)) | ||
590 | ret = PTR_ERR(task); | ||
591 | else { | ||
592 | ret = task->tk_status; | ||
593 | rpc_put_task(task); | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | int _nfs4_call_sync_session(struct nfs_server *server, | ||
599 | struct rpc_message *msg, | ||
600 | struct nfs4_sequence_args *args, | ||
601 | struct nfs4_sequence_res *res, | ||
602 | int cache_reply) | ||
603 | { | ||
604 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | ||
605 | msg, args, res, cache_reply); | ||
606 | } | ||
607 | |||
608 | #endif /* CONFIG_NFS_V4_1 */ | ||
609 | |||
610 | int _nfs4_call_sync(struct nfs_server *server, | ||
611 | struct rpc_message *msg, | ||
612 | struct nfs4_sequence_args *args, | ||
613 | struct nfs4_sequence_res *res, | ||
614 | int cache_reply) | ||
615 | { | ||
616 | args->sa_session = res->sr_session = NULL; | ||
617 | return rpc_call_sync(server->client, msg, 0); | ||
618 | } | ||
619 | |||
620 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | ||
621 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | ||
622 | &(res)->seq_res, (cache_reply)) | ||
623 | |||
624 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
625 | struct nfs4_sequence_res *res, int rpc_status) | ||
626 | { | ||
627 | #ifdef CONFIG_NFS_V4_1 | ||
628 | if (nfs4_has_session(server->nfs_client)) | ||
629 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
630 | #endif /* CONFIG_NFS_V4_1 */ | ||
631 | } | ||
632 | |||
633 | /* no restart, therefore free slot here */ | ||
634 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
635 | struct nfs4_sequence_res *res, | ||
636 | int rpc_status) | ||
637 | { | ||
638 | nfs4_sequence_done(server, res, rpc_status); | ||
639 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
640 | } | ||
641 | |||
274 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 642 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
275 | { | 643 | { |
276 | struct nfs_inode *nfsi = NFS_I(dir); | 644 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -343,6 +711,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
343 | p->o_arg.server = server; | 711 | p->o_arg.server = server; |
344 | p->o_arg.bitmask = server->attr_bitmask; | 712 | p->o_arg.bitmask = server->attr_bitmask; |
345 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 713 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
714 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
346 | if (flags & O_EXCL) { | 715 | if (flags & O_EXCL) { |
347 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 716 | u32 *s = (u32 *) p->o_arg.u.verifier.data; |
348 | s[0] = jiffies; | 717 | s[0] = jiffies; |
@@ -943,6 +1312,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
943 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1312 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
944 | } | 1313 | } |
945 | data->timestamp = jiffies; | 1314 | data->timestamp = jiffies; |
1315 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | ||
1316 | &data->o_arg.seq_args, | ||
1317 | &data->o_res.seq_res, 1, task)) | ||
1318 | return; | ||
946 | rpc_call_start(task); | 1319 | rpc_call_start(task); |
947 | return; | 1320 | return; |
948 | out_no_action: | 1321 | out_no_action: |
@@ -955,6 +1328,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
955 | struct nfs4_opendata *data = calldata; | 1328 | struct nfs4_opendata *data = calldata; |
956 | 1329 | ||
957 | data->rpc_status = task->tk_status; | 1330 | data->rpc_status = task->tk_status; |
1331 | |||
1332 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | ||
1333 | task->tk_status); | ||
1334 | |||
958 | if (RPC_ASSASSINATED(task)) | 1335 | if (RPC_ASSASSINATED(task)) |
959 | return; | 1336 | return; |
960 | if (task->tk_status == 0) { | 1337 | if (task->tk_status == 0) { |
@@ -1283,7 +1660,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1283 | } else | 1660 | } else |
1284 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1661 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1285 | 1662 | ||
1286 | status = rpc_call_sync(server->client, &msg, 0); | 1663 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
1287 | if (status == 0 && state != NULL) | 1664 | if (status == 0 && state != NULL) |
1288 | renew_lease(server, timestamp); | 1665 | renew_lease(server, timestamp); |
1289 | return status; | 1666 | return status; |
@@ -1332,6 +1709,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1332 | struct nfs4_state *state = calldata->state; | 1709 | struct nfs4_state *state = calldata->state; |
1333 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1710 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1334 | 1711 | ||
1712 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | ||
1335 | if (RPC_ASSASSINATED(task)) | 1713 | if (RPC_ASSASSINATED(task)) |
1336 | return; | 1714 | return; |
1337 | /* hmm. we are done with the inode, and in the process of freeing | 1715 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -1350,10 +1728,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1350 | break; | 1728 | break; |
1351 | default: | 1729 | default: |
1352 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1730 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1353 | rpc_restart_call(task); | 1731 | nfs4_restart_rpc(task, server->nfs_client); |
1354 | return; | 1732 | return; |
1355 | } | 1733 | } |
1356 | } | 1734 | } |
1735 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | ||
1357 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1736 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1358 | } | 1737 | } |
1359 | 1738 | ||
@@ -1394,6 +1773,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1394 | calldata->arg.fmode = FMODE_WRITE; | 1773 | calldata->arg.fmode = FMODE_WRITE; |
1395 | } | 1774 | } |
1396 | calldata->timestamp = jiffies; | 1775 | calldata->timestamp = jiffies; |
1776 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | ||
1777 | &calldata->arg.seq_args, &calldata->res.seq_res, | ||
1778 | 1, task)) | ||
1779 | return; | ||
1397 | rpc_call_start(task); | 1780 | rpc_call_start(task); |
1398 | } | 1781 | } |
1399 | 1782 | ||
@@ -1433,13 +1816,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1433 | }; | 1816 | }; |
1434 | int status = -ENOMEM; | 1817 | int status = -ENOMEM; |
1435 | 1818 | ||
1436 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1819 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); |
1437 | if (calldata == NULL) | 1820 | if (calldata == NULL) |
1438 | goto out; | 1821 | goto out; |
1439 | calldata->inode = state->inode; | 1822 | calldata->inode = state->inode; |
1440 | calldata->state = state; | 1823 | calldata->state = state; |
1441 | calldata->arg.fh = NFS_FH(state->inode); | 1824 | calldata->arg.fh = NFS_FH(state->inode); |
1442 | calldata->arg.stateid = &state->open_stateid; | 1825 | calldata->arg.stateid = &state->open_stateid; |
1826 | if (nfs4_has_session(server->nfs_client)) | ||
1827 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1443 | /* Serialization for the sequence id */ | 1828 | /* Serialization for the sequence id */ |
1444 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1829 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1445 | if (calldata->arg.seqid == NULL) | 1830 | if (calldata->arg.seqid == NULL) |
@@ -1449,6 +1834,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1449 | calldata->res.fattr = &calldata->fattr; | 1834 | calldata->res.fattr = &calldata->fattr; |
1450 | calldata->res.seqid = calldata->arg.seqid; | 1835 | calldata->res.seqid = calldata->arg.seqid; |
1451 | calldata->res.server = server; | 1836 | calldata->res.server = server; |
1837 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
1452 | calldata->path.mnt = mntget(path->mnt); | 1838 | calldata->path.mnt = mntget(path->mnt); |
1453 | calldata->path.dentry = dget(path->dentry); | 1839 | calldata->path.dentry = dget(path->dentry); |
1454 | 1840 | ||
@@ -1598,15 +1984,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
1598 | 1984 | ||
1599 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1985 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
1600 | { | 1986 | { |
1987 | struct nfs4_server_caps_arg args = { | ||
1988 | .fhandle = fhandle, | ||
1989 | }; | ||
1601 | struct nfs4_server_caps_res res = {}; | 1990 | struct nfs4_server_caps_res res = {}; |
1602 | struct rpc_message msg = { | 1991 | struct rpc_message msg = { |
1603 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], | 1992 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], |
1604 | .rpc_argp = fhandle, | 1993 | .rpc_argp = &args, |
1605 | .rpc_resp = &res, | 1994 | .rpc_resp = &res, |
1606 | }; | 1995 | }; |
1607 | int status; | 1996 | int status; |
1608 | 1997 | ||
1609 | status = rpc_call_sync(server->client, &msg, 0); | 1998 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1610 | if (status == 0) { | 1999 | if (status == 0) { |
1611 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 2000 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
1612 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 2001 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
@@ -1620,6 +2009,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1620 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 2009 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1621 | server->acl_bitmask = res.acl_bitmask; | 2010 | server->acl_bitmask = res.acl_bitmask; |
1622 | } | 2011 | } |
2012 | |||
1623 | return status; | 2013 | return status; |
1624 | } | 2014 | } |
1625 | 2015 | ||
@@ -1651,8 +2041,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1651 | .rpc_argp = &args, | 2041 | .rpc_argp = &args, |
1652 | .rpc_resp = &res, | 2042 | .rpc_resp = &res, |
1653 | }; | 2043 | }; |
2044 | int status; | ||
2045 | |||
1654 | nfs_fattr_init(info->fattr); | 2046 | nfs_fattr_init(info->fattr); |
1655 | return rpc_call_sync(server->client, &msg, 0); | 2047 | status = nfs4_recover_expired_lease(server); |
2048 | if (!status) | ||
2049 | status = nfs4_check_client_ready(server->nfs_client); | ||
2050 | if (!status) | ||
2051 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | ||
2052 | return status; | ||
1656 | } | 2053 | } |
1657 | 2054 | ||
1658 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2055 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -1742,7 +2139,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1742 | }; | 2139 | }; |
1743 | 2140 | ||
1744 | nfs_fattr_init(fattr); | 2141 | nfs_fattr_init(fattr); |
1745 | return rpc_call_sync(server->client, &msg, 0); | 2142 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
1746 | } | 2143 | } |
1747 | 2144 | ||
1748 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2145 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -1826,7 +2223,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
1826 | nfs_fattr_init(fattr); | 2223 | nfs_fattr_init(fattr); |
1827 | 2224 | ||
1828 | dprintk("NFS call lookupfh %s\n", name->name); | 2225 | dprintk("NFS call lookupfh %s\n", name->name); |
1829 | status = rpc_call_sync(server->client, &msg, 0); | 2226 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1830 | dprintk("NFS reply lookupfh: %d\n", status); | 2227 | dprintk("NFS reply lookupfh: %d\n", status); |
1831 | return status; | 2228 | return status; |
1832 | } | 2229 | } |
@@ -1912,7 +2309,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1912 | args.access |= NFS4_ACCESS_EXECUTE; | 2309 | args.access |= NFS4_ACCESS_EXECUTE; |
1913 | } | 2310 | } |
1914 | nfs_fattr_init(&fattr); | 2311 | nfs_fattr_init(&fattr); |
1915 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2312 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1916 | if (!status) { | 2313 | if (!status) { |
1917 | entry->mask = 0; | 2314 | entry->mask = 0; |
1918 | if (res.access & NFS4_ACCESS_READ) | 2315 | if (res.access & NFS4_ACCESS_READ) |
@@ -1971,13 +2368,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
1971 | .pglen = pglen, | 2368 | .pglen = pglen, |
1972 | .pages = &page, | 2369 | .pages = &page, |
1973 | }; | 2370 | }; |
2371 | struct nfs4_readlink_res res; | ||
1974 | struct rpc_message msg = { | 2372 | struct rpc_message msg = { |
1975 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], | 2373 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], |
1976 | .rpc_argp = &args, | 2374 | .rpc_argp = &args, |
1977 | .rpc_resp = NULL, | 2375 | .rpc_resp = &res, |
1978 | }; | 2376 | }; |
1979 | 2377 | ||
1980 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2378 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
1981 | } | 2379 | } |
1982 | 2380 | ||
1983 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2381 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2071,7 +2469,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2071 | int status; | 2469 | int status; |
2072 | 2470 | ||
2073 | nfs_fattr_init(&res.dir_attr); | 2471 | nfs_fattr_init(&res.dir_attr); |
2074 | status = rpc_call_sync(server->client, &msg, 0); | 2472 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
2075 | if (status == 0) { | 2473 | if (status == 0) { |
2076 | update_changeattr(dir, &res.cinfo); | 2474 | update_changeattr(dir, &res.cinfo); |
2077 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2475 | nfs_post_op_update_inode(dir, &res.dir_attr); |
@@ -2106,8 +2504,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2106 | { | 2504 | { |
2107 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2505 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2108 | 2506 | ||
2507 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | ||
2109 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2508 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2110 | return 0; | 2509 | return 0; |
2510 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2111 | update_changeattr(dir, &res->cinfo); | 2511 | update_changeattr(dir, &res->cinfo); |
2112 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2512 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2113 | return 1; | 2513 | return 1; |
@@ -2139,7 +2539,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2139 | 2539 | ||
2140 | nfs_fattr_init(res.old_fattr); | 2540 | nfs_fattr_init(res.old_fattr); |
2141 | nfs_fattr_init(res.new_fattr); | 2541 | nfs_fattr_init(res.new_fattr); |
2142 | status = rpc_call_sync(server->client, &msg, 0); | 2542 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2143 | 2543 | ||
2144 | if (!status) { | 2544 | if (!status) { |
2145 | update_changeattr(old_dir, &res.old_cinfo); | 2545 | update_changeattr(old_dir, &res.old_cinfo); |
@@ -2188,7 +2588,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2188 | 2588 | ||
2189 | nfs_fattr_init(res.fattr); | 2589 | nfs_fattr_init(res.fattr); |
2190 | nfs_fattr_init(res.dir_attr); | 2590 | nfs_fattr_init(res.dir_attr); |
2191 | status = rpc_call_sync(server->client, &msg, 0); | 2591 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2192 | if (!status) { | 2592 | if (!status) { |
2193 | update_changeattr(dir, &res.cinfo); | 2593 | update_changeattr(dir, &res.cinfo); |
2194 | nfs_post_op_update_inode(dir, res.dir_attr); | 2594 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2249,7 +2649,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2249 | 2649 | ||
2250 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2650 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2251 | { | 2651 | { |
2252 | int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 2652 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, |
2653 | &data->arg, &data->res, 1); | ||
2253 | if (status == 0) { | 2654 | if (status == 0) { |
2254 | update_changeattr(dir, &data->res.dir_cinfo); | 2655 | update_changeattr(dir, &data->res.dir_cinfo); |
2255 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2656 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2358,7 +2759,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2358 | (unsigned long long)cookie); | 2759 | (unsigned long long)cookie); |
2359 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2760 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2360 | res.pgbase = args.pgbase; | 2761 | res.pgbase = args.pgbase; |
2361 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2762 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
2362 | if (status == 0) | 2763 | if (status == 0) |
2363 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2764 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2364 | 2765 | ||
@@ -2436,14 +2837,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2436 | .fh = fhandle, | 2837 | .fh = fhandle, |
2437 | .bitmask = server->attr_bitmask, | 2838 | .bitmask = server->attr_bitmask, |
2438 | }; | 2839 | }; |
2840 | struct nfs4_statfs_res res = { | ||
2841 | .fsstat = fsstat, | ||
2842 | }; | ||
2439 | struct rpc_message msg = { | 2843 | struct rpc_message msg = { |
2440 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], | 2844 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], |
2441 | .rpc_argp = &args, | 2845 | .rpc_argp = &args, |
2442 | .rpc_resp = fsstat, | 2846 | .rpc_resp = &res, |
2443 | }; | 2847 | }; |
2444 | 2848 | ||
2445 | nfs_fattr_init(fsstat->fattr); | 2849 | nfs_fattr_init(fsstat->fattr); |
2446 | return rpc_call_sync(server->client, &msg, 0); | 2850 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2447 | } | 2851 | } |
2448 | 2852 | ||
2449 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 2853 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -2465,13 +2869,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2465 | .fh = fhandle, | 2869 | .fh = fhandle, |
2466 | .bitmask = server->attr_bitmask, | 2870 | .bitmask = server->attr_bitmask, |
2467 | }; | 2871 | }; |
2872 | struct nfs4_fsinfo_res res = { | ||
2873 | .fsinfo = fsinfo, | ||
2874 | }; | ||
2468 | struct rpc_message msg = { | 2875 | struct rpc_message msg = { |
2469 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], | 2876 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], |
2470 | .rpc_argp = &args, | 2877 | .rpc_argp = &args, |
2471 | .rpc_resp = fsinfo, | 2878 | .rpc_resp = &res, |
2472 | }; | 2879 | }; |
2473 | 2880 | ||
2474 | return rpc_call_sync(server->client, &msg, 0); | 2881 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2475 | } | 2882 | } |
2476 | 2883 | ||
2477 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2884 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -2500,10 +2907,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2500 | .fh = fhandle, | 2907 | .fh = fhandle, |
2501 | .bitmask = server->attr_bitmask, | 2908 | .bitmask = server->attr_bitmask, |
2502 | }; | 2909 | }; |
2910 | struct nfs4_pathconf_res res = { | ||
2911 | .pathconf = pathconf, | ||
2912 | }; | ||
2503 | struct rpc_message msg = { | 2913 | struct rpc_message msg = { |
2504 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], | 2914 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], |
2505 | .rpc_argp = &args, | 2915 | .rpc_argp = &args, |
2506 | .rpc_resp = pathconf, | 2916 | .rpc_resp = &res, |
2507 | }; | 2917 | }; |
2508 | 2918 | ||
2509 | /* None of the pathconf attributes are mandatory to implement */ | 2919 | /* None of the pathconf attributes are mandatory to implement */ |
@@ -2513,7 +2923,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2513 | } | 2923 | } |
2514 | 2924 | ||
2515 | nfs_fattr_init(pathconf->fattr); | 2925 | nfs_fattr_init(pathconf->fattr); |
2516 | return rpc_call_sync(server->client, &msg, 0); | 2926 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2517 | } | 2927 | } |
2518 | 2928 | ||
2519 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 2929 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2534,8 +2944,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2534 | { | 2944 | { |
2535 | struct nfs_server *server = NFS_SERVER(data->inode); | 2945 | struct nfs_server *server = NFS_SERVER(data->inode); |
2536 | 2946 | ||
2947 | dprintk("--> %s\n", __func__); | ||
2948 | |||
2949 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2950 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | ||
2951 | |||
2537 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 2952 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2538 | rpc_restart_call(task); | 2953 | nfs4_restart_rpc(task, server->nfs_client); |
2539 | return -EAGAIN; | 2954 | return -EAGAIN; |
2540 | } | 2955 | } |
2541 | 2956 | ||
@@ -2555,8 +2970,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2555 | { | 2970 | { |
2556 | struct inode *inode = data->inode; | 2971 | struct inode *inode = data->inode; |
2557 | 2972 | ||
2973 | /* slot is freed in nfs_writeback_done */ | ||
2974 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2975 | task->tk_status); | ||
2976 | |||
2558 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 2977 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2559 | rpc_restart_call(task); | 2978 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2560 | return -EAGAIN; | 2979 | return -EAGAIN; |
2561 | } | 2980 | } |
2562 | if (task->tk_status >= 0) { | 2981 | if (task->tk_status >= 0) { |
@@ -2581,10 +3000,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2581 | { | 3000 | { |
2582 | struct inode *inode = data->inode; | 3001 | struct inode *inode = data->inode; |
2583 | 3002 | ||
3003 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
3004 | task->tk_status); | ||
2584 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 3005 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2585 | rpc_restart_call(task); | 3006 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2586 | return -EAGAIN; | 3007 | return -EAGAIN; |
2587 | } | 3008 | } |
3009 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
3010 | &data->res.seq_res); | ||
2588 | nfs_refresh_inode(inode, data->res.fattr); | 3011 | nfs_refresh_inode(inode, data->res.fattr); |
2589 | return 0; | 3012 | return 0; |
2590 | } | 3013 | } |
@@ -2617,6 +3040,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
2617 | if (time_before(clp->cl_last_renewal,timestamp)) | 3040 | if (time_before(clp->cl_last_renewal,timestamp)) |
2618 | clp->cl_last_renewal = timestamp; | 3041 | clp->cl_last_renewal = timestamp; |
2619 | spin_unlock(&clp->cl_lock); | 3042 | spin_unlock(&clp->cl_lock); |
3043 | dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__, | ||
3044 | task->tk_msg.rpc_cred); | ||
3045 | put_rpccred(task->tk_msg.rpc_cred); | ||
2620 | } | 3046 | } |
2621 | 3047 | ||
2622 | static const struct rpc_call_ops nfs4_renew_ops = { | 3048 | static const struct rpc_call_ops nfs4_renew_ops = { |
@@ -2756,12 +3182,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2756 | .acl_pages = pages, | 3182 | .acl_pages = pages, |
2757 | .acl_len = buflen, | 3183 | .acl_len = buflen, |
2758 | }; | 3184 | }; |
2759 | size_t resp_len = buflen; | 3185 | struct nfs_getaclres res = { |
3186 | .acl_len = buflen, | ||
3187 | }; | ||
2760 | void *resp_buf; | 3188 | void *resp_buf; |
2761 | struct rpc_message msg = { | 3189 | struct rpc_message msg = { |
2762 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3190 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
2763 | .rpc_argp = &args, | 3191 | .rpc_argp = &args, |
2764 | .rpc_resp = &resp_len, | 3192 | .rpc_resp = &res, |
2765 | }; | 3193 | }; |
2766 | struct page *localpage = NULL; | 3194 | struct page *localpage = NULL; |
2767 | int ret; | 3195 | int ret; |
@@ -2775,26 +3203,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2775 | return -ENOMEM; | 3203 | return -ENOMEM; |
2776 | args.acl_pages[0] = localpage; | 3204 | args.acl_pages[0] = localpage; |
2777 | args.acl_pgbase = 0; | 3205 | args.acl_pgbase = 0; |
2778 | resp_len = args.acl_len = PAGE_SIZE; | 3206 | args.acl_len = PAGE_SIZE; |
2779 | } else { | 3207 | } else { |
2780 | resp_buf = buf; | 3208 | resp_buf = buf; |
2781 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3209 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
2782 | } | 3210 | } |
2783 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3211 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
2784 | if (ret) | 3212 | if (ret) |
2785 | goto out_free; | 3213 | goto out_free; |
2786 | if (resp_len > args.acl_len) | 3214 | if (res.acl_len > args.acl_len) |
2787 | nfs4_write_cached_acl(inode, NULL, resp_len); | 3215 | nfs4_write_cached_acl(inode, NULL, res.acl_len); |
2788 | else | 3216 | else |
2789 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | 3217 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); |
2790 | if (buf) { | 3218 | if (buf) { |
2791 | ret = -ERANGE; | 3219 | ret = -ERANGE; |
2792 | if (resp_len > buflen) | 3220 | if (res.acl_len > buflen) |
2793 | goto out_free; | 3221 | goto out_free; |
2794 | if (localpage) | 3222 | if (localpage) |
2795 | memcpy(buf, resp_buf, resp_len); | 3223 | memcpy(buf, resp_buf, res.acl_len); |
2796 | } | 3224 | } |
2797 | ret = resp_len; | 3225 | ret = res.acl_len; |
2798 | out_free: | 3226 | out_free: |
2799 | if (localpage) | 3227 | if (localpage) |
2800 | __free_page(localpage); | 3228 | __free_page(localpage); |
@@ -2839,10 +3267,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2839 | .acl_pages = pages, | 3267 | .acl_pages = pages, |
2840 | .acl_len = buflen, | 3268 | .acl_len = buflen, |
2841 | }; | 3269 | }; |
3270 | struct nfs_setaclres res; | ||
2842 | struct rpc_message msg = { | 3271 | struct rpc_message msg = { |
2843 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | 3272 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], |
2844 | .rpc_argp = &arg, | 3273 | .rpc_argp = &arg, |
2845 | .rpc_resp = NULL, | 3274 | .rpc_resp = &res, |
2846 | }; | 3275 | }; |
2847 | int ret; | 3276 | int ret; |
2848 | 3277 | ||
@@ -2850,7 +3279,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2850 | return -EOPNOTSUPP; | 3279 | return -EOPNOTSUPP; |
2851 | nfs_inode_return_delegation(inode); | 3280 | nfs_inode_return_delegation(inode); |
2852 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3281 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2853 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3282 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2854 | nfs_access_zap_cache(inode); | 3283 | nfs_access_zap_cache(inode); |
2855 | nfs_zap_acl_cache(inode); | 3284 | nfs_zap_acl_cache(inode); |
2856 | return ret; | 3285 | return ret; |
@@ -2869,10 +3298,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2869 | } | 3298 | } |
2870 | 3299 | ||
2871 | static int | 3300 | static int |
2872 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3301 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) |
2873 | { | 3302 | { |
2874 | struct nfs_client *clp = server->nfs_client; | ||
2875 | |||
2876 | if (!clp || task->tk_status >= 0) | 3303 | if (!clp || task->tk_status >= 0) |
2877 | return 0; | 3304 | return 0; |
2878 | switch(task->tk_status) { | 3305 | switch(task->tk_status) { |
@@ -2891,8 +3318,23 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2891 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3318 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2892 | task->tk_status = 0; | 3319 | task->tk_status = 0; |
2893 | return -EAGAIN; | 3320 | return -EAGAIN; |
3321 | #if defined(CONFIG_NFS_V4_1) | ||
3322 | case -NFS4ERR_BADSESSION: | ||
3323 | case -NFS4ERR_BADSLOT: | ||
3324 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
3325 | case -NFS4ERR_DEADSESSION: | ||
3326 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
3327 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
3328 | case -NFS4ERR_SEQ_MISORDERED: | ||
3329 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
3330 | task->tk_status); | ||
3331 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
3332 | task->tk_status = 0; | ||
3333 | return -EAGAIN; | ||
3334 | #endif /* CONFIG_NFS_V4_1 */ | ||
2894 | case -NFS4ERR_DELAY: | 3335 | case -NFS4ERR_DELAY: |
2895 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3336 | if (server) |
3337 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
2896 | case -NFS4ERR_GRACE: | 3338 | case -NFS4ERR_GRACE: |
2897 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3339 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
2898 | task->tk_status = 0; | 3340 | task->tk_status = 0; |
@@ -2905,6 +3347,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2905 | return 0; | 3347 | return 0; |
2906 | } | 3348 | } |
2907 | 3349 | ||
3350 | static int | ||
3351 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
3352 | { | ||
3353 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
3354 | } | ||
3355 | |||
2908 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3356 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2909 | { | 3357 | { |
2910 | nfs4_verifier sc_verifier; | 3358 | nfs4_verifier sc_verifier; |
@@ -3012,6 +3460,10 @@ struct nfs4_delegreturndata { | |||
3012 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 3460 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
3013 | { | 3461 | { |
3014 | struct nfs4_delegreturndata *data = calldata; | 3462 | struct nfs4_delegreturndata *data = calldata; |
3463 | |||
3464 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | ||
3465 | task->tk_status); | ||
3466 | |||
3015 | data->rpc_status = task->tk_status; | 3467 | data->rpc_status = task->tk_status; |
3016 | if (data->rpc_status == 0) | 3468 | if (data->rpc_status == 0) |
3017 | renew_lease(data->res.server, data->timestamp); | 3469 | renew_lease(data->res.server, data->timestamp); |
@@ -3022,7 +3474,25 @@ static void nfs4_delegreturn_release(void *calldata) | |||
3022 | kfree(calldata); | 3474 | kfree(calldata); |
3023 | } | 3475 | } |
3024 | 3476 | ||
3477 | #if defined(CONFIG_NFS_V4_1) | ||
3478 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | ||
3479 | { | ||
3480 | struct nfs4_delegreturndata *d_data; | ||
3481 | |||
3482 | d_data = (struct nfs4_delegreturndata *)data; | ||
3483 | |||
3484 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | ||
3485 | &d_data->args.seq_args, | ||
3486 | &d_data->res.seq_res, 1, task)) | ||
3487 | return; | ||
3488 | rpc_call_start(task); | ||
3489 | } | ||
3490 | #endif /* CONFIG_NFS_V4_1 */ | ||
3491 | |||
3025 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 3492 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
3493 | #if defined(CONFIG_NFS_V4_1) | ||
3494 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
3495 | #endif /* CONFIG_NFS_V4_1 */ | ||
3026 | .rpc_call_done = nfs4_delegreturn_done, | 3496 | .rpc_call_done = nfs4_delegreturn_done, |
3027 | .rpc_release = nfs4_delegreturn_release, | 3497 | .rpc_release = nfs4_delegreturn_release, |
3028 | }; | 3498 | }; |
@@ -3044,7 +3514,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3044 | }; | 3514 | }; |
3045 | int status = 0; | 3515 | int status = 0; |
3046 | 3516 | ||
3047 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3517 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
3048 | if (data == NULL) | 3518 | if (data == NULL) |
3049 | return -ENOMEM; | 3519 | return -ENOMEM; |
3050 | data->args.fhandle = &data->fh; | 3520 | data->args.fhandle = &data->fh; |
@@ -3054,6 +3524,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3054 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3524 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3055 | data->res.fattr = &data->fattr; | 3525 | data->res.fattr = &data->fattr; |
3056 | data->res.server = server; | 3526 | data->res.server = server; |
3527 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3057 | nfs_fattr_init(data->res.fattr); | 3528 | nfs_fattr_init(data->res.fattr); |
3058 | data->timestamp = jiffies; | 3529 | data->timestamp = jiffies; |
3059 | data->rpc_status = 0; | 3530 | data->rpc_status = 0; |
@@ -3139,7 +3610,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3139 | goto out; | 3610 | goto out; |
3140 | lsp = request->fl_u.nfs4_fl.owner; | 3611 | lsp = request->fl_u.nfs4_fl.owner; |
3141 | arg.lock_owner.id = lsp->ls_id.id; | 3612 | arg.lock_owner.id = lsp->ls_id.id; |
3142 | status = rpc_call_sync(server->client, &msg, 0); | 3613 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3143 | switch (status) { | 3614 | switch (status) { |
3144 | case 0: | 3615 | case 0: |
3145 | request->fl_type = F_UNLCK; | 3616 | request->fl_type = F_UNLCK; |
@@ -3199,13 +3670,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3199 | struct nfs4_unlockdata *p; | 3670 | struct nfs4_unlockdata *p; |
3200 | struct inode *inode = lsp->ls_state->inode; | 3671 | struct inode *inode = lsp->ls_state->inode; |
3201 | 3672 | ||
3202 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 3673 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
3203 | if (p == NULL) | 3674 | if (p == NULL) |
3204 | return NULL; | 3675 | return NULL; |
3205 | p->arg.fh = NFS_FH(inode); | 3676 | p->arg.fh = NFS_FH(inode); |
3206 | p->arg.fl = &p->fl; | 3677 | p->arg.fl = &p->fl; |
3207 | p->arg.seqid = seqid; | 3678 | p->arg.seqid = seqid; |
3208 | p->res.seqid = seqid; | 3679 | p->res.seqid = seqid; |
3680 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3209 | p->arg.stateid = &lsp->ls_stateid; | 3681 | p->arg.stateid = &lsp->ls_stateid; |
3210 | p->lsp = lsp; | 3682 | p->lsp = lsp; |
3211 | atomic_inc(&lsp->ls_count); | 3683 | atomic_inc(&lsp->ls_count); |
@@ -3229,6 +3701,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3229 | { | 3701 | { |
3230 | struct nfs4_unlockdata *calldata = data; | 3702 | struct nfs4_unlockdata *calldata = data; |
3231 | 3703 | ||
3704 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | ||
3705 | task->tk_status); | ||
3232 | if (RPC_ASSASSINATED(task)) | 3706 | if (RPC_ASSASSINATED(task)) |
3233 | return; | 3707 | return; |
3234 | switch (task->tk_status) { | 3708 | switch (task->tk_status) { |
@@ -3245,8 +3719,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3245 | break; | 3719 | break; |
3246 | default: | 3720 | default: |
3247 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3721 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3248 | rpc_restart_call(task); | 3722 | nfs4_restart_rpc(task, |
3723 | calldata->server->nfs_client); | ||
3249 | } | 3724 | } |
3725 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3726 | &calldata->res.seq_res); | ||
3250 | } | 3727 | } |
3251 | 3728 | ||
3252 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3729 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3261,6 +3738,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3261 | return; | 3738 | return; |
3262 | } | 3739 | } |
3263 | calldata->timestamp = jiffies; | 3740 | calldata->timestamp = jiffies; |
3741 | if (nfs4_setup_sequence(calldata->server->nfs_client, | ||
3742 | &calldata->arg.seq_args, | ||
3743 | &calldata->res.seq_res, 1, task)) | ||
3744 | return; | ||
3264 | rpc_call_start(task); | 3745 | rpc_call_start(task); |
3265 | } | 3746 | } |
3266 | 3747 | ||
@@ -3353,6 +3834,7 @@ struct nfs4_lockdata { | |||
3353 | unsigned long timestamp; | 3834 | unsigned long timestamp; |
3354 | int rpc_status; | 3835 | int rpc_status; |
3355 | int cancelled; | 3836 | int cancelled; |
3837 | struct nfs_server *server; | ||
3356 | }; | 3838 | }; |
3357 | 3839 | ||
3358 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 3840 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
@@ -3378,7 +3860,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3378 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3860 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3379 | p->arg.lock_owner.id = lsp->ls_id.id; | 3861 | p->arg.lock_owner.id = lsp->ls_id.id; |
3380 | p->res.lock_seqid = p->arg.lock_seqid; | 3862 | p->res.lock_seqid = p->arg.lock_seqid; |
3863 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3381 | p->lsp = lsp; | 3864 | p->lsp = lsp; |
3865 | p->server = server; | ||
3382 | atomic_inc(&lsp->ls_count); | 3866 | atomic_inc(&lsp->ls_count); |
3383 | p->ctx = get_nfs_open_context(ctx); | 3867 | p->ctx = get_nfs_open_context(ctx); |
3384 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3868 | memcpy(&p->fl, fl, sizeof(p->fl)); |
@@ -3408,6 +3892,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3408 | } else | 3892 | } else |
3409 | data->arg.new_lock_owner = 0; | 3893 | data->arg.new_lock_owner = 0; |
3410 | data->timestamp = jiffies; | 3894 | data->timestamp = jiffies; |
3895 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | ||
3896 | &data->res.seq_res, 1, task)) | ||
3897 | return; | ||
3411 | rpc_call_start(task); | 3898 | rpc_call_start(task); |
3412 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 3899 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3413 | } | 3900 | } |
@@ -3418,6 +3905,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3418 | 3905 | ||
3419 | dprintk("%s: begin!\n", __func__); | 3906 | dprintk("%s: begin!\n", __func__); |
3420 | 3907 | ||
3908 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | ||
3909 | task->tk_status); | ||
3910 | |||
3421 | data->rpc_status = task->tk_status; | 3911 | data->rpc_status = task->tk_status; |
3422 | if (RPC_ASSASSINATED(task)) | 3912 | if (RPC_ASSASSINATED(task)) |
3423 | goto out; | 3913 | goto out; |
@@ -3747,10 +4237,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3747 | .page = page, | 4237 | .page = page, |
3748 | .bitmask = bitmask, | 4238 | .bitmask = bitmask, |
3749 | }; | 4239 | }; |
4240 | struct nfs4_fs_locations_res res = { | ||
4241 | .fs_locations = fs_locations, | ||
4242 | }; | ||
3750 | struct rpc_message msg = { | 4243 | struct rpc_message msg = { |
3751 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | 4244 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], |
3752 | .rpc_argp = &args, | 4245 | .rpc_argp = &args, |
3753 | .rpc_resp = fs_locations, | 4246 | .rpc_resp = &res, |
3754 | }; | 4247 | }; |
3755 | int status; | 4248 | int status; |
3756 | 4249 | ||
@@ -3758,24 +4251,720 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3758 | nfs_fattr_init(&fs_locations->fattr); | 4251 | nfs_fattr_init(&fs_locations->fattr); |
3759 | fs_locations->server = server; | 4252 | fs_locations->server = server; |
3760 | fs_locations->nlocations = 0; | 4253 | fs_locations->nlocations = 0; |
3761 | status = rpc_call_sync(server->client, &msg, 0); | 4254 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
3762 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4255 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
3763 | dprintk("%s: returned status = %d\n", __func__, status); | 4256 | dprintk("%s: returned status = %d\n", __func__, status); |
3764 | return status; | 4257 | return status; |
3765 | } | 4258 | } |
3766 | 4259 | ||
3767 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4260 | #ifdef CONFIG_NFS_V4_1 |
4261 | /* | ||
4262 | * nfs4_proc_exchange_id() | ||
4263 | * | ||
4264 | * Since the clientid has expired, all compounds using sessions | ||
4265 | * associated with the stale clientid will be returning | ||
4266 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
4267 | * be in some phase of session reset. | ||
4268 | */ | ||
4269 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
4270 | { | ||
4271 | nfs4_verifier verifier; | ||
4272 | struct nfs41_exchange_id_args args = { | ||
4273 | .client = clp, | ||
4274 | .flags = clp->cl_exchange_flags, | ||
4275 | }; | ||
4276 | struct nfs41_exchange_id_res res = { | ||
4277 | .client = clp, | ||
4278 | }; | ||
4279 | int status; | ||
4280 | struct rpc_message msg = { | ||
4281 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
4282 | .rpc_argp = &args, | ||
4283 | .rpc_resp = &res, | ||
4284 | .rpc_cred = cred, | ||
4285 | }; | ||
4286 | __be32 *p; | ||
4287 | |||
4288 | dprintk("--> %s\n", __func__); | ||
4289 | BUG_ON(clp == NULL); | ||
4290 | |||
4291 | p = (u32 *)verifier.data; | ||
4292 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4293 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4294 | args.verifier = &verifier; | ||
4295 | |||
4296 | while (1) { | ||
4297 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
4298 | "%s/%s %u", | ||
4299 | clp->cl_ipaddr, | ||
4300 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
4301 | RPC_DISPLAY_ADDR), | ||
4302 | clp->cl_id_uniquifier); | ||
4303 | |||
4304 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4305 | |||
4306 | if (status != NFS4ERR_CLID_INUSE) | ||
4307 | break; | ||
4308 | |||
4309 | if (signalled()) | ||
4310 | break; | ||
4311 | |||
4312 | if (++clp->cl_id_uniquifier == 0) | ||
4313 | break; | ||
4314 | } | ||
4315 | |||
4316 | dprintk("<-- %s status= %d\n", __func__, status); | ||
4317 | return status; | ||
4318 | } | ||
4319 | |||
4320 | struct nfs4_get_lease_time_data { | ||
4321 | struct nfs4_get_lease_time_args *args; | ||
4322 | struct nfs4_get_lease_time_res *res; | ||
4323 | struct nfs_client *clp; | ||
4324 | }; | ||
4325 | |||
4326 | static void nfs4_get_lease_time_prepare(struct rpc_task *task, | ||
4327 | void *calldata) | ||
4328 | { | ||
4329 | int ret; | ||
4330 | struct nfs4_get_lease_time_data *data = | ||
4331 | (struct nfs4_get_lease_time_data *)calldata; | ||
4332 | |||
4333 | dprintk("--> %s\n", __func__); | ||
4334 | /* just setup sequence, do not trigger session recovery | ||
4335 | since we're invoked within one */ | ||
4336 | ret = nfs41_setup_sequence(data->clp->cl_session, | ||
4337 | &data->args->la_seq_args, | ||
4338 | &data->res->lr_seq_res, 0, task); | ||
4339 | |||
4340 | BUG_ON(ret == -EAGAIN); | ||
4341 | rpc_call_start(task); | ||
4342 | dprintk("<-- %s\n", __func__); | ||
4343 | } | ||
4344 | |||
4345 | /* | ||
4346 | * Called from nfs4_state_manager thread for session setup, so don't recover | ||
4347 | * from sequence operation or clientid errors. | ||
4348 | */ | ||
4349 | static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | ||
4350 | { | ||
4351 | struct nfs4_get_lease_time_data *data = | ||
4352 | (struct nfs4_get_lease_time_data *)calldata; | ||
4353 | |||
4354 | dprintk("--> %s\n", __func__); | ||
4355 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | ||
4356 | switch (task->tk_status) { | ||
4357 | case -NFS4ERR_DELAY: | ||
4358 | case -NFS4ERR_GRACE: | ||
4359 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | ||
4360 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | ||
4361 | task->tk_status = 0; | ||
4362 | nfs4_restart_rpc(task, data->clp); | ||
4363 | return; | ||
4364 | } | ||
4365 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4366 | dprintk("<-- %s\n", __func__); | ||
4367 | } | ||
4368 | |||
4369 | struct rpc_call_ops nfs4_get_lease_time_ops = { | ||
4370 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | ||
4371 | .rpc_call_done = nfs4_get_lease_time_done, | ||
4372 | }; | ||
4373 | |||
4374 | int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | ||
4375 | { | ||
4376 | struct rpc_task *task; | ||
4377 | struct nfs4_get_lease_time_args args; | ||
4378 | struct nfs4_get_lease_time_res res = { | ||
4379 | .lr_fsinfo = fsinfo, | ||
4380 | }; | ||
4381 | struct nfs4_get_lease_time_data data = { | ||
4382 | .args = &args, | ||
4383 | .res = &res, | ||
4384 | .clp = clp, | ||
4385 | }; | ||
4386 | struct rpc_message msg = { | ||
4387 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME], | ||
4388 | .rpc_argp = &args, | ||
4389 | .rpc_resp = &res, | ||
4390 | }; | ||
4391 | struct rpc_task_setup task_setup = { | ||
4392 | .rpc_client = clp->cl_rpcclient, | ||
4393 | .rpc_message = &msg, | ||
4394 | .callback_ops = &nfs4_get_lease_time_ops, | ||
4395 | .callback_data = &data | ||
4396 | }; | ||
4397 | int status; | ||
4398 | |||
4399 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4400 | dprintk("--> %s\n", __func__); | ||
4401 | task = rpc_run_task(&task_setup); | ||
4402 | |||
4403 | if (IS_ERR(task)) | ||
4404 | status = PTR_ERR(task); | ||
4405 | else { | ||
4406 | status = task->tk_status; | ||
4407 | rpc_put_task(task); | ||
4408 | } | ||
4409 | dprintk("<-- %s return %d\n", __func__, status); | ||
4410 | |||
4411 | return status; | ||
4412 | } | ||
4413 | |||
4414 | /* | ||
4415 | * Reset a slot table | ||
4416 | */ | ||
4417 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | ||
4418 | int old_max_slots, int ivalue) | ||
4419 | { | ||
4420 | int i; | ||
4421 | int ret = 0; | ||
4422 | |||
4423 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | ||
4424 | |||
4425 | /* | ||
4426 | * Until we have dynamic slot table adjustment, insist | ||
4427 | * upon the same slot table size | ||
4428 | */ | ||
4429 | if (max_slots != old_max_slots) { | ||
4430 | dprintk("%s reset slot table does't match old\n", | ||
4431 | __func__); | ||
4432 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | ||
4433 | goto out; | ||
4434 | } | ||
4435 | spin_lock(&tbl->slot_tbl_lock); | ||
4436 | for (i = 0; i < max_slots; ++i) | ||
4437 | tbl->slots[i].seq_nr = ivalue; | ||
4438 | tbl->highest_used_slotid = -1; | ||
4439 | spin_unlock(&tbl->slot_tbl_lock); | ||
4440 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4441 | tbl, tbl->slots, tbl->max_slots); | ||
4442 | out: | ||
4443 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4444 | return ret; | ||
4445 | } | ||
4446 | |||
4447 | /* | ||
4448 | * Reset the forechannel and backchannel slot tables | ||
4449 | */ | ||
4450 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
4451 | { | ||
4452 | int status; | ||
4453 | |||
4454 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
4455 | session->fc_attrs.max_reqs, | ||
4456 | session->fc_slot_table.max_slots, | ||
4457 | 1); | ||
4458 | if (status) | ||
4459 | return status; | ||
4460 | |||
4461 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
4462 | session->bc_attrs.max_reqs, | ||
4463 | session->bc_slot_table.max_slots, | ||
4464 | 0); | ||
4465 | return status; | ||
4466 | } | ||
4467 | |||
4468 | /* Destroy the slot table */ | ||
4469 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
4470 | { | ||
4471 | if (session->fc_slot_table.slots != NULL) { | ||
4472 | kfree(session->fc_slot_table.slots); | ||
4473 | session->fc_slot_table.slots = NULL; | ||
4474 | } | ||
4475 | if (session->bc_slot_table.slots != NULL) { | ||
4476 | kfree(session->bc_slot_table.slots); | ||
4477 | session->bc_slot_table.slots = NULL; | ||
4478 | } | ||
4479 | return; | ||
4480 | } | ||
4481 | |||
4482 | /* | ||
4483 | * Initialize slot table | ||
4484 | */ | ||
4485 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
4486 | int max_slots, int ivalue) | ||
4487 | { | ||
4488 | int i; | ||
4489 | struct nfs4_slot *slot; | ||
4490 | int ret = -ENOMEM; | ||
4491 | |||
4492 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
4493 | |||
4494 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
4495 | |||
4496 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | ||
4497 | if (!slot) | ||
4498 | goto out; | ||
4499 | for (i = 0; i < max_slots; ++i) | ||
4500 | slot[i].seq_nr = ivalue; | ||
4501 | ret = 0; | ||
4502 | |||
4503 | spin_lock(&tbl->slot_tbl_lock); | ||
4504 | if (tbl->slots != NULL) { | ||
4505 | spin_unlock(&tbl->slot_tbl_lock); | ||
4506 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4507 | __func__, tbl, tbl->slots); | ||
4508 | WARN_ON(1); | ||
4509 | goto out_free; | ||
4510 | } | ||
4511 | tbl->max_slots = max_slots; | ||
4512 | tbl->slots = slot; | ||
4513 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
4514 | spin_unlock(&tbl->slot_tbl_lock); | ||
4515 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4516 | tbl, tbl->slots, tbl->max_slots); | ||
4517 | out: | ||
4518 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4519 | return ret; | ||
4520 | |||
4521 | out_free: | ||
4522 | kfree(slot); | ||
4523 | goto out; | ||
4524 | } | ||
4525 | |||
4526 | /* | ||
4527 | * Initialize the forechannel and backchannel tables | ||
4528 | */ | ||
4529 | static int nfs4_init_slot_tables(struct nfs4_session *session) | ||
4530 | { | ||
4531 | int status; | ||
4532 | |||
4533 | status = nfs4_init_slot_table(&session->fc_slot_table, | ||
4534 | session->fc_attrs.max_reqs, 1); | ||
4535 | if (status) | ||
4536 | return status; | ||
4537 | |||
4538 | status = nfs4_init_slot_table(&session->bc_slot_table, | ||
4539 | session->bc_attrs.max_reqs, 0); | ||
4540 | if (status) | ||
4541 | nfs4_destroy_slot_tables(session); | ||
4542 | |||
4543 | return status; | ||
4544 | } | ||
4545 | |||
4546 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
4547 | { | ||
4548 | struct nfs4_session *session; | ||
4549 | struct nfs4_slot_table *tbl; | ||
4550 | |||
4551 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | ||
4552 | if (!session) | ||
4553 | return NULL; | ||
4554 | |||
4555 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4556 | /* | ||
4557 | * The create session reply races with the server back | ||
4558 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4559 | * so that the client back channel can find the | ||
4560 | * nfs_client struct | ||
4561 | */ | ||
4562 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4563 | |||
4564 | tbl = &session->fc_slot_table; | ||
4565 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4566 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
4567 | |||
4568 | tbl = &session->bc_slot_table; | ||
4569 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4570 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
4571 | |||
4572 | session->clp = clp; | ||
4573 | return session; | ||
4574 | } | ||
4575 | |||
4576 | void nfs4_destroy_session(struct nfs4_session *session) | ||
4577 | { | ||
4578 | nfs4_proc_destroy_session(session); | ||
4579 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
4580 | __func__, session->clp->cl_rpcclient->cl_xprt); | ||
4581 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | ||
4582 | NFS41_BC_MIN_CALLBACKS); | ||
4583 | nfs4_destroy_slot_tables(session); | ||
4584 | kfree(session); | ||
4585 | } | ||
4586 | |||
4587 | /* | ||
4588 | * Initialize the values to be used by the client in CREATE_SESSION | ||
4589 | * If nfs4_init_session set the fore channel request and response sizes, | ||
4590 | * use them. | ||
4591 | * | ||
4592 | * Set the back channel max_resp_sz_cached to zero to force the client to | ||
4593 | * always set csa_cachethis to FALSE because the current implementation | ||
4594 | * of the back channel DRC only supports caching the CB_SEQUENCE operation. | ||
4595 | */ | ||
4596 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | ||
4597 | { | ||
4598 | struct nfs4_session *session = args->client->cl_session; | ||
4599 | unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, | ||
4600 | mxresp_sz = session->fc_attrs.max_resp_sz; | ||
4601 | |||
4602 | if (mxrqst_sz == 0) | ||
4603 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
4604 | if (mxresp_sz == 0) | ||
4605 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
4606 | /* Fore channel attributes */ | ||
4607 | args->fc_attrs.headerpadsz = 0; | ||
4608 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | ||
4609 | args->fc_attrs.max_resp_sz = mxresp_sz; | ||
4610 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4611 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | ||
4612 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | ||
4613 | |||
4614 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4615 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4616 | __func__, | ||
4617 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | ||
4618 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | ||
4619 | args->fc_attrs.max_reqs); | ||
4620 | |||
4621 | /* Back channel attributes */ | ||
4622 | args->bc_attrs.headerpadsz = 0; | ||
4623 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | ||
4624 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | ||
4625 | args->bc_attrs.max_resp_sz_cached = 0; | ||
4626 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | ||
4627 | args->bc_attrs.max_reqs = 1; | ||
4628 | |||
4629 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4630 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4631 | __func__, | ||
4632 | args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz, | ||
4633 | args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops, | ||
4634 | args->bc_attrs.max_reqs); | ||
4635 | } | ||
4636 | |||
4637 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | ||
4638 | { | ||
4639 | if (rcvd <= sent) | ||
4640 | return 0; | ||
4641 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | ||
4642 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | ||
4643 | return -EINVAL; | ||
4644 | } | ||
4645 | |||
4646 | #define _verify_fore_channel_attr(_name_) \ | ||
4647 | _verify_channel_attr("fore", #_name_, \ | ||
4648 | args->fc_attrs._name_, \ | ||
4649 | session->fc_attrs._name_) | ||
4650 | |||
4651 | #define _verify_back_channel_attr(_name_) \ | ||
4652 | _verify_channel_attr("back", #_name_, \ | ||
4653 | args->bc_attrs._name_, \ | ||
4654 | session->bc_attrs._name_) | ||
4655 | |||
4656 | /* | ||
4657 | * The server is not allowed to increase the fore channel header pad size, | ||
4658 | * maximum response size, or maximum number of operations. | ||
4659 | * | ||
4660 | * The back channel attributes are only negotiatied down: We send what the | ||
4661 | * (back channel) server insists upon. | ||
4662 | */ | ||
4663 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | ||
4664 | struct nfs4_session *session) | ||
4665 | { | ||
4666 | int ret = 0; | ||
4667 | |||
4668 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4669 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4670 | ret |= _verify_fore_channel_attr(max_ops); | ||
4671 | |||
4672 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4673 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4674 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4675 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4676 | ret |= _verify_back_channel_attr(max_ops); | ||
4677 | ret |= _verify_back_channel_attr(max_reqs); | ||
4678 | |||
4679 | return ret; | ||
4680 | } | ||
4681 | |||
4682 | static int _nfs4_proc_create_session(struct nfs_client *clp) | ||
4683 | { | ||
4684 | struct nfs4_session *session = clp->cl_session; | ||
4685 | struct nfs41_create_session_args args = { | ||
4686 | .client = clp, | ||
4687 | .cb_program = NFS4_CALLBACK, | ||
4688 | }; | ||
4689 | struct nfs41_create_session_res res = { | ||
4690 | .client = clp, | ||
4691 | }; | ||
4692 | struct rpc_message msg = { | ||
4693 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | ||
4694 | .rpc_argp = &args, | ||
4695 | .rpc_resp = &res, | ||
4696 | }; | ||
4697 | int status; | ||
4698 | |||
4699 | nfs4_init_channel_attrs(&args); | ||
4700 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | ||
4701 | |||
4702 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4703 | |||
4704 | if (!status) | ||
4705 | /* Verify the session's negotiated channel_attrs values */ | ||
4706 | status = nfs4_verify_channel_attrs(&args, session); | ||
4707 | if (!status) { | ||
4708 | /* Increment the clientid slot sequence id */ | ||
4709 | clp->cl_seqid++; | ||
4710 | } | ||
4711 | |||
4712 | return status; | ||
4713 | } | ||
4714 | |||
4715 | /* | ||
4716 | * Issues a CREATE_SESSION operation to the server. | ||
4717 | * It is the responsibility of the caller to verify the session is | ||
4718 | * expired before calling this routine. | ||
4719 | */ | ||
4720 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | ||
4721 | { | ||
4722 | int status; | ||
4723 | unsigned *ptr; | ||
4724 | struct nfs_fsinfo fsinfo; | ||
4725 | struct nfs4_session *session = clp->cl_session; | ||
4726 | |||
4727 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | ||
4728 | |||
4729 | status = _nfs4_proc_create_session(clp); | ||
4730 | if (status) | ||
4731 | goto out; | ||
4732 | |||
4733 | /* Init or reset the fore channel */ | ||
4734 | if (reset) | ||
4735 | status = nfs4_reset_slot_tables(session); | ||
4736 | else | ||
4737 | status = nfs4_init_slot_tables(session); | ||
4738 | dprintk("fore channel slot table initialization returned %d\n", status); | ||
4739 | if (status) | ||
4740 | goto out; | ||
4741 | |||
4742 | ptr = (unsigned *)&session->sess_id.data[0]; | ||
4743 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | ||
4744 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
4745 | |||
4746 | if (reset) | ||
4747 | /* Lease time is aleady set */ | ||
4748 | goto out; | ||
4749 | |||
4750 | /* Get the lease time */ | ||
4751 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4752 | if (status == 0) { | ||
4753 | /* Update lease time and schedule renewal */ | ||
4754 | spin_lock(&clp->cl_lock); | ||
4755 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4756 | clp->cl_last_renewal = jiffies; | ||
4757 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4758 | spin_unlock(&clp->cl_lock); | ||
4759 | |||
4760 | nfs4_schedule_state_renewal(clp); | ||
4761 | } | ||
4762 | out: | ||
4763 | dprintk("<-- %s\n", __func__); | ||
4764 | return status; | ||
4765 | } | ||
4766 | |||
4767 | /* | ||
4768 | * Issue the over-the-wire RPC DESTROY_SESSION. | ||
4769 | * The caller must serialize access to this routine. | ||
4770 | */ | ||
4771 | int nfs4_proc_destroy_session(struct nfs4_session *session) | ||
4772 | { | ||
4773 | int status = 0; | ||
4774 | struct rpc_message msg; | ||
4775 | |||
4776 | dprintk("--> nfs4_proc_destroy_session\n"); | ||
4777 | |||
4778 | /* session is still being setup */ | ||
4779 | if (session->clp->cl_cons_state != NFS_CS_READY) | ||
4780 | return status; | ||
4781 | |||
4782 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION]; | ||
4783 | msg.rpc_argp = session; | ||
4784 | msg.rpc_resp = NULL; | ||
4785 | msg.rpc_cred = NULL; | ||
4786 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4787 | |||
4788 | if (status) | ||
4789 | printk(KERN_WARNING | ||
4790 | "Got error %d from the server on DESTROY_SESSION. " | ||
4791 | "Session has been destroyed regardless...\n", status); | ||
4792 | |||
4793 | dprintk("<-- nfs4_proc_destroy_session\n"); | ||
4794 | return status; | ||
4795 | } | ||
4796 | |||
4797 | /* | ||
4798 | * Renew the cl_session lease. | ||
4799 | */ | ||
4800 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
4801 | { | ||
4802 | struct nfs4_sequence_args args; | ||
4803 | struct nfs4_sequence_res res; | ||
4804 | |||
4805 | struct rpc_message msg = { | ||
4806 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4807 | .rpc_argp = &args, | ||
4808 | .rpc_resp = &res, | ||
4809 | .rpc_cred = cred, | ||
4810 | }; | ||
4811 | |||
4812 | args.sa_cache_this = 0; | ||
4813 | |||
4814 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
4815 | &res, 0); | ||
4816 | } | ||
4817 | |||
4818 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4819 | { | ||
4820 | struct nfs_client *clp = (struct nfs_client *)data; | ||
4821 | |||
4822 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
4823 | |||
4824 | if (task->tk_status < 0) { | ||
4825 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
4826 | |||
4827 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
4828 | == -EAGAIN) { | ||
4829 | nfs4_restart_rpc(task, clp); | ||
4830 | return; | ||
4831 | } | ||
4832 | } | ||
4833 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4834 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
4835 | |||
4836 | put_rpccred(task->tk_msg.rpc_cred); | ||
4837 | kfree(task->tk_msg.rpc_argp); | ||
4838 | kfree(task->tk_msg.rpc_resp); | ||
4839 | |||
4840 | dprintk("<-- %s\n", __func__); | ||
4841 | } | ||
4842 | |||
4843 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
4844 | { | ||
4845 | struct nfs_client *clp; | ||
4846 | struct nfs4_sequence_args *args; | ||
4847 | struct nfs4_sequence_res *res; | ||
4848 | |||
4849 | clp = (struct nfs_client *)data; | ||
4850 | args = task->tk_msg.rpc_argp; | ||
4851 | res = task->tk_msg.rpc_resp; | ||
4852 | |||
4853 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
4854 | return; | ||
4855 | rpc_call_start(task); | ||
4856 | } | ||
4857 | |||
4858 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
4859 | .rpc_call_done = nfs41_sequence_call_done, | ||
4860 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
4861 | }; | ||
4862 | |||
4863 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
4864 | struct rpc_cred *cred) | ||
4865 | { | ||
4866 | struct nfs4_sequence_args *args; | ||
4867 | struct nfs4_sequence_res *res; | ||
4868 | struct rpc_message msg = { | ||
4869 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4870 | .rpc_cred = cred, | ||
4871 | }; | ||
4872 | |||
4873 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
4874 | if (!args) | ||
4875 | return -ENOMEM; | ||
4876 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
4877 | if (!res) { | ||
4878 | kfree(args); | ||
4879 | return -ENOMEM; | ||
4880 | } | ||
4881 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4882 | msg.rpc_argp = args; | ||
4883 | msg.rpc_resp = res; | ||
4884 | |||
4885 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
4886 | &nfs41_sequence_ops, (void *)clp); | ||
4887 | } | ||
4888 | |||
4889 | #endif /* CONFIG_NFS_V4_1 */ | ||
4890 | |||
4891 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
3768 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 4892 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
3769 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 4893 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
3770 | .recover_open = nfs4_open_reclaim, | 4894 | .recover_open = nfs4_open_reclaim, |
3771 | .recover_lock = nfs4_lock_reclaim, | 4895 | .recover_lock = nfs4_lock_reclaim, |
4896 | .establish_clid = nfs4_init_clientid, | ||
4897 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
3772 | }; | 4898 | }; |
3773 | 4899 | ||
3774 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { | 4900 | #if defined(CONFIG_NFS_V4_1) |
4901 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | ||
4902 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
4903 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
4904 | .recover_open = nfs4_open_reclaim, | ||
4905 | .recover_lock = nfs4_lock_reclaim, | ||
4906 | .establish_clid = nfs4_proc_exchange_id, | ||
4907 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4908 | }; | ||
4909 | #endif /* CONFIG_NFS_V4_1 */ | ||
4910 | |||
4911 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | ||
3775 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 4912 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
3776 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 4913 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
3777 | .recover_open = nfs4_open_expired, | 4914 | .recover_open = nfs4_open_expired, |
3778 | .recover_lock = nfs4_lock_expired, | 4915 | .recover_lock = nfs4_lock_expired, |
4916 | .establish_clid = nfs4_init_clientid, | ||
4917 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
4918 | }; | ||
4919 | |||
4920 | #if defined(CONFIG_NFS_V4_1) | ||
4921 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | ||
4922 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
4923 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
4924 | .recover_open = nfs4_open_expired, | ||
4925 | .recover_lock = nfs4_lock_expired, | ||
4926 | .establish_clid = nfs4_proc_exchange_id, | ||
4927 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4928 | }; | ||
4929 | #endif /* CONFIG_NFS_V4_1 */ | ||
4930 | |||
4931 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | ||
4932 | .sched_state_renewal = nfs4_proc_async_renew, | ||
4933 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | ||
4934 | .renew_lease = nfs4_proc_renew, | ||
4935 | }; | ||
4936 | |||
4937 | #if defined(CONFIG_NFS_V4_1) | ||
4938 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | ||
4939 | .sched_state_renewal = nfs41_proc_async_sequence, | ||
4940 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | ||
4941 | .renew_lease = nfs4_proc_sequence, | ||
4942 | }; | ||
4943 | #endif | ||
4944 | |||
4945 | /* | ||
4946 | * Per minor version reboot and network partition recovery ops | ||
4947 | */ | ||
4948 | |||
4949 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | ||
4950 | &nfs40_reboot_recovery_ops, | ||
4951 | #if defined(CONFIG_NFS_V4_1) | ||
4952 | &nfs41_reboot_recovery_ops, | ||
4953 | #endif | ||
4954 | }; | ||
4955 | |||
4956 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
4957 | &nfs40_nograce_recovery_ops, | ||
4958 | #if defined(CONFIG_NFS_V4_1) | ||
4959 | &nfs41_nograce_recovery_ops, | ||
4960 | #endif | ||
4961 | }; | ||
4962 | |||
4963 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | ||
4964 | &nfs40_state_renewal_ops, | ||
4965 | #if defined(CONFIG_NFS_V4_1) | ||
4966 | &nfs41_state_renewal_ops, | ||
4967 | #endif | ||
3779 | }; | 4968 | }; |
3780 | 4969 | ||
3781 | static const struct inode_operations nfs4_file_inode_operations = { | 4970 | static const struct inode_operations nfs4_file_inode_operations = { |
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c index f524e932ff7b..e27c6cef18f2 100644 --- a/fs/nfs/nfs4renewd.c +++ b/fs/nfs/nfs4renewd.c | |||
@@ -59,12 +59,14 @@ | |||
59 | void | 59 | void |
60 | nfs4_renew_state(struct work_struct *work) | 60 | nfs4_renew_state(struct work_struct *work) |
61 | { | 61 | { |
62 | struct nfs4_state_maintenance_ops *ops; | ||
62 | struct nfs_client *clp = | 63 | struct nfs_client *clp = |
63 | container_of(work, struct nfs_client, cl_renewd.work); | 64 | container_of(work, struct nfs_client, cl_renewd.work); |
64 | struct rpc_cred *cred; | 65 | struct rpc_cred *cred; |
65 | long lease, timeout; | 66 | long lease, timeout; |
66 | unsigned long last, now; | 67 | unsigned long last, now; |
67 | 68 | ||
69 | ops = nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
68 | dprintk("%s: start\n", __func__); | 70 | dprintk("%s: start\n", __func__); |
69 | /* Are there any active superblocks? */ | 71 | /* Are there any active superblocks? */ |
70 | if (list_empty(&clp->cl_superblocks)) | 72 | if (list_empty(&clp->cl_superblocks)) |
@@ -76,7 +78,7 @@ nfs4_renew_state(struct work_struct *work) | |||
76 | timeout = (2 * lease) / 3 + (long)last - (long)now; | 78 | timeout = (2 * lease) / 3 + (long)last - (long)now; |
77 | /* Are we close to a lease timeout? */ | 79 | /* Are we close to a lease timeout? */ |
78 | if (time_after(now, last + lease/3)) { | 80 | if (time_after(now, last + lease/3)) { |
79 | cred = nfs4_get_renew_cred_locked(clp); | 81 | cred = ops->get_state_renewal_cred_locked(clp); |
80 | spin_unlock(&clp->cl_lock); | 82 | spin_unlock(&clp->cl_lock); |
81 | if (cred == NULL) { | 83 | if (cred == NULL) { |
82 | if (list_empty(&clp->cl_delegations)) { | 84 | if (list_empty(&clp->cl_delegations)) { |
@@ -86,7 +88,7 @@ nfs4_renew_state(struct work_struct *work) | |||
86 | nfs_expire_all_delegations(clp); | 88 | nfs_expire_all_delegations(clp); |
87 | } else { | 89 | } else { |
88 | /* Queue an asynchronous RENEW. */ | 90 | /* Queue an asynchronous RENEW. */ |
89 | nfs4_proc_async_renew(clp, cred); | 91 | ops->sched_state_renewal(clp, cred); |
90 | put_rpccred(cred); | 92 | put_rpccred(cred); |
91 | } | 93 | } |
92 | timeout = (2 * lease) / 3; | 94 | timeout = (2 * lease) / 3; |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 0b2a19bfe5a0..b73c5a728655 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -60,7 +60,7 @@ const nfs4_stateid zero_stateid; | |||
60 | 60 | ||
61 | static LIST_HEAD(nfs4_clientid_list); | 61 | static LIST_HEAD(nfs4_clientid_list); |
62 | 62 | ||
63 | static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | 63 | int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred) |
64 | { | 64 | { |
65 | unsigned short port; | 65 | unsigned short port; |
66 | int status; | 66 | int status; |
@@ -77,7 +77,7 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred) | |||
77 | return status; | 77 | return status; |
78 | } | 78 | } |
79 | 79 | ||
80 | static struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) | 80 | struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp) |
81 | { | 81 | { |
82 | struct rpc_cred *cred = NULL; | 82 | struct rpc_cred *cred = NULL; |
83 | 83 | ||
@@ -114,17 +114,21 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp) | |||
114 | return cred; | 114 | return cred; |
115 | } | 115 | } |
116 | 116 | ||
117 | static struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp) | 117 | #if defined(CONFIG_NFS_V4_1) |
118 | |||
119 | struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp) | ||
118 | { | 120 | { |
119 | struct rpc_cred *cred; | 121 | struct rpc_cred *cred; |
120 | 122 | ||
121 | spin_lock(&clp->cl_lock); | 123 | spin_lock(&clp->cl_lock); |
122 | cred = nfs4_get_renew_cred_locked(clp); | 124 | cred = nfs4_get_machine_cred_locked(clp); |
123 | spin_unlock(&clp->cl_lock); | 125 | spin_unlock(&clp->cl_lock); |
124 | return cred; | 126 | return cred; |
125 | } | 127 | } |
126 | 128 | ||
127 | static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | 129 | #endif /* CONFIG_NFS_V4_1 */ |
130 | |||
131 | struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp) | ||
128 | { | 132 | { |
129 | struct nfs4_state_owner *sp; | 133 | struct nfs4_state_owner *sp; |
130 | struct rb_node *pos; | 134 | struct rb_node *pos; |
@@ -738,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) | |||
738 | 742 | ||
739 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) | 743 | void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid) |
740 | { | 744 | { |
741 | if (status == -NFS4ERR_BAD_SEQID) { | 745 | struct nfs4_state_owner *sp = container_of(seqid->sequence, |
742 | struct nfs4_state_owner *sp = container_of(seqid->sequence, | 746 | struct nfs4_state_owner, so_seqid); |
743 | struct nfs4_state_owner, so_seqid); | 747 | struct nfs_server *server = sp->so_server; |
748 | |||
749 | if (status == -NFS4ERR_BAD_SEQID) | ||
744 | nfs4_drop_state_owner(sp); | 750 | nfs4_drop_state_owner(sp); |
745 | } | 751 | if (!nfs4_has_session(server->nfs_client)) |
746 | nfs_increment_seqid(status, seqid); | 752 | nfs_increment_seqid(status, seqid); |
747 | } | 753 | } |
748 | 754 | ||
749 | /* | 755 | /* |
@@ -1059,6 +1065,14 @@ static void nfs4_recovery_handle_error(struct nfs_client *clp, int error) | |||
1059 | case -NFS4ERR_EXPIRED: | 1065 | case -NFS4ERR_EXPIRED: |
1060 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1066 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
1061 | nfs4_state_start_reclaim_nograce(clp); | 1067 | nfs4_state_start_reclaim_nograce(clp); |
1068 | case -NFS4ERR_BADSESSION: | ||
1069 | case -NFS4ERR_BADSLOT: | ||
1070 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
1071 | case -NFS4ERR_DEADSESSION: | ||
1072 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
1073 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
1074 | case -NFS4ERR_SEQ_MISORDERED: | ||
1075 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1062 | } | 1076 | } |
1063 | } | 1077 | } |
1064 | 1078 | ||
@@ -1092,18 +1106,22 @@ restart: | |||
1092 | static int nfs4_check_lease(struct nfs_client *clp) | 1106 | static int nfs4_check_lease(struct nfs_client *clp) |
1093 | { | 1107 | { |
1094 | struct rpc_cred *cred; | 1108 | struct rpc_cred *cred; |
1109 | struct nfs4_state_maintenance_ops *ops = | ||
1110 | nfs4_state_renewal_ops[clp->cl_minorversion]; | ||
1095 | int status = -NFS4ERR_EXPIRED; | 1111 | int status = -NFS4ERR_EXPIRED; |
1096 | 1112 | ||
1097 | /* Is the client already known to have an expired lease? */ | 1113 | /* Is the client already known to have an expired lease? */ |
1098 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) | 1114 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) |
1099 | return 0; | 1115 | return 0; |
1100 | cred = nfs4_get_renew_cred(clp); | 1116 | spin_lock(&clp->cl_lock); |
1117 | cred = ops->get_state_renewal_cred_locked(clp); | ||
1118 | spin_unlock(&clp->cl_lock); | ||
1101 | if (cred == NULL) { | 1119 | if (cred == NULL) { |
1102 | cred = nfs4_get_setclientid_cred(clp); | 1120 | cred = nfs4_get_setclientid_cred(clp); |
1103 | if (cred == NULL) | 1121 | if (cred == NULL) |
1104 | goto out; | 1122 | goto out; |
1105 | } | 1123 | } |
1106 | status = nfs4_proc_renew(clp, cred); | 1124 | status = ops->renew_lease(clp, cred); |
1107 | put_rpccred(cred); | 1125 | put_rpccred(cred); |
1108 | out: | 1126 | out: |
1109 | nfs4_recovery_handle_error(clp, status); | 1127 | nfs4_recovery_handle_error(clp, status); |
@@ -1113,21 +1131,98 @@ out: | |||
1113 | static int nfs4_reclaim_lease(struct nfs_client *clp) | 1131 | static int nfs4_reclaim_lease(struct nfs_client *clp) |
1114 | { | 1132 | { |
1115 | struct rpc_cred *cred; | 1133 | struct rpc_cred *cred; |
1134 | struct nfs4_state_recovery_ops *ops = | ||
1135 | nfs4_reboot_recovery_ops[clp->cl_minorversion]; | ||
1116 | int status = -ENOENT; | 1136 | int status = -ENOENT; |
1117 | 1137 | ||
1118 | cred = nfs4_get_setclientid_cred(clp); | 1138 | cred = ops->get_clid_cred(clp); |
1119 | if (cred != NULL) { | 1139 | if (cred != NULL) { |
1120 | status = nfs4_init_client(clp, cred); | 1140 | status = ops->establish_clid(clp, cred); |
1121 | put_rpccred(cred); | 1141 | put_rpccred(cred); |
1122 | /* Handle case where the user hasn't set up machine creds */ | 1142 | /* Handle case where the user hasn't set up machine creds */ |
1123 | if (status == -EACCES && cred == clp->cl_machine_cred) { | 1143 | if (status == -EACCES && cred == clp->cl_machine_cred) { |
1124 | nfs4_clear_machine_cred(clp); | 1144 | nfs4_clear_machine_cred(clp); |
1125 | status = -EAGAIN; | 1145 | status = -EAGAIN; |
1126 | } | 1146 | } |
1147 | if (status == -NFS4ERR_MINOR_VERS_MISMATCH) | ||
1148 | status = -EPROTONOSUPPORT; | ||
1127 | } | 1149 | } |
1128 | return status; | 1150 | return status; |
1129 | } | 1151 | } |
1130 | 1152 | ||
1153 | #ifdef CONFIG_NFS_V4_1 | ||
1154 | static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err) | ||
1155 | { | ||
1156 | switch (err) { | ||
1157 | case -NFS4ERR_STALE_CLIENTID: | ||
1158 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1159 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1160 | } | ||
1161 | } | ||
1162 | |||
1163 | static int nfs4_reset_session(struct nfs_client *clp) | ||
1164 | { | ||
1165 | int status; | ||
1166 | |||
1167 | status = nfs4_proc_destroy_session(clp->cl_session); | ||
1168 | if (status && status != -NFS4ERR_BADSESSION && | ||
1169 | status != -NFS4ERR_DEADSESSION) { | ||
1170 | nfs4_session_recovery_handle_error(clp, status); | ||
1171 | goto out; | ||
1172 | } | ||
1173 | |||
1174 | memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN); | ||
1175 | status = nfs4_proc_create_session(clp, 1); | ||
1176 | if (status) | ||
1177 | nfs4_session_recovery_handle_error(clp, status); | ||
1178 | /* fall through*/ | ||
1179 | 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; | ||
1183 | } | ||
1184 | |||
1185 | static int nfs4_initialize_session(struct nfs_client *clp) | ||
1186 | { | ||
1187 | int status; | ||
1188 | |||
1189 | status = nfs4_proc_create_session(clp, 0); | ||
1190 | if (!status) { | ||
1191 | nfs_mark_client_ready(clp, NFS_CS_READY); | ||
1192 | } else if (status == -NFS4ERR_STALE_CLIENTID) { | ||
1193 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1194 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
1195 | } else { | ||
1196 | nfs_mark_client_ready(clp, status); | ||
1197 | } | ||
1198 | return status; | ||
1199 | } | ||
1200 | #else /* CONFIG_NFS_V4_1 */ | ||
1201 | static int nfs4_reset_session(struct nfs_client *clp) { return 0; } | ||
1202 | static int nfs4_initialize_session(struct nfs_client *clp) { return 0; } | ||
1203 | #endif /* CONFIG_NFS_V4_1 */ | ||
1204 | |||
1205 | /* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors | ||
1206 | * on EXCHANGE_ID for v4.1 | ||
1207 | */ | ||
1208 | static void nfs4_set_lease_expired(struct nfs_client *clp, int status) | ||
1209 | { | ||
1210 | if (nfs4_has_session(clp)) { | ||
1211 | switch (status) { | ||
1212 | case -NFS4ERR_DELAY: | ||
1213 | case -NFS4ERR_CLID_INUSE: | ||
1214 | case -EAGAIN: | ||
1215 | break; | ||
1216 | |||
1217 | case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery | ||
1218 | * in nfs4_exchange_id */ | ||
1219 | default: | ||
1220 | return; | ||
1221 | } | ||
1222 | } | ||
1223 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
1224 | } | ||
1225 | |||
1131 | static void nfs4_state_manager(struct nfs_client *clp) | 1226 | static void nfs4_state_manager(struct nfs_client *clp) |
1132 | { | 1227 | { |
1133 | int status = 0; | 1228 | int status = 0; |
@@ -1138,9 +1233,12 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1138 | /* We're going to have to re-establish a clientid */ | 1233 | /* We're going to have to re-establish a clientid */ |
1139 | status = nfs4_reclaim_lease(clp); | 1234 | status = nfs4_reclaim_lease(clp); |
1140 | if (status) { | 1235 | if (status) { |
1141 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | 1236 | nfs4_set_lease_expired(clp, status); |
1142 | if (status == -EAGAIN) | 1237 | if (status == -EAGAIN) |
1143 | continue; | 1238 | continue; |
1239 | if (clp->cl_cons_state == | ||
1240 | NFS_CS_SESSION_INITING) | ||
1241 | nfs_mark_client_ready(clp, status); | ||
1144 | goto out_error; | 1242 | goto out_error; |
1145 | } | 1243 | } |
1146 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); | 1244 | clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); |
@@ -1151,25 +1249,44 @@ static void nfs4_state_manager(struct nfs_client *clp) | |||
1151 | if (status != 0) | 1249 | if (status != 0) |
1152 | continue; | 1250 | continue; |
1153 | } | 1251 | } |
1154 | 1252 | /* Initialize or reset the session */ | |
1253 | if (nfs4_has_session(clp) && | ||
1254 | test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) { | ||
1255 | if (clp->cl_cons_state == NFS_CS_SESSION_INITING) | ||
1256 | status = nfs4_initialize_session(clp); | ||
1257 | else | ||
1258 | status = nfs4_reset_session(clp); | ||
1259 | if (status) { | ||
1260 | if (status == -NFS4ERR_STALE_CLIENTID) | ||
1261 | continue; | ||
1262 | goto out_error; | ||
1263 | } | ||
1264 | } | ||
1155 | /* First recover reboot state... */ | 1265 | /* First recover reboot state... */ |
1156 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { | 1266 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) { |
1157 | status = nfs4_do_reclaim(clp, &nfs4_reboot_recovery_ops); | 1267 | status = nfs4_do_reclaim(clp, |
1268 | nfs4_reboot_recovery_ops[clp->cl_minorversion]); | ||
1158 | if (status == -NFS4ERR_STALE_CLIENTID) | 1269 | if (status == -NFS4ERR_STALE_CLIENTID) |
1159 | continue; | 1270 | continue; |
1271 | if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
1272 | continue; | ||
1160 | nfs4_state_end_reclaim_reboot(clp); | 1273 | nfs4_state_end_reclaim_reboot(clp); |
1161 | continue; | 1274 | continue; |
1162 | } | 1275 | } |
1163 | 1276 | ||
1164 | /* Now recover expired state... */ | 1277 | /* Now recover expired state... */ |
1165 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { | 1278 | if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) { |
1166 | status = nfs4_do_reclaim(clp, &nfs4_nograce_recovery_ops); | 1279 | status = nfs4_do_reclaim(clp, |
1280 | nfs4_nograce_recovery_ops[clp->cl_minorversion]); | ||
1167 | if (status < 0) { | 1281 | if (status < 0) { |
1168 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); | 1282 | set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state); |
1169 | if (status == -NFS4ERR_STALE_CLIENTID) | 1283 | if (status == -NFS4ERR_STALE_CLIENTID) |
1170 | continue; | 1284 | continue; |
1171 | if (status == -NFS4ERR_EXPIRED) | 1285 | if (status == -NFS4ERR_EXPIRED) |
1172 | continue; | 1286 | continue; |
1287 | if (test_bit(NFS4CLNT_SESSION_SETUP, | ||
1288 | &clp->cl_state)) | ||
1289 | continue; | ||
1173 | goto out_error; | 1290 | goto out_error; |
1174 | } else | 1291 | } else |
1175 | nfs4_state_end_reclaim_nograce(clp); | 1292 | nfs4_state_end_reclaim_nograce(clp); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1690f0e44b91..617273e7d47f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int); | |||
192 | decode_verifier_maxsz) | 192 | decode_verifier_maxsz) |
193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ | 193 | #define encode_remove_maxsz (op_encode_hdr_maxsz + \ |
194 | nfs4_name_maxsz) | 194 | nfs4_name_maxsz) |
195 | #define decode_remove_maxsz (op_decode_hdr_maxsz + \ | ||
196 | decode_change_info_maxsz) | ||
195 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ | 197 | #define encode_rename_maxsz (op_encode_hdr_maxsz + \ |
196 | 2 * nfs4_name_maxsz) | 198 | 2 * nfs4_name_maxsz) |
197 | #define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5) | 199 | #define decode_rename_maxsz (op_decode_hdr_maxsz + \ |
200 | decode_change_info_maxsz + \ | ||
201 | decode_change_info_maxsz) | ||
198 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ | 202 | #define encode_link_maxsz (op_encode_hdr_maxsz + \ |
199 | nfs4_name_maxsz) | 203 | nfs4_name_maxsz) |
200 | #define decode_link_maxsz (op_decode_hdr_maxsz + 5) | 204 | #define decode_link_maxsz (op_decode_hdr_maxsz + decode_change_info_maxsz) |
201 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ | 205 | #define encode_lock_maxsz (op_encode_hdr_maxsz + \ |
202 | 7 + \ | 206 | 7 + \ |
203 | 1 + encode_stateid_maxsz + 8) | 207 | 1 + encode_stateid_maxsz + 8) |
@@ -240,43 +244,115 @@ static int nfs4_stat_to_errno(int); | |||
240 | (encode_getattr_maxsz) | 244 | (encode_getattr_maxsz) |
241 | #define decode_fs_locations_maxsz \ | 245 | #define decode_fs_locations_maxsz \ |
242 | (0) | 246 | (0) |
247 | |||
248 | #if defined(CONFIG_NFS_V4_1) | ||
249 | #define NFS4_MAX_MACHINE_NAME_LEN (64) | ||
250 | |||
251 | #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ | ||
252 | encode_verifier_maxsz + \ | ||
253 | 1 /* co_ownerid.len */ + \ | ||
254 | XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ | ||
255 | 1 /* flags */ + \ | ||
256 | 1 /* spa_how */ + \ | ||
257 | 0 /* SP4_NONE (for now) */ + \ | ||
258 | 1 /* zero implemetation id array */) | ||
259 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | ||
260 | 2 /* eir_clientid */ + \ | ||
261 | 1 /* eir_sequenceid */ + \ | ||
262 | 1 /* eir_flags */ + \ | ||
263 | 1 /* spr_how */ + \ | ||
264 | 0 /* SP4_NONE (for now) */ + \ | ||
265 | 2 /* eir_server_owner.so_minor_id */ + \ | ||
266 | /* eir_server_owner.so_major_id<> */ \ | ||
267 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
268 | /* eir_server_scope<> */ \ | ||
269 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
270 | 1 /* eir_server_impl_id array length */ + \ | ||
271 | 0 /* ignored eir_server_impl_id contents */) | ||
272 | #define encode_channel_attrs_maxsz (6 + 1 /* ca_rdma_ird.len (0) */) | ||
273 | #define decode_channel_attrs_maxsz (6 + \ | ||
274 | 1 /* ca_rdma_ird.len */ + \ | ||
275 | 1 /* ca_rdma_ird */) | ||
276 | #define encode_create_session_maxsz (op_encode_hdr_maxsz + \ | ||
277 | 2 /* csa_clientid */ + \ | ||
278 | 1 /* csa_sequence */ + \ | ||
279 | 1 /* csa_flags */ + \ | ||
280 | encode_channel_attrs_maxsz + \ | ||
281 | encode_channel_attrs_maxsz + \ | ||
282 | 1 /* csa_cb_program */ + \ | ||
283 | 1 /* csa_sec_parms.len (1) */ + \ | ||
284 | 1 /* cb_secflavor (AUTH_SYS) */ + \ | ||
285 | 1 /* stamp */ + \ | ||
286 | 1 /* machinename.len */ + \ | ||
287 | XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \ | ||
288 | 1 /* uid */ + \ | ||
289 | 1 /* gid */ + \ | ||
290 | 1 /* gids.len (0) */) | ||
291 | #define decode_create_session_maxsz (op_decode_hdr_maxsz + \ | ||
292 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ | ||
293 | 1 /* csr_sequence */ + \ | ||
294 | 1 /* csr_flags */ + \ | ||
295 | decode_channel_attrs_maxsz + \ | ||
296 | decode_channel_attrs_maxsz) | ||
297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) | ||
298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) | ||
299 | #define encode_sequence_maxsz (op_encode_hdr_maxsz + \ | ||
300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) | ||
301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | ||
302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | ||
303 | #else /* CONFIG_NFS_V4_1 */ | ||
304 | #define encode_sequence_maxsz 0 | ||
305 | #define decode_sequence_maxsz 0 | ||
306 | #endif /* CONFIG_NFS_V4_1 */ | ||
307 | |||
243 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ | 308 | #define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ |
244 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ | 309 | #define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ |
245 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ | 310 | #define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ |
311 | encode_sequence_maxsz + \ | ||
246 | encode_putfh_maxsz + \ | 312 | encode_putfh_maxsz + \ |
247 | encode_read_maxsz) | 313 | encode_read_maxsz) |
248 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ | 314 | #define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ |
315 | decode_sequence_maxsz + \ | ||
249 | decode_putfh_maxsz + \ | 316 | decode_putfh_maxsz + \ |
250 | decode_read_maxsz) | 317 | decode_read_maxsz) |
251 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ | 318 | #define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \ |
319 | encode_sequence_maxsz + \ | ||
252 | encode_putfh_maxsz + \ | 320 | encode_putfh_maxsz + \ |
253 | encode_readlink_maxsz) | 321 | encode_readlink_maxsz) |
254 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ | 322 | #define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \ |
323 | decode_sequence_maxsz + \ | ||
255 | decode_putfh_maxsz + \ | 324 | decode_putfh_maxsz + \ |
256 | decode_readlink_maxsz) | 325 | decode_readlink_maxsz) |
257 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ | 326 | #define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \ |
327 | encode_sequence_maxsz + \ | ||
258 | encode_putfh_maxsz + \ | 328 | encode_putfh_maxsz + \ |
259 | encode_readdir_maxsz) | 329 | encode_readdir_maxsz) |
260 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ | 330 | #define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \ |
331 | decode_sequence_maxsz + \ | ||
261 | decode_putfh_maxsz + \ | 332 | decode_putfh_maxsz + \ |
262 | decode_readdir_maxsz) | 333 | decode_readdir_maxsz) |
263 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ | 334 | #define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ |
335 | encode_sequence_maxsz + \ | ||
264 | encode_putfh_maxsz + \ | 336 | encode_putfh_maxsz + \ |
265 | encode_write_maxsz + \ | 337 | encode_write_maxsz + \ |
266 | encode_getattr_maxsz) | 338 | encode_getattr_maxsz) |
267 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ | 339 | #define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ |
340 | decode_sequence_maxsz + \ | ||
268 | decode_putfh_maxsz + \ | 341 | decode_putfh_maxsz + \ |
269 | decode_write_maxsz + \ | 342 | decode_write_maxsz + \ |
270 | decode_getattr_maxsz) | 343 | decode_getattr_maxsz) |
271 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ | 344 | #define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ |
345 | encode_sequence_maxsz + \ | ||
272 | encode_putfh_maxsz + \ | 346 | encode_putfh_maxsz + \ |
273 | encode_commit_maxsz + \ | 347 | encode_commit_maxsz + \ |
274 | encode_getattr_maxsz) | 348 | encode_getattr_maxsz) |
275 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ | 349 | #define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ |
350 | decode_sequence_maxsz + \ | ||
276 | decode_putfh_maxsz + \ | 351 | decode_putfh_maxsz + \ |
277 | decode_commit_maxsz + \ | 352 | decode_commit_maxsz + \ |
278 | decode_getattr_maxsz) | 353 | decode_getattr_maxsz) |
279 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ | 354 | #define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ |
355 | encode_sequence_maxsz + \ | ||
280 | encode_putfh_maxsz + \ | 356 | encode_putfh_maxsz + \ |
281 | encode_savefh_maxsz + \ | 357 | encode_savefh_maxsz + \ |
282 | encode_open_maxsz + \ | 358 | encode_open_maxsz + \ |
@@ -285,6 +361,7 @@ static int nfs4_stat_to_errno(int); | |||
285 | encode_restorefh_maxsz + \ | 361 | encode_restorefh_maxsz + \ |
286 | encode_getattr_maxsz) | 362 | encode_getattr_maxsz) |
287 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ | 363 | #define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ |
364 | decode_sequence_maxsz + \ | ||
288 | decode_putfh_maxsz + \ | 365 | decode_putfh_maxsz + \ |
289 | decode_savefh_maxsz + \ | 366 | decode_savefh_maxsz + \ |
290 | decode_open_maxsz + \ | 367 | decode_open_maxsz + \ |
@@ -301,43 +378,53 @@ static int nfs4_stat_to_errno(int); | |||
301 | decode_putfh_maxsz + \ | 378 | decode_putfh_maxsz + \ |
302 | decode_open_confirm_maxsz) | 379 | decode_open_confirm_maxsz) |
303 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ | 380 | #define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \ |
381 | encode_sequence_maxsz + \ | ||
304 | encode_putfh_maxsz + \ | 382 | encode_putfh_maxsz + \ |
305 | encode_open_maxsz + \ | 383 | encode_open_maxsz + \ |
306 | encode_getattr_maxsz) | 384 | encode_getattr_maxsz) |
307 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ | 385 | #define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ |
386 | decode_sequence_maxsz + \ | ||
308 | decode_putfh_maxsz + \ | 387 | decode_putfh_maxsz + \ |
309 | decode_open_maxsz + \ | 388 | decode_open_maxsz + \ |
310 | decode_getattr_maxsz) | 389 | decode_getattr_maxsz) |
311 | #define NFS4_enc_open_downgrade_sz \ | 390 | #define NFS4_enc_open_downgrade_sz \ |
312 | (compound_encode_hdr_maxsz + \ | 391 | (compound_encode_hdr_maxsz + \ |
392 | encode_sequence_maxsz + \ | ||
313 | encode_putfh_maxsz + \ | 393 | encode_putfh_maxsz + \ |
314 | encode_open_downgrade_maxsz + \ | 394 | encode_open_downgrade_maxsz + \ |
315 | encode_getattr_maxsz) | 395 | encode_getattr_maxsz) |
316 | #define NFS4_dec_open_downgrade_sz \ | 396 | #define NFS4_dec_open_downgrade_sz \ |
317 | (compound_decode_hdr_maxsz + \ | 397 | (compound_decode_hdr_maxsz + \ |
398 | decode_sequence_maxsz + \ | ||
318 | decode_putfh_maxsz + \ | 399 | decode_putfh_maxsz + \ |
319 | decode_open_downgrade_maxsz + \ | 400 | decode_open_downgrade_maxsz + \ |
320 | decode_getattr_maxsz) | 401 | decode_getattr_maxsz) |
321 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ | 402 | #define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ |
403 | encode_sequence_maxsz + \ | ||
322 | encode_putfh_maxsz + \ | 404 | encode_putfh_maxsz + \ |
323 | encode_close_maxsz + \ | 405 | encode_close_maxsz + \ |
324 | encode_getattr_maxsz) | 406 | encode_getattr_maxsz) |
325 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ | 407 | #define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ |
408 | decode_sequence_maxsz + \ | ||
326 | decode_putfh_maxsz + \ | 409 | decode_putfh_maxsz + \ |
327 | decode_close_maxsz + \ | 410 | decode_close_maxsz + \ |
328 | decode_getattr_maxsz) | 411 | decode_getattr_maxsz) |
329 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ | 412 | #define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ |
413 | encode_sequence_maxsz + \ | ||
330 | encode_putfh_maxsz + \ | 414 | encode_putfh_maxsz + \ |
331 | encode_setattr_maxsz + \ | 415 | encode_setattr_maxsz + \ |
332 | encode_getattr_maxsz) | 416 | encode_getattr_maxsz) |
333 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 417 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
418 | decode_sequence_maxsz + \ | ||
334 | decode_putfh_maxsz + \ | 419 | decode_putfh_maxsz + \ |
335 | decode_setattr_maxsz + \ | 420 | decode_setattr_maxsz + \ |
336 | decode_getattr_maxsz) | 421 | decode_getattr_maxsz) |
337 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ | 422 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ |
423 | encode_sequence_maxsz + \ | ||
338 | encode_putfh_maxsz + \ | 424 | encode_putfh_maxsz + \ |
339 | encode_fsinfo_maxsz) | 425 | encode_fsinfo_maxsz) |
340 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ | 426 | #define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ |
427 | decode_sequence_maxsz + \ | ||
341 | decode_putfh_maxsz + \ | 428 | decode_putfh_maxsz + \ |
342 | decode_fsinfo_maxsz) | 429 | decode_fsinfo_maxsz) |
343 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ | 430 | #define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ |
@@ -359,64 +446,81 @@ static int nfs4_stat_to_errno(int); | |||
359 | decode_putrootfh_maxsz + \ | 446 | decode_putrootfh_maxsz + \ |
360 | decode_fsinfo_maxsz) | 447 | decode_fsinfo_maxsz) |
361 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ | 448 | #define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ |
449 | encode_sequence_maxsz + \ | ||
362 | encode_putfh_maxsz + \ | 450 | encode_putfh_maxsz + \ |
363 | encode_lock_maxsz) | 451 | encode_lock_maxsz) |
364 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ | 452 | #define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ |
453 | decode_sequence_maxsz + \ | ||
365 | decode_putfh_maxsz + \ | 454 | decode_putfh_maxsz + \ |
366 | decode_lock_maxsz) | 455 | decode_lock_maxsz) |
367 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ | 456 | #define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ |
457 | encode_sequence_maxsz + \ | ||
368 | encode_putfh_maxsz + \ | 458 | encode_putfh_maxsz + \ |
369 | encode_lockt_maxsz) | 459 | encode_lockt_maxsz) |
370 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ | 460 | #define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \ |
461 | decode_sequence_maxsz + \ | ||
371 | decode_putfh_maxsz + \ | 462 | decode_putfh_maxsz + \ |
372 | decode_lockt_maxsz) | 463 | decode_lockt_maxsz) |
373 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ | 464 | #define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ |
465 | encode_sequence_maxsz + \ | ||
374 | encode_putfh_maxsz + \ | 466 | encode_putfh_maxsz + \ |
375 | encode_locku_maxsz) | 467 | encode_locku_maxsz) |
376 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ | 468 | #define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ |
469 | decode_sequence_maxsz + \ | ||
377 | decode_putfh_maxsz + \ | 470 | decode_putfh_maxsz + \ |
378 | decode_locku_maxsz) | 471 | decode_locku_maxsz) |
379 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ | 472 | #define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \ |
473 | encode_sequence_maxsz + \ | ||
380 | encode_putfh_maxsz + \ | 474 | encode_putfh_maxsz + \ |
381 | encode_access_maxsz + \ | 475 | encode_access_maxsz + \ |
382 | encode_getattr_maxsz) | 476 | encode_getattr_maxsz) |
383 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ | 477 | #define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \ |
478 | decode_sequence_maxsz + \ | ||
384 | decode_putfh_maxsz + \ | 479 | decode_putfh_maxsz + \ |
385 | decode_access_maxsz + \ | 480 | decode_access_maxsz + \ |
386 | decode_getattr_maxsz) | 481 | decode_getattr_maxsz) |
387 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ | 482 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
483 | encode_sequence_maxsz + \ | ||
388 | encode_putfh_maxsz + \ | 484 | encode_putfh_maxsz + \ |
389 | encode_getattr_maxsz) | 485 | encode_getattr_maxsz) |
390 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ | 486 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
487 | decode_sequence_maxsz + \ | ||
391 | decode_putfh_maxsz + \ | 488 | decode_putfh_maxsz + \ |
392 | decode_getattr_maxsz) | 489 | decode_getattr_maxsz) |
393 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ | 490 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
491 | encode_sequence_maxsz + \ | ||
394 | encode_putfh_maxsz + \ | 492 | encode_putfh_maxsz + \ |
395 | encode_lookup_maxsz + \ | 493 | encode_lookup_maxsz + \ |
396 | encode_getattr_maxsz + \ | 494 | encode_getattr_maxsz + \ |
397 | encode_getfh_maxsz) | 495 | encode_getfh_maxsz) |
398 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ | 496 | #define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \ |
497 | decode_sequence_maxsz + \ | ||
399 | decode_putfh_maxsz + \ | 498 | decode_putfh_maxsz + \ |
400 | decode_lookup_maxsz + \ | 499 | decode_lookup_maxsz + \ |
401 | decode_getattr_maxsz + \ | 500 | decode_getattr_maxsz + \ |
402 | decode_getfh_maxsz) | 501 | decode_getfh_maxsz) |
403 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ | 502 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ |
503 | encode_sequence_maxsz + \ | ||
404 | encode_putrootfh_maxsz + \ | 504 | encode_putrootfh_maxsz + \ |
405 | encode_getattr_maxsz + \ | 505 | encode_getattr_maxsz + \ |
406 | encode_getfh_maxsz) | 506 | encode_getfh_maxsz) |
407 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ | 507 | #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \ |
508 | decode_sequence_maxsz + \ | ||
408 | decode_putrootfh_maxsz + \ | 509 | decode_putrootfh_maxsz + \ |
409 | decode_getattr_maxsz + \ | 510 | decode_getattr_maxsz + \ |
410 | decode_getfh_maxsz) | 511 | decode_getfh_maxsz) |
411 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ | 512 | #define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \ |
513 | encode_sequence_maxsz + \ | ||
412 | encode_putfh_maxsz + \ | 514 | encode_putfh_maxsz + \ |
413 | encode_remove_maxsz + \ | 515 | encode_remove_maxsz + \ |
414 | encode_getattr_maxsz) | 516 | encode_getattr_maxsz) |
415 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ | 517 | #define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \ |
518 | decode_sequence_maxsz + \ | ||
416 | decode_putfh_maxsz + \ | 519 | decode_putfh_maxsz + \ |
417 | op_decode_hdr_maxsz + 5 + \ | 520 | decode_remove_maxsz + \ |
418 | decode_getattr_maxsz) | 521 | decode_getattr_maxsz) |
419 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ | 522 | #define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \ |
523 | encode_sequence_maxsz + \ | ||
420 | encode_putfh_maxsz + \ | 524 | encode_putfh_maxsz + \ |
421 | encode_savefh_maxsz + \ | 525 | encode_savefh_maxsz + \ |
422 | encode_putfh_maxsz + \ | 526 | encode_putfh_maxsz + \ |
@@ -425,6 +529,7 @@ static int nfs4_stat_to_errno(int); | |||
425 | encode_restorefh_maxsz + \ | 529 | encode_restorefh_maxsz + \ |
426 | encode_getattr_maxsz) | 530 | encode_getattr_maxsz) |
427 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ | 531 | #define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \ |
532 | decode_sequence_maxsz + \ | ||
428 | decode_putfh_maxsz + \ | 533 | decode_putfh_maxsz + \ |
429 | decode_savefh_maxsz + \ | 534 | decode_savefh_maxsz + \ |
430 | decode_putfh_maxsz + \ | 535 | decode_putfh_maxsz + \ |
@@ -433,6 +538,7 @@ static int nfs4_stat_to_errno(int); | |||
433 | decode_restorefh_maxsz + \ | 538 | decode_restorefh_maxsz + \ |
434 | decode_getattr_maxsz) | 539 | decode_getattr_maxsz) |
435 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ | 540 | #define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \ |
541 | encode_sequence_maxsz + \ | ||
436 | encode_putfh_maxsz + \ | 542 | encode_putfh_maxsz + \ |
437 | encode_savefh_maxsz + \ | 543 | encode_savefh_maxsz + \ |
438 | encode_putfh_maxsz + \ | 544 | encode_putfh_maxsz + \ |
@@ -441,6 +547,7 @@ static int nfs4_stat_to_errno(int); | |||
441 | encode_restorefh_maxsz + \ | 547 | encode_restorefh_maxsz + \ |
442 | decode_getattr_maxsz) | 548 | decode_getattr_maxsz) |
443 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ | 549 | #define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \ |
550 | decode_sequence_maxsz + \ | ||
444 | decode_putfh_maxsz + \ | 551 | decode_putfh_maxsz + \ |
445 | decode_savefh_maxsz + \ | 552 | decode_savefh_maxsz + \ |
446 | decode_putfh_maxsz + \ | 553 | decode_putfh_maxsz + \ |
@@ -449,16 +556,19 @@ static int nfs4_stat_to_errno(int); | |||
449 | decode_restorefh_maxsz + \ | 556 | decode_restorefh_maxsz + \ |
450 | decode_getattr_maxsz) | 557 | decode_getattr_maxsz) |
451 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ | 558 | #define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \ |
559 | encode_sequence_maxsz + \ | ||
452 | encode_putfh_maxsz + \ | 560 | encode_putfh_maxsz + \ |
453 | encode_symlink_maxsz + \ | 561 | encode_symlink_maxsz + \ |
454 | encode_getattr_maxsz + \ | 562 | encode_getattr_maxsz + \ |
455 | encode_getfh_maxsz) | 563 | encode_getfh_maxsz) |
456 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ | 564 | #define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \ |
565 | decode_sequence_maxsz + \ | ||
457 | decode_putfh_maxsz + \ | 566 | decode_putfh_maxsz + \ |
458 | decode_symlink_maxsz + \ | 567 | decode_symlink_maxsz + \ |
459 | decode_getattr_maxsz + \ | 568 | decode_getattr_maxsz + \ |
460 | decode_getfh_maxsz) | 569 | decode_getfh_maxsz) |
461 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ | 570 | #define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \ |
571 | encode_sequence_maxsz + \ | ||
462 | encode_putfh_maxsz + \ | 572 | encode_putfh_maxsz + \ |
463 | encode_savefh_maxsz + \ | 573 | encode_savefh_maxsz + \ |
464 | encode_create_maxsz + \ | 574 | encode_create_maxsz + \ |
@@ -467,6 +577,7 @@ static int nfs4_stat_to_errno(int); | |||
467 | encode_restorefh_maxsz + \ | 577 | encode_restorefh_maxsz + \ |
468 | encode_getattr_maxsz) | 578 | encode_getattr_maxsz) |
469 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ | 579 | #define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \ |
580 | decode_sequence_maxsz + \ | ||
470 | decode_putfh_maxsz + \ | 581 | decode_putfh_maxsz + \ |
471 | decode_savefh_maxsz + \ | 582 | decode_savefh_maxsz + \ |
472 | decode_create_maxsz + \ | 583 | decode_create_maxsz + \ |
@@ -475,52 +586,98 @@ static int nfs4_stat_to_errno(int); | |||
475 | decode_restorefh_maxsz + \ | 586 | decode_restorefh_maxsz + \ |
476 | decode_getattr_maxsz) | 587 | decode_getattr_maxsz) |
477 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ | 588 | #define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \ |
589 | encode_sequence_maxsz + \ | ||
478 | encode_putfh_maxsz + \ | 590 | encode_putfh_maxsz + \ |
479 | encode_getattr_maxsz) | 591 | encode_getattr_maxsz) |
480 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ | 592 | #define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \ |
593 | decode_sequence_maxsz + \ | ||
481 | decode_putfh_maxsz + \ | 594 | decode_putfh_maxsz + \ |
482 | decode_getattr_maxsz) | 595 | decode_getattr_maxsz) |
483 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ | 596 | #define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \ |
597 | encode_sequence_maxsz + \ | ||
484 | encode_putfh_maxsz + \ | 598 | encode_putfh_maxsz + \ |
485 | encode_statfs_maxsz) | 599 | encode_statfs_maxsz) |
486 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ | 600 | #define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \ |
601 | decode_sequence_maxsz + \ | ||
487 | decode_putfh_maxsz + \ | 602 | decode_putfh_maxsz + \ |
488 | decode_statfs_maxsz) | 603 | decode_statfs_maxsz) |
489 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ | 604 | #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \ |
605 | encode_sequence_maxsz + \ | ||
490 | encode_putfh_maxsz + \ | 606 | encode_putfh_maxsz + \ |
491 | encode_getattr_maxsz) | 607 | encode_getattr_maxsz) |
492 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ | 608 | #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \ |
609 | decode_sequence_maxsz + \ | ||
493 | decode_putfh_maxsz + \ | 610 | decode_putfh_maxsz + \ |
494 | decode_getattr_maxsz) | 611 | decode_getattr_maxsz) |
495 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ | 612 | #define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \ |
613 | encode_sequence_maxsz + \ | ||
496 | encode_putfh_maxsz + \ | 614 | encode_putfh_maxsz + \ |
497 | encode_delegreturn_maxsz + \ | 615 | encode_delegreturn_maxsz + \ |
498 | encode_getattr_maxsz) | 616 | encode_getattr_maxsz) |
499 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ | 617 | #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \ |
618 | decode_sequence_maxsz + \ | ||
500 | decode_delegreturn_maxsz + \ | 619 | decode_delegreturn_maxsz + \ |
501 | decode_getattr_maxsz) | 620 | decode_getattr_maxsz) |
502 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ | 621 | #define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \ |
622 | encode_sequence_maxsz + \ | ||
503 | encode_putfh_maxsz + \ | 623 | encode_putfh_maxsz + \ |
504 | encode_getacl_maxsz) | 624 | encode_getacl_maxsz) |
505 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ | 625 | #define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \ |
626 | decode_sequence_maxsz + \ | ||
506 | decode_putfh_maxsz + \ | 627 | decode_putfh_maxsz + \ |
507 | decode_getacl_maxsz) | 628 | decode_getacl_maxsz) |
508 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ | 629 | #define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \ |
630 | encode_sequence_maxsz + \ | ||
509 | encode_putfh_maxsz + \ | 631 | encode_putfh_maxsz + \ |
510 | encode_setacl_maxsz) | 632 | encode_setacl_maxsz) |
511 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ | 633 | #define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \ |
634 | decode_sequence_maxsz + \ | ||
512 | decode_putfh_maxsz + \ | 635 | decode_putfh_maxsz + \ |
513 | decode_setacl_maxsz) | 636 | decode_setacl_maxsz) |
514 | #define NFS4_enc_fs_locations_sz \ | 637 | #define NFS4_enc_fs_locations_sz \ |
515 | (compound_encode_hdr_maxsz + \ | 638 | (compound_encode_hdr_maxsz + \ |
639 | encode_sequence_maxsz + \ | ||
516 | encode_putfh_maxsz + \ | 640 | encode_putfh_maxsz + \ |
517 | encode_lookup_maxsz + \ | 641 | encode_lookup_maxsz + \ |
518 | encode_fs_locations_maxsz) | 642 | encode_fs_locations_maxsz) |
519 | #define NFS4_dec_fs_locations_sz \ | 643 | #define NFS4_dec_fs_locations_sz \ |
520 | (compound_decode_hdr_maxsz + \ | 644 | (compound_decode_hdr_maxsz + \ |
645 | decode_sequence_maxsz + \ | ||
521 | decode_putfh_maxsz + \ | 646 | decode_putfh_maxsz + \ |
522 | decode_lookup_maxsz + \ | 647 | decode_lookup_maxsz + \ |
523 | decode_fs_locations_maxsz) | 648 | decode_fs_locations_maxsz) |
649 | #if defined(CONFIG_NFS_V4_1) | ||
650 | #define NFS4_enc_exchange_id_sz \ | ||
651 | (compound_encode_hdr_maxsz + \ | ||
652 | encode_exchange_id_maxsz) | ||
653 | #define NFS4_dec_exchange_id_sz \ | ||
654 | (compound_decode_hdr_maxsz + \ | ||
655 | decode_exchange_id_maxsz) | ||
656 | #define NFS4_enc_create_session_sz \ | ||
657 | (compound_encode_hdr_maxsz + \ | ||
658 | encode_create_session_maxsz) | ||
659 | #define NFS4_dec_create_session_sz \ | ||
660 | (compound_decode_hdr_maxsz + \ | ||
661 | decode_create_session_maxsz) | ||
662 | #define NFS4_enc_destroy_session_sz (compound_encode_hdr_maxsz + \ | ||
663 | encode_destroy_session_maxsz) | ||
664 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ | ||
665 | decode_destroy_session_maxsz) | ||
666 | #define NFS4_enc_sequence_sz \ | ||
667 | (compound_decode_hdr_maxsz + \ | ||
668 | encode_sequence_maxsz) | ||
669 | #define NFS4_dec_sequence_sz \ | ||
670 | (compound_decode_hdr_maxsz + \ | ||
671 | decode_sequence_maxsz) | ||
672 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ | ||
673 | encode_sequence_maxsz + \ | ||
674 | encode_putrootfh_maxsz + \ | ||
675 | encode_fsinfo_maxsz) | ||
676 | #define NFS4_dec_get_lease_time_sz (compound_decode_hdr_maxsz + \ | ||
677 | decode_sequence_maxsz + \ | ||
678 | decode_putrootfh_maxsz + \ | ||
679 | decode_fsinfo_maxsz) | ||
680 | #endif /* CONFIG_NFS_V4_1 */ | ||
524 | 681 | ||
525 | static const umode_t nfs_type2fmt[] = { | 682 | static const umode_t nfs_type2fmt[] = { |
526 | [NF4BAD] = 0, | 683 | [NF4BAD] = 0, |
@@ -541,6 +698,8 @@ struct compound_hdr { | |||
541 | __be32 * nops_p; | 698 | __be32 * nops_p; |
542 | uint32_t taglen; | 699 | uint32_t taglen; |
543 | char * tag; | 700 | char * tag; |
701 | uint32_t replen; /* expected reply words */ | ||
702 | u32 minorversion; | ||
544 | }; | 703 | }; |
545 | 704 | ||
546 | /* | 705 | /* |
@@ -576,22 +735,31 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char * | |||
576 | xdr_encode_opaque(p, str, len); | 735 | xdr_encode_opaque(p, str, len); |
577 | } | 736 | } |
578 | 737 | ||
579 | static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr) | 738 | static void encode_compound_hdr(struct xdr_stream *xdr, |
739 | struct rpc_rqst *req, | ||
740 | struct compound_hdr *hdr) | ||
580 | { | 741 | { |
581 | __be32 *p; | 742 | __be32 *p; |
743 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
744 | |||
745 | /* initialize running count of expected bytes in reply. | ||
746 | * NOTE: the replied tag SHOULD be the same is the one sent, | ||
747 | * but this is not required as a MUST for the server to do so. */ | ||
748 | hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen; | ||
582 | 749 | ||
583 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); | 750 | dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); |
584 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); | 751 | BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); |
585 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); | 752 | RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); |
586 | WRITE32(hdr->taglen); | 753 | WRITE32(hdr->taglen); |
587 | WRITEMEM(hdr->tag, hdr->taglen); | 754 | WRITEMEM(hdr->tag, hdr->taglen); |
588 | WRITE32(NFS4_MINOR_VERSION); | 755 | WRITE32(hdr->minorversion); |
589 | hdr->nops_p = p; | 756 | hdr->nops_p = p; |
590 | WRITE32(hdr->nops); | 757 | WRITE32(hdr->nops); |
591 | } | 758 | } |
592 | 759 | ||
593 | static void encode_nops(struct compound_hdr *hdr) | 760 | static void encode_nops(struct compound_hdr *hdr) |
594 | { | 761 | { |
762 | BUG_ON(hdr->nops > NFS4_MAX_OPS); | ||
595 | *hdr->nops_p = htonl(hdr->nops); | 763 | *hdr->nops_p = htonl(hdr->nops); |
596 | } | 764 | } |
597 | 765 | ||
@@ -736,6 +904,7 @@ static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hd | |||
736 | WRITE32(OP_ACCESS); | 904 | WRITE32(OP_ACCESS); |
737 | WRITE32(access); | 905 | WRITE32(access); |
738 | hdr->nops++; | 906 | hdr->nops++; |
907 | hdr->replen += decode_access_maxsz; | ||
739 | } | 908 | } |
740 | 909 | ||
741 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 910 | static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -747,6 +916,7 @@ static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg | |||
747 | WRITE32(arg->seqid->sequence->counter); | 916 | WRITE32(arg->seqid->sequence->counter); |
748 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 917 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
749 | hdr->nops++; | 918 | hdr->nops++; |
919 | hdr->replen += decode_close_maxsz; | ||
750 | } | 920 | } |
751 | 921 | ||
752 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 922 | static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -758,6 +928,7 @@ static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *ar | |||
758 | WRITE64(args->offset); | 928 | WRITE64(args->offset); |
759 | WRITE32(args->count); | 929 | WRITE32(args->count); |
760 | hdr->nops++; | 930 | hdr->nops++; |
931 | hdr->replen += decode_commit_maxsz; | ||
761 | } | 932 | } |
762 | 933 | ||
763 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) | 934 | static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr) |
@@ -789,6 +960,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * | |||
789 | WRITE32(create->name->len); | 960 | WRITE32(create->name->len); |
790 | WRITEMEM(create->name->name, create->name->len); | 961 | WRITEMEM(create->name->name, create->name->len); |
791 | hdr->nops++; | 962 | hdr->nops++; |
963 | hdr->replen += decode_create_maxsz; | ||
792 | 964 | ||
793 | encode_attrs(xdr, create->attrs, create->server); | 965 | encode_attrs(xdr, create->attrs, create->server); |
794 | } | 966 | } |
@@ -802,6 +974,7 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c | |||
802 | WRITE32(1); | 974 | WRITE32(1); |
803 | WRITE32(bitmap); | 975 | WRITE32(bitmap); |
804 | hdr->nops++; | 976 | hdr->nops++; |
977 | hdr->replen += decode_getattr_maxsz; | ||
805 | } | 978 | } |
806 | 979 | ||
807 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) | 980 | static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr) |
@@ -814,6 +987,7 @@ static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm | |||
814 | WRITE32(bm0); | 987 | WRITE32(bm0); |
815 | WRITE32(bm1); | 988 | WRITE32(bm1); |
816 | hdr->nops++; | 989 | hdr->nops++; |
990 | hdr->replen += decode_getattr_maxsz; | ||
817 | } | 991 | } |
818 | 992 | ||
819 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) | 993 | static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr) |
@@ -841,6 +1015,7 @@ static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
841 | RESERVE_SPACE(4); | 1015 | RESERVE_SPACE(4); |
842 | WRITE32(OP_GETFH); | 1016 | WRITE32(OP_GETFH); |
843 | hdr->nops++; | 1017 | hdr->nops++; |
1018 | hdr->replen += decode_getfh_maxsz; | ||
844 | } | 1019 | } |
845 | 1020 | ||
846 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1021 | static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -852,6 +1027,7 @@ static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct | |||
852 | WRITE32(name->len); | 1027 | WRITE32(name->len); |
853 | WRITEMEM(name->name, name->len); | 1028 | WRITEMEM(name->name, name->len); |
854 | hdr->nops++; | 1029 | hdr->nops++; |
1030 | hdr->replen += decode_link_maxsz; | ||
855 | } | 1031 | } |
856 | 1032 | ||
857 | static inline int nfs4_lock_type(struct file_lock *fl, int block) | 1033 | static inline int nfs4_lock_type(struct file_lock *fl, int block) |
@@ -899,6 +1075,7 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args | |||
899 | WRITE32(args->lock_seqid->sequence->counter); | 1075 | WRITE32(args->lock_seqid->sequence->counter); |
900 | } | 1076 | } |
901 | hdr->nops++; | 1077 | hdr->nops++; |
1078 | hdr->replen += decode_lock_maxsz; | ||
902 | } | 1079 | } |
903 | 1080 | ||
904 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) | 1081 | static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr) |
@@ -915,6 +1092,7 @@ static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *ar | |||
915 | WRITEMEM("lock id:", 8); | 1092 | WRITEMEM("lock id:", 8); |
916 | WRITE64(args->lock_owner.id); | 1093 | WRITE64(args->lock_owner.id); |
917 | hdr->nops++; | 1094 | hdr->nops++; |
1095 | hdr->replen += decode_lockt_maxsz; | ||
918 | } | 1096 | } |
919 | 1097 | ||
920 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) | 1098 | static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr) |
@@ -929,6 +1107,7 @@ static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *ar | |||
929 | WRITE64(args->fl->fl_start); | 1107 | WRITE64(args->fl->fl_start); |
930 | WRITE64(nfs4_lock_length(args->fl)); | 1108 | WRITE64(nfs4_lock_length(args->fl)); |
931 | hdr->nops++; | 1109 | hdr->nops++; |
1110 | hdr->replen += decode_locku_maxsz; | ||
932 | } | 1111 | } |
933 | 1112 | ||
934 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1113 | static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -941,6 +1120,7 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc | |||
941 | WRITE32(len); | 1120 | WRITE32(len); |
942 | WRITEMEM(name->name, len); | 1121 | WRITEMEM(name->name, len); |
943 | hdr->nops++; | 1122 | hdr->nops++; |
1123 | hdr->replen += decode_lookup_maxsz; | ||
944 | } | 1124 | } |
945 | 1125 | ||
946 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) | 1126 | static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode) |
@@ -1080,6 +1260,7 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, | |||
1080 | BUG(); | 1260 | BUG(); |
1081 | } | 1261 | } |
1082 | hdr->nops++; | 1262 | hdr->nops++; |
1263 | hdr->replen += decode_open_maxsz; | ||
1083 | } | 1264 | } |
1084 | 1265 | ||
1085 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) | 1266 | static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr) |
@@ -1091,6 +1272,7 @@ static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_co | |||
1091 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); | 1272 | WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE); |
1092 | WRITE32(arg->seqid->sequence->counter); | 1273 | WRITE32(arg->seqid->sequence->counter); |
1093 | hdr->nops++; | 1274 | hdr->nops++; |
1275 | hdr->replen += decode_open_confirm_maxsz; | ||
1094 | } | 1276 | } |
1095 | 1277 | ||
1096 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) | 1278 | static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr) |
@@ -1103,6 +1285,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close | |||
1103 | WRITE32(arg->seqid->sequence->counter); | 1285 | WRITE32(arg->seqid->sequence->counter); |
1104 | encode_share_access(xdr, arg->fmode); | 1286 | encode_share_access(xdr, arg->fmode); |
1105 | hdr->nops++; | 1287 | hdr->nops++; |
1288 | hdr->replen += decode_open_downgrade_maxsz; | ||
1106 | } | 1289 | } |
1107 | 1290 | ||
1108 | static void | 1291 | static void |
@@ -1116,6 +1299,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hd | |||
1116 | WRITE32(len); | 1299 | WRITE32(len); |
1117 | WRITEMEM(fh->data, len); | 1300 | WRITEMEM(fh->data, len); |
1118 | hdr->nops++; | 1301 | hdr->nops++; |
1302 | hdr->replen += decode_putfh_maxsz; | ||
1119 | } | 1303 | } |
1120 | 1304 | ||
1121 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | 1305 | static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) |
@@ -1125,6 +1309,7 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1125 | RESERVE_SPACE(4); | 1309 | RESERVE_SPACE(4); |
1126 | WRITE32(OP_PUTROOTFH); | 1310 | WRITE32(OP_PUTROOTFH); |
1127 | hdr->nops++; | 1311 | hdr->nops++; |
1312 | hdr->replen += decode_putrootfh_maxsz; | ||
1128 | } | 1313 | } |
1129 | 1314 | ||
1130 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) | 1315 | static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx) |
@@ -1153,6 +1338,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, | |||
1153 | WRITE64(args->offset); | 1338 | WRITE64(args->offset); |
1154 | WRITE32(args->count); | 1339 | WRITE32(args->count); |
1155 | hdr->nops++; | 1340 | hdr->nops++; |
1341 | hdr->replen += decode_read_maxsz; | ||
1156 | } | 1342 | } |
1157 | 1343 | ||
1158 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) | 1344 | static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr) |
@@ -1178,6 +1364,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg | |||
1178 | WRITE32(attrs[0] & readdir->bitmask[0]); | 1364 | WRITE32(attrs[0] & readdir->bitmask[0]); |
1179 | WRITE32(attrs[1] & readdir->bitmask[1]); | 1365 | WRITE32(attrs[1] & readdir->bitmask[1]); |
1180 | hdr->nops++; | 1366 | hdr->nops++; |
1367 | hdr->replen += decode_readdir_maxsz; | ||
1181 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", | 1368 | dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n", |
1182 | __func__, | 1369 | __func__, |
1183 | (unsigned long long)readdir->cookie, | 1370 | (unsigned long long)readdir->cookie, |
@@ -1194,6 +1381,7 @@ static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink * | |||
1194 | RESERVE_SPACE(4); | 1381 | RESERVE_SPACE(4); |
1195 | WRITE32(OP_READLINK); | 1382 | WRITE32(OP_READLINK); |
1196 | hdr->nops++; | 1383 | hdr->nops++; |
1384 | hdr->replen += decode_readlink_maxsz; | ||
1197 | } | 1385 | } |
1198 | 1386 | ||
1199 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) | 1387 | static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr) |
@@ -1205,6 +1393,7 @@ static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struc | |||
1205 | WRITE32(name->len); | 1393 | WRITE32(name->len); |
1206 | WRITEMEM(name->name, name->len); | 1394 | WRITEMEM(name->name, name->len); |
1207 | hdr->nops++; | 1395 | hdr->nops++; |
1396 | hdr->replen += decode_remove_maxsz; | ||
1208 | } | 1397 | } |
1209 | 1398 | ||
1210 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) | 1399 | static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr) |
@@ -1220,6 +1409,7 @@ static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, co | |||
1220 | WRITE32(newname->len); | 1409 | WRITE32(newname->len); |
1221 | WRITEMEM(newname->name, newname->len); | 1410 | WRITEMEM(newname->name, newname->len); |
1222 | hdr->nops++; | 1411 | hdr->nops++; |
1412 | hdr->replen += decode_rename_maxsz; | ||
1223 | } | 1413 | } |
1224 | 1414 | ||
1225 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) | 1415 | static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr) |
@@ -1230,6 +1420,7 @@ static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client | |||
1230 | WRITE32(OP_RENEW); | 1420 | WRITE32(OP_RENEW); |
1231 | WRITE64(client_stateid->cl_clientid); | 1421 | WRITE64(client_stateid->cl_clientid); |
1232 | hdr->nops++; | 1422 | hdr->nops++; |
1423 | hdr->replen += decode_renew_maxsz; | ||
1233 | } | 1424 | } |
1234 | 1425 | ||
1235 | static void | 1426 | static void |
@@ -1240,6 +1431,7 @@ encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1240 | RESERVE_SPACE(4); | 1431 | RESERVE_SPACE(4); |
1241 | WRITE32(OP_RESTOREFH); | 1432 | WRITE32(OP_RESTOREFH); |
1242 | hdr->nops++; | 1433 | hdr->nops++; |
1434 | hdr->replen += decode_restorefh_maxsz; | ||
1243 | } | 1435 | } |
1244 | 1436 | ||
1245 | static int | 1437 | static int |
@@ -1259,6 +1451,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun | |||
1259 | WRITE32(arg->acl_len); | 1451 | WRITE32(arg->acl_len); |
1260 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); | 1452 | xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len); |
1261 | hdr->nops++; | 1453 | hdr->nops++; |
1454 | hdr->replen += decode_setacl_maxsz; | ||
1262 | return 0; | 1455 | return 0; |
1263 | } | 1456 | } |
1264 | 1457 | ||
@@ -1270,6 +1463,7 @@ encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr) | |||
1270 | RESERVE_SPACE(4); | 1463 | RESERVE_SPACE(4); |
1271 | WRITE32(OP_SAVEFH); | 1464 | WRITE32(OP_SAVEFH); |
1272 | hdr->nops++; | 1465 | hdr->nops++; |
1466 | hdr->replen += decode_savefh_maxsz; | ||
1273 | } | 1467 | } |
1274 | 1468 | ||
1275 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) | 1469 | static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr) |
@@ -1280,6 +1474,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs | |||
1280 | WRITE32(OP_SETATTR); | 1474 | WRITE32(OP_SETATTR); |
1281 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); | 1475 | WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE); |
1282 | hdr->nops++; | 1476 | hdr->nops++; |
1477 | hdr->replen += decode_setattr_maxsz; | ||
1283 | encode_attrs(xdr, arg->iap, server); | 1478 | encode_attrs(xdr, arg->iap, server); |
1284 | } | 1479 | } |
1285 | 1480 | ||
@@ -1299,6 +1494,7 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie | |||
1299 | RESERVE_SPACE(4); | 1494 | RESERVE_SPACE(4); |
1300 | WRITE32(setclientid->sc_cb_ident); | 1495 | WRITE32(setclientid->sc_cb_ident); |
1301 | hdr->nops++; | 1496 | hdr->nops++; |
1497 | hdr->replen += decode_setclientid_maxsz; | ||
1302 | } | 1498 | } |
1303 | 1499 | ||
1304 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) | 1500 | static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr) |
@@ -1310,6 +1506,7 @@ static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_ | |||
1310 | WRITE64(client_state->cl_clientid); | 1506 | WRITE64(client_state->cl_clientid); |
1311 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); | 1507 | WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE); |
1312 | hdr->nops++; | 1508 | hdr->nops++; |
1509 | hdr->replen += decode_setclientid_confirm_maxsz; | ||
1313 | } | 1510 | } |
1314 | 1511 | ||
1315 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) | 1512 | static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr) |
@@ -1328,6 +1525,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg | |||
1328 | 1525 | ||
1329 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); | 1526 | xdr_write_pages(xdr, args->pages, args->pgbase, args->count); |
1330 | hdr->nops++; | 1527 | hdr->nops++; |
1528 | hdr->replen += decode_write_maxsz; | ||
1331 | } | 1529 | } |
1332 | 1530 | ||
1333 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) | 1531 | static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr) |
@@ -1339,11 +1537,163 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1339 | WRITE32(OP_DELEGRETURN); | 1537 | WRITE32(OP_DELEGRETURN); |
1340 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); | 1538 | WRITEMEM(stateid->data, NFS4_STATEID_SIZE); |
1341 | hdr->nops++; | 1539 | hdr->nops++; |
1540 | hdr->replen += decode_delegreturn_maxsz; | ||
1541 | } | ||
1542 | |||
1543 | #if defined(CONFIG_NFS_V4_1) | ||
1544 | /* NFSv4.1 operations */ | ||
1545 | static void encode_exchange_id(struct xdr_stream *xdr, | ||
1546 | struct nfs41_exchange_id_args *args, | ||
1547 | struct compound_hdr *hdr) | ||
1548 | { | ||
1549 | __be32 *p; | ||
1550 | |||
1551 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | ||
1552 | WRITE32(OP_EXCHANGE_ID); | ||
1553 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | ||
1554 | |||
1555 | encode_string(xdr, args->id_len, args->id); | ||
1556 | |||
1557 | RESERVE_SPACE(12); | ||
1558 | WRITE32(args->flags); | ||
1559 | WRITE32(0); /* zero length state_protect4_a */ | ||
1560 | WRITE32(0); /* zero length implementation id array */ | ||
1561 | hdr->nops++; | ||
1562 | hdr->replen += decode_exchange_id_maxsz; | ||
1563 | } | ||
1564 | |||
1565 | static void encode_create_session(struct xdr_stream *xdr, | ||
1566 | struct nfs41_create_session_args *args, | ||
1567 | struct compound_hdr *hdr) | ||
1568 | { | ||
1569 | __be32 *p; | ||
1570 | char machine_name[NFS4_MAX_MACHINE_NAME_LEN]; | ||
1571 | uint32_t len; | ||
1572 | struct nfs_client *clp = args->client; | ||
1573 | |||
1574 | RESERVE_SPACE(4); | ||
1575 | WRITE32(OP_CREATE_SESSION); | ||
1576 | |||
1577 | RESERVE_SPACE(8); | ||
1578 | WRITE64(clp->cl_ex_clid); | ||
1579 | |||
1580 | RESERVE_SPACE(8); | ||
1581 | WRITE32(clp->cl_seqid); /*Sequence id */ | ||
1582 | WRITE32(args->flags); /*flags */ | ||
1583 | |||
1584 | RESERVE_SPACE(2*28); /* 2 channel_attrs */ | ||
1585 | /* Fore Channel */ | ||
1586 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1587 | WRITE32(args->fc_attrs.max_rqst_sz); /* max req size */ | ||
1588 | WRITE32(args->fc_attrs.max_resp_sz); /* max resp size */ | ||
1589 | WRITE32(args->fc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1590 | WRITE32(args->fc_attrs.max_ops); /* max operations */ | ||
1591 | WRITE32(args->fc_attrs.max_reqs); /* max requests */ | ||
1592 | WRITE32(0); /* rdmachannel_attrs */ | ||
1593 | |||
1594 | /* Back Channel */ | ||
1595 | WRITE32(args->fc_attrs.headerpadsz); /* header padding size */ | ||
1596 | WRITE32(args->bc_attrs.max_rqst_sz); /* max req size */ | ||
1597 | WRITE32(args->bc_attrs.max_resp_sz); /* max resp size */ | ||
1598 | WRITE32(args->bc_attrs.max_resp_sz_cached); /* Max resp sz cached */ | ||
1599 | WRITE32(args->bc_attrs.max_ops); /* max operations */ | ||
1600 | WRITE32(args->bc_attrs.max_reqs); /* max requests */ | ||
1601 | WRITE32(0); /* rdmachannel_attrs */ | ||
1602 | |||
1603 | RESERVE_SPACE(4); | ||
1604 | WRITE32(args->cb_program); /* cb_program */ | ||
1605 | |||
1606 | RESERVE_SPACE(4); /* # of security flavors */ | ||
1607 | WRITE32(1); | ||
1608 | |||
1609 | RESERVE_SPACE(4); | ||
1610 | WRITE32(RPC_AUTH_UNIX); /* auth_sys */ | ||
1611 | |||
1612 | /* authsys_parms rfc1831 */ | ||
1613 | RESERVE_SPACE(4); | ||
1614 | WRITE32((u32)clp->cl_boot_time.tv_nsec); /* stamp */ | ||
1615 | len = scnprintf(machine_name, sizeof(machine_name), "%s", | ||
1616 | clp->cl_ipaddr); | ||
1617 | RESERVE_SPACE(16 + len); | ||
1618 | WRITE32(len); | ||
1619 | WRITEMEM(machine_name, len); | ||
1620 | WRITE32(0); /* UID */ | ||
1621 | WRITE32(0); /* GID */ | ||
1622 | WRITE32(0); /* No more gids */ | ||
1623 | hdr->nops++; | ||
1624 | hdr->replen += decode_create_session_maxsz; | ||
1625 | } | ||
1626 | |||
1627 | static void encode_destroy_session(struct xdr_stream *xdr, | ||
1628 | struct nfs4_session *session, | ||
1629 | struct compound_hdr *hdr) | ||
1630 | { | ||
1631 | __be32 *p; | ||
1632 | RESERVE_SPACE(4 + NFS4_MAX_SESSIONID_LEN); | ||
1633 | WRITE32(OP_DESTROY_SESSION); | ||
1634 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1635 | hdr->nops++; | ||
1636 | hdr->replen += decode_destroy_session_maxsz; | ||
1342 | } | 1637 | } |
1638 | #endif /* CONFIG_NFS_V4_1 */ | ||
1639 | |||
1640 | static void encode_sequence(struct xdr_stream *xdr, | ||
1641 | const struct nfs4_sequence_args *args, | ||
1642 | struct compound_hdr *hdr) | ||
1643 | { | ||
1644 | #if defined(CONFIG_NFS_V4_1) | ||
1645 | struct nfs4_session *session = args->sa_session; | ||
1646 | struct nfs4_slot_table *tp; | ||
1647 | struct nfs4_slot *slot; | ||
1648 | __be32 *p; | ||
1649 | |||
1650 | if (!session) | ||
1651 | return; | ||
1652 | |||
1653 | tp = &session->fc_slot_table; | ||
1654 | |||
1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | ||
1656 | slot = tp->slots + args->sa_slotid; | ||
1657 | |||
1658 | RESERVE_SPACE(4); | ||
1659 | WRITE32(OP_SEQUENCE); | ||
1660 | |||
1661 | /* | ||
1662 | * Sessionid + seqid + slotid + max slotid + cache_this | ||
1663 | */ | ||
1664 | dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d " | ||
1665 | "max_slotid=%d cache_this=%d\n", | ||
1666 | __func__, | ||
1667 | ((u32 *)session->sess_id.data)[0], | ||
1668 | ((u32 *)session->sess_id.data)[1], | ||
1669 | ((u32 *)session->sess_id.data)[2], | ||
1670 | ((u32 *)session->sess_id.data)[3], | ||
1671 | slot->seq_nr, args->sa_slotid, | ||
1672 | tp->highest_used_slotid, args->sa_cache_this); | ||
1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | ||
1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1675 | WRITE32(slot->seq_nr); | ||
1676 | WRITE32(args->sa_slotid); | ||
1677 | WRITE32(tp->highest_used_slotid); | ||
1678 | WRITE32(args->sa_cache_this); | ||
1679 | hdr->nops++; | ||
1680 | hdr->replen += decode_sequence_maxsz; | ||
1681 | #endif /* CONFIG_NFS_V4_1 */ | ||
1682 | } | ||
1683 | |||
1343 | /* | 1684 | /* |
1344 | * END OF "GENERIC" ENCODE ROUTINES. | 1685 | * END OF "GENERIC" ENCODE ROUTINES. |
1345 | */ | 1686 | */ |
1346 | 1687 | ||
1688 | static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args) | ||
1689 | { | ||
1690 | #if defined(CONFIG_NFS_V4_1) | ||
1691 | if (args->sa_session) | ||
1692 | return args->sa_session->clp->cl_minorversion; | ||
1693 | #endif /* CONFIG_NFS_V4_1 */ | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1347 | /* | 1697 | /* |
1348 | * Encode an ACCESS request | 1698 | * Encode an ACCESS request |
1349 | */ | 1699 | */ |
@@ -1351,11 +1701,12 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1351 | { | 1701 | { |
1352 | struct xdr_stream xdr; | 1702 | struct xdr_stream xdr; |
1353 | struct compound_hdr hdr = { | 1703 | struct compound_hdr hdr = { |
1354 | .nops = 0, | 1704 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1355 | }; | 1705 | }; |
1356 | 1706 | ||
1357 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1707 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1358 | encode_compound_hdr(&xdr, &hdr); | 1708 | encode_compound_hdr(&xdr, req, &hdr); |
1709 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1359 | encode_putfh(&xdr, args->fh, &hdr); | 1710 | encode_putfh(&xdr, args->fh, &hdr); |
1360 | encode_access(&xdr, args->access, &hdr); | 1711 | encode_access(&xdr, args->access, &hdr); |
1361 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1712 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1370,11 +1721,12 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1370 | { | 1721 | { |
1371 | struct xdr_stream xdr; | 1722 | struct xdr_stream xdr; |
1372 | struct compound_hdr hdr = { | 1723 | struct compound_hdr hdr = { |
1373 | .nops = 0, | 1724 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1374 | }; | 1725 | }; |
1375 | 1726 | ||
1376 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1727 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1377 | encode_compound_hdr(&xdr, &hdr); | 1728 | encode_compound_hdr(&xdr, req, &hdr); |
1729 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1378 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1730 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1379 | encode_lookup(&xdr, args->name, &hdr); | 1731 | encode_lookup(&xdr, args->name, &hdr); |
1380 | encode_getfh(&xdr, &hdr); | 1732 | encode_getfh(&xdr, &hdr); |
@@ -1390,11 +1742,12 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc | |||
1390 | { | 1742 | { |
1391 | struct xdr_stream xdr; | 1743 | struct xdr_stream xdr; |
1392 | struct compound_hdr hdr = { | 1744 | struct compound_hdr hdr = { |
1393 | .nops = 0, | 1745 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1394 | }; | 1746 | }; |
1395 | 1747 | ||
1396 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1748 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1397 | encode_compound_hdr(&xdr, &hdr); | 1749 | encode_compound_hdr(&xdr, req, &hdr); |
1750 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1398 | encode_putrootfh(&xdr, &hdr); | 1751 | encode_putrootfh(&xdr, &hdr); |
1399 | encode_getfh(&xdr, &hdr); | 1752 | encode_getfh(&xdr, &hdr); |
1400 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1753 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1409,11 +1762,12 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1409 | { | 1762 | { |
1410 | struct xdr_stream xdr; | 1763 | struct xdr_stream xdr; |
1411 | struct compound_hdr hdr = { | 1764 | struct compound_hdr hdr = { |
1412 | .nops = 0, | 1765 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1413 | }; | 1766 | }; |
1414 | 1767 | ||
1415 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1768 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1416 | encode_compound_hdr(&xdr, &hdr); | 1769 | encode_compound_hdr(&xdr, req, &hdr); |
1770 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1417 | encode_putfh(&xdr, args->fh, &hdr); | 1771 | encode_putfh(&xdr, args->fh, &hdr); |
1418 | encode_remove(&xdr, &args->name, &hdr); | 1772 | encode_remove(&xdr, &args->name, &hdr); |
1419 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1773 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1428,11 +1782,12 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1428 | { | 1782 | { |
1429 | struct xdr_stream xdr; | 1783 | struct xdr_stream xdr; |
1430 | struct compound_hdr hdr = { | 1784 | struct compound_hdr hdr = { |
1431 | .nops = 0, | 1785 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1432 | }; | 1786 | }; |
1433 | 1787 | ||
1434 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1788 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1435 | encode_compound_hdr(&xdr, &hdr); | 1789 | encode_compound_hdr(&xdr, req, &hdr); |
1790 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1436 | encode_putfh(&xdr, args->old_dir, &hdr); | 1791 | encode_putfh(&xdr, args->old_dir, &hdr); |
1437 | encode_savefh(&xdr, &hdr); | 1792 | encode_savefh(&xdr, &hdr); |
1438 | encode_putfh(&xdr, args->new_dir, &hdr); | 1793 | encode_putfh(&xdr, args->new_dir, &hdr); |
@@ -1451,11 +1806,12 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_ | |||
1451 | { | 1806 | { |
1452 | struct xdr_stream xdr; | 1807 | struct xdr_stream xdr; |
1453 | struct compound_hdr hdr = { | 1808 | struct compound_hdr hdr = { |
1454 | .nops = 0, | 1809 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1455 | }; | 1810 | }; |
1456 | 1811 | ||
1457 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1812 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1458 | encode_compound_hdr(&xdr, &hdr); | 1813 | encode_compound_hdr(&xdr, req, &hdr); |
1814 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1459 | encode_putfh(&xdr, args->fh, &hdr); | 1815 | encode_putfh(&xdr, args->fh, &hdr); |
1460 | encode_savefh(&xdr, &hdr); | 1816 | encode_savefh(&xdr, &hdr); |
1461 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1817 | encode_putfh(&xdr, args->dir_fh, &hdr); |
@@ -1474,11 +1830,12 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1474 | { | 1830 | { |
1475 | struct xdr_stream xdr; | 1831 | struct xdr_stream xdr; |
1476 | struct compound_hdr hdr = { | 1832 | struct compound_hdr hdr = { |
1477 | .nops = 0, | 1833 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1478 | }; | 1834 | }; |
1479 | 1835 | ||
1480 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1836 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1481 | encode_compound_hdr(&xdr, &hdr); | 1837 | encode_compound_hdr(&xdr, req, &hdr); |
1838 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1482 | encode_putfh(&xdr, args->dir_fh, &hdr); | 1839 | encode_putfh(&xdr, args->dir_fh, &hdr); |
1483 | encode_savefh(&xdr, &hdr); | 1840 | encode_savefh(&xdr, &hdr); |
1484 | encode_create(&xdr, args, &hdr); | 1841 | encode_create(&xdr, args, &hdr); |
@@ -1505,11 +1862,12 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1505 | { | 1862 | { |
1506 | struct xdr_stream xdr; | 1863 | struct xdr_stream xdr; |
1507 | struct compound_hdr hdr = { | 1864 | struct compound_hdr hdr = { |
1508 | .nops = 0, | 1865 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1509 | }; | 1866 | }; |
1510 | 1867 | ||
1511 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1868 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1512 | encode_compound_hdr(&xdr, &hdr); | 1869 | encode_compound_hdr(&xdr, req, &hdr); |
1870 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1513 | encode_putfh(&xdr, args->fh, &hdr); | 1871 | encode_putfh(&xdr, args->fh, &hdr); |
1514 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1872 | encode_getfattr(&xdr, args->bitmask, &hdr); |
1515 | encode_nops(&hdr); | 1873 | encode_nops(&hdr); |
@@ -1523,11 +1881,12 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea | |||
1523 | { | 1881 | { |
1524 | struct xdr_stream xdr; | 1882 | struct xdr_stream xdr; |
1525 | struct compound_hdr hdr = { | 1883 | struct compound_hdr hdr = { |
1526 | .nops = 0, | 1884 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1527 | }; | 1885 | }; |
1528 | 1886 | ||
1529 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1887 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1530 | encode_compound_hdr(&xdr, &hdr); | 1888 | encode_compound_hdr(&xdr, req, &hdr); |
1889 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1531 | encode_putfh(&xdr, args->fh, &hdr); | 1890 | encode_putfh(&xdr, args->fh, &hdr); |
1532 | encode_close(&xdr, args, &hdr); | 1891 | encode_close(&xdr, args, &hdr); |
1533 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1892 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1542,11 +1901,12 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg | |||
1542 | { | 1901 | { |
1543 | struct xdr_stream xdr; | 1902 | struct xdr_stream xdr; |
1544 | struct compound_hdr hdr = { | 1903 | struct compound_hdr hdr = { |
1545 | .nops = 0, | 1904 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1546 | }; | 1905 | }; |
1547 | 1906 | ||
1548 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1907 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1549 | encode_compound_hdr(&xdr, &hdr); | 1908 | encode_compound_hdr(&xdr, req, &hdr); |
1909 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1550 | encode_putfh(&xdr, args->fh, &hdr); | 1910 | encode_putfh(&xdr, args->fh, &hdr); |
1551 | encode_savefh(&xdr, &hdr); | 1911 | encode_savefh(&xdr, &hdr); |
1552 | encode_open(&xdr, args, &hdr); | 1912 | encode_open(&xdr, args, &hdr); |
@@ -1569,7 +1929,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1569 | }; | 1929 | }; |
1570 | 1930 | ||
1571 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1572 | encode_compound_hdr(&xdr, &hdr); | 1932 | encode_compound_hdr(&xdr, req, &hdr); |
1573 | encode_putfh(&xdr, args->fh, &hdr); | 1933 | encode_putfh(&xdr, args->fh, &hdr); |
1574 | encode_open_confirm(&xdr, args, &hdr); | 1934 | encode_open_confirm(&xdr, args, &hdr); |
1575 | encode_nops(&hdr); | 1935 | encode_nops(&hdr); |
@@ -1583,11 +1943,12 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_ | |||
1583 | { | 1943 | { |
1584 | struct xdr_stream xdr; | 1944 | struct xdr_stream xdr; |
1585 | struct compound_hdr hdr = { | 1945 | struct compound_hdr hdr = { |
1586 | .nops = 0, | 1946 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1587 | }; | 1947 | }; |
1588 | 1948 | ||
1589 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1949 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1590 | encode_compound_hdr(&xdr, &hdr); | 1950 | encode_compound_hdr(&xdr, req, &hdr); |
1951 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1591 | encode_putfh(&xdr, args->fh, &hdr); | 1952 | encode_putfh(&xdr, args->fh, &hdr); |
1592 | encode_open(&xdr, args, &hdr); | 1953 | encode_open(&xdr, args, &hdr); |
1593 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1954 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1602,11 +1963,12 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n | |||
1602 | { | 1963 | { |
1603 | struct xdr_stream xdr; | 1964 | struct xdr_stream xdr; |
1604 | struct compound_hdr hdr = { | 1965 | struct compound_hdr hdr = { |
1605 | .nops = 0, | 1966 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1606 | }; | 1967 | }; |
1607 | 1968 | ||
1608 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1969 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1609 | encode_compound_hdr(&xdr, &hdr); | 1970 | encode_compound_hdr(&xdr, req, &hdr); |
1971 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1610 | encode_putfh(&xdr, args->fh, &hdr); | 1972 | encode_putfh(&xdr, args->fh, &hdr); |
1611 | encode_open_downgrade(&xdr, args, &hdr); | 1973 | encode_open_downgrade(&xdr, args, &hdr); |
1612 | encode_getfattr(&xdr, args->bitmask, &hdr); | 1974 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1621,11 +1983,12 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar | |||
1621 | { | 1983 | { |
1622 | struct xdr_stream xdr; | 1984 | struct xdr_stream xdr; |
1623 | struct compound_hdr hdr = { | 1985 | struct compound_hdr hdr = { |
1624 | .nops = 0, | 1986 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1625 | }; | 1987 | }; |
1626 | 1988 | ||
1627 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 1989 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1628 | encode_compound_hdr(&xdr, &hdr); | 1990 | encode_compound_hdr(&xdr, req, &hdr); |
1991 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1629 | encode_putfh(&xdr, args->fh, &hdr); | 1992 | encode_putfh(&xdr, args->fh, &hdr); |
1630 | encode_lock(&xdr, args, &hdr); | 1993 | encode_lock(&xdr, args, &hdr); |
1631 | encode_nops(&hdr); | 1994 | encode_nops(&hdr); |
@@ -1639,11 +2002,12 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_ | |||
1639 | { | 2002 | { |
1640 | struct xdr_stream xdr; | 2003 | struct xdr_stream xdr; |
1641 | struct compound_hdr hdr = { | 2004 | struct compound_hdr hdr = { |
1642 | .nops = 0, | 2005 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1643 | }; | 2006 | }; |
1644 | 2007 | ||
1645 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2008 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1646 | encode_compound_hdr(&xdr, &hdr); | 2009 | encode_compound_hdr(&xdr, req, &hdr); |
2010 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1647 | encode_putfh(&xdr, args->fh, &hdr); | 2011 | encode_putfh(&xdr, args->fh, &hdr); |
1648 | encode_lockt(&xdr, args, &hdr); | 2012 | encode_lockt(&xdr, args, &hdr); |
1649 | encode_nops(&hdr); | 2013 | encode_nops(&hdr); |
@@ -1657,11 +2021,12 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_ | |||
1657 | { | 2021 | { |
1658 | struct xdr_stream xdr; | 2022 | struct xdr_stream xdr; |
1659 | struct compound_hdr hdr = { | 2023 | struct compound_hdr hdr = { |
1660 | .nops = 0, | 2024 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1661 | }; | 2025 | }; |
1662 | 2026 | ||
1663 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2027 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1664 | encode_compound_hdr(&xdr, &hdr); | 2028 | encode_compound_hdr(&xdr, req, &hdr); |
2029 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1665 | encode_putfh(&xdr, args->fh, &hdr); | 2030 | encode_putfh(&xdr, args->fh, &hdr); |
1666 | encode_locku(&xdr, args, &hdr); | 2031 | encode_locku(&xdr, args, &hdr); |
1667 | encode_nops(&hdr); | 2032 | encode_nops(&hdr); |
@@ -1675,22 +2040,16 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n | |||
1675 | { | 2040 | { |
1676 | struct xdr_stream xdr; | 2041 | struct xdr_stream xdr; |
1677 | struct compound_hdr hdr = { | 2042 | struct compound_hdr hdr = { |
1678 | .nops = 0, | 2043 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1679 | }; | 2044 | }; |
1680 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1681 | unsigned int replen; | ||
1682 | 2045 | ||
1683 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2046 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1684 | encode_compound_hdr(&xdr, &hdr); | 2047 | encode_compound_hdr(&xdr, req, &hdr); |
2048 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1685 | encode_putfh(&xdr, args->fh, &hdr); | 2049 | encode_putfh(&xdr, args->fh, &hdr); |
1686 | encode_readlink(&xdr, args, req, &hdr); | 2050 | encode_readlink(&xdr, args, req, &hdr); |
1687 | 2051 | ||
1688 | /* set up reply kvec | 2052 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1689 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1690 | * + OP_READLINK + status + string length = 8 | ||
1691 | */ | ||
1692 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2; | ||
1693 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1694 | args->pgbase, args->pglen); | 2053 | args->pgbase, args->pglen); |
1695 | encode_nops(&hdr); | 2054 | encode_nops(&hdr); |
1696 | return 0; | 2055 | return 0; |
@@ -1703,25 +2062,19 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1703 | { | 2062 | { |
1704 | struct xdr_stream xdr; | 2063 | struct xdr_stream xdr; |
1705 | struct compound_hdr hdr = { | 2064 | struct compound_hdr hdr = { |
1706 | .nops = 0, | 2065 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1707 | }; | 2066 | }; |
1708 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1709 | int replen; | ||
1710 | 2067 | ||
1711 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2068 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1712 | encode_compound_hdr(&xdr, &hdr); | 2069 | encode_compound_hdr(&xdr, req, &hdr); |
2070 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1713 | encode_putfh(&xdr, args->fh, &hdr); | 2071 | encode_putfh(&xdr, args->fh, &hdr); |
1714 | encode_readdir(&xdr, args, req, &hdr); | 2072 | encode_readdir(&xdr, args, req, &hdr); |
1715 | 2073 | ||
1716 | /* set up reply kvec | 2074 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages, |
1717 | * toplevel_status + taglen + rescount + OP_PUTFH + status | ||
1718 | * + OP_READDIR + status + verifer(2) = 9 | ||
1719 | */ | ||
1720 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2; | ||
1721 | xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, | ||
1722 | args->pgbase, args->count); | 2075 | args->pgbase, args->count); |
1723 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", | 2076 | dprintk("%s: inlined page args = (%u, %p, %u, %u)\n", |
1724 | __func__, replen, args->pages, | 2077 | __func__, hdr.replen << 2, args->pages, |
1725 | args->pgbase, args->count); | 2078 | args->pgbase, args->count); |
1726 | encode_nops(&hdr); | 2079 | encode_nops(&hdr); |
1727 | return 0; | 2080 | return 0; |
@@ -1732,24 +2085,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf | |||
1732 | */ | 2085 | */ |
1733 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) | 2086 | static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args) |
1734 | { | 2087 | { |
1735 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1736 | struct xdr_stream xdr; | 2088 | struct xdr_stream xdr; |
1737 | struct compound_hdr hdr = { | 2089 | struct compound_hdr hdr = { |
1738 | .nops = 0, | 2090 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1739 | }; | 2091 | }; |
1740 | int replen; | ||
1741 | 2092 | ||
1742 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2093 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1743 | encode_compound_hdr(&xdr, &hdr); | 2094 | encode_compound_hdr(&xdr, req, &hdr); |
2095 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1744 | encode_putfh(&xdr, args->fh, &hdr); | 2096 | encode_putfh(&xdr, args->fh, &hdr); |
1745 | encode_read(&xdr, args, &hdr); | 2097 | encode_read(&xdr, args, &hdr); |
1746 | 2098 | ||
1747 | /* set up reply kvec | 2099 | xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, |
1748 | * toplevel status + taglen=0 + rescount + OP_PUTFH + status | ||
1749 | * + OP_READ + status + eof + datalen = 9 | ||
1750 | */ | ||
1751 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2; | ||
1752 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1753 | args->pages, args->pgbase, args->count); | 2100 | args->pages, args->pgbase, args->count); |
1754 | req->rq_rcv_buf.flags |= XDRBUF_READ; | 2101 | req->rq_rcv_buf.flags |= XDRBUF_READ; |
1755 | encode_nops(&hdr); | 2102 | encode_nops(&hdr); |
@@ -1763,11 +2110,12 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta | |||
1763 | { | 2110 | { |
1764 | struct xdr_stream xdr; | 2111 | struct xdr_stream xdr; |
1765 | struct compound_hdr hdr = { | 2112 | struct compound_hdr hdr = { |
1766 | .nops = 0, | 2113 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1767 | }; | 2114 | }; |
1768 | 2115 | ||
1769 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2116 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1770 | encode_compound_hdr(&xdr, &hdr); | 2117 | encode_compound_hdr(&xdr, req, &hdr); |
2118 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1771 | encode_putfh(&xdr, args->fh, &hdr); | 2119 | encode_putfh(&xdr, args->fh, &hdr); |
1772 | encode_setattr(&xdr, args, args->server, &hdr); | 2120 | encode_setattr(&xdr, args, args->server, &hdr); |
1773 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2121 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1783,20 +2131,19 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p, | |||
1783 | struct nfs_getaclargs *args) | 2131 | struct nfs_getaclargs *args) |
1784 | { | 2132 | { |
1785 | struct xdr_stream xdr; | 2133 | struct xdr_stream xdr; |
1786 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | ||
1787 | struct compound_hdr hdr = { | 2134 | struct compound_hdr hdr = { |
1788 | .nops = 0, | 2135 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1789 | }; | 2136 | }; |
1790 | int replen; | 2137 | uint32_t replen; |
1791 | 2138 | ||
1792 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2139 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1793 | encode_compound_hdr(&xdr, &hdr); | 2140 | encode_compound_hdr(&xdr, req, &hdr); |
2141 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1794 | encode_putfh(&xdr, args->fh, &hdr); | 2142 | encode_putfh(&xdr, args->fh, &hdr); |
2143 | replen = hdr.replen + nfs4_fattr_bitmap_maxsz + 1; | ||
1795 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); | 2144 | encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr); |
1796 | 2145 | ||
1797 | /* set up reply buffer: */ | 2146 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, |
1798 | replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2; | ||
1799 | xdr_inline_pages(&req->rq_rcv_buf, replen, | ||
1800 | args->acl_pages, args->acl_pgbase, args->acl_len); | 2147 | args->acl_pages, args->acl_pgbase, args->acl_len); |
1801 | encode_nops(&hdr); | 2148 | encode_nops(&hdr); |
1802 | return 0; | 2149 | return 0; |
@@ -1809,11 +2156,12 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea | |||
1809 | { | 2156 | { |
1810 | struct xdr_stream xdr; | 2157 | struct xdr_stream xdr; |
1811 | struct compound_hdr hdr = { | 2158 | struct compound_hdr hdr = { |
1812 | .nops = 0, | 2159 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1813 | }; | 2160 | }; |
1814 | 2161 | ||
1815 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2162 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1816 | encode_compound_hdr(&xdr, &hdr); | 2163 | encode_compound_hdr(&xdr, req, &hdr); |
2164 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1817 | encode_putfh(&xdr, args->fh, &hdr); | 2165 | encode_putfh(&xdr, args->fh, &hdr); |
1818 | encode_write(&xdr, args, &hdr); | 2166 | encode_write(&xdr, args, &hdr); |
1819 | req->rq_snd_buf.flags |= XDRBUF_WRITE; | 2167 | req->rq_snd_buf.flags |= XDRBUF_WRITE; |
@@ -1829,11 +2177,12 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write | |||
1829 | { | 2177 | { |
1830 | struct xdr_stream xdr; | 2178 | struct xdr_stream xdr; |
1831 | struct compound_hdr hdr = { | 2179 | struct compound_hdr hdr = { |
1832 | .nops = 0, | 2180 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1833 | }; | 2181 | }; |
1834 | 2182 | ||
1835 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2183 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1836 | encode_compound_hdr(&xdr, &hdr); | 2184 | encode_compound_hdr(&xdr, req, &hdr); |
2185 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1837 | encode_putfh(&xdr, args->fh, &hdr); | 2186 | encode_putfh(&xdr, args->fh, &hdr); |
1838 | encode_commit(&xdr, args, &hdr); | 2187 | encode_commit(&xdr, args, &hdr); |
1839 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2188 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1848,11 +2197,12 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin | |||
1848 | { | 2197 | { |
1849 | struct xdr_stream xdr; | 2198 | struct xdr_stream xdr; |
1850 | struct compound_hdr hdr = { | 2199 | struct compound_hdr hdr = { |
1851 | .nops = 0, | 2200 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1852 | }; | 2201 | }; |
1853 | 2202 | ||
1854 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2203 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1855 | encode_compound_hdr(&xdr, &hdr); | 2204 | encode_compound_hdr(&xdr, req, &hdr); |
2205 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1856 | encode_putfh(&xdr, args->fh, &hdr); | 2206 | encode_putfh(&xdr, args->fh, &hdr); |
1857 | encode_fsinfo(&xdr, args->bitmask, &hdr); | 2207 | encode_fsinfo(&xdr, args->bitmask, &hdr); |
1858 | encode_nops(&hdr); | 2208 | encode_nops(&hdr); |
@@ -1866,11 +2216,12 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n | |||
1866 | { | 2216 | { |
1867 | struct xdr_stream xdr; | 2217 | struct xdr_stream xdr; |
1868 | struct compound_hdr hdr = { | 2218 | struct compound_hdr hdr = { |
1869 | .nops = 0, | 2219 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1870 | }; | 2220 | }; |
1871 | 2221 | ||
1872 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2222 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1873 | encode_compound_hdr(&xdr, &hdr); | 2223 | encode_compound_hdr(&xdr, req, &hdr); |
2224 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1874 | encode_putfh(&xdr, args->fh, &hdr); | 2225 | encode_putfh(&xdr, args->fh, &hdr); |
1875 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], | 2226 | encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0], |
1876 | &hdr); | 2227 | &hdr); |
@@ -1885,11 +2236,12 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1885 | { | 2236 | { |
1886 | struct xdr_stream xdr; | 2237 | struct xdr_stream xdr; |
1887 | struct compound_hdr hdr = { | 2238 | struct compound_hdr hdr = { |
1888 | .nops = 0, | 2239 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1889 | }; | 2240 | }; |
1890 | 2241 | ||
1891 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2242 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1892 | encode_compound_hdr(&xdr, &hdr); | 2243 | encode_compound_hdr(&xdr, req, &hdr); |
2244 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1893 | encode_putfh(&xdr, args->fh, &hdr); | 2245 | encode_putfh(&xdr, args->fh, &hdr); |
1894 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], | 2246 | encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0], |
1895 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); | 2247 | args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr); |
@@ -1900,16 +2252,18 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs | |||
1900 | /* | 2252 | /* |
1901 | * GETATTR_BITMAP request | 2253 | * GETATTR_BITMAP request |
1902 | */ | 2254 | */ |
1903 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle) | 2255 | static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, |
2256 | struct nfs4_server_caps_arg *args) | ||
1904 | { | 2257 | { |
1905 | struct xdr_stream xdr; | 2258 | struct xdr_stream xdr; |
1906 | struct compound_hdr hdr = { | 2259 | struct compound_hdr hdr = { |
1907 | .nops = 0, | 2260 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1908 | }; | 2261 | }; |
1909 | 2262 | ||
1910 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2263 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1911 | encode_compound_hdr(&xdr, &hdr); | 2264 | encode_compound_hdr(&xdr, req, &hdr); |
1912 | encode_putfh(&xdr, fhandle, &hdr); | 2265 | encode_sequence(&xdr, &args->seq_args, &hdr); |
2266 | encode_putfh(&xdr, args->fhandle, &hdr); | ||
1913 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| | 2267 | encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS| |
1914 | FATTR4_WORD0_LINK_SUPPORT| | 2268 | FATTR4_WORD0_LINK_SUPPORT| |
1915 | FATTR4_WORD0_SYMLINK_SUPPORT| | 2269 | FATTR4_WORD0_SYMLINK_SUPPORT| |
@@ -1929,7 +2283,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client | |||
1929 | }; | 2283 | }; |
1930 | 2284 | ||
1931 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2285 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1932 | encode_compound_hdr(&xdr, &hdr); | 2286 | encode_compound_hdr(&xdr, req, &hdr); |
1933 | encode_renew(&xdr, clp, &hdr); | 2287 | encode_renew(&xdr, clp, &hdr); |
1934 | encode_nops(&hdr); | 2288 | encode_nops(&hdr); |
1935 | return 0; | 2289 | return 0; |
@@ -1946,7 +2300,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
1946 | }; | 2300 | }; |
1947 | 2301 | ||
1948 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2302 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1949 | encode_compound_hdr(&xdr, &hdr); | 2303 | encode_compound_hdr(&xdr, req, &hdr); |
1950 | encode_setclientid(&xdr, sc, &hdr); | 2304 | encode_setclientid(&xdr, sc, &hdr); |
1951 | encode_nops(&hdr); | 2305 | encode_nops(&hdr); |
1952 | return 0; | 2306 | return 0; |
@@ -1964,7 +2318,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str | |||
1964 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | 2318 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; |
1965 | 2319 | ||
1966 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2320 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1967 | encode_compound_hdr(&xdr, &hdr); | 2321 | encode_compound_hdr(&xdr, req, &hdr); |
1968 | encode_setclientid_confirm(&xdr, clp, &hdr); | 2322 | encode_setclientid_confirm(&xdr, clp, &hdr); |
1969 | encode_putrootfh(&xdr, &hdr); | 2323 | encode_putrootfh(&xdr, &hdr); |
1970 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | 2324 | encode_fsinfo(&xdr, lease_bitmap, &hdr); |
@@ -1979,11 +2333,12 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc | |||
1979 | { | 2333 | { |
1980 | struct xdr_stream xdr; | 2334 | struct xdr_stream xdr; |
1981 | struct compound_hdr hdr = { | 2335 | struct compound_hdr hdr = { |
1982 | .nops = 0, | 2336 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
1983 | }; | 2337 | }; |
1984 | 2338 | ||
1985 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2339 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
1986 | encode_compound_hdr(&xdr, &hdr); | 2340 | encode_compound_hdr(&xdr, req, &hdr); |
2341 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
1987 | encode_putfh(&xdr, args->fhandle, &hdr); | 2342 | encode_putfh(&xdr, args->fhandle, &hdr); |
1988 | encode_delegreturn(&xdr, args->stateid, &hdr); | 2343 | encode_delegreturn(&xdr, args->stateid, &hdr); |
1989 | encode_getfattr(&xdr, args->bitmask, &hdr); | 2344 | encode_getfattr(&xdr, args->bitmask, &hdr); |
@@ -1998,28 +2353,119 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
1998 | { | 2353 | { |
1999 | struct xdr_stream xdr; | 2354 | struct xdr_stream xdr; |
2000 | struct compound_hdr hdr = { | 2355 | struct compound_hdr hdr = { |
2001 | .nops = 0, | 2356 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
2002 | }; | 2357 | }; |
2003 | struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth; | 2358 | uint32_t replen; |
2004 | int replen; | ||
2005 | 2359 | ||
2006 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 2360 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
2007 | encode_compound_hdr(&xdr, &hdr); | 2361 | encode_compound_hdr(&xdr, req, &hdr); |
2362 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
2008 | encode_putfh(&xdr, args->dir_fh, &hdr); | 2363 | encode_putfh(&xdr, args->dir_fh, &hdr); |
2009 | encode_lookup(&xdr, args->name, &hdr); | 2364 | encode_lookup(&xdr, args->name, &hdr); |
2365 | replen = hdr.replen; /* get the attribute into args->page */ | ||
2010 | encode_fs_locations(&xdr, args->bitmask, &hdr); | 2366 | encode_fs_locations(&xdr, args->bitmask, &hdr); |
2011 | 2367 | ||
2012 | /* set up reply | 2368 | xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page, |
2013 | * toplevel_status + OP_PUTFH + status | ||
2014 | * + OP_LOOKUP + status + OP_GETATTR + status = 7 | ||
2015 | */ | ||
2016 | replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; | ||
2017 | xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page, | ||
2018 | 0, PAGE_SIZE); | 2369 | 0, PAGE_SIZE); |
2019 | encode_nops(&hdr); | 2370 | encode_nops(&hdr); |
2020 | return 0; | 2371 | return 0; |
2021 | } | 2372 | } |
2022 | 2373 | ||
2374 | #if defined(CONFIG_NFS_V4_1) | ||
2375 | /* | ||
2376 | * EXCHANGE_ID request | ||
2377 | */ | ||
2378 | static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | ||
2379 | struct nfs41_exchange_id_args *args) | ||
2380 | { | ||
2381 | struct xdr_stream xdr; | ||
2382 | struct compound_hdr hdr = { | ||
2383 | .minorversion = args->client->cl_minorversion, | ||
2384 | }; | ||
2385 | |||
2386 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2387 | encode_compound_hdr(&xdr, req, &hdr); | ||
2388 | encode_exchange_id(&xdr, args, &hdr); | ||
2389 | encode_nops(&hdr); | ||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | /* | ||
2394 | * a CREATE_SESSION request | ||
2395 | */ | ||
2396 | static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p, | ||
2397 | struct nfs41_create_session_args *args) | ||
2398 | { | ||
2399 | struct xdr_stream xdr; | ||
2400 | struct compound_hdr hdr = { | ||
2401 | .minorversion = args->client->cl_minorversion, | ||
2402 | }; | ||
2403 | |||
2404 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2405 | encode_compound_hdr(&xdr, req, &hdr); | ||
2406 | encode_create_session(&xdr, args, &hdr); | ||
2407 | encode_nops(&hdr); | ||
2408 | return 0; | ||
2409 | } | ||
2410 | |||
2411 | /* | ||
2412 | * a DESTROY_SESSION request | ||
2413 | */ | ||
2414 | static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | ||
2415 | struct nfs4_session *session) | ||
2416 | { | ||
2417 | struct xdr_stream xdr; | ||
2418 | struct compound_hdr hdr = { | ||
2419 | .minorversion = session->clp->cl_minorversion, | ||
2420 | }; | ||
2421 | |||
2422 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2423 | encode_compound_hdr(&xdr, req, &hdr); | ||
2424 | encode_destroy_session(&xdr, session, &hdr); | ||
2425 | encode_nops(&hdr); | ||
2426 | return 0; | ||
2427 | } | ||
2428 | |||
2429 | /* | ||
2430 | * a SEQUENCE request | ||
2431 | */ | ||
2432 | static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p, | ||
2433 | struct nfs4_sequence_args *args) | ||
2434 | { | ||
2435 | struct xdr_stream xdr; | ||
2436 | struct compound_hdr hdr = { | ||
2437 | .minorversion = nfs4_xdr_minorversion(args), | ||
2438 | }; | ||
2439 | |||
2440 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2441 | encode_compound_hdr(&xdr, req, &hdr); | ||
2442 | encode_sequence(&xdr, args, &hdr); | ||
2443 | encode_nops(&hdr); | ||
2444 | return 0; | ||
2445 | } | ||
2446 | |||
2447 | /* | ||
2448 | * a GET_LEASE_TIME request | ||
2449 | */ | ||
2450 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | ||
2451 | struct nfs4_get_lease_time_args *args) | ||
2452 | { | ||
2453 | struct xdr_stream xdr; | ||
2454 | struct compound_hdr hdr = { | ||
2455 | .minorversion = nfs4_xdr_minorversion(&args->la_seq_args), | ||
2456 | }; | ||
2457 | const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 }; | ||
2458 | |||
2459 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2460 | encode_compound_hdr(&xdr, req, &hdr); | ||
2461 | encode_sequence(&xdr, &args->la_seq_args, &hdr); | ||
2462 | encode_putrootfh(&xdr, &hdr); | ||
2463 | encode_fsinfo(&xdr, lease_bitmap, &hdr); | ||
2464 | encode_nops(&hdr); | ||
2465 | return 0; | ||
2466 | } | ||
2467 | #endif /* CONFIG_NFS_V4_1 */ | ||
2468 | |||
2023 | /* | 2469 | /* |
2024 | * START OF "GENERIC" DECODE ROUTINES. | 2470 | * START OF "GENERIC" DECODE ROUTINES. |
2025 | * These may look a little ugly since they are imported from a "generic" | 2471 | * These may look a little ugly since they are imported from a "generic" |
@@ -3657,7 +4103,7 @@ decode_savefh(struct xdr_stream *xdr) | |||
3657 | return decode_op_hdr(xdr, OP_SAVEFH); | 4103 | return decode_op_hdr(xdr, OP_SAVEFH); |
3658 | } | 4104 | } |
3659 | 4105 | ||
3660 | static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res) | 4106 | static int decode_setattr(struct xdr_stream *xdr) |
3661 | { | 4107 | { |
3662 | __be32 *p; | 4108 | __be32 *p; |
3663 | uint32_t bmlen; | 4109 | uint32_t bmlen; |
@@ -3735,6 +4181,169 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
3735 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 4181 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
3736 | } | 4182 | } |
3737 | 4183 | ||
4184 | #if defined(CONFIG_NFS_V4_1) | ||
4185 | static int decode_exchange_id(struct xdr_stream *xdr, | ||
4186 | struct nfs41_exchange_id_res *res) | ||
4187 | { | ||
4188 | __be32 *p; | ||
4189 | uint32_t dummy; | ||
4190 | int status; | ||
4191 | struct nfs_client *clp = res->client; | ||
4192 | |||
4193 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | ||
4194 | if (status) | ||
4195 | return status; | ||
4196 | |||
4197 | READ_BUF(8); | ||
4198 | READ64(clp->cl_ex_clid); | ||
4199 | READ_BUF(12); | ||
4200 | READ32(clp->cl_seqid); | ||
4201 | READ32(clp->cl_exchange_flags); | ||
4202 | |||
4203 | /* We ask for SP4_NONE */ | ||
4204 | READ32(dummy); | ||
4205 | if (dummy != SP4_NONE) | ||
4206 | return -EIO; | ||
4207 | |||
4208 | /* Throw away minor_id */ | ||
4209 | READ_BUF(8); | ||
4210 | |||
4211 | /* Throw away Major id */ | ||
4212 | READ_BUF(4); | ||
4213 | READ32(dummy); | ||
4214 | READ_BUF(dummy); | ||
4215 | |||
4216 | /* Throw away server_scope */ | ||
4217 | READ_BUF(4); | ||
4218 | READ32(dummy); | ||
4219 | READ_BUF(dummy); | ||
4220 | |||
4221 | /* Throw away Implementation id array */ | ||
4222 | READ_BUF(4); | ||
4223 | READ32(dummy); | ||
4224 | READ_BUF(dummy); | ||
4225 | |||
4226 | return 0; | ||
4227 | } | ||
4228 | |||
4229 | static int decode_chan_attrs(struct xdr_stream *xdr, | ||
4230 | struct nfs4_channel_attrs *attrs) | ||
4231 | { | ||
4232 | __be32 *p; | ||
4233 | u32 nr_attrs; | ||
4234 | |||
4235 | READ_BUF(28); | ||
4236 | READ32(attrs->headerpadsz); | ||
4237 | READ32(attrs->max_rqst_sz); | ||
4238 | READ32(attrs->max_resp_sz); | ||
4239 | READ32(attrs->max_resp_sz_cached); | ||
4240 | READ32(attrs->max_ops); | ||
4241 | READ32(attrs->max_reqs); | ||
4242 | READ32(nr_attrs); | ||
4243 | if (unlikely(nr_attrs > 1)) { | ||
4244 | printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n", | ||
4245 | __func__, nr_attrs); | ||
4246 | return -EINVAL; | ||
4247 | } | ||
4248 | if (nr_attrs == 1) | ||
4249 | READ_BUF(4); /* skip rdma_attrs */ | ||
4250 | return 0; | ||
4251 | } | ||
4252 | |||
4253 | static int decode_create_session(struct xdr_stream *xdr, | ||
4254 | struct nfs41_create_session_res *res) | ||
4255 | { | ||
4256 | __be32 *p; | ||
4257 | int status; | ||
4258 | struct nfs_client *clp = res->client; | ||
4259 | struct nfs4_session *session = clp->cl_session; | ||
4260 | |||
4261 | status = decode_op_hdr(xdr, OP_CREATE_SESSION); | ||
4262 | |||
4263 | if (status) | ||
4264 | return status; | ||
4265 | |||
4266 | /* sessionid */ | ||
4267 | READ_BUF(NFS4_MAX_SESSIONID_LEN); | ||
4268 | COPYMEM(&session->sess_id, NFS4_MAX_SESSIONID_LEN); | ||
4269 | |||
4270 | /* seqid, flags */ | ||
4271 | READ_BUF(8); | ||
4272 | READ32(clp->cl_seqid); | ||
4273 | READ32(session->flags); | ||
4274 | |||
4275 | /* Channel attributes */ | ||
4276 | status = decode_chan_attrs(xdr, &session->fc_attrs); | ||
4277 | if (!status) | ||
4278 | status = decode_chan_attrs(xdr, &session->bc_attrs); | ||
4279 | return status; | ||
4280 | } | ||
4281 | |||
4282 | static int decode_destroy_session(struct xdr_stream *xdr, void *dummy) | ||
4283 | { | ||
4284 | return decode_op_hdr(xdr, OP_DESTROY_SESSION); | ||
4285 | } | ||
4286 | #endif /* CONFIG_NFS_V4_1 */ | ||
4287 | |||
4288 | static int decode_sequence(struct xdr_stream *xdr, | ||
4289 | struct nfs4_sequence_res *res, | ||
4290 | struct rpc_rqst *rqstp) | ||
4291 | { | ||
4292 | #if defined(CONFIG_NFS_V4_1) | ||
4293 | struct nfs4_slot *slot; | ||
4294 | struct nfs4_sessionid id; | ||
4295 | u32 dummy; | ||
4296 | int status; | ||
4297 | __be32 *p; | ||
4298 | |||
4299 | if (!res->sr_session) | ||
4300 | return 0; | ||
4301 | |||
4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); | ||
4303 | if (status) | ||
4304 | goto out_err; | ||
4305 | |||
4306 | /* | ||
4307 | * If the server returns different values for sessionID, slotID or | ||
4308 | * sequence number, the server is looney tunes. | ||
4309 | */ | ||
4310 | status = -ESERVERFAULT; | ||
4311 | |||
4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | ||
4316 | NFS4_MAX_SESSIONID_LEN)) { | ||
4317 | dprintk("%s Invalid session id\n", __func__); | ||
4318 | goto out_err; | ||
4319 | } | ||
4320 | /* seqid */ | ||
4321 | READ32(dummy); | ||
4322 | if (dummy != slot->seq_nr) { | ||
4323 | dprintk("%s Invalid sequence number\n", __func__); | ||
4324 | goto out_err; | ||
4325 | } | ||
4326 | /* slot id */ | ||
4327 | READ32(dummy); | ||
4328 | if (dummy != res->sr_slotid) { | ||
4329 | dprintk("%s Invalid slot id\n", __func__); | ||
4330 | goto out_err; | ||
4331 | } | ||
4332 | /* highest slot id - currently not processed */ | ||
4333 | READ32(dummy); | ||
4334 | /* target highest slot id - currently not processed */ | ||
4335 | READ32(dummy); | ||
4336 | /* result flags - currently not processed */ | ||
4337 | READ32(dummy); | ||
4338 | status = 0; | ||
4339 | out_err: | ||
4340 | res->sr_status = status; | ||
4341 | return status; | ||
4342 | #else /* CONFIG_NFS_V4_1 */ | ||
4343 | return 0; | ||
4344 | #endif /* CONFIG_NFS_V4_1 */ | ||
4345 | } | ||
4346 | |||
3738 | /* | 4347 | /* |
3739 | * END OF "GENERIC" DECODE ROUTINES. | 4348 | * END OF "GENERIC" DECODE ROUTINES. |
3740 | */ | 4349 | */ |
@@ -3752,6 +4361,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct | |||
3752 | status = decode_compound_hdr(&xdr, &hdr); | 4361 | status = decode_compound_hdr(&xdr, &hdr); |
3753 | if (status) | 4362 | if (status) |
3754 | goto out; | 4363 | goto out; |
4364 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4365 | if (status) | ||
4366 | goto out; | ||
3755 | status = decode_putfh(&xdr); | 4367 | status = decode_putfh(&xdr); |
3756 | if (status) | 4368 | if (status) |
3757 | goto out; | 4369 | goto out; |
@@ -3773,7 +4385,11 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_ac | |||
3773 | int status; | 4385 | int status; |
3774 | 4386 | ||
3775 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4387 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3776 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4388 | status = decode_compound_hdr(&xdr, &hdr); |
4389 | if (status) | ||
4390 | goto out; | ||
4391 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4392 | if (status) | ||
3777 | goto out; | 4393 | goto out; |
3778 | status = decode_putfh(&xdr); | 4394 | status = decode_putfh(&xdr); |
3779 | if (status != 0) | 4395 | if (status != 0) |
@@ -3796,7 +4412,11 @@ static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lo | |||
3796 | int status; | 4412 | int status; |
3797 | 4413 | ||
3798 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4414 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3799 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4415 | status = decode_compound_hdr(&xdr, &hdr); |
4416 | if (status) | ||
4417 | goto out; | ||
4418 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4419 | if (status) | ||
3800 | goto out; | 4420 | goto out; |
3801 | if ((status = decode_putfh(&xdr)) != 0) | 4421 | if ((status = decode_putfh(&xdr)) != 0) |
3802 | goto out; | 4422 | goto out; |
@@ -3819,7 +4439,11 @@ static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
3819 | int status; | 4439 | int status; |
3820 | 4440 | ||
3821 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4441 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3822 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4442 | status = decode_compound_hdr(&xdr, &hdr); |
4443 | if (status) | ||
4444 | goto out; | ||
4445 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4446 | if (status) | ||
3823 | goto out; | 4447 | goto out; |
3824 | if ((status = decode_putrootfh(&xdr)) != 0) | 4448 | if ((status = decode_putrootfh(&xdr)) != 0) |
3825 | goto out; | 4449 | goto out; |
@@ -3839,7 +4463,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_rem | |||
3839 | int status; | 4463 | int status; |
3840 | 4464 | ||
3841 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4465 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3842 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4466 | status = decode_compound_hdr(&xdr, &hdr); |
4467 | if (status) | ||
4468 | goto out; | ||
4469 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4470 | if (status) | ||
3843 | goto out; | 4471 | goto out; |
3844 | if ((status = decode_putfh(&xdr)) != 0) | 4472 | if ((status = decode_putfh(&xdr)) != 0) |
3845 | goto out; | 4473 | goto out; |
@@ -3860,7 +4488,11 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re | |||
3860 | int status; | 4488 | int status; |
3861 | 4489 | ||
3862 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4490 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3863 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4491 | status = decode_compound_hdr(&xdr, &hdr); |
4492 | if (status) | ||
4493 | goto out; | ||
4494 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4495 | if (status) | ||
3864 | goto out; | 4496 | goto out; |
3865 | if ((status = decode_putfh(&xdr)) != 0) | 4497 | if ((status = decode_putfh(&xdr)) != 0) |
3866 | goto out; | 4498 | goto out; |
@@ -3890,7 +4522,11 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link | |||
3890 | int status; | 4522 | int status; |
3891 | 4523 | ||
3892 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4524 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3893 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4525 | status = decode_compound_hdr(&xdr, &hdr); |
4526 | if (status) | ||
4527 | goto out; | ||
4528 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4529 | if (status) | ||
3894 | goto out; | 4530 | goto out; |
3895 | if ((status = decode_putfh(&xdr)) != 0) | 4531 | if ((status = decode_putfh(&xdr)) != 0) |
3896 | goto out; | 4532 | goto out; |
@@ -3923,7 +4559,11 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_cr | |||
3923 | int status; | 4559 | int status; |
3924 | 4560 | ||
3925 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 4561 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
3926 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 4562 | status = decode_compound_hdr(&xdr, &hdr); |
4563 | if (status) | ||
4564 | goto out; | ||
4565 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4566 | if (status) | ||
3927 | goto out; | 4567 | goto out; |
3928 | if ((status = decode_putfh(&xdr)) != 0) | 4568 | if ((status = decode_putfh(&xdr)) != 0) |
3929 | goto out; | 4569 | goto out; |
@@ -3963,6 +4603,9 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_g | |||
3963 | status = decode_compound_hdr(&xdr, &hdr); | 4603 | status = decode_compound_hdr(&xdr, &hdr); |
3964 | if (status) | 4604 | if (status) |
3965 | goto out; | 4605 | goto out; |
4606 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4607 | if (status) | ||
4608 | goto out; | ||
3966 | status = decode_putfh(&xdr); | 4609 | status = decode_putfh(&xdr); |
3967 | if (status) | 4610 | if (status) |
3968 | goto out; | 4611 | goto out; |
@@ -3979,12 +4622,13 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3979 | { | 4622 | { |
3980 | struct xdr_stream xdr; | 4623 | struct xdr_stream xdr; |
3981 | struct compound_hdr hdr = { | 4624 | struct compound_hdr hdr = { |
3982 | .nops = 0, | 4625 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), |
3983 | }; | 4626 | }; |
3984 | int status; | 4627 | int status; |
3985 | 4628 | ||
3986 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | 4629 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
3987 | encode_compound_hdr(&xdr, &hdr); | 4630 | encode_compound_hdr(&xdr, req, &hdr); |
4631 | encode_sequence(&xdr, &args->seq_args, &hdr); | ||
3988 | encode_putfh(&xdr, args->fh, &hdr); | 4632 | encode_putfh(&xdr, args->fh, &hdr); |
3989 | status = encode_setacl(&xdr, args, &hdr); | 4633 | status = encode_setacl(&xdr, args, &hdr); |
3990 | encode_nops(&hdr); | 4634 | encode_nops(&hdr); |
@@ -3995,7 +4639,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args | |||
3995 | * Decode SETACL response | 4639 | * Decode SETACL response |
3996 | */ | 4640 | */ |
3997 | static int | 4641 | static int |
3998 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4642 | nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, |
4643 | struct nfs_setaclres *res) | ||
3999 | { | 4644 | { |
4000 | struct xdr_stream xdr; | 4645 | struct xdr_stream xdr; |
4001 | struct compound_hdr hdr; | 4646 | struct compound_hdr hdr; |
@@ -4005,10 +4650,13 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4005 | status = decode_compound_hdr(&xdr, &hdr); | 4650 | status = decode_compound_hdr(&xdr, &hdr); |
4006 | if (status) | 4651 | if (status) |
4007 | goto out; | 4652 | goto out; |
4653 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4654 | if (status) | ||
4655 | goto out; | ||
4008 | status = decode_putfh(&xdr); | 4656 | status = decode_putfh(&xdr); |
4009 | if (status) | 4657 | if (status) |
4010 | goto out; | 4658 | goto out; |
4011 | status = decode_setattr(&xdr, res); | 4659 | status = decode_setattr(&xdr); |
4012 | out: | 4660 | out: |
4013 | return status; | 4661 | return status; |
4014 | } | 4662 | } |
@@ -4017,7 +4665,8 @@ out: | |||
4017 | * Decode GETACL response | 4665 | * Decode GETACL response |
4018 | */ | 4666 | */ |
4019 | static int | 4667 | static int |
4020 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | 4668 | nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, |
4669 | struct nfs_getaclres *res) | ||
4021 | { | 4670 | { |
4022 | struct xdr_stream xdr; | 4671 | struct xdr_stream xdr; |
4023 | struct compound_hdr hdr; | 4672 | struct compound_hdr hdr; |
@@ -4027,10 +4676,13 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len) | |||
4027 | status = decode_compound_hdr(&xdr, &hdr); | 4676 | status = decode_compound_hdr(&xdr, &hdr); |
4028 | if (status) | 4677 | if (status) |
4029 | goto out; | 4678 | goto out; |
4679 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4680 | if (status) | ||
4681 | goto out; | ||
4030 | status = decode_putfh(&xdr); | 4682 | status = decode_putfh(&xdr); |
4031 | if (status) | 4683 | if (status) |
4032 | goto out; | 4684 | goto out; |
4033 | status = decode_getacl(&xdr, rqstp, acl_len); | 4685 | status = decode_getacl(&xdr, rqstp, &res->acl_len); |
4034 | 4686 | ||
4035 | out: | 4687 | out: |
4036 | return status; | 4688 | return status; |
@@ -4049,6 +4701,9 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_clos | |||
4049 | status = decode_compound_hdr(&xdr, &hdr); | 4701 | status = decode_compound_hdr(&xdr, &hdr); |
4050 | if (status) | 4702 | if (status) |
4051 | goto out; | 4703 | goto out; |
4704 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4705 | if (status) | ||
4706 | goto out; | ||
4052 | status = decode_putfh(&xdr); | 4707 | status = decode_putfh(&xdr); |
4053 | if (status) | 4708 | if (status) |
4054 | goto out; | 4709 | goto out; |
@@ -4079,6 +4734,9 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr | |||
4079 | status = decode_compound_hdr(&xdr, &hdr); | 4734 | status = decode_compound_hdr(&xdr, &hdr); |
4080 | if (status) | 4735 | if (status) |
4081 | goto out; | 4736 | goto out; |
4737 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4738 | if (status) | ||
4739 | goto out; | ||
4082 | status = decode_putfh(&xdr); | 4740 | status = decode_putfh(&xdr); |
4083 | if (status) | 4741 | if (status) |
4084 | goto out; | 4742 | goto out; |
@@ -4133,6 +4791,9 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4133 | status = decode_compound_hdr(&xdr, &hdr); | 4791 | status = decode_compound_hdr(&xdr, &hdr); |
4134 | if (status) | 4792 | if (status) |
4135 | goto out; | 4793 | goto out; |
4794 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4795 | if (status) | ||
4796 | goto out; | ||
4136 | status = decode_putfh(&xdr); | 4797 | status = decode_putfh(&xdr); |
4137 | if (status) | 4798 | if (status) |
4138 | goto out; | 4799 | goto out; |
@@ -4157,10 +4818,13 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se | |||
4157 | status = decode_compound_hdr(&xdr, &hdr); | 4818 | status = decode_compound_hdr(&xdr, &hdr); |
4158 | if (status) | 4819 | if (status) |
4159 | goto out; | 4820 | goto out; |
4821 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4822 | if (status) | ||
4823 | goto out; | ||
4160 | status = decode_putfh(&xdr); | 4824 | status = decode_putfh(&xdr); |
4161 | if (status) | 4825 | if (status) |
4162 | goto out; | 4826 | goto out; |
4163 | status = decode_setattr(&xdr, res); | 4827 | status = decode_setattr(&xdr); |
4164 | if (status) | 4828 | if (status) |
4165 | goto out; | 4829 | goto out; |
4166 | decode_getfattr(&xdr, res->fattr, res->server); | 4830 | decode_getfattr(&xdr, res->fattr, res->server); |
@@ -4181,6 +4845,9 @@ static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_ | |||
4181 | status = decode_compound_hdr(&xdr, &hdr); | 4845 | status = decode_compound_hdr(&xdr, &hdr); |
4182 | if (status) | 4846 | if (status) |
4183 | goto out; | 4847 | goto out; |
4848 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4849 | if (status) | ||
4850 | goto out; | ||
4184 | status = decode_putfh(&xdr); | 4851 | status = decode_putfh(&xdr); |
4185 | if (status) | 4852 | if (status) |
4186 | goto out; | 4853 | goto out; |
@@ -4202,6 +4869,9 @@ static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4202 | status = decode_compound_hdr(&xdr, &hdr); | 4869 | status = decode_compound_hdr(&xdr, &hdr); |
4203 | if (status) | 4870 | if (status) |
4204 | goto out; | 4871 | goto out; |
4872 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4873 | if (status) | ||
4874 | goto out; | ||
4205 | status = decode_putfh(&xdr); | 4875 | status = decode_putfh(&xdr); |
4206 | if (status) | 4876 | if (status) |
4207 | goto out; | 4877 | goto out; |
@@ -4223,6 +4893,9 @@ static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock | |||
4223 | status = decode_compound_hdr(&xdr, &hdr); | 4893 | status = decode_compound_hdr(&xdr, &hdr); |
4224 | if (status) | 4894 | if (status) |
4225 | goto out; | 4895 | goto out; |
4896 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4897 | if (status) | ||
4898 | goto out; | ||
4226 | status = decode_putfh(&xdr); | 4899 | status = decode_putfh(&xdr); |
4227 | if (status) | 4900 | if (status) |
4228 | goto out; | 4901 | goto out; |
@@ -4234,7 +4907,8 @@ out: | |||
4234 | /* | 4907 | /* |
4235 | * Decode READLINK response | 4908 | * Decode READLINK response |
4236 | */ | 4909 | */ |
4237 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | 4910 | static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, |
4911 | struct nfs4_readlink_res *res) | ||
4238 | { | 4912 | { |
4239 | struct xdr_stream xdr; | 4913 | struct xdr_stream xdr; |
4240 | struct compound_hdr hdr; | 4914 | struct compound_hdr hdr; |
@@ -4244,6 +4918,9 @@ static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res) | |||
4244 | status = decode_compound_hdr(&xdr, &hdr); | 4918 | status = decode_compound_hdr(&xdr, &hdr); |
4245 | if (status) | 4919 | if (status) |
4246 | goto out; | 4920 | goto out; |
4921 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4922 | if (status) | ||
4923 | goto out; | ||
4247 | status = decode_putfh(&xdr); | 4924 | status = decode_putfh(&xdr); |
4248 | if (status) | 4925 | if (status) |
4249 | goto out; | 4926 | goto out; |
@@ -4265,6 +4942,9 @@ static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_r | |||
4265 | status = decode_compound_hdr(&xdr, &hdr); | 4942 | status = decode_compound_hdr(&xdr, &hdr); |
4266 | if (status) | 4943 | if (status) |
4267 | goto out; | 4944 | goto out; |
4945 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4946 | if (status) | ||
4947 | goto out; | ||
4268 | status = decode_putfh(&xdr); | 4948 | status = decode_putfh(&xdr); |
4269 | if (status) | 4949 | if (status) |
4270 | goto out; | 4950 | goto out; |
@@ -4286,6 +4966,9 @@ static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readr | |||
4286 | status = decode_compound_hdr(&xdr, &hdr); | 4966 | status = decode_compound_hdr(&xdr, &hdr); |
4287 | if (status) | 4967 | if (status) |
4288 | goto out; | 4968 | goto out; |
4969 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4970 | if (status) | ||
4971 | goto out; | ||
4289 | status = decode_putfh(&xdr); | 4972 | status = decode_putfh(&xdr); |
4290 | if (status) | 4973 | if (status) |
4291 | goto out; | 4974 | goto out; |
@@ -4309,6 +4992,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writ | |||
4309 | status = decode_compound_hdr(&xdr, &hdr); | 4992 | status = decode_compound_hdr(&xdr, &hdr); |
4310 | if (status) | 4993 | if (status) |
4311 | goto out; | 4994 | goto out; |
4995 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
4996 | if (status) | ||
4997 | goto out; | ||
4312 | status = decode_putfh(&xdr); | 4998 | status = decode_putfh(&xdr); |
4313 | if (status) | 4999 | if (status) |
4314 | goto out; | 5000 | goto out; |
@@ -4335,6 +5021,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_wri | |||
4335 | status = decode_compound_hdr(&xdr, &hdr); | 5021 | status = decode_compound_hdr(&xdr, &hdr); |
4336 | if (status) | 5022 | if (status) |
4337 | goto out; | 5023 | goto out; |
5024 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5025 | if (status) | ||
5026 | goto out; | ||
4338 | status = decode_putfh(&xdr); | 5027 | status = decode_putfh(&xdr); |
4339 | if (status) | 5028 | if (status) |
4340 | goto out; | 5029 | goto out; |
@@ -4349,7 +5038,8 @@ out: | |||
4349 | /* | 5038 | /* |
4350 | * FSINFO request | 5039 | * FSINFO request |
4351 | */ | 5040 | */ |
4352 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo) | 5041 | static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, |
5042 | struct nfs4_fsinfo_res *res) | ||
4353 | { | 5043 | { |
4354 | struct xdr_stream xdr; | 5044 | struct xdr_stream xdr; |
4355 | struct compound_hdr hdr; | 5045 | struct compound_hdr hdr; |
@@ -4358,16 +5048,19 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf | |||
4358 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5048 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4359 | status = decode_compound_hdr(&xdr, &hdr); | 5049 | status = decode_compound_hdr(&xdr, &hdr); |
4360 | if (!status) | 5050 | if (!status) |
5051 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5052 | if (!status) | ||
4361 | status = decode_putfh(&xdr); | 5053 | status = decode_putfh(&xdr); |
4362 | if (!status) | 5054 | if (!status) |
4363 | status = decode_fsinfo(&xdr, fsinfo); | 5055 | status = decode_fsinfo(&xdr, res->fsinfo); |
4364 | return status; | 5056 | return status; |
4365 | } | 5057 | } |
4366 | 5058 | ||
4367 | /* | 5059 | /* |
4368 | * PATHCONF request | 5060 | * PATHCONF request |
4369 | */ | 5061 | */ |
4370 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf) | 5062 | static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, |
5063 | struct nfs4_pathconf_res *res) | ||
4371 | { | 5064 | { |
4372 | struct xdr_stream xdr; | 5065 | struct xdr_stream xdr; |
4373 | struct compound_hdr hdr; | 5066 | struct compound_hdr hdr; |
@@ -4376,16 +5069,19 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat | |||
4376 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5069 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4377 | status = decode_compound_hdr(&xdr, &hdr); | 5070 | status = decode_compound_hdr(&xdr, &hdr); |
4378 | if (!status) | 5071 | if (!status) |
5072 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5073 | if (!status) | ||
4379 | status = decode_putfh(&xdr); | 5074 | status = decode_putfh(&xdr); |
4380 | if (!status) | 5075 | if (!status) |
4381 | status = decode_pathconf(&xdr, pathconf); | 5076 | status = decode_pathconf(&xdr, res->pathconf); |
4382 | return status; | 5077 | return status; |
4383 | } | 5078 | } |
4384 | 5079 | ||
4385 | /* | 5080 | /* |
4386 | * STATFS request | 5081 | * STATFS request |
4387 | */ | 5082 | */ |
4388 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat) | 5083 | static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, |
5084 | struct nfs4_statfs_res *res) | ||
4389 | { | 5085 | { |
4390 | struct xdr_stream xdr; | 5086 | struct xdr_stream xdr; |
4391 | struct compound_hdr hdr; | 5087 | struct compound_hdr hdr; |
@@ -4394,9 +5090,11 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta | |||
4394 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5090 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4395 | status = decode_compound_hdr(&xdr, &hdr); | 5091 | status = decode_compound_hdr(&xdr, &hdr); |
4396 | if (!status) | 5092 | if (!status) |
5093 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5094 | if (!status) | ||
4397 | status = decode_putfh(&xdr); | 5095 | status = decode_putfh(&xdr); |
4398 | if (!status) | 5096 | if (!status) |
4399 | status = decode_statfs(&xdr, fsstat); | 5097 | status = decode_statfs(&xdr, res->fsstat); |
4400 | return status; | 5098 | return status; |
4401 | } | 5099 | } |
4402 | 5100 | ||
@@ -4410,7 +5108,11 @@ static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4 | |||
4410 | int status; | 5108 | int status; |
4411 | 5109 | ||
4412 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5110 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4413 | if ((status = decode_compound_hdr(&xdr, &hdr)) != 0) | 5111 | status = decode_compound_hdr(&xdr, &hdr); |
5112 | if (status) | ||
5113 | goto out; | ||
5114 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5115 | if (status) | ||
4414 | goto out; | 5116 | goto out; |
4415 | if ((status = decode_putfh(&xdr)) != 0) | 5117 | if ((status = decode_putfh(&xdr)) != 0) |
4416 | goto out; | 5118 | goto out; |
@@ -4483,7 +5185,10 @@ static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nf | |||
4483 | 5185 | ||
4484 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | 5186 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); |
4485 | status = decode_compound_hdr(&xdr, &hdr); | 5187 | status = decode_compound_hdr(&xdr, &hdr); |
4486 | if (status != 0) | 5188 | if (status) |
5189 | goto out; | ||
5190 | status = decode_sequence(&xdr, &res->seq_res, rqstp); | ||
5191 | if (status) | ||
4487 | goto out; | 5192 | goto out; |
4488 | status = decode_putfh(&xdr); | 5193 | status = decode_putfh(&xdr); |
4489 | if (status != 0) | 5194 | if (status != 0) |
@@ -4497,7 +5202,8 @@ out: | |||
4497 | /* | 5202 | /* |
4498 | * FS_LOCATIONS request | 5203 | * FS_LOCATIONS request |
4499 | */ | 5204 | */ |
4500 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res) | 5205 | static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, |
5206 | struct nfs4_fs_locations_res *res) | ||
4501 | { | 5207 | { |
4502 | struct xdr_stream xdr; | 5208 | struct xdr_stream xdr; |
4503 | struct compound_hdr hdr; | 5209 | struct compound_hdr hdr; |
@@ -4505,18 +5211,113 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
4505 | 5211 | ||
4506 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); | 5212 | xdr_init_decode(&xdr, &req->rq_rcv_buf, p); |
4507 | status = decode_compound_hdr(&xdr, &hdr); | 5213 | status = decode_compound_hdr(&xdr, &hdr); |
4508 | if (status != 0) | 5214 | if (status) |
5215 | goto out; | ||
5216 | status = decode_sequence(&xdr, &res->seq_res, req); | ||
5217 | if (status) | ||
4509 | goto out; | 5218 | goto out; |
4510 | if ((status = decode_putfh(&xdr)) != 0) | 5219 | if ((status = decode_putfh(&xdr)) != 0) |
4511 | goto out; | 5220 | goto out; |
4512 | if ((status = decode_lookup(&xdr)) != 0) | 5221 | if ((status = decode_lookup(&xdr)) != 0) |
4513 | goto out; | 5222 | goto out; |
4514 | xdr_enter_page(&xdr, PAGE_SIZE); | 5223 | xdr_enter_page(&xdr, PAGE_SIZE); |
4515 | status = decode_getfattr(&xdr, &res->fattr, res->server); | 5224 | status = decode_getfattr(&xdr, &res->fs_locations->fattr, |
5225 | res->fs_locations->server); | ||
4516 | out: | 5226 | out: |
4517 | return status; | 5227 | return status; |
4518 | } | 5228 | } |
4519 | 5229 | ||
5230 | #if defined(CONFIG_NFS_V4_1) | ||
5231 | /* | ||
5232 | * EXCHANGE_ID request | ||
5233 | */ | ||
5234 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | ||
5235 | void *res) | ||
5236 | { | ||
5237 | struct xdr_stream xdr; | ||
5238 | struct compound_hdr hdr; | ||
5239 | int status; | ||
5240 | |||
5241 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5242 | status = decode_compound_hdr(&xdr, &hdr); | ||
5243 | if (!status) | ||
5244 | status = decode_exchange_id(&xdr, res); | ||
5245 | return status; | ||
5246 | } | ||
5247 | |||
5248 | /* | ||
5249 | * a CREATE_SESSION request | ||
5250 | */ | ||
5251 | static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5252 | struct nfs41_create_session_res *res) | ||
5253 | { | ||
5254 | struct xdr_stream xdr; | ||
5255 | struct compound_hdr hdr; | ||
5256 | int status; | ||
5257 | |||
5258 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5259 | status = decode_compound_hdr(&xdr, &hdr); | ||
5260 | if (!status) | ||
5261 | status = decode_create_session(&xdr, res); | ||
5262 | return status; | ||
5263 | } | ||
5264 | |||
5265 | /* | ||
5266 | * a DESTROY_SESSION request | ||
5267 | */ | ||
5268 | static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | ||
5269 | void *dummy) | ||
5270 | { | ||
5271 | struct xdr_stream xdr; | ||
5272 | struct compound_hdr hdr; | ||
5273 | int status; | ||
5274 | |||
5275 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5276 | status = decode_compound_hdr(&xdr, &hdr); | ||
5277 | if (!status) | ||
5278 | status = decode_destroy_session(&xdr, dummy); | ||
5279 | return status; | ||
5280 | } | ||
5281 | |||
5282 | /* | ||
5283 | * a SEQUENCE request | ||
5284 | */ | ||
5285 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | ||
5286 | struct nfs4_sequence_res *res) | ||
5287 | { | ||
5288 | struct xdr_stream xdr; | ||
5289 | struct compound_hdr hdr; | ||
5290 | int status; | ||
5291 | |||
5292 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5293 | status = decode_compound_hdr(&xdr, &hdr); | ||
5294 | if (!status) | ||
5295 | status = decode_sequence(&xdr, res, rqstp); | ||
5296 | return status; | ||
5297 | } | ||
5298 | |||
5299 | /* | ||
5300 | * a GET_LEASE_TIME request | ||
5301 | */ | ||
5302 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | ||
5303 | struct nfs4_get_lease_time_res *res) | ||
5304 | { | ||
5305 | struct xdr_stream xdr; | ||
5306 | struct compound_hdr hdr; | ||
5307 | int status; | ||
5308 | |||
5309 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5310 | status = decode_compound_hdr(&xdr, &hdr); | ||
5311 | if (!status) | ||
5312 | status = decode_sequence(&xdr, &res->lr_seq_res, rqstp); | ||
5313 | if (!status) | ||
5314 | status = decode_putrootfh(&xdr); | ||
5315 | if (!status) | ||
5316 | status = decode_fsinfo(&xdr, res->lr_fsinfo); | ||
5317 | return status; | ||
5318 | } | ||
5319 | #endif /* CONFIG_NFS_V4_1 */ | ||
5320 | |||
4520 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 5321 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
4521 | { | 5322 | { |
4522 | uint32_t bitmap[2] = {0}; | 5323 | uint32_t bitmap[2] = {0}; |
@@ -4686,6 +5487,13 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4686 | PROC(GETACL, enc_getacl, dec_getacl), | 5487 | PROC(GETACL, enc_getacl, dec_getacl), |
4687 | PROC(SETACL, enc_setacl, dec_setacl), | 5488 | PROC(SETACL, enc_setacl, dec_setacl), |
4688 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5489 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
5490 | #if defined(CONFIG_NFS_V4_1) | ||
5491 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | ||
5492 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | ||
5493 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | ||
5494 | PROC(SEQUENCE, enc_sequence, dec_sequence), | ||
5495 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | ||
5496 | #endif /* CONFIG_NFS_V4_1 */ | ||
4689 | }; | 5497 | }; |
4690 | 5498 | ||
4691 | struct rpc_version nfs_version4 = { | 5499 | struct rpc_version nfs_version4 = { |
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 4ace3c50a8eb..96c4ebfa46f4 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | 24 | ||
25 | #include "nfs4_fs.h" | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
26 | #include "iostat.h" | 27 | #include "iostat.h" |
27 | #include "fscache.h" | 28 | #include "fscache.h" |
@@ -46,6 +47,7 @@ struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) | |||
46 | memset(p, 0, sizeof(*p)); | 47 | memset(p, 0, sizeof(*p)); |
47 | INIT_LIST_HEAD(&p->pages); | 48 | INIT_LIST_HEAD(&p->pages); |
48 | p->npages = pagecount; | 49 | p->npages = pagecount; |
50 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
49 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 51 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
50 | p->pagevec = p->page_array; | 52 | p->pagevec = p->page_array; |
51 | else { | 53 | else { |
@@ -357,19 +359,25 @@ static void nfs_readpage_retry(struct rpc_task *task, struct nfs_read_data *data | |||
357 | struct nfs_readres *resp = &data->res; | 359 | struct nfs_readres *resp = &data->res; |
358 | 360 | ||
359 | if (resp->eof || resp->count == argp->count) | 361 | if (resp->eof || resp->count == argp->count) |
360 | return; | 362 | goto out; |
361 | 363 | ||
362 | /* This is a short read! */ | 364 | /* This is a short read! */ |
363 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); | 365 | nfs_inc_stats(data->inode, NFSIOS_SHORTREAD); |
364 | /* Has the server at least made some progress? */ | 366 | /* Has the server at least made some progress? */ |
365 | if (resp->count == 0) | 367 | if (resp->count == 0) |
366 | return; | 368 | goto out; |
367 | 369 | ||
368 | /* Yes, so retry the read at the end of the data */ | 370 | /* Yes, so retry the read at the end of the data */ |
369 | argp->offset += resp->count; | 371 | argp->offset += resp->count; |
370 | argp->pgbase += resp->count; | 372 | argp->pgbase += resp->count; |
371 | argp->count -= resp->count; | 373 | argp->count -= resp->count; |
372 | rpc_restart_call(task); | 374 | nfs4_restart_rpc(task, NFS_SERVER(data->inode)->nfs_client); |
375 | return; | ||
376 | out: | ||
377 | nfs4_sequence_free_slot(NFS_SERVER(data->inode)->nfs_client, | ||
378 | &data->res.seq_res); | ||
379 | return; | ||
380 | |||
373 | } | 381 | } |
374 | 382 | ||
375 | /* | 383 | /* |
@@ -406,7 +414,23 @@ static void nfs_readpage_release_partial(void *calldata) | |||
406 | nfs_readdata_release(calldata); | 414 | nfs_readdata_release(calldata); |
407 | } | 415 | } |
408 | 416 | ||
417 | #if defined(CONFIG_NFS_V4_1) | ||
418 | void nfs_read_prepare(struct rpc_task *task, void *calldata) | ||
419 | { | ||
420 | struct nfs_read_data *data = calldata; | ||
421 | |||
422 | if (nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client, | ||
423 | &data->args.seq_args, &data->res.seq_res, | ||
424 | 0, task)) | ||
425 | return; | ||
426 | rpc_call_start(task); | ||
427 | } | ||
428 | #endif /* CONFIG_NFS_V4_1 */ | ||
429 | |||
409 | static const struct rpc_call_ops nfs_read_partial_ops = { | 430 | static const struct rpc_call_ops nfs_read_partial_ops = { |
431 | #if defined(CONFIG_NFS_V4_1) | ||
432 | .rpc_call_prepare = nfs_read_prepare, | ||
433 | #endif /* CONFIG_NFS_V4_1 */ | ||
410 | .rpc_call_done = nfs_readpage_result_partial, | 434 | .rpc_call_done = nfs_readpage_result_partial, |
411 | .rpc_release = nfs_readpage_release_partial, | 435 | .rpc_release = nfs_readpage_release_partial, |
412 | }; | 436 | }; |
@@ -470,6 +494,9 @@ static void nfs_readpage_release_full(void *calldata) | |||
470 | } | 494 | } |
471 | 495 | ||
472 | static const struct rpc_call_ops nfs_read_full_ops = { | 496 | static const struct rpc_call_ops nfs_read_full_ops = { |
497 | #if defined(CONFIG_NFS_V4_1) | ||
498 | .rpc_call_prepare = nfs_read_prepare, | ||
499 | #endif /* CONFIG_NFS_V4_1 */ | ||
473 | .rpc_call_done = nfs_readpage_result_full, | 500 | .rpc_call_done = nfs_readpage_result_full, |
474 | .rpc_release = nfs_readpage_release_full, | 501 | .rpc_release = nfs_readpage_release_full, |
475 | }; | 502 | }; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b798ed1bd36d..3d460527daab 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -90,6 +90,7 @@ enum { | |||
90 | Opt_mountport, | 90 | Opt_mountport, |
91 | Opt_mountvers, | 91 | Opt_mountvers, |
92 | Opt_nfsvers, | 92 | Opt_nfsvers, |
93 | Opt_minorversion, | ||
93 | 94 | ||
94 | /* Mount options that take string arguments */ | 95 | /* Mount options that take string arguments */ |
95 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, | 96 | Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost, |
@@ -155,6 +156,7 @@ static const match_table_t nfs_mount_option_tokens = { | |||
155 | { Opt_mountvers, "mountvers=%s" }, | 156 | { Opt_mountvers, "mountvers=%s" }, |
156 | { Opt_nfsvers, "nfsvers=%s" }, | 157 | { Opt_nfsvers, "nfsvers=%s" }, |
157 | { Opt_nfsvers, "vers=%s" }, | 158 | { Opt_nfsvers, "vers=%s" }, |
159 | { Opt_minorversion, "minorversion=%u" }, | ||
158 | 160 | ||
159 | { Opt_sec, "sec=%s" }, | 161 | { Opt_sec, "sec=%s" }, |
160 | { Opt_proto, "proto=%s" }, | 162 | { Opt_proto, "proto=%s" }, |
@@ -977,6 +979,7 @@ static int nfs_parse_mount_options(char *raw, | |||
977 | while ((p = strsep(&raw, ",")) != NULL) { | 979 | while ((p = strsep(&raw, ",")) != NULL) { |
978 | substring_t args[MAX_OPT_ARGS]; | 980 | substring_t args[MAX_OPT_ARGS]; |
979 | unsigned long option; | 981 | unsigned long option; |
982 | int int_option; | ||
980 | int token; | 983 | int token; |
981 | 984 | ||
982 | if (!*p) | 985 | if (!*p) |
@@ -1247,6 +1250,13 @@ static int nfs_parse_mount_options(char *raw, | |||
1247 | goto out_invalid_value; | 1250 | goto out_invalid_value; |
1248 | } | 1251 | } |
1249 | break; | 1252 | break; |
1253 | case Opt_minorversion: | ||
1254 | if (match_int(args, &int_option)) | ||
1255 | return 0; | ||
1256 | if (int_option < 0 || int_option > NFS4_MAX_MINOR_VERSION) | ||
1257 | return 0; | ||
1258 | mnt->minorversion = int_option; | ||
1259 | break; | ||
1250 | 1260 | ||
1251 | /* | 1261 | /* |
1252 | * options that take text values | 1262 | * options that take text values |
@@ -2308,6 +2318,7 @@ static int nfs4_validate_mount_data(void *options, | |||
2308 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ | 2318 | args->nfs_server.port = NFS_PORT; /* 2049 unless user set port= */ |
2309 | args->auth_flavors[0] = RPC_AUTH_UNIX; | 2319 | args->auth_flavors[0] = RPC_AUTH_UNIX; |
2310 | args->auth_flavor_len = 0; | 2320 | args->auth_flavor_len = 0; |
2321 | args->minorversion = 0; | ||
2311 | 2322 | ||
2312 | switch (data->version) { | 2323 | switch (data->version) { |
2313 | case 1: | 2324 | case 1: |
@@ -2524,12 +2535,13 @@ static void nfs4_kill_super(struct super_block *sb) | |||
2524 | { | 2535 | { |
2525 | struct nfs_server *server = NFS_SB(sb); | 2536 | struct nfs_server *server = NFS_SB(sb); |
2526 | 2537 | ||
2538 | dprintk("--> %s\n", __func__); | ||
2527 | nfs_super_return_all_delegations(sb); | 2539 | nfs_super_return_all_delegations(sb); |
2528 | kill_anon_super(sb); | 2540 | kill_anon_super(sb); |
2529 | |||
2530 | nfs4_renewd_prepare_shutdown(server); | 2541 | nfs4_renewd_prepare_shutdown(server); |
2531 | nfs_fscache_release_super_cookie(sb); | 2542 | nfs_fscache_release_super_cookie(sb); |
2532 | nfs_free_server(server); | 2543 | nfs_free_server(server); |
2544 | dprintk("<-- %s\n", __func__); | ||
2533 | } | 2545 | } |
2534 | 2546 | ||
2535 | /* | 2547 | /* |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index ecc295347775..1064c91ae810 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/wait.h> | 15 | #include <linux/wait.h> |
16 | 16 | ||
17 | #include "internal.h" | 17 | #include "internal.h" |
18 | #include "nfs4_fs.h" | ||
18 | 19 | ||
19 | struct nfs_unlinkdata { | 20 | struct nfs_unlinkdata { |
20 | struct hlist_node list; | 21 | struct hlist_node list; |
@@ -82,7 +83,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) | |||
82 | struct inode *dir = data->dir; | 83 | struct inode *dir = data->dir; |
83 | 84 | ||
84 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) | 85 | if (!NFS_PROTO(dir)->unlink_done(task, dir)) |
85 | rpc_restart_call(task); | 86 | nfs4_restart_rpc(task, NFS_SERVER(dir)->nfs_client); |
86 | } | 87 | } |
87 | 88 | ||
88 | /** | 89 | /** |
@@ -102,9 +103,25 @@ static void nfs_async_unlink_release(void *calldata) | |||
102 | nfs_sb_deactive(sb); | 103 | nfs_sb_deactive(sb); |
103 | } | 104 | } |
104 | 105 | ||
106 | #if defined(CONFIG_NFS_V4_1) | ||
107 | void nfs_unlink_prepare(struct rpc_task *task, void *calldata) | ||
108 | { | ||
109 | struct nfs_unlinkdata *data = calldata; | ||
110 | struct nfs_server *server = NFS_SERVER(data->dir); | ||
111 | |||
112 | if (nfs4_setup_sequence(server->nfs_client, &data->args.seq_args, | ||
113 | &data->res.seq_res, 1, task)) | ||
114 | return; | ||
115 | rpc_call_start(task); | ||
116 | } | ||
117 | #endif /* CONFIG_NFS_V4_1 */ | ||
118 | |||
105 | static const struct rpc_call_ops nfs_unlink_ops = { | 119 | static const struct rpc_call_ops nfs_unlink_ops = { |
106 | .rpc_call_done = nfs_async_unlink_done, | 120 | .rpc_call_done = nfs_async_unlink_done, |
107 | .rpc_release = nfs_async_unlink_release, | 121 | .rpc_release = nfs_async_unlink_release, |
122 | #if defined(CONFIG_NFS_V4_1) | ||
123 | .rpc_call_prepare = nfs_unlink_prepare, | ||
124 | #endif /* CONFIG_NFS_V4_1 */ | ||
108 | }; | 125 | }; |
109 | 126 | ||
110 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) | 127 | static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct nfs_unlinkdata *data) |
@@ -241,6 +258,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
241 | status = PTR_ERR(data->cred); | 258 | status = PTR_ERR(data->cred); |
242 | goto out_free; | 259 | goto out_free; |
243 | } | 260 | } |
261 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
244 | 262 | ||
245 | status = -EBUSY; | 263 | status = -EBUSY; |
246 | spin_lock(&dentry->d_lock); | 264 | spin_lock(&dentry->d_lock); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e560a78995a3..ce728829f79a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "delegation.h" | 25 | #include "delegation.h" |
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | #include "iostat.h" | 27 | #include "iostat.h" |
28 | #include "nfs4_fs.h" | ||
28 | 29 | ||
29 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 30 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
30 | 31 | ||
@@ -52,6 +53,7 @@ struct nfs_write_data *nfs_commitdata_alloc(void) | |||
52 | if (p) { | 53 | if (p) { |
53 | memset(p, 0, sizeof(*p)); | 54 | memset(p, 0, sizeof(*p)); |
54 | INIT_LIST_HEAD(&p->pages); | 55 | INIT_LIST_HEAD(&p->pages); |
56 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
55 | } | 57 | } |
56 | return p; | 58 | return p; |
57 | } | 59 | } |
@@ -71,6 +73,7 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) | |||
71 | memset(p, 0, sizeof(*p)); | 73 | memset(p, 0, sizeof(*p)); |
72 | INIT_LIST_HEAD(&p->pages); | 74 | INIT_LIST_HEAD(&p->pages); |
73 | p->npages = pagecount; | 75 | p->npages = pagecount; |
76 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
74 | if (pagecount <= ARRAY_SIZE(p->page_array)) | 77 | if (pagecount <= ARRAY_SIZE(p->page_array)) |
75 | p->pagevec = p->page_array; | 78 | p->pagevec = p->page_array; |
76 | else { | 79 | else { |
@@ -1048,7 +1051,23 @@ out: | |||
1048 | nfs_writedata_release(calldata); | 1051 | nfs_writedata_release(calldata); |
1049 | } | 1052 | } |
1050 | 1053 | ||
1054 | #if defined(CONFIG_NFS_V4_1) | ||
1055 | void nfs_write_prepare(struct rpc_task *task, void *calldata) | ||
1056 | { | ||
1057 | struct nfs_write_data *data = calldata; | ||
1058 | struct nfs_client *clp = (NFS_SERVER(data->inode))->nfs_client; | ||
1059 | |||
1060 | if (nfs4_setup_sequence(clp, &data->args.seq_args, | ||
1061 | &data->res.seq_res, 1, task)) | ||
1062 | return; | ||
1063 | rpc_call_start(task); | ||
1064 | } | ||
1065 | #endif /* CONFIG_NFS_V4_1 */ | ||
1066 | |||
1051 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1067 | static const struct rpc_call_ops nfs_write_partial_ops = { |
1068 | #if defined(CONFIG_NFS_V4_1) | ||
1069 | .rpc_call_prepare = nfs_write_prepare, | ||
1070 | #endif /* CONFIG_NFS_V4_1 */ | ||
1052 | .rpc_call_done = nfs_writeback_done_partial, | 1071 | .rpc_call_done = nfs_writeback_done_partial, |
1053 | .rpc_release = nfs_writeback_release_partial, | 1072 | .rpc_release = nfs_writeback_release_partial, |
1054 | }; | 1073 | }; |
@@ -1111,6 +1130,9 @@ remove_request: | |||
1111 | } | 1130 | } |
1112 | 1131 | ||
1113 | static const struct rpc_call_ops nfs_write_full_ops = { | 1132 | static const struct rpc_call_ops nfs_write_full_ops = { |
1133 | #if defined(CONFIG_NFS_V4_1) | ||
1134 | .rpc_call_prepare = nfs_write_prepare, | ||
1135 | #endif /* CONFIG_NFS_V4_1 */ | ||
1114 | .rpc_call_done = nfs_writeback_done_full, | 1136 | .rpc_call_done = nfs_writeback_done_full, |
1115 | .rpc_release = nfs_writeback_release_full, | 1137 | .rpc_release = nfs_writeback_release_full, |
1116 | }; | 1138 | }; |
@@ -1123,6 +1145,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1123 | { | 1145 | { |
1124 | struct nfs_writeargs *argp = &data->args; | 1146 | struct nfs_writeargs *argp = &data->args; |
1125 | struct nfs_writeres *resp = &data->res; | 1147 | struct nfs_writeres *resp = &data->res; |
1148 | struct nfs_server *server = NFS_SERVER(data->inode); | ||
1126 | int status; | 1149 | int status; |
1127 | 1150 | ||
1128 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", | 1151 | dprintk("NFS: %5u nfs_writeback_done (status %d)\n", |
@@ -1155,7 +1178,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1155 | if (time_before(complain, jiffies)) { | 1178 | if (time_before(complain, jiffies)) { |
1156 | dprintk("NFS: faulty NFS server %s:" | 1179 | dprintk("NFS: faulty NFS server %s:" |
1157 | " (committed = %d) != (stable = %d)\n", | 1180 | " (committed = %d) != (stable = %d)\n", |
1158 | NFS_SERVER(data->inode)->nfs_client->cl_hostname, | 1181 | server->nfs_client->cl_hostname, |
1159 | resp->verf->committed, argp->stable); | 1182 | resp->verf->committed, argp->stable); |
1160 | complain = jiffies + 300 * HZ; | 1183 | complain = jiffies + 300 * HZ; |
1161 | } | 1184 | } |
@@ -1181,7 +1204,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1181 | */ | 1204 | */ |
1182 | argp->stable = NFS_FILE_SYNC; | 1205 | argp->stable = NFS_FILE_SYNC; |
1183 | } | 1206 | } |
1184 | rpc_restart_call(task); | 1207 | nfs4_restart_rpc(task, server->nfs_client); |
1185 | return -EAGAIN; | 1208 | return -EAGAIN; |
1186 | } | 1209 | } |
1187 | if (time_before(complain, jiffies)) { | 1210 | if (time_before(complain, jiffies)) { |
@@ -1193,6 +1216,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1193 | /* Can't do anything about it except throw an error. */ | 1216 | /* Can't do anything about it except throw an error. */ |
1194 | task->tk_status = -EIO; | 1217 | task->tk_status = -EIO; |
1195 | } | 1218 | } |
1219 | nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res); | ||
1196 | return 0; | 1220 | return 0; |
1197 | } | 1221 | } |
1198 | 1222 | ||
@@ -1349,6 +1373,9 @@ static void nfs_commit_release(void *calldata) | |||
1349 | } | 1373 | } |
1350 | 1374 | ||
1351 | static const struct rpc_call_ops nfs_commit_ops = { | 1375 | static const struct rpc_call_ops nfs_commit_ops = { |
1376 | #if defined(CONFIG_NFS_V4_1) | ||
1377 | .rpc_call_prepare = nfs_write_prepare, | ||
1378 | #endif /* CONFIG_NFS_V4_1 */ | ||
1352 | .rpc_call_done = nfs_commit_done, | 1379 | .rpc_call_done = nfs_commit_done, |
1353 | .rpc_release = nfs_commit_release, | 1380 | .rpc_release = nfs_commit_release, |
1354 | }; | 1381 | }; |