nfs4proc.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,052 行 · 第 1/2 页
C
1,052 行
/* * fs/nfsd/nfs4proc.c * * Server-side procedures for NFSv4. * * Copyright (c) 2002 The Regents of the University of Michigan. * All rights reserved. * * Kendrick Smith <kmsmith@umich.edu> * Andy Adamson <andros@umich.edu> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Note: some routines in this file are just trivial wrappers * (e.g. nfsd4_lookup()) defined solely for the sake of consistent * naming. Since all such routines have been declared "inline", * there shouldn't be any associated overhead. At some point in * the future, I might inline these "by hand" to clean up a * little. */#include <linux/param.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/cache.h>#include <linux/nfs4.h>#include <linux/nfsd/state.h>#include <linux/nfsd/xdr4.h>#include <linux/nfs4_acl.h>#define NFSDDBG_FACILITY NFSDDBG_PROCstatic inline voidfh_dup2(struct svc_fh *dst, struct svc_fh *src){ fh_put(dst); dget(src->fh_dentry); if (src->fh_export) cache_get(&src->fh_export->h); *dst = *src;}static intdo_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){ int accmode, status; if (open->op_truncate && !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) return nfserr_inval; accmode = MAY_NOP; if (open->op_share_access & NFS4_SHARE_ACCESS_READ) accmode = MAY_READ; if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE) accmode |= (MAY_WRITE | MAY_TRUNC); accmode |= MAY_OWNER_OVERRIDE; status = fh_verify(rqstp, current_fh, S_IFREG, accmode); return status;}static intdo_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){ struct svc_fh resfh; int status; fh_init(&resfh, NFS4_FHSIZE); open->op_truncate = 0; if (open->op_create) { /* * Note: create modes (UNCHECKED,GUARDED...) are the same * in NFSv4 as in v3. */ status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &open->op_iattr, &resfh, open->op_createmode, (u32 *)open->op_verf.data, &open->op_truncate); } else { status = nfsd_lookup(rqstp, current_fh, open->op_fname.data, open->op_fname.len, &resfh); fh_unlock(current_fh); } if (!status) { set_change_info(&open->op_cinfo, current_fh); /* set reply cache */ fh_dup2(current_fh, &resfh); /* XXXJBF: keep a saved svc_fh struct instead?? */ open->op_stateowner->so_replay.rp_openfh_len = resfh.fh_handle.fh_size; memcpy(open->op_stateowner->so_replay.rp_openfh, &resfh.fh_handle.fh_base, resfh.fh_handle.fh_size); status = do_open_permission(rqstp, current_fh, open); } fh_put(&resfh); return status;}static intdo_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){ int status; /* Only reclaims from previously confirmed clients are valid */ if ((status = nfs4_check_open_reclaim(&open->op_clientid))) return status; /* We don't know the target directory, and therefore can not * set the change info */ memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info)); /* set replay cache */ open->op_stateowner->so_replay.rp_openfh_len = current_fh->fh_handle.fh_size; memcpy(open->op_stateowner->so_replay.rp_openfh, ¤t_fh->fh_handle.fh_base, current_fh->fh_handle.fh_size); open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) && !open->op_iattr.ia_size; status = do_open_permission(rqstp, current_fh, open); return status;}/* * nfs4_unlock_state() called in encode */static inline intnfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open){ int status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", (int)open->op_fname.len, open->op_fname.data, open->op_stateowner); if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) return nfserr_grace; if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) return nfserr_no_grace; /* This check required by spec. */ if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) return nfserr_inval; open->op_stateowner = NULL; nfs4_lock_state(); /* check seqid for replay. set nfs4_owner */ status = nfsd4_process_open1(open); if (status == NFSERR_REPLAY_ME) { struct nfs4_replay *rp = &open->op_stateowner->so_replay; fh_put(current_fh); current_fh->fh_handle.fh_size = rp->rp_openfh_len; memcpy(¤t_fh->fh_handle.fh_base, rp->rp_openfh, rp->rp_openfh_len); status = fh_verify(rqstp, current_fh, 0, MAY_NOP); if (status) dprintk("nfsd4_open: replay failed" " restoring previous filehandle\n"); else status = NFSERR_REPLAY_ME; } if (status) return status; if (open->op_claim_type == NFS4_OPEN_CLAIM_NULL) { /* * This block of code will (1) set CURRENT_FH to the file being opened, * creating it if necessary, (2) set open->op_cinfo, * (3) set open->op_truncate if the file is to be truncated * after opening, (4) do permission checking. */ status = do_open_lookup(rqstp, current_fh, open); if (status) return status; } else if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) { /* * The CURRENT_FH is already set to the file being opened. This * block of code will (1) set open->op_cinfo, (2) set * open->op_truncate if the file is to be truncated after opening, * (3) do permission checking. */ status = do_open_fhandle(rqstp, current_fh, open); if (status) return status; } else { printk("NFSD: unsupported OPEN claim type\n"); return nfserr_inval; } /* * nfsd4_process_open2() does the actual opening of the file. If * successful, it (1) truncates the file if open->op_truncate was * set, (2) sets open->op_stateid, (3) sets open->op_delegation. */ status = nfsd4_process_open2(rqstp, current_fh, open); if (status) return status; return 0;}/* * filehandle-manipulating ops. */static inline intnfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh){ if (!current_fh->fh_dentry) return nfserr_nofilehandle; *getfh = current_fh; return nfs_ok;}static inline intnfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh){ fh_put(current_fh); current_fh->fh_handle.fh_size = putfh->pf_fhlen; memcpy(¤t_fh->fh_handle.fh_base, putfh->pf_fhval, putfh->pf_fhlen); return fh_verify(rqstp, current_fh, 0, MAY_NOP);}static inline intnfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh){ int status; fh_put(current_fh); status = exp_pseudoroot(rqstp->rq_client, current_fh, &rqstp->rq_chandle); if (!status) status = nfsd_setuser(rqstp, current_fh->fh_export); return status;}static inline intnfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh){ if (!save_fh->fh_dentry) return nfserr_restorefh; fh_dup2(current_fh, save_fh); return nfs_ok;}static inline intnfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh){ if (!current_fh->fh_dentry) return nfserr_nofilehandle; fh_dup2(save_fh, current_fh); return nfs_ok;}/* * misc nfsv4 ops */static inline intnfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access){ if (access->ac_req_access & ~NFS3_ACCESS_FULL) return nfserr_inval; access->ac_resp_access = access->ac_req_access; return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported);}static inline intnfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit){ int status; u32 *p = (u32 *)commit->co_verf.data; *p++ = nfssvc_boot.tv_sec; *p++ = nfssvc_boot.tv_usec; status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count); if (status == nfserr_symlink) status = nfserr_inval; return status;}static intnfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create){ struct svc_fh resfh; int status; dev_t rdev; fh_init(&resfh, NFS4_FHSIZE); status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE); if (status == nfserr_symlink) status = nfserr_notdir; if (status) return status; switch (create->cr_type) { case NF4LNK: /* ugh! we have to null-terminate the linktext, or * vfs_symlink() will choke. it is always safe to * null-terminate by brute force, since at worst we * will overwrite the first byte of the create namelen * in the XDR buffer, which has already been extracted * during XDR decode. */ create->cr_linkname[create->cr_linklen] = 0; status = nfsd_symlink(rqstp, current_fh, create->cr_name, create->cr_namelen, create->cr_linkname, create->cr_linklen, &resfh, &create->cr_iattr); break; case NF4BLK: rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); if (MAJOR(rdev) != create->cr_specdata1 || MINOR(rdev) != create->cr_specdata2) return nfserr_inval; status = nfsd_create(rqstp, current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr, S_IFBLK, rdev, &resfh); break; case NF4CHR: rdev = MKDEV(create->cr_specdata1, create->cr_specdata2); if (MAJOR(rdev) != create->cr_specdata1 || MINOR(rdev) != create->cr_specdata2) return nfserr_inval; status = nfsd_create(rqstp, current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr, S_IFCHR, rdev, &resfh); break; case NF4SOCK: status = nfsd_create(rqstp, current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr, S_IFSOCK, 0, &resfh); break; case NF4FIFO: status = nfsd_create(rqstp, current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr, S_IFIFO, 0, &resfh); break; case NF4DIR: create->cr_iattr.ia_valid &= ~ATTR_SIZE; status = nfsd_create(rqstp, current_fh, create->cr_name, create->cr_namelen, &create->cr_iattr, S_IFDIR, 0, &resfh); break; default: status = nfserr_badtype; } if (!status) { fh_unlock(current_fh); set_change_info(&create->cr_cinfo, current_fh); fh_dup2(current_fh, &resfh); } fh_put(&resfh); return status;}static inline intnfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr){ int status; status = fh_verify(rqstp, current_fh, 0, MAY_NOP); if (status) return status; if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1) return nfserr_inval; getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0; getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1; getattr->ga_fhp = current_fh; return nfs_ok;}static inline intnfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct svc_fh *save_fh, struct nfsd4_link *link){ int status = nfserr_nofilehandle; if (!save_fh->fh_dentry) return status; status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh); if (!status) set_change_info(&link->li_cinfo, current_fh); return status;}static intnfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh){ struct svc_fh tmp_fh; int ret; fh_init(&tmp_fh, NFS4_FHSIZE); if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle)) != 0) return ret; if (tmp_fh.fh_dentry == current_fh->fh_dentry) { fh_put(&tmp_fh); return nfserr_noent; } fh_put(&tmp_fh); return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);}static inline intnfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup){ return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);}static inline intaccess_bits_permit_read(unsigned long access_bmap){ return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);}static inline intaccess_bits_permit_write(unsigned long access_bmap){ return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);}static inline intnfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read){ struct nfs4_stateid *stp; int status; /* no need to check permission - this will be done in nfsd_read() */ if (nfs4_in_grace()) return nfserr_grace; if (read->rd_offset >= OFFSET_MAX) return nfserr_inval; nfs4_lock_state(); status = nfs_ok; /* For stateid -1, we don't check share reservations. */ if (ONE_STATEID(&read->rd_stateid)) { dprintk("NFSD: nfsd4_read: -1 stateid...\n"); goto out; } /* * For stateid 0, the client doesn't have to have the file open, but * we still check for share reservation conflicts. */ if (ZERO_STATEID(&read->rd_stateid)) { dprintk("NFSD: nfsd4_read: zero stateid...\n"); if ((status = nfs4_share_conflict(current_fh, NFS4_SHARE_DENY_READ))) { dprintk("NFSD: nfsd4_read: conflicting share reservation!\n"); goto out; } status = nfs_ok; goto out; } /* check stateid */ if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, CHECK_FH | RDWR_STATE, &stp))) { dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); goto out; } status = nfserr_openmode; if (!access_bits_permit_read(stp->st_access_bmap)) { dprintk("NFSD: nfsd4_read: file not opened for read!\n"); goto out; } status = nfs_ok;out: nfs4_unlock_state(); read->rd_rqstp = rqstp; read->rd_fhp = current_fh;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?