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