Comment.
[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 /* 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. */
156 void
157 inode_close (struct inode *inode) 
158 {
159   /* Ignore null pointer. */
160   if (inode == NULL)
161     return;
162
163   /* Release resources if this was the last opener. */
164   if (--inode->open_cnt == 0)
165     {
166       /* Remove from inode list and release lock. */
167       list_remove (&inode->elem);
168  
169       /* Deallocate blocks if removed. */
170       if (inode->removed) 
171         {
172           free_map_release (inode->sector, 1);
173           free_map_release (inode->data.start,
174                             bytes_to_sectors (inode->data.length)); 
175         }
176
177       free (inode); 
178     }
179 }
180
181 /* Marks INODE to be deleted when it is closed by the last caller who
182    has it open. */
183 void
184 inode_remove (struct inode *inode) 
185 {
186   ASSERT (inode != NULL);
187   inode->removed = true;
188 }
189
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. */
193 off_t
194 inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset) 
195 {
196   uint8_t *buffer = buffer_;
197   off_t bytes_read = 0;
198   uint8_t *bounce = NULL;
199
200   while (size > 0) 
201     {
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;
205
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;
210
211       /* Number of bytes to actually copy out of this sector. */
212       int chunk_size = size < min_left ? size : min_left;
213       if (chunk_size <= 0)
214         break;
215
216       if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
217         {
218           /* Read full sector directly into caller's buffer. */
219           disk_read (filesys_disk, sector_idx, buffer + bytes_read); 
220         }
221       else 
222         {
223           /* Read sector into bounce buffer, then partially copy
224              into caller's buffer. */
225           if (bounce == NULL) 
226             {
227               bounce = malloc (DISK_SECTOR_SIZE);
228               if (bounce == NULL)
229                 break;
230             }
231           disk_read (filesys_disk, sector_idx, bounce);
232           memcpy (buffer + bytes_read, bounce + sector_ofs, chunk_size);
233         }
234       
235       /* Advance. */
236       size -= chunk_size;
237       offset += chunk_size;
238       bytes_read += chunk_size;
239     }
240   free (bounce);
241
242   return bytes_read;
243 }
244
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.) */
250 off_t
251 inode_write_at (struct inode *inode, const void *buffer_, off_t size,
252                 off_t offset) 
253 {
254   const uint8_t *buffer = buffer_;
255   off_t bytes_written = 0;
256   uint8_t *bounce = NULL;
257
258   if (inode->deny_write_cnt)
259     return 0;
260
261   while (size > 0) 
262     {
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;
266
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;
271
272       /* Number of bytes to actually write into this sector. */
273       int chunk_size = size < min_left ? size : min_left;
274       if (chunk_size <= 0)
275         break;
276
277       if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
278         {
279           /* Write full sector directly to disk. */
280           disk_write (filesys_disk, sector_idx, buffer + bytes_written); 
281         }
282       else 
283         {
284           /* We need a bounce buffer. */
285           if (bounce == NULL) 
286             {
287               bounce = malloc (DISK_SECTOR_SIZE);
288               if (bounce == NULL)
289                 break;
290             }
291
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);
297           else
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); 
301         }
302
303       /* Advance. */
304       size -= chunk_size;
305       offset += chunk_size;
306       bytes_written += chunk_size;
307     }
308   free (bounce);
309
310   return bytes_written;
311 }
312
313 /* Disables writes to INODE.
314    May be called at most once per inode opener. */
315 void
316 inode_deny_write (struct inode *inode) 
317 {
318   inode->deny_write_cnt++;
319   ASSERT (inode->deny_write_cnt <= inode->open_cnt);
320 }
321
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. */
325 void
326 inode_allow_write (struct inode *inode) 
327 {
328   ASSERT (inode->deny_write_cnt > 0);
329   ASSERT (inode->deny_write_cnt <= inode->open_cnt);
330   inode->deny_write_cnt--;
331 }
332
333 /* Returns the length, in bytes, of INODE's data. */
334 off_t
335 inode_length (const struct inode *inode)
336 {
337   return inode->data.length;
338 }