1 #include "filesys/inode.h"
6 #include "filesys/filesys.h"
7 #include "filesys/free-map.h"
8 #include "threads/malloc.h"
10 /* Identifies an inode. */
11 #define INODE_MAGIC 0x494e4f44
14 Must be exactly DISK_SECTOR_SIZE bytes long. */
17 disk_sector_t start; /* First data sector. */
18 off_t length; /* File size in bytes. */
19 unsigned magic; /* Magic number. */
20 uint32_t unused[125]; /* Not used. */
23 /* Returns the number of sectors to allocate for an inode SIZE
26 bytes_to_sectors (off_t size)
28 return DIV_ROUND_UP (size, DISK_SECTOR_SIZE);
31 /* In-memory inode. */
34 struct list_elem elem; /* Element in inode list. */
35 disk_sector_t sector; /* Sector number of disk location. */
36 int open_cnt; /* Number of openers. */
37 bool removed; /* True if deleted, false otherwise. */
38 int deny_write_cnt; /* 0: writes ok, >0: deny writes. */
39 struct inode_disk data; /* Inode content. */
42 /* Returns the disk sector that contains byte offset POS within
44 Returns -1 if INODE does not contain data for a byte at offset
47 byte_to_sector (const struct inode *inode, off_t pos)
49 ASSERT (inode != NULL);
50 if (pos < inode->data.length)
51 return inode->data.start + pos / DISK_SECTOR_SIZE;
56 /* List of open inodes, so that opening a single inode twice
57 returns the same `struct inode'. */
58 static struct list open_inodes;
60 /* Initializes the inode module. */
64 list_init (&open_inodes);
67 /* Initializes an inode with LENGTH bytes of data and
68 writes the new inode to sector SECTOR on the file system
70 Returns true if successful.
71 Returns false if memory or disk allocation fails. */
73 inode_create (disk_sector_t sector, off_t length)
75 struct inode_disk *disk_inode = NULL;
80 /* If this assertion fails, the inode structure is not exactly
81 one sector in size, and you should fix that. */
82 ASSERT (sizeof *disk_inode == DISK_SECTOR_SIZE);
84 disk_inode = calloc (1, sizeof *disk_inode);
85 if (disk_inode != NULL)
87 size_t sectors = bytes_to_sectors (length);
88 disk_inode->length = length;
89 disk_inode->magic = INODE_MAGIC;
90 if (free_map_allocate (sectors, &disk_inode->start))
92 disk_write (filesys_disk, sector, disk_inode);
95 static char zeros[DISK_SECTOR_SIZE];
98 for (i = 0; i < sectors; i++)
99 disk_write (filesys_disk, disk_inode->start + i, zeros);
108 /* Reads an inode from SECTOR
109 and returns a `struct inode' that contains it.
110 Returns a null pointer if memory allocation fails. */
112 inode_open (disk_sector_t sector)
117 /* Check whether this inode is already open. */
118 for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
121 inode = list_entry (e, struct inode, elem);
122 if (inode->sector == sector)
124 inode_reopen (inode);
129 /* Allocate memory. */
130 inode = malloc (sizeof *inode);
135 list_push_front (&open_inodes, &inode->elem);
136 inode->sector = sector;
138 inode->deny_write_cnt = 0;
139 inode->removed = false;
140 disk_read (filesys_disk, inode->sector, &inode->data);
144 /* Reopens and returns INODE. */
146 inode_reopen (struct inode *inode)
153 /* Closes INODE and writes it to disk.
154 If this was the last reference to INODE, frees its memory.
155 If INODE was also a removed inode, frees its blocks. */
157 inode_close (struct inode *inode)
159 /* Ignore null pointer. */
163 /* Release resources if this was the last opener. */
164 if (--inode->open_cnt == 0)
166 /* Remove from inode list and release lock. */
167 list_remove (&inode->elem);
169 /* Deallocate blocks if removed. */
172 free_map_release (inode->sector, 1);
173 free_map_release (inode->data.start,
174 bytes_to_sectors (inode->data.length));
181 /* Marks INODE to be deleted when it is closed by the last caller who
184 inode_remove (struct inode *inode)
186 ASSERT (inode != NULL);
187 inode->removed = true;
190 /* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
191 Returns the number of bytes actually read, which may be less
192 than SIZE if an error occurs or end of file is reached. */
194 inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset)
196 uint8_t *buffer = buffer_;
197 off_t bytes_read = 0;
198 uint8_t *bounce = NULL;
202 /* Disk sector to read, starting byte offset within sector. */
203 disk_sector_t sector_idx = byte_to_sector (inode, offset);
204 int sector_ofs = offset % DISK_SECTOR_SIZE;
206 /* Bytes left in inode, bytes left in sector, lesser of the two. */
207 off_t inode_left = inode_length (inode) - offset;
208 int sector_left = DISK_SECTOR_SIZE - sector_ofs;
209 int min_left = inode_left < sector_left ? inode_left : sector_left;
211 /* Number of bytes to actually copy out of this sector. */
212 int chunk_size = size < min_left ? size : min_left;
216 if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE)
218 /* Read full sector directly into caller's buffer. */
219 disk_read (filesys_disk, sector_idx, buffer + bytes_read);
223 /* Read sector into bounce buffer, then partially copy
224 into caller's buffer. */
227 bounce = malloc (DISK_SECTOR_SIZE);
231 disk_read (filesys_disk, sector_idx, bounce);
232 memcpy (buffer + bytes_read, bounce + sector_ofs, chunk_size);
237 offset += chunk_size;
238 bytes_read += chunk_size;
245 /* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
246 Returns the number of bytes actually written, which may be
247 less than SIZE if end of file is reached or an error occurs.
248 (Normally a write at end of file would extend the inode, but
249 growth is not yet implemented.) */
251 inode_write_at (struct inode *inode, const void *buffer_, off_t size,
254 const uint8_t *buffer = buffer_;
255 off_t bytes_written = 0;
256 uint8_t *bounce = NULL;
258 if (inode->deny_write_cnt)
263 /* Sector to write, starting byte offset within sector. */
264 disk_sector_t sector_idx = byte_to_sector (inode, offset);
265 int sector_ofs = offset % DISK_SECTOR_SIZE;
267 /* Bytes left in inode, bytes left in sector, lesser of the two. */
268 off_t inode_left = inode_length (inode) - offset;
269 int sector_left = DISK_SECTOR_SIZE - sector_ofs;
270 int min_left = inode_left < sector_left ? inode_left : sector_left;
272 /* Number of bytes to actually write into this sector. */
273 int chunk_size = size < min_left ? size : min_left;
277 if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE)
279 /* Write full sector directly to disk. */
280 disk_write (filesys_disk, sector_idx, buffer + bytes_written);
284 /* We need a bounce buffer. */
287 bounce = malloc (DISK_SECTOR_SIZE);
292 /* If the sector contains data before or after the chunk
293 we're writing, then we need to read in the sector
294 first. Otherwise we start with a sector of all zeros. */
295 if (sector_ofs > 0 || chunk_size < sector_left)
296 disk_read (filesys_disk, sector_idx, bounce);
298 memset (bounce, 0, DISK_SECTOR_SIZE);
299 memcpy (bounce + sector_ofs, buffer + bytes_written, chunk_size);
300 disk_write (filesys_disk, sector_idx, bounce);
305 offset += chunk_size;
306 bytes_written += chunk_size;
310 return bytes_written;
313 /* Disables writes to INODE.
314 May be called at most once per inode opener. */
316 inode_deny_write (struct inode *inode)
318 inode->deny_write_cnt++;
319 ASSERT (inode->deny_write_cnt <= inode->open_cnt);
322 /* Re-enables writes to INODE.
323 Must be called once by each inode opener who has called
324 inode_deny_write() on the inode, before closing the inode. */
326 inode_allow_write (struct inode *inode)
328 ASSERT (inode->deny_write_cnt > 0);
329 ASSERT (inode->deny_write_cnt <= inode->open_cnt);
330 inode->deny_write_cnt--;
333 /* Returns the length, in bytes, of INODE's data. */
335 inode_length (const struct inode *inode)
337 return inode->data.length;