Remove building with NOCRYPTO option
[minix3.git] / minix / lib / libvtreefs / inode.c
blobec0e61a3e288d49760f2ce2bfac5ae3029e27272
1 /* VTreeFS - inode.c - inode management */
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((unsigned int)(node - &inode[0]) == node->i_num);\
23 assert(node == &inode[0] || node->i_parent != NULL || \
24 (node->i_flags & I_DELETED)); \
25 } while (0);
28 * Initialize the inode-related state.
30 int
31 init_inodes(unsigned int inodes, struct inode_stat * istat,
32 index_t nr_indexed_entries)
34 struct inode *node;
35 unsigned int i;
37 assert(inodes > 0);
38 assert(nr_indexed_entries >= 0);
40 nr_inodes = inodes;
42 /* Allocate the inode and hash tables. */
43 if ((inode = malloc(nr_inodes * sizeof(inode[0]))) == NULL)
44 return ENOMEM;
46 parent_name_head = malloc(nr_inodes * sizeof(parent_name_head[0]));
47 if (parent_name_head == NULL) {
48 free(inode);
49 return ENOMEM;
52 parent_index_head = malloc(nr_inodes * sizeof(parent_index_head[0]));
53 if (parent_index_head == NULL) {
54 free(parent_name_head);
55 free(inode);
56 return ENOMEM;
59 #if DEBUG
60 printf("VTREEFS: allocated %zu+%zu+%zu bytes\n",
61 nr_inodes * sizeof(inode[0]),
62 nr_inodes * sizeof(parent_name_head[0]),
63 nr_inodes * sizeof(parent_index_head[0]));
64 #endif
66 /* Initialize the free/unused list. */
67 TAILQ_INIT(&unused_inodes);
69 /* Add free inodes to the unused/free list. Skip the root inode. */
70 for (i = 1; i < nr_inodes; i++) {
71 node = &inode[i];
72 node->i_num = i;
73 node->i_name = NULL;
74 node->i_parent = NULL;
75 node->i_count = 0;
76 TAILQ_INIT(&node->i_children);
77 TAILQ_INSERT_HEAD(&unused_inodes, node, i_unused);
80 /* Initialize the hash lists. */
81 for (i = 0; i < nr_inodes; i++) {
82 LIST_INIT(&parent_name_head[i]);
83 LIST_INIT(&parent_index_head[i]);
86 /* Initialize the root inode. */
87 node = &inode[0];
88 node->i_num = 0;
89 node->i_parent = NULL;
90 node->i_count = 0;
91 TAILQ_INIT(&node->i_children);
92 node->i_flags = 0;
93 node->i_index = NO_INDEX;
94 set_inode_stat(node, istat);
95 node->i_indexed = nr_indexed_entries;
96 node->i_cbdata = NULL;
98 return OK;
102 * Clean up the inode-related state.
104 void
105 cleanup_inodes(void)
108 /* Free the inode and hash tables. */
109 free(parent_index_head);
110 free(parent_name_head);
111 free(inode);
115 * Return the hash value of <parent,name> tuple.
117 static int
118 parent_name_hash(const struct inode * parent, const char *name)
120 unsigned int name_hash;
122 /* Use the sdbm algorithm to hash the name. */
123 name_hash = sdbm_hash(name, strlen(name));
125 /* The parent hash is a simple array entry. */
126 return (parent->i_num ^ name_hash) % nr_inodes;
130 * Return the hash value of a <parent,index> tuple.
132 static int
133 parent_index_hash(const struct inode * parent, index_t idx)
136 return (parent->i_num ^ idx) % nr_inodes;
140 * Delete a deletable inode to make room for a new inode.
142 static void
143 purge_inode(struct inode * parent)
146 * An inode is deletable if:
147 * - it is in use;
148 * - it is indexed;
149 * - it is not the given parent inode;
150 * - it has a zero reference count;
151 * - it does not have any children.
152 * The first point is true for all inodes, or we would not be here.
153 * The latter two points also imply that I_DELETED is not set.
155 static int last_checked = 0;
156 struct inode *node;
157 unsigned int count;
159 assert(TAILQ_EMPTY(&unused_inodes));
162 * This should not happen often enough to warrant an extra linked list,
163 * especially as maintenance of that list would be rather error-prone..
165 for (count = 0; count < nr_inodes; count++) {
166 node = &inode[last_checked];
167 last_checked = (last_checked + 1) % nr_inodes;
169 if (node != parent && node->i_index != NO_INDEX &&
170 node->i_count == 0 && TAILQ_EMPTY(&node->i_children)) {
172 assert(!(node->i_flags & I_DELETED));
174 delete_inode(node);
176 break;
182 * Add an inode.
184 struct inode *
185 add_inode(struct inode * parent, const char * name, index_t idx,
186 const struct inode_stat * istat, index_t nr_indexed_entries,
187 cbdata_t cbdata)
189 struct inode *newnode;
190 char *newname;
191 int slot;
193 CHECK_INODE(parent);
194 assert(S_ISDIR(parent->i_stat.mode));
195 assert(!(parent->i_flags & I_DELETED));
196 assert(strlen(name) <= NAME_MAX);
197 assert(idx >= 0 || idx == NO_INDEX);
198 assert(istat != NULL);
199 assert(nr_indexed_entries >= 0);
200 assert(get_inode_by_name(parent, name) == NULL);
202 /* Get a free inode. Free one up if necessary. */
203 if (TAILQ_EMPTY(&unused_inodes))
204 purge_inode(parent);
206 assert(!TAILQ_EMPTY(&unused_inodes));
208 newnode = TAILQ_FIRST(&unused_inodes);
210 /* Use the static name buffer if the name is short enough. Otherwise,
211 * allocate heap memory for the name.
213 newname = newnode->i_namebuf;
214 if (strlen(name) > PNAME_MAX &&
215 (newname = malloc(strlen(name) + 1)) == NULL)
216 return NULL;
218 TAILQ_REMOVE(&unused_inodes, newnode, i_unused);
220 assert(newnode->i_count == 0);
222 /* Copy the relevant data to the inode. */
223 newnode->i_parent = parent;
224 newnode->i_name = newname;
225 newnode->i_flags = 0;
226 newnode->i_index = idx;
227 newnode->i_stat = *istat;
228 newnode->i_indexed = nr_indexed_entries;
229 newnode->i_cbdata = cbdata;
230 strcpy(newnode->i_name, name);
232 /* Clear the extra data for this inode, if present. */
233 clear_inode_extra(newnode);
235 /* Add the inode to the list of children inodes of the parent. */
236 TAILQ_INSERT_HEAD(&parent->i_children, newnode, i_siblings);
238 /* Add the inode to the <parent,name> hash table. */
239 slot = parent_name_hash(parent, name);
240 LIST_INSERT_HEAD(&parent_name_head[slot], newnode, i_hname);
242 /* Add the inode to the <parent,index> hash table. */
243 if (idx != NO_INDEX) {
244 slot = parent_index_hash(parent, idx);
245 LIST_INSERT_HEAD(&parent_index_head[slot], newnode, i_hindex);
248 return newnode;
252 * Return the file system's root inode.
254 struct inode *
255 get_root_inode(void)
258 /* The root node is always the first node in the inode table. */
259 return &inode[0];
263 * Return the name that an inode has in its parent directory.
265 const char *
266 get_inode_name(const struct inode * node)
269 CHECK_INODE(node);
270 assert(!(node->i_flags & I_DELETED));
271 assert(node->i_name != NULL);
273 return node->i_name;
277 * Return the index that an inode has in its parent directory.
279 index_t
280 get_inode_index(const struct inode * node)
283 CHECK_INODE(node);
285 return node->i_index;
289 * Return the number of indexed slots for the given (directory) inode.
291 index_t
292 get_inode_slots(const struct inode * node)
295 CHECK_INODE(node);
297 return node->i_indexed;
301 * Return the callback data associated with the given inode.
303 cbdata_t
304 get_inode_cbdata(const struct inode * node)
307 CHECK_INODE(node);
309 return node->i_cbdata;
313 * Return an inode's parent inode.
315 struct inode *
316 get_parent_inode(const struct inode * node)
319 CHECK_INODE(node);
321 /* The root inode does not have parent. */
322 if (node == &inode[0])
323 return NULL;
325 return node->i_parent;
329 * Return a directory's first (non-deleted) child inode.
331 struct inode *
332 get_first_inode(const struct inode * parent)
334 struct inode *node;
336 CHECK_INODE(parent);
337 assert(S_ISDIR(parent->i_stat.mode));
339 node = TAILQ_FIRST(&parent->i_children);
341 while (node != NULL && (node->i_flags & I_DELETED))
342 node = TAILQ_NEXT(node, i_siblings);
344 return node;
348 * Return a directory's next (non-deleted) child inode.
350 struct inode *
351 get_next_inode(const struct inode * previous)
353 struct inode *node;
355 CHECK_INODE(previous);
357 node = TAILQ_NEXT(previous, i_siblings);
359 while (node != NULL && (node->i_flags & I_DELETED))
360 node = TAILQ_NEXT(node, i_siblings);
362 return node;
366 * Return the inode number of the given inode.
369 get_inode_number(const struct inode * node)
372 CHECK_INODE(node);
374 return node->i_num + 1;
378 * Retrieve an inode's status.
380 void
381 get_inode_stat(const struct inode * node, struct inode_stat * istat)
384 CHECK_INODE(node);
386 *istat = node->i_stat;
390 * Set an inode's status.
392 void
393 set_inode_stat(struct inode * node, struct inode_stat * istat)
396 CHECK_INODE(node);
398 node->i_stat = *istat;
402 * Look up an inode using a <parent,name> tuple.
404 struct inode *
405 get_inode_by_name(const struct inode * parent, const char * name)
407 struct inode *node;
408 int slot;
410 CHECK_INODE(parent);
411 assert(strlen(name) <= NAME_MAX);
412 assert(S_ISDIR(parent->i_stat.mode));
414 /* Get the hash value, and search for the inode. */
415 slot = parent_name_hash(parent, name);
416 LIST_FOREACH(node, &parent_name_head[slot], i_hname) {
417 if (parent == node->i_parent && !strcmp(name, node->i_name))
418 return node; /* found */
421 return NULL;
425 * Look up an inode using a <parent,index> tuple.
427 struct inode *
428 get_inode_by_index(const struct inode * parent, index_t idx)
430 struct inode *node;
431 int slot;
433 CHECK_INODE(parent);
434 assert(S_ISDIR(parent->i_stat.mode));
435 assert(idx >= 0);
437 if (idx >= parent->i_indexed)
438 return NULL;
440 /* Get the hash value, and search for the inode. */
441 slot = parent_index_hash(parent, idx);
442 LIST_FOREACH(node, &parent_index_head[slot], i_hindex) {
443 if (parent == node->i_parent && idx == node->i_index)
444 return node; /* found */
447 return NULL;
451 * Retrieve an inode by inode number.
453 struct inode *
454 find_inode(ino_t num)
456 struct inode *node;
458 node = &inode[num - 1];
460 CHECK_INODE(node);
462 return node;
466 * Retrieve an inode by inode number, and increase its reference count.
468 struct inode *
469 get_inode(ino_t num)
471 struct inode *node;
473 if ((node = find_inode(num)) == NULL)
474 return NULL;
476 node->i_count++;
477 return node;
481 * Decrease an inode's reference count.
483 void
484 put_inode(struct inode * node)
487 CHECK_INODE(node);
488 assert(node->i_count > 0);
490 node->i_count--;
493 * If the inode is scheduled for deletion, and has no more references,
494 * actually delete it now.
496 if ((node->i_flags & I_DELETED) && node->i_count == 0)
497 delete_inode(node);
501 * Increase an inode's reference count.
503 void
504 ref_inode(struct inode * node)
507 CHECK_INODE(node);
509 node->i_count++;
513 * Unlink the given node from its parent, if it is still linked in.
515 static void
516 unlink_inode(struct inode * node)
518 struct inode *parent;
520 assert(node->i_flags & I_DELETED);
522 parent = node->i_parent;
523 if (parent == NULL)
524 return;
526 /* Delete the node from the parent list. */
527 node->i_parent = NULL;
529 TAILQ_REMOVE(&parent->i_children, node, i_siblings);
531 /* Optionally recheck if the parent can now be deleted. */
532 if (parent->i_flags & I_DELETED)
533 delete_inode(parent);
537 * Delete the given inode. If its reference count is nonzero, or it still has
538 * children that cannot be deleted for the same reason, keep the inode around
539 * for the time being. If the node is a directory, keep around its parent so
540 * that we can still do a "cd .." out of it. For these reasons, this function
541 * may be called on an inode more than once before it is actually deleted.
543 void
544 delete_inode(struct inode * node)
546 struct inode *cnode, *ctmp;
548 CHECK_INODE(node);
549 assert(node != &inode[0]);
552 * If the inode was not already scheduled for deletion, partially
553 * remove the node.
555 if (!(node->i_flags & I_DELETED)) {
556 /* Remove any children first (before I_DELETED is set!). */
557 TAILQ_FOREACH_SAFE(cnode, &node->i_children, i_siblings, ctmp)
558 delete_inode(cnode);
560 /* Unhash the inode from the <parent,name> table. */
561 LIST_REMOVE(node, i_hname);
563 /* Unhash the inode from the <parent,index> table if needed. */
564 if (node->i_index != NO_INDEX)
565 LIST_REMOVE(node, i_hindex);
567 /* Free the name if allocated dynamically. */
568 assert(node->i_name != NULL);
569 if (node->i_name != node->i_namebuf)
570 free(node->i_name);
571 node->i_name = NULL;
573 node->i_flags |= I_DELETED;
576 * If this inode is not a directory, we don't care about being
577 * able to find its parent. Unlink it from the parent now.
579 if (!S_ISDIR(node->i_stat.mode))
580 unlink_inode(node);
583 if (node->i_count == 0 && TAILQ_EMPTY(&node->i_children)) {
585 * If this inode still has a parent at this point, unlink it
586 * now; noone can possibly refer to it anymore.
588 if (node->i_parent != NULL)
589 unlink_inode(node);
591 /* Delete the actual node. */
592 TAILQ_INSERT_HEAD(&unused_inodes, node, i_unused);
597 * Return whether the given inode has been deleted.
600 is_inode_deleted(const struct inode * node)
603 return (node->i_flags & I_DELETED);
607 * Find the inode specified by the request message, and decrease its reference
608 * count.
611 fs_putnode(ino_t ino_nr, unsigned int count)
613 struct inode *node;
615 /* Get the inode specified by its number. */
616 if ((node = find_inode(ino_nr)) == NULL)
617 return EINVAL;
619 /* Decrease the reference count. */
620 assert(node->i_count >= count);
622 node->i_count -= count - 1;
623 put_inode(node);
625 return OK;