1 /* VTreeFS - inode.c - inode management */
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) \
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)); \
28 * Initialize the inode-related state.
31 init_inodes(unsigned int inodes
, struct inode_stat
* istat
,
32 index_t nr_indexed_entries
)
38 assert(nr_indexed_entries
>= 0);
42 /* Allocate the inode and hash tables. */
43 if ((inode
= malloc(nr_inodes
* sizeof(inode
[0]))) == NULL
)
46 parent_name_head
= malloc(nr_inodes
* sizeof(parent_name_head
[0]));
47 if (parent_name_head
== NULL
) {
52 parent_index_head
= malloc(nr_inodes
* sizeof(parent_index_head
[0]));
53 if (parent_index_head
== NULL
) {
54 free(parent_name_head
);
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]));
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
++) {
74 node
->i_parent
= NULL
;
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. */
89 node
->i_parent
= NULL
;
91 TAILQ_INIT(&node
->i_children
);
93 node
->i_index
= NO_INDEX
;
94 set_inode_stat(node
, istat
);
95 node
->i_indexed
= nr_indexed_entries
;
96 node
->i_cbdata
= NULL
;
102 * Clean up the inode-related state.
108 /* Free the inode and hash tables. */
109 free(parent_index_head
);
110 free(parent_name_head
);
115 * Return the hash value of <parent,name> tuple.
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.
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.
143 purge_inode(struct inode
* parent
)
146 * An inode is deletable if:
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;
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
));
185 add_inode(struct inode
* parent
, const char * name
, index_t idx
,
186 const struct inode_stat
* istat
, index_t nr_indexed_entries
,
189 struct inode
*newnode
;
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
))
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
)
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
);
252 * Return the file system's root inode.
258 /* The root node is always the first node in the inode table. */
263 * Return the name that an inode has in its parent directory.
266 get_inode_name(const struct inode
* node
)
270 assert(!(node
->i_flags
& I_DELETED
));
271 assert(node
->i_name
!= NULL
);
277 * Return the index that an inode has in its parent directory.
280 get_inode_index(const struct inode
* node
)
285 return node
->i_index
;
289 * Return the number of indexed slots for the given (directory) inode.
292 get_inode_slots(const struct inode
* node
)
297 return node
->i_indexed
;
301 * Return the callback data associated with the given inode.
304 get_inode_cbdata(const struct inode
* node
)
309 return node
->i_cbdata
;
313 * Return an inode's parent inode.
316 get_parent_inode(const struct inode
* node
)
321 /* The root inode does not have parent. */
322 if (node
== &inode
[0])
325 return node
->i_parent
;
329 * Return a directory's first (non-deleted) child inode.
332 get_first_inode(const struct 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
);
348 * Return a directory's next (non-deleted) child inode.
351 get_next_inode(const struct inode
* previous
)
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
);
366 * Return the inode number of the given inode.
369 get_inode_number(const struct inode
* node
)
374 return node
->i_num
+ 1;
378 * Retrieve an inode's status.
381 get_inode_stat(const struct inode
* node
, struct inode_stat
* istat
)
386 *istat
= node
->i_stat
;
390 * Set an inode's status.
393 set_inode_stat(struct inode
* node
, struct inode_stat
* istat
)
398 node
->i_stat
= *istat
;
402 * Look up an inode using a <parent,name> tuple.
405 get_inode_by_name(const struct inode
* parent
, const char * name
)
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 */
425 * Look up an inode using a <parent,index> tuple.
428 get_inode_by_index(const struct inode
* parent
, index_t idx
)
434 assert(S_ISDIR(parent
->i_stat
.mode
));
437 if (idx
>= parent
->i_indexed
)
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 */
451 * Retrieve an inode by inode number.
454 find_inode(ino_t num
)
458 node
= &inode
[num
- 1];
466 * Retrieve an inode by inode number, and increase its reference count.
473 if ((node
= find_inode(num
)) == NULL
)
481 * Decrease an inode's reference count.
484 put_inode(struct inode
* node
)
488 assert(node
->i_count
> 0);
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)
501 * Increase an inode's reference count.
504 ref_inode(struct inode
* node
)
513 * Unlink the given node from its parent, if it is still linked in.
516 unlink_inode(struct inode
* node
)
518 struct inode
*parent
;
520 assert(node
->i_flags
& I_DELETED
);
522 parent
= node
->i_parent
;
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.
544 delete_inode(struct inode
* node
)
546 struct inode
*cnode
, *ctmp
;
549 assert(node
!= &inode
[0]);
552 * If the inode was not already scheduled for deletion, partially
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
)
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
)
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
))
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
)
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
611 fs_putnode(ino_t ino_nr
, unsigned int count
)
615 /* Get the inode specified by its number. */
616 if ((node
= find_inode(ino_nr
)) == NULL
)
619 /* Decrease the reference count. */
620 assert(node
->i_count
>= count
);
622 node
->i_count
-= count
- 1;