138418Smckusick /*
263233Sbostic * Copyright (c) 1989, 1993
363233Sbostic * The Regents of the University of California. All rights reserved.
438418Smckusick *
538418Smckusick * This code is derived from software contributed to Berkeley by
638418Smckusick * Rick Macklem at The University of Guelph.
738418Smckusick *
844510Sbostic * %sccs.include.redist.c%
938418Smckusick *
10*69424Smckusick * @(#)nfs_serv.c 8.7 (Berkeley) 05/14/95
1138418Smckusick */
1238418Smckusick
1338418Smckusick /*
1468653Smckusick * nfs version 2 and 3 server calls to vnode ops
1538418Smckusick * - these routines generally have 3 phases
1638418Smckusick * 1 - break down and validate rpc request in mbuf list
1738418Smckusick * 2 - do the vnode ops for the request
1838425Smckusick * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
1938418Smckusick * 3 - build the rpc reply in an mbuf list
2038418Smckusick * nb:
2138418Smckusick * - do not mix the phases, since the nfsm_?? macros can return failures
2241899Smckusick * on a bad rpc or similar and do not do any vrele() or vput()'s
2338418Smckusick *
2438425Smckusick * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
2538418Smckusick * error number iff error != 0 whereas
2641899Smckusick * returning an error from the server function implies a fatal error
2741899Smckusick * such as a badly constructed rpc request that should be dropped without
2841899Smckusick * a reply.
2968653Smckusick * For Version 3, nfsm_reply() does not return for the error case, since
3068653Smckusick * most version 3 rpcs return more than the status for error cases.
3138418Smckusick */
3238418Smckusick
3353322Smckusick #include <sys/param.h>
3455073Spendry #include <sys/systm.h>
3553322Smckusick #include <sys/proc.h>
3653322Smckusick #include <sys/file.h>
3753322Smckusick #include <sys/namei.h>
3853322Smckusick #include <sys/vnode.h>
3953322Smckusick #include <sys/mount.h>
4068653Smckusick #include <sys/socket.h>
4168653Smckusick #include <sys/socketvar.h>
4253322Smckusick #include <sys/mbuf.h>
4353322Smckusick #include <sys/dirent.h>
4454446Smckusick #include <sys/stat.h>
4568653Smckusick #include <sys/kernel.h>
4668653Smckusick #include <ufs/ufs/dir.h>
4747573Skarels
4853322Smckusick #include <vm/vm.h>
4947573Skarels
5068653Smckusick #include <nfs/nfsproto.h>
5153322Smckusick #include <nfs/rpcv2.h>
5253322Smckusick #include <nfs/nfs.h>
5353322Smckusick #include <nfs/xdr_subs.h>
5453322Smckusick #include <nfs/nfsm_subs.h>
5553322Smckusick #include <nfs/nqnfs.h>
5653322Smckusick
5738418Smckusick /* Global vars */
5838418Smckusick extern u_long nfs_xdrneg1;
5938418Smckusick extern u_long nfs_false, nfs_true;
6068653Smckusick extern enum vtype nv3tov_type[8];
6168653Smckusick extern struct nfsstats nfsstats;
6268653Smckusick nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
6342242Smckusick NFCHR, NFNON };
6468653Smckusick nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
6568653Smckusick NFFIFO, NFNON };
6668653Smckusick int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
6738418Smckusick
6838418Smckusick /*
6968653Smckusick * nfs v3 access service
7056360Smckusick */
7168653Smckusick int
nfsrv3_access(nfsd,slp,procp,mrq)7268653Smckusick nfsrv3_access(nfsd, slp, procp, mrq)
7368653Smckusick struct nfsrv_descript *nfsd;
7468653Smckusick struct nfssvc_sock *slp;
7568653Smckusick struct proc *procp;
7668653Smckusick struct mbuf **mrq;
7756360Smckusick {
7868653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
7968653Smckusick struct mbuf *nam = nfsd->nd_nam;
8068653Smckusick caddr_t dpos = nfsd->nd_dpos;
8168653Smckusick struct ucred *cred = &nfsd->nd_cr;
8256360Smckusick struct vnode *vp;
8368653Smckusick nfsfh_t nfh;
8456360Smckusick fhandle_t *fhp;
8556360Smckusick register u_long *tl;
8656360Smckusick register long t1;
8756360Smckusick caddr_t bpos;
8868653Smckusick int error = 0, rdonly, cache, getret;
8956360Smckusick char *cp2;
9068653Smckusick struct mbuf *mb, *mreq, *mb2;
9168653Smckusick struct vattr vattr, *vap = &vattr;
9268653Smckusick u_long testmode, nfsmode;
9356360Smckusick u_quad_t frev;
9456360Smckusick
9568653Smckusick #ifndef nolint
9668653Smckusick cache = 0;
9768653Smckusick #endif
9856360Smckusick fhp = &nfh.fh_generic;
9956360Smckusick nfsm_srvmtofh(fhp);
10068653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
10168653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
10268653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
10368653Smckusick nfsm_reply(NFSX_UNSIGNED);
10468653Smckusick nfsm_srvpostop_attr(1, (struct vattr *)0);
10568653Smckusick return (0);
10668653Smckusick }
10768653Smckusick nfsmode = fxdr_unsigned(u_long, *tl);
10868653Smckusick if ((nfsmode & NFSV3ACCESS_READ) &&
10968653Smckusick nfsrv_access(vp, VREAD, cred, rdonly, procp))
11068653Smckusick nfsmode &= ~NFSV3ACCESS_READ;
11168653Smckusick if (vp->v_type == VDIR)
11268653Smckusick testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
11368653Smckusick NFSV3ACCESS_DELETE);
11468653Smckusick else
11568653Smckusick testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
11668653Smckusick if ((nfsmode & testmode) &&
11768653Smckusick nfsrv_access(vp, VWRITE, cred, rdonly, procp))
11868653Smckusick nfsmode &= ~testmode;
11968653Smckusick if (vp->v_type == VDIR)
12068653Smckusick testmode = NFSV3ACCESS_LOOKUP;
12168653Smckusick else
12268653Smckusick testmode = NFSV3ACCESS_EXECUTE;
12368653Smckusick if ((nfsmode & testmode) &&
12468653Smckusick nfsrv_access(vp, VEXEC, cred, rdonly, procp))
12568653Smckusick nfsmode &= ~testmode;
12668653Smckusick getret = VOP_GETATTR(vp, vap, cred, procp);
12756360Smckusick vput(vp);
12868653Smckusick nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
12968653Smckusick nfsm_srvpostop_attr(getret, vap);
13068653Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
13168653Smckusick *tl = txdr_unsigned(nfsmode);
13256360Smckusick nfsm_srvdone;
13356360Smckusick }
13456360Smckusick
13556360Smckusick /*
13638418Smckusick * nfs getattr service
13738418Smckusick */
13868653Smckusick int
nfsrv_getattr(nfsd,slp,procp,mrq)13968653Smckusick nfsrv_getattr(nfsd, slp, procp, mrq)
14068653Smckusick struct nfsrv_descript *nfsd;
14168653Smckusick struct nfssvc_sock *slp;
14268653Smckusick struct proc *procp;
14368653Smckusick struct mbuf **mrq;
14438418Smckusick {
14568653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
14668653Smckusick struct mbuf *nam = nfsd->nd_nam;
14768653Smckusick caddr_t dpos = nfsd->nd_dpos;
14868653Smckusick struct ucred *cred = &nfsd->nd_cr;
14968653Smckusick register struct nfs_fattr *fp;
15038418Smckusick struct vattr va;
15138418Smckusick register struct vattr *vap = &va;
15238418Smckusick struct vnode *vp;
15368653Smckusick nfsfh_t nfh;
15438418Smckusick fhandle_t *fhp;
15548050Smckusick register u_long *tl;
15639494Smckusick register long t1;
15739494Smckusick caddr_t bpos;
15852196Smckusick int error = 0, rdonly, cache;
15939494Smckusick char *cp2;
16039753Smckusick struct mbuf *mb, *mb2, *mreq;
16152196Smckusick u_quad_t frev;
16238418Smckusick
16338418Smckusick fhp = &nfh.fh_generic;
16438418Smckusick nfsm_srvmtofh(fhp);
16568653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
16668653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
16738418Smckusick nfsm_reply(0);
16868653Smckusick return (0);
16968653Smckusick }
17068653Smckusick nqsrv_getl(vp, ND_READ);
17168653Smckusick error = VOP_GETATTR(vp, vap, cred, procp);
17238418Smckusick vput(vp);
17368653Smckusick nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
17468653Smckusick if (error)
17568653Smckusick return (0);
17668653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
17768653Smckusick nfsm_srvfillattr(vap, fp);
17838418Smckusick nfsm_srvdone;
17938418Smckusick }
18038418Smckusick
18138418Smckusick /*
18238418Smckusick * nfs setattr service
18338418Smckusick */
18468653Smckusick int
nfsrv_setattr(nfsd,slp,procp,mrq)18568653Smckusick nfsrv_setattr(nfsd, slp, procp, mrq)
18668653Smckusick struct nfsrv_descript *nfsd;
18768653Smckusick struct nfssvc_sock *slp;
18868653Smckusick struct proc *procp;
18968653Smckusick struct mbuf **mrq;
19038418Smckusick {
19168653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
19268653Smckusick struct mbuf *nam = nfsd->nd_nam;
19368653Smckusick caddr_t dpos = nfsd->nd_dpos;
19468653Smckusick struct ucred *cred = &nfsd->nd_cr;
19568653Smckusick struct vattr va, preat;
19638418Smckusick register struct vattr *vap = &va;
19738884Smacklem register struct nfsv2_sattr *sp;
19868653Smckusick register struct nfs_fattr *fp;
19938418Smckusick struct vnode *vp;
20068653Smckusick nfsfh_t nfh;
20138418Smckusick fhandle_t *fhp;
20248050Smckusick register u_long *tl;
20339494Smckusick register long t1;
20439494Smckusick caddr_t bpos;
20568653Smckusick int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
20668653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
20739494Smckusick char *cp2;
20839753Smckusick struct mbuf *mb, *mb2, *mreq;
20968653Smckusick u_quad_t frev;
21068653Smckusick struct timespec guard;
21138418Smckusick
21238418Smckusick fhp = &nfh.fh_generic;
21338418Smckusick nfsm_srvmtofh(fhp);
21441361Smckusick VATTR_NULL(vap);
21568653Smckusick if (v3) {
21668653Smckusick nfsm_srvsattr(vap);
21768653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
21868653Smckusick gcheck = fxdr_unsigned(int, *tl);
21968653Smckusick if (gcheck) {
22068653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
22168653Smckusick fxdr_nfsv3time(tl, &guard);
22268653Smckusick }
22368653Smckusick } else {
22468653Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
22568653Smckusick /*
22668653Smckusick * Nah nah nah nah na nah
22768653Smckusick * There is a bug in the Sun client that puts 0xffff in the mode
22868653Smckusick * field of sattr when it should put in 0xffffffff. The u_short
22968653Smckusick * doesn't sign extend.
23068653Smckusick * --> check the low order 2 bytes for 0xffff
23168653Smckusick */
23268653Smckusick if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
23368653Smckusick vap->va_mode = nfstov_mode(sp->sa_mode);
23468653Smckusick if (sp->sa_uid != nfs_xdrneg1)
23568653Smckusick vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
23668653Smckusick if (sp->sa_gid != nfs_xdrneg1)
23768653Smckusick vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
23868653Smckusick if (sp->sa_size != nfs_xdrneg1)
23968653Smckusick vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
24068653Smckusick if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
24158880Smckusick #ifdef notyet
24268653Smckusick fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
24358880Smckusick #else
24458880Smckusick vap->va_atime.ts_sec =
24568653Smckusick fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
24656285Smckusick vap->va_atime.ts_nsec = 0;
24758880Smckusick #endif
24856285Smckusick }
24968653Smckusick if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
25068653Smckusick fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
25168653Smckusick
25238425Smckusick }
25359526Smckusick
25459526Smckusick /*
25568653Smckusick * Now that we have all the fields, lets do it.
25668653Smckusick */
25768653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
25868653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
25968653Smckusick nfsm_reply(2 * NFSX_UNSIGNED);
26068653Smckusick nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
26168653Smckusick return (0);
26268653Smckusick }
26368653Smckusick nqsrv_getl(vp, ND_WRITE);
26468653Smckusick if (v3) {
26568653Smckusick error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
26668653Smckusick if (!error && gcheck &&
26768653Smckusick (preat.va_ctime.ts_sec != guard.ts_sec ||
26868653Smckusick preat.va_ctime.ts_nsec != guard.ts_nsec))
26968653Smckusick error = NFSERR_NOT_SYNC;
27068653Smckusick if (error) {
27168653Smckusick vput(vp);
27268653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
27368653Smckusick nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
27468653Smckusick return (0);
27568653Smckusick }
27668653Smckusick }
27768653Smckusick
27868653Smckusick /*
27959526Smckusick * If the size is being changed write acces is required, otherwise
28059526Smckusick * just check for a read only file system.
28159526Smckusick */
28259526Smckusick if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
28359526Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
28459526Smckusick error = EROFS;
28559526Smckusick goto out;
28659526Smckusick }
28759526Smckusick } else {
28859526Smckusick if (vp->v_type == VDIR) {
28959526Smckusick error = EISDIR;
29059526Smckusick goto out;
29159526Smckusick } else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
29268653Smckusick procp))
29359526Smckusick goto out;
29459526Smckusick }
29568653Smckusick error = VOP_SETATTR(vp, vap, cred, procp);
29668653Smckusick postat_ret = VOP_GETATTR(vp, vap, cred, procp);
29768653Smckusick if (!error)
29868653Smckusick error = postat_ret;
29938418Smckusick out:
30038418Smckusick vput(vp);
30168653Smckusick nfsm_reply(NFSX_WCCORFATTR(v3));
30268653Smckusick if (v3) {
30368653Smckusick nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
30468653Smckusick return (0);
30568653Smckusick } else {
30668653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
30768653Smckusick nfsm_srvfillattr(vap, fp);
30852196Smckusick }
30938418Smckusick nfsm_srvdone;
31038418Smckusick }
31138418Smckusick
31238418Smckusick /*
31338418Smckusick * nfs lookup rpc
31438418Smckusick */
31568653Smckusick int
nfsrv_lookup(nfsd,slp,procp,mrq)31668653Smckusick nfsrv_lookup(nfsd, slp, procp, mrq)
31768653Smckusick struct nfsrv_descript *nfsd;
31868653Smckusick struct nfssvc_sock *slp;
31968653Smckusick struct proc *procp;
32068653Smckusick struct mbuf **mrq;
32138418Smckusick {
32268653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
32368653Smckusick struct mbuf *nam = nfsd->nd_nam;
32468653Smckusick caddr_t dpos = nfsd->nd_dpos;
32568653Smckusick struct ucred *cred = &nfsd->nd_cr;
32668653Smckusick register struct nfs_fattr *fp;
32749742Smckusick struct nameidata nd;
32868653Smckusick struct vnode *vp, *dirp;
32968653Smckusick nfsfh_t nfh;
33038418Smckusick fhandle_t *fhp;
33139494Smckusick register caddr_t cp;
33248050Smckusick register u_long *tl;
33339494Smckusick register long t1;
33439494Smckusick caddr_t bpos;
33568653Smckusick int error = 0, cache, len, dirattr_ret = 1;
33668653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
33739494Smckusick char *cp2;
33839753Smckusick struct mbuf *mb, *mb2, *mreq;
33968653Smckusick struct vattr va, dirattr, *vap = &va;
34068653Smckusick u_quad_t frev;
34138418Smckusick
34238418Smckusick fhp = &nfh.fh_generic;
34338418Smckusick nfsm_srvmtofh(fhp);
34468653Smckusick nfsm_srvnamesiz(len);
34552316Sheideman nd.ni_cnd.cn_cred = cred;
34652316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP;
34752316Sheideman nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
34868653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
34968653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
35068653Smckusick if (dirp) {
35168653Smckusick if (v3)
35268653Smckusick dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
35368653Smckusick procp);
35468653Smckusick vrele(dirp);
35568653Smckusick }
35668653Smckusick if (error) {
35768653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3));
35868653Smckusick nfsm_srvpostop_attr(dirattr_ret, &dirattr);
35968653Smckusick return (0);
36068653Smckusick }
36168653Smckusick nqsrv_getl(nd.ni_startdir, ND_READ);
36252196Smckusick vrele(nd.ni_startdir);
36352653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
36449742Smckusick vp = nd.ni_vp;
36538418Smckusick bzero((caddr_t)fhp, sizeof(nfh));
36641398Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
36768653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid);
36868653Smckusick if (!error)
36968653Smckusick error = VOP_GETATTR(vp, vap, cred, procp);
37038418Smckusick vput(vp);
37168653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
37268653Smckusick if (error) {
37368653Smckusick nfsm_srvpostop_attr(dirattr_ret, &dirattr);
37468653Smckusick return (0);
37552196Smckusick }
37668653Smckusick nfsm_srvfhtom(fhp, v3);
37768653Smckusick if (v3) {
37868653Smckusick nfsm_srvpostop_attr(0, vap);
37968653Smckusick nfsm_srvpostop_attr(dirattr_ret, &dirattr);
38068653Smckusick } else {
38168653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
38268653Smckusick nfsm_srvfillattr(vap, fp);
38368653Smckusick }
38438418Smckusick nfsm_srvdone;
38538418Smckusick }
38638418Smckusick
38738418Smckusick /*
38838418Smckusick * nfs readlink service
38938418Smckusick */
39068653Smckusick int
nfsrv_readlink(nfsd,slp,procp,mrq)39168653Smckusick nfsrv_readlink(nfsd, slp, procp, mrq)
39268653Smckusick struct nfsrv_descript *nfsd;
39368653Smckusick struct nfssvc_sock *slp;
39468653Smckusick struct proc *procp;
39568653Smckusick struct mbuf **mrq;
39638418Smckusick {
39768653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
39868653Smckusick struct mbuf *nam = nfsd->nd_nam;
39968653Smckusick caddr_t dpos = nfsd->nd_dpos;
40068653Smckusick struct ucred *cred = &nfsd->nd_cr;
40141899Smckusick struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
40238418Smckusick register struct iovec *ivp = iv;
40338418Smckusick register struct mbuf *mp;
40448050Smckusick register u_long *tl;
40539494Smckusick register long t1;
40639494Smckusick caddr_t bpos;
40768653Smckusick int error = 0, rdonly, cache, i, tlen, len, getret;
40868653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
40939494Smckusick char *cp2;
41039753Smckusick struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
41138418Smckusick struct vnode *vp;
41268653Smckusick struct vattr attr;
41368653Smckusick nfsfh_t nfh;
41438418Smckusick fhandle_t *fhp;
41538418Smckusick struct uio io, *uiop = &io;
41652196Smckusick u_quad_t frev;
41738418Smckusick
41868653Smckusick #ifndef nolint
41968653Smckusick mp2 = mp3 = (struct mbuf *)0;
42068653Smckusick #endif
42138418Smckusick fhp = &nfh.fh_generic;
42238418Smckusick nfsm_srvmtofh(fhp);
42338418Smckusick len = 0;
42438418Smckusick i = 0;
42538418Smckusick while (len < NFS_MAXPATHLEN) {
42638418Smckusick MGET(mp, M_WAIT, MT_DATA);
42741899Smckusick MCLGET(mp, M_WAIT);
42838418Smckusick mp->m_len = NFSMSIZ(mp);
42938418Smckusick if (len == 0)
43038418Smckusick mp3 = mp2 = mp;
43141899Smckusick else {
43238418Smckusick mp2->m_next = mp;
43341899Smckusick mp2 = mp;
43441899Smckusick }
43538418Smckusick if ((len+mp->m_len) > NFS_MAXPATHLEN) {
43638418Smckusick mp->m_len = NFS_MAXPATHLEN-len;
43738418Smckusick len = NFS_MAXPATHLEN;
43838418Smckusick } else
43938418Smckusick len += mp->m_len;
44038418Smckusick ivp->iov_base = mtod(mp, caddr_t);
44138418Smckusick ivp->iov_len = mp->m_len;
44238418Smckusick i++;
44338418Smckusick ivp++;
44438418Smckusick }
44538418Smckusick uiop->uio_iov = iv;
44638418Smckusick uiop->uio_iovcnt = i;
44738418Smckusick uiop->uio_offset = 0;
44838418Smckusick uiop->uio_resid = len;
44938418Smckusick uiop->uio_rw = UIO_READ;
45038418Smckusick uiop->uio_segflg = UIO_SYSSPACE;
45148050Smckusick uiop->uio_procp = (struct proc *)0;
45268653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
45368653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
45438418Smckusick m_freem(mp3);
45568653Smckusick nfsm_reply(2 * NFSX_UNSIGNED);
45668653Smckusick nfsm_srvpostop_attr(1, (struct vattr *)0);
45768653Smckusick return (0);
45838418Smckusick }
45938418Smckusick if (vp->v_type != VLNK) {
46068653Smckusick if (v3)
46168653Smckusick error = EINVAL;
46268653Smckusick else
46368653Smckusick error = ENXIO;
46438418Smckusick goto out;
46538418Smckusick }
46668653Smckusick nqsrv_getl(vp, ND_READ);
46738418Smckusick error = VOP_READLINK(vp, uiop, cred);
46838418Smckusick out:
46968653Smckusick getret = VOP_GETATTR(vp, &attr, cred, procp);
47038418Smckusick vput(vp);
47138418Smckusick if (error)
47238418Smckusick m_freem(mp3);
47368653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
47468653Smckusick if (v3) {
47568653Smckusick nfsm_srvpostop_attr(getret, &attr);
47668653Smckusick if (error)
47768653Smckusick return (0);
47868653Smckusick }
47938418Smckusick if (uiop->uio_resid > 0) {
48038418Smckusick len -= uiop->uio_resid;
48138418Smckusick tlen = nfsm_rndup(len);
48238418Smckusick nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
48338418Smckusick }
48448050Smckusick nfsm_build(tl, u_long *, NFSX_UNSIGNED);
48548050Smckusick *tl = txdr_unsigned(len);
48638418Smckusick mb->m_next = mp3;
48738418Smckusick nfsm_srvdone;
48838418Smckusick }
48938418Smckusick
49038418Smckusick /*
49138418Smckusick * nfs read service
49238418Smckusick */
49368653Smckusick int
nfsrv_read(nfsd,slp,procp,mrq)49468653Smckusick nfsrv_read(nfsd, slp, procp, mrq)
49568653Smckusick struct nfsrv_descript *nfsd;
49668653Smckusick struct nfssvc_sock *slp;
49768653Smckusick struct proc *procp;
49868653Smckusick struct mbuf **mrq;
49938418Smckusick {
50068653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
50168653Smckusick struct mbuf *nam = nfsd->nd_nam;
50268653Smckusick caddr_t dpos = nfsd->nd_dpos;
50368653Smckusick struct ucred *cred = &nfsd->nd_cr;
50443350Smckusick register struct iovec *iv;
50543350Smckusick struct iovec *iv2;
50641899Smckusick register struct mbuf *m;
50768653Smckusick register struct nfs_fattr *fp;
50848050Smckusick register u_long *tl;
50939494Smckusick register long t1;
51068653Smckusick register int i;
51139494Smckusick caddr_t bpos;
51268653Smckusick int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
51368653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
51439494Smckusick char *cp2;
51539753Smckusick struct mbuf *mb, *mb2, *mreq;
51652196Smckusick struct mbuf *m2;
51738418Smckusick struct vnode *vp;
51868653Smckusick nfsfh_t nfh;
51938418Smckusick fhandle_t *fhp;
52038418Smckusick struct uio io, *uiop = &io;
52138418Smckusick struct vattr va, *vap = &va;
52238418Smckusick off_t off;
52352196Smckusick u_quad_t frev;
52438418Smckusick
52538418Smckusick fhp = &nfh.fh_generic;
52638418Smckusick nfsm_srvmtofh(fhp);
52768653Smckusick if (v3) {
52868653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
52968653Smckusick fxdr_hyper(tl, &off);
53068653Smckusick } else {
53156285Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
53256285Smckusick off = (off_t)fxdr_unsigned(u_long, *tl);
53356285Smckusick }
53468653Smckusick nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
53568653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
53668653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
53768653Smckusick nfsm_reply(2 * NFSX_UNSIGNED);
53868653Smckusick nfsm_srvpostop_attr(1, (struct vattr *)0);
53968653Smckusick return (0);
54068653Smckusick }
54160186Smckusick if (vp->v_type != VREG) {
54268653Smckusick if (v3)
54368653Smckusick error = EINVAL;
54468653Smckusick else
54568653Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES;
54660186Smckusick }
54768653Smckusick if (!error) {
54868653Smckusick nqsrv_getl(vp, ND_READ);
54968653Smckusick if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
55068653Smckusick error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
55138418Smckusick }
55268653Smckusick getret = VOP_GETATTR(vp, vap, cred, procp);
55368653Smckusick if (!error)
55468653Smckusick error = getret;
55568653Smckusick if (error) {
55638418Smckusick vput(vp);
55768653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3));
55868653Smckusick nfsm_srvpostop_attr(getret, vap);
55968653Smckusick return (0);
56038418Smckusick }
56152196Smckusick if (off >= vap->va_size)
56252196Smckusick cnt = 0;
56368653Smckusick else if ((off + reqlen) > vap->va_size)
56452196Smckusick cnt = nfsm_rndup(vap->va_size - off);
56568653Smckusick else
56668653Smckusick cnt = reqlen;
56768653Smckusick nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
56868653Smckusick if (v3) {
56968653Smckusick nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
57068653Smckusick *tl++ = nfs_true;
57168653Smckusick fp = (struct nfs_fattr *)tl;
57268653Smckusick tl += (NFSX_V3FATTR / sizeof (u_long));
57368653Smckusick } else {
57468653Smckusick nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
57568653Smckusick fp = (struct nfs_fattr *)tl;
57668653Smckusick tl += (NFSX_V2FATTR / sizeof (u_long));
57768653Smckusick }
57852196Smckusick len = left = cnt;
57952196Smckusick if (cnt > 0) {
58052196Smckusick /*
58152196Smckusick * Generate the mbuf list with the uio_iov ref. to it.
58252196Smckusick */
58352196Smckusick i = 0;
58452196Smckusick m = m2 = mb;
58552196Smckusick while (left > 0) {
58655057Spendry siz = min(M_TRAILINGSPACE(m), left);
58752196Smckusick if (siz > 0) {
58868653Smckusick left -= siz;
58952196Smckusick i++;
59052196Smckusick }
59152196Smckusick if (left > 0) {
59252196Smckusick MGET(m, M_WAIT, MT_DATA);
59352196Smckusick MCLGET(m, M_WAIT);
59452196Smckusick m->m_len = 0;
59552196Smckusick m2->m_next = m;
59652196Smckusick m2 = m;
59752196Smckusick }
59852196Smckusick }
59968653Smckusick MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
60068653Smckusick M_TEMP, M_WAITOK);
60168653Smckusick uiop->uio_iov = iv2 = iv;
60268653Smckusick m = mb;
60368653Smckusick left = cnt;
60468653Smckusick i = 0;
60568653Smckusick while (left > 0) {
60668653Smckusick if (m == NULL)
60768653Smckusick panic("nfsrv_read iov");
60868653Smckusick siz = min(M_TRAILINGSPACE(m), left);
60968653Smckusick if (siz > 0) {
61068653Smckusick iv->iov_base = mtod(m, caddr_t) + m->m_len;
61168653Smckusick iv->iov_len = siz;
61268653Smckusick m->m_len += siz;
61368653Smckusick left -= siz;
61468653Smckusick iv++;
61568653Smckusick i++;
61668653Smckusick }
61768653Smckusick m = m->m_next;
61868653Smckusick }
61952196Smckusick uiop->uio_iovcnt = i;
62052196Smckusick uiop->uio_offset = off;
62152196Smckusick uiop->uio_resid = cnt;
62252196Smckusick uiop->uio_rw = UIO_READ;
62352196Smckusick uiop->uio_segflg = UIO_SYSSPACE;
62452196Smckusick error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
62552196Smckusick off = uiop->uio_offset;
62652196Smckusick FREE((caddr_t)iv2, M_TEMP);
62768653Smckusick if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
62868653Smckusick if (!error)
62968653Smckusick error = getret;
63052196Smckusick m_freem(mreq);
63152196Smckusick vput(vp);
63268653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3));
63368653Smckusick nfsm_srvpostop_attr(getret, vap);
63468653Smckusick return (0);
63552196Smckusick }
63652196Smckusick } else
63752196Smckusick uiop->uio_resid = 0;
63838418Smckusick vput(vp);
63968653Smckusick nfsm_srvfillattr(vap, fp);
64045877Smckusick len -= uiop->uio_resid;
64152196Smckusick tlen = nfsm_rndup(len);
64252196Smckusick if (cnt != tlen || tlen != len)
64368653Smckusick nfsm_adj(mb, cnt - tlen, tlen - len);
64468653Smckusick if (v3) {
64568653Smckusick *tl++ = txdr_unsigned(len);
64668653Smckusick if (len < reqlen)
64768653Smckusick *tl++ = nfs_true;
64868653Smckusick else
64968653Smckusick *tl++ = nfs_false;
65068653Smckusick }
65148050Smckusick *tl = txdr_unsigned(len);
65238418Smckusick nfsm_srvdone;
65338418Smckusick }
65438418Smckusick
65538418Smckusick /*
65638418Smckusick * nfs write service
65738418Smckusick */
65868653Smckusick int
nfsrv_write(nfsd,slp,procp,mrq)65968653Smckusick nfsrv_write(nfsd, slp, procp, mrq)
66068653Smckusick struct nfsrv_descript *nfsd;
66168653Smckusick struct nfssvc_sock *slp;
66268653Smckusick struct proc *procp;
66368653Smckusick struct mbuf **mrq;
66438418Smckusick {
66568653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
66668653Smckusick struct mbuf *nam = nfsd->nd_nam;
66768653Smckusick caddr_t dpos = nfsd->nd_dpos;
66868653Smckusick struct ucred *cred = &nfsd->nd_cr;
66938418Smckusick register struct iovec *ivp;
67068653Smckusick register int i, cnt;
67138418Smckusick register struct mbuf *mp;
67268653Smckusick register struct nfs_fattr *fp;
67368653Smckusick struct iovec *iv;
67468653Smckusick struct vattr va, forat;
67538418Smckusick register struct vattr *vap = &va;
67648050Smckusick register u_long *tl;
67739494Smckusick register long t1;
67839494Smckusick caddr_t bpos;
67968653Smckusick int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1;
68068653Smckusick int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
68168653Smckusick int stable = NFSV3WRITE_FILESYNC;
68268653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
68339494Smckusick char *cp2;
68439753Smckusick struct mbuf *mb, *mb2, *mreq;
68538418Smckusick struct vnode *vp;
68668653Smckusick nfsfh_t nfh;
68738418Smckusick fhandle_t *fhp;
68838418Smckusick struct uio io, *uiop = &io;
68938418Smckusick off_t off;
69052196Smckusick u_quad_t frev;
69138418Smckusick
69268653Smckusick if (mrep == NULL) {
69368653Smckusick *mrq = NULL;
69468653Smckusick return (0);
69568653Smckusick }
69638418Smckusick fhp = &nfh.fh_generic;
69738418Smckusick nfsm_srvmtofh(fhp);
69868653Smckusick if (v3) {
69968653Smckusick nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
70068653Smckusick fxdr_hyper(tl, &off);
70168653Smckusick tl += 3;
70268653Smckusick stable = fxdr_unsigned(int, *tl++);
70368653Smckusick } else {
70468653Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
70556285Smckusick off = (off_t)fxdr_unsigned(u_long, *++tl);
70656285Smckusick tl += 2;
70756285Smckusick }
70868653Smckusick retlen = len = fxdr_unsigned(long, *tl);
70968653Smckusick cnt = i = 0;
71068653Smckusick
71168653Smckusick /*
71268653Smckusick * For NFS Version 2, it is not obvious what a write of zero length
71368653Smckusick * should do, but I might as well be consistent with Version 3,
71468653Smckusick * which is to return ok so long as there are no permission problems.
71568653Smckusick */
71668653Smckusick if (len > 0) {
71768653Smckusick zeroing = 1;
71868653Smckusick mp = mrep;
71968653Smckusick while (mp) {
72068653Smckusick if (mp == md) {
72168653Smckusick zeroing = 0;
72268653Smckusick adjust = dpos - mtod(mp, caddr_t);
72368653Smckusick mp->m_len -= adjust;
72468653Smckusick if (mp->m_len > 0 && adjust > 0)
72568653Smckusick NFSMADV(mp, adjust);
72638418Smckusick }
72768653Smckusick if (zeroing)
72868653Smckusick mp->m_len = 0;
72968653Smckusick else if (mp->m_len > 0) {
73068653Smckusick i += mp->m_len;
73168653Smckusick if (i > len) {
73268653Smckusick mp->m_len -= (i - len);
73368653Smckusick zeroing = 1;
73468653Smckusick }
73568653Smckusick if (mp->m_len > 0)
73668653Smckusick cnt++;
73768653Smckusick }
73868653Smckusick mp = mp->m_next;
73968653Smckusick }
74038418Smckusick }
74168653Smckusick if (len > NFS_MAXDATA || len < 0 || i < len) {
74268653Smckusick error = EIO;
74368653Smckusick nfsm_reply(2 * NFSX_UNSIGNED);
74468653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
74568653Smckusick return (0);
74668653Smckusick }
74768653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
74868653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
74968653Smckusick nfsm_reply(2 * NFSX_UNSIGNED);
75068653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
75168653Smckusick return (0);
75268653Smckusick }
75368653Smckusick if (v3)
75468653Smckusick forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
75560186Smckusick if (vp->v_type != VREG) {
75668653Smckusick if (v3)
75768653Smckusick error = EINVAL;
75868653Smckusick else
75968653Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES;
76060186Smckusick }
76168653Smckusick if (!error) {
76268653Smckusick nqsrv_getl(vp, ND_WRITE);
76368653Smckusick error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
76468653Smckusick }
76568653Smckusick if (error) {
76638418Smckusick vput(vp);
76768653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
76868653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
76968653Smckusick return (0);
77038418Smckusick }
77168653Smckusick
77268653Smckusick if (len > 0) {
77368653Smckusick MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
77468653Smckusick M_WAITOK);
77568653Smckusick uiop->uio_iov = iv = ivp;
77668653Smckusick uiop->uio_iovcnt = cnt;
77768653Smckusick mp = mrep;
77868653Smckusick while (mp) {
77968653Smckusick if (mp->m_len > 0) {
78068653Smckusick ivp->iov_base = mtod(mp, caddr_t);
78168653Smckusick ivp->iov_len = mp->m_len;
78268653Smckusick ivp++;
78368653Smckusick }
78468653Smckusick mp = mp->m_next;
78568653Smckusick }
78668653Smckusick
78768653Smckusick /*
78868653Smckusick * XXX
78968653Smckusick * The IO_METASYNC flag indicates that all metadata (and not just
79068653Smckusick * enough to ensure data integrity) mus be written to stable storage
79168653Smckusick * synchronously.
79268653Smckusick * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
79368653Smckusick */
79468653Smckusick if (stable == NFSV3WRITE_UNSTABLE)
79568653Smckusick ioflags = IO_NODELOCKED;
79668653Smckusick else if (stable == NFSV3WRITE_DATASYNC)
79768653Smckusick ioflags = (IO_SYNC | IO_NODELOCKED);
79868653Smckusick else
79968653Smckusick ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
80068653Smckusick uiop->uio_resid = len;
80168653Smckusick uiop->uio_rw = UIO_WRITE;
80268653Smckusick uiop->uio_segflg = UIO_SYSSPACE;
80368653Smckusick uiop->uio_procp = (struct proc *)0;
80468653Smckusick uiop->uio_offset = off;
80568653Smckusick error = VOP_WRITE(vp, uiop, ioflags, cred);
80668653Smckusick nfsstats.srvvop_writes++;
80768653Smckusick FREE((caddr_t)iv, M_TEMP);
80868653Smckusick }
80968653Smckusick aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
81068653Smckusick vput(vp);
81168653Smckusick if (!error)
81268653Smckusick error = aftat_ret;
81368653Smckusick nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
81468653Smckusick 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
81568653Smckusick if (v3) {
81668653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
81768653Smckusick if (error)
81868653Smckusick return (0);
81968653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
82068653Smckusick *tl++ = txdr_unsigned(retlen);
82168653Smckusick if (stable == NFSV3WRITE_UNSTABLE)
82268653Smckusick *tl++ = txdr_unsigned(stable);
82368653Smckusick else
82468653Smckusick *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
82568653Smckusick /*
82668653Smckusick * Actually, there is no need to txdr these fields,
82768653Smckusick * but it may make the values more human readable,
82868653Smckusick * for debugging purposes.
82968653Smckusick */
83068653Smckusick *tl++ = txdr_unsigned(boottime.tv_sec);
83168653Smckusick *tl = txdr_unsigned(boottime.tv_usec);
83268653Smckusick } else {
83368653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
83468653Smckusick nfsm_srvfillattr(vap, fp);
83568653Smckusick }
83668653Smckusick nfsm_srvdone;
83768653Smckusick }
83868653Smckusick
83968653Smckusick /*
84068653Smckusick * NFS write service with write gathering support. Called when
84168653Smckusick * nfsrvw_procrastinate > 0.
84268653Smckusick * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
84368653Smckusick * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
84468653Smckusick * Jan. 1994.
84568653Smckusick */
84668653Smckusick int
nfsrv_writegather(ndp,slp,procp,mrq)84768653Smckusick nfsrv_writegather(ndp, slp, procp, mrq)
84868653Smckusick struct nfsrv_descript **ndp;
84968653Smckusick struct nfssvc_sock *slp;
85068653Smckusick struct proc *procp;
85168653Smckusick struct mbuf **mrq;
85268653Smckusick {
85368653Smckusick register struct iovec *ivp;
85468653Smckusick register struct mbuf *mp;
85568653Smckusick register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
85668653Smckusick register struct nfs_fattr *fp;
85768653Smckusick register int i;
85868653Smckusick struct iovec *iov;
85968653Smckusick struct nfsrvw_delayhash *wpp;
86068653Smckusick struct ucred *cred;
86168653Smckusick struct vattr va, forat;
86268653Smckusick register u_long *tl;
86368653Smckusick register long t1;
86468653Smckusick caddr_t bpos, dpos;
86568653Smckusick int error = 0, rdonly, cache, len, forat_ret = 1;
86668653Smckusick int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
86768653Smckusick char *cp2;
86868653Smckusick struct mbuf *mb, *mb2, *mreq, *mrep, *md;
86968653Smckusick struct vnode *vp;
87068653Smckusick struct uio io, *uiop = &io;
87168653Smckusick off_t off;
87268653Smckusick u_quad_t frev, cur_usec;
87368653Smckusick
87468653Smckusick #ifndef nolint
87568653Smckusick i = 0;
87668653Smckusick len = 0;
87768653Smckusick #endif
87868653Smckusick *mrq = NULL;
87968653Smckusick if (*ndp) {
88068653Smckusick nfsd = *ndp;
88168653Smckusick *ndp = NULL;
88268653Smckusick mrep = nfsd->nd_mrep;
88368653Smckusick md = nfsd->nd_md;
88468653Smckusick dpos = nfsd->nd_dpos;
88568653Smckusick cred = &nfsd->nd_cr;
88668653Smckusick v3 = (nfsd->nd_flag & ND_NFSV3);
88768653Smckusick LIST_INIT(&nfsd->nd_coalesce);
88868653Smckusick nfsd->nd_mreq = NULL;
88968653Smckusick nfsd->nd_stable = NFSV3WRITE_FILESYNC;
89068653Smckusick cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
89168653Smckusick nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
89268653Smckusick
89368653Smckusick /*
89468653Smckusick * Now, get the write header..
89568653Smckusick */
89668653Smckusick nfsm_srvmtofh(&nfsd->nd_fh);
89768653Smckusick if (v3) {
89868653Smckusick nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
89968653Smckusick fxdr_hyper(tl, &nfsd->nd_off);
90068653Smckusick tl += 3;
90168653Smckusick nfsd->nd_stable = fxdr_unsigned(int, *tl++);
90268653Smckusick } else {
90368653Smckusick nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
90468653Smckusick nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
90568653Smckusick tl += 2;
90668653Smckusick }
90768653Smckusick len = fxdr_unsigned(long, *tl);
90868653Smckusick nfsd->nd_len = len;
90968653Smckusick nfsd->nd_eoff = nfsd->nd_off + len;
91068653Smckusick
91168653Smckusick /*
91268653Smckusick * Trim the header out of the mbuf list and trim off any trailing
91368653Smckusick * junk so that the mbuf list has only the write data.
91468653Smckusick */
91568653Smckusick zeroing = 1;
91668653Smckusick i = 0;
91768653Smckusick mp = mrep;
91868653Smckusick while (mp) {
91968653Smckusick if (mp == md) {
92068653Smckusick zeroing = 0;
92168653Smckusick adjust = dpos - mtod(mp, caddr_t);
92268653Smckusick mp->m_len -= adjust;
92368653Smckusick if (mp->m_len > 0 && adjust > 0)
92468653Smckusick NFSMADV(mp, adjust);
92568653Smckusick }
92668653Smckusick if (zeroing)
92768653Smckusick mp->m_len = 0;
92868653Smckusick else {
92968653Smckusick i += mp->m_len;
93068653Smckusick if (i > len) {
93168653Smckusick mp->m_len -= (i - len);
93268653Smckusick zeroing = 1;
93368653Smckusick }
93468653Smckusick }
93568653Smckusick mp = mp->m_next;
93668653Smckusick }
93768653Smckusick if (len > NFS_MAXDATA || len < 0 || i < len) {
93868653Smckusick nfsmout:
93968653Smckusick m_freem(mrep);
94068653Smckusick error = EIO;
94168653Smckusick nfsm_writereply(2 * NFSX_UNSIGNED, v3);
94268653Smckusick if (v3)
94368653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
94468653Smckusick nfsd->nd_mreq = mreq;
94568653Smckusick nfsd->nd_mrep = NULL;
94668653Smckusick nfsd->nd_time = 0;
94768653Smckusick }
94868653Smckusick
94968653Smckusick /*
95068653Smckusick * Add this entry to the hash and time queues.
95168653Smckusick */
95268653Smckusick s = splsoftclock();
95368653Smckusick owp = NULL;
95468653Smckusick wp = slp->ns_tq.lh_first;
95568653Smckusick while (wp && wp->nd_time < nfsd->nd_time) {
95668653Smckusick owp = wp;
95768653Smckusick wp = wp->nd_tq.le_next;
95868653Smckusick }
95968653Smckusick if (owp) {
96068653Smckusick LIST_INSERT_AFTER(owp, nfsd, nd_tq);
96168653Smckusick } else {
96268653Smckusick LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
96368653Smckusick }
96468653Smckusick if (nfsd->nd_mrep) {
96568653Smckusick wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
96668653Smckusick owp = NULL;
96768653Smckusick wp = wpp->lh_first;
96868653Smckusick while (wp &&
96968653Smckusick bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
97068653Smckusick owp = wp;
97168653Smckusick wp = wp->nd_hash.le_next;
97268653Smckusick }
97368653Smckusick while (wp && wp->nd_off < nfsd->nd_off &&
97468653Smckusick !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
97568653Smckusick owp = wp;
97668653Smckusick wp = wp->nd_hash.le_next;
97768653Smckusick }
97868653Smckusick if (owp) {
97968653Smckusick LIST_INSERT_AFTER(owp, nfsd, nd_hash);
98068653Smckusick
98168653Smckusick /*
98268653Smckusick * Search the hash list for overlapping entries and
98368653Smckusick * coalesce.
98468653Smckusick */
98568653Smckusick for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
98668653Smckusick wp = nfsd->nd_hash.le_next;
98768653Smckusick if (NFSW_SAMECRED(owp, nfsd))
98868653Smckusick nfsrvw_coalesce(owp, nfsd);
98968653Smckusick }
99068653Smckusick } else {
99168653Smckusick LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
99268653Smckusick }
99368653Smckusick }
99468653Smckusick splx(s);
99568653Smckusick }
99668653Smckusick
99738418Smckusick /*
99868653Smckusick * Now, do VOP_WRITE()s for any one(s) that need to be done now
99968653Smckusick * and generate the associated reply mbuf list(s).
100038418Smckusick */
100168653Smckusick loop1:
100268653Smckusick cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
100368653Smckusick s = splsoftclock();
100468653Smckusick for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
100568653Smckusick owp = nfsd->nd_tq.le_next;
100668653Smckusick if (nfsd->nd_time > cur_usec)
100768653Smckusick break;
100868653Smckusick if (nfsd->nd_mreq)
100968653Smckusick continue;
101068653Smckusick LIST_REMOVE(nfsd, nd_tq);
101168653Smckusick LIST_REMOVE(nfsd, nd_hash);
101268653Smckusick splx(s);
101368653Smckusick mrep = nfsd->nd_mrep;
101468653Smckusick nfsd->nd_mrep = NULL;
101568653Smckusick cred = &nfsd->nd_cr;
101668653Smckusick v3 = (nfsd->nd_flag & ND_NFSV3);
101768653Smckusick forat_ret = aftat_ret = 1;
101868653Smckusick error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
101968653Smckusick nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
102068653Smckusick if (!error) {
102168653Smckusick if (v3)
102268653Smckusick forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
102368653Smckusick if (vp->v_type != VREG) {
102468653Smckusick if (v3)
102568653Smckusick error = EINVAL;
102638418Smckusick else
102768653Smckusick error = (vp->v_type == VDIR) ? EISDIR : EACCES;
102868653Smckusick }
102968653Smckusick } else
103068653Smckusick vp = NULL;
103168653Smckusick if (!error) {
103268653Smckusick nqsrv_getl(vp, ND_WRITE);
103368653Smckusick error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
103468653Smckusick }
103568653Smckusick
103668653Smckusick if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
103768653Smckusick ioflags = IO_NODELOCKED;
103868653Smckusick else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
103968653Smckusick ioflags = (IO_SYNC | IO_NODELOCKED);
104068653Smckusick else
104168653Smckusick ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
104268653Smckusick uiop->uio_rw = UIO_WRITE;
104368653Smckusick uiop->uio_segflg = UIO_SYSSPACE;
104468653Smckusick uiop->uio_procp = (struct proc *)0;
104568653Smckusick uiop->uio_offset = nfsd->nd_off;
104668653Smckusick uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
104768653Smckusick if (uiop->uio_resid > 0) {
104868653Smckusick mp = mrep;
104968653Smckusick i = 0;
105068653Smckusick while (mp) {
105168653Smckusick if (mp->m_len > 0)
105268653Smckusick i++;
105338418Smckusick mp = mp->m_next;
105468653Smckusick }
105568653Smckusick uiop->uio_iovcnt = i;
105668653Smckusick MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
105768653Smckusick M_TEMP, M_WAITOK);
105868653Smckusick uiop->uio_iov = ivp = iov;
105968653Smckusick mp = mrep;
106068653Smckusick while (mp) {
106168653Smckusick if (mp->m_len > 0) {
106268653Smckusick ivp->iov_base = mtod(mp, caddr_t);
106368653Smckusick ivp->iov_len = mp->m_len;
106468653Smckusick ivp++;
106568653Smckusick }
106668653Smckusick mp = mp->m_next;
106768653Smckusick }
106868653Smckusick if (!error) {
106968653Smckusick error = VOP_WRITE(vp, uiop, ioflags, cred);
107068653Smckusick nfsstats.srvvop_writes++;
107168653Smckusick }
107268653Smckusick FREE((caddr_t)iov, M_TEMP);
107338418Smckusick }
107468653Smckusick m_freem(mrep);
107568653Smckusick if (vp) {
107668653Smckusick aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
107768653Smckusick vput(vp);
107838418Smckusick }
107968653Smckusick
108068653Smckusick /*
108168653Smckusick * Loop around generating replies for all write rpcs that have
108268653Smckusick * now been completed.
108368653Smckusick */
108468653Smckusick swp = nfsd;
108568653Smckusick do {
108668653Smckusick if (error) {
108768653Smckusick nfsm_writereply(NFSX_WCCDATA(v3), v3);
108868653Smckusick if (v3) {
108968653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
109068653Smckusick }
109168653Smckusick } else {
109268653Smckusick nfsm_writereply(NFSX_PREOPATTR(v3) +
109368653Smckusick NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
109468653Smckusick NFSX_WRITEVERF(v3), v3);
109568653Smckusick if (v3) {
109668653Smckusick nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
109768653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
109868653Smckusick *tl++ = txdr_unsigned(nfsd->nd_len);
109968653Smckusick *tl++ = txdr_unsigned(swp->nd_stable);
110068653Smckusick /*
110168653Smckusick * Actually, there is no need to txdr these fields,
110268653Smckusick * but it may make the values more human readable,
110368653Smckusick * for debugging purposes.
110468653Smckusick */
110568653Smckusick *tl++ = txdr_unsigned(boottime.tv_sec);
110668653Smckusick *tl = txdr_unsigned(boottime.tv_usec);
110768653Smckusick } else {
110868653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
110968653Smckusick nfsm_srvfillattr(&va, fp);
111068653Smckusick }
111168653Smckusick }
111268653Smckusick nfsd->nd_mreq = mreq;
111368653Smckusick if (nfsd->nd_mrep)
111468653Smckusick panic("nfsrv_write: nd_mrep not free");
111568653Smckusick
111668653Smckusick /*
111768653Smckusick * Done. Put it at the head of the timer queue so that
111868653Smckusick * the final phase can return the reply.
111968653Smckusick */
112068653Smckusick s = splsoftclock();
112168653Smckusick if (nfsd != swp) {
112268653Smckusick nfsd->nd_time = 0;
112368653Smckusick LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
112468653Smckusick }
112568653Smckusick nfsd = swp->nd_coalesce.lh_first;
112668653Smckusick if (nfsd) {
112768653Smckusick LIST_REMOVE(nfsd, nd_tq);
112868653Smckusick }
112968653Smckusick splx(s);
113068653Smckusick } while (nfsd);
113168653Smckusick s = splsoftclock();
113268653Smckusick swp->nd_time = 0;
113368653Smckusick LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
113468653Smckusick splx(s);
113568653Smckusick goto loop1;
113668653Smckusick }
113768653Smckusick splx(s);
113868653Smckusick
113968653Smckusick /*
114068653Smckusick * Search for a reply to return.
114168653Smckusick */
114268653Smckusick s = splsoftclock();
114368653Smckusick for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
114468653Smckusick if (nfsd->nd_mreq) {
114568653Smckusick LIST_REMOVE(nfsd, nd_tq);
114668653Smckusick *mrq = nfsd->nd_mreq;
114768653Smckusick *ndp = nfsd;
114868653Smckusick break;
114938418Smckusick }
115068653Smckusick splx(s);
115168653Smckusick return (0);
115268653Smckusick }
115368653Smckusick
115468653Smckusick /*
115568653Smckusick * Coalesce the write request nfsd into owp. To do this we must:
115668653Smckusick * - remove nfsd from the queues
115768653Smckusick * - merge nfsd->nd_mrep into owp->nd_mrep
115868653Smckusick * - update the nd_eoff and nd_stable for owp
115968653Smckusick * - put nfsd on owp's nd_coalesce list
116068653Smckusick * NB: Must be called at splsoftclock().
116168653Smckusick */
116268653Smckusick void
nfsrvw_coalesce(owp,nfsd)116368653Smckusick nfsrvw_coalesce(owp, nfsd)
116468653Smckusick register struct nfsrv_descript *owp;
116568653Smckusick register struct nfsrv_descript *nfsd;
116668653Smckusick {
116768653Smckusick register int overlap;
116868653Smckusick register struct mbuf *mp;
116968653Smckusick
117068653Smckusick LIST_REMOVE(nfsd, nd_hash);
117168653Smckusick LIST_REMOVE(nfsd, nd_tq);
117268653Smckusick if (owp->nd_eoff < nfsd->nd_eoff) {
117368653Smckusick overlap = owp->nd_eoff - nfsd->nd_off;
117468653Smckusick if (overlap < 0)
117568653Smckusick panic("nfsrv_coalesce: bad off");
117668653Smckusick if (overlap > 0)
117768653Smckusick m_adj(nfsd->nd_mrep, overlap);
117868653Smckusick mp = owp->nd_mrep;
117968653Smckusick while (mp->m_next)
118068653Smckusick mp = mp->m_next;
118168653Smckusick mp->m_next = nfsd->nd_mrep;
118268653Smckusick owp->nd_eoff = nfsd->nd_eoff;
118368653Smckusick } else
118468653Smckusick m_freem(nfsd->nd_mrep);
118568653Smckusick nfsd->nd_mrep = NULL;
118668653Smckusick if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
118768653Smckusick owp->nd_stable = NFSV3WRITE_FILESYNC;
118868653Smckusick else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
118968653Smckusick owp->nd_stable == NFSV3WRITE_UNSTABLE)
119068653Smckusick owp->nd_stable = NFSV3WRITE_DATASYNC;
119168653Smckusick LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
119268653Smckusick }
119368653Smckusick
119468653Smckusick /*
119568653Smckusick * Sort the group list in increasing numerical order.
119668653Smckusick * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
119768653Smckusick * that used to be here.)
119868653Smckusick */
119968653Smckusick void
nfsrvw_sort(list,num)120068653Smckusick nfsrvw_sort(list, num)
120168653Smckusick register gid_t *list;
120268653Smckusick register int num;
120368653Smckusick {
120468653Smckusick register int i, j;
120568653Smckusick gid_t v;
120668653Smckusick
120768653Smckusick /* Insertion sort. */
120868653Smckusick for (i = 1; i < num; i++) {
120968653Smckusick v = list[i];
121068653Smckusick /* find correct slot for value v, moving others up */
121168653Smckusick for (j = i; --j >= 0 && v < list[j];)
121268653Smckusick list[j + 1] = list[j];
121368653Smckusick list[j + 1] = v;
121438418Smckusick }
121538418Smckusick }
121638418Smckusick
121738418Smckusick /*
121868653Smckusick * copy credentials making sure that the result can be compared with bcmp().
121968653Smckusick */
122068653Smckusick void
nfsrv_setcred(incred,outcred)122168653Smckusick nfsrv_setcred(incred, outcred)
122268653Smckusick register struct ucred *incred, *outcred;
122368653Smckusick {
122468653Smckusick register int i;
122568653Smckusick
122668653Smckusick bzero((caddr_t)outcred, sizeof (struct ucred));
122768653Smckusick outcred->cr_ref = 1;
122868653Smckusick outcred->cr_uid = incred->cr_uid;
122968653Smckusick outcred->cr_ngroups = incred->cr_ngroups;
123068653Smckusick for (i = 0; i < incred->cr_ngroups; i++)
123168653Smckusick outcred->cr_groups[i] = incred->cr_groups[i];
123268653Smckusick nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
123368653Smckusick }
123468653Smckusick
123568653Smckusick /*
123638418Smckusick * nfs create service
123738418Smckusick * now does a truncate to 0 length via. setattr if it already exists
123838418Smckusick */
123968653Smckusick int
nfsrv_create(nfsd,slp,procp,mrq)124068653Smckusick nfsrv_create(nfsd, slp, procp, mrq)
124168653Smckusick struct nfsrv_descript *nfsd;
124268653Smckusick struct nfssvc_sock *slp;
124368653Smckusick struct proc *procp;
124468653Smckusick struct mbuf **mrq;
124538418Smckusick {
124668653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
124768653Smckusick struct mbuf *nam = nfsd->nd_nam;
124868653Smckusick caddr_t dpos = nfsd->nd_dpos;
124968653Smckusick struct ucred *cred = &nfsd->nd_cr;
125068653Smckusick register struct nfs_fattr *fp;
125168653Smckusick struct vattr va, dirfor, diraft;
125238418Smckusick register struct vattr *vap = &va;
125356285Smckusick register struct nfsv2_sattr *sp;
125456285Smckusick register u_long *tl;
125549742Smckusick struct nameidata nd;
125639494Smckusick register caddr_t cp;
125739494Smckusick register long t1;
125839494Smckusick caddr_t bpos;
125968653Smckusick int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
126068653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
126139494Smckusick char *cp2;
126239753Smckusick struct mbuf *mb, *mb2, *mreq;
126368653Smckusick struct vnode *vp, *dirp = (struct vnode *)0;
126468653Smckusick nfsfh_t nfh;
126538418Smckusick fhandle_t *fhp;
126668653Smckusick u_quad_t frev, tempsize;
126768653Smckusick u_char cverf[NFSX_V3CREATEVERF];
126838418Smckusick
126968653Smckusick #ifndef nolint
127068653Smckusick rdev = 0;
127168653Smckusick #endif
127252316Sheideman nd.ni_cnd.cn_nameiop = 0;
127338418Smckusick fhp = &nfh.fh_generic;
127438418Smckusick nfsm_srvmtofh(fhp);
127568653Smckusick nfsm_srvnamesiz(len);
127652316Sheideman nd.ni_cnd.cn_cred = cred;
127752316Sheideman nd.ni_cnd.cn_nameiop = CREATE;
127852316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
127968653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
128068653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
128168653Smckusick if (dirp) {
128268653Smckusick if (v3)
128368653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
128468653Smckusick procp);
128568653Smckusick else {
128668653Smckusick vrele(dirp);
128768653Smckusick dirp = (struct vnode *)0;
128868653Smckusick }
128968653Smckusick }
129068653Smckusick if (error) {
129168653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
129268653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
129368653Smckusick if (dirp)
129468653Smckusick vrele(dirp);
129568653Smckusick return (0);
129668653Smckusick }
129741361Smckusick VATTR_NULL(vap);
129868653Smckusick if (v3) {
129968653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
130068653Smckusick how = fxdr_unsigned(int, *tl);
130168653Smckusick switch (how) {
130268653Smckusick case NFSV3CREATE_GUARDED:
130368653Smckusick if (nd.ni_vp) {
130468653Smckusick error = EEXIST;
130568653Smckusick break;
130668653Smckusick }
130768653Smckusick case NFSV3CREATE_UNCHECKED:
130868653Smckusick nfsm_srvsattr(vap);
130968653Smckusick break;
131068653Smckusick case NFSV3CREATE_EXCLUSIVE:
131168653Smckusick nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
131268653Smckusick bcopy(cp, cverf, NFSX_V3CREATEVERF);
131368653Smckusick exclusive_flag = 1;
131468653Smckusick if (nd.ni_vp == NULL)
131568653Smckusick vap->va_mode = 0;
131668653Smckusick break;
131768653Smckusick };
131868653Smckusick vap->va_type = VREG;
131968653Smckusick } else {
132068653Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
132168653Smckusick vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
132268653Smckusick if (vap->va_type == VNON)
132368653Smckusick vap->va_type = VREG;
132468653Smckusick vap->va_mode = nfstov_mode(sp->sa_mode);
132568653Smckusick switch (vap->va_type) {
132668653Smckusick case VREG:
132768653Smckusick tsize = fxdr_unsigned(long, sp->sa_size);
132868653Smckusick if (tsize != -1)
132968653Smckusick vap->va_size = (u_quad_t)tsize;
133068653Smckusick break;
133168653Smckusick case VCHR:
133268653Smckusick case VBLK:
133368653Smckusick case VFIFO:
133468653Smckusick rdev = fxdr_unsigned(long, sp->sa_size);
133568653Smckusick break;
133668653Smckusick };
133768653Smckusick }
133868653Smckusick
133938418Smckusick /*
134038418Smckusick * Iff doesn't exist, create it
134138418Smckusick * otherwise just truncate to 0 length
134238418Smckusick * should I set the mode too ??
134338418Smckusick */
134449742Smckusick if (nd.ni_vp == NULL) {
134546988Smckusick if (vap->va_type == VREG || vap->va_type == VSOCK) {
134649742Smckusick vrele(nd.ni_startdir);
134768653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
134868653Smckusick error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
134968653Smckusick if (!error) {
135068653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
135168653Smckusick if (exclusive_flag) {
135268653Smckusick exclusive_flag = 0;
135368653Smckusick VATTR_NULL(vap);
135468653Smckusick bcopy(cverf, (caddr_t)&vap->va_atime,
135568653Smckusick NFSX_V3CREATEVERF);
135668653Smckusick error = VOP_SETATTR(nd.ni_vp, vap, cred,
135768653Smckusick procp);
135868653Smckusick }
135968653Smckusick }
136042242Smckusick } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
136142242Smckusick vap->va_type == VFIFO) {
136242242Smckusick if (vap->va_type == VCHR && rdev == 0xffffffff)
136342242Smckusick vap->va_type = VFIFO;
136468653Smckusick if (error = suser(cred, (u_short *)0)) {
136568653Smckusick vrele(nd.ni_startdir);
136668653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
136752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
136849742Smckusick vput(nd.ni_dvp);
136968653Smckusick nfsm_reply(0);
137068653Smckusick return (error);
137142242Smckusick } else
137242242Smckusick vap->va_rdev = (dev_t)rdev;
137368653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
137452234Sheideman if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
137549742Smckusick vrele(nd.ni_startdir);
137642242Smckusick nfsm_reply(0);
137749742Smckusick }
137852316Sheideman nd.ni_cnd.cn_nameiop = LOOKUP;
137952316Sheideman nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
138068653Smckusick nd.ni_cnd.cn_proc = procp;
138168653Smckusick nd.ni_cnd.cn_cred = cred;
138252316Sheideman if (error = lookup(&nd)) {
138352316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
138442242Smckusick nfsm_reply(0);
138549742Smckusick }
138652316Sheideman FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
138752316Sheideman if (nd.ni_cnd.cn_flags & ISSYMLINK) {
138849742Smckusick vrele(nd.ni_dvp);
138949742Smckusick vput(nd.ni_vp);
139052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
139149742Smckusick error = EINVAL;
139249742Smckusick nfsm_reply(0);
139349742Smckusick }
139442242Smckusick } else {
139568653Smckusick vrele(nd.ni_startdir);
139668653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
139752234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
139849742Smckusick vput(nd.ni_dvp);
139942242Smckusick error = ENXIO;
140042242Smckusick }
140149742Smckusick vp = nd.ni_vp;
140238418Smckusick } else {
140349742Smckusick vrele(nd.ni_startdir);
140452316Sheideman free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
140549742Smckusick vp = nd.ni_vp;
140649742Smckusick if (nd.ni_dvp == vp)
140749742Smckusick vrele(nd.ni_dvp);
140843359Smckusick else
140949742Smckusick vput(nd.ni_dvp);
141052234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
141156285Smckusick if (vap->va_size != -1) {
141268653Smckusick error = nfsrv_access(vp, VWRITE, cred,
141368653Smckusick (nd.ni_cnd.cn_flags & RDONLY), procp);
141468653Smckusick if (!error) {
141568653Smckusick nqsrv_getl(vp, ND_WRITE);
141668653Smckusick tempsize = vap->va_size;
141768653Smckusick VATTR_NULL(vap);
141868653Smckusick vap->va_size = tempsize;
141968653Smckusick error = VOP_SETATTR(vp, vap, cred,
142068653Smckusick procp);
142160401Smckusick }
142268653Smckusick if (error)
142356285Smckusick vput(vp);
142442506Smckusick }
142538418Smckusick }
142668653Smckusick if (!error) {
142768653Smckusick bzero((caddr_t)fhp, sizeof(nfh));
142868653Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
142968653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid);
143068653Smckusick if (!error)
143168653Smckusick error = VOP_GETATTR(vp, vap, cred, procp);
143238418Smckusick vput(vp);
143338418Smckusick }
143468653Smckusick if (v3) {
143568653Smckusick if (exclusive_flag && !error &&
143668653Smckusick bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
143768653Smckusick error = EEXIST;
143868653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
143968653Smckusick vrele(dirp);
144068653Smckusick }
144168653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
144268653Smckusick if (v3) {
144368653Smckusick if (!error) {
144468653Smckusick nfsm_srvpostop_fh(fhp);
144568653Smckusick nfsm_srvpostop_attr(0, vap);
144668653Smckusick }
144768653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
144868653Smckusick } else {
144968653Smckusick nfsm_srvfhtom(fhp, v3);
145068653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
145168653Smckusick nfsm_srvfillattr(vap, fp);
145268653Smckusick }
145368653Smckusick return (0);
145438418Smckusick nfsmout:
145568653Smckusick if (dirp)
145668653Smckusick vrele(dirp);
145768653Smckusick if (nd.ni_cnd.cn_nameiop) {
145851464Sbostic vrele(nd.ni_startdir);
145968653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
146068653Smckusick }
146152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
146249742Smckusick if (nd.ni_dvp == nd.ni_vp)
146349742Smckusick vrele(nd.ni_dvp);
146443359Smckusick else
146549742Smckusick vput(nd.ni_dvp);
146649742Smckusick if (nd.ni_vp)
146749742Smckusick vput(nd.ni_vp);
146838418Smckusick return (error);
146938418Smckusick }
147038418Smckusick
147138418Smckusick /*
147268653Smckusick * nfs v3 mknod service
147338418Smckusick */
147468653Smckusick int
nfsrv_mknod(nfsd,slp,procp,mrq)147568653Smckusick nfsrv_mknod(nfsd, slp, procp, mrq)
147668653Smckusick struct nfsrv_descript *nfsd;
147768653Smckusick struct nfssvc_sock *slp;
147868653Smckusick struct proc *procp;
147968653Smckusick struct mbuf **mrq;
148038418Smckusick {
148168653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
148268653Smckusick struct mbuf *nam = nfsd->nd_nam;
148368653Smckusick caddr_t dpos = nfsd->nd_dpos;
148468653Smckusick struct ucred *cred = &nfsd->nd_cr;
148568653Smckusick register struct nfs_fattr *fp;
148668653Smckusick struct vattr va, dirfor, diraft;
148768653Smckusick register struct vattr *vap = &va;
148868653Smckusick register u_long *tl;
148949742Smckusick struct nameidata nd;
149068653Smckusick register caddr_t cp;
149139494Smckusick register long t1;
149239494Smckusick caddr_t bpos;
149368653Smckusick int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
149468653Smckusick u_long major, minor;
149568653Smckusick enum vtype vtyp;
149639494Smckusick char *cp2;
149768653Smckusick struct mbuf *mb, *mb2, *mreq;
149868653Smckusick struct vnode *vp, *dirp = (struct vnode *)0;
149968653Smckusick nfsfh_t nfh;
150038418Smckusick fhandle_t *fhp;
150152196Smckusick u_quad_t frev;
150238418Smckusick
150368653Smckusick nd.ni_cnd.cn_nameiop = 0;
150438418Smckusick fhp = &nfh.fh_generic;
150538418Smckusick nfsm_srvmtofh(fhp);
150668653Smckusick nfsm_srvnamesiz(len);
150752316Sheideman nd.ni_cnd.cn_cred = cred;
150868653Smckusick nd.ni_cnd.cn_nameiop = CREATE;
150968653Smckusick nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
151068653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
151168653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
151268653Smckusick if (dirp)
151368653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
151468653Smckusick if (error) {
151568653Smckusick nfsm_reply(NFSX_WCCDATA(1));
151668653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
151768653Smckusick if (dirp)
151868653Smckusick vrele(dirp);
151968653Smckusick return (0);
152068653Smckusick }
152168653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
152268653Smckusick vtyp = nfsv3tov_type(*tl);
152368653Smckusick if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
152468653Smckusick vrele(nd.ni_startdir);
152568653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
152668653Smckusick error = NFSERR_BADTYPE;
152768653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
152868653Smckusick vput(nd.ni_dvp);
152938418Smckusick goto out;
153068653Smckusick }
153168653Smckusick VATTR_NULL(vap);
153268653Smckusick nfsm_srvsattr(vap);
153368653Smckusick if (vtyp == VCHR || vtyp == VBLK) {
153468653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
153568653Smckusick major = fxdr_unsigned(u_long, *tl++);
153668653Smckusick minor = fxdr_unsigned(u_long, *tl);
153768653Smckusick vap->va_rdev = makedev(major, minor);
153868653Smckusick }
153968653Smckusick
154038418Smckusick /*
154168653Smckusick * Iff doesn't exist, create it.
154238418Smckusick */
154368653Smckusick if (nd.ni_vp) {
154468653Smckusick vrele(nd.ni_startdir);
154568653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
154668653Smckusick error = EEXIST;
154768653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
154868653Smckusick vput(nd.ni_dvp);
154938418Smckusick goto out;
155038418Smckusick }
155168653Smckusick vap->va_type = vtyp;
155268653Smckusick if (vtyp == VSOCK) {
155368653Smckusick vrele(nd.ni_startdir);
155468653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
155568653Smckusick error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
155668653Smckusick if (!error)
155768653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
155868653Smckusick } else {
155968653Smckusick if (error = suser(cred, (u_short *)0)) {
156068653Smckusick vrele(nd.ni_startdir);
156168653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
156268653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
156368653Smckusick vput(nd.ni_dvp);
156468653Smckusick goto out;
156568653Smckusick }
156668653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
156768653Smckusick if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
156868653Smckusick vrele(nd.ni_startdir);
156968653Smckusick goto out;
157068653Smckusick }
157168653Smckusick nd.ni_cnd.cn_nameiop = LOOKUP;
157268653Smckusick nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
157368653Smckusick nd.ni_cnd.cn_proc = procp;
157468653Smckusick nd.ni_cnd.cn_cred = procp->p_ucred;
157568653Smckusick error = lookup(&nd);
157668653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
157768653Smckusick if (error)
157868653Smckusick goto out;
157968653Smckusick if (nd.ni_cnd.cn_flags & ISSYMLINK) {
158068653Smckusick vrele(nd.ni_dvp);
158168653Smckusick vput(nd.ni_vp);
158268653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
158368653Smckusick error = EINVAL;
158468653Smckusick }
158568653Smckusick }
158638418Smckusick out:
158768653Smckusick vp = nd.ni_vp;
158842467Smckusick if (!error) {
158968653Smckusick bzero((caddr_t)fhp, sizeof(nfh));
159068653Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
159168653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid);
159268653Smckusick if (!error)
159368653Smckusick error = VOP_GETATTR(vp, vap, cred, procp);
159442467Smckusick vput(vp);
159542467Smckusick }
159668653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
159768653Smckusick vrele(dirp);
159868653Smckusick nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
159968653Smckusick if (!error) {
160068653Smckusick nfsm_srvpostop_fh(fhp);
160168653Smckusick nfsm_srvpostop_attr(0, vap);
160268653Smckusick }
160368653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
160468653Smckusick return (0);
160568653Smckusick nfsmout:
160668653Smckusick if (dirp)
160768653Smckusick vrele(dirp);
160868653Smckusick if (nd.ni_cnd.cn_nameiop) {
160968653Smckusick vrele(nd.ni_startdir);
161068653Smckusick free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
161168653Smckusick }
161268653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
161368653Smckusick if (nd.ni_dvp == nd.ni_vp)
161468653Smckusick vrele(nd.ni_dvp);
161568653Smckusick else
161668653Smckusick vput(nd.ni_dvp);
161768653Smckusick if (nd.ni_vp)
161868653Smckusick vput(nd.ni_vp);
161968653Smckusick return (error);
162068653Smckusick }
162168653Smckusick
162268653Smckusick /*
162368653Smckusick * nfs remove service
162468653Smckusick */
162568653Smckusick int
nfsrv_remove(nfsd,slp,procp,mrq)162668653Smckusick nfsrv_remove(nfsd, slp, procp, mrq)
162768653Smckusick struct nfsrv_descript *nfsd;
162868653Smckusick struct nfssvc_sock *slp;
162968653Smckusick struct proc *procp;
163068653Smckusick struct mbuf **mrq;
163168653Smckusick {
163268653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
163368653Smckusick struct mbuf *nam = nfsd->nd_nam;
163468653Smckusick caddr_t dpos = nfsd->nd_dpos;
163568653Smckusick struct ucred *cred = &nfsd->nd_cr;
163668653Smckusick struct nameidata nd;
163768653Smckusick register u_long *tl;
163868653Smckusick register long t1;
163968653Smckusick caddr_t bpos;
164068653Smckusick int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
164168653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
164268653Smckusick char *cp2;
164368653Smckusick struct mbuf *mb, *mreq, *mb2;
164468653Smckusick struct vnode *vp, *dirp;
164568653Smckusick struct vattr dirfor, diraft;
164668653Smckusick nfsfh_t nfh;
164768653Smckusick fhandle_t *fhp;
164868653Smckusick u_quad_t frev;
164968653Smckusick
165068653Smckusick #ifndef nolint
165168653Smckusick vp = (struct vnode *)0;
165268653Smckusick #endif
165368653Smckusick fhp = &nfh.fh_generic;
165468653Smckusick nfsm_srvmtofh(fhp);
165568653Smckusick nfsm_srvnamesiz(len);
165668653Smckusick nd.ni_cnd.cn_cred = cred;
165768653Smckusick nd.ni_cnd.cn_nameiop = DELETE;
165868653Smckusick nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
165968653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
166068653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
166168653Smckusick if (dirp) {
166268653Smckusick if (v3)
166368653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
166468653Smckusick procp);
166568653Smckusick else
166668653Smckusick vrele(dirp);
166768653Smckusick }
166868653Smckusick if (!error) {
166968653Smckusick vp = nd.ni_vp;
167068653Smckusick if (vp->v_type == VDIR &&
167168653Smckusick (error = suser(cred, (u_short *)0)))
167268653Smckusick goto out;
167368653Smckusick /*
167468653Smckusick * The root of a mounted filesystem cannot be deleted.
167568653Smckusick */
167668653Smckusick if (vp->v_flag & VROOT) {
167768653Smckusick error = EBUSY;
167868653Smckusick goto out;
167968653Smckusick }
168068653Smckusick if (vp->v_flag & VTEXT)
168168653Smckusick (void) vnode_pager_uncache(vp);
168268653Smckusick out:
168368653Smckusick if (!error) {
168468653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
168568653Smckusick nqsrv_getl(vp, ND_WRITE);
168668653Smckusick error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
168768653Smckusick } else {
168868653Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
168968653Smckusick if (nd.ni_dvp == vp)
169068653Smckusick vrele(nd.ni_dvp);
169168653Smckusick else
169268653Smckusick vput(nd.ni_dvp);
169368653Smckusick vput(vp);
169468653Smckusick }
169568653Smckusick }
169668653Smckusick if (dirp && v3) {
169768653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
169868653Smckusick vrele(dirp);
169968653Smckusick }
170068653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
170168653Smckusick if (v3) {
170268653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
170368653Smckusick return (0);
170468653Smckusick }
170538418Smckusick nfsm_srvdone;
170638418Smckusick }
170738418Smckusick
170838418Smckusick /*
170938418Smckusick * nfs rename service
171038418Smckusick */
171168653Smckusick int
nfsrv_rename(nfsd,slp,procp,mrq)171268653Smckusick nfsrv_rename(nfsd, slp, procp, mrq)
171368653Smckusick struct nfsrv_descript *nfsd;
171468653Smckusick struct nfssvc_sock *slp;
171568653Smckusick struct proc *procp;
171668653Smckusick struct mbuf **mrq;
171738418Smckusick {
171868653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
171968653Smckusick struct mbuf *nam = nfsd->nd_nam;
172068653Smckusick caddr_t dpos = nfsd->nd_dpos;
172168653Smckusick struct ucred *cred = &nfsd->nd_cr;
172248050Smckusick register u_long *tl;
172339494Smckusick register long t1;
172439494Smckusick caddr_t bpos;
172568653Smckusick int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
172668653Smckusick int tdirfor_ret = 1, tdiraft_ret = 1;
172768653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
172839494Smckusick char *cp2;
172968653Smckusick struct mbuf *mb, *mreq, *mb2;
173049742Smckusick struct nameidata fromnd, tond;
173168653Smckusick struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
173268653Smckusick struct vnode *tdirp = (struct vnode *)0;
173368653Smckusick struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
173468653Smckusick nfsfh_t fnfh, tnfh;
173538418Smckusick fhandle_t *ffhp, *tfhp;
173652196Smckusick u_quad_t frev;
173752196Smckusick uid_t saved_uid;
173838418Smckusick
173968653Smckusick #ifndef nolint
174068653Smckusick fvp = (struct vnode *)0;
174168653Smckusick #endif
174238418Smckusick ffhp = &fnfh.fh_generic;
174338418Smckusick tfhp = &tnfh.fh_generic;
174452316Sheideman fromnd.ni_cnd.cn_nameiop = 0;
174552316Sheideman tond.ni_cnd.cn_nameiop = 0;
174638418Smckusick nfsm_srvmtofh(ffhp);
174768653Smckusick nfsm_srvnamesiz(len);
174838418Smckusick /*
174952196Smckusick * Remember our original uid so that we can reset cr_uid before
175052196Smckusick * the second nfs_namei() call, in case it is remapped.
175138418Smckusick */
175252196Smckusick saved_uid = cred->cr_uid;
175352316Sheideman fromnd.ni_cnd.cn_cred = cred;
175452316Sheideman fromnd.ni_cnd.cn_nameiop = DELETE;
175552316Sheideman fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
175668653Smckusick error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
175768653Smckusick &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
175868653Smckusick if (fdirp) {
175968653Smckusick if (v3)
176068653Smckusick fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
176168653Smckusick procp);
176268653Smckusick else {
176368653Smckusick vrele(fdirp);
176468653Smckusick fdirp = (struct vnode *)0;
176568653Smckusick }
176668653Smckusick }
176768653Smckusick if (error) {
176868653Smckusick nfsm_reply(2 * NFSX_WCCDATA(v3));
176968653Smckusick nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
177068653Smckusick nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
177168653Smckusick if (fdirp)
177268653Smckusick vrele(fdirp);
177368653Smckusick return (0);
177468653Smckusick }
177549742Smckusick fvp = fromnd.ni_vp;
177638418Smckusick nfsm_srvmtofh(tfhp);
177741899Smckusick nfsm_strsiz(len2, NFS_MAXNAMLEN);
177852196Smckusick cred->cr_uid = saved_uid;
177952316Sheideman tond.ni_cnd.cn_cred = cred;
178052316Sheideman tond.ni_cnd.cn_nameiop = RENAME;
178152316Sheideman tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
178268653Smckusick error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
178368653Smckusick &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
178468653Smckusick if (tdirp) {
178568653Smckusick if (v3)
178668653Smckusick tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
178768653Smckusick procp);
178868653Smckusick else {
178968653Smckusick vrele(tdirp);
179068653Smckusick tdirp = (struct vnode *)0;
179168653Smckusick }
179268653Smckusick }
179368653Smckusick if (error) {
179452234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
179549742Smckusick vrele(fromnd.ni_dvp);
179642467Smckusick vrele(fvp);
179742467Smckusick goto out1;
179842467Smckusick }
179938425Smckusick tdvp = tond.ni_dvp;
180038425Smckusick tvp = tond.ni_vp;
180138418Smckusick if (tvp != NULL) {
180238418Smckusick if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
180368653Smckusick if (v3)
180468653Smckusick error = EEXIST;
180568653Smckusick else
180668653Smckusick error = EISDIR;
180738418Smckusick goto out;
180838418Smckusick } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
180968653Smckusick if (v3)
181068653Smckusick error = EEXIST;
181168653Smckusick else
181268653Smckusick error = ENOTDIR;
181338418Smckusick goto out;
181438418Smckusick }
181552196Smckusick if (tvp->v_type == VDIR && tvp->v_mountedhere) {
181668653Smckusick if (v3)
181768653Smckusick error = EXDEV;
181868653Smckusick else
181968653Smckusick error = ENOTEMPTY;
182052196Smckusick goto out;
182152196Smckusick }
182238418Smckusick }
182352196Smckusick if (fvp->v_type == VDIR && fvp->v_mountedhere) {
182468653Smckusick if (v3)
182568653Smckusick error = EXDEV;
182668653Smckusick else
182768653Smckusick error = ENOTEMPTY;
182852196Smckusick goto out;
182952196Smckusick }
183038418Smckusick if (fvp->v_mount != tdvp->v_mount) {
183168653Smckusick if (v3)
183268653Smckusick error = EXDEV;
183368653Smckusick else
183468653Smckusick error = ENOTEMPTY;
183538418Smckusick goto out;
183638418Smckusick }
183749742Smckusick if (fvp == tdvp)
183868653Smckusick if (v3)
183968653Smckusick error = EINVAL;
184068653Smckusick else
184168653Smckusick error = ENOTEMPTY;
184249742Smckusick /*
184349742Smckusick * If source is the same as the destination (that is the
184449742Smckusick * same vnode with the same name in the same directory),
184549742Smckusick * then there is nothing to do.
184649742Smckusick */
184749742Smckusick if (fvp == tvp && fromnd.ni_dvp == tdvp &&
184852316Sheideman fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
184952316Sheideman !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
185052316Sheideman fromnd.ni_cnd.cn_namelen))
185149742Smckusick error = -1;
185238418Smckusick out:
185342467Smckusick if (!error) {
185468653Smckusick nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
185568653Smckusick nqsrv_getl(tdvp, ND_WRITE);
185652196Smckusick if (tvp)
185768653Smckusick nqsrv_getl(tvp, ND_WRITE);
185852234Sheideman error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
185952234Sheideman tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
186042467Smckusick } else {
186152234Sheideman VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
186243359Smckusick if (tdvp == tvp)
186343359Smckusick vrele(tdvp);
186443359Smckusick else
186543359Smckusick vput(tdvp);
186642467Smckusick if (tvp)
186742467Smckusick vput(tvp);
186852234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
186949742Smckusick vrele(fromnd.ni_dvp);
187042467Smckusick vrele(fvp);
187168653Smckusick if (error == -1)
187268653Smckusick error = 0;
187338418Smckusick }
187446513Smckusick vrele(tond.ni_startdir);
187552316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
187638418Smckusick out1:
187768653Smckusick if (fdirp) {
187868653Smckusick fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
187968653Smckusick vrele(fdirp);
188068653Smckusick }
188168653Smckusick if (tdirp) {
188268653Smckusick tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
188368653Smckusick vrele(tdirp);
188468653Smckusick }
188549742Smckusick vrele(fromnd.ni_startdir);
188652316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
188768653Smckusick nfsm_reply(2 * NFSX_WCCDATA(v3));
188868653Smckusick if (v3) {
188968653Smckusick nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
189068653Smckusick nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
189168653Smckusick }
189268653Smckusick return (0);
189349742Smckusick
189438418Smckusick nfsmout:
189568653Smckusick if (fdirp)
189668653Smckusick vrele(fdirp);
189768653Smckusick if (tdirp)
189868653Smckusick vrele(tdirp);
189968653Smckusick if (tond.ni_cnd.cn_nameiop) {
190049742Smckusick vrele(tond.ni_startdir);
190152316Sheideman FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
190249742Smckusick }
190368653Smckusick if (fromnd.ni_cnd.cn_nameiop) {
190449742Smckusick vrele(fromnd.ni_startdir);
190552316Sheideman FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
190652234Sheideman VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
190749742Smckusick vrele(fromnd.ni_dvp);
190849742Smckusick vrele(fvp);
190949742Smckusick }
191038418Smckusick return (error);
191138418Smckusick }
191238418Smckusick
191338418Smckusick /*
191438418Smckusick * nfs link service
191538418Smckusick */
191668653Smckusick int
nfsrv_link(nfsd,slp,procp,mrq)191768653Smckusick nfsrv_link(nfsd, slp, procp, mrq)
191868653Smckusick struct nfsrv_descript *nfsd;
191968653Smckusick struct nfssvc_sock *slp;
192068653Smckusick struct proc *procp;
192168653Smckusick struct mbuf **mrq;
192238418Smckusick {
192368653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
192468653Smckusick struct mbuf *nam = nfsd->nd_nam;
192568653Smckusick caddr_t dpos = nfsd->nd_dpos;
192668653Smckusick struct ucred *cred = &nfsd->nd_cr;
192749742Smckusick struct nameidata nd;
192848050Smckusick register u_long *tl;
192939494Smckusick register long t1;
193039494Smckusick caddr_t bpos;
193168653Smckusick int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
193268653Smckusick int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
193339494Smckusick char *cp2;
193468653Smckusick struct mbuf *mb, *mreq, *mb2;
193568653Smckusick struct vnode *vp, *xp, *dirp = (struct vnode *)0;
193668653Smckusick struct vattr dirfor, diraft, at;
193768653Smckusick nfsfh_t nfh, dnfh;
193838418Smckusick fhandle_t *fhp, *dfhp;
193952196Smckusick u_quad_t frev;
194038418Smckusick
194138418Smckusick fhp = &nfh.fh_generic;
194238418Smckusick dfhp = &dnfh.fh_generic;
194338418Smckusick nfsm_srvmtofh(fhp);
194438418Smckusick nfsm_srvmtofh(dfhp);
194568653Smckusick nfsm_srvnamesiz(len);
194668653Smckusick if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
194768653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
194868653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
194968653Smckusick nfsm_srvpostop_attr(getret, &at);
195068653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
195168653Smckusick return (0);
195268653Smckusick }
195352196Smckusick if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
195438418Smckusick goto out1;
195552316Sheideman nd.ni_cnd.cn_cred = cred;
195652316Sheideman nd.ni_cnd.cn_nameiop = CREATE;
195752316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT;
195868653Smckusick error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
195968653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
196068653Smckusick if (dirp) {
196168653Smckusick if (v3)
196268653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
196368653Smckusick procp);
196468653Smckusick else {
196568653Smckusick vrele(dirp);
196668653Smckusick dirp = (struct vnode *)0;
196768653Smckusick }
196868653Smckusick }
196968653Smckusick if (error)
197038418Smckusick goto out1;
197149742Smckusick xp = nd.ni_vp;
197238418Smckusick if (xp != NULL) {
197338418Smckusick error = EEXIST;
197438418Smckusick goto out;
197538418Smckusick }
197649742Smckusick xp = nd.ni_dvp;
197738418Smckusick if (vp->v_mount != xp->v_mount)
197838418Smckusick error = EXDEV;
197938418Smckusick out:
198042467Smckusick if (!error) {
198168653Smckusick nqsrv_getl(vp, ND_WRITE);
198268653Smckusick nqsrv_getl(xp, ND_WRITE);
198368539Smckusick error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
198442467Smckusick } else {
198552234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
198649742Smckusick if (nd.ni_dvp == nd.ni_vp)
198749742Smckusick vrele(nd.ni_dvp);
198843359Smckusick else
198949742Smckusick vput(nd.ni_dvp);
199049742Smckusick if (nd.ni_vp)
199149742Smckusick vrele(nd.ni_vp);
199242467Smckusick }
199338418Smckusick out1:
199468653Smckusick if (v3)
199568653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp);
199668653Smckusick if (dirp) {
199768653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
199868653Smckusick vrele(dirp);
199968653Smckusick }
200038418Smckusick vrele(vp);
200168653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
200268653Smckusick if (v3) {
200368653Smckusick nfsm_srvpostop_attr(getret, &at);
200468653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
200568653Smckusick return (0);
200668653Smckusick }
200738418Smckusick nfsm_srvdone;
200838418Smckusick }
200938418Smckusick
201038418Smckusick /*
201138418Smckusick * nfs symbolic link service
201238418Smckusick */
201368653Smckusick int
nfsrv_symlink(nfsd,slp,procp,mrq)201468653Smckusick nfsrv_symlink(nfsd, slp, procp, mrq)
201568653Smckusick struct nfsrv_descript *nfsd;
201668653Smckusick struct nfssvc_sock *slp;
201768653Smckusick struct proc *procp;
201868653Smckusick struct mbuf **mrq;
201938418Smckusick {
202068653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
202168653Smckusick struct mbuf *nam = nfsd->nd_nam;
202268653Smckusick caddr_t dpos = nfsd->nd_dpos;
202368653Smckusick struct ucred *cred = &nfsd->nd_cr;
202468653Smckusick struct vattr va, dirfor, diraft;
202549742Smckusick struct nameidata nd;
202638418Smckusick register struct vattr *vap = &va;
202748050Smckusick register u_long *tl;
202839494Smckusick register long t1;
202945285Smckusick struct nfsv2_sattr *sp;
203068653Smckusick char *bpos, *cp, *pathcp = (char *)0, *cp2;
203141899Smckusick struct uio io;
203241899Smckusick struct iovec iv;
203368653Smckusick int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
203468653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
203568653Smckusick struct mbuf *mb, *mreq, *mb2;
203668653Smckusick struct vnode *dirp = (struct vnode *)0;
203768653Smckusick nfsfh_t nfh;
203838418Smckusick fhandle_t *fhp;
203952196Smckusick u_quad_t frev;
204038418Smckusick
204168653Smckusick nd.ni_cnd.cn_nameiop = 0;
204238418Smckusick fhp = &nfh.fh_generic;
204338418Smckusick nfsm_srvmtofh(fhp);
204468653Smckusick nfsm_srvnamesiz(len);
204552316Sheideman nd.ni_cnd.cn_cred = cred;
204652316Sheideman nd.ni_cnd.cn_nameiop = CREATE;
204768653Smckusick nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
204868653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
204968653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
205068653Smckusick if (dirp) {
205168653Smckusick if (v3)
205268653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
205368653Smckusick procp);
205468653Smckusick else {
205568653Smckusick vrele(dirp);
205668653Smckusick dirp = (struct vnode *)0;
205768653Smckusick }
205868653Smckusick }
205968653Smckusick if (error)
206042467Smckusick goto out;
206168653Smckusick VATTR_NULL(vap);
206268653Smckusick if (v3)
206368653Smckusick nfsm_srvsattr(vap);
206441899Smckusick nfsm_strsiz(len2, NFS_MAXPATHLEN);
206541899Smckusick MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
206641899Smckusick iv.iov_base = pathcp;
206741899Smckusick iv.iov_len = len2;
206841899Smckusick io.uio_resid = len2;
206941899Smckusick io.uio_offset = 0;
207041899Smckusick io.uio_iov = &iv;
207141899Smckusick io.uio_iovcnt = 1;
207241899Smckusick io.uio_segflg = UIO_SYSSPACE;
207341899Smckusick io.uio_rw = UIO_READ;
207448050Smckusick io.uio_procp = (struct proc *)0;
207541899Smckusick nfsm_mtouio(&io, len2);
207668653Smckusick if (!v3) {
207768653Smckusick nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
207868653Smckusick vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
207968653Smckusick }
208041899Smckusick *(pathcp + len2) = '\0';
208149742Smckusick if (nd.ni_vp) {
208268653Smckusick vrele(nd.ni_startdir);
208368653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
208452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
208549742Smckusick if (nd.ni_dvp == nd.ni_vp)
208649742Smckusick vrele(nd.ni_dvp);
208743359Smckusick else
208849742Smckusick vput(nd.ni_dvp);
208949742Smckusick vrele(nd.ni_vp);
209038418Smckusick error = EEXIST;
209138418Smckusick goto out;
209238418Smckusick }
209368653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
209452234Sheideman error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
209568653Smckusick if (error)
209668653Smckusick vrele(nd.ni_startdir);
209768653Smckusick else {
209868653Smckusick if (v3) {
209968653Smckusick nd.ni_cnd.cn_nameiop = LOOKUP;
210068653Smckusick nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
210168653Smckusick nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
210268653Smckusick nd.ni_cnd.cn_proc = procp;
210368653Smckusick nd.ni_cnd.cn_cred = cred;
210468653Smckusick error = lookup(&nd);
210568653Smckusick if (!error) {
210668653Smckusick bzero((caddr_t)fhp, sizeof(nfh));
210768653Smckusick fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
210868653Smckusick error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
210968653Smckusick if (!error)
211068653Smckusick error = VOP_GETATTR(nd.ni_vp, vap, cred,
211168653Smckusick procp);
211268653Smckusick vput(nd.ni_vp);
211368653Smckusick }
211468653Smckusick } else
211568653Smckusick vrele(nd.ni_startdir);
211668653Smckusick FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
211768653Smckusick }
211838418Smckusick out:
211941899Smckusick if (pathcp)
212041899Smckusick FREE(pathcp, M_TEMP);
212168653Smckusick if (dirp) {
212268653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
212368653Smckusick vrele(dirp);
212468653Smckusick }
212568653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
212668653Smckusick if (v3) {
212768653Smckusick if (!error) {
212868653Smckusick nfsm_srvpostop_fh(fhp);
212968653Smckusick nfsm_srvpostop_attr(0, vap);
213068653Smckusick }
213168653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
213268653Smckusick }
213368653Smckusick return (0);
213438418Smckusick nfsmout:
213568653Smckusick if (nd.ni_cnd.cn_nameiop) {
213668653Smckusick vrele(nd.ni_startdir);
213768653Smckusick free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
213868653Smckusick }
213968653Smckusick if (dirp)
214068653Smckusick vrele(dirp);
214152234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
214249742Smckusick if (nd.ni_dvp == nd.ni_vp)
214349742Smckusick vrele(nd.ni_dvp);
214443359Smckusick else
214549742Smckusick vput(nd.ni_dvp);
214649742Smckusick if (nd.ni_vp)
214749742Smckusick vrele(nd.ni_vp);
214841899Smckusick if (pathcp)
214941899Smckusick FREE(pathcp, M_TEMP);
215038418Smckusick return (error);
215138418Smckusick }
215238418Smckusick
215338418Smckusick /*
215438418Smckusick * nfs mkdir service
215538418Smckusick */
215668653Smckusick int
nfsrv_mkdir(nfsd,slp,procp,mrq)215768653Smckusick nfsrv_mkdir(nfsd, slp, procp, mrq)
215868653Smckusick struct nfsrv_descript *nfsd;
215968653Smckusick struct nfssvc_sock *slp;
216068653Smckusick struct proc *procp;
216168653Smckusick struct mbuf **mrq;
216238418Smckusick {
216368653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
216468653Smckusick struct mbuf *nam = nfsd->nd_nam;
216568653Smckusick caddr_t dpos = nfsd->nd_dpos;
216668653Smckusick struct ucred *cred = &nfsd->nd_cr;
216768653Smckusick struct vattr va, dirfor, diraft;
216838418Smckusick register struct vattr *vap = &va;
216968653Smckusick register struct nfs_fattr *fp;
217049742Smckusick struct nameidata nd;
217139494Smckusick register caddr_t cp;
217248050Smckusick register u_long *tl;
217339494Smckusick register long t1;
217439494Smckusick caddr_t bpos;
217568653Smckusick int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
217668653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
217739494Smckusick char *cp2;
217839753Smckusick struct mbuf *mb, *mb2, *mreq;
217968653Smckusick struct vnode *vp, *dirp = (struct vnode *)0;
218068653Smckusick nfsfh_t nfh;
218138418Smckusick fhandle_t *fhp;
218252196Smckusick u_quad_t frev;
218338418Smckusick
218438418Smckusick fhp = &nfh.fh_generic;
218538418Smckusick nfsm_srvmtofh(fhp);
218668653Smckusick nfsm_srvnamesiz(len);
218752316Sheideman nd.ni_cnd.cn_cred = cred;
218852316Sheideman nd.ni_cnd.cn_nameiop = CREATE;
218952316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT;
219068653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
219168653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
219268653Smckusick if (dirp) {
219368653Smckusick if (v3)
219468653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
219568653Smckusick procp);
219668653Smckusick else {
219768653Smckusick vrele(dirp);
219868653Smckusick dirp = (struct vnode *)0;
219968653Smckusick }
220068653Smckusick }
220168653Smckusick if (error) {
220268653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
220368653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
220468653Smckusick if (dirp)
220568653Smckusick vrele(dirp);
220668653Smckusick return (0);
220768653Smckusick }
220841361Smckusick VATTR_NULL(vap);
220968653Smckusick if (v3) {
221068653Smckusick nfsm_srvsattr(vap);
221168653Smckusick } else {
221268653Smckusick nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
221368653Smckusick vap->va_mode = nfstov_mode(*tl++);
221468653Smckusick }
221538418Smckusick vap->va_type = VDIR;
221649742Smckusick vp = nd.ni_vp;
221738418Smckusick if (vp != NULL) {
221852234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
221949742Smckusick if (nd.ni_dvp == vp)
222049742Smckusick vrele(nd.ni_dvp);
222143359Smckusick else
222249742Smckusick vput(nd.ni_dvp);
222342467Smckusick vrele(vp);
222438418Smckusick error = EEXIST;
222568653Smckusick goto out;
222638418Smckusick }
222768653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
222868653Smckusick error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
222968653Smckusick if (!error) {
223068653Smckusick vp = nd.ni_vp;
223168653Smckusick bzero((caddr_t)fhp, sizeof(nfh));
223268653Smckusick fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
223368653Smckusick error = VFS_VPTOFH(vp, &fhp->fh_fid);
223468653Smckusick if (!error)
223568653Smckusick error = VOP_GETATTR(vp, vap, cred, procp);
223638418Smckusick vput(vp);
223738418Smckusick }
223868653Smckusick out:
223968653Smckusick if (dirp) {
224068653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
224168653Smckusick vrele(dirp);
224268653Smckusick }
224368653Smckusick nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
224468653Smckusick if (v3) {
224568653Smckusick if (!error) {
224668653Smckusick nfsm_srvpostop_fh(fhp);
224768653Smckusick nfsm_srvpostop_attr(0, vap);
224868653Smckusick }
224968653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
225068653Smckusick } else {
225168653Smckusick nfsm_srvfhtom(fhp, v3);
225268653Smckusick nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
225368653Smckusick nfsm_srvfillattr(vap, fp);
225468653Smckusick }
225568653Smckusick return (0);
225638418Smckusick nfsmout:
225768653Smckusick if (dirp)
225868653Smckusick vrele(dirp);
225952234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
226049742Smckusick if (nd.ni_dvp == nd.ni_vp)
226149742Smckusick vrele(nd.ni_dvp);
226243359Smckusick else
226349742Smckusick vput(nd.ni_dvp);
226449742Smckusick if (nd.ni_vp)
226549742Smckusick vrele(nd.ni_vp);
226638418Smckusick return (error);
226738418Smckusick }
226838418Smckusick
226938418Smckusick /*
227038418Smckusick * nfs rmdir service
227138418Smckusick */
227268653Smckusick int
nfsrv_rmdir(nfsd,slp,procp,mrq)227368653Smckusick nfsrv_rmdir(nfsd, slp, procp, mrq)
227468653Smckusick struct nfsrv_descript *nfsd;
227568653Smckusick struct nfssvc_sock *slp;
227668653Smckusick struct proc *procp;
227768653Smckusick struct mbuf **mrq;
227838418Smckusick {
227968653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
228068653Smckusick struct mbuf *nam = nfsd->nd_nam;
228168653Smckusick caddr_t dpos = nfsd->nd_dpos;
228268653Smckusick struct ucred *cred = &nfsd->nd_cr;
228348050Smckusick register u_long *tl;
228439494Smckusick register long t1;
228539494Smckusick caddr_t bpos;
228668653Smckusick int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
228768653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
228839494Smckusick char *cp2;
228968653Smckusick struct mbuf *mb, *mreq, *mb2;
229068653Smckusick struct vnode *vp, *dirp = (struct vnode *)0;
229168653Smckusick struct vattr dirfor, diraft;
229268653Smckusick nfsfh_t nfh;
229338418Smckusick fhandle_t *fhp;
229449742Smckusick struct nameidata nd;
229552196Smckusick u_quad_t frev;
229638418Smckusick
229738418Smckusick fhp = &nfh.fh_generic;
229838418Smckusick nfsm_srvmtofh(fhp);
229968653Smckusick nfsm_srvnamesiz(len);
230052316Sheideman nd.ni_cnd.cn_cred = cred;
230152316Sheideman nd.ni_cnd.cn_nameiop = DELETE;
230252316Sheideman nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
230368653Smckusick error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
230468653Smckusick &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
230568653Smckusick if (dirp) {
230668653Smckusick if (v3)
230768653Smckusick dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
230868653Smckusick procp);
230968653Smckusick else {
231068653Smckusick vrele(dirp);
231168653Smckusick dirp = (struct vnode *)0;
231268653Smckusick }
231368653Smckusick }
231468653Smckusick if (error) {
231568653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
231668653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
231768653Smckusick if (dirp)
231868653Smckusick vrele(dirp);
231968653Smckusick return (0);
232068653Smckusick }
232149742Smckusick vp = nd.ni_vp;
232238418Smckusick if (vp->v_type != VDIR) {
232338418Smckusick error = ENOTDIR;
232438418Smckusick goto out;
232538418Smckusick }
232638418Smckusick /*
232738418Smckusick * No rmdir "." please.
232838418Smckusick */
232949742Smckusick if (nd.ni_dvp == vp) {
233038418Smckusick error = EINVAL;
233138418Smckusick goto out;
233238418Smckusick }
233338418Smckusick /*
233449454Smckusick * The root of a mounted filesystem cannot be deleted.
233538418Smckusick */
233638418Smckusick if (vp->v_flag & VROOT)
233738418Smckusick error = EBUSY;
233838418Smckusick out:
233942467Smckusick if (!error) {
234068653Smckusick nqsrv_getl(nd.ni_dvp, ND_WRITE);
234168653Smckusick nqsrv_getl(vp, ND_WRITE);
234252234Sheideman error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
234342467Smckusick } else {
234452234Sheideman VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
234549742Smckusick if (nd.ni_dvp == nd.ni_vp)
234649742Smckusick vrele(nd.ni_dvp);
234743359Smckusick else
234849742Smckusick vput(nd.ni_dvp);
234942467Smckusick vput(vp);
235042467Smckusick }
235168653Smckusick if (dirp) {
235268653Smckusick diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
235368653Smckusick vrele(dirp);
235468653Smckusick }
235568653Smckusick nfsm_reply(NFSX_WCCDATA(v3));
235668653Smckusick if (v3) {
235768653Smckusick nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
235868653Smckusick return (0);
235968653Smckusick }
236038418Smckusick nfsm_srvdone;
236138418Smckusick }
236238418Smckusick
236338418Smckusick /*
236438418Smckusick * nfs readdir service
236538418Smckusick * - mallocs what it thinks is enough to read
236648050Smckusick * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
236738418Smckusick * - calls VOP_READDIR()
236840115Smckusick * - loops around building the reply
236938425Smckusick * if the output generated exceeds count break out of loop
237038425Smckusick * The nfsm_clget macro is used here so that the reply will be packed
237138425Smckusick * tightly in mbuf clusters.
237238418Smckusick * - it only knows that it has encountered eof when the VOP_READDIR()
237338425Smckusick * reads nothing
237438418Smckusick * - as such one readdir rpc will return eof false although you are there
237538425Smckusick * and then the next will return eof
237652441Smckusick * - it trims out records with d_fileno == 0
237738425Smckusick * this doesn't matter for Unix clients, but they might confuse clients
237838425Smckusick * for other os'.
237938418Smckusick * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
238038425Smckusick * than requested, but this may not apply to all filesystems. For
238138425Smckusick * example, client NFS does not { although it is never remote mounted
238238425Smckusick * anyhow }
238368653Smckusick * The alternate call nfsrv_readdirplus() does lookups as well.
238438418Smckusick * PS: The NFS protocol spec. does not clarify what the "count" byte
238538425Smckusick * argument is a count of.. just name strings and file id's or the
238638425Smckusick * entire reply rpc or ...
238738425Smckusick * I tried just file name and id sizes and it confused the Sun client,
238838425Smckusick * so I am using the full rpc size now. The "paranoia.." comment refers
238938425Smckusick * to including the status longwords that are not a part of the dir.
239038425Smckusick * "entry" structures, but are in the rpc.
239138418Smckusick */
239252196Smckusick struct flrep {
239368653Smckusick nfsuint64 fl_off;
239468653Smckusick u_long fl_postopok;
239568653Smckusick u_long fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
239668653Smckusick u_long fl_fhok;
239768653Smckusick u_long fl_fhsize;
239868653Smckusick u_long fl_nfh[NFSX_V3FH / sizeof (u_long)];
239952196Smckusick };
240052196Smckusick
240168653Smckusick int
nfsrv_readdir(nfsd,slp,procp,mrq)240268653Smckusick nfsrv_readdir(nfsd, slp, procp, mrq)
240368653Smckusick struct nfsrv_descript *nfsd;
240468653Smckusick struct nfssvc_sock *slp;
240568653Smckusick struct proc *procp;
240668653Smckusick struct mbuf **mrq;
240738418Smckusick {
240868653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
240968653Smckusick struct mbuf *nam = nfsd->nd_nam;
241068653Smckusick caddr_t dpos = nfsd->nd_dpos;
241168653Smckusick struct ucred *cred = &nfsd->nd_cr;
241238418Smckusick register char *bp, *be;
241338418Smckusick register struct mbuf *mp;
241452441Smckusick register struct dirent *dp;
241539494Smckusick register caddr_t cp;
241648050Smckusick register u_long *tl;
241739494Smckusick register long t1;
241839494Smckusick caddr_t bpos;
241952196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2;
242052196Smckusick char *cpos, *cend, *cp2, *rbuf;
242138418Smckusick struct vnode *vp;
242268653Smckusick struct vattr at;
242368653Smckusick nfsfh_t nfh;
242438418Smckusick fhandle_t *fhp;
242538418Smckusick struct uio io;
242638418Smckusick struct iovec iv;
242768653Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
242868653Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
242968653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
243068653Smckusick u_quad_t frev, off, toff, verf;
243168653Smckusick u_long *cookies = NULL, *cookiep;
243238418Smckusick
243338418Smckusick fhp = &nfh.fh_generic;
243438418Smckusick nfsm_srvmtofh(fhp);
243568653Smckusick if (v3) {
243668653Smckusick nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
243768653Smckusick fxdr_hyper(tl, &toff);
243868653Smckusick tl += 2;
243968653Smckusick fxdr_hyper(tl, &verf);
244068653Smckusick tl += 2;
244168653Smckusick } else {
244268653Smckusick nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
244368653Smckusick toff = fxdr_unsigned(u_quad_t, *tl++);
244468653Smckusick }
244568653Smckusick off = toff;
244648050Smckusick cnt = fxdr_unsigned(int, *tl);
244768653Smckusick siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
244868653Smckusick xfer = NFS_SRVMAXDATA(nfsd);
244968653Smckusick if (siz > xfer)
245068653Smckusick siz = xfer;
245138418Smckusick fullsiz = siz;
245268653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
245368653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
245468653Smckusick nfsm_reply(NFSX_UNSIGNED);
245568653Smckusick nfsm_srvpostop_attr(getret, &at);
245668653Smckusick return (0);
245768653Smckusick }
245868653Smckusick nqsrv_getl(vp, ND_READ);
245968653Smckusick if (v3) {
246068653Smckusick error = getret = VOP_GETATTR(vp, &at, cred, procp);
246168653Smckusick if (!error && toff && verf != at.va_filerev)
246268653Smckusick error = NFSERR_BAD_COOKIE;
246368653Smckusick }
246468653Smckusick if (!error)
246568653Smckusick error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
246668653Smckusick if (error) {
246738418Smckusick vput(vp);
246868653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3));
246968653Smckusick nfsm_srvpostop_attr(getret, &at);
247068653Smckusick return (0);
247138418Smckusick }
2472*69424Smckusick VOP_UNLOCK(vp, 0, procp);
247338418Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
247438418Smckusick again:
247538418Smckusick iv.iov_base = rbuf;
247638418Smckusick iv.iov_len = fullsiz;
247738418Smckusick io.uio_iov = &iv;
247838418Smckusick io.uio_iovcnt = 1;
247956285Smckusick io.uio_offset = (off_t)off;
248038418Smckusick io.uio_resid = fullsiz;
248138418Smckusick io.uio_segflg = UIO_SYSSPACE;
248238418Smckusick io.uio_rw = UIO_READ;
248348050Smckusick io.uio_procp = (struct proc *)0;
248468653Smckusick eofflag = 0;
248568653Smckusick if (cookies) {
248668653Smckusick free((caddr_t)cookies, M_TEMP);
248768653Smckusick cookies = NULL;
248868653Smckusick }
248968653Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
249056285Smckusick off = (off_t)io.uio_offset;
249168653Smckusick if (!cookies && !error)
249268653Smckusick error = NFSERR_PERM;
249368653Smckusick if (v3) {
249468653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp);
249568653Smckusick if (!error)
249668653Smckusick error = getret;
249768653Smckusick }
249838418Smckusick if (error) {
249938418Smckusick vrele(vp);
250038418Smckusick free((caddr_t)rbuf, M_TEMP);
250168653Smckusick if (cookies)
250268653Smckusick free((caddr_t)cookies, M_TEMP);
250368653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3));
250468653Smckusick nfsm_srvpostop_attr(getret, &at);
250568653Smckusick return (0);
250638418Smckusick }
250738418Smckusick if (io.uio_resid) {
250838418Smckusick siz -= io.uio_resid;
250938418Smckusick
251038418Smckusick /*
251138418Smckusick * If nothing read, return eof
251238418Smckusick * rpc reply
251338418Smckusick */
251438418Smckusick if (siz == 0) {
251538418Smckusick vrele(vp);
251668653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
251768653Smckusick 2 * NFSX_UNSIGNED);
251868653Smckusick if (v3) {
251968653Smckusick nfsm_srvpostop_attr(getret, &at);
252068653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
252168653Smckusick txdr_hyper(&at.va_filerev, tl);
252268653Smckusick tl += 2;
252368653Smckusick } else
252468653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
252548050Smckusick *tl++ = nfs_false;
252648050Smckusick *tl = nfs_true;
252738418Smckusick FREE((caddr_t)rbuf, M_TEMP);
252868653Smckusick FREE((caddr_t)cookies, M_TEMP);
252938418Smckusick return (0);
253038418Smckusick }
253138418Smckusick }
253240115Smckusick
253338418Smckusick /*
253438418Smckusick * Check for degenerate cases of nothing useful read.
253540115Smckusick * If so go try again
253638418Smckusick */
253767363Smckusick cpos = rbuf;
253840115Smckusick cend = rbuf + siz;
253968653Smckusick dp = (struct dirent *)cpos;
254068653Smckusick cookiep = cookies;
254168653Smckusick while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
254268653Smckusick cpos += dp->d_reclen;
254352441Smckusick dp = (struct dirent *)cpos;
254468653Smckusick cookiep++;
254568653Smckusick ncookies--;
254640115Smckusick }
254768653Smckusick if (cpos >= cend || ncookies == 0) {
254868653Smckusick toff = off;
254938418Smckusick siz = fullsiz;
255038418Smckusick goto again;
255138418Smckusick }
255240115Smckusick
255368653Smckusick len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
255468653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
255568653Smckusick if (v3) {
255668653Smckusick nfsm_srvpostop_attr(getret, &at);
255768653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
255868653Smckusick txdr_hyper(&at.va_filerev, tl);
255968653Smckusick }
256052196Smckusick mp = mp2 = mb;
256152196Smckusick bp = bpos;
256252196Smckusick be = bp + M_TRAILINGSPACE(mp);
256352196Smckusick
256452196Smckusick /* Loop through the records and build reply */
256568653Smckusick while (cpos < cend && ncookies > 0) {
256652441Smckusick if (dp->d_fileno != 0) {
256752196Smckusick nlen = dp->d_namlen;
256852196Smckusick rem = nfsm_rndup(nlen)-nlen;
256968653Smckusick len += (4 * NFSX_UNSIGNED + nlen + rem);
257068653Smckusick if (v3)
257168653Smckusick len += 2 * NFSX_UNSIGNED;
257252196Smckusick if (len > cnt) {
257352196Smckusick eofflag = 0;
257452196Smckusick break;
257552196Smckusick }
257652441Smckusick /*
257752441Smckusick * Build the directory record xdr from
257852441Smckusick * the dirent entry.
257952441Smckusick */
258052196Smckusick nfsm_clget;
258152196Smckusick *tl = nfs_true;
258252196Smckusick bp += NFSX_UNSIGNED;
258368653Smckusick if (v3) {
258468653Smckusick nfsm_clget;
258568653Smckusick *tl = 0;
258668653Smckusick bp += NFSX_UNSIGNED;
258768653Smckusick }
258852196Smckusick nfsm_clget;
258952441Smckusick *tl = txdr_unsigned(dp->d_fileno);
259052196Smckusick bp += NFSX_UNSIGNED;
259152196Smckusick nfsm_clget;
259252196Smckusick *tl = txdr_unsigned(nlen);
259352196Smckusick bp += NFSX_UNSIGNED;
259452196Smckusick
259552196Smckusick /* And loop around copying the name */
259652196Smckusick xfer = nlen;
259752196Smckusick cp = dp->d_name;
259852196Smckusick while (xfer > 0) {
259952196Smckusick nfsm_clget;
260052196Smckusick if ((bp+xfer) > be)
260152196Smckusick tsiz = be-bp;
260252196Smckusick else
260352196Smckusick tsiz = xfer;
260452196Smckusick bcopy(cp, bp, tsiz);
260552196Smckusick bp += tsiz;
260652196Smckusick xfer -= tsiz;
260752196Smckusick if (xfer > 0)
260852196Smckusick cp += tsiz;
260952196Smckusick }
261052196Smckusick /* And null pad to a long boundary */
261152196Smckusick for (i = 0; i < rem; i++)
261252196Smckusick *bp++ = '\0';
261352196Smckusick nfsm_clget;
261452196Smckusick
261552196Smckusick /* Finish off the record */
261668653Smckusick if (v3) {
261768653Smckusick *tl = 0;
261868653Smckusick bp += NFSX_UNSIGNED;
261968653Smckusick nfsm_clget;
262068653Smckusick }
262168653Smckusick *tl = txdr_unsigned(*cookiep);
262252196Smckusick bp += NFSX_UNSIGNED;
262367363Smckusick }
262452196Smckusick cpos += dp->d_reclen;
262552441Smckusick dp = (struct dirent *)cpos;
262668653Smckusick cookiep++;
262768653Smckusick ncookies--;
262852196Smckusick }
262938418Smckusick vrele(vp);
263052196Smckusick nfsm_clget;
263152196Smckusick *tl = nfs_false;
263252196Smckusick bp += NFSX_UNSIGNED;
263352196Smckusick nfsm_clget;
263452196Smckusick if (eofflag)
263552196Smckusick *tl = nfs_true;
263652196Smckusick else
263752196Smckusick *tl = nfs_false;
263852196Smckusick bp += NFSX_UNSIGNED;
263952196Smckusick if (mp != mb) {
264052196Smckusick if (bp < be)
264152196Smckusick mp->m_len = bp - mtod(mp, caddr_t);
264252196Smckusick } else
264352196Smckusick mp->m_len += bp - bpos;
264468653Smckusick FREE((caddr_t)rbuf, M_TEMP);
264568653Smckusick FREE((caddr_t)cookies, M_TEMP);
264652196Smckusick nfsm_srvdone;
264752196Smckusick }
264852196Smckusick
264968653Smckusick int
nfsrv_readdirplus(nfsd,slp,procp,mrq)265068653Smckusick nfsrv_readdirplus(nfsd, slp, procp, mrq)
265168653Smckusick struct nfsrv_descript *nfsd;
265268653Smckusick struct nfssvc_sock *slp;
265368653Smckusick struct proc *procp;
265468653Smckusick struct mbuf **mrq;
265552196Smckusick {
265668653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
265768653Smckusick struct mbuf *nam = nfsd->nd_nam;
265868653Smckusick caddr_t dpos = nfsd->nd_dpos;
265968653Smckusick struct ucred *cred = &nfsd->nd_cr;
266052196Smckusick register char *bp, *be;
266152196Smckusick register struct mbuf *mp;
266252441Smckusick register struct dirent *dp;
266352196Smckusick register caddr_t cp;
266452196Smckusick register u_long *tl;
266552196Smckusick register long t1;
266652196Smckusick caddr_t bpos;
266752196Smckusick struct mbuf *mb, *mb2, *mreq, *mp2;
266852196Smckusick char *cpos, *cend, *cp2, *rbuf;
266952196Smckusick struct vnode *vp, *nvp;
267052196Smckusick struct flrep fl;
267168653Smckusick nfsfh_t nfh;
267268653Smckusick fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
267352196Smckusick struct uio io;
267452196Smckusick struct iovec iv;
267568653Smckusick struct vattr va, at, *vap = &va;
267668653Smckusick struct nfs_fattr *fp;
267768653Smckusick int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
267868653Smckusick int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
267968653Smckusick u_quad_t frev, off, toff, verf;
268068653Smckusick u_long *cookies = NULL, *cookiep;
268152196Smckusick
268252196Smckusick fhp = &nfh.fh_generic;
268352196Smckusick nfsm_srvmtofh(fhp);
268468653Smckusick nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
268568653Smckusick fxdr_hyper(tl, &toff);
268668653Smckusick tl += 2;
268768653Smckusick fxdr_hyper(tl, &verf);
268868653Smckusick tl += 2;
268968653Smckusick siz = fxdr_unsigned(int, *tl++);
269068653Smckusick cnt = fxdr_unsigned(int, *tl);
269168653Smckusick off = toff;
269268653Smckusick siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
269368653Smckusick xfer = NFS_SRVMAXDATA(nfsd);
269468653Smckusick if (siz > xfer)
269568653Smckusick siz = xfer;
269652196Smckusick fullsiz = siz;
269768653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
269868653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
269968653Smckusick nfsm_reply(NFSX_UNSIGNED);
270068653Smckusick nfsm_srvpostop_attr(getret, &at);
270168653Smckusick return (0);
270268653Smckusick }
270368653Smckusick error = getret = VOP_GETATTR(vp, &at, cred, procp);
270468653Smckusick if (!error && toff && verf != at.va_filerev)
270568653Smckusick error = NFSERR_BAD_COOKIE;
270668653Smckusick if (!error) {
270768653Smckusick nqsrv_getl(vp, ND_READ);
270868653Smckusick error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
270968653Smckusick }
271068653Smckusick if (error) {
271152196Smckusick vput(vp);
271268653Smckusick nfsm_reply(NFSX_V3POSTOPATTR);
271368653Smckusick nfsm_srvpostop_attr(getret, &at);
271468653Smckusick return (0);
271552196Smckusick }
2716*69424Smckusick VOP_UNLOCK(vp, 0, procp);
271752196Smckusick MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
271852196Smckusick again:
271952196Smckusick iv.iov_base = rbuf;
272052196Smckusick iv.iov_len = fullsiz;
272152196Smckusick io.uio_iov = &iv;
272252196Smckusick io.uio_iovcnt = 1;
272356285Smckusick io.uio_offset = (off_t)off;
272452196Smckusick io.uio_resid = fullsiz;
272552196Smckusick io.uio_segflg = UIO_SYSSPACE;
272652196Smckusick io.uio_rw = UIO_READ;
272752196Smckusick io.uio_procp = (struct proc *)0;
272868653Smckusick eofflag = 0;
272968653Smckusick if (cookies) {
273068653Smckusick free((caddr_t)cookies, M_TEMP);
273168653Smckusick cookies = NULL;
273268653Smckusick }
273368653Smckusick error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
273468653Smckusick off = (u_quad_t)io.uio_offset;
273568653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp);
273668653Smckusick if (!cookies && !error)
273768653Smckusick error = NFSERR_PERM;
273868653Smckusick if (!error)
273968653Smckusick error = getret;
274052196Smckusick if (error) {
274152196Smckusick vrele(vp);
274268653Smckusick if (cookies)
274368653Smckusick free((caddr_t)cookies, M_TEMP);
274452196Smckusick free((caddr_t)rbuf, M_TEMP);
274568653Smckusick nfsm_reply(NFSX_V3POSTOPATTR);
274668653Smckusick nfsm_srvpostop_attr(getret, &at);
274768653Smckusick return (0);
274852196Smckusick }
274952196Smckusick if (io.uio_resid) {
275052196Smckusick siz -= io.uio_resid;
275152196Smckusick
275252196Smckusick /*
275352196Smckusick * If nothing read, return eof
275452196Smckusick * rpc reply
275552196Smckusick */
275652196Smckusick if (siz == 0) {
275752196Smckusick vrele(vp);
275868653Smckusick nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
275968653Smckusick 2 * NFSX_UNSIGNED);
276068653Smckusick nfsm_srvpostop_attr(getret, &at);
276168653Smckusick nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
276268653Smckusick txdr_hyper(&at.va_filerev, tl);
276368653Smckusick tl += 2;
276452196Smckusick *tl++ = nfs_false;
276552196Smckusick *tl = nfs_true;
276668653Smckusick FREE((caddr_t)cookies, M_TEMP);
276752196Smckusick FREE((caddr_t)rbuf, M_TEMP);
276852196Smckusick return (0);
276952196Smckusick }
277052196Smckusick }
277152196Smckusick
277252196Smckusick /*
277352196Smckusick * Check for degenerate cases of nothing useful read.
277452196Smckusick * If so go try again
277552196Smckusick */
277667363Smckusick cpos = rbuf;
277752196Smckusick cend = rbuf + siz;
277868653Smckusick dp = (struct dirent *)cpos;
277968653Smckusick cookiep = cookies;
278068653Smckusick while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
278168653Smckusick cpos += dp->d_reclen;
278252441Smckusick dp = (struct dirent *)cpos;
278368653Smckusick cookiep++;
278468653Smckusick ncookies--;
278552196Smckusick }
278668653Smckusick if (cpos >= cend || ncookies == 0) {
278768653Smckusick toff = off;
278852196Smckusick siz = fullsiz;
278952196Smckusick goto again;
279052196Smckusick }
279152196Smckusick
279268653Smckusick dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
279368653Smckusick nfsm_reply(cnt);
279468653Smckusick nfsm_srvpostop_attr(getret, &at);
279568653Smckusick nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
279668653Smckusick txdr_hyper(&at.va_filerev, tl);
279752196Smckusick mp = mp2 = mb;
279852196Smckusick bp = bpos;
279952196Smckusick be = bp + M_TRAILINGSPACE(mp);
280038418Smckusick
280138418Smckusick /* Loop through the records and build reply */
280268653Smckusick while (cpos < cend && ncookies > 0) {
280352441Smckusick if (dp->d_fileno != 0) {
280438418Smckusick nlen = dp->d_namlen;
280538418Smckusick rem = nfsm_rndup(nlen)-nlen;
280638425Smckusick
280738418Smckusick /*
280852196Smckusick * For readdir_and_lookup get the vnode using
280952196Smckusick * the file number.
281038418Smckusick */
281154665Smckusick if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
281252196Smckusick goto invalid;
281368653Smckusick bzero((caddr_t)nfhp, NFSX_V3FH);
281468653Smckusick nfhp->fh_fsid =
281555655Smckusick nvp->v_mount->mnt_stat.f_fsid;
281668653Smckusick if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
281755655Smckusick vput(nvp);
281855655Smckusick goto invalid;
281955655Smckusick }
282068653Smckusick if (VOP_GETATTR(nvp, vap, cred, procp)) {
282152196Smckusick vput(nvp);
282252196Smckusick goto invalid;
282352196Smckusick }
282452196Smckusick vput(nvp);
282568653Smckusick
282668653Smckusick /*
282768653Smckusick * If either the dircount or maxcount will be
282868653Smckusick * exceeded, get out now. Both of these lengths
282968653Smckusick * are calculated conservatively, including all
283068653Smckusick * XDR overheads.
283168653Smckusick */
283268653Smckusick len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
283368653Smckusick NFSX_V3POSTOPATTR);
283468653Smckusick dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
283568653Smckusick if (len > cnt || dirlen > fullsiz) {
283641899Smckusick eofflag = 0;
283738418Smckusick break;
283841899Smckusick }
283968653Smckusick
284052441Smckusick /*
284152441Smckusick * Build the directory record xdr from
284252441Smckusick * the dirent entry.
284352441Smckusick */
284468653Smckusick fp = (struct nfs_fattr *)&fl.fl_fattr;
284568653Smckusick nfsm_srvfillattr(vap, fp);
284668653Smckusick fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
284768653Smckusick fl.fl_fhok = nfs_true;
284868653Smckusick fl.fl_postopok = nfs_true;
284968653Smckusick fl.fl_off.nfsuquad[0] = 0;
285068653Smckusick fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
285168653Smckusick
285238418Smckusick nfsm_clget;
285348050Smckusick *tl = nfs_true;
285438418Smckusick bp += NFSX_UNSIGNED;
285538418Smckusick nfsm_clget;
285668653Smckusick *tl = 0;
285768653Smckusick bp += NFSX_UNSIGNED;
285868653Smckusick nfsm_clget;
285952441Smckusick *tl = txdr_unsigned(dp->d_fileno);
286038418Smckusick bp += NFSX_UNSIGNED;
286138418Smckusick nfsm_clget;
286248050Smckusick *tl = txdr_unsigned(nlen);
286338418Smckusick bp += NFSX_UNSIGNED;
286438425Smckusick
286552196Smckusick /* And loop around copying the name */
286638418Smckusick xfer = nlen;
286738418Smckusick cp = dp->d_name;
286838418Smckusick while (xfer > 0) {
286938418Smckusick nfsm_clget;
287068653Smckusick if ((bp + xfer) > be)
287168653Smckusick tsiz = be - bp;
287238418Smckusick else
287338418Smckusick tsiz = xfer;
287438418Smckusick bcopy(cp, bp, tsiz);
287538418Smckusick bp += tsiz;
287638418Smckusick xfer -= tsiz;
287738418Smckusick if (xfer > 0)
287838418Smckusick cp += tsiz;
287938418Smckusick }
288038418Smckusick /* And null pad to a long boundary */
288138418Smckusick for (i = 0; i < rem; i++)
288238418Smckusick *bp++ = '\0';
288338425Smckusick
288468653Smckusick /*
288568653Smckusick * Now copy the flrep structure out.
288668653Smckusick */
288768653Smckusick xfer = sizeof (struct flrep);
288868653Smckusick cp = (caddr_t)&fl;
288968653Smckusick while (xfer > 0) {
289068653Smckusick nfsm_clget;
289168653Smckusick if ((bp + xfer) > be)
289268653Smckusick tsiz = be - bp;
289368653Smckusick else
289468653Smckusick tsiz = xfer;
289568653Smckusick bcopy(cp, bp, tsiz);
289668653Smckusick bp += tsiz;
289768653Smckusick xfer -= tsiz;
289868653Smckusick if (xfer > 0)
289968653Smckusick cp += tsiz;
290068653Smckusick }
290167363Smckusick }
290252196Smckusick invalid:
290338418Smckusick cpos += dp->d_reclen;
290452441Smckusick dp = (struct dirent *)cpos;
290568653Smckusick cookiep++;
290668653Smckusick ncookies--;
290738418Smckusick }
290852196Smckusick vrele(vp);
290938418Smckusick nfsm_clget;
291048050Smckusick *tl = nfs_false;
291138418Smckusick bp += NFSX_UNSIGNED;
291238418Smckusick nfsm_clget;
291340296Smckusick if (eofflag)
291448050Smckusick *tl = nfs_true;
291540296Smckusick else
291648050Smckusick *tl = nfs_false;
291738418Smckusick bp += NFSX_UNSIGNED;
291852196Smckusick if (mp != mb) {
291952196Smckusick if (bp < be)
292052196Smckusick mp->m_len = bp - mtod(mp, caddr_t);
292152196Smckusick } else
292252196Smckusick mp->m_len += bp - bpos;
292368653Smckusick FREE((caddr_t)cookies, M_TEMP);
292468653Smckusick FREE((caddr_t)rbuf, M_TEMP);
292538418Smckusick nfsm_srvdone;
292638418Smckusick }
292738418Smckusick
292838418Smckusick /*
292968653Smckusick * nfs commit service
293068653Smckusick */
293168653Smckusick int
nfsrv_commit(nfsd,slp,procp,mrq)293268653Smckusick nfsrv_commit(nfsd, slp, procp, mrq)
293368653Smckusick struct nfsrv_descript *nfsd;
293468653Smckusick struct nfssvc_sock *slp;
293568653Smckusick struct proc *procp;
293668653Smckusick struct mbuf **mrq;
293768653Smckusick {
293868653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
293968653Smckusick struct mbuf *nam = nfsd->nd_nam;
294068653Smckusick caddr_t dpos = nfsd->nd_dpos;
294168653Smckusick struct ucred *cred = &nfsd->nd_cr;
294268653Smckusick struct vattr bfor, aft;
294368653Smckusick struct vnode *vp;
294468653Smckusick nfsfh_t nfh;
294568653Smckusick fhandle_t *fhp;
294668653Smckusick register u_long *tl;
294768653Smckusick register long t1;
294868653Smckusick caddr_t bpos;
294968653Smckusick int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
295068653Smckusick char *cp2;
295168653Smckusick struct mbuf *mb, *mb2, *mreq;
295268653Smckusick u_quad_t frev, off;
295368653Smckusick
295468653Smckusick #ifndef nolint
295568653Smckusick cache = 0;
295668653Smckusick #endif
295768653Smckusick fhp = &nfh.fh_generic;
295868653Smckusick nfsm_srvmtofh(fhp);
295968653Smckusick nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
296068653Smckusick
296168653Smckusick /*
296268653Smckusick * XXX At this time VOP_FSYNC() does not accept offset and byte
296368653Smckusick * count parameters, so these arguments are useless (someday maybe).
296468653Smckusick */
296568653Smckusick fxdr_hyper(tl, &off);
296668653Smckusick tl += 2;
296768653Smckusick cnt = fxdr_unsigned(int, *tl);
296868653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
296968653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
297068653Smckusick nfsm_reply(2 * NFSX_UNSIGNED);
297168653Smckusick nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
297268653Smckusick return (0);
297368653Smckusick }
297468653Smckusick for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
297568653Smckusick error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
297668653Smckusick aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
297768653Smckusick vput(vp);
297868653Smckusick nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
297968653Smckusick nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
298068653Smckusick if (!error) {
298168653Smckusick nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
298268653Smckusick *tl++ = txdr_unsigned(boottime.tv_sec);
298368653Smckusick *tl = txdr_unsigned(boottime.tv_usec);
298468653Smckusick } else
298568653Smckusick return (0);
298668653Smckusick nfsm_srvdone;
298768653Smckusick }
298868653Smckusick
298968653Smckusick /*
299038418Smckusick * nfs statfs service
299138418Smckusick */
299268653Smckusick int
nfsrv_statfs(nfsd,slp,procp,mrq)299368653Smckusick nfsrv_statfs(nfsd, slp, procp, mrq)
299468653Smckusick struct nfsrv_descript *nfsd;
299568653Smckusick struct nfssvc_sock *slp;
299668653Smckusick struct proc *procp;
299768653Smckusick struct mbuf **mrq;
299838418Smckusick {
299968653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
300068653Smckusick struct mbuf *nam = nfsd->nd_nam;
300168653Smckusick caddr_t dpos = nfsd->nd_dpos;
300268653Smckusick struct ucred *cred = &nfsd->nd_cr;
300338418Smckusick register struct statfs *sf;
300468653Smckusick register struct nfs_statfs *sfp;
300548050Smckusick register u_long *tl;
300639494Smckusick register long t1;
300739494Smckusick caddr_t bpos;
300868653Smckusick int error = 0, rdonly, cache, getret = 1;
300968653Smckusick int v3 = (nfsd->nd_flag & ND_NFSV3);
301039494Smckusick char *cp2;
301139753Smckusick struct mbuf *mb, *mb2, *mreq;
301238418Smckusick struct vnode *vp;
301368653Smckusick struct vattr at;
301468653Smckusick nfsfh_t nfh;
301538418Smckusick fhandle_t *fhp;
301638418Smckusick struct statfs statfs;
301768653Smckusick u_quad_t frev, tval;
301838418Smckusick
301968653Smckusick #ifndef nolint
302068653Smckusick cache = 0;
302168653Smckusick #endif
302238418Smckusick fhp = &nfh.fh_generic;
302338418Smckusick nfsm_srvmtofh(fhp);
302468653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
302568653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
302668653Smckusick nfsm_reply(NFSX_UNSIGNED);
302768653Smckusick nfsm_srvpostop_attr(getret, &at);
302868653Smckusick return (0);
302968653Smckusick }
303038418Smckusick sf = &statfs;
303168653Smckusick error = VFS_STATFS(vp->v_mount, sf, procp);
303268653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp);
303338418Smckusick vput(vp);
303468653Smckusick nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
303568653Smckusick if (v3)
303668653Smckusick nfsm_srvpostop_attr(getret, &at);
303768653Smckusick if (error)
303868653Smckusick return (0);
303968653Smckusick nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
304068653Smckusick if (v3) {
304168653Smckusick tval = (u_quad_t)sf->f_blocks;
304268653Smckusick tval *= (u_quad_t)sf->f_bsize;
304368653Smckusick txdr_hyper(&tval, &sfp->sf_tbytes);
304468653Smckusick tval = (u_quad_t)sf->f_bfree;
304568653Smckusick tval *= (u_quad_t)sf->f_bsize;
304668653Smckusick txdr_hyper(&tval, &sfp->sf_fbytes);
304768653Smckusick tval = (u_quad_t)sf->f_bavail;
304868653Smckusick tval *= (u_quad_t)sf->f_bsize;
304968653Smckusick txdr_hyper(&tval, &sfp->sf_abytes);
305068653Smckusick sfp->sf_tfiles.nfsuquad[0] = 0;
305168653Smckusick sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
305268653Smckusick sfp->sf_ffiles.nfsuquad[0] = 0;
305368653Smckusick sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
305468653Smckusick sfp->sf_afiles.nfsuquad[0] = 0;
305568653Smckusick sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
305668653Smckusick sfp->sf_invarsec = 0;
305768653Smckusick } else {
305868653Smckusick sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
305968653Smckusick sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
306068653Smckusick sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
306168653Smckusick sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
306268653Smckusick sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
306356285Smckusick }
306438418Smckusick nfsm_srvdone;
306538418Smckusick }
306638418Smckusick
306738418Smckusick /*
306868653Smckusick * nfs fsinfo service
306968653Smckusick */
307068653Smckusick int
nfsrv_fsinfo(nfsd,slp,procp,mrq)307168653Smckusick nfsrv_fsinfo(nfsd, slp, procp, mrq)
307268653Smckusick struct nfsrv_descript *nfsd;
307368653Smckusick struct nfssvc_sock *slp;
307468653Smckusick struct proc *procp;
307568653Smckusick struct mbuf **mrq;
307668653Smckusick {
307768653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
307868653Smckusick struct mbuf *nam = nfsd->nd_nam;
307968653Smckusick caddr_t dpos = nfsd->nd_dpos;
308068653Smckusick struct ucred *cred = &nfsd->nd_cr;
308168653Smckusick register u_long *tl;
308268653Smckusick register struct nfsv3_fsinfo *sip;
308368653Smckusick register long t1;
308468653Smckusick caddr_t bpos;
308568653Smckusick int error = 0, rdonly, cache, getret = 1, pref;
308668653Smckusick char *cp2;
308768653Smckusick struct mbuf *mb, *mb2, *mreq;
308868653Smckusick struct vnode *vp;
308968653Smckusick struct vattr at;
309068653Smckusick nfsfh_t nfh;
309168653Smckusick fhandle_t *fhp;
309268653Smckusick u_quad_t frev;
309368653Smckusick
309468653Smckusick #ifndef nolint
309568653Smckusick cache = 0;
309668653Smckusick #endif
309768653Smckusick fhp = &nfh.fh_generic;
309868653Smckusick nfsm_srvmtofh(fhp);
309968653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
310068653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
310168653Smckusick nfsm_reply(NFSX_UNSIGNED);
310268653Smckusick nfsm_srvpostop_attr(getret, &at);
310368653Smckusick return (0);
310468653Smckusick }
310568653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp);
310668653Smckusick vput(vp);
310768653Smckusick nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
310868653Smckusick nfsm_srvpostop_attr(getret, &at);
310968653Smckusick nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
311068653Smckusick
311168653Smckusick /*
311268653Smckusick * XXX
311368653Smckusick * There should be file system VFS OP(s) to get this information.
311468653Smckusick * For now, assume ufs.
311568653Smckusick */
311668653Smckusick if (slp->ns_so->so_type == SOCK_DGRAM)
311768653Smckusick pref = NFS_MAXDGRAMDATA;
311868653Smckusick else
311968653Smckusick pref = NFS_MAXDATA;
312068653Smckusick sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
312168653Smckusick sip->fs_rtpref = txdr_unsigned(pref);
312268653Smckusick sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
312368653Smckusick sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
312468653Smckusick sip->fs_wtpref = txdr_unsigned(pref);
312568653Smckusick sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
312668653Smckusick sip->fs_dtpref = txdr_unsigned(pref);
312768653Smckusick sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
312868653Smckusick sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
312968653Smckusick sip->fs_timedelta.nfsv3_sec = 0;
313068653Smckusick sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
313168653Smckusick sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
313268653Smckusick NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
313368653Smckusick NFSV3FSINFO_CANSETTIME);
313468653Smckusick nfsm_srvdone;
313568653Smckusick }
313668653Smckusick
313768653Smckusick /*
313868653Smckusick * nfs pathconf service
313968653Smckusick */
314068653Smckusick int
nfsrv_pathconf(nfsd,slp,procp,mrq)314168653Smckusick nfsrv_pathconf(nfsd, slp, procp, mrq)
314268653Smckusick struct nfsrv_descript *nfsd;
314368653Smckusick struct nfssvc_sock *slp;
314468653Smckusick struct proc *procp;
314568653Smckusick struct mbuf **mrq;
314668653Smckusick {
314768653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
314868653Smckusick struct mbuf *nam = nfsd->nd_nam;
314968653Smckusick caddr_t dpos = nfsd->nd_dpos;
315068653Smckusick struct ucred *cred = &nfsd->nd_cr;
315168653Smckusick register u_long *tl;
315268653Smckusick register struct nfsv3_pathconf *pc;
315368653Smckusick register long t1;
315468653Smckusick caddr_t bpos;
315568653Smckusick int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
315668653Smckusick int chownres, notrunc;
315768653Smckusick char *cp2;
315868653Smckusick struct mbuf *mb, *mb2, *mreq;
315968653Smckusick struct vnode *vp;
316068653Smckusick struct vattr at;
316168653Smckusick nfsfh_t nfh;
316268653Smckusick fhandle_t *fhp;
316368653Smckusick u_quad_t frev;
316468653Smckusick
316568653Smckusick #ifndef nolint
316668653Smckusick cache = 0;
316768653Smckusick #endif
316868653Smckusick fhp = &nfh.fh_generic;
316968653Smckusick nfsm_srvmtofh(fhp);
317068653Smckusick if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
317168653Smckusick &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
317268653Smckusick nfsm_reply(NFSX_UNSIGNED);
317368653Smckusick nfsm_srvpostop_attr(getret, &at);
317468653Smckusick return (0);
317568653Smckusick }
317668653Smckusick error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
317768653Smckusick if (!error)
317868653Smckusick error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
317968653Smckusick if (!error)
318068653Smckusick error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
318168653Smckusick if (!error)
318268653Smckusick error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
318368653Smckusick getret = VOP_GETATTR(vp, &at, cred, procp);
318468653Smckusick vput(vp);
318568653Smckusick nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
318668653Smckusick nfsm_srvpostop_attr(getret, &at);
318768653Smckusick if (error)
318868653Smckusick return (0);
318968653Smckusick nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
319068653Smckusick
319168653Smckusick pc->pc_linkmax = txdr_unsigned(linkmax);
319268653Smckusick pc->pc_namemax = txdr_unsigned(namemax);
319368653Smckusick pc->pc_notrunc = txdr_unsigned(notrunc);
319468653Smckusick pc->pc_chownrestricted = txdr_unsigned(chownres);
319568653Smckusick
319668653Smckusick /*
319768653Smckusick * These should probably be supported by VOP_PATHCONF(), but
319868653Smckusick * until msdosfs is exportable (why would you want to?), the
319968653Smckusick * Unix defaults should be ok.
320068653Smckusick */
320168653Smckusick pc->pc_caseinsensitive = nfs_false;
320268653Smckusick pc->pc_casepreserving = nfs_true;
320368653Smckusick nfsm_srvdone;
320468653Smckusick }
320568653Smckusick
320668653Smckusick /*
320738418Smckusick * Null operation, used by clients to ping server
320838418Smckusick */
320939494Smckusick /* ARGSUSED */
321068653Smckusick int
nfsrv_null(nfsd,slp,procp,mrq)321168653Smckusick nfsrv_null(nfsd, slp, procp, mrq)
321268653Smckusick struct nfsrv_descript *nfsd;
321368653Smckusick struct nfssvc_sock *slp;
321468653Smckusick struct proc *procp;
321568653Smckusick struct mbuf **mrq;
321638418Smckusick {
321768653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
321868653Smckusick struct mbuf *nam = nfsd->nd_nam;
321968653Smckusick caddr_t dpos = nfsd->nd_dpos;
322068653Smckusick struct ucred *cred = &nfsd->nd_cr;
322139494Smckusick caddr_t bpos;
322268653Smckusick int error = NFSERR_RETVOID, cache;
322339753Smckusick struct mbuf *mb, *mreq;
322452196Smckusick u_quad_t frev;
322538418Smckusick
322668653Smckusick #ifndef nolint
322768653Smckusick cache = 0;
322868653Smckusick #endif
322938418Smckusick nfsm_reply(0);
323068653Smckusick return (0);
323138418Smckusick }
323238418Smckusick
323338418Smckusick /*
323438418Smckusick * No operation, used for obsolete procedures
323538418Smckusick */
323639494Smckusick /* ARGSUSED */
323768653Smckusick int
nfsrv_noop(nfsd,slp,procp,mrq)323868653Smckusick nfsrv_noop(nfsd, slp, procp, mrq)
323968653Smckusick struct nfsrv_descript *nfsd;
324068653Smckusick struct nfssvc_sock *slp;
324168653Smckusick struct proc *procp;
324268653Smckusick struct mbuf **mrq;
324338418Smckusick {
324468653Smckusick struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
324568653Smckusick struct mbuf *nam = nfsd->nd_nam;
324668653Smckusick caddr_t dpos = nfsd->nd_dpos;
324768653Smckusick struct ucred *cred = &nfsd->nd_cr;
324839494Smckusick caddr_t bpos;
324952196Smckusick int error, cache;
325039753Smckusick struct mbuf *mb, *mreq;
325152196Smckusick u_quad_t frev;
325238418Smckusick
325368653Smckusick #ifndef nolint
325468653Smckusick cache = 0;
325568653Smckusick #endif
325652196Smckusick if (nfsd->nd_repstat)
325752196Smckusick error = nfsd->nd_repstat;
325852196Smckusick else
325952196Smckusick error = EPROCUNAVAIL;
326038418Smckusick nfsm_reply(0);
326168653Smckusick return (0);
326238418Smckusick }
326338425Smckusick
326438450Smckusick /*
326538450Smckusick * Perform access checking for vnodes obtained from file handles that would
326638450Smckusick * refer to files already opened by a Unix client. You cannot just use
326738450Smckusick * vn_writechk() and VOP_ACCESS() for two reasons.
326852196Smckusick * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
326938450Smckusick * 2 - The owner is to be given access irrespective of mode bits so that
327038450Smckusick * processes that chmod after opening a file don't break. I don't like
327138450Smckusick * this because it opens a security hole, but since the nfs server opens
327238450Smckusick * a security hole the size of a barn door anyhow, what the heck.
327338450Smckusick */
327468653Smckusick int
nfsrv_access(vp,flags,cred,rdonly,p)327552196Smckusick nfsrv_access(vp, flags, cred, rdonly, p)
327638450Smckusick register struct vnode *vp;
327738450Smckusick int flags;
327838450Smckusick register struct ucred *cred;
327952196Smckusick int rdonly;
328048050Smckusick struct proc *p;
328138450Smckusick {
328238450Smckusick struct vattr vattr;
328338450Smckusick int error;
328438450Smckusick if (flags & VWRITE) {
328552196Smckusick /* Just vn_writechk() changed to check rdonly */
328638450Smckusick /*
328738450Smckusick * Disallow write attempts on read-only file systems;
328838450Smckusick * unless the file is a socket or a block or character
328938450Smckusick * device resident on the file system.
329038450Smckusick */
329152196Smckusick if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
329245059Smckusick switch (vp->v_type) {
329345059Smckusick case VREG: case VDIR: case VLNK:
329438450Smckusick return (EROFS);
329545059Smckusick }
329645059Smckusick }
329738450Smckusick /*
329838450Smckusick * If there's shared text associated with
329938450Smckusick * the inode, try to free it up once. If
330038450Smckusick * we fail, we can't allow writing.
330138450Smckusick */
330245715Smckusick if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
330338450Smckusick return (ETXTBSY);
330438450Smckusick }
330548050Smckusick if (error = VOP_GETATTR(vp, &vattr, cred, p))
330645059Smckusick return (error);
330748050Smckusick if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
330845059Smckusick cred->cr_uid != vattr.va_uid)
330945059Smckusick return (error);
331045059Smckusick return (0);
331138450Smckusick }
3312