Home | History | Annotate | Line # | Download | only in fsck_lfs
vnode.c revision 1.16.8.1
      1 /* $NetBSD: vnode.c,v 1.16.8.1 2024/06/29 19:43:25 perseant Exp $ */
      2 /*-
      3  * Copyright (c) 2003 The NetBSD Foundation, Inc.
      4  * All rights reserved.
      5  *
      6  * This code is derived from software contributed to The NetBSD Foundation
      7  * by Konrad E. Schroder <perseant (at) hhhh.org>.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/types.h>
     32 #include <sys/param.h>
     33 #include <sys/time.h>
     34 #include <sys/buf.h>
     35 #include <sys/mount.h>
     36 #include <sys/queue.h>
     37 
     38 #define VU_DIROP 0x01000000 /* XXX XXX from sys/vnode.h */
     39 #define vnode uvnode
     40 #include <ufs/lfs/lfs.h>
     41 #include <ufs/lfs/lfs_inode.h>
     42 #undef vnode
     43 
     44 #include <assert.h>
     45 #include <err.h>
     46 #include <errno.h>
     47 #include <stdarg.h>
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 #include <util.h>
     53 
     54 #include "bufcache.h"
     55 #include "extern.h"
     56 #include "kernelops.h"
     57 
     58 struct uvnodetq vnodetq;
     59 struct uvnodelst getvnodelist[VNODE_HASH_MAX];
     60 struct vgrlst    vgrlist;
     61 
     62 int nvnodes;
     63 
     64 /* Convert between inode pointers and vnode pointers. */
     65 #ifndef VTOI
     66 #define	VTOI(vp)	((struct inode *)(vp)->v_data)
     67 #endif
     68 
     69 /*
     70  * Raw device uvnode ops
     71  */
     72 
     73 int
     74 raw_vop_strategy(struct ubuf * bp)
     75 {
     76 	if (bp->b_flags & B_READ) {
     77 		if (kops.ko_pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
     78 				  bp->b_blkno * dev_bsize) < bp->b_bcount)
     79 			return errno;
     80 		return 0;
     81 	} else {
     82 		return kops.ko_pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
     83 		    bp->b_blkno * dev_bsize);
     84 	}
     85 }
     86 
     87 int
     88 raw_vop_bwrite(struct ubuf * bp)
     89 {
     90 	bp->b_flags &= ~(B_READ | B_DELWRI | B_DONE | B_ERROR);
     91 	raw_vop_strategy(bp);
     92 	brelse(bp, 0);
     93 	return 0;
     94 }
     95 
     96 int
     97 raw_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
     98 {
     99 	*daddrp = lbn;
    100 	return 0;
    101 }
    102 
    103 /* Register fs-specific vnode create and destroy functions */
    104 void
    105 register_vget(void *fs, struct uvnode *getfunc(void *, ino_t, void *),
    106 	      int freefunc(struct uvnode *))
    107 {
    108 	struct vget_reg *vgr;
    109 
    110 	vgr = emalloc(sizeof(*vgr));
    111 	vgr->vgr_fs = fs;
    112 	vgr->vgr_getfunc = getfunc;
    113 	vgr->vgr_freefunc = freefunc;
    114 	LIST_INSERT_HEAD(&vgrlist, vgr, vgr_list);
    115 }
    116 
    117 static struct uvnode *
    118 VFS_VGET(void *fs, ino_t ino, void *arg)
    119 {
    120 	struct vget_reg *vgr;
    121 	struct uvnode *vp;
    122 	int hash;
    123 
    124 	LIST_FOREACH(vgr, &vgrlist, vgr_list) {
    125 		if (vgr->vgr_fs == fs) {
    126 			vp = vgr->vgr_getfunc(fs, ino, arg);
    127 			++nvnodes;
    128 			hash = ((int)(intptr_t)fs + ino) & (VNODE_HASH_MAX - 1);
    129 			LIST_INSERT_HEAD(&getvnodelist[hash], vp, v_getvnodes);
    130 			TAILQ_INSERT_HEAD(&vnodetq, vp, v_mntvnodes);
    131 			return vp;
    132 		}
    133 	}
    134 	return NULL;
    135 }
    136 
    137 void
    138 vnode_destroy(struct uvnode *tossvp)
    139 {
    140 	struct vget_reg *vgr;
    141 	struct ubuf *bp;
    142 
    143 	--nvnodes;
    144 	LIST_REMOVE(tossvp, v_getvnodes);
    145 	TAILQ_REMOVE(&vnodetq, tossvp, v_mntvnodes);
    146 	while ((bp = LIST_FIRST(&tossvp->v_dirtyblkhd)) != NULL) {
    147 		LIST_REMOVE(bp, b_vnbufs);
    148 		bremfree(bp);
    149 		buf_destroy(bp);
    150 	}
    151 	while ((bp = LIST_FIRST(&tossvp->v_cleanblkhd)) != NULL) {
    152 		LIST_REMOVE(bp, b_vnbufs);
    153 		bremfree(bp);
    154 		buf_destroy(bp);
    155 	}
    156 	LIST_FOREACH(vgr, &vgrlist, vgr_list) {
    157 		if (vgr->vgr_fs == tossvp->v_fs) {
    158 			if (vgr->vgr_freefunc == NULL
    159 			    || vgr->vgr_freefunc(tossvp) == 0) {
    160 				free(tossvp->v_data);
    161 			}
    162 			break;
    163 		}
    164 	}
    165 	memset(tossvp, 0, sizeof(*tossvp));
    166 	free(tossvp);
    167 }
    168 
    169 int hits, misses;
    170 
    171 /*
    172  * Find a vnode in the cache; if not present, get it from the
    173  * filesystem-specific vget routine.
    174  */
    175 struct uvnode *
    176 vget(void *fs, ino_t ino)
    177 {
    178 	return vget3(fs, ino, NULL);
    179 }
    180 
    181 struct uvnode *
    182 vget3(void *fs, ino_t ino, void *arg)
    183 {
    184 	struct uvnode *vp, *tossvp;
    185 	int hash;
    186 
    187 	/* Look in the uvnode cache */
    188 	hash = ((unsigned long)fs + ino) & (VNODE_HASH_MAX - 1);
    189 	LIST_FOREACH(vp, &getvnodelist[hash], v_getvnodes) {
    190 		if (vp->v_fs != fs)
    191 			continue;
    192 		if (VTOI(vp)->i_number == ino) {
    193 			/* Move to the front of both lists */
    194 			LIST_REMOVE(vp, v_getvnodes);
    195 			LIST_INSERT_HEAD(&getvnodelist[hash], vp, v_getvnodes);
    196 			TAILQ_REMOVE(&vnodetq, vp, v_mntvnodes);
    197 			TAILQ_INSERT_HEAD(&vnodetq, vp, v_mntvnodes);
    198 			++hits;
    199 			break;
    200 		}
    201 	}
    202 
    203 	/* Don't let vnode list grow arbitrarily */
    204 	while (nvnodes > VNODE_CACHE_SIZE) {
    205 		TAILQ_FOREACH_REVERSE(tossvp, &vnodetq, uvnodetq, v_mntvnodes) {
    206 			if (LIST_EMPTY(&tossvp->v_dirtyblkhd) &&
    207 			    tossvp->v_usecount == 0 &&
    208 			    !(tossvp->v_uflag & VU_DIROP)) {
    209 				vnode_destroy(tossvp);
    210 				break;
    211 			}
    212 		}
    213 		if (tossvp == NULL)
    214 			break;
    215 	}
    216 
    217 	if (vp)
    218 		return vp;
    219 
    220 	++misses;
    221 	return VFS_VGET(fs, ino, arg);
    222 }
    223 
    224 void
    225 vref(struct uvnode *vp)
    226 {
    227 	++vp->v_usecount;
    228 }
    229 
    230 void
    231 vrele(struct uvnode *vp)
    232 {
    233 	--vp->v_usecount;
    234 }
    235 
    236 void
    237 vfs_init(void)
    238 {
    239 	int i;
    240 
    241 	nvnodes = 0;
    242 	TAILQ_INIT(&vnodetq);
    243 	for (i = 0; i < VNODE_HASH_MAX; i++)
    244 		LIST_INIT(&getvnodelist[i]);
    245 	LIST_INIT(&vgrlist);
    246 }
    247