blob: 4c8f67d4752338d1eb67a58f3b2f30c92d998a8a [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)
Trond Myklebuste6889622007-07-02 13:58:30 -0400122#define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz)
123#define decode_lookup_maxsz (op_decode_hdr_maxsz)
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)
Trond Myklebuste6889622007-07-02 13:58:30 -0400164#define encode_fs_locations_maxsz \
165 (encode_getattr_maxsz)
166#define decode_fs_locations_maxsz \
167 (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */
169#define NFS4_dec_compound_sz (1024) /* XXX: large enough? */
170#define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \
171 encode_putfh_maxsz + \
172 op_encode_hdr_maxsz + 7)
173#define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \
174 decode_putfh_maxsz + \
175 op_decode_hdr_maxsz + 2)
176#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \
177 encode_putfh_maxsz + \
178 op_encode_hdr_maxsz)
179#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \
180 decode_putfh_maxsz + \
181 op_decode_hdr_maxsz)
182#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \
183 encode_putfh_maxsz + \
184 op_encode_hdr_maxsz + 9)
185#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \
186 decode_putfh_maxsz + \
187 op_decode_hdr_maxsz + 2)
188#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \
189 encode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400190 op_encode_hdr_maxsz + 8 + \
191 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \
193 decode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400194 op_decode_hdr_maxsz + 4 + \
195 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196#define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \
197 encode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400198 op_encode_hdr_maxsz + 3 + \
199 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200#define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \
201 decode_putfh_maxsz + \
Trond Myklebust4f9838c2005-10-27 22:12:44 -0400202 op_decode_hdr_maxsz + 2 + \
203 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204#define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400205 encode_putfh_maxsz + \
206 encode_savefh_maxsz + \
207 encode_open_maxsz + \
208 encode_getfh_maxsz + \
209 encode_getattr_maxsz + \
210 encode_restorefh_maxsz + \
211 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400213 decode_putfh_maxsz + \
214 decode_savefh_maxsz + \
215 decode_open_maxsz + \
216 decode_getfh_maxsz + \
217 decode_getattr_maxsz + \
218 decode_restorefh_maxsz + \
219 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220#define NFS4_enc_open_confirm_sz \
221 (compound_encode_hdr_maxsz + \
222 encode_putfh_maxsz + \
223 op_encode_hdr_maxsz + 5)
224#define NFS4_dec_open_confirm_sz (compound_decode_hdr_maxsz + \
225 decode_putfh_maxsz + \
226 op_decode_hdr_maxsz + 4)
227#define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \
228 encode_putfh_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400229 encode_open_maxsz + \
230 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \
232 decode_putfh_maxsz + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400233 decode_open_maxsz + \
234 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235#define NFS4_enc_open_downgrade_sz \
236 (compound_encode_hdr_maxsz + \
237 encode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400238 op_encode_hdr_maxsz + 7 + \
239 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240#define NFS4_dec_open_downgrade_sz \
241 (compound_decode_hdr_maxsz + \
242 decode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400243 op_decode_hdr_maxsz + 4 + \
244 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \
246 encode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400247 op_encode_hdr_maxsz + 5 + \
248 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \
250 decode_putfh_maxsz + \
Trond Myklebust516a6af2005-10-27 22:12:41 -0400251 op_decode_hdr_maxsz + 4 + \
252 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \
254 encode_putfh_maxsz + \
255 op_encode_hdr_maxsz + 4 + \
J. Bruce Fields96928202005-06-22 17:16:22 +0000256 nfs4_fattr_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 encode_getattr_maxsz)
258#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \
259 decode_putfh_maxsz + \
Chuck Lever6ce7dc92007-05-08 18:23:28 -0400260 op_decode_hdr_maxsz + 3 + \
261 nfs4_fattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262#define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \
263 encode_putfh_maxsz + \
264 encode_fsinfo_maxsz)
265#define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \
266 decode_putfh_maxsz + \
267 decode_fsinfo_maxsz)
268#define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \
269 encode_renew_maxsz)
270#define NFS4_dec_renew_sz (compound_decode_hdr_maxsz + \
271 decode_renew_maxsz)
272#define NFS4_enc_setclientid_sz (compound_encode_hdr_maxsz + \
273 encode_setclientid_maxsz)
274#define NFS4_dec_setclientid_sz (compound_decode_hdr_maxsz + \
275 decode_setclientid_maxsz)
276#define NFS4_enc_setclientid_confirm_sz \
277 (compound_encode_hdr_maxsz + \
278 encode_setclientid_confirm_maxsz + \
279 encode_putrootfh_maxsz + \
280 encode_fsinfo_maxsz)
281#define NFS4_dec_setclientid_confirm_sz \
282 (compound_decode_hdr_maxsz + \
283 decode_setclientid_confirm_maxsz + \
284 decode_putrootfh_maxsz + \
285 decode_fsinfo_maxsz)
286#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
287 encode_putfh_maxsz + \
288 encode_getattr_maxsz + \
289 op_encode_hdr_maxsz + \
290 1 + 1 + 2 + 2 + \
291 1 + 4 + 1 + 2 + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400292 lock_owner_id_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293#define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \
294 decode_putfh_maxsz + \
295 decode_getattr_maxsz + \
296 op_decode_hdr_maxsz + \
297 2 + 2 + 1 + 2 + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400298 lock_owner_id_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299#define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \
300 encode_putfh_maxsz + \
301 encode_getattr_maxsz + \
302 op_encode_hdr_maxsz + \
303 1 + 2 + 2 + 2 + \
Trond Myklebust2cebf822007-07-02 13:57:28 -0400304 lock_owner_id_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305#define NFS4_dec_lockt_sz (NFS4_dec_lock_sz)
306#define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \
307 encode_putfh_maxsz + \
308 encode_getattr_maxsz + \
309 op_encode_hdr_maxsz + \
310 1 + 1 + 4 + 2 + 2)
311#define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \
312 decode_putfh_maxsz + \
313 decode_getattr_maxsz + \
314 op_decode_hdr_maxsz + 4)
315#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
316 encode_putfh_maxsz + \
317 op_encode_hdr_maxsz + 1)
318#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
319 decode_putfh_maxsz + \
320 op_decode_hdr_maxsz + 2)
321#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
322 encode_putfh_maxsz + \
323 encode_getattr_maxsz)
324#define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \
325 decode_putfh_maxsz + \
326 decode_getattr_maxsz)
327#define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \
328 encode_putfh_maxsz + \
329 encode_lookup_maxsz + \
330 encode_getattr_maxsz + \
331 encode_getfh_maxsz)
332#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \
333 decode_putfh_maxsz + \
Trond Myklebuste6889622007-07-02 13:58:30 -0400334 decode_lookup_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 decode_getattr_maxsz + \
336 decode_getfh_maxsz)
337#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
338 encode_putrootfh_maxsz + \
339 encode_getattr_maxsz + \
340 encode_getfh_maxsz)
341#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
342 decode_putrootfh_maxsz + \
343 decode_getattr_maxsz + \
344 decode_getfh_maxsz)
345#define NFS4_enc_remove_sz (compound_encode_hdr_maxsz + \
346 encode_putfh_maxsz + \
Trond Myklebust16e42952005-10-27 22:12:44 -0400347 encode_remove_maxsz + \
348 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349#define NFS4_dec_remove_sz (compound_decode_hdr_maxsz + \
350 decode_putfh_maxsz + \
Trond Myklebust16e42952005-10-27 22:12:44 -0400351 op_decode_hdr_maxsz + 5 + \
352 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353#define NFS4_enc_rename_sz (compound_encode_hdr_maxsz + \
354 encode_putfh_maxsz + \
355 encode_savefh_maxsz + \
356 encode_putfh_maxsz + \
Trond Myklebust6caf2c82005-10-27 22:12:43 -0400357 encode_rename_maxsz + \
358 encode_getattr_maxsz + \
359 encode_restorefh_maxsz + \
360 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361#define NFS4_dec_rename_sz (compound_decode_hdr_maxsz + \
362 decode_putfh_maxsz + \
363 decode_savefh_maxsz + \
364 decode_putfh_maxsz + \
Trond Myklebust6caf2c82005-10-27 22:12:43 -0400365 decode_rename_maxsz + \
366 decode_getattr_maxsz + \
367 decode_restorefh_maxsz + \
368 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369#define NFS4_enc_link_sz (compound_encode_hdr_maxsz + \
370 encode_putfh_maxsz + \
371 encode_savefh_maxsz + \
372 encode_putfh_maxsz + \
Trond Myklebust91ba2ee2005-10-27 22:12:42 -0400373 encode_link_maxsz + \
374 decode_getattr_maxsz + \
375 encode_restorefh_maxsz + \
376 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377#define NFS4_dec_link_sz (compound_decode_hdr_maxsz + \
378 decode_putfh_maxsz + \
379 decode_savefh_maxsz + \
380 decode_putfh_maxsz + \
Trond Myklebust91ba2ee2005-10-27 22:12:42 -0400381 decode_link_maxsz + \
382 decode_getattr_maxsz + \
383 decode_restorefh_maxsz + \
384 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385#define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \
386 encode_putfh_maxsz + \
387 encode_symlink_maxsz + \
388 encode_getattr_maxsz + \
389 encode_getfh_maxsz)
390#define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \
391 decode_putfh_maxsz + \
392 decode_symlink_maxsz + \
393 decode_getattr_maxsz + \
394 decode_getfh_maxsz)
395#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
396 encode_putfh_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400397 encode_savefh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 encode_create_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400399 encode_getfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 encode_getattr_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400401 encode_restorefh_maxsz + \
402 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403#define NFS4_dec_create_sz (compound_decode_hdr_maxsz + \
404 decode_putfh_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400405 decode_savefh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 decode_create_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400407 decode_getfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 decode_getattr_maxsz + \
Trond Myklebust56ae19f2005-10-27 22:12:40 -0400409 decode_restorefh_maxsz + \
410 decode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411#define NFS4_enc_pathconf_sz (compound_encode_hdr_maxsz + \
412 encode_putfh_maxsz + \
413 encode_getattr_maxsz)
414#define NFS4_dec_pathconf_sz (compound_decode_hdr_maxsz + \
415 decode_putfh_maxsz + \
416 decode_getattr_maxsz)
417#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \
418 encode_putfh_maxsz + \
419 encode_getattr_maxsz)
420#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \
421 decode_putfh_maxsz + \
422 op_decode_hdr_maxsz + 12)
423#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
Trond Myklebustab91f262007-02-02 14:47:17 -0800424 encode_putfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 encode_getattr_maxsz)
426#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
Trond Myklebustab91f262007-02-02 14:47:17 -0800427 decode_putfh_maxsz + \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 decode_getattr_maxsz)
429#define NFS4_enc_delegreturn_sz (compound_encode_hdr_maxsz + \
430 encode_putfh_maxsz + \
Trond Myklebustfa178f22006-01-03 09:55:38 +0100431 encode_delegreturn_maxsz + \
432 encode_getattr_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
Trond Myklebustfa178f22006-01-03 09:55:38 +0100434 decode_delegreturn_maxsz + \
435 decode_getattr_maxsz)
J. Bruce Fields029d1052005-06-22 17:16:22 +0000436#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
437 encode_putfh_maxsz + \
438 encode_getattr_maxsz)
439#define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \
440 decode_putfh_maxsz + \
441 op_decode_hdr_maxsz + \
442 nfs4_fattr_bitmap_maxsz + 1)
J. Bruce Fields23ec6962005-06-22 17:16:22 +0000443#define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \
444 encode_putfh_maxsz + \
445 op_encode_hdr_maxsz + 4 + \
446 nfs4_fattr_bitmap_maxsz + 1)
447#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
448 decode_putfh_maxsz + \
449 op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
Trond Myklebust683b57b2006-06-09 09:34:22 -0400450#define NFS4_enc_fs_locations_sz \
451 (compound_encode_hdr_maxsz + \
452 encode_putfh_maxsz + \
Trond Myklebuste6889622007-07-02 13:58:30 -0400453 encode_lookup_maxsz + \
454 encode_fs_locations_maxsz)
Trond Myklebust683b57b2006-06-09 09:34:22 -0400455#define NFS4_dec_fs_locations_sz \
456 (compound_decode_hdr_maxsz + \
457 decode_putfh_maxsz + \
Trond Myklebuste6889622007-07-02 13:58:30 -0400458 decode_lookup_maxsz + \
459 decode_fs_locations_maxsz)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461static struct {
462 unsigned int mode;
463 unsigned int nfs2type;
464} nfs_type2fmt[] = {
465 { 0, NFNON },
466 { S_IFREG, NFREG },
467 { S_IFDIR, NFDIR },
468 { S_IFBLK, NFBLK },
469 { S_IFCHR, NFCHR },
470 { S_IFLNK, NFLNK },
471 { S_IFSOCK, NFSOCK },
472 { S_IFIFO, NFFIFO },
473 { 0, NFNON },
474 { 0, NFNON },
475};
476
477struct compound_hdr {
478 int32_t status;
479 uint32_t nops;
480 uint32_t taglen;
481 char * tag;
482};
483
484/*
485 * START OF "GENERIC" ENCODE ROUTINES.
486 * These may look a little ugly since they are imported from a "generic"
487 * set of XDR encode/decode routines which are intended to be shared by
488 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
489 *
490 * If the pain of reading these is too great, it should be a straightforward
491 * task to translate them into Linux-specific versions which are more
492 * consistent with the style used in NFSv2/v3...
493 */
494#define WRITE32(n) *p++ = htonl(n)
495#define WRITE64(n) do { \
496 *p++ = htonl((uint32_t)((n) >> 32)); \
497 *p++ = htonl((uint32_t)(n)); \
498} while (0)
499#define WRITEMEM(ptr,nbytes) do { \
500 p = xdr_encode_opaque_fixed(p, ptr, nbytes); \
501} while (0)
502
503#define RESERVE_SPACE(nbytes) do { \
504 p = xdr_reserve_space(xdr, nbytes); \
505 if (!p) printk("RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
506 BUG_ON(!p); \
507} while (0)
508
509static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
510{
Al Viro8687b632006-10-19 23:28:48 -0700511 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 p = xdr_reserve_space(xdr, 4 + len);
514 BUG_ON(p == NULL);
515 xdr_encode_opaque(p, str, len);
516}
517
518static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
519{
Al Viro8687b632006-10-19 23:28:48 -0700520 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
522 dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
523 BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
524 RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2));
525 WRITE32(hdr->taglen);
526 WRITEMEM(hdr->tag, hdr->taglen);
527 WRITE32(NFS4_MINOR_VERSION);
528 WRITE32(hdr->nops);
529 return 0;
530}
531
532static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
533{
Al Viro8687b632006-10-19 23:28:48 -0700534 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
537 BUG_ON(p == NULL);
538 xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
539}
540
541static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
542{
543 char owner_name[IDMAP_NAMESZ];
544 char owner_group[IDMAP_NAMESZ];
545 int owner_namelen = 0;
546 int owner_grouplen = 0;
Al Viro8687b632006-10-19 23:28:48 -0700547 __be32 *p;
548 __be32 *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 int len;
550 uint32_t bmval0 = 0;
551 uint32_t bmval1 = 0;
552 int status;
553
554 /*
555 * We reserve enough space to write the entire attribute buffer at once.
556 * In the worst-case, this would be
557 * 12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
558 * = 36 bytes, plus any contribution from variable-length fields
J. Bruce Fields23ec6962005-06-22 17:16:22 +0000559 * such as owner/group.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 */
561 len = 16;
562
563 /* Sigh */
564 if (iap->ia_valid & ATTR_SIZE)
565 len += 8;
566 if (iap->ia_valid & ATTR_MODE)
567 len += 4;
568 if (iap->ia_valid & ATTR_UID) {
David Howells7539bba2006-08-22 20:06:09 -0400569 owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (owner_namelen < 0) {
571 printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
572 iap->ia_uid);
573 /* XXX */
574 strcpy(owner_name, "nobody");
575 owner_namelen = sizeof("nobody") - 1;
576 /* goto out; */
577 }
578 len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
579 }
580 if (iap->ia_valid & ATTR_GID) {
David Howells7539bba2006-08-22 20:06:09 -0400581 owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 if (owner_grouplen < 0) {
583 printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
584 iap->ia_gid);
585 strcpy(owner_group, "nobody");
586 owner_grouplen = sizeof("nobody") - 1;
587 /* goto out; */
588 }
589 len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
590 }
591 if (iap->ia_valid & ATTR_ATIME_SET)
592 len += 16;
593 else if (iap->ia_valid & ATTR_ATIME)
594 len += 4;
595 if (iap->ia_valid & ATTR_MTIME_SET)
596 len += 16;
597 else if (iap->ia_valid & ATTR_MTIME)
598 len += 4;
599 RESERVE_SPACE(len);
600
601 /*
602 * We write the bitmap length now, but leave the bitmap and the attribute
603 * buffer length to be backfilled at the end of this routine.
604 */
605 WRITE32(2);
606 q = p;
607 p += 3;
608
609 if (iap->ia_valid & ATTR_SIZE) {
610 bmval0 |= FATTR4_WORD0_SIZE;
611 WRITE64(iap->ia_size);
612 }
613 if (iap->ia_valid & ATTR_MODE) {
614 bmval1 |= FATTR4_WORD1_MODE;
Trond Myklebustcf3fff52006-01-03 09:55:53 +0100615 WRITE32(iap->ia_mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 }
617 if (iap->ia_valid & ATTR_UID) {
618 bmval1 |= FATTR4_WORD1_OWNER;
619 WRITE32(owner_namelen);
620 WRITEMEM(owner_name, owner_namelen);
621 }
622 if (iap->ia_valid & ATTR_GID) {
623 bmval1 |= FATTR4_WORD1_OWNER_GROUP;
624 WRITE32(owner_grouplen);
625 WRITEMEM(owner_group, owner_grouplen);
626 }
627 if (iap->ia_valid & ATTR_ATIME_SET) {
628 bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
629 WRITE32(NFS4_SET_TO_CLIENT_TIME);
630 WRITE32(0);
631 WRITE32(iap->ia_mtime.tv_sec);
632 WRITE32(iap->ia_mtime.tv_nsec);
633 }
634 else if (iap->ia_valid & ATTR_ATIME) {
635 bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
636 WRITE32(NFS4_SET_TO_SERVER_TIME);
637 }
638 if (iap->ia_valid & ATTR_MTIME_SET) {
639 bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
640 WRITE32(NFS4_SET_TO_CLIENT_TIME);
641 WRITE32(0);
642 WRITE32(iap->ia_mtime.tv_sec);
643 WRITE32(iap->ia_mtime.tv_nsec);
644 }
645 else if (iap->ia_valid & ATTR_MTIME) {
646 bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
647 WRITE32(NFS4_SET_TO_SERVER_TIME);
648 }
649
650 /*
651 * Now we backfill the bitmap and the attribute buffer length.
652 */
653 if (len != ((char *)p - (char *)q) + 4) {
654 printk ("encode_attr: Attr length calculation error! %u != %Zu\n",
655 len, ((char *)p - (char *)q) + 4);
656 BUG();
657 }
658 len = (char *)p - (char *)q - 12;
659 *q++ = htonl(bmval0);
660 *q++ = htonl(bmval1);
661 *q++ = htonl(len);
662
663 status = 0;
664/* out: */
665 return status;
666}
667
668static int encode_access(struct xdr_stream *xdr, u32 access)
669{
Al Viro8687b632006-10-19 23:28:48 -0700670 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
672 RESERVE_SPACE(8);
673 WRITE32(OP_ACCESS);
674 WRITE32(access);
675
676 return 0;
677}
678
679static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
680{
Al Viro8687b632006-10-19 23:28:48 -0700681 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400683 RESERVE_SPACE(8+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 WRITE32(OP_CLOSE);
Trond Myklebustcee54fc2005-10-18 14:20:12 -0700685 WRITE32(arg->seqid->sequence->counter);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400686 WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 return 0;
689}
690
691static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
692{
Al Viro8687b632006-10-19 23:28:48 -0700693 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 RESERVE_SPACE(16);
696 WRITE32(OP_COMMIT);
697 WRITE64(args->offset);
698 WRITE32(args->count);
699
700 return 0;
701}
702
703static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
704{
Al Viro8687b632006-10-19 23:28:48 -0700705 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707 RESERVE_SPACE(8);
708 WRITE32(OP_CREATE);
709 WRITE32(create->ftype);
710
711 switch (create->ftype) {
712 case NF4LNK:
Chuck Lever94a6d752006-08-22 20:06:23 -0400713 RESERVE_SPACE(4);
714 WRITE32(create->u.symlink.len);
715 xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 break;
717
718 case NF4BLK: case NF4CHR:
719 RESERVE_SPACE(8);
720 WRITE32(create->u.device.specdata1);
721 WRITE32(create->u.device.specdata2);
722 break;
723
724 default:
725 break;
726 }
727
728 RESERVE_SPACE(4 + create->name->len);
729 WRITE32(create->name->len);
730 WRITEMEM(create->name->name, create->name->len);
731
732 return encode_attrs(xdr, create->attrs, create->server);
733}
734
735static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
736{
Al Viro8687b632006-10-19 23:28:48 -0700737 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 RESERVE_SPACE(12);
740 WRITE32(OP_GETATTR);
741 WRITE32(1);
742 WRITE32(bitmap);
743 return 0;
744}
745
746static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
747{
Al Viro8687b632006-10-19 23:28:48 -0700748 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 RESERVE_SPACE(16);
751 WRITE32(OP_GETATTR);
752 WRITE32(2);
753 WRITE32(bm0);
754 WRITE32(bm1);
755 return 0;
756}
757
758static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
759{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 return encode_getattr_two(xdr,
761 bitmask[0] & nfs4_fattr_bitmap[0],
762 bitmask[1] & nfs4_fattr_bitmap[1]);
763}
764
765static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
766{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
768 bitmask[1] & nfs4_fsinfo_bitmap[1]);
769}
770
Manoj Naik830b8e32006-06-09 09:34:25 -0400771static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
772{
773 return encode_getattr_two(xdr,
774 bitmask[0] & nfs4_fs_locations_bitmap[0],
775 bitmask[1] & nfs4_fs_locations_bitmap[1]);
776}
777
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778static int encode_getfh(struct xdr_stream *xdr)
779{
Al Viro8687b632006-10-19 23:28:48 -0700780 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 RESERVE_SPACE(4);
783 WRITE32(OP_GETFH);
784
785 return 0;
786}
787
788static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
789{
Al Viro8687b632006-10-19 23:28:48 -0700790 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 RESERVE_SPACE(8 + name->len);
793 WRITE32(OP_LINK);
794 WRITE32(name->len);
795 WRITEMEM(name->name, name->len);
796
797 return 0;
798}
799
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100800static inline int nfs4_lock_type(struct file_lock *fl, int block)
801{
802 if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
803 return block ? NFS4_READW_LT : NFS4_READ_LT;
804 return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
805}
806
807static inline uint64_t nfs4_lock_length(struct file_lock *fl)
808{
809 if (fl->fl_end == OFFSET_MAX)
810 return ~(uint64_t)0;
811 return fl->fl_end - fl->fl_start + 1;
812}
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814/*
815 * opcode,type,reclaim,offset,length,new_lock_owner = 32
816 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
817 */
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100818static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819{
Al Viro8687b632006-10-19 23:28:48 -0700820 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822 RESERVE_SPACE(32);
823 WRITE32(OP_LOCK);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100824 WRITE32(nfs4_lock_type(args->fl, args->block));
825 WRITE32(args->reclaim);
826 WRITE64(args->fl->fl_start);
827 WRITE64(nfs4_lock_length(args->fl));
828 WRITE32(args->new_lock_owner);
829 if (args->new_lock_owner){
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400830 RESERVE_SPACE(4+NFS4_STATEID_SIZE+20);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100831 WRITE32(args->open_seqid->sequence->counter);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400832 WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100833 WRITE32(args->lock_seqid->sequence->counter);
834 WRITE64(args->lock_owner.clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 WRITE32(4);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100836 WRITE32(args->lock_owner.id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838 else {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400839 RESERVE_SPACE(NFS4_STATEID_SIZE+4);
840 WRITEMEM(args->lock_stateid->data, NFS4_STATEID_SIZE);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100841 WRITE32(args->lock_seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 }
843
844 return 0;
845}
846
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100847static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
Al Viro8687b632006-10-19 23:28:48 -0700849 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851 RESERVE_SPACE(40);
852 WRITE32(OP_LOCKT);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100853 WRITE32(nfs4_lock_type(args->fl, 0));
854 WRITE64(args->fl->fl_start);
855 WRITE64(nfs4_lock_length(args->fl));
856 WRITE64(args->lock_owner.clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 WRITE32(4);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100858 WRITE32(args->lock_owner.id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
860 return 0;
861}
862
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100863static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
Al Viro8687b632006-10-19 23:28:48 -0700865 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400867 RESERVE_SPACE(12+NFS4_STATEID_SIZE+16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 WRITE32(OP_LOCKU);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100869 WRITE32(nfs4_lock_type(args->fl, 0));
870 WRITE32(args->seqid->sequence->counter);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -0400871 WRITEMEM(args->stateid->data, NFS4_STATEID_SIZE);
Trond Myklebust911d1aa2006-01-03 09:55:16 +0100872 WRITE64(args->fl->fl_start);
873 WRITE64(nfs4_lock_length(args->fl));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874
875 return 0;
876}
877
878static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
879{
880 int len = name->len;
Al Viro8687b632006-10-19 23:28:48 -0700881 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 RESERVE_SPACE(8 + len);
884 WRITE32(OP_LOOKUP);
885 WRITE32(len);
886 WRITEMEM(name->name, len);
887
888 return 0;
889}
890
891static void encode_share_access(struct xdr_stream *xdr, int open_flags)
892{
Al Viro8687b632006-10-19 23:28:48 -0700893 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894
895 RESERVE_SPACE(8);
896 switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
897 case FMODE_READ:
898 WRITE32(NFS4_SHARE_ACCESS_READ);
899 break;
900 case FMODE_WRITE:
901 WRITE32(NFS4_SHARE_ACCESS_WRITE);
902 break;
903 case FMODE_READ|FMODE_WRITE:
904 WRITE32(NFS4_SHARE_ACCESS_BOTH);
905 break;
906 default:
907 BUG();
908 }
909 WRITE32(0); /* for linux, share_deny = 0 always */
910}
911
912static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
913{
Al Viro8687b632006-10-19 23:28:48 -0700914 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 /*
916 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
917 * owner 4 = 32
918 */
919 RESERVE_SPACE(8);
920 WRITE32(OP_OPEN);
Trond Myklebustcee54fc2005-10-18 14:20:12 -0700921 WRITE32(arg->seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 encode_share_access(xdr, arg->open_flags);
923 RESERVE_SPACE(16);
924 WRITE64(arg->clientid);
925 WRITE32(4);
926 WRITE32(arg->id);
927}
928
929static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
930{
Al Viro8687b632006-10-19 23:28:48 -0700931 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
933 RESERVE_SPACE(4);
934 switch(arg->open_flags & O_EXCL) {
935 case 0:
936 WRITE32(NFS4_CREATE_UNCHECKED);
937 encode_attrs(xdr, arg->u.attrs, arg->server);
938 break;
939 default:
940 WRITE32(NFS4_CREATE_EXCLUSIVE);
941 encode_nfs4_verifier(xdr, &arg->u.verifier);
942 }
943}
944
945static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
946{
Al Viro8687b632006-10-19 23:28:48 -0700947 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 RESERVE_SPACE(4);
950 switch (arg->open_flags & O_CREAT) {
951 case 0:
952 WRITE32(NFS4_OPEN_NOCREATE);
953 break;
954 default:
955 BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
956 WRITE32(NFS4_OPEN_CREATE);
957 encode_createmode(xdr, arg);
958 }
959}
960
961static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
962{
Al Viro8687b632006-10-19 23:28:48 -0700963 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964
965 RESERVE_SPACE(4);
966 switch (delegation_type) {
967 case 0:
968 WRITE32(NFS4_OPEN_DELEGATE_NONE);
969 break;
970 case FMODE_READ:
971 WRITE32(NFS4_OPEN_DELEGATE_READ);
972 break;
973 case FMODE_WRITE|FMODE_READ:
974 WRITE32(NFS4_OPEN_DELEGATE_WRITE);
975 break;
976 default:
977 BUG();
978 }
979}
980
981static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
982{
Al Viro8687b632006-10-19 23:28:48 -0700983 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985 RESERVE_SPACE(4);
986 WRITE32(NFS4_OPEN_CLAIM_NULL);
987 encode_string(xdr, name->len, name->name);
988}
989
990static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
991{
Al Viro8687b632006-10-19 23:28:48 -0700992 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994 RESERVE_SPACE(4);
995 WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
996 encode_delegation_type(xdr, type);
997}
998
999static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
1000{
Al Viro8687b632006-10-19 23:28:48 -07001001 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001003 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001005 WRITEMEM(stateid->data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 encode_string(xdr, name->len, name->name);
1007}
1008
1009static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
1010{
1011 encode_openhdr(xdr, arg);
1012 encode_opentype(xdr, arg);
1013 switch (arg->claim) {
1014 case NFS4_OPEN_CLAIM_NULL:
1015 encode_claim_null(xdr, arg->name);
1016 break;
1017 case NFS4_OPEN_CLAIM_PREVIOUS:
1018 encode_claim_previous(xdr, arg->u.delegation_type);
1019 break;
1020 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1021 encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
1022 break;
1023 default:
1024 BUG();
1025 }
1026 return 0;
1027}
1028
1029static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
1030{
Al Viro8687b632006-10-19 23:28:48 -07001031 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001033 RESERVE_SPACE(4+NFS4_STATEID_SIZE+4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 WRITE32(OP_OPEN_CONFIRM);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001035 WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
Trond Myklebustcee54fc2005-10-18 14:20:12 -07001036 WRITE32(arg->seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 return 0;
1039}
1040
1041static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
1042{
Al Viro8687b632006-10-19 23:28:48 -07001043 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001045 RESERVE_SPACE(4+NFS4_STATEID_SIZE+4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 WRITE32(OP_OPEN_DOWNGRADE);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001047 WRITEMEM(arg->stateid->data, NFS4_STATEID_SIZE);
Trond Myklebustcee54fc2005-10-18 14:20:12 -07001048 WRITE32(arg->seqid->sequence->counter);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 encode_share_access(xdr, arg->open_flags);
1050 return 0;
1051}
1052
1053static int
1054encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
1055{
1056 int len = fh->size;
Al Viro8687b632006-10-19 23:28:48 -07001057 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
1059 RESERVE_SPACE(8 + len);
1060 WRITE32(OP_PUTFH);
1061 WRITE32(len);
1062 WRITEMEM(fh->data, len);
1063
1064 return 0;
1065}
1066
1067static int encode_putrootfh(struct xdr_stream *xdr)
1068{
Al Viro8687b632006-10-19 23:28:48 -07001069 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
1071 RESERVE_SPACE(4);
1072 WRITE32(OP_PUTROOTFH);
1073
1074 return 0;
1075}
1076
1077static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
1078{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 nfs4_stateid stateid;
Al Viro8687b632006-10-19 23:28:48 -07001080 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001082 RESERVE_SPACE(NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 if (ctx->state != NULL) {
1084 nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001085 WRITEMEM(stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 } else
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001087 WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088}
1089
1090static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
1091{
Al Viro8687b632006-10-19 23:28:48 -07001092 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
1094 RESERVE_SPACE(4);
1095 WRITE32(OP_READ);
1096
1097 encode_stateid(xdr, args->context);
1098
1099 RESERVE_SPACE(12);
1100 WRITE64(args->offset);
1101 WRITE32(args->count);
1102
1103 return 0;
1104}
1105
1106static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
1107{
Trond Myklebust1be27f32007-06-27 14:29:04 -04001108 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Manoj Naik97d312d2005-06-22 17:16:39 +00001109 uint32_t attrs[2] = {
1110 FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
1111 FATTR4_WORD1_MOUNTED_ON_FILEID,
1112 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 int replen;
Al Viro8687b632006-10-19 23:28:48 -07001114 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001116 RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 WRITE32(OP_READDIR);
1118 WRITE64(readdir->cookie);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001119 WRITEMEM(readdir->verifier.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 WRITE32(readdir->count >> 1); /* We're not doing readdirplus */
1121 WRITE32(readdir->count);
1122 WRITE32(2);
Manoj Naik97d312d2005-06-22 17:16:39 +00001123 /* Switch to mounted_on_fileid if the server supports it */
1124 if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
1125 attrs[0] &= ~FATTR4_WORD0_FILEID;
1126 else
1127 attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
1128 WRITE32(attrs[0] & readdir->bitmask[0]);
1129 WRITE32(attrs[1] & readdir->bitmask[1]);
Trond Myklebusteadf4592005-06-22 17:16:39 +00001130 dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n",
1131 __FUNCTION__,
1132 (unsigned long long)readdir->cookie,
1133 ((u32 *)readdir->verifier.data)[0],
1134 ((u32 *)readdir->verifier.data)[1],
1135 attrs[0] & readdir->bitmask[0],
1136 attrs[1] & readdir->bitmask[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 /* set up reply kvec
1139 * toplevel_status + taglen + rescount + OP_PUTFH + status
1140 * + OP_READDIR + status + verifer(2) = 9
1141 */
1142 replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
1143 xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
1144 readdir->pgbase, readdir->count);
Trond Myklebusteadf4592005-06-22 17:16:39 +00001145 dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
1146 __FUNCTION__, replen, readdir->pages,
1147 readdir->pgbase, readdir->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 return 0;
1150}
1151
1152static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
1153{
Trond Myklebust1be27f32007-06-27 14:29:04 -04001154 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 unsigned int replen;
Al Viro8687b632006-10-19 23:28:48 -07001156 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
1158 RESERVE_SPACE(4);
1159 WRITE32(OP_READLINK);
1160
1161 /* set up reply kvec
1162 * toplevel_status + taglen + rescount + OP_PUTFH + status
1163 * + OP_READLINK + status + string length = 8
1164 */
1165 replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2;
1166 xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages,
1167 readlink->pgbase, readlink->pglen);
1168
1169 return 0;
1170}
1171
1172static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
1173{
Al Viro8687b632006-10-19 23:28:48 -07001174 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175
1176 RESERVE_SPACE(8 + name->len);
1177 WRITE32(OP_REMOVE);
1178 WRITE32(name->len);
1179 WRITEMEM(name->name, name->len);
1180
1181 return 0;
1182}
1183
1184static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
1185{
Al Viro8687b632006-10-19 23:28:48 -07001186 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
1188 RESERVE_SPACE(8 + oldname->len);
1189 WRITE32(OP_RENAME);
1190 WRITE32(oldname->len);
1191 WRITEMEM(oldname->name, oldname->len);
1192
1193 RESERVE_SPACE(4 + newname->len);
1194 WRITE32(newname->len);
1195 WRITEMEM(newname->name, newname->len);
1196
1197 return 0;
1198}
1199
David Howellsadfa6f92006-08-22 20:06:08 -04001200static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
Al Viro8687b632006-10-19 23:28:48 -07001202 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 RESERVE_SPACE(12);
1205 WRITE32(OP_RENEW);
1206 WRITE64(client_stateid->cl_clientid);
1207
1208 return 0;
1209}
1210
1211static int
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001212encode_restorefh(struct xdr_stream *xdr)
1213{
Al Viro8687b632006-10-19 23:28:48 -07001214 __be32 *p;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001215
1216 RESERVE_SPACE(4);
1217 WRITE32(OP_RESTOREFH);
1218
1219 return 0;
1220}
1221
1222static int
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001223encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
1224{
Al Viro8687b632006-10-19 23:28:48 -07001225 __be32 *p;
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001226
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001227 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001228 WRITE32(OP_SETATTR);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001229 WRITEMEM(zero_stateid.data, NFS4_STATEID_SIZE);
J. Bruce Fields23ec6962005-06-22 17:16:22 +00001230 RESERVE_SPACE(2*4);
1231 WRITE32(1);
1232 WRITE32(FATTR4_WORD0_ACL);
1233 if (arg->acl_len % 4)
1234 return -EINVAL;
1235 RESERVE_SPACE(4);
1236 WRITE32(arg->acl_len);
1237 xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1238 return 0;
1239}
1240
1241static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242encode_savefh(struct xdr_stream *xdr)
1243{
Al Viro8687b632006-10-19 23:28:48 -07001244 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246 RESERVE_SPACE(4);
1247 WRITE32(OP_SAVEFH);
1248
1249 return 0;
1250}
1251
1252static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
1253{
1254 int status;
Al Viro8687b632006-10-19 23:28:48 -07001255 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001257 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 WRITE32(OP_SETATTR);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001259 WRITEMEM(arg->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 if ((status = encode_attrs(xdr, arg->iap, server)))
1262 return status;
1263
1264 return 0;
1265}
1266
1267static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
1268{
Al Viro8687b632006-10-19 23:28:48 -07001269 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001271 RESERVE_SPACE(4 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 WRITE32(OP_SETCLIENTID);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001273 WRITEMEM(setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
1275 encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
1276 RESERVE_SPACE(4);
1277 WRITE32(setclientid->sc_prog);
1278 encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
1279 encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1280 RESERVE_SPACE(4);
1281 WRITE32(setclientid->sc_cb_ident);
1282
1283 return 0;
1284}
1285
David Howellsadfa6f92006-08-22 20:06:08 -04001286static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
Al Viro8687b632006-10-19 23:28:48 -07001288 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001290 RESERVE_SPACE(12 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 WRITE32(OP_SETCLIENTID_CONFIRM);
1292 WRITE64(client_state->cl_clientid);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001293 WRITEMEM(client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
1295 return 0;
1296}
1297
1298static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
1299{
Al Viro8687b632006-10-19 23:28:48 -07001300 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 RESERVE_SPACE(4);
1303 WRITE32(OP_WRITE);
1304
1305 encode_stateid(xdr, args->context);
1306
1307 RESERVE_SPACE(16);
1308 WRITE64(args->offset);
1309 WRITE32(args->stable);
1310 WRITE32(args->count);
1311
1312 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1313
1314 return 0;
1315}
1316
1317static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
1318{
Al Viro8687b632006-10-19 23:28:48 -07001319 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001321 RESERVE_SPACE(4+NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
1323 WRITE32(OP_DELEGRETURN);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04001324 WRITEMEM(stateid->data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 return 0;
1326
1327}
1328/*
1329 * END OF "GENERIC" ENCODE ROUTINES.
1330 */
1331
1332/*
1333 * Encode an ACCESS request
1334 */
Al Viro8687b632006-10-19 23:28:48 -07001335static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336{
1337 struct xdr_stream xdr;
1338 struct compound_hdr hdr = {
1339 .nops = 2,
1340 };
1341 int status;
1342
1343 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1344 encode_compound_hdr(&xdr, &hdr);
1345 if ((status = encode_putfh(&xdr, args->fh)) == 0)
1346 status = encode_access(&xdr, args->access);
1347 return status;
1348}
1349
1350/*
1351 * Encode LOOKUP request
1352 */
Al Viro8687b632006-10-19 23:28:48 -07001353static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354{
1355 struct xdr_stream xdr;
1356 struct compound_hdr hdr = {
1357 .nops = 4,
1358 };
1359 int status;
1360
1361 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1362 encode_compound_hdr(&xdr, &hdr);
1363 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
1364 goto out;
1365 if ((status = encode_lookup(&xdr, args->name)) != 0)
1366 goto out;
1367 if ((status = encode_getfh(&xdr)) != 0)
1368 goto out;
1369 status = encode_getfattr(&xdr, args->bitmask);
1370out:
1371 return status;
1372}
1373
1374/*
1375 * Encode LOOKUP_ROOT request
1376 */
Al Viro8687b632006-10-19 23:28:48 -07001377static 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 -07001378{
1379 struct xdr_stream xdr;
1380 struct compound_hdr hdr = {
1381 .nops = 3,
1382 };
1383 int status;
1384
1385 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1386 encode_compound_hdr(&xdr, &hdr);
1387 if ((status = encode_putrootfh(&xdr)) != 0)
1388 goto out;
1389 if ((status = encode_getfh(&xdr)) == 0)
1390 status = encode_getfattr(&xdr, args->bitmask);
1391out:
1392 return status;
1393}
1394
1395/*
1396 * Encode REMOVE request
1397 */
Al Viro8687b632006-10-19 23:28:48 -07001398static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399{
1400 struct xdr_stream xdr;
1401 struct compound_hdr hdr = {
Trond Myklebust16e42952005-10-27 22:12:44 -04001402 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 };
1404 int status;
1405
1406 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1407 encode_compound_hdr(&xdr, &hdr);
Trond Myklebust16e42952005-10-27 22:12:44 -04001408 if ((status = encode_putfh(&xdr, args->fh)) != 0)
1409 goto out;
1410 if ((status = encode_remove(&xdr, args->name)) != 0)
1411 goto out;
1412 status = encode_getfattr(&xdr, args->bitmask);
1413out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 return status;
1415}
1416
1417/*
1418 * Encode RENAME request
1419 */
Al Viro8687b632006-10-19 23:28:48 -07001420static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421{
1422 struct xdr_stream xdr;
1423 struct compound_hdr hdr = {
Trond Myklebust6caf2c82005-10-27 22:12:43 -04001424 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 };
1426 int status;
1427
1428 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1429 encode_compound_hdr(&xdr, &hdr);
1430 if ((status = encode_putfh(&xdr, args->old_dir)) != 0)
1431 goto out;
1432 if ((status = encode_savefh(&xdr)) != 0)
1433 goto out;
1434 if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
1435 goto out;
Trond Myklebust6caf2c82005-10-27 22:12:43 -04001436 if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0)
1437 goto out;
1438 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
1439 goto out;
1440 if ((status = encode_restorefh(&xdr)) != 0)
1441 goto out;
1442 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443out:
1444 return status;
1445}
1446
1447/*
1448 * Encode LINK request
1449 */
Al Viro8687b632006-10-19 23:28:48 -07001450static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 struct xdr_stream xdr;
1453 struct compound_hdr hdr = {
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04001454 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 };
1456 int status;
1457
1458 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1459 encode_compound_hdr(&xdr, &hdr);
1460 if ((status = encode_putfh(&xdr, args->fh)) != 0)
1461 goto out;
1462 if ((status = encode_savefh(&xdr)) != 0)
1463 goto out;
1464 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
1465 goto out;
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04001466 if ((status = encode_link(&xdr, args->name)) != 0)
1467 goto out;
1468 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
1469 goto out;
1470 if ((status = encode_restorefh(&xdr)) != 0)
1471 goto out;
1472 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473out:
1474 return status;
1475}
1476
1477/*
1478 * Encode CREATE request
1479 */
Al Viro8687b632006-10-19 23:28:48 -07001480static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481{
1482 struct xdr_stream xdr;
1483 struct compound_hdr hdr = {
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001484 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 };
1486 int status;
1487
1488 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1489 encode_compound_hdr(&xdr, &hdr);
1490 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
1491 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001492 if ((status = encode_savefh(&xdr)) != 0)
1493 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 if ((status = encode_create(&xdr, args)) != 0)
1495 goto out;
1496 if ((status = encode_getfh(&xdr)) != 0)
1497 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001498 if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
1499 goto out;
1500 if ((status = encode_restorefh(&xdr)) != 0)
1501 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 status = encode_getfattr(&xdr, args->bitmask);
1503out:
1504 return status;
1505}
1506
1507/*
1508 * Encode SYMLINK request
1509 */
Al Viro8687b632006-10-19 23:28:48 -07001510static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 return nfs4_xdr_enc_create(req, p, args);
1513}
1514
1515/*
1516 * Encode GETATTR request
1517 */
Al Viro8687b632006-10-19 23:28:48 -07001518static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
1520 struct xdr_stream xdr;
1521 struct compound_hdr hdr = {
1522 .nops = 2,
1523 };
1524 int status;
1525
1526 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1527 encode_compound_hdr(&xdr, &hdr);
1528 if ((status = encode_putfh(&xdr, args->fh)) == 0)
1529 status = encode_getfattr(&xdr, args->bitmask);
1530 return status;
1531}
1532
1533/*
1534 * Encode a CLOSE request
1535 */
Al Viro8687b632006-10-19 23:28:48 -07001536static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
1538 struct xdr_stream xdr;
1539 struct compound_hdr hdr = {
Trond Myklebust516a6af2005-10-27 22:12:41 -04001540 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 };
1542 int status;
1543
1544 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1545 encode_compound_hdr(&xdr, &hdr);
1546 status = encode_putfh(&xdr, args->fh);
1547 if(status)
1548 goto out;
1549 status = encode_close(&xdr, args);
Trond Myklebust516a6af2005-10-27 22:12:41 -04001550 if (status != 0)
1551 goto out;
1552 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553out:
1554 return status;
1555}
1556
1557/*
1558 * Encode an OPEN request
1559 */
Al Viro8687b632006-10-19 23:28:48 -07001560static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561{
1562 struct xdr_stream xdr;
1563 struct compound_hdr hdr = {
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001564 .nops = 7,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 };
1566 int status;
1567
1568 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1569 encode_compound_hdr(&xdr, &hdr);
1570 status = encode_putfh(&xdr, args->fh);
1571 if (status)
1572 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001573 status = encode_savefh(&xdr);
1574 if (status)
1575 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 status = encode_open(&xdr, args);
1577 if (status)
1578 goto out;
1579 status = encode_getfh(&xdr);
1580 if (status)
1581 goto out;
1582 status = encode_getfattr(&xdr, args->bitmask);
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001583 if (status)
1584 goto out;
1585 status = encode_restorefh(&xdr);
1586 if (status)
1587 goto out;
1588 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589out:
1590 return status;
1591}
1592
1593/*
1594 * Encode an OPEN_CONFIRM request
1595 */
Al Viro8687b632006-10-19 23:28:48 -07001596static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
1598 struct xdr_stream xdr;
1599 struct compound_hdr hdr = {
1600 .nops = 2,
1601 };
1602 int status;
1603
1604 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1605 encode_compound_hdr(&xdr, &hdr);
1606 status = encode_putfh(&xdr, args->fh);
1607 if(status)
1608 goto out;
1609 status = encode_open_confirm(&xdr, args);
1610out:
1611 return status;
1612}
1613
1614/*
1615 * Encode an OPEN request with no attributes.
1616 */
Al Viro8687b632006-10-19 23:28:48 -07001617static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
1619 struct xdr_stream xdr;
1620 struct compound_hdr hdr = {
Trond Myklebust864472e2006-01-03 09:55:15 +01001621 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 };
1623 int status;
1624
1625 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1626 encode_compound_hdr(&xdr, &hdr);
1627 status = encode_putfh(&xdr, args->fh);
1628 if (status)
1629 goto out;
1630 status = encode_open(&xdr, args);
Trond Myklebust864472e2006-01-03 09:55:15 +01001631 if (status)
1632 goto out;
1633 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634out:
1635 return status;
1636}
1637
1638/*
1639 * Encode an OPEN_DOWNGRADE request
1640 */
Al Viro8687b632006-10-19 23:28:48 -07001641static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
1643 struct xdr_stream xdr;
1644 struct compound_hdr hdr = {
Trond Myklebust516a6af2005-10-27 22:12:41 -04001645 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 };
1647 int status;
1648
1649 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1650 encode_compound_hdr(&xdr, &hdr);
1651 status = encode_putfh(&xdr, args->fh);
1652 if (status)
1653 goto out;
1654 status = encode_open_downgrade(&xdr, args);
Trond Myklebust516a6af2005-10-27 22:12:41 -04001655 if (status != 0)
1656 goto out;
1657 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658out:
1659 return status;
1660}
1661
1662/*
1663 * Encode a LOCK request
1664 */
Al Viro8687b632006-10-19 23:28:48 -07001665static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666{
1667 struct xdr_stream xdr;
1668 struct compound_hdr hdr = {
1669 .nops = 2,
1670 };
1671 int status;
1672
1673 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1674 encode_compound_hdr(&xdr, &hdr);
1675 status = encode_putfh(&xdr, args->fh);
1676 if(status)
1677 goto out;
1678 status = encode_lock(&xdr, args);
1679out:
1680 return status;
1681}
1682
1683/*
1684 * Encode a LOCKT request
1685 */
Al Viro8687b632006-10-19 23:28:48 -07001686static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
1688 struct xdr_stream xdr;
1689 struct compound_hdr hdr = {
1690 .nops = 2,
1691 };
1692 int status;
1693
1694 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1695 encode_compound_hdr(&xdr, &hdr);
1696 status = encode_putfh(&xdr, args->fh);
1697 if(status)
1698 goto out;
1699 status = encode_lockt(&xdr, args);
1700out:
1701 return status;
1702}
1703
1704/*
1705 * Encode a LOCKU request
1706 */
Al Viro8687b632006-10-19 23:28:48 -07001707static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708{
1709 struct xdr_stream xdr;
1710 struct compound_hdr hdr = {
1711 .nops = 2,
1712 };
1713 int status;
1714
1715 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1716 encode_compound_hdr(&xdr, &hdr);
1717 status = encode_putfh(&xdr, args->fh);
1718 if(status)
1719 goto out;
1720 status = encode_locku(&xdr, args);
1721out:
1722 return status;
1723}
1724
1725/*
1726 * Encode a READLINK request
1727 */
Al Viro8687b632006-10-19 23:28:48 -07001728static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729{
1730 struct xdr_stream xdr;
1731 struct compound_hdr hdr = {
1732 .nops = 2,
1733 };
1734 int status;
1735
1736 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1737 encode_compound_hdr(&xdr, &hdr);
1738 status = encode_putfh(&xdr, args->fh);
1739 if(status)
1740 goto out;
1741 status = encode_readlink(&xdr, args, req);
1742out:
1743 return status;
1744}
1745
1746/*
1747 * Encode a READDIR request
1748 */
Al Viro8687b632006-10-19 23:28:48 -07001749static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750{
1751 struct xdr_stream xdr;
1752 struct compound_hdr hdr = {
1753 .nops = 2,
1754 };
1755 int status;
1756
1757 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1758 encode_compound_hdr(&xdr, &hdr);
1759 status = encode_putfh(&xdr, args->fh);
1760 if(status)
1761 goto out;
1762 status = encode_readdir(&xdr, args, req);
1763out:
1764 return status;
1765}
1766
1767/*
1768 * Encode a READ request
1769 */
Al Viro8687b632006-10-19 23:28:48 -07001770static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
Trond Myklebust1be27f32007-06-27 14:29:04 -04001772 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 struct xdr_stream xdr;
1774 struct compound_hdr hdr = {
1775 .nops = 2,
1776 };
1777 int replen, status;
1778
1779 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1780 encode_compound_hdr(&xdr, &hdr);
1781 status = encode_putfh(&xdr, args->fh);
1782 if (status)
1783 goto out;
1784 status = encode_read(&xdr, args);
1785 if (status)
1786 goto out;
1787
1788 /* set up reply kvec
1789 * toplevel status + taglen=0 + rescount + OP_PUTFH + status
1790 * + OP_READ + status + eof + datalen = 9
1791 */
1792 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
1793 xdr_inline_pages(&req->rq_rcv_buf, replen,
1794 args->pages, args->pgbase, args->count);
1795out:
1796 return status;
1797}
1798
1799/*
1800 * Encode an SETATTR request
1801 */
Al Viro8687b632006-10-19 23:28:48 -07001802static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804{
1805 struct xdr_stream xdr;
1806 struct compound_hdr hdr = {
1807 .nops = 3,
1808 };
1809 int status;
1810
1811 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1812 encode_compound_hdr(&xdr, &hdr);
1813 status = encode_putfh(&xdr, args->fh);
1814 if(status)
1815 goto out;
1816 status = encode_setattr(&xdr, args, args->server);
1817 if(status)
1818 goto out;
1819 status = encode_getfattr(&xdr, args->bitmask);
1820out:
1821 return status;
1822}
1823
1824/*
J. Bruce Fields029d1052005-06-22 17:16:22 +00001825 * Encode a GETACL request
1826 */
1827static int
Al Viro8687b632006-10-19 23:28:48 -07001828nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
J. Bruce Fields029d1052005-06-22 17:16:22 +00001829 struct nfs_getaclargs *args)
1830{
1831 struct xdr_stream xdr;
Trond Myklebust1be27f32007-06-27 14:29:04 -04001832 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
J. Bruce Fields029d1052005-06-22 17:16:22 +00001833 struct compound_hdr hdr = {
1834 .nops = 2,
1835 };
1836 int replen, status;
1837
1838 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1839 encode_compound_hdr(&xdr, &hdr);
1840 status = encode_putfh(&xdr, args->fh);
1841 if (status)
1842 goto out;
1843 status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
1844 /* set up reply buffer: */
1845 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
1846 xdr_inline_pages(&req->rq_rcv_buf, replen,
1847 args->acl_pages, args->acl_pgbase, args->acl_len);
1848out:
1849 return status;
1850}
1851
1852/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 * Encode a WRITE request
1854 */
Al Viro8687b632006-10-19 23:28:48 -07001855static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856{
1857 struct xdr_stream xdr;
1858 struct compound_hdr hdr = {
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001859 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 };
1861 int status;
1862
1863 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1864 encode_compound_hdr(&xdr, &hdr);
1865 status = encode_putfh(&xdr, args->fh);
1866 if (status)
1867 goto out;
1868 status = encode_write(&xdr, args);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001869 if (status)
1870 goto out;
1871 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872out:
1873 return status;
1874}
1875
1876/*
1877 * a COMMIT request
1878 */
Al Viro8687b632006-10-19 23:28:48 -07001879static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880{
1881 struct xdr_stream xdr;
1882 struct compound_hdr hdr = {
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001883 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 };
1885 int status;
1886
1887 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1888 encode_compound_hdr(&xdr, &hdr);
1889 status = encode_putfh(&xdr, args->fh);
1890 if (status)
1891 goto out;
1892 status = encode_commit(&xdr, args);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04001893 if (status)
1894 goto out;
1895 status = encode_getfattr(&xdr, args->bitmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896out:
1897 return status;
1898}
1899
1900/*
1901 * FSINFO request
1902 */
Al Viro8687b632006-10-19 23:28:48 -07001903static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904{
1905 struct xdr_stream xdr;
1906 struct compound_hdr hdr = {
1907 .nops = 2,
1908 };
1909 int status;
1910
1911 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1912 encode_compound_hdr(&xdr, &hdr);
1913 status = encode_putfh(&xdr, args->fh);
1914 if (!status)
1915 status = encode_fsinfo(&xdr, args->bitmask);
1916 return status;
1917}
1918
1919/*
1920 * a PATHCONF request
1921 */
Al Viro8687b632006-10-19 23:28:48 -07001922static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 struct xdr_stream xdr;
1925 struct compound_hdr hdr = {
1926 .nops = 2,
1927 };
1928 int status;
1929
1930 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1931 encode_compound_hdr(&xdr, &hdr);
1932 status = encode_putfh(&xdr, args->fh);
1933 if (!status)
1934 status = encode_getattr_one(&xdr,
1935 args->bitmask[0] & nfs4_pathconf_bitmap[0]);
1936 return status;
1937}
1938
1939/*
1940 * a STATFS request
1941 */
Al Viro8687b632006-10-19 23:28:48 -07001942static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 struct xdr_stream xdr;
1945 struct compound_hdr hdr = {
1946 .nops = 2,
1947 };
1948 int status;
1949
1950 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1951 encode_compound_hdr(&xdr, &hdr);
1952 status = encode_putfh(&xdr, args->fh);
1953 if (status == 0)
1954 status = encode_getattr_two(&xdr,
1955 args->bitmask[0] & nfs4_statfs_bitmap[0],
1956 args->bitmask[1] & nfs4_statfs_bitmap[1]);
1957 return status;
1958}
1959
1960/*
1961 * GETATTR_BITMAP request
1962 */
Al Viro8687b632006-10-19 23:28:48 -07001963static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964{
1965 struct xdr_stream xdr;
1966 struct compound_hdr hdr = {
1967 .nops = 2,
1968 };
1969 int status;
1970
1971 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1972 encode_compound_hdr(&xdr, &hdr);
1973 status = encode_putfh(&xdr, fhandle);
1974 if (status == 0)
1975 status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
1976 FATTR4_WORD0_LINK_SUPPORT|
1977 FATTR4_WORD0_SYMLINK_SUPPORT|
1978 FATTR4_WORD0_ACLSUPPORT);
1979 return status;
1980}
1981
1982/*
1983 * a RENEW request
1984 */
Al Viro8687b632006-10-19 23:28:48 -07001985static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986{
1987 struct xdr_stream xdr;
1988 struct compound_hdr hdr = {
1989 .nops = 1,
1990 };
1991
1992 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1993 encode_compound_hdr(&xdr, &hdr);
1994 return encode_renew(&xdr, clp);
1995}
1996
1997/*
1998 * a SETCLIENTID request
1999 */
Al Viro8687b632006-10-19 23:28:48 -07002000static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
2002 struct xdr_stream xdr;
2003 struct compound_hdr hdr = {
2004 .nops = 1,
2005 };
2006
2007 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2008 encode_compound_hdr(&xdr, &hdr);
2009 return encode_setclientid(&xdr, sc);
2010}
2011
2012/*
2013 * a SETCLIENTID_CONFIRM request
2014 */
Al Viro8687b632006-10-19 23:28:48 -07002015static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016{
2017 struct xdr_stream xdr;
2018 struct compound_hdr hdr = {
2019 .nops = 3,
2020 };
2021 const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
2022 int status;
2023
2024 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2025 encode_compound_hdr(&xdr, &hdr);
2026 status = encode_setclientid_confirm(&xdr, clp);
2027 if (!status)
2028 status = encode_putrootfh(&xdr);
2029 if (!status)
2030 status = encode_fsinfo(&xdr, lease_bitmap);
2031 return status;
2032}
2033
2034/*
2035 * DELEGRETURN request
2036 */
Al Viro8687b632006-10-19 23:28:48 -07002037static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038{
2039 struct xdr_stream xdr;
2040 struct compound_hdr hdr = {
Trond Myklebustfa178f22006-01-03 09:55:38 +01002041 .nops = 3,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 };
2043 int status;
2044
2045 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2046 encode_compound_hdr(&xdr, &hdr);
Trond Myklebustfa178f22006-01-03 09:55:38 +01002047 status = encode_putfh(&xdr, args->fhandle);
2048 if (status != 0)
2049 goto out;
2050 status = encode_delegreturn(&xdr, args->stateid);
2051 if (status != 0)
2052 goto out;
2053 status = encode_getfattr(&xdr, args->bitmask);
2054out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 return status;
2056}
2057
2058/*
Trond Myklebust683b57b2006-06-09 09:34:22 -04002059 * Encode FS_LOCATIONS request
2060 */
Al Viro8687b632006-10-19 23:28:48 -07002061static 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 -04002062{
2063 struct xdr_stream xdr;
2064 struct compound_hdr hdr = {
2065 .nops = 3,
2066 };
Trond Myklebust1be27f32007-06-27 14:29:04 -04002067 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Trond Myklebust683b57b2006-06-09 09:34:22 -04002068 int replen;
2069 int status;
2070
2071 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2072 encode_compound_hdr(&xdr, &hdr);
2073 if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
2074 goto out;
2075 if ((status = encode_lookup(&xdr, args->name)) != 0)
2076 goto out;
Manoj Naik830b8e32006-06-09 09:34:25 -04002077 if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002078 goto out;
2079 /* set up reply
Manoj Naik830b8e32006-06-09 09:34:25 -04002080 * toplevel_status + OP_PUTFH + status
Trond Myklebust683b57b2006-06-09 09:34:22 -04002081 * + OP_LOOKUP + status + OP_GETATTR + status = 7
2082 */
2083 replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
2084 xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
2085 0, PAGE_SIZE);
2086out:
2087 return status;
2088}
2089
2090/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 * START OF "GENERIC" DECODE ROUTINES.
2092 * These may look a little ugly since they are imported from a "generic"
2093 * set of XDR encode/decode routines which are intended to be shared by
2094 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
2095 *
2096 * If the pain of reading these is too great, it should be a straightforward
2097 * task to translate them into Linux-specific versions which are more
2098 * consistent with the style used in NFSv2/v3...
2099 */
2100#define READ32(x) (x) = ntohl(*p++)
2101#define READ64(x) do { \
2102 (x) = (u64)ntohl(*p++) << 32; \
2103 (x) |= ntohl(*p++); \
2104} while (0)
2105#define READTIME(x) do { \
2106 p++; \
2107 (x.tv_sec) = ntohl(*p++); \
2108 (x.tv_nsec) = ntohl(*p++); \
2109} while (0)
2110#define COPYMEM(x,nbytes) do { \
2111 memcpy((x), p, nbytes); \
2112 p += XDR_QUADLEN(nbytes); \
2113} while (0)
2114
2115#define READ_BUF(nbytes) do { \
2116 p = xdr_inline_decode(xdr, nbytes); \
Chuck Levere4cc6ee2007-05-08 18:23:28 -04002117 if (unlikely(!p)) { \
2118 printk(KERN_INFO "%s: prematurely hit end of receive" \
2119 " buffer\n", __FUNCTION__); \
2120 printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \
2121 __FUNCTION__, xdr->p, nbytes, xdr->end); \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 return -EIO; \
2123 } \
2124} while (0)
2125
Trond Myklebust683b57b2006-06-09 09:34:22 -04002126static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127{
Al Viro8687b632006-10-19 23:28:48 -07002128 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129
2130 READ_BUF(4);
2131 READ32(*len);
2132 READ_BUF(*len);
2133 *string = (char *)p;
2134 return 0;
2135}
2136
2137static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
2138{
Al Viro8687b632006-10-19 23:28:48 -07002139 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
2141 READ_BUF(8);
2142 READ32(hdr->status);
2143 READ32(hdr->taglen);
2144
2145 READ_BUF(hdr->taglen + 4);
2146 hdr->tag = (char *)p;
2147 p += XDR_QUADLEN(hdr->taglen);
2148 READ32(hdr->nops);
2149 return 0;
2150}
2151
2152static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
2153{
Al Viro8687b632006-10-19 23:28:48 -07002154 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 uint32_t opnum;
2156 int32_t nfserr;
2157
2158 READ_BUF(8);
2159 READ32(opnum);
2160 if (opnum != expected) {
2161 printk(KERN_NOTICE
2162 "nfs4_decode_op_hdr: Server returned operation"
2163 " %d but we issued a request for %d\n",
2164 opnum, expected);
2165 return -EIO;
2166 }
2167 READ32(nfserr);
2168 if (nfserr != NFS_OK)
David Howells0a8ea432006-08-22 20:06:08 -04002169 return -nfs4_stat_to_errno(nfserr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 return 0;
2171}
2172
2173/* Dummy routine */
David Howellsadfa6f92006-08-22 20:06:08 -04002174static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175{
Al Viro8687b632006-10-19 23:28:48 -07002176 __be32 *p;
Trond Myklebust683b57b2006-06-09 09:34:22 -04002177 unsigned int strlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 char *str;
2179
2180 READ_BUF(12);
2181 return decode_opaque_inline(xdr, &strlen, &str);
2182}
2183
2184static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
2185{
Al Viro8687b632006-10-19 23:28:48 -07002186 uint32_t bmlen;
2187 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188
2189 READ_BUF(4);
2190 READ32(bmlen);
2191
2192 bitmap[0] = bitmap[1] = 0;
2193 READ_BUF((bmlen << 2));
2194 if (bmlen > 0) {
2195 READ32(bitmap[0]);
2196 if (bmlen > 1)
2197 READ32(bitmap[1]);
2198 }
2199 return 0;
2200}
2201
Al Viro8687b632006-10-19 23:28:48 -07002202static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203{
Al Viro8687b632006-10-19 23:28:48 -07002204 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206 READ_BUF(4);
2207 READ32(*attrlen);
2208 *savep = xdr->p;
2209 return 0;
2210}
2211
2212static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
2213{
2214 if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
2215 decode_attr_bitmap(xdr, bitmask);
2216 bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
2217 } else
2218 bitmask[0] = bitmask[1] = 0;
2219 dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]);
2220 return 0;
2221}
2222
2223static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
2224{
Al Viro8687b632006-10-19 23:28:48 -07002225 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
2227 *type = 0;
2228 if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
2229 return -EIO;
2230 if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
2231 READ_BUF(4);
2232 READ32(*type);
2233 if (*type < NF4REG || *type > NF4NAMEDATTR) {
2234 dprintk("%s: bad type %d\n", __FUNCTION__, *type);
2235 return -EIO;
2236 }
2237 bitmap[0] &= ~FATTR4_WORD0_TYPE;
2238 }
2239 dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type);
2240 return 0;
2241}
2242
2243static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
2244{
Al Viro8687b632006-10-19 23:28:48 -07002245 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
2247 *change = 0;
2248 if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
2249 return -EIO;
2250 if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
2251 READ_BUF(8);
2252 READ64(*change);
2253 bitmap[0] &= ~FATTR4_WORD0_CHANGE;
2254 }
2255 dprintk("%s: change attribute=%Lu\n", __FUNCTION__,
2256 (unsigned long long)*change);
2257 return 0;
2258}
2259
2260static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
2261{
Al Viro8687b632006-10-19 23:28:48 -07002262 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263
2264 *size = 0;
2265 if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
2266 return -EIO;
2267 if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
2268 READ_BUF(8);
2269 READ64(*size);
2270 bitmap[0] &= ~FATTR4_WORD0_SIZE;
2271 }
2272 dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size);
2273 return 0;
2274}
2275
2276static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2277{
Al Viro8687b632006-10-19 23:28:48 -07002278 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279
2280 *res = 0;
2281 if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
2282 return -EIO;
2283 if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
2284 READ_BUF(4);
2285 READ32(*res);
2286 bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
2287 }
2288 dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
2289 return 0;
2290}
2291
2292static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2293{
Al Viro8687b632006-10-19 23:28:48 -07002294 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295
2296 *res = 0;
2297 if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
2298 return -EIO;
2299 if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
2300 READ_BUF(4);
2301 READ32(*res);
2302 bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
2303 }
2304 dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
2305 return 0;
2306}
2307
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -04002308static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309{
Al Viro8687b632006-10-19 23:28:48 -07002310 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
2312 fsid->major = 0;
2313 fsid->minor = 0;
2314 if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
2315 return -EIO;
2316 if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
2317 READ_BUF(16);
2318 READ64(fsid->major);
2319 READ64(fsid->minor);
2320 bitmap[0] &= ~FATTR4_WORD0_FSID;
2321 }
2322 dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__,
2323 (unsigned long long)fsid->major,
2324 (unsigned long long)fsid->minor);
2325 return 0;
2326}
2327
2328static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2329{
Al Viro8687b632006-10-19 23:28:48 -07002330 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
2332 *res = 60;
2333 if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
2334 return -EIO;
2335 if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
2336 READ_BUF(4);
2337 READ32(*res);
2338 bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
2339 }
2340 dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res);
2341 return 0;
2342}
2343
2344static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2345{
Al Viro8687b632006-10-19 23:28:48 -07002346 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
2348 *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
2349 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
2350 return -EIO;
2351 if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
2352 READ_BUF(4);
2353 READ32(*res);
2354 bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
2355 }
2356 dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res);
2357 return 0;
2358}
2359
2360static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
2361{
Al Viro8687b632006-10-19 23:28:48 -07002362 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
2364 *fileid = 0;
2365 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
2366 return -EIO;
2367 if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
2368 READ_BUF(8);
2369 READ64(*fileid);
2370 bitmap[0] &= ~FATTR4_WORD0_FILEID;
2371 }
2372 dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
2373 return 0;
2374}
2375
Manoj Naik99baf622006-06-09 09:34:24 -04002376static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
2377{
Al Viro8687b632006-10-19 23:28:48 -07002378 __be32 *p;
Manoj Naik99baf622006-06-09 09:34:24 -04002379
2380 *fileid = 0;
2381 if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
2382 return -EIO;
2383 if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
2384 READ_BUF(8);
2385 READ64(*fileid);
2386 bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
2387 }
2388 dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
2389 return 0;
2390}
2391
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2393{
Al Viro8687b632006-10-19 23:28:48 -07002394 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 int status = 0;
2396
2397 *res = 0;
2398 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
2399 return -EIO;
2400 if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
2401 READ_BUF(8);
2402 READ64(*res);
2403 bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
2404 }
2405 dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2406 return status;
2407}
2408
2409static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2410{
Al Viro8687b632006-10-19 23:28:48 -07002411 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 int status = 0;
2413
2414 *res = 0;
2415 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
2416 return -EIO;
2417 if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
2418 READ_BUF(8);
2419 READ64(*res);
2420 bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
2421 }
2422 dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2423 return status;
2424}
2425
2426static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2427{
Al Viro8687b632006-10-19 23:28:48 -07002428 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 int status = 0;
2430
2431 *res = 0;
2432 if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
2433 return -EIO;
2434 if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
2435 READ_BUF(8);
2436 READ64(*res);
2437 bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
2438 }
2439 dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2440 return status;
2441}
2442
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002443static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
2444{
2445 int n;
Al Viro8687b632006-10-19 23:28:48 -07002446 __be32 *p;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002447 int status = 0;
2448
2449 READ_BUF(4);
2450 READ32(n);
Andy Adamson33a43f22006-06-09 09:34:30 -04002451 if (n < 0)
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002452 goto out_eio;
Andy Adamson33a43f22006-06-09 09:34:30 -04002453 if (n == 0)
2454 goto root_path;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002455 dprintk("path ");
2456 path->ncomponents = 0;
2457 while (path->ncomponents < n) {
2458 struct nfs4_string *component = &path->components[path->ncomponents];
2459 status = decode_opaque_inline(xdr, &component->len, &component->data);
2460 if (unlikely(status != 0))
2461 goto out_eio;
2462 if (path->ncomponents != n)
2463 dprintk("/");
2464 dprintk("%s", component->data);
2465 if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
2466 path->ncomponents++;
2467 else {
2468 dprintk("cannot parse %d components in path\n", n);
2469 goto out_eio;
2470 }
2471 }
2472out:
2473 dprintk("\n");
2474 return status;
Andy Adamson33a43f22006-06-09 09:34:30 -04002475root_path:
2476/* a root pathname is sent as a zero component4 */
2477 path->ncomponents = 1;
2478 path->components[0].len=0;
2479 path->components[0].data=NULL;
2480 dprintk("path /\n");
2481 goto out;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002482out_eio:
2483 dprintk(" status %d", status);
2484 status = -EIO;
2485 goto out;
2486}
2487
2488static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002489{
2490 int n;
Al Viro8687b632006-10-19 23:28:48 -07002491 __be32 *p;
Trond Myklebust683b57b2006-06-09 09:34:22 -04002492 int status = -EIO;
2493
2494 if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
2495 goto out;
2496 status = 0;
2497 if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
2498 goto out;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002499 dprintk("%s: fsroot ", __FUNCTION__);
2500 status = decode_pathname(xdr, &res->fs_path);
Trond Myklebust683b57b2006-06-09 09:34:22 -04002501 if (unlikely(status != 0))
2502 goto out;
2503 READ_BUF(4);
2504 READ32(n);
2505 if (n <= 0)
2506 goto out_eio;
2507 res->nlocations = 0;
2508 while (res->nlocations < n) {
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002509 int m;
2510 struct nfs4_fs_location *loc = &res->locations[res->nlocations];
Trond Myklebust683b57b2006-06-09 09:34:22 -04002511
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002512 READ_BUF(4);
2513 READ32(m);
2514 if (m <= 0)
2515 goto out_eio;
2516
2517 loc->nservers = 0;
2518 dprintk("%s: servers ", __FUNCTION__);
2519 while (loc->nservers < m) {
2520 struct nfs4_string *server = &loc->servers[loc->nservers];
2521 status = decode_opaque_inline(xdr, &server->len, &server->data);
2522 if (unlikely(status != 0))
2523 goto out_eio;
2524 dprintk("%s ", server->data);
2525 if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
2526 loc->nservers++;
2527 else {
2528 int i;
2529 dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations);
2530 for (i = loc->nservers; i < m; i++) {
Trond Myklebust2e42c3e2007-05-14 17:20:41 -04002531 unsigned int len;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002532 char *data;
2533 status = decode_opaque_inline(xdr, &len, &data);
2534 if (unlikely(status != 0))
2535 goto out_eio;
2536 }
2537 }
2538 }
2539 status = decode_pathname(xdr, &loc->rootpath);
Trond Myklebust683b57b2006-06-09 09:34:22 -04002540 if (unlikely(status != 0))
2541 goto out_eio;
Manoj Naik7aaa0b32006-06-09 09:34:23 -04002542 if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
Trond Myklebust683b57b2006-06-09 09:34:22 -04002543 res->nlocations++;
2544 }
2545out:
2546 dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
2547 return status;
2548out_eio:
2549 status = -EIO;
2550 goto out;
2551}
2552
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2554{
Al Viro8687b632006-10-19 23:28:48 -07002555 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 int status = 0;
2557
2558 *res = 0;
2559 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
2560 return -EIO;
2561 if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
2562 READ_BUF(8);
2563 READ64(*res);
2564 bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
2565 }
2566 dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2567 return status;
2568}
2569
2570static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
2571{
Al Viro8687b632006-10-19 23:28:48 -07002572 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 int status = 0;
2574
2575 *maxlink = 1;
2576 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
2577 return -EIO;
2578 if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
2579 READ_BUF(4);
2580 READ32(*maxlink);
2581 bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
2582 }
2583 dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink);
2584 return status;
2585}
2586
2587static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
2588{
Al Viro8687b632006-10-19 23:28:48 -07002589 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 int status = 0;
2591
2592 *maxname = 1024;
2593 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
2594 return -EIO;
2595 if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
2596 READ_BUF(4);
2597 READ32(*maxname);
2598 bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
2599 }
2600 dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname);
2601 return status;
2602}
2603
2604static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2605{
Al Viro8687b632006-10-19 23:28:48 -07002606 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 int status = 0;
2608
2609 *res = 1024;
2610 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
2611 return -EIO;
2612 if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
2613 uint64_t maxread;
2614 READ_BUF(8);
2615 READ64(maxread);
2616 if (maxread > 0x7FFFFFFF)
2617 maxread = 0x7FFFFFFF;
2618 *res = (uint32_t)maxread;
2619 bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
2620 }
2621 dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res);
2622 return status;
2623}
2624
2625static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
2626{
Al Viro8687b632006-10-19 23:28:48 -07002627 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 int status = 0;
2629
2630 *res = 1024;
2631 if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
2632 return -EIO;
2633 if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
2634 uint64_t maxwrite;
2635 READ_BUF(8);
2636 READ64(maxwrite);
2637 if (maxwrite > 0x7FFFFFFF)
2638 maxwrite = 0x7FFFFFFF;
2639 *res = (uint32_t)maxwrite;
2640 bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
2641 }
2642 dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res);
2643 return status;
2644}
2645
2646static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
2647{
Al Viro8687b632006-10-19 23:28:48 -07002648 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 *mode = 0;
2651 if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
2652 return -EIO;
2653 if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
2654 READ_BUF(4);
2655 READ32(*mode);
2656 *mode &= ~S_IFMT;
2657 bitmap[1] &= ~FATTR4_WORD1_MODE;
2658 }
2659 dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode);
2660 return 0;
2661}
2662
2663static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
2664{
Al Viro8687b632006-10-19 23:28:48 -07002665 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
2667 *nlink = 1;
2668 if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
2669 return -EIO;
2670 if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
2671 READ_BUF(4);
2672 READ32(*nlink);
2673 bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
2674 }
2675 dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink);
2676 return 0;
2677}
2678
Trond Myklebust2e42c3e2007-05-14 17:20:41 -04002679static 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 -07002680{
Al Viro8687b632006-10-19 23:28:48 -07002681 uint32_t len;
2682 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684 *uid = -2;
2685 if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
2686 return -EIO;
2687 if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
2688 READ_BUF(4);
2689 READ32(len);
2690 READ_BUF(len);
2691 if (len < XDR_MAX_NETOBJ) {
2692 if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
2693 dprintk("%s: nfs_map_name_to_uid failed!\n",
2694 __FUNCTION__);
2695 } else
2696 printk(KERN_WARNING "%s: name too long (%u)!\n",
2697 __FUNCTION__, len);
2698 bitmap[1] &= ~FATTR4_WORD1_OWNER;
2699 }
2700 dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid);
2701 return 0;
2702}
2703
Trond Myklebust2e42c3e2007-05-14 17:20:41 -04002704static 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 -07002705{
Al Viro8687b632006-10-19 23:28:48 -07002706 uint32_t len;
2707 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709 *gid = -2;
2710 if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
2711 return -EIO;
2712 if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
2713 READ_BUF(4);
2714 READ32(len);
2715 READ_BUF(len);
2716 if (len < XDR_MAX_NETOBJ) {
2717 if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
2718 dprintk("%s: nfs_map_group_to_gid failed!\n",
2719 __FUNCTION__);
2720 } else
2721 printk(KERN_WARNING "%s: name too long (%u)!\n",
2722 __FUNCTION__, len);
2723 bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
2724 }
2725 dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid);
2726 return 0;
2727}
2728
2729static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
2730{
Al Viro8687b632006-10-19 23:28:48 -07002731 uint32_t major = 0, minor = 0;
2732 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
2734 *rdev = MKDEV(0,0);
2735 if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
2736 return -EIO;
2737 if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
2738 dev_t tmp;
2739
2740 READ_BUF(8);
2741 READ32(major);
2742 READ32(minor);
2743 tmp = MKDEV(major, minor);
2744 if (MAJOR(tmp) == major && MINOR(tmp) == minor)
2745 *rdev = tmp;
2746 bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
2747 }
2748 dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor);
2749 return 0;
2750}
2751
2752static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2753{
Al Viro8687b632006-10-19 23:28:48 -07002754 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 int status = 0;
2756
2757 *res = 0;
2758 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
2759 return -EIO;
2760 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
2761 READ_BUF(8);
2762 READ64(*res);
2763 bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
2764 }
2765 dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2766 return status;
2767}
2768
2769static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2770{
Al Viro8687b632006-10-19 23:28:48 -07002771 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 int status = 0;
2773
2774 *res = 0;
2775 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
2776 return -EIO;
2777 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
2778 READ_BUF(8);
2779 READ64(*res);
2780 bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
2781 }
2782 dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2783 return status;
2784}
2785
2786static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
2787{
Al Viro8687b632006-10-19 23:28:48 -07002788 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 int status = 0;
2790
2791 *res = 0;
2792 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
2793 return -EIO;
2794 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
2795 READ_BUF(8);
2796 READ64(*res);
2797 bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
2798 }
2799 dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
2800 return status;
2801}
2802
2803static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
2804{
Al Viro8687b632006-10-19 23:28:48 -07002805 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
2807 *used = 0;
2808 if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
2809 return -EIO;
2810 if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
2811 READ_BUF(8);
2812 READ64(*used);
2813 bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
2814 }
2815 dprintk("%s: space used=%Lu\n", __FUNCTION__,
2816 (unsigned long long)*used);
2817 return 0;
2818}
2819
2820static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
2821{
Al Viro8687b632006-10-19 23:28:48 -07002822 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 uint64_t sec;
2824 uint32_t nsec;
2825
2826 READ_BUF(12);
2827 READ64(sec);
2828 READ32(nsec);
2829 time->tv_sec = (time_t)sec;
2830 time->tv_nsec = (long)nsec;
2831 return 0;
2832}
2833
2834static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
2835{
2836 int status = 0;
2837
2838 time->tv_sec = 0;
2839 time->tv_nsec = 0;
2840 if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
2841 return -EIO;
2842 if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
2843 status = decode_attr_time(xdr, time);
2844 bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
2845 }
2846 dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec);
2847 return status;
2848}
2849
2850static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
2851{
2852 int status = 0;
2853
2854 time->tv_sec = 0;
2855 time->tv_nsec = 0;
2856 if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
2857 return -EIO;
2858 if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
2859 status = decode_attr_time(xdr, time);
2860 bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
2861 }
2862 dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec);
2863 return status;
2864}
2865
2866static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
2867{
2868 int status = 0;
2869
2870 time->tv_sec = 0;
2871 time->tv_nsec = 0;
2872 if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
2873 return -EIO;
2874 if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
2875 status = decode_attr_time(xdr, time);
2876 bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
2877 }
2878 dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec);
2879 return status;
2880}
2881
Al Viro8687b632006-10-19 23:28:48 -07002882static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883{
2884 unsigned int attrwords = XDR_QUADLEN(attrlen);
2885 unsigned int nwords = xdr->p - savep;
2886
2887 if (unlikely(attrwords != nwords)) {
2888 printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n",
2889 __FUNCTION__,
2890 attrwords << 2,
2891 (attrwords < nwords) ? '<' : '>',
2892 nwords << 2);
2893 return -EIO;
2894 }
2895 return 0;
2896}
2897
2898static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
2899{
Al Viro8687b632006-10-19 23:28:48 -07002900 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902 READ_BUF(20);
2903 READ32(cinfo->atomic);
2904 READ64(cinfo->before);
2905 READ64(cinfo->after);
2906 return 0;
2907}
2908
2909static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
2910{
Al Viro8687b632006-10-19 23:28:48 -07002911 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 uint32_t supp, acc;
2913 int status;
2914
2915 status = decode_op_hdr(xdr, OP_ACCESS);
2916 if (status)
2917 return status;
2918 READ_BUF(8);
2919 READ32(supp);
2920 READ32(acc);
2921 access->supported = supp;
2922 access->access = acc;
2923 return 0;
2924}
2925
2926static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
2927{
Al Viro8687b632006-10-19 23:28:48 -07002928 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 int status;
2930
2931 status = decode_op_hdr(xdr, OP_CLOSE);
2932 if (status)
2933 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04002934 READ_BUF(NFS4_STATEID_SIZE);
2935 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 return 0;
2937}
2938
2939static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
2940{
Al Viro8687b632006-10-19 23:28:48 -07002941 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 int status;
2943
2944 status = decode_op_hdr(xdr, OP_COMMIT);
2945 if (status)
2946 return status;
2947 READ_BUF(8);
2948 COPYMEM(res->verf->verifier, 8);
2949 return 0;
2950}
2951
2952static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
2953{
Al Viro8687b632006-10-19 23:28:48 -07002954 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 uint32_t bmlen;
2956 int status;
2957
2958 status = decode_op_hdr(xdr, OP_CREATE);
2959 if (status)
2960 return status;
2961 if ((status = decode_change_info(xdr, cinfo)))
2962 return status;
2963 READ_BUF(4);
2964 READ32(bmlen);
2965 READ_BUF(bmlen << 2);
2966 return 0;
2967}
2968
2969static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
2970{
Al Viro8687b632006-10-19 23:28:48 -07002971 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 uint32_t attrlen,
2973 bitmap[2] = {0};
2974 int status;
2975
2976 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
2977 goto xdr_error;
2978 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
2979 goto xdr_error;
2980 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
2981 goto xdr_error;
2982 if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
2983 goto xdr_error;
2984 if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
2985 goto xdr_error;
2986 if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
2987 goto xdr_error;
2988 if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
2989 goto xdr_error;
2990 status = verify_attr_len(xdr, savep, attrlen);
2991xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04002992 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return status;
2994}
2995
2996static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
2997{
Al Viro8687b632006-10-19 23:28:48 -07002998 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 uint32_t attrlen,
3000 bitmap[2] = {0};
3001 int status;
3002
3003 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3004 goto xdr_error;
3005 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3006 goto xdr_error;
3007 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3008 goto xdr_error;
3009
3010 if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
3011 goto xdr_error;
3012 if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
3013 goto xdr_error;
3014 if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
3015 goto xdr_error;
3016 if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
3017 goto xdr_error;
3018 if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
3019 goto xdr_error;
3020 if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
3021 goto xdr_error;
3022
3023 status = verify_attr_len(xdr, savep, attrlen);
3024xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003025 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 return status;
3027}
3028
3029static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
3030{
Al Viro8687b632006-10-19 23:28:48 -07003031 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 uint32_t attrlen,
3033 bitmap[2] = {0};
3034 int status;
3035
3036 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3037 goto xdr_error;
3038 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3039 goto xdr_error;
3040 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3041 goto xdr_error;
3042
3043 if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
3044 goto xdr_error;
3045 if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
3046 goto xdr_error;
3047
3048 status = verify_attr_len(xdr, savep, attrlen);
3049xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003050 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 return status;
3052}
3053
3054static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
3055{
Al Viro8687b632006-10-19 23:28:48 -07003056 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 uint32_t attrlen,
3058 bitmap[2] = {0},
3059 type;
3060 int status, fmode = 0;
Manoj Naik99baf622006-06-09 09:34:24 -04003061 uint64_t fileid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
3063 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3064 goto xdr_error;
3065 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3066 goto xdr_error;
3067
3068 fattr->bitmap[0] = bitmap[0];
3069 fattr->bitmap[1] = bitmap[1];
3070
3071 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3072 goto xdr_error;
3073
3074
3075 if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
3076 goto xdr_error;
3077 fattr->type = nfs_type2fmt[type].nfs2type;
3078 fmode = nfs_type2fmt[type].mode;
3079
3080 if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
3081 goto xdr_error;
3082 if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
3083 goto xdr_error;
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -04003084 if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 goto xdr_error;
3086 if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
3087 goto xdr_error;
Trond Myklebust683b57b2006-06-09 09:34:22 -04003088 if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
Manoj Naik7aaa0b32006-06-09 09:34:23 -04003089 struct nfs4_fs_locations,
Trond Myklebust683b57b2006-06-09 09:34:22 -04003090 fattr))) != 0)
3091 goto xdr_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
3093 goto xdr_error;
3094 fattr->mode |= fmode;
3095 if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
3096 goto xdr_error;
David Howells7539bba2006-08-22 20:06:09 -04003097 if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 goto xdr_error;
David Howells7539bba2006-08-22 20:06:09 -04003099 if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 goto xdr_error;
3101 if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
3102 goto xdr_error;
3103 if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
3104 goto xdr_error;
3105 if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
3106 goto xdr_error;
3107 if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
3108 goto xdr_error;
3109 if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
3110 goto xdr_error;
Manoj Naik99baf622006-06-09 09:34:24 -04003111 if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
3112 goto xdr_error;
3113 if (fattr->fileid == 0 && fileid != 0)
3114 fattr->fileid = fileid;
Trond Myklebust33801142005-10-27 22:12:39 -04003115 if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003118 dprintk("%s: xdr returned %d\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 return status;
3120}
3121
3122
3123static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
3124{
Al Viro8687b632006-10-19 23:28:48 -07003125 __be32 *savep;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126 uint32_t attrlen, bitmap[2];
3127 int status;
3128
3129 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3130 goto xdr_error;
3131 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3132 goto xdr_error;
3133 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3134 goto xdr_error;
3135
3136 fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */
3137
3138 if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
3139 goto xdr_error;
3140 if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
3141 goto xdr_error;
3142 if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
3143 goto xdr_error;
3144 fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
3145 if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
3146 goto xdr_error;
3147 fsinfo->wtpref = fsinfo->wtmax;
3148
3149 status = verify_attr_len(xdr, savep, attrlen);
3150xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003151 dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 return status;
3153}
3154
3155static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
3156{
Al Viro8687b632006-10-19 23:28:48 -07003157 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 uint32_t len;
3159 int status;
3160
3161 status = decode_op_hdr(xdr, OP_GETFH);
3162 if (status)
3163 return status;
3164 /* Zero handle first to allow comparisons */
3165 memset(fh, 0, sizeof(*fh));
3166
3167 READ_BUF(4);
3168 READ32(len);
3169 if (len > NFS4_FHSIZE)
3170 return -EIO;
3171 fh->size = len;
3172 READ_BUF(len);
3173 COPYMEM(fh->data, len);
3174 return 0;
3175}
3176
3177static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
3178{
3179 int status;
3180
3181 status = decode_op_hdr(xdr, OP_LINK);
3182 if (status)
3183 return status;
3184 return decode_change_info(xdr, cinfo);
3185}
3186
3187/*
3188 * We create the owner, so we know a proper owner.id length is 4.
3189 */
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003190static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191{
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003192 uint64_t offset, length, clientid;
Al Viro8687b632006-10-19 23:28:48 -07003193 __be32 *p;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003194 uint32_t namelen, type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195
3196 READ_BUF(32);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003197 READ64(offset);
3198 READ64(length);
3199 READ32(type);
3200 if (fl != NULL) {
3201 fl->fl_start = (loff_t)offset;
3202 fl->fl_end = fl->fl_start + (loff_t)length - 1;
3203 if (length == ~(uint64_t)0)
3204 fl->fl_end = OFFSET_MAX;
3205 fl->fl_type = F_WRLCK;
3206 if (type & 1)
3207 fl->fl_type = F_RDLCK;
3208 fl->fl_pid = 0;
3209 }
3210 READ64(clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 READ32(namelen);
3212 READ_BUF(namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 return -NFS4ERR_DENIED;
3214}
3215
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003216static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217{
Al Viro8687b632006-10-19 23:28:48 -07003218 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 int status;
3220
3221 status = decode_op_hdr(xdr, OP_LOCK);
3222 if (status == 0) {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003223 READ_BUF(NFS4_STATEID_SIZE);
3224 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 } else if (status == -NFS4ERR_DENIED)
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003226 return decode_lock_denied(xdr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 return status;
3228}
3229
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003230static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231{
3232 int status;
3233 status = decode_op_hdr(xdr, OP_LOCKT);
3234 if (status == -NFS4ERR_DENIED)
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003235 return decode_lock_denied(xdr, res->denied);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 return status;
3237}
3238
Trond Myklebust911d1aa2006-01-03 09:55:16 +01003239static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240{
Al Viro8687b632006-10-19 23:28:48 -07003241 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 int status;
3243
3244 status = decode_op_hdr(xdr, OP_LOCKU);
3245 if (status == 0) {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003246 READ_BUF(NFS4_STATEID_SIZE);
3247 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 }
3249 return status;
3250}
3251
3252static int decode_lookup(struct xdr_stream *xdr)
3253{
3254 return decode_op_hdr(xdr, OP_LOOKUP);
3255}
3256
3257/* This is too sick! */
3258static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
3259{
Al Viro8687b632006-10-19 23:28:48 -07003260 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 uint32_t limit_type, nblocks, blocksize;
3262
3263 READ_BUF(12);
3264 READ32(limit_type);
3265 switch (limit_type) {
3266 case 1:
3267 READ64(*maxsize);
3268 break;
3269 case 2:
3270 READ32(nblocks);
3271 READ32(blocksize);
3272 *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
3273 }
3274 return 0;
3275}
3276
3277static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
3278{
Al Viro8687b632006-10-19 23:28:48 -07003279 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 uint32_t delegation_type;
3281
3282 READ_BUF(4);
3283 READ32(delegation_type);
3284 if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
3285 res->delegation_type = 0;
3286 return 0;
3287 }
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003288 READ_BUF(NFS4_STATEID_SIZE+4);
3289 COPYMEM(res->delegation.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 READ32(res->do_recall);
3291 switch (delegation_type) {
3292 case NFS4_OPEN_DELEGATE_READ:
3293 res->delegation_type = FMODE_READ;
3294 break;
3295 case NFS4_OPEN_DELEGATE_WRITE:
3296 res->delegation_type = FMODE_WRITE|FMODE_READ;
3297 if (decode_space_limit(xdr, &res->maxsize) < 0)
3298 return -EIO;
3299 }
David Howells7539bba2006-08-22 20:06:09 -04003300 return decode_ace(xdr, NULL, res->server->nfs_client);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301}
3302
3303static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
3304{
Al Viro8687b632006-10-19 23:28:48 -07003305 __be32 *p;
Jeff Laytonaa53ed52007-06-05 14:49:03 -04003306 uint32_t savewords, bmlen, i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 int status;
3308
3309 status = decode_op_hdr(xdr, OP_OPEN);
3310 if (status)
3311 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003312 READ_BUF(NFS4_STATEID_SIZE);
3313 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
3315 decode_change_info(xdr, &res->cinfo);
3316
3317 READ_BUF(8);
3318 READ32(res->rflags);
3319 READ32(bmlen);
3320 if (bmlen > 10)
3321 goto xdr_error;
3322
3323 READ_BUF(bmlen << 2);
Jeff Laytonaa53ed52007-06-05 14:49:03 -04003324 savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
3325 for (i = 0; i < savewords; ++i)
3326 READ32(res->attrset[i]);
3327 for (; i < NFS4_BITMAP_SIZE; i++)
3328 res->attrset[i] = 0;
3329
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 return decode_delegation(xdr, res);
3331xdr_error:
Trond Myklebust16c32b72005-10-27 22:12:45 -04003332 dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 return -EIO;
3334}
3335
3336static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
3337{
Al Viro8687b632006-10-19 23:28:48 -07003338 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 int status;
3340
3341 status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
3342 if (status)
3343 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003344 READ_BUF(NFS4_STATEID_SIZE);
3345 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 return 0;
3347}
3348
3349static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
3350{
Al Viro8687b632006-10-19 23:28:48 -07003351 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 int status;
3353
3354 status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
3355 if (status)
3356 return status;
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003357 READ_BUF(NFS4_STATEID_SIZE);
3358 COPYMEM(res->stateid.data, NFS4_STATEID_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 return 0;
3360}
3361
3362static int decode_putfh(struct xdr_stream *xdr)
3363{
3364 return decode_op_hdr(xdr, OP_PUTFH);
3365}
3366
3367static int decode_putrootfh(struct xdr_stream *xdr)
3368{
3369 return decode_op_hdr(xdr, OP_PUTROOTFH);
3370}
3371
3372static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
3373{
3374 struct kvec *iov = req->rq_rcv_buf.head;
Al Viro8687b632006-10-19 23:28:48 -07003375 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 uint32_t count, eof, recvd, hdrlen;
3377 int status;
3378
3379 status = decode_op_hdr(xdr, OP_READ);
3380 if (status)
3381 return status;
3382 READ_BUF(8);
3383 READ32(eof);
3384 READ32(count);
3385 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
3386 recvd = req->rq_rcv_buf.len - hdrlen;
3387 if (count > recvd) {
3388 printk(KERN_WARNING "NFS: server cheating in read reply: "
3389 "count %u > recvd %u\n", count, recvd);
3390 count = recvd;
3391 eof = 0;
3392 }
3393 xdr_read_pages(xdr, count);
3394 res->eof = eof;
3395 res->count = count;
3396 return 0;
3397}
3398
3399static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
3400{
3401 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
3402 struct page *page = *rcvbuf->pages;
3403 struct kvec *iov = rcvbuf->head;
3404 unsigned int nr, pglen = rcvbuf->page_len;
Al Viro8687b632006-10-19 23:28:48 -07003405 __be32 *end, *entry, *p, *kaddr;
David Howellse8896492006-08-24 15:44:19 -04003406 uint32_t len, attrlen, xlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 int hdrlen, recvd, status;
3408
3409 status = decode_op_hdr(xdr, OP_READDIR);
3410 if (status)
3411 return status;
3412 READ_BUF(8);
3413 COPYMEM(readdir->verifier.data, 8);
Trond Myklebusteadf4592005-06-22 17:16:39 +00003414 dprintk("%s: verifier = 0x%x%x\n",
3415 __FUNCTION__,
3416 ((u32 *)readdir->verifier.data)[0],
3417 ((u32 *)readdir->verifier.data)[1]);
3418
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419
3420 hdrlen = (char *) p - (char *) iov->iov_base;
3421 recvd = rcvbuf->len - hdrlen;
3422 if (pglen > recvd)
3423 pglen = recvd;
3424 xdr_read_pages(xdr, pglen);
3425
3426 BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
Al Viro8687b632006-10-19 23:28:48 -07003427 kaddr = p = kmap_atomic(page, KM_USER0);
David Howellse8896492006-08-24 15:44:19 -04003428 end = p + ((pglen + readdir->pgbase) >> 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 entry = p;
3430 for (nr = 0; *p++; nr++) {
David Howellse8896492006-08-24 15:44:19 -04003431 if (end - p < 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 goto short_pkt;
Trond Myklebusteadf4592005-06-22 17:16:39 +00003433 dprintk("cookie = %Lu, ", *((unsigned long long *)p));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 p += 2; /* cookie */
3435 len = ntohl(*p++); /* filename length */
3436 if (len > NFS4_MAXNAMLEN) {
3437 printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
3438 goto err_unmap;
3439 }
David Howellse8896492006-08-24 15:44:19 -04003440 xlen = XDR_QUADLEN(len);
3441 if (end - p < xlen + 1)
3442 goto short_pkt;
Trond Myklebusteadf4592005-06-22 17:16:39 +00003443 dprintk("filename = %*s\n", len, (char *)p);
David Howellse8896492006-08-24 15:44:19 -04003444 p += xlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 len = ntohl(*p++); /* bitmap length */
David Howellse8896492006-08-24 15:44:19 -04003446 if (end - p < len + 1)
3447 goto short_pkt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448 p += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 attrlen = XDR_QUADLEN(ntohl(*p++));
David Howellse8896492006-08-24 15:44:19 -04003450 if (end - p < attrlen + 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 goto short_pkt;
David Howellse8896492006-08-24 15:44:19 -04003452 p += attrlen; /* attributes */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 entry = p;
3454 }
3455 if (!nr && (entry[0] != 0 || entry[1] == 0))
3456 goto short_pkt;
3457out:
3458 kunmap_atomic(kaddr, KM_USER0);
3459 return 0;
3460short_pkt:
Trond Myklebusteadf4592005-06-22 17:16:39 +00003461 dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 entry[0] = entry[1] = 0;
3463 /* truncate listing ? */
3464 if (!nr) {
3465 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
3466 entry[1] = 1;
3467 }
3468 goto out;
3469err_unmap:
3470 kunmap_atomic(kaddr, KM_USER0);
3471 return -errno_NFSERR_IO;
3472}
3473
3474static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
3475{
3476 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
3477 struct kvec *iov = rcvbuf->head;
3478 int hdrlen, len, recvd;
Al Viro8687b632006-10-19 23:28:48 -07003479 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 char *kaddr;
3481 int status;
3482
3483 status = decode_op_hdr(xdr, OP_READLINK);
3484 if (status)
3485 return status;
3486
3487 /* Convert length of symlink */
3488 READ_BUF(4);
3489 READ32(len);
3490 if (len >= rcvbuf->page_len || len <= 0) {
3491 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
3492 return -ENAMETOOLONG;
3493 }
3494 hdrlen = (char *) xdr->p - (char *) iov->iov_base;
3495 recvd = req->rq_rcv_buf.len - hdrlen;
3496 if (recvd < len) {
3497 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
3498 "count %u > recvd %u\n", len, recvd);
3499 return -EIO;
3500 }
3501 xdr_read_pages(xdr, len);
3502 /*
3503 * The XDR encode routine has set things up so that
3504 * the link text will be copied directly into the
3505 * buffer. We just have to do overflow-checking,
3506 * and and null-terminate the text (the VFS expects
3507 * null-termination).
3508 */
3509 kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
3510 kaddr[len+rcvbuf->page_base] = '\0';
3511 kunmap_atomic(kaddr, KM_USER0);
3512 return 0;
3513}
3514
3515static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
3516{
3517 int status;
3518
3519 status = decode_op_hdr(xdr, OP_REMOVE);
3520 if (status)
3521 goto out;
3522 status = decode_change_info(xdr, cinfo);
3523out:
3524 return status;
3525}
3526
3527static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
3528 struct nfs4_change_info *new_cinfo)
3529{
3530 int status;
3531
3532 status = decode_op_hdr(xdr, OP_RENAME);
3533 if (status)
3534 goto out;
3535 if ((status = decode_change_info(xdr, old_cinfo)))
3536 goto out;
3537 status = decode_change_info(xdr, new_cinfo);
3538out:
3539 return status;
3540}
3541
3542static int decode_renew(struct xdr_stream *xdr)
3543{
3544 return decode_op_hdr(xdr, OP_RENEW);
3545}
3546
Trond Myklebust56ae19f2005-10-27 22:12:40 -04003547static int
3548decode_restorefh(struct xdr_stream *xdr)
3549{
3550 return decode_op_hdr(xdr, OP_RESTOREFH);
3551}
3552
J. Bruce Fields029d1052005-06-22 17:16:22 +00003553static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
3554 size_t *acl_len)
3555{
Al Viro8687b632006-10-19 23:28:48 -07003556 __be32 *savep;
J. Bruce Fields029d1052005-06-22 17:16:22 +00003557 uint32_t attrlen,
3558 bitmap[2] = {0};
3559 struct kvec *iov = req->rq_rcv_buf.head;
3560 int status;
3561
3562 *acl_len = 0;
3563 if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
3564 goto out;
3565 if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
3566 goto out;
3567 if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
3568 goto out;
3569
3570 if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
3571 return -EIO;
3572 if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
3573 int hdrlen, recvd;
3574
3575 /* We ignore &savep and don't do consistency checks on
3576 * the attr length. Let userspace figure it out.... */
3577 hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
3578 recvd = req->rq_rcv_buf.len - hdrlen;
3579 if (attrlen > recvd) {
3580 printk(KERN_WARNING "NFS: server cheating in getattr"
3581 " acl reply: attrlen %u > recvd %u\n",
3582 attrlen, recvd);
3583 return -EINVAL;
3584 }
J. Bruce Fieldsc04871e2006-05-30 16:28:58 -04003585 xdr_read_pages(xdr, attrlen);
J. Bruce Fields029d1052005-06-22 17:16:22 +00003586 *acl_len = attrlen;
J. Bruce Fields8c233cf2005-10-13 16:54:27 -04003587 } else
3588 status = -EOPNOTSUPP;
J. Bruce Fields029d1052005-06-22 17:16:22 +00003589
3590out:
3591 return status;
3592}
3593
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594static int
3595decode_savefh(struct xdr_stream *xdr)
3596{
3597 return decode_op_hdr(xdr, OP_SAVEFH);
3598}
3599
3600static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
3601{
Al Viro8687b632006-10-19 23:28:48 -07003602 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 uint32_t bmlen;
3604 int status;
3605
3606
3607 status = decode_op_hdr(xdr, OP_SETATTR);
3608 if (status)
3609 return status;
3610 READ_BUF(4);
3611 READ32(bmlen);
3612 READ_BUF(bmlen << 2);
3613 return 0;
3614}
3615
David Howellsadfa6f92006-08-22 20:06:08 -04003616static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617{
Al Viro8687b632006-10-19 23:28:48 -07003618 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 uint32_t opnum;
3620 int32_t nfserr;
3621
3622 READ_BUF(8);
3623 READ32(opnum);
3624 if (opnum != OP_SETCLIENTID) {
3625 printk(KERN_NOTICE
3626 "nfs4_decode_setclientid: Server returned operation"
3627 " %d\n", opnum);
3628 return -EIO;
3629 }
3630 READ32(nfserr);
3631 if (nfserr == NFS_OK) {
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003632 READ_BUF(8 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633 READ64(clp->cl_clientid);
Trond Myklebust8ae20ab2007-05-14 16:50:45 -04003634 COPYMEM(clp->cl_confirm.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 } else if (nfserr == NFSERR_CLID_INUSE) {
3636 uint32_t len;
3637
3638 /* skip netid string */
3639 READ_BUF(4);
3640 READ32(len);
3641 READ_BUF(len);
3642
3643 /* skip uaddr string */
3644 READ_BUF(4);
3645 READ32(len);
3646 READ_BUF(len);
3647 return -NFSERR_CLID_INUSE;
3648 } else
David Howells0a8ea432006-08-22 20:06:08 -04003649 return -nfs4_stat_to_errno(nfserr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650
3651 return 0;
3652}
3653
3654static int decode_setclientid_confirm(struct xdr_stream *xdr)
3655{
3656 return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
3657}
3658
3659static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
3660{
Al Viro8687b632006-10-19 23:28:48 -07003661 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 int status;
3663
3664 status = decode_op_hdr(xdr, OP_WRITE);
3665 if (status)
3666 return status;
3667
3668 READ_BUF(16);
3669 READ32(res->count);
3670 READ32(res->verf->committed);
3671 COPYMEM(res->verf->verifier, 8);
3672 return 0;
3673}
3674
3675static int decode_delegreturn(struct xdr_stream *xdr)
3676{
3677 return decode_op_hdr(xdr, OP_DELEGRETURN);
3678}
3679
3680/*
3681 * Decode OPEN_DOWNGRADE response
3682 */
Al Viro8687b632006-10-19 23:28:48 -07003683static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684{
3685 struct xdr_stream xdr;
3686 struct compound_hdr hdr;
3687 int status;
3688
3689 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3690 status = decode_compound_hdr(&xdr, &hdr);
3691 if (status)
3692 goto out;
3693 status = decode_putfh(&xdr);
3694 if (status)
3695 goto out;
3696 status = decode_open_downgrade(&xdr, res);
Trond Myklebust516a6af2005-10-27 22:12:41 -04003697 if (status != 0)
3698 goto out;
3699 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700out:
3701 return status;
3702}
3703
3704/*
3705 * END OF "GENERIC" DECODE ROUTINES.
3706 */
3707
3708/*
3709 * Decode ACCESS response
3710 */
Al Viro8687b632006-10-19 23:28:48 -07003711static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712{
3713 struct xdr_stream xdr;
3714 struct compound_hdr hdr;
3715 int status;
3716
3717 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3718 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3719 goto out;
3720 if ((status = decode_putfh(&xdr)) == 0)
3721 status = decode_access(&xdr, res);
3722out:
3723 return status;
3724}
3725
3726/*
3727 * Decode LOOKUP response
3728 */
Al Viro8687b632006-10-19 23:28:48 -07003729static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730{
3731 struct xdr_stream xdr;
3732 struct compound_hdr hdr;
3733 int status;
3734
3735 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3736 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3737 goto out;
3738 if ((status = decode_putfh(&xdr)) != 0)
3739 goto out;
3740 if ((status = decode_lookup(&xdr)) != 0)
3741 goto out;
3742 if ((status = decode_getfh(&xdr, res->fh)) != 0)
3743 goto out;
3744 status = decode_getfattr(&xdr, res->fattr, res->server);
3745out:
3746 return status;
3747}
3748
3749/*
3750 * Decode LOOKUP_ROOT response
3751 */
Al Viro8687b632006-10-19 23:28:48 -07003752static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753{
3754 struct xdr_stream xdr;
3755 struct compound_hdr hdr;
3756 int status;
3757
3758 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3759 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3760 goto out;
3761 if ((status = decode_putrootfh(&xdr)) != 0)
3762 goto out;
3763 if ((status = decode_getfh(&xdr, res->fh)) == 0)
3764 status = decode_getfattr(&xdr, res->fattr, res->server);
3765out:
3766 return status;
3767}
3768
3769/*
3770 * Decode REMOVE response
3771 */
Al Viro8687b632006-10-19 23:28:48 -07003772static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773{
3774 struct xdr_stream xdr;
3775 struct compound_hdr hdr;
3776 int status;
3777
3778 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3779 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3780 goto out;
Trond Myklebust16e42952005-10-27 22:12:44 -04003781 if ((status = decode_putfh(&xdr)) != 0)
3782 goto out;
3783 if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
3784 goto out;
3785 decode_getfattr(&xdr, res->dir_attr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786out:
3787 return status;
3788}
3789
3790/*
3791 * Decode RENAME response
3792 */
Al Viro8687b632006-10-19 23:28:48 -07003793static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794{
3795 struct xdr_stream xdr;
3796 struct compound_hdr hdr;
3797 int status;
3798
3799 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3800 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3801 goto out;
3802 if ((status = decode_putfh(&xdr)) != 0)
3803 goto out;
3804 if ((status = decode_savefh(&xdr)) != 0)
3805 goto out;
3806 if ((status = decode_putfh(&xdr)) != 0)
3807 goto out;
Trond Myklebust6caf2c82005-10-27 22:12:43 -04003808 if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
3809 goto out;
3810 /* Current FH is target directory */
3811 if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0)
3812 goto out;
3813 if ((status = decode_restorefh(&xdr)) != 0)
3814 goto out;
3815 decode_getfattr(&xdr, res->old_fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816out:
3817 return status;
3818}
3819
3820/*
3821 * Decode LINK response
3822 */
Al Viro8687b632006-10-19 23:28:48 -07003823static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824{
3825 struct xdr_stream xdr;
3826 struct compound_hdr hdr;
3827 int status;
3828
3829 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3830 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3831 goto out;
3832 if ((status = decode_putfh(&xdr)) != 0)
3833 goto out;
3834 if ((status = decode_savefh(&xdr)) != 0)
3835 goto out;
3836 if ((status = decode_putfh(&xdr)) != 0)
3837 goto out;
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003838 if ((status = decode_link(&xdr, &res->cinfo)) != 0)
3839 goto out;
3840 /*
3841 * Note order: OP_LINK leaves the directory as the current
3842 * filehandle.
3843 */
3844 if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0)
3845 goto out;
3846 if ((status = decode_restorefh(&xdr)) != 0)
3847 goto out;
3848 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849out:
3850 return status;
3851}
3852
3853/*
3854 * Decode CREATE response
3855 */
Al Viro8687b632006-10-19 23:28:48 -07003856static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857{
3858 struct xdr_stream xdr;
3859 struct compound_hdr hdr;
3860 int status;
3861
3862 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3863 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
3864 goto out;
3865 if ((status = decode_putfh(&xdr)) != 0)
3866 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04003867 if ((status = decode_savefh(&xdr)) != 0)
3868 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
3870 goto out;
3871 if ((status = decode_getfh(&xdr, res->fh)) != 0)
3872 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04003873 if (decode_getfattr(&xdr, res->fattr, res->server) != 0)
3874 goto out;
3875 if ((status = decode_restorefh(&xdr)) != 0)
3876 goto out;
3877 decode_getfattr(&xdr, res->dir_fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878out:
3879 return status;
3880}
3881
3882/*
3883 * Decode SYMLINK response
3884 */
Al Viro8687b632006-10-19 23:28:48 -07003885static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886{
3887 return nfs4_xdr_dec_create(rqstp, p, res);
3888}
3889
3890/*
3891 * Decode GETATTR response
3892 */
Al Viro8687b632006-10-19 23:28:48 -07003893static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894{
3895 struct xdr_stream xdr;
3896 struct compound_hdr hdr;
3897 int status;
3898
3899 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3900 status = decode_compound_hdr(&xdr, &hdr);
3901 if (status)
3902 goto out;
3903 status = decode_putfh(&xdr);
3904 if (status)
3905 goto out;
3906 status = decode_getfattr(&xdr, res->fattr, res->server);
3907out:
3908 return status;
3909
3910}
3911
J. Bruce Fields23ec6962005-06-22 17:16:22 +00003912/*
3913 * Encode an SETACL request
3914 */
3915static int
Al Viro8687b632006-10-19 23:28:48 -07003916nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
J. Bruce Fields23ec6962005-06-22 17:16:22 +00003917{
3918 struct xdr_stream xdr;
3919 struct compound_hdr hdr = {
3920 .nops = 2,
3921 };
3922 int status;
3923
3924 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
3925 encode_compound_hdr(&xdr, &hdr);
3926 status = encode_putfh(&xdr, args->fh);
3927 if (status)
3928 goto out;
3929 status = encode_setacl(&xdr, args);
3930out:
3931 return status;
3932}
3933/*
3934 * Decode SETACL response
3935 */
3936static int
Al Viro8687b632006-10-19 23:28:48 -07003937nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
J. Bruce Fields23ec6962005-06-22 17:16:22 +00003938{
3939 struct xdr_stream xdr;
3940 struct compound_hdr hdr;
3941 int status;
3942
3943 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3944 status = decode_compound_hdr(&xdr, &hdr);
3945 if (status)
3946 goto out;
3947 status = decode_putfh(&xdr);
3948 if (status)
3949 goto out;
3950 status = decode_setattr(&xdr, res);
3951out:
3952 return status;
3953}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954
3955/*
J. Bruce Fields029d1052005-06-22 17:16:22 +00003956 * Decode GETACL response
3957 */
3958static int
Al Viro8687b632006-10-19 23:28:48 -07003959nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
J. Bruce Fields029d1052005-06-22 17:16:22 +00003960{
3961 struct xdr_stream xdr;
3962 struct compound_hdr hdr;
3963 int status;
3964
3965 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3966 status = decode_compound_hdr(&xdr, &hdr);
3967 if (status)
3968 goto out;
3969 status = decode_putfh(&xdr);
3970 if (status)
3971 goto out;
3972 status = decode_getacl(&xdr, rqstp, acl_len);
3973
3974out:
3975 return status;
3976}
3977
3978/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 * Decode CLOSE response
3980 */
Al Viro8687b632006-10-19 23:28:48 -07003981static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982{
3983 struct xdr_stream xdr;
3984 struct compound_hdr hdr;
3985 int status;
3986
3987 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
3988 status = decode_compound_hdr(&xdr, &hdr);
3989 if (status)
3990 goto out;
3991 status = decode_putfh(&xdr);
3992 if (status)
3993 goto out;
3994 status = decode_close(&xdr, res);
Trond Myklebust516a6af2005-10-27 22:12:41 -04003995 if (status != 0)
3996 goto out;
3997 /*
3998 * Note: Server may do delete on close for this file
3999 * in which case the getattr call will fail with
4000 * an ESTALE error. Shouldn't be a problem,
4001 * though, since fattr->valid will remain unset.
4002 */
4003 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004out:
4005 return status;
4006}
4007
4008/*
4009 * Decode OPEN response
4010 */
Al Viro8687b632006-10-19 23:28:48 -07004011static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012{
4013 struct xdr_stream xdr;
4014 struct compound_hdr hdr;
4015 int status;
4016
4017 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4018 status = decode_compound_hdr(&xdr, &hdr);
4019 if (status)
4020 goto out;
4021 status = decode_putfh(&xdr);
4022 if (status)
4023 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04004024 status = decode_savefh(&xdr);
4025 if (status)
4026 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 status = decode_open(&xdr, res);
4028 if (status)
4029 goto out;
4030 status = decode_getfh(&xdr, &res->fh);
4031 if (status)
4032 goto out;
Trond Myklebust56ae19f2005-10-27 22:12:40 -04004033 if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
4034 goto out;
4035 if ((status = decode_restorefh(&xdr)) != 0)
4036 goto out;
4037 decode_getfattr(&xdr, res->dir_attr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038out:
4039 return status;
4040}
4041
4042/*
4043 * Decode OPEN_CONFIRM response
4044 */
Al Viro8687b632006-10-19 23:28:48 -07004045static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046{
4047 struct xdr_stream xdr;
4048 struct compound_hdr hdr;
4049 int status;
4050
4051 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4052 status = decode_compound_hdr(&xdr, &hdr);
4053 if (status)
4054 goto out;
4055 status = decode_putfh(&xdr);
4056 if (status)
4057 goto out;
4058 status = decode_open_confirm(&xdr, res);
4059out:
4060 return status;
4061}
4062
4063/*
4064 * Decode OPEN response
4065 */
Al Viro8687b632006-10-19 23:28:48 -07004066static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067{
4068 struct xdr_stream xdr;
4069 struct compound_hdr hdr;
4070 int status;
4071
4072 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4073 status = decode_compound_hdr(&xdr, &hdr);
4074 if (status)
4075 goto out;
4076 status = decode_putfh(&xdr);
4077 if (status)
4078 goto out;
4079 status = decode_open(&xdr, res);
Trond Myklebust864472e2006-01-03 09:55:15 +01004080 if (status)
4081 goto out;
4082 decode_getfattr(&xdr, res->f_attr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083out:
4084 return status;
4085}
4086
4087/*
4088 * Decode SETATTR response
4089 */
Al Viro8687b632006-10-19 23:28:48 -07004090static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091{
4092 struct xdr_stream xdr;
4093 struct compound_hdr hdr;
4094 int status;
4095
4096 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4097 status = decode_compound_hdr(&xdr, &hdr);
4098 if (status)
4099 goto out;
4100 status = decode_putfh(&xdr);
4101 if (status)
4102 goto out;
4103 status = decode_setattr(&xdr, res);
4104 if (status)
4105 goto out;
4106 status = decode_getfattr(&xdr, res->fattr, res->server);
4107 if (status == NFS4ERR_DELAY)
4108 status = 0;
4109out:
4110 return status;
4111}
4112
4113/*
4114 * Decode LOCK response
4115 */
Al Viro8687b632006-10-19 23:28:48 -07004116static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117{
4118 struct xdr_stream xdr;
4119 struct compound_hdr hdr;
4120 int status;
4121
4122 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4123 status = decode_compound_hdr(&xdr, &hdr);
4124 if (status)
4125 goto out;
4126 status = decode_putfh(&xdr);
4127 if (status)
4128 goto out;
4129 status = decode_lock(&xdr, res);
4130out:
4131 return status;
4132}
4133
4134/*
4135 * Decode LOCKT response
4136 */
Al Viro8687b632006-10-19 23:28:48 -07004137static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138{
4139 struct xdr_stream xdr;
4140 struct compound_hdr hdr;
4141 int status;
4142
4143 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4144 status = decode_compound_hdr(&xdr, &hdr);
4145 if (status)
4146 goto out;
4147 status = decode_putfh(&xdr);
4148 if (status)
4149 goto out;
4150 status = decode_lockt(&xdr, res);
4151out:
4152 return status;
4153}
4154
4155/*
4156 * Decode LOCKU response
4157 */
Al Viro8687b632006-10-19 23:28:48 -07004158static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159{
4160 struct xdr_stream xdr;
4161 struct compound_hdr hdr;
4162 int status;
4163
4164 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4165 status = decode_compound_hdr(&xdr, &hdr);
4166 if (status)
4167 goto out;
4168 status = decode_putfh(&xdr);
4169 if (status)
4170 goto out;
4171 status = decode_locku(&xdr, res);
4172out:
4173 return status;
4174}
4175
4176/*
4177 * Decode READLINK response
4178 */
Al Viro8687b632006-10-19 23:28:48 -07004179static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180{
4181 struct xdr_stream xdr;
4182 struct compound_hdr hdr;
4183 int status;
4184
4185 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4186 status = decode_compound_hdr(&xdr, &hdr);
4187 if (status)
4188 goto out;
4189 status = decode_putfh(&xdr);
4190 if (status)
4191 goto out;
4192 status = decode_readlink(&xdr, rqstp);
4193out:
4194 return status;
4195}
4196
4197/*
4198 * Decode READDIR response
4199 */
Al Viro8687b632006-10-19 23:28:48 -07004200static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201{
4202 struct xdr_stream xdr;
4203 struct compound_hdr hdr;
4204 int status;
4205
4206 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4207 status = decode_compound_hdr(&xdr, &hdr);
4208 if (status)
4209 goto out;
4210 status = decode_putfh(&xdr);
4211 if (status)
4212 goto out;
4213 status = decode_readdir(&xdr, rqstp, res);
4214out:
4215 return status;
4216}
4217
4218/*
4219 * Decode Read response
4220 */
Al Viro8687b632006-10-19 23:28:48 -07004221static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222{
4223 struct xdr_stream xdr;
4224 struct compound_hdr hdr;
4225 int status;
4226
4227 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4228 status = decode_compound_hdr(&xdr, &hdr);
4229 if (status)
4230 goto out;
4231 status = decode_putfh(&xdr);
4232 if (status)
4233 goto out;
4234 status = decode_read(&xdr, rqstp, res);
4235 if (!status)
4236 status = res->count;
4237out:
4238 return status;
4239}
4240
4241/*
4242 * Decode WRITE response
4243 */
Al Viro8687b632006-10-19 23:28:48 -07004244static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245{
4246 struct xdr_stream xdr;
4247 struct compound_hdr hdr;
4248 int status;
4249
4250 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4251 status = decode_compound_hdr(&xdr, &hdr);
4252 if (status)
4253 goto out;
4254 status = decode_putfh(&xdr);
4255 if (status)
4256 goto out;
4257 status = decode_write(&xdr, res);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004258 if (status)
4259 goto out;
4260 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 if (!status)
4262 status = res->count;
4263out:
4264 return status;
4265}
4266
4267/*
4268 * Decode COMMIT response
4269 */
Al Viro8687b632006-10-19 23:28:48 -07004270static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271{
4272 struct xdr_stream xdr;
4273 struct compound_hdr hdr;
4274 int status;
4275
4276 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4277 status = decode_compound_hdr(&xdr, &hdr);
4278 if (status)
4279 goto out;
4280 status = decode_putfh(&xdr);
4281 if (status)
4282 goto out;
4283 status = decode_commit(&xdr, res);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004284 if (status)
4285 goto out;
4286 decode_getfattr(&xdr, res->fattr, res->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287out:
4288 return status;
4289}
4290
4291/*
4292 * FSINFO request
4293 */
Al Viro8687b632006-10-19 23:28:48 -07004294static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295{
4296 struct xdr_stream xdr;
4297 struct compound_hdr hdr;
4298 int status;
4299
4300 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4301 status = decode_compound_hdr(&xdr, &hdr);
4302 if (!status)
4303 status = decode_putfh(&xdr);
4304 if (!status)
4305 status = decode_fsinfo(&xdr, fsinfo);
4306 if (!status)
David Howells0a8ea432006-08-22 20:06:08 -04004307 status = -nfs4_stat_to_errno(hdr.status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 return status;
4309}
4310
4311/*
4312 * PATHCONF request
4313 */
Al Viro8687b632006-10-19 23:28:48 -07004314static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315{
4316 struct xdr_stream xdr;
4317 struct compound_hdr hdr;
4318 int status;
4319
4320 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4321 status = decode_compound_hdr(&xdr, &hdr);
4322 if (!status)
4323 status = decode_putfh(&xdr);
4324 if (!status)
4325 status = decode_pathconf(&xdr, pathconf);
4326 return status;
4327}
4328
4329/*
4330 * STATFS request
4331 */
Al Viro8687b632006-10-19 23:28:48 -07004332static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333{
4334 struct xdr_stream xdr;
4335 struct compound_hdr hdr;
4336 int status;
4337
4338 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4339 status = decode_compound_hdr(&xdr, &hdr);
4340 if (!status)
4341 status = decode_putfh(&xdr);
4342 if (!status)
4343 status = decode_statfs(&xdr, fsstat);
4344 return status;
4345}
4346
4347/*
4348 * GETATTR_BITMAP request
4349 */
Al Viro8687b632006-10-19 23:28:48 -07004350static 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 -07004351{
4352 struct xdr_stream xdr;
4353 struct compound_hdr hdr;
4354 int status;
4355
4356 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4357 if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
4358 goto out;
4359 if ((status = decode_putfh(&xdr)) != 0)
4360 goto out;
4361 status = decode_server_caps(&xdr, res);
4362out:
4363 return status;
4364}
4365
4366/*
4367 * Decode RENEW response
4368 */
Al Viro8687b632006-10-19 23:28:48 -07004369static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370{
4371 struct xdr_stream xdr;
4372 struct compound_hdr hdr;
4373 int status;
4374
4375 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4376 status = decode_compound_hdr(&xdr, &hdr);
4377 if (!status)
4378 status = decode_renew(&xdr);
4379 return status;
4380}
4381
4382/*
4383 * a SETCLIENTID request
4384 */
Al Viro8687b632006-10-19 23:28:48 -07004385static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
David Howellsadfa6f92006-08-22 20:06:08 -04004386 struct nfs_client *clp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387{
4388 struct xdr_stream xdr;
4389 struct compound_hdr hdr;
4390 int status;
4391
4392 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4393 status = decode_compound_hdr(&xdr, &hdr);
4394 if (!status)
4395 status = decode_setclientid(&xdr, clp);
4396 if (!status)
David Howells0a8ea432006-08-22 20:06:08 -04004397 status = -nfs4_stat_to_errno(hdr.status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 return status;
4399}
4400
4401/*
4402 * a SETCLIENTID_CONFIRM request
4403 */
Al Viro8687b632006-10-19 23:28:48 -07004404static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405{
4406 struct xdr_stream xdr;
4407 struct compound_hdr hdr;
4408 int status;
4409
4410 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4411 status = decode_compound_hdr(&xdr, &hdr);
4412 if (!status)
4413 status = decode_setclientid_confirm(&xdr);
4414 if (!status)
4415 status = decode_putrootfh(&xdr);
4416 if (!status)
4417 status = decode_fsinfo(&xdr, fsinfo);
4418 if (!status)
David Howells0a8ea432006-08-22 20:06:08 -04004419 status = -nfs4_stat_to_errno(hdr.status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 return status;
4421}
4422
4423/*
4424 * DELEGRETURN request
4425 */
Al Viro8687b632006-10-19 23:28:48 -07004426static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427{
4428 struct xdr_stream xdr;
4429 struct compound_hdr hdr;
4430 int status;
4431
4432 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4433 status = decode_compound_hdr(&xdr, &hdr);
Trond Myklebustfa178f22006-01-03 09:55:38 +01004434 if (status != 0)
4435 goto out;
4436 status = decode_putfh(&xdr);
4437 if (status != 0)
4438 goto out;
4439 status = decode_delegreturn(&xdr);
4440 decode_getfattr(&xdr, res->fattr, res->server);
4441out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 return status;
4443}
4444
Trond Myklebust683b57b2006-06-09 09:34:22 -04004445/*
4446 * FS_LOCATIONS request
4447 */
Al Viro8687b632006-10-19 23:28:48 -07004448static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res)
Trond Myklebust683b57b2006-06-09 09:34:22 -04004449{
4450 struct xdr_stream xdr;
4451 struct compound_hdr hdr;
4452 int status;
4453
4454 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
4455 status = decode_compound_hdr(&xdr, &hdr);
4456 if (status != 0)
4457 goto out;
4458 if ((status = decode_putfh(&xdr)) != 0)
4459 goto out;
4460 if ((status = decode_lookup(&xdr)) != 0)
4461 goto out;
4462 xdr_enter_page(&xdr, PAGE_SIZE);
4463 status = decode_getfattr(&xdr, &res->fattr, res->server);
4464out:
4465 return status;
4466}
4467
Al Viro0dbb4c62006-10-19 23:28:49 -07004468__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469{
4470 uint32_t bitmap[2] = {0};
4471 uint32_t len;
4472
4473 if (!*p++) {
4474 if (!*p)
4475 return ERR_PTR(-EAGAIN);
4476 entry->eof = 1;
4477 return ERR_PTR(-EBADCOOKIE);
4478 }
4479
4480 entry->prev_cookie = entry->cookie;
4481 p = xdr_decode_hyper(p, &entry->cookie);
4482 entry->len = ntohl(*p++);
4483 entry->name = (const char *) p;
4484 p += XDR_QUADLEN(entry->len);
4485
4486 /*
4487 * In case the server doesn't return an inode number,
4488 * we fake one here. (We don't use inode number 0,
4489 * since glibc seems to choke on it...)
4490 */
4491 entry->ino = 1;
4492
4493 len = ntohl(*p++); /* bitmap length */
4494 if (len-- > 0) {
4495 bitmap[0] = ntohl(*p++);
4496 if (len-- > 0) {
4497 bitmap[1] = ntohl(*p++);
4498 p += len;
4499 }
4500 }
4501 len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */
4502 if (len > 0) {
Manoj Naik97d312d2005-06-22 17:16:39 +00004503 if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
4504 bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
4505 /* Ignore the return value of rdattr_error for now */
4506 p++;
4507 len--;
4508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
4510 xdr_decode_hyper(p, &entry->ino);
4511 else if (bitmap[0] == FATTR4_WORD0_FILEID)
4512 xdr_decode_hyper(p, &entry->ino);
4513 p += len;
4514 }
4515
4516 entry->eof = !p[0] && p[1];
4517 return p;
4518}
4519
4520/*
4521 * We need to translate between nfs status return values and
4522 * the local errno values which may not be the same.
4523 */
4524static struct {
4525 int stat;
4526 int errno;
4527} nfs_errtbl[] = {
4528 { NFS4_OK, 0 },
4529 { NFS4ERR_PERM, EPERM },
4530 { NFS4ERR_NOENT, ENOENT },
4531 { NFS4ERR_IO, errno_NFSERR_IO },
4532 { NFS4ERR_NXIO, ENXIO },
4533 { NFS4ERR_ACCESS, EACCES },
4534 { NFS4ERR_EXIST, EEXIST },
4535 { NFS4ERR_XDEV, EXDEV },
4536 { NFS4ERR_NOTDIR, ENOTDIR },
4537 { NFS4ERR_ISDIR, EISDIR },
4538 { NFS4ERR_INVAL, EINVAL },
4539 { NFS4ERR_FBIG, EFBIG },
4540 { NFS4ERR_NOSPC, ENOSPC },
4541 { NFS4ERR_ROFS, EROFS },
4542 { NFS4ERR_MLINK, EMLINK },
4543 { NFS4ERR_NAMETOOLONG, ENAMETOOLONG },
4544 { NFS4ERR_NOTEMPTY, ENOTEMPTY },
4545 { NFS4ERR_DQUOT, EDQUOT },
4546 { NFS4ERR_STALE, ESTALE },
4547 { NFS4ERR_BADHANDLE, EBADHANDLE },
Manoj Naik6ebf3652005-06-22 17:16:39 +00004548 { NFS4ERR_BADOWNER, EINVAL },
4549 { NFS4ERR_BADNAME, EINVAL },
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 { NFS4ERR_BAD_COOKIE, EBADCOOKIE },
4551 { NFS4ERR_NOTSUPP, ENOTSUPP },
4552 { NFS4ERR_TOOSMALL, ETOOSMALL },
4553 { NFS4ERR_SERVERFAULT, ESERVERFAULT },
4554 { NFS4ERR_BADTYPE, EBADTYPE },
4555 { NFS4ERR_LOCKED, EAGAIN },
4556 { NFS4ERR_RESOURCE, EREMOTEIO },
4557 { NFS4ERR_SYMLINK, ELOOP },
4558 { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP },
4559 { NFS4ERR_DEADLOCK, EDEADLK },
4560 { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs
4561 * to be handled by a
4562 * middle-layer.
4563 */
4564 { -1, EIO }
4565};
4566
4567/*
4568 * Convert an NFS error code to a local one.
4569 * This one is used jointly by NFSv2 and NFSv3.
4570 */
4571static int
David Howells0a8ea432006-08-22 20:06:08 -04004572nfs4_stat_to_errno(int stat)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573{
4574 int i;
4575 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
4576 if (nfs_errtbl[i].stat == stat)
4577 return nfs_errtbl[i].errno;
4578 }
4579 if (stat <= 10000 || stat > 10100) {
4580 /* The server is looney tunes. */
4581 return ESERVERFAULT;
4582 }
4583 /* If we cannot translate the error, the recovery routines should
4584 * handle it.
4585 * Note: remaining NFSv4 error codes have values > 10000, so should
4586 * not conflict with native Linux error codes.
4587 */
4588 return stat;
4589}
4590
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591#define PROC(proc, argtype, restype) \
4592[NFSPROC4_CLNT_##proc] = { \
4593 .p_proc = NFSPROC4_COMPOUND, \
4594 .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \
4595 .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04004596 .p_arglen = NFS4_##argtype##_sz, \
4597 .p_replen = NFS4_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05004598 .p_statidx = NFSPROC4_CLNT_##proc, \
4599 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 }
4601
4602struct rpc_procinfo nfs4_procedures[] = {
4603 PROC(READ, enc_read, dec_read),
4604 PROC(WRITE, enc_write, dec_write),
4605 PROC(COMMIT, enc_commit, dec_commit),
4606 PROC(OPEN, enc_open, dec_open),
4607 PROC(OPEN_CONFIRM, enc_open_confirm, dec_open_confirm),
4608 PROC(OPEN_NOATTR, enc_open_noattr, dec_open_noattr),
4609 PROC(OPEN_DOWNGRADE, enc_open_downgrade, dec_open_downgrade),
4610 PROC(CLOSE, enc_close, dec_close),
4611 PROC(SETATTR, enc_setattr, dec_setattr),
4612 PROC(FSINFO, enc_fsinfo, dec_fsinfo),
4613 PROC(RENEW, enc_renew, dec_renew),
4614 PROC(SETCLIENTID, enc_setclientid, dec_setclientid),
4615 PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
4616 PROC(LOCK, enc_lock, dec_lock),
4617 PROC(LOCKT, enc_lockt, dec_lockt),
4618 PROC(LOCKU, enc_locku, dec_locku),
4619 PROC(ACCESS, enc_access, dec_access),
4620 PROC(GETATTR, enc_getattr, dec_getattr),
4621 PROC(LOOKUP, enc_lookup, dec_lookup),
4622 PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root),
4623 PROC(REMOVE, enc_remove, dec_remove),
4624 PROC(RENAME, enc_rename, dec_rename),
4625 PROC(LINK, enc_link, dec_link),
4626 PROC(SYMLINK, enc_symlink, dec_symlink),
4627 PROC(CREATE, enc_create, dec_create),
4628 PROC(PATHCONF, enc_pathconf, dec_pathconf),
4629 PROC(STATFS, enc_statfs, dec_statfs),
4630 PROC(READLINK, enc_readlink, dec_readlink),
4631 PROC(READDIR, enc_readdir, dec_readdir),
4632 PROC(SERVER_CAPS, enc_server_caps, dec_server_caps),
4633 PROC(DELEGRETURN, enc_delegreturn, dec_delegreturn),
J. Bruce Fields029d1052005-06-22 17:16:22 +00004634 PROC(GETACL, enc_getacl, dec_getacl),
J. Bruce Fields23ec6962005-06-22 17:16:22 +00004635 PROC(SETACL, enc_setacl, dec_setacl),
Trond Myklebust683b57b2006-06-09 09:34:22 -04004636 PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637};
4638
4639struct rpc_version nfs_version4 = {
4640 .number = 4,
Tobias Klausere8c96f82006-03-24 03:15:34 -08004641 .nrprocs = ARRAY_SIZE(nfs4_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 .procs = nfs4_procedures
4643};
4644
4645/*
4646 * Local variables:
4647 * c-basic-offset: 8
4648 * End:
4649 */