xref: /minix3/minix/lib/libvtreefs/inode.c (revision 7c48de6cc4c6d56f2277d378dba01dbac8a8c3b9)
1693ad767SDavid van Moolenbroek /* VTreeFS - inode.c - inode management */
2433d6423SLionel Sambuc 
3433d6423SLionel Sambuc #include "inc.h"
4433d6423SLionel Sambuc 
5433d6423SLionel Sambuc /* The number of inodes and hash table slots. */
6433d6423SLionel Sambuc static unsigned int nr_inodes;
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc /* The table of all the inodes. */
9433d6423SLionel Sambuc static struct inode *inode;
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc /* The list of unused inodes. */
12433d6423SLionel Sambuc static TAILQ_HEAD(unused_head, inode) unused_inodes;
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc /* The hash tables for lookup of <parent,name> and <parent,index> to inode. */
LIST_HEAD(name_head,inode)15433d6423SLionel Sambuc static LIST_HEAD(name_head, inode) *parent_name_head;
16433d6423SLionel Sambuc static LIST_HEAD(index_head, inode) *parent_index_head;
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc /* Internal integrity check. */
19433d6423SLionel Sambuc #define CHECK_INODE(node)						\
20433d6423SLionel Sambuc 	do {								\
21433d6423SLionel Sambuc 		assert(node >= &inode[0] && node < &inode[nr_inodes]);	\
2252be5c0aSDavid van Moolenbroek 		assert((unsigned int)(node - &inode[0]) == node->i_num);\
23693ad767SDavid van Moolenbroek 		assert(node == &inode[0] || node->i_parent != NULL ||	\
24433d6423SLionel Sambuc 		    (node->i_flags & I_DELETED));			\
25433d6423SLionel Sambuc 	} while (0);
26433d6423SLionel Sambuc 
27693ad767SDavid van Moolenbroek /*
28693ad767SDavid van Moolenbroek  * Initialize the inode-related state.
29693ad767SDavid van Moolenbroek  */
305eefd0feSDavid van Moolenbroek int
31*7c48de6cSDavid van Moolenbroek init_inodes(unsigned int inodes, struct inode_stat * istat,
32433d6423SLionel Sambuc 	index_t nr_indexed_entries)
33433d6423SLionel Sambuc {
34433d6423SLionel Sambuc 	struct inode *node;
350dc5c83eSDavid van Moolenbroek 	unsigned int i;
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc 	assert(inodes > 0);
38433d6423SLionel Sambuc 	assert(nr_indexed_entries >= 0);
39433d6423SLionel Sambuc 
40433d6423SLionel Sambuc 	nr_inodes = inodes;
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc 	/* Allocate the inode and hash tables. */
435eefd0feSDavid van Moolenbroek 	if ((inode = malloc(nr_inodes * sizeof(inode[0]))) == NULL)
445eefd0feSDavid van Moolenbroek 		return ENOMEM;
45433d6423SLionel Sambuc 
465eefd0feSDavid van Moolenbroek 	parent_name_head = malloc(nr_inodes * sizeof(parent_name_head[0]));
475eefd0feSDavid van Moolenbroek 	if (parent_name_head == NULL) {
485eefd0feSDavid van Moolenbroek 		free(inode);
495eefd0feSDavid van Moolenbroek 		return ENOMEM;
505eefd0feSDavid van Moolenbroek 	}
515eefd0feSDavid van Moolenbroek 
525eefd0feSDavid van Moolenbroek 	parent_index_head = malloc(nr_inodes * sizeof(parent_index_head[0]));
535eefd0feSDavid van Moolenbroek 	if (parent_index_head == NULL) {
545eefd0feSDavid van Moolenbroek 		free(parent_name_head);
555eefd0feSDavid van Moolenbroek 		free(inode);
565eefd0feSDavid van Moolenbroek 		return ENOMEM;
575eefd0feSDavid van Moolenbroek 	}
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc #if DEBUG
60d91890d2SEmmanuel Blot 	printf("VTREEFS: allocated %zu+%zu+%zu bytes\n",
61433d6423SLionel Sambuc 	    nr_inodes * sizeof(inode[0]),
62433d6423SLionel Sambuc 	    nr_inodes * sizeof(parent_name_head[0]),
63433d6423SLionel Sambuc 	    nr_inodes * sizeof(parent_index_head[0]));
64433d6423SLionel Sambuc #endif
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc 	/* Initialize the free/unused list. */
67433d6423SLionel Sambuc 	TAILQ_INIT(&unused_inodes);
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc 	/* Add free inodes to the unused/free list.  Skip the root inode. */
70433d6423SLionel Sambuc 	for (i = 1; i < nr_inodes; i++) {
71433d6423SLionel Sambuc 		node = &inode[i];
7252be5c0aSDavid van Moolenbroek 		node->i_num = i;
73c21aa858SCristiano Giuffrida 		node->i_name = NULL;
74433d6423SLionel Sambuc 		node->i_parent = NULL;
75433d6423SLionel Sambuc 		node->i_count = 0;
76433d6423SLionel Sambuc 		TAILQ_INIT(&node->i_children);
77433d6423SLionel Sambuc 		TAILQ_INSERT_HEAD(&unused_inodes, node, i_unused);
78433d6423SLionel Sambuc 	}
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	/* Initialize the hash lists. */
81433d6423SLionel Sambuc 	for (i = 0; i < nr_inodes; i++) {
82433d6423SLionel Sambuc 		LIST_INIT(&parent_name_head[i]);
83433d6423SLionel Sambuc 		LIST_INIT(&parent_index_head[i]);
84433d6423SLionel Sambuc 	}
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc 	/* Initialize the root inode. */
87433d6423SLionel Sambuc 	node = &inode[0];
8852be5c0aSDavid van Moolenbroek 	node->i_num = 0;
89433d6423SLionel Sambuc 	node->i_parent = NULL;
90433d6423SLionel Sambuc 	node->i_count = 0;
91433d6423SLionel Sambuc 	TAILQ_INIT(&node->i_children);
92433d6423SLionel Sambuc 	node->i_flags = 0;
93433d6423SLionel Sambuc 	node->i_index = NO_INDEX;
94*7c48de6cSDavid van Moolenbroek 	set_inode_stat(node, istat);
95433d6423SLionel Sambuc 	node->i_indexed = nr_indexed_entries;
96433d6423SLionel Sambuc 	node->i_cbdata = NULL;
975eefd0feSDavid van Moolenbroek 
985eefd0feSDavid van Moolenbroek 	return OK;
99433d6423SLionel Sambuc }
100433d6423SLionel Sambuc 
101693ad767SDavid van Moolenbroek /*
102693ad767SDavid van Moolenbroek  * Clean up the inode-related state.
103433d6423SLionel Sambuc  */
104693ad767SDavid van Moolenbroek void
cleanup_inodes(void)105693ad767SDavid van Moolenbroek cleanup_inodes(void)
106693ad767SDavid van Moolenbroek {
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 	/* Free the inode and hash tables. */
109433d6423SLionel Sambuc 	free(parent_index_head);
110433d6423SLionel Sambuc 	free(parent_name_head);
111433d6423SLionel Sambuc 	free(inode);
112433d6423SLionel Sambuc }
113433d6423SLionel Sambuc 
114693ad767SDavid van Moolenbroek /*
115693ad767SDavid van Moolenbroek  * Return the hash value of <parent,name> tuple.
116433d6423SLionel Sambuc  */
117693ad767SDavid van Moolenbroek static int
parent_name_hash(const struct inode * parent,const char * name)118693ad767SDavid van Moolenbroek parent_name_hash(const struct inode * parent, const char *name)
119693ad767SDavid van Moolenbroek {
12052be5c0aSDavid van Moolenbroek 	unsigned int name_hash;
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc 	/* Use the sdbm algorithm to hash the name. */
123433d6423SLionel Sambuc 	name_hash = sdbm_hash(name, strlen(name));
124433d6423SLionel Sambuc 
12552be5c0aSDavid van Moolenbroek 	/* The parent hash is a simple array entry. */
12652be5c0aSDavid van Moolenbroek 	return (parent->i_num ^ name_hash) % nr_inodes;
127433d6423SLionel Sambuc }
128433d6423SLionel Sambuc 
129693ad767SDavid van Moolenbroek /*
130693ad767SDavid van Moolenbroek  * Return the hash value of a <parent,index> tuple.
131433d6423SLionel Sambuc  */
132693ad767SDavid van Moolenbroek static int
parent_index_hash(const struct inode * parent,index_t idx)133*7c48de6cSDavid van Moolenbroek parent_index_hash(const struct inode * parent, index_t idx)
134693ad767SDavid van Moolenbroek {
135433d6423SLionel Sambuc 
136*7c48de6cSDavid van Moolenbroek 	return (parent->i_num ^ idx) % nr_inodes;
137433d6423SLionel Sambuc }
138433d6423SLionel Sambuc 
139693ad767SDavid van Moolenbroek /*
140693ad767SDavid van Moolenbroek  * Delete a deletable inode to make room for a new inode.
141433d6423SLionel Sambuc  */
142693ad767SDavid van Moolenbroek static void
purge_inode(struct inode * parent)143693ad767SDavid van Moolenbroek purge_inode(struct inode * parent)
144693ad767SDavid van Moolenbroek {
145693ad767SDavid van Moolenbroek 	/*
146693ad767SDavid van Moolenbroek 	 * An inode is deletable if:
147433d6423SLionel Sambuc 	 * - it is in use;
148433d6423SLionel Sambuc 	 * - it is indexed;
149433d6423SLionel Sambuc 	 * - it is not the given parent inode;
150433d6423SLionel Sambuc 	 * - it has a zero reference count;
151433d6423SLionel Sambuc 	 * - it does not have any children.
152433d6423SLionel Sambuc 	 * The first point is true for all inodes, or we would not be here.
153433d6423SLionel Sambuc 	 * The latter two points also imply that I_DELETED is not set.
154433d6423SLionel Sambuc 	 */
155433d6423SLionel Sambuc 	static int last_checked = 0;
156433d6423SLionel Sambuc 	struct inode *node;
1570dc5c83eSDavid van Moolenbroek 	unsigned int count;
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc 	assert(TAILQ_EMPTY(&unused_inodes));
160433d6423SLionel Sambuc 
161693ad767SDavid van Moolenbroek 	/*
162693ad767SDavid van Moolenbroek 	 * This should not happen often enough to warrant an extra linked list,
163433d6423SLionel Sambuc 	 * especially as maintenance of that list would be rather error-prone..
164433d6423SLionel Sambuc 	 */
165433d6423SLionel Sambuc 	for (count = 0; count < nr_inodes; count++) {
166433d6423SLionel Sambuc 		node = &inode[last_checked];
167433d6423SLionel Sambuc 		last_checked = (last_checked + 1) % nr_inodes;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 		if (node != parent && node->i_index != NO_INDEX &&
170433d6423SLionel Sambuc 		    node->i_count == 0 && TAILQ_EMPTY(&node->i_children)) {
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc 			assert(!(node->i_flags & I_DELETED));
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc 			delete_inode(node);
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc 			break;
177433d6423SLionel Sambuc 		}
178433d6423SLionel Sambuc 	}
179433d6423SLionel Sambuc }
180433d6423SLionel Sambuc 
181693ad767SDavid van Moolenbroek /*
182693ad767SDavid van Moolenbroek  * Add an inode.
183693ad767SDavid van Moolenbroek  */
184693ad767SDavid van Moolenbroek struct inode *
add_inode(struct inode * parent,const char * name,index_t idx,const struct inode_stat * istat,index_t nr_indexed_entries,cbdata_t cbdata)185*7c48de6cSDavid van Moolenbroek add_inode(struct inode * parent, const char * name, index_t idx,
186*7c48de6cSDavid van Moolenbroek 	const struct inode_stat * istat, index_t nr_indexed_entries,
187433d6423SLionel Sambuc 	cbdata_t cbdata)
188433d6423SLionel Sambuc {
189433d6423SLionel Sambuc 	struct inode *newnode;
190c21aa858SCristiano Giuffrida 	char *newname;
191433d6423SLionel Sambuc 	int slot;
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc 	CHECK_INODE(parent);
194433d6423SLionel Sambuc 	assert(S_ISDIR(parent->i_stat.mode));
195433d6423SLionel Sambuc 	assert(!(parent->i_flags & I_DELETED));
196c21aa858SCristiano Giuffrida 	assert(strlen(name) <= NAME_MAX);
197*7c48de6cSDavid van Moolenbroek 	assert(idx >= 0 || idx == NO_INDEX);
198*7c48de6cSDavid van Moolenbroek 	assert(istat != NULL);
199433d6423SLionel Sambuc 	assert(nr_indexed_entries >= 0);
200433d6423SLionel Sambuc 	assert(get_inode_by_name(parent, name) == NULL);
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc 	/* Get a free inode.  Free one up if necessary. */
203433d6423SLionel Sambuc 	if (TAILQ_EMPTY(&unused_inodes))
204433d6423SLionel Sambuc 		purge_inode(parent);
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	assert(!TAILQ_EMPTY(&unused_inodes));
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc 	newnode = TAILQ_FIRST(&unused_inodes);
209c21aa858SCristiano Giuffrida 
210c21aa858SCristiano Giuffrida 	/* Use the static name buffer if the name is short enough. Otherwise,
211c21aa858SCristiano Giuffrida 	 * allocate heap memory for the name.
212c21aa858SCristiano Giuffrida 	 */
213c21aa858SCristiano Giuffrida 	newname = newnode->i_namebuf;
214c21aa858SCristiano Giuffrida 	if (strlen(name) > PNAME_MAX &&
215c21aa858SCristiano Giuffrida 	    (newname = malloc(strlen(name) + 1)) == NULL)
216c21aa858SCristiano Giuffrida 		return NULL;
217c21aa858SCristiano Giuffrida 
218433d6423SLionel Sambuc 	TAILQ_REMOVE(&unused_inodes, newnode, i_unused);
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc 	assert(newnode->i_count == 0);
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 	/* Copy the relevant data to the inode. */
223433d6423SLionel Sambuc 	newnode->i_parent = parent;
224c21aa858SCristiano Giuffrida 	newnode->i_name = newname;
225433d6423SLionel Sambuc 	newnode->i_flags = 0;
226*7c48de6cSDavid van Moolenbroek 	newnode->i_index = idx;
227*7c48de6cSDavid van Moolenbroek 	newnode->i_stat = *istat;
228433d6423SLionel Sambuc 	newnode->i_indexed = nr_indexed_entries;
229433d6423SLionel Sambuc 	newnode->i_cbdata = cbdata;
230c21aa858SCristiano Giuffrida 	strcpy(newnode->i_name, name);
231433d6423SLionel Sambuc 
23252be5c0aSDavid van Moolenbroek 	/* Clear the extra data for this inode, if present. */
23352be5c0aSDavid van Moolenbroek 	clear_inode_extra(newnode);
23452be5c0aSDavid van Moolenbroek 
235433d6423SLionel Sambuc 	/* Add the inode to the list of children inodes of the parent. */
236433d6423SLionel Sambuc 	TAILQ_INSERT_HEAD(&parent->i_children, newnode, i_siblings);
237433d6423SLionel Sambuc 
238433d6423SLionel Sambuc 	/* Add the inode to the <parent,name> hash table. */
239433d6423SLionel Sambuc 	slot = parent_name_hash(parent, name);
240433d6423SLionel Sambuc 	LIST_INSERT_HEAD(&parent_name_head[slot], newnode, i_hname);
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc 	/* Add the inode to the <parent,index> hash table. */
243*7c48de6cSDavid van Moolenbroek 	if (idx != NO_INDEX) {
244*7c48de6cSDavid van Moolenbroek 		slot = parent_index_hash(parent, idx);
245433d6423SLionel Sambuc 		LIST_INSERT_HEAD(&parent_index_head[slot], newnode, i_hindex);
246433d6423SLionel Sambuc 	}
247433d6423SLionel Sambuc 
248433d6423SLionel Sambuc 	return newnode;
249433d6423SLionel Sambuc }
250433d6423SLionel Sambuc 
251693ad767SDavid van Moolenbroek /*
252693ad767SDavid van Moolenbroek  * Return the file system's root inode.
253433d6423SLionel Sambuc  */
254693ad767SDavid van Moolenbroek struct inode *
get_root_inode(void)255693ad767SDavid van Moolenbroek get_root_inode(void)
256693ad767SDavid van Moolenbroek {
257433d6423SLionel Sambuc 
258693ad767SDavid van Moolenbroek 	/* The root node is always the first node in the inode table. */
259433d6423SLionel Sambuc 	return &inode[0];
260433d6423SLionel Sambuc }
261433d6423SLionel Sambuc 
262693ad767SDavid van Moolenbroek /*
263693ad767SDavid van Moolenbroek  * Return the name that an inode has in its parent directory.
264433d6423SLionel Sambuc  */
265693ad767SDavid van Moolenbroek const char *
get_inode_name(const struct inode * node)266693ad767SDavid van Moolenbroek get_inode_name(const struct inode * node)
267693ad767SDavid van Moolenbroek {
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	CHECK_INODE(node);
270c21aa858SCristiano Giuffrida 	assert(!(node->i_flags & I_DELETED));
271c21aa858SCristiano Giuffrida 	assert(node->i_name != NULL);
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc 	return node->i_name;
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc 
276693ad767SDavid van Moolenbroek /*
277693ad767SDavid van Moolenbroek  * Return the index that an inode has in its parent directory.
278433d6423SLionel Sambuc  */
279693ad767SDavid van Moolenbroek index_t
get_inode_index(const struct inode * node)280693ad767SDavid van Moolenbroek get_inode_index(const struct inode * node)
281693ad767SDavid van Moolenbroek {
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc 	CHECK_INODE(node);
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc 	return node->i_index;
286433d6423SLionel Sambuc }
287433d6423SLionel Sambuc 
288693ad767SDavid van Moolenbroek /*
28952be5c0aSDavid van Moolenbroek  * Return the number of indexed slots for the given (directory) inode.
29052be5c0aSDavid van Moolenbroek  */
29152be5c0aSDavid van Moolenbroek index_t
get_inode_slots(const struct inode * node)29252be5c0aSDavid van Moolenbroek get_inode_slots(const struct inode * node)
29352be5c0aSDavid van Moolenbroek {
29452be5c0aSDavid van Moolenbroek 
29552be5c0aSDavid van Moolenbroek 	CHECK_INODE(node);
29652be5c0aSDavid van Moolenbroek 
29752be5c0aSDavid van Moolenbroek 	return node->i_indexed;
29852be5c0aSDavid van Moolenbroek }
29952be5c0aSDavid van Moolenbroek 
30052be5c0aSDavid van Moolenbroek /*
301693ad767SDavid van Moolenbroek  * Return the callback data associated with the given inode.
302433d6423SLionel Sambuc  */
303693ad767SDavid van Moolenbroek cbdata_t
get_inode_cbdata(const struct inode * node)304693ad767SDavid van Moolenbroek get_inode_cbdata(const struct inode * node)
305693ad767SDavid van Moolenbroek {
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc 	CHECK_INODE(node);
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc 	return node->i_cbdata;
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc 
312693ad767SDavid van Moolenbroek /*
313693ad767SDavid van Moolenbroek  * Return an inode's parent inode.
314433d6423SLionel Sambuc  */
315693ad767SDavid van Moolenbroek struct inode *
get_parent_inode(const struct inode * node)316693ad767SDavid van Moolenbroek get_parent_inode(const struct inode * node)
317693ad767SDavid van Moolenbroek {
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc 	CHECK_INODE(node);
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc 	/* The root inode does not have parent. */
322433d6423SLionel Sambuc 	if (node == &inode[0])
323433d6423SLionel Sambuc 		return NULL;
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc 	return node->i_parent;
326433d6423SLionel Sambuc }
327433d6423SLionel Sambuc 
328693ad767SDavid van Moolenbroek /*
329693ad767SDavid van Moolenbroek  * Return a directory's first (non-deleted) child inode.
330433d6423SLionel Sambuc  */
331693ad767SDavid van Moolenbroek struct inode *
get_first_inode(const struct inode * parent)332693ad767SDavid van Moolenbroek get_first_inode(const struct inode * parent)
333693ad767SDavid van Moolenbroek {
334433d6423SLionel Sambuc 	struct inode *node;
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	CHECK_INODE(parent);
337433d6423SLionel Sambuc 	assert(S_ISDIR(parent->i_stat.mode));
338433d6423SLionel Sambuc 
339433d6423SLionel Sambuc 	node = TAILQ_FIRST(&parent->i_children);
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc 	while (node != NULL && (node->i_flags & I_DELETED))
342433d6423SLionel Sambuc 		node = TAILQ_NEXT(node, i_siblings);
343433d6423SLionel Sambuc 
344433d6423SLionel Sambuc 	return node;
345433d6423SLionel Sambuc }
346433d6423SLionel Sambuc 
347693ad767SDavid van Moolenbroek /*
348693ad767SDavid van Moolenbroek  * Return a directory's next (non-deleted) child inode.
349433d6423SLionel Sambuc  */
350693ad767SDavid van Moolenbroek struct inode *
get_next_inode(const struct inode * previous)351693ad767SDavid van Moolenbroek get_next_inode(const struct inode * previous)
352693ad767SDavid van Moolenbroek {
353433d6423SLionel Sambuc 	struct inode *node;
354433d6423SLionel Sambuc 
355433d6423SLionel Sambuc 	CHECK_INODE(previous);
356433d6423SLionel Sambuc 
357433d6423SLionel Sambuc 	node = TAILQ_NEXT(previous, i_siblings);
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	while (node != NULL && (node->i_flags & I_DELETED))
360433d6423SLionel Sambuc 		node = TAILQ_NEXT(node, i_siblings);
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc 	return node;
363433d6423SLionel Sambuc }
364433d6423SLionel Sambuc 
365693ad767SDavid van Moolenbroek /*
366693ad767SDavid van Moolenbroek  * Return the inode number of the given inode.
367433d6423SLionel Sambuc  */
368693ad767SDavid van Moolenbroek int
get_inode_number(const struct inode * node)369693ad767SDavid van Moolenbroek get_inode_number(const struct inode * node)
370693ad767SDavid van Moolenbroek {
371433d6423SLionel Sambuc 
372433d6423SLionel Sambuc 	CHECK_INODE(node);
373433d6423SLionel Sambuc 
37452be5c0aSDavid van Moolenbroek 	return node->i_num + 1;
375433d6423SLionel Sambuc }
376433d6423SLionel Sambuc 
377693ad767SDavid van Moolenbroek /*
378693ad767SDavid van Moolenbroek  * Retrieve an inode's status.
379433d6423SLionel Sambuc  */
380693ad767SDavid van Moolenbroek void
get_inode_stat(const struct inode * node,struct inode_stat * istat)381*7c48de6cSDavid van Moolenbroek get_inode_stat(const struct inode * node, struct inode_stat * istat)
382693ad767SDavid van Moolenbroek {
383433d6423SLionel Sambuc 
384433d6423SLionel Sambuc 	CHECK_INODE(node);
385433d6423SLionel Sambuc 
386*7c48de6cSDavid van Moolenbroek 	*istat = node->i_stat;
387433d6423SLionel Sambuc }
388433d6423SLionel Sambuc 
389693ad767SDavid van Moolenbroek /*
390693ad767SDavid van Moolenbroek  * Set an inode's status.
391433d6423SLionel Sambuc  */
392693ad767SDavid van Moolenbroek void
set_inode_stat(struct inode * node,struct inode_stat * istat)393*7c48de6cSDavid van Moolenbroek set_inode_stat(struct inode * node, struct inode_stat * istat)
394693ad767SDavid van Moolenbroek {
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc 	CHECK_INODE(node);
397433d6423SLionel Sambuc 
398*7c48de6cSDavid van Moolenbroek 	node->i_stat = *istat;
399433d6423SLionel Sambuc }
400433d6423SLionel Sambuc 
401693ad767SDavid van Moolenbroek /*
402693ad767SDavid van Moolenbroek  * Look up an inode using a <parent,name> tuple.
403433d6423SLionel Sambuc  */
404693ad767SDavid van Moolenbroek struct inode *
get_inode_by_name(const struct inode * parent,const char * name)405693ad767SDavid van Moolenbroek get_inode_by_name(const struct inode * parent, const char * name)
406693ad767SDavid van Moolenbroek {
407433d6423SLionel Sambuc 	struct inode *node;
408433d6423SLionel Sambuc 	int slot;
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc 	CHECK_INODE(parent);
411c21aa858SCristiano Giuffrida 	assert(strlen(name) <= NAME_MAX);
412433d6423SLionel Sambuc 	assert(S_ISDIR(parent->i_stat.mode));
413433d6423SLionel Sambuc 
414433d6423SLionel Sambuc 	/* Get the hash value, and search for the inode. */
415433d6423SLionel Sambuc 	slot = parent_name_hash(parent, name);
416433d6423SLionel Sambuc 	LIST_FOREACH(node, &parent_name_head[slot], i_hname) {
417433d6423SLionel Sambuc 		if (parent == node->i_parent && !strcmp(name, node->i_name))
418433d6423SLionel Sambuc 			return node;	/* found */
419433d6423SLionel Sambuc 	}
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc 	return NULL;
422433d6423SLionel Sambuc }
423433d6423SLionel Sambuc 
424693ad767SDavid van Moolenbroek /*
425693ad767SDavid van Moolenbroek  * Look up an inode using a <parent,index> tuple.
426433d6423SLionel Sambuc  */
427693ad767SDavid van Moolenbroek struct inode *
get_inode_by_index(const struct inode * parent,index_t idx)428*7c48de6cSDavid van Moolenbroek get_inode_by_index(const struct inode * parent, index_t idx)
429693ad767SDavid van Moolenbroek {
430433d6423SLionel Sambuc 	struct inode *node;
431433d6423SLionel Sambuc 	int slot;
432433d6423SLionel Sambuc 
433433d6423SLionel Sambuc 	CHECK_INODE(parent);
434433d6423SLionel Sambuc 	assert(S_ISDIR(parent->i_stat.mode));
435*7c48de6cSDavid van Moolenbroek 	assert(idx >= 0);
43664d15bd9SCristiano Giuffrida 
437*7c48de6cSDavid van Moolenbroek 	if (idx >= parent->i_indexed)
43864d15bd9SCristiano Giuffrida 		return NULL;
439433d6423SLionel Sambuc 
440433d6423SLionel Sambuc 	/* Get the hash value, and search for the inode. */
441*7c48de6cSDavid van Moolenbroek 	slot = parent_index_hash(parent, idx);
442433d6423SLionel Sambuc 	LIST_FOREACH(node, &parent_index_head[slot], i_hindex) {
443*7c48de6cSDavid van Moolenbroek 		if (parent == node->i_parent && idx == node->i_index)
444433d6423SLionel Sambuc 			return node;	/* found */
445433d6423SLionel Sambuc 	}
446433d6423SLionel Sambuc 
447433d6423SLionel Sambuc 	return NULL;
448433d6423SLionel Sambuc }
449433d6423SLionel Sambuc 
450693ad767SDavid van Moolenbroek /*
451693ad767SDavid van Moolenbroek  * Retrieve an inode by inode number.
452433d6423SLionel Sambuc  */
453693ad767SDavid van Moolenbroek struct inode *
find_inode(ino_t num)454693ad767SDavid van Moolenbroek find_inode(ino_t num)
455693ad767SDavid van Moolenbroek {
456433d6423SLionel Sambuc 	struct inode *node;
457433d6423SLionel Sambuc 
458433d6423SLionel Sambuc 	node = &inode[num - 1];
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc 	CHECK_INODE(node);
461433d6423SLionel Sambuc 
462433d6423SLionel Sambuc 	return node;
463433d6423SLionel Sambuc }
464433d6423SLionel Sambuc 
465693ad767SDavid van Moolenbroek /*
466693ad767SDavid van Moolenbroek  * Retrieve an inode by inode number, and increase its reference count.
467433d6423SLionel Sambuc  */
468693ad767SDavid van Moolenbroek struct inode *
get_inode(ino_t num)469693ad767SDavid van Moolenbroek get_inode(ino_t num)
470693ad767SDavid van Moolenbroek {
471433d6423SLionel Sambuc 	struct inode *node;
472433d6423SLionel Sambuc 
473433d6423SLionel Sambuc 	if ((node = find_inode(num)) == NULL)
474433d6423SLionel Sambuc 		return NULL;
475433d6423SLionel Sambuc 
476433d6423SLionel Sambuc 	node->i_count++;
477433d6423SLionel Sambuc 	return node;
478433d6423SLionel Sambuc }
479433d6423SLionel Sambuc 
480693ad767SDavid van Moolenbroek /*
481693ad767SDavid van Moolenbroek  * Decrease an inode's reference count.
482433d6423SLionel Sambuc  */
483693ad767SDavid van Moolenbroek void
put_inode(struct inode * node)484693ad767SDavid van Moolenbroek put_inode(struct inode * node)
485693ad767SDavid van Moolenbroek {
486433d6423SLionel Sambuc 
487433d6423SLionel Sambuc 	CHECK_INODE(node);
488433d6423SLionel Sambuc 	assert(node->i_count > 0);
489433d6423SLionel Sambuc 
490433d6423SLionel Sambuc 	node->i_count--;
491433d6423SLionel Sambuc 
492693ad767SDavid van Moolenbroek 	/*
493693ad767SDavid van Moolenbroek 	 * If the inode is scheduled for deletion, and has no more references,
494433d6423SLionel Sambuc 	 * actually delete it now.
495433d6423SLionel Sambuc 	 */
496433d6423SLionel Sambuc 	if ((node->i_flags & I_DELETED) && node->i_count == 0)
497433d6423SLionel Sambuc 		delete_inode(node);
498433d6423SLionel Sambuc }
499433d6423SLionel Sambuc 
500693ad767SDavid van Moolenbroek /*
501693ad767SDavid van Moolenbroek  * Increase an inode's reference count.
502433d6423SLionel Sambuc  */
503693ad767SDavid van Moolenbroek void
ref_inode(struct inode * node)504693ad767SDavid van Moolenbroek ref_inode(struct inode * node)
505693ad767SDavid van Moolenbroek {
506433d6423SLionel Sambuc 
507433d6423SLionel Sambuc 	CHECK_INODE(node);
508433d6423SLionel Sambuc 
509433d6423SLionel Sambuc 	node->i_count++;
510433d6423SLionel Sambuc }
511433d6423SLionel Sambuc 
512693ad767SDavid van Moolenbroek /*
513693ad767SDavid van Moolenbroek  * Unlink the given node from its parent, if it is still linked in.
514433d6423SLionel Sambuc  */
515693ad767SDavid van Moolenbroek static void
unlink_inode(struct inode * node)516693ad767SDavid van Moolenbroek unlink_inode(struct inode * node)
517693ad767SDavid van Moolenbroek {
518433d6423SLionel Sambuc 	struct inode *parent;
519433d6423SLionel Sambuc 
520433d6423SLionel Sambuc 	assert(node->i_flags & I_DELETED);
521433d6423SLionel Sambuc 
522433d6423SLionel Sambuc 	parent = node->i_parent;
523433d6423SLionel Sambuc 	if (parent == NULL)
524433d6423SLionel Sambuc 		return;
525433d6423SLionel Sambuc 
526433d6423SLionel Sambuc 	/* Delete the node from the parent list. */
527433d6423SLionel Sambuc 	node->i_parent = NULL;
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc 	TAILQ_REMOVE(&parent->i_children, node, i_siblings);
530433d6423SLionel Sambuc 
531433d6423SLionel Sambuc 	/* Optionally recheck if the parent can now be deleted. */
532433d6423SLionel Sambuc 	if (parent->i_flags & I_DELETED)
533433d6423SLionel Sambuc 		delete_inode(parent);
534433d6423SLionel Sambuc }
535433d6423SLionel Sambuc 
536693ad767SDavid van Moolenbroek /*
537693ad767SDavid van Moolenbroek  * Delete the given inode.  If its reference count is nonzero, or it still has
538693ad767SDavid van Moolenbroek  * children that cannot be deleted for the same reason, keep the inode around
539693ad767SDavid van Moolenbroek  * for the time being.  If the node is a directory, keep around its parent so
540693ad767SDavid van Moolenbroek  * that we can still do a "cd .." out of it.  For these reasons, this function
541693ad767SDavid van Moolenbroek  * may be called on an inode more than once before it is actually deleted.
542433d6423SLionel Sambuc  */
543693ad767SDavid van Moolenbroek void
delete_inode(struct inode * node)544693ad767SDavid van Moolenbroek delete_inode(struct inode * node)
545693ad767SDavid van Moolenbroek {
546433d6423SLionel Sambuc 	struct inode *cnode, *ctmp;
547433d6423SLionel Sambuc 
548433d6423SLionel Sambuc 	CHECK_INODE(node);
549433d6423SLionel Sambuc 	assert(node != &inode[0]);
550433d6423SLionel Sambuc 
551693ad767SDavid van Moolenbroek 	/*
552693ad767SDavid van Moolenbroek 	 * If the inode was not already scheduled for deletion, partially
553693ad767SDavid van Moolenbroek 	 * remove the node.
554433d6423SLionel Sambuc 	 */
555433d6423SLionel Sambuc 	if (!(node->i_flags & I_DELETED)) {
556433d6423SLionel Sambuc 		/* Remove any children first (before I_DELETED is set!). */
557433d6423SLionel Sambuc 		TAILQ_FOREACH_SAFE(cnode, &node->i_children, i_siblings, ctmp)
558433d6423SLionel Sambuc 			delete_inode(cnode);
559433d6423SLionel Sambuc 
560433d6423SLionel Sambuc 		/* Unhash the inode from the <parent,name> table. */
561433d6423SLionel Sambuc 		LIST_REMOVE(node, i_hname);
562433d6423SLionel Sambuc 
563433d6423SLionel Sambuc 		/* Unhash the inode from the <parent,index> table if needed. */
564433d6423SLionel Sambuc 		if (node->i_index != NO_INDEX)
565433d6423SLionel Sambuc 			LIST_REMOVE(node, i_hindex);
566433d6423SLionel Sambuc 
567c21aa858SCristiano Giuffrida 		/* Free the name if allocated dynamically. */
568c21aa858SCristiano Giuffrida 		assert(node->i_name != NULL);
569c21aa858SCristiano Giuffrida 		if (node->i_name != node->i_namebuf)
570c21aa858SCristiano Giuffrida 			free(node->i_name);
571c21aa858SCristiano Giuffrida 		node->i_name = NULL;
572c21aa858SCristiano Giuffrida 
573433d6423SLionel Sambuc 		node->i_flags |= I_DELETED;
574433d6423SLionel Sambuc 
575693ad767SDavid van Moolenbroek 		/*
576693ad767SDavid van Moolenbroek 		 * If this inode is not a directory, we don't care about being
577433d6423SLionel Sambuc 		 * able to find its parent.  Unlink it from the parent now.
578433d6423SLionel Sambuc 		 */
579433d6423SLionel Sambuc 		if (!S_ISDIR(node->i_stat.mode))
580433d6423SLionel Sambuc 			unlink_inode(node);
581433d6423SLionel Sambuc 	}
582433d6423SLionel Sambuc 
583433d6423SLionel Sambuc 	if (node->i_count == 0 && TAILQ_EMPTY(&node->i_children)) {
584693ad767SDavid van Moolenbroek 		/*
585693ad767SDavid van Moolenbroek 		 * If this inode still has a parent at this point, unlink it
586433d6423SLionel Sambuc 		 * now; noone can possibly refer to it anymore.
587433d6423SLionel Sambuc 		 */
588433d6423SLionel Sambuc 		if (node->i_parent != NULL)
589433d6423SLionel Sambuc 			unlink_inode(node);
590433d6423SLionel Sambuc 
591433d6423SLionel Sambuc 		/* Delete the actual node. */
592433d6423SLionel Sambuc 		TAILQ_INSERT_HEAD(&unused_inodes, node, i_unused);
593433d6423SLionel Sambuc 	}
594433d6423SLionel Sambuc }
595433d6423SLionel Sambuc 
596693ad767SDavid van Moolenbroek /*
597693ad767SDavid van Moolenbroek  * Return whether the given inode has been deleted.
598433d6423SLionel Sambuc  */
599693ad767SDavid van Moolenbroek int
is_inode_deleted(const struct inode * node)600693ad767SDavid van Moolenbroek is_inode_deleted(const struct inode * node)
601693ad767SDavid van Moolenbroek {
602433d6423SLionel Sambuc 
603433d6423SLionel Sambuc 	return (node->i_flags & I_DELETED);
604433d6423SLionel Sambuc }
605433d6423SLionel Sambuc 
606693ad767SDavid van Moolenbroek /*
607693ad767SDavid van Moolenbroek  * Find the inode specified by the request message, and decrease its reference
608693ad767SDavid van Moolenbroek  * count.
609433d6423SLionel Sambuc  */
610693ad767SDavid van Moolenbroek int
fs_putnode(ino_t ino_nr,unsigned int count)611693ad767SDavid van Moolenbroek fs_putnode(ino_t ino_nr, unsigned int count)
612693ad767SDavid van Moolenbroek {
613433d6423SLionel Sambuc 	struct inode *node;
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc 	/* Get the inode specified by its number. */
6160dc5c83eSDavid van Moolenbroek 	if ((node = find_inode(ino_nr)) == NULL)
617433d6423SLionel Sambuc 		return EINVAL;
618433d6423SLionel Sambuc 
619433d6423SLionel Sambuc 	/* Decrease the reference count. */
6200dc5c83eSDavid van Moolenbroek 	assert(node->i_count >= count);
621433d6423SLionel Sambuc 
6220dc5c83eSDavid van Moolenbroek 	node->i_count -= count - 1;
623433d6423SLionel Sambuc 	put_inode(node);
624433d6423SLionel Sambuc 
625433d6423SLionel Sambuc 	return OK;
626433d6423SLionel Sambuc }
627