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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [nfsd/] [nfs4xdr.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  fs/nfs/nfs4xdr.c
3
 *
4
 *  Server-side XDR for NFSv4
5
 *
6
 *  Copyright (c) 2002 The Regents of the University of Michigan.
7
 *  All rights reserved.
8
 *
9
 *  Kendrick Smith <kmsmith@umich.edu>
10
 *  Andy Adamson   <andros@umich.edu>
11
 *
12
 *  Redistribution and use in source and binary forms, with or without
13
 *  modification, are permitted provided that the following conditions
14
 *  are met:
15
 *
16
 *  1. Redistributions of source code must retain the above copyright
17
 *     notice, this list of conditions and the following disclaimer.
18
 *  2. Redistributions in binary form must reproduce the above copyright
19
 *     notice, this list of conditions and the following disclaimer in the
20
 *     documentation and/or other materials provided with the distribution.
21
 *  3. Neither the name of the University nor the names of its
22
 *     contributors may be used to endorse or promote products derived
23
 *     from this software without specific prior written permission.
24
 *
25
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 *
37
 * TODO: Neil Brown made the following observation:  We currently
38
 * initially reserve NFSD_BUFSIZE space on the transmit queue and
39
 * never release any of that until the request is complete.
40
 * It would be good to calculate a new maximum response size while
41
 * decoding the COMPOUND, and call svc_reserve with this number
42
 * at the end of nfs4svc_decode_compoundargs.
43
 */
44
 
45
#include <linux/param.h>
46
#include <linux/smp.h>
47
#include <linux/fs.h>
48
#include <linux/namei.h>
49
#include <linux/vfs.h>
50
#include <linux/sunrpc/xdr.h>
51
#include <linux/sunrpc/svc.h>
52
#include <linux/sunrpc/clnt.h>
53
#include <linux/nfsd/nfsd.h>
54
#include <linux/nfsd/state.h>
55
#include <linux/nfsd/xdr4.h>
56
#include <linux/nfsd_idmap.h>
57
#include <linux/nfs4.h>
58
#include <linux/nfs4_acl.h>
59
#include <linux/sunrpc/gss_api.h>
60
#include <linux/sunrpc/svcauth_gss.h>
61
 
62
#define NFSDDBG_FACILITY                NFSDDBG_XDR
63
 
64
/*
65
 * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
66
 * directory in order to indicate to the client that a filesystem boundary is present
67
 * We use a fixed fsid for a referral
68
 */
69
#define NFS4_REFERRAL_FSID_MAJOR        0x8000000ULL
70
#define NFS4_REFERRAL_FSID_MINOR        0x8000000ULL
71
 
72
static __be32
73
check_filename(char *str, int len, __be32 err)
74
{
75
        int i;
76
 
77
        if (len == 0)
78
                return nfserr_inval;
79
        if (isdotent(str, len))
80
                return err;
81
        for (i = 0; i < len; i++)
82
                if (str[i] == '/')
83
                        return err;
84
        return 0;
85
}
86
 
87
/*
88
 * START OF "GENERIC" DECODE ROUTINES.
89
 *   These may look a little ugly since they are imported from a "generic"
90
 * set of XDR encode/decode routines which are intended to be shared by
91
 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
92
 *
93
 * If the pain of reading these is too great, it should be a straightforward
94
 * task to translate them into Linux-specific versions which are more
95
 * consistent with the style used in NFSv2/v3...
96
 */
97
#define DECODE_HEAD                             \
98
        __be32 *p;                              \
99
        __be32 status
100
#define DECODE_TAIL                             \
101
        status = 0;                              \
102
out:                                            \
103
        return status;                          \
104
xdr_error:                                      \
105
        dprintk("NFSD: xdr error (%s:%d)\n",    \
106
                        __FILE__, __LINE__);    \
107
        status = nfserr_bad_xdr;                \
108
        goto out
109
 
110
#define READ32(x)         (x) = ntohl(*p++)
111
#define READ64(x)         do {                  \
112
        (x) = (u64)ntohl(*p++) << 32;           \
113
        (x) |= ntohl(*p++);                     \
114
} while (0)
115
#define READTIME(x)       do {                  \
116
        p++;                                    \
117
        (x) = ntohl(*p++);                      \
118
        p++;                                    \
119
} while (0)
120
#define READMEM(x,nbytes) do {                  \
121
        x = (char *)p;                          \
122
        p += XDR_QUADLEN(nbytes);               \
123
} while (0)
124
#define SAVEMEM(x,nbytes) do {                  \
125
        if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
126
                savemem(argp, p, nbytes) :      \
127
                (char *)p)) {                   \
128
                dprintk("NFSD: xdr error (%s:%d)\n", \
129
                                __FILE__, __LINE__); \
130
                goto xdr_error;                 \
131
                }                               \
132
        p += XDR_QUADLEN(nbytes);               \
133
} while (0)
134
#define COPYMEM(x,nbytes) do {                  \
135
        memcpy((x), p, nbytes);                 \
136
        p += XDR_QUADLEN(nbytes);               \
137
} while (0)
138
 
139
/* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */
140
#define READ_BUF(nbytes)  do {                  \
141
        if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) {     \
142
                p = argp->p;                    \
143
                argp->p += XDR_QUADLEN(nbytes); \
144
        } else if (!(p = read_buf(argp, nbytes))) { \
145
                dprintk("NFSD: xdr error (%s:%d)\n", \
146
                                __FILE__, __LINE__); \
147
                goto xdr_error;                 \
148
        }                                       \
149
} while (0)
150
 
151
static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
152
{
153
        /* We want more bytes than seem to be available.
154
         * Maybe we need a new page, maybe we have just run out
155
         */
156
        int avail = (char*)argp->end - (char*)argp->p;
157
        __be32 *p;
158
        if (avail + argp->pagelen < nbytes)
159
                return NULL;
160
        if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
161
                return NULL;
162
        /* ok, we can do it with the current plus the next page */
163
        if (nbytes <= sizeof(argp->tmp))
164
                p = argp->tmp;
165
        else {
166
                kfree(argp->tmpp);
167
                p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL);
168
                if (!p)
169
                        return NULL;
170
 
171
        }
172
        memcpy(p, argp->p, avail);
173
        /* step to next page */
174
        argp->p = page_address(argp->pagelist[0]);
175
        argp->pagelist++;
176
        if (argp->pagelen < PAGE_SIZE) {
177
                argp->end = p + (argp->pagelen>>2);
178
                argp->pagelen = 0;
179
        } else {
180
                argp->end = p + (PAGE_SIZE>>2);
181
                argp->pagelen -= PAGE_SIZE;
182
        }
183
        memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
184
        argp->p += XDR_QUADLEN(nbytes - avail);
185
        return p;
186
}
187
 
188
static int
189
defer_free(struct nfsd4_compoundargs *argp,
190
                void (*release)(const void *), void *p)
191
{
192
        struct tmpbuf *tb;
193
 
194
        tb = kmalloc(sizeof(*tb), GFP_KERNEL);
195
        if (!tb)
196
                return -ENOMEM;
197
        tb->buf = p;
198
        tb->release = release;
199
        tb->next = argp->to_free;
200
        argp->to_free = tb;
201
        return 0;
202
}
203
 
204
static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
205
{
206
        if (p == argp->tmp) {
207
                p = kmalloc(nbytes, GFP_KERNEL);
208
                if (!p)
209
                        return NULL;
210
                memcpy(p, argp->tmp, nbytes);
211
        } else {
212
                BUG_ON(p != argp->tmpp);
213
                argp->tmpp = NULL;
214
        }
215
        if (defer_free(argp, kfree, p)) {
216
                kfree(p);
217
                return NULL;
218
        } else
219
                return (char *)p;
220
}
221
 
222
static __be32
223
nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
224
{
225
        u32 bmlen;
226
        DECODE_HEAD;
227
 
228
        bmval[0] = 0;
229
        bmval[1] = 0;
230
 
231
        READ_BUF(4);
232
        READ32(bmlen);
233
        if (bmlen > 1000)
234
                goto xdr_error;
235
 
236
        READ_BUF(bmlen << 2);
237
        if (bmlen > 0)
238
                READ32(bmval[0]);
239
        if (bmlen > 1)
240
                READ32(bmval[1]);
241
 
242
        DECODE_TAIL;
243
}
244
 
245
static __be32
246
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
247
    struct nfs4_acl **acl)
248
{
249
        int expected_len, len = 0;
250
        u32 dummy32;
251
        char *buf;
252
        int host_err;
253
 
254
        DECODE_HEAD;
255
        iattr->ia_valid = 0;
256
        if ((status = nfsd4_decode_bitmap(argp, bmval)))
257
                return status;
258
 
259
        /*
260
         * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;
261
         * read-only attributes return ERR_INVAL.
262
         */
263
        if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
264
                return nfserr_attrnotsupp;
265
        if ((bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0) || (bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1))
266
                return nfserr_inval;
267
 
268
        READ_BUF(4);
269
        READ32(expected_len);
270
 
271
        if (bmval[0] & FATTR4_WORD0_SIZE) {
272
                READ_BUF(8);
273
                len += 8;
274
                READ64(iattr->ia_size);
275
                iattr->ia_valid |= ATTR_SIZE;
276
        }
277
        if (bmval[0] & FATTR4_WORD0_ACL) {
278
                int nace;
279
                struct nfs4_ace *ace;
280
 
281
                READ_BUF(4); len += 4;
282
                READ32(nace);
283
 
284
                if (nace > NFS4_ACL_MAX)
285
                        return nfserr_resource;
286
 
287
                *acl = nfs4_acl_new(nace);
288
                if (*acl == NULL) {
289
                        host_err = -ENOMEM;
290
                        goto out_nfserr;
291
                }
292
                defer_free(argp, kfree, *acl);
293
 
294
                (*acl)->naces = nace;
295
                for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
296
                        READ_BUF(16); len += 16;
297
                        READ32(ace->type);
298
                        READ32(ace->flag);
299
                        READ32(ace->access_mask);
300
                        READ32(dummy32);
301
                        READ_BUF(dummy32);
302
                        len += XDR_QUADLEN(dummy32) << 2;
303
                        READMEM(buf, dummy32);
304
                        ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
305
                        host_err = 0;
306
                        if (ace->whotype != NFS4_ACL_WHO_NAMED)
307
                                ace->who = 0;
308
                        else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
309
                                host_err = nfsd_map_name_to_gid(argp->rqstp,
310
                                                buf, dummy32, &ace->who);
311
                        else
312
                                host_err = nfsd_map_name_to_uid(argp->rqstp,
313
                                                buf, dummy32, &ace->who);
314
                        if (host_err)
315
                                goto out_nfserr;
316
                }
317
        } else
318
                *acl = NULL;
319
        if (bmval[1] & FATTR4_WORD1_MODE) {
320
                READ_BUF(4);
321
                len += 4;
322
                READ32(iattr->ia_mode);
323
                iattr->ia_mode &= (S_IFMT | S_IALLUGO);
324
                iattr->ia_valid |= ATTR_MODE;
325
        }
326
        if (bmval[1] & FATTR4_WORD1_OWNER) {
327
                READ_BUF(4);
328
                len += 4;
329
                READ32(dummy32);
330
                READ_BUF(dummy32);
331
                len += (XDR_QUADLEN(dummy32) << 2);
332
                READMEM(buf, dummy32);
333
                if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
334
                        goto out_nfserr;
335
                iattr->ia_valid |= ATTR_UID;
336
        }
337
        if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
338
                READ_BUF(4);
339
                len += 4;
340
                READ32(dummy32);
341
                READ_BUF(dummy32);
342
                len += (XDR_QUADLEN(dummy32) << 2);
343
                READMEM(buf, dummy32);
344
                if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
345
                        goto out_nfserr;
346
                iattr->ia_valid |= ATTR_GID;
347
        }
348
        if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
349
                READ_BUF(4);
350
                len += 4;
351
                READ32(dummy32);
352
                switch (dummy32) {
353
                case NFS4_SET_TO_CLIENT_TIME:
354
                        /* We require the high 32 bits of 'seconds' to be 0, and we ignore
355
                           all 32 bits of 'nseconds'. */
356
                        READ_BUF(12);
357
                        len += 12;
358
                        READ32(dummy32);
359
                        if (dummy32)
360
                                return nfserr_inval;
361
                        READ32(iattr->ia_atime.tv_sec);
362
                        READ32(iattr->ia_atime.tv_nsec);
363
                        if (iattr->ia_atime.tv_nsec >= (u32)1000000000)
364
                                return nfserr_inval;
365
                        iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
366
                        break;
367
                case NFS4_SET_TO_SERVER_TIME:
368
                        iattr->ia_valid |= ATTR_ATIME;
369
                        break;
370
                default:
371
                        goto xdr_error;
372
                }
373
        }
374
        if (bmval[1] & FATTR4_WORD1_TIME_METADATA) {
375
                /* We require the high 32 bits of 'seconds' to be 0, and we ignore
376
                   all 32 bits of 'nseconds'. */
377
                READ_BUF(12);
378
                len += 12;
379
                READ32(dummy32);
380
                if (dummy32)
381
                        return nfserr_inval;
382
                READ32(iattr->ia_ctime.tv_sec);
383
                READ32(iattr->ia_ctime.tv_nsec);
384
                if (iattr->ia_ctime.tv_nsec >= (u32)1000000000)
385
                        return nfserr_inval;
386
                iattr->ia_valid |= ATTR_CTIME;
387
        }
388
        if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
389
                READ_BUF(4);
390
                len += 4;
391
                READ32(dummy32);
392
                switch (dummy32) {
393
                case NFS4_SET_TO_CLIENT_TIME:
394
                        /* We require the high 32 bits of 'seconds' to be 0, and we ignore
395
                           all 32 bits of 'nseconds'. */
396
                        READ_BUF(12);
397
                        len += 12;
398
                        READ32(dummy32);
399
                        if (dummy32)
400
                                return nfserr_inval;
401
                        READ32(iattr->ia_mtime.tv_sec);
402
                        READ32(iattr->ia_mtime.tv_nsec);
403
                        if (iattr->ia_mtime.tv_nsec >= (u32)1000000000)
404
                                return nfserr_inval;
405
                        iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
406
                        break;
407
                case NFS4_SET_TO_SERVER_TIME:
408
                        iattr->ia_valid |= ATTR_MTIME;
409
                        break;
410
                default:
411
                        goto xdr_error;
412
                }
413
        }
414
        if (len != expected_len)
415
                goto xdr_error;
416
 
417
        DECODE_TAIL;
418
 
419
out_nfserr:
420
        status = nfserrno(host_err);
421
        goto out;
422
}
423
 
424
static __be32
425
nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
426
{
427
        DECODE_HEAD;
428
 
429
        READ_BUF(4);
430
        READ32(access->ac_req_access);
431
 
432
        DECODE_TAIL;
433
}
434
 
435
static __be32
436
nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
437
{
438
        DECODE_HEAD;
439
 
440
        close->cl_stateowner = NULL;
441
        READ_BUF(4 + sizeof(stateid_t));
442
        READ32(close->cl_seqid);
443
        READ32(close->cl_stateid.si_generation);
444
        COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
445
 
446
        DECODE_TAIL;
447
}
448
 
449
 
450
static __be32
451
nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
452
{
453
        DECODE_HEAD;
454
 
455
        READ_BUF(12);
456
        READ64(commit->co_offset);
457
        READ32(commit->co_count);
458
 
459
        DECODE_TAIL;
460
}
461
 
462
static __be32
463
nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
464
{
465
        DECODE_HEAD;
466
 
467
        READ_BUF(4);
468
        READ32(create->cr_type);
469
        switch (create->cr_type) {
470
        case NF4LNK:
471
                READ_BUF(4);
472
                READ32(create->cr_linklen);
473
                READ_BUF(create->cr_linklen);
474
                SAVEMEM(create->cr_linkname, create->cr_linklen);
475
                break;
476
        case NF4BLK:
477
        case NF4CHR:
478
                READ_BUF(8);
479
                READ32(create->cr_specdata1);
480
                READ32(create->cr_specdata2);
481
                break;
482
        case NF4SOCK:
483
        case NF4FIFO:
484
        case NF4DIR:
485
        default:
486
                break;
487
        }
488
 
489
        READ_BUF(4);
490
        READ32(create->cr_namelen);
491
        READ_BUF(create->cr_namelen);
492
        SAVEMEM(create->cr_name, create->cr_namelen);
493
        if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
494
                return status;
495
 
496
        if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))
497
                goto out;
498
 
499
        DECODE_TAIL;
500
}
501
 
502
static inline __be32
503
nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
504
{
505
        DECODE_HEAD;
506
 
507
        READ_BUF(sizeof(stateid_t));
508
        READ32(dr->dr_stateid.si_generation);
509
        COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t));
510
 
511
        DECODE_TAIL;
512
}
513
 
514
static inline __be32
515
nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
516
{
517
        return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
518
}
519
 
520
static __be32
521
nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
522
{
523
        DECODE_HEAD;
524
 
525
        READ_BUF(4);
526
        READ32(link->li_namelen);
527
        READ_BUF(link->li_namelen);
528
        SAVEMEM(link->li_name, link->li_namelen);
529
        if ((status = check_filename(link->li_name, link->li_namelen, nfserr_inval)))
530
                return status;
531
 
532
        DECODE_TAIL;
533
}
534
 
535
static __be32
536
nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
537
{
538
        DECODE_HEAD;
539
 
540
        lock->lk_replay_owner = NULL;
541
        /*
542
        * type, reclaim(boolean), offset, length, new_lock_owner(boolean)
543
        */
544
        READ_BUF(28);
545
        READ32(lock->lk_type);
546
        if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT))
547
                goto xdr_error;
548
        READ32(lock->lk_reclaim);
549
        READ64(lock->lk_offset);
550
        READ64(lock->lk_length);
551
        READ32(lock->lk_is_new);
552
 
553
        if (lock->lk_is_new) {
554
                READ_BUF(36);
555
                READ32(lock->lk_new_open_seqid);
556
                READ32(lock->lk_new_open_stateid.si_generation);
557
 
558
                COPYMEM(&lock->lk_new_open_stateid.si_opaque, sizeof(stateid_opaque_t));
559
                READ32(lock->lk_new_lock_seqid);
560
                COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
561
                READ32(lock->lk_new_owner.len);
562
                READ_BUF(lock->lk_new_owner.len);
563
                READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
564
        } else {
565
                READ_BUF(20);
566
                READ32(lock->lk_old_lock_stateid.si_generation);
567
                COPYMEM(&lock->lk_old_lock_stateid.si_opaque, sizeof(stateid_opaque_t));
568
                READ32(lock->lk_old_lock_seqid);
569
        }
570
 
571
        DECODE_TAIL;
572
}
573
 
574
static __be32
575
nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
576
{
577
        DECODE_HEAD;
578
 
579
        READ_BUF(32);
580
        READ32(lockt->lt_type);
581
        if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT))
582
                goto xdr_error;
583
        READ64(lockt->lt_offset);
584
        READ64(lockt->lt_length);
585
        COPYMEM(&lockt->lt_clientid, 8);
586
        READ32(lockt->lt_owner.len);
587
        READ_BUF(lockt->lt_owner.len);
588
        READMEM(lockt->lt_owner.data, lockt->lt_owner.len);
589
 
590
        DECODE_TAIL;
591
}
592
 
593
static __be32
594
nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
595
{
596
        DECODE_HEAD;
597
 
598
        locku->lu_stateowner = NULL;
599
        READ_BUF(24 + sizeof(stateid_t));
600
        READ32(locku->lu_type);
601
        if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
602
                goto xdr_error;
603
        READ32(locku->lu_seqid);
604
        READ32(locku->lu_stateid.si_generation);
605
        COPYMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
606
        READ64(locku->lu_offset);
607
        READ64(locku->lu_length);
608
 
609
        DECODE_TAIL;
610
}
611
 
612
static __be32
613
nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
614
{
615
        DECODE_HEAD;
616
 
617
        READ_BUF(4);
618
        READ32(lookup->lo_len);
619
        READ_BUF(lookup->lo_len);
620
        SAVEMEM(lookup->lo_name, lookup->lo_len);
621
        if ((status = check_filename(lookup->lo_name, lookup->lo_len, nfserr_noent)))
622
                return status;
623
 
624
        DECODE_TAIL;
625
}
626
 
627
static __be32
628
nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
629
{
630
        DECODE_HEAD;
631
 
632
        memset(open->op_bmval, 0, sizeof(open->op_bmval));
633
        open->op_iattr.ia_valid = 0;
634
        open->op_stateowner = NULL;
635
 
636
        /* seqid, share_access, share_deny, clientid, ownerlen */
637
        READ_BUF(16 + sizeof(clientid_t));
638
        READ32(open->op_seqid);
639
        READ32(open->op_share_access);
640
        READ32(open->op_share_deny);
641
        COPYMEM(&open->op_clientid, sizeof(clientid_t));
642
        READ32(open->op_owner.len);
643
 
644
        /* owner, open_flag */
645
        READ_BUF(open->op_owner.len + 4);
646
        SAVEMEM(open->op_owner.data, open->op_owner.len);
647
        READ32(open->op_create);
648
        switch (open->op_create) {
649
        case NFS4_OPEN_NOCREATE:
650
                break;
651
        case NFS4_OPEN_CREATE:
652
                READ_BUF(4);
653
                READ32(open->op_createmode);
654
                switch (open->op_createmode) {
655
                case NFS4_CREATE_UNCHECKED:
656
                case NFS4_CREATE_GUARDED:
657
                        if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl)))
658
                                goto out;
659
                        break;
660
                case NFS4_CREATE_EXCLUSIVE:
661
                        READ_BUF(8);
662
                        COPYMEM(open->op_verf.data, 8);
663
                        break;
664
                default:
665
                        goto xdr_error;
666
                }
667
                break;
668
        default:
669
                goto xdr_error;
670
        }
671
 
672
        /* open_claim */
673
        READ_BUF(4);
674
        READ32(open->op_claim_type);
675
        switch (open->op_claim_type) {
676
        case NFS4_OPEN_CLAIM_NULL:
677
        case NFS4_OPEN_CLAIM_DELEGATE_PREV:
678
                READ_BUF(4);
679
                READ32(open->op_fname.len);
680
                READ_BUF(open->op_fname.len);
681
                SAVEMEM(open->op_fname.data, open->op_fname.len);
682
                if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
683
                        return status;
684
                break;
685
        case NFS4_OPEN_CLAIM_PREVIOUS:
686
                READ_BUF(4);
687
                READ32(open->op_delegate_type);
688
                break;
689
        case NFS4_OPEN_CLAIM_DELEGATE_CUR:
690
                READ_BUF(sizeof(stateid_t) + 4);
691
                COPYMEM(&open->op_delegate_stateid, sizeof(stateid_t));
692
                READ32(open->op_fname.len);
693
                READ_BUF(open->op_fname.len);
694
                SAVEMEM(open->op_fname.data, open->op_fname.len);
695
                if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
696
                        return status;
697
                break;
698
        default:
699
                goto xdr_error;
700
        }
701
 
702
        DECODE_TAIL;
703
}
704
 
705
static __be32
706
nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
707
{
708
        DECODE_HEAD;
709
 
710
        open_conf->oc_stateowner = NULL;
711
        READ_BUF(4 + sizeof(stateid_t));
712
        READ32(open_conf->oc_req_stateid.si_generation);
713
        COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
714
        READ32(open_conf->oc_seqid);
715
 
716
        DECODE_TAIL;
717
}
718
 
719
static __be32
720
nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
721
{
722
        DECODE_HEAD;
723
 
724
        open_down->od_stateowner = NULL;
725
        READ_BUF(12 + sizeof(stateid_t));
726
        READ32(open_down->od_stateid.si_generation);
727
        COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
728
        READ32(open_down->od_seqid);
729
        READ32(open_down->od_share_access);
730
        READ32(open_down->od_share_deny);
731
 
732
        DECODE_TAIL;
733
}
734
 
735
static __be32
736
nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
737
{
738
        DECODE_HEAD;
739
 
740
        READ_BUF(4);
741
        READ32(putfh->pf_fhlen);
742
        if (putfh->pf_fhlen > NFS4_FHSIZE)
743
                goto xdr_error;
744
        READ_BUF(putfh->pf_fhlen);
745
        SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen);
746
 
747
        DECODE_TAIL;
748
}
749
 
750
static __be32
751
nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
752
{
753
        DECODE_HEAD;
754
 
755
        READ_BUF(sizeof(stateid_t) + 12);
756
        READ32(read->rd_stateid.si_generation);
757
        COPYMEM(&read->rd_stateid.si_opaque, sizeof(stateid_opaque_t));
758
        READ64(read->rd_offset);
759
        READ32(read->rd_length);
760
 
761
        DECODE_TAIL;
762
}
763
 
764
static __be32
765
nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
766
{
767
        DECODE_HEAD;
768
 
769
        READ_BUF(24);
770
        READ64(readdir->rd_cookie);
771
        COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data));
772
        READ32(readdir->rd_dircount);    /* just in case you needed a useless field... */
773
        READ32(readdir->rd_maxcount);
774
        if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval)))
775
                goto out;
776
 
777
        DECODE_TAIL;
778
}
779
 
780
static __be32
781
nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
782
{
783
        DECODE_HEAD;
784
 
785
        READ_BUF(4);
786
        READ32(remove->rm_namelen);
787
        READ_BUF(remove->rm_namelen);
788
        SAVEMEM(remove->rm_name, remove->rm_namelen);
789
        if ((status = check_filename(remove->rm_name, remove->rm_namelen, nfserr_noent)))
790
                return status;
791
 
792
        DECODE_TAIL;
793
}
794
 
795
static __be32
796
nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
797
{
798
        DECODE_HEAD;
799
 
800
        READ_BUF(4);
801
        READ32(rename->rn_snamelen);
802
        READ_BUF(rename->rn_snamelen + 4);
803
        SAVEMEM(rename->rn_sname, rename->rn_snamelen);
804
        READ32(rename->rn_tnamelen);
805
        READ_BUF(rename->rn_tnamelen);
806
        SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
807
        if ((status = check_filename(rename->rn_sname, rename->rn_snamelen, nfserr_noent)))
808
                return status;
809
        if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen, nfserr_inval)))
810
                return status;
811
 
812
        DECODE_TAIL;
813
}
814
 
815
static __be32
816
nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
817
{
818
        DECODE_HEAD;
819
 
820
        READ_BUF(sizeof(clientid_t));
821
        COPYMEM(clientid, sizeof(clientid_t));
822
 
823
        DECODE_TAIL;
824
}
825
 
826
static __be32
827
nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
828
                     struct nfsd4_secinfo *secinfo)
829
{
830
        DECODE_HEAD;
831
 
832
        READ_BUF(4);
833
        READ32(secinfo->si_namelen);
834
        READ_BUF(secinfo->si_namelen);
835
        SAVEMEM(secinfo->si_name, secinfo->si_namelen);
836
        status = check_filename(secinfo->si_name, secinfo->si_namelen,
837
                                                                nfserr_noent);
838
        if (status)
839
                return status;
840
        DECODE_TAIL;
841
}
842
 
843
static __be32
844
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
845
{
846
        DECODE_HEAD;
847
 
848
        READ_BUF(sizeof(stateid_t));
849
        READ32(setattr->sa_stateid.si_generation);
850
        COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
851
        if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
852
                goto out;
853
 
854
        DECODE_TAIL;
855
}
856
 
857
static __be32
858
nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
859
{
860
        DECODE_HEAD;
861
 
862
        READ_BUF(12);
863
        COPYMEM(setclientid->se_verf.data, 8);
864
        READ32(setclientid->se_namelen);
865
 
866
        READ_BUF(setclientid->se_namelen + 8);
867
        SAVEMEM(setclientid->se_name, setclientid->se_namelen);
868
        READ32(setclientid->se_callback_prog);
869
        READ32(setclientid->se_callback_netid_len);
870
 
871
        READ_BUF(setclientid->se_callback_netid_len + 4);
872
        SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
873
        READ32(setclientid->se_callback_addr_len);
874
 
875
        READ_BUF(setclientid->se_callback_addr_len + 4);
876
        SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
877
        READ32(setclientid->se_callback_ident);
878
 
879
        DECODE_TAIL;
880
}
881
 
882
static __be32
883
nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
884
{
885
        DECODE_HEAD;
886
 
887
        READ_BUF(8 + sizeof(nfs4_verifier));
888
        COPYMEM(&scd_c->sc_clientid, 8);
889
        COPYMEM(&scd_c->sc_confirm, sizeof(nfs4_verifier));
890
 
891
        DECODE_TAIL;
892
}
893
 
894
/* Also used for NVERIFY */
895
static __be32
896
nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
897
{
898
#if 0
899
        struct nfsd4_compoundargs save = {
900
                .p = argp->p,
901
                .end = argp->end,
902
                .rqstp = argp->rqstp,
903
        };
904
        u32             ve_bmval[2];
905
        struct iattr    ve_iattr;           /* request */
906
        struct nfs4_acl *ve_acl;            /* request */
907
#endif
908
        DECODE_HEAD;
909
 
910
        if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval)))
911
                goto out;
912
 
913
        /* For convenience's sake, we compare raw xdr'd attributes in
914
         * nfsd4_proc_verify; however we still decode here just to return
915
         * correct error in case of bad xdr. */
916
#if 0
917
        status = nfsd4_decode_fattr(ve_bmval, &ve_iattr, &ve_acl);
918
        if (status == nfserr_inval) {
919
                status = nfserrno(status);
920
                goto out;
921
        }
922
#endif
923
        READ_BUF(4);
924
        READ32(verify->ve_attrlen);
925
        READ_BUF(verify->ve_attrlen);
926
        SAVEMEM(verify->ve_attrval, verify->ve_attrlen);
927
 
928
        DECODE_TAIL;
929
}
930
 
931
static __be32
932
nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
933
{
934
        int avail;
935
        int v;
936
        int len;
937
        DECODE_HEAD;
938
 
939
        READ_BUF(sizeof(stateid_opaque_t) + 20);
940
        READ32(write->wr_stateid.si_generation);
941
        COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
942
        READ64(write->wr_offset);
943
        READ32(write->wr_stable_how);
944
        if (write->wr_stable_how > 2)
945
                goto xdr_error;
946
        READ32(write->wr_buflen);
947
 
948
        /* Sorry .. no magic macros for this.. *
949
         * READ_BUF(write->wr_buflen);
950
         * SAVEMEM(write->wr_buf, write->wr_buflen);
951
         */
952
        avail = (char*)argp->end - (char*)argp->p;
953
        if (avail + argp->pagelen < write->wr_buflen) {
954
                dprintk("NFSD: xdr error (%s:%d)\n",
955
                                __FILE__, __LINE__);
956
                goto xdr_error;
957
        }
958
        argp->rqstp->rq_vec[0].iov_base = p;
959
        argp->rqstp->rq_vec[0].iov_len = avail;
960
        v = 0;
961
        len = write->wr_buflen;
962
        while (len > argp->rqstp->rq_vec[v].iov_len) {
963
                len -= argp->rqstp->rq_vec[v].iov_len;
964
                v++;
965
                argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
966
                argp->pagelist++;
967
                if (argp->pagelen >= PAGE_SIZE) {
968
                        argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
969
                        argp->pagelen -= PAGE_SIZE;
970
                } else {
971
                        argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
972
                        argp->pagelen -= len;
973
                }
974
        }
975
        argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
976
        argp->p = (__be32*)  (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
977
        argp->rqstp->rq_vec[v].iov_len = len;
978
        write->wr_vlen = v+1;
979
 
980
        DECODE_TAIL;
981
}
982
 
983
static __be32
984
nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
985
{
986
        DECODE_HEAD;
987
 
988
        READ_BUF(12);
989
        COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
990
        READ32(rlockowner->rl_owner.len);
991
        READ_BUF(rlockowner->rl_owner.len);
992
        READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
993
 
994
        DECODE_TAIL;
995
}
996
 
997
static __be32
998
nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
999
{
1000
        DECODE_HEAD;
1001
        struct nfsd4_op *op;
1002
        int i;
1003
 
1004
        /*
1005
         * XXX: According to spec, we should check the tag
1006
         * for UTF-8 compliance.  I'm postponing this for
1007
         * now because it seems that some clients do use
1008
         * binary tags.
1009
         */
1010
        READ_BUF(4);
1011
        READ32(argp->taglen);
1012
        READ_BUF(argp->taglen + 8);
1013
        SAVEMEM(argp->tag, argp->taglen);
1014
        READ32(argp->minorversion);
1015
        READ32(argp->opcnt);
1016
 
1017
        if (argp->taglen > NFSD4_MAX_TAGLEN)
1018
                goto xdr_error;
1019
        if (argp->opcnt > 100)
1020
                goto xdr_error;
1021
 
1022
        if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
1023
                argp->ops = kmalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
1024
                if (!argp->ops) {
1025
                        argp->ops = argp->iops;
1026
                        dprintk("nfsd: couldn't allocate room for COMPOUND\n");
1027
                        goto xdr_error;
1028
                }
1029
        }
1030
 
1031
        for (i = 0; i < argp->opcnt; i++) {
1032
                op = &argp->ops[i];
1033
                op->replay = NULL;
1034
 
1035
                /*
1036
                 * We can't use READ_BUF() here because we need to handle
1037
                 * a missing opcode as an OP_WRITE + 1. So we need to check
1038
                 * to see if we're truly at the end of our buffer or if there
1039
                 * is another page we need to flip to.
1040
                 */
1041
 
1042
                if (argp->p == argp->end) {
1043
                        if (argp->pagelen < 4) {
1044
                                /* There isn't an opcode still on the wire */
1045
                                op->opnum = OP_WRITE + 1;
1046
                                op->status = nfserr_bad_xdr;
1047
                                argp->opcnt = i+1;
1048
                                break;
1049
                        }
1050
 
1051
                        /*
1052
                         * False alarm. We just hit a page boundary, but there
1053
                         * is still data available.  Move pointer across page
1054
                         * boundary.  *snip from READ_BUF*
1055
                         */
1056
                        argp->p = page_address(argp->pagelist[0]);
1057
                        argp->pagelist++;
1058
                        if (argp->pagelen < PAGE_SIZE) {
1059
                                argp->end = p + (argp->pagelen>>2);
1060
                                argp->pagelen = 0;
1061
                        } else {
1062
                                argp->end = p + (PAGE_SIZE>>2);
1063
                                argp->pagelen -= PAGE_SIZE;
1064
                        }
1065
                }
1066
                op->opnum = ntohl(*argp->p++);
1067
 
1068
                switch (op->opnum) {
1069
                case 2: /* Reserved operation */
1070
                        op->opnum = OP_ILLEGAL;
1071
                        if (argp->minorversion == 0)
1072
                                op->status = nfserr_op_illegal;
1073
                        else
1074
                                op->status = nfserr_minor_vers_mismatch;
1075
                        break;
1076
                case OP_ACCESS:
1077
                        op->status = nfsd4_decode_access(argp, &op->u.access);
1078
                        break;
1079
                case OP_CLOSE:
1080
                        op->status = nfsd4_decode_close(argp, &op->u.close);
1081
                        break;
1082
                case OP_COMMIT:
1083
                        op->status = nfsd4_decode_commit(argp, &op->u.commit);
1084
                        break;
1085
                case OP_CREATE:
1086
                        op->status = nfsd4_decode_create(argp, &op->u.create);
1087
                        break;
1088
                case OP_DELEGRETURN:
1089
                        op->status = nfsd4_decode_delegreturn(argp, &op->u.delegreturn);
1090
                        break;
1091
                case OP_GETATTR:
1092
                        op->status = nfsd4_decode_getattr(argp, &op->u.getattr);
1093
                        break;
1094
                case OP_GETFH:
1095
                        op->status = nfs_ok;
1096
                        break;
1097
                case OP_LINK:
1098
                        op->status = nfsd4_decode_link(argp, &op->u.link);
1099
                        break;
1100
                case OP_LOCK:
1101
                        op->status = nfsd4_decode_lock(argp, &op->u.lock);
1102
                        break;
1103
                case OP_LOCKT:
1104
                        op->status = nfsd4_decode_lockt(argp, &op->u.lockt);
1105
                        break;
1106
                case OP_LOCKU:
1107
                        op->status = nfsd4_decode_locku(argp, &op->u.locku);
1108
                        break;
1109
                case OP_LOOKUP:
1110
                        op->status = nfsd4_decode_lookup(argp, &op->u.lookup);
1111
                        break;
1112
                case OP_LOOKUPP:
1113
                        op->status = nfs_ok;
1114
                        break;
1115
                case OP_NVERIFY:
1116
                        op->status = nfsd4_decode_verify(argp, &op->u.nverify);
1117
                        break;
1118
                case OP_OPEN:
1119
                        op->status = nfsd4_decode_open(argp, &op->u.open);
1120
                        break;
1121
                case OP_OPEN_CONFIRM:
1122
                        op->status = nfsd4_decode_open_confirm(argp, &op->u.open_confirm);
1123
                        break;
1124
                case OP_OPEN_DOWNGRADE:
1125
                        op->status = nfsd4_decode_open_downgrade(argp, &op->u.open_downgrade);
1126
                        break;
1127
                case OP_PUTFH:
1128
                        op->status = nfsd4_decode_putfh(argp, &op->u.putfh);
1129
                        break;
1130
                case OP_PUTROOTFH:
1131
                        op->status = nfs_ok;
1132
                        break;
1133
                case OP_READ:
1134
                        op->status = nfsd4_decode_read(argp, &op->u.read);
1135
                        break;
1136
                case OP_READDIR:
1137
                        op->status = nfsd4_decode_readdir(argp, &op->u.readdir);
1138
                        break;
1139
                case OP_READLINK:
1140
                        op->status = nfs_ok;
1141
                        break;
1142
                case OP_REMOVE:
1143
                        op->status = nfsd4_decode_remove(argp, &op->u.remove);
1144
                        break;
1145
                case OP_RENAME:
1146
                        op->status = nfsd4_decode_rename(argp, &op->u.rename);
1147
                        break;
1148
                case OP_RESTOREFH:
1149
                        op->status = nfs_ok;
1150
                        break;
1151
                case OP_RENEW:
1152
                        op->status = nfsd4_decode_renew(argp, &op->u.renew);
1153
                        break;
1154
                case OP_SAVEFH:
1155
                        op->status = nfs_ok;
1156
                        break;
1157
                case OP_SECINFO:
1158
                        op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
1159
                        break;
1160
                case OP_SETATTR:
1161
                        op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
1162
                        break;
1163
                case OP_SETCLIENTID:
1164
                        op->status = nfsd4_decode_setclientid(argp, &op->u.setclientid);
1165
                        break;
1166
                case OP_SETCLIENTID_CONFIRM:
1167
                        op->status = nfsd4_decode_setclientid_confirm(argp, &op->u.setclientid_confirm);
1168
                        break;
1169
                case OP_VERIFY:
1170
                        op->status = nfsd4_decode_verify(argp, &op->u.verify);
1171
                        break;
1172
                case OP_WRITE:
1173
                        op->status = nfsd4_decode_write(argp, &op->u.write);
1174
                        break;
1175
                case OP_RELEASE_LOCKOWNER:
1176
                        op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner);
1177
                        break;
1178
                default:
1179
                        op->opnum = OP_ILLEGAL;
1180
                        op->status = nfserr_op_illegal;
1181
                        break;
1182
                }
1183
 
1184
                if (op->status) {
1185
                        argp->opcnt = i+1;
1186
                        break;
1187
                }
1188
        }
1189
 
1190
        DECODE_TAIL;
1191
}
1192
/*
1193
 * END OF "GENERIC" DECODE ROUTINES.
1194
 */
1195
 
1196
/*
1197
 * START OF "GENERIC" ENCODE ROUTINES.
1198
 *   These may look a little ugly since they are imported from a "generic"
1199
 * set of XDR encode/decode routines which are intended to be shared by
1200
 * all of our NFSv4 implementations (OpenBSD, MacOS X...).
1201
 *
1202
 * If the pain of reading these is too great, it should be a straightforward
1203
 * task to translate them into Linux-specific versions which are more
1204
 * consistent with the style used in NFSv2/v3...
1205
 */
1206
#define ENCODE_HEAD              __be32 *p
1207
 
1208
#define WRITE32(n)               *p++ = htonl(n)
1209
#define WRITE64(n)               do {                           \
1210
        *p++ = htonl((u32)((n) >> 32));                         \
1211
        *p++ = htonl((u32)(n));                                 \
1212
} while (0)
1213
#define WRITEMEM(ptr,nbytes)     do {                           \
1214
        *(p + XDR_QUADLEN(nbytes) -1) = 0;                      \
1215
        memcpy(p, ptr, nbytes);                                 \
1216
        p += XDR_QUADLEN(nbytes);                               \
1217
} while (0)
1218
#define WRITECINFO(c)           do {                            \
1219
        *p++ = htonl(c.atomic);                                 \
1220
        *p++ = htonl(c.before_ctime_sec);                               \
1221
        *p++ = htonl(c.before_ctime_nsec);                              \
1222
        *p++ = htonl(c.after_ctime_sec);                                \
1223
        *p++ = htonl(c.after_ctime_nsec);                               \
1224
} while (0)
1225
 
1226
#define RESERVE_SPACE(nbytes)   do {                            \
1227
        p = resp->p;                                            \
1228
        BUG_ON(p + XDR_QUADLEN(nbytes) > resp->end);            \
1229
} while (0)
1230
#define ADJUST_ARGS()           resp->p = p
1231
 
1232
/*
1233
 * Header routine to setup seqid operation replay cache
1234
 */
1235
#define ENCODE_SEQID_OP_HEAD                                    \
1236
        __be32 *p;                                              \
1237
        __be32 *save;                                           \
1238
                                                                \
1239
        save = resp->p;
1240
 
1241
/*
1242
 * Routine for encoding the result of a "seqid-mutating" NFSv4 operation.  This
1243
 * is where sequence id's are incremented, and the replay cache is filled.
1244
 * Note that we increment sequence id's here, at the last moment, so we're sure
1245
 * we know whether the error to be returned is a sequence id mutating error.
1246
 */
1247
 
1248
#define ENCODE_SEQID_OP_TAIL(stateowner) do {                   \
1249
        if (seqid_mutating_err(nfserr) && stateowner) {         \
1250
                stateowner->so_seqid++;                         \
1251
                stateowner->so_replay.rp_status = nfserr;       \
1252
                stateowner->so_replay.rp_buflen =               \
1253
                          (((char *)(resp)->p - (char *)save)); \
1254
                memcpy(stateowner->so_replay.rp_buf, save,      \
1255
                        stateowner->so_replay.rp_buflen);       \
1256
        } } while (0);
1257
 
1258
/* Encode as an array of strings the string given with components
1259
 * seperated @sep.
1260
 */
1261
static __be32 nfsd4_encode_components(char sep, char *components,
1262
                                   __be32 **pp, int *buflen)
1263
{
1264
        __be32 *p = *pp;
1265
        __be32 *countp = p;
1266
        int strlen, count=0;
1267
        char *str, *end;
1268
 
1269
        dprintk("nfsd4_encode_components(%s)\n", components);
1270
        if ((*buflen -= 4) < 0)
1271
                return nfserr_resource;
1272
        WRITE32(0); /* We will fill this in with @count later */
1273
        end = str = components;
1274
        while (*end) {
1275
                for (; *end && (*end != sep); end++)
1276
                        ; /* Point to end of component */
1277
                strlen = end - str;
1278
                if (strlen) {
1279
                        if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
1280
                                return nfserr_resource;
1281
                        WRITE32(strlen);
1282
                        WRITEMEM(str, strlen);
1283
                        count++;
1284
                }
1285
                else
1286
                        end++;
1287
                str = end;
1288
        }
1289
        *pp = p;
1290
        p = countp;
1291
        WRITE32(count);
1292
        return 0;
1293
}
1294
 
1295
/*
1296
 * encode a location element of a fs_locations structure
1297
 */
1298
static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
1299
                                    __be32 **pp, int *buflen)
1300
{
1301
        __be32 status;
1302
        __be32 *p = *pp;
1303
 
1304
        status = nfsd4_encode_components(':', location->hosts, &p, buflen);
1305
        if (status)
1306
                return status;
1307
        status = nfsd4_encode_components('/', location->path, &p, buflen);
1308
        if (status)
1309
                return status;
1310
        *pp = p;
1311
        return 0;
1312
}
1313
 
1314
/*
1315
 * Return the path to an export point in the pseudo filesystem namespace
1316
 * Returned string is safe to use as long as the caller holds a reference
1317
 * to @exp.
1318
 */
1319
static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
1320
{
1321
        struct svc_fh tmp_fh;
1322
        char *path, *rootpath;
1323
 
1324
        fh_init(&tmp_fh, NFS4_FHSIZE);
1325
        *stat = exp_pseudoroot(rqstp, &tmp_fh);
1326
        if (*stat)
1327
                return NULL;
1328
        rootpath = tmp_fh.fh_export->ex_path;
1329
 
1330
        path = exp->ex_path;
1331
 
1332
        if (strncmp(path, rootpath, strlen(rootpath))) {
1333
                dprintk("nfsd: fs_locations failed;"
1334
                        "%s is not contained in %s\n", path, rootpath);
1335
                *stat = nfserr_notsupp;
1336
                return NULL;
1337
        }
1338
 
1339
        return path + strlen(rootpath);
1340
}
1341
 
1342
/*
1343
 *  encode a fs_locations structure
1344
 */
1345
static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
1346
                                     struct svc_export *exp,
1347
                                     __be32 **pp, int *buflen)
1348
{
1349
        __be32 status;
1350
        int i;
1351
        __be32 *p = *pp;
1352
        struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
1353
        char *root = nfsd4_path(rqstp, exp, &status);
1354
 
1355
        if (status)
1356
                return status;
1357
        status = nfsd4_encode_components('/', root, &p, buflen);
1358
        if (status)
1359
                return status;
1360
        if ((*buflen -= 4) < 0)
1361
                return nfserr_resource;
1362
        WRITE32(fslocs->locations_count);
1363
        for (i=0; i<fslocs->locations_count; i++) {
1364
                status = nfsd4_encode_fs_location4(&fslocs->locations[i],
1365
                                                   &p, buflen);
1366
                if (status)
1367
                        return status;
1368
        }
1369
        *pp = p;
1370
        return 0;
1371
}
1372
 
1373
static u32 nfs4_ftypes[16] = {
1374
        NF4BAD,  NF4FIFO, NF4CHR, NF4BAD,
1375
        NF4DIR,  NF4BAD,  NF4BLK, NF4BAD,
1376
        NF4REG,  NF4BAD,  NF4LNK, NF4BAD,
1377
        NF4SOCK, NF4BAD,  NF4LNK, NF4BAD,
1378
};
1379
 
1380
static __be32
1381
nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
1382
                        __be32 **p, int *buflen)
1383
{
1384
        int status;
1385
 
1386
        if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
1387
                return nfserr_resource;
1388
        if (whotype != NFS4_ACL_WHO_NAMED)
1389
                status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));
1390
        else if (group)
1391
                status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));
1392
        else
1393
                status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));
1394
        if (status < 0)
1395
                return nfserrno(status);
1396
        *p = xdr_encode_opaque(*p, NULL, status);
1397
        *buflen -= (XDR_QUADLEN(status) << 2) + 4;
1398
        BUG_ON(*buflen < 0);
1399
        return 0;
1400
}
1401
 
1402
static inline __be32
1403
nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen)
1404
{
1405
        return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
1406
}
1407
 
1408
static inline __be32
1409
nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen)
1410
{
1411
        return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
1412
}
1413
 
1414
static inline __be32
1415
nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
1416
                __be32 **p, int *buflen)
1417
{
1418
        return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
1419
}
1420
 
1421
#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
1422
                              FATTR4_WORD0_RDATTR_ERROR)
1423
#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
1424
 
1425
static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
1426
{
1427
        /* As per referral draft:  */
1428
        if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
1429
            *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
1430
                if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
1431
                    *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
1432
                        *rdattr_err = NFSERR_MOVED;
1433
                else
1434
                        return nfserr_moved;
1435
        }
1436
        *bmval0 &= WORD0_ABSENT_FS_ATTRS;
1437
        *bmval1 &= WORD1_ABSENT_FS_ATTRS;
1438
        return 0;
1439
}
1440
 
1441
/*
1442
 * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
1443
 * ourselves.
1444
 *
1445
 * @countp is the buffer size in _words_; upon successful return this becomes
1446
 * replaced with the number of words written.
1447
 */
1448
__be32
1449
nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
1450
                struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
1451
                struct svc_rqst *rqstp)
1452
{
1453
        u32 bmval0 = bmval[0];
1454
        u32 bmval1 = bmval[1];
1455
        struct kstat stat;
1456
        struct svc_fh tempfh;
1457
        struct kstatfs statfs;
1458
        int buflen = *countp << 2;
1459
        __be32 *attrlenp;
1460
        u32 dummy;
1461
        u64 dummy64;
1462
        u32 rdattr_err = 0;
1463
        __be32 *p = buffer;
1464
        __be32 status;
1465
        int err;
1466
        int aclsupport = 0;
1467
        struct nfs4_acl *acl = NULL;
1468
 
1469
        BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
1470
        BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
1471
        BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
1472
 
1473
        if (exp->ex_fslocs.migrated) {
1474
                status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
1475
                if (status)
1476
                        goto out;
1477
        }
1478
 
1479
        err = vfs_getattr(exp->ex_mnt, dentry, &stat);
1480
        if (err)
1481
                goto out_nfserr;
1482
        if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |
1483
                        FATTR4_WORD0_MAXNAME)) ||
1484
            (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
1485
                       FATTR4_WORD1_SPACE_TOTAL))) {
1486
                err = vfs_statfs(dentry, &statfs);
1487
                if (err)
1488
                        goto out_nfserr;
1489
        }
1490
        if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
1491
                fh_init(&tempfh, NFS4_FHSIZE);
1492
                status = fh_compose(&tempfh, exp, dentry, NULL);
1493
                if (status)
1494
                        goto out;
1495
                fhp = &tempfh;
1496
        }
1497
        if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
1498
                        | FATTR4_WORD0_SUPPORTED_ATTRS)) {
1499
                err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
1500
                aclsupport = (err == 0);
1501
                if (bmval0 & FATTR4_WORD0_ACL) {
1502
                        if (err == -EOPNOTSUPP)
1503
                                bmval0 &= ~FATTR4_WORD0_ACL;
1504
                        else if (err == -EINVAL) {
1505
                                status = nfserr_attrnotsupp;
1506
                                goto out;
1507
                        } else if (err != 0)
1508
                                goto out_nfserr;
1509
                }
1510
        }
1511
        if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
1512
                if (exp->ex_fslocs.locations == NULL) {
1513
                        bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
1514
                }
1515
        }
1516
        if ((buflen -= 16) < 0)
1517
                goto out_resource;
1518
 
1519
        WRITE32(2);
1520
        WRITE32(bmval0);
1521
        WRITE32(bmval1);
1522
        attrlenp = p++;                /* to be backfilled later */
1523
 
1524
        if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
1525
                u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
1526
                if ((buflen -= 12) < 0)
1527
                        goto out_resource;
1528
                if (!aclsupport)
1529
                        word0 &= ~FATTR4_WORD0_ACL;
1530
                if (!exp->ex_fslocs.locations)
1531
                        word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
1532
                WRITE32(2);
1533
                WRITE32(word0);
1534
                WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
1535
        }
1536
        if (bmval0 & FATTR4_WORD0_TYPE) {
1537
                if ((buflen -= 4) < 0)
1538
                        goto out_resource;
1539
                dummy = nfs4_ftypes[(stat.mode & S_IFMT) >> 12];
1540
                if (dummy == NF4BAD)
1541
                        goto out_serverfault;
1542
                WRITE32(dummy);
1543
        }
1544
        if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
1545
                if ((buflen -= 4) < 0)
1546
                        goto out_resource;
1547
                if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
1548
                        WRITE32(NFS4_FH_PERSISTENT);
1549
                else
1550
                        WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
1551
        }
1552
        if (bmval0 & FATTR4_WORD0_CHANGE) {
1553
                /*
1554
                 * Note: This _must_ be consistent with the scheme for writing
1555
                 * change_info, so any changes made here must be reflected there
1556
                 * as well.  (See xdr4.h:set_change_info() and the WRITECINFO()
1557
                 * macro above.)
1558
                 */
1559
                if ((buflen -= 8) < 0)
1560
                        goto out_resource;
1561
                WRITE32(stat.ctime.tv_sec);
1562
                WRITE32(stat.ctime.tv_nsec);
1563
        }
1564
        if (bmval0 & FATTR4_WORD0_SIZE) {
1565
                if ((buflen -= 8) < 0)
1566
                        goto out_resource;
1567
                WRITE64(stat.size);
1568
        }
1569
        if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) {
1570
                if ((buflen -= 4) < 0)
1571
                        goto out_resource;
1572
                WRITE32(1);
1573
        }
1574
        if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) {
1575
                if ((buflen -= 4) < 0)
1576
                        goto out_resource;
1577
                WRITE32(1);
1578
        }
1579
        if (bmval0 & FATTR4_WORD0_NAMED_ATTR) {
1580
                if ((buflen -= 4) < 0)
1581
                        goto out_resource;
1582
                WRITE32(0);
1583
        }
1584
        if (bmval0 & FATTR4_WORD0_FSID) {
1585
                if ((buflen -= 16) < 0)
1586
                        goto out_resource;
1587
                if (exp->ex_fslocs.migrated) {
1588
                        WRITE64(NFS4_REFERRAL_FSID_MAJOR);
1589
                        WRITE64(NFS4_REFERRAL_FSID_MINOR);
1590
                } else switch(fsid_source(fhp)) {
1591
                case FSIDSOURCE_FSID:
1592
                        WRITE64((u64)exp->ex_fsid);
1593
                        WRITE64((u64)0);
1594
                        break;
1595
                case FSIDSOURCE_DEV:
1596
                        WRITE32(0);
1597
                        WRITE32(MAJOR(stat.dev));
1598
                        WRITE32(0);
1599
                        WRITE32(MINOR(stat.dev));
1600
                        break;
1601
                case FSIDSOURCE_UUID:
1602
                        WRITEMEM(exp->ex_uuid, 16);
1603
                        break;
1604
                }
1605
        }
1606
        if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
1607
                if ((buflen -= 4) < 0)
1608
                        goto out_resource;
1609
                WRITE32(0);
1610
        }
1611
        if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
1612
                if ((buflen -= 4) < 0)
1613
                        goto out_resource;
1614
                WRITE32(NFSD_LEASE_TIME);
1615
        }
1616
        if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
1617
                if ((buflen -= 4) < 0)
1618
                        goto out_resource;
1619
                WRITE32(rdattr_err);
1620
        }
1621
        if (bmval0 & FATTR4_WORD0_ACL) {
1622
                struct nfs4_ace *ace;
1623
 
1624
                if (acl == NULL) {
1625
                        if ((buflen -= 4) < 0)
1626
                                goto out_resource;
1627
 
1628
                        WRITE32(0);
1629
                        goto out_acl;
1630
                }
1631
                if ((buflen -= 4) < 0)
1632
                        goto out_resource;
1633
                WRITE32(acl->naces);
1634
 
1635
                for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
1636
                        if ((buflen -= 4*3) < 0)
1637
                                goto out_resource;
1638
                        WRITE32(ace->type);
1639
                        WRITE32(ace->flag);
1640
                        WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
1641
                        status = nfsd4_encode_aclname(rqstp, ace->whotype,
1642
                                ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP,
1643
                                &p, &buflen);
1644
                        if (status == nfserr_resource)
1645
                                goto out_resource;
1646
                        if (status)
1647
                                goto out;
1648
                }
1649
        }
1650
out_acl:
1651
        if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
1652
                if ((buflen -= 4) < 0)
1653
                        goto out_resource;
1654
                WRITE32(aclsupport ?
1655
                        ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
1656
        }
1657
        if (bmval0 & FATTR4_WORD0_CANSETTIME) {
1658
                if ((buflen -= 4) < 0)
1659
                        goto out_resource;
1660
                WRITE32(1);
1661
        }
1662
        if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
1663
                if ((buflen -= 4) < 0)
1664
                        goto out_resource;
1665
                WRITE32(1);
1666
        }
1667
        if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
1668
                if ((buflen -= 4) < 0)
1669
                        goto out_resource;
1670
                WRITE32(1);
1671
        }
1672
        if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) {
1673
                if ((buflen -= 4) < 0)
1674
                        goto out_resource;
1675
                WRITE32(1);
1676
        }
1677
        if (bmval0 & FATTR4_WORD0_FILEHANDLE) {
1678
                buflen -= (XDR_QUADLEN(fhp->fh_handle.fh_size) << 2) + 4;
1679
                if (buflen < 0)
1680
                        goto out_resource;
1681
                WRITE32(fhp->fh_handle.fh_size);
1682
                WRITEMEM(&fhp->fh_handle.fh_base, fhp->fh_handle.fh_size);
1683
        }
1684
        if (bmval0 & FATTR4_WORD0_FILEID) {
1685
                if ((buflen -= 8) < 0)
1686
                        goto out_resource;
1687
                WRITE64(stat.ino);
1688
        }
1689
        if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
1690
                if ((buflen -= 8) < 0)
1691
                        goto out_resource;
1692
                WRITE64((u64) statfs.f_ffree);
1693
        }
1694
        if (bmval0 & FATTR4_WORD0_FILES_FREE) {
1695
                if ((buflen -= 8) < 0)
1696
                        goto out_resource;
1697
                WRITE64((u64) statfs.f_ffree);
1698
        }
1699
        if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
1700
                if ((buflen -= 8) < 0)
1701
                        goto out_resource;
1702
                WRITE64((u64) statfs.f_files);
1703
        }
1704
        if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
1705
                status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
1706
                if (status == nfserr_resource)
1707
                        goto out_resource;
1708
                if (status)
1709
                        goto out;
1710
        }
1711
        if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
1712
                if ((buflen -= 4) < 0)
1713
                        goto out_resource;
1714
                WRITE32(1);
1715
        }
1716
        if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
1717
                if ((buflen -= 8) < 0)
1718
                        goto out_resource;
1719
                WRITE64(~(u64)0);
1720
        }
1721
        if (bmval0 & FATTR4_WORD0_MAXLINK) {
1722
                if ((buflen -= 4) < 0)
1723
                        goto out_resource;
1724
                WRITE32(255);
1725
        }
1726
        if (bmval0 & FATTR4_WORD0_MAXNAME) {
1727
                if ((buflen -= 4) < 0)
1728
                        goto out_resource;
1729
                WRITE32(statfs.f_namelen);
1730
        }
1731
        if (bmval0 & FATTR4_WORD0_MAXREAD) {
1732
                if ((buflen -= 8) < 0)
1733
                        goto out_resource;
1734
                WRITE64((u64) svc_max_payload(rqstp));
1735
        }
1736
        if (bmval0 & FATTR4_WORD0_MAXWRITE) {
1737
                if ((buflen -= 8) < 0)
1738
                        goto out_resource;
1739
                WRITE64((u64) svc_max_payload(rqstp));
1740
        }
1741
        if (bmval1 & FATTR4_WORD1_MODE) {
1742
                if ((buflen -= 4) < 0)
1743
                        goto out_resource;
1744
                WRITE32(stat.mode & S_IALLUGO);
1745
        }
1746
        if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
1747
                if ((buflen -= 4) < 0)
1748
                        goto out_resource;
1749
                WRITE32(1);
1750
        }
1751
        if (bmval1 & FATTR4_WORD1_NUMLINKS) {
1752
                if ((buflen -= 4) < 0)
1753
                        goto out_resource;
1754
                WRITE32(stat.nlink);
1755
        }
1756
        if (bmval1 & FATTR4_WORD1_OWNER) {
1757
                status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
1758
                if (status == nfserr_resource)
1759
                        goto out_resource;
1760
                if (status)
1761
                        goto out;
1762
        }
1763
        if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
1764
                status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
1765
                if (status == nfserr_resource)
1766
                        goto out_resource;
1767
                if (status)
1768
                        goto out;
1769
        }
1770
        if (bmval1 & FATTR4_WORD1_RAWDEV) {
1771
                if ((buflen -= 8) < 0)
1772
                        goto out_resource;
1773
                WRITE32((u32) MAJOR(stat.rdev));
1774
                WRITE32((u32) MINOR(stat.rdev));
1775
        }
1776
        if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
1777
                if ((buflen -= 8) < 0)
1778
                        goto out_resource;
1779
                dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize;
1780
                WRITE64(dummy64);
1781
        }
1782
        if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
1783
                if ((buflen -= 8) < 0)
1784
                        goto out_resource;
1785
                dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize;
1786
                WRITE64(dummy64);
1787
        }
1788
        if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
1789
                if ((buflen -= 8) < 0)
1790
                        goto out_resource;
1791
                dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize;
1792
                WRITE64(dummy64);
1793
        }
1794
        if (bmval1 & FATTR4_WORD1_SPACE_USED) {
1795
                if ((buflen -= 8) < 0)
1796
                        goto out_resource;
1797
                dummy64 = (u64)stat.blocks << 9;
1798
                WRITE64(dummy64);
1799
        }
1800
        if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
1801
                if ((buflen -= 12) < 0)
1802
                        goto out_resource;
1803
                WRITE32(0);
1804
                WRITE32(stat.atime.tv_sec);
1805
                WRITE32(stat.atime.tv_nsec);
1806
        }
1807
        if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
1808
                if ((buflen -= 12) < 0)
1809
                        goto out_resource;
1810
                WRITE32(0);
1811
                WRITE32(1);
1812
                WRITE32(0);
1813
        }
1814
        if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
1815
                if ((buflen -= 12) < 0)
1816
                        goto out_resource;
1817
                WRITE32(0);
1818
                WRITE32(stat.ctime.tv_sec);
1819
                WRITE32(stat.ctime.tv_nsec);
1820
        }
1821
        if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
1822
                if ((buflen -= 12) < 0)
1823
                        goto out_resource;
1824
                WRITE32(0);
1825
                WRITE32(stat.mtime.tv_sec);
1826
                WRITE32(stat.mtime.tv_nsec);
1827
        }
1828
        if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
1829
                if ((buflen -= 8) < 0)
1830
                        goto out_resource;
1831
                if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
1832
                        err = vfs_getattr(exp->ex_mnt->mnt_parent,
1833
                                exp->ex_mnt->mnt_mountpoint, &stat);
1834
                        if (err)
1835
                                goto out_nfserr;
1836
                }
1837
                WRITE64(stat.ino);
1838
        }
1839
        *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
1840
        *countp = p - buffer;
1841
        status = nfs_ok;
1842
 
1843
out:
1844
        kfree(acl);
1845
        if (fhp == &tempfh)
1846
                fh_put(&tempfh);
1847
        return status;
1848
out_nfserr:
1849
        status = nfserrno(err);
1850
        goto out;
1851
out_resource:
1852
        *countp = 0;
1853
        status = nfserr_resource;
1854
        goto out;
1855
out_serverfault:
1856
        status = nfserr_serverfault;
1857
        goto out;
1858
}
1859
 
1860
static __be32
1861
nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1862
                const char *name, int namlen, __be32 *p, int *buflen)
1863
{
1864
        struct svc_export *exp = cd->rd_fhp->fh_export;
1865
        struct dentry *dentry;
1866
        __be32 nfserr;
1867
 
1868
        dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
1869
        if (IS_ERR(dentry))
1870
                return nfserrno(PTR_ERR(dentry));
1871
 
1872
        exp_get(exp);
1873
        if (d_mountpoint(dentry)) {
1874
                int err;
1875
 
1876
                /*
1877
                 * Why the heck aren't we just using nfsd_lookup??
1878
                 * Different "."/".." handling?  Something else?
1879
                 * At least, add a comment here to explain....
1880
                 */
1881
                err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
1882
                if (err) {
1883
                        nfserr = nfserrno(err);
1884
                        goto out_put;
1885
                }
1886
                nfserr = check_nfsd_access(exp, cd->rd_rqstp);
1887
                if (nfserr)
1888
                        goto out_put;
1889
 
1890
        }
1891
        nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
1892
                                        cd->rd_rqstp);
1893
out_put:
1894
        dput(dentry);
1895
        exp_put(exp);
1896
        return nfserr;
1897
}
1898
 
1899
static __be32 *
1900
nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
1901
{
1902
        __be32 *attrlenp;
1903
 
1904
        if (buflen < 6)
1905
                return NULL;
1906
        *p++ = htonl(2);
1907
        *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
1908
        *p++ = htonl(0);                  /* bmval1 */
1909
 
1910
        attrlenp = p++;
1911
        *p++ = nfserr;       /* no htonl */
1912
        *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
1913
        return p;
1914
}
1915
 
1916
static int
1917
nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
1918
                    loff_t offset, u64 ino, unsigned int d_type)
1919
{
1920
        struct readdir_cd *ccd = ccdv;
1921
        struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
1922
        int buflen;
1923
        __be32 *p = cd->buffer;
1924
        __be32 nfserr = nfserr_toosmall;
1925
 
1926
        /* In nfsv4, "." and ".." never make it onto the wire.. */
1927
        if (name && isdotent(name, namlen)) {
1928
                cd->common.err = nfs_ok;
1929
                return 0;
1930
        }
1931
 
1932
        if (cd->offset)
1933
                xdr_encode_hyper(cd->offset, (u64) offset);
1934
 
1935
        buflen = cd->buflen - 4 - XDR_QUADLEN(namlen);
1936
        if (buflen < 0)
1937
                goto fail;
1938
 
1939
        *p++ = xdr_one;                             /* mark entry present */
1940
        cd->offset = p;                             /* remember pointer */
1941
        p = xdr_encode_hyper(p, NFS_OFFSET_MAX);    /* offset of next entry */
1942
        p = xdr_encode_array(p, name, namlen);      /* name length & name */
1943
 
1944
        nfserr = nfsd4_encode_dirent_fattr(cd, name, namlen, p, &buflen);
1945
        switch (nfserr) {
1946
        case nfs_ok:
1947
                p += buflen;
1948
                break;
1949
        case nfserr_resource:
1950
                nfserr = nfserr_toosmall;
1951
                goto fail;
1952
        case nfserr_dropit:
1953
                goto fail;
1954
        default:
1955
                /*
1956
                 * If the client requested the RDATTR_ERROR attribute,
1957
                 * we stuff the error code into this attribute
1958
                 * and continue.  If this attribute was not requested,
1959
                 * then in accordance with the spec, we fail the
1960
                 * entire READDIR operation(!)
1961
                 */
1962
                if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
1963
                        goto fail;
1964
                p = nfsd4_encode_rdattr_error(p, buflen, nfserr);
1965
                if (p == NULL) {
1966
                        nfserr = nfserr_toosmall;
1967
                        goto fail;
1968
                }
1969
        }
1970
        cd->buflen -= (p - cd->buffer);
1971
        cd->buffer = p;
1972
        cd->common.err = nfs_ok;
1973
        return 0;
1974
fail:
1975
        cd->common.err = nfserr;
1976
        return -EINVAL;
1977
}
1978
 
1979
static void
1980
nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
1981
{
1982
        ENCODE_HEAD;
1983
 
1984
        if (!nfserr) {
1985
                RESERVE_SPACE(8);
1986
                WRITE32(access->ac_supported);
1987
                WRITE32(access->ac_resp_access);
1988
                ADJUST_ARGS();
1989
        }
1990
}
1991
 
1992
static void
1993
nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
1994
{
1995
        ENCODE_SEQID_OP_HEAD;
1996
 
1997
        if (!nfserr) {
1998
                RESERVE_SPACE(sizeof(stateid_t));
1999
                WRITE32(close->cl_stateid.si_generation);
2000
                WRITEMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
2001
                ADJUST_ARGS();
2002
        }
2003
        ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
2004
}
2005
 
2006
 
2007
static void
2008
nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
2009
{
2010
        ENCODE_HEAD;
2011
 
2012
        if (!nfserr) {
2013
                RESERVE_SPACE(8);
2014
                WRITEMEM(commit->co_verf.data, 8);
2015
                ADJUST_ARGS();
2016
        }
2017
}
2018
 
2019
static void
2020
nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
2021
{
2022
        ENCODE_HEAD;
2023
 
2024
        if (!nfserr) {
2025
                RESERVE_SPACE(32);
2026
                WRITECINFO(create->cr_cinfo);
2027
                WRITE32(2);
2028
                WRITE32(create->cr_bmval[0]);
2029
                WRITE32(create->cr_bmval[1]);
2030
                ADJUST_ARGS();
2031
        }
2032
}
2033
 
2034
static __be32
2035
nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
2036
{
2037
        struct svc_fh *fhp = getattr->ga_fhp;
2038
        int buflen;
2039
 
2040
        if (nfserr)
2041
                return nfserr;
2042
 
2043
        buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
2044
        nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
2045
                                    resp->p, &buflen, getattr->ga_bmval,
2046
                                    resp->rqstp);
2047
        if (!nfserr)
2048
                resp->p += buflen;
2049
        return nfserr;
2050
}
2051
 
2052
static void
2053
nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp)
2054
{
2055
        unsigned int len;
2056
        ENCODE_HEAD;
2057
 
2058
        if (!nfserr) {
2059
                len = fhp->fh_handle.fh_size;
2060
                RESERVE_SPACE(len + 4);
2061
                WRITE32(len);
2062
                WRITEMEM(&fhp->fh_handle.fh_base, len);
2063
                ADJUST_ARGS();
2064
        }
2065
}
2066
 
2067
/*
2068
* Including all fields other than the name, a LOCK4denied structure requires
2069
*   8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
2070
*/
2071
static void
2072
nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denied *ld)
2073
{
2074
        ENCODE_HEAD;
2075
 
2076
        RESERVE_SPACE(32 + XDR_LEN(ld->ld_sop ? ld->ld_sop->so_owner.len : 0));
2077
        WRITE64(ld->ld_start);
2078
        WRITE64(ld->ld_length);
2079
        WRITE32(ld->ld_type);
2080
        if (ld->ld_sop) {
2081
                WRITEMEM(&ld->ld_clientid, 8);
2082
                WRITE32(ld->ld_sop->so_owner.len);
2083
                WRITEMEM(ld->ld_sop->so_owner.data, ld->ld_sop->so_owner.len);
2084
                kref_put(&ld->ld_sop->so_ref, nfs4_free_stateowner);
2085
        }  else {  /* non - nfsv4 lock in conflict, no clientid nor owner */
2086
                WRITE64((u64)0); /* clientid */
2087
                WRITE32(0); /* length of owner name */
2088
        }
2089
        ADJUST_ARGS();
2090
}
2091
 
2092
static void
2093
nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
2094
{
2095
        ENCODE_SEQID_OP_HEAD;
2096
 
2097
        if (!nfserr) {
2098
                RESERVE_SPACE(4 + sizeof(stateid_t));
2099
                WRITE32(lock->lk_resp_stateid.si_generation);
2100
                WRITEMEM(&lock->lk_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
2101
                ADJUST_ARGS();
2102
        } else if (nfserr == nfserr_denied)
2103
                nfsd4_encode_lock_denied(resp, &lock->lk_denied);
2104
 
2105
        ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
2106
}
2107
 
2108
static void
2109
nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
2110
{
2111
        if (nfserr == nfserr_denied)
2112
                nfsd4_encode_lock_denied(resp, &lockt->lt_denied);
2113
}
2114
 
2115
static void
2116
nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
2117
{
2118
        ENCODE_SEQID_OP_HEAD;
2119
 
2120
        if (!nfserr) {
2121
                RESERVE_SPACE(sizeof(stateid_t));
2122
                WRITE32(locku->lu_stateid.si_generation);
2123
                WRITEMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
2124
                ADJUST_ARGS();
2125
        }
2126
 
2127
        ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
2128
}
2129
 
2130
 
2131
static void
2132
nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
2133
{
2134
        ENCODE_HEAD;
2135
 
2136
        if (!nfserr) {
2137
                RESERVE_SPACE(20);
2138
                WRITECINFO(link->li_cinfo);
2139
                ADJUST_ARGS();
2140
        }
2141
}
2142
 
2143
 
2144
static void
2145
nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
2146
{
2147
        ENCODE_SEQID_OP_HEAD;
2148
 
2149
        if (nfserr)
2150
                goto out;
2151
 
2152
        RESERVE_SPACE(36 + sizeof(stateid_t));
2153
        WRITE32(open->op_stateid.si_generation);
2154
        WRITEMEM(&open->op_stateid.si_opaque, sizeof(stateid_opaque_t));
2155
        WRITECINFO(open->op_cinfo);
2156
        WRITE32(open->op_rflags);
2157
        WRITE32(2);
2158
        WRITE32(open->op_bmval[0]);
2159
        WRITE32(open->op_bmval[1]);
2160
        WRITE32(open->op_delegate_type);
2161
        ADJUST_ARGS();
2162
 
2163
        switch (open->op_delegate_type) {
2164
        case NFS4_OPEN_DELEGATE_NONE:
2165
                break;
2166
        case NFS4_OPEN_DELEGATE_READ:
2167
                RESERVE_SPACE(20 + sizeof(stateid_t));
2168
                WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
2169
                WRITE32(open->op_recall);
2170
 
2171
                /*
2172
                 * TODO: ACE's in delegations
2173
                 */
2174
                WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
2175
                WRITE32(0);
2176
                WRITE32(0);
2177
                WRITE32(0);   /* XXX: is NULL principal ok? */
2178
                ADJUST_ARGS();
2179
                break;
2180
        case NFS4_OPEN_DELEGATE_WRITE:
2181
                RESERVE_SPACE(32 + sizeof(stateid_t));
2182
                WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
2183
                WRITE32(0);
2184
 
2185
                /*
2186
                 * TODO: space_limit's in delegations
2187
                 */
2188
                WRITE32(NFS4_LIMIT_SIZE);
2189
                WRITE32(~(u32)0);
2190
                WRITE32(~(u32)0);
2191
 
2192
                /*
2193
                 * TODO: ACE's in delegations
2194
                 */
2195
                WRITE32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
2196
                WRITE32(0);
2197
                WRITE32(0);
2198
                WRITE32(0);   /* XXX: is NULL principal ok? */
2199
                ADJUST_ARGS();
2200
                break;
2201
        default:
2202
                BUG();
2203
        }
2204
        /* XXX save filehandle here */
2205
out:
2206
        ENCODE_SEQID_OP_TAIL(open->op_stateowner);
2207
}
2208
 
2209
static void
2210
nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
2211
{
2212
        ENCODE_SEQID_OP_HEAD;
2213
 
2214
        if (!nfserr) {
2215
                RESERVE_SPACE(sizeof(stateid_t));
2216
                WRITE32(oc->oc_resp_stateid.si_generation);
2217
                WRITEMEM(&oc->oc_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
2218
                ADJUST_ARGS();
2219
        }
2220
 
2221
        ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
2222
}
2223
 
2224
static void
2225
nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
2226
{
2227
        ENCODE_SEQID_OP_HEAD;
2228
 
2229
        if (!nfserr) {
2230
                RESERVE_SPACE(sizeof(stateid_t));
2231
                WRITE32(od->od_stateid.si_generation);
2232
                WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
2233
                ADJUST_ARGS();
2234
        }
2235
 
2236
        ENCODE_SEQID_OP_TAIL(od->od_stateowner);
2237
}
2238
 
2239
static __be32
2240
nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
2241
                  struct nfsd4_read *read)
2242
{
2243
        u32 eof;
2244
        int v, pn;
2245
        unsigned long maxcount;
2246
        long len;
2247
        ENCODE_HEAD;
2248
 
2249
        if (nfserr)
2250
                return nfserr;
2251
        if (resp->xbuf->page_len)
2252
                return nfserr_resource;
2253
 
2254
        RESERVE_SPACE(8); /* eof flag and byte count */
2255
 
2256
        maxcount = svc_max_payload(resp->rqstp);
2257
        if (maxcount > read->rd_length)
2258
                maxcount = read->rd_length;
2259
 
2260
        len = maxcount;
2261
        v = 0;
2262
        while (len > 0) {
2263
                pn = resp->rqstp->rq_resused++;
2264
                resp->rqstp->rq_vec[v].iov_base =
2265
                        page_address(resp->rqstp->rq_respages[pn]);
2266
                resp->rqstp->rq_vec[v].iov_len =
2267
                        len < PAGE_SIZE ? len : PAGE_SIZE;
2268
                v++;
2269
                len -= PAGE_SIZE;
2270
        }
2271
        read->rd_vlen = v;
2272
 
2273
        nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
2274
                        read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
2275
                        &maxcount);
2276
 
2277
        if (nfserr == nfserr_symlink)
2278
                nfserr = nfserr_inval;
2279
        if (nfserr)
2280
                return nfserr;
2281
        eof = (read->rd_offset + maxcount >=
2282
               read->rd_fhp->fh_dentry->d_inode->i_size);
2283
 
2284
        WRITE32(eof);
2285
        WRITE32(maxcount);
2286
        ADJUST_ARGS();
2287
        resp->xbuf->head[0].iov_len = (char*)p
2288
                                        - (char*)resp->xbuf->head[0].iov_base;
2289
        resp->xbuf->page_len = maxcount;
2290
 
2291
        /* Use rest of head for padding and remaining ops: */
2292
        resp->xbuf->tail[0].iov_base = p;
2293
        resp->xbuf->tail[0].iov_len = 0;
2294
        if (maxcount&3) {
2295
                RESERVE_SPACE(4);
2296
                WRITE32(0);
2297
                resp->xbuf->tail[0].iov_base += maxcount&3;
2298
                resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
2299
                ADJUST_ARGS();
2300
        }
2301
        return 0;
2302
}
2303
 
2304
static __be32
2305
nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
2306
{
2307
        int maxcount;
2308
        char *page;
2309
        ENCODE_HEAD;
2310
 
2311
        if (nfserr)
2312
                return nfserr;
2313
        if (resp->xbuf->page_len)
2314
                return nfserr_resource;
2315
 
2316
        page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
2317
 
2318
        maxcount = PAGE_SIZE;
2319
        RESERVE_SPACE(4);
2320
 
2321
        /*
2322
         * XXX: By default, the ->readlink() VFS op will truncate symlinks
2323
         * if they would overflow the buffer.  Is this kosher in NFSv4?  If
2324
         * not, one easy fix is: if ->readlink() precisely fills the buffer,
2325
         * assume that truncation occurred, and return NFS4ERR_RESOURCE.
2326
         */
2327
        nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount);
2328
        if (nfserr == nfserr_isdir)
2329
                return nfserr_inval;
2330
        if (nfserr)
2331
                return nfserr;
2332
 
2333
        WRITE32(maxcount);
2334
        ADJUST_ARGS();
2335
        resp->xbuf->head[0].iov_len = (char*)p
2336
                                - (char*)resp->xbuf->head[0].iov_base;
2337
        resp->xbuf->page_len = maxcount;
2338
 
2339
        /* Use rest of head for padding and remaining ops: */
2340
        resp->xbuf->tail[0].iov_base = p;
2341
        resp->xbuf->tail[0].iov_len = 0;
2342
        if (maxcount&3) {
2343
                RESERVE_SPACE(4);
2344
                WRITE32(0);
2345
                resp->xbuf->tail[0].iov_base += maxcount&3;
2346
                resp->xbuf->tail[0].iov_len = 4 - (maxcount&3);
2347
                ADJUST_ARGS();
2348
        }
2349
        return 0;
2350
}
2351
 
2352
static __be32
2353
nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
2354
{
2355
        int maxcount;
2356
        loff_t offset;
2357
        __be32 *page, *savep, *tailbase;
2358
        ENCODE_HEAD;
2359
 
2360
        if (nfserr)
2361
                return nfserr;
2362
        if (resp->xbuf->page_len)
2363
                return nfserr_resource;
2364
 
2365
        RESERVE_SPACE(8);  /* verifier */
2366
        savep = p;
2367
 
2368
        /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
2369
        WRITE32(0);
2370
        WRITE32(0);
2371
        ADJUST_ARGS();
2372
        resp->xbuf->head[0].iov_len = ((char*)resp->p) - (char*)resp->xbuf->head[0].iov_base;
2373
        tailbase = p;
2374
 
2375
        maxcount = PAGE_SIZE;
2376
        if (maxcount > readdir->rd_maxcount)
2377
                maxcount = readdir->rd_maxcount;
2378
 
2379
        /*
2380
         * Convert from bytes to words, account for the two words already
2381
         * written, make sure to leave two words at the end for the next
2382
         * pointer and eof field.
2383
         */
2384
        maxcount = (maxcount >> 2) - 4;
2385
        if (maxcount < 0) {
2386
                nfserr =  nfserr_toosmall;
2387
                goto err_no_verf;
2388
        }
2389
 
2390
        page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
2391
        readdir->common.err = 0;
2392
        readdir->buflen = maxcount;
2393
        readdir->buffer = page;
2394
        readdir->offset = NULL;
2395
 
2396
        offset = readdir->rd_cookie;
2397
        nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
2398
                              &offset,
2399
                              &readdir->common, nfsd4_encode_dirent);
2400
        if (nfserr == nfs_ok &&
2401
            readdir->common.err == nfserr_toosmall &&
2402
            readdir->buffer == page)
2403
                nfserr = nfserr_toosmall;
2404
        if (nfserr == nfserr_symlink)
2405
                nfserr = nfserr_notdir;
2406
        if (nfserr)
2407
                goto err_no_verf;
2408
 
2409
        if (readdir->offset)
2410
                xdr_encode_hyper(readdir->offset, offset);
2411
 
2412
        p = readdir->buffer;
2413
        *p++ = 0;        /* no more entries */
2414
        *p++ = htonl(readdir->common.err == nfserr_eof);
2415
        resp->xbuf->page_len = ((char*)p) - (char*)page_address(
2416
                resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
2417
 
2418
        /* Use rest of head for padding and remaining ops: */
2419
        resp->xbuf->tail[0].iov_base = tailbase;
2420
        resp->xbuf->tail[0].iov_len = 0;
2421
        resp->p = resp->xbuf->tail[0].iov_base;
2422
        resp->end = resp->p + (PAGE_SIZE - resp->xbuf->head[0].iov_len)/4;
2423
 
2424
        return 0;
2425
err_no_verf:
2426
        p = savep;
2427
        ADJUST_ARGS();
2428
        return nfserr;
2429
}
2430
 
2431
static void
2432
nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
2433
{
2434
        ENCODE_HEAD;
2435
 
2436
        if (!nfserr) {
2437
                RESERVE_SPACE(20);
2438
                WRITECINFO(remove->rm_cinfo);
2439
                ADJUST_ARGS();
2440
        }
2441
}
2442
 
2443
static void
2444
nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
2445
{
2446
        ENCODE_HEAD;
2447
 
2448
        if (!nfserr) {
2449
                RESERVE_SPACE(40);
2450
                WRITECINFO(rename->rn_sinfo);
2451
                WRITECINFO(rename->rn_tinfo);
2452
                ADJUST_ARGS();
2453
        }
2454
}
2455
 
2456
static void
2457
nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
2458
                     struct nfsd4_secinfo *secinfo)
2459
{
2460
        int i = 0;
2461
        struct svc_export *exp = secinfo->si_exp;
2462
        u32 nflavs;
2463
        struct exp_flavor_info *flavs;
2464
        struct exp_flavor_info def_flavs[2];
2465
        ENCODE_HEAD;
2466
 
2467
        if (nfserr)
2468
                goto out;
2469
        if (exp->ex_nflavors) {
2470
                flavs = exp->ex_flavors;
2471
                nflavs = exp->ex_nflavors;
2472
        } else { /* Handling of some defaults in absence of real secinfo: */
2473
                flavs = def_flavs;
2474
                if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
2475
                        nflavs = 2;
2476
                        flavs[0].pseudoflavor = RPC_AUTH_UNIX;
2477
                        flavs[1].pseudoflavor = RPC_AUTH_NULL;
2478
                } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
2479
                        nflavs = 1;
2480
                        flavs[0].pseudoflavor
2481
                                        = svcauth_gss_flavor(exp->ex_client);
2482
                } else {
2483
                        nflavs = 1;
2484
                        flavs[0].pseudoflavor
2485
                                        = exp->ex_client->flavour->flavour;
2486
                }
2487
        }
2488
 
2489
        RESERVE_SPACE(4);
2490
        WRITE32(nflavs);
2491
        ADJUST_ARGS();
2492
        for (i = 0; i < nflavs; i++) {
2493
                u32 flav = flavs[i].pseudoflavor;
2494
                struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
2495
 
2496
                if (gm) {
2497
                        RESERVE_SPACE(4);
2498
                        WRITE32(RPC_AUTH_GSS);
2499
                        ADJUST_ARGS();
2500
                        RESERVE_SPACE(4 + gm->gm_oid.len);
2501
                        WRITE32(gm->gm_oid.len);
2502
                        WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
2503
                        ADJUST_ARGS();
2504
                        RESERVE_SPACE(4);
2505
                        WRITE32(0); /* qop */
2506
                        ADJUST_ARGS();
2507
                        RESERVE_SPACE(4);
2508
                        WRITE32(gss_pseudoflavor_to_service(gm, flav));
2509
                        ADJUST_ARGS();
2510
                        gss_mech_put(gm);
2511
                } else {
2512
                        RESERVE_SPACE(4);
2513
                        WRITE32(flav);
2514
                        ADJUST_ARGS();
2515
                }
2516
        }
2517
out:
2518
        if (exp)
2519
                exp_put(exp);
2520
}
2521
 
2522
/*
2523
 * The SETATTR encode routine is special -- it always encodes a bitmap,
2524
 * regardless of the error status.
2525
 */
2526
static void
2527
nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
2528
{
2529
        ENCODE_HEAD;
2530
 
2531
        RESERVE_SPACE(12);
2532
        if (nfserr) {
2533
                WRITE32(2);
2534
                WRITE32(0);
2535
                WRITE32(0);
2536
        }
2537
        else {
2538
                WRITE32(2);
2539
                WRITE32(setattr->sa_bmval[0]);
2540
                WRITE32(setattr->sa_bmval[1]);
2541
        }
2542
        ADJUST_ARGS();
2543
}
2544
 
2545
static void
2546
nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
2547
{
2548
        ENCODE_HEAD;
2549
 
2550
        if (!nfserr) {
2551
                RESERVE_SPACE(8 + sizeof(nfs4_verifier));
2552
                WRITEMEM(&scd->se_clientid, 8);
2553
                WRITEMEM(&scd->se_confirm, sizeof(nfs4_verifier));
2554
                ADJUST_ARGS();
2555
        }
2556
        else if (nfserr == nfserr_clid_inuse) {
2557
                RESERVE_SPACE(8);
2558
                WRITE32(0);
2559
                WRITE32(0);
2560
                ADJUST_ARGS();
2561
        }
2562
}
2563
 
2564
static void
2565
nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
2566
{
2567
        ENCODE_HEAD;
2568
 
2569
        if (!nfserr) {
2570
                RESERVE_SPACE(16);
2571
                WRITE32(write->wr_bytes_written);
2572
                WRITE32(write->wr_how_written);
2573
                WRITEMEM(write->wr_verifier.data, 8);
2574
                ADJUST_ARGS();
2575
        }
2576
}
2577
 
2578
void
2579
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
2580
{
2581
        __be32 *statp;
2582
        ENCODE_HEAD;
2583
 
2584
        RESERVE_SPACE(8);
2585
        WRITE32(op->opnum);
2586
        statp = p++;    /* to be backfilled at the end */
2587
        ADJUST_ARGS();
2588
 
2589
        switch (op->opnum) {
2590
        case OP_ACCESS:
2591
                nfsd4_encode_access(resp, op->status, &op->u.access);
2592
                break;
2593
        case OP_CLOSE:
2594
                nfsd4_encode_close(resp, op->status, &op->u.close);
2595
                break;
2596
        case OP_COMMIT:
2597
                nfsd4_encode_commit(resp, op->status, &op->u.commit);
2598
                break;
2599
        case OP_CREATE:
2600
                nfsd4_encode_create(resp, op->status, &op->u.create);
2601
                break;
2602
        case OP_DELEGRETURN:
2603
                break;
2604
        case OP_GETATTR:
2605
                op->status = nfsd4_encode_getattr(resp, op->status, &op->u.getattr);
2606
                break;
2607
        case OP_GETFH:
2608
                nfsd4_encode_getfh(resp, op->status, op->u.getfh);
2609
                break;
2610
        case OP_LINK:
2611
                nfsd4_encode_link(resp, op->status, &op->u.link);
2612
                break;
2613
        case OP_LOCK:
2614
                nfsd4_encode_lock(resp, op->status, &op->u.lock);
2615
                break;
2616
        case OP_LOCKT:
2617
                nfsd4_encode_lockt(resp, op->status, &op->u.lockt);
2618
                break;
2619
        case OP_LOCKU:
2620
                nfsd4_encode_locku(resp, op->status, &op->u.locku);
2621
                break;
2622
        case OP_LOOKUP:
2623
                break;
2624
        case OP_LOOKUPP:
2625
                break;
2626
        case OP_NVERIFY:
2627
                break;
2628
        case OP_OPEN:
2629
                nfsd4_encode_open(resp, op->status, &op->u.open);
2630
                break;
2631
        case OP_OPEN_CONFIRM:
2632
                nfsd4_encode_open_confirm(resp, op->status, &op->u.open_confirm);
2633
                break;
2634
        case OP_OPEN_DOWNGRADE:
2635
                nfsd4_encode_open_downgrade(resp, op->status, &op->u.open_downgrade);
2636
                break;
2637
        case OP_PUTFH:
2638
                break;
2639
        case OP_PUTROOTFH:
2640
                break;
2641
        case OP_READ:
2642
                op->status = nfsd4_encode_read(resp, op->status, &op->u.read);
2643
                break;
2644
        case OP_READDIR:
2645
                op->status = nfsd4_encode_readdir(resp, op->status, &op->u.readdir);
2646
                break;
2647
        case OP_READLINK:
2648
                op->status = nfsd4_encode_readlink(resp, op->status, &op->u.readlink);
2649
                break;
2650
        case OP_REMOVE:
2651
                nfsd4_encode_remove(resp, op->status, &op->u.remove);
2652
                break;
2653
        case OP_RENAME:
2654
                nfsd4_encode_rename(resp, op->status, &op->u.rename);
2655
                break;
2656
        case OP_RENEW:
2657
                break;
2658
        case OP_RESTOREFH:
2659
                break;
2660
        case OP_SAVEFH:
2661
                break;
2662
        case OP_SECINFO:
2663
                nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
2664
                break;
2665
        case OP_SETATTR:
2666
                nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
2667
                break;
2668
        case OP_SETCLIENTID:
2669
                nfsd4_encode_setclientid(resp, op->status, &op->u.setclientid);
2670
                break;
2671
        case OP_SETCLIENTID_CONFIRM:
2672
                break;
2673
        case OP_VERIFY:
2674
                break;
2675
        case OP_WRITE:
2676
                nfsd4_encode_write(resp, op->status, &op->u.write);
2677
                break;
2678
        case OP_RELEASE_LOCKOWNER:
2679
                break;
2680
        default:
2681
                break;
2682
        }
2683
 
2684
        /*
2685
         * Note: We write the status directly, instead of using WRITE32(),
2686
         * since it is already in network byte order.
2687
         */
2688
        *statp = op->status;
2689
}
2690
 
2691
/*
2692
 * Encode the reply stored in the stateowner reply cache
2693
 *
2694
 * XDR note: do not encode rp->rp_buflen: the buffer contains the
2695
 * previously sent already encoded operation.
2696
 *
2697
 * called with nfs4_lock_state() held
2698
 */
2699
void
2700
nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
2701
{
2702
        ENCODE_HEAD;
2703
        struct nfs4_replay *rp = op->replay;
2704
 
2705
        BUG_ON(!rp);
2706
 
2707
        RESERVE_SPACE(8);
2708
        WRITE32(op->opnum);
2709
        *p++ = rp->rp_status;  /* already xdr'ed */
2710
        ADJUST_ARGS();
2711
 
2712
        RESERVE_SPACE(rp->rp_buflen);
2713
        WRITEMEM(rp->rp_buf, rp->rp_buflen);
2714
        ADJUST_ARGS();
2715
}
2716
 
2717
/*
2718
 * END OF "GENERIC" ENCODE ROUTINES.
2719
 */
2720
 
2721
int
2722
nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
2723
{
2724
        return xdr_ressize_check(rqstp, p);
2725
}
2726
 
2727
void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
2728
{
2729
        if (args->ops != args->iops) {
2730
                kfree(args->ops);
2731
                args->ops = args->iops;
2732
        }
2733
        kfree(args->tmpp);
2734
        args->tmpp = NULL;
2735
        while (args->to_free) {
2736
                struct tmpbuf *tb = args->to_free;
2737
                args->to_free = tb->next;
2738
                tb->release(tb->buf);
2739
                kfree(tb);
2740
        }
2741
}
2742
 
2743
int
2744
nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
2745
{
2746
        __be32 status;
2747
 
2748
        args->p = p;
2749
        args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
2750
        args->pagelist = rqstp->rq_arg.pages;
2751
        args->pagelen = rqstp->rq_arg.page_len;
2752
        args->tmpp = NULL;
2753
        args->to_free = NULL;
2754
        args->ops = args->iops;
2755
        args->rqstp = rqstp;
2756
 
2757
        status = nfsd4_decode_compound(args);
2758
        if (status) {
2759
                nfsd4_release_compoundargs(args);
2760
        }
2761
        return !status;
2762
}
2763
 
2764
int
2765
nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
2766
{
2767
        /*
2768
         * All that remains is to write the tag and operation count...
2769
         */
2770
        struct kvec *iov;
2771
        p = resp->tagp;
2772
        *p++ = htonl(resp->taglen);
2773
        memcpy(p, resp->tag, resp->taglen);
2774
        p += XDR_QUADLEN(resp->taglen);
2775
        *p++ = htonl(resp->opcnt);
2776
 
2777
        if (rqstp->rq_res.page_len)
2778
                iov = &rqstp->rq_res.tail[0];
2779
        else
2780
                iov = &rqstp->rq_res.head[0];
2781
        iov->iov_len = ((char*)resp->p) - (char*)iov->iov_base;
2782
        BUG_ON(iov->iov_len > PAGE_SIZE);
2783
        return 1;
2784
}
2785
 
2786
/*
2787
 * Local variables:
2788
 *  c-basic-offset: 8
2789
 * End:
2790
 */

powered by: WebSVN 2.1.0

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