📄 nfs4proc.c
字号:
static __be32nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_readlink *readlink){ readlink->rl_rqstp = rqstp; readlink->rl_fhp = &cstate->current_fh; return nfs_ok;}static __be32nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_remove *remove){ __be32 status; if (nfs4_in_grace()) return nfserr_grace; status = nfsd_unlink(rqstp, &cstate->current_fh, 0, remove->rm_name, remove->rm_namelen); if (status == nfserr_symlink) return nfserr_notdir; if (!status) { fh_unlock(&cstate->current_fh); set_change_info(&remove->rm_cinfo, &cstate->current_fh); } return status;}static __be32nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_rename *rename){ __be32 status = nfserr_nofilehandle; if (!cstate->save_fh.fh_dentry) return status; if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK)) return nfserr_grace; status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, rename->rn_snamelen, &cstate->current_fh, rename->rn_tname, rename->rn_tnamelen); /* the underlying filesystem returns different error's than required * by NFSv4. both save_fh and current_fh have been verified.. */ if (status == nfserr_isdir) status = nfserr_exist; else if ((status == nfserr_notdir) && (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) && S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode))) status = nfserr_exist; else if (status == nfserr_symlink) status = nfserr_notdir; if (!status) { set_change_info(&rename->rn_sinfo, &cstate->current_fh); set_change_info(&rename->rn_tinfo, &cstate->save_fh); } return status;}static __be32nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_secinfo *secinfo){ struct svc_fh resfh; struct svc_export *exp; struct dentry *dentry; __be32 err; fh_init(&resfh, NFS4_FHSIZE); err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, secinfo->si_name, secinfo->si_namelen, &exp, &dentry); if (err) return err; if (dentry->d_inode == NULL) { exp_put(exp); err = nfserr_noent; } else secinfo->si_exp = exp; dput(dentry); return err;}static __be32nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr){ __be32 status = nfs_ok; if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { nfs4_lock_state(); status = nfs4_preprocess_stateid_op(&cstate->current_fh, &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); nfs4_unlock_state(); if (status) { dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); return status; } } status = nfs_ok; if (setattr->sa_acl != NULL) status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, setattr->sa_acl); if (status) return status; status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, 0, (time_t)0); return status;}static __be32nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_write *write){ stateid_t *stateid = &write->wr_stateid; struct file *filp = NULL; u32 *p; __be32 status = nfs_ok; /* no need to check permission - this will be done in nfsd_write() */ if (write->wr_offset >= OFFSET_MAX) return nfserr_inval; nfs4_lock_state(); status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid, CHECK_FH | WR_STATE, &filp); if (filp) get_file(filp); nfs4_unlock_state(); if (status) { dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); return status; } write->wr_bytes_written = write->wr_buflen; write->wr_how_written = write->wr_stable_how; p = (u32 *)write->wr_verifier.data; *p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_usec; status = nfsd_write(rqstp, &cstate->current_fh, filp, write->wr_offset, rqstp->rq_vec, write->wr_vlen, write->wr_buflen, &write->wr_how_written); if (filp) fput(filp); if (status == nfserr_symlink) status = nfserr_inval; return status;}/* This routine never returns NFS_OK! If there are no other errors, it * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the * attributes matched. VERIFY is implemented by mapping NFSERR_SAME * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK. */static __be32_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_verify *verify){ __be32 *buf, *p; int count; __be32 status; status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP); if (status) return status; if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1)) return nfserr_attrnotsupp; if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR) || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)) return nfserr_inval; if (verify->ve_attrlen & 3) return nfserr_inval; /* count in words: * bitmap_len(1) + bitmap(2) + attr_len(1) = 4 */ count = 4 + (verify->ve_attrlen >> 2); buf = kmalloc(count << 2, GFP_KERNEL); if (!buf) return nfserr_resource; status = nfsd4_encode_fattr(&cstate->current_fh, cstate->current_fh.fh_export, cstate->current_fh.fh_dentry, buf, &count, verify->ve_bmval, rqstp); /* this means that nfsd4_encode_fattr() ran out of space */ if (status == nfserr_resource && count == 0) status = nfserr_not_same; if (status) goto out_kfree; p = buf + 3; status = nfserr_not_same; if (ntohl(*p++) != verify->ve_attrlen) goto out_kfree; if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen)) status = nfserr_same;out_kfree: kfree(buf); return status;}static __be32nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_verify *verify){ __be32 status; status = _nfsd4_verify(rqstp, cstate, verify); return status == nfserr_not_same ? nfs_ok : status;}static __be32nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_verify *verify){ __be32 status; status = _nfsd4_verify(rqstp, cstate, verify); return status == nfserr_same ? nfs_ok : status;}/* * NULL call. */static __be32nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp){ return nfs_ok;}static inline void nfsd4_increment_op_stats(u32 opnum){ if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP) nfsdstats.nfs4_opcount[opnum]++;}static void cstate_free(struct nfsd4_compound_state *cstate){ if (cstate == NULL) return; fh_put(&cstate->current_fh); fh_put(&cstate->save_fh); BUG_ON(cstate->replay_owner); kfree(cstate);}static struct nfsd4_compound_state *cstate_alloc(void){ struct nfsd4_compound_state *cstate; cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL); if (cstate == NULL) return NULL; fh_init(&cstate->current_fh, NFS4_FHSIZE); fh_init(&cstate->save_fh, NFS4_FHSIZE); cstate->replay_owner = NULL; return cstate;}typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *, void *);struct nfsd4_operation { nfsd4op_func op_func; u32 op_flags;/* Most ops require a valid current filehandle; a few don't: */#define ALLOWED_WITHOUT_FH 1/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */#define ALLOWED_ON_ABSENT_FS 2};static struct nfsd4_operation nfsd4_ops[];/* * COMPOUND call. */static __be32nfsd4_proc_compound(struct svc_rqst *rqstp, struct nfsd4_compoundargs *args, struct nfsd4_compoundres *resp){ struct nfsd4_op *op; struct nfsd4_operation *opdesc; struct nfsd4_compound_state *cstate = NULL; int slack_bytes; __be32 status; status = nfserr_resource; cstate = cstate_alloc(); if (cstate == NULL) goto out; resp->xbuf = &rqstp->rq_res; resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; resp->tagp = resp->p; /* reserve space for: taglen, tag, and opcnt */ resp->p += 2 + XDR_QUADLEN(args->taglen); resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE; resp->taglen = args->taglen; resp->tag = args->tag; resp->opcnt = 0; resp->rqstp = rqstp; /* * According to RFC3010, this takes precedence over all other errors. */ status = nfserr_minor_vers_mismatch; if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION) goto out; status = nfs_ok; while (!status && resp->opcnt < args->opcnt) { op = &args->ops[resp->opcnt++]; dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum); /* * The XDR decode routines may have pre-set op->status; * for example, if there is a miscellaneous XDR error * it will be set to nfserr_bad_xdr. */ if (op->status) goto encode_op; /* We must be able to encode a successful response to * this operation, with enough room left over to encode a * failed response to the next operation. If we don't * have enough room, fail with ERR_RESOURCE. */ slack_bytes = (char *)resp->end - (char *)resp->p; if (slack_bytes < COMPOUND_SLACK_SPACE + COMPOUND_ERR_SLACK_SPACE) { BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE); op->status = nfserr_resource; goto encode_op; } opdesc = &nfsd4_ops[op->opnum]; if (!cstate->current_fh.fh_dentry) { if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) { op->status = nfserr_nofilehandle; goto encode_op; } } else if (cstate->current_fh.fh_export->ex_fslocs.migrated && !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) { op->status = nfserr_moved; goto encode_op; } if (opdesc->op_func) op->status = opdesc->op_func(rqstp, cstate, &op->u); else BUG_ON(op->status == nfs_ok);encode_op: if (op->status == nfserr_replay_me) { op->replay = &cstate->replay_owner->so_replay; nfsd4_encode_replay(resp, op); status = op->status = op->replay->rp_status; } else { nfsd4_encode_operation(resp, op); status = op->status; } if (cstate->replay_owner) { nfs4_put_stateowner(cstate->replay_owner); cstate->replay_owner = NULL; } /* XXX Ugh, we need to get rid of this kind of special case: */ if (op->opnum == OP_READ && op->u.read.rd_filp) fput(op->u.read.rd_filp); nfsd4_increment_op_stats(op->opnum); }out: nfsd4_release_compoundargs(args); cstate_free(cstate); return status;}static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { [OP_ACCESS] = { .op_func = (nfsd4op_func)nfsd4_access, }, [OP_CLOSE] = { .op_func = (nfsd4op_func)nfsd4_close, }, [OP_COMMIT] = { .op_func = (nfsd4op_func)nfsd4_commit, }, [OP_CREATE] = { .op_func = (nfsd4op_func)nfsd4_create, }, [OP_DELEGRETURN] = { .op_func = (nfsd4op_func)nfsd4_delegreturn, }, [OP_GETATTR] = { .op_func = (nfsd4op_func)nfsd4_getattr, .op_flags = ALLOWED_ON_ABSENT_FS, }, [OP_GETFH] = { .op_func = (nfsd4op_func)nfsd4_getfh, }, [OP_LINK] = { .op_func = (nfsd4op_func)nfsd4_link, }, [OP_LOCK] = { .op_func = (nfsd4op_func)nfsd4_lock, }, [OP_LOCKT] = { .op_func = (nfsd4op_func)nfsd4_lockt, }, [OP_LOCKU] = { .op_func = (nfsd4op_func)nfsd4_locku, }, [OP_LOOKUP] = { .op_func = (nfsd4op_func)nfsd4_lookup, }, [OP_LOOKUPP] = { .op_func = (nfsd4op_func)nfsd4_lookupp, }, [OP_NVERIFY] = { .op_func = (nfsd4op_func)nfsd4_nverify, }, [OP_OPEN] = { .op_func = (nfsd4op_func)nfsd4_open, }, [OP_OPEN_CONFIRM] = { .op_func = (nfsd4op_func)nfsd4_open_confirm, }, [OP_OPEN_DOWNGRADE] = { .op_func = (nfsd4op_func)nfsd4_open_downgrade, }, [OP_PUTFH] = { .op_func = (nfsd4op_func)nfsd4_putfh, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_PUTPUBFH] = { /* unsupported; just for future reference: */ .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_PUTROOTFH] = { .op_func = (nfsd4op_func)nfsd4_putrootfh, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_READ] = { .op_func = (nfsd4op_func)nfsd4_read, }, [OP_READDIR] = { .op_func = (nfsd4op_func)nfsd4_readdir, }, [OP_READLINK] = { .op_func = (nfsd4op_func)nfsd4_readlink, }, [OP_REMOVE] = { .op_func = (nfsd4op_func)nfsd4_remove, }, [OP_RENAME] = { .op_func = (nfsd4op_func)nfsd4_rename, }, [OP_RENEW] = { .op_func = (nfsd4op_func)nfsd4_renew, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_RESTOREFH] = { .op_func = (nfsd4op_func)nfsd4_restorefh, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_SAVEFH] = { .op_func = (nfsd4op_func)nfsd4_savefh, }, [OP_SECINFO] = { .op_func = (nfsd4op_func)nfsd4_secinfo, }, [OP_SETATTR] = { .op_func = (nfsd4op_func)nfsd4_setattr, }, [OP_SETCLIENTID] = { .op_func = (nfsd4op_func)nfsd4_setclientid, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_SETCLIENTID_CONFIRM] = { .op_func = (nfsd4op_func)nfsd4_setclientid_confirm, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, }, [OP_VERIFY] = { .op_func = (nfsd4op_func)nfsd4_verify, }, [OP_WRITE] = { .op_func = (nfsd4op_func)nfsd4_write, }, [OP_RELEASE_LOCKOWNER] = { .op_func = (nfsd4op_func)nfsd4_release_lockowner, .op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS, },};#define nfs4svc_decode_voidargs NULL#define nfs4svc_release_void NULL#define nfsd4_voidres nfsd4_voidargs#define nfs4svc_release_compound NULLstruct nfsd4_voidargs { int dummy; };#define PROC(name, argt, rest, relt, cache, respsize) \ { (svc_procfunc) nfsd4_proc_##name, \ (kxdrproc_t) nfs4svc_decode_##argt##args, \ (kxdrproc_t) nfs4svc_encode_##rest##res, \ (kxdrproc_t) nfs4svc_release_##relt, \ sizeof(struct nfsd4_##argt##args), \ sizeof(struct nfsd4_##rest##res), \ 0, \ cache, \ respsize, \ }/* * TODO: At the present time, the NFSv4 server does not do XID caching * of requests. Implementing XID caching would not be a serious problem, * although it would require a mild change in interfaces since one * doesn't know whether an NFSv4 request is idempotent until after the * XDR decode. However, XID caching totally confuses pynfs (Peter * Astrand's regression testsuite for NFSv4 servers), which reuses * XID's liberally, so I've left it unimplemented until pynfs generates * better XID's. */static struct svc_procedure nfsd_procedures4[2] = { PROC(null, void, void, void, RC_NOCACHE, 1), PROC(compound, compound, compound, compound, RC_NOCACHE, NFSD_BUFSIZE/4)};struct svc_version nfsd_version4 = { .vs_vers = 4, .vs_nproc = 2, .vs_proc = nfsd_procedures4, .vs_dispatch = nfsd_dispatch, .vs_xdrsize = NFS4_SVC_XDRSIZE,};/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -