VM: restore >4k secondary cache functionality
[minix.git] / lib / libsffs / inode.c
blob7b2e969b4742c23034ee2ea5d7270f6f368ea45e
1 /* This file deals with inode management.
3 * The entry points into this file are:
4 * init_inode initialize the inode table, return the root inode
5 * find_inode find an inode based on its inode number
6 * get_inode increase the reference count of an inode
7 * put_inode decrease the reference count of an inode
8 * link_inode link an inode as a directory entry to another inode
9 * unlink_inode unlink an inode from its parent directory
10 * get_free_inode return a free inode object
11 * have_free_inode check whether there is a free inode available
12 * have_used_inode check whether any inode is still in use
13 * do_putnode perform the PUTNODE file system call
15 * Created:
16 * April 2009 (D.C. van Moolenbroek)
19 #include "inc.h"
21 static struct inode inodes[NUM_INODES];
23 static TAILQ_HEAD(free_head, inode) free_list;
25 /*===========================================================================*
26 * init_inode *
27 *===========================================================================*/
28 struct inode *init_inode()
30 /* Initialize inode table. Return the root inode.
32 struct inode *ino;
33 unsigned int index;
35 TAILQ_INIT(&free_list);
37 dprintf(("%s: %d inodes, %u bytes each, equals %u bytes\n",
38 sffs_name, NUM_INODES, sizeof(struct inode), sizeof(inodes)));
40 /* Mark all inodes except the root inode as free. */
41 for (index = 1; index < NUM_INODES; index++) {
42 ino = &inodes[index];
43 ino->i_parent = NULL;
44 LIST_INIT(&ino->i_child);
45 ino->i_num = index + 1;
46 ino->i_gen = (unsigned short)-1; /* aesthetics */
47 ino->i_ref = 0;
48 ino->i_flags = 0;
49 TAILQ_INSERT_TAIL(&free_list, ino, i_free);
52 /* Initialize and return the root inode. */
53 ino = &inodes[0];
54 ino->i_parent = ino; /* root inode is its own parent */
55 LIST_INIT(&ino->i_child);
56 ino->i_num = ROOT_INODE_NR;
57 ino->i_gen = 0; /* unused by root node */
58 ino->i_ref = 1; /* root inode is hereby in use */
59 ino->i_flags = I_DIR; /* root inode is a directory */
60 ino->i_name[0] = 0; /* root inode has empty name */
62 return ino;
65 /*===========================================================================*
66 * find_inode *
67 *===========================================================================*/
68 struct inode *find_inode(ino_nr)
69 ino_t ino_nr;
71 /* Get an inode based on its inode number. Do not increase its reference count.
73 struct inode *ino;
74 int index;
76 /* Inode 0 (= index -1) is not a valid inode number. */
77 index = INODE_INDEX(ino_nr);
78 if (index < 0) {
79 printf("%s: VFS passed invalid inode number!\n", sffs_name);
81 return NULL;
84 assert(index < NUM_INODES);
86 ino = &inodes[index];
88 /* Make sure the generation number matches. */
89 if (INODE_GEN(ino_nr) != ino->i_gen) {
90 printf("%s: VFS passed outdated inode number!\n", sffs_name);
92 return NULL;
95 /* The VFS/FS protocol only uses referenced inodes. */
96 if (ino->i_ref == 0)
97 printf("%s: VFS passed unused inode!\n", sffs_name);
99 return ino;
102 /*===========================================================================*
103 * get_inode *
104 *===========================================================================*/
105 void get_inode(ino)
106 struct inode *ino;
108 /* Increase the given inode's reference count. If both reference and link
109 * count were zero before, remove the inode from the free list.
112 dprintf(("%s: get_inode(%p) ['%s']\n", sffs_name, ino, ino->i_name));
114 /* (INUSE, CACHED) -> INUSE */
116 /* If this is the first reference, remove the node from the free list. */
117 if (ino->i_ref == 0 && !HAS_CHILDREN(ino))
118 TAILQ_REMOVE(&free_list, ino, i_free);
120 ino->i_ref++;
122 if (ino->i_ref == 0)
123 panic("inode reference count wrapped");
126 /*===========================================================================*
127 * put_inode *
128 *===========================================================================*/
129 void put_inode(ino)
130 struct inode *ino;
132 /* Decrease an inode's reference count. If this count has reached zero, close
133 * the inode's file handle, if any. If both reference and link count have
134 * reached zero, mark the inode as cached or free.
137 dprintf(("%s: put_inode(%p) ['%s']\n", sffs_name, ino, ino->i_name));
139 assert(ino != NULL);
140 assert(ino->i_ref > 0);
142 ino->i_ref--;
144 /* If there are still references to this inode, we're done here. */
145 if (ino->i_ref > 0)
146 return;
148 /* Close any file handle associated with this inode. */
149 put_handle(ino);
151 /* Only add the inode to the free list if there are also no links to it. */
152 if (HAS_CHILDREN(ino))
153 return;
155 /* INUSE -> CACHED, DELETED -> FREE */
157 /* Add the inode to the head or tail of the free list, depending on whether
158 * it is also deleted (and therefore can never be reused as is).
160 if (ino->i_parent == NULL)
161 TAILQ_INSERT_HEAD(&free_list, ino, i_free);
162 else
163 TAILQ_INSERT_TAIL(&free_list, ino, i_free);
166 /*===========================================================================*
167 * link_inode *
168 *===========================================================================*/
169 void link_inode(parent, ino)
170 struct inode *parent;
171 struct inode *ino;
173 /* Link an inode to a parent. If both reference and link count were zero
174 * before, remove the inode from the free list. This function should only be
175 * called from add_dentry().
178 /* This can never happen, right? */
179 if (parent->i_ref == 0 && !HAS_CHILDREN(parent))
180 TAILQ_REMOVE(&free_list, parent, i_free);
182 LIST_INSERT_HEAD(&parent->i_child, ino, i_next);
184 ino->i_parent = parent;
187 /*===========================================================================*
188 * unlink_inode *
189 *===========================================================================*/
190 void unlink_inode(ino)
191 struct inode *ino;
193 /* Unlink an inode from its parent. If both reference and link count have
194 * reached zero, mark the inode as cached or free. This function should only
195 * be used from del_dentry().
197 struct inode *parent;
199 parent = ino->i_parent;
201 LIST_REMOVE(ino, i_next);
203 if (parent->i_ref == 0 && !HAS_CHILDREN(parent)) {
204 if (parent->i_parent == NULL)
205 TAILQ_INSERT_HEAD(&free_list, parent, i_free);
206 else
207 TAILQ_INSERT_TAIL(&free_list, parent, i_free);
210 ino->i_parent = NULL;
213 /*===========================================================================*
214 * get_free_inode *
215 *===========================================================================*/
216 struct inode *get_free_inode()
218 /* Return a free inode object (with reference count 1), if available.
220 struct inode *ino;
222 /* [CACHED -> FREE,] FREE -> DELETED */
224 /* If there are no inodes on the free list, we cannot satisfy the request. */
225 if (TAILQ_EMPTY(&free_list)) {
226 printf("%s: out of inodes!\n", sffs_name);
228 return NULL;
231 ino = TAILQ_FIRST(&free_list);
232 TAILQ_REMOVE(&free_list, ino, i_free);
234 assert(ino->i_ref == 0);
235 assert(!HAS_CHILDREN(ino));
237 /* If this was a cached inode, free it first. */
238 if (ino->i_parent != NULL)
239 del_dentry(ino);
241 assert(ino->i_parent == NULL);
243 /* Initialize a subset of its fields */
244 ino->i_gen++;
245 ino->i_ref = 1;
247 return ino;
250 /*===========================================================================*
251 * have_free_inode *
252 *===========================================================================*/
253 int have_free_inode()
255 /* Check whether there are any free inodes at the moment. Kind of lame, but
256 * this allows for easier error recovery in some places.
259 return !TAILQ_EMPTY(&free_list);
262 /*===========================================================================*
263 * have_used_inode *
264 *===========================================================================*/
265 int have_used_inode()
267 /* Check whether any inodes are still in use, that is, any of the inodes have
268 * a reference count larger than zero.
270 unsigned int index;
272 for (index = 0; index < NUM_INODES; index++)
273 if (inodes[index].i_ref > 0)
274 return TRUE;
276 return FALSE;
279 /*===========================================================================*
280 * do_putnode *
281 *===========================================================================*/
282 int do_putnode()
284 /* Decrease an inode's reference count.
286 struct inode *ino;
287 int count;
289 if ((ino = find_inode(m_in.REQ_INODE_NR)) == NULL)
290 return EINVAL;
292 count = m_in.REQ_COUNT;
294 if (count <= 0 || count > ino->i_ref) return EINVAL;
296 ino->i_ref -= count - 1;
298 put_inode(ino);
300 return OK;