1 #include "filesys/inode.h"
6 #include "filesys/filesys.h"
7 #include "threads/malloc.h"
9 /* Number of direct sector pointers in an inode. */
10 #define DIRECT_CNT ((DISK_SECTOR_SIZE - sizeof (off_t) - sizeof (size_t)) \
11 / sizeof (disk_sector_t))
14 It is exactly DISK_SECTOR_SIZE bytes long. */
17 off_t length; /* File size in bytes. */
18 size_t sector_cnt; /* File size in sectors. */
19 disk_sector_t sectors[DIRECT_CNT]; /* Sectors allocated for file. */
22 /* In-memory inode. */
25 list_elem elem; /* Element in inode list. */
26 disk_sector_t sector; /* Sector number of disk location. */
27 int open_cnt; /* Number of openers. */
28 bool removed; /* True if deleted, false otherwise. */
29 struct inode_disk data; /* On-disk data. */
32 /* List of open inodes, so that opening a single inode twice
33 returns the same `struct inode'. */
34 struct list open_inodes;
36 static struct inode *alloc_inode (disk_sector_t);
38 /* Initializes the inode module. */
42 list_init (&open_inodes);
45 /* Allocates sectors from bitmap B for the content of a file
46 whose size is LENGTH bytes, and returns a new `struct inode'
47 properly initialized for the file.
48 It is the caller's responsible to write the inode to disk with
49 inode_commit(), as well as the bitmap.
50 If memory or disk allocation fails, returns a null pointer,
51 leaving bitmap B is unchanged. */
53 inode_create (struct bitmap *b, disk_sector_t sector, off_t length)
61 /* Calculate number of sectors to allocate for file data. */
62 sector_cnt = (length / DISK_SECTOR_SIZE) + (length % DISK_SECTOR_SIZE > 0);
63 if (sector_cnt > DIRECT_CNT)
67 idx = alloc_inode (sector);
71 /* Allocate disk sectors. */
72 idx->data.length = length;
73 while (idx->data.sector_cnt < sector_cnt)
75 size_t sector = bitmap_scan_and_flip (b, 0, 1, false);
76 if (sector == BITMAP_ERROR)
79 idx->data.sectors[idx->data.sector_cnt++] = sector;
82 /* Zero out the file contents. */
88 zero_sector = calloc (1, DISK_SECTOR_SIZE);
89 if (zero_sector == NULL)
91 for (i = 0; i < sector_cnt; i++)
92 disk_write (filesys_disk, idx->data.sectors[i], zero_sector);
104 /* Reads an inode from SECTOR
105 and returns a `struct inode' that contains it.
106 Returns a null pointer if memory allocation fails. */
108 inode_open (disk_sector_t sector)
113 /* Check whether this inode is already open.
114 (A hash table would be better, but the Pintos base code
115 avoids using the hash table so that users are free to modify
117 for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
120 idx = list_entry (e, struct inode, elem);
121 if (idx->sector == sector)
128 /* Allocate inode. */
129 idx = alloc_inode (sector);
133 /* Read from disk. */
134 ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
135 disk_read (filesys_disk, sector, &idx->data);
140 /* Closes inode IDX and writes it to disk.
141 If this was the last reference to IDX, frees its memory.
142 If IDX was also a removed inode, frees its blocks. */
144 inode_close (struct inode *idx)
149 if (--idx->open_cnt == 0)
153 struct bitmap *free_map;
156 free_map = bitmap_create (disk_size (filesys_disk));
157 if (free_map != NULL)
159 bitmap_read (free_map, free_map_file);
161 bitmap_reset (free_map, idx->sector);
162 for (i = 0; i < idx->data.sector_cnt; i++)
163 bitmap_reset (free_map, idx->data.sectors[i]);
165 bitmap_write (free_map, free_map_file);
166 bitmap_destroy (free_map);
169 printf ("inode_close(): can't free blocks");
171 list_remove (&idx->elem);
176 /* Writes IDX to disk. */
178 inode_commit (const struct inode *idx)
180 ASSERT (idx != NULL);
181 ASSERT (sizeof idx->data == DISK_SECTOR_SIZE);
182 disk_write (filesys_disk, idx->sector, &idx->data);
185 /* Marks IDX to be deleted when it is closed by the last caller who
188 inode_remove (struct inode *idx)
190 ASSERT (idx != NULL);
194 /* Returns the disk sector that contains byte offset POS within
195 the file with inode IDX.
196 Returns -1 if IDX does not contain data for a byte at offset
199 inode_byte_to_sector (const struct inode *idx, off_t pos)
203 ASSERT (idx != NULL);
205 i = pos / DISK_SECTOR_SIZE;
206 return i < idx->data.sector_cnt ? idx->data.sectors[i] : (disk_sector_t) -1;
209 /* Returns the length, in bytes, of the file with inode IDX. */
211 inode_length (const struct inode *idx)
213 ASSERT (idx != NULL);
214 return idx->data.length;
217 /* Prints a representation of IDX to the system console. */
219 inode_print (const struct inode *idx)
223 printf ("Inode %"PRDSNu": %"PRDSNu" bytes, %zu sectors (",
224 idx->sector, idx->data.length, idx->data.sector_cnt);
226 /* This loop could be unsafe for large idx->data.sector_cnt, can
228 for (i = 0; i < idx->data.sector_cnt; i++)
232 printf ("%"PRDSNu, idx->data.sectors[i]);
237 /* Returns a newly allocated and initialized inode. */
238 static struct inode *
239 alloc_inode (disk_sector_t sector)
241 /* Allocate memory. */
242 struct inode *idx = calloc (1, sizeof *idx);
247 list_push_front (&open_inodes, &idx->elem);
248 idx->sector = sector;
250 idx->removed = false;