add bmap entry for dead texts
[unix-history] / usr / src / sys / kern / vfs_subr.c
CommitLineData
3c4390e8
KM
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 *
ff4fb102 17 * @(#)vfs_subr.c 7.12 (Berkeley) %G%
3c4390e8
KM
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"
c60798ca
KM
28#include "namei.h"
29#include "ucred.h"
3c4390e8 30#include "errno.h"
ef24f6dd 31#include "malloc.h"
3c4390e8 32
3c4390e8
KM
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
594501df
KM
58 while(mp->m_flag & M_MLOCK) {
59 mp->m_flag |= M_MWAIT;
60 sleep((caddr_t)mp, PVFS);
61 }
3c4390e8
KM
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
d713f801
KM
93 mp = rootfs;
94 do {
3c4390e8
KM
95 if (mp->m_fsid.val[0] == fsid->val[0] &&
96 mp->m_fsid.val[1] == fsid->val[1]) {
d713f801 97 return (mp);
3c4390e8 98 }
d713f801
KM
99 mp = mp->m_next;
100 } while (mp != rootfs);
101 return ((struct mount *)0);
3c4390e8
KM
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 =
8cf4d4fb
KM
118 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
119 vap->va_flags = vap->va_gen = VNOVAL;
3c4390e8 120}
c60798ca
KM
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_segflg = 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;
8fe1c702 146 VREF(newndp->ni_cdir);
c60798ca
KM
147 newndp->ni_rdir = ndp->ni_rdir;
148 if (newndp->ni_rdir)
8fe1c702 149 VREF(newndp->ni_rdir);
c60798ca
KM
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}
36d09cb1
KM
166
167/*
168 * Routines having to do with the management of the vnode table.
169 */
170struct vnode *vfreeh, **vfreet;
4ef5d036 171extern struct vnodeops dead_vnodeops, spec_vnodeops;
ef24f6dd
KM
172struct speclist *speclisth;
173struct speclist {
174 struct speclist *sl_next;
175 struct vnode *sl_vp;
176};
36d09cb1
KM
177
178/*
ef24f6dd 179 * Initialize the vnode structures and initialize each file system type.
36d09cb1 180 */
ef24f6dd 181vfsinit()
36d09cb1
KM
182{
183 register struct vnode *vp = vnode;
ef24f6dd 184 struct vfsops **vfsp;
36d09cb1 185
ef24f6dd
KM
186 /*
187 * Build vnode free list.
188 */
36d09cb1
KM
189 vfreeh = vp;
190 vfreet = &vp->v_freef;
191 vp->v_freeb = &vfreeh;
192 vp->v_op = &dead_vnodeops;
193 for (vp++; vp < vnodeNVNODE; vp++) {
194 *vfreet = vp;
195 vp->v_freeb = vfreet;
196 vfreet = &vp->v_freef;
197 vp->v_op = &dead_vnodeops;
198 }
199 vp--;
200 vp->v_freef = NULL;
ef24f6dd
KM
201 /*
202 * Initialize the vnode name cache
203 */
204 nchinit();
205 /*
206 * Initialize each file system type.
207 */
208 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
209 if (*vfsp == NULL)
210 continue;
211 (*(*vfsp)->vfs_init)();
212 }
36d09cb1
KM
213}
214
215/*
216 * Return the next vnode from the free list.
217 */
218getnewvnode(tag, mp, vops, vpp)
219 enum vtagtype tag;
220 struct mount *mp;
221 struct vnodeops *vops;
222 struct vnode **vpp;
223{
224 register struct vnode *vp, *vq;
225
226 if ((vp = vfreeh) == NULL) {
227 tablefull("vnode");
228 *vpp = 0;
229 return (ENFILE);
230 }
ef24f6dd 231 if (vp->v_count)
36d09cb1
KM
232 panic("free vnode isn't");
233 if (vq = vp->v_freef)
234 vq->v_freeb = &vfreeh;
235 vfreeh = vq;
236 vp->v_freef = NULL;
237 vp->v_freeb = NULL;
ef24f6dd
KM
238 if (vp->v_type != VNON)
239 vgone(vp);
36d09cb1
KM
240 vp->v_flag = 0;
241 vp->v_shlockc = 0;
242 vp->v_exlockc = 0;
243 vp->v_socket = 0;
36d09cb1
KM
244 cache_purge(vp);
245 vp->v_tag = tag;
ef24f6dd 246 vp->v_op = vops;
36d09cb1
KM
247 vp->v_mount = mp;
248 insmntque(vp, mp);
249 VREF(vp);
250 *vpp = vp;
251 return (0);
252}
253
254/*
255 * Move a vnode from one mount queue to another.
256 */
257insmntque(vp, mp)
258 register struct vnode *vp;
259 register struct mount *mp;
260{
261 struct vnode *vq;
262
263 /*
264 * Delete from old mount point vnode list, if on one.
265 */
266 if (vp->v_mountb) {
267 if (vq = vp->v_mountf)
268 vq->v_mountb = vp->v_mountb;
269 *vp->v_mountb = vq;
270 }
271 /*
272 * Insert into list of vnodes for the new mount point, if available.
273 */
274 if (mp == NULL) {
275 vp->v_mountf = NULL;
276 vp->v_mountb = NULL;
277 return;
278 }
279 if (mp->m_mounth) {
280 vp->v_mountf = mp->m_mounth;
281 vp->v_mountb = &mp->m_mounth;
282 mp->m_mounth->v_mountb = &vp->v_mountf;
283 mp->m_mounth = vp;
284 } else {
285 mp->m_mounth = vp;
286 vp->v_mountb = &mp->m_mounth;
287 vp->v_mountf = NULL;
288 }
289}
290
291/*
ef24f6dd
KM
292 * Create a vnode for a block device.
293 * Used for root filesystem, argdev, and swap areas.
294 * Also used for memory file system special devices.
295 */
296bdevvp(dev, vpp)
297 dev_t dev;
298 struct vnode **vpp;
299{
ef24f6dd
KM
300 register struct vnode *vp;
301 struct vnode *nvp;
302 int error;
303
4ef5d036 304 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
305 if (error) {
306 *vpp = 0;
307 return (error);
308 }
309 vp = nvp;
310 vp->v_type = VBLK;
311 vp->v_rdev = dev;
312 if (nvp = checkalias(vp, (struct mount *)0)) {
313 vput(vp);
314 vp = nvp;
315 }
316 *vpp = vp;
317 return (0);
318}
319
320/*
321 * Check to see if the new vnode represents a special device
322 * for which we already have a vnode (either because of
323 * bdevvp() or because of a different vnode representing
324 * the same block device). If such an alias exists, deallocate
325 * the existing contents and return the aliased inode. The
326 * caller is responsible for filling it with its new contents.
327 */
328struct vnode *
329checkalias(nvp, mp)
330 register struct vnode *nvp;
331 struct mount *mp;
332{
333 register struct vnode *vp;
334 register struct speclist *slp;
335
336 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
337 return ((struct vnode *)0);
338loop:
339 for (slp = speclisth; slp; slp = slp->sl_next) {
340 vp = slp->sl_vp;
341 if (nvp->v_rdev != vp->v_rdev ||
342 nvp->v_type != vp->v_type)
343 continue;
344 if (vget(vp))
345 goto loop;
346 break;
347 }
348 if (slp == NULL) {
349 MALLOC(slp, struct speclist *, sizeof(*slp), M_VNODE, M_WAITOK);
350 slp->sl_vp = nvp;
351 slp->sl_next = speclisth;
352 speclisth = slp;
353 return ((struct vnode *)0);
354 }
2bae1875
KM
355 VOP_UNLOCK(vp);
356 vclean(vp, 0);
ef24f6dd
KM
357 vp->v_op = nvp->v_op;
358 vp->v_tag = nvp->v_tag;
359 nvp->v_type = VNON;
360 insmntque(vp, mp);
361 return (vp);
362}
363
364/*
365 * Grab a particular vnode from the free list, increment its
366 * reference count and lock it. The vnode lock bit is set the
367 * vnode is being eliminated in vgone. The process is awakened
368 * when the transition is completed, and an error returned to
369 * indicate that the vnode is no longer usable (possibly having
370 * been changed to a new file system type).
36d09cb1
KM
371 */
372vget(vp)
373 register struct vnode *vp;
374{
375 register struct vnode *vq;
376
ef24f6dd
KM
377 if (vp->v_flag & VXLOCK) {
378 vp->v_flag |= VXWANT;
379 sleep((caddr_t)vp, PINOD);
380 return (1);
381 }
382 if (vp->v_count == 0) {
383 if (vq = vp->v_freef)
384 vq->v_freeb = vp->v_freeb;
385 else
386 vfreet = vp->v_freeb;
387 *vp->v_freeb = vq;
388 vp->v_freef = NULL;
389 vp->v_freeb = NULL;
390 }
36d09cb1 391 VREF(vp);
ef24f6dd
KM
392 VOP_LOCK(vp);
393 return (0);
36d09cb1
KM
394}
395
396/*
397 * Vnode reference, just increment the count
398 */
399void vref(vp)
400 struct vnode *vp;
401{
402
403 vp->v_count++;
404}
405
406/*
407 * vput(), just unlock and vrele()
408 */
409void vput(vp)
410 register struct vnode *vp;
411{
412 VOP_UNLOCK(vp);
413 vrele(vp);
414}
415
416/*
417 * Vnode release.
418 * If count drops to zero, call inactive routine and return to freelist.
419 */
420void vrele(vp)
421 register struct vnode *vp;
422{
423
424 if (vp == NULL)
ef24f6dd 425 panic("vrele: null vp");
36d09cb1
KM
426 vp->v_count--;
427 if (vp->v_count < 0)
428 printf("vnode bad ref count %d, type %d, tag %d\n",
429 vp->v_count, vp->v_type, vp->v_tag);
430 if (vp->v_count > 0)
431 return;
36d09cb1
KM
432 if (vfreeh == (struct vnode *)0) {
433 /*
434 * insert into empty list
435 */
436 vfreeh = vp;
437 vp->v_freeb = &vfreeh;
36d09cb1
KM
438 } else {
439 /*
440 * insert at tail of list
441 */
442 *vfreet = vp;
443 vp->v_freeb = vfreet;
36d09cb1 444 }
ef24f6dd
KM
445 vp->v_freef = NULL;
446 vfreet = &vp->v_freef;
447 VOP_INACTIVE(vp);
448}
449
450/*
451 * Disassociate the underlying file system from a vnode.
ef24f6dd 452 */
2bae1875 453void vclean(vp, doclose)
ef24f6dd 454 register struct vnode *vp;
2bae1875 455 long doclose;
ef24f6dd
KM
456{
457 struct vnodeops *origops;
2bae1875 458 int active;
ef24f6dd 459
2bae1875
KM
460 /*
461 * Check to see if the vnode is in use.
462 * If so we have to lock it before we clean it out.
463 */
464 if (active = vp->v_count) {
465 VREF(vp);
466 VOP_LOCK(vp);
467 }
468 /*
469 * Prevent the vnode from being recycled or
470 * brought into use while we clean it out.
471 */
ef24f6dd
KM
472 while (vp->v_flag & VXLOCK) {
473 vp->v_flag |= VXWANT;
474 sleep((caddr_t)vp, PINOD);
475 }
476 vp->v_flag |= VXLOCK;
477 /*
478 * Prevent any further operations on the vnode from
479 * being passed through to the old file system.
480 */
481 origops = vp->v_op;
482 vp->v_op = &dead_vnodeops;
483 vp->v_tag = VT_NON;
484 /*
2bae1875
KM
485 * If purging an active vnode, it must be unlocked, closed,
486 * and deactivated before being reclaimed.
ef24f6dd 487 */
2bae1875 488 if (active) {
ef24f6dd 489 (*(origops->vn_unlock))(vp);
2bae1875
KM
490 if (doclose)
491 (*(origops->vn_close))(vp, 0, NOCRED);
ef24f6dd
KM
492 (*(origops->vn_inactive))(vp);
493 }
494 /*
495 * Reclaim the vnode.
496 */
497 if ((*(origops->vn_reclaim))(vp))
498 panic("vclean: cannot reclaim");
2bae1875
KM
499 if (active)
500 vrele(vp);
ef24f6dd
KM
501 /*
502 * Done with purge, notify sleepers in vget of the grim news.
503 */
504 vp->v_flag &= ~VXLOCK;
505 if (vp->v_flag & VXWANT) {
506 vp->v_flag &= ~VXWANT;
507 wakeup((caddr_t)vp);
508 }
509}
510
511/*
512 * Eliminate all activity associated with a vnode
513 * in preparation for reuse.
514 */
515void vgone(vp)
516 register struct vnode *vp;
517{
518 register struct speclist *slp;
519 struct speclist *pslp;
520 register struct vnode *vq;
521
ef24f6dd
KM
522 /*
523 * Clean out the filesystem specific data.
524 */
2bae1875 525 vclean(vp, 1);
ef24f6dd
KM
526 /*
527 * Delete from old mount point vnode list, if on one.
528 */
529 if (vp->v_mountb) {
530 if (vq = vp->v_mountf)
531 vq->v_mountb = vp->v_mountb;
532 *vp->v_mountb = vq;
533 vp->v_mountf = NULL;
534 vp->v_mountb = NULL;
535 }
536 /*
537 * If special device, remove it from special device alias list.
538 */
539 if (vp->v_type == VBLK || vp->v_type == VCHR) {
540 if (speclisth->sl_vp == vp) {
541 slp = speclisth;
542 speclisth = slp->sl_next;
543 } else {
ff4fb102 544 for (pslp = speclisth, slp = pslp->sl_next; slp;
ef24f6dd
KM
545 pslp = slp, slp = slp->sl_next) {
546 if (slp->sl_vp != vp)
547 continue;
548 pslp->sl_next = slp->sl_next;
549 break;
550 }
551 if (slp == NULL)
552 panic("missing bdev");
553 }
554 FREE(slp, M_VNODE);
555 }
556 /*
557 * If it is on the freelist, move it to the head of the list.
558 */
559 if (vp->v_freeb) {
560 if (vq = vp->v_freef)
561 vq->v_freeb = vp->v_freeb;
562 else
563 vfreet = vp->v_freeb;
564 *vp->v_freeb = vq;
565 vp->v_freef = vfreeh;
566 vp->v_freeb = &vfreeh;
567 vfreeh->v_freeb = &vp->v_freef;
568 vfreeh = vp;
569 }
2bae1875 570 vp->v_type = VBAD;
36d09cb1 571}