1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * fs/nfsd/nfs4proc.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Server-side procedures for NFSv4. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (c) 2002 The Regents of the University of Michigan. 7*1da177e4SLinus Torvalds * All rights reserved. 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * Kendrick Smith <kmsmith@umich.edu> 10*1da177e4SLinus Torvalds * Andy Adamson <andros@umich.edu> 11*1da177e4SLinus Torvalds * 12*1da177e4SLinus Torvalds * Redistribution and use in source and binary forms, with or without 13*1da177e4SLinus Torvalds * modification, are permitted provided that the following conditions 14*1da177e4SLinus Torvalds * are met: 15*1da177e4SLinus Torvalds * 16*1da177e4SLinus Torvalds * 1. Redistributions of source code must retain the above copyright 17*1da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer. 18*1da177e4SLinus Torvalds * 2. Redistributions in binary form must reproduce the above copyright 19*1da177e4SLinus Torvalds * notice, this list of conditions and the following disclaimer in the 20*1da177e4SLinus Torvalds * documentation and/or other materials provided with the distribution. 21*1da177e4SLinus Torvalds * 3. Neither the name of the University nor the names of its 22*1da177e4SLinus Torvalds * contributors may be used to endorse or promote products derived 23*1da177e4SLinus Torvalds * from this software without specific prior written permission. 24*1da177e4SLinus Torvalds * 25*1da177e4SLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 26*1da177e4SLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27*1da177e4SLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28*1da177e4SLinus Torvalds * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29*1da177e4SLinus Torvalds * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30*1da177e4SLinus Torvalds * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31*1da177e4SLinus Torvalds * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 32*1da177e4SLinus Torvalds * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33*1da177e4SLinus Torvalds * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34*1da177e4SLinus Torvalds * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35*1da177e4SLinus Torvalds * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36*1da177e4SLinus Torvalds * 37*1da177e4SLinus Torvalds * Note: some routines in this file are just trivial wrappers 38*1da177e4SLinus Torvalds * (e.g. nfsd4_lookup()) defined solely for the sake of consistent 39*1da177e4SLinus Torvalds * naming. Since all such routines have been declared "inline", 40*1da177e4SLinus Torvalds * there shouldn't be any associated overhead. At some point in 41*1da177e4SLinus Torvalds * the future, I might inline these "by hand" to clean up a 42*1da177e4SLinus Torvalds * little. 43*1da177e4SLinus Torvalds */ 44*1da177e4SLinus Torvalds 45*1da177e4SLinus Torvalds #include <linux/param.h> 46*1da177e4SLinus Torvalds #include <linux/major.h> 47*1da177e4SLinus Torvalds #include <linux/slab.h> 48*1da177e4SLinus Torvalds 49*1da177e4SLinus Torvalds #include <linux/sunrpc/svc.h> 50*1da177e4SLinus Torvalds #include <linux/nfsd/nfsd.h> 51*1da177e4SLinus Torvalds #include <linux/nfsd/cache.h> 52*1da177e4SLinus Torvalds #include <linux/nfs4.h> 53*1da177e4SLinus Torvalds #include <linux/nfsd/state.h> 54*1da177e4SLinus Torvalds #include <linux/nfsd/xdr4.h> 55*1da177e4SLinus Torvalds #include <linux/nfs4_acl.h> 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds static inline void 60*1da177e4SLinus Torvalds fh_dup2(struct svc_fh *dst, struct svc_fh *src) 61*1da177e4SLinus Torvalds { 62*1da177e4SLinus Torvalds fh_put(dst); 63*1da177e4SLinus Torvalds dget(src->fh_dentry); 64*1da177e4SLinus Torvalds if (src->fh_export) 65*1da177e4SLinus Torvalds cache_get(&src->fh_export->h); 66*1da177e4SLinus Torvalds *dst = *src; 67*1da177e4SLinus Torvalds } 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds static int 70*1da177e4SLinus Torvalds do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 71*1da177e4SLinus Torvalds { 72*1da177e4SLinus Torvalds int accmode, status; 73*1da177e4SLinus Torvalds 74*1da177e4SLinus Torvalds if (open->op_truncate && 75*1da177e4SLinus Torvalds !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 76*1da177e4SLinus Torvalds return nfserr_inval; 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds accmode = MAY_NOP; 79*1da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_READ) 80*1da177e4SLinus Torvalds accmode = MAY_READ; 81*1da177e4SLinus Torvalds if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE) 82*1da177e4SLinus Torvalds accmode |= (MAY_WRITE | MAY_TRUNC); 83*1da177e4SLinus Torvalds accmode |= MAY_OWNER_OVERRIDE; 84*1da177e4SLinus Torvalds 85*1da177e4SLinus Torvalds status = fh_verify(rqstp, current_fh, S_IFREG, accmode); 86*1da177e4SLinus Torvalds 87*1da177e4SLinus Torvalds return status; 88*1da177e4SLinus Torvalds } 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds static int 91*1da177e4SLinus Torvalds do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 92*1da177e4SLinus Torvalds { 93*1da177e4SLinus Torvalds struct svc_fh resfh; 94*1da177e4SLinus Torvalds int status; 95*1da177e4SLinus Torvalds 96*1da177e4SLinus Torvalds fh_init(&resfh, NFS4_FHSIZE); 97*1da177e4SLinus Torvalds open->op_truncate = 0; 98*1da177e4SLinus Torvalds 99*1da177e4SLinus Torvalds if (open->op_create) { 100*1da177e4SLinus Torvalds /* 101*1da177e4SLinus Torvalds * Note: create modes (UNCHECKED,GUARDED...) are the same 102*1da177e4SLinus Torvalds * in NFSv4 as in v3. 103*1da177e4SLinus Torvalds */ 104*1da177e4SLinus Torvalds status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, 105*1da177e4SLinus Torvalds open->op_fname.len, &open->op_iattr, 106*1da177e4SLinus Torvalds &resfh, open->op_createmode, 107*1da177e4SLinus Torvalds (u32 *)open->op_verf.data, &open->op_truncate); 108*1da177e4SLinus Torvalds } 109*1da177e4SLinus Torvalds else { 110*1da177e4SLinus Torvalds status = nfsd_lookup(rqstp, current_fh, 111*1da177e4SLinus Torvalds open->op_fname.data, open->op_fname.len, &resfh); 112*1da177e4SLinus Torvalds fh_unlock(current_fh); 113*1da177e4SLinus Torvalds } 114*1da177e4SLinus Torvalds 115*1da177e4SLinus Torvalds if (!status) { 116*1da177e4SLinus Torvalds set_change_info(&open->op_cinfo, current_fh); 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds /* set reply cache */ 119*1da177e4SLinus Torvalds fh_dup2(current_fh, &resfh); 120*1da177e4SLinus Torvalds open->op_stateowner->so_replay.rp_openfh_len = 121*1da177e4SLinus Torvalds resfh.fh_handle.fh_size; 122*1da177e4SLinus Torvalds memcpy(open->op_stateowner->so_replay.rp_openfh, 123*1da177e4SLinus Torvalds &resfh.fh_handle.fh_base, 124*1da177e4SLinus Torvalds resfh.fh_handle.fh_size); 125*1da177e4SLinus Torvalds 126*1da177e4SLinus Torvalds status = do_open_permission(rqstp, current_fh, open); 127*1da177e4SLinus Torvalds } 128*1da177e4SLinus Torvalds 129*1da177e4SLinus Torvalds fh_put(&resfh); 130*1da177e4SLinus Torvalds return status; 131*1da177e4SLinus Torvalds } 132*1da177e4SLinus Torvalds 133*1da177e4SLinus Torvalds static int 134*1da177e4SLinus Torvalds do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 135*1da177e4SLinus Torvalds { 136*1da177e4SLinus Torvalds int status; 137*1da177e4SLinus Torvalds 138*1da177e4SLinus Torvalds /* Only reclaims from previously confirmed clients are valid */ 139*1da177e4SLinus Torvalds if ((status = nfs4_check_open_reclaim(&open->op_clientid))) 140*1da177e4SLinus Torvalds return status; 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds /* We don't know the target directory, and therefore can not 143*1da177e4SLinus Torvalds * set the change info 144*1da177e4SLinus Torvalds */ 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); 147*1da177e4SLinus Torvalds 148*1da177e4SLinus Torvalds /* set replay cache */ 149*1da177e4SLinus Torvalds open->op_stateowner->so_replay.rp_openfh_len = current_fh->fh_handle.fh_size; 150*1da177e4SLinus Torvalds memcpy(open->op_stateowner->so_replay.rp_openfh, 151*1da177e4SLinus Torvalds ¤t_fh->fh_handle.fh_base, 152*1da177e4SLinus Torvalds current_fh->fh_handle.fh_size); 153*1da177e4SLinus Torvalds 154*1da177e4SLinus Torvalds open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && 155*1da177e4SLinus Torvalds (open->op_iattr.ia_size == 0); 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds status = do_open_permission(rqstp, current_fh, open); 158*1da177e4SLinus Torvalds 159*1da177e4SLinus Torvalds return status; 160*1da177e4SLinus Torvalds } 161*1da177e4SLinus Torvalds 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds static inline int 164*1da177e4SLinus Torvalds nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 165*1da177e4SLinus Torvalds { 166*1da177e4SLinus Torvalds int status; 167*1da177e4SLinus Torvalds dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", 168*1da177e4SLinus Torvalds (int)open->op_fname.len, open->op_fname.data, 169*1da177e4SLinus Torvalds open->op_stateowner); 170*1da177e4SLinus Torvalds 171*1da177e4SLinus Torvalds if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) 172*1da177e4SLinus Torvalds return nfserr_grace; 173*1da177e4SLinus Torvalds 174*1da177e4SLinus Torvalds if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 175*1da177e4SLinus Torvalds return nfserr_no_grace; 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds /* This check required by spec. */ 178*1da177e4SLinus Torvalds if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) 179*1da177e4SLinus Torvalds return nfserr_inval; 180*1da177e4SLinus Torvalds 181*1da177e4SLinus Torvalds nfs4_lock_state(); 182*1da177e4SLinus Torvalds 183*1da177e4SLinus Torvalds /* check seqid for replay. set nfs4_owner */ 184*1da177e4SLinus Torvalds status = nfsd4_process_open1(open); 185*1da177e4SLinus Torvalds if (status == NFSERR_REPLAY_ME) { 186*1da177e4SLinus Torvalds struct nfs4_replay *rp = &open->op_stateowner->so_replay; 187*1da177e4SLinus Torvalds fh_put(current_fh); 188*1da177e4SLinus Torvalds current_fh->fh_handle.fh_size = rp->rp_openfh_len; 189*1da177e4SLinus Torvalds memcpy(¤t_fh->fh_handle.fh_base, rp->rp_openfh, 190*1da177e4SLinus Torvalds rp->rp_openfh_len); 191*1da177e4SLinus Torvalds status = fh_verify(rqstp, current_fh, 0, MAY_NOP); 192*1da177e4SLinus Torvalds if (status) 193*1da177e4SLinus Torvalds dprintk("nfsd4_open: replay failed" 194*1da177e4SLinus Torvalds " restoring previous filehandle\n"); 195*1da177e4SLinus Torvalds else 196*1da177e4SLinus Torvalds status = NFSERR_REPLAY_ME; 197*1da177e4SLinus Torvalds } 198*1da177e4SLinus Torvalds if (status) 199*1da177e4SLinus Torvalds goto out; 200*1da177e4SLinus Torvalds switch (open->op_claim_type) { 201*1da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_NULL: 202*1da177e4SLinus Torvalds /* 203*1da177e4SLinus Torvalds * (1) set CURRENT_FH to the file being opened, 204*1da177e4SLinus Torvalds * creating it if necessary, (2) set open->op_cinfo, 205*1da177e4SLinus Torvalds * (3) set open->op_truncate if the file is to be 206*1da177e4SLinus Torvalds * truncated after opening, (4) do permission checking. 207*1da177e4SLinus Torvalds */ 208*1da177e4SLinus Torvalds status = do_open_lookup(rqstp, current_fh, open); 209*1da177e4SLinus Torvalds if (status) 210*1da177e4SLinus Torvalds goto out; 211*1da177e4SLinus Torvalds break; 212*1da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_PREVIOUS: 213*1da177e4SLinus Torvalds /* 214*1da177e4SLinus Torvalds * The CURRENT_FH is already set to the file being 215*1da177e4SLinus Torvalds * opened. (1) set open->op_cinfo, (2) set 216*1da177e4SLinus Torvalds * open->op_truncate if the file is to be truncated 217*1da177e4SLinus Torvalds * after opening, (3) do permission checking. 218*1da177e4SLinus Torvalds */ 219*1da177e4SLinus Torvalds status = do_open_fhandle(rqstp, current_fh, open); 220*1da177e4SLinus Torvalds if (status) 221*1da177e4SLinus Torvalds goto out; 222*1da177e4SLinus Torvalds break; 223*1da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_CUR: 224*1da177e4SLinus Torvalds case NFS4_OPEN_CLAIM_DELEGATE_PREV: 225*1da177e4SLinus Torvalds printk("NFSD: unsupported OPEN claim type %d\n", 226*1da177e4SLinus Torvalds open->op_claim_type); 227*1da177e4SLinus Torvalds status = nfserr_notsupp; 228*1da177e4SLinus Torvalds goto out; 229*1da177e4SLinus Torvalds default: 230*1da177e4SLinus Torvalds printk("NFSD: Invalid OPEN claim type %d\n", 231*1da177e4SLinus Torvalds open->op_claim_type); 232*1da177e4SLinus Torvalds status = nfserr_inval; 233*1da177e4SLinus Torvalds goto out; 234*1da177e4SLinus Torvalds } 235*1da177e4SLinus Torvalds /* 236*1da177e4SLinus Torvalds * nfsd4_process_open2() does the actual opening of the file. If 237*1da177e4SLinus Torvalds * successful, it (1) truncates the file if open->op_truncate was 238*1da177e4SLinus Torvalds * set, (2) sets open->op_stateid, (3) sets open->op_delegation. 239*1da177e4SLinus Torvalds */ 240*1da177e4SLinus Torvalds status = nfsd4_process_open2(rqstp, current_fh, open); 241*1da177e4SLinus Torvalds out: 242*1da177e4SLinus Torvalds if (open->op_stateowner) 243*1da177e4SLinus Torvalds nfs4_get_stateowner(open->op_stateowner); 244*1da177e4SLinus Torvalds nfs4_unlock_state(); 245*1da177e4SLinus Torvalds return status; 246*1da177e4SLinus Torvalds } 247*1da177e4SLinus Torvalds 248*1da177e4SLinus Torvalds /* 249*1da177e4SLinus Torvalds * filehandle-manipulating ops. 250*1da177e4SLinus Torvalds */ 251*1da177e4SLinus Torvalds static inline int 252*1da177e4SLinus Torvalds nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh) 253*1da177e4SLinus Torvalds { 254*1da177e4SLinus Torvalds if (!current_fh->fh_dentry) 255*1da177e4SLinus Torvalds return nfserr_nofilehandle; 256*1da177e4SLinus Torvalds 257*1da177e4SLinus Torvalds *getfh = current_fh; 258*1da177e4SLinus Torvalds return nfs_ok; 259*1da177e4SLinus Torvalds } 260*1da177e4SLinus Torvalds 261*1da177e4SLinus Torvalds static inline int 262*1da177e4SLinus Torvalds nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh) 263*1da177e4SLinus Torvalds { 264*1da177e4SLinus Torvalds fh_put(current_fh); 265*1da177e4SLinus Torvalds current_fh->fh_handle.fh_size = putfh->pf_fhlen; 266*1da177e4SLinus Torvalds memcpy(¤t_fh->fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen); 267*1da177e4SLinus Torvalds return fh_verify(rqstp, current_fh, 0, MAY_NOP); 268*1da177e4SLinus Torvalds } 269*1da177e4SLinus Torvalds 270*1da177e4SLinus Torvalds static inline int 271*1da177e4SLinus Torvalds nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh) 272*1da177e4SLinus Torvalds { 273*1da177e4SLinus Torvalds int status; 274*1da177e4SLinus Torvalds 275*1da177e4SLinus Torvalds fh_put(current_fh); 276*1da177e4SLinus Torvalds status = exp_pseudoroot(rqstp->rq_client, current_fh, 277*1da177e4SLinus Torvalds &rqstp->rq_chandle); 278*1da177e4SLinus Torvalds if (!status) 279*1da177e4SLinus Torvalds status = nfserrno(nfsd_setuser(rqstp, current_fh->fh_export)); 280*1da177e4SLinus Torvalds return status; 281*1da177e4SLinus Torvalds } 282*1da177e4SLinus Torvalds 283*1da177e4SLinus Torvalds static inline int 284*1da177e4SLinus Torvalds nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh) 285*1da177e4SLinus Torvalds { 286*1da177e4SLinus Torvalds if (!save_fh->fh_dentry) 287*1da177e4SLinus Torvalds return nfserr_restorefh; 288*1da177e4SLinus Torvalds 289*1da177e4SLinus Torvalds fh_dup2(current_fh, save_fh); 290*1da177e4SLinus Torvalds return nfs_ok; 291*1da177e4SLinus Torvalds } 292*1da177e4SLinus Torvalds 293*1da177e4SLinus Torvalds static inline int 294*1da177e4SLinus Torvalds nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh) 295*1da177e4SLinus Torvalds { 296*1da177e4SLinus Torvalds if (!current_fh->fh_dentry) 297*1da177e4SLinus Torvalds return nfserr_nofilehandle; 298*1da177e4SLinus Torvalds 299*1da177e4SLinus Torvalds fh_dup2(save_fh, current_fh); 300*1da177e4SLinus Torvalds return nfs_ok; 301*1da177e4SLinus Torvalds } 302*1da177e4SLinus Torvalds 303*1da177e4SLinus Torvalds /* 304*1da177e4SLinus Torvalds * misc nfsv4 ops 305*1da177e4SLinus Torvalds */ 306*1da177e4SLinus Torvalds static inline int 307*1da177e4SLinus Torvalds nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access) 308*1da177e4SLinus Torvalds { 309*1da177e4SLinus Torvalds if (access->ac_req_access & ~NFS3_ACCESS_FULL) 310*1da177e4SLinus Torvalds return nfserr_inval; 311*1da177e4SLinus Torvalds 312*1da177e4SLinus Torvalds access->ac_resp_access = access->ac_req_access; 313*1da177e4SLinus Torvalds return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported); 314*1da177e4SLinus Torvalds } 315*1da177e4SLinus Torvalds 316*1da177e4SLinus Torvalds static inline int 317*1da177e4SLinus Torvalds nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit) 318*1da177e4SLinus Torvalds { 319*1da177e4SLinus Torvalds int status; 320*1da177e4SLinus Torvalds 321*1da177e4SLinus Torvalds u32 *p = (u32 *)commit->co_verf.data; 322*1da177e4SLinus Torvalds *p++ = nfssvc_boot.tv_sec; 323*1da177e4SLinus Torvalds *p++ = nfssvc_boot.tv_usec; 324*1da177e4SLinus Torvalds 325*1da177e4SLinus Torvalds status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count); 326*1da177e4SLinus Torvalds if (status == nfserr_symlink) 327*1da177e4SLinus Torvalds status = nfserr_inval; 328*1da177e4SLinus Torvalds return status; 329*1da177e4SLinus Torvalds } 330*1da177e4SLinus Torvalds 331*1da177e4SLinus Torvalds static int 332*1da177e4SLinus Torvalds nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create) 333*1da177e4SLinus Torvalds { 334*1da177e4SLinus Torvalds struct svc_fh resfh; 335*1da177e4SLinus Torvalds int status; 336*1da177e4SLinus Torvalds dev_t rdev; 337*1da177e4SLinus Torvalds 338*1da177e4SLinus Torvalds fh_init(&resfh, NFS4_FHSIZE); 339*1da177e4SLinus Torvalds 340*1da177e4SLinus Torvalds status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE); 341*1da177e4SLinus Torvalds if (status == nfserr_symlink) 342*1da177e4SLinus Torvalds status = nfserr_notdir; 343*1da177e4SLinus Torvalds if (status) 344*1da177e4SLinus Torvalds return status; 345*1da177e4SLinus Torvalds 346*1da177e4SLinus Torvalds switch (create->cr_type) { 347*1da177e4SLinus Torvalds case NF4LNK: 348*1da177e4SLinus Torvalds /* ugh! we have to null-terminate the linktext, or 349*1da177e4SLinus Torvalds * vfs_symlink() will choke. it is always safe to 350*1da177e4SLinus Torvalds * null-terminate by brute force, since at worst we 351*1da177e4SLinus Torvalds * will overwrite the first byte of the create namelen 352*1da177e4SLinus Torvalds * in the XDR buffer, which has already been extracted 353*1da177e4SLinus Torvalds * during XDR decode. 354*1da177e4SLinus Torvalds */ 355*1da177e4SLinus Torvalds create->cr_linkname[create->cr_linklen] = 0; 356*1da177e4SLinus Torvalds 357*1da177e4SLinus Torvalds status = nfsd_symlink(rqstp, current_fh, create->cr_name, 358*1da177e4SLinus Torvalds create->cr_namelen, create->cr_linkname, 359*1da177e4SLinus Torvalds create->cr_linklen, &resfh, &create->cr_iattr); 360*1da177e4SLinus Torvalds break; 361*1da177e4SLinus Torvalds 362*1da177e4SLinus Torvalds case NF4BLK: 363*1da177e4SLinus Torvalds rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); 364*1da177e4SLinus Torvalds if (MAJOR(rdev) != create->cr_specdata1 || 365*1da177e4SLinus Torvalds MINOR(rdev) != create->cr_specdata2) 366*1da177e4SLinus Torvalds return nfserr_inval; 367*1da177e4SLinus Torvalds status = nfsd_create(rqstp, current_fh, create->cr_name, 368*1da177e4SLinus Torvalds create->cr_namelen, &create->cr_iattr, 369*1da177e4SLinus Torvalds S_IFBLK, rdev, &resfh); 370*1da177e4SLinus Torvalds break; 371*1da177e4SLinus Torvalds 372*1da177e4SLinus Torvalds case NF4CHR: 373*1da177e4SLinus Torvalds rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); 374*1da177e4SLinus Torvalds if (MAJOR(rdev) != create->cr_specdata1 || 375*1da177e4SLinus Torvalds MINOR(rdev) != create->cr_specdata2) 376*1da177e4SLinus Torvalds return nfserr_inval; 377*1da177e4SLinus Torvalds status = nfsd_create(rqstp, current_fh, create->cr_name, 378*1da177e4SLinus Torvalds create->cr_namelen, &create->cr_iattr, 379*1da177e4SLinus Torvalds S_IFCHR, rdev, &resfh); 380*1da177e4SLinus Torvalds break; 381*1da177e4SLinus Torvalds 382*1da177e4SLinus Torvalds case NF4SOCK: 383*1da177e4SLinus Torvalds status = nfsd_create(rqstp, current_fh, create->cr_name, 384*1da177e4SLinus Torvalds create->cr_namelen, &create->cr_iattr, 385*1da177e4SLinus Torvalds S_IFSOCK, 0, &resfh); 386*1da177e4SLinus Torvalds break; 387*1da177e4SLinus Torvalds 388*1da177e4SLinus Torvalds case NF4FIFO: 389*1da177e4SLinus Torvalds status = nfsd_create(rqstp, current_fh, create->cr_name, 390*1da177e4SLinus Torvalds create->cr_namelen, &create->cr_iattr, 391*1da177e4SLinus Torvalds S_IFIFO, 0, &resfh); 392*1da177e4SLinus Torvalds break; 393*1da177e4SLinus Torvalds 394*1da177e4SLinus Torvalds case NF4DIR: 395*1da177e4SLinus Torvalds create->cr_iattr.ia_valid &= ~ATTR_SIZE; 396*1da177e4SLinus Torvalds status = nfsd_create(rqstp, current_fh, create->cr_name, 397*1da177e4SLinus Torvalds create->cr_namelen, &create->cr_iattr, 398*1da177e4SLinus Torvalds S_IFDIR, 0, &resfh); 399*1da177e4SLinus Torvalds break; 400*1da177e4SLinus Torvalds 401*1da177e4SLinus Torvalds default: 402*1da177e4SLinus Torvalds status = nfserr_badtype; 403*1da177e4SLinus Torvalds } 404*1da177e4SLinus Torvalds 405*1da177e4SLinus Torvalds if (!status) { 406*1da177e4SLinus Torvalds fh_unlock(current_fh); 407*1da177e4SLinus Torvalds set_change_info(&create->cr_cinfo, current_fh); 408*1da177e4SLinus Torvalds fh_dup2(current_fh, &resfh); 409*1da177e4SLinus Torvalds } 410*1da177e4SLinus Torvalds 411*1da177e4SLinus Torvalds fh_put(&resfh); 412*1da177e4SLinus Torvalds return status; 413*1da177e4SLinus Torvalds } 414*1da177e4SLinus Torvalds 415*1da177e4SLinus Torvalds static inline int 416*1da177e4SLinus Torvalds nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr) 417*1da177e4SLinus Torvalds { 418*1da177e4SLinus Torvalds int status; 419*1da177e4SLinus Torvalds 420*1da177e4SLinus Torvalds status = fh_verify(rqstp, current_fh, 0, MAY_NOP); 421*1da177e4SLinus Torvalds if (status) 422*1da177e4SLinus Torvalds return status; 423*1da177e4SLinus Torvalds 424*1da177e4SLinus Torvalds if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) 425*1da177e4SLinus Torvalds return nfserr_inval; 426*1da177e4SLinus Torvalds 427*1da177e4SLinus Torvalds getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0; 428*1da177e4SLinus Torvalds getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1; 429*1da177e4SLinus Torvalds 430*1da177e4SLinus Torvalds getattr->ga_fhp = current_fh; 431*1da177e4SLinus Torvalds return nfs_ok; 432*1da177e4SLinus Torvalds } 433*1da177e4SLinus Torvalds 434*1da177e4SLinus Torvalds static inline int 435*1da177e4SLinus Torvalds nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, 436*1da177e4SLinus Torvalds struct svc_fh *save_fh, struct nfsd4_link *link) 437*1da177e4SLinus Torvalds { 438*1da177e4SLinus Torvalds int status = nfserr_nofilehandle; 439*1da177e4SLinus Torvalds 440*1da177e4SLinus Torvalds if (!save_fh->fh_dentry) 441*1da177e4SLinus Torvalds return status; 442*1da177e4SLinus Torvalds status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh); 443*1da177e4SLinus Torvalds if (!status) 444*1da177e4SLinus Torvalds set_change_info(&link->li_cinfo, current_fh); 445*1da177e4SLinus Torvalds return status; 446*1da177e4SLinus Torvalds } 447*1da177e4SLinus Torvalds 448*1da177e4SLinus Torvalds static int 449*1da177e4SLinus Torvalds nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh) 450*1da177e4SLinus Torvalds { 451*1da177e4SLinus Torvalds struct svc_fh tmp_fh; 452*1da177e4SLinus Torvalds int ret; 453*1da177e4SLinus Torvalds 454*1da177e4SLinus Torvalds fh_init(&tmp_fh, NFS4_FHSIZE); 455*1da177e4SLinus Torvalds if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, 456*1da177e4SLinus Torvalds &rqstp->rq_chandle)) != 0) 457*1da177e4SLinus Torvalds return ret; 458*1da177e4SLinus Torvalds if (tmp_fh.fh_dentry == current_fh->fh_dentry) { 459*1da177e4SLinus Torvalds fh_put(&tmp_fh); 460*1da177e4SLinus Torvalds return nfserr_noent; 461*1da177e4SLinus Torvalds } 462*1da177e4SLinus Torvalds fh_put(&tmp_fh); 463*1da177e4SLinus Torvalds return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh); 464*1da177e4SLinus Torvalds } 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds static inline int 467*1da177e4SLinus Torvalds nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup) 468*1da177e4SLinus Torvalds { 469*1da177e4SLinus Torvalds return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh); 470*1da177e4SLinus Torvalds } 471*1da177e4SLinus Torvalds 472*1da177e4SLinus Torvalds static inline int 473*1da177e4SLinus Torvalds nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) 474*1da177e4SLinus Torvalds { 475*1da177e4SLinus Torvalds int status; 476*1da177e4SLinus Torvalds struct file *filp = NULL; 477*1da177e4SLinus Torvalds 478*1da177e4SLinus Torvalds /* no need to check permission - this will be done in nfsd_read() */ 479*1da177e4SLinus Torvalds 480*1da177e4SLinus Torvalds if (read->rd_offset >= OFFSET_MAX) 481*1da177e4SLinus Torvalds return nfserr_inval; 482*1da177e4SLinus Torvalds 483*1da177e4SLinus Torvalds nfs4_lock_state(); 484*1da177e4SLinus Torvalds /* check stateid */ 485*1da177e4SLinus Torvalds if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, 486*1da177e4SLinus Torvalds CHECK_FH | RD_STATE, &filp))) { 487*1da177e4SLinus Torvalds dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); 488*1da177e4SLinus Torvalds goto out; 489*1da177e4SLinus Torvalds } 490*1da177e4SLinus Torvalds status = nfs_ok; 491*1da177e4SLinus Torvalds out: 492*1da177e4SLinus Torvalds nfs4_unlock_state(); 493*1da177e4SLinus Torvalds read->rd_rqstp = rqstp; 494*1da177e4SLinus Torvalds read->rd_fhp = current_fh; 495*1da177e4SLinus Torvalds read->rd_filp = filp; 496*1da177e4SLinus Torvalds return status; 497*1da177e4SLinus Torvalds } 498*1da177e4SLinus Torvalds 499*1da177e4SLinus Torvalds static inline int 500*1da177e4SLinus Torvalds nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir) 501*1da177e4SLinus Torvalds { 502*1da177e4SLinus Torvalds u64 cookie = readdir->rd_cookie; 503*1da177e4SLinus Torvalds static const nfs4_verifier zeroverf; 504*1da177e4SLinus Torvalds 505*1da177e4SLinus Torvalds /* no need to check permission - this will be done in nfsd_readdir() */ 506*1da177e4SLinus Torvalds 507*1da177e4SLinus Torvalds if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) 508*1da177e4SLinus Torvalds return nfserr_inval; 509*1da177e4SLinus Torvalds 510*1da177e4SLinus Torvalds readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0; 511*1da177e4SLinus Torvalds readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1; 512*1da177e4SLinus Torvalds 513*1da177e4SLinus Torvalds if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) || 514*1da177e4SLinus Torvalds (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) 515*1da177e4SLinus Torvalds return nfserr_bad_cookie; 516*1da177e4SLinus Torvalds 517*1da177e4SLinus Torvalds readdir->rd_rqstp = rqstp; 518*1da177e4SLinus Torvalds readdir->rd_fhp = current_fh; 519*1da177e4SLinus Torvalds return nfs_ok; 520*1da177e4SLinus Torvalds } 521*1da177e4SLinus Torvalds 522*1da177e4SLinus Torvalds static inline int 523*1da177e4SLinus Torvalds nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink) 524*1da177e4SLinus Torvalds { 525*1da177e4SLinus Torvalds readlink->rl_rqstp = rqstp; 526*1da177e4SLinus Torvalds readlink->rl_fhp = current_fh; 527*1da177e4SLinus Torvalds return nfs_ok; 528*1da177e4SLinus Torvalds } 529*1da177e4SLinus Torvalds 530*1da177e4SLinus Torvalds static inline int 531*1da177e4SLinus Torvalds nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove) 532*1da177e4SLinus Torvalds { 533*1da177e4SLinus Torvalds int status; 534*1da177e4SLinus Torvalds 535*1da177e4SLinus Torvalds status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); 536*1da177e4SLinus Torvalds if (status == nfserr_symlink) 537*1da177e4SLinus Torvalds return nfserr_notdir; 538*1da177e4SLinus Torvalds if (!status) { 539*1da177e4SLinus Torvalds fh_unlock(current_fh); 540*1da177e4SLinus Torvalds set_change_info(&remove->rm_cinfo, current_fh); 541*1da177e4SLinus Torvalds } 542*1da177e4SLinus Torvalds return status; 543*1da177e4SLinus Torvalds } 544*1da177e4SLinus Torvalds 545*1da177e4SLinus Torvalds static inline int 546*1da177e4SLinus Torvalds nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, 547*1da177e4SLinus Torvalds struct svc_fh *save_fh, struct nfsd4_rename *rename) 548*1da177e4SLinus Torvalds { 549*1da177e4SLinus Torvalds int status = nfserr_nofilehandle; 550*1da177e4SLinus Torvalds 551*1da177e4SLinus Torvalds if (!save_fh->fh_dentry) 552*1da177e4SLinus Torvalds return status; 553*1da177e4SLinus Torvalds status = nfsd_rename(rqstp, save_fh, rename->rn_sname, 554*1da177e4SLinus Torvalds rename->rn_snamelen, current_fh, 555*1da177e4SLinus Torvalds rename->rn_tname, rename->rn_tnamelen); 556*1da177e4SLinus Torvalds 557*1da177e4SLinus Torvalds /* the underlying filesystem returns different error's than required 558*1da177e4SLinus Torvalds * by NFSv4. both save_fh and current_fh have been verified.. */ 559*1da177e4SLinus Torvalds if (status == nfserr_isdir) 560*1da177e4SLinus Torvalds status = nfserr_exist; 561*1da177e4SLinus Torvalds else if ((status == nfserr_notdir) && 562*1da177e4SLinus Torvalds (S_ISDIR(save_fh->fh_dentry->d_inode->i_mode) && 563*1da177e4SLinus Torvalds S_ISDIR(current_fh->fh_dentry->d_inode->i_mode))) 564*1da177e4SLinus Torvalds status = nfserr_exist; 565*1da177e4SLinus Torvalds else if (status == nfserr_symlink) 566*1da177e4SLinus Torvalds status = nfserr_notdir; 567*1da177e4SLinus Torvalds 568*1da177e4SLinus Torvalds if (!status) { 569*1da177e4SLinus Torvalds set_change_info(&rename->rn_sinfo, current_fh); 570*1da177e4SLinus Torvalds set_change_info(&rename->rn_tinfo, save_fh); 571*1da177e4SLinus Torvalds } 572*1da177e4SLinus Torvalds return status; 573*1da177e4SLinus Torvalds } 574*1da177e4SLinus Torvalds 575*1da177e4SLinus Torvalds static inline int 576*1da177e4SLinus Torvalds nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr) 577*1da177e4SLinus Torvalds { 578*1da177e4SLinus Torvalds int status = nfs_ok; 579*1da177e4SLinus Torvalds 580*1da177e4SLinus Torvalds if (!current_fh->fh_dentry) 581*1da177e4SLinus Torvalds return nfserr_nofilehandle; 582*1da177e4SLinus Torvalds 583*1da177e4SLinus Torvalds status = nfs_ok; 584*1da177e4SLinus Torvalds if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { 585*1da177e4SLinus Torvalds nfs4_lock_state(); 586*1da177e4SLinus Torvalds if ((status = nfs4_preprocess_stateid_op(current_fh, 587*1da177e4SLinus Torvalds &setattr->sa_stateid, 588*1da177e4SLinus Torvalds CHECK_FH | WR_STATE, NULL))) { 589*1da177e4SLinus Torvalds dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); 590*1da177e4SLinus Torvalds goto out_unlock; 591*1da177e4SLinus Torvalds } 592*1da177e4SLinus Torvalds nfs4_unlock_state(); 593*1da177e4SLinus Torvalds } 594*1da177e4SLinus Torvalds status = nfs_ok; 595*1da177e4SLinus Torvalds if (setattr->sa_acl != NULL) 596*1da177e4SLinus Torvalds status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); 597*1da177e4SLinus Torvalds if (status) 598*1da177e4SLinus Torvalds goto out; 599*1da177e4SLinus Torvalds status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 600*1da177e4SLinus Torvalds 0, (time_t)0); 601*1da177e4SLinus Torvalds out: 602*1da177e4SLinus Torvalds return status; 603*1da177e4SLinus Torvalds out_unlock: 604*1da177e4SLinus Torvalds nfs4_unlock_state(); 605*1da177e4SLinus Torvalds return status; 606*1da177e4SLinus Torvalds } 607*1da177e4SLinus Torvalds 608*1da177e4SLinus Torvalds static inline int 609*1da177e4SLinus Torvalds nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write) 610*1da177e4SLinus Torvalds { 611*1da177e4SLinus Torvalds stateid_t *stateid = &write->wr_stateid; 612*1da177e4SLinus Torvalds struct file *filp = NULL; 613*1da177e4SLinus Torvalds u32 *p; 614*1da177e4SLinus Torvalds int status = nfs_ok; 615*1da177e4SLinus Torvalds 616*1da177e4SLinus Torvalds /* no need to check permission - this will be done in nfsd_write() */ 617*1da177e4SLinus Torvalds 618*1da177e4SLinus Torvalds if (write->wr_offset >= OFFSET_MAX) 619*1da177e4SLinus Torvalds return nfserr_inval; 620*1da177e4SLinus Torvalds 621*1da177e4SLinus Torvalds nfs4_lock_state(); 622*1da177e4SLinus Torvalds if ((status = nfs4_preprocess_stateid_op(current_fh, stateid, 623*1da177e4SLinus Torvalds CHECK_FH | WR_STATE, &filp))) { 624*1da177e4SLinus Torvalds dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); 625*1da177e4SLinus Torvalds goto out; 626*1da177e4SLinus Torvalds } 627*1da177e4SLinus Torvalds nfs4_unlock_state(); 628*1da177e4SLinus Torvalds 629*1da177e4SLinus Torvalds write->wr_bytes_written = write->wr_buflen; 630*1da177e4SLinus Torvalds write->wr_how_written = write->wr_stable_how; 631*1da177e4SLinus Torvalds p = (u32 *)write->wr_verifier.data; 632*1da177e4SLinus Torvalds *p++ = nfssvc_boot.tv_sec; 633*1da177e4SLinus Torvalds *p++ = nfssvc_boot.tv_usec; 634*1da177e4SLinus Torvalds 635*1da177e4SLinus Torvalds status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, 636*1da177e4SLinus Torvalds write->wr_vec, write->wr_vlen, write->wr_buflen, 637*1da177e4SLinus Torvalds &write->wr_how_written); 638*1da177e4SLinus Torvalds 639*1da177e4SLinus Torvalds if (status == nfserr_symlink) 640*1da177e4SLinus Torvalds status = nfserr_inval; 641*1da177e4SLinus Torvalds return status; 642*1da177e4SLinus Torvalds out: 643*1da177e4SLinus Torvalds nfs4_unlock_state(); 644*1da177e4SLinus Torvalds return status; 645*1da177e4SLinus Torvalds } 646*1da177e4SLinus Torvalds 647*1da177e4SLinus Torvalds /* This routine never returns NFS_OK! If there are no other errors, it 648*1da177e4SLinus Torvalds * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the 649*1da177e4SLinus Torvalds * attributes matched. VERIFY is implemented by mapping NFSERR_SAME 650*1da177e4SLinus Torvalds * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. 651*1da177e4SLinus Torvalds */ 652*1da177e4SLinus Torvalds static int 653*1da177e4SLinus Torvalds nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify) 654*1da177e4SLinus Torvalds { 655*1da177e4SLinus Torvalds u32 *buf, *p; 656*1da177e4SLinus Torvalds int count; 657*1da177e4SLinus Torvalds int status; 658*1da177e4SLinus Torvalds 659*1da177e4SLinus Torvalds status = fh_verify(rqstp, current_fh, 0, MAY_NOP); 660*1da177e4SLinus Torvalds if (status) 661*1da177e4SLinus Torvalds return status; 662*1da177e4SLinus Torvalds 663*1da177e4SLinus Torvalds if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) 664*1da177e4SLinus Torvalds || (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1)) 665*1da177e4SLinus Torvalds return nfserr_attrnotsupp; 666*1da177e4SLinus Torvalds if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) 667*1da177e4SLinus Torvalds || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) 668*1da177e4SLinus Torvalds return nfserr_inval; 669*1da177e4SLinus Torvalds if (verify->ve_attrlen & 3) 670*1da177e4SLinus Torvalds return nfserr_inval; 671*1da177e4SLinus Torvalds 672*1da177e4SLinus Torvalds /* count in words: 673*1da177e4SLinus Torvalds * bitmap_len(1) + bitmap(2) + attr_len(1) = 4 674*1da177e4SLinus Torvalds */ 675*1da177e4SLinus Torvalds count = 4 + (verify->ve_attrlen >> 2); 676*1da177e4SLinus Torvalds buf = kmalloc(count << 2, GFP_KERNEL); 677*1da177e4SLinus Torvalds if (!buf) 678*1da177e4SLinus Torvalds return nfserr_resource; 679*1da177e4SLinus Torvalds 680*1da177e4SLinus Torvalds status = nfsd4_encode_fattr(current_fh, current_fh->fh_export, 681*1da177e4SLinus Torvalds current_fh->fh_dentry, buf, 682*1da177e4SLinus Torvalds &count, verify->ve_bmval, 683*1da177e4SLinus Torvalds rqstp); 684*1da177e4SLinus Torvalds 685*1da177e4SLinus Torvalds /* this means that nfsd4_encode_fattr() ran out of space */ 686*1da177e4SLinus Torvalds if (status == nfserr_resource && count == 0) 687*1da177e4SLinus Torvalds status = nfserr_not_same; 688*1da177e4SLinus Torvalds if (status) 689*1da177e4SLinus Torvalds goto out_kfree; 690*1da177e4SLinus Torvalds 691*1da177e4SLinus Torvalds p = buf + 3; 692*1da177e4SLinus Torvalds status = nfserr_not_same; 693*1da177e4SLinus Torvalds if (ntohl(*p++) != verify->ve_attrlen) 694*1da177e4SLinus Torvalds goto out_kfree; 695*1da177e4SLinus Torvalds if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen)) 696*1da177e4SLinus Torvalds status = nfserr_same; 697*1da177e4SLinus Torvalds 698*1da177e4SLinus Torvalds out_kfree: 699*1da177e4SLinus Torvalds kfree(buf); 700*1da177e4SLinus Torvalds return status; 701*1da177e4SLinus Torvalds } 702*1da177e4SLinus Torvalds 703*1da177e4SLinus Torvalds /* 704*1da177e4SLinus Torvalds * NULL call. 705*1da177e4SLinus Torvalds */ 706*1da177e4SLinus Torvalds static int 707*1da177e4SLinus Torvalds nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 708*1da177e4SLinus Torvalds { 709*1da177e4SLinus Torvalds return nfs_ok; 710*1da177e4SLinus Torvalds } 711*1da177e4SLinus Torvalds 712*1da177e4SLinus Torvalds 713*1da177e4SLinus Torvalds /* 714*1da177e4SLinus Torvalds * COMPOUND call. 715*1da177e4SLinus Torvalds */ 716*1da177e4SLinus Torvalds static int 717*1da177e4SLinus Torvalds nfsd4_proc_compound(struct svc_rqst *rqstp, 718*1da177e4SLinus Torvalds struct nfsd4_compoundargs *args, 719*1da177e4SLinus Torvalds struct nfsd4_compoundres *resp) 720*1da177e4SLinus Torvalds { 721*1da177e4SLinus Torvalds struct nfsd4_op *op; 722*1da177e4SLinus Torvalds struct svc_fh *current_fh = NULL; 723*1da177e4SLinus Torvalds struct svc_fh *save_fh = NULL; 724*1da177e4SLinus Torvalds struct nfs4_stateowner *replay_owner = NULL; 725*1da177e4SLinus Torvalds int slack_space; /* in words, not bytes! */ 726*1da177e4SLinus Torvalds int status; 727*1da177e4SLinus Torvalds 728*1da177e4SLinus Torvalds status = nfserr_resource; 729*1da177e4SLinus Torvalds current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL); 730*1da177e4SLinus Torvalds if (current_fh == NULL) 731*1da177e4SLinus Torvalds goto out; 732*1da177e4SLinus Torvalds fh_init(current_fh, NFS4_FHSIZE); 733*1da177e4SLinus Torvalds save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL); 734*1da177e4SLinus Torvalds if (save_fh == NULL) 735*1da177e4SLinus Torvalds goto out; 736*1da177e4SLinus Torvalds fh_init(save_fh, NFS4_FHSIZE); 737*1da177e4SLinus Torvalds 738*1da177e4SLinus Torvalds resp->xbuf = &rqstp->rq_res; 739*1da177e4SLinus Torvalds resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; 740*1da177e4SLinus Torvalds resp->tagp = resp->p; 741*1da177e4SLinus Torvalds /* reserve space for: taglen, tag, and opcnt */ 742*1da177e4SLinus Torvalds resp->p += 2 + XDR_QUADLEN(args->taglen); 743*1da177e4SLinus Torvalds resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE; 744*1da177e4SLinus Torvalds resp->taglen = args->taglen; 745*1da177e4SLinus Torvalds resp->tag = args->tag; 746*1da177e4SLinus Torvalds resp->opcnt = 0; 747*1da177e4SLinus Torvalds resp->rqstp = rqstp; 748*1da177e4SLinus Torvalds 749*1da177e4SLinus Torvalds /* 750*1da177e4SLinus Torvalds * According to RFC3010, this takes precedence over all other errors. 751*1da177e4SLinus Torvalds */ 752*1da177e4SLinus Torvalds status = nfserr_minor_vers_mismatch; 753*1da177e4SLinus Torvalds if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) 754*1da177e4SLinus Torvalds goto out; 755*1da177e4SLinus Torvalds 756*1da177e4SLinus Torvalds status = nfs_ok; 757*1da177e4SLinus Torvalds while (!status && resp->opcnt < args->opcnt) { 758*1da177e4SLinus Torvalds op = &args->ops[resp->opcnt++]; 759*1da177e4SLinus Torvalds 760*1da177e4SLinus Torvalds /* 761*1da177e4SLinus Torvalds * The XDR decode routines may have pre-set op->status; 762*1da177e4SLinus Torvalds * for example, if there is a miscellaneous XDR error 763*1da177e4SLinus Torvalds * it will be set to nfserr_bad_xdr. 764*1da177e4SLinus Torvalds */ 765*1da177e4SLinus Torvalds if (op->status) 766*1da177e4SLinus Torvalds goto encode_op; 767*1da177e4SLinus Torvalds 768*1da177e4SLinus Torvalds /* We must be able to encode a successful response to 769*1da177e4SLinus Torvalds * this operation, with enough room left over to encode a 770*1da177e4SLinus Torvalds * failed response to the next operation. If we don't 771*1da177e4SLinus Torvalds * have enough room, fail with ERR_RESOURCE. 772*1da177e4SLinus Torvalds */ 773*1da177e4SLinus Torvalds /* FIXME - is slack_space *really* words, or bytes??? - neilb */ 774*1da177e4SLinus Torvalds slack_space = (char *)resp->end - (char *)resp->p; 775*1da177e4SLinus Torvalds if (slack_space < COMPOUND_SLACK_SPACE + COMPOUND_ERR_SLACK_SPACE) { 776*1da177e4SLinus Torvalds BUG_ON(slack_space < COMPOUND_ERR_SLACK_SPACE); 777*1da177e4SLinus Torvalds op->status = nfserr_resource; 778*1da177e4SLinus Torvalds goto encode_op; 779*1da177e4SLinus Torvalds } 780*1da177e4SLinus Torvalds 781*1da177e4SLinus Torvalds /* All operations except RENEW, SETCLIENTID, RESTOREFH 782*1da177e4SLinus Torvalds * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH 783*1da177e4SLinus Torvalds * require a valid current filehandle 784*1da177e4SLinus Torvalds * 785*1da177e4SLinus Torvalds * SETATTR NOFILEHANDLE error handled in nfsd4_setattr 786*1da177e4SLinus Torvalds * due to required returned bitmap argument 787*1da177e4SLinus Torvalds */ 788*1da177e4SLinus Torvalds if ((!current_fh->fh_dentry) && 789*1da177e4SLinus Torvalds !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || 790*1da177e4SLinus Torvalds (op->opnum == OP_SETCLIENTID) || 791*1da177e4SLinus Torvalds (op->opnum == OP_SETCLIENTID_CONFIRM) || 792*1da177e4SLinus Torvalds (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || 793*1da177e4SLinus Torvalds (op->opnum == OP_RELEASE_LOCKOWNER) || 794*1da177e4SLinus Torvalds (op->opnum == OP_SETATTR))) { 795*1da177e4SLinus Torvalds op->status = nfserr_nofilehandle; 796*1da177e4SLinus Torvalds goto encode_op; 797*1da177e4SLinus Torvalds } 798*1da177e4SLinus Torvalds switch (op->opnum) { 799*1da177e4SLinus Torvalds case OP_ACCESS: 800*1da177e4SLinus Torvalds op->status = nfsd4_access(rqstp, current_fh, &op->u.access); 801*1da177e4SLinus Torvalds break; 802*1da177e4SLinus Torvalds case OP_CLOSE: 803*1da177e4SLinus Torvalds op->status = nfsd4_close(rqstp, current_fh, &op->u.close); 804*1da177e4SLinus Torvalds replay_owner = op->u.close.cl_stateowner; 805*1da177e4SLinus Torvalds break; 806*1da177e4SLinus Torvalds case OP_COMMIT: 807*1da177e4SLinus Torvalds op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); 808*1da177e4SLinus Torvalds break; 809*1da177e4SLinus Torvalds case OP_CREATE: 810*1da177e4SLinus Torvalds op->status = nfsd4_create(rqstp, current_fh, &op->u.create); 811*1da177e4SLinus Torvalds break; 812*1da177e4SLinus Torvalds case OP_DELEGRETURN: 813*1da177e4SLinus Torvalds op->status = nfsd4_delegreturn(rqstp, current_fh, &op->u.delegreturn); 814*1da177e4SLinus Torvalds break; 815*1da177e4SLinus Torvalds case OP_GETATTR: 816*1da177e4SLinus Torvalds op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr); 817*1da177e4SLinus Torvalds break; 818*1da177e4SLinus Torvalds case OP_GETFH: 819*1da177e4SLinus Torvalds op->status = nfsd4_getfh(current_fh, &op->u.getfh); 820*1da177e4SLinus Torvalds break; 821*1da177e4SLinus Torvalds case OP_LINK: 822*1da177e4SLinus Torvalds op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); 823*1da177e4SLinus Torvalds break; 824*1da177e4SLinus Torvalds case OP_LOCK: 825*1da177e4SLinus Torvalds op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock); 826*1da177e4SLinus Torvalds replay_owner = op->u.lock.lk_stateowner; 827*1da177e4SLinus Torvalds break; 828*1da177e4SLinus Torvalds case OP_LOCKT: 829*1da177e4SLinus Torvalds op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); 830*1da177e4SLinus Torvalds break; 831*1da177e4SLinus Torvalds case OP_LOCKU: 832*1da177e4SLinus Torvalds op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku); 833*1da177e4SLinus Torvalds replay_owner = op->u.locku.lu_stateowner; 834*1da177e4SLinus Torvalds break; 835*1da177e4SLinus Torvalds case OP_LOOKUP: 836*1da177e4SLinus Torvalds op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); 837*1da177e4SLinus Torvalds break; 838*1da177e4SLinus Torvalds case OP_LOOKUPP: 839*1da177e4SLinus Torvalds op->status = nfsd4_lookupp(rqstp, current_fh); 840*1da177e4SLinus Torvalds break; 841*1da177e4SLinus Torvalds case OP_NVERIFY: 842*1da177e4SLinus Torvalds op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify); 843*1da177e4SLinus Torvalds if (op->status == nfserr_not_same) 844*1da177e4SLinus Torvalds op->status = nfs_ok; 845*1da177e4SLinus Torvalds break; 846*1da177e4SLinus Torvalds case OP_OPEN: 847*1da177e4SLinus Torvalds op->status = nfsd4_open(rqstp, current_fh, &op->u.open); 848*1da177e4SLinus Torvalds replay_owner = op->u.open.op_stateowner; 849*1da177e4SLinus Torvalds break; 850*1da177e4SLinus Torvalds case OP_OPEN_CONFIRM: 851*1da177e4SLinus Torvalds op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm); 852*1da177e4SLinus Torvalds replay_owner = op->u.open_confirm.oc_stateowner; 853*1da177e4SLinus Torvalds break; 854*1da177e4SLinus Torvalds case OP_OPEN_DOWNGRADE: 855*1da177e4SLinus Torvalds op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade); 856*1da177e4SLinus Torvalds replay_owner = op->u.open_downgrade.od_stateowner; 857*1da177e4SLinus Torvalds break; 858*1da177e4SLinus Torvalds case OP_PUTFH: 859*1da177e4SLinus Torvalds op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); 860*1da177e4SLinus Torvalds break; 861*1da177e4SLinus Torvalds case OP_PUTROOTFH: 862*1da177e4SLinus Torvalds op->status = nfsd4_putrootfh(rqstp, current_fh); 863*1da177e4SLinus Torvalds break; 864*1da177e4SLinus Torvalds case OP_READ: 865*1da177e4SLinus Torvalds op->status = nfsd4_read(rqstp, current_fh, &op->u.read); 866*1da177e4SLinus Torvalds break; 867*1da177e4SLinus Torvalds case OP_READDIR: 868*1da177e4SLinus Torvalds op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir); 869*1da177e4SLinus Torvalds break; 870*1da177e4SLinus Torvalds case OP_READLINK: 871*1da177e4SLinus Torvalds op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink); 872*1da177e4SLinus Torvalds break; 873*1da177e4SLinus Torvalds case OP_REMOVE: 874*1da177e4SLinus Torvalds op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove); 875*1da177e4SLinus Torvalds break; 876*1da177e4SLinus Torvalds case OP_RENAME: 877*1da177e4SLinus Torvalds op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename); 878*1da177e4SLinus Torvalds break; 879*1da177e4SLinus Torvalds case OP_RENEW: 880*1da177e4SLinus Torvalds op->status = nfsd4_renew(&op->u.renew); 881*1da177e4SLinus Torvalds break; 882*1da177e4SLinus Torvalds case OP_RESTOREFH: 883*1da177e4SLinus Torvalds op->status = nfsd4_restorefh(current_fh, save_fh); 884*1da177e4SLinus Torvalds break; 885*1da177e4SLinus Torvalds case OP_SAVEFH: 886*1da177e4SLinus Torvalds op->status = nfsd4_savefh(current_fh, save_fh); 887*1da177e4SLinus Torvalds break; 888*1da177e4SLinus Torvalds case OP_SETATTR: 889*1da177e4SLinus Torvalds op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr); 890*1da177e4SLinus Torvalds break; 891*1da177e4SLinus Torvalds case OP_SETCLIENTID: 892*1da177e4SLinus Torvalds op->status = nfsd4_setclientid(rqstp, &op->u.setclientid); 893*1da177e4SLinus Torvalds break; 894*1da177e4SLinus Torvalds case OP_SETCLIENTID_CONFIRM: 895*1da177e4SLinus Torvalds op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm); 896*1da177e4SLinus Torvalds break; 897*1da177e4SLinus Torvalds case OP_VERIFY: 898*1da177e4SLinus Torvalds op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify); 899*1da177e4SLinus Torvalds if (op->status == nfserr_same) 900*1da177e4SLinus Torvalds op->status = nfs_ok; 901*1da177e4SLinus Torvalds break; 902*1da177e4SLinus Torvalds case OP_WRITE: 903*1da177e4SLinus Torvalds op->status = nfsd4_write(rqstp, current_fh, &op->u.write); 904*1da177e4SLinus Torvalds break; 905*1da177e4SLinus Torvalds case OP_RELEASE_LOCKOWNER: 906*1da177e4SLinus Torvalds op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner); 907*1da177e4SLinus Torvalds break; 908*1da177e4SLinus Torvalds default: 909*1da177e4SLinus Torvalds BUG_ON(op->status == nfs_ok); 910*1da177e4SLinus Torvalds break; 911*1da177e4SLinus Torvalds } 912*1da177e4SLinus Torvalds 913*1da177e4SLinus Torvalds encode_op: 914*1da177e4SLinus Torvalds if (op->status == NFSERR_REPLAY_ME) { 915*1da177e4SLinus Torvalds op->replay = &replay_owner->so_replay; 916*1da177e4SLinus Torvalds nfsd4_encode_replay(resp, op); 917*1da177e4SLinus Torvalds status = op->status = op->replay->rp_status; 918*1da177e4SLinus Torvalds } else { 919*1da177e4SLinus Torvalds nfsd4_encode_operation(resp, op); 920*1da177e4SLinus Torvalds status = op->status; 921*1da177e4SLinus Torvalds } 922*1da177e4SLinus Torvalds if (replay_owner && (replay_owner != (void *)(-1))) { 923*1da177e4SLinus Torvalds nfs4_put_stateowner(replay_owner); 924*1da177e4SLinus Torvalds replay_owner = NULL; 925*1da177e4SLinus Torvalds } 926*1da177e4SLinus Torvalds } 927*1da177e4SLinus Torvalds 928*1da177e4SLinus Torvalds out: 929*1da177e4SLinus Torvalds nfsd4_release_compoundargs(args); 930*1da177e4SLinus Torvalds if (current_fh) 931*1da177e4SLinus Torvalds fh_put(current_fh); 932*1da177e4SLinus Torvalds kfree(current_fh); 933*1da177e4SLinus Torvalds if (save_fh) 934*1da177e4SLinus Torvalds fh_put(save_fh); 935*1da177e4SLinus Torvalds kfree(save_fh); 936*1da177e4SLinus Torvalds return status; 937*1da177e4SLinus Torvalds } 938*1da177e4SLinus Torvalds 939*1da177e4SLinus Torvalds #define nfs4svc_decode_voidargs NULL 940*1da177e4SLinus Torvalds #define nfs4svc_release_void NULL 941*1da177e4SLinus Torvalds #define nfsd4_voidres nfsd4_voidargs 942*1da177e4SLinus Torvalds #define nfs4svc_release_compound NULL 943*1da177e4SLinus Torvalds struct nfsd4_voidargs { int dummy; }; 944*1da177e4SLinus Torvalds 945*1da177e4SLinus Torvalds #define PROC(name, argt, rest, relt, cache, respsize) \ 946*1da177e4SLinus Torvalds { (svc_procfunc) nfsd4_proc_##name, \ 947*1da177e4SLinus Torvalds (kxdrproc_t) nfs4svc_decode_##argt##args, \ 948*1da177e4SLinus Torvalds (kxdrproc_t) nfs4svc_encode_##rest##res, \ 949*1da177e4SLinus Torvalds (kxdrproc_t) nfs4svc_release_##relt, \ 950*1da177e4SLinus Torvalds sizeof(struct nfsd4_##argt##args), \ 951*1da177e4SLinus Torvalds sizeof(struct nfsd4_##rest##res), \ 952*1da177e4SLinus Torvalds 0, \ 953*1da177e4SLinus Torvalds cache, \ 954*1da177e4SLinus Torvalds respsize, \ 955*1da177e4SLinus Torvalds } 956*1da177e4SLinus Torvalds 957*1da177e4SLinus Torvalds /* 958*1da177e4SLinus Torvalds * TODO: At the present time, the NFSv4 server does not do XID caching 959*1da177e4SLinus Torvalds * of requests. Implementing XID caching would not be a serious problem, 960*1da177e4SLinus Torvalds * although it would require a mild change in interfaces since one 961*1da177e4SLinus Torvalds * doesn't know whether an NFSv4 request is idempotent until after the 962*1da177e4SLinus Torvalds * XDR decode. However, XID caching totally confuses pynfs (Peter 963*1da177e4SLinus Torvalds * Astrand's regression testsuite for NFSv4 servers), which reuses 964*1da177e4SLinus Torvalds * XID's liberally, so I've left it unimplemented until pynfs generates 965*1da177e4SLinus Torvalds * better XID's. 966*1da177e4SLinus Torvalds */ 967*1da177e4SLinus Torvalds static struct svc_procedure nfsd_procedures4[2] = { 968*1da177e4SLinus Torvalds PROC(null, void, void, void, RC_NOCACHE, 1), 969*1da177e4SLinus Torvalds PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE) 970*1da177e4SLinus Torvalds }; 971*1da177e4SLinus Torvalds 972*1da177e4SLinus Torvalds struct svc_version nfsd_version4 = { 973*1da177e4SLinus Torvalds .vs_vers = 4, 974*1da177e4SLinus Torvalds .vs_nproc = 2, 975*1da177e4SLinus Torvalds .vs_proc = nfsd_procedures4, 976*1da177e4SLinus Torvalds .vs_dispatch = nfsd_dispatch, 977*1da177e4SLinus Torvalds .vs_xdrsize = NFS4_SVC_XDRSIZE, 978*1da177e4SLinus Torvalds }; 979*1da177e4SLinus Torvalds 980*1da177e4SLinus Torvalds /* 981*1da177e4SLinus Torvalds * Local variables: 982*1da177e4SLinus Torvalds * c-basic-offset: 8 983*1da177e4SLinus Torvalds * End: 984*1da177e4SLinus Torvalds */ 985