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

Linux Cross Reference
Linux/fs/nfsd/nfs3xdr.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/fs/nfsd/nfs3xdr.c
  3  *
  4  * XDR support for nfsd/protocol version 3.
  5  *
  6  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  7  */
  8 
  9 #include <linux/types.h>
 10 #include <linux/sched.h>
 11 #include <linux/nfs3.h>
 12 
 13 #include <linux/sunrpc/xdr.h>
 14 #include <linux/sunrpc/svc.h>
 15 #include <linux/nfsd/nfsd.h>
 16 #include <linux/nfsd/xdr3.h>
 17 
 18 #define NFSDDBG_FACILITY                NFSDDBG_XDR
 19 
 20 #ifdef NFSD_OPTIMIZE_SPACE
 21 # define inline
 22 #endif
 23 
 24 
 25 /*
 26  * Mapping of S_IF* types to NFS file types
 27  */
 28 static u32      nfs3_ftypes[] = {
 29         NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
 30         NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
 31         NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
 32         NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
 33 };
 34 
 35 /*
 36  * XDR functions for basic NFS types
 37  */
 38 static inline u32 *
 39 encode_time3(u32 *p, time_t secs)
 40 {
 41         *p++ = htonl((u32) secs); *p++ = 0;
 42         return p;
 43 }
 44 
 45 static inline u32 *
 46 decode_time3(u32 *p, time_t *secp)
 47 {
 48         *secp = ntohl(*p++);
 49         return p + 1;
 50 }
 51 
 52 static inline u32 *
 53 decode_fh(u32 *p, struct svc_fh *fhp)
 54 {
 55         int size;
 56         fh_init(fhp, NFS3_FHSIZE);
 57         size = ntohl(*p++);
 58         if (size > NFS3_FHSIZE)
 59                 return NULL;
 60 
 61         memcpy(&fhp->fh_handle.fh_base, p, size);
 62         fhp->fh_handle.fh_size = size;
 63         return p + XDR_QUADLEN(size);
 64 }
 65 
 66 static inline u32 *
 67 encode_fh(u32 *p, struct svc_fh *fhp)
 68 {
 69         int size = fhp->fh_handle.fh_size;
 70         *p++ = htonl(size);
 71         if (size) p[XDR_QUADLEN(size)-1]=0;
 72         memcpy(p, &fhp->fh_handle.fh_base, size);
 73         return p + XDR_QUADLEN(size);
 74 }
 75 
 76 /*
 77  * Decode a file name and make sure that the path contains
 78  * no slashes or null bytes.
 79  */
 80 static inline u32 *
 81 decode_filename(u32 *p, char **namp, int *lenp)
 82 {
 83         char            *name;
 84         int             i;
 85 
 86         if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
 87                 for (i = 0, name = *namp; i < *lenp; i++, name++) {
 88                         if (*name == '\0' || *name == '/')
 89                                 return NULL;
 90                 }
 91                 *name = '\0';
 92         }
 93 
 94         return p;
 95 }
 96 
 97 static inline u32 *
 98 decode_pathname(u32 *p, char **namp, int *lenp)
 99 {
100         char            *name;
101         int             i;
102 
103         if ((p = xdr_decode_string(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
104                 for (i = 0, name = *namp; i < *lenp; i++, name++) {
105                         if (*name == '\0')
106                                 return NULL;
107                 }
108                 *name = '\0';
109         }
110 
111         return p;
112 }
113 
114 static inline u32 *
115 decode_sattr3(u32 *p, struct iattr *iap)
116 {
117         u32     tmp;
118 
119         iap->ia_valid = 0;
120 
121         if (*p++) {
122                 iap->ia_valid |= ATTR_MODE;
123                 iap->ia_mode = ntohl(*p++);
124         }
125         if (*p++) {
126                 iap->ia_valid |= ATTR_UID;
127                 iap->ia_uid = ntohl(*p++);
128         }
129         if (*p++) {
130                 iap->ia_valid |= ATTR_GID;
131                 iap->ia_gid = ntohl(*p++);
132         }
133         if (*p++) {
134                 u64     newsize;
135 
136                 iap->ia_valid |= ATTR_SIZE;
137                 p = xdr_decode_hyper(p, &newsize);
138                 if (newsize <= NFS_OFFSET_MAX)
139                         iap->ia_size = newsize;
140                 else
141                         iap->ia_size = NFS_OFFSET_MAX;
142         }
143         if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
144                 iap->ia_valid |= ATTR_ATIME;
145         } else if (tmp == 2) {          /* set to client time */
146                 iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
147                 iap->ia_atime = ntohl(*p++), p++;
148         }
149         if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
150                 iap->ia_valid |= ATTR_MTIME;
151         } else if (tmp == 2) {          /* set to client time */
152                 iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
153                 iap->ia_mtime = ntohl(*p++), p++;
154         }
155         return p;
156 }
157 
158 static inline u32 *
159 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
160 {
161         struct inode    *inode = dentry->d_inode;
162 
163         if (!inode) {
164                 printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
165                 return NULL;
166         }
167 
168         *p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
169         *p++ = htonl((u32) inode->i_mode);
170         *p++ = htonl((u32) inode->i_nlink);
171         *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
172         *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
173         if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
174                 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
175         } else {
176                 p = xdr_encode_hyper(p, (u64) inode->i_size);
177         }
178         if (inode->i_blksize == 0 && inode->i_blocks == 0)
179                 /* Minix file system(?) i_size is (hopefully) close enough */
180                 p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
181         else
182                 p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
183         *p++ = htonl((u32) MAJOR(inode->i_rdev));
184         *p++ = htonl((u32) MINOR(inode->i_rdev));
185         p = xdr_encode_hyper(p, (u64) inode->i_dev);
186         p = xdr_encode_hyper(p, (u64) inode->i_ino);
187         p = encode_time3(p, inode->i_atime);
188         p = encode_time3(p, lease_get_mtime(inode));
189         p = encode_time3(p, inode->i_ctime);
190 
191         return p;
192 }
193 
194 static inline u32 *
195 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
196 {
197         struct inode    *inode = fhp->fh_dentry->d_inode;
198 
199         /* Attributes to follow */
200         *p++ = xdr_one;
201 
202         *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
203         *p++ = htonl((u32) fhp->fh_post_mode);
204         *p++ = htonl((u32) fhp->fh_post_nlink);
205         *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
206         *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
207         if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
208                 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
209         } else {
210                 p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
211         }
212         p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
213         *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
214         *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
215         p = xdr_encode_hyper(p, (u64) inode->i_dev);
216         p = xdr_encode_hyper(p, (u64) inode->i_ino);
217         p = encode_time3(p, fhp->fh_post_atime);
218         p = encode_time3(p, fhp->fh_post_mtime);
219         p = encode_time3(p, fhp->fh_post_ctime);
220 
221         return p;
222 }
223 
224 /*
225  * Encode post-operation attributes.
226  * The inode may be NULL if the call failed because of a stale file
227  * handle. In this case, no attributes are returned.
228  */
229 static u32 *
230 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
231 {
232         if (dentry && dentry->d_inode != NULL) {
233                 *p++ = xdr_one;         /* attributes follow */
234                 return encode_fattr3(rqstp, p, dentry);
235         }
236         *p++ = xdr_zero;
237         return p;
238 }
239 
240 /*
241  * Enocde weak cache consistency data
242  */
243 static u32 *
244 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
245 {
246         struct dentry   *dentry = fhp->fh_dentry;
247 
248         if (dentry && dentry->d_inode && fhp->fh_post_saved) {
249                 if (fhp->fh_pre_saved) {
250                         *p++ = xdr_one;
251                         p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
252                         p = encode_time3(p, fhp->fh_pre_mtime);
253                         p = encode_time3(p, fhp->fh_pre_ctime);
254                 } else {
255                         *p++ = xdr_zero;
256                 }
257                 return encode_saved_post_attr(rqstp, p, fhp);
258         }
259         /* no pre- or post-attrs */
260         *p++ = xdr_zero;
261         return encode_post_op_attr(rqstp, p, dentry);
262 }
263 
264 /*
265  * Check buffer bounds after decoding arguments
266  */
267 static inline int
268 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
269 {
270         struct svc_buf  *buf = &rqstp->rq_argbuf;
271 
272         return p - buf->base <= buf->buflen;
273 }
274 
275 static inline int
276 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
277 {
278         struct svc_buf  *buf = &rqstp->rq_resbuf;
279 
280         buf->len = p - buf->base;
281         dprintk("nfsd: ressize_check p %p base %p len %d\n",
282                         p, buf->base, buf->buflen);
283         return (buf->len <= buf->buflen);
284 }
285 
286 /*
287  * XDR decode functions
288  */
289 int
290 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
291 {
292         if (!(p = decode_fh(p, fhp)))
293                 return 0;
294         return xdr_argsize_check(rqstp, p);
295 }
296 
297 int
298 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
299                                         struct nfsd3_sattrargs *args)
300 {
301         if (!(p = decode_fh(p, &args->fh))
302          || !(p = decode_sattr3(p, &args->attrs)))
303                 return 0;
304 
305         if ((args->check_guard = ntohl(*p++)) != 0)
306                 p = decode_time3(p, &args->guardtime);
307 
308         return xdr_argsize_check(rqstp, p);
309 }
310 
311 int
312 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
313                                         struct nfsd3_diropargs *args)
314 {
315         if (!(p = decode_fh(p, &args->fh))
316          || !(p = decode_filename(p, &args->name, &args->len)))
317                 return 0;
318 
319         return xdr_argsize_check(rqstp, p);
320 }
321 
322 int
323 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
324                                         struct nfsd3_accessargs *args)
325 {
326         if (!(p = decode_fh(p, &args->fh)))
327                 return 0;
328         args->access = ntohl(*p++);
329 
330         return xdr_argsize_check(rqstp, p);
331 }
332 
333 int
334 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
335                                         struct nfsd3_readargs *args)
336 {
337         if (!(p = decode_fh(p, &args->fh))
338          || !(p = xdr_decode_hyper(p, &args->offset)))
339                 return 0;
340 
341         args->count = ntohl(*p++);
342         return xdr_argsize_check(rqstp, p);
343 }
344 
345 int
346 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
347                                         struct nfsd3_writeargs *args)
348 {
349         if (!(p = decode_fh(p, &args->fh))
350          || !(p = xdr_decode_hyper(p, &args->offset)))
351                 return 0;
352 
353         args->count = ntohl(*p++);
354         args->stable = ntohl(*p++);
355         args->len = ntohl(*p++);
356         args->data = (char *) p;
357         p += XDR_QUADLEN(args->len);
358 
359         return xdr_argsize_check(rqstp, p);
360 }
361 
362 int
363 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
364                                         struct nfsd3_createargs *args)
365 {
366         if (!(p = decode_fh(p, &args->fh))
367          || !(p = decode_filename(p, &args->name, &args->len)))
368                 return 0;
369 
370         switch (args->createmode = ntohl(*p++)) {
371         case NFS3_CREATE_UNCHECKED:
372         case NFS3_CREATE_GUARDED:
373                 if (!(p = decode_sattr3(p, &args->attrs)))
374                         return 0;
375                 break;
376         case NFS3_CREATE_EXCLUSIVE:
377                 args->verf = p;
378                 p += 2;
379                 break;
380         default:
381                 return 0;
382         }
383 
384         return xdr_argsize_check(rqstp, p);
385 }
386 int
387 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
388                                         struct nfsd3_createargs *args)
389 {
390         if (!(p = decode_fh(p, &args->fh))
391          || !(p = decode_filename(p, &args->name, &args->len))
392          || !(p = decode_sattr3(p, &args->attrs)))
393                 return 0;
394 
395         return xdr_argsize_check(rqstp, p);
396 }
397 
398 int
399 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
400                                         struct nfsd3_symlinkargs *args)
401 {
402         if (!(p = decode_fh(p, &args->ffh))
403          || !(p = decode_filename(p, &args->fname, &args->flen))
404          || !(p = decode_sattr3(p, &args->attrs))
405          || !(p = decode_pathname(p, &args->tname, &args->tlen)))
406                 return 0;
407 
408         return xdr_argsize_check(rqstp, p);
409 }
410 
411 int
412 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
413                                         struct nfsd3_mknodargs *args)
414 {
415         if (!(p = decode_fh(p, &args->fh))
416          || !(p = decode_filename(p, &args->name, &args->len)))
417                 return 0;
418 
419         args->ftype = ntohl(*p++);
420 
421         if (args->ftype == NF3BLK  || args->ftype == NF3CHR
422          || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
423                 if (!(p = decode_sattr3(p, &args->attrs)))
424                         return 0;
425         }
426 
427         if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
428                 args->major = ntohl(*p++);
429                 args->minor = ntohl(*p++);
430         }
431 
432         return xdr_argsize_check(rqstp, p);
433 }
434 
435 int
436 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
437                                         struct nfsd3_renameargs *args)
438 {
439         if (!(p = decode_fh(p, &args->ffh))
440          || !(p = decode_filename(p, &args->fname, &args->flen))
441          || !(p = decode_fh(p, &args->tfh))
442          || !(p = decode_filename(p, &args->tname, &args->tlen)))
443                 return 0;
444 
445         return xdr_argsize_check(rqstp, p);
446 }
447 
448 int
449 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
450                                         struct nfsd3_linkargs *args)
451 {
452         if (!(p = decode_fh(p, &args->ffh))
453          || !(p = decode_fh(p, &args->tfh))
454          || !(p = decode_filename(p, &args->tname, &args->tlen)))
455                 return 0;
456 
457         return xdr_argsize_check(rqstp, p);
458 }
459 
460 int
461 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
462                                         struct nfsd3_readdirargs *args)
463 {
464         if (!(p = decode_fh(p, &args->fh)))
465                 return 0;
466         p = xdr_decode_hyper(p, &args->cookie);
467         args->verf   = p; p += 2;
468         args->dircount = ~0;
469         args->count  = ntohl(*p++);
470 
471         return xdr_argsize_check(rqstp, p);
472 }
473 
474 int
475 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
476                                         struct nfsd3_readdirargs *args)
477 {
478         if (!(p = decode_fh(p, &args->fh)))
479                 return 0;
480         p = xdr_decode_hyper(p, &args->cookie);
481         args->verf     = p; p += 2;
482         args->dircount = ntohl(*p++);
483         args->count    = ntohl(*p++);
484 
485         return xdr_argsize_check(rqstp, p);
486 }
487 
488 int
489 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
490                                         struct nfsd3_commitargs *args)
491 {
492         if (!(p = decode_fh(p, &args->fh)))
493                 return 0;
494         p = xdr_decode_hyper(p, &args->offset);
495         args->count = ntohl(*p++);
496 
497         return xdr_argsize_check(rqstp, p);
498 }
499 
500 /*
501  * XDR encode functions
502  */
503 /*
504  * There must be an encoding function for void results so svc_process
505  * will work properly.
506  */
507 int
508 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
509 {
510         return xdr_ressize_check(rqstp, p);
511 }
512 
513 /* GETATTR */
514 int
515 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
516                                         struct nfsd3_attrstat *resp)
517 {
518         if (resp->status == 0
519          && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
520                 return 0;
521         return xdr_ressize_check(rqstp, p);
522 }
523 
524 /* SETATTR, REMOVE, RMDIR */
525 int
526 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
527                                         struct nfsd3_attrstat *resp)
528 {
529         if (!(p = encode_wcc_data(rqstp, p, &resp->fh)))
530                 return 0;
531         return xdr_ressize_check(rqstp, p);
532 }
533 
534 /* LOOKUP */
535 int
536 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
537                                         struct nfsd3_diropres *resp)
538 {
539         if (resp->status == 0) {
540                 p = encode_fh(p, &resp->fh);
541                 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
542         }
543         p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
544         return xdr_ressize_check(rqstp, p);
545 }
546 
547 /* ACCESS */
548 int
549 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
550                                         struct nfsd3_accessres *resp)
551 {
552         p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
553         if (resp->status == 0)
554                 *p++ = htonl(resp->access);
555         return xdr_ressize_check(rqstp, p);
556 }
557 
558 /* READLINK */
559 int
560 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
561                                         struct nfsd3_readlinkres *resp)
562 {
563         p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
564         if (resp->status == 0) {
565                 *p++ = htonl(resp->len);
566                 p += XDR_QUADLEN(resp->len);
567         }
568         return xdr_ressize_check(rqstp, p);
569 }
570 
571 /* READ */
572 int
573 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
574                                         struct nfsd3_readres *resp)
575 {
576         p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
577         if (resp->status == 0) {
578                 *p++ = htonl(resp->count);
579                 *p++ = htonl(resp->eof);
580                 *p++ = htonl(resp->count);      /* xdr opaque count */
581                 p += XDR_QUADLEN(resp->count);
582         }
583         return xdr_ressize_check(rqstp, p);
584 }
585 
586 /* WRITE */
587 int
588 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
589                                         struct nfsd3_writeres *resp)
590 {
591         p = encode_wcc_data(rqstp, p, &resp->fh);
592         if (resp->status == 0) {
593                 *p++ = htonl(resp->count);
594                 *p++ = htonl(resp->committed);
595                 *p++ = htonl(nfssvc_boot.tv_sec);
596                 *p++ = htonl(nfssvc_boot.tv_usec);
597         }
598         return xdr_ressize_check(rqstp, p);
599 }
600 
601 /* CREATE, MKDIR, SYMLINK, MKNOD */
602 int
603 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
604                                         struct nfsd3_diropres *resp)
605 {
606         if (resp->status == 0) {
607                 *p++ = xdr_one;
608                 p = encode_fh(p, &resp->fh);
609                 p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
610         }
611         p = encode_wcc_data(rqstp, p, &resp->dirfh);
612         return xdr_ressize_check(rqstp, p);
613 }
614 
615 /* RENAME */
616 int
617 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
618                                         struct nfsd3_renameres *resp)
619 {
620         p = encode_wcc_data(rqstp, p, &resp->ffh);
621         p = encode_wcc_data(rqstp, p, &resp->tfh);
622         return xdr_ressize_check(rqstp, p);
623 }
624 
625 /* LINK */
626 int
627 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
628                                         struct nfsd3_linkres *resp)
629 {
630         p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
631         p = encode_wcc_data(rqstp, p, &resp->tfh);
632         return xdr_ressize_check(rqstp, p);
633 }
634 
635 /* READDIR */
636 int
637 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
638                                         struct nfsd3_readdirres *resp)
639 {
640         p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
641         if (resp->status == 0) {
642                 /* stupid readdir cookie */
643                 memcpy(p, resp->verf, 8); p += 2;
644                 p += XDR_QUADLEN(resp->count);
645         }
646 
647         return xdr_ressize_check(rqstp, p);
648 }
649 
650 /*
651  * Encode a directory entry. This one works for both normal readdir
652  * and readdirplus.
653  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
654  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
655  * 
656  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
657  * file handle.
658  */
659 
660 #define NFS3_ENTRY_BAGGAGE      (2 + 1 + 2 + 1)
661 #define NFS3_ENTRYPLUS_BAGGAGE  (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
662 static int
663 encode_entry(struct readdir_cd *cd, const char *name,
664              int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
665 {
666         u32             *p = cd->buffer;
667         int             buflen, slen, elen;
668 
669         if (cd->offset)
670                 xdr_encode_hyper(cd->offset, (u64) offset);
671 
672         /* nfsd_readdir calls us with name == 0 when it wants us to
673          * set the last offset entry. */
674         if (name == 0)
675                 return 0;
676 
677         /*
678         dprintk("encode_entry(%.*s @%ld%s)\n",
679                 namlen, name, (long) offset, plus? " plus" : "");
680          */
681 
682         /* truncate filename if too long */
683         if (namlen > NFS3_MAXNAMLEN)
684                 namlen = NFS3_MAXNAMLEN;
685 
686         slen = XDR_QUADLEN(namlen);
687         elen = slen + NFS3_ENTRY_BAGGAGE
688                 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
689         if ((buflen = cd->buflen - elen) < 0) {
690                 cd->eob = 1;
691                 return -EINVAL;
692         }
693         *p++ = xdr_one;                          /* mark entry present */
694         p    = xdr_encode_hyper(p, ino);         /* file id */
695         p    = xdr_encode_array(p, name, namlen);/* name length & name */
696 
697         cd->offset = p;                 /* remember pointer */
698         p = xdr_encode_hyper(p, NFS_OFFSET_MAX);        /* offset of next entry */
699 
700         /* throw in readdirplus baggage */
701         if (plus) {
702                 struct svc_fh   fh;
703                 struct svc_export       *exp;
704                 struct dentry           *dparent, *dchild;
705 
706                 dparent = cd->dirfh->fh_dentry;
707                 exp  = cd->dirfh->fh_export;
708 
709                 fh_init(&fh, NFS3_FHSIZE);
710                 if (fh_verify(cd->rqstp, cd->dirfh, S_IFDIR, MAY_EXEC) != 0)
711                         goto noexec;
712                 if (isdotent(name, namlen)) {
713                         dchild = dparent;
714                         if (namlen == 2)
715                                 dchild = dchild->d_parent;
716                         dchild = dget(dchild);
717                 } else
718                         dchild = lookup_one(name, dparent);
719                 if (IS_ERR(dchild))
720                         goto noexec;
721                 if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode)
722                         goto noexec;
723                 p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
724                 *p++ = xdr_one; /* yes, a file handle follows */
725                 p = encode_fh(p, &fh);
726                 fh_put(&fh);
727         }
728 
729 out:
730         cd->buflen = buflen;
731         cd->buffer = p;
732         return 0;
733 
734 noexec:
735         *p++ = 0;
736         *p++ = 0;
737         goto out;
738 }
739 
740 int
741 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
742                      int namlen, off_t offset, ino_t ino, unsigned int d_type)
743 {
744         return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
745 }
746 
747 int
748 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
749                           int namlen, off_t offset, ino_t ino, unsigned int d_type)
750 {
751         return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
752 }
753 
754 /* FSSTAT */
755 int
756 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
757                                         struct nfsd3_fsstatres *resp)
758 {
759         struct statfs   *s = &resp->stats;
760         u64             bs = s->f_bsize;
761 
762         *p++ = xdr_zero;        /* no post_op_attr */
763 
764         if (resp->status == 0) {
765                 p = xdr_encode_hyper(p, bs * s->f_blocks);      /* total bytes */
766                 p = xdr_encode_hyper(p, bs * s->f_bfree);       /* free bytes */
767                 p = xdr_encode_hyper(p, bs * s->f_bavail);      /* user available bytes */
768                 p = xdr_encode_hyper(p, s->f_files);    /* total inodes */
769                 p = xdr_encode_hyper(p, s->f_ffree);    /* free inodes */
770                 p = xdr_encode_hyper(p, s->f_ffree);    /* user available inodes */
771                 *p++ = htonl(resp->invarsec);   /* mean unchanged time */
772         }
773         return xdr_ressize_check(rqstp, p);
774 }
775 
776 /* FSINFO */
777 int
778 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
779                                         struct nfsd3_fsinfores *resp)
780 {
781         *p++ = xdr_zero;        /* no post_op_attr */
782 
783         if (resp->status == 0) {
784                 *p++ = htonl(resp->f_rtmax);
785                 *p++ = htonl(resp->f_rtpref);
786                 *p++ = htonl(resp->f_rtmult);
787                 *p++ = htonl(resp->f_wtmax);
788                 *p++ = htonl(resp->f_wtpref);
789                 *p++ = htonl(resp->f_wtmult);
790                 *p++ = htonl(resp->f_dtpref);
791                 p = xdr_encode_hyper(p, resp->f_maxfilesize);
792                 *p++ = xdr_one;
793                 *p++ = xdr_zero;
794                 *p++ = htonl(resp->f_properties);
795         }
796 
797         return xdr_ressize_check(rqstp, p);
798 }
799 
800 /* PATHCONF */
801 int
802 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
803                                         struct nfsd3_pathconfres *resp)
804 {
805         *p++ = xdr_zero;        /* no post_op_attr */
806 
807         if (resp->status == 0) {
808                 *p++ = htonl(resp->p_link_max);
809                 *p++ = htonl(resp->p_name_max);
810                 *p++ = htonl(resp->p_no_trunc);
811                 *p++ = htonl(resp->p_chown_restricted);
812                 *p++ = htonl(resp->p_case_insensitive);
813                 *p++ = htonl(resp->p_case_preserving);
814         }
815 
816         return xdr_ressize_check(rqstp, p);
817 }
818 
819 /* COMMIT */
820 int
821 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
822                                         struct nfsd3_commitres *resp)
823 {
824         p = encode_wcc_data(rqstp, p, &resp->fh);
825         /* Write verifier */
826         if (resp->status == 0) {
827                 *p++ = htonl(nfssvc_boot.tv_sec);
828                 *p++ = htonl(nfssvc_boot.tv_usec);
829         }
830         return xdr_ressize_check(rqstp, p);
831 }
832 
833 /*
834  * XDR release functions
835  */
836 int
837 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
838                                         struct nfsd3_attrstat *resp)
839 {
840         fh_put(&resp->fh);
841         return 1;
842 }
843 
844 int
845 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
846                                         struct nfsd3_fhandle_pair *resp)
847 {
848         fh_put(&resp->fh1);
849         fh_put(&resp->fh2);
850         return 1;
851 }
852 

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

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.