xref: /haiku/src/add-ons/kernel/file_systems/fat/vcache.cpp (revision 342a1b221b5bb385410f758df2c625b70cafdd03)
19f3ba01bSAlexander von Gluck IV /*
2*342a1b22SJim906  * Copyright 1999-2001, Be Incorporated.   All Rights Reserved.
3*342a1b22SJim906  * Copyright 2024, Haiku, Inc. All rights reserved.
4*342a1b22SJim906  * This file may be used under the terms of the Be Sample Code License.
59f3ba01bSAlexander von Gluck IV */
6*342a1b22SJim906 
7*342a1b22SJim906 
89f3ba01bSAlexander von Gluck IV /*
99f3ba01bSAlexander von Gluck IV The FAT file system has no good way of assigning unique persistent values to
109f3ba01bSAlexander von Gluck IV nodes. The only obvious choice, storing the starting cluster number of the
119f3ba01bSAlexander von Gluck IV file, is unusable because 0 byte files exist as directory entries only.
129f3ba01bSAlexander von Gluck IV Further, even if it were usable, it would potentially require a full directory
139f3ba01bSAlexander von Gluck IV tree traversal to locate an arbitrary node. We must resort to some ickiness
149f3ba01bSAlexander von Gluck IV in order to make persistent vnode id's (at least across a given mount) work.
159f3ba01bSAlexander von Gluck IV 
169f3ba01bSAlexander von Gluck IV There are three ways to encode a vnode id:
179f3ba01bSAlexander von Gluck IV 
189f3ba01bSAlexander von Gluck IV 1. Combine the starting cluster of the entry with the starting cluster of the
199f3ba01bSAlexander von Gluck IV    directory it appears in. This is used for files with data.
209f3ba01bSAlexander von Gluck IV 2. Combine the starting cluster of the directory the entry appears in with the
219f3ba01bSAlexander von Gluck IV    index of the entry in the directory. This is used for 0-byte files.
229f3ba01bSAlexander von Gluck IV 3. A unique number that doesn't match any possible values from encodings 1 or
239f3ba01bSAlexander von Gluck IV    2.
249f3ba01bSAlexander von Gluck IV 
259f3ba01bSAlexander von Gluck IV With the first encoding, the vnode id is invalidated (i.e. no longer describes
269f3ba01bSAlexander von Gluck IV the file's location) when the file moves to a different directory or when
279f3ba01bSAlexander von Gluck IV its starting cluster changes (this can occur if the file is truncated and data
289f3ba01bSAlexander von Gluck IV is subsequently written to it).
299f3ba01bSAlexander von Gluck IV 
309f3ba01bSAlexander von Gluck IV With the second encoding, the vnode id is invalidated when the file position
319f3ba01bSAlexander von Gluck IV is moved within a directory (as a result of a renaming), when it's moved to a
329f3ba01bSAlexander von Gluck IV different directory, or when data is written to it.
339f3ba01bSAlexander von Gluck IV 
349f3ba01bSAlexander von Gluck IV The third encoding doesn't describe the file's location on disk, and so it is
359f3ba01bSAlexander von Gluck IV invalid from the start.
369f3ba01bSAlexander von Gluck IV 
379f3ba01bSAlexander von Gluck IV Since we can't change vnode id's once they are assigned, we have to create a
389f3ba01bSAlexander von Gluck IV mapping table to translate vnode id's to locations. This file serves this
399f3ba01bSAlexander von Gluck IV purpose.
40*342a1b22SJim906 
41*342a1b22SJim906 It also allows the FS to check whether a node with a given inode number has been constructed,
42*342a1b22SJim906 without calling get_vnode().
439f3ba01bSAlexander von Gluck IV */
449f3ba01bSAlexander von Gluck IV 
459f3ba01bSAlexander von Gluck IV 
469f3ba01bSAlexander von Gluck IV #include "vcache.h"
479f3ba01bSAlexander von Gluck IV 
48*342a1b22SJim906 #ifdef FS_SHELL
49*342a1b22SJim906 #include "fssh_api_wrapper.h"
50*342a1b22SJim906 #else // !FS_SHELL
51*342a1b22SJim906 #include <new>
52*342a1b22SJim906 #include <stdint.h>
53*342a1b22SJim906 #include <stdio.h>
54*342a1b22SJim906 #include <stdlib.h>
55*342a1b22SJim906 #endif // !FS_SHELL
569f3ba01bSAlexander von Gluck IV 
57*342a1b22SJim906 #ifndef FS_SHELL
58*342a1b22SJim906 #include <fs_cache.h>
59*342a1b22SJim906 #include <fs_interface.h>
60*342a1b22SJim906 #endif // !FS_SHELL
61*342a1b22SJim906 
62*342a1b22SJim906 #define _KERNEL
63*342a1b22SJim906 #include "sys/vnode.h"
64*342a1b22SJim906 
65*342a1b22SJim906 #include "debug.h"
669f3ba01bSAlexander von Gluck IV #include "dosfs.h"
679f3ba01bSAlexander von Gluck IV 
689f3ba01bSAlexander von Gluck IV 
699f3ba01bSAlexander von Gluck IV #define LOCK_CACHE_R \
709f3ba01bSAlexander von Gluck IV 	rw_lock_read_lock(&vol->vcache.lock)
719f3ba01bSAlexander von Gluck IV 
729f3ba01bSAlexander von Gluck IV #define LOCK_CACHE_W \
739f3ba01bSAlexander von Gluck IV 	rw_lock_write_lock(&vol->vcache.lock)
749f3ba01bSAlexander von Gluck IV 
759f3ba01bSAlexander von Gluck IV #define UNLOCK_CACHE_R \
769f3ba01bSAlexander von Gluck IV 	rw_lock_read_unlock(&vol->vcache.lock)
779f3ba01bSAlexander von Gluck IV 
789f3ba01bSAlexander von Gluck IV #define UNLOCK_CACHE_W \
799f3ba01bSAlexander von Gluck IV 	rw_lock_write_unlock(&vol->vcache.lock)
809f3ba01bSAlexander von Gluck IV 
819f3ba01bSAlexander von Gluck IV #define hash(v) ((v) & (vol->vcache.cache_size-1))
829f3ba01bSAlexander von Gluck IV 
839f3ba01bSAlexander von Gluck IV 
849f3ba01bSAlexander von Gluck IV struct vcache_entry {
859f3ba01bSAlexander von Gluck IV 	ino_t	vnid;		/* originally reported vnid */
869f3ba01bSAlexander von Gluck IV 	ino_t	loc;		/* where the file is now */
87*342a1b22SJim906 	bool	constructed;	/* has the node been set up by _dosfs_read_vnode */
889f3ba01bSAlexander von Gluck IV 	struct vcache_entry *next_vnid; /* next entry in vnid hash table */
899f3ba01bSAlexander von Gluck IV 	struct vcache_entry *next_loc;  /* next entry in location hash table */
90*342a1b22SJim906 #ifdef DEBUG
91*342a1b22SJim906 	struct vnode* node;
92*342a1b22SJim906 #endif
939f3ba01bSAlexander von Gluck IV };
949f3ba01bSAlexander von Gluck IV 
959f3ba01bSAlexander von Gluck IV 
969f3ba01bSAlexander von Gluck IV void
dump_vcache(const mount * vol)97*342a1b22SJim906 dump_vcache(const mount* vol)
989f3ba01bSAlexander von Gluck IV {
999f3ba01bSAlexander von Gluck IV 	uint32 i;
1009f3ba01bSAlexander von Gluck IV 	struct vcache_entry *c;
101*342a1b22SJim906 #if defined DEBUG && defined _KERNEL_MODE
102*342a1b22SJim906 	kprintf("vnid cache size %" B_PRIu32 ", cur vnid = %" B_PRIdINO "\n"
103*342a1b22SJim906 		"vnid                loc              %-*s\n", vol->vcache.cache_size, vol->vcache.cur_vnid,
104*342a1b22SJim906 		B_PRINTF_POINTER_WIDTH, "struct vnode");
105*342a1b22SJim906 	for (i = 0; i < vol->vcache.cache_size; i++) {
106*342a1b22SJim906 		for (c = vol->vcache.by_vnid[i]; c ; c = c->next_vnid)
107*342a1b22SJim906 			kprintf("%19" B_PRIdINO " %16" B_PRIdINO " %p\n", c->vnid, c->loc, c->node);
108*342a1b22SJim906 	}
109*342a1b22SJim906 #else
1109f3ba01bSAlexander von Gluck IV 	kprintf("vnid cache size %" B_PRIu32 ", cur vnid = %" B_PRIdINO "\n"
1119f3ba01bSAlexander von Gluck IV 		"vnid                loc\n", vol->vcache.cache_size, vol->vcache.cur_vnid);
1129f3ba01bSAlexander von Gluck IV 	for (i = 0; i < vol->vcache.cache_size; i++) {
1139f3ba01bSAlexander von Gluck IV 		for (c = vol->vcache.by_vnid[i]; c ; c = c->next_vnid)
114*342a1b22SJim906 			kprintf("%19" B_PRIdINO " %16" B_PRIdINO "\n", c->vnid, c->loc);
1159f3ba01bSAlexander von Gluck IV 	}
116*342a1b22SJim906 #endif // !DEBUG
1179f3ba01bSAlexander von Gluck IV }
1189f3ba01bSAlexander von Gluck IV 
1199f3ba01bSAlexander von Gluck IV 
1209f3ba01bSAlexander von Gluck IV status_t
init_vcache(mount * vol)121*342a1b22SJim906 init_vcache(mount* vol)
1229f3ba01bSAlexander von Gluck IV {
1239f3ba01bSAlexander von Gluck IV 	char name[16];
124*342a1b22SJim906 	FUNCTION();
1259f3ba01bSAlexander von Gluck IV 
1269f3ba01bSAlexander von Gluck IV 	vol->vcache.cur_vnid = ARTIFICIAL_VNID_BITS;
1279f3ba01bSAlexander von Gluck IV #if DEBUG
1289f3ba01bSAlexander von Gluck IV 	vol->vcache.cache_size = 1;
1299f3ba01bSAlexander von Gluck IV #else
1309f3ba01bSAlexander von Gluck IV 	vol->vcache.cache_size = 512; /* must be power of 2 */
1319f3ba01bSAlexander von Gluck IV #endif
1329f3ba01bSAlexander von Gluck IV 
1339f3ba01bSAlexander von Gluck IV 	vol->vcache.by_vnid = (vcache_entry**)calloc(sizeof(struct vache_entry *),
1349f3ba01bSAlexander von Gluck IV 		vol->vcache.cache_size);
1359f3ba01bSAlexander von Gluck IV 	if (vol->vcache.by_vnid == NULL) {
136*342a1b22SJim906 		INFORM("init_vcache: out of memory\n");
1379f3ba01bSAlexander von Gluck IV 		return ENOMEM;
1389f3ba01bSAlexander von Gluck IV 	}
1399f3ba01bSAlexander von Gluck IV 
1409f3ba01bSAlexander von Gluck IV 	vol->vcache.by_loc = (vcache_entry**)calloc(sizeof(struct vache_entry *),
1419f3ba01bSAlexander von Gluck IV 		vol->vcache.cache_size);
1429f3ba01bSAlexander von Gluck IV 	if (vol->vcache.by_loc == NULL) {
143*342a1b22SJim906 		INFORM("init_vcache: out of memory\n");
1449f3ba01bSAlexander von Gluck IV 		free(vol->vcache.by_vnid);
1459f3ba01bSAlexander von Gluck IV 		vol->vcache.by_vnid = NULL;
1469f3ba01bSAlexander von Gluck IV 		return ENOMEM;
1479f3ba01bSAlexander von Gluck IV 	}
1489f3ba01bSAlexander von Gluck IV 
149*342a1b22SJim906 	sprintf(name, "fat cache %" B_PRIdDEV, vol->mnt_fsvolume->id);
1509f3ba01bSAlexander von Gluck IV 	rw_lock_init(&vol->vcache.lock, "fat cache");
1519f3ba01bSAlexander von Gluck IV 
152*342a1b22SJim906 	PRINT("init_vcache: initialized vnid cache with %" B_PRIu32
153*342a1b22SJim906 		" entries\n", vol->vcache.cache_size);
1549f3ba01bSAlexander von Gluck IV 
1559f3ba01bSAlexander von Gluck IV 	return 0;
1569f3ba01bSAlexander von Gluck IV }
1579f3ba01bSAlexander von Gluck IV 
1589f3ba01bSAlexander von Gluck IV 
1599f3ba01bSAlexander von Gluck IV status_t
uninit_vcache(mount * vol)160*342a1b22SJim906 uninit_vcache(mount* vol)
1619f3ba01bSAlexander von Gluck IV {
1629f3ba01bSAlexander von Gluck IV 	uint32 i, count = 0;
1639f3ba01bSAlexander von Gluck IV 	struct vcache_entry *c, *n;
164*342a1b22SJim906 	FUNCTION();
1659f3ba01bSAlexander von Gluck IV 
1669f3ba01bSAlexander von Gluck IV 	LOCK_CACHE_W;
1679f3ba01bSAlexander von Gluck IV 
1689f3ba01bSAlexander von Gluck IV 	/* free entries */
1699f3ba01bSAlexander von Gluck IV 	for (i = 0; i < vol->vcache.cache_size; i++) {
1709f3ba01bSAlexander von Gluck IV 		c = vol->vcache.by_vnid[i];
1719f3ba01bSAlexander von Gluck IV 		while (c) {
1729f3ba01bSAlexander von Gluck IV 			count++;
1739f3ba01bSAlexander von Gluck IV 			n = c->next_vnid;
1749f3ba01bSAlexander von Gluck IV 			free(c);
1759f3ba01bSAlexander von Gluck IV 			c = n;
1769f3ba01bSAlexander von Gluck IV 		}
1779f3ba01bSAlexander von Gluck IV 	}
1789f3ba01bSAlexander von Gluck IV 
179*342a1b22SJim906 	PRINT("%" B_PRIu32 " vcache entries removed\n", count);
1809f3ba01bSAlexander von Gluck IV 
1819f3ba01bSAlexander von Gluck IV 	free(vol->vcache.by_vnid); vol->vcache.by_vnid = NULL;
1829f3ba01bSAlexander von Gluck IV 	free(vol->vcache.by_loc); vol->vcache.by_loc = NULL;
1839f3ba01bSAlexander von Gluck IV 
1849f3ba01bSAlexander von Gluck IV 	rw_lock_destroy(&vol->vcache.lock);
1859f3ba01bSAlexander von Gluck IV 	return B_OK;
1869f3ba01bSAlexander von Gluck IV }
1879f3ba01bSAlexander von Gluck IV 
1889f3ba01bSAlexander von Gluck IV 
1899f3ba01bSAlexander von Gluck IV ino_t
generate_unique_vnid(mount * vol)190*342a1b22SJim906 generate_unique_vnid(mount* vol)
1919f3ba01bSAlexander von Gluck IV {
192*342a1b22SJim906 	FUNCTION();
193*342a1b22SJim906 
194*342a1b22SJim906 #ifdef FS_SHELL
195*342a1b22SJim906 	LOCK_CACHE_W;
196*342a1b22SJim906 	ino_t current = vol->vcache.cur_vnid++;
197*342a1b22SJim906 	UNLOCK_CACHE_W;
198*342a1b22SJim906 
199*342a1b22SJim906 	return current;
200*342a1b22SJim906 #else
201*342a1b22SJim906 	return atomic_add64(&vol->vcache.cur_vnid, 1);
202*342a1b22SJim906 #endif // !FS_SHELL
2039f3ba01bSAlexander von Gluck IV }
2049f3ba01bSAlexander von Gluck IV 
2059f3ba01bSAlexander von Gluck IV 
2069f3ba01bSAlexander von Gluck IV static status_t
_add_to_vcache_(mount * vol,ino_t vnid,ino_t loc)207*342a1b22SJim906 _add_to_vcache_(mount* vol, ino_t vnid, ino_t loc)
2089f3ba01bSAlexander von Gluck IV {
2099f3ba01bSAlexander von Gluck IV 	int hash1 = hash(vnid), hash2 = hash(loc);
2109f3ba01bSAlexander von Gluck IV 	struct vcache_entry *e, *c, *p;
2119f3ba01bSAlexander von Gluck IV 
212*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO "/%" B_PRIdINO "\n", vnid, loc);
2139f3ba01bSAlexander von Gluck IV 
2149f3ba01bSAlexander von Gluck IV 	e = (vcache_entry*)malloc(sizeof(struct vcache_entry));
2159f3ba01bSAlexander von Gluck IV 	if (e == NULL)
2169f3ba01bSAlexander von Gluck IV 		return ENOMEM;
2179f3ba01bSAlexander von Gluck IV 
218*342a1b22SJim906 	e->vnid = vnid; e->loc = loc; e->constructed = false; e->next_vnid = NULL; e->next_loc = NULL;
2199f3ba01bSAlexander von Gluck IV 
2209f3ba01bSAlexander von Gluck IV 	c = p = vol->vcache.by_vnid[hash1];
2219f3ba01bSAlexander von Gluck IV 	while (c) {
2229f3ba01bSAlexander von Gluck IV 		if (vnid < c->vnid)
2239f3ba01bSAlexander von Gluck IV 			break;
2249f3ba01bSAlexander von Gluck IV 		ASSERT(vnid != c->vnid); ASSERT(loc != c->loc);
2259f3ba01bSAlexander von Gluck IV 		p = c;
2269f3ba01bSAlexander von Gluck IV 		c = c->next_vnid;
2279f3ba01bSAlexander von Gluck IV 	}
2289f3ba01bSAlexander von Gluck IV 	ASSERT(!c || (vnid != c->vnid));
2299f3ba01bSAlexander von Gluck IV 
2309f3ba01bSAlexander von Gluck IV 	e->next_vnid = c;
2319f3ba01bSAlexander von Gluck IV 	if (p == c)
2329f3ba01bSAlexander von Gluck IV 		vol->vcache.by_vnid[hash1] = e;
2339f3ba01bSAlexander von Gluck IV 	else
2349f3ba01bSAlexander von Gluck IV 		p->next_vnid = e;
2359f3ba01bSAlexander von Gluck IV 
2369f3ba01bSAlexander von Gluck IV 	c = p = vol->vcache.by_loc[hash2];
2379f3ba01bSAlexander von Gluck IV 	while (c) {
2389f3ba01bSAlexander von Gluck IV 		if (loc < c->loc)
2399f3ba01bSAlexander von Gluck IV 			break;
2409f3ba01bSAlexander von Gluck IV 		ASSERT(vnid != c->vnid); ASSERT(loc != c->loc);
2419f3ba01bSAlexander von Gluck IV 		p = c;
2429f3ba01bSAlexander von Gluck IV 		c = c->next_loc;
2439f3ba01bSAlexander von Gluck IV 	}
2449f3ba01bSAlexander von Gluck IV 	ASSERT(!c || (loc != c->loc));
2459f3ba01bSAlexander von Gluck IV 
2469f3ba01bSAlexander von Gluck IV 	e->next_loc = c;
2479f3ba01bSAlexander von Gluck IV 	if (p == c)
2489f3ba01bSAlexander von Gluck IV 		vol->vcache.by_loc[hash2] = e;
2499f3ba01bSAlexander von Gluck IV 	else
2509f3ba01bSAlexander von Gluck IV 		p->next_loc = e;
2519f3ba01bSAlexander von Gluck IV 
2529f3ba01bSAlexander von Gluck IV 	return B_OK;
2539f3ba01bSAlexander von Gluck IV }
2549f3ba01bSAlexander von Gluck IV 
2559f3ba01bSAlexander von Gluck IV 
2569f3ba01bSAlexander von Gluck IV static status_t
_remove_from_vcache_(mount * vol,ino_t vnid)257*342a1b22SJim906 _remove_from_vcache_(mount* vol, ino_t vnid)
2589f3ba01bSAlexander von Gluck IV {
2599f3ba01bSAlexander von Gluck IV 	int hash1 = hash(vnid), hash2;
2609f3ba01bSAlexander von Gluck IV 	struct vcache_entry *c, *p, *e;
2619f3ba01bSAlexander von Gluck IV 
262*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO "\n", vnid);
2639f3ba01bSAlexander von Gluck IV 
2649f3ba01bSAlexander von Gluck IV 	c = p = vol->vcache.by_vnid[hash1];
2659f3ba01bSAlexander von Gluck IV 	while (c) {
2669f3ba01bSAlexander von Gluck IV 		if (vnid == c->vnid)
2679f3ba01bSAlexander von Gluck IV 			break;
2689f3ba01bSAlexander von Gluck IV 		ASSERT(c->vnid < vnid);
2699f3ba01bSAlexander von Gluck IV 		p = c;
2709f3ba01bSAlexander von Gluck IV 		c = c->next_vnid;
2719f3ba01bSAlexander von Gluck IV 	}
2729f3ba01bSAlexander von Gluck IV 	ASSERT(c);
2739f3ba01bSAlexander von Gluck IV 	if (!c) return ENOENT;
2749f3ba01bSAlexander von Gluck IV 
2759f3ba01bSAlexander von Gluck IV 	if (p == c)
2769f3ba01bSAlexander von Gluck IV 		vol->vcache.by_vnid[hash1] = c->next_vnid;
2779f3ba01bSAlexander von Gluck IV 	else
2789f3ba01bSAlexander von Gluck IV 		p->next_vnid = c->next_vnid;
2799f3ba01bSAlexander von Gluck IV 
2809f3ba01bSAlexander von Gluck IV 	e = c;
2819f3ba01bSAlexander von Gluck IV 
2829f3ba01bSAlexander von Gluck IV 	hash2 = hash(c->loc);
2839f3ba01bSAlexander von Gluck IV 	c = p = vol->vcache.by_loc[hash2];
2849f3ba01bSAlexander von Gluck IV 
2859f3ba01bSAlexander von Gluck IV 	while (c) {
2869f3ba01bSAlexander von Gluck IV 		if (vnid == c->vnid)
2879f3ba01bSAlexander von Gluck IV 			break;
2889f3ba01bSAlexander von Gluck IV 		ASSERT(c->loc < e->loc);
2899f3ba01bSAlexander von Gluck IV 		p = c;
2909f3ba01bSAlexander von Gluck IV 		c = c->next_loc;
2919f3ba01bSAlexander von Gluck IV 	}
2929f3ba01bSAlexander von Gluck IV 	ASSERT(c);
2939f3ba01bSAlexander von Gluck IV 	if (!c) return ENOENT;
2949f3ba01bSAlexander von Gluck IV 	if (p == c)
2959f3ba01bSAlexander von Gluck IV 		vol->vcache.by_loc[hash2] = c->next_loc;
2969f3ba01bSAlexander von Gluck IV 	else
2979f3ba01bSAlexander von Gluck IV 		p->next_loc = c->next_loc;
2989f3ba01bSAlexander von Gluck IV 
2999f3ba01bSAlexander von Gluck IV 	free(c);
3009f3ba01bSAlexander von Gluck IV 
3019f3ba01bSAlexander von Gluck IV 	return 0;
3029f3ba01bSAlexander von Gluck IV }
3039f3ba01bSAlexander von Gluck IV 
3049f3ba01bSAlexander von Gluck IV 
3059f3ba01bSAlexander von Gluck IV static struct vcache_entry *
_find_vnid_in_vcache_(mount * vol,ino_t vnid)306*342a1b22SJim906 _find_vnid_in_vcache_(mount* vol, ino_t vnid)
3079f3ba01bSAlexander von Gluck IV {
3089f3ba01bSAlexander von Gluck IV 	int hash1 = hash(vnid);
3099f3ba01bSAlexander von Gluck IV 	struct vcache_entry *c;
3109f3ba01bSAlexander von Gluck IV 	c = vol->vcache.by_vnid[hash1];
3119f3ba01bSAlexander von Gluck IV 	while (c) {
3129f3ba01bSAlexander von Gluck IV 		if (c->vnid == vnid)
3139f3ba01bSAlexander von Gluck IV 			break;
3149f3ba01bSAlexander von Gluck IV 		if (c->vnid > vnid)
3159f3ba01bSAlexander von Gluck IV 			return NULL;
3169f3ba01bSAlexander von Gluck IV 		c = c->next_vnid;
3179f3ba01bSAlexander von Gluck IV 	}
3189f3ba01bSAlexander von Gluck IV 
3199f3ba01bSAlexander von Gluck IV 	return c;
3209f3ba01bSAlexander von Gluck IV }
3219f3ba01bSAlexander von Gluck IV 
3229f3ba01bSAlexander von Gluck IV 
3239f3ba01bSAlexander von Gluck IV static struct vcache_entry *
_find_loc_in_vcache_(mount * vol,ino_t loc)324*342a1b22SJim906 _find_loc_in_vcache_(mount* vol, ino_t loc)
3259f3ba01bSAlexander von Gluck IV {
3269f3ba01bSAlexander von Gluck IV 	int hash2 = hash(loc);
3279f3ba01bSAlexander von Gluck IV 	struct vcache_entry *c;
3289f3ba01bSAlexander von Gluck IV 	c = vol->vcache.by_loc[hash2];
3299f3ba01bSAlexander von Gluck IV 	while (c) {
3309f3ba01bSAlexander von Gluck IV 		if (c->loc == loc)
3319f3ba01bSAlexander von Gluck IV 			break;
3329f3ba01bSAlexander von Gluck IV 		if (c->loc > loc)
3339f3ba01bSAlexander von Gluck IV 			return NULL;
3349f3ba01bSAlexander von Gluck IV 		c = c->next_loc;
3359f3ba01bSAlexander von Gluck IV 	}
3369f3ba01bSAlexander von Gluck IV 
3379f3ba01bSAlexander von Gluck IV 	return c;
3389f3ba01bSAlexander von Gluck IV }
3399f3ba01bSAlexander von Gluck IV 
3409f3ba01bSAlexander von Gluck IV 
3419f3ba01bSAlexander von Gluck IV status_t
add_to_vcache(mount * vol,ino_t vnid,ino_t loc)342*342a1b22SJim906 add_to_vcache(mount* vol, ino_t vnid, ino_t loc)
3439f3ba01bSAlexander von Gluck IV {
3449f3ba01bSAlexander von Gluck IV 	status_t result;
3459f3ba01bSAlexander von Gluck IV 
3469f3ba01bSAlexander von Gluck IV 	LOCK_CACHE_W;
3479f3ba01bSAlexander von Gluck IV 	result = _add_to_vcache_(vol,vnid,loc);
3489f3ba01bSAlexander von Gluck IV 	UNLOCK_CACHE_W;
3499f3ba01bSAlexander von Gluck IV 
350*342a1b22SJim906 	if (result < 0) INFORM("add_to_vcache failed (%s)\n", strerror(result));
3519f3ba01bSAlexander von Gluck IV 	return result;
3529f3ba01bSAlexander von Gluck IV }
3539f3ba01bSAlexander von Gluck IV 
3549f3ba01bSAlexander von Gluck IV 
3559f3ba01bSAlexander von Gluck IV static status_t
_update_loc_in_vcache_(mount * vol,ino_t vnid,ino_t loc)356*342a1b22SJim906 _update_loc_in_vcache_(mount* vol, ino_t vnid, ino_t loc)
3579f3ba01bSAlexander von Gluck IV {
3589f3ba01bSAlexander von Gluck IV 	status_t result;
359*342a1b22SJim906 	bool constructed;
360*342a1b22SJim906 	result = vcache_get_constructed(vol, vnid, &constructed);
361*342a1b22SJim906 	if (result != B_OK)
362*342a1b22SJim906 		return result;
363*342a1b22SJim906 #if DEBUG
364*342a1b22SJim906 	struct vnode *node;
365*342a1b22SJim906 	result = vcache_get_node(vol, vnid, &node);
366*342a1b22SJim906 	if (result != B_OK)
367*342a1b22SJim906 		return result;
368*342a1b22SJim906 #endif // DEBUG
3699f3ba01bSAlexander von Gluck IV 
3709f3ba01bSAlexander von Gluck IV 	result = _remove_from_vcache_(vol, vnid);
371*342a1b22SJim906 	if (result == 0) {
3729f3ba01bSAlexander von Gluck IV 		result = _add_to_vcache_(vol, vnid, loc);
373*342a1b22SJim906 		if (result == B_OK && constructed == true)
374*342a1b22SJim906 			result = vcache_set_constructed(vol, vnid);
375*342a1b22SJim906 #if DEBUG
376*342a1b22SJim906 		if (result == B_OK)
377*342a1b22SJim906 			result = vcache_set_node(vol, vnid, node);
378*342a1b22SJim906 #endif // DEBUG
379*342a1b22SJim906 	}
3809f3ba01bSAlexander von Gluck IV 
3819f3ba01bSAlexander von Gluck IV 	return result;
3829f3ba01bSAlexander von Gluck IV }
3839f3ba01bSAlexander von Gluck IV 
3849f3ba01bSAlexander von Gluck IV 
3859f3ba01bSAlexander von Gluck IV status_t
remove_from_vcache(mount * vol,ino_t vnid)386*342a1b22SJim906 remove_from_vcache(mount* vol, ino_t vnid)
3879f3ba01bSAlexander von Gluck IV {
3889f3ba01bSAlexander von Gluck IV 	status_t result;
3899f3ba01bSAlexander von Gluck IV 
3909f3ba01bSAlexander von Gluck IV 	LOCK_CACHE_W;
3919f3ba01bSAlexander von Gluck IV 	result = _remove_from_vcache_(vol, vnid);
3929f3ba01bSAlexander von Gluck IV 	UNLOCK_CACHE_W;
3939f3ba01bSAlexander von Gluck IV 
394*342a1b22SJim906 	if (result < 0) INFORM("remove_from_vcache failed (%s)\n", strerror(result));
3959f3ba01bSAlexander von Gluck IV 	return result;
3969f3ba01bSAlexander von Gluck IV }
3979f3ba01bSAlexander von Gluck IV 
3989f3ba01bSAlexander von Gluck IV 
3999f3ba01bSAlexander von Gluck IV status_t
vcache_vnid_to_loc(mount * vol,ino_t vnid,ino_t * loc)400*342a1b22SJim906 vcache_vnid_to_loc(mount* vol, ino_t vnid, ino_t* loc)
4019f3ba01bSAlexander von Gluck IV {
4029f3ba01bSAlexander von Gluck IV 	struct vcache_entry *e;
4039f3ba01bSAlexander von Gluck IV 
404*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO " %p\n", vnid,	loc);
4059f3ba01bSAlexander von Gluck IV 
4069f3ba01bSAlexander von Gluck IV 	LOCK_CACHE_R;
4079f3ba01bSAlexander von Gluck IV 	e = _find_vnid_in_vcache_(vol, vnid);
4089f3ba01bSAlexander von Gluck IV 	if (loc && e)
4099f3ba01bSAlexander von Gluck IV 			*loc = e->loc;
4109f3ba01bSAlexander von Gluck IV 	UNLOCK_CACHE_R;
4119f3ba01bSAlexander von Gluck IV 
4129f3ba01bSAlexander von Gluck IV 	return (e) ? B_OK : ENOENT;
4139f3ba01bSAlexander von Gluck IV }
4149f3ba01bSAlexander von Gluck IV 
4159f3ba01bSAlexander von Gluck IV 
4169f3ba01bSAlexander von Gluck IV status_t
vcache_loc_to_vnid(mount * vol,ino_t loc,ino_t * vnid)417*342a1b22SJim906 vcache_loc_to_vnid(mount* vol, ino_t loc, ino_t* vnid)
4189f3ba01bSAlexander von Gluck IV {
4199f3ba01bSAlexander von Gluck IV 	struct vcache_entry *e;
4209f3ba01bSAlexander von Gluck IV 
421*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO " %p\n", loc, vnid);
4229f3ba01bSAlexander von Gluck IV 
4239f3ba01bSAlexander von Gluck IV 	LOCK_CACHE_R;
4249f3ba01bSAlexander von Gluck IV 	e = _find_loc_in_vcache_(vol, loc);
4259f3ba01bSAlexander von Gluck IV 	if (vnid && e)
4269f3ba01bSAlexander von Gluck IV 			*vnid = e->vnid;
4279f3ba01bSAlexander von Gluck IV 	UNLOCK_CACHE_R;
4289f3ba01bSAlexander von Gluck IV 
4299f3ba01bSAlexander von Gluck IV 	return (e) ? B_OK : ENOENT;
4309f3ba01bSAlexander von Gluck IV }
4319f3ba01bSAlexander von Gluck IV 
4329f3ba01bSAlexander von Gluck IV 
4339f3ba01bSAlexander von Gluck IV status_t
vcache_set_entry(mount * vol,ino_t vnid,ino_t loc)434*342a1b22SJim906 vcache_set_entry(mount* vol, ino_t vnid, ino_t loc)
4359f3ba01bSAlexander von Gluck IV {
4369f3ba01bSAlexander von Gluck IV 	struct vcache_entry *e;
4379f3ba01bSAlexander von Gluck IV 	status_t result = B_OK;
4389f3ba01bSAlexander von Gluck IV 
439*342a1b22SJim906 	FUNCTION_START("vcache_set_entry: %" B_PRIdINO " -> %" B_PRIdINO "\n", vnid, loc);
4409f3ba01bSAlexander von Gluck IV 
4419f3ba01bSAlexander von Gluck IV 	LOCK_CACHE_W;
4429f3ba01bSAlexander von Gluck IV 
4439f3ba01bSAlexander von Gluck IV 	e = _find_vnid_in_vcache_(vol, vnid);
4449f3ba01bSAlexander von Gluck IV 
445*342a1b22SJim906 	if (e)
4469f3ba01bSAlexander von Gluck IV 		result = _update_loc_in_vcache_(vol, vnid, loc);
447*342a1b22SJim906 	else
4489f3ba01bSAlexander von Gluck IV 		result = _add_to_vcache_(vol,vnid,loc);
4499f3ba01bSAlexander von Gluck IV 
4509f3ba01bSAlexander von Gluck IV 	UNLOCK_CACHE_W;
4519f3ba01bSAlexander von Gluck IV 
4529f3ba01bSAlexander von Gluck IV 	return result;
4539f3ba01bSAlexander von Gluck IV }
4549f3ba01bSAlexander von Gluck IV 
455*342a1b22SJim906 
456*342a1b22SJim906 status_t
vcache_set_constructed(mount * vol,ino_t vnid,bool constructed)457*342a1b22SJim906 vcache_set_constructed(mount* vol, ino_t vnid, bool constructed)
458*342a1b22SJim906 {
459*342a1b22SJim906 	struct vcache_entry* cEntry;
460*342a1b22SJim906 	status_t result = B_OK;
461*342a1b22SJim906 
462*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO "\n", vnid);
463*342a1b22SJim906 
464*342a1b22SJim906 	LOCK_CACHE_W;
465*342a1b22SJim906 
466*342a1b22SJim906 	cEntry = _find_vnid_in_vcache_(vol, vnid);
467*342a1b22SJim906 
468*342a1b22SJim906 	if (cEntry != NULL)
469*342a1b22SJim906 		cEntry->constructed = constructed;
470*342a1b22SJim906 	else
471*342a1b22SJim906 		result = B_BAD_VALUE;
472*342a1b22SJim906 
473*342a1b22SJim906 	UNLOCK_CACHE_W;
474*342a1b22SJim906 
475*342a1b22SJim906 	return result;
476*342a1b22SJim906 }
477*342a1b22SJim906 
478*342a1b22SJim906 
479*342a1b22SJim906 status_t
vcache_get_constructed(mount * vol,ino_t vnid,bool * constructed)480*342a1b22SJim906 vcache_get_constructed(mount* vol, ino_t vnid, bool* constructed)
481*342a1b22SJim906 {
482*342a1b22SJim906 	struct vcache_entry* cEntry;
483*342a1b22SJim906 	status_t result = B_OK;
484*342a1b22SJim906 
485*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO "\n", vnid);
486*342a1b22SJim906 
487*342a1b22SJim906 	LOCK_CACHE_W;
488*342a1b22SJim906 
489*342a1b22SJim906 	cEntry = _find_vnid_in_vcache_(vol, vnid);
490*342a1b22SJim906 
491*342a1b22SJim906 	if (cEntry != NULL)
492*342a1b22SJim906 		*constructed = cEntry->constructed;
493*342a1b22SJim906 	else
494*342a1b22SJim906 		result = B_BAD_VALUE;
495*342a1b22SJim906 
496*342a1b22SJim906 	UNLOCK_CACHE_W;
497*342a1b22SJim906 
498*342a1b22SJim906 	return result;
499*342a1b22SJim906 }
500*342a1b22SJim906 
501*342a1b22SJim906 
502*342a1b22SJim906 status_t
sync_all_files(mount * vol)503*342a1b22SJim906 sync_all_files(mount* vol)
504*342a1b22SJim906 {
505*342a1b22SJim906 	uint32 count = 0, errors = 0;
506*342a1b22SJim906 	vnode* bsdNode = NULL;
507*342a1b22SJim906 	status_t status = B_OK;
508*342a1b22SJim906 
509*342a1b22SJim906 	FUNCTION_START("volume @ %p\n", vol);
510*342a1b22SJim906 
511*342a1b22SJim906 	LOCK_CACHE_R;
512*342a1b22SJim906 
513*342a1b22SJim906 	for (uint32 i = 0; i < vol->vcache.cache_size; i++) {
514*342a1b22SJim906 		for (vcache_entry* cEntry = vol->vcache.by_vnid[i]; cEntry != NULL ;
515*342a1b22SJim906 			cEntry = cEntry->next_vnid) {
516*342a1b22SJim906 			if (cEntry->constructed == true) {
517*342a1b22SJim906 				status = get_vnode(vol->mnt_fsvolume, cEntry->vnid,
518*342a1b22SJim906 					reinterpret_cast<void**>(&bsdNode));
519*342a1b22SJim906 				if (status != B_OK) {
520*342a1b22SJim906 					INFORM("get_vnode:  %s\n", strerror(status));
521*342a1b22SJim906 					errors++;
522*342a1b22SJim906 				} else {
523*342a1b22SJim906 					if (bsdNode->v_type == VREG) {
524*342a1b22SJim906 						status = file_cache_sync(bsdNode->v_cache);
525*342a1b22SJim906 						if (status != B_OK)
526*342a1b22SJim906 							errors++;
527*342a1b22SJim906 						else
528*342a1b22SJim906 							count++;
529*342a1b22SJim906 					}
530*342a1b22SJim906 					put_vnode(vol->mnt_fsvolume, cEntry->vnid);
531*342a1b22SJim906 				}
532*342a1b22SJim906 			}
533*342a1b22SJim906 		}
534*342a1b22SJim906 	}
535*342a1b22SJim906 
536*342a1b22SJim906 	UNLOCK_CACHE_R;
537*342a1b22SJim906 
538*342a1b22SJim906 	PRINT("sync'd %" B_PRIu32 " files with %" B_PRIu32 " errors\n", count, errors);
539*342a1b22SJim906 
540*342a1b22SJim906 	return (errors == 0) ? B_OK : B_ERROR;
541*342a1b22SJim906 }
542*342a1b22SJim906 
543*342a1b22SJim906 
5449f3ba01bSAlexander von Gluck IV #if DEBUG
545*342a1b22SJim906 status_t
vcache_set_node(mount * vol,ino_t vnid,struct vnode * node)546*342a1b22SJim906 vcache_set_node(mount* vol, ino_t vnid, struct vnode* node)
547*342a1b22SJim906 {
548*342a1b22SJim906 	vcache_entry* cEntry;
549*342a1b22SJim906 	status_t result = B_OK;
550*342a1b22SJim906 
551*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO "\n", vnid);
552*342a1b22SJim906 
553*342a1b22SJim906 	LOCK_CACHE_W;
554*342a1b22SJim906 
555*342a1b22SJim906 	cEntry = _find_vnid_in_vcache_(vol, vnid);
556*342a1b22SJim906 
557*342a1b22SJim906 	if (cEntry != NULL)
558*342a1b22SJim906 		cEntry->node = node;
559*342a1b22SJim906 	else
560*342a1b22SJim906 		result = B_BAD_VALUE;
561*342a1b22SJim906 
562*342a1b22SJim906 	UNLOCK_CACHE_W;
563*342a1b22SJim906 
564*342a1b22SJim906 	return result;
565*342a1b22SJim906 }
566*342a1b22SJim906 
567*342a1b22SJim906 
568*342a1b22SJim906 status_t
vcache_get_node(mount * vol,ino_t vnid,struct vnode ** node)569*342a1b22SJim906 vcache_get_node(mount* vol, ino_t vnid, struct vnode** node)
570*342a1b22SJim906 {
571*342a1b22SJim906 	vcache_entry* cEntry;
572*342a1b22SJim906 	status_t result = B_OK;
573*342a1b22SJim906 
574*342a1b22SJim906 	FUNCTION_START("%" B_PRIdINO "\n", vnid);
575*342a1b22SJim906 
576*342a1b22SJim906 	LOCK_CACHE_W;
577*342a1b22SJim906 
578*342a1b22SJim906 	cEntry = _find_vnid_in_vcache_(vol, vnid);
579*342a1b22SJim906 
580*342a1b22SJim906 	if (cEntry != NULL)
581*342a1b22SJim906 		*node = cEntry->node;
582*342a1b22SJim906 	else
583*342a1b22SJim906 		result = B_BAD_VALUE;
584*342a1b22SJim906 
585*342a1b22SJim906 	UNLOCK_CACHE_W;
586*342a1b22SJim906 
587*342a1b22SJim906 	return result;
588*342a1b22SJim906 }
589*342a1b22SJim906 
5909f3ba01bSAlexander von Gluck IV 
5919f3ba01bSAlexander von Gluck IV int
debug_dfvnid(int argc,char ** argv)5929f3ba01bSAlexander von Gluck IV debug_dfvnid(int argc, char **argv)
5939f3ba01bSAlexander von Gluck IV {
5949f3ba01bSAlexander von Gluck IV 	int i;
595*342a1b22SJim906 	mount* vol;
5969f3ba01bSAlexander von Gluck IV 
5979f3ba01bSAlexander von Gluck IV 	if (argc < 3) {
598*342a1b22SJim906 		kprintf("dfvnid volume vnid\n");
5999f3ba01bSAlexander von Gluck IV 		return B_OK;
6009f3ba01bSAlexander von Gluck IV 	}
6019f3ba01bSAlexander von Gluck IV 
602*342a1b22SJim906 	vol = reinterpret_cast<mount*>(strtoul(argv[1], NULL, 0));
6039f3ba01bSAlexander von Gluck IV 	if (vol == NULL)
6049f3ba01bSAlexander von Gluck IV 		return B_OK;
6059f3ba01bSAlexander von Gluck IV 
6069f3ba01bSAlexander von Gluck IV 	for (i = 2; i < argc; i++) {
6079f3ba01bSAlexander von Gluck IV 		ino_t vnid = strtoull(argv[i], NULL, 0);
6089f3ba01bSAlexander von Gluck IV 		struct vcache_entry *e;
6099f3ba01bSAlexander von Gluck IV 		if ((e = _find_vnid_in_vcache_(vol, vnid)) != NULL) {
6109f3ba01bSAlexander von Gluck IV 			kprintf("vnid %" B_PRIdINO " -> loc %" B_PRIdINO " @ %p\n", vnid,
6119f3ba01bSAlexander von Gluck IV 				e->loc, e);
6129f3ba01bSAlexander von Gluck IV 		} else {
6139f3ba01bSAlexander von Gluck IV 			kprintf("vnid %" B_PRIdINO " not found in vnid cache\n", vnid);
6149f3ba01bSAlexander von Gluck IV 		}
6159f3ba01bSAlexander von Gluck IV 	}
6169f3ba01bSAlexander von Gluck IV 
6179f3ba01bSAlexander von Gluck IV 	return B_OK;
6189f3ba01bSAlexander von Gluck IV }
6199f3ba01bSAlexander von Gluck IV 
6209f3ba01bSAlexander von Gluck IV 
6219f3ba01bSAlexander von Gluck IV int
debug_dfloc(int argc,char ** argv)6229f3ba01bSAlexander von Gluck IV debug_dfloc(int argc, char **argv)
6239f3ba01bSAlexander von Gluck IV {
6249f3ba01bSAlexander von Gluck IV 	int i;
625*342a1b22SJim906 	mount* vol;
6269f3ba01bSAlexander von Gluck IV 
6279f3ba01bSAlexander von Gluck IV 	if (argc < 3) {
628*342a1b22SJim906 		kprintf("dfloc volume vnid\n");
6299f3ba01bSAlexander von Gluck IV 		return B_OK;
6309f3ba01bSAlexander von Gluck IV 	}
6319f3ba01bSAlexander von Gluck IV 
632*342a1b22SJim906 	vol = reinterpret_cast<mount*>(strtoul(argv[1], NULL, 0));
6339f3ba01bSAlexander von Gluck IV 	if (vol == NULL)
6349f3ba01bSAlexander von Gluck IV 		return B_OK;
6359f3ba01bSAlexander von Gluck IV 
6369f3ba01bSAlexander von Gluck IV 	for (i = 2; i < argc; i++) {
6379f3ba01bSAlexander von Gluck IV 		ino_t loc = strtoull(argv[i], NULL, 0);
6389f3ba01bSAlexander von Gluck IV 		struct vcache_entry *e;
6399f3ba01bSAlexander von Gluck IV 		if ((e = _find_loc_in_vcache_(vol, loc)) != NULL) {
6409f3ba01bSAlexander von Gluck IV 			kprintf("loc %" B_PRIdINO " -> vnid %" B_PRIdINO " @ %p\n", loc,
6419f3ba01bSAlexander von Gluck IV 				e->vnid, e);
6429f3ba01bSAlexander von Gluck IV 		} else {
6439f3ba01bSAlexander von Gluck IV 			kprintf("loc %" B_PRIdINO " not found in vnid cache\n", loc);
6449f3ba01bSAlexander von Gluck IV 		}
6459f3ba01bSAlexander von Gluck IV 	}
6469f3ba01bSAlexander von Gluck IV 
6479f3ba01bSAlexander von Gluck IV 	return B_OK;
6489f3ba01bSAlexander von Gluck IV }
649*342a1b22SJim906 #endif // DEBUG
650