VM: restore >4k secondary cache functionality
[minix.git] / lib / libvtreefs / inode.c
blobbb0410807381474d3e51950b8fc8a75b26b2217a
1 /* VTreeFS - inode.c - by Alen Stojanov and David van Moolenbroek */
3 #include "inc.h"
5 /* The number of inodes and hash table slots. */
6 static unsigned int nr_inodes;
8 /* The table of all the inodes. */
9 static struct inode *inode;
11 /* The list of unused inodes. */
12 static TAILQ_HEAD(unused_head, inode) unused_inodes;
14 /* The hash tables for lookup of <parent,name> and <parent,index> to inode. */
15 static LIST_HEAD(name_head, inode) *parent_name_head;
16 static LIST_HEAD(index_head, inode) *parent_index_head;
18 /* Internal integrity check. */
19 #define CHECK_INODE(node) \
20 do { \
21 assert(node >= &inode[0] && node < &inode[nr_inodes]); \
22 assert(node == &inode[0] || \
23 node->i_parent != NULL || \
24 (node->i_flags & I_DELETED)); \
25 } while (0);
27 /*===========================================================================*
28 * init_inodes *
29 *===========================================================================*/
30 void init_inodes(unsigned int inodes, struct inode_stat *stat,
31 index_t nr_indexed_entries)
33 /* Initialize the inode-related state.
35 struct inode *node;
36 int i;
38 assert(inodes > 0);
39 assert(nr_indexed_entries >= 0);
41 nr_inodes = inodes;
43 /* Allocate the inode and hash tables. */
44 inode = malloc(nr_inodes * sizeof(inode[0]));
45 parent_name_head = malloc(nr_inodes * sizeof(parent_name_head[0]));
46 parent_index_head = malloc(nr_inodes * sizeof(parent_index_head[0]));
48 assert(inode != NULL);
49 assert(parent_name_head != NULL);
50 assert(parent_index_head != NULL);
52 #if DEBUG
53 printf("VTREEFS: allocated %d+%d+%d bytes\n",
54 nr_inodes * sizeof(inode[0]),
55 nr_inodes * sizeof(parent_name_head[0]),
56 nr_inodes * sizeof(parent_index_head[0]));
57 #endif
59 /* Initialize the free/unused list. */
60 TAILQ_INIT(&unused_inodes);
62 /* Add free inodes to the unused/free list. Skip the root inode. */
63 for (i = 1; i < nr_inodes; i++) {
64 node = &inode[i];
66 node->i_parent = NULL;
67 node->i_count = 0;
68 TAILQ_INIT(&node->i_children);
69 TAILQ_INSERT_HEAD(&unused_inodes, node, i_unused);
72 /* Initialize the hash lists. */
73 for (i = 0; i < nr_inodes; i++) {
74 LIST_INIT(&parent_name_head[i]);
75 LIST_INIT(&parent_index_head[i]);
78 /* Initialize the root inode. */
79 node = &inode[0];
80 node->i_parent = NULL;
81 node->i_count = 0;
82 TAILQ_INIT(&node->i_children);
83 node->i_flags = 0;
84 node->i_index = NO_INDEX;
85 set_inode_stat(node, stat);
86 node->i_indexed = nr_indexed_entries;
87 node->i_cbdata = NULL;
90 /*===========================================================================*
91 * cleanup_inodes *
92 *===========================================================================*/
93 void cleanup_inodes(void)
95 /* Clean up the inode-related state.
98 /* Free the inode and hash tables. */
99 free(parent_index_head);
100 free(parent_name_head);
101 free(inode);
104 /*===========================================================================*
105 * parent_name_hash *
106 *===========================================================================*/
107 static int parent_name_hash(struct inode *parent, char *name)
109 /* Return the hash value of <parent,name> tuple.
111 unsigned int name_hash;
112 unsigned long parent_hash;
114 /* The parent hash is a simple array entry; find its index. */
115 parent_hash = parent - &inode[0];
117 /* Use the sdbm algorithm to hash the name. */
118 name_hash = sdbm_hash(name, strlen(name));
120 return (parent_hash ^ name_hash) % nr_inodes;
123 /*===========================================================================*
124 * parent_index_hash *
125 *===========================================================================*/
126 static int parent_index_hash(struct inode *parent, index_t index)
128 /* Return the hash value of a <parent,index> tuple.
131 return ((parent - &inode[0]) ^ index) % nr_inodes;
134 /*===========================================================================*
135 * purge_inode *
136 *===========================================================================*/
137 void purge_inode(struct inode *parent)
139 /* Delete a deletable inode to make room for a new inode.
141 /* An inode is deletable if:
142 * - it is in use;
143 * - it is indexed;
144 * - it is not the given parent inode;
145 * - it has a zero reference count;
146 * - it does not have any children.
147 * The first point is true for all inodes, or we would not be here.
148 * The latter two points also imply that I_DELETED is not set.
150 static int last_checked = 0;
151 struct inode *node;
152 int count;
154 assert(TAILQ_EMPTY(&unused_inodes));
156 /* This should not happen often enough to warrant an extra linked list,
157 * especially as maintenance of that list would be rather error-prone..
159 for (count = 0; count < nr_inodes; count++) {
160 node = &inode[last_checked];
161 last_checked = (last_checked + 1) % nr_inodes;
163 if (node != parent && node->i_index != NO_INDEX &&
164 node->i_count == 0 && TAILQ_EMPTY(&node->i_children)) {
166 assert(!(node->i_flags & I_DELETED));
168 delete_inode(node);
170 break;
175 /*===========================================================================*
176 * add_inode *
177 *===========================================================================*/
178 struct inode *add_inode(struct inode *parent, char *name,
179 index_t index, struct inode_stat *stat, index_t nr_indexed_entries,
180 cbdata_t cbdata)
182 /* Add an inode.
184 struct inode *newnode;
185 int slot;
187 CHECK_INODE(parent);
188 assert(S_ISDIR(parent->i_stat.mode));
189 assert(!(parent->i_flags & I_DELETED));
190 assert(strlen(name) <= PNAME_MAX);
191 assert(index >= 0 || index == NO_INDEX);
192 assert(stat != NULL);
193 assert(nr_indexed_entries >= 0);
194 assert(get_inode_by_name(parent, name) == NULL);
196 /* Get a free inode. Free one up if necessary. */
197 if (TAILQ_EMPTY(&unused_inodes))
198 purge_inode(parent);
200 assert(!TAILQ_EMPTY(&unused_inodes));
202 newnode = TAILQ_FIRST(&unused_inodes);
203 TAILQ_REMOVE(&unused_inodes, newnode, i_unused);
205 assert(newnode->i_count == 0);
207 /* Copy the relevant data to the inode. */
208 newnode->i_parent = parent;
209 newnode->i_flags = 0;
210 newnode->i_index = index;
211 newnode->i_stat = *stat;
212 newnode->i_indexed = nr_indexed_entries;
213 newnode->i_cbdata = cbdata;
214 strlcpy(newnode->i_name, name, sizeof(newnode->i_name));
216 /* Add the inode to the list of children inodes of the parent. */
217 TAILQ_INSERT_HEAD(&parent->i_children, newnode, i_siblings);
219 /* Add the inode to the <parent,name> hash table. */
220 slot = parent_name_hash(parent, name);
221 LIST_INSERT_HEAD(&parent_name_head[slot], newnode, i_hname);
223 /* Add the inode to the <parent,index> hash table. */
224 if (index != NO_INDEX) {
225 slot = parent_index_hash(parent, index);
226 LIST_INSERT_HEAD(&parent_index_head[slot], newnode, i_hindex);
229 return newnode;
232 /*===========================================================================*
233 * get_root_inode *
234 *===========================================================================*/
235 struct inode *get_root_inode(void)
237 /* Return the file system's root inode.
240 /* The root node is always the first node in the inode table */
241 return &inode[0];
244 /*===========================================================================*
245 * get_inode_name *
246 *===========================================================================*/
247 char const *get_inode_name(struct inode *node)
249 /* Return the name that an inode has in its parent directory.
252 CHECK_INODE(node);
254 return node->i_name;
257 /*===========================================================================*
258 * get_inode_index *
259 *===========================================================================*/
260 index_t get_inode_index(struct inode *node)
262 /* Return the index that an inode has in its parent directory.
265 CHECK_INODE(node);
267 return node->i_index;
270 /*===========================================================================*
271 * get_inode_cbdata *
272 *===========================================================================*/
273 cbdata_t get_inode_cbdata(struct inode *node)
275 /* Return the callback data associated with the given inode.
278 CHECK_INODE(node);
280 return node->i_cbdata;
283 /*===========================================================================*
284 * get_parent_inode *
285 *===========================================================================*/
286 struct inode *get_parent_inode(struct inode *node)
288 /* Return an inode's parent inode.
291 CHECK_INODE(node);
293 /* The root inode does not have parent. */
294 if (node == &inode[0])
295 return NULL;
297 return node->i_parent;
300 /*===========================================================================*
301 * get_first_inode *
302 *===========================================================================*/
303 struct inode *get_first_inode(struct inode *parent)
305 /* Return a directory's first (non-deleted) child inode.
307 struct inode *node;
309 CHECK_INODE(parent);
310 assert(S_ISDIR(parent->i_stat.mode));
312 node = TAILQ_FIRST(&parent->i_children);
314 while (node != NULL && (node->i_flags & I_DELETED))
315 node = TAILQ_NEXT(node, i_siblings);
317 return node;
320 /*===========================================================================*
321 * get_next_inode *
322 *===========================================================================*/
323 struct inode *get_next_inode(struct inode *previous)
325 /* Return a directory's next (non-deleted) child inode.
327 struct inode *node;
329 CHECK_INODE(previous);
331 node = TAILQ_NEXT(previous, i_siblings);
333 while (node != NULL && (node->i_flags & I_DELETED))
334 node = TAILQ_NEXT(node, i_siblings);
336 return node;
339 /*===========================================================================*
340 * get_inode_number *
341 *===========================================================================*/
342 int get_inode_number(struct inode *node)
344 /* Return the inode number of the given inode.
347 CHECK_INODE(node);
349 return (int) (node - &inode[0]) + 1;
352 /*===========================================================================*
353 * get_inode_stat *
354 *===========================================================================*/
355 void get_inode_stat(struct inode *node, struct inode_stat *stat)
357 /* Retrieve an inode's status.
360 CHECK_INODE(node);
362 *stat = node->i_stat;
365 /*===========================================================================*
366 * set_inode_stat *
367 *===========================================================================*/
368 void set_inode_stat(struct inode *node, struct inode_stat *stat)
370 /* Set an inode's status.
373 CHECK_INODE(node);
375 node->i_stat = *stat;
378 /*===========================================================================*
379 * get_inode_by_name *
380 *===========================================================================*/
381 struct inode *get_inode_by_name(struct inode *parent, char *name)
383 /* Look up an inode using a <parent,name> tuple.
385 struct inode *node;
386 int slot;
388 CHECK_INODE(parent);
389 assert(strlen(name) <= PNAME_MAX);
390 assert(S_ISDIR(parent->i_stat.mode));
392 /* Get the hash value, and search for the inode. */
393 slot = parent_name_hash(parent, name);
394 LIST_FOREACH(node, &parent_name_head[slot], i_hname) {
395 if (parent == node->i_parent && !strcmp(name, node->i_name))
396 return node; /* found */
399 return NULL;
402 /*===========================================================================*
403 * get_inode_by_index *
404 *===========================================================================*/
405 struct inode *get_inode_by_index(struct inode *parent, index_t index)
407 /* Look up an inode using a <parent,index> tuple.
409 struct inode *node;
410 int slot;
412 CHECK_INODE(parent);
413 assert(S_ISDIR(parent->i_stat.mode));
414 assert(index >= 0 && index < parent->i_indexed);
416 /* Get the hash value, and search for the inode. */
417 slot = parent_index_hash(parent, index);
418 LIST_FOREACH(node, &parent_index_head[slot], i_hindex) {
419 if (parent == node->i_parent && index == node->i_index)
420 return node; /* found */
423 return NULL;
426 /*===========================================================================*
427 * find_inode *
428 *===========================================================================*/
429 struct inode *find_inode(ino_t num)
431 /* Retrieve an inode by inode number.
433 struct inode *node;
435 node = &inode[num - 1];
437 CHECK_INODE(node);
439 return node;
442 /*===========================================================================*
443 * get_inode *
444 *===========================================================================*/
445 struct inode *get_inode(ino_t num)
447 /* Retrieve an inode by inode number, and increase its reference count.
449 struct inode *node;
451 if ((node = find_inode(num)) == NULL)
452 return NULL;
454 node->i_count++;
455 return node;
458 /*===========================================================================*
459 * put_inode *
460 *===========================================================================*/
461 void put_inode(struct inode *node)
463 /* Decrease an inode's reference count.
466 CHECK_INODE(node);
467 assert(node->i_count > 0);
469 node->i_count--;
471 /* If the inode is scheduled for deletion, and has no more references,
472 * actually delete it now.
474 if ((node->i_flags & I_DELETED) && node->i_count == 0)
475 delete_inode(node);
478 /*===========================================================================*
479 * ref_inode *
480 *===========================================================================*/
481 void ref_inode(struct inode *node)
483 /* Increase an inode's reference count.
486 CHECK_INODE(node);
487 assert(node->i_count >= 0);
489 node->i_count++;
492 /*===========================================================================*
493 * unlink_inode *
494 *===========================================================================*/
495 static void unlink_inode(struct inode *node)
497 /* Unlink the given node from its parent, if it is still linked in.
499 struct inode *parent;
501 assert(node->i_flags & I_DELETED);
503 parent = node->i_parent;
504 if (parent == NULL)
505 return;
507 /* Delete the node from the parent list. */
508 node->i_parent = NULL;
510 TAILQ_REMOVE(&parent->i_children, node, i_siblings);
512 /* Optionally recheck if the parent can now be deleted. */
513 if (parent->i_flags & I_DELETED)
514 delete_inode(parent);
517 /*===========================================================================*
518 * delete_inode *
519 *===========================================================================*/
520 void delete_inode(struct inode *node)
522 /* Delete the given inode. If its reference count is nonzero, or it
523 * still has children that cannot be deleted for the same reason, keep
524 * the inode around for the time being. If the node is a directory,
525 * keep around its parent so that we can still do a "cd .." out of it.
526 * For these reasons, this function may be called on an inode more than
527 * once before it is actually deleted.
529 struct inode *cnode, *ctmp;
531 CHECK_INODE(node);
532 assert(node != &inode[0]);
534 /* If the inode was not already scheduled for deletion,
535 * partially remove the node.
537 if (!(node->i_flags & I_DELETED)) {
538 /* Remove any children first (before I_DELETED is set!). */
539 TAILQ_FOREACH_SAFE(cnode, &node->i_children, i_siblings, ctmp)
540 delete_inode(cnode);
542 /* Unhash the inode from the <parent,name> table. */
543 LIST_REMOVE(node, i_hname);
545 /* Unhash the inode from the <parent,index> table if needed. */
546 if (node->i_index != NO_INDEX)
547 LIST_REMOVE(node, i_hindex);
549 node->i_flags |= I_DELETED;
551 /* If this inode is not a directory, we don't care about being
552 * able to find its parent. Unlink it from the parent now.
554 if (!S_ISDIR(node->i_stat.mode))
555 unlink_inode(node);
558 if (node->i_count == 0 && TAILQ_EMPTY(&node->i_children)) {
559 /* If this inode still has a parent at this point, unlink it
560 * now; noone can possibly refer to it anymore.
562 if (node->i_parent != NULL)
563 unlink_inode(node);
565 /* Delete the actual node. */
566 TAILQ_INSERT_HEAD(&unused_inodes, node, i_unused);
570 /*===========================================================================*
571 * is_inode_deleted *
572 *===========================================================================*/
573 int is_inode_deleted(struct inode *node)
575 /* Return whether the given inode has been deleted.
578 return (node->i_flags & I_DELETED);
581 /*===========================================================================*
582 * fs_putnode *
583 *===========================================================================*/
584 int fs_putnode(void)
586 /* Find the inode specified by the request message, and decrease its
587 * reference count.
589 struct inode *node;
591 /* Get the inode specified by its number. */
592 if ((node = find_inode(fs_m_in.REQ_INODE_NR)) == NULL)
593 return EINVAL;
595 /* Decrease the reference count. */
596 node->i_count -= fs_m_in.REQ_COUNT - 1;
598 assert(node->i_count > 0);
600 put_inode(node);
602 return OK;