blob: f6068bf3823a9c598f85fdb6a2581fed3a69da4c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/nfs/nfs4xdr.c
3 *
4 * Client-side XDR for NFSv4.
5 *
6 * Copyright (c) 2002 The Regents of the University of Michigan.
7 * All rights reserved.
8 *
9 * Kendrick Smith <kmsmith@umich.edu>
10 * Andy Adamson <andros@umich.edu>
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include <linux/param.h>
39#include <linux/time.h>
40#include <linux/mm.h>
41#include <linux/slab.h>
42#include <linux/utsname.h>
43#include <linux/errno.h>
44#include <linux/string.h>
45#include <linux/in.h>
46#include <linux/pagemap.h>
47#include <linux/proc_fs.h>
48#include <linux/kdev_t.h>
49#include <linux/sunrpc/clnt.h>
50#include <linux/nfs.h>
51#include <linux/nfs4.h>
52#include <linux/nfs_fs.h>
53#include <linux/nfs_idmap.h>
Trond Myklebust4ce79712005-06-22 17:16:21 +000054#include "nfs4_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
56#define NFSDBG_FACILITY NFSDBG_XDR
57
58/* Mapping from NFS error code to "errno" error code. */
59#define errno_NFSERR_IO EIO
60
David Howells0a8ea432006-08-22 20:06:08 -040061static int nfs4_stat_to_errno(int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63/* NFSv4 COMPOUND tags are only wanted for debugging purposes */
64#ifdef DEBUG
65#define NFS4_MAXTAGLEN 20
66#else
67#define NFS4_MAXTAGLEN 0
68#endif
69
70/* lock,open owner id:
71 * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2)
72 */
Trond Myklebust2cebf822007-07-02 13:57:28 -040073#define open_owner_id_maxsz (1 + 1)
74#define lock_owner_id_maxsz (1 + 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
76#define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
77#define op_encode_hdr_maxsz (1)
78#define op_decode_hdr_maxsz (2)
79#define encode_putfh_maxsz (op_encode_hdr_maxsz + 1 + \
80 (NFS4_FHSIZE >> 2))
81#define decode_putfh_maxsz (op_decode_hdr_maxsz)
82#define encode_putrootfh_maxsz (op_encode_hdr_maxsz)
83#define decode_putrootfh_maxsz (op_decode_hdr_maxsz)
84#define encode_getfh_maxsz (op_encode_hdr_maxsz)
85#define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \
86 ((3+NFS4_FHSIZE) >> 2))
J. Bruce Fields96928202005-06-22 17:16:22 +000087#define nfs4_fattr_bitmap_maxsz 3
88#define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
90#define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
Trond Myklebustbd625ba2007-07-08 18:38:23 -040091#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
92#define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
J. Bruce Fields96928202005-06-22 17:16:22 +000093/* This is based on getfattr, which uses the most attributes: */
94#define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
Trond Myklebustbd625ba2007-07-08 18:38:23 -040095 3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
J. Bruce Fields96928202005-06-22 17:16:22 +000096#define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
97 nfs4_fattr_value_maxsz)
98#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099#define encode_savefh_maxsz (op_encode_hdr_maxsz)
100#define decode_savefh_maxsz (op_decode_hdr_maxsz)
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400101#define encode_restorefh_maxsz (op_encode_hdr_maxsz)
102#define decode_restorefh_maxsz (op_decode_hdr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103#define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2)
104#define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11)
105#define encode_renew_maxsz (op_encode_hdr_maxsz + 3)
106#define decode_renew_maxsz (op_decode_hdr_maxsz)
107#define encode_setclientid_maxsz \
108 (op_encode_hdr_maxsz + \
109 4 /*server->ip_addr*/ + \
110 1 /*Netid*/ + \
111 6 /*uaddr*/ + \
112 6 + (NFS4_VERIFIER_SIZE >> 2))
113#define decode_setclientid_maxsz \
114 (op_decode_hdr_maxsz + \
115 2 + \
116 1024) /* large value for CLID_INUSE */
117#define encode_setclientid_confirm_maxsz \
118 (op_encode_hdr_maxsz + \
119 3 + (NFS4_VERIFIER_SIZE >> 2))
120#define decode_setclientid_confirm_maxsz \
121 (op_decode_hdr_maxsz)
122#define encode_lookup_maxsz (op_encode_hdr_maxsz + \
123 1 + ((3 + NFS4_FHSIZE) >> 2))
Trond Myklebust2cebf822007-07-02 13:57:28 -0400124#define encode_share_access_maxsz \
125 (2)
126#define encode_createmode_maxsz (1 + nfs4_fattr_maxsz)
127#define encode_opentype_maxsz (1 + encode_createmode_maxsz)
128#define encode_claim_null_maxsz (1 + nfs4_name_maxsz)
129#define encode_open_maxsz (op_encode_hdr_maxsz + \
130 2 + encode_share_access_maxsz + 2 + \
131 open_owner_id_maxsz + \
132 encode_opentype_maxsz + \
133 encode_claim_null_maxsz)
134#define decode_ace_maxsz (3 + nfs4_owner_maxsz)
135#define decode_delegation_maxsz (1 + XDR_QUADLEN(NFS4_STATEID_SIZE) + 1 + \
136 decode_ace_maxsz)
137#define decode_change_info_maxsz (5)
138#define decode_open_maxsz (op_decode_hdr_maxsz + \
139 XDR_QUADLEN(NFS4_STATEID_SIZE) + \
140 decode_change_info_maxsz + 1 + \
141 nfs4_fattr_bitmap_maxsz + \
142 decode_delegation_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143#define encode_remove_maxsz (op_encode_hdr_maxsz + \
144 nfs4_name_maxsz)
145#define encode_rename_maxsz (op_encode_hdr_maxsz + \
146 2 * nfs4_name_maxsz)
147#define decode_rename_maxsz (op_decode_hdr_maxsz + 5 + 5)
148#define encode_link_maxsz (op_encode_hdr_maxsz + \
149 nfs4_name_maxsz)
150#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
151#define encode_symlink_maxsz (op_encode_hdr_maxsz + \
152 1 + nfs4_name_maxsz + \
Chuck Lever94a6d752006-08-22 20:06:23 -0400153 1 + \
J. Bruce Fields96928202005-06-22 17:16:22 +0000154 nfs4_fattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
156#define encode_create_maxsz (op_encode_hdr_maxsz + \
157 2 + nfs4_name_maxsz + \
J. Bruce Fields96928202005-06-22 17:16:22 +0000158 nfs4_fattr_maxsz)
Trond Myklebust2cebf822007-07-02 13:57:28 -0400159#define decode_create_maxsz (op_decode_hdr_maxsz + \
160 decode_change_info_maxsz + \
161 nfs4_fattr_bitmap_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
163#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
164#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */
165#define NFS4_dec_compound_sz (1024) /* XXX: large enough? */
166#define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \
167 encode_putfh_maxsz + \
168 op_encode_hdr_maxsz + 7)
169#define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \
170 decode_putfh_maxsz + \
171 op_decode_hdr_maxsz + 2)
172#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \
173 encode_putfh_maxsz + \
174 op_encode_hdr_maxsz)
175#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \
176 decode_putfh_maxsz + \
177 op_decode_hdr_maxsz)
178#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \
179 encode_putfh_maxsz + \
180 op_encode_hdr_maxsz + 9)
181#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \
182 decode_putfh_maxsz + \
183 op_decode_hdr_maxsz + 2)
184#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \
185 encode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400186 op_encode_hdr_maxsz + 8 + \
187 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188#define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \
189 decode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400190 op_decode_hdr_maxsz + 4 + \
191 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \
193 encode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400194 op_encode_hdr_maxsz + 3 + \
195 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196#define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \
197 decode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400198 op_decode_hdr_maxsz + 2 + \
199 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400201 encode_putfh_maxsz + \
202 encode_savefh_maxsz + \
203 encode_open_maxsz + \
204 encode_getfh_maxsz + \
205 encode_getattr_maxsz + \
206 encode_restorefh_maxsz + \
207 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400209 decode_putfh_maxsz + \
210 decode_savefh_maxsz + \
211 decode_open_maxsz + \
212 decode_getfh_maxsz + \
213 decode_getattr_maxsz + \
214 decode_restorefh_maxsz + \
215 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216#define NFS4_enc_open_confirm_sz \
217 (compound_encode_hdr_maxsz + \
218 encode_putfh_maxsz + \
219 op_encode_hdr_maxsz + 5)
220#define NFS4_dec_open_confirm_sz (compound_decode_hdr_maxsz + \
221 decode_putfh_maxsz + \
222 op_decode_hdr_maxsz + 4)
223#define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \
224 encode_putfh_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400225 encode_open_maxsz + \
226 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \
228 decode_putfh_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400229 decode_open_maxsz + \
230 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231#define NFS4_enc_open_downgrade_sz \
232 (compound_encode_hdr_maxsz + \
233 encode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400234 op_encode_hdr_maxsz + 7 + \
235 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236#define NFS4_dec_open_downgrade_sz \
237 (compound_decode_hdr_maxsz + \
238 decode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400239 op_decode_hdr_maxsz + 4 + \
240 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \
242 encode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400243 op_encode_hdr_maxsz + 5 + \
244 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \
246 decode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400247 op_decode_hdr_maxsz + 4 + \
248 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \
250 encode_putfh_maxsz + \
251 op_encode_hdr_maxsz + 4 + \
J. Bruce Fields96928202005-06-22 17:16:22 +0000252 nfs4_fattr_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 encode_getattr_maxsz)
254#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \
255 decode_putfh_maxsz + \
Chuck Lever6ce7dc92007-05-08 18:23:28 -0400256 op_decode_hdr_maxsz + 3 + \
257 nfs4_fattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258#define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \
259 encode_putfh_maxsz + \
260 encode_fsinfo_maxsz)
261#define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \
262 decode_putfh_maxsz + \
263 decode_fsinfo_maxsz)
264#define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \
265 encode_renew_maxsz)
266#define NFS4_dec_renew_sz (compound_decode_hdr_maxsz + \
267 decode_renew_maxsz)
268#define NFS4_enc_setclientid_sz (compound_encode_hdr_maxsz + \
269 encode_setclientid_maxsz)
270#define NFS4_dec_setclientid_sz (compound_decode_hdr_maxsz + \
271 decode_setclientid_maxsz)
272#define NFS4_enc_setclientid_confirm_sz \
273 (compound_encode_hdr_maxsz + \
274 encode_setclientid_confirm_maxsz + \
275 encode_putrootfh_maxsz + \
276 encode_fsinfo_maxsz)
277#define NFS4_dec_setclientid_confirm_sz \
278 (compound_decode_hdr_maxsz + \
279 decode_setclientid_confirm_maxsz + \
280 decode_putrootfh_maxsz + \
281 decode_fsinfo_maxsz)
282#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
283 encode_putfh_maxsz + \
284 encode_getattr_maxsz + \
285 op_encode_hdr_maxsz + \
286 1 + 1 + 2 + 2 + \
287 1 + 4 + 1 + 2 + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400288 lock_owner_id_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289#define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \
290 decode_putfh_maxsz + \
291 decode_getattr_maxsz + \
292 op_decode_hdr_maxsz + \
293 2 + 2 + 1 + 2 + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400294 lock_owner_id_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295#define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \
296 encode_putfh_maxsz + \
297 encode_getattr_maxsz + \
298 op_encode_hdr_maxsz + \
299 1 + 2 + 2 + 2 + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400300 lock_owner_id_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#define NFS4_dec_lockt_sz (NFS4_dec_lock_sz)
302#define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \
303 encode_putfh_maxsz + \
304 encode_getattr_maxsz + \
305 op_encode_hdr_maxsz + \
306 1 + 1 + 4 + 2 + 2)
307#define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \
308 decode_putfh_maxsz + \
309 decode_getattr_maxsz + \
310 op_decode_hdr_maxsz + 4)
311#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
312 encode_putfh_maxsz + \
313 op_encode_hdr_maxsz + 1)
314#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
315 decode_putfh_maxsz + \
316 op_decode_hdr_maxsz + 2)
317#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
318 encode_putfh_maxsz + \
319 encode_getattr_maxsz)
320#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \
321 decode_putfh_maxsz + \
322 decode_getattr_maxsz)
323#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \
324 encode_putfh_maxsz + \
325 encode_lookup_maxsz + \
326 encode_getattr_maxsz + \
327 encode_getfh_maxsz)
328#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \
329 decode_putfh_maxsz + \
330 op_decode_hdr_maxsz + \
331 decode_getattr_maxsz + \
332 decode_getfh_maxsz)
333#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
334 encode_putrootfh_maxsz + \
335 encode_getattr_maxsz + \
336 encode_getfh_maxsz)
337#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
338 decode_putrootfh_maxsz + \
339 decode_getattr_maxsz + \
340 decode_getfh_maxsz)
341#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \
342 encode_putfh_maxsz + \
Trond Myklebust16e42952005-10-27 22:12:44 -0400343 encode_remove_maxsz + \
344 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345#define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \
346 decode_putfh_maxsz + \
Trond Myklebust16e42952005-10-27 22:12:44 -0400347 op_decode_hdr_maxsz + 5 + \
348 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349#define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \
350 encode_putfh_maxsz + \
351 encode_savefh_maxsz + \
352 encode_putfh_maxsz + \
Trond Myklebust6caf2c82005-10-27 22:12:43 -0400353 encode_rename_maxsz + \
354 encode_getattr_maxsz + \
355 encode_restorefh_maxsz + \
356 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357#define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \
358 decode_putfh_maxsz + \
359 decode_savefh_maxsz + \
360 decode_putfh_maxsz + \
Trond Myklebust6caf2c82005-10-27 22:12:43 -0400361 decode_rename_maxsz + \
362 decode_getattr_maxsz + \
363 decode_restorefh_maxsz + \
364 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365#define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \
366 encode_putfh_maxsz + \
367 encode_savefh_maxsz + \
368 encode_putfh_maxsz + \
Trond Myklebust91ba2ee2005-10-27 22:12:42 -0400369 encode_link_maxsz + \
370 decode_getattr_maxsz + \
371 encode_restorefh_maxsz + \
372 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373#define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \
374 decode_putfh_maxsz + \
375 decode_savefh_maxsz + \
376 decode_putfh_maxsz + \
Trond Myklebust91ba2ee2005-10-27 22:12:42 -0400377 decode_link_maxsz + \
378 decode_getattr_maxsz + \
379 decode_restorefh_maxsz + \
380 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381#define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \
382 encode_putfh_maxsz + \
383 encode_symlink_maxsz + \
384 encode_getattr_maxsz + \
385 encode_getfh_maxsz)
386#define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \
387 decode_putfh_maxsz + \
388 decode_symlink_maxsz + \
389 decode_getattr_maxsz + \
390 decode_getfh_maxsz)
391#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
392 encode_putfh_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400393 encode_savefh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 encode_create_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400395 encode_getfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 encode_getattr_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400397 encode_restorefh_maxsz + \
398 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399#define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \
400 decode_putfh_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400401 decode_savefh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 decode_create_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400403 decode_getfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 decode_getattr_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400405 decode_restorefh_maxsz + \
406 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407#define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \
408 encode_putfh_maxsz + \
409 encode_getattr_maxsz)
410#define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \
411 decode_putfh_maxsz + \
412 decode_getattr_maxsz)
413#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \
414 encode_putfh_maxsz + \
415 encode_getattr_maxsz)
416#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \
417 decode_putfh_maxsz + \
418 op_decode_hdr_maxsz + 12)
419#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
Trond Myklebustab91f262007-02-02 14:47:17 -0800420 encode_putfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 encode_getattr_maxsz)
422#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
Trond Myklebustab91f262007-02-02 14:47:17 -0800423 decode_putfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 decode_getattr_maxsz)
425#define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \
426 encode_putfh_maxsz + \
Trond Myklebustfa178f22006-01-03 09:55:38 +0100427 encode_delegreturn_maxsz + \
428 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
Trond Myklebustfa178f22006-01-03 09:55:38 +0100430 decode_delegreturn_maxsz + \
431 decode_getattr_maxsz)
J. Bruce Fields029d1052005-06-22 17:16:22 +0000432#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
433 encode_putfh_maxsz + \
434 encode_getattr_maxsz)
435#define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \
436 decode_putfh_maxsz + \
437 op_decode_hdr_maxsz + \
438 nfs4_fattr_bitmap_maxsz + 1)
J. Bruce Fields23ec6962005-06-22 17:16:22 +0000439#define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \
440 encode_putfh_maxsz + \
441 op_encode_hdr_maxsz + 4 + \
442 nfs4_fattr_bitmap_maxsz + 1)
443#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
444 decode_putfh_maxsz + \
445 op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
Trond Myklebust683b57b2006-06-09 09:34:22 -0400446#define NFS4_enc_fs_locations_sz \
447 (compound_encode_hdr_maxsz + \
448 encode_putfh_maxsz + \
449 encode_getattr_maxsz)
450#define NFS4_dec_fs_locations_sz \
451 (compound_decode_hdr_maxsz + \
452 decode_putfh_maxsz + \
453 op_decode_hdr_maxsz + \
454 nfs4_fattr_bitmap_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456static struct {
457 unsigned int mode;
458 unsigned int nfs2type;
459} nfs_type2fmt[] = {
460 { 0, NFNON },
461 { S_IFREG, NFREG },
462 { S_IFDIR, NFDIR },
463 { S_IFBLK, NFBLK },
464 { S_IFCHR, NFCHR },
465 { S_IFLNK, NFLNK },
466 { S_IFSOCK, NFSOCK },
467 { S_IFIFO, NFFIFO },
468 { 0, NFNON },
469 { 0, NFNON },
470};
471
472struct compound_hdr {
473 int32_t status;
474 uint32_t nops;
475 uint32_t taglen;
476 char * tag;
477};
478
479/*
480 * START OF "GENERIC" ENCODE ROUTINES.
481 * These may look a little ugly since they are imported from a "generic"
482 * set of XDR encode/decode routines which are intended to be shared by
483 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
484 *
485 * If the pain of reading these is too great, it should be a straightforward
486 * task to translate them into Linux-specific versions which are more
487 * consistent with the style used in NFSv2/v3...
488 */
489#define WRITE32(n) *p++ = htonl(n)
490#define WRITE64(n) do { \
491 *p++ = htonl((uint32_t)((n) >> 32)); \
492 *p++ = htonl((uint32_t)(n)); \
493} while (0)
494#define WRITEMEM(ptr,nbytes) do { \
495 p = xdr_encode_opaque_fixed(p, ptr, nbytes); \
496} while (0)
497
498#define RESERVE_SPACE(nbytes) do { \
499 p = xdr_reserve_space(xdr, nbytes); \
500 if (!p) printk("RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
501 BUG_ON(!p); \
502} while (0)
503
504static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
505{
Al Viro8687b632006-10-19 23:28:48 -0700506 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 p = xdr_reserve_space(xdr, 4 + len);
509 BUG_ON(p == NULL);
510 xdr_encode_opaque(p, str, len);
511}
512
513static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
514{
Al Viro8687b632006-10-19 23:28:48 -0700515 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517 dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
518 BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
519 RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2));
520 WRITE32(hdr->taglen);
521 WRITEMEM(hdr->tag, hdr->taglen);
522 WRITE32(NFS4_MINOR_VERSION);
523 WRITE32(hdr->nops);
524 return 0;
525}
526
527static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
528{
Al Viro8687b632006-10-19 23:28:48 -0700529 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531 p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
532 BUG_ON(p == NULL);
533 xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
534}
535
536static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
537{
538 char owner_name[IDMAP_NAMESZ];
539 char owner_group[IDMAP_NAMESZ];
540 int owner_namelen = 0;
541 int owner_grouplen = 0;
Al Viro8687b632006-10-19 23:28:48 -0700542 __be32 *p;
543 __be32 *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 int len;
545 uint32_t bmval0 = 0;
546 uint32_t bmval1 = 0;
547 int status;
548
549 /*
550 * We reserve enough space to write the entire attribute buffer at once.
551 * In the worst-case, this would be
552 * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
553 * = 36 bytes, plus any contribution from variable-length fields
J. Bruce Fields23ec6962005-06-22 17:16:22 +0000554 * such as owner/group.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 */
556 len = 16;
557
558 /* Sigh */
559 if (iap->ia_valid & ATTR_SIZE)
560 len += 8;
561 if (iap->ia_valid & ATTR_MODE)
562 len += 4;
563 if (iap->ia_valid & ATTR_UID) {
David Howells7539bba2006-08-22 20:06:09 -0400564 owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (owner_namelen < 0) {
566 printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
567 iap->ia_uid);
568 /* XXX */
569 strcpy(owner_name, "nobody");
570 owner_namelen = sizeof("nobody") - 1;
571 /* goto out; */
572 }
573 len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
574 }
575 if (iap->ia_valid & ATTR_GID) {
David Howells7539bba2006-08-22 20:06:09 -0400576 owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 if (owner_grouplen < 0) {
578 printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
579 iap->ia_gid);
580 strcpy(owner_group, "nobody");
581 owner_grouplen = sizeof("nobody") - 1;
582 /* goto out; */
583 }
584 len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
585 }
586 if (iap->ia_valid & ATTR_ATIME_SET)
587 len += 16;
588 else if (iap->ia_valid & ATTR_ATIME)
589 len += 4;
590 if (iap->ia_valid & ATTR_MTIME_SET)
591 len += 16;
592 else if (iap->ia_valid & ATTR_MTIME)
593 len += 4;
594 RESERVE_SPACE(len);
595
596 /*
597 * We write the bitmap length now, but leave the bitmap and the attribute
598 * buffer length to be backfilled at the end of this routine.
599 */
600 WRITE32(2);
601 q = p;
602 p += 3;
603
604 if (iap->ia_valid & ATTR_SIZE) {
605 bmval0 |= FATTR4_WORD0_SIZE;
606 WRITE64(iap->ia_size);
607 }
608 if (iap->ia_valid & ATTR_MODE) {
609 bmval1 |= FATTR4_WORD1_MODE;
Trond Myklebustcf3fff52006-01-03 09:55:53 +0100610 WRITE32(iap->ia_mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 }
612 if (iap->ia_valid & ATTR_UID) {
613 bmval1 |= FATTR4_WORD1_OWNER;
614 WRITE32(owner_namelen);
615 WRITEMEM(owner_name, owner_namelen);
616 }
617 if (iap->ia_valid & ATTR_GID) {
618 bmval1 |= FATTR4_WORD1_OWNER_GROUP;
619 WRITE32(owner_grouplen);
620 WRITEMEM(owner_group, owner_grouplen);
621 }
622 if (iap->ia_valid & ATTR_ATIME_SET) {
623 bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
624 WRITE32(NFS4_SET_TO_CLIENT_TIME);
625 WRITE32(0);
626 WRITE32(iap->ia_mtime.tv_sec);
627 WRITE32(iap->ia_mtime.tv_nsec);
628 }
629 else if (iap->ia_valid & ATTR_ATIME) {
630 bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
631 WRITE32(NFS4_SET_TO_SERVER_TIME);
632 }
633 if (iap->ia_valid & ATTR_MTIME_SET) {
634 bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
635 WRITE32(NFS4_SET_TO_CLIENT_TIME);
636 WRITE32(0);
637 WRITE32(iap->ia_mtime.tv_sec);
638 WRITE32(iap->ia_mtime.tv_nsec);
639 }
640 else if (iap->ia_valid & ATTR_MTIME) {
641 bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
642 WRITE32(NFS4_SET_TO_SERVER_TIME);
643 }
644
645 /*
646 * Now we backfill the bitmap and the attribute buffer length.
647 */
648 if (len != ((char *)p - (char *)q) + 4) {
649 printk ("encode_attr: Attr length calculation error! %u != %Zu\n",
650 len, ((char *)p - (char *)q) + 4);
651 BUG();
652 }
653 len = (char *)p - (char *)q - 12;
654 *q++ = htonl(bmval0);
655 *q++ = htonl(bmval1);
656 *q++ = htonl(len);
657
658 status = 0;
659/* out: */
660 return status;
661}
662
663static int encode_access(struct xdr_stream *xdr, u32 access)
664{
Al Viro8687b632006-10-19 23:28:48 -0700665 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666
667 RESERVE_SPACE(8);
668 WRITE32(OP_ACCESS);
669 WRITE32(access);
670
671 return 0;
672}
673
674static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
675{
Al Viro8687b632006-10-19 23:28:48 -0700676 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400678 RESERVE_SPACE(8+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 WRITE32(OP_CLOSE);
Trond Myklebustcee54fc2005-10-18 14:20:12 -0700680 WRITE32(arg->seqid->sequence->counter);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400681 WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
683 return 0;
684}
685
686static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
687{
Al Viro8687b632006-10-19 23:28:48 -0700688 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 RESERVE_SPACE(16);
691 WRITE32(OP_COMMIT);
692 WRITE64(args->offset);
693 WRITE32(args->count);
694
695 return 0;
696}
697
698static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
699{
Al Viro8687b632006-10-19 23:28:48 -0700700 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 RESERVE_SPACE(8);
703 WRITE32(OP_CREATE);
704 WRITE32(create->ftype);
705
706 switch (create->ftype) {
707 case NF4LNK:
Chuck Lever94a6d752006-08-22 20:06:23 -0400708 RESERVE_SPACE(4);
709 WRITE32(create->u.symlink.len);
710 xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 break;
712
713 case NF4BLK: case NF4CHR:
714 RESERVE_SPACE(8);
715 WRITE32(create->u.device.specdata1);
716 WRITE32(create->u.device.specdata2);
717 break;
718
719 default:
720 break;
721 }
722
723 RESERVE_SPACE(4 + create->name->len);
724 WRITE32(create->name->len);
725 WRITEMEM(create->name->name, create->name->len);
726
727 return encode_attrs(xdr, create->attrs, create->server);
728}
729
730static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
731{
Al Viro8687b632006-10-19 23:28:48 -0700732 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 RESERVE_SPACE(12);
735 WRITE32(OP_GETATTR);
736 WRITE32(1);
737 WRITE32(bitmap);
738 return 0;
739}
740
741static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
742{
Al Viro8687b632006-10-19 23:28:48 -0700743 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 RESERVE_SPACE(16);
746 WRITE32(OP_GETATTR);
747 WRITE32(2);
748 WRITE32(bm0);
749 WRITE32(bm1);
750 return 0;
751}
752
753static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
754{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 return encode_getattr_two(xdr,
756 bitmask[0] & nfs4_fattr_bitmap[0],
757 bitmask[1] & nfs4_fattr_bitmap[1]);
758}
759
760static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
761{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
763 bitmask[1] & nfs4_fsinfo_bitmap[1]);
764}
765
Manoj Naik830b8e32006-06-09 09:34:25 -0400766static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
767{
768 return encode_getattr_two(xdr,
769 bitmask[0] & nfs4_fs_locations_bitmap[0],
770 bitmask[1] & nfs4_fs_locations_bitmap[1]);
771}
772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773static int encode_getfh(struct xdr_stream *xdr)
774{
Al Viro8687b632006-10-19 23:28:48 -0700775 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
777 RESERVE_SPACE(4);
778 WRITE32(OP_GETFH);
779
780 return 0;
781}
782
783static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
784{
Al Viro8687b632006-10-19 23:28:48 -0700785 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
787 RESERVE_SPACE(8 + name->len);
788 WRITE32(OP_LINK);
789 WRITE32(name->len);
790 WRITEMEM(name->name, name->len);
791
792 return 0;
793}
794
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100795static inline int nfs4_lock_type(struct file_lock *fl, int block)
796{
797 if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
798 return block ? NFS4_READW_LT : NFS4_READ_LT;
799 return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
800}
801
802static inline uint64_t nfs4_lock_length(struct file_lock *fl)
803{
804 if (fl->fl_end == OFFSET_MAX)
805 return ~(uint64_t)0;
806 return fl->fl_end - fl->fl_start + 1;
807}
808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809/*
810 * opcode,type,reclaim,offset,length,new_lock_owner = 32
811 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
812 */
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100813static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
Al Viro8687b632006-10-19 23:28:48 -0700815 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
817 RESERVE_SPACE(32);
818 WRITE32(OP_LOCK);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100819 WRITE32(nfs4_lock_type(args->fl, args->block));
820 WRITE32(args->reclaim);
821 WRITE64(args->fl->fl_start);
822 WRITE64(nfs4_lock_length(args->fl));
823 WRITE32(args->new_lock_owner);
824 if (args->new_lock_owner){
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400825 RESERVE_SPACE(4+NFS4_STATEID_SIZE+20);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100826 WRITE32(args->open_seqid->sequence->counter);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400827 WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100828 WRITE32(args->lock_seqid->sequence->counter);
829 WRITE64(args->lock_owner.clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 WRITE32(4);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100831 WRITE32(args->lock_owner.id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
833 else {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400834 RESERVE_SPACE(NFS4_STATEID_SIZE+4);
835 WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100836 WRITE32(args->lock_seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838
839 return 0;
840}
841
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100842static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843{
Al Viro8687b632006-10-19 23:28:48 -0700844 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 RESERVE_SPACE(40);
847 WRITE32(OP_LOCKT);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100848 WRITE32(nfs4_lock_type(args->fl, 0));
849 WRITE64(args->fl->fl_start);
850 WRITE64(nfs4_lock_length(args->fl));
851 WRITE64(args->lock_owner.clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 WRITE32(4);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100853 WRITE32(args->lock_owner.id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 return 0;
856}
857
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100858static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
Al Viro8687b632006-10-19 23:28:48 -0700860 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400862 RESERVE_SPACE(12+NFS4_STATEID_SIZE+16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 WRITE32(OP_LOCKU);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100864 WRITE32(nfs4_lock_type(args->fl, 0));
865 WRITE32(args->seqid->sequence->counter);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400866 WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100867 WRITE64(args->fl->fl_start);
868 WRITE64(nfs4_lock_length(args->fl));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 return 0;
871}
872
873static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
874{
875 int len = name->len;
Al Viro8687b632006-10-19 23:28:48 -0700876 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
878 RESERVE_SPACE(8 + len);
879 WRITE32(OP_LOOKUP);
880 WRITE32(len);
881 WRITEMEM(name->name, len);
882
883 return 0;
884}
885
886static void encode_share_access(struct xdr_stream *xdr, int open_flags)
887{
Al Viro8687b632006-10-19 23:28:48 -0700888 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890 RESERVE_SPACE(8);
891 switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
892 case FMODE_READ:
893 WRITE32(NFS4_SHARE_ACCESS_READ);
894 break;
895 case FMODE_WRITE:
896 WRITE32(NFS4_SHARE_ACCESS_WRITE);
897 break;
898 case FMODE_READ|FMODE_WRITE:
899 WRITE32(NFS4_SHARE_ACCESS_BOTH);
900 break;
901 default:
902 BUG();
903 }
904 WRITE32(0); /* for linux, share_deny = 0 always */
905}
906
907static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
908{
Al Viro8687b632006-10-19 23:28:48 -0700909 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /*
911 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
912 * owner 4 = 32
913 */
914 RESERVE_SPACE(8);
915 WRITE32(OP_OPEN);
Trond Myklebustcee54fc2005-10-18 14:20:12 -0700916 WRITE32(arg->seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 encode_share_access(xdr, arg->open_flags);
918 RESERVE_SPACE(16);
919 WRITE64(arg->clientid);
920 WRITE32(4);
921 WRITE32(arg->id);
922}
923
924static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
925{
Al Viro8687b632006-10-19 23:28:48 -0700926 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 RESERVE_SPACE(4);
929 switch(arg->open_flags & O_EXCL) {
930 case 0:
931 WRITE32(NFS4_CREATE_UNCHECKED);
932 encode_attrs(xdr, arg->u.attrs, arg->server);
933 break;
934 default:
935 WRITE32(NFS4_CREATE_EXCLUSIVE);
936 encode_nfs4_verifier(xdr, &arg->u.verifier);
937 }
938}
939
940static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
941{
Al Viro8687b632006-10-19 23:28:48 -0700942 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 RESERVE_SPACE(4);
945 switch (arg->open_flags & O_CREAT) {
946 case 0:
947 WRITE32(NFS4_OPEN_NOCREATE);
948 break;
949 default:
950 BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
951 WRITE32(NFS4_OPEN_CREATE);
952 encode_createmode(xdr, arg);
953 }
954}
955
956static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
957{
Al Viro8687b632006-10-19 23:28:48 -0700958 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 RESERVE_SPACE(4);
961 switch (delegation_type) {
962 case 0:
963 WRITE32(NFS4_OPEN_DELEGATE_NONE);
964 break;
965 case FMODE_READ:
966 WRITE32(NFS4_OPEN_DELEGATE_READ);
967 break;
968 case FMODE_WRITE|FMODE_READ:
969 WRITE32(NFS4_OPEN_DELEGATE_WRITE);
970 break;
971 default:
972 BUG();
973 }
974}
975
976static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
977{
Al Viro8687b632006-10-19 23:28:48 -0700978 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 RESERVE_SPACE(4);
981 WRITE32(NFS4_OPEN_CLAIM_NULL);
982 encode_string(xdr, name->len, name->name);
983}
984
985static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
986{
Al Viro8687b632006-10-19 23:28:48 -0700987 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989 RESERVE_SPACE(4);
990 WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
991 encode_delegation_type(xdr, type);
992}
993
994static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
995{
Al Viro8687b632006-10-19 23:28:48 -0700996 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400998 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001000 WRITEMEM(stateid->data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 encode_string(xdr, name->len, name->name);
1002}
1003
1004static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
1005{
1006 encode_openhdr(xdr, arg);
1007 encode_opentype(xdr, arg);
1008 switch (arg->claim) {
1009 case NFS4_OPEN_CLAIM_NULL:
1010 encode_claim_null(xdr, arg->name);
1011 break;
1012 case NFS4_OPEN_CLAIM_PREVIOUS:
1013 encode_claim_previous(xdr, arg->u.delegation_type);
1014 break;
1015 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1016 encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
1017 break;
1018 default:
1019 BUG();
1020 }
1021 return 0;
1022}
1023
1024static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
1025{
Al Viro8687b632006-10-19 23:28:48 -07001026 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001028 RESERVE_SPACE(4+NFS4_STATEID_SIZE+4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 WRITE32(OP_OPEN_CONFIRM);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001030 WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
Trond Myklebustcee54fc2005-10-18 14:20:12 -07001031 WRITE32(arg->seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033 return 0;
1034}
1035
1036static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
1037{
Al Viro8687b632006-10-19 23:28:48 -07001038 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001040 RESERVE_SPACE(4+NFS4_STATEID_SIZE+4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 WRITE32(OP_OPEN_DOWNGRADE);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001042 WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
Trond Myklebustcee54fc2005-10-18 14:20:12 -07001043 WRITE32(arg->seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 encode_share_access(xdr, arg->open_flags);
1045 return 0;
1046}
1047
1048static int
1049encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
1050{
1051 int len = fh->size;
Al Viro8687b632006-10-19 23:28:48 -07001052 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
1054 RESERVE_SPACE(8 + len);
1055 WRITE32(OP_PUTFH);
1056 WRITE32(len);
1057 WRITEMEM(fh->data, len);
1058
1059 return 0;
1060}
1061
1062static int encode_putrootfh(struct xdr_stream *xdr)
1063{
Al Viro8687b632006-10-19 23:28:48 -07001064 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066 RESERVE_SPACE(4);
1067 WRITE32(OP_PUTROOTFH);
1068
1069 return 0;
1070}
1071
1072static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
1073{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 nfs4_stateid stateid;
Al Viro8687b632006-10-19 23:28:48 -07001075 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001077 RESERVE_SPACE(NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 if (ctx->state != NULL) {
1079 nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001080 WRITEMEM(stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 } else
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001082 WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083}
1084
1085static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
1086{
Al Viro8687b632006-10-19 23:28:48 -07001087 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 RESERVE_SPACE(4);
1090 WRITE32(OP_READ);
1091
1092 encode_stateid(xdr, args->context);
1093
1094 RESERVE_SPACE(12);
1095 WRITE64(args->offset);
1096 WRITE32(args->count);
1097
1098 return 0;
1099}
1100
1101static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
1102{
Trond Myklebust1be27f32007-06-27 14:29:04 -04001103 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Manoj Naik97d312d2005-06-22 17:16:39 +00001104 uint32_t attrs[2] = {
1105 FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
1106 FATTR4_WORD1_MOUNTED_ON_FILEID,
1107 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 int replen;
Al Viro8687b632006-10-19 23:28:48 -07001109 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001111 RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 WRITE32(OP_READDIR);
1113 WRITE64(readdir->cookie);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001114 WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 WRITE32(readdir->count >> 1); /* We're not doing readdirplus */
1116 WRITE32(readdir->count);
1117 WRITE32(2);
Manoj Naik97d312d2005-06-22 17:16:39 +00001118 /* Switch to mounted_on_fileid if the server supports it */
1119 if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
1120 attrs[0] &= ~FATTR4_WORD0_FILEID;
1121 else
1122 attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
1123 WRITE32(attrs[0] & readdir->bitmask[0]);
1124 WRITE32(attrs[1] & readdir->bitmask[1]);
Trond Myklebusteadf4592005-06-22 17:16:39 +00001125 dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n",
1126 __FUNCTION__,
1127 (unsigned long long)readdir->cookie,
1128 ((u32 *)readdir->verifier.data)[0],
1129 ((u32 *)readdir->verifier.data)[1],
1130 attrs[0] & readdir->bitmask[0],
1131 attrs[1] & readdir->bitmask[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 /* set up reply kvec
1134 * toplevel_status + taglen + rescount + OP_PUTFH + status
1135 * + OP_READDIR + status + verifer(2) = 9
1136 */
1137 replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
1138 xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
1139 readdir->pgbase, readdir->count);
Trond Myklebusteadf4592005-06-22 17:16:39 +00001140 dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
1141 __FUNCTION__, replen, readdir->pages,
1142 readdir->pgbase, readdir->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144 return 0;
1145}
1146
1147static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
1148{
Trond Myklebust1be27f32007-06-27 14:29:04 -04001149 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 unsigned int replen;
Al Viro8687b632006-10-19 23:28:48 -07001151 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 RESERVE_SPACE(4);
1154 WRITE32(OP_READLINK);
1155
1156 /* set up reply kvec
1157 * toplevel_status + taglen + rescount + OP_PUTFH + status
1158 * + OP_READLINK + status + string length = 8
1159 */
1160 replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2;
1161 xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages,
1162 readlink->pgbase, readlink->pglen);
1163
1164 return 0;
1165}
1166
1167static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
1168{
Al Viro8687b632006-10-19 23:28:48 -07001169 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 RESERVE_SPACE(8 + name->len);
1172 WRITE32(OP_REMOVE);
1173 WRITE32(name->len);
1174 WRITEMEM(name->name, name->len);
1175
1176 return 0;
1177}
1178
1179static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
1180{
Al Viro8687b632006-10-19 23:28:48 -07001181 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
1183 RESERVE_SPACE(8 + oldname->len);
1184 WRITE32(OP_RENAME);
1185 WRITE32(oldname->len);
1186 WRITEMEM(oldname->name, oldname->len);
1187
1188 RESERVE_SPACE(4 + newname->len);
1189 WRITE32(newname->len);
1190 WRITEMEM(newname->name, newname->len);
1191
1192 return 0;
1193}
1194
David Howellsadfa6f92006-08-22 20:06:08 -04001195static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196{
Al Viro8687b632006-10-19 23:28:48 -07001197 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 RESERVE_SPACE(12);
1200 WRITE32(OP_RENEW);
1201 WRITE64(client_stateid->cl_clientid);
1202
1203 return 0;
1204}
1205
1206static int
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001207encode_restorefh(struct xdr_stream *xdr)
1208{
Al Viro8687b632006-10-19 23:28:48 -07001209 __be32 *p;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001210
1211 RESERVE_SPACE(4);
1212 WRITE32(OP_RESTOREFH);
1213
1214 return 0;
1215}
1216
1217static int
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001218encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
1219{
Al Viro8687b632006-10-19 23:28:48 -07001220 __be32 *p;
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001221
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001222 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001223 WRITE32(OP_SETATTR);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001224 WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE);
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001225 RESERVE_SPACE(2*4);
1226 WRITE32(1);
1227 WRITE32(FATTR4_WORD0_ACL);
1228 if (arg->acl_len % 4)
1229 return -EINVAL;
1230 RESERVE_SPACE(4);
1231 WRITE32(arg->acl_len);
1232 xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1233 return 0;
1234}
1235
1236static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237encode_savefh(struct xdr_stream *xdr)
1238{
Al Viro8687b632006-10-19 23:28:48 -07001239 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 RESERVE_SPACE(4);
1242 WRITE32(OP_SAVEFH);
1243
1244 return 0;
1245}
1246
1247static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
1248{
1249 int status;
Al Viro8687b632006-10-19 23:28:48 -07001250 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001252 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 WRITE32(OP_SETATTR);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001254 WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 if ((status = encode_attrs(xdr, arg->iap, server)))
1257 return status;
1258
1259 return 0;
1260}
1261
1262static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
1263{
Al Viro8687b632006-10-19 23:28:48 -07001264 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001266 RESERVE_SPACE(4 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 WRITE32(OP_SETCLIENTID);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001268 WRITEMEM(setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
1271 RESERVE_SPACE(4);
1272 WRITE32(setclientid->sc_prog);
1273 encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
1274 encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1275 RESERVE_SPACE(4);
1276 WRITE32(setclientid->sc_cb_ident);
1277
1278 return 0;
1279}
1280
David Howellsadfa6f92006-08-22 20:06:08 -04001281static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
Al Viro8687b632006-10-19 23:28:48 -07001283 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001285 RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 WRITE32(OP_SETCLIENTID_CONFIRM);
1287 WRITE64(client_state->cl_clientid);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001288 WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 return 0;
1291}
1292
1293static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
1294{
Al Viro8687b632006-10-19 23:28:48 -07001295 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296
1297 RESERVE_SPACE(4);
1298 WRITE32(OP_WRITE);
1299
1300 encode_stateid(xdr, args->context);
1301
1302 RESERVE_SPACE(16);
1303 WRITE64(args->offset);
1304 WRITE32(args->stable);
1305 WRITE32(args->count);
1306
1307 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1308
1309 return 0;
1310}
1311
1312static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
1313{
Al Viro8687b632006-10-19 23:28:48 -07001314 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001316 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 WRITE32(OP_DELEGRETURN);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001319 WRITEMEM(stateid->data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 return 0;
1321
1322}
1323/*
1324 * END OF "GENERIC" ENCODE ROUTINES.
1325 */
1326
1327/*
1328 * Encode an ACCESS request
1329 */
Al Viro8687b632006-10-19 23:28:48 -07001330static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331{
1332 struct xdr_stream xdr;
1333 struct compound_hdr hdr = {
1334 .nops = 2,
1335 };
1336 int status;
1337
1338 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1339 encode_compound_hdr(&xdr, &hdr);
1340 if ((status = encode_putfh(&xdr, args->fh)) == 0)
1341 status = encode_access(&xdr, args->access);
1342 return status;
1343}
1344
1345/*
1346 * Encode LOOKUP request
1347 */
Al Viro8687b632006-10-19 23:28:48 -07001348static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349{
1350 struct xdr_stream xdr;
1351 struct compound_hdr hdr = {
1352 .nops = 4,
1353 };
1354 int status;
1355
1356 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1357 encode_compound_hdr(&xdr, &hdr);
1358 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
1359 goto out;
1360 if ((status = encode_lookup(&xdr, args->name)) != 0)
1361 goto out;
1362 if ((status = encode_getfh(&xdr)) != 0)
1363 goto out;
1364 status = encode_getfattr(&xdr, args->bitmask);
1365out:
1366 return status;
1367}
1368
1369/*
1370 * Encode LOOKUP_ROOT request
1371 */
Al Viro8687b632006-10-19 23:28:48 -07001372static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373{
1374 struct xdr_stream xdr;
1375 struct compound_hdr hdr = {
1376 .nops = 3,
1377 };
1378 int status;
1379
1380 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1381 encode_compound_hdr(&xdr, &hdr);
1382 if ((status = encode_putrootfh(&xdr)) != 0)
1383 goto out;
1384 if ((status = encode_getfh(&xdr)) == 0)
1385 status = encode_getfattr(&xdr, args->bitmask);
1386out:
1387 return status;
1388}
1389
1390/*
1391 * Encode REMOVE request
1392 */
Al Viro8687b632006-10-19 23:28:48 -07001393static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394{
1395 struct xdr_stream xdr;
1396 struct compound_hdr hdr = {
Trond Myklebust16e42952005-10-27 22:12:44 -04001397 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 };
1399 int status;
1400
1401 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1402 encode_compound_hdr(&xdr, &hdr);
Trond Myklebust16e42952005-10-27 22:12:44 -04001403 if ((status = encode_putfh(&xdr, args->fh)) != 0)
1404 goto out;
1405 if ((status = encode_remove(&xdr, args->name)) != 0)
1406 goto out;
1407 status = encode_getfattr(&xdr, args->bitmask);
1408out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 return status;
1410}
1411
1412/*
1413 * Encode RENAME request
1414 */
Al Viro8687b632006-10-19 23:28:48 -07001415static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416{
1417 struct xdr_stream xdr;
1418 struct compound_hdr hdr = {
Trond Myklebust6caf2c82005-10-27 22:12:43 -04001419 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 };
1421 int status;
1422
1423 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1424 encode_compound_hdr(&xdr, &hdr);
1425 if ((status = encode_putfh(&xdr, args->old_dir)) != 0)
1426 goto out;
1427 if ((status = encode_savefh(&xdr)) != 0)
1428 goto out;
1429 if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
1430 goto out;
Trond Myklebust6caf2c82005-10-27 22:12:43 -04001431 if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0)
1432 goto out;
1433 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
1434 goto out;
1435 if ((status = encode_restorefh(&xdr)) != 0)
1436 goto out;
1437 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438out:
1439 return status;
1440}
1441
1442/*
1443 * Encode LINK request
1444 */
Al Viro8687b632006-10-19 23:28:48 -07001445static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446{
1447 struct xdr_stream xdr;
1448 struct compound_hdr hdr = {
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04001449 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 };
1451 int status;
1452
1453 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1454 encode_compound_hdr(&xdr, &hdr);
1455 if ((status = encode_putfh(&xdr, args->fh)) != 0)
1456 goto out;
1457 if ((status = encode_savefh(&xdr)) != 0)
1458 goto out;
1459 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
1460 goto out;
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04001461 if ((status = encode_link(&xdr, args->name)) != 0)
1462 goto out;
1463 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
1464 goto out;
1465 if ((status = encode_restorefh(&xdr)) != 0)
1466 goto out;
1467 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468out:
1469 return status;
1470}
1471
1472/*
1473 * Encode CREATE request
1474 */
Al Viro8687b632006-10-19 23:28:48 -07001475static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476{
1477 struct xdr_stream xdr;
1478 struct compound_hdr hdr = {
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001479 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 };
1481 int status;
1482
1483 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1484 encode_compound_hdr(&xdr, &hdr);
1485 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
1486 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001487 if ((status = encode_savefh(&xdr)) != 0)
1488 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if ((status = encode_create(&xdr, args)) != 0)
1490 goto out;
1491 if ((status = encode_getfh(&xdr)) != 0)
1492 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001493 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
1494 goto out;
1495 if ((status = encode_restorefh(&xdr)) != 0)
1496 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 status = encode_getfattr(&xdr, args->bitmask);
1498out:
1499 return status;
1500}
1501
1502/*
1503 * Encode SYMLINK request
1504 */
Al Viro8687b632006-10-19 23:28:48 -07001505static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 return nfs4_xdr_enc_create(req, p, args);
1508}
1509
1510/*
1511 * Encode GETATTR request
1512 */
Al Viro8687b632006-10-19 23:28:48 -07001513static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514{
1515 struct xdr_stream xdr;
1516 struct compound_hdr hdr = {
1517 .nops = 2,
1518 };
1519 int status;
1520
1521 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1522 encode_compound_hdr(&xdr, &hdr);
1523 if ((status = encode_putfh(&xdr, args->fh)) == 0)
1524 status = encode_getfattr(&xdr, args->bitmask);
1525 return status;
1526}
1527
1528/*
1529 * Encode a CLOSE request
1530 */
Al Viro8687b632006-10-19 23:28:48 -07001531static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532{
1533 struct xdr_stream xdr;
1534 struct compound_hdr hdr = {
Trond Myklebust516a6af2005-10-27 22:12:41 -04001535 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 };
1537 int status;
1538
1539 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1540 encode_compound_hdr(&xdr, &hdr);
1541 status = encode_putfh(&xdr, args->fh);
1542 if(status)
1543 goto out;
1544 status = encode_close(&xdr, args);
Trond Myklebust516a6af2005-10-27 22:12:41 -04001545 if (status != 0)
1546 goto out;
1547 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548out:
1549 return status;
1550}
1551
1552/*
1553 * Encode an OPEN request
1554 */
Al Viro8687b632006-10-19 23:28:48 -07001555static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556{
1557 struct xdr_stream xdr;
1558 struct compound_hdr hdr = {
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001559 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 };
1561 int status;
1562
1563 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1564 encode_compound_hdr(&xdr, &hdr);
1565 status = encode_putfh(&xdr, args->fh);
1566 if (status)
1567 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001568 status = encode_savefh(&xdr);
1569 if (status)
1570 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 status = encode_open(&xdr, args);
1572 if (status)
1573 goto out;
1574 status = encode_getfh(&xdr);
1575 if (status)
1576 goto out;
1577 status = encode_getfattr(&xdr, args->bitmask);
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001578 if (status)
1579 goto out;
1580 status = encode_restorefh(&xdr);
1581 if (status)
1582 goto out;
1583 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584out:
1585 return status;
1586}
1587
1588/*
1589 * Encode an OPEN_CONFIRM request
1590 */
Al Viro8687b632006-10-19 23:28:48 -07001591static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592{
1593 struct xdr_stream xdr;
1594 struct compound_hdr hdr = {
1595 .nops = 2,
1596 };
1597 int status;
1598
1599 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1600 encode_compound_hdr(&xdr, &hdr);
1601 status = encode_putfh(&xdr, args->fh);
1602 if(status)
1603 goto out;
1604 status = encode_open_confirm(&xdr, args);
1605out:
1606 return status;
1607}
1608
1609/*
1610 * Encode an OPEN request with no attributes.
1611 */
Al Viro8687b632006-10-19 23:28:48 -07001612static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
1614 struct xdr_stream xdr;
1615 struct compound_hdr hdr = {
Trond Myklebust864472e2006-01-03 09:55:15 +01001616 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 };
1618 int status;
1619
1620 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1621 encode_compound_hdr(&xdr, &hdr);
1622 status = encode_putfh(&xdr, args->fh);
1623 if (status)
1624 goto out;
1625 status = encode_open(&xdr, args);
Trond Myklebust864472e2006-01-03 09:55:15 +01001626 if (status)
1627 goto out;
1628 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629out:
1630 return status;
1631}
1632
1633/*
1634 * Encode an OPEN_DOWNGRADE request
1635 */
Al Viro8687b632006-10-19 23:28:48 -07001636static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637{
1638 struct xdr_stream xdr;
1639 struct compound_hdr hdr = {
Trond Myklebust516a6af2005-10-27 22:12:41 -04001640 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 };
1642 int status;
1643
1644 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1645 encode_compound_hdr(&xdr, &hdr);
1646 status = encode_putfh(&xdr, args->fh);
1647 if (status)
1648 goto out;
1649 status = encode_open_downgrade(&xdr, args);
Trond Myklebust516a6af2005-10-27 22:12:41 -04001650 if (status != 0)
1651 goto out;
1652 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653out:
1654 return status;
1655}
1656
1657/*
1658 * Encode a LOCK request
1659 */
Al Viro8687b632006-10-19 23:28:48 -07001660static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661{
1662 struct xdr_stream xdr;
1663 struct compound_hdr hdr = {
1664 .nops = 2,
1665 };
1666 int status;
1667
1668 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1669 encode_compound_hdr(&xdr, &hdr);
1670 status = encode_putfh(&xdr, args->fh);
1671 if(status)
1672 goto out;
1673 status = encode_lock(&xdr, args);
1674out:
1675 return status;
1676}
1677
1678/*
1679 * Encode a LOCKT request
1680 */
Al Viro8687b632006-10-19 23:28:48 -07001681static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682{
1683 struct xdr_stream xdr;
1684 struct compound_hdr hdr = {
1685 .nops = 2,
1686 };
1687 int status;
1688
1689 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1690 encode_compound_hdr(&xdr, &hdr);
1691 status = encode_putfh(&xdr, args->fh);
1692 if(status)
1693 goto out;
1694 status = encode_lockt(&xdr, args);
1695out:
1696 return status;
1697}
1698
1699/*
1700 * Encode a LOCKU request
1701 */
Al Viro8687b632006-10-19 23:28:48 -07001702static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703{
1704 struct xdr_stream xdr;
1705 struct compound_hdr hdr = {
1706 .nops = 2,
1707 };
1708 int status;
1709
1710 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1711 encode_compound_hdr(&xdr, &hdr);
1712 status = encode_putfh(&xdr, args->fh);
1713 if(status)
1714 goto out;
1715 status = encode_locku(&xdr, args);
1716out:
1717 return status;
1718}
1719
1720/*
1721 * Encode a READLINK request
1722 */
Al Viro8687b632006-10-19 23:28:48 -07001723static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724{
1725 struct xdr_stream xdr;
1726 struct compound_hdr hdr = {
1727 .nops = 2,
1728 };
1729 int status;
1730
1731 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1732 encode_compound_hdr(&xdr, &hdr);
1733 status = encode_putfh(&xdr, args->fh);
1734 if(status)
1735 goto out;
1736 status = encode_readlink(&xdr, args, req);
1737out:
1738 return status;
1739}
1740
1741/*
1742 * Encode a READDIR request
1743 */
Al Viro8687b632006-10-19 23:28:48 -07001744static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
1746 struct xdr_stream xdr;
1747 struct compound_hdr hdr = {
1748 .nops = 2,
1749 };
1750 int status;
1751
1752 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1753 encode_compound_hdr(&xdr, &hdr);
1754 status = encode_putfh(&xdr, args->fh);
1755 if(status)
1756 goto out;
1757 status = encode_readdir(&xdr, args, req);
1758out:
1759 return status;
1760}
1761
1762/*
1763 * Encode a READ request
1764 */
Al Viro8687b632006-10-19 23:28:48 -07001765static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766{
Trond Myklebust1be27f32007-06-27 14:29:04 -04001767 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 struct xdr_stream xdr;
1769 struct compound_hdr hdr = {
1770 .nops = 2,
1771 };
1772 int replen, status;
1773
1774 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1775 encode_compound_hdr(&xdr, &hdr);
1776 status = encode_putfh(&xdr, args->fh);
1777 if (status)
1778 goto out;
1779 status = encode_read(&xdr, args);
1780 if (status)
1781 goto out;
1782
1783 /* set up reply kvec
1784 * toplevel status + taglen=0 + rescount + OP_PUTFH + status
1785 * + OP_READ + status + eof + datalen = 9
1786 */
1787 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
1788 xdr_inline_pages(&req->rq_rcv_buf, replen,
1789 args->pages, args->pgbase, args->count);
1790out:
1791 return status;
1792}
1793
1794/*
1795 * Encode an SETATTR request
1796 */
Al Viro8687b632006-10-19 23:28:48 -07001797static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
1799{
1800 struct xdr_stream xdr;
1801 struct compound_hdr hdr = {
1802 .nops = 3,
1803 };
1804 int status;
1805
1806 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1807 encode_compound_hdr(&xdr, &hdr);
1808 status = encode_putfh(&xdr, args->fh);
1809 if(status)
1810 goto out;
1811 status = encode_setattr(&xdr, args, args->server);
1812 if(status)
1813 goto out;
1814 status = encode_getfattr(&xdr, args->bitmask);
1815out:
1816 return status;
1817}
1818
1819/*
J. Bruce Fields029d1052005-06-22 17:16:22 +00001820 * Encode a GETACL request
1821 */
1822static int
Al Viro8687b632006-10-19 23:28:48 -07001823nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
J. Bruce Fields029d1052005-06-22 17:16:22 +00001824 struct nfs_getaclargs *args)
1825{
1826 struct xdr_stream xdr;
Trond Myklebust1be27f32007-06-27 14:29:04 -04001827 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
J. Bruce Fields029d1052005-06-22 17:16:22 +00001828 struct compound_hdr hdr = {
1829 .nops = 2,
1830 };
1831 int replen, status;
1832
1833 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1834 encode_compound_hdr(&xdr, &hdr);
1835 status = encode_putfh(&xdr, args->fh);
1836 if (status)
1837 goto out;
1838 status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
1839 /* set up reply buffer: */
1840 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
1841 xdr_inline_pages(&req->rq_rcv_buf, replen,
1842 args->acl_pages, args->acl_pgbase, args->acl_len);
1843out:
1844 return status;
1845}
1846
1847/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 * Encode a WRITE request
1849 */
Al Viro8687b632006-10-19 23:28:48 -07001850static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
1852 struct xdr_stream xdr;
1853 struct compound_hdr hdr = {
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001854 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 };
1856 int status;
1857
1858 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1859 encode_compound_hdr(&xdr, &hdr);
1860 status = encode_putfh(&xdr, args->fh);
1861 if (status)
1862 goto out;
1863 status = encode_write(&xdr, args);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001864 if (status)
1865 goto out;
1866 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867out:
1868 return status;
1869}
1870
1871/*
1872 * a COMMIT request
1873 */
Al Viro8687b632006-10-19 23:28:48 -07001874static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
1876 struct xdr_stream xdr;
1877 struct compound_hdr hdr = {
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001878 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 };
1880 int status;
1881
1882 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1883 encode_compound_hdr(&xdr, &hdr);
1884 status = encode_putfh(&xdr, args->fh);
1885 if (status)
1886 goto out;
1887 status = encode_commit(&xdr, args);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001888 if (status)
1889 goto out;
1890 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891out:
1892 return status;
1893}
1894
1895/*
1896 * FSINFO request
1897 */
Al Viro8687b632006-10-19 23:28:48 -07001898static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899{
1900 struct xdr_stream xdr;
1901 struct compound_hdr hdr = {
1902 .nops = 2,
1903 };
1904 int status;
1905
1906 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1907 encode_compound_hdr(&xdr, &hdr);
1908 status = encode_putfh(&xdr, args->fh);
1909 if (!status)
1910 status = encode_fsinfo(&xdr, args->bitmask);
1911 return status;
1912}
1913
1914/*
1915 * a PATHCONF request
1916 */
Al Viro8687b632006-10-19 23:28:48 -07001917static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 struct xdr_stream xdr;
1920 struct compound_hdr hdr = {
1921 .nops = 2,
1922 };
1923 int status;
1924
1925 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1926 encode_compound_hdr(&xdr, &hdr);
1927 status = encode_putfh(&xdr, args->fh);
1928 if (!status)
1929 status = encode_getattr_one(&xdr,
1930 args->bitmask[0] & nfs4_pathconf_bitmap[0]);
1931 return status;
1932}
1933
1934/*
1935 * a STATFS request
1936 */
Al Viro8687b632006-10-19 23:28:48 -07001937static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 struct xdr_stream xdr;
1940 struct compound_hdr hdr = {
1941 .nops = 2,
1942 };
1943 int status;
1944
1945 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1946 encode_compound_hdr(&xdr, &hdr);
1947 status = encode_putfh(&xdr, args->fh);
1948 if (status == 0)
1949 status = encode_getattr_two(&xdr,
1950 args->bitmask[0] & nfs4_statfs_bitmap[0],
1951 args->bitmask[1] & nfs4_statfs_bitmap[1]);
1952 return status;
1953}
1954
1955/*
1956 * GETATTR_BITMAP request
1957 */
Al Viro8687b632006-10-19 23:28:48 -07001958static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959{
1960 struct xdr_stream xdr;
1961 struct compound_hdr hdr = {
1962 .nops = 2,
1963 };
1964 int status;
1965
1966 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1967 encode_compound_hdr(&xdr, &hdr);
1968 status = encode_putfh(&xdr, fhandle);
1969 if (status == 0)
1970 status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
1971 FATTR4_WORD0_LINK_SUPPORT|
1972 FATTR4_WORD0_SYMLINK_SUPPORT|
1973 FATTR4_WORD0_ACLSUPPORT);
1974 return status;
1975}
1976
1977/*
1978 * a RENEW request
1979 */
Al Viro8687b632006-10-19 23:28:48 -07001980static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981{
1982 struct xdr_stream xdr;
1983 struct compound_hdr hdr = {
1984 .nops = 1,
1985 };
1986
1987 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1988 encode_compound_hdr(&xdr, &hdr);
1989 return encode_renew(&xdr, clp);
1990}
1991
1992/*
1993 * a SETCLIENTID request
1994 */
Al Viro8687b632006-10-19 23:28:48 -07001995static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
1997 struct xdr_stream xdr;
1998 struct compound_hdr hdr = {
1999 .nops = 1,
2000 };
2001
2002 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2003 encode_compound_hdr(&xdr, &hdr);
2004 return encode_setclientid(&xdr, sc);
2005}
2006
2007/*
2008 * a SETCLIENTID_CONFIRM request
2009 */
Al Viro8687b632006-10-19 23:28:48 -07002010static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011{
2012 struct xdr_stream xdr;
2013 struct compound_hdr hdr = {
2014 .nops = 3,
2015 };
2016 const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
2017 int status;
2018
2019 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2020 encode_compound_hdr(&xdr, &hdr);
2021 status = encode_setclientid_confirm(&xdr, clp);
2022 if (!status)
2023 status = encode_putrootfh(&xdr);
2024 if (!status)
2025 status = encode_fsinfo(&xdr, lease_bitmap);
2026 return status;
2027}
2028
2029/*
2030 * DELEGRETURN request
2031 */
Al Viro8687b632006-10-19 23:28:48 -07002032static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033{
2034 struct xdr_stream xdr;
2035 struct compound_hdr hdr = {
Trond Myklebustfa178f22006-01-03 09:55:38 +01002036 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 };
2038 int status;
2039
2040 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2041 encode_compound_hdr(&xdr, &hdr);
Trond Myklebustfa178f22006-01-03 09:55:38 +01002042 status = encode_putfh(&xdr, args->fhandle);
2043 if (status != 0)
2044 goto out;
2045 status = encode_delegreturn(&xdr, args->stateid);
2046 if (status != 0)
2047 goto out;
2048 status = encode_getfattr(&xdr, args->bitmask);
2049out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050 return status;
2051}
2052
2053/*
Trond Myklebust683b57b2006-06-09 09:34:22 -04002054 * Encode FS_LOCATIONS request
2055 */
Al Viro8687b632006-10-19 23:28:48 -07002056static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002057{
2058 struct xdr_stream xdr;
2059 struct compound_hdr hdr = {
2060 .nops = 3,
2061 };
Trond Myklebust1be27f32007-06-27 14:29:04 -04002062 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Trond Myklebust683b57b2006-06-09 09:34:22 -04002063 int replen;
2064 int status;
2065
2066 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2067 encode_compound_hdr(&xdr, &hdr);
2068 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
2069 goto out;
2070 if ((status = encode_lookup(&xdr, args->name)) != 0)
2071 goto out;
Manoj Naik830b8e32006-06-09 09:34:25 -04002072 if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002073 goto out;
2074 /* set up reply
Manoj Naik830b8e32006-06-09 09:34:25 -04002075 * toplevel_status + OP_PUTFH + status
Trond Myklebust683b57b2006-06-09 09:34:22 -04002076 * + OP_LOOKUP + status + OP_GETATTR + status = 7
2077 */
2078 replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
2079 xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
2080 0, PAGE_SIZE);
2081out:
2082 return status;
2083}
2084
2085/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 * START OF "GENERIC" DECODE ROUTINES.
2087 * These may look a little ugly since they are imported from a "generic"
2088 * set of XDR encode/decode routines which are intended to be shared by
2089 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
2090 *
2091 * If the pain of reading these is too great, it should be a straightforward
2092 * task to translate them into Linux-specific versions which are more
2093 * consistent with the style used in NFSv2/v3...
2094 */
2095#define READ32(x) (x) = ntohl(*p++)
2096#define READ64(x) do { \
2097 (x) = (u64)ntohl(*p++) << 32; \
2098 (x) |= ntohl(*p++); \
2099} while (0)
2100#define READTIME(x) do { \
2101 p++; \
2102 (x.tv_sec) = ntohl(*p++); \
2103 (x.tv_nsec) = ntohl(*p++); \
2104} while (0)
2105#define COPYMEM(x,nbytes) do { \
2106 memcpy((x), p, nbytes); \
2107 p += XDR_QUADLEN(nbytes); \
2108} while (0)
2109
2110#define READ_BUF(nbytes) do { \
2111 p = xdr_inline_decode(xdr, nbytes); \
Chuck Levere4cc6ee2007-05-08 18:23:28 -04002112 if (unlikely(!p)) { \
2113 printk(KERN_INFO "%s: prematurely hit end of receive" \
2114 " buffer\n", __FUNCTION__); \
2115 printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
2116 __FUNCTION__, xdr->p, nbytes, xdr->end); \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 return -EIO; \
2118 } \
2119} while (0)
2120
Trond Myklebust683b57b2006-06-09 09:34:22 -04002121static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
Al Viro8687b632006-10-19 23:28:48 -07002123 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124
2125 READ_BUF(4);
2126 READ32(*len);
2127 READ_BUF(*len);
2128 *string = (char *)p;
2129 return 0;
2130}
2131
2132static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
2133{
Al Viro8687b632006-10-19 23:28:48 -07002134 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
2136 READ_BUF(8);
2137 READ32(hdr->status);
2138 READ32(hdr->taglen);
2139
2140 READ_BUF(hdr->taglen + 4);
2141 hdr->tag = (char *)p;
2142 p += XDR_QUADLEN(hdr->taglen);
2143 READ32(hdr->nops);
2144 return 0;
2145}
2146
2147static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
2148{
Al Viro8687b632006-10-19 23:28:48 -07002149 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 uint32_t opnum;
2151 int32_t nfserr;
2152
2153 READ_BUF(8);
2154 READ32(opnum);
2155 if (opnum != expected) {
2156 printk(KERN_NOTICE
2157 "nfs4_decode_op_hdr: Server returned operation"
2158 " %d but we issued a request for %d\n",
2159 opnum, expected);
2160 return -EIO;
2161 }
2162 READ32(nfserr);
2163 if (nfserr != NFS_OK)
David Howells0a8ea432006-08-22 20:06:08 -04002164 return -nfs4_stat_to_errno(nfserr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 return 0;
2166}
2167
2168/* Dummy routine */
David Howellsadfa6f92006-08-22 20:06:08 -04002169static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170{
Al Viro8687b632006-10-19 23:28:48 -07002171 __be32 *p;
Trond Myklebust683b57b2006-06-09 09:34:22 -04002172 unsigned int strlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 char *str;
2174
2175 READ_BUF(12);
2176 return decode_opaque_inline(xdr, &strlen, &str);
2177}
2178
2179static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
2180{
Al Viro8687b632006-10-19 23:28:48 -07002181 uint32_t bmlen;
2182 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
2184 READ_BUF(4);
2185 READ32(bmlen);
2186
2187 bitmap[0] = bitmap[1] = 0;
2188 READ_BUF((bmlen << 2));
2189 if (bmlen > 0) {
2190 READ32(bitmap[0]);
2191 if (bmlen > 1)
2192 READ32(bitmap[1]);
2193 }
2194 return 0;
2195}
2196
Al Viro8687b632006-10-19 23:28:48 -07002197static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198{
Al Viro8687b632006-10-19 23:28:48 -07002199 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
2201 READ_BUF(4);
2202 READ32(*attrlen);
2203 *savep = xdr->p;
2204 return 0;
2205}
2206
2207static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
2208{
2209 if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
2210 decode_attr_bitmap(xdr, bitmask);
2211 bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
2212 } else
2213 bitmask[0] = bitmask[1] = 0;
2214 dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]);
2215 return 0;
2216}
2217
2218static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
2219{
Al Viro8687b632006-10-19 23:28:48 -07002220 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 *type = 0;
2223 if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
2224 return -EIO;
2225 if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
2226 READ_BUF(4);
2227 READ32(*type);
2228 if (*type < NF4REG || *type > NF4NAMEDATTR) {
2229 dprintk("%s: bad type %d\n", __FUNCTION__, *type);
2230 return -EIO;
2231 }
2232 bitmap[0] &= ~FATTR4_WORD0_TYPE;
2233 }
2234 dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type);
2235 return 0;
2236}
2237
2238static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
2239{
Al Viro8687b632006-10-19 23:28:48 -07002240 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
2242 *change = 0;
2243 if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
2244 return -EIO;
2245 if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
2246 READ_BUF(8);
2247 READ64(*change);
2248 bitmap[0] &= ~FATTR4_WORD0_CHANGE;
2249 }
2250 dprintk("%s: change attribute=%Lu\n", __FUNCTION__,
2251 (unsigned long long)*change);
2252 return 0;
2253}
2254
2255static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
2256{
Al Viro8687b632006-10-19 23:28:48 -07002257 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258
2259 *size = 0;
2260 if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
2261 return -EIO;
2262 if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
2263 READ_BUF(8);
2264 READ64(*size);
2265 bitmap[0] &= ~FATTR4_WORD0_SIZE;
2266 }
2267 dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size);
2268 return 0;
2269}
2270
2271static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2272{
Al Viro8687b632006-10-19 23:28:48 -07002273 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274
2275 *res = 0;
2276 if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
2277 return -EIO;
2278 if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
2279 READ_BUF(4);
2280 READ32(*res);
2281 bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
2282 }
2283 dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
2284 return 0;
2285}
2286
2287static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2288{
Al Viro8687b632006-10-19 23:28:48 -07002289 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291 *res = 0;
2292 if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
2293 return -EIO;
2294 if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
2295 READ_BUF(4);
2296 READ32(*res);
2297 bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
2298 }
2299 dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
2300 return 0;
2301}
2302
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -04002303static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
Al Viro8687b632006-10-19 23:28:48 -07002305 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 fsid->major = 0;
2308 fsid->minor = 0;
2309 if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
2310 return -EIO;
2311 if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
2312 READ_BUF(16);
2313 READ64(fsid->major);
2314 READ64(fsid->minor);
2315 bitmap[0] &= ~FATTR4_WORD0_FSID;
2316 }
2317 dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__,
2318 (unsigned long long)fsid->major,
2319 (unsigned long long)fsid->minor);
2320 return 0;
2321}
2322
2323static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2324{
Al Viro8687b632006-10-19 23:28:48 -07002325 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326
2327 *res = 60;
2328 if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
2329 return -EIO;
2330 if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
2331 READ_BUF(4);
2332 READ32(*res);
2333 bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
2334 }
2335 dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res);
2336 return 0;
2337}
2338
2339static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2340{
Al Viro8687b632006-10-19 23:28:48 -07002341 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342
2343 *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
2344 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
2345 return -EIO;
2346 if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
2347 READ_BUF(4);
2348 READ32(*res);
2349 bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
2350 }
2351 dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res);
2352 return 0;
2353}
2354
2355static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
2356{
Al Viro8687b632006-10-19 23:28:48 -07002357 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
2359 *fileid = 0;
2360 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
2361 return -EIO;
2362 if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
2363 READ_BUF(8);
2364 READ64(*fileid);
2365 bitmap[0] &= ~FATTR4_WORD0_FILEID;
2366 }
2367 dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
2368 return 0;
2369}
2370
Manoj Naik99baf622006-06-09 09:34:24 -04002371static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
2372{
Al Viro8687b632006-10-19 23:28:48 -07002373 __be32 *p;
Manoj Naik99baf622006-06-09 09:34:24 -04002374
2375 *fileid = 0;
2376 if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
2377 return -EIO;
2378 if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
2379 READ_BUF(8);
2380 READ64(*fileid);
2381 bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
2382 }
2383 dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
2384 return 0;
2385}
2386
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2388{
Al Viro8687b632006-10-19 23:28:48 -07002389 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 int status = 0;
2391
2392 *res = 0;
2393 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
2394 return -EIO;
2395 if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
2396 READ_BUF(8);
2397 READ64(*res);
2398 bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
2399 }
2400 dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2401 return status;
2402}
2403
2404static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2405{
Al Viro8687b632006-10-19 23:28:48 -07002406 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 int status = 0;
2408
2409 *res = 0;
2410 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
2411 return -EIO;
2412 if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
2413 READ_BUF(8);
2414 READ64(*res);
2415 bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
2416 }
2417 dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2418 return status;
2419}
2420
2421static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2422{
Al Viro8687b632006-10-19 23:28:48 -07002423 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 int status = 0;
2425
2426 *res = 0;
2427 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
2428 return -EIO;
2429 if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
2430 READ_BUF(8);
2431 READ64(*res);
2432 bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
2433 }
2434 dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2435 return status;
2436}
2437
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002438static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
2439{
2440 int n;
Al Viro8687b632006-10-19 23:28:48 -07002441 __be32 *p;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002442 int status = 0;
2443
2444 READ_BUF(4);
2445 READ32(n);
Andy Adamson33a43f22006-06-09 09:34:30 -04002446 if (n < 0)
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002447 goto out_eio;
Andy Adamson33a43f22006-06-09 09:34:30 -04002448 if (n == 0)
2449 goto root_path;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002450 dprintk("path ");
2451 path->ncomponents = 0;
2452 while (path->ncomponents < n) {
2453 struct nfs4_string *component = &path->components[path->ncomponents];
2454 status = decode_opaque_inline(xdr, &component->len, &component->data);
2455 if (unlikely(status != 0))
2456 goto out_eio;
2457 if (path->ncomponents != n)
2458 dprintk("/");
2459 dprintk("%s", component->data);
2460 if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
2461 path->ncomponents++;
2462 else {
2463 dprintk("cannot parse %d components in path\n", n);
2464 goto out_eio;
2465 }
2466 }
2467out:
2468 dprintk("\n");
2469 return status;
Andy Adamson33a43f22006-06-09 09:34:30 -04002470root_path:
2471/* a root pathname is sent as a zero component4 */
2472 path->ncomponents = 1;
2473 path->components[0].len=0;
2474 path->components[0].data=NULL;
2475 dprintk("path /\n");
2476 goto out;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002477out_eio:
2478 dprintk(" status %d", status);
2479 status = -EIO;
2480 goto out;
2481}
2482
2483static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002484{
2485 int n;
Al Viro8687b632006-10-19 23:28:48 -07002486 __be32 *p;
Trond Myklebust683b57b2006-06-09 09:34:22 -04002487 int status = -EIO;
2488
2489 if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
2490 goto out;
2491 status = 0;
2492 if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
2493 goto out;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002494 dprintk("%s: fsroot ", __FUNCTION__);
2495 status = decode_pathname(xdr, &res->fs_path);
Trond Myklebust683b57b2006-06-09 09:34:22 -04002496 if (unlikely(status != 0))
2497 goto out;
2498 READ_BUF(4);
2499 READ32(n);
2500 if (n <= 0)
2501 goto out_eio;
2502 res->nlocations = 0;
2503 while (res->nlocations < n) {
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002504 int m;
2505 struct nfs4_fs_location *loc = &res->locations[res->nlocations];
Trond Myklebust683b57b2006-06-09 09:34:22 -04002506
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002507 READ_BUF(4);
2508 READ32(m);
2509 if (m <= 0)
2510 goto out_eio;
2511
2512 loc->nservers = 0;
2513 dprintk("%s: servers ", __FUNCTION__);
2514 while (loc->nservers < m) {
2515 struct nfs4_string *server = &loc->servers[loc->nservers];
2516 status = decode_opaque_inline(xdr, &server->len, &server->data);
2517 if (unlikely(status != 0))
2518 goto out_eio;
2519 dprintk("%s ", server->data);
2520 if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
2521 loc->nservers++;
2522 else {
2523 int i;
2524 dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations);
2525 for (i = loc->nservers; i < m; i++) {
Trond Myklebust2e42c3e2007-05-14 17:20:41 -04002526 unsigned int len;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002527 char *data;
2528 status = decode_opaque_inline(xdr, &len, &data);
2529 if (unlikely(status != 0))
2530 goto out_eio;
2531 }
2532 }
2533 }
2534 status = decode_pathname(xdr, &loc->rootpath);
Trond Myklebust683b57b2006-06-09 09:34:22 -04002535 if (unlikely(status != 0))
2536 goto out_eio;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002537 if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002538 res->nlocations++;
2539 }
2540out:
2541 dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
2542 return status;
2543out_eio:
2544 status = -EIO;
2545 goto out;
2546}
2547
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2549{
Al Viro8687b632006-10-19 23:28:48 -07002550 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 int status = 0;
2552
2553 *res = 0;
2554 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
2555 return -EIO;
2556 if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
2557 READ_BUF(8);
2558 READ64(*res);
2559 bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
2560 }
2561 dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2562 return status;
2563}
2564
2565static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
2566{
Al Viro8687b632006-10-19 23:28:48 -07002567 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568 int status = 0;
2569
2570 *maxlink = 1;
2571 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
2572 return -EIO;
2573 if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
2574 READ_BUF(4);
2575 READ32(*maxlink);
2576 bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
2577 }
2578 dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink);
2579 return status;
2580}
2581
2582static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
2583{
Al Viro8687b632006-10-19 23:28:48 -07002584 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 int status = 0;
2586
2587 *maxname = 1024;
2588 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
2589 return -EIO;
2590 if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
2591 READ_BUF(4);
2592 READ32(*maxname);
2593 bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
2594 }
2595 dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname);
2596 return status;
2597}
2598
2599static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2600{
Al Viro8687b632006-10-19 23:28:48 -07002601 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 int status = 0;
2603
2604 *res = 1024;
2605 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
2606 return -EIO;
2607 if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
2608 uint64_t maxread;
2609 READ_BUF(8);
2610 READ64(maxread);
2611 if (maxread > 0x7FFFFFFF)
2612 maxread = 0x7FFFFFFF;
2613 *res = (uint32_t)maxread;
2614 bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
2615 }
2616 dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res);
2617 return status;
2618}
2619
2620static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2621{
Al Viro8687b632006-10-19 23:28:48 -07002622 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 int status = 0;
2624
2625 *res = 1024;
2626 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
2627 return -EIO;
2628 if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
2629 uint64_t maxwrite;
2630 READ_BUF(8);
2631 READ64(maxwrite);
2632 if (maxwrite > 0x7FFFFFFF)
2633 maxwrite = 0x7FFFFFFF;
2634 *res = (uint32_t)maxwrite;
2635 bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
2636 }
2637 dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res);
2638 return status;
2639}
2640
2641static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
2642{
Al Viro8687b632006-10-19 23:28:48 -07002643 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 *mode = 0;
2646 if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
2647 return -EIO;
2648 if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
2649 READ_BUF(4);
2650 READ32(*mode);
2651 *mode &= ~S_IFMT;
2652 bitmap[1] &= ~FATTR4_WORD1_MODE;
2653 }
2654 dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode);
2655 return 0;
2656}
2657
2658static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
2659{
Al Viro8687b632006-10-19 23:28:48 -07002660 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
2662 *nlink = 1;
2663 if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
2664 return -EIO;
2665 if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
2666 READ_BUF(4);
2667 READ32(*nlink);
2668 bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
2669 }
2670 dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink);
2671 return 0;
2672}
2673
Trond Myklebust2e42c3e2007-05-14 17:20:41 -04002674static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675{
Al Viro8687b632006-10-19 23:28:48 -07002676 uint32_t len;
2677 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678
2679 *uid = -2;
2680 if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
2681 return -EIO;
2682 if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
2683 READ_BUF(4);
2684 READ32(len);
2685 READ_BUF(len);
2686 if (len < XDR_MAX_NETOBJ) {
2687 if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
2688 dprintk("%s: nfs_map_name_to_uid failed!\n",
2689 __FUNCTION__);
2690 } else
2691 printk(KERN_WARNING "%s: name too long (%u)!\n",
2692 __FUNCTION__, len);
2693 bitmap[1] &= ~FATTR4_WORD1_OWNER;
2694 }
2695 dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid);
2696 return 0;
2697}
2698
Trond Myklebust2e42c3e2007-05-14 17:20:41 -04002699static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
Al Viro8687b632006-10-19 23:28:48 -07002701 uint32_t len;
2702 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704 *gid = -2;
2705 if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
2706 return -EIO;
2707 if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
2708 READ_BUF(4);
2709 READ32(len);
2710 READ_BUF(len);
2711 if (len < XDR_MAX_NETOBJ) {
2712 if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
2713 dprintk("%s: nfs_map_group_to_gid failed!\n",
2714 __FUNCTION__);
2715 } else
2716 printk(KERN_WARNING "%s: name too long (%u)!\n",
2717 __FUNCTION__, len);
2718 bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
2719 }
2720 dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid);
2721 return 0;
2722}
2723
2724static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
2725{
Al Viro8687b632006-10-19 23:28:48 -07002726 uint32_t major = 0, minor = 0;
2727 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
2729 *rdev = MKDEV(0,0);
2730 if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
2731 return -EIO;
2732 if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
2733 dev_t tmp;
2734
2735 READ_BUF(8);
2736 READ32(major);
2737 READ32(minor);
2738 tmp = MKDEV(major, minor);
2739 if (MAJOR(tmp) == major && MINOR(tmp) == minor)
2740 *rdev = tmp;
2741 bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
2742 }
2743 dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor);
2744 return 0;
2745}
2746
2747static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2748{
Al Viro8687b632006-10-19 23:28:48 -07002749 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 int status = 0;
2751
2752 *res = 0;
2753 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
2754 return -EIO;
2755 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
2756 READ_BUF(8);
2757 READ64(*res);
2758 bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
2759 }
2760 dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2761 return status;
2762}
2763
2764static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2765{
Al Viro8687b632006-10-19 23:28:48 -07002766 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 int status = 0;
2768
2769 *res = 0;
2770 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
2771 return -EIO;
2772 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
2773 READ_BUF(8);
2774 READ64(*res);
2775 bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
2776 }
2777 dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2778 return status;
2779}
2780
2781static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2782{
Al Viro8687b632006-10-19 23:28:48 -07002783 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 int status = 0;
2785
2786 *res = 0;
2787 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
2788 return -EIO;
2789 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
2790 READ_BUF(8);
2791 READ64(*res);
2792 bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
2793 }
2794 dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2795 return status;
2796}
2797
2798static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
2799{
Al Viro8687b632006-10-19 23:28:48 -07002800 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 *used = 0;
2803 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
2804 return -EIO;
2805 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
2806 READ_BUF(8);
2807 READ64(*used);
2808 bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
2809 }
2810 dprintk("%s: space used=%Lu\n", __FUNCTION__,
2811 (unsigned long long)*used);
2812 return 0;
2813}
2814
2815static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
2816{
Al Viro8687b632006-10-19 23:28:48 -07002817 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 uint64_t sec;
2819 uint32_t nsec;
2820
2821 READ_BUF(12);
2822 READ64(sec);
2823 READ32(nsec);
2824 time->tv_sec = (time_t)sec;
2825 time->tv_nsec = (long)nsec;
2826 return 0;
2827}
2828
2829static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
2830{
2831 int status = 0;
2832
2833 time->tv_sec = 0;
2834 time->tv_nsec = 0;
2835 if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
2836 return -EIO;
2837 if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
2838 status = decode_attr_time(xdr, time);
2839 bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
2840 }
2841 dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec);
2842 return status;
2843}
2844
2845static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
2846{
2847 int status = 0;
2848
2849 time->tv_sec = 0;
2850 time->tv_nsec = 0;
2851 if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
2852 return -EIO;
2853 if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
2854 status = decode_attr_time(xdr, time);
2855 bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
2856 }
2857 dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec);
2858 return status;
2859}
2860
2861static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
2862{
2863 int status = 0;
2864
2865 time->tv_sec = 0;
2866 time->tv_nsec = 0;
2867 if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
2868 return -EIO;
2869 if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
2870 status = decode_attr_time(xdr, time);
2871 bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
2872 }
2873 dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec);
2874 return status;
2875}
2876
Al Viro8687b632006-10-19 23:28:48 -07002877static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878{
2879 unsigned int attrwords = XDR_QUADLEN(attrlen);
2880 unsigned int nwords = xdr->p - savep;
2881
2882 if (unlikely(attrwords != nwords)) {
2883 printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n",
2884 __FUNCTION__,
2885 attrwords << 2,
2886 (attrwords < nwords) ? '<' : '>',
2887 nwords << 2);
2888 return -EIO;
2889 }
2890 return 0;
2891}
2892
2893static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
2894{
Al Viro8687b632006-10-19 23:28:48 -07002895 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897 READ_BUF(20);
2898 READ32(cinfo->atomic);
2899 READ64(cinfo->before);
2900 READ64(cinfo->after);
2901 return 0;
2902}
2903
2904static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
2905{
Al Viro8687b632006-10-19 23:28:48 -07002906 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 uint32_t supp, acc;
2908 int status;
2909
2910 status = decode_op_hdr(xdr, OP_ACCESS);
2911 if (status)
2912 return status;
2913 READ_BUF(8);
2914 READ32(supp);
2915 READ32(acc);
2916 access->supported = supp;
2917 access->access = acc;
2918 return 0;
2919}
2920
2921static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
2922{
Al Viro8687b632006-10-19 23:28:48 -07002923 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 int status;
2925
2926 status = decode_op_hdr(xdr, OP_CLOSE);
2927 if (status)
2928 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04002929 READ_BUF(NFS4_STATEID_SIZE);
2930 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 return 0;
2932}
2933
2934static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
2935{
Al Viro8687b632006-10-19 23:28:48 -07002936 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 int status;
2938
2939 status = decode_op_hdr(xdr, OP_COMMIT);
2940 if (status)
2941 return status;
2942 READ_BUF(8);
2943 COPYMEM(res->verf->verifier, 8);
2944 return 0;
2945}
2946
2947static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
2948{
Al Viro8687b632006-10-19 23:28:48 -07002949 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 uint32_t bmlen;
2951 int status;
2952
2953 status = decode_op_hdr(xdr, OP_CREATE);
2954 if (status)
2955 return status;
2956 if ((status = decode_change_info(xdr, cinfo)))
2957 return status;
2958 READ_BUF(4);
2959 READ32(bmlen);
2960 READ_BUF(bmlen << 2);
2961 return 0;
2962}
2963
2964static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
2965{
Al Viro8687b632006-10-19 23:28:48 -07002966 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 uint32_t attrlen,
2968 bitmap[2] = {0};
2969 int status;
2970
2971 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
2972 goto xdr_error;
2973 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
2974 goto xdr_error;
2975 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
2976 goto xdr_error;
2977 if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
2978 goto xdr_error;
2979 if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
2980 goto xdr_error;
2981 if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
2982 goto xdr_error;
2983 if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
2984 goto xdr_error;
2985 status = verify_attr_len(xdr, savep, attrlen);
2986xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04002987 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 return status;
2989}
2990
2991static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
2992{
Al Viro8687b632006-10-19 23:28:48 -07002993 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 uint32_t attrlen,
2995 bitmap[2] = {0};
2996 int status;
2997
2998 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
2999 goto xdr_error;
3000 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3001 goto xdr_error;
3002 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3003 goto xdr_error;
3004
3005 if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
3006 goto xdr_error;
3007 if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
3008 goto xdr_error;
3009 if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
3010 goto xdr_error;
3011 if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
3012 goto xdr_error;
3013 if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
3014 goto xdr_error;
3015 if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
3016 goto xdr_error;
3017
3018 status = verify_attr_len(xdr, savep, attrlen);
3019xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003020 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 return status;
3022}
3023
3024static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
3025{
Al Viro8687b632006-10-19 23:28:48 -07003026 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 uint32_t attrlen,
3028 bitmap[2] = {0};
3029 int status;
3030
3031 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3032 goto xdr_error;
3033 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3034 goto xdr_error;
3035 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3036 goto xdr_error;
3037
3038 if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
3039 goto xdr_error;
3040 if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
3041 goto xdr_error;
3042
3043 status = verify_attr_len(xdr, savep, attrlen);
3044xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003045 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 return status;
3047}
3048
3049static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
3050{
Al Viro8687b632006-10-19 23:28:48 -07003051 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 uint32_t attrlen,
3053 bitmap[2] = {0},
3054 type;
3055 int status, fmode = 0;
Manoj Naik99baf622006-06-09 09:34:24 -04003056 uint64_t fileid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
3058 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3059 goto xdr_error;
3060 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3061 goto xdr_error;
3062
3063 fattr->bitmap[0] = bitmap[0];
3064 fattr->bitmap[1] = bitmap[1];
3065
3066 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3067 goto xdr_error;
3068
3069
3070 if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
3071 goto xdr_error;
3072 fattr->type = nfs_type2fmt[type].nfs2type;
3073 fmode = nfs_type2fmt[type].mode;
3074
3075 if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
3076 goto xdr_error;
3077 if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
3078 goto xdr_error;
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -04003079 if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 goto xdr_error;
3081 if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
3082 goto xdr_error;
Trond Myklebust683b57b2006-06-09 09:34:22 -04003083 if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
Manoj Naik7aaa0b32006-06-09 09:34:23 -04003084 struct nfs4_fs_locations,
Trond Myklebust683b57b2006-06-09 09:34:22 -04003085 fattr))) != 0)
3086 goto xdr_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
3088 goto xdr_error;
3089 fattr->mode |= fmode;
3090 if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
3091 goto xdr_error;
David Howells7539bba2006-08-22 20:06:09 -04003092 if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 goto xdr_error;
David Howells7539bba2006-08-22 20:06:09 -04003094 if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 goto xdr_error;
3096 if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
3097 goto xdr_error;
3098 if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
3099 goto xdr_error;
3100 if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
3101 goto xdr_error;
3102 if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
3103 goto xdr_error;
3104 if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
3105 goto xdr_error;
Manoj Naik99baf622006-06-09 09:34:24 -04003106 if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
3107 goto xdr_error;
3108 if (fattr->fileid == 0 && fileid != 0)
3109 fattr->fileid = fileid;
Trond Myklebust33801142005-10-27 22:12:39 -04003110 if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003113 dprintk("%s: xdr returned %d\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 return status;
3115}
3116
3117
3118static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
3119{
Al Viro8687b632006-10-19 23:28:48 -07003120 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121 uint32_t attrlen, bitmap[2];
3122 int status;
3123
3124 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3125 goto xdr_error;
3126 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3127 goto xdr_error;
3128 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3129 goto xdr_error;
3130
3131 fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */
3132
3133 if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
3134 goto xdr_error;
3135 if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
3136 goto xdr_error;
3137 if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
3138 goto xdr_error;
3139 fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
3140 if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
3141 goto xdr_error;
3142 fsinfo->wtpref = fsinfo->wtmax;
3143
3144 status = verify_attr_len(xdr, savep, attrlen);
3145xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003146 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003147 return status;
3148}
3149
3150static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
3151{
Al Viro8687b632006-10-19 23:28:48 -07003152 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 uint32_t len;
3154 int status;
3155
3156 status = decode_op_hdr(xdr, OP_GETFH);
3157 if (status)
3158 return status;
3159 /* Zero handle first to allow comparisons */
3160 memset(fh, 0, sizeof(*fh));
3161
3162 READ_BUF(4);
3163 READ32(len);
3164 if (len > NFS4_FHSIZE)
3165 return -EIO;
3166 fh->size = len;
3167 READ_BUF(len);
3168 COPYMEM(fh->data, len);
3169 return 0;
3170}
3171
3172static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
3173{
3174 int status;
3175
3176 status = decode_op_hdr(xdr, OP_LINK);
3177 if (status)
3178 return status;
3179 return decode_change_info(xdr, cinfo);
3180}
3181
3182/*
3183 * We create the owner, so we know a proper owner.id length is 4.
3184 */
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003185static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186{
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003187 uint64_t offset, length, clientid;
Al Viro8687b632006-10-19 23:28:48 -07003188 __be32 *p;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003189 uint32_t namelen, type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190
3191 READ_BUF(32);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003192 READ64(offset);
3193 READ64(length);
3194 READ32(type);
3195 if (fl != NULL) {
3196 fl->fl_start = (loff_t)offset;
3197 fl->fl_end = fl->fl_start + (loff_t)length - 1;
3198 if (length == ~(uint64_t)0)
3199 fl->fl_end = OFFSET_MAX;
3200 fl->fl_type = F_WRLCK;
3201 if (type & 1)
3202 fl->fl_type = F_RDLCK;
3203 fl->fl_pid = 0;
3204 }
3205 READ64(clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 READ32(namelen);
3207 READ_BUF(namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 return -NFS4ERR_DENIED;
3209}
3210
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003211static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212{
Al Viro8687b632006-10-19 23:28:48 -07003213 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 int status;
3215
3216 status = decode_op_hdr(xdr, OP_LOCK);
3217 if (status == 0) {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003218 READ_BUF(NFS4_STATEID_SIZE);
3219 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003220 } else if (status == -NFS4ERR_DENIED)
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003221 return decode_lock_denied(xdr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 return status;
3223}
3224
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003225static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226{
3227 int status;
3228 status = decode_op_hdr(xdr, OP_LOCKT);
3229 if (status == -NFS4ERR_DENIED)
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003230 return decode_lock_denied(xdr, res->denied);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 return status;
3232}
3233
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003234static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235{
Al Viro8687b632006-10-19 23:28:48 -07003236 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 int status;
3238
3239 status = decode_op_hdr(xdr, OP_LOCKU);
3240 if (status == 0) {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003241 READ_BUF(NFS4_STATEID_SIZE);
3242 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 }
3244 return status;
3245}
3246
3247static int decode_lookup(struct xdr_stream *xdr)
3248{
3249 return decode_op_hdr(xdr, OP_LOOKUP);
3250}
3251
3252/* This is too sick! */
3253static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
3254{
Al Viro8687b632006-10-19 23:28:48 -07003255 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 uint32_t limit_type, nblocks, blocksize;
3257
3258 READ_BUF(12);
3259 READ32(limit_type);
3260 switch (limit_type) {
3261 case 1:
3262 READ64(*maxsize);
3263 break;
3264 case 2:
3265 READ32(nblocks);
3266 READ32(blocksize);
3267 *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
3268 }
3269 return 0;
3270}
3271
3272static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
3273{
Al Viro8687b632006-10-19 23:28:48 -07003274 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 uint32_t delegation_type;
3276
3277 READ_BUF(4);
3278 READ32(delegation_type);
3279 if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
3280 res->delegation_type = 0;
3281 return 0;
3282 }
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003283 READ_BUF(NFS4_STATEID_SIZE+4);
3284 COPYMEM(res->delegation.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 READ32(res->do_recall);
3286 switch (delegation_type) {
3287 case NFS4_OPEN_DELEGATE_READ:
3288 res->delegation_type = FMODE_READ;
3289 break;
3290 case NFS4_OPEN_DELEGATE_WRITE:
3291 res->delegation_type = FMODE_WRITE|FMODE_READ;
3292 if (decode_space_limit(xdr, &res->maxsize) < 0)
3293 return -EIO;
3294 }
David Howells7539bba2006-08-22 20:06:09 -04003295 return decode_ace(xdr, NULL, res->server->nfs_client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296}
3297
3298static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
3299{
Al Viro8687b632006-10-19 23:28:48 -07003300 __be32 *p;
Jeff Laytonaa53ed52007-06-05 14:49:03 -04003301 uint32_t savewords, bmlen, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 int status;
3303
3304 status = decode_op_hdr(xdr, OP_OPEN);
3305 if (status)
3306 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003307 READ_BUF(NFS4_STATEID_SIZE);
3308 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
3310 decode_change_info(xdr, &res->cinfo);
3311
3312 READ_BUF(8);
3313 READ32(res->rflags);
3314 READ32(bmlen);
3315 if (bmlen > 10)
3316 goto xdr_error;
3317
3318 READ_BUF(bmlen << 2);
Jeff Laytonaa53ed52007-06-05 14:49:03 -04003319 savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
3320 for (i = 0; i < savewords; ++i)
3321 READ32(res->attrset[i]);
3322 for (; i < NFS4_BITMAP_SIZE; i++)
3323 res->attrset[i] = 0;
3324
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 return decode_delegation(xdr, res);
3326xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003327 dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 return -EIO;
3329}
3330
3331static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
3332{
Al Viro8687b632006-10-19 23:28:48 -07003333 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 int status;
3335
3336 status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
3337 if (status)
3338 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003339 READ_BUF(NFS4_STATEID_SIZE);
3340 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 return 0;
3342}
3343
3344static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
3345{
Al Viro8687b632006-10-19 23:28:48 -07003346 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 int status;
3348
3349 status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
3350 if (status)
3351 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003352 READ_BUF(NFS4_STATEID_SIZE);
3353 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 return 0;
3355}
3356
3357static int decode_putfh(struct xdr_stream *xdr)
3358{
3359 return decode_op_hdr(xdr, OP_PUTFH);
3360}
3361
3362static int decode_putrootfh(struct xdr_stream *xdr)
3363{
3364 return decode_op_hdr(xdr, OP_PUTROOTFH);
3365}
3366
3367static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
3368{
3369 struct kvec *iov = req->rq_rcv_buf.head;
Al Viro8687b632006-10-19 23:28:48 -07003370 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 uint32_t count, eof, recvd, hdrlen;
3372 int status;
3373
3374 status = decode_op_hdr(xdr, OP_READ);
3375 if (status)
3376 return status;
3377 READ_BUF(8);
3378 READ32(eof);
3379 READ32(count);
3380 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
3381 recvd = req->rq_rcv_buf.len - hdrlen;
3382 if (count > recvd) {
3383 printk(KERN_WARNING "NFS: server cheating in read reply: "
3384 "count %u > recvd %u\n", count, recvd);
3385 count = recvd;
3386 eof = 0;
3387 }
3388 xdr_read_pages(xdr, count);
3389 res->eof = eof;
3390 res->count = count;
3391 return 0;
3392}
3393
3394static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
3395{
3396 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
3397 struct page *page = *rcvbuf->pages;
3398 struct kvec *iov = rcvbuf->head;
3399 unsigned int nr, pglen = rcvbuf->page_len;
Al Viro8687b632006-10-19 23:28:48 -07003400 __be32 *end, *entry, *p, *kaddr;
David Howellse8896492006-08-24 15:44:19 -04003401 uint32_t len, attrlen, xlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402 int hdrlen, recvd, status;
3403
3404 status = decode_op_hdr(xdr, OP_READDIR);
3405 if (status)
3406 return status;
3407 READ_BUF(8);
3408 COPYMEM(readdir->verifier.data, 8);
Trond Myklebusteadf4592005-06-22 17:16:39 +00003409 dprintk("%s: verifier = 0x%x%x\n",
3410 __FUNCTION__,
3411 ((u32 *)readdir->verifier.data)[0],
3412 ((u32 *)readdir->verifier.data)[1]);
3413
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
3415 hdrlen = (char *) p - (char *) iov->iov_base;
3416 recvd = rcvbuf->len - hdrlen;
3417 if (pglen > recvd)
3418 pglen = recvd;
3419 xdr_read_pages(xdr, pglen);
3420
3421 BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
Al Viro8687b632006-10-19 23:28:48 -07003422 kaddr = p = kmap_atomic(page, KM_USER0);
David Howellse8896492006-08-24 15:44:19 -04003423 end = p + ((pglen + readdir->pgbase) >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 entry = p;
3425 for (nr = 0; *p++; nr++) {
David Howellse8896492006-08-24 15:44:19 -04003426 if (end - p < 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 goto short_pkt;
Trond Myklebusteadf4592005-06-22 17:16:39 +00003428 dprintk("cookie = %Lu, ", *((unsigned long long *)p));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 p += 2; /* cookie */
3430 len = ntohl(*p++); /* filename length */
3431 if (len > NFS4_MAXNAMLEN) {
3432 printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
3433 goto err_unmap;
3434 }
David Howellse8896492006-08-24 15:44:19 -04003435 xlen = XDR_QUADLEN(len);
3436 if (end - p < xlen + 1)
3437 goto short_pkt;
Trond Myklebusteadf4592005-06-22 17:16:39 +00003438 dprintk("filename = %*s\n", len, (char *)p);
David Howellse8896492006-08-24 15:44:19 -04003439 p += xlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 len = ntohl(*p++); /* bitmap length */
David Howellse8896492006-08-24 15:44:19 -04003441 if (end - p < len + 1)
3442 goto short_pkt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 p += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 attrlen = XDR_QUADLEN(ntohl(*p++));
David Howellse8896492006-08-24 15:44:19 -04003445 if (end - p < attrlen + 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 goto short_pkt;
David Howellse8896492006-08-24 15:44:19 -04003447 p += attrlen; /* attributes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 entry = p;
3449 }
3450 if (!nr && (entry[0] != 0 || entry[1] == 0))
3451 goto short_pkt;
3452out:
3453 kunmap_atomic(kaddr, KM_USER0);
3454 return 0;
3455short_pkt:
Trond Myklebusteadf4592005-06-22 17:16:39 +00003456 dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003457 entry[0] = entry[1] = 0;
3458 /* truncate listing ? */
3459 if (!nr) {
3460 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
3461 entry[1] = 1;
3462 }
3463 goto out;
3464err_unmap:
3465 kunmap_atomic(kaddr, KM_USER0);
3466 return -errno_NFSERR_IO;
3467}
3468
3469static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
3470{
3471 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
3472 struct kvec *iov = rcvbuf->head;
3473 int hdrlen, len, recvd;
Al Viro8687b632006-10-19 23:28:48 -07003474 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 char *kaddr;
3476 int status;
3477
3478 status = decode_op_hdr(xdr, OP_READLINK);
3479 if (status)
3480 return status;
3481
3482 /* Convert length of symlink */
3483 READ_BUF(4);
3484 READ32(len);
3485 if (len >= rcvbuf->page_len || len <= 0) {
3486 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
3487 return -ENAMETOOLONG;
3488 }
3489 hdrlen = (char *) xdr->p - (char *) iov->iov_base;
3490 recvd = req->rq_rcv_buf.len - hdrlen;
3491 if (recvd < len) {
3492 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
3493 "count %u > recvd %u\n", len, recvd);
3494 return -EIO;
3495 }
3496 xdr_read_pages(xdr, len);
3497 /*
3498 * The XDR encode routine has set things up so that
3499 * the link text will be copied directly into the
3500 * buffer. We just have to do overflow-checking,
3501 * and and null-terminate the text (the VFS expects
3502 * null-termination).
3503 */
3504 kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
3505 kaddr[len+rcvbuf->page_base] = '\0';
3506 kunmap_atomic(kaddr, KM_USER0);
3507 return 0;
3508}
3509
3510static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
3511{
3512 int status;
3513
3514 status = decode_op_hdr(xdr, OP_REMOVE);
3515 if (status)
3516 goto out;
3517 status = decode_change_info(xdr, cinfo);
3518out:
3519 return status;
3520}
3521
3522static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
3523 struct nfs4_change_info *new_cinfo)
3524{
3525 int status;
3526
3527 status = decode_op_hdr(xdr, OP_RENAME);
3528 if (status)
3529 goto out;
3530 if ((status = decode_change_info(xdr, old_cinfo)))
3531 goto out;
3532 status = decode_change_info(xdr, new_cinfo);
3533out:
3534 return status;
3535}
3536
3537static int decode_renew(struct xdr_stream *xdr)
3538{
3539 return decode_op_hdr(xdr, OP_RENEW);
3540}
3541
Trond Myklebust56ae19f2005-10-27 22:12:40 -04003542static int
3543decode_restorefh(struct xdr_stream *xdr)
3544{
3545 return decode_op_hdr(xdr, OP_RESTOREFH);
3546}
3547
J. Bruce Fields029d1052005-06-22 17:16:22 +00003548static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
3549 size_t *acl_len)
3550{
Al Viro8687b632006-10-19 23:28:48 -07003551 __be32 *savep;
J. Bruce Fields029d1052005-06-22 17:16:22 +00003552 uint32_t attrlen,
3553 bitmap[2] = {0};
3554 struct kvec *iov = req->rq_rcv_buf.head;
3555 int status;
3556
3557 *acl_len = 0;
3558 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3559 goto out;
3560 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3561 goto out;
3562 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3563 goto out;
3564
3565 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
3566 return -EIO;
3567 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
3568 int hdrlen, recvd;
3569
3570 /* We ignore &savep and don't do consistency checks on
3571 * the attr length. Let userspace figure it out.... */
3572 hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
3573 recvd = req->rq_rcv_buf.len - hdrlen;
3574 if (attrlen > recvd) {
3575 printk(KERN_WARNING "NFS: server cheating in getattr"
3576 " acl reply: attrlen %u > recvd %u\n",
3577 attrlen, recvd);
3578 return -EINVAL;
3579 }
J. Bruce Fieldsc04871e2006-05-30 16:28:58 -04003580 xdr_read_pages(xdr, attrlen);
J. Bruce Fields029d1052005-06-22 17:16:22 +00003581 *acl_len = attrlen;
J. Bruce Fields8c233cf2005-10-13 16:54:27 -04003582 } else
3583 status = -EOPNOTSUPP;
J. Bruce Fields029d1052005-06-22 17:16:22 +00003584
3585out:
3586 return status;
3587}
3588
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589static int
3590decode_savefh(struct xdr_stream *xdr)
3591{
3592 return decode_op_hdr(xdr, OP_SAVEFH);
3593}
3594
3595static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
3596{
Al Viro8687b632006-10-19 23:28:48 -07003597 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 uint32_t bmlen;
3599 int status;
3600
3601
3602 status = decode_op_hdr(xdr, OP_SETATTR);
3603 if (status)
3604 return status;
3605 READ_BUF(4);
3606 READ32(bmlen);
3607 READ_BUF(bmlen << 2);
3608 return 0;
3609}
3610
David Howellsadfa6f92006-08-22 20:06:08 -04003611static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612{
Al Viro8687b632006-10-19 23:28:48 -07003613 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 uint32_t opnum;
3615 int32_t nfserr;
3616
3617 READ_BUF(8);
3618 READ32(opnum);
3619 if (opnum != OP_SETCLIENTID) {
3620 printk(KERN_NOTICE
3621 "nfs4_decode_setclientid: Server returned operation"
3622 " %d\n", opnum);
3623 return -EIO;
3624 }
3625 READ32(nfserr);
3626 if (nfserr == NFS_OK) {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003627 READ_BUF(8 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 READ64(clp->cl_clientid);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003629 COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 } else if (nfserr == NFSERR_CLID_INUSE) {
3631 uint32_t len;
3632
3633 /* skip netid string */
3634 READ_BUF(4);
3635 READ32(len);
3636 READ_BUF(len);
3637
3638 /* skip uaddr string */
3639 READ_BUF(4);
3640 READ32(len);
3641 READ_BUF(len);
3642 return -NFSERR_CLID_INUSE;
3643 } else
David Howells0a8ea432006-08-22 20:06:08 -04003644 return -nfs4_stat_to_errno(nfserr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645
3646 return 0;
3647}
3648
3649static int decode_setclientid_confirm(struct xdr_stream *xdr)
3650{
3651 return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
3652}
3653
3654static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
3655{
Al Viro8687b632006-10-19 23:28:48 -07003656 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 int status;
3658
3659 status = decode_op_hdr(xdr, OP_WRITE);
3660 if (status)
3661 return status;
3662
3663 READ_BUF(16);
3664 READ32(res->count);
3665 READ32(res->verf->committed);
3666 COPYMEM(res->verf->verifier, 8);
3667 return 0;
3668}
3669
3670static int decode_delegreturn(struct xdr_stream *xdr)
3671{
3672 return decode_op_hdr(xdr, OP_DELEGRETURN);
3673}
3674
3675/*
3676 * Decode OPEN_DOWNGRADE response
3677 */
Al Viro8687b632006-10-19 23:28:48 -07003678static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679{
3680 struct xdr_stream xdr;
3681 struct compound_hdr hdr;
3682 int status;
3683
3684 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3685 status = decode_compound_hdr(&xdr, &hdr);
3686 if (status)
3687 goto out;
3688 status = decode_putfh(&xdr);
3689 if (status)
3690 goto out;
3691 status = decode_open_downgrade(&xdr, res);
Trond Myklebust516a6af2005-10-27 22:12:41 -04003692 if (status != 0)
3693 goto out;
3694 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695out:
3696 return status;
3697}
3698
3699/*
3700 * END OF "GENERIC" DECODE ROUTINES.
3701 */
3702
3703/*
3704 * Decode ACCESS response
3705 */
Al Viro8687b632006-10-19 23:28:48 -07003706static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707{
3708 struct xdr_stream xdr;
3709 struct compound_hdr hdr;
3710 int status;
3711
3712 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3713 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3714 goto out;
3715 if ((status = decode_putfh(&xdr)) == 0)
3716 status = decode_access(&xdr, res);
3717out:
3718 return status;
3719}
3720
3721/*
3722 * Decode LOOKUP response
3723 */
Al Viro8687b632006-10-19 23:28:48 -07003724static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725{
3726 struct xdr_stream xdr;
3727 struct compound_hdr hdr;
3728 int status;
3729
3730 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3731 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3732 goto out;
3733 if ((status = decode_putfh(&xdr)) != 0)
3734 goto out;
3735 if ((status = decode_lookup(&xdr)) != 0)
3736 goto out;
3737 if ((status = decode_getfh(&xdr, res->fh)) != 0)
3738 goto out;
3739 status = decode_getfattr(&xdr, res->fattr, res->server);
3740out:
3741 return status;
3742}
3743
3744/*
3745 * Decode LOOKUP_ROOT response
3746 */
Al Viro8687b632006-10-19 23:28:48 -07003747static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748{
3749 struct xdr_stream xdr;
3750 struct compound_hdr hdr;
3751 int status;
3752
3753 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3754 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3755 goto out;
3756 if ((status = decode_putrootfh(&xdr)) != 0)
3757 goto out;
3758 if ((status = decode_getfh(&xdr, res->fh)) == 0)
3759 status = decode_getfattr(&xdr, res->fattr, res->server);
3760out:
3761 return status;
3762}
3763
3764/*
3765 * Decode REMOVE response
3766 */
Al Viro8687b632006-10-19 23:28:48 -07003767static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768{
3769 struct xdr_stream xdr;
3770 struct compound_hdr hdr;
3771 int status;
3772
3773 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3774 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3775 goto out;
Trond Myklebust16e42952005-10-27 22:12:44 -04003776 if ((status = decode_putfh(&xdr)) != 0)
3777 goto out;
3778 if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
3779 goto out;
3780 decode_getfattr(&xdr, res->dir_attr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781out:
3782 return status;
3783}
3784
3785/*
3786 * Decode RENAME response
3787 */
Al Viro8687b632006-10-19 23:28:48 -07003788static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789{
3790 struct xdr_stream xdr;
3791 struct compound_hdr hdr;
3792 int status;
3793
3794 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3795 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3796 goto out;
3797 if ((status = decode_putfh(&xdr)) != 0)
3798 goto out;
3799 if ((status = decode_savefh(&xdr)) != 0)
3800 goto out;
3801 if ((status = decode_putfh(&xdr)) != 0)
3802 goto out;
Trond Myklebust6caf2c82005-10-27 22:12:43 -04003803 if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
3804 goto out;
3805 /* Current FH is target directory */
3806 if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0)
3807 goto out;
3808 if ((status = decode_restorefh(&xdr)) != 0)
3809 goto out;
3810 decode_getfattr(&xdr, res->old_fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811out:
3812 return status;
3813}
3814
3815/*
3816 * Decode LINK response
3817 */
Al Viro8687b632006-10-19 23:28:48 -07003818static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819{
3820 struct xdr_stream xdr;
3821 struct compound_hdr hdr;
3822 int status;
3823
3824 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3825 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3826 goto out;
3827 if ((status = decode_putfh(&xdr)) != 0)
3828 goto out;
3829 if ((status = decode_savefh(&xdr)) != 0)
3830 goto out;
3831 if ((status = decode_putfh(&xdr)) != 0)
3832 goto out;
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003833 if ((status = decode_link(&xdr, &res->cinfo)) != 0)
3834 goto out;
3835 /*
3836 * Note order: OP_LINK leaves the directory as the current
3837 * filehandle.
3838 */
3839 if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0)
3840 goto out;
3841 if ((status = decode_restorefh(&xdr)) != 0)
3842 goto out;
3843 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844out:
3845 return status;
3846}
3847
3848/*
3849 * Decode CREATE response
3850 */
Al Viro8687b632006-10-19 23:28:48 -07003851static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852{
3853 struct xdr_stream xdr;
3854 struct compound_hdr hdr;
3855 int status;
3856
3857 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3858 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3859 goto out;
3860 if ((status = decode_putfh(&xdr)) != 0)
3861 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04003862 if ((status = decode_savefh(&xdr)) != 0)
3863 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
3865 goto out;
3866 if ((status = decode_getfh(&xdr, res->fh)) != 0)
3867 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04003868 if (decode_getfattr(&xdr, res->fattr, res->server) != 0)
3869 goto out;
3870 if ((status = decode_restorefh(&xdr)) != 0)
3871 goto out;
3872 decode_getfattr(&xdr, res->dir_fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873out:
3874 return status;
3875}
3876
3877/*
3878 * Decode SYMLINK response
3879 */
Al Viro8687b632006-10-19 23:28:48 -07003880static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881{
3882 return nfs4_xdr_dec_create(rqstp, p, res);
3883}
3884
3885/*
3886 * Decode GETATTR response
3887 */
Al Viro8687b632006-10-19 23:28:48 -07003888static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889{
3890 struct xdr_stream xdr;
3891 struct compound_hdr hdr;
3892 int status;
3893
3894 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3895 status = decode_compound_hdr(&xdr, &hdr);
3896 if (status)
3897 goto out;
3898 status = decode_putfh(&xdr);
3899 if (status)
3900 goto out;
3901 status = decode_getfattr(&xdr, res->fattr, res->server);
3902out:
3903 return status;
3904
3905}
3906
J. Bruce Fields23ec6962005-06-22 17:16:22 +00003907/*
3908 * Encode an SETACL request
3909 */
3910static int
Al Viro8687b632006-10-19 23:28:48 -07003911nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
J. Bruce Fields23ec6962005-06-22 17:16:22 +00003912{
3913 struct xdr_stream xdr;
3914 struct compound_hdr hdr = {
3915 .nops = 2,
3916 };
3917 int status;
3918
3919 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
3920 encode_compound_hdr(&xdr, &hdr);
3921 status = encode_putfh(&xdr, args->fh);
3922 if (status)
3923 goto out;
3924 status = encode_setacl(&xdr, args);
3925out:
3926 return status;
3927}
3928/*
3929 * Decode SETACL response
3930 */
3931static int
Al Viro8687b632006-10-19 23:28:48 -07003932nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
J. Bruce Fields23ec6962005-06-22 17:16:22 +00003933{
3934 struct xdr_stream xdr;
3935 struct compound_hdr hdr;
3936 int status;
3937
3938 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3939 status = decode_compound_hdr(&xdr, &hdr);
3940 if (status)
3941 goto out;
3942 status = decode_putfh(&xdr);
3943 if (status)
3944 goto out;
3945 status = decode_setattr(&xdr, res);
3946out:
3947 return status;
3948}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949
3950/*
J. Bruce Fields029d1052005-06-22 17:16:22 +00003951 * Decode GETACL response
3952 */
3953static int
Al Viro8687b632006-10-19 23:28:48 -07003954nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
J. Bruce Fields029d1052005-06-22 17:16:22 +00003955{
3956 struct xdr_stream xdr;
3957 struct compound_hdr hdr;
3958 int status;
3959
3960 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3961 status = decode_compound_hdr(&xdr, &hdr);
3962 if (status)
3963 goto out;
3964 status = decode_putfh(&xdr);
3965 if (status)
3966 goto out;
3967 status = decode_getacl(&xdr, rqstp, acl_len);
3968
3969out:
3970 return status;
3971}
3972
3973/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 * Decode CLOSE response
3975 */
Al Viro8687b632006-10-19 23:28:48 -07003976static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977{
3978 struct xdr_stream xdr;
3979 struct compound_hdr hdr;
3980 int status;
3981
3982 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3983 status = decode_compound_hdr(&xdr, &hdr);
3984 if (status)
3985 goto out;
3986 status = decode_putfh(&xdr);
3987 if (status)
3988 goto out;
3989 status = decode_close(&xdr, res);
Trond Myklebust516a6af2005-10-27 22:12:41 -04003990 if (status != 0)
3991 goto out;
3992 /*
3993 * Note: Server may do delete on close for this file
3994 * in which case the getattr call will fail with
3995 * an ESTALE error. Shouldn't be a problem,
3996 * though, since fattr->valid will remain unset.
3997 */
3998 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999out:
4000 return status;
4001}
4002
4003/*
4004 * Decode OPEN response
4005 */
Al Viro8687b632006-10-19 23:28:48 -07004006static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007{
4008 struct xdr_stream xdr;
4009 struct compound_hdr hdr;
4010 int status;
4011
4012 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4013 status = decode_compound_hdr(&xdr, &hdr);
4014 if (status)
4015 goto out;
4016 status = decode_putfh(&xdr);
4017 if (status)
4018 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04004019 status = decode_savefh(&xdr);
4020 if (status)
4021 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 status = decode_open(&xdr, res);
4023 if (status)
4024 goto out;
4025 status = decode_getfh(&xdr, &res->fh);
4026 if (status)
4027 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04004028 if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
4029 goto out;
4030 if ((status = decode_restorefh(&xdr)) != 0)
4031 goto out;
4032 decode_getfattr(&xdr, res->dir_attr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033out:
4034 return status;
4035}
4036
4037/*
4038 * Decode OPEN_CONFIRM response
4039 */
Al Viro8687b632006-10-19 23:28:48 -07004040static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041{
4042 struct xdr_stream xdr;
4043 struct compound_hdr hdr;
4044 int status;
4045
4046 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4047 status = decode_compound_hdr(&xdr, &hdr);
4048 if (status)
4049 goto out;
4050 status = decode_putfh(&xdr);
4051 if (status)
4052 goto out;
4053 status = decode_open_confirm(&xdr, res);
4054out:
4055 return status;
4056}
4057
4058/*
4059 * Decode OPEN response
4060 */
Al Viro8687b632006-10-19 23:28:48 -07004061static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062{
4063 struct xdr_stream xdr;
4064 struct compound_hdr hdr;
4065 int status;
4066
4067 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4068 status = decode_compound_hdr(&xdr, &hdr);
4069 if (status)
4070 goto out;
4071 status = decode_putfh(&xdr);
4072 if (status)
4073 goto out;
4074 status = decode_open(&xdr, res);
Trond Myklebust864472e2006-01-03 09:55:15 +01004075 if (status)
4076 goto out;
4077 decode_getfattr(&xdr, res->f_attr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078out:
4079 return status;
4080}
4081
4082/*
4083 * Decode SETATTR response
4084 */
Al Viro8687b632006-10-19 23:28:48 -07004085static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086{
4087 struct xdr_stream xdr;
4088 struct compound_hdr hdr;
4089 int status;
4090
4091 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4092 status = decode_compound_hdr(&xdr, &hdr);
4093 if (status)
4094 goto out;
4095 status = decode_putfh(&xdr);
4096 if (status)
4097 goto out;
4098 status = decode_setattr(&xdr, res);
4099 if (status)
4100 goto out;
4101 status = decode_getfattr(&xdr, res->fattr, res->server);
4102 if (status == NFS4ERR_DELAY)
4103 status = 0;
4104out:
4105 return status;
4106}
4107
4108/*
4109 * Decode LOCK response
4110 */
Al Viro8687b632006-10-19 23:28:48 -07004111static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112{
4113 struct xdr_stream xdr;
4114 struct compound_hdr hdr;
4115 int status;
4116
4117 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4118 status = decode_compound_hdr(&xdr, &hdr);
4119 if (status)
4120 goto out;
4121 status = decode_putfh(&xdr);
4122 if (status)
4123 goto out;
4124 status = decode_lock(&xdr, res);
4125out:
4126 return status;
4127}
4128
4129/*
4130 * Decode LOCKT response
4131 */
Al Viro8687b632006-10-19 23:28:48 -07004132static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133{
4134 struct xdr_stream xdr;
4135 struct compound_hdr hdr;
4136 int status;
4137
4138 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4139 status = decode_compound_hdr(&xdr, &hdr);
4140 if (status)
4141 goto out;
4142 status = decode_putfh(&xdr);
4143 if (status)
4144 goto out;
4145 status = decode_lockt(&xdr, res);
4146out:
4147 return status;
4148}
4149
4150/*
4151 * Decode LOCKU response
4152 */
Al Viro8687b632006-10-19 23:28:48 -07004153static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154{
4155 struct xdr_stream xdr;
4156 struct compound_hdr hdr;
4157 int status;
4158
4159 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4160 status = decode_compound_hdr(&xdr, &hdr);
4161 if (status)
4162 goto out;
4163 status = decode_putfh(&xdr);
4164 if (status)
4165 goto out;
4166 status = decode_locku(&xdr, res);
4167out:
4168 return status;
4169}
4170
4171/*
4172 * Decode READLINK response
4173 */
Al Viro8687b632006-10-19 23:28:48 -07004174static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
4176 struct xdr_stream xdr;
4177 struct compound_hdr hdr;
4178 int status;
4179
4180 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4181 status = decode_compound_hdr(&xdr, &hdr);
4182 if (status)
4183 goto out;
4184 status = decode_putfh(&xdr);
4185 if (status)
4186 goto out;
4187 status = decode_readlink(&xdr, rqstp);
4188out:
4189 return status;
4190}
4191
4192/*
4193 * Decode READDIR response
4194 */
Al Viro8687b632006-10-19 23:28:48 -07004195static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196{
4197 struct xdr_stream xdr;
4198 struct compound_hdr hdr;
4199 int status;
4200
4201 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4202 status = decode_compound_hdr(&xdr, &hdr);
4203 if (status)
4204 goto out;
4205 status = decode_putfh(&xdr);
4206 if (status)
4207 goto out;
4208 status = decode_readdir(&xdr, rqstp, res);
4209out:
4210 return status;
4211}
4212
4213/*
4214 * Decode Read response
4215 */
Al Viro8687b632006-10-19 23:28:48 -07004216static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217{
4218 struct xdr_stream xdr;
4219 struct compound_hdr hdr;
4220 int status;
4221
4222 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4223 status = decode_compound_hdr(&xdr, &hdr);
4224 if (status)
4225 goto out;
4226 status = decode_putfh(&xdr);
4227 if (status)
4228 goto out;
4229 status = decode_read(&xdr, rqstp, res);
4230 if (!status)
4231 status = res->count;
4232out:
4233 return status;
4234}
4235
4236/*
4237 * Decode WRITE response
4238 */
Al Viro8687b632006-10-19 23:28:48 -07004239static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240{
4241 struct xdr_stream xdr;
4242 struct compound_hdr hdr;
4243 int status;
4244
4245 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4246 status = decode_compound_hdr(&xdr, &hdr);
4247 if (status)
4248 goto out;
4249 status = decode_putfh(&xdr);
4250 if (status)
4251 goto out;
4252 status = decode_write(&xdr, res);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004253 if (status)
4254 goto out;
4255 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 if (!status)
4257 status = res->count;
4258out:
4259 return status;
4260}
4261
4262/*
4263 * Decode COMMIT response
4264 */
Al Viro8687b632006-10-19 23:28:48 -07004265static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266{
4267 struct xdr_stream xdr;
4268 struct compound_hdr hdr;
4269 int status;
4270
4271 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4272 status = decode_compound_hdr(&xdr, &hdr);
4273 if (status)
4274 goto out;
4275 status = decode_putfh(&xdr);
4276 if (status)
4277 goto out;
4278 status = decode_commit(&xdr, res);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004279 if (status)
4280 goto out;
4281 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282out:
4283 return status;
4284}
4285
4286/*
4287 * FSINFO request
4288 */
Al Viro8687b632006-10-19 23:28:48 -07004289static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290{
4291 struct xdr_stream xdr;
4292 struct compound_hdr hdr;
4293 int status;
4294
4295 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4296 status = decode_compound_hdr(&xdr, &hdr);
4297 if (!status)
4298 status = decode_putfh(&xdr);
4299 if (!status)
4300 status = decode_fsinfo(&xdr, fsinfo);
4301 if (!status)
David Howells0a8ea432006-08-22 20:06:08 -04004302 status = -nfs4_stat_to_errno(hdr.status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 return status;
4304}
4305
4306/*
4307 * PATHCONF request
4308 */
Al Viro8687b632006-10-19 23:28:48 -07004309static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310{
4311 struct xdr_stream xdr;
4312 struct compound_hdr hdr;
4313 int status;
4314
4315 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4316 status = decode_compound_hdr(&xdr, &hdr);
4317 if (!status)
4318 status = decode_putfh(&xdr);
4319 if (!status)
4320 status = decode_pathconf(&xdr, pathconf);
4321 return status;
4322}
4323
4324/*
4325 * STATFS request
4326 */
Al Viro8687b632006-10-19 23:28:48 -07004327static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328{
4329 struct xdr_stream xdr;
4330 struct compound_hdr hdr;
4331 int status;
4332
4333 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4334 status = decode_compound_hdr(&xdr, &hdr);
4335 if (!status)
4336 status = decode_putfh(&xdr);
4337 if (!status)
4338 status = decode_statfs(&xdr, fsstat);
4339 return status;
4340}
4341
4342/*
4343 * GETATTR_BITMAP request
4344 */
Al Viro8687b632006-10-19 23:28:48 -07004345static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346{
4347 struct xdr_stream xdr;
4348 struct compound_hdr hdr;
4349 int status;
4350
4351 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4352 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
4353 goto out;
4354 if ((status = decode_putfh(&xdr)) != 0)
4355 goto out;
4356 status = decode_server_caps(&xdr, res);
4357out:
4358 return status;
4359}
4360
4361/*
4362 * Decode RENEW response
4363 */
Al Viro8687b632006-10-19 23:28:48 -07004364static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365{
4366 struct xdr_stream xdr;
4367 struct compound_hdr hdr;
4368 int status;
4369
4370 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4371 status = decode_compound_hdr(&xdr, &hdr);
4372 if (!status)
4373 status = decode_renew(&xdr);
4374 return status;
4375}
4376
4377/*
4378 * a SETCLIENTID request
4379 */
Al Viro8687b632006-10-19 23:28:48 -07004380static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
David Howellsadfa6f92006-08-22 20:06:08 -04004381 struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382{
4383 struct xdr_stream xdr;
4384 struct compound_hdr hdr;
4385 int status;
4386
4387 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4388 status = decode_compound_hdr(&xdr, &hdr);
4389 if (!status)
4390 status = decode_setclientid(&xdr, clp);
4391 if (!status)
David Howells0a8ea432006-08-22 20:06:08 -04004392 status = -nfs4_stat_to_errno(hdr.status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 return status;
4394}
4395
4396/*
4397 * a SETCLIENTID_CONFIRM request
4398 */
Al Viro8687b632006-10-19 23:28:48 -07004399static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400{
4401 struct xdr_stream xdr;
4402 struct compound_hdr hdr;
4403 int status;
4404
4405 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4406 status = decode_compound_hdr(&xdr, &hdr);
4407 if (!status)
4408 status = decode_setclientid_confirm(&xdr);
4409 if (!status)
4410 status = decode_putrootfh(&xdr);
4411 if (!status)
4412 status = decode_fsinfo(&xdr, fsinfo);
4413 if (!status)
David Howells0a8ea432006-08-22 20:06:08 -04004414 status = -nfs4_stat_to_errno(hdr.status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 return status;
4416}
4417
4418/*
4419 * DELEGRETURN request
4420 */
Al Viro8687b632006-10-19 23:28:48 -07004421static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422{
4423 struct xdr_stream xdr;
4424 struct compound_hdr hdr;
4425 int status;
4426
4427 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4428 status = decode_compound_hdr(&xdr, &hdr);
Trond Myklebustfa178f22006-01-03 09:55:38 +01004429 if (status != 0)
4430 goto out;
4431 status = decode_putfh(&xdr);
4432 if (status != 0)
4433 goto out;
4434 status = decode_delegreturn(&xdr);
4435 decode_getfattr(&xdr, res->fattr, res->server);
4436out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 return status;
4438}
4439
Trond Myklebust683b57b2006-06-09 09:34:22 -04004440/*
4441 * FS_LOCATIONS request
4442 */
Al Viro8687b632006-10-19 23:28:48 -07004443static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res)
Trond Myklebust683b57b2006-06-09 09:34:22 -04004444{
4445 struct xdr_stream xdr;
4446 struct compound_hdr hdr;
4447 int status;
4448
4449 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4450 status = decode_compound_hdr(&xdr, &hdr);
4451 if (status != 0)
4452 goto out;
4453 if ((status = decode_putfh(&xdr)) != 0)
4454 goto out;
4455 if ((status = decode_lookup(&xdr)) != 0)
4456 goto out;
4457 xdr_enter_page(&xdr, PAGE_SIZE);
4458 status = decode_getfattr(&xdr, &res->fattr, res->server);
4459out:
4460 return status;
4461}
4462
Al Viro0dbb4c62006-10-19 23:28:49 -07004463__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464{
4465 uint32_t bitmap[2] = {0};
4466 uint32_t len;
4467
4468 if (!*p++) {
4469 if (!*p)
4470 return ERR_PTR(-EAGAIN);
4471 entry->eof = 1;
4472 return ERR_PTR(-EBADCOOKIE);
4473 }
4474
4475 entry->prev_cookie = entry->cookie;
4476 p = xdr_decode_hyper(p, &entry->cookie);
4477 entry->len = ntohl(*p++);
4478 entry->name = (const char *) p;
4479 p += XDR_QUADLEN(entry->len);
4480
4481 /*
4482 * In case the server doesn't return an inode number,
4483 * we fake one here. (We don't use inode number 0,
4484 * since glibc seems to choke on it...)
4485 */
4486 entry->ino = 1;
4487
4488 len = ntohl(*p++); /* bitmap length */
4489 if (len-- > 0) {
4490 bitmap[0] = ntohl(*p++);
4491 if (len-- > 0) {
4492 bitmap[1] = ntohl(*p++);
4493 p += len;
4494 }
4495 }
4496 len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */
4497 if (len > 0) {
Manoj Naik97d312d2005-06-22 17:16:39 +00004498 if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
4499 bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
4500 /* Ignore the return value of rdattr_error for now */
4501 p++;
4502 len--;
4503 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
4505 xdr_decode_hyper(p, &entry->ino);
4506 else if (bitmap[0] == FATTR4_WORD0_FILEID)
4507 xdr_decode_hyper(p, &entry->ino);
4508 p += len;
4509 }
4510
4511 entry->eof = !p[0] && p[1];
4512 return p;
4513}
4514
4515/*
4516 * We need to translate between nfs status return values and
4517 * the local errno values which may not be the same.
4518 */
4519static struct {
4520 int stat;
4521 int errno;
4522} nfs_errtbl[] = {
4523 { NFS4_OK, 0 },
4524 { NFS4ERR_PERM, EPERM },
4525 { NFS4ERR_NOENT, ENOENT },
4526 { NFS4ERR_IO, errno_NFSERR_IO },
4527 { NFS4ERR_NXIO, ENXIO },
4528 { NFS4ERR_ACCESS, EACCES },
4529 { NFS4ERR_EXIST, EEXIST },
4530 { NFS4ERR_XDEV, EXDEV },
4531 { NFS4ERR_NOTDIR, ENOTDIR },
4532 { NFS4ERR_ISDIR, EISDIR },
4533 { NFS4ERR_INVAL, EINVAL },
4534 { NFS4ERR_FBIG, EFBIG },
4535 { NFS4ERR_NOSPC, ENOSPC },
4536 { NFS4ERR_ROFS, EROFS },
4537 { NFS4ERR_MLINK, EMLINK },
4538 { NFS4ERR_NAMETOOLONG, ENAMETOOLONG },
4539 { NFS4ERR_NOTEMPTY, ENOTEMPTY },
4540 { NFS4ERR_DQUOT, EDQUOT },
4541 { NFS4ERR_STALE, ESTALE },
4542 { NFS4ERR_BADHANDLE, EBADHANDLE },
Manoj Naik6ebf3652005-06-22 17:16:39 +00004543 { NFS4ERR_BADOWNER, EINVAL },
4544 { NFS4ERR_BADNAME, EINVAL },
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 { NFS4ERR_BAD_COOKIE, EBADCOOKIE },
4546 { NFS4ERR_NOTSUPP, ENOTSUPP },
4547 { NFS4ERR_TOOSMALL, ETOOSMALL },
4548 { NFS4ERR_SERVERFAULT, ESERVERFAULT },
4549 { NFS4ERR_BADTYPE, EBADTYPE },
4550 { NFS4ERR_LOCKED, EAGAIN },
4551 { NFS4ERR_RESOURCE, EREMOTEIO },
4552 { NFS4ERR_SYMLINK, ELOOP },
4553 { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP },
4554 { NFS4ERR_DEADLOCK, EDEADLK },
4555 { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs
4556 * to be handled by a
4557 * middle-layer.
4558 */
4559 { -1, EIO }
4560};
4561
4562/*
4563 * Convert an NFS error code to a local one.
4564 * This one is used jointly by NFSv2 and NFSv3.
4565 */
4566static int
David Howells0a8ea432006-08-22 20:06:08 -04004567nfs4_stat_to_errno(int stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568{
4569 int i;
4570 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
4571 if (nfs_errtbl[i].stat == stat)
4572 return nfs_errtbl[i].errno;
4573 }
4574 if (stat <= 10000 || stat > 10100) {
4575 /* The server is looney tunes. */
4576 return ESERVERFAULT;
4577 }
4578 /* If we cannot translate the error, the recovery routines should
4579 * handle it.
4580 * Note: remaining NFSv4 error codes have values > 10000, so should
4581 * not conflict with native Linux error codes.
4582 */
4583 return stat;
4584}
4585
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586#define PROC(proc, argtype, restype) \
4587[NFSPROC4_CLNT_##proc] = { \
4588 .p_proc = NFSPROC4_COMPOUND, \
4589 .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \
4590 .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04004591 .p_arglen = NFS4_##argtype##_sz, \
4592 .p_replen = NFS4_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05004593 .p_statidx = NFSPROC4_CLNT_##proc, \
4594 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 }
4596
4597struct rpc_procinfo nfs4_procedures[] = {
4598 PROC(READ, enc_read, dec_read),
4599 PROC(WRITE, enc_write, dec_write),
4600 PROC(COMMIT, enc_commit, dec_commit),
4601 PROC(OPEN, enc_open, dec_open),
4602 PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm),
4603 PROC(OPEN_NOATTR, enc_open_noattr, dec_open_noattr),
4604 PROC(OPEN_DOWNGRADE, enc_open_downgrade, dec_open_downgrade),
4605 PROC(CLOSE, enc_close, dec_close),
4606 PROC(SETATTR, enc_setattr, dec_setattr),
4607 PROC(FSINFO, enc_fsinfo, dec_fsinfo),
4608 PROC(RENEW, enc_renew, dec_renew),
4609 PROC(SETCLIENTID, enc_setclientid, dec_setclientid),
4610 PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
4611 PROC(LOCK, enc_lock, dec_lock),
4612 PROC(LOCKT, enc_lockt, dec_lockt),
4613 PROC(LOCKU, enc_locku, dec_locku),
4614 PROC(ACCESS, enc_access, dec_access),
4615 PROC(GETATTR, enc_getattr, dec_getattr),
4616 PROC(LOOKUP, enc_lookup, dec_lookup),
4617 PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root),
4618 PROC(REMOVE, enc_remove, dec_remove),
4619 PROC(RENAME, enc_rename, dec_rename),
4620 PROC(LINK, enc_link, dec_link),
4621 PROC(SYMLINK, enc_symlink, dec_symlink),
4622 PROC(CREATE, enc_create, dec_create),
4623 PROC(PATHCONF, enc_pathconf, dec_pathconf),
4624 PROC(STATFS, enc_statfs, dec_statfs),
4625 PROC(READLINK, enc_readlink, dec_readlink),
4626 PROC(READDIR, enc_readdir, dec_readdir),
4627 PROC(SERVER_CAPS, enc_server_caps, dec_server_caps),
4628 PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
J. Bruce Fields029d1052005-06-22 17:16:22 +00004629 PROC(GETACL, enc_getacl, dec_getacl),
J. Bruce Fields23ec6962005-06-22 17:16:22 +00004630 PROC(SETACL, enc_setacl, dec_setacl),
Trond Myklebust683b57b2006-06-09 09:34:22 -04004631 PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632};
4633
4634struct rpc_version nfs_version4 = {
4635 .number = 4,
Tobias Klausere8c96f82006-03-24 03:15:34 -08004636 .nrprocs = ARRAY_SIZE(nfs4_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 .procs = nfs4_procedures
4638};
4639
4640/*
4641 * Local variables:
4642 * c-basic-offset: 8
4643 * End:
4644 */