~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/nfs/nfs2xdr.c

Version: ~ [ linux-5.5-rc6 ] ~ [ linux-5.4.11 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.95 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.164 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.209 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.209 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/fs/nfs/nfs2xdr.c
  3  *
  4  * XDR functions to encode/decode NFS RPC arguments and results.
  5  *
  6  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
  7  * Copyright (C) 1996 Olaf Kirch
  8  * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
  9  *              FIFO's need special handling in NFSv2
 10  */
 11 
 12 #include <linux/param.h>
 13 #include <linux/time.h>
 14 #include <linux/mm.h>
 15 #include <linux/slab.h>
 16 #include <linux/errno.h>
 17 #include <linux/string.h>
 18 #include <linux/in.h>
 19 #include <linux/pagemap.h>
 20 #include <linux/proc_fs.h>
 21 #include <linux/sunrpc/clnt.h>
 22 #include <linux/nfs.h>
 23 #include <linux/nfs2.h>
 24 #include <linux/nfs_fs.h>
 25 #include "internal.h"
 26 
 27 #define NFSDBG_FACILITY         NFSDBG_XDR
 28 
 29 /* Mapping from NFS error code to "errno" error code. */
 30 #define errno_NFSERR_IO         EIO
 31 
 32 /*
 33  * Declare the space requirements for NFS arguments and replies as
 34  * number of 32bit-words
 35  */
 36 #define NFS_fhandle_sz          (8)
 37 #define NFS_sattr_sz            (8)
 38 #define NFS_filename_sz         (1+(NFS2_MAXNAMLEN>>2))
 39 #define NFS_path_sz             (1+(NFS2_MAXPATHLEN>>2))
 40 #define NFS_fattr_sz            (17)
 41 #define NFS_info_sz             (5)
 42 #define NFS_entry_sz            (NFS_filename_sz+3)
 43 
 44 #define NFS_diropargs_sz        (NFS_fhandle_sz+NFS_filename_sz)
 45 #define NFS_removeargs_sz       (NFS_fhandle_sz+NFS_filename_sz)
 46 #define NFS_sattrargs_sz        (NFS_fhandle_sz+NFS_sattr_sz)
 47 #define NFS_readlinkargs_sz     (NFS_fhandle_sz)
 48 #define NFS_readargs_sz         (NFS_fhandle_sz+3)
 49 #define NFS_writeargs_sz        (NFS_fhandle_sz+4)
 50 #define NFS_createargs_sz       (NFS_diropargs_sz+NFS_sattr_sz)
 51 #define NFS_renameargs_sz       (NFS_diropargs_sz+NFS_diropargs_sz)
 52 #define NFS_linkargs_sz         (NFS_fhandle_sz+NFS_diropargs_sz)
 53 #define NFS_symlinkargs_sz      (NFS_diropargs_sz+1+NFS_sattr_sz)
 54 #define NFS_readdirargs_sz      (NFS_fhandle_sz+2)
 55 
 56 #define NFS_attrstat_sz         (1+NFS_fattr_sz)
 57 #define NFS_diropres_sz         (1+NFS_fhandle_sz+NFS_fattr_sz)
 58 #define NFS_readlinkres_sz      (2)
 59 #define NFS_readres_sz          (1+NFS_fattr_sz+1)
 60 #define NFS_writeres_sz         (NFS_attrstat_sz)
 61 #define NFS_stat_sz             (1)
 62 #define NFS_readdirres_sz       (1)
 63 #define NFS_statfsres_sz        (1+NFS_info_sz)
 64 
 65 /*
 66  * Common NFS XDR functions as inlines
 67  */
 68 static inline __be32 *
 69 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
 70 {
 71         memcpy(p, fhandle->data, NFS2_FHSIZE);
 72         return p + XDR_QUADLEN(NFS2_FHSIZE);
 73 }
 74 
 75 static inline __be32 *
 76 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
 77 {
 78         /* NFSv2 handles have a fixed length */
 79         fhandle->size = NFS2_FHSIZE;
 80         memcpy(fhandle->data, p, NFS2_FHSIZE);
 81         return p + XDR_QUADLEN(NFS2_FHSIZE);
 82 }
 83 
 84 static inline __be32*
 85 xdr_encode_time(__be32 *p, struct timespec *timep)
 86 {
 87         *p++ = htonl(timep->tv_sec);
 88         /* Convert nanoseconds into microseconds */
 89         *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
 90         return p;
 91 }
 92 
 93 static inline __be32*
 94 xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
 95 {
 96         /*
 97          * Passing the invalid value useconds=1000000 is a
 98          * Sun convention for "set to current server time".
 99          * It's needed to make permissions checks for the
100          * "touch" program across v2 mounts to Solaris and
101          * Irix boxes work correctly. See description of
102          * sattr in section 6.1 of "NFS Illustrated" by
103          * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
104          */
105         *p++ = htonl(timep->tv_sec);
106         *p++ = htonl(1000000);
107         return p;
108 }
109 
110 static inline __be32*
111 xdr_decode_time(__be32 *p, struct timespec *timep)
112 {
113         timep->tv_sec = ntohl(*p++);
114         /* Convert microseconds into nanoseconds */
115         timep->tv_nsec = ntohl(*p++) * 1000;
116         return p;
117 }
118 
119 static __be32 *
120 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
121 {
122         u32 rdev, type;
123         type = ntohl(*p++);
124         fattr->mode = ntohl(*p++);
125         fattr->nlink = ntohl(*p++);
126         fattr->uid = ntohl(*p++);
127         fattr->gid = ntohl(*p++);
128         fattr->size = ntohl(*p++);
129         fattr->du.nfs2.blocksize = ntohl(*p++);
130         rdev = ntohl(*p++);
131         fattr->du.nfs2.blocks = ntohl(*p++);
132         fattr->fsid.major = ntohl(*p++);
133         fattr->fsid.minor = 0;
134         fattr->fileid = ntohl(*p++);
135         p = xdr_decode_time(p, &fattr->atime);
136         p = xdr_decode_time(p, &fattr->mtime);
137         p = xdr_decode_time(p, &fattr->ctime);
138         fattr->valid |= NFS_ATTR_FATTR_V2;
139         fattr->rdev = new_decode_dev(rdev);
140         if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
141                 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
142                 fattr->rdev = 0;
143         }
144         return p;
145 }
146 
147 static inline __be32 *
148 xdr_encode_sattr(__be32 *p, struct iattr *attr)
149 {
150         const __be32 not_set = __constant_htonl(0xFFFFFFFF);
151 
152         *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
153         *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
154         *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
155         *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
156 
157         if (attr->ia_valid & ATTR_ATIME_SET) {
158                 p = xdr_encode_time(p, &attr->ia_atime);
159         } else if (attr->ia_valid & ATTR_ATIME) {
160                 p = xdr_encode_current_server_time(p, &attr->ia_atime);
161         } else {
162                 *p++ = not_set;
163                 *p++ = not_set;
164         }
165 
166         if (attr->ia_valid & ATTR_MTIME_SET) {
167                 p = xdr_encode_time(p, &attr->ia_mtime);
168         } else if (attr->ia_valid & ATTR_MTIME) {
169                 p = xdr_encode_current_server_time(p, &attr->ia_mtime);
170         } else {
171                 *p++ = not_set; 
172                 *p++ = not_set;
173         }
174         return p;
175 }
176 
177 /*
178  * NFS encode functions
179  */
180 /*
181  * Encode file handle argument
182  * GETATTR, READLINK, STATFS
183  */
184 static int
185 nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
186 {
187         p = xdr_encode_fhandle(p, fh);
188         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
189         return 0;
190 }
191 
192 /*
193  * Encode SETATTR arguments
194  */
195 static int
196 nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
197 {
198         p = xdr_encode_fhandle(p, args->fh);
199         p = xdr_encode_sattr(p, args->sattr);
200         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
201         return 0;
202 }
203 
204 /*
205  * Encode directory ops argument
206  * LOOKUP, RMDIR
207  */
208 static int
209 nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
210 {
211         p = xdr_encode_fhandle(p, args->fh);
212         p = xdr_encode_array(p, args->name, args->len);
213         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
214         return 0;
215 }
216 
217 /*
218  * Encode REMOVE argument
219  */
220 static int
221 nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
222 {
223         p = xdr_encode_fhandle(p, args->fh);
224         p = xdr_encode_array(p, args->name.name, args->name.len);
225         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
226         return 0;
227 }
228 
229 /*
230  * Arguments to a READ call. Since we read data directly into the page
231  * cache, we also set up the reply iovec here so that iov[1] points
232  * exactly to the page we want to fetch.
233  */
234 static int
235 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
236 {
237         struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
238         unsigned int replen;
239         u32 offset = (u32)args->offset;
240         u32 count = args->count;
241 
242         p = xdr_encode_fhandle(p, args->fh);
243         *p++ = htonl(offset);
244         *p++ = htonl(count);
245         *p++ = htonl(count);
246         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
247 
248         /* Inline the page array */
249         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
250         xdr_inline_pages(&req->rq_rcv_buf, replen,
251                          args->pages, args->pgbase, count);
252         req->rq_rcv_buf.flags |= XDRBUF_READ;
253         return 0;
254 }
255 
256 /*
257  * Decode READ reply
258  */
259 static int
260 nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
261 {
262         struct kvec *iov = req->rq_rcv_buf.head;
263         size_t hdrlen;
264         u32 count, recvd;
265         int status;
266 
267         if ((status = ntohl(*p++)))
268                 return nfs_stat_to_errno(status);
269         p = xdr_decode_fattr(p, res->fattr);
270 
271         count = ntohl(*p++);
272         res->eof = 0;
273         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
274         if (iov->iov_len < hdrlen) {
275                 dprintk("NFS: READ reply header overflowed:"
276                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
277                 return -errno_NFSERR_IO;
278         } else if (iov->iov_len != hdrlen) {
279                 dprintk("NFS: READ header is short. iovec will be shifted.\n");
280                 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
281         }
282 
283         recvd = req->rq_rcv_buf.len - hdrlen;
284         if (count > recvd) {
285                 dprintk("NFS: server cheating in read reply: "
286                         "count %u > recvd %u\n", count, recvd);
287                 count = recvd;
288         }
289 
290         dprintk("RPC:      readres OK count %u\n", count);
291         if (count < res->count)
292                 res->count = count;
293 
294         return count;
295 }
296 
297 
298 /*
299  * Write arguments. Splice the buffer to be written into the iovec.
300  */
301 static int
302 nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
303 {
304         struct xdr_buf *sndbuf = &req->rq_snd_buf;
305         u32 offset = (u32)args->offset;
306         u32 count = args->count;
307 
308         p = xdr_encode_fhandle(p, args->fh);
309         *p++ = htonl(offset);
310         *p++ = htonl(offset);
311         *p++ = htonl(count);
312         *p++ = htonl(count);
313         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
314 
315         /* Copy the page array */
316         xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
317         sndbuf->flags |= XDRBUF_WRITE;
318         return 0;
319 }
320 
321 /*
322  * Encode create arguments
323  * CREATE, MKDIR
324  */
325 static int
326 nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
327 {
328         p = xdr_encode_fhandle(p, args->fh);
329         p = xdr_encode_array(p, args->name, args->len);
330         p = xdr_encode_sattr(p, args->sattr);
331         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
332         return 0;
333 }
334 
335 /*
336  * Encode RENAME arguments
337  */
338 static int
339 nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
340 {
341         p = xdr_encode_fhandle(p, args->fromfh);
342         p = xdr_encode_array(p, args->fromname, args->fromlen);
343         p = xdr_encode_fhandle(p, args->tofh);
344         p = xdr_encode_array(p, args->toname, args->tolen);
345         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
346         return 0;
347 }
348 
349 /*
350  * Encode LINK arguments
351  */
352 static int
353 nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
354 {
355         p = xdr_encode_fhandle(p, args->fromfh);
356         p = xdr_encode_fhandle(p, args->tofh);
357         p = xdr_encode_array(p, args->toname, args->tolen);
358         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
359         return 0;
360 }
361 
362 /*
363  * Encode SYMLINK arguments
364  */
365 static int
366 nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
367 {
368         struct xdr_buf *sndbuf = &req->rq_snd_buf;
369         size_t pad;
370 
371         p = xdr_encode_fhandle(p, args->fromfh);
372         p = xdr_encode_array(p, args->fromname, args->fromlen);
373         *p++ = htonl(args->pathlen);
374         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
375 
376         xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
377 
378         /*
379          * xdr_encode_pages may have added a few bytes to ensure the
380          * pathname ends on a 4-byte boundary.  Start encoding the
381          * attributes after the pad bytes.
382          */
383         pad = sndbuf->tail->iov_len;
384         if (pad > 0)
385                 p++;
386         p = xdr_encode_sattr(p, args->sattr);
387         sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
388         return 0;
389 }
390 
391 /*
392  * Encode arguments to readdir call
393  */
394 static int
395 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
396 {
397         struct rpc_task *task = req->rq_task;
398         struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
399         unsigned int replen;
400         u32 count = args->count;
401 
402         p = xdr_encode_fhandle(p, args->fh);
403         *p++ = htonl(args->cookie);
404         *p++ = htonl(count); /* see above */
405         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
406 
407         /* Inline the page array */
408         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
409         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
410         return 0;
411 }
412 
413 /*
414  * Decode the result of a readdir call.
415  * We're not really decoding anymore, we just leave the buffer untouched
416  * and only check that it is syntactically correct.
417  * The real decoding happens in nfs_decode_entry below, called directly
418  * from nfs_readdir for each entry.
419  */
420 static int
421 nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
422 {
423         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
424         struct kvec *iov = rcvbuf->head;
425         struct page **page;
426         size_t hdrlen;
427         unsigned int pglen, recvd;
428         u32 len;
429         int status, nr = 0;
430         __be32 *end, *entry, *kaddr;
431 
432         if ((status = ntohl(*p++)))
433                 return nfs_stat_to_errno(status);
434 
435         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
436         if (iov->iov_len < hdrlen) {
437                 dprintk("NFS: READDIR reply header overflowed:"
438                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
439                 return -errno_NFSERR_IO;
440         } else if (iov->iov_len != hdrlen) {
441                 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
442                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
443         }
444 
445         pglen = rcvbuf->page_len;
446         recvd = rcvbuf->len - hdrlen;
447         if (pglen > recvd)
448                 pglen = recvd;
449         page = rcvbuf->pages;
450         kaddr = p = kmap_atomic(*page, KM_USER0);
451         end = (__be32 *)((char *)p + pglen);
452         entry = p;
453 
454         /* Make sure the packet actually has a value_follows and EOF entry */
455         if ((entry + 1) > end)
456                 goto short_pkt;
457 
458         for (; *p++; nr++) {
459                 if (p + 2 > end)
460                         goto short_pkt;
461                 p++; /* fileid */
462                 len = ntohl(*p++);
463                 p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
464                 if (len > NFS2_MAXNAMLEN) {
465                         dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
466                                                 len);
467                         goto err_unmap;
468                 }
469                 if (p + 2 > end)
470                         goto short_pkt;
471                 entry = p;
472         }
473 
474         /*
475          * Apparently some server sends responses that are a valid size, but
476          * contain no entries, and have value_follows==0 and EOF==0. For
477          * those, just set the EOF marker.
478          */
479         if (!nr && entry[1] == 0) {
480                 dprintk("NFS: readdir reply truncated!\n");
481                 entry[1] = 1;
482         }
483  out:
484         kunmap_atomic(kaddr, KM_USER0);
485         return nr;
486  short_pkt:
487         /*
488          * When we get a short packet there are 2 possibilities. We can
489          * return an error, or fix up the response to look like a valid
490          * response and return what we have so far. If there are no
491          * entries and the packet was short, then return -EIO. If there
492          * are valid entries in the response, return them and pretend that
493          * the call was successful, but incomplete. The caller can retry the
494          * readdir starting at the last cookie.
495          */
496         entry[0] = entry[1] = 0;
497         if (!nr)
498                 nr = -errno_NFSERR_IO;
499         goto out;
500 err_unmap:
501         nr = -errno_NFSERR_IO;
502         goto out;
503 }
504 
505 __be32 *
506 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
507 {
508         if (!*p++) {
509                 if (!*p)
510                         return ERR_PTR(-EAGAIN);
511                 entry->eof = 1;
512                 return ERR_PTR(-EBADCOOKIE);
513         }
514 
515         entry->ino        = ntohl(*p++);
516         entry->len        = ntohl(*p++);
517         entry->name       = (const char *) p;
518         p                += XDR_QUADLEN(entry->len);
519         entry->prev_cookie        = entry->cookie;
520         entry->cookie     = ntohl(*p++);
521         entry->eof        = !p[0] && p[1];
522 
523         return p;
524 }
525 
526 /*
527  * NFS XDR decode functions
528  */
529 /*
530  * Decode simple status reply
531  */
532 static int
533 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
534 {
535         int     status;
536 
537         if ((status = ntohl(*p++)) != 0)
538                 status = nfs_stat_to_errno(status);
539         return status;
540 }
541 
542 /*
543  * Decode attrstat reply
544  * GETATTR, SETATTR, WRITE
545  */
546 static int
547 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
548 {
549         int     status;
550 
551         if ((status = ntohl(*p++)))
552                 return nfs_stat_to_errno(status);
553         xdr_decode_fattr(p, fattr);
554         return 0;
555 }
556 
557 /*
558  * Decode diropres reply
559  * LOOKUP, CREATE, MKDIR
560  */
561 static int
562 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
563 {
564         int     status;
565 
566         if ((status = ntohl(*p++)))
567                 return nfs_stat_to_errno(status);
568         p = xdr_decode_fhandle(p, res->fh);
569         xdr_decode_fattr(p, res->fattr);
570         return 0;
571 }
572 
573 /*
574  * Encode READLINK args
575  */
576 static int
577 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
578 {
579         struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
580         unsigned int replen;
581 
582         p = xdr_encode_fhandle(p, args->fh);
583         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
584 
585         /* Inline the page array */
586         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
587         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
588         return 0;
589 }
590 
591 /*
592  * Decode READLINK reply
593  */
594 static int
595 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
596 {
597         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
598         struct kvec *iov = rcvbuf->head;
599         size_t hdrlen;
600         u32 len, recvd;
601         char    *kaddr;
602         int     status;
603 
604         if ((status = ntohl(*p++)))
605                 return nfs_stat_to_errno(status);
606         /* Convert length of symlink */
607         len = ntohl(*p++);
608         if (len >= rcvbuf->page_len) {
609                 dprintk("nfs: server returned giant symlink!\n");
610                 return -ENAMETOOLONG;
611         }
612         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
613         if (iov->iov_len < hdrlen) {
614                 dprintk("NFS: READLINK reply header overflowed:"
615                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
616                 return -errno_NFSERR_IO;
617         } else if (iov->iov_len != hdrlen) {
618                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
619                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
620         }
621         recvd = req->rq_rcv_buf.len - hdrlen;
622         if (recvd < len) {
623                 dprintk("NFS: server cheating in readlink reply: "
624                                 "count %u > recvd %u\n", len, recvd);
625                 return -EIO;
626         }
627 
628         /* NULL terminate the string we got */
629         kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
630         kaddr[len+rcvbuf->page_base] = '\0';
631         kunmap_atomic(kaddr, KM_USER0);
632         return 0;
633 }
634 
635 /*
636  * Decode WRITE reply
637  */
638 static int
639 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
640 {
641         res->verf->committed = NFS_FILE_SYNC;
642         return nfs_xdr_attrstat(req, p, res->fattr);
643 }
644 
645 /*
646  * Decode STATFS reply
647  */
648 static int
649 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
650 {
651         int     status;
652 
653         if ((status = ntohl(*p++)))
654                 return nfs_stat_to_errno(status);
655 
656         res->tsize  = ntohl(*p++);
657         res->bsize  = ntohl(*p++);
658         res->blocks = ntohl(*p++);
659         res->bfree  = ntohl(*p++);
660         res->bavail = ntohl(*p++);
661         return 0;
662 }
663 
664 /*
665  * We need to translate between nfs status return values and
666  * the local errno values which may not be the same.
667  */
668 static struct {
669         int stat;
670         int errno;
671 } nfs_errtbl[] = {
672         { NFS_OK,               0               },
673         { NFSERR_PERM,          -EPERM          },
674         { NFSERR_NOENT,         -ENOENT         },
675         { NFSERR_IO,            -errno_NFSERR_IO},
676         { NFSERR_NXIO,          -ENXIO          },
677 /*      { NFSERR_EAGAIN,        -EAGAIN         }, */
678         { NFSERR_ACCES,         -EACCES         },
679         { NFSERR_EXIST,         -EEXIST         },
680         { NFSERR_XDEV,          -EXDEV          },
681         { NFSERR_NODEV,         -ENODEV         },
682         { NFSERR_NOTDIR,        -ENOTDIR        },
683         { NFSERR_ISDIR,         -EISDIR         },
684         { NFSERR_INVAL,         -EINVAL         },
685         { NFSERR_FBIG,          -EFBIG          },
686         { NFSERR_NOSPC,         -ENOSPC         },
687         { NFSERR_ROFS,          -EROFS          },
688         { NFSERR_MLINK,         -EMLINK         },
689         { NFSERR_NAMETOOLONG,   -ENAMETOOLONG   },
690         { NFSERR_NOTEMPTY,      -ENOTEMPTY      },
691         { NFSERR_DQUOT,         -EDQUOT         },
692         { NFSERR_STALE,         -ESTALE         },
693         { NFSERR_REMOTE,        -EREMOTE        },
694 #ifdef EWFLUSH
695         { NFSERR_WFLUSH,        -EWFLUSH        },
696 #endif
697         { NFSERR_BADHANDLE,     -EBADHANDLE     },
698         { NFSERR_NOT_SYNC,      -ENOTSYNC       },
699         { NFSERR_BAD_COOKIE,    -EBADCOOKIE     },
700         { NFSERR_NOTSUPP,       -ENOTSUPP       },
701         { NFSERR_TOOSMALL,      -ETOOSMALL      },
702         { NFSERR_SERVERFAULT,   -EREMOTEIO      },
703         { NFSERR_BADTYPE,       -EBADTYPE       },
704         { NFSERR_JUKEBOX,       -EJUKEBOX       },
705         { -1,                   -EIO            }
706 };
707 
708 /*
709  * Convert an NFS error code to a local one.
710  * This one is used jointly by NFSv2 and NFSv3.
711  */
712 int
713 nfs_stat_to_errno(int stat)
714 {
715         int i;
716 
717         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
718                 if (nfs_errtbl[i].stat == stat)
719                         return nfs_errtbl[i].errno;
720         }
721         dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
722         return nfs_errtbl[i].errno;
723 }
724 
725 #define PROC(proc, argtype, restype, timer)                             \
726 [NFSPROC_##proc] = {                                                    \
727         .p_proc     =  NFSPROC_##proc,                                  \
728         .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
729         .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
730         .p_arglen   =  NFS_##argtype##_sz,                              \
731         .p_replen   =  NFS_##restype##_sz,                              \
732         .p_timer    =  timer,                                           \
733         .p_statidx  =  NFSPROC_##proc,                                  \
734         .p_name     =  #proc,                                           \
735         }
736 struct rpc_procinfo     nfs_procedures[] = {
737     PROC(GETATTR,       fhandle,        attrstat, 1),
738     PROC(SETATTR,       sattrargs,      attrstat, 0),
739     PROC(LOOKUP,        diropargs,      diropres, 2),
740     PROC(READLINK,      readlinkargs,   readlinkres, 3),
741     PROC(READ,          readargs,       readres, 3),
742     PROC(WRITE,         writeargs,      writeres, 4),
743     PROC(CREATE,        createargs,     diropres, 0),
744     PROC(REMOVE,        removeargs,     stat, 0),
745     PROC(RENAME,        renameargs,     stat, 0),
746     PROC(LINK,          linkargs,       stat, 0),
747     PROC(SYMLINK,       symlinkargs,    stat, 0),
748     PROC(MKDIR,         createargs,     diropres, 0),
749     PROC(RMDIR,         diropargs,      stat, 0),
750     PROC(READDIR,       readdirargs,    readdirres, 3),
751     PROC(STATFS,        fhandle,        statfsres, 0),
752 };
753 
754 struct rpc_version              nfs_version2 = {
755         .number                 = 2,
756         .nrprocs                = ARRAY_SIZE(nfs_procedures),
757         .procs                  = nfs_procedures
758 };
759 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp