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