xref: /minix3/minix/lib/libsffs/inode.c (revision 7c48de6cc4c6d56f2277d378dba01dbac8a8c3b9)
1433d6423SLionel Sambuc /* This file deals with inode management.
2433d6423SLionel Sambuc  *
3433d6423SLionel Sambuc  * The entry points into this file are:
4433d6423SLionel Sambuc  *   init_inode		initialize the inode table, return the root inode
5433d6423SLionel Sambuc  *   find_inode		find an inode based on its inode number
6433d6423SLionel Sambuc  *   get_inode		increase the reference count of an inode
7433d6423SLionel Sambuc  *   put_inode		decrease the reference count of an inode
8433d6423SLionel Sambuc  *   link_inode		link an inode as a directory entry to another inode
9433d6423SLionel Sambuc  *   unlink_inode	unlink an inode from its parent directory
10433d6423SLionel Sambuc  *   get_free_inode	return a free inode object
11433d6423SLionel Sambuc  *   have_free_inode	check whether there is a free inode available
12433d6423SLionel Sambuc  *   have_used_inode	check whether any inode is still in use
13433d6423SLionel Sambuc  *   do_putnode		perform the PUTNODE file system call
14433d6423SLionel Sambuc  *
15433d6423SLionel Sambuc  * Created:
16433d6423SLionel Sambuc  *   April 2009 (D.C. van Moolenbroek)
17433d6423SLionel Sambuc  */
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include "inc.h"
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc static struct inode inodes[NUM_INODES];
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc static TAILQ_HEAD(free_head, inode) free_list;
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc /*===========================================================================*
26433d6423SLionel Sambuc  *				init_inode				     *
27433d6423SLionel Sambuc  *===========================================================================*/
init_inode(void)28433d6423SLionel Sambuc struct inode *init_inode(void)
29433d6423SLionel Sambuc {
30433d6423SLionel Sambuc /* Initialize inode table. Return the root inode.
31433d6423SLionel Sambuc  */
32433d6423SLionel Sambuc   struct inode *ino;
33*7c48de6cSDavid van Moolenbroek   unsigned int i;
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc   TAILQ_INIT(&free_list);
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc   dprintf(("%s: %d inodes, %u bytes each, equals %u bytes\n",
38433d6423SLionel Sambuc 	sffs_name, NUM_INODES, sizeof(struct inode), sizeof(inodes)));
39433d6423SLionel Sambuc 
40433d6423SLionel Sambuc   /* Mark all inodes except the root inode as free. */
41*7c48de6cSDavid van Moolenbroek   for (i = 1; i < NUM_INODES; i++) {
42*7c48de6cSDavid van Moolenbroek 	ino = &inodes[i];
43433d6423SLionel Sambuc 	ino->i_parent = NULL;
44433d6423SLionel Sambuc 	LIST_INIT(&ino->i_child);
45*7c48de6cSDavid van Moolenbroek 	ino->i_num = i + 1;
46433d6423SLionel Sambuc 	ino->i_gen = (unsigned short)-1; /* aesthetics */
47433d6423SLionel Sambuc 	ino->i_ref = 0;
48433d6423SLionel Sambuc 	ino->i_flags = 0;
49433d6423SLionel Sambuc 	TAILQ_INSERT_TAIL(&free_list, ino, i_free);
50433d6423SLionel Sambuc   }
51433d6423SLionel Sambuc 
52433d6423SLionel Sambuc   /* Initialize and return the root inode. */
53433d6423SLionel Sambuc   ino = &inodes[0];
54433d6423SLionel Sambuc   ino->i_parent = ino;		/* root inode is its own parent */
55433d6423SLionel Sambuc   LIST_INIT(&ino->i_child);
56433d6423SLionel Sambuc   ino->i_num = ROOT_INODE_NR;
57433d6423SLionel Sambuc   ino->i_gen = 0;		/* unused by root node */
58433d6423SLionel Sambuc   ino->i_ref = 1;		/* root inode is hereby in use */
59433d6423SLionel Sambuc   ino->i_flags = I_DIR;		/* root inode is a directory */
60433d6423SLionel Sambuc   ino->i_name[0] = 0;		/* root inode has empty name */
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc   return ino;
63433d6423SLionel Sambuc }
64433d6423SLionel Sambuc 
65433d6423SLionel Sambuc /*===========================================================================*
66433d6423SLionel Sambuc  *				find_inode				     *
67433d6423SLionel Sambuc  *===========================================================================*/
find_inode(ino_t ino_nr)68433d6423SLionel Sambuc struct inode *find_inode(ino_t ino_nr)
69433d6423SLionel Sambuc {
70433d6423SLionel Sambuc /* Get an inode based on its inode number. Do not increase its reference count.
71433d6423SLionel Sambuc  */
72433d6423SLionel Sambuc   struct inode *ino;
73*7c48de6cSDavid van Moolenbroek   int i;
74433d6423SLionel Sambuc 
75433d6423SLionel Sambuc   /* Inode 0 (= index -1) is not a valid inode number. */
76*7c48de6cSDavid van Moolenbroek   i = INODE_INDEX(ino_nr);
77*7c48de6cSDavid van Moolenbroek   if (i < 0) {
78433d6423SLionel Sambuc 	printf("%s: VFS passed invalid inode number!\n", sffs_name);
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	return NULL;
81433d6423SLionel Sambuc   }
82433d6423SLionel Sambuc 
83*7c48de6cSDavid van Moolenbroek   assert(i < NUM_INODES);
84433d6423SLionel Sambuc 
85*7c48de6cSDavid van Moolenbroek   ino = &inodes[i];
86433d6423SLionel Sambuc 
87433d6423SLionel Sambuc   /* Make sure the generation number matches. */
88433d6423SLionel Sambuc   if (INODE_GEN(ino_nr) != ino->i_gen) {
89433d6423SLionel Sambuc 	printf("%s: VFS passed outdated inode number!\n", sffs_name);
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc 	return NULL;
92433d6423SLionel Sambuc   }
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc   /* The VFS/FS protocol only uses referenced inodes. */
95433d6423SLionel Sambuc   if (ino->i_ref == 0)
96433d6423SLionel Sambuc 	printf("%s: VFS passed unused inode!\n", sffs_name);
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc   return ino;
99433d6423SLionel Sambuc }
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc /*===========================================================================*
102433d6423SLionel Sambuc  *				get_inode				     *
103433d6423SLionel Sambuc  *===========================================================================*/
get_inode(struct inode * ino)104433d6423SLionel Sambuc void get_inode(struct inode *ino)
105433d6423SLionel Sambuc {
106433d6423SLionel Sambuc /* Increase the given inode's reference count. If both reference and link
107433d6423SLionel Sambuc  * count were zero before, remove the inode from the free list.
108433d6423SLionel Sambuc  */
109433d6423SLionel Sambuc 
110433d6423SLionel Sambuc   dprintf(("%s: get_inode(%p) ['%s']\n", sffs_name, ino, ino->i_name));
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc   /* (INUSE, CACHED) -> INUSE */
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc   /* If this is the first reference, remove the node from the free list. */
115433d6423SLionel Sambuc   if (ino->i_ref == 0 && !HAS_CHILDREN(ino))
116433d6423SLionel Sambuc 	TAILQ_REMOVE(&free_list, ino, i_free);
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc   ino->i_ref++;
119433d6423SLionel Sambuc 
120433d6423SLionel Sambuc   if (ino->i_ref == 0)
121433d6423SLionel Sambuc 	panic("inode reference count wrapped");
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc /*===========================================================================*
125433d6423SLionel Sambuc  *				put_inode				     *
126433d6423SLionel Sambuc  *===========================================================================*/
put_inode(struct inode * ino)127433d6423SLionel Sambuc void put_inode(struct inode *ino)
128433d6423SLionel Sambuc {
129433d6423SLionel Sambuc /* Decrease an inode's reference count. If this count has reached zero, close
130433d6423SLionel Sambuc  * the inode's file handle, if any. If both reference and link count have
131433d6423SLionel Sambuc  * reached zero, mark the inode as cached or free.
132433d6423SLionel Sambuc  */
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc   dprintf(("%s: put_inode(%p) ['%s']\n", sffs_name, ino, ino->i_name));
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc   assert(ino != NULL);
137433d6423SLionel Sambuc   assert(ino->i_ref > 0);
138433d6423SLionel Sambuc 
139433d6423SLionel Sambuc   ino->i_ref--;
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc   /* If there are still references to this inode, we're done here. */
142433d6423SLionel Sambuc   if (ino->i_ref > 0)
143433d6423SLionel Sambuc 	return;
144433d6423SLionel Sambuc 
145433d6423SLionel Sambuc   /* Close any file handle associated with this inode. */
146433d6423SLionel Sambuc   put_handle(ino);
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc   /* Only add the inode to the free list if there are also no links to it. */
149433d6423SLionel Sambuc   if (HAS_CHILDREN(ino))
150433d6423SLionel Sambuc 	return;
151433d6423SLionel Sambuc 
152433d6423SLionel Sambuc   /* INUSE -> CACHED, DELETED -> FREE */
153433d6423SLionel Sambuc 
154433d6423SLionel Sambuc   /* Add the inode to the head or tail of the free list, depending on whether
155433d6423SLionel Sambuc    * it is also deleted (and therefore can never be reused as is).
156433d6423SLionel Sambuc    */
157433d6423SLionel Sambuc   if (ino->i_parent == NULL)
158433d6423SLionel Sambuc 	TAILQ_INSERT_HEAD(&free_list, ino, i_free);
159433d6423SLionel Sambuc   else
160433d6423SLionel Sambuc 	TAILQ_INSERT_TAIL(&free_list, ino, i_free);
161433d6423SLionel Sambuc }
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc /*===========================================================================*
164433d6423SLionel Sambuc  *				link_inode				     *
165433d6423SLionel Sambuc  *===========================================================================*/
link_inode(struct inode * parent,struct inode * ino)166433d6423SLionel Sambuc void link_inode(struct inode *parent, struct inode *ino)
167433d6423SLionel Sambuc {
168433d6423SLionel Sambuc /* Link an inode to a parent. If both reference and link count were zero
169433d6423SLionel Sambuc  * before, remove the inode from the free list. This function should only be
170433d6423SLionel Sambuc  * called from add_dentry().
171433d6423SLionel Sambuc  */
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc   /* This can never happen, right? */
174433d6423SLionel Sambuc   if (parent->i_ref == 0 && !HAS_CHILDREN(parent))
175433d6423SLionel Sambuc 	TAILQ_REMOVE(&free_list, parent, i_free);
176433d6423SLionel Sambuc 
177433d6423SLionel Sambuc   LIST_INSERT_HEAD(&parent->i_child, ino, i_next);
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc   ino->i_parent = parent;
180433d6423SLionel Sambuc }
181433d6423SLionel Sambuc 
182433d6423SLionel Sambuc /*===========================================================================*
183433d6423SLionel Sambuc  *				unlink_inode				     *
184433d6423SLionel Sambuc  *===========================================================================*/
unlink_inode(struct inode * ino)185433d6423SLionel Sambuc void unlink_inode(struct inode *ino)
186433d6423SLionel Sambuc {
187433d6423SLionel Sambuc /* Unlink an inode from its parent. If both reference and link count have
188433d6423SLionel Sambuc  * reached zero, mark the inode as cached or free. This function should only
189433d6423SLionel Sambuc  * be used from del_dentry().
190433d6423SLionel Sambuc  */
191433d6423SLionel Sambuc   struct inode *parent;
192433d6423SLionel Sambuc 
193433d6423SLionel Sambuc   parent = ino->i_parent;
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc   LIST_REMOVE(ino, i_next);
196433d6423SLionel Sambuc 
197433d6423SLionel Sambuc   if (parent->i_ref == 0 && !HAS_CHILDREN(parent)) {
198433d6423SLionel Sambuc 	if (parent->i_parent == NULL)
199433d6423SLionel Sambuc 		TAILQ_INSERT_HEAD(&free_list, parent, i_free);
200433d6423SLionel Sambuc 	else
201433d6423SLionel Sambuc 		TAILQ_INSERT_TAIL(&free_list, parent, i_free);
202433d6423SLionel Sambuc   }
203433d6423SLionel Sambuc 
204433d6423SLionel Sambuc   ino->i_parent = NULL;
205433d6423SLionel Sambuc }
206433d6423SLionel Sambuc 
207433d6423SLionel Sambuc /*===========================================================================*
208433d6423SLionel Sambuc  *				get_free_inode				     *
209433d6423SLionel Sambuc  *===========================================================================*/
get_free_inode(void)210433d6423SLionel Sambuc struct inode *get_free_inode(void)
211433d6423SLionel Sambuc {
212433d6423SLionel Sambuc /* Return a free inode object (with reference count 1), if available.
213433d6423SLionel Sambuc  */
214433d6423SLionel Sambuc   struct inode *ino;
215433d6423SLionel Sambuc 
216433d6423SLionel Sambuc   /* [CACHED -> FREE,] FREE -> DELETED */
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc   /* If there are no inodes on the free list, we cannot satisfy the request. */
219433d6423SLionel Sambuc   if (TAILQ_EMPTY(&free_list)) {
220433d6423SLionel Sambuc 	printf("%s: out of inodes!\n", sffs_name);
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 	return NULL;
223433d6423SLionel Sambuc   }
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc   ino = TAILQ_FIRST(&free_list);
226433d6423SLionel Sambuc   TAILQ_REMOVE(&free_list, ino, i_free);
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc   assert(ino->i_ref == 0);
229433d6423SLionel Sambuc   assert(!HAS_CHILDREN(ino));
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc   /* If this was a cached inode, free it first. */
232433d6423SLionel Sambuc   if (ino->i_parent != NULL)
233433d6423SLionel Sambuc 	del_dentry(ino);
234433d6423SLionel Sambuc 
235433d6423SLionel Sambuc   assert(ino->i_parent == NULL);
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc   /* Initialize a subset of its fields */
238433d6423SLionel Sambuc   ino->i_gen++;
239433d6423SLionel Sambuc   ino->i_ref = 1;
240433d6423SLionel Sambuc 
241433d6423SLionel Sambuc   return ino;
242433d6423SLionel Sambuc }
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc /*===========================================================================*
245433d6423SLionel Sambuc  *				have_free_inode				     *
246433d6423SLionel Sambuc  *===========================================================================*/
have_free_inode(void)247433d6423SLionel Sambuc int have_free_inode(void)
248433d6423SLionel Sambuc {
249433d6423SLionel Sambuc /* Check whether there are any free inodes at the moment. Kind of lame, but
250433d6423SLionel Sambuc  * this allows for easier error recovery in some places.
251433d6423SLionel Sambuc  */
252433d6423SLionel Sambuc 
253433d6423SLionel Sambuc   return !TAILQ_EMPTY(&free_list);
254433d6423SLionel Sambuc }
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc /*===========================================================================*
257433d6423SLionel Sambuc  *				have_used_inode				     *
258433d6423SLionel Sambuc  *===========================================================================*/
have_used_inode(void)259433d6423SLionel Sambuc int have_used_inode(void)
260433d6423SLionel Sambuc {
261433d6423SLionel Sambuc /* Check whether any inodes are still in use, that is, any of the inodes have
262433d6423SLionel Sambuc  * a reference count larger than zero.
263433d6423SLionel Sambuc  */
264*7c48de6cSDavid van Moolenbroek   unsigned int i;
265433d6423SLionel Sambuc 
266*7c48de6cSDavid van Moolenbroek   for (i = 0; i < NUM_INODES; i++)
267*7c48de6cSDavid van Moolenbroek 	if (inodes[i].i_ref > 0)
268433d6423SLionel Sambuc 		return TRUE;
269433d6423SLionel Sambuc 
270433d6423SLionel Sambuc   return FALSE;
271433d6423SLionel Sambuc }
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc /*===========================================================================*
274433d6423SLionel Sambuc  *				do_putnode				     *
275433d6423SLionel Sambuc  *===========================================================================*/
do_putnode(ino_t ino_nr,unsigned int count)276a99c939dSDavid van Moolenbroek int do_putnode(ino_t ino_nr, unsigned int count)
277433d6423SLionel Sambuc {
278433d6423SLionel Sambuc /* Decrease an inode's reference count.
279433d6423SLionel Sambuc  */
280433d6423SLionel Sambuc   struct inode *ino;
281433d6423SLionel Sambuc 
282a99c939dSDavid van Moolenbroek   if ((ino = find_inode(ino_nr)) == NULL)
283433d6423SLionel Sambuc 	return EINVAL;
284433d6423SLionel Sambuc 
285a99c939dSDavid van Moolenbroek   if (count > ino->i_ref) return EINVAL;
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc   ino->i_ref -= count - 1;
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc   put_inode(ino);
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc   return OK;
292433d6423SLionel Sambuc }
293