📄 nfs_server.c
字号:
} dr->dr_status = puterrno(error); grele(vp); return(0);}/* * Remove a directory. * Remove the given directory name from the given parent directory. */intrfs_rmdir(da, status, req, xprt, xpd) struct nfsdiropargs *da; enum nfsstat *status; struct svc_req *req; SVCXPRT *xprt; struct exportdata *xpd;{ register int error = 0; register struct vnode *vp; struct timeval duptime; int dupmark; vp = fhtovp(&da->da_fhandle, xprt, RFS_RMDIR, xpd); if (vp == NULL) { *status = NFSERR_STALE; return(ESTALE); } if (rdonly(vp, xpd)) { gfs_unlock(vp); error = EROFS; } else { if (svckudp_dup(req, &duptime, &dupmark) && duptime.tv_sec == vp->g_ctime.tv_sec && duptime.tv_usec == vp->g_ctime.tv_usec) { ++nfs_dupstats.rmdirs; gfs_unlock(vp); } else { error = VOP_RMDIR(vp, da->da_name, u.u_cred); } if (error) { svckudp_dupsave(req, *timepick, DUP_FAIL); } else { svckudp_dupsave(req, vp->g_ctime, DUP_DONE); } } *status = puterrno(error); grele(vp); return(0);}intrfs_readdir(rda, rd, req, xprt, xpd) struct nfsrddirargs *rda; register struct nfsrddirres *rd; struct svc_req *req; SVCXPRT *xprt; struct exportdata *xpd;{ register int error = 0; register u_long offset; register u_long skipped; register struct vnode *vp; register struct direct *dp; struct iovec iov; struct uio uio; vp = fhtovp(&rda->rda_fh, xprt, RFS_READDIR, xpd); if (vp == NULL) { rd->rd_status = NFSERR_STALE; return(ESTALE); } /* * check cd access to dir. we have to do this here because * the opendir doesn't go over the wire. */ error = VOP_ACCESS(vp, VEXEC, u.u_cred); if (error) { goto bad; } /* * Allocate data for entries. This will be freed by rfs_rdfree. */ rd->rd_bufallocsize = rd->rd_bufsize = rda->rda_count; kmem_alloc(rd->rd_bufallocaddr, char *, rda->rda_count, KM_NFS); rd->rd_entries = (struct direct *)rd->rd_bufallocaddr;nxtblk: rd->rd_offset = rda->rda_offset & ~(DIRBLKSIZ -1); /* * Set up io vector to read directory data */ iov.iov_base = (caddr_t)rd->rd_bufallocaddr; iov.iov_len = rda->rda_count; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_offset = rd->rd_offset; uio.uio_resid = rda->rda_count; /* * read directory */ error = VOP_READDIR(vp, &uio, u.u_cred); /* * Clean up */ if (error) { rd->rd_size = 0; goto bad; } /* * set size and eof */ if (uio.uio_resid) { rd->rd_size = rda->rda_count - uio.uio_resid; rd->rd_eof = TRUE; } else { rd->rd_size = rda->rda_count; rd->rd_eof = FALSE; } /* * if client request was in the middle of a block * or block begins with null entries skip entries * til we are on a valid entry >= client's requested * offset. */ dp = rd->rd_entries; offset = rd->rd_offset; skipped = 0; while ((skipped < rd->rd_size) && ((offset + dp->d_reclen <= rda->rda_offset) || (dp->d_ino == 0))) { skipped += dp->d_reclen; offset += dp->d_reclen; dp = (struct direct *)((int)dp + dp->d_reclen); } /* * Reset entries pointer */ if (skipped) { rd->rd_size -= skipped; if (rd->rd_size == 0 && !rd->rd_eof) { /* * we have skipped a whole block, reset offset * and read another block (unless eof) */ rda->rda_offset = offset; goto nxtblk; } rd->rd_bufsize -= skipped; rd->rd_offset = offset; rd->rd_entries = dp; }bad: rd->rd_status = puterrno(error); gput(vp); return(0);}rfs_rddirfree(rd) struct nfsrddirres *rd;{ if (rd->rd_bufallocaddr) kmem_free(rd->rd_bufallocaddr, KM_NFS);}rfs_statfs(fh, fs, req, xprt, xpd) fhandle_t *fh; register struct nfsstatfs *fs; struct svc_req *req; SVCXPRT *xprt; struct exportdata *xpd;{ register struct gnode *gp; struct fs_data *fsd; gp = (struct gnode *)fhtovp(fh, xprt, RFS_STATFS, xpd); if (gp == NULL) { fs->fs_status = NFSERR_STALE; return(ESTALE); } fsd = GGETFSDATA(gp->g_mp); fs->fs_tsize = nfstsize(); fs->fsstat_bsize = FSDUNIT; fs->fs_blocks = fsd->fd_btot; fs->fs_bfree = fsd->fd_bfree; fs->fs_bavail = fsd->fd_bfreen; gput(gp); return(0);}/*ARGSUSED*/rfs_null(argp, resp) caddr_t *argp; caddr_t *resp;{ /* do nothing */ return (0);}/*ARGSUSED*/rfs_error(argp, resp) caddr_t *argp; caddr_t *resp;{ return (EOPNOTSUPP);}intnullfree(){}/* * rfs dispatch table * Indexed by version,proc */struct rfsdisp { int (*dis_proc)(); /* proc to call */ xdrproc_t dis_xdrargs; /* xdr routine to get args */ int dis_argsz; /* sizeof args */ xdrproc_t dis_xdrres; /* xdr routine to put results */ int dis_ressz; /* size of results */ int (*dis_resfree)(); /* frees space allocated by proc */} rfsdisptab[][RFS_NPROC] = { { /* * VERSION 2 * Changed rddirres to have eof at end instead of beginning */ /* RFS_NULL = 0 */ {rfs_null, xdr_void, 0, xdr_void, 0, nullfree}, /* RFS_GETATTR = 1 */ {rfs_getattr, xdr_fhandle, sizeof(fhandle_t), xdr_attrstat, sizeof(struct nfsattrstat), nullfree}, /* RFS_SETATTR = 2 */ {rfs_setattr, xdr_saargs, sizeof(struct nfssaargs), xdr_attrstat, sizeof(struct nfsattrstat), nullfree}, /* RFS_ROOT = 3 *** NO LONGER SUPPORTED *** */ {rfs_error, xdr_void, 0, xdr_void, 0, nullfree}, /* RFS_LOOKUP = 4 */ {rfs_lookup, xdr_diropargs, sizeof(struct nfsdiropargs), xdr_diropres, sizeof(struct nfsdiropres), nullfree}, /* RFS_READLINK = 5 */ {rfs_readlink, xdr_fhandle, sizeof(fhandle_t), xdr_rdlnres, sizeof(struct nfsrdlnres), rfs_rlfree}, /* RFS_READ = 6 */ {rfs_read, xdr_readargs, sizeof(struct nfsreadargs), xdr_rdresult, sizeof(struct nfsrdresult), rfs_rdfree}, /* RFS_WRITECACHE = 7 *** NO LONGER SUPPORTED *** */ {rfs_error, xdr_void, 0, xdr_void, 0, nullfree}, /* RFS_WRITE = 8 */ {rfs_write, xdr_writeargs, sizeof(struct nfswriteargs), xdr_attrstat, sizeof(struct nfsattrstat), nullfree}, /* RFS_CREATE = 9 */ {rfs_create, xdr_creatargs, sizeof(struct nfscreatargs), xdr_diropres, sizeof(struct nfsdiropres), nullfree}, /* RFS_REMOVE = 10 */ {rfs_remove, xdr_diropargs, sizeof(struct nfsdiropargs), xdr_enum, sizeof(enum nfsstat), nullfree}, /* RFS_RENAME = 11 */ {rfs_rename, xdr_rnmargs, sizeof(struct nfsrnmargs), xdr_enum, sizeof(enum nfsstat), nullfree}, /* RFS_LINK = 12 */ {rfs_link, xdr_linkargs, sizeof(struct nfslinkargs), xdr_enum, sizeof(enum nfsstat), nullfree}, /* RFS_SYMLINK = 13 */ {rfs_symlink, xdr_slargs, sizeof(struct nfsslargs), xdr_enum, sizeof(enum nfsstat), nullfree}, /* RFS_MKDIR = 14 */ {rfs_mkdir, xdr_creatargs, sizeof(struct nfscreatargs), xdr_diropres, sizeof(struct nfsdiropres), nullfree}, /* RFS_RMDIR = 15 */ {rfs_rmdir, xdr_diropargs, sizeof(struct nfsdiropargs), xdr_enum, sizeof(enum nfsstat), nullfree}, /* RFS_READDIR = 16 */ {rfs_readdir, xdr_rddirargs, sizeof(struct nfsrddirargs), xdr_putrddirres, sizeof(struct nfsrddirres), rfs_rddirfree}, /* RFS_STATFS = 17 */ {rfs_statfs, xdr_fhandle, sizeof(fhandle_t), xdr_statfs, sizeof(struct nfsstatfs), nullfree}, }};struct rfsspace { struct rfsspace *rs_next; caddr_t rs_dummy;};struct rfsspace *rfsfreesp = NULL;int rfssize = 0;caddr_trfsget(){ int i; struct rfsdisp *dis; caddr_t ret; smp_lock(&lk_nfsargs, LK_RETRY); if (rfssize == 0) { for (i = 0; i < 1 + VERSIONMAX - VERSIONMIN; i++) { for (dis = &rfsdisptab[i][0]; dis < &rfsdisptab[i][RFS_NPROC]; dis++) { rfssize = MAX(rfssize, dis->dis_argsz); rfssize = MAX(rfssize, dis->dis_ressz); } } } if (rfsfreesp) { ret = (caddr_t)rfsfreesp; rfsfreesp = rfsfreesp->rs_next; smp_unlock(&lk_nfsargs); } else { smp_unlock(&lk_nfsargs); kmem_alloc(ret, caddr_t, rfssize, KM_NFS); } return (ret);}rfsput(rs) struct rfsspace *rs;{ smp_lock(&lk_nfsargs, LK_RETRY); rs->rs_next = rfsfreesp; rfsfreesp = rs; smp_unlock(&lk_nfsargs);}/* * If nfsportmon is set, then clients are required to use * privileged ports (ports < IPPORT_RESERVED) in order to get NFS services. */int nfs_second_chance=1;int nfsportmon = 0;int nfs_cpu_count[32];int nfs_throwaways[RFS_NPROC];voidrfs_dispatch(req, xprt) register struct svc_req *req; register SVCXPRT *xprt;{ register struct rfsdisp *disp = NULL; register int error = 0; register caddr_t *args = NULL; register caddr_t *res = NULL; struct exportdata xpd; struct export *ep; fhandle_t *fh; int which; int vers; struct authunix_parms *aup; int *gp; struct ucred *tmpcr; struct ucred *newcr = NULL; int dup_xid = 0; smp_lock(&lk_nfsstat, LK_RETRY); svstat.ncalls++; smp_unlock(&lk_nfsstat); nfs_cpu_count[CURRENT_CPUDATA->cpu_num]++; which = req->rq_proc; if (which < 0 || which >= RFS_NPROC) { svcerr_noproc(req->rq_xprt); error++; goto done; } /* check for in-progress request in server cache. */ /* if not found, this request is added and flagged */ /* in-progress. */ if (svckudp_dupbusy(req)) { dup_xid = 1; nfs_dupstats.throwaways++; ++nfs_throwaways[which]; goto done; } vers = req->rq_vers; if (vers < VERSIONMIN || vers > VERSIONMAX) { svcerr_progvers(req->rq_xprt, (u_long)VERSIONMIN, (u_long)VERSIONMAX); error++; goto done; } vers -= VERSIONMIN; disp = &rfsdisptab[vers][which]; /* * Clean up as if a system call just started */ u.u_error = 0; /* * Allocate args struct and deserialize into it. */ args = (caddr_t *)rfsget(); bzero((caddr_t)args, rfssize); if ( ! SVC_GETARGS(xprt, disp->dis_xdrargs, args)) { svcerr_decode(xprt); error++; goto done; } /* * Find export information and check authentication, * setting the credential if everything is ok. */ if (which != RFS_NULL) { /* * XXX: this isn't really quite correct. Instead of doing * this blind cast, we should extract out the fhandle for * each NFS call. What's more, some procedures (like rename) * have more than one fhandle passed in, and we should check * that the two fhandles point to the same exported path. */ fhandle_t *fh = (fhandle_t *) args; if ((nfs_second_chance == 1) && (fh->fh_eno == 0)) { fh->fh_eno = fh->fh_fno; fh->fh_egen = fh->fh_fgen; } xpd.x_flags=0; /* mark it unexported. . .*/ smp_lock(&lk_gnode, LK_RETRY); ep = exported; while (ep != NULL) { if ((ep->e_fsid == fh->fh_fsid) && (ep->e_gnum == fh->fh_eno) && (ep->e_gen == fh->fh_egen)) { xpd.x_flags=ep->e_flags | M_EXPORTED; xpd.x_rootmap=ep->e_rootmap; break; } else { ep = ep->e_next; } } smp_unlock(&lk_gnode); } /* * Check for unix style credentials */ if (req->rq_cred.oa_flavor != AUTH_UNIX && which != RFS_NULL) { svcerr_weakauth(xprt); error++; goto done; } if (nfsportmon) { /* * Check for privileged port number */ static count = 0; if (ntohs(xprt->xp_raddr.sin_port) >= IPPORT_RESERVED) { svcerr_weakauth(xprt); if (count == 0) { printf("NFS request from unprivileged port, "); printf("source IP address = %u.%u.%u.%u\n", xprt->xp_raddr.sin_addr.s_net, xprt->xp_raddr.sin_addr.s_host, xprt->xp_raddr.sin_addr.s_lh, xprt->xp_raddr.sin_addr.s_impno); } count++; count %= 256; error++; goto done; } } /* * Set uid, gid, and gids to auth params */ if (which != RFS_NULL) { aup = (struct authunix_parms *)req->rq_clntcred; newcr = crget(); /* * root over the net gets mapped in fhtovp() */ newcr->cr_uid = newcr->cr_ruid = aup->aup_uid; newcr->cr_gid = newcr->cr_rgid = aup->aup_gid; bcopy((caddr_t)aup->aup_gids, (caddr_t)newcr->cr_groups, aup->aup_len * sizeof(newcr->cr_groups[0])); for (gp = &newcr->cr_groups[aup->aup_len]; gp < &newcr->cr_groups[NGROUPS]; gp++) { *gp = NOGROUP; } tmpcr = u.u_cred; u.u_cred = newcr; } /* * Allocate results struct. */ res = (caddr_t *)rfsget(); bzero((caddr_t)res, rfssize); smp_lock(&lk_nfsstat, LK_RETRY); svstat.reqs[which]++; smp_unlock(&lk_nfsstat); /* * Call service routine with arg struct and results struct */ (*disp->dis_proc)(args, res, req, xprt, &xpd);done: if (CURRENT_CPUDATA->cpu_hlock != NULL) panic("nfsd holding lock"); /* * Free arguments struct */ if (disp) { if (!SVC_FREEARGS(xprt, disp->dis_xdrargs, args)) error++; } else if (!SVC_FREEARGS(xprt, NULL, NULL)) error++; if (args != NULL) { rfsput((struct rfsspace *)args); } /* * Serialize and send results struct */ if (!error && !dup_xid) { if (!svc_sendreply(xprt, disp->dis_xdrres, (caddr_t)res)) { error++; } } /* * Free results struct */ if (res != NULL) { if ( disp->dis_resfree != nullfree ) { (*disp->dis_resfree)(res); } rfsput((struct rfsspace *)res); } /* * restore original credentials */ if (newcr) { u.u_cred = tmpcr; crfree(newcr); } smp_lock(&lk_nfsstat, LK_RETRY); svstat.nbadcalls += error; smp_unlock(&lk_nfsstat); /* mark this request not in-progress in server cache */ if (!dup_xid) svckudp_dupdone(req);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -