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