|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Rick Macklem at The University of Guelph.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
36: * @(#)nfs_vnops.c 7.60 (Berkeley) 5/24/91
37: */
38:
39: /*
40: * vnode op calls for sun nfs version 2
41: */
42:
43: #include "param.h"
44: #include "proc.h"
45: #include "kernel.h"
46: #include "systm.h"
47: #include "mount.h"
48: #include "buf.h"
49: #include "malloc.h"
50: #include "mbuf.h"
51: #include "conf.h"
52: #include "namei.h"
53: #include "vnode.h"
54: #include "specdev.h"
55: #include "fifo.h"
56: #include "map.h"
57:
58: #include "../ufs/quota.h"
59: #include "../ufs/inode.h"
60: #include "../ufs/dir.h"
61:
62: #include "nfsv2.h"
63: #include "nfs.h"
64: #include "nfsnode.h"
65: #include "nfsmount.h"
66: #include "xdr_subs.h"
67: #include "nfsm_subs.h"
68: #include "nfsiom.h"
69:
70: #include "machine/mtpr.h"
71:
72: /* Defs */
73: #define TRUE 1
74: #define FALSE 0
75:
76: /*
77: * Global vfs data structures for nfs
78: */
79: struct vnodeops nfsv2_vnodeops = {
80: nfs_lookup, /* lookup */
81: nfs_create, /* create */
82: nfs_mknod, /* mknod */
83: nfs_open, /* open */
84: nfs_close, /* close */
85: nfs_access, /* access */
86: nfs_getattr, /* getattr */
87: nfs_setattr, /* setattr */
88: nfs_read, /* read */
89: nfs_write, /* write */
90: nfs_ioctl, /* ioctl */
91: nfs_select, /* select */
92: nfs_mmap, /* mmap */
93: nfs_fsync, /* fsync */
94: nfs_seek, /* seek */
95: nfs_remove, /* remove */
96: nfs_link, /* link */
97: nfs_rename, /* rename */
98: nfs_mkdir, /* mkdir */
99: nfs_rmdir, /* rmdir */
100: nfs_symlink, /* symlink */
101: nfs_readdir, /* readdir */
102: nfs_readlink, /* readlink */
103: nfs_abortop, /* abortop */
104: nfs_inactive, /* inactive */
105: nfs_reclaim, /* reclaim */
106: nfs_lock, /* lock */
107: nfs_unlock, /* unlock */
108: nfs_bmap, /* bmap */
109: nfs_strategy, /* strategy */
110: nfs_print, /* print */
111: nfs_islocked, /* islocked */
112: nfs_advlock, /* advlock */
113: };
114:
115: /*
116: * Special device vnode ops
117: */
118: struct vnodeops spec_nfsv2nodeops = {
119: spec_lookup, /* lookup */
120: spec_create, /* create */
121: spec_mknod, /* mknod */
122: spec_open, /* open */
123: spec_close, /* close */
124: nfs_access, /* access */
125: nfs_getattr, /* getattr */
126: nfs_setattr, /* setattr */
127: spec_read, /* read */
128: spec_write, /* write */
129: spec_ioctl, /* ioctl */
130: spec_select, /* select */
131: spec_mmap, /* mmap */
132: spec_fsync, /* fsync */
133: spec_seek, /* seek */
134: spec_remove, /* remove */
135: spec_link, /* link */
136: spec_rename, /* rename */
137: spec_mkdir, /* mkdir */
138: spec_rmdir, /* rmdir */
139: spec_symlink, /* symlink */
140: spec_readdir, /* readdir */
141: spec_readlink, /* readlink */
142: spec_abortop, /* abortop */
143: nfs_inactive, /* inactive */
144: nfs_reclaim, /* reclaim */
145: nfs_lock, /* lock */
146: nfs_unlock, /* unlock */
147: spec_bmap, /* bmap */
148: spec_strategy, /* strategy */
149: nfs_print, /* print */
150: nfs_islocked, /* islocked */
151: spec_advlock, /* advlock */
152: };
153:
154: #ifdef FIFO
155: struct vnodeops fifo_nfsv2nodeops = {
156: fifo_lookup, /* lookup */
157: fifo_create, /* create */
158: fifo_mknod, /* mknod */
159: fifo_open, /* open */
160: fifo_close, /* close */
161: nfs_access, /* access */
162: nfs_getattr, /* getattr */
163: nfs_setattr, /* setattr */
164: fifo_read, /* read */
165: fifo_write, /* write */
166: fifo_ioctl, /* ioctl */
167: fifo_select, /* select */
168: fifo_mmap, /* mmap */
169: fifo_fsync, /* fsync */
170: fifo_seek, /* seek */
171: fifo_remove, /* remove */
172: fifo_link, /* link */
173: fifo_rename, /* rename */
174: fifo_mkdir, /* mkdir */
175: fifo_rmdir, /* rmdir */
176: fifo_symlink, /* symlink */
177: fifo_readdir, /* readdir */
178: fifo_readlink, /* readlink */
179: fifo_abortop, /* abortop */
180: nfs_inactive, /* inactive */
181: nfs_reclaim, /* reclaim */
182: nfs_lock, /* lock */
183: nfs_unlock, /* unlock */
184: fifo_bmap, /* bmap */
185: fifo_badop, /* strategy */
186: nfs_print, /* print */
187: nfs_islocked, /* islocked */
188: fifo_advlock, /* advlock */
189: };
190: #endif /* FIFO */
191:
192: /*
193: * Global vars
194: */
195: extern u_long nfs_procids[NFS_NPROCS];
196: extern u_long nfs_prog, nfs_vers;
197: extern char nfsiobuf[MAXPHYS+NBPG];
198: struct map nfsmap[NFS_MSIZ];
199: struct buf nfs_bqueue; /* Queue head for nfsiod's */
200: struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
201: int nfs_numasync = 0;
202: static int nfsmap_want = 0;
203:
204: /*
205: * nfs null call from vfs.
206: */
207: nfs_null(vp, cred, p)
208: struct vnode *vp;
209: struct ucred *cred;
210: struct proc *p;
211: {
212: caddr_t bpos, dpos;
213: u_long xid;
214: int error = 0;
215: struct mbuf *mreq, *mrep, *md, *mb;
216:
217: nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
218: nfsm_request(vp, NFSPROC_NULL, p, 0);
219: nfsm_reqdone;
220: return (error);
221: }
222:
223: /*
224: * nfs access vnode op.
225: * Essentially just get vattr and then imitate iaccess()
226: */
227: nfs_access(vp, mode, cred, p)
228: struct vnode *vp;
229: int mode;
230: register struct ucred *cred;
231: struct proc *p;
232: {
233: register struct vattr *vap;
234: register gid_t *gp;
235: struct vattr vattr;
236: register int i;
237: int error;
238:
239: /*
240: * If you're the super-user,
241: * you always get access.
242: */
243: if (cred->cr_uid == 0)
244: return (0);
245: vap = &vattr;
246: if (error = nfs_dogetattr(vp, vap, cred, 0, p))
247: return (error);
248: /*
249: * Access check is based on only one of owner, group, public.
250: * If not owner, then check group. If not a member of the
251: * group, then check public access.
252: */
253: if (cred->cr_uid != vap->va_uid) {
254: mode >>= 3;
255: gp = cred->cr_groups;
256: for (i = 0; i < cred->cr_ngroups; i++, gp++)
257: if (vap->va_gid == *gp)
258: goto found;
259: mode >>= 3;
260: found:
261: ;
262: }
263: if ((vap->va_mode & mode) != 0)
264: return (0);
265: return (EACCES);
266: }
267:
268: /*
269: * nfs open vnode op
270: * Just check to see if the type is ok
271: */
272: /* ARGSUSED */
273: nfs_open(vp, mode, cred, p)
274: struct vnode *vp;
275: int mode;
276: struct ucred *cred;
277: struct proc *p;
278: {
279: register enum vtype vtyp;
280:
281: vtyp = vp->v_type;
282: if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
283: return (0);
284: else
285: return (EACCES);
286: }
287:
288: /*
289: * nfs close vnode op
290: * For reg files, invalidate any buffer cache entries.
291: */
292: /* ARGSUSED */
293: nfs_close(vp, fflags, cred, p)
294: register struct vnode *vp;
295: int fflags;
296: struct ucred *cred;
297: struct proc *p;
298: {
299: register struct nfsnode *np = VTONFS(vp);
300: int error = 0;
301:
302: if (vp->v_type == VREG && (np->n_flag & NMODIFIED)) {
303: nfs_lock(vp);
304: np->n_flag &= ~NMODIFIED;
305: vinvalbuf(vp, TRUE);
306: np->n_attrstamp = 0;
307: if (np->n_flag & NWRITEERR) {
308: np->n_flag &= ~NWRITEERR;
309: error = np->n_error;
310: }
311: nfs_unlock(vp);
312: }
313: return (error);
314: }
315:
316: /*
317: * nfs getattr call from vfs.
318: */
319: nfs_getattr(vp, vap, cred, p)
320: register struct vnode *vp;
321: struct vattr *vap;
322: struct ucred *cred;
323: struct proc *p;
324: {
325: return (nfs_dogetattr(vp, vap, cred, 0, p));
326: }
327:
328: nfs_dogetattr(vp, vap, cred, tryhard, p)
329: register struct vnode *vp;
330: struct vattr *vap;
331: struct ucred *cred;
332: int tryhard;
333: struct proc *p;
334: {
335: register caddr_t cp;
336: register long t1;
337: caddr_t bpos, dpos;
338: u_long xid;
339: int error = 0;
340: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
341:
342: /* First look in the cache.. */
343: if (nfs_getattrcache(vp, vap) == 0)
344: return (0);
345: nfsstats.rpccnt[NFSPROC_GETATTR]++;
346: nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
347: nfsm_fhtom(vp);
348: nfsm_request(vp, NFSPROC_GETATTR, p, tryhard);
349: nfsm_loadattr(vp, vap);
350: nfsm_reqdone;
351: return (error);
352: }
353:
354: /*
355: * nfs setattr call.
356: */
357: nfs_setattr(vp, vap, cred, p)
358: register struct vnode *vp;
359: register struct vattr *vap;
360: struct ucred *cred;
361: struct proc *p;
362: {
363: register struct nfsv2_sattr *sp;
364: register caddr_t cp;
365: register long t1;
366: caddr_t bpos, dpos;
367: u_long xid;
368: int error = 0;
369: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
370: struct nfsnode *np;
371:
372: nfsstats.rpccnt[NFSPROC_SETATTR]++;
373: nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
374: nfsm_fhtom(vp);
375: nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
376: if (vap->va_mode == 0xffff)
377: sp->sa_mode = VNOVAL;
378: else
379: sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
380: if (vap->va_uid == 0xffff)
381: sp->sa_uid = VNOVAL;
382: else
383: sp->sa_uid = txdr_unsigned(vap->va_uid);
384: if (vap->va_gid == 0xffff)
385: sp->sa_gid = VNOVAL;
386: else
387: sp->sa_gid = txdr_unsigned(vap->va_gid);
388: sp->sa_size = txdr_unsigned(vap->va_size);
389: sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
390: sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
391: txdr_time(&vap->va_mtime, &sp->sa_mtime);
392: if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
393: vap->va_atime.tv_sec != VNOVAL) {
394: np = VTONFS(vp);
395: if (np->n_flag & NMODIFIED) {
396: np->n_flag &= ~NMODIFIED;
397: if (vap->va_size == 0)
398: vinvalbuf(vp, FALSE);
399: else
400: vinvalbuf(vp, TRUE);
401: np->n_attrstamp = 0;
402: }
403: }
404: nfsm_request(vp, NFSPROC_SETATTR, p, 1);
405: nfsm_loadattr(vp, (struct vattr *)0);
406: /* should we fill in any vap fields ?? */
407: nfsm_reqdone;
408: return (error);
409: }
410:
411: /*
412: * nfs lookup call, one step at a time...
413: * First look in cache
414: * If not found, unlock the directory nfsnode and do the rpc
415: */
416: nfs_lookup(vp, ndp, p)
417: register struct vnode *vp;
418: register struct nameidata *ndp;
419: struct proc *p;
420: {
421: register struct vnode *vdp;
422: register u_long *tl;
423: register caddr_t cp;
424: register long t1, t2;
425: caddr_t bpos, dpos, cp2;
426: u_long xid;
427: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
428: struct vnode *newvp;
429: long len;
430: nfsv2fh_t *fhp;
431: struct nfsnode *np;
432: int lockparent, wantparent, flag, error = 0;
433:
434: ndp->ni_dvp = vp;
435: ndp->ni_vp = NULL;
436: if (vp->v_type != VDIR)
437: return (ENOTDIR);
438: lockparent = ndp->ni_nameiop & LOCKPARENT;
439: flag = ndp->ni_nameiop & OPMASK;
440: wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
441: if ((error = cache_lookup(ndp)) && error != ENOENT) {
442: struct vattr vattr;
443: int vpid;
444:
445: vdp = ndp->ni_vp;
446: vpid = vdp->v_id;
447: /*
448: * See the comment starting `Step through' in ufs/ufs_lookup.c
449: * for an explanation of the locking protocol
450: */
451: if (vp == vdp) {
452: VREF(vdp);
453: error = 0;
454: } else if (ndp->ni_isdotdot) {
455: nfs_unlock(vp);
456: error = vget(vdp);
457: if (!error && lockparent && *ndp->ni_next == '\0')
458: nfs_lock(vp);
459: } else {
460: error = vget(vdp);
461: if (!lockparent || error || *ndp->ni_next != '\0')
462: nfs_unlock(vp);
463: }
464: if (!error) {
465: if (vpid == vdp->v_id) {
466: if (!nfs_dogetattr(vdp, &vattr, ndp->ni_cred, 0, p)&&
467: vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) {
468: nfsstats.lookupcache_hits++;
469: if (flag != LOOKUP && *ndp->ni_next == 0)
470: ndp->ni_nameiop |= SAVENAME;
471: return (0);
472: }
473: cache_purge(vdp);
474: }
475: nfs_nput(vdp);
476: if (lockparent && vdp != vp && *ndp->ni_next == '\0')
477: nfs_unlock(vp);
478: }
479: ndp->ni_vp = NULLVP;
480: } else
481: nfs_unlock(vp);
482: error = 0;
483: nfsstats.lookupcache_misses++;
484: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
485: len = ndp->ni_namelen;
486: nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
487: nfsm_fhtom(vp);
488: nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
489: nfsm_request(vp, NFSPROC_LOOKUP, p, 0);
490: nfsmout:
491: if (error) {
492: if (lockparent || (flag != CREATE && flag != RENAME) ||
493: *ndp->ni_next != 0)
494: nfs_lock(vp);
495: if (flag != LOOKUP && *ndp->ni_next == 0)
496: ndp->ni_nameiop |= SAVENAME;
497: return (error);
498: }
499: nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
500:
501: /*
502: * Handle DELETE and RENAME cases...
503: */
504: if (flag == DELETE && *ndp->ni_next == 0) {
505: if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
506: VREF(vp);
507: newvp = vp;
508: np = VTONFS(vp);
509: } else {
510: if (error = nfs_nget(vp->v_mount, fhp, &np)) {
511: nfs_lock(vp);
512: m_freem(mrep);
513: return (error);
514: }
515: newvp = NFSTOV(np);
516: }
517: if (error =
518: nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
519: nfs_lock(vp);
520: if (newvp != vp)
521: nfs_nput(newvp);
522: else
523: vrele(vp);
524: m_freem(mrep);
525: return (error);
526: }
527: ndp->ni_vp = newvp;
528: if (lockparent || vp == newvp)
529: nfs_lock(vp);
530: m_freem(mrep);
531: ndp->ni_nameiop |= SAVENAME;
532: return (0);
533: }
534:
535: if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
536: if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
537: nfs_lock(vp);
538: m_freem(mrep);
539: return (EISDIR);
540: }
541: if (error = nfs_nget(vp->v_mount, fhp, &np)) {
542: nfs_lock(vp);
543: m_freem(mrep);
544: return (error);
545: }
546: newvp = NFSTOV(np);
547: if (error =
548: nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
549: nfs_lock(vp);
550: nfs_nput(newvp);
551: m_freem(mrep);
552: return (error);
553: }
554: ndp->ni_vp = newvp;
555: if (lockparent)
556: nfs_lock(vp);
557: m_freem(mrep);
558: ndp->ni_nameiop |= SAVENAME;
559: return (0);
560: }
561:
562: if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
563: VREF(vp);
564: newvp = vp;
565: np = VTONFS(vp);
566: } else if (ndp->ni_isdotdot) {
567: if (error = nfs_nget(vp->v_mount, fhp, &np)) {
568: nfs_lock(vp);
569: m_freem(mrep);
570: return (error);
571: }
572: newvp = NFSTOV(np);
573: } else {
574: if (error = nfs_nget(vp->v_mount, fhp, &np)) {
575: nfs_lock(vp);
576: m_freem(mrep);
577: return (error);
578: }
579: newvp = NFSTOV(np);
580: }
581: if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
582: nfs_lock(vp);
583: if (newvp != vp)
584: nfs_nput(newvp);
585: else
586: vrele(vp);
587: m_freem(mrep);
588: return (error);
589: }
590: m_freem(mrep);
591:
592: if (vp == newvp || (lockparent && *ndp->ni_next == '\0'))
593: nfs_lock(vp);
594: ndp->ni_vp = newvp;
595: if (flag != LOOKUP && *ndp->ni_next == 0)
596: ndp->ni_nameiop |= SAVENAME;
597: if (error == 0 && ndp->ni_makeentry) {
598: np->n_ctime = np->n_vattr.va_ctime.tv_sec;
599: cache_enter(ndp);
600: }
601: return (error);
602: }
603:
604: /*
605: * nfs read call.
606: * Just call nfs_bioread() to do the work.
607: */
608: nfs_read(vp, uiop, ioflag, cred)
609: register struct vnode *vp;
610: struct uio *uiop;
611: int ioflag;
612: struct ucred *cred;
613: {
614: if (vp->v_type != VREG)
615: return (EPERM);
616: return (nfs_bioread(vp, uiop, ioflag, cred));
617: }
618:
619: /*
620: * nfs readlink call
621: */
622: nfs_readlink(vp, uiop, cred)
623: struct vnode *vp;
624: struct uio *uiop;
625: struct ucred *cred;
626: {
627: if (vp->v_type != VLNK)
628: return (EPERM);
629: return (nfs_bioread(vp, uiop, 0, cred));
630: }
631:
632: /*
633: * Do a readlink rpc.
634: * Called by nfs_doio() from below the buffer cache.
635: */
636: nfs_readlinkrpc(vp, uiop, cred)
637: register struct vnode *vp;
638: struct uio *uiop;
639: struct ucred *cred;
640: {
641: register u_long *tl;
642: register caddr_t cp;
643: register long t1;
644: caddr_t bpos, dpos, cp2;
645: u_long xid;
646: int error = 0;
647: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
648: long len;
649:
650: nfsstats.rpccnt[NFSPROC_READLINK]++;
651: nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
652: nfsm_fhtom(vp);
653: nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, 0);
654: nfsm_strsiz(len, NFS_MAXPATHLEN);
655: nfsm_mtouio(uiop, len);
656: nfsm_reqdone;
657: return (error);
658: }
659:
660: /*
661: * nfs read rpc call
662: * Ditto above
663: */
664: nfs_readrpc(vp, uiop, cred)
665: register struct vnode *vp;
666: struct uio *uiop;
667: struct ucred *cred;
668: {
669: register u_long *tl;
670: register caddr_t cp;
671: register long t1;
672: caddr_t bpos, dpos, cp2;
673: u_long xid;
674: int error = 0;
675: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
676: struct nfsmount *nmp;
677: long len, retlen, tsiz;
678:
679: nmp = VFSTONFS(vp->v_mount);
680: tsiz = uiop->uio_resid;
681: while (tsiz > 0) {
682: nfsstats.rpccnt[NFSPROC_READ]++;
683: len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
684: nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
685: nfsm_fhtom(vp);
686: nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
687: *tl++ = txdr_unsigned(uiop->uio_offset);
688: *tl++ = txdr_unsigned(len);
689: *tl = 0;
690: nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, 1);
691: nfsm_loadattr(vp, (struct vattr *)0);
692: nfsm_strsiz(retlen, nmp->nm_rsize);
693: nfsm_mtouio(uiop, retlen);
694: m_freem(mrep);
695: if (retlen < len)
696: tsiz = 0;
697: else
698: tsiz -= len;
699: }
700: nfsmout:
701: return (error);
702: }
703:
704: /*
705: * nfs write call
706: */
707: nfs_writerpc(vp, uiop, cred)
708: register struct vnode *vp;
709: struct uio *uiop;
710: struct ucred *cred;
711: {
712: register u_long *tl;
713: register caddr_t cp;
714: register long t1;
715: caddr_t bpos, dpos;
716: u_long xid;
717: int error = 0;
718: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
719: struct nfsmount *nmp;
720: long len, tsiz;
721:
722: nmp = VFSTONFS(vp->v_mount);
723: tsiz = uiop->uio_resid;
724: while (tsiz > 0) {
725: nfsstats.rpccnt[NFSPROC_WRITE]++;
726: len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
727: nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
728: NFSX_FH+NFSX_UNSIGNED*4);
729: nfsm_fhtom(vp);
730: nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
731: *(tl+1) = txdr_unsigned(uiop->uio_offset);
732: *(tl+3) = txdr_unsigned(len);
733: nfsm_uiotom(uiop, len);
734: nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, 1);
735: nfsm_loadattr(vp, (struct vattr *)0);
736: m_freem(mrep);
737: tsiz -= len;
738: }
739: nfsmout:
740: return (error);
741: }
742:
743: /*
744: * nfs mknod call
745: * This is a kludge. Use a create rpc but with the IFMT bits of the mode
746: * set to specify the file type and the size field for rdev.
747: */
748: /* ARGSUSED */
749: nfs_mknod(ndp, vap, cred, p)
750: struct nameidata *ndp;
751: struct ucred *cred;
752: register struct vattr *vap;
753: struct proc *p;
754: {
755: register struct nfsv2_sattr *sp;
756: register u_long *tl;
757: register caddr_t cp;
758: register long t1, t2;
759: caddr_t bpos, dpos;
760: u_long xid;
761: int error = 0;
762: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
763: u_long rdev;
764:
765: if (vap->va_type == VCHR || vap->va_type == VBLK)
766: rdev = txdr_unsigned(vap->va_rdev);
767: #ifdef FIFO
768: else if (vap->va_type == VFIFO)
769: rdev = 0xffffffff;
770: #endif /* FIFO */
771: else {
772: VOP_ABORTOP(ndp);
773: vput(ndp->ni_dvp);
774: return (EOPNOTSUPP);
775: }
776: nfsstats.rpccnt[NFSPROC_CREATE]++;
777: nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
778: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
779: nfsm_fhtom(ndp->ni_dvp);
780: nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
781: nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
782: sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
783: sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
784: sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
785: sp->sa_size = rdev;
786: /* or should these be VNOVAL ?? */
787: txdr_time(&vap->va_atime, &sp->sa_atime);
788: txdr_time(&vap->va_mtime, &sp->sa_mtime);
789: nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1);
790: nfsm_reqdone;
791: FREE(ndp->ni_pnbuf, M_NAMEI);
792: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
793: nfs_nput(ndp->ni_dvp);
794: return (error);
795: }
796:
797: /*
798: * nfs file create call
799: */
800: nfs_create(ndp, vap, p)
801: register struct nameidata *ndp;
802: register struct vattr *vap;
803: struct proc *p;
804: {
805: register struct nfsv2_sattr *sp;
806: register u_long *tl;
807: register caddr_t cp;
808: register long t1, t2;
809: caddr_t bpos, dpos, cp2;
810: u_long xid;
811: int error = 0;
812: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
813:
814: nfsstats.rpccnt[NFSPROC_CREATE]++;
815: nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
816: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
817: nfsm_fhtom(ndp->ni_dvp);
818: nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
819: nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
820: sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
821: sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
822: sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
823: sp->sa_size = txdr_unsigned(0);
824: /* or should these be VNOVAL ?? */
825: txdr_time(&vap->va_atime, &sp->sa_atime);
826: txdr_time(&vap->va_mtime, &sp->sa_mtime);
827: nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1);
828: nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
829: nfsm_reqdone;
830: FREE(ndp->ni_pnbuf, M_NAMEI);
831: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
832: nfs_nput(ndp->ni_dvp);
833: return (error);
834: }
835:
836: /*
837: * nfs file remove call
838: * To try and make nfs semantics closer to ufs semantics, a file that has
839: * other processes using the vnode is renamed instead of removed and then
840: * removed later on the last close.
841: * - If v_usecount > 1
842: * If a rename is not already in the works
843: * call nfs_sillyrename() to set it up
844: * else
845: * do the remove rpc
846: */
847: nfs_remove(ndp, p)
848: register struct nameidata *ndp;
849: struct proc *p;
850: {
851: register struct vnode *vp = ndp->ni_vp;
852: register struct nfsnode *np = VTONFS(ndp->ni_vp);
853: register u_long *tl;
854: register caddr_t cp;
855: register long t1, t2;
856: caddr_t bpos, dpos;
857: u_long xid;
858: int error = 0;
859: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
860:
861: if (vp->v_usecount > 1) {
862: if (!np->n_sillyrename)
863: error = nfs_sillyrename(ndp, p);
864: } else {
865: nfsstats.rpccnt[NFSPROC_REMOVE]++;
866: nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
867: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
868: nfsm_fhtom(ndp->ni_dvp);
869: nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
870: nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, p, 1);
871: nfsm_reqdone;
872: FREE(ndp->ni_pnbuf, M_NAMEI);
873: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
874: /*
875: * Kludge City: If the first reply to the remove rpc is lost..
876: * the reply to the retransmitted request will be ENOENT
877: * since the file was in fact removed
878: * Therefore, we cheat and return success.
879: */
880: if (error == ENOENT)
881: error = 0;
882: }
883: np->n_attrstamp = 0;
884: if (ndp->ni_dvp == vp)
885: vrele(vp);
886: else
887: nfs_nput(ndp->ni_dvp);
888: nfs_nput(vp);
889: return (error);
890: }
891:
892: /*
893: * nfs file remove rpc called from nfs_inactive
894: */
895: nfs_removeit(sp, p)
896: register struct sillyrename *sp;
897: struct proc *p;
898: {
899: register u_long *tl;
900: register caddr_t cp;
901: register long t1, t2;
902: caddr_t bpos, dpos;
903: u_long xid;
904: int error = 0;
905: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
906:
907: nfsstats.rpccnt[NFSPROC_REMOVE]++;
908: nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], sp->s_cred,
909: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
910: nfsm_fhtom(sp->s_dvp);
911: nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
912: nfsm_request(sp->s_dvp, NFSPROC_REMOVE, p, 1);
913: nfsm_reqdone;
914: VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
915: return (error);
916: }
917:
918: /*
919: * nfs file rename call
920: */
921: nfs_rename(sndp, tndp, p)
922: register struct nameidata *sndp, *tndp;
923: struct proc *p;
924: {
925: register u_long *tl;
926: register caddr_t cp;
927: register long t1, t2;
928: caddr_t bpos, dpos;
929: u_long xid;
930: int error = 0;
931: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
932:
933: nfsstats.rpccnt[NFSPROC_RENAME]++;
934: nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
935: (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) +
936: nfsm_rndup(tndp->ni_namelen)); /* or sndp->ni_cred?*/
937: nfsm_fhtom(sndp->ni_dvp);
938: nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
939: nfsm_fhtom(tndp->ni_dvp);
940: nfsm_strtom(tndp->ni_ptr, tndp->ni_namelen, NFS_MAXNAMLEN);
941: nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1);
942: nfsm_reqdone;
943: VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
944: VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED;
945: if (sndp->ni_vp->v_type == VDIR) {
946: if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
947: cache_purge(tndp->ni_dvp);
948: cache_purge(sndp->ni_dvp);
949: }
950: if (tndp->ni_dvp == tndp->ni_vp)
951: vrele(tndp->ni_dvp);
952: else
953: vput(tndp->ni_dvp);
954: if (tndp->ni_vp)
955: vput(tndp->ni_vp);
956: vrele(sndp->ni_dvp);
957: vrele(sndp->ni_vp);
958: /*
959: * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
960: */
961: if (error == ENOENT)
962: error = 0;
963: return (error);
964: }
965:
966: /*
967: * nfs file rename rpc called from nfs_remove() above
968: */
969: nfs_renameit(sndp, sp, p)
970: register struct nameidata *sndp;
971: register struct sillyrename *sp;
972: struct proc *p;
973: {
974: register u_long *tl;
975: register caddr_t cp;
976: register long t1, t2;
977: caddr_t bpos, dpos;
978: u_long xid;
979: int error = 0;
980: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
981:
982: nfsstats.rpccnt[NFSPROC_RENAME]++;
983: nfsm_reqhead(nfs_procids[NFSPROC_RENAME], sp->s_cred,
984: (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) +
985: nfsm_rndup(sp->s_namlen)); /* or sndp->ni_cred?*/
986: nfsm_fhtom(sndp->ni_dvp);
987: nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
988: nfsm_fhtom(sp->s_dvp);
989: nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
990: nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1);
991: nfsm_reqdone;
992: FREE(sndp->ni_pnbuf, M_NAMEI);
993: VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
994: VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
995: return (error);
996: }
997:
998: /*
999: * nfs hard link create call
1000: */
1001: nfs_link(vp, ndp, p)
1002: register struct vnode *vp;
1003: register struct nameidata *ndp;
1004: struct proc *p;
1005: {
1006: register u_long *tl;
1007: register caddr_t cp;
1008: register long t1, t2;
1009: caddr_t bpos, dpos;
1010: u_long xid;
1011: int error = 0;
1012: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1013:
1014: if (ndp->ni_dvp != vp)
1015: nfs_lock(vp);
1016: nfsstats.rpccnt[NFSPROC_LINK]++;
1017: nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
1018: NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
1019: nfsm_fhtom(vp);
1020: nfsm_fhtom(ndp->ni_dvp);
1021: nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
1022: nfsm_request(vp, NFSPROC_LINK, p, 1);
1023: nfsm_reqdone;
1024: FREE(ndp->ni_pnbuf, M_NAMEI);
1025: VTONFS(vp)->n_attrstamp = 0;
1026: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
1027: if (ndp->ni_dvp != vp)
1028: nfs_unlock(vp);
1029: nfs_nput(ndp->ni_dvp);
1030: /*
1031: * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1032: */
1033: if (error == EEXIST)
1034: error = 0;
1035: return (error);
1036: }
1037:
1038: /*
1039: * nfs symbolic link create call
1040: */
1041: nfs_symlink(ndp, vap, nm, p)
1042: struct nameidata *ndp;
1043: struct vattr *vap;
1044: char *nm; /* is this the path ?? */
1045: struct proc *p;
1046: {
1047: register struct nfsv2_sattr *sp;
1048: register u_long *tl;
1049: register caddr_t cp;
1050: register long t1, t2;
1051: caddr_t bpos, dpos;
1052: u_long xid;
1053: int error = 0;
1054: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1055:
1056: nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1057: nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
1058: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_UNSIGNED);
1059: nfsm_fhtom(ndp->ni_dvp);
1060: nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
1061: nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
1062: nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
1063: sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
1064: sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
1065: sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
1066: sp->sa_size = txdr_unsigned(VNOVAL);
1067: txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */
1068: txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */
1069: nfsm_request(ndp->ni_dvp, NFSPROC_SYMLINK, p, 1);
1070: nfsm_reqdone;
1071: FREE(ndp->ni_pnbuf, M_NAMEI);
1072: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
1073: nfs_nput(ndp->ni_dvp);
1074: /*
1075: * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1076: */
1077: if (error == EEXIST)
1078: error = 0;
1079: return (error);
1080: }
1081:
1082: /*
1083: * nfs make dir call
1084: */
1085: nfs_mkdir(ndp, vap, p)
1086: register struct nameidata *ndp;
1087: struct vattr *vap;
1088: struct proc *p;
1089: {
1090: register struct nfsv2_sattr *sp;
1091: register u_long *tl;
1092: register caddr_t cp;
1093: register long t1, t2;
1094: register int len;
1095: caddr_t bpos, dpos, cp2;
1096: u_long xid;
1097: int error = 0, firsttry = 1;
1098: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1099:
1100: len = ndp->ni_namelen;
1101: nfsstats.rpccnt[NFSPROC_MKDIR]++;
1102: nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
1103: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
1104: nfsm_fhtom(ndp->ni_dvp);
1105: nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
1106: nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
1107: sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
1108: sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
1109: sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
1110: sp->sa_size = txdr_unsigned(VNOVAL);
1111: txdr_time(&vap->va_atime, &sp->sa_atime); /* or VNOVAL ?? */
1112: txdr_time(&vap->va_mtime, &sp->sa_mtime); /* or VNOVAL ?? */
1113: nfsm_request(ndp->ni_dvp, NFSPROC_MKDIR, p, 1);
1114: nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
1115: nfsm_reqdone;
1116: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
1117: /*
1118: * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1119: * if we can succeed in looking up the directory.
1120: * "firsttry" is necessary since the macros may "goto nfsmout" which
1121: * is above the if on errors. (Ugh)
1122: */
1123: if (error == EEXIST && firsttry) {
1124: firsttry = 0;
1125: error = 0;
1126: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1127: ndp->ni_vp = NULL;
1128: nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred,
1129: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1130: nfsm_fhtom(ndp->ni_dvp);
1131: nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
1132: nfsm_request(ndp->ni_dvp, NFSPROC_LOOKUP, p, 1);
1133: nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
1134: if (ndp->ni_vp->v_type != VDIR) {
1135: vput(ndp->ni_vp);
1136: error = EEXIST;
1137: }
1138: m_freem(mrep);
1139: }
1140: FREE(ndp->ni_pnbuf, M_NAMEI);
1141: nfs_nput(ndp->ni_dvp);
1142: return (error);
1143: }
1144:
1145: /*
1146: * nfs remove directory call
1147: */
1148: nfs_rmdir(ndp, p)
1149: register struct nameidata *ndp;
1150: struct proc *p;
1151: {
1152: register u_long *tl;
1153: register caddr_t cp;
1154: register long t1, t2;
1155: caddr_t bpos, dpos;
1156: u_long xid;
1157: int error = 0;
1158: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1159:
1160: if (ndp->ni_dvp == ndp->ni_vp) {
1161: vrele(ndp->ni_dvp);
1162: nfs_nput(ndp->ni_dvp);
1163: return (EINVAL);
1164: }
1165: nfsstats.rpccnt[NFSPROC_RMDIR]++;
1166: nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
1167: NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
1168: nfsm_fhtom(ndp->ni_dvp);
1169: nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
1170: nfsm_request(ndp->ni_dvp, NFSPROC_RMDIR, p, 1);
1171: nfsm_reqdone;
1172: FREE(ndp->ni_pnbuf, M_NAMEI);
1173: VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
1174: cache_purge(ndp->ni_dvp);
1175: cache_purge(ndp->ni_vp);
1176: nfs_nput(ndp->ni_vp);
1177: nfs_nput(ndp->ni_dvp);
1178: /*
1179: * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1180: */
1181: if (error == ENOENT)
1182: error = 0;
1183: return (error);
1184: }
1185:
1186: /*
1187: * nfs readdir call
1188: * Although cookie is defined as opaque, I translate it to/from net byte
1189: * order so that it looks more sensible. This appears consistent with the
1190: * Ultrix implementation of NFS.
1191: */
1192: nfs_readdir(vp, uiop, cred, eofflagp)
1193: register struct vnode *vp;
1194: struct uio *uiop;
1195: struct ucred *cred;
1196: int *eofflagp;
1197: {
1198: register struct nfsnode *np = VTONFS(vp);
1199: int tresid, error;
1200: struct vattr vattr;
1201:
1202: if (vp->v_type != VDIR)
1203: return (EPERM);
1204: /*
1205: * First, check for hit on the EOF offset cache
1206: */
1207: if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset &&
1208: (np->n_flag & NMODIFIED) == 0 &&
1209: nfs_dogetattr(vp, &vattr, cred, 0, uiop->uio_procp) == 0 &&
1210: np->n_mtime == vattr.va_mtime.tv_sec) {
1211: *eofflagp = 1;
1212: nfsstats.direofcache_hits++;
1213: return (0);
1214: }
1215:
1216: /*
1217: * Call nfs_bioread() to do the real work.
1218: */
1219: tresid = uiop->uio_resid;
1220: error = nfs_bioread(vp, uiop, 0, cred);
1221:
1222: if (!error && uiop->uio_resid == tresid) {
1223: *eofflagp = 1;
1224: nfsstats.direofcache_misses++;
1225: } else
1226: *eofflagp = 0;
1227: return (error);
1228: }
1229:
1230: /*
1231: * Readdir rpc call.
1232: * Called from below the buffer cache by nfs_doio().
1233: */
1234: nfs_readdirrpc(vp, uiop, cred)
1235: register struct vnode *vp;
1236: struct uio *uiop;
1237: struct ucred *cred;
1238: {
1239: register long len;
1240: register struct direct *dp;
1241: register u_long *tl;
1242: register caddr_t cp;
1243: register long t1;
1244: long tlen, lastlen;
1245: caddr_t bpos, dpos, cp2;
1246: u_long xid;
1247: int error = 0;
1248: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1249: struct mbuf *md2;
1250: caddr_t dpos2;
1251: int siz;
1252: int more_dirs = 1;
1253: off_t off, savoff;
1254: struct direct *savdp;
1255: struct nfsmount *nmp;
1256: struct nfsnode *np = VTONFS(vp);
1257: long tresid;
1258:
1259: nmp = VFSTONFS(vp->v_mount);
1260: tresid = uiop->uio_resid;
1261: /*
1262: * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
1263: * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
1264: * The stopping criteria is EOF or buffer full.
1265: */
1266: while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
1267: nfsstats.rpccnt[NFSPROC_READDIR]++;
1268: nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
1269: nfsm_fhtom(vp);
1270: nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1271: *tl++ = txdr_unsigned(uiop->uio_offset);
1272: *tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1273: nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
1274: nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, 0);
1275: siz = 0;
1276: nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
1277: more_dirs = fxdr_unsigned(int, *tl);
1278:
1279: /* Save the position so that we can do nfsm_mtouio() later */
1280: dpos2 = dpos;
1281: md2 = md;
1282:
1283: /* loop thru the dir entries, doctoring them to 4bsd form */
1284: off = uiop->uio_offset;
1285: #ifdef lint
1286: dp = (struct direct *)0;
1287: #endif /* lint */
1288: while (more_dirs && siz < uiop->uio_resid) {
1289: savoff = off; /* Hold onto offset and dp */
1290: savdp = dp;
1291: nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED);
1292: dp = (struct direct *)tl;
1293: dp->d_ino = fxdr_unsigned(u_long, *tl++);
1294: len = fxdr_unsigned(int, *tl);
1295: if (len <= 0 || len > NFS_MAXNAMLEN) {
1296: error = EBADRPC;
1297: m_freem(mrep);
1298: goto nfsmout;
1299: }
1300: dp->d_namlen = (u_short)len;
1301: nfsm_adv(len); /* Point past name */
1302: tlen = nfsm_rndup(len);
1303: /*
1304: * This should not be necessary, but some servers have
1305: * broken XDR such that these bytes are not null filled.
1306: */
1307: if (tlen != len) {
1308: *dpos = '\0'; /* Null-terminate */
1309: nfsm_adv(tlen - len);
1310: len = tlen;
1311: }
1312: nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED);
1313: off = fxdr_unsigned(off_t, *tl);
1314: *tl++ = 0; /* Ensures null termination of name */
1315: more_dirs = fxdr_unsigned(int, *tl);
1316: dp->d_reclen = len+4*NFSX_UNSIGNED;
1317: siz += dp->d_reclen;
1318: }
1319: /*
1320: * If at end of rpc data, get the eof boolean
1321: */
1322: if (!more_dirs) {
1323: nfsm_disecton(tl, u_long *, NFSX_UNSIGNED);
1324: more_dirs = (fxdr_unsigned(int, *tl) == 0);
1325:
1326: /*
1327: * If at EOF, cache directory offset
1328: */
1329: if (!more_dirs)
1330: np->n_direofoffset = off;
1331: }
1332: /*
1333: * If there is too much to fit in the data buffer, use savoff and
1334: * savdp to trim off the last record.
1335: * --> we are not at eof
1336: */
1337: if (siz > uiop->uio_resid) {
1338: off = savoff;
1339: siz -= dp->d_reclen;
1340: dp = savdp;
1341: more_dirs = 0; /* Paranoia */
1342: }
1343: if (siz > 0) {
1344: lastlen = dp->d_reclen;
1345: md = md2;
1346: dpos = dpos2;
1347: nfsm_mtouio(uiop, siz);
1348: uiop->uio_offset = off;
1349: } else
1350: more_dirs = 0; /* Ugh, never happens, but in case.. */
1351: m_freem(mrep);
1352: }
1353: /*
1354: * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
1355: * by increasing d_reclen for the last record.
1356: */
1357: if (uiop->uio_resid < tresid) {
1358: len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1359: if (len > 0) {
1360: dp = (struct direct *)
1361: (uiop->uio_iov->iov_base - lastlen);
1362: dp->d_reclen += len;
1363: uiop->uio_iov->iov_base += len;
1364: uiop->uio_iov->iov_len -= len;
1365: uiop->uio_resid -= len;
1366: }
1367: }
1368: nfsmout:
1369: return (error);
1370: }
1371:
1372: static char hextoasc[] = "0123456789abcdef";
1373:
1374: /*
1375: * Silly rename. To make the NFS filesystem that is stateless look a little
1376: * more like the "ufs" a remove of an active vnode is translated to a rename
1377: * to a funny looking filename that is removed by nfs_inactive on the
1378: * nfsnode. There is the potential for another process on a different client
1379: * to create the same funny name between the nfs_lookitup() fails and the
1380: * nfs_rename() completes, but...
1381: */
1382: nfs_sillyrename(ndp, p)
1383: register struct nameidata *ndp;
1384: struct proc *p;
1385: {
1386: register struct nfsnode *np;
1387: register struct sillyrename *sp;
1388: int error;
1389: short pid;
1390:
1391: np = VTONFS(ndp->ni_dvp);
1392: cache_purge(ndp->ni_dvp);
1393: MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
1394: M_NFSREQ, M_WAITOK);
1395: bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
1396: np = VTONFS(ndp->ni_vp);
1397: sp->s_cred = crdup(ndp->ni_cred);
1398: sp->s_dvp = ndp->ni_dvp;
1399: VREF(sp->s_dvp);
1400:
1401: /* Fudge together a funny name */
1402: pid = p->p_pid;
1403: bcopy(".nfsAxxxx4.4", sp->s_name, 13);
1404: sp->s_namlen = 12;
1405: sp->s_name[8] = hextoasc[pid & 0xf];
1406: sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
1407: sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
1408: sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
1409:
1410: /* Try lookitups until we get one that isn't there */
1411: while (nfs_lookitup(sp, (nfsv2fh_t *)0, p) == 0) {
1412: sp->s_name[4]++;
1413: if (sp->s_name[4] > 'z') {
1414: error = EINVAL;
1415: goto bad;
1416: }
1417: }
1418: if (error = nfs_renameit(ndp, sp, p))
1419: goto bad;
1420: nfs_lookitup(sp, &np->n_fh, p);
1421: np->n_sillyrename = sp;
1422: return (0);
1423: bad:
1424: vrele(sp->s_dvp);
1425: crfree(sp->s_cred);
1426: free((caddr_t)sp, M_NFSREQ);
1427: return (error);
1428: }
1429:
1430: /*
1431: * Look up a file name for silly rename stuff.
1432: * Just like nfs_lookup() except that it doesn't load returned values
1433: * into the nfsnode table.
1434: * If fhp != NULL it copies the returned file handle out
1435: */
1436: nfs_lookitup(sp, fhp, p)
1437: register struct sillyrename *sp;
1438: nfsv2fh_t *fhp;
1439: struct proc *p;
1440: {
1441: register struct vnode *vp = sp->s_dvp;
1442: register u_long *tl;
1443: register caddr_t cp;
1444: register long t1, t2;
1445: caddr_t bpos, dpos, cp2;
1446: u_long xid;
1447: int error = 0;
1448: struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1449: long len;
1450:
1451: nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1452: len = sp->s_namlen;
1453: nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], sp->s_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1454: nfsm_fhtom(vp);
1455: nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
1456: nfsm_request(vp, NFSPROC_LOOKUP, p, 1);
1457: if (fhp != NULL) {
1458: nfsm_disect(cp, caddr_t, NFSX_FH);
1459: bcopy(cp, (caddr_t)fhp, NFSX_FH);
1460: }
1461: nfsm_reqdone;
1462: return (error);
1463: }
1464:
1465: /*
1466: * Kludge City..
1467: * - make nfs_bmap() essentially a no-op that does no translation
1468: * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
1469: * after mapping the physical addresses into Kernel Virtual space in the
1470: * nfsiobuf area.
1471: * (Maybe I could use the process's page mapping, but I was concerned that
1472: * Kernel Write might not be enabled and also figured copyout() would do
1473: * a lot more work than bcopy() and also it currently happens in the
1474: * context of the swapper process (2).
1475: */
1476: nfs_bmap(vp, bn, vpp, bnp)
1477: struct vnode *vp;
1478: daddr_t bn;
1479: struct vnode **vpp;
1480: daddr_t *bnp;
1481: {
1482: if (vpp != NULL)
1483: *vpp = vp;
1484: if (bnp != NULL)
1485: *bnp = bn * btodb(vp->v_mount->mnt_stat.f_bsize);
1486: return (0);
1487: }
1488:
1489: /*
1490: * Strategy routine for phys. i/o
1491: * If the biod's are running, queue a request
1492: * otherwise just call nfs_doio() to get it done
1493: */
1494: nfs_strategy(bp)
1495: register struct buf *bp;
1496: {
1497: register struct buf *dp;
1498: register int i;
1499: int error = 0;
1500: int fnd = 0;
1501:
1502: /*
1503: * Set b_proc. It seems a bit silly to do it here, but since bread()
1504: * doesn't set it, I will.
1505: * Set b_proc == NULL for asynchronous ops, since these may still
1506: * be hanging about after the process terminates.
1507: */
1508: if ((bp->b_flags & B_PHYS) == 0) {
1509: if (bp->b_flags & B_ASYNC)
1510: bp->b_proc = (struct proc *)0;
1511: else
1512: bp->b_proc = curproc;
1513: }
1514: /*
1515: * If the op is asynchronous and an i/o daemon is waiting
1516: * queue the request, wake it up and wait for completion
1517: * otherwise just do it ourselves.
1518: */
1519: if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
1520: return (nfs_doio(bp));
1521: for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1522: if (nfs_iodwant[i]) {
1523: dp = &nfs_bqueue;
1524: if (dp->b_actf == NULL) {
1525: dp->b_actl = bp;
1526: bp->b_actf = dp;
1527: } else {
1528: dp->b_actf->b_actl = bp;
1529: bp->b_actf = dp->b_actf;
1530: }
1531: dp->b_actf = bp;
1532: bp->b_actl = dp;
1533: fnd++;
1534: wakeup((caddr_t)&nfs_iodwant[i]);
1535: break;
1536: }
1537: }
1538: if (!fnd)
1539: error = nfs_doio(bp);
1540: return (error);
1541: }
1542:
1543: /*
1544: * Fun and games with i/o
1545: * Essentially play ubasetup() and disk interrupt service routine by
1546: * mapping the data buffer into kernel virtual space and doing the
1547: * nfs read or write rpc's from it.
1548: * If the nfsiod's are not running, this is just called from nfs_strategy(),
1549: * otherwise it is called by the nfsiods to do what would normally be
1550: * partially disk interrupt driven.
1551: */
1552: nfs_doio(bp)
1553: register struct buf *bp;
1554: {
1555: register struct uio *uiop;
1556: register struct vnode *vp;
1557: struct nfsnode *np;
1558: struct ucred *cr;
1559: int error;
1560: struct uio uio;
1561: struct iovec io;
1562: #if !defined(hp300) && !defined(i386)
1563: register struct pte *pte, *ppte;
1564: register caddr_t vaddr;
1565: int npf, npf2;
1566: int reg, o;
1567: caddr_t vbase;
1568: unsigned v;
1569: #endif
1570:
1571: vp = bp->b_vp;
1572: np = VTONFS(vp);
1573: uiop = &uio;
1574: uiop->uio_iov = &io;
1575: uiop->uio_iovcnt = 1;
1576: uiop->uio_segflg = UIO_SYSSPACE;
1577: uiop->uio_procp = (struct proc *)0;
1578:
1579: /*
1580: * For phys i/o, map the b_addr into kernel virtual space using
1581: * the Nfsiomap pte's
1582: * Also, add a temporary b_rcred for reading using the process's uid
1583: * and a guess at a group
1584: */
1585: if (bp->b_flags & B_PHYS) {
1586: if (bp->b_flags & B_DIRTY)
1587: uiop->uio_procp = pageproc;
1588: cr = crcopy(uiop->uio_procp->p_ucred);
1589: #if defined(hp300) || defined(i386)
1590: /* mapping was already done by vmapbuf */
1591: io.iov_base = bp->b_un.b_addr;
1592: #else
1593: o = (int)bp->b_un.b_addr & PGOFSET;
1594: npf2 = npf = btoc(bp->b_bcount + o);
1595:
1596: /*
1597: * Get some mapping page table entries
1598: */
1599: while ((reg = rmalloc(nfsmap, (long)npf)) == 0) {
1600: nfsmap_want++;
1601: (void) tsleep((caddr_t)&nfsmap_want, PZERO-1, "nfsmap",
1602: 0);
1603: }
1604: reg--;
1605: if (bp->b_flags & B_PAGET)
1606: pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
1607: else {
1608: v = btop(bp->b_un.b_addr);
1609: if (bp->b_flags & B_UAREA)
1610: pte = &uiop->uio_procp->p_addr[v];
1611: else
1612: pte = vtopte(uiop->uio_procp, v);
1613: }
1614:
1615: /*
1616: * Play vmaccess() but with the Nfsiomap page table
1617: */
1618: ppte = &Nfsiomap[reg];
1619: vbase = vaddr = &nfsiobuf[reg*NBPG];
1620: while (npf != 0) {
1621: mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW));
1622: #if defined(tahoe)
1623: mtpr(P1DC, vaddr);
1624: #endif
1625: ppte++;
1626: pte++;
1627: vaddr += NBPG;
1628: --npf;
1629: }
1630: io.iov_base = vbase+o;
1631: #endif /* !defined(hp300) */
1632:
1633: /*
1634: * And do the i/o rpc
1635: */
1636: io.iov_len = uiop->uio_resid = bp->b_bcount;
1637: uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
1638: if (bp->b_flags & B_READ) {
1639: uiop->uio_rw = UIO_READ;
1640: nfsstats.read_physios++;
1641: bp->b_error = error = nfs_readrpc(vp, uiop, cr);
1642: (void) vnode_pager_uncache(vp);
1643: } else {
1644: uiop->uio_rw = UIO_WRITE;
1645: nfsstats.write_physios++;
1646: bp->b_error = error = nfs_writerpc(vp, uiop, cr);
1647: }
1648:
1649: /*
1650: * Finally, release pte's used by physical i/o
1651: */
1652: crfree(cr);
1653: #if !defined(hp300) && !defined(i386)
1654: rmfree(nfsmap, (long)npf2, (long)++reg);
1655: if (nfsmap_want) {
1656: nfsmap_want = 0;
1657: wakeup((caddr_t)&nfsmap_want);
1658: }
1659: #endif
1660: } else {
1661: if (bp->b_flags & B_READ) {
1662: io.iov_len = uiop->uio_resid = bp->b_bcount;
1663: io.iov_base = bp->b_un.b_addr;
1664: uiop->uio_rw = UIO_READ;
1665: switch (vp->v_type) {
1666: case VREG:
1667: uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
1668: nfsstats.read_bios++;
1669: error = nfs_readrpc(vp, uiop, bp->b_rcred);
1670: break;
1671: case VLNK:
1672: uiop->uio_offset = 0;
1673: nfsstats.readlink_bios++;
1674: error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
1675: break;
1676: case VDIR:
1677: uiop->uio_offset = bp->b_lblkno;
1678: nfsstats.readdir_bios++;
1679: error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
1680: /*
1681: * Save offset cookie in b_blkno.
1682: */
1683: bp->b_blkno = uiop->uio_offset;
1684: break;
1685: };
1686: bp->b_error = error;
1687: } else {
1688: io.iov_len = uiop->uio_resid = bp->b_dirtyend
1689: - bp->b_dirtyoff;
1690: uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
1691: + bp->b_dirtyoff;
1692: io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
1693: uiop->uio_rw = UIO_WRITE;
1694: nfsstats.write_bios++;
1695: bp->b_error = error = nfs_writerpc(vp, uiop,
1696: bp->b_wcred);
1697: if (error) {
1698: np->n_error = error;
1699: np->n_flag |= NWRITEERR;
1700: }
1701: bp->b_dirtyoff = bp->b_dirtyend = 0;
1702: }
1703: }
1704: if (error)
1705: bp->b_flags |= B_ERROR;
1706: bp->b_resid = uiop->uio_resid;
1707: biodone(bp);
1708: return (error);
1709: }
1710:
1711: /*
1712: * Mmap a file
1713: *
1714: * NB Currently unsupported.
1715: */
1716: /* ARGSUSED */
1717: nfs_mmap(vp, fflags, cred, p)
1718: struct vnode *vp;
1719: int fflags;
1720: struct ucred *cred;
1721: struct proc *p;
1722: {
1723:
1724: return (EINVAL);
1725: }
1726:
1727: /*
1728: * Flush all the blocks associated with a vnode.
1729: * Walk through the buffer pool and push any dirty pages
1730: * associated with the vnode.
1731: */
1732: /* ARGSUSED */
1733: nfs_fsync(vp, fflags, cred, waitfor, p)
1734: register struct vnode *vp;
1735: int fflags;
1736: struct ucred *cred;
1737: int waitfor;
1738: struct proc *p;
1739: {
1740: register struct nfsnode *np = VTONFS(vp);
1741: int error = 0;
1742:
1743: if (np->n_flag & NMODIFIED) {
1744: np->n_flag &= ~NMODIFIED;
1745: vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
1746: }
1747: if (!error && (np->n_flag & NWRITEERR))
1748: error = np->n_error;
1749: return (error);
1750: }
1751:
1752: /*
1753: * NFS advisory byte-level locks.
1754: * Currently unsupported.
1755: */
1756: nfs_advlock(vp, id, op, fl, flags)
1757: struct vnode *vp;
1758: caddr_t id;
1759: int op;
1760: struct flock *fl;
1761: int flags;
1762: {
1763:
1764: return (EOPNOTSUPP);
1765: }
1766:
1767: /*
1768: * Print out the contents of an nfsnode.
1769: */
1770: nfs_print(vp)
1771: struct vnode *vp;
1772: {
1773: register struct nfsnode *np = VTONFS(vp);
1774:
1775: printf("tag VT_NFS, fileid %d fsid 0x%x",
1776: np->n_vattr.va_fileid, np->n_vattr.va_fsid);
1777: #ifdef FIFO
1778: if (vp->v_type == VFIFO)
1779: fifo_printinfo(vp);
1780: #endif /* FIFO */
1781: printf("%s\n", (np->n_flag & NLOCKED) ? " (LOCKED)" : "");
1782: if (np->n_lockholder == 0)
1783: return;
1784: printf("\towner pid %d", np->n_lockholder);
1785: if (np->n_lockwaiter)
1786: printf(" waiting pid %d", np->n_lockwaiter);
1787: printf("\n");
1788: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.