1 #include "filesys/inode.h"
7 #include "filesys/filesys.h"
8 #include "threads/malloc.h"
11 Must be exactly DISK_SECTOR_SIZE bytes long. */
14 off_t length; /* File size in bytes. */
15 disk_sector_t start; /* Starting sector. */
16 uint32_t unused[126]; /* Unused padding. */
19 /* Returns the number of sectors to allocate for a file SIZE
22 bytes_to_sectors (off_t size)
24 return DIV_ROUND_UP (size, DISK_SECTOR_SIZE);
27 /* In-memory inode. */
30 list_elem elem; /* Element in inode list. */
31 disk_sector_t sector; /* Sector number of disk location. */
32 int open_cnt; /* Number of openers. */
33 bool removed; /* True if deleted, false otherwise. */
34 struct inode_disk data; /* On-disk data. */
37 /* List of open inodes, so that opening a single inode twice
38 returns the same `struct inode'. */
39 static struct list open_inodes;
41 static void deallocate_inode (const struct inode *);
43 /* Initializes the inode module. */
47 list_init (&open_inodes);
50 /* Initializes an inode for a file LENGTH bytes in size and
51 writes the new inode to sector SECTOR on the file system
52 disk. Allocates sectors for the file from FREE_MAP.
53 Returns true if successful.
54 Returns false if memory or disk allocation fails. FREE_MAP
55 may be modified regardless. */
57 inode_create (struct bitmap *free_map, disk_sector_t sector, off_t length)
59 static const char zero_sector[DISK_SECTOR_SIZE];
60 struct inode_disk *idx;
64 ASSERT (free_map != NULL);
67 /* Allocate sectors. */
68 start = bitmap_scan_and_flip (free_map, 0, bytes_to_sectors (length), false);
69 if (start == BITMAP_ERROR)
73 idx = calloc (sizeof *idx, 1);
80 disk_write (filesys_disk, sector, idx);
81 for (i = 0; i < bytes_to_sectors (length); i++)
82 disk_write (filesys_disk, idx->start + i, zero_sector);
88 /* Reads an inode from SECTOR
89 and returns a `struct inode' that contains it.
90 Returns a null pointer if memory allocation fails. */
92 inode_open (disk_sector_t sector)
97 /* Check whether this inode is already open.
98 (A hash table would be better, but the Pintos base code
99 avoids using the hash table so that users are free to modify
101 for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
104 idx = list_entry (e, struct inode, elem);
105 if (idx->sector == sector)
112 /* Allocate memory. */
113 idx = calloc (1, sizeof *idx);
118 list_push_front (&open_inodes, &idx->elem);
119 idx->sector = sector;
121 idx->removed = false;
123 /* Read from disk. */
124 ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
125 disk_read (filesys_disk, sector, &idx->data);
130 /* Closes inode IDX and writes it to disk.
131 If this was the last reference to IDX, frees its memory.
132 If IDX was also a removed inode, frees its blocks. */
134 inode_close (struct inode *idx)
136 /* Ignore null pointer. */
140 /* Release resources if this was the last opener. */
141 if (--idx->open_cnt == 0)
143 /* Deallocate blocks if removed. */
145 deallocate_inode (idx);
147 /* Remove from inode list and free memory. */
148 list_remove (&idx->elem);
153 /* Deallocates the blocks allocated for IDX. */
155 deallocate_inode (const struct inode *idx)
157 struct bitmap *free_map = bitmap_create (disk_size (filesys_disk));
158 if (free_map != NULL)
160 bitmap_read (free_map, free_map_file);
161 bitmap_reset (free_map, idx->sector);
162 bitmap_set_multiple (free_map, idx->data.start,
163 bytes_to_sectors (idx->data.length), false);
164 bitmap_write (free_map, free_map_file);
165 bitmap_destroy (free_map);
168 printf ("inode_close(): can't free blocks");
171 /* Marks IDX to be deleted when it is closed by the last caller who
174 inode_remove (struct inode *idx)
176 ASSERT (idx != NULL);
180 /* Returns the disk sector that contains byte offset POS within
181 the file with inode IDX.
182 Returns -1 if IDX does not contain data for a byte at offset
185 inode_byte_to_sector (const struct inode *idx, off_t pos)
187 ASSERT (idx != NULL);
188 ASSERT (pos < idx->data.length);
189 return idx->data.start + pos / DISK_SECTOR_SIZE;
192 /* Returns the length, in bytes, of the file with inode IDX. */
194 inode_length (const struct inode *idx)
196 ASSERT (idx != NULL);
197 return idx->data.length;
200 /* Prints a representation of IDX to the system console. */
202 inode_print (const struct inode *idx)
204 ASSERT (idx != NULL);
205 printf ("Inode %"PRDSNu": %"PRDSNu" bytes, "
206 "%zu sectors starting at %"PRDSNu"\n",
207 idx->sector, idx->data.length,
208 (size_t) DIV_ROUND_UP (idx->data.length, DISK_SECTOR_SIZE),