Annotation of src/sys/nfs/nfs_serv.c, Revision 1.45
1.45 ! thorpej 1: /* $NetBSD: nfs_serv.c,v 1.44 1998/08/09 21:19:51 perry Exp $ */
1.16 cgd 2:
1.1 cgd 3: /*
1.15 mycroft 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software contributed to Berkeley by
8: * Rick Macklem at The University of Guelph.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: *
1.42 fvdl 38: * @(#)nfs_serv.c 8.8 (Berkeley) 7/31/95
1.1 cgd 39: */
40:
41: /*
1.23 fvdl 42: * nfs version 2 and 3 server calls to vnode ops
1.1 cgd 43: * - these routines generally have 3 phases
44: * 1 - break down and validate rpc request in mbuf list
45: * 2 - do the vnode ops for the request
46: * (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
47: * 3 - build the rpc reply in an mbuf list
48: * nb:
49: * - do not mix the phases, since the nfsm_?? macros can return failures
50: * on a bad rpc or similar and do not do any vrele() or vput()'s
51: *
52: * - the nfsm_reply() macro generates an nfs rpc reply with the nfs
53: * error number iff error != 0 whereas
54: * returning an error from the server function implies a fatal error
55: * such as a badly constructed rpc request that should be dropped without
56: * a reply.
1.23 fvdl 57: * For Version 3, nfsm_reply() does not return for the error case, since
58: * most version 3 rpcs return more than the status for error cases.
1.1 cgd 59: */
1.41 mrg 60:
61: #include "opt_uvm.h"
1.1 cgd 62:
1.10 mycroft 63: #include <sys/param.h>
64: #include <sys/systm.h>
65: #include <sys/proc.h>
66: #include <sys/file.h>
67: #include <sys/namei.h>
68: #include <sys/vnode.h>
69: #include <sys/mount.h>
1.23 fvdl 70: #include <sys/socket.h>
71: #include <sys/socketvar.h>
1.10 mycroft 72: #include <sys/mbuf.h>
1.15 mycroft 73: #include <sys/dirent.h>
74: #include <sys/stat.h>
1.23 fvdl 75: #include <sys/kernel.h>
76: #include <ufs/ufs/dir.h>
1.1 cgd 77:
1.15 mycroft 78: #include <vm/vm.h>
1.1 cgd 79:
1.40 mrg 80: #if defined(UVM)
81: #include <uvm/uvm_extern.h>
82: #endif
83:
1.23 fvdl 84: #include <nfs/nfsproto.h>
1.15 mycroft 85: #include <nfs/rpcv2.h>
1.10 mycroft 86: #include <nfs/nfs.h>
87: #include <nfs/xdr_subs.h>
88: #include <nfs/nfsm_subs.h>
1.15 mycroft 89: #include <nfs/nqnfs.h>
1.22 christos 90: #include <nfs/nfs_var.h>
1.1 cgd 91:
92: /* Global vars */
1.19 cgd 93: extern u_int32_t nfs_xdrneg1;
94: extern u_int32_t nfs_false, nfs_true;
1.23 fvdl 95: extern enum vtype nv3tov_type[8];
96: extern struct nfsstats nfsstats;
97: extern nfstype nfsv2_type[9];
98: extern nfstype nfsv3_type[9];
1.35 fvdl 99: extern struct nfs_public nfs_pub;
1.23 fvdl 100: int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
1.1 cgd 101:
1.15 mycroft 102: /*
1.23 fvdl 103: * nfs v3 access service
1.15 mycroft 104: */
1.22 christos 105: int
1.23 fvdl 106: nfsrv3_access(nfsd, slp, procp, mrq)
107: struct nfsrv_descript *nfsd;
108: struct nfssvc_sock *slp;
109: struct proc *procp;
110: struct mbuf **mrq;
1.15 mycroft 111: {
1.23 fvdl 112: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
113: struct mbuf *nam = nfsd->nd_nam;
114: caddr_t dpos = nfsd->nd_dpos;
115: struct ucred *cred = &nfsd->nd_cr;
1.15 mycroft 116: struct vnode *vp;
1.23 fvdl 117: nfsfh_t nfh;
1.15 mycroft 118: fhandle_t *fhp;
1.19 cgd 119: register u_int32_t *tl;
120: register int32_t t1;
1.15 mycroft 121: caddr_t bpos;
1.23 fvdl 122: int error = 0, rdonly, cache = 0, getret;
1.15 mycroft 123: char *cp2;
1.23 fvdl 124: struct mbuf *mb, *mreq, *mb2;
125: struct vattr va;
1.32 mycroft 126: u_long inmode, testmode, outmode;
1.15 mycroft 127: u_quad_t frev;
128:
129: fhp = &nfh.fh_generic;
130: nfsm_srvmtofh(fhp);
1.23 fvdl 131: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
132: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
1.35 fvdl 133: (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 134: if (error) {
135: nfsm_reply(NFSX_UNSIGNED);
136: nfsm_srvpostop_attr(1, (struct vattr *)0);
137: return (0);
138: }
1.32 mycroft 139: inmode = fxdr_unsigned(u_int32_t, *tl);
140: outmode = 0;
141: if ((inmode & NFSV3ACCESS_READ) &&
142: nfsrv_access(vp, VREAD, cred, rdonly, procp, 0) == 0)
143: outmode |= NFSV3ACCESS_READ;
144: if (vp->v_type != VDIR) {
145: testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
146: if (testmode &&
147: nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0) == 0)
148: outmode |= testmode;
149: if ((inmode & NFSV3ACCESS_EXECUTE) &&
150: nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0) == 0)
151: outmode |= NFSV3ACCESS_EXECUTE;
152: } else {
153: testmode = inmode & (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
154: NFSV3ACCESS_DELETE);
155: if (testmode &&
156: nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0) == 0)
157: outmode |= testmode;
158: if ((inmode & NFSV3ACCESS_LOOKUP) &&
1.33 mycroft 159: nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0) == 0)
1.32 mycroft 160: outmode |= NFSV3ACCESS_LOOKUP;
161: }
1.23 fvdl 162: getret = VOP_GETATTR(vp, &va, cred, procp);
1.15 mycroft 163: vput(vp);
1.23 fvdl 164: nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
165: nfsm_srvpostop_attr(getret, &va);
166: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1.32 mycroft 167: *tl = txdr_unsigned(outmode);
1.15 mycroft 168: nfsm_srvdone;
169: }
170:
1.1 cgd 171: /*
172: * nfs getattr service
173: */
1.22 christos 174: int
1.23 fvdl 175: nfsrv_getattr(nfsd, slp, procp, mrq)
176: struct nfsrv_descript *nfsd;
177: struct nfssvc_sock *slp;
178: struct proc *procp;
179: struct mbuf **mrq;
1.1 cgd 180: {
1.23 fvdl 181: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
182: struct mbuf *nam = nfsd->nd_nam;
183: caddr_t dpos = nfsd->nd_dpos;
184: struct ucred *cred = &nfsd->nd_cr;
185: register struct nfs_fattr *fp;
1.1 cgd 186: struct vattr va;
187: struct vnode *vp;
1.23 fvdl 188: nfsfh_t nfh;
1.1 cgd 189: fhandle_t *fhp;
1.19 cgd 190: register u_int32_t *tl;
191: register int32_t t1;
1.1 cgd 192: caddr_t bpos;
1.15 mycroft 193: int error = 0, rdonly, cache;
1.1 cgd 194: char *cp2;
195: struct mbuf *mb, *mb2, *mreq;
1.15 mycroft 196: u_quad_t frev;
1.1 cgd 197:
198: fhp = &nfh.fh_generic;
199: nfsm_srvmtofh(fhp);
1.23 fvdl 200: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
1.35 fvdl 201: (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 202: if (error) {
1.1 cgd 203: nfsm_reply(0);
1.23 fvdl 204: return (0);
205: }
206: nqsrv_getl(vp, ND_READ);
207: error = VOP_GETATTR(vp, &va, cred, procp);
1.1 cgd 208: vput(vp);
1.23 fvdl 209: nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
210: if (error)
211: return (0);
212: nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
213: nfsm_srvfillattr(&va, fp);
1.1 cgd 214: nfsm_srvdone;
215: }
216:
217: /*
218: * nfs setattr service
219: */
1.22 christos 220: int
1.23 fvdl 221: nfsrv_setattr(nfsd, slp, procp, mrq)
222: struct nfsrv_descript *nfsd;
223: struct nfssvc_sock *slp;
224: struct proc *procp;
225: struct mbuf **mrq;
1.1 cgd 226: {
1.23 fvdl 227: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
228: struct mbuf *nam = nfsd->nd_nam;
229: caddr_t dpos = nfsd->nd_dpos;
230: struct ucred *cred = &nfsd->nd_cr;
231: struct vattr va, preat;
1.1 cgd 232: register struct nfsv2_sattr *sp;
1.23 fvdl 233: register struct nfs_fattr *fp;
1.1 cgd 234: struct vnode *vp;
1.23 fvdl 235: nfsfh_t nfh;
1.1 cgd 236: fhandle_t *fhp;
1.19 cgd 237: register u_int32_t *tl;
238: register int32_t t1;
1.1 cgd 239: caddr_t bpos;
1.23 fvdl 240: int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
241: int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
1.1 cgd 242: char *cp2;
243: struct mbuf *mb, *mb2, *mreq;
1.23 fvdl 244: u_quad_t frev;
245: struct timespec guard;
1.1 cgd 246:
247: fhp = &nfh.fh_generic;
248: nfsm_srvmtofh(fhp);
1.18 mycroft 249: VATTR_NULL(&va);
1.23 fvdl 250: if (v3) {
251: nfsm_srvsattr(&va);
252: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
253: gcheck = fxdr_unsigned(int, *tl);
254: if (gcheck) {
255: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
256: fxdr_nfsv3time(tl, &guard);
257: }
258: } else {
259: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
260: /*
261: * Nah nah nah nah na nah
262: * There is a bug in the Sun client that puts 0xffff in the mode
263: * field of sattr when it should put in 0xffffffff. The u_short
264: * doesn't sign extend.
265: * --> check the low order 2 bytes for 0xffff
266: */
267: if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
268: va.va_mode = nfstov_mode(sp->sa_mode);
269: if (sp->sa_uid != nfs_xdrneg1)
270: va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
271: if (sp->sa_gid != nfs_xdrneg1)
272: va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
273: if (sp->sa_size != nfs_xdrneg1)
274: va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
275: if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
1.15 mycroft 276: #ifdef notyet
1.23 fvdl 277: fxdr_nfsv2time(&sp->sa_atime, &va.va_atime);
1.15 mycroft 278: #else
1.20 jtc 279: va.va_atime.tv_sec =
1.23 fvdl 280: fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
1.20 jtc 281: va.va_atime.tv_nsec = 0;
1.15 mycroft 282: #endif
283: }
1.23 fvdl 284: if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
285: fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime);
286:
287: }
288:
289: /*
290: * Now that we have all the fields, lets do it.
291: */
292: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly,
1.35 fvdl 293: (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 294: if (error) {
295: nfsm_reply(2 * NFSX_UNSIGNED);
296: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
297: return (0);
298: }
299: nqsrv_getl(vp, ND_WRITE);
300: if (v3) {
301: error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
302: if (!error && gcheck &&
303: (preat.va_ctime.tv_sec != guard.tv_sec ||
304: preat.va_ctime.tv_nsec != guard.tv_nsec))
305: error = NFSERR_NOT_SYNC;
306: if (error) {
307: vput(vp);
308: nfsm_reply(NFSX_WCCDATA(v3));
309: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
310: return (0);
311: }
1.15 mycroft 312: }
313:
1.1 cgd 314: /*
1.15 mycroft 315: * If the size is being changed write acces is required, otherwise
316: * just check for a read only file system.
1.1 cgd 317: */
1.18 mycroft 318: if (va.va_size == ((u_quad_t)((quad_t) -1))) {
1.15 mycroft 319: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
320: error = EROFS;
321: goto out;
322: }
323: } else {
324: if (vp->v_type == VDIR) {
325: error = EISDIR;
326: goto out;
1.22 christos 327: } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
1.27 fvdl 328: procp, 0)) != 0)
1.15 mycroft 329: goto out;
1.1 cgd 330: }
1.23 fvdl 331: error = VOP_SETATTR(vp, &va, cred, procp);
332: postat_ret = VOP_GETATTR(vp, &va, cred, procp);
333: if (!error)
334: error = postat_ret;
1.1 cgd 335: out:
336: vput(vp);
1.23 fvdl 337: nfsm_reply(NFSX_WCCORFATTR(v3));
338: if (v3) {
339: nfsm_srvwcc_data(preat_ret, &preat, postat_ret, &va);
340: return (0);
341: } else {
342: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
343: nfsm_srvfillattr(&va, fp);
1.15 mycroft 344: }
1.1 cgd 345: nfsm_srvdone;
346: }
347:
348: /*
349: * nfs lookup rpc
350: */
1.22 christos 351: int
1.23 fvdl 352: nfsrv_lookup(nfsd, slp, procp, mrq)
353: struct nfsrv_descript *nfsd;
354: struct nfssvc_sock *slp;
355: struct proc *procp;
356: struct mbuf **mrq;
1.1 cgd 357: {
1.23 fvdl 358: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
359: struct mbuf *nam = nfsd->nd_nam;
360: caddr_t dpos = nfsd->nd_dpos;
361: struct ucred *cred = &nfsd->nd_cr;
362: register struct nfs_fattr *fp;
1.35 fvdl 363: struct nameidata nd, ind, *ndp = &nd;
1.23 fvdl 364: struct vnode *vp, *dirp;
365: nfsfh_t nfh;
1.1 cgd 366: fhandle_t *fhp;
367: register caddr_t cp;
1.19 cgd 368: register u_int32_t *tl;
369: register int32_t t1;
1.1 cgd 370: caddr_t bpos;
1.23 fvdl 371: int error = 0, cache, len, dirattr_ret = 1;
1.35 fvdl 372: int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
1.1 cgd 373: char *cp2;
374: struct mbuf *mb, *mb2, *mreq;
1.23 fvdl 375: struct vattr va, dirattr;
376: u_quad_t frev;
1.1 cgd 377:
378: fhp = &nfh.fh_generic;
379: nfsm_srvmtofh(fhp);
1.23 fvdl 380: nfsm_srvnamesiz(len);
1.35 fvdl 381:
382: pubflag = nfs_ispublicfh(fhp);
383:
1.15 mycroft 384: nd.ni_cnd.cn_cred = cred;
385: nd.ni_cnd.cn_nameiop = LOOKUP;
386: nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
1.23 fvdl 387: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 388: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
389:
390: if (!error && pubflag) {
391: if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) {
392: /*
393: * Setup call to lookup() to see if we can find
394: * the index file. Arguably, this doesn't belong
395: * in a kernel.. Ugh.
396: */
397: ind = nd;
1.42 fvdl 398: VOP_UNLOCK(nd.ni_vp, 0);
1.35 fvdl 399: ind.ni_pathlen = strlen(nfs_pub.np_index);
400: ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf =
401: nfs_pub.np_index;
402: ind.ni_startdir = nd.ni_vp;
403: VREF(ind.ni_startdir);
404: error = lookup(&ind);
405: if (!error) {
406: /*
407: * Found an index file. Get rid of
408: * the old references.
409: */
410: if (dirp)
411: vrele(dirp);
412: dirp = nd.ni_vp;
413: vrele(nd.ni_startdir);
414: ndp = &ind;
415: } else
416: error = 0;
417: }
418: /*
419: * If the public filehandle was used, check that this lookup
420: * didn't result in a filehandle outside the publicly exported
421: * filesystem.
422: */
423:
424: if (!error && ndp->ni_vp->v_mount != nfs_pub.np_mount) {
425: vput(nd.ni_vp);
426: error = EPERM;
427: }
428: }
429:
1.23 fvdl 430: if (dirp) {
431: if (v3)
432: dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
433: procp);
434: vrele(dirp);
435: }
1.35 fvdl 436:
1.23 fvdl 437: if (error) {
438: nfsm_reply(NFSX_POSTOPATTR(v3));
439: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
440: return (0);
441: }
1.35 fvdl 442:
443: nqsrv_getl(ndp->ni_startdir, ND_READ);
444: vrele(ndp->ni_startdir);
1.15 mycroft 445: FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1.35 fvdl 446: vp = ndp->ni_vp;
1.44 perry 447: memset((caddr_t)fhp, 0, sizeof(nfh));
1.1 cgd 448: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1.23 fvdl 449: error = VFS_VPTOFH(vp, &fhp->fh_fid);
450: if (!error)
451: error = VOP_GETATTR(vp, &va, cred, procp);
452: vput(vp);
453: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
454: if (error) {
455: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
456: return (0);
1.1 cgd 457: }
1.23 fvdl 458: nfsm_srvfhtom(fhp, v3);
459: if (v3) {
460: nfsm_srvpostop_attr(0, &va);
461: nfsm_srvpostop_attr(dirattr_ret, &dirattr);
462: } else {
463: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
464: nfsm_srvfillattr(&va, fp);
1.15 mycroft 465: }
1.1 cgd 466: nfsm_srvdone;
467: }
468:
469: /*
470: * nfs readlink service
471: */
1.22 christos 472: int
1.23 fvdl 473: nfsrv_readlink(nfsd, slp, procp, mrq)
474: struct nfsrv_descript *nfsd;
475: struct nfssvc_sock *slp;
476: struct proc *procp;
477: struct mbuf **mrq;
1.1 cgd 478: {
1.23 fvdl 479: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
480: struct mbuf *nam = nfsd->nd_nam;
481: caddr_t dpos = nfsd->nd_dpos;
482: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 483: struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
484: register struct iovec *ivp = iv;
485: register struct mbuf *mp;
1.19 cgd 486: register u_int32_t *tl;
487: register int32_t t1;
1.1 cgd 488: caddr_t bpos;
1.23 fvdl 489: int error = 0, rdonly, cache, i, tlen, len, getret;
490: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 491: char *cp2;
1.22 christos 492: struct mbuf *mb, *mb2, *mp2 = NULL, *mp3 = NULL, *mreq;
1.1 cgd 493: struct vnode *vp;
1.23 fvdl 494: struct vattr attr;
495: nfsfh_t nfh;
1.1 cgd 496: fhandle_t *fhp;
497: struct uio io, *uiop = &io;
1.15 mycroft 498: u_quad_t frev;
1.1 cgd 499:
500: fhp = &nfh.fh_generic;
501: nfsm_srvmtofh(fhp);
502: len = 0;
503: i = 0;
504: while (len < NFS_MAXPATHLEN) {
505: MGET(mp, M_WAIT, MT_DATA);
506: MCLGET(mp, M_WAIT);
507: mp->m_len = NFSMSIZ(mp);
508: if (len == 0)
509: mp3 = mp2 = mp;
510: else {
511: mp2->m_next = mp;
512: mp2 = mp;
513: }
514: if ((len+mp->m_len) > NFS_MAXPATHLEN) {
515: mp->m_len = NFS_MAXPATHLEN-len;
516: len = NFS_MAXPATHLEN;
517: } else
518: len += mp->m_len;
519: ivp->iov_base = mtod(mp, caddr_t);
520: ivp->iov_len = mp->m_len;
521: i++;
522: ivp++;
523: }
524: uiop->uio_iov = iv;
525: uiop->uio_iovcnt = i;
526: uiop->uio_offset = 0;
527: uiop->uio_resid = len;
528: uiop->uio_rw = UIO_READ;
529: uiop->uio_segflg = UIO_SYSSPACE;
530: uiop->uio_procp = (struct proc *)0;
1.23 fvdl 531: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 532: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.22 christos 533: if (error) {
1.1 cgd 534: m_freem(mp3);
1.23 fvdl 535: nfsm_reply(2 * NFSX_UNSIGNED);
536: nfsm_srvpostop_attr(1, (struct vattr *)0);
537: return (0);
1.1 cgd 538: }
539: if (vp->v_type != VLNK) {
1.23 fvdl 540: if (v3)
541: error = EINVAL;
542: else
543: error = ENXIO;
1.1 cgd 544: goto out;
545: }
1.23 fvdl 546: nqsrv_getl(vp, ND_READ);
1.1 cgd 547: error = VOP_READLINK(vp, uiop, cred);
548: out:
1.23 fvdl 549: getret = VOP_GETATTR(vp, &attr, cred, procp);
1.1 cgd 550: vput(vp);
551: if (error)
552: m_freem(mp3);
1.23 fvdl 553: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
554: if (v3) {
555: nfsm_srvpostop_attr(getret, &attr);
556: if (error)
557: return (0);
558: }
1.1 cgd 559: if (uiop->uio_resid > 0) {
560: len -= uiop->uio_resid;
561: tlen = nfsm_rndup(len);
562: nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
563: }
1.19 cgd 564: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1.1 cgd 565: *tl = txdr_unsigned(len);
566: mb->m_next = mp3;
567: nfsm_srvdone;
568: }
569:
570: /*
571: * nfs read service
572: */
1.22 christos 573: int
1.23 fvdl 574: nfsrv_read(nfsd, slp, procp, mrq)
575: struct nfsrv_descript *nfsd;
576: struct nfssvc_sock *slp;
577: struct proc *procp;
578: struct mbuf **mrq;
1.1 cgd 579: {
1.23 fvdl 580: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
581: struct mbuf *nam = nfsd->nd_nam;
582: caddr_t dpos = nfsd->nd_dpos;
583: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 584: register struct iovec *iv;
585: struct iovec *iv2;
586: register struct mbuf *m;
1.23 fvdl 587: register struct nfs_fattr *fp;
1.19 cgd 588: register u_int32_t *tl;
589: register int32_t t1;
1.23 fvdl 590: register int i;
1.1 cgd 591: caddr_t bpos;
1.23 fvdl 592: int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
593: int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
1.1 cgd 594: char *cp2;
595: struct mbuf *mb, *mb2, *mreq;
1.15 mycroft 596: struct mbuf *m2;
1.1 cgd 597: struct vnode *vp;
1.23 fvdl 598: nfsfh_t nfh;
1.1 cgd 599: fhandle_t *fhp;
600: struct uio io, *uiop = &io;
1.18 mycroft 601: struct vattr va;
1.1 cgd 602: off_t off;
1.15 mycroft 603: u_quad_t frev;
1.1 cgd 604:
605: fhp = &nfh.fh_generic;
606: nfsm_srvmtofh(fhp);
1.23 fvdl 607: if (v3) {
608: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
609: fxdr_hyper(tl, &off);
610: } else {
1.19 cgd 611: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
612: off = (off_t)fxdr_unsigned(u_int32_t, *tl);
1.15 mycroft 613: }
1.23 fvdl 614: nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
615: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 616: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 617: if (error) {
618: nfsm_reply(2 * NFSX_UNSIGNED);
619: nfsm_srvpostop_attr(1, (struct vattr *)0);
620: return (0);
621: }
1.15 mycroft 622: if (vp->v_type != VREG) {
1.23 fvdl 623: if (v3)
624: error = EINVAL;
625: else
626: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1.1 cgd 627: }
1.23 fvdl 628: if (!error) {
629: nqsrv_getl(vp, ND_READ);
1.27 fvdl 630: if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0)
631: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1);
1.23 fvdl 632: }
633: getret = VOP_GETATTR(vp, &va, cred, procp);
634: if (!error)
635: error = getret;
1.22 christos 636: if (error) {
1.1 cgd 637: vput(vp);
1.23 fvdl 638: nfsm_reply(NFSX_POSTOPATTR(v3));
639: nfsm_srvpostop_attr(getret, &va);
640: return (0);
1.1 cgd 641: }
1.18 mycroft 642: if (off >= va.va_size)
1.15 mycroft 643: cnt = 0;
1.23 fvdl 644: else if ((off + reqlen) > va.va_size)
1.18 mycroft 645: cnt = nfsm_rndup(va.va_size - off);
1.23 fvdl 646: else
647: cnt = reqlen;
648: nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
649: if (v3) {
650: nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
651: *tl++ = nfs_true;
652: fp = (struct nfs_fattr *)tl;
653: tl += (NFSX_V3FATTR / sizeof (u_int32_t));
654: } else {
655: nfsm_build(tl, u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED);
656: fp = (struct nfs_fattr *)tl;
657: tl += (NFSX_V2FATTR / sizeof (u_int32_t));
658: }
1.15 mycroft 659: len = left = cnt;
660: if (cnt > 0) {
661: /*
662: * Generate the mbuf list with the uio_iov ref. to it.
663: */
664: i = 0;
665: m = m2 = mb;
666: while (left > 0) {
667: siz = min(M_TRAILINGSPACE(m), left);
668: if (siz > 0) {
1.23 fvdl 669: left -= siz;
1.15 mycroft 670: i++;
671: }
672: if (left > 0) {
673: MGET(m, M_WAIT, MT_DATA);
674: MCLGET(m, M_WAIT);
675: m->m_len = 0;
676: m2->m_next = m;
677: m2 = m;
678: }
679: }
1.23 fvdl 680: MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
681: M_TEMP, M_WAITOK);
682: uiop->uio_iov = iv2 = iv;
683: m = mb;
684: left = cnt;
685: i = 0;
686: while (left > 0) {
687: if (m == NULL)
688: panic("nfsrv_read iov");
689: siz = min(M_TRAILINGSPACE(m), left);
690: if (siz > 0) {
691: iv->iov_base = mtod(m, caddr_t) + m->m_len;
692: iv->iov_len = siz;
693: m->m_len += siz;
694: left -= siz;
695: iv++;
696: i++;
697: }
698: m = m->m_next;
699: }
1.15 mycroft 700: uiop->uio_iovcnt = i;
701: uiop->uio_offset = off;
702: uiop->uio_resid = cnt;
703: uiop->uio_rw = UIO_READ;
704: uiop->uio_segflg = UIO_SYSSPACE;
705: error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
706: off = uiop->uio_offset;
707: FREE((caddr_t)iv2, M_TEMP);
1.23 fvdl 708: if (error || (getret = VOP_GETATTR(vp, &va, cred, procp)) != 0){
709: if (!error)
710: error = getret;
1.15 mycroft 711: m_freem(mreq);
712: vput(vp);
1.23 fvdl 713: nfsm_reply(NFSX_POSTOPATTR(v3));
714: nfsm_srvpostop_attr(getret, &va);
715: return (0);
1.15 mycroft 716: }
717: } else
718: uiop->uio_resid = 0;
1.1 cgd 719: vput(vp);
1.23 fvdl 720: nfsm_srvfillattr(&va, fp);
1.1 cgd 721: len -= uiop->uio_resid;
1.15 mycroft 722: tlen = nfsm_rndup(len);
723: if (cnt != tlen || tlen != len)
1.23 fvdl 724: nfsm_adj(mb, cnt - tlen, tlen - len);
725: if (v3) {
726: *tl++ = txdr_unsigned(len);
727: if (len < reqlen)
728: *tl++ = nfs_true;
729: else
730: *tl++ = nfs_false;
731: }
1.1 cgd 732: *tl = txdr_unsigned(len);
733: nfsm_srvdone;
734: }
735:
736: /*
737: * nfs write service
738: */
1.22 christos 739: int
1.23 fvdl 740: nfsrv_write(nfsd, slp, procp, mrq)
741: struct nfsrv_descript *nfsd;
742: struct nfssvc_sock *slp;
743: struct proc *procp;
744: struct mbuf **mrq;
1.1 cgd 745: {
1.23 fvdl 746: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
747: struct mbuf *nam = nfsd->nd_nam;
748: caddr_t dpos = nfsd->nd_dpos;
749: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 750: register struct iovec *ivp;
1.23 fvdl 751: register int i, cnt;
1.1 cgd 752: register struct mbuf *mp;
1.23 fvdl 753: register struct nfs_fattr *fp;
754: struct iovec *iv;
755: struct vattr va, forat;
1.19 cgd 756: register u_int32_t *tl;
757: register int32_t t1;
1.1 cgd 758: caddr_t bpos;
1.23 fvdl 759: int error = 0, rdonly, cache, len, forat_ret = 1;
760: int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
761: int stable = NFSV3WRITE_FILESYNC;
762: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 763: char *cp2;
764: struct mbuf *mb, *mb2, *mreq;
765: struct vnode *vp;
1.23 fvdl 766: nfsfh_t nfh;
1.1 cgd 767: fhandle_t *fhp;
768: struct uio io, *uiop = &io;
769: off_t off;
1.15 mycroft 770: u_quad_t frev;
1.1 cgd 771:
1.23 fvdl 772: if (mrep == NULL) {
773: *mrq = NULL;
774: return (0);
775: }
1.1 cgd 776: fhp = &nfh.fh_generic;
777: nfsm_srvmtofh(fhp);
1.23 fvdl 778: if (v3) {
779: nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
780: fxdr_hyper(tl, &off);
781: tl += 3;
782: stable = fxdr_unsigned(int, *tl++);
783: } else {
784: nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1.19 cgd 785: off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1.15 mycroft 786: tl += 2;
787: }
1.23 fvdl 788: retlen = len = fxdr_unsigned(int32_t, *tl);
789: cnt = i = 0;
790:
791: /*
792: * For NFS Version 2, it is not obvious what a write of zero length
793: * should do, but I might as well be consistent with Version 3,
794: * which is to return ok so long as there are no permission problems.
795: */
796: if (len > 0) {
797: zeroing = 1;
798: mp = mrep;
799: while (mp) {
800: if (mp == md) {
801: zeroing = 0;
802: adjust = dpos - mtod(mp, caddr_t);
803: mp->m_len -= adjust;
804: if (mp->m_len > 0 && adjust > 0)
805: NFSMADV(mp, adjust);
806: }
807: if (zeroing)
808: mp->m_len = 0;
809: else if (mp->m_len > 0) {
810: i += mp->m_len;
811: if (i > len) {
812: mp->m_len -= (i - len);
813: zeroing = 1;
814: }
815: if (mp->m_len > 0)
816: cnt++;
817: }
818: mp = mp->m_next;
819: }
820: }
821: if (len > NFS_MAXDATA || len < 0 || i < len) {
822: error = EIO;
823: nfsm_reply(2 * NFSX_UNSIGNED);
824: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
825: return (0);
1.1 cgd 826: }
1.23 fvdl 827: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 828: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 829: if (error) {
830: nfsm_reply(2 * NFSX_UNSIGNED);
831: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
832: return (0);
1.1 cgd 833: }
1.23 fvdl 834: if (v3)
835: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1.15 mycroft 836: if (vp->v_type != VREG) {
1.23 fvdl 837: if (v3)
838: error = EINVAL;
839: else
840: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
841: }
842: if (!error) {
843: nqsrv_getl(vp, ND_WRITE);
1.27 fvdl 844: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1);
1.15 mycroft 845: }
1.22 christos 846: if (error) {
1.1 cgd 847: vput(vp);
1.23 fvdl 848: nfsm_reply(NFSX_WCCDATA(v3));
849: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
850: return (0);
851: }
852:
853: if (len > 0) {
854: MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
855: M_WAITOK);
856: uiop->uio_iov = iv = ivp;
857: uiop->uio_iovcnt = cnt;
858: mp = mrep;
859: while (mp) {
860: if (mp->m_len > 0) {
861: ivp->iov_base = mtod(mp, caddr_t);
862: ivp->iov_len = mp->m_len;
863: ivp++;
864: }
865: mp = mp->m_next;
866: }
867:
868: /*
869: * XXX
870: * The IO_METASYNC flag indicates that all metadata (and not just
871: * enough to ensure data integrity) mus be written to stable storage
872: * synchronously.
873: * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
874: */
875: if (stable == NFSV3WRITE_UNSTABLE)
876: ioflags = IO_NODELOCKED;
877: else if (stable == NFSV3WRITE_DATASYNC)
878: ioflags = (IO_SYNC | IO_NODELOCKED);
879: else
880: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
881: uiop->uio_resid = len;
882: uiop->uio_rw = UIO_WRITE;
883: uiop->uio_segflg = UIO_SYSSPACE;
884: uiop->uio_procp = (struct proc *)0;
885: uiop->uio_offset = off;
886: error = VOP_WRITE(vp, uiop, ioflags, cred);
887: nfsstats.srvvop_writes++;
888: FREE((caddr_t)iv, M_TEMP);
889: }
890: aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
891: vput(vp);
892: if (!error)
893: error = aftat_ret;
894: nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
895: 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
896: if (v3) {
897: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
898: if (error)
899: return (0);
900: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
901: *tl++ = txdr_unsigned(retlen);
902: if (stable == NFSV3WRITE_UNSTABLE)
903: *tl++ = txdr_unsigned(stable);
904: else
905: *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
906: /*
907: * Actually, there is no need to txdr these fields,
908: * but it may make the values more human readable,
909: * for debugging purposes.
910: */
911: *tl++ = txdr_unsigned(boottime.tv_sec);
912: *tl = txdr_unsigned(boottime.tv_usec);
913: } else {
914: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
915: nfsm_srvfillattr(&va, fp);
916: }
917: nfsm_srvdone;
918: }
919:
920: /*
921: * NFS write service with write gathering support. Called when
922: * nfsrvw_procrastinate > 0.
923: * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
924: * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
925: * Jan. 1994.
926: */
927: int
928: nfsrv_writegather(ndp, slp, procp, mrq)
929: struct nfsrv_descript **ndp;
930: struct nfssvc_sock *slp;
931: struct proc *procp;
932: struct mbuf **mrq;
933: {
934: register struct iovec *ivp;
935: register struct mbuf *mp;
936: register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
937: register struct nfs_fattr *fp;
938: register int i = 0;
939: struct iovec *iov;
940: struct nfsrvw_delayhash *wpp;
941: struct ucred *cred;
942: struct vattr va, forat;
943: register u_int32_t *tl;
944: register int32_t t1;
945: caddr_t bpos, dpos;
946: int error = 0, rdonly, cache, len = 0, forat_ret = 1;
947: int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
948: char *cp2;
949: struct mbuf *mb, *mb2, *mreq, *mrep, *md;
950: struct vnode *vp;
951: struct uio io, *uiop = &io;
952: u_quad_t frev, cur_usec;
953:
954: *mrq = NULL;
955: if (*ndp) {
956: nfsd = *ndp;
957: *ndp = NULL;
958: mrep = nfsd->nd_mrep;
959: md = nfsd->nd_md;
960: dpos = nfsd->nd_dpos;
961: cred = &nfsd->nd_cr;
962: v3 = (nfsd->nd_flag & ND_NFSV3);
963: LIST_INIT(&nfsd->nd_coalesce);
964: nfsd->nd_mreq = NULL;
965: nfsd->nd_stable = NFSV3WRITE_FILESYNC;
966: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
967: nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
968:
969: /*
970: * Now, get the write header..
971: */
972: nfsm_srvmtofh(&nfsd->nd_fh);
973: if (v3) {
974: nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
975: fxdr_hyper(tl, &nfsd->nd_off);
976: tl += 3;
977: nfsd->nd_stable = fxdr_unsigned(int, *tl++);
978: } else {
979: nfsm_dissect(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
980: nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
981: tl += 2;
982: }
983: len = fxdr_unsigned(int32_t, *tl);
984: nfsd->nd_len = len;
985: nfsd->nd_eoff = nfsd->nd_off + len;
986:
987: /*
988: * Trim the header out of the mbuf list and trim off any trailing
989: * junk so that the mbuf list has only the write data.
990: */
991: zeroing = 1;
992: i = 0;
993: mp = mrep;
994: while (mp) {
995: if (mp == md) {
996: zeroing = 0;
997: adjust = dpos - mtod(mp, caddr_t);
998: mp->m_len -= adjust;
999: if (mp->m_len > 0 && adjust > 0)
1000: NFSMADV(mp, adjust);
1001: }
1002: if (zeroing)
1003: mp->m_len = 0;
1004: else {
1005: i += mp->m_len;
1006: if (i > len) {
1007: mp->m_len -= (i - len);
1008: zeroing = 1;
1009: }
1010: }
1011: mp = mp->m_next;
1012: }
1013: if (len > NFS_MAXDATA || len < 0 || i < len) {
1014: nfsmout:
1015: m_freem(mrep);
1016: error = EIO;
1017: nfsm_writereply(2 * NFSX_UNSIGNED, v3);
1018: if (v3)
1019: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1020: nfsd->nd_mreq = mreq;
1021: nfsd->nd_mrep = NULL;
1022: nfsd->nd_time = 0;
1023: }
1024:
1025: /*
1026: * Add this entry to the hash and time queues.
1027: */
1028: s = splsoftclock();
1029: owp = NULL;
1030: wp = slp->ns_tq.lh_first;
1031: while (wp && wp->nd_time < nfsd->nd_time) {
1032: owp = wp;
1033: wp = wp->nd_tq.le_next;
1034: }
1035: if (owp) {
1036: LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1037: } else {
1038: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1039: }
1040: if (nfsd->nd_mrep) {
1041: wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
1042: owp = NULL;
1043: wp = wpp->lh_first;
1044: while (wp &&
1.44 perry 1045: memcmp((caddr_t)&nfsd->nd_fh, (caddr_t)&wp->nd_fh, NFSX_V3FH)) {
1.23 fvdl 1046: owp = wp;
1047: wp = wp->nd_hash.le_next;
1048: }
1049: while (wp && wp->nd_off < nfsd->nd_off &&
1.44 perry 1050: !memcmp((caddr_t)&nfsd->nd_fh, (caddr_t)&wp->nd_fh, NFSX_V3FH)) {
1.23 fvdl 1051: owp = wp;
1052: wp = wp->nd_hash.le_next;
1053: }
1054: if (owp) {
1055: LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1056:
1057: /*
1058: * Search the hash list for overlapping entries and
1059: * coalesce.
1060: */
1061: for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1062: wp = nfsd->nd_hash.le_next;
1063: if (NFSW_SAMECRED(owp, nfsd))
1064: nfsrvw_coalesce(owp, nfsd);
1065: }
1066: } else {
1067: LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1068: }
1069: }
1070: splx(s);
1.1 cgd 1071: }
1.23 fvdl 1072:
1.1 cgd 1073: /*
1.23 fvdl 1074: * Now, do VOP_WRITE()s for any one(s) that need to be done now
1075: * and generate the associated reply mbuf list(s).
1.1 cgd 1076: */
1.23 fvdl 1077: loop1:
1078: cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1079: s = splsoftclock();
1080: for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1081: owp = nfsd->nd_tq.le_next;
1082: if (nfsd->nd_time > cur_usec)
1083: break;
1084: if (nfsd->nd_mreq)
1085: continue;
1086: LIST_REMOVE(nfsd, nd_tq);
1087: LIST_REMOVE(nfsd, nd_hash);
1088: splx(s);
1089: mrep = nfsd->nd_mrep;
1090: nfsd->nd_mrep = NULL;
1091: cred = &nfsd->nd_cr;
1092: v3 = (nfsd->nd_flag & ND_NFSV3);
1093: forat_ret = aftat_ret = 1;
1094: error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1.35 fvdl 1095: nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH),
1096: FALSE);
1.23 fvdl 1097: if (!error) {
1098: if (v3)
1099: forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1100: if (vp->v_type != VREG) {
1101: if (v3)
1102: error = EINVAL;
1.1 cgd 1103: else
1.23 fvdl 1104: error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1105: }
1106: } else
1107: vp = NULL;
1108: if (!error) {
1109: nqsrv_getl(vp, ND_WRITE);
1.27 fvdl 1110: error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1);
1.23 fvdl 1111: }
1112:
1113: if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1114: ioflags = IO_NODELOCKED;
1115: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1116: ioflags = (IO_SYNC | IO_NODELOCKED);
1117: else
1118: ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1119: uiop->uio_rw = UIO_WRITE;
1120: uiop->uio_segflg = UIO_SYSSPACE;
1121: uiop->uio_procp = (struct proc *)0;
1122: uiop->uio_offset = nfsd->nd_off;
1123: uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1124: if (uiop->uio_resid > 0) {
1125: mp = mrep;
1126: i = 0;
1127: while (mp) {
1128: if (mp->m_len > 0)
1129: i++;
1130: mp = mp->m_next;
1131: }
1132: uiop->uio_iovcnt = i;
1133: MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1134: M_TEMP, M_WAITOK);
1135: uiop->uio_iov = ivp = iov;
1136: mp = mrep;
1137: while (mp) {
1138: if (mp->m_len > 0) {
1139: ivp->iov_base = mtod(mp, caddr_t);
1140: ivp->iov_len = mp->m_len;
1141: ivp++;
1142: }
1.1 cgd 1143: mp = mp->m_next;
1.23 fvdl 1144: }
1145: if (!error) {
1146: error = VOP_WRITE(vp, uiop, ioflags, cred);
1147: nfsstats.srvvop_writes++;
1148: }
1149: FREE((caddr_t)iov, M_TEMP);
1.1 cgd 1150: }
1.23 fvdl 1151: m_freem(mrep);
1152: if (vp) {
1153: aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1154: vput(vp);
1.1 cgd 1155: }
1.23 fvdl 1156:
1157: /*
1158: * Loop around generating replies for all write rpcs that have
1159: * now been completed.
1160: */
1161: swp = nfsd;
1162: do {
1163: if (error) {
1164: nfsm_writereply(NFSX_WCCDATA(v3), v3);
1165: if (v3) {
1166: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1167: }
1168: } else {
1169: nfsm_writereply(NFSX_PREOPATTR(v3) +
1170: NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1171: NFSX_WRITEVERF(v3), v3);
1172: if (v3) {
1173: nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1174: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1175: *tl++ = txdr_unsigned(nfsd->nd_len);
1176: *tl++ = txdr_unsigned(swp->nd_stable);
1177: /*
1178: * Actually, there is no need to txdr these fields,
1179: * but it may make the values more human readable,
1180: * for debugging purposes.
1181: */
1182: *tl++ = txdr_unsigned(boottime.tv_sec);
1183: *tl = txdr_unsigned(boottime.tv_usec);
1184: } else {
1185: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1186: nfsm_srvfillattr(&va, fp);
1187: }
1188: }
1189: nfsd->nd_mreq = mreq;
1190: if (nfsd->nd_mrep)
1191: panic("nfsrv_write: nd_mrep not free");
1192:
1193: /*
1194: * Done. Put it at the head of the timer queue so that
1195: * the final phase can return the reply.
1196: */
1197: s = splsoftclock();
1198: if (nfsd != swp) {
1199: nfsd->nd_time = 0;
1200: LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1201: }
1202: nfsd = swp->nd_coalesce.lh_first;
1203: if (nfsd) {
1204: LIST_REMOVE(nfsd, nd_tq);
1205: }
1206: splx(s);
1207: } while (nfsd);
1208: s = splsoftclock();
1209: swp->nd_time = 0;
1210: LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1211: splx(s);
1212: goto loop1;
1213: }
1214: splx(s);
1215:
1216: /*
1217: * Search for a reply to return.
1218: */
1219: s = splsoftclock();
1220: for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1221: if (nfsd->nd_mreq) {
1222: LIST_REMOVE(nfsd, nd_tq);
1223: *mrq = nfsd->nd_mreq;
1224: *ndp = nfsd;
1225: break;
1.1 cgd 1226: }
1.23 fvdl 1227: splx(s);
1228: return (0);
1229: }
1230:
1231: /*
1232: * Coalesce the write request nfsd into owp. To do this we must:
1233: * - remove nfsd from the queues
1234: * - merge nfsd->nd_mrep into owp->nd_mrep
1235: * - update the nd_eoff and nd_stable for owp
1236: * - put nfsd on owp's nd_coalesce list
1237: * NB: Must be called at splsoftclock().
1238: */
1239: void
1240: nfsrvw_coalesce(owp, nfsd)
1241: register struct nfsrv_descript *owp;
1242: register struct nfsrv_descript *nfsd;
1243: {
1244: register int overlap;
1245: register struct mbuf *mp;
1246:
1247: LIST_REMOVE(nfsd, nd_hash);
1248: LIST_REMOVE(nfsd, nd_tq);
1249: if (owp->nd_eoff < nfsd->nd_eoff) {
1250: overlap = owp->nd_eoff - nfsd->nd_off;
1251: if (overlap < 0)
1252: panic("nfsrv_coalesce: bad off");
1253: if (overlap > 0)
1254: m_adj(nfsd->nd_mrep, overlap);
1255: mp = owp->nd_mrep;
1256: while (mp->m_next)
1257: mp = mp->m_next;
1258: mp->m_next = nfsd->nd_mrep;
1259: owp->nd_eoff = nfsd->nd_eoff;
1260: } else
1261: m_freem(nfsd->nd_mrep);
1262: nfsd->nd_mrep = NULL;
1263: if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1264: owp->nd_stable = NFSV3WRITE_FILESYNC;
1265: else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1266: owp->nd_stable == NFSV3WRITE_UNSTABLE)
1267: owp->nd_stable = NFSV3WRITE_DATASYNC;
1268: LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1.34 fvdl 1269: /*
1270: * nfsd might hold coalesce elements! Move them to owp.
1271: * Otherwise, requests may be lost and clients will be stuck.
1272: */
1273: if (nfsd->nd_coalesce.lh_first)
1274: {
1275: register struct nfsrv_descript *m;
1276:
1277: while ((m = nfsd->nd_coalesce.lh_first))
1278: {
1279: LIST_REMOVE(m, nd_tq);
1280: LIST_INSERT_HEAD(&owp->nd_coalesce, m, nd_tq);
1281: }
1282: }
1.1 cgd 1283: }
1284:
1285: /*
1286: * nfs create service
1.15 mycroft 1287: * now does a truncate to 0 length via. setattr if it already exists
1.1 cgd 1288: */
1.22 christos 1289: int
1.23 fvdl 1290: nfsrv_create(nfsd, slp, procp, mrq)
1291: struct nfsrv_descript *nfsd;
1292: struct nfssvc_sock *slp;
1293: struct proc *procp;
1294: struct mbuf **mrq;
1.1 cgd 1295: {
1.23 fvdl 1296: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1297: struct mbuf *nam = nfsd->nd_nam;
1298: caddr_t dpos = nfsd->nd_dpos;
1299: struct ucred *cred = &nfsd->nd_cr;
1300: register struct nfs_fattr *fp;
1301: struct vattr va, dirfor, diraft;
1.15 mycroft 1302: register struct nfsv2_sattr *sp;
1.19 cgd 1303: register u_int32_t *tl;
1.1 cgd 1304: struct nameidata nd;
1305: register caddr_t cp;
1.19 cgd 1306: register int32_t t1;
1.1 cgd 1307: caddr_t bpos;
1.23 fvdl 1308: int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1309: int rdev = 0;
1310: int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
1.1 cgd 1311: char *cp2;
1312: struct mbuf *mb, *mb2, *mreq;
1.23 fvdl 1313: struct vnode *vp = NULL, *dirp = NULL;
1314: nfsfh_t nfh;
1.1 cgd 1315: fhandle_t *fhp;
1.23 fvdl 1316: u_quad_t frev, tempsize;
1317: u_char cverf[NFSX_V3CREATEVERF];
1.1 cgd 1318:
1.15 mycroft 1319: nd.ni_cnd.cn_nameiop = 0;
1.1 cgd 1320: fhp = &nfh.fh_generic;
1321: nfsm_srvmtofh(fhp);
1.23 fvdl 1322: nfsm_srvnamesiz(len);
1.15 mycroft 1323: nd.ni_cnd.cn_cred = cred;
1324: nd.ni_cnd.cn_nameiop = CREATE;
1325: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1.23 fvdl 1326: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 1327: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 1328: if (dirp) {
1329: if (v3)
1330: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1331: procp);
1332: else {
1333: vrele(dirp);
1334: dirp = (struct vnode *)0;
1335: }
1336: }
1337: if (error) {
1338: nfsm_reply(NFSX_WCCDATA(v3));
1339: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1340: if (dirp)
1341: vrele(dirp);
1342: return (0);
1343: }
1.18 mycroft 1344: VATTR_NULL(&va);
1.23 fvdl 1345: if (v3) {
1346: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1347: how = fxdr_unsigned(int, *tl);
1348: switch (how) {
1349: case NFSV3CREATE_GUARDED:
1350: if (nd.ni_vp) {
1351: error = EEXIST;
1352: break;
1353: }
1354: case NFSV3CREATE_UNCHECKED:
1355: nfsm_srvsattr(&va);
1356: break;
1357: case NFSV3CREATE_EXCLUSIVE:
1358: nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1.44 perry 1359: memcpy(cverf, cp, NFSX_V3CREATEVERF);
1.23 fvdl 1360: exclusive_flag = 1;
1361: if (nd.ni_vp == NULL)
1362: va.va_mode = 0;
1363: break;
1364: };
1365: va.va_type = VREG;
1366: } else {
1367: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1368: va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1369: if (va.va_type == VNON)
1370: va.va_type = VREG;
1371: va.va_mode = nfstov_mode(sp->sa_mode);
1372: switch (va.va_type) {
1373: case VREG:
1374: tsize = fxdr_unsigned(int32_t, sp->sa_size);
1375: if (tsize != -1)
1376: va.va_size = (u_quad_t)tsize;
1377: break;
1378: case VCHR:
1379: case VBLK:
1380: case VFIFO:
1381: rdev = fxdr_unsigned(int32_t, sp->sa_size);
1382: break;
1383: default:
1384: break;
1385: };
1386: }
1387:
1.1 cgd 1388: /*
1.15 mycroft 1389: * Iff doesn't exist, create it
1390: * otherwise just truncate to 0 length
1.1 cgd 1391: * should I set the mode too ??
1392: */
1393: if (nd.ni_vp == NULL) {
1.18 mycroft 1394: if (va.va_type == VREG || va.va_type == VSOCK) {
1.1 cgd 1395: vrele(nd.ni_startdir);
1.23 fvdl 1396: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1397: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1398: if (!error) {
1399: FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1400: if (exclusive_flag) {
1401: exclusive_flag = 0;
1402: VATTR_NULL(&va);
1.44 perry 1403: memcpy((caddr_t)&va.va_atime, cverf,
1.23 fvdl 1404: NFSX_V3CREATEVERF);
1405: error = VOP_SETATTR(nd.ni_vp, &va, cred,
1406: procp);
1407: }
1408: }
1.18 mycroft 1409: } else if (va.va_type == VCHR || va.va_type == VBLK ||
1410: va.va_type == VFIFO) {
1411: if (va.va_type == VCHR && rdev == 0xffffffff)
1412: va.va_type = VFIFO;
1.23 fvdl 1413: error = suser(cred, (u_short *)0);
1414: if (error) {
1415: vrele(nd.ni_startdir);
1416: free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1.15 mycroft 1417: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 1418: vput(nd.ni_dvp);
1.23 fvdl 1419: nfsm_reply(0);
1420: return (error);
1.1 cgd 1421: } else
1.18 mycroft 1422: va.va_rdev = (dev_t)rdev;
1.23 fvdl 1423: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1.22 christos 1424: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1.23 fvdl 1425: &va);
1.22 christos 1426: if (error) {
1.1 cgd 1427: vrele(nd.ni_startdir);
1428: nfsm_reply(0);
1429: }
1.15 mycroft 1430: nd.ni_cnd.cn_nameiop = LOOKUP;
1431: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1.23 fvdl 1432: nd.ni_cnd.cn_proc = procp;
1433: nd.ni_cnd.cn_cred = cred;
1.22 christos 1434: if ((error = lookup(&nd)) != 0) {
1.15 mycroft 1435: free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1.1 cgd 1436: nfsm_reply(0);
1437: }
1.15 mycroft 1438: FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1439: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1.1 cgd 1440: vrele(nd.ni_dvp);
1441: vput(nd.ni_vp);
1.15 mycroft 1442: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 1443: error = EINVAL;
1444: nfsm_reply(0);
1445: }
1446: } else {
1.23 fvdl 1447: vrele(nd.ni_startdir);
1448: free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1.15 mycroft 1449: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 1450: vput(nd.ni_dvp);
1451: error = ENXIO;
1452: }
1453: vp = nd.ni_vp;
1454: } else {
1455: vrele(nd.ni_startdir);
1.15 mycroft 1456: free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1.1 cgd 1457: vp = nd.ni_vp;
1458: if (nd.ni_dvp == vp)
1459: vrele(nd.ni_dvp);
1460: else
1461: vput(nd.ni_dvp);
1.15 mycroft 1462: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.18 mycroft 1463: if (va.va_size != -1) {
1.22 christos 1464: error = nfsrv_access(vp, VWRITE, cred,
1.27 fvdl 1465: (nd.ni_cnd.cn_flags & RDONLY), procp, 0);
1.23 fvdl 1466: if (!error) {
1467: nqsrv_getl(vp, ND_WRITE);
1468: tempsize = va.va_size;
1469: VATTR_NULL(&va);
1470: va.va_size = tempsize;
1471: error = VOP_SETATTR(vp, &va, cred,
1472: procp);
1.15 mycroft 1473: }
1.23 fvdl 1474: if (error)
1.15 mycroft 1475: vput(vp);
1.1 cgd 1476: }
1477: }
1.23 fvdl 1478: if (!error) {
1.44 perry 1479: memset((caddr_t)fhp, 0, sizeof(nfh));
1.23 fvdl 1480: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1481: error = VFS_VPTOFH(vp, &fhp->fh_fid);
1482: if (!error)
1483: error = VOP_GETATTR(vp, &va, cred, procp);
1.1 cgd 1484: vput(vp);
1485: }
1.23 fvdl 1486: if (v3) {
1487: if (exclusive_flag && !error &&
1.44 perry 1488: memcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF))
1.23 fvdl 1489: error = EEXIST;
1490: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1491: vrele(dirp);
1492: }
1493: nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1494: if (v3) {
1495: if (!error) {
1496: nfsm_srvpostop_fh(fhp);
1497: nfsm_srvpostop_attr(0, &va);
1498: }
1499: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1500: } else {
1501: nfsm_srvfhtom(fhp, v3);
1502: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1503: nfsm_srvfillattr(&va, fp);
1504: }
1505: return (0);
1.1 cgd 1506: nfsmout:
1.23 fvdl 1507: if (dirp)
1508: vrele(dirp);
1509: if (nd.ni_cnd.cn_nameiop) {
1.1 cgd 1510: vrele(nd.ni_startdir);
1.23 fvdl 1511: free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1512: }
1.15 mycroft 1513: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 1514: if (nd.ni_dvp == nd.ni_vp)
1515: vrele(nd.ni_dvp);
1516: else
1517: vput(nd.ni_dvp);
1518: if (nd.ni_vp)
1519: vput(nd.ni_vp);
1520: return (error);
1.23 fvdl 1521: }
1522:
1523: /*
1524: * nfs v3 mknod service
1525: */
1526: int
1527: nfsrv_mknod(nfsd, slp, procp, mrq)
1528: struct nfsrv_descript *nfsd;
1529: struct nfssvc_sock *slp;
1530: struct proc *procp;
1531: struct mbuf **mrq;
1532: {
1533: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1534: struct mbuf *nam = nfsd->nd_nam;
1535: caddr_t dpos = nfsd->nd_dpos;
1536: struct ucred *cred = &nfsd->nd_cr;
1537: struct vattr va, dirfor, diraft;
1538: register u_int32_t *tl;
1539: struct nameidata nd;
1540: register int32_t t1;
1541: caddr_t bpos;
1542: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1543: u_int32_t major, minor;
1544: enum vtype vtyp;
1545: char *cp2;
1546: struct mbuf *mb, *mb2, *mreq;
1547: struct vnode *vp, *dirp = (struct vnode *)0;
1548: nfsfh_t nfh;
1549: fhandle_t *fhp;
1550: u_quad_t frev;
1551:
1552: nd.ni_cnd.cn_nameiop = 0;
1553: fhp = &nfh.fh_generic;
1554: nfsm_srvmtofh(fhp);
1555: nfsm_srvnamesiz(len);
1556: nd.ni_cnd.cn_cred = cred;
1557: nd.ni_cnd.cn_nameiop = CREATE;
1558: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1559: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 1560: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 1561: if (dirp)
1562: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1563: if (error) {
1564: nfsm_reply(NFSX_WCCDATA(1));
1565: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1566: if (dirp)
1567: vrele(dirp);
1568: return (0);
1569: }
1570: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
1571: vtyp = nfsv3tov_type(*tl);
1572: if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1573: vrele(nd.ni_startdir);
1574: free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1575: error = NFSERR_BADTYPE;
1576: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1577: vput(nd.ni_dvp);
1578: goto out;
1579: }
1580: VATTR_NULL(&va);
1581: nfsm_srvsattr(&va);
1582: if (vtyp == VCHR || vtyp == VBLK) {
1583: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1584: major = fxdr_unsigned(u_int32_t, *tl++);
1585: minor = fxdr_unsigned(u_int32_t, *tl);
1586: va.va_rdev = makedev(major, minor);
1587: }
1.1 cgd 1588:
1.23 fvdl 1589: /*
1590: * Iff doesn't exist, create it.
1591: */
1592: if (nd.ni_vp) {
1593: vrele(nd.ni_startdir);
1594: free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1595: error = EEXIST;
1596: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1597: vput(nd.ni_dvp);
1598: goto out;
1599: }
1600: va.va_type = vtyp;
1601: if (vtyp == VSOCK) {
1602: vrele(nd.ni_startdir);
1603: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1604: error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1605: if (!error)
1606: FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1607: } else {
1608: error = suser(cred, (u_short *)0);
1609: if (error) {
1610: vrele(nd.ni_startdir);
1611: free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1612: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1613: vput(nd.ni_dvp);
1614: goto out;
1615: }
1616: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1617: error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1618: if (error) {
1619: vrele(nd.ni_startdir);
1620: goto out;
1621: }
1622: nd.ni_cnd.cn_nameiop = LOOKUP;
1623: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1624: nd.ni_cnd.cn_proc = procp;
1625: nd.ni_cnd.cn_cred = procp->p_ucred;
1626: error = lookup(&nd);
1627: FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1628: if (error)
1629: goto out;
1630: if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1631: vrele(nd.ni_dvp);
1632: vput(nd.ni_vp);
1633: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1634: error = EINVAL;
1635: }
1636: }
1.1 cgd 1637: out:
1.23 fvdl 1638: vp = nd.ni_vp;
1639: if (!error) {
1.44 perry 1640: memset((caddr_t)fhp, 0, sizeof(nfh));
1.23 fvdl 1641: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1642: error = VFS_VPTOFH(vp, &fhp->fh_fid);
1643: if (!error)
1644: error = VOP_GETATTR(vp, &va, cred, procp);
1645: vput(vp);
1646: }
1647: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1648: vrele(dirp);
1649: nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1650: if (!error) {
1651: nfsm_srvpostop_fh(fhp);
1652: nfsm_srvpostop_attr(0, &va);
1653: }
1654: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1655: return (0);
1656: nfsmout:
1657: if (dirp)
1658: vrele(dirp);
1659: if (nd.ni_cnd.cn_nameiop) {
1660: vrele(nd.ni_startdir);
1661: free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1662: }
1663: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1664: if (nd.ni_dvp == nd.ni_vp)
1665: vrele(nd.ni_dvp);
1666: else
1667: vput(nd.ni_dvp);
1668: if (nd.ni_vp)
1669: vput(nd.ni_vp);
1670: return (error);
1.1 cgd 1671: }
1672:
1673: /*
1674: * nfs remove service
1675: */
1.22 christos 1676: int
1.23 fvdl 1677: nfsrv_remove(nfsd, slp, procp, mrq)
1678: struct nfsrv_descript *nfsd;
1679: struct nfssvc_sock *slp;
1680: struct proc *procp;
1681: struct mbuf **mrq;
1.1 cgd 1682: {
1.23 fvdl 1683: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1684: struct mbuf *nam = nfsd->nd_nam;
1685: caddr_t dpos = nfsd->nd_dpos;
1686: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 1687: struct nameidata nd;
1.19 cgd 1688: register u_int32_t *tl;
1689: register int32_t t1;
1.1 cgd 1690: caddr_t bpos;
1.23 fvdl 1691: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1692: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 1693: char *cp2;
1694: struct mbuf *mb, *mreq;
1.23 fvdl 1695: struct vnode *vp, *dirp;
1696: struct vattr dirfor, diraft;
1697: nfsfh_t nfh;
1.1 cgd 1698: fhandle_t *fhp;
1.15 mycroft 1699: u_quad_t frev;
1.1 cgd 1700:
1.23 fvdl 1701: #ifndef nolint
1702: vp = (struct vnode *)0;
1703: #endif
1.1 cgd 1704: fhp = &nfh.fh_generic;
1705: nfsm_srvmtofh(fhp);
1.23 fvdl 1706: nfsm_srvnamesiz(len);
1.15 mycroft 1707: nd.ni_cnd.cn_cred = cred;
1708: nd.ni_cnd.cn_nameiop = DELETE;
1709: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1.23 fvdl 1710: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 1711: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 1712: if (dirp) {
1713: if (v3)
1714: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1715: procp);
1.1 cgd 1716: else
1.23 fvdl 1717: vrele(dirp);
1.1 cgd 1718: }
1.23 fvdl 1719: if (!error) {
1720: vp = nd.ni_vp;
1721: if (vp->v_type == VDIR &&
1722: (error = suser(cred, (u_short *)0)) != 0)
1723: goto out;
1724: /*
1725: * The root of a mounted filesystem cannot be deleted.
1726: */
1727: if (vp->v_flag & VROOT) {
1728: error = EBUSY;
1729: goto out;
1730: }
1.21 mycroft 1731: out:
1.23 fvdl 1732: if (!error) {
1.40 mrg 1733: #if defined(UVM)
1734: (void)uvm_vnp_uncache(vp);
1735: #else
1.30 fvdl 1736: (void)vnode_pager_uncache(vp);
1.40 mrg 1737: #endif
1.23 fvdl 1738: nqsrv_getl(nd.ni_dvp, ND_WRITE);
1739: nqsrv_getl(vp, ND_WRITE);
1740: error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1741: } else {
1742: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1743: if (nd.ni_dvp == vp)
1744: vrele(nd.ni_dvp);
1745: else
1746: vput(nd.ni_dvp);
1747: vput(vp);
1748: }
1749: }
1750: if (dirp && v3) {
1751: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1752: vrele(dirp);
1753: }
1754: nfsm_reply(NFSX_WCCDATA(v3));
1755: if (v3) {
1756: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1757: return (0);
1758: }
1.1 cgd 1759: nfsm_srvdone;
1760: }
1761:
1762: /*
1763: * nfs rename service
1764: */
1.22 christos 1765: int
1.23 fvdl 1766: nfsrv_rename(nfsd, slp, procp, mrq)
1767: struct nfsrv_descript *nfsd;
1768: struct nfssvc_sock *slp;
1769: struct proc *procp;
1770: struct mbuf **mrq;
1.1 cgd 1771: {
1.23 fvdl 1772: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1773: struct mbuf *nam = nfsd->nd_nam;
1774: caddr_t dpos = nfsd->nd_dpos;
1775: struct ucred *cred = &nfsd->nd_cr;
1.19 cgd 1776: register u_int32_t *tl;
1777: register int32_t t1;
1.1 cgd 1778: caddr_t bpos;
1.23 fvdl 1779: int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1780: int tdirfor_ret = 1, tdiraft_ret = 1;
1781: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 1782: char *cp2;
1783: struct mbuf *mb, *mreq;
1784: struct nameidata fromnd, tond;
1.23 fvdl 1785: struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
1786: struct vnode *tdirp = (struct vnode *)0;
1787: struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1788: nfsfh_t fnfh, tnfh;
1.1 cgd 1789: fhandle_t *ffhp, *tfhp;
1.15 mycroft 1790: u_quad_t frev;
1791: uid_t saved_uid;
1.1 cgd 1792:
1.23 fvdl 1793: #ifndef nolint
1794: fvp = (struct vnode *)0;
1795: #endif
1.1 cgd 1796: ffhp = &fnfh.fh_generic;
1797: tfhp = &tnfh.fh_generic;
1.15 mycroft 1798: fromnd.ni_cnd.cn_nameiop = 0;
1799: tond.ni_cnd.cn_nameiop = 0;
1.1 cgd 1800: nfsm_srvmtofh(ffhp);
1.23 fvdl 1801: nfsm_srvnamesiz(len);
1.1 cgd 1802: /*
1.15 mycroft 1803: * Remember our original uid so that we can reset cr_uid before
1804: * the second nfs_namei() call, in case it is remapped.
1.1 cgd 1805: */
1.15 mycroft 1806: saved_uid = cred->cr_uid;
1807: fromnd.ni_cnd.cn_cred = cred;
1808: fromnd.ni_cnd.cn_nameiop = DELETE;
1809: fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1.23 fvdl 1810: error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1.35 fvdl 1811: &dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 1812: if (fdirp) {
1813: if (v3)
1814: fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1815: procp);
1816: else {
1817: vrele(fdirp);
1818: fdirp = (struct vnode *)0;
1819: }
1820: }
1821: if (error) {
1822: nfsm_reply(2 * NFSX_WCCDATA(v3));
1823: nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1824: nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1825: if (fdirp)
1826: vrele(fdirp);
1827: return (0);
1828: }
1.1 cgd 1829: fvp = fromnd.ni_vp;
1830: nfsm_srvmtofh(tfhp);
1831: nfsm_strsiz(len2, NFS_MAXNAMLEN);
1.15 mycroft 1832: cred->cr_uid = saved_uid;
1833: tond.ni_cnd.cn_cred = cred;
1834: tond.ni_cnd.cn_nameiop = RENAME;
1835: tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1.23 fvdl 1836: error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1.35 fvdl 1837: &dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 1838: if (tdirp) {
1839: if (v3)
1840: tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1841: procp);
1842: else {
1843: vrele(tdirp);
1844: tdirp = (struct vnode *)0;
1845: }
1846: }
1.22 christos 1847: if (error) {
1.15 mycroft 1848: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1.1 cgd 1849: vrele(fromnd.ni_dvp);
1850: vrele(fvp);
1851: goto out1;
1852: }
1853: tdvp = tond.ni_dvp;
1854: tvp = tond.ni_vp;
1855: if (tvp != NULL) {
1856: if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1.23 fvdl 1857: if (v3)
1858: error = EEXIST;
1859: else
1860: error = EISDIR;
1.1 cgd 1861: goto out;
1862: } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1.23 fvdl 1863: if (v3)
1864: error = EEXIST;
1865: else
1866: error = ENOTDIR;
1.1 cgd 1867: goto out;
1868: }
1.15 mycroft 1869: if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1.23 fvdl 1870: if (v3)
1871: error = EXDEV;
1872: else
1873: error = ENOTEMPTY;
1.15 mycroft 1874: goto out;
1875: }
1876: }
1877: if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1.23 fvdl 1878: if (v3)
1879: error = EXDEV;
1880: else
1881: error = ENOTEMPTY;
1.15 mycroft 1882: goto out;
1.1 cgd 1883: }
1884: if (fvp->v_mount != tdvp->v_mount) {
1.23 fvdl 1885: if (v3)
1886: error = EXDEV;
1887: else
1888: error = ENOTEMPTY;
1.1 cgd 1889: goto out;
1890: }
1.45 ! thorpej 1891: if (fvp == tdvp) {
1.23 fvdl 1892: if (v3)
1893: error = EINVAL;
1894: else
1895: error = ENOTEMPTY;
1.45 ! thorpej 1896: }
1.1 cgd 1897: /*
1898: * If source is the same as the destination (that is the
1899: * same vnode with the same name in the same directory),
1900: * then there is nothing to do.
1901: */
1902: if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1.15 mycroft 1903: fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1.44 perry 1904: !memcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1.15 mycroft 1905: fromnd.ni_cnd.cn_namelen))
1.1 cgd 1906: error = -1;
1907: out:
1908: if (!error) {
1.23 fvdl 1909: nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
1910: nqsrv_getl(tdvp, ND_WRITE);
1.30 fvdl 1911: if (tvp) {
1.40 mrg 1912: #if defined(UVM)
1913: (void)uvm_vnp_uncache(tvp);
1914: #else
1.30 fvdl 1915: (void)vnode_pager_uncache(tvp);
1.40 mrg 1916: #endif
1.23 fvdl 1917: nqsrv_getl(tvp, ND_WRITE);
1.30 fvdl 1918: }
1.15 mycroft 1919: error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1920: tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1.1 cgd 1921: } else {
1.15 mycroft 1922: VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1.1 cgd 1923: if (tdvp == tvp)
1924: vrele(tdvp);
1925: else
1926: vput(tdvp);
1927: if (tvp)
1928: vput(tvp);
1.15 mycroft 1929: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1.1 cgd 1930: vrele(fromnd.ni_dvp);
1931: vrele(fvp);
1.23 fvdl 1932: if (error == -1)
1933: error = 0;
1.1 cgd 1934: }
1935: vrele(tond.ni_startdir);
1.15 mycroft 1936: FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1.1 cgd 1937: out1:
1.23 fvdl 1938: if (fdirp) {
1939: fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1940: vrele(fdirp);
1941: }
1942: if (tdirp) {
1943: tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1944: vrele(tdirp);
1945: }
1.1 cgd 1946: vrele(fromnd.ni_startdir);
1.15 mycroft 1947: FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1.23 fvdl 1948: nfsm_reply(2 * NFSX_WCCDATA(v3));
1949: if (v3) {
1950: nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1951: nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1952: }
1953: return (0);
1.1 cgd 1954:
1955: nfsmout:
1.23 fvdl 1956: if (fdirp)
1957: vrele(fdirp);
1958: if (tdirp)
1959: vrele(tdirp);
1960: if (tond.ni_cnd.cn_nameiop) {
1.1 cgd 1961: vrele(tond.ni_startdir);
1.15 mycroft 1962: FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
1.1 cgd 1963: }
1.23 fvdl 1964: if (fromnd.ni_cnd.cn_nameiop) {
1.1 cgd 1965: vrele(fromnd.ni_startdir);
1.15 mycroft 1966: FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1967: VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1.1 cgd 1968: vrele(fromnd.ni_dvp);
1969: vrele(fvp);
1970: }
1971: return (error);
1972: }
1973:
1974: /*
1975: * nfs link service
1976: */
1.22 christos 1977: int
1.23 fvdl 1978: nfsrv_link(nfsd, slp, procp, mrq)
1979: struct nfsrv_descript *nfsd;
1980: struct nfssvc_sock *slp;
1981: struct proc *procp;
1982: struct mbuf **mrq;
1.1 cgd 1983: {
1.23 fvdl 1984: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1985: struct mbuf *nam = nfsd->nd_nam;
1986: caddr_t dpos = nfsd->nd_dpos;
1987: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 1988: struct nameidata nd;
1.19 cgd 1989: register u_int32_t *tl;
1990: register int32_t t1;
1.1 cgd 1991: caddr_t bpos;
1.23 fvdl 1992: int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
1993: int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 1994: char *cp2;
1995: struct mbuf *mb, *mreq;
1.23 fvdl 1996: struct vnode *vp, *xp, *dirp = (struct vnode *)0;
1997: struct vattr dirfor, diraft, at;
1998: nfsfh_t nfh, dnfh;
1.1 cgd 1999: fhandle_t *fhp, *dfhp;
1.15 mycroft 2000: u_quad_t frev;
1.1 cgd 2001:
2002: fhp = &nfh.fh_generic;
2003: dfhp = &dnfh.fh_generic;
2004: nfsm_srvmtofh(fhp);
2005: nfsm_srvmtofh(dfhp);
1.23 fvdl 2006: nfsm_srvnamesiz(len);
2007: error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
1.35 fvdl 2008: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 2009: if (error) {
2010: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2011: nfsm_srvpostop_attr(getret, &at);
2012: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2013: return (0);
2014: }
2015: if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)) != 0)
2016: goto out1;
1.15 mycroft 2017: nd.ni_cnd.cn_cred = cred;
2018: nd.ni_cnd.cn_nameiop = CREATE;
2019: nd.ni_cnd.cn_flags = LOCKPARENT;
1.23 fvdl 2020: error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
1.35 fvdl 2021: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 2022: if (dirp) {
2023: if (v3)
2024: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2025: procp);
2026: else {
2027: vrele(dirp);
2028: dirp = (struct vnode *)0;
2029: }
2030: }
1.22 christos 2031: if (error)
1.23 fvdl 2032: goto out1;
2033: xp = nd.ni_vp;
2034: if (xp != NULL) {
2035: error = EEXIST;
1.1 cgd 2036: goto out;
1.23 fvdl 2037: }
2038: xp = nd.ni_dvp;
2039: if (vp->v_mount != xp->v_mount)
2040: error = EXDEV;
2041: out:
2042: if (!error) {
2043: nqsrv_getl(vp, ND_WRITE);
2044: nqsrv_getl(xp, ND_WRITE);
2045: error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
2046: } else {
1.15 mycroft 2047: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 2048: if (nd.ni_dvp == nd.ni_vp)
2049: vrele(nd.ni_dvp);
2050: else
2051: vput(nd.ni_dvp);
1.23 fvdl 2052: if (nd.ni_vp)
2053: vrele(nd.ni_vp);
2054: }
2055: out1:
2056: if (v3)
2057: getret = VOP_GETATTR(vp, &at, cred, procp);
2058: if (dirp) {
2059: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2060: vrele(dirp);
1.1 cgd 2061: }
2062: vrele(vp);
1.23 fvdl 2063: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2064: if (v3) {
2065: nfsm_srvpostop_attr(getret, &at);
2066: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2067: return (0);
2068: }
1.1 cgd 2069: nfsm_srvdone;
2070: }
2071:
2072: /*
2073: * nfs symbolic link service
2074: */
1.22 christos 2075: int
1.23 fvdl 2076: nfsrv_symlink(nfsd, slp, procp, mrq)
2077: struct nfsrv_descript *nfsd;
2078: struct nfssvc_sock *slp;
2079: struct proc *procp;
2080: struct mbuf **mrq;
1.1 cgd 2081: {
1.23 fvdl 2082: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2083: struct mbuf *nam = nfsd->nd_nam;
2084: caddr_t dpos = nfsd->nd_dpos;
2085: struct ucred *cred = &nfsd->nd_cr;
2086: struct vattr va, dirfor, diraft;
1.1 cgd 2087: struct nameidata nd;
1.19 cgd 2088: register u_int32_t *tl;
2089: register int32_t t1;
1.1 cgd 2090: struct nfsv2_sattr *sp;
1.23 fvdl 2091: char *bpos, *pathcp = NULL, *cp2;
1.1 cgd 2092: struct uio io;
2093: struct iovec iv;
1.23 fvdl 2094: int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2095: int v3 = (nfsd->nd_flag & ND_NFSV3);
2096: struct mbuf *mb, *mreq, *mb2;
2097: struct vnode *dirp = (struct vnode *)0;
2098: nfsfh_t nfh;
1.1 cgd 2099: fhandle_t *fhp;
1.15 mycroft 2100: u_quad_t frev;
1.1 cgd 2101:
1.23 fvdl 2102: nd.ni_cnd.cn_nameiop = 0;
1.1 cgd 2103: fhp = &nfh.fh_generic;
2104: nfsm_srvmtofh(fhp);
1.23 fvdl 2105: nfsm_srvnamesiz(len);
1.15 mycroft 2106: nd.ni_cnd.cn_cred = cred;
2107: nd.ni_cnd.cn_nameiop = CREATE;
1.23 fvdl 2108: nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2109: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 2110: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 2111: if (dirp) {
2112: if (v3)
2113: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2114: procp);
2115: else {
2116: vrele(dirp);
2117: dirp = (struct vnode *)0;
2118: }
2119: }
1.22 christos 2120: if (error)
1.1 cgd 2121: goto out;
1.23 fvdl 2122: VATTR_NULL(&va);
2123: if (v3)
2124: nfsm_srvsattr(&va);
1.1 cgd 2125: nfsm_strsiz(len2, NFS_MAXPATHLEN);
2126: MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
2127: iv.iov_base = pathcp;
2128: iv.iov_len = len2;
2129: io.uio_resid = len2;
2130: io.uio_offset = 0;
2131: io.uio_iov = &iv;
2132: io.uio_iovcnt = 1;
2133: io.uio_segflg = UIO_SYSSPACE;
2134: io.uio_rw = UIO_READ;
2135: io.uio_procp = (struct proc *)0;
2136: nfsm_mtouio(&io, len2);
1.23 fvdl 2137: if (!v3) {
2138: nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2139: va.va_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
2140: }
1.1 cgd 2141: *(pathcp + len2) = '\0';
2142: if (nd.ni_vp) {
1.23 fvdl 2143: vrele(nd.ni_startdir);
2144: free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1.15 mycroft 2145: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 2146: if (nd.ni_dvp == nd.ni_vp)
2147: vrele(nd.ni_dvp);
2148: else
2149: vput(nd.ni_dvp);
2150: vrele(nd.ni_vp);
2151: error = EEXIST;
2152: goto out;
2153: }
1.23 fvdl 2154: nqsrv_getl(nd.ni_dvp, ND_WRITE);
2155: error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
2156: if (error)
2157: vrele(nd.ni_startdir);
2158: else {
2159: if (v3) {
2160: nd.ni_cnd.cn_nameiop = LOOKUP;
2161: nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
2162: nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2163: nd.ni_cnd.cn_proc = procp;
2164: nd.ni_cnd.cn_cred = cred;
2165: error = lookup(&nd);
2166: if (!error) {
1.44 perry 2167: memset((caddr_t)fhp, 0, sizeof(nfh));
1.23 fvdl 2168: fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2169: error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2170: if (!error)
2171: error = VOP_GETATTR(nd.ni_vp, &va, cred,
2172: procp);
2173: vput(nd.ni_vp);
2174: }
2175: } else
2176: vrele(nd.ni_startdir);
2177: FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2178: }
1.1 cgd 2179: out:
2180: if (pathcp)
2181: FREE(pathcp, M_TEMP);
1.23 fvdl 2182: if (dirp) {
2183: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2184: vrele(dirp);
2185: }
2186: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2187: if (v3) {
2188: if (!error) {
2189: nfsm_srvpostop_fh(fhp);
2190: nfsm_srvpostop_attr(0, &va);
2191: }
2192: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2193: }
2194: return (0);
1.1 cgd 2195: nfsmout:
1.23 fvdl 2196: if (nd.ni_cnd.cn_nameiop) {
2197: vrele(nd.ni_startdir);
2198: free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2199: }
2200: if (dirp)
2201: vrele(dirp);
1.15 mycroft 2202: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 2203: if (nd.ni_dvp == nd.ni_vp)
2204: vrele(nd.ni_dvp);
2205: else
2206: vput(nd.ni_dvp);
2207: if (nd.ni_vp)
2208: vrele(nd.ni_vp);
2209: if (pathcp)
2210: FREE(pathcp, M_TEMP);
2211: return (error);
2212: }
2213:
2214: /*
2215: * nfs mkdir service
2216: */
1.22 christos 2217: int
1.23 fvdl 2218: nfsrv_mkdir(nfsd, slp, procp, mrq)
2219: struct nfsrv_descript *nfsd;
2220: struct nfssvc_sock *slp;
2221: struct proc *procp;
2222: struct mbuf **mrq;
1.1 cgd 2223: {
1.23 fvdl 2224: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2225: struct mbuf *nam = nfsd->nd_nam;
2226: caddr_t dpos = nfsd->nd_dpos;
2227: struct ucred *cred = &nfsd->nd_cr;
2228: struct vattr va, dirfor, diraft;
2229: register struct nfs_fattr *fp;
1.1 cgd 2230: struct nameidata nd;
2231: register caddr_t cp;
1.19 cgd 2232: register u_int32_t *tl;
2233: register int32_t t1;
1.1 cgd 2234: caddr_t bpos;
1.23 fvdl 2235: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2236: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 2237: char *cp2;
2238: struct mbuf *mb, *mb2, *mreq;
1.23 fvdl 2239: struct vnode *vp, *dirp = (struct vnode *)0;
2240: nfsfh_t nfh;
1.1 cgd 2241: fhandle_t *fhp;
1.15 mycroft 2242: u_quad_t frev;
1.1 cgd 2243:
2244: fhp = &nfh.fh_generic;
2245: nfsm_srvmtofh(fhp);
1.23 fvdl 2246: nfsm_srvnamesiz(len);
1.15 mycroft 2247: nd.ni_cnd.cn_cred = cred;
2248: nd.ni_cnd.cn_nameiop = CREATE;
2249: nd.ni_cnd.cn_flags = LOCKPARENT;
1.23 fvdl 2250: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 2251: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 2252: if (dirp) {
2253: if (v3)
2254: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2255: procp);
2256: else {
2257: vrele(dirp);
2258: dirp = (struct vnode *)0;
2259: }
2260: }
2261: if (error) {
2262: nfsm_reply(NFSX_WCCDATA(v3));
2263: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2264: if (dirp)
2265: vrele(dirp);
2266: return (0);
2267: }
1.18 mycroft 2268: VATTR_NULL(&va);
1.23 fvdl 2269: if (v3) {
2270: nfsm_srvsattr(&va);
2271: } else {
2272: nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
2273: va.va_mode = nfstov_mode(*tl++);
2274: }
1.18 mycroft 2275: va.va_type = VDIR;
1.1 cgd 2276: vp = nd.ni_vp;
2277: if (vp != NULL) {
1.15 mycroft 2278: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 2279: if (nd.ni_dvp == vp)
2280: vrele(nd.ni_dvp);
2281: else
2282: vput(nd.ni_dvp);
2283: vrele(vp);
2284: error = EEXIST;
1.23 fvdl 2285: goto out;
1.1 cgd 2286: }
1.23 fvdl 2287: nqsrv_getl(nd.ni_dvp, ND_WRITE);
2288: error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
2289: if (!error) {
2290: vp = nd.ni_vp;
1.44 perry 2291: memset((caddr_t)fhp, 0, sizeof(nfh));
1.23 fvdl 2292: fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2293: error = VFS_VPTOFH(vp, &fhp->fh_fid);
2294: if (!error)
2295: error = VOP_GETATTR(vp, &va, cred, procp);
1.1 cgd 2296: vput(vp);
2297: }
1.23 fvdl 2298: out:
2299: if (dirp) {
2300: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2301: vrele(dirp);
2302: }
2303: nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2304: if (v3) {
2305: if (!error) {
2306: nfsm_srvpostop_fh(fhp);
2307: nfsm_srvpostop_attr(0, &va);
2308: }
2309: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2310: } else {
2311: nfsm_srvfhtom(fhp, v3);
2312: nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2313: nfsm_srvfillattr(&va, fp);
2314: }
2315: return (0);
1.1 cgd 2316: nfsmout:
1.23 fvdl 2317: if (dirp)
2318: vrele(dirp);
1.15 mycroft 2319: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 2320: if (nd.ni_dvp == nd.ni_vp)
2321: vrele(nd.ni_dvp);
2322: else
2323: vput(nd.ni_dvp);
2324: if (nd.ni_vp)
2325: vrele(nd.ni_vp);
2326: return (error);
2327: }
2328:
2329: /*
2330: * nfs rmdir service
2331: */
1.22 christos 2332: int
1.23 fvdl 2333: nfsrv_rmdir(nfsd, slp, procp, mrq)
2334: struct nfsrv_descript *nfsd;
2335: struct nfssvc_sock *slp;
2336: struct proc *procp;
2337: struct mbuf **mrq;
1.1 cgd 2338: {
1.23 fvdl 2339: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2340: struct mbuf *nam = nfsd->nd_nam;
2341: caddr_t dpos = nfsd->nd_dpos;
2342: struct ucred *cred = &nfsd->nd_cr;
1.19 cgd 2343: register u_int32_t *tl;
2344: register int32_t t1;
1.1 cgd 2345: caddr_t bpos;
1.23 fvdl 2346: int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2347: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 2348: char *cp2;
2349: struct mbuf *mb, *mreq;
1.23 fvdl 2350: struct vnode *vp, *dirp = (struct vnode *)0;
2351: struct vattr dirfor, diraft;
2352: nfsfh_t nfh;
1.1 cgd 2353: fhandle_t *fhp;
2354: struct nameidata nd;
1.15 mycroft 2355: u_quad_t frev;
1.1 cgd 2356:
2357: fhp = &nfh.fh_generic;
2358: nfsm_srvmtofh(fhp);
1.23 fvdl 2359: nfsm_srvnamesiz(len);
1.15 mycroft 2360: nd.ni_cnd.cn_cred = cred;
2361: nd.ni_cnd.cn_nameiop = DELETE;
2362: nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1.23 fvdl 2363: error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1.35 fvdl 2364: &dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 2365: if (dirp) {
2366: if (v3)
2367: dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2368: procp);
2369: else {
2370: vrele(dirp);
2371: dirp = (struct vnode *)0;
2372: }
2373: }
2374: if (error) {
2375: nfsm_reply(NFSX_WCCDATA(v3));
2376: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2377: if (dirp)
2378: vrele(dirp);
2379: return (0);
2380: }
1.1 cgd 2381: vp = nd.ni_vp;
2382: if (vp->v_type != VDIR) {
2383: error = ENOTDIR;
2384: goto out;
2385: }
2386: /*
2387: * No rmdir "." please.
2388: */
2389: if (nd.ni_dvp == vp) {
2390: error = EINVAL;
2391: goto out;
2392: }
2393: /*
2394: * The root of a mounted filesystem cannot be deleted.
2395: */
2396: if (vp->v_flag & VROOT)
2397: error = EBUSY;
2398: out:
2399: if (!error) {
1.23 fvdl 2400: nqsrv_getl(nd.ni_dvp, ND_WRITE);
2401: nqsrv_getl(vp, ND_WRITE);
1.15 mycroft 2402: error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1.1 cgd 2403: } else {
1.15 mycroft 2404: VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1.1 cgd 2405: if (nd.ni_dvp == nd.ni_vp)
2406: vrele(nd.ni_dvp);
2407: else
2408: vput(nd.ni_dvp);
2409: vput(vp);
2410: }
1.23 fvdl 2411: if (dirp) {
2412: diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2413: vrele(dirp);
2414: }
2415: nfsm_reply(NFSX_WCCDATA(v3));
2416: if (v3) {
2417: nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2418: return (0);
2419: }
1.1 cgd 2420: nfsm_srvdone;
2421: }
2422:
2423: /*
2424: * nfs readdir service
2425: * - mallocs what it thinks is enough to read
2426: * count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2427: * - calls VOP_READDIR()
2428: * - loops around building the reply
2429: * if the output generated exceeds count break out of loop
2430: * The nfsm_clget macro is used here so that the reply will be packed
2431: * tightly in mbuf clusters.
2432: * - it only knows that it has encountered eof when the VOP_READDIR()
2433: * reads nothing
2434: * - as such one readdir rpc will return eof false although you are there
2435: * and then the next will return eof
1.11 ws 2436: * - it trims out records with d_fileno == 0
1.1 cgd 2437: * this doesn't matter for Unix clients, but they might confuse clients
2438: * for other os'.
1.25 jtk 2439: * - it trims out records with d_type == DT_WHT
2440: * these cannot be seen through NFS (unless we extend the protocol)
1.1 cgd 2441: * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2442: * than requested, but this may not apply to all filesystems. For
2443: * example, client NFS does not { although it is never remote mounted
2444: * anyhow }
1.23 fvdl 2445: * The alternate call nfsrv_readdirplus() does lookups as well.
1.1 cgd 2446: * PS: The NFS protocol spec. does not clarify what the "count" byte
2447: * argument is a count of.. just name strings and file id's or the
2448: * entire reply rpc or ...
2449: * I tried just file name and id sizes and it confused the Sun client,
2450: * so I am using the full rpc size now. The "paranoia.." comment refers
2451: * to including the status longwords that are not a part of the dir.
2452: * "entry" structures, but are in the rpc.
2453: */
1.15 mycroft 2454: struct flrep {
1.23 fvdl 2455: nfsuint64 fl_off;
2456: u_int32_t fl_postopok;
2457: u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2458: u_int32_t fl_fhok;
2459: u_int32_t fl_fhsize;
2460: u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
1.15 mycroft 2461: };
2462:
1.22 christos 2463: int
1.23 fvdl 2464: nfsrv_readdir(nfsd, slp, procp, mrq)
2465: struct nfsrv_descript *nfsd;
2466: struct nfssvc_sock *slp;
2467: struct proc *procp;
2468: struct mbuf **mrq;
1.1 cgd 2469: {
1.23 fvdl 2470: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2471: struct mbuf *nam = nfsd->nd_nam;
2472: caddr_t dpos = nfsd->nd_dpos;
2473: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 2474: register char *bp, *be;
2475: register struct mbuf *mp;
1.23 fvdl 2476: register struct dirent *dp;
1.1 cgd 2477: register caddr_t cp;
1.19 cgd 2478: register u_int32_t *tl;
2479: register int32_t t1;
1.1 cgd 2480: caddr_t bpos;
1.15 mycroft 2481: struct mbuf *mb, *mb2, *mreq, *mp2;
2482: char *cpos, *cend, *cp2, *rbuf;
1.1 cgd 2483: struct vnode *vp;
1.23 fvdl 2484: struct vattr at;
2485: nfsfh_t nfh;
1.1 cgd 2486: fhandle_t *fhp;
2487: struct uio io;
2488: struct iovec iv;
1.23 fvdl 2489: int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2490: int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2491: int v3 = (nfsd->nd_flag & ND_NFSV3);
2492: u_quad_t frev, off, toff, verf;
1.38 fvdl 2493: off_t *cookies = NULL, *cookiep;
2494: nfsuint64 jar;
1.15 mycroft 2495:
1.1 cgd 2496: fhp = &nfh.fh_generic;
2497: nfsm_srvmtofh(fhp);
1.23 fvdl 2498: if (v3) {
2499: nfsm_dissect(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2500: fxdr_hyper(tl, &toff);
2501: tl += 2;
2502: fxdr_hyper(tl, &verf);
2503: tl += 2;
2504: } else {
2505: nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2506: toff = fxdr_unsigned(u_quad_t, *tl++);
2507: }
2508: off = toff;
1.1 cgd 2509: cnt = fxdr_unsigned(int, *tl);
1.23 fvdl 2510: siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2511: xfer = NFS_SRVMAXDATA(nfsd);
2512: if (siz > xfer)
2513: siz = xfer;
1.1 cgd 2514: fullsiz = siz;
1.23 fvdl 2515: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 2516: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.39 fvdl 2517: if (!error && vp->v_type != VDIR) {
2518: error = ENOTDIR;
2519: vput(vp);
2520: }
1.23 fvdl 2521: if (error) {
2522: nfsm_reply(NFSX_UNSIGNED);
2523: nfsm_srvpostop_attr(getret, &at);
2524: return (0);
2525: }
2526: nqsrv_getl(vp, ND_READ);
2527: if (v3) {
2528: error = getret = VOP_GETATTR(vp, &at, cred, procp);
2529: #ifdef NFS3_STRICTVERF
2530: /*
2531: * XXX This check is too strict for Solaris 2.5 clients.
2532: */
2533: if (!error && toff && verf != at.va_filerev)
2534: error = NFSERR_BAD_COOKIE;
2535: #endif
2536: }
2537: if (!error)
1.33 mycroft 2538: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
1.22 christos 2539: if (error) {
1.1 cgd 2540: vput(vp);
1.23 fvdl 2541: nfsm_reply(NFSX_POSTOPATTR(v3));
2542: nfsm_srvpostop_attr(getret, &at);
2543: return (0);
1.1 cgd 2544: }
1.42 fvdl 2545: VOP_UNLOCK(vp, 0);
1.1 cgd 2546: MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2547: again:
2548: iv.iov_base = rbuf;
2549: iv.iov_len = fullsiz;
2550: io.uio_iov = &iv;
2551: io.uio_iovcnt = 1;
1.15 mycroft 2552: io.uio_offset = (off_t)off;
1.1 cgd 2553: io.uio_resid = fullsiz;
2554: io.uio_segflg = UIO_SYSSPACE;
2555: io.uio_rw = UIO_READ;
2556: io.uio_procp = (struct proc *)0;
1.23 fvdl 2557: eofflag = 0;
1.42 fvdl 2558: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
1.23 fvdl 2559:
1.42 fvdl 2560: error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
1.23 fvdl 2561:
1.15 mycroft 2562: off = (off_t)io.uio_offset;
1.23 fvdl 2563: if (!cookies && !error)
2564: error = NFSERR_PERM;
2565: if (v3) {
2566: getret = VOP_GETATTR(vp, &at, cred, procp);
2567: if (!error)
2568: error = getret;
2569: }
2570:
1.42 fvdl 2571: VOP_UNLOCK(vp, 0);
1.1 cgd 2572: if (error) {
2573: vrele(vp);
1.42 fvdl 2574: FREE((caddr_t)rbuf, M_TEMP);
1.23 fvdl 2575: if (cookies)
2576: free((caddr_t)cookies, M_TEMP);
2577: nfsm_reply(NFSX_POSTOPATTR(v3));
2578: nfsm_srvpostop_attr(getret, &at);
2579: return (0);
1.1 cgd 2580: }
2581: if (io.uio_resid) {
2582: siz -= io.uio_resid;
2583:
2584: /*
2585: * If nothing read, return eof
2586: * rpc reply
2587: */
2588: if (siz == 0) {
2589: vrele(vp);
1.23 fvdl 2590: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2591: 2 * NFSX_UNSIGNED);
2592: if (v3) {
2593: nfsm_srvpostop_attr(getret, &at);
2594: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2595: txdr_hyper(&at.va_filerev, tl);
2596: tl += 2;
2597: } else
2598: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1.1 cgd 2599: *tl++ = nfs_false;
2600: *tl = nfs_true;
2601: FREE((caddr_t)rbuf, M_TEMP);
1.23 fvdl 2602: FREE((caddr_t)cookies, M_TEMP);
1.1 cgd 2603: return (0);
2604: }
2605: }
2606:
2607: /*
2608: * Check for degenerate cases of nothing useful read.
2609: * If so go try again
2610: */
1.8 ws 2611: cpos = rbuf;
1.1 cgd 2612: cend = rbuf + siz;
1.23 fvdl 2613: dp = (struct dirent *)cpos;
2614: cookiep = cookies;
2615:
1.28 fvdl 2616: while (cpos < cend && ncookies > 0 &&
2617: (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
1.23 fvdl 2618: cpos += dp->d_reclen;
1.11 ws 2619: dp = (struct dirent *)cpos;
1.23 fvdl 2620: cookiep++;
2621: ncookies--;
1.1 cgd 2622: }
1.23 fvdl 2623: if (cpos >= cend || ncookies == 0) {
2624: toff = off;
1.1 cgd 2625: siz = fullsiz;
2626: goto again;
2627: }
2628:
1.23 fvdl 2629: len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
2630: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2631: if (v3) {
2632: nfsm_srvpostop_attr(getret, &at);
2633: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2634: txdr_hyper(&at.va_filerev, tl);
2635: }
1.15 mycroft 2636: mp = mp2 = mb;
2637: bp = bpos;
2638: be = bp + M_TRAILINGSPACE(mp);
2639:
2640: /* Loop through the records and build reply */
1.23 fvdl 2641: while (cpos < cend && ncookies > 0) {
1.25 jtk 2642: if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
1.15 mycroft 2643: nlen = dp->d_namlen;
2644: rem = nfsm_rndup(nlen)-nlen;
1.23 fvdl 2645: len += (4 * NFSX_UNSIGNED + nlen + rem);
2646: if (v3)
2647: len += 2 * NFSX_UNSIGNED;
1.15 mycroft 2648: if (len > cnt) {
2649: eofflag = 0;
2650: break;
2651: }
2652: /*
2653: * Build the directory record xdr from
2654: * the dirent entry.
2655: */
2656: nfsm_clget;
2657: *tl = nfs_true;
2658: bp += NFSX_UNSIGNED;
1.23 fvdl 2659: if (v3) {
2660: nfsm_clget;
2661: *tl = 0;
2662: bp += NFSX_UNSIGNED;
2663: }
1.15 mycroft 2664: nfsm_clget;
2665: *tl = txdr_unsigned(dp->d_fileno);
2666: bp += NFSX_UNSIGNED;
2667: nfsm_clget;
2668: *tl = txdr_unsigned(nlen);
2669: bp += NFSX_UNSIGNED;
2670:
2671: /* And loop around copying the name */
2672: xfer = nlen;
2673: cp = dp->d_name;
2674: while (xfer > 0) {
2675: nfsm_clget;
2676: if ((bp+xfer) > be)
2677: tsiz = be-bp;
2678: else
2679: tsiz = xfer;
1.44 perry 2680: memcpy(bp, cp, tsiz);
1.15 mycroft 2681: bp += tsiz;
2682: xfer -= tsiz;
2683: if (xfer > 0)
2684: cp += tsiz;
2685: }
1.23 fvdl 2686: /* And null pad to an int32_t boundary */
1.15 mycroft 2687: for (i = 0; i < rem; i++)
2688: *bp++ = '\0';
2689: nfsm_clget;
2690:
2691: /* Finish off the record */
1.38 fvdl 2692: txdr_hyper(cookiep, &jar);
1.23 fvdl 2693: if (v3) {
1.38 fvdl 2694: *tl = jar.nfsuquad[0];
1.23 fvdl 2695: bp += NFSX_UNSIGNED;
2696: nfsm_clget;
2697: }
1.38 fvdl 2698: *tl = jar.nfsuquad[1];
1.15 mycroft 2699: bp += NFSX_UNSIGNED;
2700: }
2701: cpos += dp->d_reclen;
2702: dp = (struct dirent *)cpos;
1.23 fvdl 2703: cookiep++;
2704: ncookies--;
1.15 mycroft 2705: }
1.1 cgd 2706: vrele(vp);
1.15 mycroft 2707: nfsm_clget;
2708: *tl = nfs_false;
2709: bp += NFSX_UNSIGNED;
2710: nfsm_clget;
2711: if (eofflag)
2712: *tl = nfs_true;
2713: else
2714: *tl = nfs_false;
2715: bp += NFSX_UNSIGNED;
2716: if (mp != mb) {
2717: if (bp < be)
2718: mp->m_len = bp - mtod(mp, caddr_t);
2719: } else
2720: mp->m_len += bp - bpos;
1.23 fvdl 2721: FREE((caddr_t)rbuf, M_TEMP);
2722: FREE((caddr_t)cookies, M_TEMP);
1.15 mycroft 2723: nfsm_srvdone;
2724: }
2725:
1.22 christos 2726: int
1.23 fvdl 2727: nfsrv_readdirplus(nfsd, slp, procp, mrq)
2728: struct nfsrv_descript *nfsd;
2729: struct nfssvc_sock *slp;
2730: struct proc *procp;
2731: struct mbuf **mrq;
1.15 mycroft 2732: {
1.23 fvdl 2733: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2734: struct mbuf *nam = nfsd->nd_nam;
2735: caddr_t dpos = nfsd->nd_dpos;
2736: struct ucred *cred = &nfsd->nd_cr;
1.15 mycroft 2737: register char *bp, *be;
2738: register struct mbuf *mp;
1.23 fvdl 2739: register struct dirent *dp;
1.15 mycroft 2740: register caddr_t cp;
1.19 cgd 2741: register u_int32_t *tl;
2742: register int32_t t1;
1.15 mycroft 2743: caddr_t bpos;
2744: struct mbuf *mb, *mb2, *mreq, *mp2;
2745: char *cpos, *cend, *cp2, *rbuf;
2746: struct vnode *vp, *nvp;
2747: struct flrep fl;
1.23 fvdl 2748: nfsfh_t nfh;
2749: fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
1.15 mycroft 2750: struct uio io;
2751: struct iovec iv;
1.23 fvdl 2752: struct vattr va, at, *vap = &va;
2753: struct nfs_fattr *fp;
2754: int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2755: int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
2756: u_quad_t frev, off, toff, verf;
1.38 fvdl 2757: off_t *cookies = NULL, *cookiep;
1.15 mycroft 2758:
2759: fhp = &nfh.fh_generic;
2760: nfsm_srvmtofh(fhp);
1.23 fvdl 2761: nfsm_dissect(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2762: fxdr_hyper(tl, &toff);
2763: tl += 2;
2764: fxdr_hyper(tl, &verf);
2765: tl += 2;
2766: siz = fxdr_unsigned(int, *tl++);
2767: cnt = fxdr_unsigned(int, *tl);
2768: off = toff;
2769: siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2770: xfer = NFS_SRVMAXDATA(nfsd);
2771: if (siz > xfer)
2772: siz = xfer;
1.15 mycroft 2773: fullsiz = siz;
1.23 fvdl 2774: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 2775: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.39 fvdl 2776: if (!error && vp->v_type != VDIR) {
2777: error = ENOTDIR;
2778: vput(vp);
2779: }
1.23 fvdl 2780: if (error) {
2781: nfsm_reply(NFSX_UNSIGNED);
2782: nfsm_srvpostop_attr(getret, &at);
2783: return (0);
2784: }
2785: error = getret = VOP_GETATTR(vp, &at, cred, procp);
2786: #ifdef NFS3_STRICTVERF
2787: /*
2788: * XXX This check is too strict for Solaris 2.5 clients.
2789: */
2790: if (!error && toff && verf != at.va_filerev)
2791: error = NFSERR_BAD_COOKIE;
2792: #endif
2793: if (!error) {
2794: nqsrv_getl(vp, ND_READ);
1.33 mycroft 2795: error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
1.23 fvdl 2796: }
1.22 christos 2797: if (error) {
1.15 mycroft 2798: vput(vp);
1.23 fvdl 2799: nfsm_reply(NFSX_V3POSTOPATTR);
2800: nfsm_srvpostop_attr(getret, &at);
2801: return (0);
1.15 mycroft 2802: }
1.42 fvdl 2803: VOP_UNLOCK(vp, 0);
1.23 fvdl 2804:
1.15 mycroft 2805: MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
2806: again:
2807: iv.iov_base = rbuf;
2808: iv.iov_len = fullsiz;
2809: io.uio_iov = &iv;
2810: io.uio_iovcnt = 1;
2811: io.uio_offset = (off_t)off;
2812: io.uio_resid = fullsiz;
2813: io.uio_segflg = UIO_SYSSPACE;
2814: io.uio_rw = UIO_READ;
2815: io.uio_procp = (struct proc *)0;
1.23 fvdl 2816: eofflag = 0;
2817:
1.42 fvdl 2818: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2819:
2820: error = VOP_READDIR(vp, &io, cred, &eofflag, &cookies, &ncookies);
1.23 fvdl 2821:
2822: off = (u_quad_t)io.uio_offset;
2823: getret = VOP_GETATTR(vp, &at, cred, procp);
2824:
1.42 fvdl 2825: VOP_UNLOCK(vp, 0);
1.36 fvdl 2826:
2827: /*
2828: * If the VGET operation doesn't work for this filesystem,
2829: * we can't support readdirplus. Returning NOTSUPP should
2830: * make clients fall back to plain readdir.
2831: * There's no need to check for VPTOFH as well, we wouldn't
2832: * even be here otherwise.
2833: */
2834: if (!getret) {
2835: if ((getret = VFS_VGET(vp->v_mount, at.va_fileid, &nvp)))
2836: getret = (getret == EOPNOTSUPP) ?
2837: NFSERR_NOTSUPP : NFSERR_IO;
2838: else
2839: vput(nvp);
2840: }
2841:
1.23 fvdl 2842: if (!cookies && !error)
2843: error = NFSERR_PERM;
2844: if (!error)
2845: error = getret;
1.15 mycroft 2846: if (error) {
2847: vrele(vp);
1.23 fvdl 2848: if (cookies)
1.42 fvdl 2849: FREE((caddr_t)cookies, M_TEMP);
2850: FREE((caddr_t)rbuf, M_TEMP);
1.23 fvdl 2851: nfsm_reply(NFSX_V3POSTOPATTR);
2852: nfsm_srvpostop_attr(getret, &at);
2853: return (0);
1.15 mycroft 2854: }
2855: if (io.uio_resid) {
2856: siz -= io.uio_resid;
2857:
2858: /*
2859: * If nothing read, return eof
2860: * rpc reply
2861: */
2862: if (siz == 0) {
2863: vrele(vp);
1.23 fvdl 2864: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2865: 2 * NFSX_UNSIGNED);
2866: nfsm_srvpostop_attr(getret, &at);
2867: nfsm_build(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
2868: txdr_hyper(&at.va_filerev, tl);
2869: tl += 2;
1.15 mycroft 2870: *tl++ = nfs_false;
2871: *tl = nfs_true;
1.23 fvdl 2872: FREE((caddr_t)cookies, M_TEMP);
1.15 mycroft 2873: FREE((caddr_t)rbuf, M_TEMP);
2874: return (0);
2875: }
2876: }
2877:
2878: /*
2879: * Check for degenerate cases of nothing useful read.
2880: * If so go try again
2881: */
2882: cpos = rbuf;
2883: cend = rbuf + siz;
1.23 fvdl 2884: dp = (struct dirent *)cpos;
2885: cookiep = cookies;
2886:
1.29 fvdl 2887: while (cpos < cend && ncookies > 0 &&
2888: (dp->d_fileno == 0 || dp->d_type == DT_WHT)) {
1.23 fvdl 2889: cpos += dp->d_reclen;
1.15 mycroft 2890: dp = (struct dirent *)cpos;
1.23 fvdl 2891: cookiep++;
2892: ncookies--;
1.15 mycroft 2893: }
1.23 fvdl 2894: if (cpos >= cend || ncookies == 0) {
2895: toff = off;
1.15 mycroft 2896: siz = fullsiz;
2897: goto again;
2898: }
2899:
1.23 fvdl 2900: dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2901: nfsm_reply(cnt);
2902: nfsm_srvpostop_attr(getret, &at);
2903: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2904: txdr_hyper(&at.va_filerev, tl);
1.15 mycroft 2905: mp = mp2 = mb;
2906: bp = bpos;
2907: be = bp + M_TRAILINGSPACE(mp);
1.1 cgd 2908:
2909: /* Loop through the records and build reply */
1.23 fvdl 2910: while (cpos < cend && ncookies > 0) {
1.25 jtk 2911: if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
1.1 cgd 2912: nlen = dp->d_namlen;
2913: rem = nfsm_rndup(nlen)-nlen;
2914:
2915: /*
1.15 mycroft 2916: * For readdir_and_lookup get the vnode using
2917: * the file number.
1.1 cgd 2918: */
1.15 mycroft 2919: if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
2920: goto invalid;
1.44 perry 2921: memset((caddr_t)nfhp, 0, NFSX_V3FH);
1.23 fvdl 2922: nfhp->fh_fsid =
1.15 mycroft 2923: nvp->v_mount->mnt_stat.f_fsid;
1.23 fvdl 2924: if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
1.15 mycroft 2925: vput(nvp);
2926: goto invalid;
2927: }
1.23 fvdl 2928: if (VOP_GETATTR(nvp, vap, cred, procp)) {
1.15 mycroft 2929: vput(nvp);
2930: goto invalid;
2931: }
2932: vput(nvp);
1.23 fvdl 2933:
2934: /*
2935: * If either the dircount or maxcount will be
2936: * exceeded, get out now. Both of these lengths
2937: * are calculated conservatively, including all
2938: * XDR overheads.
2939: */
2940: len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
2941: NFSX_V3POSTOPATTR);
2942: dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
2943: if (len > cnt || dirlen > fullsiz) {
1.1 cgd 2944: eofflag = 0;
2945: break;
2946: }
1.23 fvdl 2947:
1.15 mycroft 2948: /*
2949: * Build the directory record xdr from
2950: * the dirent entry.
2951: */
1.23 fvdl 2952: fp = (struct nfs_fattr *)&fl.fl_fattr;
2953: nfsm_srvfillattr(vap, fp);
2954: fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2955: fl.fl_fhok = nfs_true;
2956: fl.fl_postopok = nfs_true;
1.38 fvdl 2957: txdr_hyper(cookiep, fl.fl_off.nfsuquad);
1.23 fvdl 2958:
1.1 cgd 2959: nfsm_clget;
2960: *tl = nfs_true;
2961: bp += NFSX_UNSIGNED;
1.23 fvdl 2962: nfsm_clget;
2963: *tl = 0;
2964: bp += NFSX_UNSIGNED;
1.1 cgd 2965: nfsm_clget;
1.11 ws 2966: *tl = txdr_unsigned(dp->d_fileno);
1.1 cgd 2967: bp += NFSX_UNSIGNED;
2968: nfsm_clget;
2969: *tl = txdr_unsigned(nlen);
2970: bp += NFSX_UNSIGNED;
2971:
1.15 mycroft 2972: /* And loop around copying the name */
1.1 cgd 2973: xfer = nlen;
2974: cp = dp->d_name;
2975: while (xfer > 0) {
2976: nfsm_clget;
1.23 fvdl 2977: if ((bp + xfer) > be)
2978: tsiz = be - bp;
1.1 cgd 2979: else
2980: tsiz = xfer;
1.44 perry 2981: memcpy(bp, cp, tsiz);
1.1 cgd 2982: bp += tsiz;
2983: xfer -= tsiz;
2984: if (xfer > 0)
2985: cp += tsiz;
2986: }
1.23 fvdl 2987: /* And null pad to an int32_t boundary */
1.1 cgd 2988: for (i = 0; i < rem; i++)
2989: *bp++ = '\0';
2990:
1.23 fvdl 2991: /*
2992: * Now copy the flrep structure out.
2993: */
2994: xfer = sizeof (struct flrep);
2995: cp = (caddr_t)&fl;
2996: while (xfer > 0) {
2997: nfsm_clget;
2998: if ((bp + xfer) > be)
2999: tsiz = be - bp;
3000: else
3001: tsiz = xfer;
1.44 perry 3002: memcpy(bp, cp, tsiz);
1.23 fvdl 3003: bp += tsiz;
3004: xfer -= tsiz;
3005: if (xfer > 0)
3006: cp += tsiz;
3007: }
1.8 ws 3008: }
1.15 mycroft 3009: invalid:
1.1 cgd 3010: cpos += dp->d_reclen;
1.11 ws 3011: dp = (struct dirent *)cpos;
1.23 fvdl 3012: cookiep++;
3013: ncookies--;
1.1 cgd 3014: }
1.15 mycroft 3015: vrele(vp);
1.1 cgd 3016: nfsm_clget;
3017: *tl = nfs_false;
3018: bp += NFSX_UNSIGNED;
3019: nfsm_clget;
3020: if (eofflag)
3021: *tl = nfs_true;
3022: else
3023: *tl = nfs_false;
3024: bp += NFSX_UNSIGNED;
1.15 mycroft 3025: if (mp != mb) {
3026: if (bp < be)
3027: mp->m_len = bp - mtod(mp, caddr_t);
3028: } else
3029: mp->m_len += bp - bpos;
1.23 fvdl 3030: FREE((caddr_t)cookies, M_TEMP);
3031: FREE((caddr_t)rbuf, M_TEMP);
3032: nfsm_srvdone;
3033: }
3034:
3035: /*
3036: * nfs commit service
3037: */
3038: int
3039: nfsrv_commit(nfsd, slp, procp, mrq)
3040: struct nfsrv_descript *nfsd;
3041: struct nfssvc_sock *slp;
3042: struct proc *procp;
3043: struct mbuf **mrq;
3044: {
3045: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3046: struct mbuf *nam = nfsd->nd_nam;
3047: caddr_t dpos = nfsd->nd_dpos;
3048: struct ucred *cred = &nfsd->nd_cr;
3049: struct vattr bfor, aft;
3050: struct vnode *vp;
3051: nfsfh_t nfh;
3052: fhandle_t *fhp;
3053: register u_int32_t *tl;
3054: register int32_t t1;
3055: caddr_t bpos;
3056: int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
3057: char *cp2;
3058: struct mbuf *mb, *mb2, *mreq;
3059: u_quad_t frev, off;
3060:
3061: #ifndef nolint
3062: cache = 0;
3063: #endif
3064: fhp = &nfh.fh_generic;
3065: nfsm_srvmtofh(fhp);
3066: nfsm_dissect(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3067:
3068: /*
3069: * XXX At this time VOP_FSYNC() does not accept offset and byte
3070: * count parameters, so these arguments are useless (someday maybe).
3071: */
3072: fxdr_hyper(tl, &off);
3073: tl += 2;
3074: cnt = fxdr_unsigned(int, *tl);
3075: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 3076: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 3077: if (error) {
3078: nfsm_reply(2 * NFSX_UNSIGNED);
3079: nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3080: return (0);
3081: }
3082: for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
1.43 kleink 3083: error = VOP_FSYNC(vp, cred, FSYNC_WAIT, procp);
1.23 fvdl 3084: aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
3085: vput(vp);
3086: nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
3087: nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
3088: if (!error) {
3089: nfsm_build(tl, u_int32_t *, NFSX_V3WRITEVERF);
3090: *tl++ = txdr_unsigned(boottime.tv_sec);
3091: *tl = txdr_unsigned(boottime.tv_usec);
3092: } else
3093: return (0);
1.1 cgd 3094: nfsm_srvdone;
3095: }
3096:
3097: /*
3098: * nfs statfs service
3099: */
1.22 christos 3100: int
1.23 fvdl 3101: nfsrv_statfs(nfsd, slp, procp, mrq)
3102: struct nfsrv_descript *nfsd;
3103: struct nfssvc_sock *slp;
3104: struct proc *procp;
3105: struct mbuf **mrq;
1.1 cgd 3106: {
1.23 fvdl 3107: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3108: struct mbuf *nam = nfsd->nd_nam;
3109: caddr_t dpos = nfsd->nd_dpos;
3110: struct ucred *cred = &nfsd->nd_cr;
1.1 cgd 3111: register struct statfs *sf;
1.23 fvdl 3112: register struct nfs_statfs *sfp;
1.19 cgd 3113: register u_int32_t *tl;
3114: register int32_t t1;
1.1 cgd 3115: caddr_t bpos;
1.23 fvdl 3116: int error = 0, rdonly, cache, getret = 1;
3117: int v3 = (nfsd->nd_flag & ND_NFSV3);
1.1 cgd 3118: char *cp2;
3119: struct mbuf *mb, *mb2, *mreq;
3120: struct vnode *vp;
1.23 fvdl 3121: struct vattr at;
3122: nfsfh_t nfh;
1.1 cgd 3123: fhandle_t *fhp;
3124: struct statfs statfs;
1.23 fvdl 3125: u_quad_t frev, tval;
1.1 cgd 3126:
1.23 fvdl 3127: #ifndef nolint
3128: cache = 0;
3129: #endif
1.1 cgd 3130: fhp = &nfh.fh_generic;
3131: nfsm_srvmtofh(fhp);
1.23 fvdl 3132: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 3133: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 3134: if (error) {
3135: nfsm_reply(NFSX_UNSIGNED);
3136: nfsm_srvpostop_attr(getret, &at);
3137: return (0);
3138: }
1.1 cgd 3139: sf = &statfs;
1.23 fvdl 3140: error = VFS_STATFS(vp->v_mount, sf, procp);
3141: getret = VOP_GETATTR(vp, &at, cred, procp);
1.1 cgd 3142: vput(vp);
1.23 fvdl 3143: nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3144: if (v3)
3145: nfsm_srvpostop_attr(getret, &at);
3146: if (error)
3147: return (0);
3148: nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3149: if (v3) {
3150: tval = (u_quad_t)sf->f_blocks;
3151: tval *= (u_quad_t)sf->f_bsize;
3152: txdr_hyper(&tval, &sfp->sf_tbytes);
3153: tval = (u_quad_t)sf->f_bfree;
3154: tval *= (u_quad_t)sf->f_bsize;
3155: txdr_hyper(&tval, &sfp->sf_fbytes);
3156: tval = (u_quad_t)sf->f_bavail;
3157: tval *= (u_quad_t)sf->f_bsize;
3158: txdr_hyper(&tval, &sfp->sf_abytes);
3159: sfp->sf_tfiles.nfsuquad[0] = 0;
3160: sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3161: sfp->sf_ffiles.nfsuquad[0] = 0;
3162: sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3163: sfp->sf_afiles.nfsuquad[0] = 0;
3164: sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3165: sfp->sf_invarsec = 0;
3166: } else {
3167: sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3168: sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3169: sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3170: sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3171: sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3172: }
3173: nfsm_srvdone;
3174: }
3175:
3176: /*
3177: * nfs fsinfo service
3178: */
3179: int
3180: nfsrv_fsinfo(nfsd, slp, procp, mrq)
3181: struct nfsrv_descript *nfsd;
3182: struct nfssvc_sock *slp;
3183: struct proc *procp;
3184: struct mbuf **mrq;
3185: {
3186: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3187: struct mbuf *nam = nfsd->nd_nam;
3188: caddr_t dpos = nfsd->nd_dpos;
3189: struct ucred *cred = &nfsd->nd_cr;
3190: register u_int32_t *tl;
3191: register struct nfsv3_fsinfo *sip;
3192: register int32_t t1;
3193: caddr_t bpos;
3194: int error = 0, rdonly, cache, getret = 1, pref;
3195: char *cp2;
3196: struct mbuf *mb, *mb2, *mreq;
3197: struct vnode *vp;
3198: struct vattr at;
3199: nfsfh_t nfh;
3200: fhandle_t *fhp;
1.37 fvdl 3201: u_quad_t frev, maxfsize;
3202: struct statfs sb;
1.23 fvdl 3203:
3204: #ifndef nolint
3205: cache = 0;
3206: #endif
3207: fhp = &nfh.fh_generic;
3208: nfsm_srvmtofh(fhp);
3209: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 3210: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 3211: if (error) {
3212: nfsm_reply(NFSX_UNSIGNED);
3213: nfsm_srvpostop_attr(getret, &at);
3214: return (0);
1.15 mycroft 3215: }
1.37 fvdl 3216:
3217: /* XXX Try to make a guess on the max file size. */
3218: VFS_STATFS(vp->v_mount, &sb, (struct proc *)0);
3219: maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1;
3220:
1.23 fvdl 3221: getret = VOP_GETATTR(vp, &at, cred, procp);
3222: vput(vp);
3223: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3224: nfsm_srvpostop_attr(getret, &at);
3225: nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3226:
3227: /*
3228: * XXX
3229: * There should be file system VFS OP(s) to get this information.
3230: * For now, assume ufs.
3231: */
3232: if (slp->ns_so->so_type == SOCK_DGRAM)
3233: pref = NFS_MAXDGRAMDATA;
3234: else
3235: pref = NFS_MAXDATA;
3236: sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3237: sip->fs_rtpref = txdr_unsigned(pref);
3238: sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3239: sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3240: sip->fs_wtpref = txdr_unsigned(pref);
3241: sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3242: sip->fs_dtpref = txdr_unsigned(pref);
1.37 fvdl 3243: txdr_hyper(&maxfsize, &sip->fs_maxfilesize);
1.23 fvdl 3244: sip->fs_timedelta.nfsv3_sec = 0;
3245: sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3246: sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3247: NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3248: NFSV3FSINFO_CANSETTIME);
3249: nfsm_srvdone;
3250: }
3251:
3252: /*
3253: * nfs pathconf service
3254: */
3255: int
3256: nfsrv_pathconf(nfsd, slp, procp, mrq)
3257: struct nfsrv_descript *nfsd;
3258: struct nfssvc_sock *slp;
3259: struct proc *procp;
3260: struct mbuf **mrq;
3261: {
3262: struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3263: struct mbuf *nam = nfsd->nd_nam;
3264: caddr_t dpos = nfsd->nd_dpos;
3265: struct ucred *cred = &nfsd->nd_cr;
3266: register u_int32_t *tl;
3267: register struct nfsv3_pathconf *pc;
3268: register int32_t t1;
3269: caddr_t bpos;
1.24 cgd 3270: int error = 0, rdonly, cache, getret = 1;
3271: register_t linkmax, namemax, chownres, notrunc;
1.23 fvdl 3272: char *cp2;
3273: struct mbuf *mb, *mb2, *mreq;
3274: struct vnode *vp;
3275: struct vattr at;
3276: nfsfh_t nfh;
3277: fhandle_t *fhp;
3278: u_quad_t frev;
3279:
3280: #ifndef nolint
3281: cache = 0;
3282: #endif
3283: fhp = &nfh.fh_generic;
3284: nfsm_srvmtofh(fhp);
3285: error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
1.35 fvdl 3286: &rdonly, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1.23 fvdl 3287: if (error) {
3288: nfsm_reply(NFSX_UNSIGNED);
3289: nfsm_srvpostop_attr(getret, &at);
3290: return (0);
3291: }
3292: error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3293: if (!error)
3294: error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3295: if (!error)
3296: error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3297: if (!error)
3298: error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc);
3299: getret = VOP_GETATTR(vp, &at, cred, procp);
3300: vput(vp);
3301: nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3302: nfsm_srvpostop_attr(getret, &at);
3303: if (error)
3304: return (0);
3305: nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3306:
3307: pc->pc_linkmax = txdr_unsigned(linkmax);
3308: pc->pc_namemax = txdr_unsigned(namemax);
3309: pc->pc_notrunc = txdr_unsigned(notrunc);
3310: pc->pc_chownrestricted = txdr_unsigned(chownres);
3311:
3312: /*
3313: * These should probably be supported by VOP_PATHCONF(), but
3314: * until msdosfs is exportable (why would you want to?), the
3315: * Unix defaults should be ok.
3316: */
3317: pc->pc_caseinsensitive = nfs_false;
3318: pc->pc_casepreserving = nfs_true;
1.1 cgd 3319: nfsm_srvdone;
3320: }
3321:
3322: /*
3323: * Null operation, used by clients to ping server
3324: */
3325: /* ARGSUSED */
1.22 christos 3326: int
1.23 fvdl 3327: nfsrv_null(nfsd, slp, procp, mrq)
3328: struct nfsrv_descript *nfsd;
3329: struct nfssvc_sock *slp;
3330: struct proc *procp;
3331: struct mbuf **mrq;
1.1 cgd 3332: {
1.23 fvdl 3333: struct mbuf *mrep = nfsd->nd_mrep;
1.1 cgd 3334: caddr_t bpos;
1.23 fvdl 3335: int error = NFSERR_RETVOID, cache = 0;
1.1 cgd 3336: struct mbuf *mb, *mreq;
1.15 mycroft 3337: u_quad_t frev;
1.1 cgd 3338:
3339: nfsm_reply(0);
1.23 fvdl 3340: return (0);
1.1 cgd 3341: }
3342:
3343: /*
3344: * No operation, used for obsolete procedures
3345: */
3346: /* ARGSUSED */
1.22 christos 3347: int
1.23 fvdl 3348: nfsrv_noop(nfsd, slp, procp, mrq)
3349: struct nfsrv_descript *nfsd;
3350: struct nfssvc_sock *slp;
3351: struct proc *procp;
3352: struct mbuf **mrq;
1.1 cgd 3353: {
1.23 fvdl 3354: struct mbuf *mrep = nfsd->nd_mrep;
1.1 cgd 3355: caddr_t bpos;
1.22 christos 3356: int error, cache = 0;
1.1 cgd 3357: struct mbuf *mb, *mreq;
1.15 mycroft 3358: u_quad_t frev;
1.1 cgd 3359:
1.15 mycroft 3360: if (nfsd->nd_repstat)
3361: error = nfsd->nd_repstat;
1.2 cgd 3362: else
3363: error = EPROCUNAVAIL;
1.1 cgd 3364: nfsm_reply(0);
1.23 fvdl 3365: return (0);
1.1 cgd 3366: }
3367:
3368: /*
3369: * Perform access checking for vnodes obtained from file handles that would
3370: * refer to files already opened by a Unix client. You cannot just use
3371: * vn_writechk() and VOP_ACCESS() for two reasons.
1.15 mycroft 3372: * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
1.27 fvdl 3373: * 2 - The owner is to be given access irrespective of mode bits for some
3374: * operations, so that processes that chmod after opening a file don't
3375: * break. I don't like this because it opens a security hole, but since
3376: * the nfs server opens a security hole the size of a barn door anyhow,
3377: * what the heck.
1.31 fvdl 3378: *
3379: * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
3380: * will return EPERM instead of EACCESS. EPERM is always an error.
1.1 cgd 3381: */
1.22 christos 3382: int
1.27 fvdl 3383: nfsrv_access(vp, flags, cred, rdonly, p, override)
1.1 cgd 3384: register struct vnode *vp;
3385: int flags;
3386: register struct ucred *cred;
1.15 mycroft 3387: int rdonly;
1.1 cgd 3388: struct proc *p;
3389: {
3390: struct vattr vattr;
3391: int error;
3392: if (flags & VWRITE) {
1.15 mycroft 3393: /* Just vn_writechk() changed to check rdonly */
1.1 cgd 3394: /*
3395: * Disallow write attempts on read-only file systems;
3396: * unless the file is a socket or a block or character
3397: * device resident on the file system.
3398: */
1.15 mycroft 3399: if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
1.1 cgd 3400: switch (vp->v_type) {
1.23 fvdl 3401: case VREG:
3402: case VDIR:
3403: case VLNK:
1.1 cgd 3404: return (EROFS);
1.23 fvdl 3405: default:
1.22 christos 3406: break;
1.1 cgd 3407: }
3408: }
3409: /*
3410: * If there's shared text associated with
3411: * the inode, try to free it up once. If
3412: * we fail, we can't allow writing.
3413: */
1.40 mrg 3414: #if defined(UVM)
3415: if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
3416: return (ETXTBSY);
3417: #else
1.1 cgd 3418: if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
3419: return (ETXTBSY);
1.40 mrg 3420: #endif
1.1 cgd 3421: }
1.23 fvdl 3422: error = VOP_GETATTR(vp, &vattr, cred, p);
3423: if (error)
1.1 cgd 3424: return (error);
1.27 fvdl 3425: error = VOP_ACCESS(vp, flags, cred, p);
3426: /*
3427: * Allow certain operations for the owner (reads and writes
3428: * on files that are already open).
3429: */
1.31 fvdl 3430: if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
1.27 fvdl 3431: error = 0;
3432: return error;
1.1 cgd 3433: }
CVSweb <webmaster@jp.NetBSD.org>