new IBM 8512 High Function Terminal (HFT) entry
[unix-history] / usr / src / sys / kern / vfs_subr.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * @(#)vfs_subr.c 7.38 (Berkeley) %G%
18 */
19
20/*
21 * External virtual filesystem routines
22 */
23
24#include "param.h"
25#include "mount.h"
26#include "time.h"
27#include "vnode.h"
28#include "specdev.h"
29#include "namei.h"
30#include "ucred.h"
31#include "errno.h"
32#include "malloc.h"
33
34/*
35 * Remove a mount point from the list of mounted filesystems.
36 * Unmount of the root is illegal.
37 */
38void
39vfs_remove(mp)
40 register struct mount *mp;
41{
42
43 if (mp == rootfs)
44 panic("vfs_remove: unmounting root");
45 mp->m_prev->m_next = mp->m_next;
46 mp->m_next->m_prev = mp->m_prev;
47 mp->m_vnodecovered->v_mountedhere = (struct mount *)0;
48 vfs_unlock(mp);
49}
50
51/*
52 * Lock a filesystem.
53 * Used to prevent access to it while mounting and unmounting.
54 */
55vfs_lock(mp)
56 register struct mount *mp;
57{
58
59 while(mp->m_flag & M_MLOCK) {
60 mp->m_flag |= M_MWAIT;
61 sleep((caddr_t)mp, PVFS);
62 }
63 mp->m_flag |= M_MLOCK;
64 return (0);
65}
66
67/*
68 * Unlock a locked filesystem.
69 * Panic if filesystem is not locked.
70 */
71void
72vfs_unlock(mp)
73 register struct mount *mp;
74{
75
76 if ((mp->m_flag & M_MLOCK) == 0)
77 panic("vfs_unlock: locked fs");
78 mp->m_flag &= ~M_MLOCK;
79 if (mp->m_flag & M_MWAIT) {
80 mp->m_flag &= ~M_MWAIT;
81 wakeup((caddr_t)mp);
82 }
83}
84
85/*
86 * Lookup a mount point by filesystem identifier.
87 */
88struct mount *
89getvfs(fsid)
90 fsid_t *fsid;
91{
92 register struct mount *mp;
93
94 mp = rootfs;
95 do {
96 if (mp->m_stat.f_fsid.val[0] == fsid->val[0] &&
97 mp->m_stat.f_fsid.val[1] == fsid->val[1]) {
98 return (mp);
99 }
100 mp = mp->m_next;
101 } while (mp != rootfs);
102 return ((struct mount *)0);
103}
104
105/*
106 * Set vnode attributes to VNOVAL
107 */
108void vattr_null(vap)
109 register struct vattr *vap;
110{
111
112 vap->va_type = VNON;
113 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
114 vap->va_fsid = vap->va_fileid = vap->va_size =
115 vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
116 vap->va_bytes = vap->va_bytes_rsv =
117 vap->va_atime.tv_sec = vap->va_atime.tv_usec =
118 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
119 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
120 vap->va_flags = vap->va_gen = VNOVAL;
121}
122
123/*
124 * Initialize a nameidata structure
125 */
126ndinit(ndp)
127 register struct nameidata *ndp;
128{
129
130 bzero((caddr_t)ndp, sizeof(struct nameidata));
131 ndp->ni_iov = &ndp->ni_nd.nd_iovec;
132 ndp->ni_iovcnt = 1;
133 ndp->ni_base = (caddr_t)&ndp->ni_dent;
134 ndp->ni_rw = UIO_WRITE;
135 ndp->ni_uioseg = UIO_SYSSPACE;
136}
137
138/*
139 * Duplicate a nameidata structure
140 */
141nddup(ndp, newndp)
142 register struct nameidata *ndp, *newndp;
143{
144
145 ndinit(newndp);
146 newndp->ni_cdir = ndp->ni_cdir;
147 VREF(newndp->ni_cdir);
148 newndp->ni_rdir = ndp->ni_rdir;
149 if (newndp->ni_rdir)
150 VREF(newndp->ni_rdir);
151 newndp->ni_cred = ndp->ni_cred;
152 crhold(newndp->ni_cred);
153}
154
155/*
156 * Release a nameidata structure
157 */
158ndrele(ndp)
159 register struct nameidata *ndp;
160{
161
162 vrele(ndp->ni_cdir);
163 if (ndp->ni_rdir)
164 vrele(ndp->ni_rdir);
165 crfree(ndp->ni_cred);
166}
167
168/*
169 * Routines having to do with the management of the vnode table.
170 */
171struct vnode *vfreeh, **vfreet;
172extern struct vnodeops dead_vnodeops, spec_vnodeops;
173extern void vclean();
174long numvnodes;
175
176/*
177 * Initialize the vnode structures and initialize each file system type.
178 */
179vfsinit()
180{
181 struct vfsops **vfsp;
182
183 /*
184 * Initialize the vnode name cache
185 */
186 nchinit();
187 /*
188 * Initialize each file system type.
189 */
190 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
191 if (*vfsp == NULL)
192 continue;
193 (*(*vfsp)->vfs_init)();
194 }
195}
196
197/*
198 * Return the next vnode from the free list.
199 */
200getnewvnode(tag, mp, vops, vpp)
201 enum vtagtype tag;
202 struct mount *mp;
203 struct vnodeops *vops;
204 struct vnode **vpp;
205{
206 register struct vnode *vp, *vq;
207
208 if (numvnodes < desiredvnodes) {
209 vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
210 bzero((char *)vp, sizeof *vp);
211 numvnodes++;
212 } else {
213 if ((vp = vfreeh) == NULL) {
214 tablefull("vnode");
215 *vpp = 0;
216 return (ENFILE);
217 }
218 if (vp->v_usecount)
219 panic("free vnode isn't");
220 if (vq = vp->v_freef)
221 vq->v_freeb = &vfreeh;
222 else
223 vfreet = &vfreeh;
224 vfreeh = vq;
225 vp->v_freef = NULL;
226 vp->v_freeb = NULL;
227 if (vp->v_type != VBAD)
228 vgone(vp);
229 vp->v_flag = 0;
230 vp->v_shlockc = 0;
231 vp->v_exlockc = 0;
232 vp->v_lastr = 0;
233 vp->v_socket = 0;
234 }
235 vp->v_type = VNON;
236 cache_purge(vp);
237 vp->v_tag = tag;
238 vp->v_op = vops;
239 insmntque(vp, mp);
240 VREF(vp);
241 *vpp = vp;
242 return (0);
243}
244
245/*
246 * Move a vnode from one mount queue to another.
247 */
248insmntque(vp, mp)
249 register struct vnode *vp;
250 register struct mount *mp;
251{
252 struct vnode *vq;
253
254 /*
255 * Delete from old mount point vnode list, if on one.
256 */
257 if (vp->v_mountb) {
258 if (vq = vp->v_mountf)
259 vq->v_mountb = vp->v_mountb;
260 *vp->v_mountb = vq;
261 }
262 /*
263 * Insert into list of vnodes for the new mount point, if available.
264 */
265 vp->v_mount = mp;
266 if (mp == NULL) {
267 vp->v_mountf = NULL;
268 vp->v_mountb = NULL;
269 return;
270 }
271 if (mp->m_mounth) {
272 vp->v_mountf = mp->m_mounth;
273 vp->v_mountb = &mp->m_mounth;
274 mp->m_mounth->v_mountb = &vp->v_mountf;
275 mp->m_mounth = vp;
276 } else {
277 mp->m_mounth = vp;
278 vp->v_mountb = &mp->m_mounth;
279 vp->v_mountf = NULL;
280 }
281}
282
283/*
284 * Create a vnode for a block device.
285 * Used for root filesystem, argdev, and swap areas.
286 * Also used for memory file system special devices.
287 */
288bdevvp(dev, vpp)
289 dev_t dev;
290 struct vnode **vpp;
291{
292 register struct vnode *vp;
293 struct vnode *nvp;
294 int error;
295
296 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
297 if (error) {
298 *vpp = 0;
299 return (error);
300 }
301 vp = nvp;
302 vp->v_type = VBLK;
303 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
304 vput(vp);
305 vp = nvp;
306 }
307 *vpp = vp;
308 return (0);
309}
310
311/*
312 * Check to see if the new vnode represents a special device
313 * for which we already have a vnode (either because of
314 * bdevvp() or because of a different vnode representing
315 * the same block device). If such an alias exists, deallocate
316 * the existing contents and return the aliased vnode. The
317 * caller is responsible for filling it with its new contents.
318 */
319struct vnode *
320checkalias(nvp, nvp_rdev, mp)
321 register struct vnode *nvp;
322 dev_t nvp_rdev;
323 struct mount *mp;
324{
325 register struct vnode *vp;
326 struct vnode **vpp;
327
328 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
329 return ((struct vnode *)0);
330
331 vpp = &speclisth[SPECHASH(nvp_rdev)];
332loop:
333 for (vp = *vpp; vp; vp = vp->v_specnext) {
334 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
335 continue;
336 /*
337 * Alias, but not in use, so flush it out.
338 */
339 if (vp->v_usecount == 0) {
340 vgone(vp);
341 goto loop;
342 }
343 if (vget(vp))
344 goto loop;
345 break;
346 }
347 if (vp == NULL || vp->v_tag != VT_NON) {
348 MALLOC(nvp->v_specinfo, struct specinfo *,
349 sizeof(struct specinfo), M_VNODE, M_WAITOK);
350 nvp->v_rdev = nvp_rdev;
351 nvp->v_hashchain = vpp;
352 nvp->v_specnext = *vpp;
353 *vpp = nvp;
354 if (vp != NULL) {
355 nvp->v_flag |= VALIASED;
356 vp->v_flag |= VALIASED;
357 vput(vp);
358 }
359 return ((struct vnode *)0);
360 }
361 VOP_UNLOCK(vp);
362 vclean(vp, 0);
363 vp->v_op = nvp->v_op;
364 vp->v_tag = nvp->v_tag;
365 nvp->v_type = VNON;
366 insmntque(vp, mp);
367 return (vp);
368}
369
370/*
371 * Grab a particular vnode from the free list, increment its
372 * reference count and lock it. The vnode lock bit is set the
373 * vnode is being eliminated in vgone. The process is awakened
374 * when the transition is completed, and an error returned to
375 * indicate that the vnode is no longer usable (possibly having
376 * been changed to a new file system type).
377 */
378vget(vp)
379 register struct vnode *vp;
380{
381 register struct vnode *vq;
382
383 if (vp->v_flag & VXLOCK) {
384 vp->v_flag |= VXWANT;
385 sleep((caddr_t)vp, PINOD);
386 return (1);
387 }
388 if (vp->v_usecount == 0) {
389 if (vq = vp->v_freef)
390 vq->v_freeb = vp->v_freeb;
391 else
392 vfreet = vp->v_freeb;
393 *vp->v_freeb = vq;
394 vp->v_freef = NULL;
395 vp->v_freeb = NULL;
396 }
397 VREF(vp);
398 VOP_LOCK(vp);
399 return (0);
400}
401
402/*
403 * Vnode reference, just increment the count
404 */
405void vref(vp)
406 struct vnode *vp;
407{
408
409 vp->v_usecount++;
410}
411
412/*
413 * vput(), just unlock and vrele()
414 */
415void vput(vp)
416 register struct vnode *vp;
417{
418 VOP_UNLOCK(vp);
419 vrele(vp);
420}
421
422/*
423 * Vnode release.
424 * If count drops to zero, call inactive routine and return to freelist.
425 */
426void vrele(vp)
427 register struct vnode *vp;
428{
429
430 if (vp == NULL)
431 panic("vrele: null vp");
432 vp->v_usecount--;
433 if (vp->v_usecount < 0)
434 vprint("vrele: bad ref count", vp);
435 if (vp->v_usecount > 0)
436 return;
437 if (vfreeh == (struct vnode *)0) {
438 /*
439 * insert into empty list
440 */
441 vfreeh = vp;
442 vp->v_freeb = &vfreeh;
443 } else {
444 /*
445 * insert at tail of list
446 */
447 *vfreet = vp;
448 vp->v_freeb = vfreet;
449 }
450 vp->v_freef = NULL;
451 vfreet = &vp->v_freef;
452 VOP_INACTIVE(vp);
453}
454
455/*
456 * Page or buffer structure gets a reference.
457 */
458vhold(vp)
459 register struct vnode *vp;
460{
461
462 vp->v_holdcnt++;
463}
464
465/*
466 * Page or buffer structure frees a reference.
467 */
468holdrele(vp)
469 register struct vnode *vp;
470{
471
472 if (vp->v_holdcnt <= 0)
473 panic("holdrele: holdcnt");
474 vp->v_holdcnt--;
475}
476
477/*
478 * Remove any vnodes in the vnode table belonging to mount point mp.
479 *
480 * If MNT_NOFORCE is specified, there should not be any active ones,
481 * return error if any are found (nb: this is a user error, not a
482 * system error). If MNT_FORCE is specified, detach any active vnodes
483 * that are found.
484 */
485int busyprt = 0; /* patch to print out busy vnodes */
486
487vflush(mp, skipvp, flags)
488 struct mount *mp;
489 struct vnode *skipvp;
490 int flags;
491{
492 register struct vnode *vp, *nvp;
493 int busy = 0;
494
495 for (vp = mp->m_mounth; vp; vp = nvp) {
496 nvp = vp->v_mountf;
497 /*
498 * Skip over a selected vnode.
499 * Used by ufs to skip over the quota structure inode.
500 */
501 if (vp == skipvp)
502 continue;
503 /*
504 * With v_usecount == 0, all we need to do is clear
505 * out the vnode data structures and we are done.
506 */
507 if (vp->v_usecount == 0) {
508 vgone(vp);
509 continue;
510 }
511 /*
512 * For block or character devices, revert to an
513 * anonymous device. For all other files, just kill them.
514 */
515 if (flags & MNT_FORCE) {
516 if (vp->v_type != VBLK && vp->v_type != VCHR) {
517 vgone(vp);
518 } else {
519 vclean(vp, 0);
520 vp->v_op = &spec_vnodeops;
521 insmntque(vp, (struct mount *)0);
522 }
523 continue;
524 }
525 if (busyprt)
526 vprint("vflush: busy vnode", vp);
527 busy++;
528 }
529 if (busy)
530 return (EBUSY);
531 return (0);
532}
533
534/*
535 * Disassociate the underlying file system from a vnode.
536 */
537void vclean(vp, doclose)
538 register struct vnode *vp;
539 long doclose;
540{
541 struct vnodeops *origops;
542 int active;
543
544 /*
545 * Check to see if the vnode is in use.
546 * If so we have to reference it before we clean it out
547 * so that its count cannot fall to zero and generate a
548 * race against ourselves to recycle it.
549 */
550 if (active = vp->v_usecount)
551 VREF(vp);
552 /*
553 * Prevent the vnode from being recycled or
554 * brought into use while we clean it out.
555 */
556 if (vp->v_flag & VXLOCK)
557 panic("vclean: deadlock");
558 vp->v_flag |= VXLOCK;
559 /*
560 * Even if the count is zero, the VOP_INACTIVE routine may still
561 * have the object locked while it cleans it out. The VOP_LOCK
562 * ensures that the VOP_INACTIVE routine is done with its work.
563 * For active vnodes, it ensures that no other activity can
564 * occur while the buffer list is being cleaned out.
565 */
566 VOP_LOCK(vp);
567 if (doclose)
568 vinvalbuf(vp, 1);
569 /*
570 * Prevent any further operations on the vnode from
571 * being passed through to the old file system.
572 */
573 origops = vp->v_op;
574 vp->v_op = &dead_vnodeops;
575 vp->v_tag = VT_NON;
576 /*
577 * If purging an active vnode, it must be unlocked, closed,
578 * and deactivated before being reclaimed.
579 */
580 (*(origops->vn_unlock))(vp);
581 if (active) {
582 if (doclose)
583 (*(origops->vn_close))(vp, 0, NOCRED);
584 (*(origops->vn_inactive))(vp);
585 }
586 /*
587 * Reclaim the vnode.
588 */
589 if ((*(origops->vn_reclaim))(vp))
590 panic("vclean: cannot reclaim");
591 if (active)
592 vrele(vp);
593 /*
594 * Done with purge, notify sleepers in vget of the grim news.
595 */
596 vp->v_flag &= ~VXLOCK;
597 if (vp->v_flag & VXWANT) {
598 vp->v_flag &= ~VXWANT;
599 wakeup((caddr_t)vp);
600 }
601}
602
603/*
604 * Eliminate all activity associated with the requested vnode
605 * and with all vnodes aliased to the requested vnode.
606 */
607void vgoneall(vp)
608 register struct vnode *vp;
609{
610 register struct vnode *vq;
611
612 if (vp->v_flag & VALIASED) {
613 /*
614 * If a vgone (or vclean) is already in progress,
615 * wait until it is done and return.
616 */
617 if (vp->v_flag & VXLOCK) {
618 vp->v_flag |= VXWANT;
619 sleep((caddr_t)vp, PINOD);
620 return;
621 }
622 /*
623 * Ensure that vp will not be vgone'd while we
624 * are eliminating its aliases.
625 */
626 vp->v_flag |= VXLOCK;
627 while (vp->v_flag & VALIASED) {
628 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
629 if (vq->v_rdev != vp->v_rdev ||
630 vq->v_type != vp->v_type || vp == vq)
631 continue;
632 vgone(vq);
633 break;
634 }
635 }
636 /*
637 * Remove the lock so that vgone below will
638 * really eliminate the vnode after which time
639 * vgone will awaken any sleepers.
640 */
641 vp->v_flag &= ~VXLOCK;
642 }
643 vgone(vp);
644}
645
646/*
647 * Eliminate all activity associated with a vnode
648 * in preparation for reuse.
649 */
650void vgone(vp)
651 register struct vnode *vp;
652{
653 register struct vnode *vq;
654 struct vnode *vx;
655 long count;
656
657 /*
658 * If a vgone (or vclean) is already in progress,
659 * wait until it is done and return.
660 */
661 if (vp->v_flag & VXLOCK) {
662 vp->v_flag |= VXWANT;
663 sleep((caddr_t)vp, PINOD);
664 return;
665 }
666 /*
667 * Clean out the filesystem specific data.
668 */
669 vclean(vp, 1);
670 /*
671 * Delete from old mount point vnode list, if on one.
672 */
673 if (vp->v_mountb) {
674 if (vq = vp->v_mountf)
675 vq->v_mountb = vp->v_mountb;
676 *vp->v_mountb = vq;
677 vp->v_mountf = NULL;
678 vp->v_mountb = NULL;
679 }
680 /*
681 * If special device, remove it from special device alias list.
682 */
683 if (vp->v_type == VBLK || vp->v_type == VCHR) {
684 if (*vp->v_hashchain == vp) {
685 *vp->v_hashchain = vp->v_specnext;
686 } else {
687 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
688 if (vq->v_specnext != vp)
689 continue;
690 vq->v_specnext = vp->v_specnext;
691 break;
692 }
693 if (vq == NULL)
694 panic("missing bdev");
695 }
696 if (vp->v_flag & VALIASED) {
697 count = 0;
698 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
699 if (vq->v_rdev != vp->v_rdev ||
700 vq->v_type != vp->v_type)
701 continue;
702 count++;
703 vx = vq;
704 }
705 if (count == 0)
706 panic("missing alias");
707 if (count == 1)
708 vx->v_flag &= ~VALIASED;
709 vp->v_flag &= ~VALIASED;
710 }
711 FREE(vp->v_specinfo, M_VNODE);
712 vp->v_specinfo = NULL;
713 }
714 /*
715 * If it is on the freelist, move it to the head of the list.
716 */
717 if (vp->v_freeb) {
718 if (vq = vp->v_freef)
719 vq->v_freeb = vp->v_freeb;
720 else
721 vfreet = vp->v_freeb;
722 *vp->v_freeb = vq;
723 vp->v_freef = vfreeh;
724 vp->v_freeb = &vfreeh;
725 vfreeh->v_freeb = &vp->v_freef;
726 vfreeh = vp;
727 }
728 vp->v_type = VBAD;
729}
730
731/*
732 * Lookup a vnode by device number.
733 */
734vfinddev(dev, type, vpp)
735 dev_t dev;
736 enum vtype type;
737 struct vnode **vpp;
738{
739 register struct vnode *vp;
740
741 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
742 if (dev != vp->v_rdev || type != vp->v_type)
743 continue;
744 *vpp = vp;
745 return (0);
746 }
747 return (1);
748}
749
750/*
751 * Calculate the total number of references to a special device.
752 */
753vcount(vp)
754 register struct vnode *vp;
755{
756 register struct vnode *vq;
757 int count;
758
759 if ((vp->v_flag & VALIASED) == 0)
760 return (vp->v_usecount);
761loop:
762 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
763 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
764 continue;
765 /*
766 * Alias, but not in use, so flush it out.
767 */
768 if (vq->v_usecount == 0) {
769 vgone(vq);
770 goto loop;
771 }
772 count += vq->v_usecount;
773 }
774 return (count);
775}
776
777/*
778 * Print out a description of a vnode.
779 */
780static char *typename[] =
781 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
782
783vprint(label, vp)
784 char *label;
785 register struct vnode *vp;
786{
787 char buf[64];
788
789 if (label != NULL)
790 printf("%s: ", label);
791 printf("type %s, usecount %d, refcount %d,", typename[vp->v_type],
792 vp->v_usecount, vp->v_holdcnt);
793 buf[0] = '\0';
794 if (vp->v_flag & VROOT)
795 strcat(buf, "|VROOT");
796 if (vp->v_flag & VTEXT)
797 strcat(buf, "|VTEXT");
798 if (vp->v_flag & VXLOCK)
799 strcat(buf, "|VXLOCK");
800 if (vp->v_flag & VXWANT)
801 strcat(buf, "|VXWANT");
802 if (vp->v_flag & VEXLOCK)
803 strcat(buf, "|VEXLOCK");
804 if (vp->v_flag & VSHLOCK)
805 strcat(buf, "|VSHLOCK");
806 if (vp->v_flag & VLWAIT)
807 strcat(buf, "|VLWAIT");
808 if (vp->v_flag & VALIASED)
809 strcat(buf, "|VALIASED");
810 if (vp->v_flag & VBWAIT)
811 strcat(buf, "|VBWAIT");
812 if (buf[0] != '\0')
813 printf(" flags (%s)", &buf[1]);
814 printf("\n\t");
815 VOP_PRINT(vp);
816}