Root/fs/nfsd/nfs4proc.c

1/*
2 * Server-side procedures for NFSv4.
3 *
4 * Copyright (c) 2002 The Regents of the University of Michigan.
5 * All rights reserved.
6 *
7 * Kendrick Smith <kmsmith@umich.edu>
8 * Andy Adamson <andros@umich.edu>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35#include <linux/file.h>
36#include <linux/slab.h>
37
38#include "cache.h"
39#include "xdr4.h"
40#include "vfs.h"
41
42#define NFSDDBG_FACILITY NFSDDBG_PROC
43
44static u32 nfsd_attrmask[] = {
45    NFSD_WRITEABLE_ATTRS_WORD0,
46    NFSD_WRITEABLE_ATTRS_WORD1,
47    NFSD_WRITEABLE_ATTRS_WORD2
48};
49
50static u32 nfsd41_ex_attrmask[] = {
51    NFSD_SUPPATTR_EXCLCREAT_WORD0,
52    NFSD_SUPPATTR_EXCLCREAT_WORD1,
53    NFSD_SUPPATTR_EXCLCREAT_WORD2
54};
55
56static __be32
57check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
58           u32 *bmval, u32 *writable)
59{
60    struct dentry *dentry = cstate->current_fh.fh_dentry;
61
62    /*
63     * Check about attributes are supported by the NFSv4 server or not.
64     * According to spec, unsupported attributes return ERR_ATTRNOTSUPP.
65     */
66    if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) ||
67        (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) ||
68        (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
69        return nfserr_attrnotsupp;
70
71    /*
72     * Check FATTR4_WORD0_ACL can be supported
73     * in current environment or not.
74     */
75    if (bmval[0] & FATTR4_WORD0_ACL) {
76        if (!IS_POSIXACL(dentry->d_inode))
77            return nfserr_attrnotsupp;
78    }
79
80    /*
81     * According to spec, read-only attributes return ERR_INVAL.
82     */
83    if (writable) {
84        if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
85            (bmval[2] & ~writable[2]))
86            return nfserr_inval;
87    }
88
89    return nfs_ok;
90}
91
92static __be32
93nfsd4_check_open_attributes(struct svc_rqst *rqstp,
94    struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
95{
96    __be32 status = nfs_ok;
97
98    if (open->op_create == NFS4_OPEN_CREATE) {
99        if (open->op_createmode == NFS4_CREATE_UNCHECKED
100            || open->op_createmode == NFS4_CREATE_GUARDED)
101            status = check_attr_support(rqstp, cstate,
102                    open->op_bmval, nfsd_attrmask);
103        else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
104            status = check_attr_support(rqstp, cstate,
105                    open->op_bmval, nfsd41_ex_attrmask);
106    }
107
108    return status;
109}
110
111static int
112is_create_with_attrs(struct nfsd4_open *open)
113{
114    return open->op_create == NFS4_OPEN_CREATE
115        && (open->op_createmode == NFS4_CREATE_UNCHECKED
116            || open->op_createmode == NFS4_CREATE_GUARDED
117            || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
118}
119
120/*
121 * if error occurs when setting the acl, just clear the acl bit
122 * in the returned attr bitmap.
123 */
124static void
125do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
126        struct nfs4_acl *acl, u32 *bmval)
127{
128    __be32 status;
129
130    status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
131    if (status)
132        /*
133         * We should probably fail the whole open at this point,
134         * but we've already created the file, so it's too late;
135         * So this seems the least of evils:
136         */
137        bmval[0] &= ~FATTR4_WORD0_ACL;
138}
139
140static inline void
141fh_dup2(struct svc_fh *dst, struct svc_fh *src)
142{
143    fh_put(dst);
144    dget(src->fh_dentry);
145    if (src->fh_export)
146        cache_get(&src->fh_export->h);
147    *dst = *src;
148}
149
150static __be32
151do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
152{
153    __be32 status;
154
155    if (open->op_truncate &&
156        !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
157        return nfserr_inval;
158
159    if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
160        accmode |= NFSD_MAY_READ;
161    if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
162        accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
163    if (open->op_share_deny & NFS4_SHARE_DENY_READ)
164        accmode |= NFSD_MAY_WRITE;
165
166    status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
167
168    return status;
169}
170
171static __be32
172do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
173{
174    struct svc_fh resfh;
175    __be32 status;
176    int created = 0;
177
178    fh_init(&resfh, NFS4_FHSIZE);
179    open->op_truncate = 0;
180
181    if (open->op_create) {
182        /* FIXME: check session persistence and pnfs flags.
183         * The nfsv4.1 spec requires the following semantics:
184         *
185         * Persistent | pNFS | Server REQUIRED | Client Allowed
186         * Reply Cache | server | |
187         * -------------+--------+-----------------+--------------------
188         * no | no | EXCLUSIVE4_1 | EXCLUSIVE4_1
189         * | | | (SHOULD)
190         * | | and EXCLUSIVE4 | or EXCLUSIVE4
191         * | | | (SHOULD NOT)
192         * no | yes | EXCLUSIVE4_1 | EXCLUSIVE4_1
193         * yes | no | GUARDED4 | GUARDED4
194         * yes | yes | GUARDED4 | GUARDED4
195         */
196
197        /*
198         * Note: create modes (UNCHECKED,GUARDED...) are the same
199         * in NFSv4 as in v3 except EXCLUSIVE4_1.
200         */
201        status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
202                    open->op_fname.len, &open->op_iattr,
203                    &resfh, open->op_createmode,
204                    (u32 *)open->op_verf.data,
205                    &open->op_truncate, &created);
206
207        /*
208         * Following rfc 3530 14.2.16, use the returned bitmask
209         * to indicate which attributes we used to store the
210         * verifier:
211         */
212        if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
213            open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
214                        FATTR4_WORD1_TIME_MODIFY);
215    } else {
216        status = nfsd_lookup(rqstp, current_fh,
217                     open->op_fname.data, open->op_fname.len, &resfh);
218        fh_unlock(current_fh);
219    }
220    if (status)
221        goto out;
222
223    if (is_create_with_attrs(open) && open->op_acl != NULL)
224        do_set_nfs4_acl(rqstp, &resfh, open->op_acl, open->op_bmval);
225
226    set_change_info(&open->op_cinfo, current_fh);
227    fh_dup2(current_fh, &resfh);
228
229    /* set reply cache */
230    fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
231            &resfh.fh_handle);
232    if (!created)
233        status = do_open_permission(rqstp, current_fh, open,
234                        NFSD_MAY_NOP);
235
236out:
237    fh_put(&resfh);
238    return status;
239}
240
241static __be32
242do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
243{
244    __be32 status;
245
246    /* Only reclaims from previously confirmed clients are valid */
247    if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
248        return status;
249
250    /* We don't know the target directory, and therefore can not
251    * set the change info
252    */
253
254    memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
255
256    /* set replay cache */
257    fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
258            &current_fh->fh_handle);
259
260    open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
261        (open->op_iattr.ia_size == 0);
262
263    status = do_open_permission(rqstp, current_fh, open,
264                    NFSD_MAY_OWNER_OVERRIDE);
265
266    return status;
267}
268
269static void
270copy_clientid(clientid_t *clid, struct nfsd4_session *session)
271{
272    struct nfsd4_sessionid *sid =
273            (struct nfsd4_sessionid *)session->se_sessionid.data;
274
275    clid->cl_boot = sid->clientid.cl_boot;
276    clid->cl_id = sid->clientid.cl_id;
277}
278
279static __be32
280nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
281       struct nfsd4_open *open)
282{
283    __be32 status;
284    struct nfsd4_compoundres *resp;
285
286    dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
287        (int)open->op_fname.len, open->op_fname.data,
288        open->op_stateowner);
289
290    /* This check required by spec. */
291    if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
292        return nfserr_inval;
293
294    if (nfsd4_has_session(cstate))
295        copy_clientid(&open->op_clientid, cstate->session);
296
297    nfs4_lock_state();
298
299    /* check seqid for replay. set nfs4_owner */
300    resp = rqstp->rq_resp;
301    status = nfsd4_process_open1(&resp->cstate, open);
302    if (status == nfserr_replay_me) {
303        struct nfs4_replay *rp = &open->op_stateowner->so_replay;
304        fh_put(&cstate->current_fh);
305        fh_copy_shallow(&cstate->current_fh.fh_handle,
306                &rp->rp_openfh);
307        status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
308        if (status)
309            dprintk("nfsd4_open: replay failed"
310                " restoring previous filehandle\n");
311        else
312            status = nfserr_replay_me;
313    }
314    if (status)
315        goto out;
316
317    status = nfsd4_check_open_attributes(rqstp, cstate, open);
318    if (status)
319        goto out;
320
321    /* Openowner is now set, so sequence id will get bumped. Now we need
322     * these checks before we do any creates: */
323    status = nfserr_grace;
324    if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
325        goto out;
326    status = nfserr_no_grace;
327    if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
328        goto out;
329
330    switch (open->op_claim_type) {
331        case NFS4_OPEN_CLAIM_DELEGATE_CUR:
332        case NFS4_OPEN_CLAIM_NULL:
333            /*
334             * (1) set CURRENT_FH to the file being opened,
335             * creating it if necessary, (2) set open->op_cinfo,
336             * (3) set open->op_truncate if the file is to be
337             * truncated after opening, (4) do permission checking.
338             */
339            status = do_open_lookup(rqstp, &cstate->current_fh,
340                        open);
341            if (status)
342                goto out;
343            break;
344        case NFS4_OPEN_CLAIM_PREVIOUS:
345            open->op_stateowner->so_confirmed = 1;
346            /*
347             * The CURRENT_FH is already set to the file being
348             * opened. (1) set open->op_cinfo, (2) set
349             * open->op_truncate if the file is to be truncated
350             * after opening, (3) do permission checking.
351            */
352            status = do_open_fhandle(rqstp, &cstate->current_fh,
353                         open);
354            if (status)
355                goto out;
356            break;
357                 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
358            open->op_stateowner->so_confirmed = 1;
359            dprintk("NFSD: unsupported OPEN claim type %d\n",
360                open->op_claim_type);
361            status = nfserr_notsupp;
362            goto out;
363        default:
364            dprintk("NFSD: Invalid OPEN claim type %d\n",
365                open->op_claim_type);
366            status = nfserr_inval;
367            goto out;
368    }
369    /*
370     * nfsd4_process_open2() does the actual opening of the file. If
371     * successful, it (1) truncates the file if open->op_truncate was
372     * set, (2) sets open->op_stateid, (3) sets open->op_delegation.
373     */
374    status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
375out:
376    if (open->op_stateowner) {
377        nfs4_get_stateowner(open->op_stateowner);
378        cstate->replay_owner = open->op_stateowner;
379    }
380    nfs4_unlock_state();
381    return status;
382}
383
384/*
385 * filehandle-manipulating ops.
386 */
387static __be32
388nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
389        struct svc_fh **getfh)
390{
391    if (!cstate->current_fh.fh_dentry)
392        return nfserr_nofilehandle;
393
394    *getfh = &cstate->current_fh;
395    return nfs_ok;
396}
397
398static __be32
399nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
400        struct nfsd4_putfh *putfh)
401{
402    fh_put(&cstate->current_fh);
403    cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
404    memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
405           putfh->pf_fhlen);
406    return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
407}
408
409static __be32
410nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
411        void *arg)
412{
413    __be32 status;
414
415    fh_put(&cstate->current_fh);
416    status = exp_pseudoroot(rqstp, &cstate->current_fh);
417    return status;
418}
419
420static __be32
421nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
422        void *arg)
423{
424    if (!cstate->save_fh.fh_dentry)
425        return nfserr_restorefh;
426
427    fh_dup2(&cstate->current_fh, &cstate->save_fh);
428    return nfs_ok;
429}
430
431static __be32
432nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
433         void *arg)
434{
435    if (!cstate->current_fh.fh_dentry)
436        return nfserr_nofilehandle;
437
438    fh_dup2(&cstate->save_fh, &cstate->current_fh);
439    return nfs_ok;
440}
441
442/*
443 * misc nfsv4 ops
444 */
445static __be32
446nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
447         struct nfsd4_access *access)
448{
449    if (access->ac_req_access & ~NFS3_ACCESS_FULL)
450        return nfserr_inval;
451
452    access->ac_resp_access = access->ac_req_access;
453    return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
454               &access->ac_supported);
455}
456
457static __be32
458nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
459         struct nfsd4_commit *commit)
460{
461    __be32 status;
462
463    u32 *p = (u32 *)commit->co_verf.data;
464    *p++ = nfssvc_boot.tv_sec;
465    *p++ = nfssvc_boot.tv_usec;
466
467    status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
468                 commit->co_count);
469    if (status == nfserr_symlink)
470        status = nfserr_inval;
471    return status;
472}
473
474static __be32
475nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
476         struct nfsd4_create *create)
477{
478    struct svc_fh resfh;
479    __be32 status;
480    dev_t rdev;
481
482    fh_init(&resfh, NFS4_FHSIZE);
483
484    status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
485               NFSD_MAY_CREATE);
486    if (status == nfserr_symlink)
487        status = nfserr_notdir;
488    if (status)
489        return status;
490
491    status = check_attr_support(rqstp, cstate, create->cr_bmval,
492                    nfsd_attrmask);
493    if (status)
494        return status;
495
496    switch (create->cr_type) {
497    case NF4LNK:
498        /* ugh! we have to null-terminate the linktext, or
499         * vfs_symlink() will choke. it is always safe to
500         * null-terminate by brute force, since at worst we
501         * will overwrite the first byte of the create namelen
502         * in the XDR buffer, which has already been extracted
503         * during XDR decode.
504         */
505        create->cr_linkname[create->cr_linklen] = 0;
506
507        status = nfsd_symlink(rqstp, &cstate->current_fh,
508                      create->cr_name, create->cr_namelen,
509                      create->cr_linkname, create->cr_linklen,
510                      &resfh, &create->cr_iattr);
511        break;
512
513    case NF4BLK:
514        rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
515        if (MAJOR(rdev) != create->cr_specdata1 ||
516            MINOR(rdev) != create->cr_specdata2)
517            return nfserr_inval;
518        status = nfsd_create(rqstp, &cstate->current_fh,
519                     create->cr_name, create->cr_namelen,
520                     &create->cr_iattr, S_IFBLK, rdev, &resfh);
521        break;
522
523    case NF4CHR:
524        rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
525        if (MAJOR(rdev) != create->cr_specdata1 ||
526            MINOR(rdev) != create->cr_specdata2)
527            return nfserr_inval;
528        status = nfsd_create(rqstp, &cstate->current_fh,
529                     create->cr_name, create->cr_namelen,
530                     &create->cr_iattr,S_IFCHR, rdev, &resfh);
531        break;
532
533    case NF4SOCK:
534        status = nfsd_create(rqstp, &cstate->current_fh,
535                     create->cr_name, create->cr_namelen,
536                     &create->cr_iattr, S_IFSOCK, 0, &resfh);
537        break;
538
539    case NF4FIFO:
540        status = nfsd_create(rqstp, &cstate->current_fh,
541                     create->cr_name, create->cr_namelen,
542                     &create->cr_iattr, S_IFIFO, 0, &resfh);
543        break;
544
545    case NF4DIR:
546        create->cr_iattr.ia_valid &= ~ATTR_SIZE;
547        status = nfsd_create(rqstp, &cstate->current_fh,
548                     create->cr_name, create->cr_namelen,
549                     &create->cr_iattr, S_IFDIR, 0, &resfh);
550        break;
551
552    default:
553        status = nfserr_badtype;
554    }
555
556    if (status)
557        goto out;
558
559    if (create->cr_acl != NULL)
560        do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
561                create->cr_bmval);
562
563    fh_unlock(&cstate->current_fh);
564    set_change_info(&create->cr_cinfo, &cstate->current_fh);
565    fh_dup2(&cstate->current_fh, &resfh);
566out:
567    fh_put(&resfh);
568    return status;
569}
570
571static __be32
572nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
573          struct nfsd4_getattr *getattr)
574{
575    __be32 status;
576
577    status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
578    if (status)
579        return status;
580
581    if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
582        return nfserr_inval;
583
584    getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
585    getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
586    getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
587
588    getattr->ga_fhp = &cstate->current_fh;
589    return nfs_ok;
590}
591
592static __be32
593nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
594       struct nfsd4_link *link)
595{
596    __be32 status = nfserr_nofilehandle;
597
598    if (!cstate->save_fh.fh_dentry)
599        return status;
600    status = nfsd_link(rqstp, &cstate->current_fh,
601               link->li_name, link->li_namelen, &cstate->save_fh);
602    if (!status)
603        set_change_info(&link->li_cinfo, &cstate->current_fh);
604    return status;
605}
606
607static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
608{
609    struct svc_fh tmp_fh;
610    __be32 ret;
611
612    fh_init(&tmp_fh, NFS4_FHSIZE);
613    ret = exp_pseudoroot(rqstp, &tmp_fh);
614    if (ret)
615        return ret;
616    if (tmp_fh.fh_dentry == fh->fh_dentry) {
617        fh_put(&tmp_fh);
618        return nfserr_noent;
619    }
620    fh_put(&tmp_fh);
621    return nfsd_lookup(rqstp, fh, "..", 2, fh);
622}
623
624static __be32
625nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
626          void *arg)
627{
628    return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
629}
630
631static __be32
632nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
633         struct nfsd4_lookup *lookup)
634{
635    return nfsd_lookup(rqstp, &cstate->current_fh,
636               lookup->lo_name, lookup->lo_len,
637               &cstate->current_fh);
638}
639
640static __be32
641nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
642       struct nfsd4_read *read)
643{
644    __be32 status;
645
646    /* no need to check permission - this will be done in nfsd_read() */
647
648    read->rd_filp = NULL;
649    if (read->rd_offset >= OFFSET_MAX)
650        return nfserr_inval;
651
652    nfs4_lock_state();
653    /* check stateid */
654    if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid,
655                         RD_STATE, &read->rd_filp))) {
656        dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
657        goto out;
658    }
659    if (read->rd_filp)
660        get_file(read->rd_filp);
661    status = nfs_ok;
662out:
663    nfs4_unlock_state();
664    read->rd_rqstp = rqstp;
665    read->rd_fhp = &cstate->current_fh;
666    return status;
667}
668
669static __be32
670nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
671          struct nfsd4_readdir *readdir)
672{
673    u64 cookie = readdir->rd_cookie;
674    static const nfs4_verifier zeroverf;
675
676    /* no need to check permission - this will be done in nfsd_readdir() */
677
678    if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
679        return nfserr_inval;
680
681    readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
682    readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
683    readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
684
685    if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
686        (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
687        return nfserr_bad_cookie;
688
689    readdir->rd_rqstp = rqstp;
690    readdir->rd_fhp = &cstate->current_fh;
691    return nfs_ok;
692}
693
694static __be32
695nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
696           struct nfsd4_readlink *readlink)
697{
698    readlink->rl_rqstp = rqstp;
699    readlink->rl_fhp = &cstate->current_fh;
700    return nfs_ok;
701}
702
703static __be32
704nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
705         struct nfsd4_remove *remove)
706{
707    __be32 status;
708
709    if (locks_in_grace())
710        return nfserr_grace;
711    status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
712                 remove->rm_name, remove->rm_namelen);
713    if (status == nfserr_symlink)
714        return nfserr_notdir;
715    if (!status) {
716        fh_unlock(&cstate->current_fh);
717        set_change_info(&remove->rm_cinfo, &cstate->current_fh);
718    }
719    return status;
720}
721
722static __be32
723nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
724         struct nfsd4_rename *rename)
725{
726    __be32 status = nfserr_nofilehandle;
727
728    if (!cstate->save_fh.fh_dentry)
729        return status;
730    if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
731                    & NFSEXP_NOSUBTREECHECK))
732        return nfserr_grace;
733    status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
734                 rename->rn_snamelen, &cstate->current_fh,
735                 rename->rn_tname, rename->rn_tnamelen);
736
737    /* the underlying filesystem returns different error's than required
738     * by NFSv4. both save_fh and current_fh have been verified.. */
739    if (status == nfserr_isdir)
740        status = nfserr_exist;
741    else if ((status == nfserr_notdir) &&
742                  (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) &&
743                   S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode)))
744        status = nfserr_exist;
745    else if (status == nfserr_symlink)
746        status = nfserr_notdir;
747
748    if (!status) {
749        set_change_info(&rename->rn_sinfo, &cstate->current_fh);
750        set_change_info(&rename->rn_tinfo, &cstate->save_fh);
751    }
752    return status;
753}
754
755static __be32
756nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
757          struct nfsd4_secinfo *secinfo)
758{
759    struct svc_fh resfh;
760    struct svc_export *exp;
761    struct dentry *dentry;
762    __be32 err;
763
764    fh_init(&resfh, NFS4_FHSIZE);
765    err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC);
766    if (err)
767        return err;
768    err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
769                    secinfo->si_name, secinfo->si_namelen,
770                    &exp, &dentry);
771    if (err)
772        return err;
773    if (dentry->d_inode == NULL) {
774        exp_put(exp);
775        err = nfserr_noent;
776    } else
777        secinfo->si_exp = exp;
778    dput(dentry);
779    if (cstate->minorversion)
780        /* See rfc 5661 section 2.6.3.1.1.8 */
781        fh_put(&cstate->current_fh);
782    return err;
783}
784
785static __be32
786nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
787          struct nfsd4_secinfo_no_name *sin)
788{
789    __be32 err;
790
791    switch (sin->sin_style) {
792    case NFS4_SECINFO_STYLE4_CURRENT_FH:
793        break;
794    case NFS4_SECINFO_STYLE4_PARENT:
795        err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
796        if (err)
797            return err;
798        break;
799    default:
800        return nfserr_inval;
801    }
802    exp_get(cstate->current_fh.fh_export);
803    sin->sin_exp = cstate->current_fh.fh_export;
804    fh_put(&cstate->current_fh);
805    return nfs_ok;
806}
807
808static __be32
809nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
810          struct nfsd4_setattr *setattr)
811{
812    __be32 status = nfs_ok;
813
814    if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
815        nfs4_lock_state();
816        status = nfs4_preprocess_stateid_op(cstate,
817            &setattr->sa_stateid, WR_STATE, NULL);
818        nfs4_unlock_state();
819        if (status) {
820            dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
821            return status;
822        }
823    }
824    status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt);
825    if (status)
826        return status;
827    status = nfs_ok;
828
829    status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
830                    nfsd_attrmask);
831    if (status)
832        goto out;
833
834    if (setattr->sa_acl != NULL)
835        status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
836                        setattr->sa_acl);
837    if (status)
838        goto out;
839    status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
840                0, (time_t)0);
841out:
842    mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt);
843    return status;
844}
845
846static __be32
847nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
848        struct nfsd4_write *write)
849{
850    stateid_t *stateid = &write->wr_stateid;
851    struct file *filp = NULL;
852    u32 *p;
853    __be32 status = nfs_ok;
854    unsigned long cnt;
855
856    /* no need to check permission - this will be done in nfsd_write() */
857
858    if (write->wr_offset >= OFFSET_MAX)
859        return nfserr_inval;
860
861    nfs4_lock_state();
862    status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp);
863    if (filp)
864        get_file(filp);
865    nfs4_unlock_state();
866
867    if (status) {
868        dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
869        return status;
870    }
871
872    cnt = write->wr_buflen;
873    write->wr_how_written = write->wr_stable_how;
874    p = (u32 *)write->wr_verifier.data;
875    *p++ = nfssvc_boot.tv_sec;
876    *p++ = nfssvc_boot.tv_usec;
877
878    status = nfsd_write(rqstp, &cstate->current_fh, filp,
879                 write->wr_offset, rqstp->rq_vec, write->wr_vlen,
880                 &cnt, &write->wr_how_written);
881    if (filp)
882        fput(filp);
883
884    write->wr_bytes_written = cnt;
885
886    if (status == nfserr_symlink)
887        status = nfserr_inval;
888    return status;
889}
890
891/* This routine never returns NFS_OK! If there are no other errors, it
892 * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
893 * attributes matched. VERIFY is implemented by mapping NFSERR_SAME
894 * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
895 */
896static __be32
897_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
898         struct nfsd4_verify *verify)
899{
900    __be32 *buf, *p;
901    int count;
902    __be32 status;
903
904    status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
905    if (status)
906        return status;
907
908    status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
909    if (status)
910        return status;
911
912    if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
913        || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
914        return nfserr_inval;
915    if (verify->ve_attrlen & 3)
916        return nfserr_inval;
917
918    /* count in words:
919     * bitmap_len(1) + bitmap(2) + attr_len(1) = 4
920     */
921    count = 4 + (verify->ve_attrlen >> 2);
922    buf = kmalloc(count << 2, GFP_KERNEL);
923    if (!buf)
924        return nfserr_resource;
925
926    status = nfsd4_encode_fattr(&cstate->current_fh,
927                    cstate->current_fh.fh_export,
928                    cstate->current_fh.fh_dentry, buf,
929                    &count, verify->ve_bmval,
930                    rqstp, 0);
931
932    /* this means that nfsd4_encode_fattr() ran out of space */
933    if (status == nfserr_resource && count == 0)
934        status = nfserr_not_same;
935    if (status)
936        goto out_kfree;
937
938    /* skip bitmap */
939    p = buf + 1 + ntohl(buf[0]);
940    status = nfserr_not_same;
941    if (ntohl(*p++) != verify->ve_attrlen)
942        goto out_kfree;
943    if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen))
944        status = nfserr_same;
945
946out_kfree:
947    kfree(buf);
948    return status;
949}
950
951static __be32
952nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
953          struct nfsd4_verify *verify)
954{
955    __be32 status;
956
957    status = _nfsd4_verify(rqstp, cstate, verify);
958    return status == nfserr_not_same ? nfs_ok : status;
959}
960
961static __be32
962nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
963         struct nfsd4_verify *verify)
964{
965    __be32 status;
966
967    status = _nfsd4_verify(rqstp, cstate, verify);
968    return status == nfserr_same ? nfs_ok : status;
969}
970
971/*
972 * NULL call.
973 */
974static __be32
975nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
976{
977    return nfs_ok;
978}
979
980static inline void nfsd4_increment_op_stats(u32 opnum)
981{
982    if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
983        nfsdstats.nfs4_opcount[opnum]++;
984}
985
986typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
987                  void *);
988enum nfsd4_op_flags {
989    ALLOWED_WITHOUT_FH = 1 << 0, /* No current filehandle required */
990    ALLOWED_ON_ABSENT_FS = 1 << 1, /* ops processed on absent fs */
991    ALLOWED_AS_FIRST_OP = 1 << 2, /* ops reqired first in compound */
992    /* For rfc 5661 section 2.6.3.1.1: */
993    OP_HANDLES_WRONGSEC = 1 << 3,
994    OP_IS_PUTFH_LIKE = 1 << 4,
995};
996
997struct nfsd4_operation {
998    nfsd4op_func op_func;
999    u32 op_flags;
1000    char *op_name;
1001};
1002
1003static struct nfsd4_operation nfsd4_ops[];
1004
1005static const char *nfsd4_op_name(unsigned opnum);
1006
1007/*
1008 * Enforce NFSv4.1 COMPOUND ordering rules:
1009 *
1010 * Also note, enforced elsewhere:
1011 * - SEQUENCE other than as first op results in
1012 * NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
1013 * - BIND_CONN_TO_SESSION must be the only op in its compound.
1014 * (Enforced in nfsd4_bind_conn_to_session().)
1015 * - DESTROY_SESSION must be the final operation in a compound, if
1016 * sessionid's in SEQUENCE and DESTROY_SESSION are the same.
1017 * (Enforced in nfsd4_destroy_session().)
1018 */
1019static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
1020{
1021    struct nfsd4_op *op = &args->ops[0];
1022
1023    /* These ordering requirements don't apply to NFSv4.0: */
1024    if (args->minorversion == 0)
1025        return nfs_ok;
1026    /* This is weird, but OK, not our problem: */
1027    if (args->opcnt == 0)
1028        return nfs_ok;
1029    if (op->status == nfserr_op_illegal)
1030        return nfs_ok;
1031    if (!(nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP))
1032        return nfserr_op_not_in_session;
1033    if (op->opnum == OP_SEQUENCE)
1034        return nfs_ok;
1035    if (args->opcnt != 1)
1036        return nfserr_not_only_op;
1037    return nfs_ok;
1038}
1039
1040static inline struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
1041{
1042    return &nfsd4_ops[op->opnum];
1043}
1044
1045static bool need_wrongsec_check(struct svc_rqst *rqstp)
1046{
1047    struct nfsd4_compoundres *resp = rqstp->rq_resp;
1048    struct nfsd4_compoundargs *argp = rqstp->rq_argp;
1049    struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
1050    struct nfsd4_op *next = &argp->ops[resp->opcnt];
1051    struct nfsd4_operation *thisd;
1052    struct nfsd4_operation *nextd;
1053
1054    thisd = OPDESC(this);
1055    /*
1056     * Most ops check wronsec on our own; only the putfh-like ops
1057     * have special rules.
1058     */
1059    if (!(thisd->op_flags & OP_IS_PUTFH_LIKE))
1060        return false;
1061    /*
1062     * rfc 5661 2.6.3.1.1.6: don't bother erroring out a
1063     * put-filehandle operation if we're not going to use the
1064     * result:
1065     */
1066    if (argp->opcnt == resp->opcnt)
1067        return false;
1068
1069    nextd = OPDESC(next);
1070    /*
1071     * Rest of 2.6.3.1.1: certain operations will return WRONGSEC
1072     * errors themselves as necessary; others should check for them
1073     * now:
1074     */
1075    return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
1076}
1077
1078/*
1079 * COMPOUND call.
1080 */
1081static __be32
1082nfsd4_proc_compound(struct svc_rqst *rqstp,
1083            struct nfsd4_compoundargs *args,
1084            struct nfsd4_compoundres *resp)
1085{
1086    struct nfsd4_op *op;
1087    struct nfsd4_operation *opdesc;
1088    struct nfsd4_compound_state *cstate = &resp->cstate;
1089    int slack_bytes;
1090    __be32 status;
1091
1092    resp->xbuf = &rqstp->rq_res;
1093    resp->p = rqstp->rq_res.head[0].iov_base +
1094                        rqstp->rq_res.head[0].iov_len;
1095    resp->tagp = resp->p;
1096    /* reserve space for: taglen, tag, and opcnt */
1097    resp->p += 2 + XDR_QUADLEN(args->taglen);
1098    resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE;
1099    resp->taglen = args->taglen;
1100    resp->tag = args->tag;
1101    resp->opcnt = 0;
1102    resp->rqstp = rqstp;
1103    resp->cstate.minorversion = args->minorversion;
1104    resp->cstate.replay_owner = NULL;
1105    resp->cstate.session = NULL;
1106    fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
1107    fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
1108    /*
1109     * Don't use the deferral mechanism for NFSv4; compounds make it
1110     * too hard to avoid non-idempotency problems.
1111     */
1112    rqstp->rq_usedeferral = 0;
1113
1114    /*
1115     * According to RFC3010, this takes precedence over all other errors.
1116     */
1117    status = nfserr_minor_vers_mismatch;
1118    if (args->minorversion > nfsd_supported_minorversion)
1119        goto out;
1120
1121    status = nfs41_check_op_ordering(args);
1122    if (status) {
1123        op = &args->ops[0];
1124        op->status = status;
1125        goto encode_op;
1126    }
1127
1128    while (!status && resp->opcnt < args->opcnt) {
1129        op = &args->ops[resp->opcnt++];
1130
1131        dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
1132            resp->opcnt, args->opcnt, op->opnum,
1133            nfsd4_op_name(op->opnum));
1134        /*
1135         * The XDR decode routines may have pre-set op->status;
1136         * for example, if there is a miscellaneous XDR error
1137         * it will be set to nfserr_bad_xdr.
1138         */
1139        if (op->status)
1140            goto encode_op;
1141
1142        /* We must be able to encode a successful response to
1143         * this operation, with enough room left over to encode a
1144         * failed response to the next operation. If we don't
1145         * have enough room, fail with ERR_RESOURCE.
1146         */
1147        slack_bytes = (char *)resp->end - (char *)resp->p;
1148        if (slack_bytes < COMPOUND_SLACK_SPACE
1149                + COMPOUND_ERR_SLACK_SPACE) {
1150            BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE);
1151            op->status = nfserr_resource;
1152            goto encode_op;
1153        }
1154
1155        opdesc = OPDESC(op);
1156
1157        if (!cstate->current_fh.fh_dentry) {
1158            if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
1159                op->status = nfserr_nofilehandle;
1160                goto encode_op;
1161            }
1162        } else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
1163              !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
1164            op->status = nfserr_moved;
1165            goto encode_op;
1166        }
1167
1168        if (opdesc->op_func)
1169            op->status = opdesc->op_func(rqstp, cstate, &op->u);
1170        else
1171            BUG_ON(op->status == nfs_ok);
1172
1173        if (!op->status && need_wrongsec_check(rqstp))
1174            op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
1175
1176encode_op:
1177        /* Only from SEQUENCE */
1178        if (resp->cstate.status == nfserr_replay_cache) {
1179            dprintk("%s NFS4.1 replay from cache\n", __func__);
1180            status = op->status;
1181            goto out;
1182        }
1183        if (op->status == nfserr_replay_me) {
1184            op->replay = &cstate->replay_owner->so_replay;
1185            nfsd4_encode_replay(resp, op);
1186            status = op->status = op->replay->rp_status;
1187        } else {
1188            nfsd4_encode_operation(resp, op);
1189            status = op->status;
1190        }
1191
1192        dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
1193            args->ops, args->opcnt, resp->opcnt, op->opnum,
1194            be32_to_cpu(status));
1195
1196        if (cstate->replay_owner) {
1197            nfs4_put_stateowner(cstate->replay_owner);
1198            cstate->replay_owner = NULL;
1199        }
1200        /* XXX Ugh, we need to get rid of this kind of special case: */
1201        if (op->opnum == OP_READ && op->u.read.rd_filp)
1202            fput(op->u.read.rd_filp);
1203
1204        nfsd4_increment_op_stats(op->opnum);
1205    }
1206
1207    resp->cstate.status = status;
1208    fh_put(&resp->cstate.current_fh);
1209    fh_put(&resp->cstate.save_fh);
1210    BUG_ON(resp->cstate.replay_owner);
1211out:
1212    nfsd4_release_compoundargs(args);
1213    /* Reset deferral mechanism for RPC deferrals */
1214    rqstp->rq_usedeferral = 1;
1215    dprintk("nfsv4 compound returned %d\n", ntohl(status));
1216    return status;
1217}
1218
1219static struct nfsd4_operation nfsd4_ops[] = {
1220    [OP_ACCESS] = {
1221        .op_func = (nfsd4op_func)nfsd4_access,
1222        .op_name = "OP_ACCESS",
1223    },
1224    [OP_CLOSE] = {
1225        .op_func = (nfsd4op_func)nfsd4_close,
1226        .op_name = "OP_CLOSE",
1227    },
1228    [OP_COMMIT] = {
1229        .op_func = (nfsd4op_func)nfsd4_commit,
1230        .op_name = "OP_COMMIT",
1231    },
1232    [OP_CREATE] = {
1233        .op_func = (nfsd4op_func)nfsd4_create,
1234        .op_name = "OP_CREATE",
1235    },
1236    [OP_DELEGRETURN] = {
1237        .op_func = (nfsd4op_func)nfsd4_delegreturn,
1238        .op_name = "OP_DELEGRETURN",
1239    },
1240    [OP_GETATTR] = {
1241        .op_func = (nfsd4op_func)nfsd4_getattr,
1242        .op_flags = ALLOWED_ON_ABSENT_FS,
1243        .op_name = "OP_GETATTR",
1244    },
1245    [OP_GETFH] = {
1246        .op_func = (nfsd4op_func)nfsd4_getfh,
1247        .op_name = "OP_GETFH",
1248    },
1249    [OP_LINK] = {
1250        .op_func = (nfsd4op_func)nfsd4_link,
1251        .op_name = "OP_LINK",
1252    },
1253    [OP_LOCK] = {
1254        .op_func = (nfsd4op_func)nfsd4_lock,
1255        .op_name = "OP_LOCK",
1256    },
1257    [OP_LOCKT] = {
1258        .op_func = (nfsd4op_func)nfsd4_lockt,
1259        .op_name = "OP_LOCKT",
1260    },
1261    [OP_LOCKU] = {
1262        .op_func = (nfsd4op_func)nfsd4_locku,
1263        .op_name = "OP_LOCKU",
1264    },
1265    [OP_LOOKUP] = {
1266        .op_func = (nfsd4op_func)nfsd4_lookup,
1267        .op_flags = OP_HANDLES_WRONGSEC,
1268        .op_name = "OP_LOOKUP",
1269    },
1270    [OP_LOOKUPP] = {
1271        .op_func = (nfsd4op_func)nfsd4_lookupp,
1272        .op_flags = OP_HANDLES_WRONGSEC,
1273        .op_name = "OP_LOOKUPP",
1274    },
1275    [OP_NVERIFY] = {
1276        .op_func = (nfsd4op_func)nfsd4_nverify,
1277        .op_name = "OP_NVERIFY",
1278    },
1279    [OP_OPEN] = {
1280        .op_func = (nfsd4op_func)nfsd4_open,
1281        .op_flags = OP_HANDLES_WRONGSEC,
1282        .op_name = "OP_OPEN",
1283    },
1284    [OP_OPEN_CONFIRM] = {
1285        .op_func = (nfsd4op_func)nfsd4_open_confirm,
1286        .op_name = "OP_OPEN_CONFIRM",
1287    },
1288    [OP_OPEN_DOWNGRADE] = {
1289        .op_func = (nfsd4op_func)nfsd4_open_downgrade,
1290        .op_name = "OP_OPEN_DOWNGRADE",
1291    },
1292    [OP_PUTFH] = {
1293        .op_func = (nfsd4op_func)nfsd4_putfh,
1294        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1295                | OP_IS_PUTFH_LIKE,
1296        .op_name = "OP_PUTFH",
1297    },
1298    [OP_PUTPUBFH] = {
1299        .op_func = (nfsd4op_func)nfsd4_putrootfh,
1300        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1301                | OP_IS_PUTFH_LIKE,
1302        .op_name = "OP_PUTPUBFH",
1303    },
1304    [OP_PUTROOTFH] = {
1305        .op_func = (nfsd4op_func)nfsd4_putrootfh,
1306        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1307                | OP_IS_PUTFH_LIKE,
1308        .op_name = "OP_PUTROOTFH",
1309    },
1310    [OP_READ] = {
1311        .op_func = (nfsd4op_func)nfsd4_read,
1312        .op_name = "OP_READ",
1313    },
1314    [OP_READDIR] = {
1315        .op_func = (nfsd4op_func)nfsd4_readdir,
1316        .op_name = "OP_READDIR",
1317    },
1318    [OP_READLINK] = {
1319        .op_func = (nfsd4op_func)nfsd4_readlink,
1320        .op_name = "OP_READLINK",
1321    },
1322    [OP_REMOVE] = {
1323        .op_func = (nfsd4op_func)nfsd4_remove,
1324        .op_name = "OP_REMOVE",
1325    },
1326    [OP_RENAME] = {
1327        .op_name = "OP_RENAME",
1328        .op_func = (nfsd4op_func)nfsd4_rename,
1329    },
1330    [OP_RENEW] = {
1331        .op_func = (nfsd4op_func)nfsd4_renew,
1332        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1333        .op_name = "OP_RENEW",
1334    },
1335    [OP_RESTOREFH] = {
1336        .op_func = (nfsd4op_func)nfsd4_restorefh,
1337        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
1338                | OP_IS_PUTFH_LIKE,
1339        .op_name = "OP_RESTOREFH",
1340    },
1341    [OP_SAVEFH] = {
1342        .op_func = (nfsd4op_func)nfsd4_savefh,
1343        .op_flags = OP_HANDLES_WRONGSEC,
1344        .op_name = "OP_SAVEFH",
1345    },
1346    [OP_SECINFO] = {
1347        .op_func = (nfsd4op_func)nfsd4_secinfo,
1348        .op_flags = OP_HANDLES_WRONGSEC,
1349        .op_name = "OP_SECINFO",
1350    },
1351    [OP_SETATTR] = {
1352        .op_func = (nfsd4op_func)nfsd4_setattr,
1353        .op_name = "OP_SETATTR",
1354    },
1355    [OP_SETCLIENTID] = {
1356        .op_func = (nfsd4op_func)nfsd4_setclientid,
1357        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1358        .op_name = "OP_SETCLIENTID",
1359    },
1360    [OP_SETCLIENTID_CONFIRM] = {
1361        .op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1362        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1363        .op_name = "OP_SETCLIENTID_CONFIRM",
1364    },
1365    [OP_VERIFY] = {
1366        .op_func = (nfsd4op_func)nfsd4_verify,
1367        .op_name = "OP_VERIFY",
1368    },
1369    [OP_WRITE] = {
1370        .op_func = (nfsd4op_func)nfsd4_write,
1371        .op_name = "OP_WRITE",
1372    },
1373    [OP_RELEASE_LOCKOWNER] = {
1374        .op_func = (nfsd4op_func)nfsd4_release_lockowner,
1375        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1376        .op_name = "OP_RELEASE_LOCKOWNER",
1377    },
1378
1379    /* NFSv4.1 operations */
1380    [OP_EXCHANGE_ID] = {
1381        .op_func = (nfsd4op_func)nfsd4_exchange_id,
1382        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1383        .op_name = "OP_EXCHANGE_ID",
1384    },
1385    [OP_BIND_CONN_TO_SESSION] = {
1386        .op_func = (nfsd4op_func)nfsd4_bind_conn_to_session,
1387        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1388        .op_name = "OP_BIND_CONN_TO_SESSION",
1389    },
1390    [OP_CREATE_SESSION] = {
1391        .op_func = (nfsd4op_func)nfsd4_create_session,
1392        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1393        .op_name = "OP_CREATE_SESSION",
1394    },
1395    [OP_DESTROY_SESSION] = {
1396        .op_func = (nfsd4op_func)nfsd4_destroy_session,
1397        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1398        .op_name = "OP_DESTROY_SESSION",
1399    },
1400    [OP_SEQUENCE] = {
1401        .op_func = (nfsd4op_func)nfsd4_sequence,
1402        .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
1403        .op_name = "OP_SEQUENCE",
1404    },
1405    [OP_RECLAIM_COMPLETE] = {
1406        .op_func = (nfsd4op_func)nfsd4_reclaim_complete,
1407        .op_flags = ALLOWED_WITHOUT_FH,
1408        .op_name = "OP_RECLAIM_COMPLETE",
1409    },
1410    [OP_SECINFO_NO_NAME] = {
1411        .op_func = (nfsd4op_func)nfsd4_secinfo_no_name,
1412        .op_flags = OP_HANDLES_WRONGSEC,
1413        .op_name = "OP_SECINFO_NO_NAME",
1414    },
1415};
1416
1417static const char *nfsd4_op_name(unsigned opnum)
1418{
1419    if (opnum < ARRAY_SIZE(nfsd4_ops))
1420        return nfsd4_ops[opnum].op_name;
1421    return "unknown_operation";
1422}
1423
1424#define nfsd4_voidres nfsd4_voidargs
1425struct nfsd4_voidargs { int dummy; };
1426
1427/*
1428 * TODO: At the present time, the NFSv4 server does not do XID caching
1429 * of requests. Implementing XID caching would not be a serious problem,
1430 * although it would require a mild change in interfaces since one
1431 * doesn't know whether an NFSv4 request is idempotent until after the
1432 * XDR decode. However, XID caching totally confuses pynfs (Peter
1433 * Astrand's regression testsuite for NFSv4 servers), which reuses
1434 * XID's liberally, so I've left it unimplemented until pynfs generates
1435 * better XID's.
1436 */
1437static struct svc_procedure nfsd_procedures4[2] = {
1438    [NFSPROC4_NULL] = {
1439        .pc_func = (svc_procfunc) nfsd4_proc_null,
1440        .pc_encode = (kxdrproc_t) nfs4svc_encode_voidres,
1441        .pc_argsize = sizeof(struct nfsd4_voidargs),
1442        .pc_ressize = sizeof(struct nfsd4_voidres),
1443        .pc_cachetype = RC_NOCACHE,
1444        .pc_xdrressize = 1,
1445    },
1446    [NFSPROC4_COMPOUND] = {
1447        .pc_func = (svc_procfunc) nfsd4_proc_compound,
1448        .pc_decode = (kxdrproc_t) nfs4svc_decode_compoundargs,
1449        .pc_encode = (kxdrproc_t) nfs4svc_encode_compoundres,
1450        .pc_argsize = sizeof(struct nfsd4_compoundargs),
1451        .pc_ressize = sizeof(struct nfsd4_compoundres),
1452        .pc_cachetype = RC_NOCACHE,
1453        .pc_xdrressize = NFSD_BUFSIZE/4,
1454    },
1455};
1456
1457struct svc_version nfsd_version4 = {
1458        .vs_vers = 4,
1459        .vs_nproc = 2,
1460        .vs_proc = nfsd_procedures4,
1461        .vs_dispatch = nfsd_dispatch,
1462        .vs_xdrsize = NFS4_SVC_XDRSIZE,
1463};
1464
1465/*
1466 * Local variables:
1467 * c-basic-offset: 8
1468 * End:
1469 */
1470

Archive Download this file



interactive