d890ed8d3c7f0375dc9f3a6a1178254d2c2db011
[pintos-anon] / src / filesys / inode.c
1 #include "filesys/inode.h"
2 #include <list.h>
3 #include <debug.h>
4 #include <round.h>
5 #include <string.h>
6 #include "filesys/filesys.h"
7 #include "filesys/free-map.h"
8 #include "threads/malloc.h"
9
10 /* Identifies an inode. */
11 #define INODE_MAGIC 0x494e4f44
12
13 /* On-disk inode.
14    Must be exactly DISK_SECTOR_SIZE bytes long. */
15 struct inode_disk
16   {
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. */
21   };
22
23 /* Returns the number of sectors to allocate for an inode SIZE
24    bytes long. */
25 static inline size_t
26 bytes_to_sectors (off_t size)
27 {
28   return DIV_ROUND_UP (size, DISK_SECTOR_SIZE);
29 }
30
31 /* In-memory inode. */
32 struct inode 
33   {
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. */
40   };
41
42 /* Returns the disk sector that contains byte offset POS within
43    INODE.
44    Returns -1 if INODE does not contain data for a byte at offset
45    POS. */
46 static disk_sector_t
47 byte_to_sector (const struct inode *inode, off_t pos) 
48 {
49   ASSERT (inode != NULL);
50   if (pos < inode->data.length)
51     return inode->data.start + pos / DISK_SECTOR_SIZE;
52   else
53     return -1;
54 }
55
56 /* List of open inodes, so that opening a single inode twice
57    returns the same `struct inode'. */
58 static struct list open_inodes;
59
60 /* Initializes the inode module. */
61 void
62 inode_init (void) 
63 {
64   list_init (&open_inodes);
65 }
66
67 /* Initializes an inode with LENGTH bytes of data and
68    writes the new inode to sector SECTOR on the file system
69    disk.
70    Returns true if successful.
71    Returns false if memory or disk allocation fails. */
72 bool
73 inode_create (disk_sector_t sector, off_t length)
74 {
75   struct inode_disk *disk_inode = NULL;
76   bool success = false;
77
78   ASSERT (length >= 0);
79
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);
83
84   disk_inode = calloc (1, sizeof *disk_inode);
85   if (disk_inode != NULL)
86     {
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))
91         {
92           disk_write (filesys_disk, sector, disk_inode);
93           if (sectors > 0) 
94             {
95               static char zeros[DISK_SECTOR_SIZE];
96               size_t i;
97               
98               for (i = 0; i < sectors; i++) 
99                 disk_write (filesys_disk, disk_inode->start + i, zeros); 
100             }
101           success = true; 
102         } 
103       free (disk_inode);
104     }
105   return success;
106 }
107
108 /* Reads an inode from SECTOR
109    and returns a `struct inode' that contains it.
110    Returns a null pointer if memory allocation fails. */
111 struct inode *
112 inode_open (disk_sector_t sector) 
113 {
114   struct list_elem *e;
115   struct inode *inode;
116
117   /* Check whether this inode is already open. */
118   for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
119        e = list_next (e)) 
120     {
121       inode = list_entry (e, struct inode, elem);
122       if (inode->sector == sector) 
123         {
124           inode_reopen (inode);
125           return inode; 
126         }
127     }
128
129   /* Allocate memory. */
130   inode = malloc (sizeof *inode);
131   if (inode == NULL)
132     return NULL;
133
134   /* Initialize. */
135   list_push_front (&open_inodes, &inode->elem);
136   inode->sector = sector;
137   inode->open_cnt = 1;
138   inode->deny_write_cnt = 0;
139   inode->removed = false;
140   disk_read (filesys_disk, inode->sector, &inode->data);
141   return inode;
142 }
143
144 /* Reopens and returns INODE. */
145 struct inode *
146 inode_reopen (struct inode *inode)
147 {
148   if (inode != NULL)
149     inode->open_cnt++;
150   return inode;
151 }
152
153 /* Returns INODE's inode number. */
154 disk_sector_t
155 inode_get_inumber (const struct inode *inode)
156 {
157   return inode->sector;
158 }
159
160 /* Closes INODE and writes it to disk.
161    If this was the last reference to INODE, frees its memory.
162    If INODE was also a removed inode, frees its blocks. */
163 void
164 inode_close (struct inode *inode) 
165 {
166   /* Ignore null pointer. */
167   if (inode == NULL)
168     return;
169
170   /* Release resources if this was the last opener. */
171   if (--inode->open_cnt == 0)
172     {
173       /* Remove from inode list and release lock. */
174       list_remove (&inode->elem);
175  
176       /* Deallocate blocks if removed. */
177       if (inode->removed) 
178         {
179           free_map_release (inode->sector, 1);
180           free_map_release (inode->data.start,
181                             bytes_to_sectors (inode->data.length)); 
182         }
183
184       free (inode); 
185     }
186 }
187
188 /* Marks INODE to be deleted when it is closed by the last caller who
189    has it open. */
190 void
191 inode_remove (struct inode *inode) 
192 {
193   ASSERT (inode != NULL);
194   inode->removed = true;
195 }
196
197 /* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
198    Returns the number of bytes actually read, which may be less
199    than SIZE if an error occurs or end of file is reached. */
200 off_t
201 inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset) 
202 {
203   uint8_t *buffer = buffer_;
204   off_t bytes_read = 0;
205   uint8_t *bounce = NULL;
206
207   while (size > 0) 
208     {
209       /* Disk sector to read, starting byte offset within sector. */
210       disk_sector_t sector_idx = byte_to_sector (inode, offset);
211       int sector_ofs = offset % DISK_SECTOR_SIZE;
212
213       /* Bytes left in inode, bytes left in sector, lesser of the two. */
214       off_t inode_left = inode_length (inode) - offset;
215       int sector_left = DISK_SECTOR_SIZE - sector_ofs;
216       int min_left = inode_left < sector_left ? inode_left : sector_left;
217
218       /* Number of bytes to actually copy out of this sector. */
219       int chunk_size = size < min_left ? size : min_left;
220       if (chunk_size <= 0)
221         break;
222
223       if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
224         {
225           /* Read full sector directly into caller's buffer. */
226           disk_read (filesys_disk, sector_idx, buffer + bytes_read); 
227         }
228       else 
229         {
230           /* Read sector into bounce buffer, then partially copy
231              into caller's buffer. */
232           if (bounce == NULL) 
233             {
234               bounce = malloc (DISK_SECTOR_SIZE);
235               if (bounce == NULL)
236                 break;
237             }
238           disk_read (filesys_disk, sector_idx, bounce);
239           memcpy (buffer + bytes_read, bounce + sector_ofs, chunk_size);
240         }
241       
242       /* Advance. */
243       size -= chunk_size;
244       offset += chunk_size;
245       bytes_read += chunk_size;
246     }
247   free (bounce);
248
249   return bytes_read;
250 }
251
252 /* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
253    Returns the number of bytes actually written, which may be
254    less than SIZE if end of file is reached or an error occurs.
255    (Normally a write at end of file would extend the inode, but
256    growth is not yet implemented.) */
257 off_t
258 inode_write_at (struct inode *inode, const void *buffer_, off_t size,
259                 off_t offset) 
260 {
261   const uint8_t *buffer = buffer_;
262   off_t bytes_written = 0;
263   uint8_t *bounce = NULL;
264
265   if (inode->deny_write_cnt)
266     return 0;
267
268   while (size > 0) 
269     {
270       /* Sector to write, starting byte offset within sector. */
271       disk_sector_t sector_idx = byte_to_sector (inode, offset);
272       int sector_ofs = offset % DISK_SECTOR_SIZE;
273
274       /* Bytes left in inode, bytes left in sector, lesser of the two. */
275       off_t inode_left = inode_length (inode) - offset;
276       int sector_left = DISK_SECTOR_SIZE - sector_ofs;
277       int min_left = inode_left < sector_left ? inode_left : sector_left;
278
279       /* Number of bytes to actually write into this sector. */
280       int chunk_size = size < min_left ? size : min_left;
281       if (chunk_size <= 0)
282         break;
283
284       if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
285         {
286           /* Write full sector directly to disk. */
287           disk_write (filesys_disk, sector_idx, buffer + bytes_written); 
288         }
289       else 
290         {
291           /* We need a bounce buffer. */
292           if (bounce == NULL) 
293             {
294               bounce = malloc (DISK_SECTOR_SIZE);
295               if (bounce == NULL)
296                 break;
297             }
298
299           /* If the sector contains data before or after the chunk
300              we're writing, then we need to read in the sector
301              first.  Otherwise we start with a sector of all zeros. */
302           if (sector_ofs > 0 || chunk_size < sector_left) 
303             disk_read (filesys_disk, sector_idx, bounce);
304           else
305             memset (bounce, 0, DISK_SECTOR_SIZE);
306           memcpy (bounce + sector_ofs, buffer + bytes_written, chunk_size);
307           disk_write (filesys_disk, sector_idx, bounce); 
308         }
309
310       /* Advance. */
311       size -= chunk_size;
312       offset += chunk_size;
313       bytes_written += chunk_size;
314     }
315   free (bounce);
316
317   return bytes_written;
318 }
319
320 /* Disables writes to INODE.
321    May be called at most once per inode opener. */
322 void
323 inode_deny_write (struct inode *inode) 
324 {
325   inode->deny_write_cnt++;
326   ASSERT (inode->deny_write_cnt <= inode->open_cnt);
327 }
328
329 /* Re-enables writes to INODE.
330    Must be called once by each inode opener who has called
331    inode_deny_write() on the inode, before closing the inode. */
332 void
333 inode_allow_write (struct inode *inode) 
334 {
335   ASSERT (inode->deny_write_cnt > 0);
336   ASSERT (inode->deny_write_cnt <= inode->open_cnt);
337   inode->deny_write_cnt--;
338 }
339
340 /* Returns the length, in bytes, of INODE's data. */
341 off_t
342 inode_length (const struct inode *inode)
343 {
344   return inode->data.length;
345 }