arm: make signal handlers work
[minix.git] / servers / ext2 / inode.c
blob72a228991bea10aed89632f0f0e7905f2b32e9f1
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.
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
14 * Created (MFS based):
15 * February 2010 (Evgeniy Ivanov)
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>
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);
31 /*===========================================================================*
32 * fs_putnode *
33 *===========================================================================*/
34 int fs_putnode(void)
36 /* Find the inode specified by the request message and decrease its counter.*/
38 struct inode *rip;
39 int count;
41 rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR);
43 if (!rip) {
44 printf("%s:%d put_inode: inode #%u dev: %d not found\n", __FILE__,
45 __LINE__, (ino_t) fs_m_in.REQ_INODE_NR, fs_dev);
46 panic("fs_putnode failed");
49 count = fs_m_in.REQ_COUNT;
50 if (count <= 0) {
51 printf("%s:%d put_inode: bad value for count: %d\n", __FILE__,
52 __LINE__, count);
53 panic("fs_putnode failed");
54 } else if (count > rip->i_count) {
55 printf("%s:%d put_inode: count too high: %d > %d\n", __FILE__,
56 __LINE__, count, rip->i_count);
57 panic("fs_putnode failed");
60 /* Decrease reference counter, but keep one reference;
61 * it will be consumed by put_inode().
63 rip->i_count -= count - 1;
64 put_inode(rip);
66 return(OK);
70 /*===========================================================================*
71 * init_inode_cache *
72 *===========================================================================*/
73 void init_inode_cache()
75 struct inode *rip;
76 struct inodelist *rlp;
78 inode_cache_hit = 0;
79 inode_cache_miss = 0;
81 /* init free/unused list */
82 TAILQ_INIT(&unused_inodes);
84 /* init hash lists */
85 for (rlp = &hash_inodes[0]; rlp < &hash_inodes[INODE_HASH_SIZE]; ++rlp)
86 LIST_INIT(rlp);
88 /* add free inodes to unused/free list */
89 for (rip = &inode[0]; rip < &inode[NR_INODES]; ++rip) {
90 rip->i_num = NO_ENTRY;
91 TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused);
96 /*===========================================================================*
97 * addhash_inode *
98 *===========================================================================*/
99 static void addhash_inode(struct inode *node)
101 int hashi = node->i_num & INODE_HASH_MASK;
103 /* insert into hash table */
104 LIST_INSERT_HEAD(&hash_inodes[hashi], node, i_hash);
108 /*===========================================================================*
109 * unhash_inode *
110 *===========================================================================*/
111 static void unhash_inode(struct inode *node)
113 /* remove from hash table */
114 LIST_REMOVE(node, i_hash);
118 /*===========================================================================*
119 * get_inode *
120 *===========================================================================*/
121 struct inode *get_inode(
122 dev_t dev, /* device on which inode resides */
123 ino_t numb /* inode number (ANSI: may not be unshort) */
126 /* Find the inode in the hash table. If it is not there, get a free inode
127 * load it from the disk if it's necessary and put on the hash list
129 register struct inode *rip;
130 int hashi;
131 int i;
133 hashi = (int) numb & INODE_HASH_MASK;
135 /* Search inode in the hash table */
136 LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) {
137 if (rip->i_num == numb && rip->i_dev == dev) {
138 /* If unused, remove it from the unused/free list */
139 if (rip->i_count == 0) {
140 inode_cache_hit++;
141 TAILQ_REMOVE(&unused_inodes, rip, i_unused);
143 ++rip->i_count;
144 return(rip);
148 inode_cache_miss++;
150 /* Inode is not on the hash, get a free one */
151 if (TAILQ_EMPTY(&unused_inodes)) {
152 err_code = ENFILE;
153 return(NULL);
155 rip = TAILQ_FIRST(&unused_inodes);
157 /* If not free unhash it */
158 if (rip->i_num != NO_ENTRY)
159 unhash_inode(rip);
161 /* Inode is not unused any more */
162 TAILQ_REMOVE(&unused_inodes, rip, i_unused);
164 /* Load the inode. */
165 rip->i_dev = dev;
166 rip->i_num = numb;
167 rip->i_count = 1;
168 if (dev != NO_DEV)
169 rw_inode(rip, READING); /* get inode from disk */
170 rip->i_update = 0; /* all the times are initially up-to-date */
171 rip->i_last_dpos = 0; /* no dentries searched for yet */
172 rip->i_bsearch = NO_BLOCK;
173 rip->i_last_pos_bl_alloc = 0;
174 rip->i_last_dentry_size = 0;
175 rip->i_mountpoint= FALSE;
177 rip->i_preallocation = opt.use_prealloc;
178 rip->i_prealloc_count = rip->i_prealloc_index = 0;
180 for (i = 0; i < EXT2_PREALLOC_BLOCKS; i++) {
181 if (rip->i_prealloc_blocks[i] != NO_BLOCK) {
182 /* Actually this should never happen */
183 free_block(rip->i_sp, rip->i_prealloc_blocks[i]);
184 rip->i_prealloc_blocks[i] = NO_BLOCK;
185 ext2_debug("Warning: Unexpected preallocated block.");
189 /* Add to hash */
190 addhash_inode(rip);
192 return(rip);
196 /*===========================================================================*
197 * find_inode *
198 *===========================================================================*/
199 struct inode *find_inode(
200 dev_t dev, /* device on which inode resides */
201 ino_t numb /* inode number (ANSI: may not be unshort) */
204 /* Find the inode specified by the inode and device number. */
205 struct inode *rip;
206 int hashi;
208 hashi = (int) numb & INODE_HASH_MASK;
210 /* Search inode in the hash table */
211 LIST_FOREACH(rip, &hash_inodes[hashi], i_hash) {
212 if (rip->i_count > 0 && rip->i_num == numb && rip->i_dev == dev) {
213 return(rip);
217 return(NULL);
221 /*===========================================================================*
222 * put_inode *
223 *===========================================================================*/
224 void put_inode(
225 register struct inode *rip /* pointer to inode to be released */
228 /* The caller is no longer using this inode. If no one else is using it either
229 * write it back to the disk immediately. If it has no links, truncate it and
230 * return it to the pool of available inodes.
233 if (rip == NULL)
234 return; /* checking here is easier than in caller */
236 if (rip->i_count < 1)
237 panic("put_inode: i_count already below 1", rip->i_count);
239 if (--rip->i_count == 0) { /* i_count == 0 means no one is using it now */
240 if (rip->i_links_count == NO_LINK) {
241 /* i_nlinks == NO_LINK means free the inode. */
242 /* return all the disk blocks */
244 /* Ignore errors by truncate_inode in case inode is a block
245 * special or character special file.
247 (void) truncate_inode(rip, (off_t) 0);
248 /* free inode clears I_TYPE field, since it's used there */
249 rip->i_dirt = IN_DIRTY;
250 free_inode(rip);
253 rip->i_mountpoint = FALSE;
254 if (rip->i_dirt == IN_DIRTY) rw_inode(rip, WRITING);
256 discard_preallocated_blocks(rip); /* Return blocks to the filesystem */
258 if (rip->i_links_count == NO_LINK) {
259 /* free, put at the front of the LRU list */
260 unhash_inode(rip);
261 rip->i_num = NO_ENTRY;
262 TAILQ_INSERT_HEAD(&unused_inodes, rip, i_unused);
263 } else {
264 /* unused, put at the back of the LRU (cache it) */
265 TAILQ_INSERT_TAIL(&unused_inodes, rip, i_unused);
271 /*===========================================================================*
272 * update_times *
273 *===========================================================================*/
274 void update_times(
275 register struct inode *rip /* pointer to inode to be read/written */
278 /* Various system calls are required by the standard to update atime, ctime,
279 * or mtime. Since updating a time requires sending a message to the clock
280 * task--an expensive business--the times are marked for update by setting
281 * bits in i_update. When a stat, fstat, or sync is done, or an inode is
282 * released, update_times() may be called to actually fill in the times.
285 time_t cur_time;
286 struct super_block *sp;
288 sp = rip->i_sp; /* get pointer to super block. */
289 if (sp->s_rd_only)
290 return; /* no updates for read-only file systems */
292 cur_time = clock_time();
293 if (rip->i_update & ATIME)
294 rip->i_atime = cur_time;
295 if (rip->i_update & CTIME)
296 rip->i_ctime = cur_time;
297 if (rip->i_update & MTIME)
298 rip->i_mtime = cur_time;
299 rip->i_update = 0; /* they are all up-to-date now */
302 /*===========================================================================*
303 * rw_inode *
304 *===========================================================================*/
305 void rw_inode(
306 register struct inode *rip, /* pointer to inode to be read/written */
307 int rw_flag /* READING or WRITING */
310 /* An entry in the inode table is to be copied to or from the disk. */
312 register struct buf *bp;
313 register struct super_block *sp;
314 register struct group_desc *gd;
315 register d_inode *dip;
316 u32_t block_group_number;
317 block_t b, offset;
319 /* Get the block where the inode resides. */
320 sp = get_super(rip->i_dev); /* get pointer to super block */
321 rip->i_sp = sp; /* inode must contain super block pointer */
323 block_group_number = (rip->i_num - 1) / sp->s_inodes_per_group;
325 gd = get_group_desc(block_group_number);
327 if (gd == NULL)
328 panic("can't get group_desc to read/write inode");
330 offset = ((rip->i_num - 1) % sp->s_inodes_per_group) * EXT2_INODE_SIZE(sp);
331 /* offset requires shifting, since each block contains several inodes,
332 * e.g. inode 2 is stored in bklock 0.
334 b = (block_t) gd->inode_table + (offset >> sp->s_blocksize_bits);
335 bp = get_block(rip->i_dev, b, NORMAL);
337 offset &= (sp->s_block_size - 1);
338 dip = (d_inode*) (b_data(bp) + offset);
340 /* Do the read or write. */
341 if (rw_flag == WRITING) {
342 if (rip->i_update)
343 update_times(rip); /* times need updating */
344 if (sp->s_rd_only == FALSE)
345 lmfs_markdirty(bp);
348 icopy(rip, dip, rw_flag, TRUE);
350 put_block(bp, INODE_BLOCK);
351 rip->i_dirt = IN_CLEAN;
355 /*===========================================================================*
356 * icopy *
357 *===========================================================================*/
358 static void icopy(
359 register struct inode *rip, /* pointer to the in-core inode struct */
360 register d_inode *dip, /* pointer to the on-disk struct */
361 int direction, /* READING (from disk) or WRITING (to disk) */
362 int norm /* TRUE = do not swap bytes; FALSE = swap */
365 int i;
367 if (direction == READING) {
368 /* Copy inode to the in-core table, swapping bytes if need be. */
369 rip->i_mode = conv2(norm,dip->i_mode);
370 rip->i_uid = conv2(norm,dip->i_uid);
371 rip->i_size = conv4(norm,dip->i_size);
372 rip->i_atime = conv4(norm,dip->i_atime);
373 rip->i_ctime = conv4(norm,dip->i_ctime);
374 rip->i_mtime = conv4(norm,dip->i_mtime);
375 rip->i_dtime = conv4(norm,dip->i_dtime);
376 rip->i_gid = conv2(norm,dip->i_gid);
377 rip->i_links_count = conv2(norm,dip->i_links_count);
378 rip->i_blocks = conv4(norm,dip->i_blocks);
379 rip->i_flags = conv4(norm,dip->i_flags);
380 /* Minix doesn't touch osd1 and osd2 either, so just copy. */
381 memcpy(&rip->osd1, &dip->osd1, sizeof(rip->osd1));
382 for (i = 0; i < EXT2_N_BLOCKS; i++)
383 rip->i_block[i] = conv4(norm, dip->i_block[i]);
384 rip->i_generation = conv4(norm,dip->i_generation);
385 rip->i_file_acl = conv4(norm,dip->i_file_acl);
386 rip->i_dir_acl = conv4(norm,dip->i_dir_acl);
387 rip->i_faddr = conv4(norm,dip->i_faddr);
388 memcpy(&rip->osd2, &dip->osd2, sizeof(rip->osd2));
389 } else {
390 /* Copying inode to disk from the in-core table. */
391 dip->i_mode = conv2(norm,rip->i_mode);
392 dip->i_uid = conv2(norm,rip->i_uid);
393 dip->i_size = conv4(norm,rip->i_size);
394 dip->i_atime = conv4(norm,rip->i_atime);
395 dip->i_ctime = conv4(norm,rip->i_ctime);
396 dip->i_mtime = conv4(norm,rip->i_mtime);
397 dip->i_dtime = conv4(norm,rip->i_dtime);
398 dip->i_gid = conv2(norm,rip->i_gid);
399 dip->i_links_count = conv2(norm,rip->i_links_count);
400 dip->i_blocks = conv4(norm,rip->i_blocks);
401 dip->i_flags = conv4(norm,rip->i_flags);
402 /* Minix doesn't touch osd1 and osd2 either, so just copy. */
403 memcpy(&dip->osd1, &rip->osd1, sizeof(dip->osd1));
404 for (i = 0; i < EXT2_N_BLOCKS; i++)
405 dip->i_block[i] = conv4(norm, rip->i_block[i]);
406 dip->i_generation = conv4(norm,rip->i_generation);
407 dip->i_file_acl = conv4(norm,rip->i_file_acl);
408 dip->i_dir_acl = conv4(norm,rip->i_dir_acl);
409 dip->i_faddr = conv4(norm,rip->i_faddr);
410 memcpy(&dip->osd2, &rip->osd2, sizeof(dip->osd2));
415 /*===========================================================================*
416 * dup_inode *
417 *===========================================================================*/
418 void dup_inode(
419 struct inode *ip /* The inode to be duplicated. */
422 /* This routine is a simplified form of get_inode() for the case where
423 * the inode pointer is already known.
425 ip->i_count++;