OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [nfsd/] [nfs3xdr.c] - Blame information for rev 79

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
 * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
9
 */
10
 
11
#include <linux/types.h>
12
#include <linux/time.h>
13
#include <linux/nfs3.h>
14
#include <linux/list.h>
15
#include <linux/spinlock.h>
16
#include <linux/dcache.h>
17
#include <linux/namei.h>
18
#include <linux/mm.h>
19
#include <linux/vfs.h>
20
#include <linux/sunrpc/xdr.h>
21
#include <linux/sunrpc/svc.h>
22
#include <linux/nfsd/nfsd.h>
23
#include <linux/nfsd/xdr3.h>
24
 
25
#define NFSDDBG_FACILITY                NFSDDBG_XDR
26
 
27
 
28
/*
29
 * Mapping of S_IF* types to NFS file types
30
 */
31
static u32      nfs3_ftypes[] = {
32
        NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
33
        NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
34
        NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
35
        NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
36
};
37
 
38
/*
39
 * XDR functions for basic NFS types
40
 */
41
static __be32 *
42
encode_time3(__be32 *p, struct timespec *time)
43
{
44
        *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
45
        return p;
46
}
47
 
48
static __be32 *
49
decode_time3(__be32 *p, struct timespec *time)
50
{
51
        time->tv_sec = ntohl(*p++);
52
        time->tv_nsec = ntohl(*p++);
53
        return p;
54
}
55
 
56
static __be32 *
57
decode_fh(__be32 *p, struct svc_fh *fhp)
58
{
59
        unsigned int size;
60
        fh_init(fhp, NFS3_FHSIZE);
61
        size = ntohl(*p++);
62
        if (size > NFS3_FHSIZE)
63
                return NULL;
64
 
65
        memcpy(&fhp->fh_handle.fh_base, p, size);
66
        fhp->fh_handle.fh_size = size;
67
        return p + XDR_QUADLEN(size);
68
}
69
 
70
/* Helper function for NFSv3 ACL code */
71
__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
72
{
73
        return decode_fh(p, fhp);
74
}
75
 
76
static __be32 *
77
encode_fh(__be32 *p, struct svc_fh *fhp)
78
{
79
        unsigned int size = fhp->fh_handle.fh_size;
80
        *p++ = htonl(size);
81
        if (size) p[XDR_QUADLEN(size)-1]=0;
82
        memcpy(p, &fhp->fh_handle.fh_base, size);
83
        return p + XDR_QUADLEN(size);
84
}
85
 
86
/*
87
 * Decode a file name and make sure that the path contains
88
 * no slashes or null bytes.
89
 */
90
static __be32 *
91
decode_filename(__be32 *p, char **namp, int *lenp)
92
{
93
        char            *name;
94
        int             i;
95
 
96
        if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
97
                for (i = 0, name = *namp; i < *lenp; i++, name++) {
98
                        if (*name == '\0' || *name == '/')
99
                                return NULL;
100
                }
101
        }
102
 
103
        return p;
104
}
105
 
106
static __be32 *
107
decode_sattr3(__be32 *p, struct iattr *iap)
108
{
109
        u32     tmp;
110
 
111
        iap->ia_valid = 0;
112
 
113
        if (*p++) {
114
                iap->ia_valid |= ATTR_MODE;
115
                iap->ia_mode = ntohl(*p++);
116
        }
117
        if (*p++) {
118
                iap->ia_valid |= ATTR_UID;
119
                iap->ia_uid = ntohl(*p++);
120
        }
121
        if (*p++) {
122
                iap->ia_valid |= ATTR_GID;
123
                iap->ia_gid = ntohl(*p++);
124
        }
125
        if (*p++) {
126
                u64     newsize;
127
 
128
                iap->ia_valid |= ATTR_SIZE;
129
                p = xdr_decode_hyper(p, &newsize);
130
                if (newsize <= NFS_OFFSET_MAX)
131
                        iap->ia_size = newsize;
132
                else
133
                        iap->ia_size = NFS_OFFSET_MAX;
134
        }
135
        if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
136
                iap->ia_valid |= ATTR_ATIME;
137
        } else if (tmp == 2) {          /* set to client time */
138
                iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
139
                iap->ia_atime.tv_sec = ntohl(*p++);
140
                iap->ia_atime.tv_nsec = ntohl(*p++);
141
        }
142
        if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
143
                iap->ia_valid |= ATTR_MTIME;
144
        } else if (tmp == 2) {          /* set to client time */
145
                iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
146
                iap->ia_mtime.tv_sec = ntohl(*p++);
147
                iap->ia_mtime.tv_nsec = ntohl(*p++);
148
        }
149
        return p;
150
}
151
 
152
static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
153
{
154
        u64 f;
155
        switch(fsid_source(fhp)) {
156
        default:
157
        case FSIDSOURCE_DEV:
158
                p = xdr_encode_hyper(p, (u64)huge_encode_dev
159
                                     (fhp->fh_dentry->d_inode->i_sb->s_dev));
160
                break;
161
        case FSIDSOURCE_FSID:
162
                p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
163
                break;
164
        case FSIDSOURCE_UUID:
165
                f = ((u64*)fhp->fh_export->ex_uuid)[0];
166
                f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
167
                p = xdr_encode_hyper(p, f);
168
                break;
169
        }
170
        return p;
171
}
172
 
173
static __be32 *
174
encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
175
              struct kstat *stat)
176
{
177
        *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
178
        *p++ = htonl((u32) stat->mode);
179
        *p++ = htonl((u32) stat->nlink);
180
        *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
181
        *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
182
        if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
183
                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
184
        } else {
185
                p = xdr_encode_hyper(p, (u64) stat->size);
186
        }
187
        p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
188
        *p++ = htonl((u32) MAJOR(stat->rdev));
189
        *p++ = htonl((u32) MINOR(stat->rdev));
190
        p = encode_fsid(p, fhp);
191
        p = xdr_encode_hyper(p, stat->ino);
192
        p = encode_time3(p, &stat->atime);
193
        p = encode_time3(p, &stat->mtime);
194
        p = encode_time3(p, &stat->ctime);
195
 
196
        return p;
197
}
198
 
199
static __be32 *
200
encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
201
{
202
        /* Attributes to follow */
203
        *p++ = xdr_one;
204
        return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
205
}
206
 
207
/*
208
 * Encode post-operation attributes.
209
 * The inode may be NULL if the call failed because of a stale file
210
 * handle. In this case, no attributes are returned.
211
 */
212
static __be32 *
213
encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
214
{
215
        struct dentry *dentry = fhp->fh_dentry;
216
        if (dentry && dentry->d_inode) {
217
                int err;
218
                struct kstat stat;
219
 
220
                err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
221
                if (!err) {
222
                        *p++ = xdr_one;         /* attributes follow */
223
                        lease_get_mtime(dentry->d_inode, &stat.mtime);
224
                        return encode_fattr3(rqstp, p, fhp, &stat);
225
                }
226
        }
227
        *p++ = xdr_zero;
228
        return p;
229
}
230
 
231
/* Helper for NFSv3 ACLs */
232
__be32 *
233
nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
234
{
235
        return encode_post_op_attr(rqstp, p, fhp);
236
}
237
 
238
/*
239
 * Enocde weak cache consistency data
240
 */
241
static __be32 *
242
encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
243
{
244
        struct dentry   *dentry = fhp->fh_dentry;
245
 
246
        if (dentry && dentry->d_inode && fhp->fh_post_saved) {
247
                if (fhp->fh_pre_saved) {
248
                        *p++ = xdr_one;
249
                        p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
250
                        p = encode_time3(p, &fhp->fh_pre_mtime);
251
                        p = encode_time3(p, &fhp->fh_pre_ctime);
252
                } else {
253
                        *p++ = xdr_zero;
254
                }
255
                return encode_saved_post_attr(rqstp, p, fhp);
256
        }
257
        /* no pre- or post-attrs */
258
        *p++ = xdr_zero;
259
        return encode_post_op_attr(rqstp, p, fhp);
260
}
261
 
262
/*
263
 * Fill in the post_op attr for the wcc data
264
 */
265
void fill_post_wcc(struct svc_fh *fhp)
266
{
267
        int err;
268
 
269
        if (fhp->fh_post_saved)
270
                printk("nfsd: inode locked twice during operation.\n");
271
 
272
        err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry,
273
                        &fhp->fh_post_attr);
274
        if (err)
275
                fhp->fh_post_saved = 0;
276
        else
277
                fhp->fh_post_saved = 1;
278
}
279
 
280
/*
281
 * XDR decode functions
282
 */
283
int
284
nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
285
{
286
        if (!(p = decode_fh(p, &args->fh)))
287
                return 0;
288
        return xdr_argsize_check(rqstp, p);
289
}
290
 
291
int
292
nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
293
                                        struct nfsd3_sattrargs *args)
294
{
295
        if (!(p = decode_fh(p, &args->fh)))
296
                return 0;
297
        p = decode_sattr3(p, &args->attrs);
298
 
299
        if ((args->check_guard = ntohl(*p++)) != 0) {
300
                struct timespec time;
301
                p = decode_time3(p, &time);
302
                args->guardtime = time.tv_sec;
303
        }
304
 
305
        return xdr_argsize_check(rqstp, p);
306
}
307
 
308
int
309
nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
310
                                        struct nfsd3_diropargs *args)
311
{
312
        if (!(p = decode_fh(p, &args->fh))
313
         || !(p = decode_filename(p, &args->name, &args->len)))
314
                return 0;
315
 
316
        return xdr_argsize_check(rqstp, p);
317
}
318
 
319
int
320
nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
321
                                        struct nfsd3_accessargs *args)
322
{
323
        if (!(p = decode_fh(p, &args->fh)))
324
                return 0;
325
        args->access = ntohl(*p++);
326
 
327
        return xdr_argsize_check(rqstp, p);
328
}
329
 
330
int
331
nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
332
                                        struct nfsd3_readargs *args)
333
{
334
        unsigned int len;
335
        int v,pn;
336
        u32 max_blocksize = svc_max_payload(rqstp);
337
 
338
        if (!(p = decode_fh(p, &args->fh)))
339
                return 0;
340
        p = xdr_decode_hyper(p, &args->offset);
341
 
342
        len = args->count = ntohl(*p++);
343
 
344
        if (len > max_blocksize)
345
                len = max_blocksize;
346
 
347
        /* set up the kvec */
348
        v=0;
349
        while (len > 0) {
350
                pn = rqstp->rq_resused++;
351
                rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
352
                rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
353
                len -= rqstp->rq_vec[v].iov_len;
354
                v++;
355
        }
356
        args->vlen = v;
357
        return xdr_argsize_check(rqstp, p);
358
}
359
 
360
int
361
nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
362
                                        struct nfsd3_writeargs *args)
363
{
364
        unsigned int len, v, hdr, dlen;
365
        u32 max_blocksize = svc_max_payload(rqstp);
366
 
367
        if (!(p = decode_fh(p, &args->fh)))
368
                return 0;
369
        p = xdr_decode_hyper(p, &args->offset);
370
 
371
        args->count = ntohl(*p++);
372
        args->stable = ntohl(*p++);
373
        len = args->len = ntohl(*p++);
374
        /*
375
         * The count must equal the amount of data passed.
376
         */
377
        if (args->count != args->len)
378
                return 0;
379
 
380
        /*
381
         * Check to make sure that we got the right number of
382
         * bytes.
383
         */
384
        hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
385
        dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
386
                - hdr;
387
        /*
388
         * Round the length of the data which was specified up to
389
         * the next multiple of XDR units and then compare that
390
         * against the length which was actually received.
391
         * Note that when RPCSEC/GSS (for example) is used, the
392
         * data buffer can be padded so dlen might be larger
393
         * than required.  It must never be smaller.
394
         */
395
        if (dlen < XDR_QUADLEN(len)*4)
396
                return 0;
397
 
398
        if (args->count > max_blocksize) {
399
                args->count = max_blocksize;
400
                len = args->len = max_blocksize;
401
        }
402
        rqstp->rq_vec[0].iov_base = (void*)p;
403
        rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
404
        v = 0;
405
        while (len > rqstp->rq_vec[v].iov_len) {
406
                len -= rqstp->rq_vec[v].iov_len;
407
                v++;
408
                rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
409
                rqstp->rq_vec[v].iov_len = PAGE_SIZE;
410
        }
411
        rqstp->rq_vec[v].iov_len = len;
412
        args->vlen = v + 1;
413
        return 1;
414
}
415
 
416
int
417
nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
418
                                        struct nfsd3_createargs *args)
419
{
420
        if (!(p = decode_fh(p, &args->fh))
421
         || !(p = decode_filename(p, &args->name, &args->len)))
422
                return 0;
423
 
424
        switch (args->createmode = ntohl(*p++)) {
425
        case NFS3_CREATE_UNCHECKED:
426
        case NFS3_CREATE_GUARDED:
427
                p = decode_sattr3(p, &args->attrs);
428
                break;
429
        case NFS3_CREATE_EXCLUSIVE:
430
                args->verf = p;
431
                p += 2;
432
                break;
433
        default:
434
                return 0;
435
        }
436
 
437
        return xdr_argsize_check(rqstp, p);
438
}
439
int
440
nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
441
                                        struct nfsd3_createargs *args)
442
{
443
        if (!(p = decode_fh(p, &args->fh)) ||
444
            !(p = decode_filename(p, &args->name, &args->len)))
445
                return 0;
446
        p = decode_sattr3(p, &args->attrs);
447
 
448
        return xdr_argsize_check(rqstp, p);
449
}
450
 
451
int
452
nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
453
                                        struct nfsd3_symlinkargs *args)
454
{
455
        unsigned int len;
456
        int avail;
457
        char *old, *new;
458
        struct kvec *vec;
459
 
460
        if (!(p = decode_fh(p, &args->ffh)) ||
461
            !(p = decode_filename(p, &args->fname, &args->flen))
462
                )
463
                return 0;
464
        p = decode_sattr3(p, &args->attrs);
465
 
466
        /* now decode the pathname, which might be larger than the first page.
467
         * As we have to check for nul's anyway, we copy it into a new page
468
         * This page appears in the rq_res.pages list, but as pages_len is always
469
         * 0, it won't get in the way
470
         */
471
        len = ntohl(*p++);
472
        if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
473
                return 0;
474
        args->tname = new =
475
                page_address(rqstp->rq_respages[rqstp->rq_resused++]);
476
        args->tlen = len;
477
        /* first copy and check from the first page */
478
        old = (char*)p;
479
        vec = &rqstp->rq_arg.head[0];
480
        avail = vec->iov_len - (old - (char*)vec->iov_base);
481
        while (len && avail && *old) {
482
                *new++ = *old++;
483
                len--;
484
                avail--;
485
        }
486
        /* now copy next page if there is one */
487
        if (len && !avail && rqstp->rq_arg.page_len) {
488
                avail = rqstp->rq_arg.page_len;
489
                if (avail > PAGE_SIZE) avail = PAGE_SIZE;
490
                old = page_address(rqstp->rq_arg.pages[0]);
491
        }
492
        while (len && avail && *old) {
493
                *new++ = *old++;
494
                len--;
495
                avail--;
496
        }
497
        *new = '\0';
498
        if (len)
499
                return 0;
500
 
501
        return 1;
502
}
503
 
504
int
505
nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
506
                                        struct nfsd3_mknodargs *args)
507
{
508
        if (!(p = decode_fh(p, &args->fh))
509
         || !(p = decode_filename(p, &args->name, &args->len)))
510
                return 0;
511
 
512
        args->ftype = ntohl(*p++);
513
 
514
        if (args->ftype == NF3BLK  || args->ftype == NF3CHR
515
         || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
516
                p = decode_sattr3(p, &args->attrs);
517
 
518
        if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
519
                args->major = ntohl(*p++);
520
                args->minor = ntohl(*p++);
521
        }
522
 
523
        return xdr_argsize_check(rqstp, p);
524
}
525
 
526
int
527
nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
528
                                        struct nfsd3_renameargs *args)
529
{
530
        if (!(p = decode_fh(p, &args->ffh))
531
         || !(p = decode_filename(p, &args->fname, &args->flen))
532
         || !(p = decode_fh(p, &args->tfh))
533
         || !(p = decode_filename(p, &args->tname, &args->tlen)))
534
                return 0;
535
 
536
        return xdr_argsize_check(rqstp, p);
537
}
538
 
539
int
540
nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
541
                                        struct nfsd3_readlinkargs *args)
542
{
543
        if (!(p = decode_fh(p, &args->fh)))
544
                return 0;
545
        args->buffer =
546
                page_address(rqstp->rq_respages[rqstp->rq_resused++]);
547
 
548
        return xdr_argsize_check(rqstp, p);
549
}
550
 
551
int
552
nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
553
                                        struct nfsd3_linkargs *args)
554
{
555
        if (!(p = decode_fh(p, &args->ffh))
556
         || !(p = decode_fh(p, &args->tfh))
557
         || !(p = decode_filename(p, &args->tname, &args->tlen)))
558
                return 0;
559
 
560
        return xdr_argsize_check(rqstp, p);
561
}
562
 
563
int
564
nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
565
                                        struct nfsd3_readdirargs *args)
566
{
567
        if (!(p = decode_fh(p, &args->fh)))
568
                return 0;
569
        p = xdr_decode_hyper(p, &args->cookie);
570
        args->verf   = p; p += 2;
571
        args->dircount = ~0;
572
        args->count  = ntohl(*p++);
573
 
574
        if (args->count > PAGE_SIZE)
575
                args->count = PAGE_SIZE;
576
 
577
        args->buffer =
578
                page_address(rqstp->rq_respages[rqstp->rq_resused++]);
579
 
580
        return xdr_argsize_check(rqstp, p);
581
}
582
 
583
int
584
nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
585
                                        struct nfsd3_readdirargs *args)
586
{
587
        int len, pn;
588
        u32 max_blocksize = svc_max_payload(rqstp);
589
 
590
        if (!(p = decode_fh(p, &args->fh)))
591
                return 0;
592
        p = xdr_decode_hyper(p, &args->cookie);
593
        args->verf     = p; p += 2;
594
        args->dircount = ntohl(*p++);
595
        args->count    = ntohl(*p++);
596
 
597
        len = (args->count > max_blocksize) ? max_blocksize :
598
                                                  args->count;
599
        args->count = len;
600
 
601
        while (len > 0) {
602
                pn = rqstp->rq_resused++;
603
                if (!args->buffer)
604
                        args->buffer = page_address(rqstp->rq_respages[pn]);
605
                len -= PAGE_SIZE;
606
        }
607
 
608
        return xdr_argsize_check(rqstp, p);
609
}
610
 
611
int
612
nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
613
                                        struct nfsd3_commitargs *args)
614
{
615
        if (!(p = decode_fh(p, &args->fh)))
616
                return 0;
617
        p = xdr_decode_hyper(p, &args->offset);
618
        args->count = ntohl(*p++);
619
 
620
        return xdr_argsize_check(rqstp, p);
621
}
622
 
623
/*
624
 * XDR encode functions
625
 */
626
/*
627
 * There must be an encoding function for void results so svc_process
628
 * will work properly.
629
 */
630
int
631
nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
632
{
633
        return xdr_ressize_check(rqstp, p);
634
}
635
 
636
/* GETATTR */
637
int
638
nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
639
                                        struct nfsd3_attrstat *resp)
640
{
641
        if (resp->status == 0) {
642
                lease_get_mtime(resp->fh.fh_dentry->d_inode,
643
                                &resp->stat.mtime);
644
                p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
645
        }
646
        return xdr_ressize_check(rqstp, p);
647
}
648
 
649
/* SETATTR, REMOVE, RMDIR */
650
int
651
nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
652
                                        struct nfsd3_attrstat *resp)
653
{
654
        p = encode_wcc_data(rqstp, p, &resp->fh);
655
        return xdr_ressize_check(rqstp, p);
656
}
657
 
658
/* LOOKUP */
659
int
660
nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
661
                                        struct nfsd3_diropres *resp)
662
{
663
        if (resp->status == 0) {
664
                p = encode_fh(p, &resp->fh);
665
                p = encode_post_op_attr(rqstp, p, &resp->fh);
666
        }
667
        p = encode_post_op_attr(rqstp, p, &resp->dirfh);
668
        return xdr_ressize_check(rqstp, p);
669
}
670
 
671
/* ACCESS */
672
int
673
nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
674
                                        struct nfsd3_accessres *resp)
675
{
676
        p = encode_post_op_attr(rqstp, p, &resp->fh);
677
        if (resp->status == 0)
678
                *p++ = htonl(resp->access);
679
        return xdr_ressize_check(rqstp, p);
680
}
681
 
682
/* READLINK */
683
int
684
nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
685
                                        struct nfsd3_readlinkres *resp)
686
{
687
        p = encode_post_op_attr(rqstp, p, &resp->fh);
688
        if (resp->status == 0) {
689
                *p++ = htonl(resp->len);
690
                xdr_ressize_check(rqstp, p);
691
                rqstp->rq_res.page_len = resp->len;
692
                if (resp->len & 3) {
693
                        /* need to pad the tail */
694
                        rqstp->rq_res.tail[0].iov_base = p;
695
                        *p = 0;
696
                        rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
697
                }
698
                return 1;
699
        } else
700
                return xdr_ressize_check(rqstp, p);
701
}
702
 
703
/* READ */
704
int
705
nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
706
                                        struct nfsd3_readres *resp)
707
{
708
        p = encode_post_op_attr(rqstp, p, &resp->fh);
709
        if (resp->status == 0) {
710
                *p++ = htonl(resp->count);
711
                *p++ = htonl(resp->eof);
712
                *p++ = htonl(resp->count);      /* xdr opaque count */
713
                xdr_ressize_check(rqstp, p);
714
                /* now update rqstp->rq_res to reflect data aswell */
715
                rqstp->rq_res.page_len = resp->count;
716
                if (resp->count & 3) {
717
                        /* need to pad the tail */
718
                        rqstp->rq_res.tail[0].iov_base = p;
719
                        *p = 0;
720
                        rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
721
                }
722
                return 1;
723
        } else
724
                return xdr_ressize_check(rqstp, p);
725
}
726
 
727
/* WRITE */
728
int
729
nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
730
                                        struct nfsd3_writeres *resp)
731
{
732
        p = encode_wcc_data(rqstp, p, &resp->fh);
733
        if (resp->status == 0) {
734
                *p++ = htonl(resp->count);
735
                *p++ = htonl(resp->committed);
736
                *p++ = htonl(nfssvc_boot.tv_sec);
737
                *p++ = htonl(nfssvc_boot.tv_usec);
738
        }
739
        return xdr_ressize_check(rqstp, p);
740
}
741
 
742
/* CREATE, MKDIR, SYMLINK, MKNOD */
743
int
744
nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
745
                                        struct nfsd3_diropres *resp)
746
{
747
        if (resp->status == 0) {
748
                *p++ = xdr_one;
749
                p = encode_fh(p, &resp->fh);
750
                p = encode_post_op_attr(rqstp, p, &resp->fh);
751
        }
752
        p = encode_wcc_data(rqstp, p, &resp->dirfh);
753
        return xdr_ressize_check(rqstp, p);
754
}
755
 
756
/* RENAME */
757
int
758
nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
759
                                        struct nfsd3_renameres *resp)
760
{
761
        p = encode_wcc_data(rqstp, p, &resp->ffh);
762
        p = encode_wcc_data(rqstp, p, &resp->tfh);
763
        return xdr_ressize_check(rqstp, p);
764
}
765
 
766
/* LINK */
767
int
768
nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
769
                                        struct nfsd3_linkres *resp)
770
{
771
        p = encode_post_op_attr(rqstp, p, &resp->fh);
772
        p = encode_wcc_data(rqstp, p, &resp->tfh);
773
        return xdr_ressize_check(rqstp, p);
774
}
775
 
776
/* READDIR */
777
int
778
nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
779
                                        struct nfsd3_readdirres *resp)
780
{
781
        p = encode_post_op_attr(rqstp, p, &resp->fh);
782
 
783
        if (resp->status == 0) {
784
                /* stupid readdir cookie */
785
                memcpy(p, resp->verf, 8); p += 2;
786
                xdr_ressize_check(rqstp, p);
787
                if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
788
                        return 1; /*No room for trailer */
789
                rqstp->rq_res.page_len = (resp->count) << 2;
790
 
791
                /* add the 'tail' to the end of the 'head' page - page 0. */
792
                rqstp->rq_res.tail[0].iov_base = p;
793
                *p++ = 0;                /* no more entries */
794
                *p++ = htonl(resp->common.err == nfserr_eof);
795
                rqstp->rq_res.tail[0].iov_len = 2<<2;
796
                return 1;
797
        } else
798
                return xdr_ressize_check(rqstp, p);
799
}
800
 
801
static __be32 *
802
encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
803
             int namlen, u64 ino)
804
{
805
        *p++ = xdr_one;                          /* mark entry present */
806
        p    = xdr_encode_hyper(p, ino);         /* file id */
807
        p    = xdr_encode_array(p, name, namlen);/* name length & name */
808
 
809
        cd->offset = p;                         /* remember pointer */
810
        p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
811
 
812
        return p;
813
}
814
 
815
static __be32 *
816
encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
817
                struct svc_fh *fhp)
818
{
819
                p = encode_post_op_attr(cd->rqstp, p, fhp);
820
                *p++ = xdr_one;                 /* yes, a file handle follows */
821
                p = encode_fh(p, fhp);
822
                fh_put(fhp);
823
                return p;
824
}
825
 
826
static int
827
compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
828
                const char *name, int namlen)
829
{
830
        struct svc_export       *exp;
831
        struct dentry           *dparent, *dchild;
832
        int rv = 0;
833
 
834
        dparent = cd->fh.fh_dentry;
835
        exp  = cd->fh.fh_export;
836
 
837
        fh_init(fhp, NFS3_FHSIZE);
838
        if (isdotent(name, namlen)) {
839
                if (namlen == 2) {
840
                        dchild = dget_parent(dparent);
841
                        if (dchild == dparent) {
842
                                /* filesystem root - cannot return filehandle for ".." */
843
                                dput(dchild);
844
                                return 1;
845
                        }
846
                } else
847
                        dchild = dget(dparent);
848
        } else
849
                dchild = lookup_one_len(name, dparent, namlen);
850
        if (IS_ERR(dchild))
851
                return 1;
852
        if (d_mountpoint(dchild) ||
853
            fh_compose(fhp, exp, dchild, &cd->fh) != 0 ||
854
            !dchild->d_inode)
855
                rv = 1;
856
        dput(dchild);
857
        return rv;
858
}
859
 
860
/*
861
 * Encode a directory entry. This one works for both normal readdir
862
 * and readdirplus.
863
 * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
864
 * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
865
 *
866
 * The readdirplus baggage is 1+21 words for post_op_attr, plus the
867
 * file handle.
868
 */
869
 
870
#define NFS3_ENTRY_BAGGAGE      (2 + 1 + 2 + 1)
871
#define NFS3_ENTRYPLUS_BAGGAGE  (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
872
static int
873
encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
874
             loff_t offset, u64 ino, unsigned int d_type, int plus)
875
{
876
        struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
877
                                                        common);
878
        __be32          *p = cd->buffer;
879
        caddr_t         curr_page_addr = NULL;
880
        int             pn;             /* current page number */
881
        int             slen;           /* string (name) length */
882
        int             elen;           /* estimated entry length in words */
883
        int             num_entry_words = 0;     /* actual number of words */
884
 
885
        if (cd->offset) {
886
                u64 offset64 = offset;
887
 
888
                if (unlikely(cd->offset1)) {
889
                        /* we ended up with offset on a page boundary */
890
                        *cd->offset = htonl(offset64 >> 32);
891
                        *cd->offset1 = htonl(offset64 & 0xffffffff);
892
                        cd->offset1 = NULL;
893
                } else {
894
                        xdr_encode_hyper(cd->offset, offset64);
895
                }
896
        }
897
 
898
        /*
899
        dprintk("encode_entry(%.*s @%ld%s)\n",
900
                namlen, name, (long) offset, plus? " plus" : "");
901
         */
902
 
903
        /* truncate filename if too long */
904
        if (namlen > NFS3_MAXNAMLEN)
905
                namlen = NFS3_MAXNAMLEN;
906
 
907
        slen = XDR_QUADLEN(namlen);
908
        elen = slen + NFS3_ENTRY_BAGGAGE
909
                + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
910
 
911
        if (cd->buflen < elen) {
912
                cd->common.err = nfserr_toosmall;
913
                return -EINVAL;
914
        }
915
 
916
        /* determine which page in rq_respages[] we are currently filling */
917
        for (pn=1; pn < cd->rqstp->rq_resused; pn++) {
918
                curr_page_addr = page_address(cd->rqstp->rq_respages[pn]);
919
 
920
                if (((caddr_t)cd->buffer >= curr_page_addr) &&
921
                    ((caddr_t)cd->buffer <  curr_page_addr + PAGE_SIZE))
922
                        break;
923
        }
924
 
925
        if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
926
                /* encode entry in current page */
927
 
928
                p = encode_entry_baggage(cd, p, name, namlen, ino);
929
 
930
                /* throw in readdirplus baggage */
931
                if (plus) {
932
                        struct svc_fh   fh;
933
 
934
                        if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
935
                                *p++ = 0;
936
                                *p++ = 0;
937
                        } else
938
                                p = encode_entryplus_baggage(cd, p, &fh);
939
                }
940
                num_entry_words = p - cd->buffer;
941
        } else if (cd->rqstp->rq_respages[pn+1] != NULL) {
942
                /* temporarily encode entry into next page, then move back to
943
                 * current and next page in rq_respages[] */
944
                __be32 *p1, *tmp;
945
                int len1, len2;
946
 
947
                /* grab next page for temporary storage of entry */
948
                p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]);
949
 
950
                p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
951
 
952
                /* throw in readdirplus baggage */
953
                if (plus) {
954
                        struct svc_fh   fh;
955
 
956
                        if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
957
                                /* zero out the filehandle */
958
                                *p1++ = 0;
959
                                *p1++ = 0;
960
                        } else
961
                                p1 = encode_entryplus_baggage(cd, p1, &fh);
962
                }
963
 
964
                /* determine entry word length and lengths to go in pages */
965
                num_entry_words = p1 - tmp;
966
                len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
967
                if ((num_entry_words << 2) < len1) {
968
                        /* the actual number of words in the entry is less
969
                         * than elen and can still fit in the current page
970
                         */
971
                        memmove(p, tmp, num_entry_words << 2);
972
                        p += num_entry_words;
973
 
974
                        /* update offset */
975
                        cd->offset = cd->buffer + (cd->offset - tmp);
976
                } else {
977
                        unsigned int offset_r = (cd->offset - tmp) << 2;
978
 
979
                        /* update pointer to offset location.
980
                         * This is a 64bit quantity, so we need to
981
                         * deal with 3 cases:
982
                         *  -   entirely in first page
983
                         *  -   entirely in second page
984
                         *  -   4 bytes in each page
985
                         */
986
                        if (offset_r + 8 <= len1) {
987
                                cd->offset = p + (cd->offset - tmp);
988
                        } else if (offset_r >= len1) {
989
                                cd->offset -= len1 >> 2;
990
                        } else {
991
                                /* sitting on the fence */
992
                                BUG_ON(offset_r != len1 - 4);
993
                                cd->offset = p + (cd->offset - tmp);
994
                                cd->offset1 = tmp;
995
                        }
996
 
997
                        len2 = (num_entry_words << 2) - len1;
998
 
999
                        /* move from temp page to current and next pages */
1000
                        memmove(p, tmp, len1);
1001
                        memmove(tmp, (caddr_t)tmp+len1, len2);
1002
 
1003
                        p = tmp + (len2 >> 2);
1004
                }
1005
        }
1006
        else {
1007
                cd->common.err = nfserr_toosmall;
1008
                return -EINVAL;
1009
        }
1010
 
1011
        cd->buflen -= num_entry_words;
1012
        cd->buffer = p;
1013
        cd->common.err = nfs_ok;
1014
        return 0;
1015
 
1016
}
1017
 
1018
int
1019
nfs3svc_encode_entry(void *cd, const char *name,
1020
                     int namlen, loff_t offset, u64 ino, unsigned int d_type)
1021
{
1022
        return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
1023
}
1024
 
1025
int
1026
nfs3svc_encode_entry_plus(void *cd, const char *name,
1027
                          int namlen, loff_t offset, u64 ino,
1028
                          unsigned int d_type)
1029
{
1030
        return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
1031
}
1032
 
1033
/* FSSTAT */
1034
int
1035
nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
1036
                                        struct nfsd3_fsstatres *resp)
1037
{
1038
        struct kstatfs  *s = &resp->stats;
1039
        u64             bs = s->f_bsize;
1040
 
1041
        *p++ = xdr_zero;        /* no post_op_attr */
1042
 
1043
        if (resp->status == 0) {
1044
                p = xdr_encode_hyper(p, bs * s->f_blocks);      /* total bytes */
1045
                p = xdr_encode_hyper(p, bs * s->f_bfree);       /* free bytes */
1046
                p = xdr_encode_hyper(p, bs * s->f_bavail);      /* user available bytes */
1047
                p = xdr_encode_hyper(p, s->f_files);    /* total inodes */
1048
                p = xdr_encode_hyper(p, s->f_ffree);    /* free inodes */
1049
                p = xdr_encode_hyper(p, s->f_ffree);    /* user available inodes */
1050
                *p++ = htonl(resp->invarsec);   /* mean unchanged time */
1051
        }
1052
        return xdr_ressize_check(rqstp, p);
1053
}
1054
 
1055
/* FSINFO */
1056
int
1057
nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
1058
                                        struct nfsd3_fsinfores *resp)
1059
{
1060
        *p++ = xdr_zero;        /* no post_op_attr */
1061
 
1062
        if (resp->status == 0) {
1063
                *p++ = htonl(resp->f_rtmax);
1064
                *p++ = htonl(resp->f_rtpref);
1065
                *p++ = htonl(resp->f_rtmult);
1066
                *p++ = htonl(resp->f_wtmax);
1067
                *p++ = htonl(resp->f_wtpref);
1068
                *p++ = htonl(resp->f_wtmult);
1069
                *p++ = htonl(resp->f_dtpref);
1070
                p = xdr_encode_hyper(p, resp->f_maxfilesize);
1071
                *p++ = xdr_one;
1072
                *p++ = xdr_zero;
1073
                *p++ = htonl(resp->f_properties);
1074
        }
1075
 
1076
        return xdr_ressize_check(rqstp, p);
1077
}
1078
 
1079
/* PATHCONF */
1080
int
1081
nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
1082
                                        struct nfsd3_pathconfres *resp)
1083
{
1084
        *p++ = xdr_zero;        /* no post_op_attr */
1085
 
1086
        if (resp->status == 0) {
1087
                *p++ = htonl(resp->p_link_max);
1088
                *p++ = htonl(resp->p_name_max);
1089
                *p++ = htonl(resp->p_no_trunc);
1090
                *p++ = htonl(resp->p_chown_restricted);
1091
                *p++ = htonl(resp->p_case_insensitive);
1092
                *p++ = htonl(resp->p_case_preserving);
1093
        }
1094
 
1095
        return xdr_ressize_check(rqstp, p);
1096
}
1097
 
1098
/* COMMIT */
1099
int
1100
nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
1101
                                        struct nfsd3_commitres *resp)
1102
{
1103
        p = encode_wcc_data(rqstp, p, &resp->fh);
1104
        /* Write verifier */
1105
        if (resp->status == 0) {
1106
                *p++ = htonl(nfssvc_boot.tv_sec);
1107
                *p++ = htonl(nfssvc_boot.tv_usec);
1108
        }
1109
        return xdr_ressize_check(rqstp, p);
1110
}
1111
 
1112
/*
1113
 * XDR release functions
1114
 */
1115
int
1116
nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
1117
                                        struct nfsd3_attrstat *resp)
1118
{
1119
        fh_put(&resp->fh);
1120
        return 1;
1121
}
1122
 
1123
int
1124
nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p,
1125
                                        struct nfsd3_fhandle_pair *resp)
1126
{
1127
        fh_put(&resp->fh1);
1128
        fh_put(&resp->fh2);
1129
        return 1;
1130
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.