1 /* This file manages the inode table. There are procedures to allocate and
2 * deallocate inodes, acquire, erase, and release them, and read and write
3 * them from the disk.
4 *
5 * The entry points into this file are
6 * get_inode: search inode table for a given inode; if not there,
7 * read it
8 * put_inode: indicate that an inode is no longer needed in memory
9 * update_times: update atime, ctime, and mtime
10 * rw_inode: read a disk block and extract an inode, or corresp. write
11 * dup_inode: indicate that someone else is using an inode table entry
12 * find_inode: retrieve pointer to inode in inode cache
13 *
14 * Created (MFS based):
15 * February 2010 (Evgeniy Ivanov)
16 */
17
18 #include "fs.h"
19 #include <string.h>
20 #include "buf.h"
21 #include "inode.h"
22 #include "super.h"
23 #include <minix/vfsif.h>
24
25 static void icopy(struct inode *rip, d_inode *dip, int direction, int
26 norm);
27 static void addhash_inode(struct inode *node);
28 static void unhash_inode(struct inode *node);
29
30
31 /*===========================================================================*
32 * fs_putnode *
33 *===========================================================================*/
fs_putnode(ino_t ino_nr,unsigned int count)34 int fs_putnode(ino_t ino_nr, unsigned int count)
35 {
36 /* Find the inode specified by the request message and decrease its counter.*/
37
38 struct inode *rip;
39
40 rip = find_inode(fs_dev, ino_nr);
41
42 if (!rip) {
43 printf("%s:%d put_inode: inode #%llu dev: %llx not found\n", __FILE__,
44 __LINE__, ino_nr, fs_dev);
45 panic("fs_putnode failed");
46 }
47
48 if (count > rip->i_count) {
49 printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__,
50 __LINE__, count, rip->i_count);
51 panic("fs_putnode failed");
52 }
53
54 /* Decrease reference counter, but keep one reference;
55 * it will be consumed by put_inode().
56 */
57 rip->i_count -= count - 1;
58 put_inode(rip);
59
60 return(OK);
61 }
62
63
64 /*===========================================================================*
65 * init_inode_cache *
66 *===========================================================================*/
init_inode_cache()67 void init_inode_cache()
68 {
69 struct inode *rip;
70 struct inodelist *rlp;
71
72 inode_cache_hit = 0;
73 inode_cache_miss = 0;
74
75 /* init free/unused list */
76 TAILQ_INIT(&unused_inodes);
77
78 /* init hash lists */
79 for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp)
80 LIST_INIT(rlp);
81
82 /* add free inodes to unused/free list */
83 for (rip = &inode[0]; rip < &inode[NR_INODES]; ++rip) {
84 rip->i_num = NO_ENTRY;
85 TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused);
86 }
87 }
88
89
90 /*===========================================================================*
91 * addhash_inode *
92 *===========================================================================*/
addhash_inode(struct inode * node)93 static void addhash_inode(struct inode *node)
94 {
95 int hashi = node->i_num & INODE_HASH_MASK;
96
97 /* insert into hash table */
98 LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash);
99 }
100
101
102 /*===========================================================================*
103 * unhash_inode *
104 *===========================================================================*/
unhash_inode(struct inode * node)105 static void unhash_inode(struct inode *node)
106 {
107 /* remove from hash table */
108 LIST_REMOVE(node, i_hash);
109 }
110
111
112 /*===========================================================================*
113 * get_inode *
114 *===========================================================================*/
get_inode(dev_t dev,ino_t numb)115 struct inode *get_inode(
116 dev_t dev, /* device on which inode resides */
117 ino_t numb /* inode number (ANSI: may not be unshort) */
118 )
119 {
120 /* Find the inode in the hash table. If it is not there, get a free inode
121 * load it from the disk if it's necessary and put on the hash list
122 */
123 register struct inode *rip;
124 int hashi;
125 int i;
126
127 hashi = (int) numb & INODE_HASH_MASK;
128
129 /* Search inode in the hash table */
130 LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) {
131 if (rip->i_num == numb && rip->i_dev == dev) {
132 /* If unused, remove it from the unused/free list */
133 if (rip->i_count == 0) {
134 inode_cache_hit++;
135 TAILQ_REMOVE(&unused_inodes, rip, i_unused);
136 }
137 ++rip->i_count;
138 return(rip);
139 }
140 }
141
142 inode_cache_miss++;
143
144 /* Inode is not on the hash, get a free one */
145 if (TAILQ_EMPTY(&unused_inodes)) {
146 err_code = ENFILE;
147 return(NULL);
148 }
149 rip = TAILQ_FIRST(&unused_inodes);
150
151 /* If not free unhash it */
152 if (rip->i_num != NO_ENTRY)
153 unhash_inode(rip);
154
155 /* Inode is not unused any more */
156 TAILQ_REMOVE(&unused_inodes, rip, i_unused);
157
158 /* Load the inode. */
159 rip->i_dev = dev;
160 rip->i_num = numb;
161 rip->i_count = 1;
162 if (dev != NO_DEV)
163 rw_inode(rip, READING); /* get inode from disk */
164 rip->i_update = 0; /* all the times are initially up-to-date */
165 rip->i_last_dpos = 0; /* no dentries searched for yet */
166 rip->i_bsearch = NO_BLOCK;
167 rip->i_last_pos_bl_alloc = 0;
168 rip->i_last_dentry_size = 0;
169 rip->i_mountpoint= FALSE;
170
171 rip->i_preallocation = opt.use_prealloc;
172 rip->i_prealloc_count = rip->i_prealloc_index = 0;
173
174 for (i = 0; i < EXT2_PREALLOC_BLOCKS; i++) {
175 if (rip->i_prealloc_blocks[i] != NO_BLOCK) {
176 /* Actually this should never happen */
177 free_block(rip->i_sp, rip->i_prealloc_blocks[i]);
178 rip->i_prealloc_blocks[i] = NO_BLOCK;
179 ext2_debug("Warning: Unexpected preallocated block.");
180 }
181 }
182
183 /* Add to hash */
184 addhash_inode(rip);
185
186 return(rip);
187 }
188
189
190 /*===========================================================================*
191 * find_inode *
192 *===========================================================================*/
find_inode(dev_t dev,ino_t numb)193 struct inode *find_inode(
194 dev_t dev, /* device on which inode resides */
195 ino_t numb /* inode number (ANSI: may not be unshort) */
196 )
197 {
198 /* Find the inode specified by the inode and device number. */
199 struct inode *rip;
200 int hashi;
201
202 hashi = (int) numb & INODE_HASH_MASK;
203
204 /* Search inode in the hash table */
205 LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) {
206 if (rip->i_count > 0 && rip->i_num == numb && rip->i_dev == dev) {
207 return(rip);
208 }
209 }
210
211 return(NULL);
212 }
213
214
215 /*===========================================================================*
216 * put_inode *
217 *===========================================================================*/
put_inode(register struct inode * rip)218 void put_inode(
219 register struct inode *rip /* pointer to inode to be released */
220 )
221 {
222 /* The caller is no longer using this inode. If no one else is using it either
223 * write it back to the disk immediately. If it has no links, truncate it and
224 * return it to the pool of available inodes.
225 */
226
227 if (rip == NULL)
228 return; /* checking here is easier than in caller */
229
230 if (rip->i_count < 1)
231 panic("put_inode: i_count already below 1: %d", rip->i_count);
232
233 if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */
234 if (rip->i_links_count == NO_LINK) {
235 /* i_nlinks == NO_LINK means free the inode. */
236 /* return all the disk blocks */
237
238 /* Ignore errors by truncate_inode in case inode is a block
239 * special or character special file.
240 */
241 (void) truncate_inode(rip, (off_t) 0);
242 /* free inode clears I_TYPE field, since it's used there */
243 rip->i_dirt = IN_DIRTY;
244 free_inode(rip);
245 }
246
247 rip->i_mountpoint = FALSE;
248 if (rip->i_dirt == IN_DIRTY) rw_inode(rip, WRITING);
249
250 discard_preallocated_blocks(rip); /* Return blocks to the filesystem */
251
252 if (rip->i_links_count == NO_LINK) {
253 /* free, put at the front of the LRU list */
254 unhash_inode(rip);
255 rip->i_num = NO_ENTRY;
256 TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused);
257 } else {
258 /* unused, put at the back of the LRU (cache it) */
259 TAILQ_INSERT_TAIL(&unused_inodes, rip, i_unused);
260 }
261 }
262 }
263
264
265 /*===========================================================================*
266 * update_times *
267 *===========================================================================*/
update_times(register struct inode * rip)268 void update_times(
269 register struct inode *rip /* pointer to inode to be read/written */
270 )
271 {
272 /* Various system calls are required by the standard to update atime, ctime,
273 * or mtime. Since updating a time requires sending a message to the clock
274 * task--an expensive business--the times are marked for update by setting
275 * bits in i_update. When a stat, fstat, or sync is done, or an inode is
276 * released, update_times() may be called to actually fill in the times.
277 */
278
279 time_t cur_time;
280 struct super_block *sp;
281
282 sp = rip->i_sp; /* get pointer to super block. */
283 if (sp->s_rd_only)
284 return; /* no updates for read-only file systems */
285
286 cur_time = clock_time(NULL);
287 if (rip->i_update & ATIME)
288 rip->i_atime = cur_time;
289 if (rip->i_update & CTIME)
290 rip->i_ctime = cur_time;
291 if (rip->i_update & MTIME)
292 rip->i_mtime = cur_time;
293 rip->i_update = 0; /* they are all up-to-date now */
294 }
295
296 /*===========================================================================*
297 * rw_inode *
298 *===========================================================================*/
rw_inode(register struct inode * rip,int rw_flag)299 void rw_inode(
300 register struct inode *rip, /* pointer to inode to be read/written */
301 int rw_flag /* READING or WRITING */
302 )
303 {
304 /* An entry in the inode table is to be copied to or from the disk. */
305
306 register struct buf *bp;
307 register struct super_block *sp;
308 register struct group_desc *gd;
309 register d_inode *dip;
310 u32_t block_group_number;
311 block_t b, offset;
312
313 /* Get the block where the inode resides. */
314 sp = get_super(rip->i_dev); /* get pointer to super block */
315 rip->i_sp = sp; /* inode must contain super block pointer */
316
317 block_group_number = (rip->i_num - 1) / sp->s_inodes_per_group;
318
319 gd = get_group_desc(block_group_number);
320
321 if (gd == NULL)
322 panic("can't get group_desc to read/write inode");
323
324 offset = ((rip->i_num - 1) % sp->s_inodes_per_group) * EXT2_INODE_SIZE(sp);
325 /* offset requires shifting, since each block contains several inodes,
326 * e.g. inode 2 is stored in bklock 0.
327 */
328 b = (block_t) gd->inode_table + (offset >> sp->s_blocksize_bits);
329 bp = get_block(rip->i_dev, b, NORMAL);
330
331 offset &= (sp->s_block_size - 1);
332 dip = (d_inode*) (b_data(bp) + offset);
333
334 /* Do the read or write. */
335 if (rw_flag == WRITING) {
336 if (rip->i_update)
337 update_times(rip); /* times need updating */
338 if (sp->s_rd_only == FALSE)
339 lmfs_markdirty(bp);
340 }
341
342 icopy(rip, dip, rw_flag, TRUE);
343
344 put_block(bp);
345 rip->i_dirt = IN_CLEAN;
346 }
347
348
349 /*===========================================================================*
350 * icopy *
351 *===========================================================================*/
icopy(register struct inode * rip,register d_inode * dip,int direction,int norm)352 static void icopy(
353 register struct inode *rip, /* pointer to the in-core inode struct */
354 register d_inode *dip, /* pointer to the on-disk struct */
355 int direction, /* READING (from disk) or WRITING (to disk) */
356 int norm /* TRUE = do not swap bytes; FALSE = swap */
357 )
358 {
359 int i;
360
361 if (direction == READING) {
362 /* Copy inode to the in-core table, swapping bytes if need be. */
363 rip->i_mode = conv2(norm,dip->i_mode);
364 rip->i_uid = conv2(norm,dip->i_uid);
365 rip->i_size = conv4(norm,dip->i_size);
366 rip->i_atime = conv4(norm,dip->i_atime);
367 rip->i_ctime = conv4(norm,dip->i_ctime);
368 rip->i_mtime = conv4(norm,dip->i_mtime);
369 rip->i_dtime = conv4(norm,dip->i_dtime);
370 rip->i_gid = conv2(norm,dip->i_gid);
371 rip->i_links_count = conv2(norm,dip->i_links_count);
372 rip->i_blocks = conv4(norm,dip->i_blocks);
373 rip->i_flags = conv4(norm,dip->i_flags);
374 /* Minix doesn't touch osd1 and osd2 either, so just copy. */
375 memcpy(&rip->osd1, &dip->osd1, sizeof(rip->osd1));
376 for (i = 0; i < EXT2_N_BLOCKS; i++)
377 rip->i_block[i] = conv4(norm, dip->i_block[i]);
378 rip->i_generation = conv4(norm,dip->i_generation);
379 rip->i_file_acl = conv4(norm,dip->i_file_acl);
380 rip->i_dir_acl = conv4(norm,dip->i_dir_acl);
381 rip->i_faddr = conv4(norm,dip->i_faddr);
382 memcpy(&rip->osd2, &dip->osd2, sizeof(rip->osd2));
383 } else {
384 /* Copying inode to disk from the in-core table. */
385 dip->i_mode = conv2(norm,rip->i_mode);
386 dip->i_uid = conv2(norm,rip->i_uid);
387 dip->i_size = conv4(norm,rip->i_size);
388 dip->i_atime = conv4(norm,rip->i_atime);
389 dip->i_ctime = conv4(norm,rip->i_ctime);
390 dip->i_mtime = conv4(norm,rip->i_mtime);
391 dip->i_dtime = conv4(norm,rip->i_dtime);
392 dip->i_gid = conv2(norm,rip->i_gid);
393 dip->i_links_count = conv2(norm,rip->i_links_count);
394 dip->i_blocks = conv4(norm,rip->i_blocks);
395 dip->i_flags = conv4(norm,rip->i_flags);
396 /* Minix doesn't touch osd1 and osd2 either, so just copy. */
397 memcpy(&dip->osd1, &rip->osd1, sizeof(dip->osd1));
398 for (i = 0; i < EXT2_N_BLOCKS; i++)
399 dip->i_block[i] = conv4(norm, rip->i_block[i]);
400 dip->i_generation = conv4(norm,rip->i_generation);
401 dip->i_file_acl = conv4(norm,rip->i_file_acl);
402 dip->i_dir_acl = conv4(norm,rip->i_dir_acl);
403 dip->i_faddr = conv4(norm,rip->i_faddr);
404 memcpy(&dip->osd2, &rip->osd2, sizeof(dip->osd2));
405 }
406 }
407
408
409 /*===========================================================================*
410 * dup_inode *
411 *===========================================================================*/
dup_inode(struct inode * ip)412 void dup_inode(
413 struct inode *ip /* The inode to be duplicated. */
414 )
415 {
416 /* This routine is a simplified form of get_inode() for the case where
417 * the inode pointer is already known.
418 */
419 ip->i_count++;
420 }
421