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