xref: /openbsd-src/sys/miscfs/fuse/fuse_ihash.c (revision 51d8761d1e63aff7173adb7b282dbb4d6279257d)
1*51d8761dSclaudio /*	$OpenBSD: fuse_ihash.c,v 1.1 2024/10/31 13:55:21 claudio Exp $	*/
2*51d8761dSclaudio /*	$NetBSD: ufs_ihash.c,v 1.3 1996/02/09 22:36:04 christos Exp $	*/
3*51d8761dSclaudio 
4*51d8761dSclaudio /*
5*51d8761dSclaudio  * Copyright (c) 1982, 1986, 1989, 1991, 1993
6*51d8761dSclaudio  *	The Regents of the University of California.  All rights reserved.
7*51d8761dSclaudio  *
8*51d8761dSclaudio  * Redistribution and use in source and binary forms, with or without
9*51d8761dSclaudio  * modification, are permitted provided that the following conditions
10*51d8761dSclaudio  * are met:
11*51d8761dSclaudio  * 1. Redistributions of source code must retain the above copyright
12*51d8761dSclaudio  *    notice, this list of conditions and the following disclaimer.
13*51d8761dSclaudio  * 2. Redistributions in binary form must reproduce the above copyright
14*51d8761dSclaudio  *    notice, this list of conditions and the following disclaimer in the
15*51d8761dSclaudio  *    documentation and/or other materials provided with the distribution.
16*51d8761dSclaudio  * 3. Neither the name of the University nor the names of its contributors
17*51d8761dSclaudio  *    may be used to endorse or promote products derived from this software
18*51d8761dSclaudio  *    without specific prior written permission.
19*51d8761dSclaudio  *
20*51d8761dSclaudio  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21*51d8761dSclaudio  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*51d8761dSclaudio  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*51d8761dSclaudio  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24*51d8761dSclaudio  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*51d8761dSclaudio  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*51d8761dSclaudio  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*51d8761dSclaudio  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*51d8761dSclaudio  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*51d8761dSclaudio  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*51d8761dSclaudio  * SUCH DAMAGE.
31*51d8761dSclaudio  *
32*51d8761dSclaudio  *	@(#)ufs_ihash.c	8.4 (Berkeley) 12/30/93
33*51d8761dSclaudio  */
34*51d8761dSclaudio 
35*51d8761dSclaudio #include <sys/param.h>
36*51d8761dSclaudio #include <sys/systm.h>
37*51d8761dSclaudio #include <sys/vnode.h>
38*51d8761dSclaudio #include <sys/malloc.h>
39*51d8761dSclaudio #include <sys/mount.h>
40*51d8761dSclaudio #include <sys/lock.h>
41*51d8761dSclaudio 
42*51d8761dSclaudio #include "fusefs_node.h"
43*51d8761dSclaudio 
44*51d8761dSclaudio #include <crypto/siphash.h>
45*51d8761dSclaudio 
46*51d8761dSclaudio /*
47*51d8761dSclaudio  * Structures associated with inode caching.
48*51d8761dSclaudio  */
49*51d8761dSclaudio LIST_HEAD(fuse_ihashhead, fusefs_node) *fuse_ihashtbl;
50*51d8761dSclaudio u_long	fuse_ihashsz;		/* size of hash table - 1 */
51*51d8761dSclaudio SIPHASH_KEY fuse_ihashkey;
52*51d8761dSclaudio 
53*51d8761dSclaudio struct fuse_ihashhead *fuse_ihash(dev_t, ino_t);
54*51d8761dSclaudio 
55*51d8761dSclaudio struct fuse_ihashhead *
56*51d8761dSclaudio fuse_ihash(dev_t dev, ino_t inum)
57*51d8761dSclaudio {
58*51d8761dSclaudio 	SIPHASH_CTX ctx;
59*51d8761dSclaudio 
60*51d8761dSclaudio 	SipHash24_Init(&ctx, &fuse_ihashkey);
61*51d8761dSclaudio 	SipHash24_Update(&ctx, &dev, sizeof(dev));
62*51d8761dSclaudio 	SipHash24_Update(&ctx, &inum, sizeof(inum));
63*51d8761dSclaudio 
64*51d8761dSclaudio 	return (&fuse_ihashtbl[SipHash24_End(&ctx) & fuse_ihashsz]);
65*51d8761dSclaudio }
66*51d8761dSclaudio 
67*51d8761dSclaudio /*
68*51d8761dSclaudio  * Initialize inode hash table.
69*51d8761dSclaudio  */
70*51d8761dSclaudio void
71*51d8761dSclaudio fuse_ihashinit(void)
72*51d8761dSclaudio {
73*51d8761dSclaudio 	fuse_ihashtbl = hashinit(initialvnodes, M_FUSEFS, M_WAITOK,
74*51d8761dSclaudio 	    &fuse_ihashsz);
75*51d8761dSclaudio 	arc4random_buf(&fuse_ihashkey, sizeof(fuse_ihashkey));
76*51d8761dSclaudio }
77*51d8761dSclaudio 
78*51d8761dSclaudio /*
79*51d8761dSclaudio  * Use the device/inum pair to find the incore inode, and return a pointer
80*51d8761dSclaudio  * to it. If it is in core, but locked, wait for it.
81*51d8761dSclaudio  */
82*51d8761dSclaudio struct vnode *
83*51d8761dSclaudio fuse_ihashget(dev_t dev, ino_t inum)
84*51d8761dSclaudio {
85*51d8761dSclaudio 	struct fuse_ihashhead *ipp;
86*51d8761dSclaudio 	struct fusefs_node *ip;
87*51d8761dSclaudio 	struct vnode *vp;
88*51d8761dSclaudio loop:
89*51d8761dSclaudio 	/* XXXLOCKING lock hash list */
90*51d8761dSclaudio 	ipp = fuse_ihash(dev, inum);
91*51d8761dSclaudio 	LIST_FOREACH(ip, ipp, i_hash) {
92*51d8761dSclaudio 		if (inum == ip->i_number && dev == ip->i_dev) {
93*51d8761dSclaudio 			vp = ITOV(ip);
94*51d8761dSclaudio 			/* XXXLOCKING unlock hash list? */
95*51d8761dSclaudio 			if (vget(vp, LK_EXCLUSIVE))
96*51d8761dSclaudio 				goto loop;
97*51d8761dSclaudio 
98*51d8761dSclaudio 			return (vp);
99*51d8761dSclaudio 		}
100*51d8761dSclaudio 	}
101*51d8761dSclaudio 	/* XXXLOCKING unlock hash list? */
102*51d8761dSclaudio 	return (NULL);
103*51d8761dSclaudio }
104*51d8761dSclaudio 
105*51d8761dSclaudio /*
106*51d8761dSclaudio  * Insert the inode into the hash table, and return it locked.
107*51d8761dSclaudio  */
108*51d8761dSclaudio int
109*51d8761dSclaudio fuse_ihashins(struct fusefs_node *ip)
110*51d8761dSclaudio {
111*51d8761dSclaudio 	struct   fusefs_node *curip;
112*51d8761dSclaudio 	struct   fuse_ihashhead *ipp;
113*51d8761dSclaudio 	dev_t    dev = ip->i_dev;
114*51d8761dSclaudio 	ino_t	 inum = ip->i_number;
115*51d8761dSclaudio 
116*51d8761dSclaudio 	/* lock the inode, then put it on the appropriate hash list */
117*51d8761dSclaudio 	VOP_LOCK(ITOV(ip), LK_EXCLUSIVE);
118*51d8761dSclaudio 
119*51d8761dSclaudio 	/* XXXLOCKING lock hash list */
120*51d8761dSclaudio 
121*51d8761dSclaudio 	ipp = fuse_ihash(dev, inum);
122*51d8761dSclaudio 	LIST_FOREACH(curip, ipp, i_hash) {
123*51d8761dSclaudio 		if (inum == curip->i_number && dev == curip->i_dev) {
124*51d8761dSclaudio 			/* XXXLOCKING unlock hash list? */
125*51d8761dSclaudio 			VOP_UNLOCK(ITOV(ip));
126*51d8761dSclaudio 			return (EEXIST);
127*51d8761dSclaudio 		}
128*51d8761dSclaudio 	}
129*51d8761dSclaudio 
130*51d8761dSclaudio 	LIST_INSERT_HEAD(ipp, ip, i_hash);
131*51d8761dSclaudio 	/* XXXLOCKING unlock hash list? */
132*51d8761dSclaudio 
133*51d8761dSclaudio 	return (0);
134*51d8761dSclaudio }
135*51d8761dSclaudio 
136*51d8761dSclaudio /*
137*51d8761dSclaudio  * Remove the inode from the hash table.
138*51d8761dSclaudio  */
139*51d8761dSclaudio void
140*51d8761dSclaudio fuse_ihashrem(struct fusefs_node *ip)
141*51d8761dSclaudio {
142*51d8761dSclaudio 	/* XXXLOCKING lock hash list */
143*51d8761dSclaudio 
144*51d8761dSclaudio 	if (ip->i_hash.le_prev == NULL)
145*51d8761dSclaudio 		return;
146*51d8761dSclaudio 	LIST_REMOVE(ip, i_hash);
147*51d8761dSclaudio #ifdef DIAGNOSTIC
148*51d8761dSclaudio 	ip->i_hash.le_next = NULL;
149*51d8761dSclaudio 	ip->i_hash.le_prev = NULL;
150*51d8761dSclaudio #endif
151*51d8761dSclaudio 	/* XXXLOCKING unlock hash list? */
152*51d8761dSclaudio }
153