Update spacing.
[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   ASSERT (sizeof *disk_inode == DISK_SECTOR_SIZE);
80
81   disk_inode = calloc (1, sizeof *disk_inode);
82   if (disk_inode != NULL)
83     {
84       size_t sectors = bytes_to_sectors (length);
85       disk_inode->length = length;
86       disk_inode->magic = INODE_MAGIC;
87       if (free_map_allocate (sectors, &disk_inode->start))
88         {
89           disk_write (filesys_disk, sector, disk_inode);
90           if (sectors > 0) 
91             {
92               static char zeros[DISK_SECTOR_SIZE];
93               size_t i;
94               
95               for (i = 0; i < sectors; i++) 
96                 disk_write (filesys_disk, disk_inode->start + i, zeros); 
97             }
98           success = true; 
99         } 
100       free (disk_inode);
101     }
102   return success;
103 }
104
105 /* Reads an inode from SECTOR
106    and returns a `struct inode' that contains it.
107    Returns a null pointer if memory allocation fails. */
108 struct inode *
109 inode_open (disk_sector_t sector) 
110 {
111   struct list_elem *e;
112   struct inode *inode;
113
114   /* Check whether this inode is already open. */
115   for (e = list_begin (&open_inodes); e != list_end (&open_inodes);
116        e = list_next (e)) 
117     {
118       inode = list_entry (e, struct inode, elem);
119       if (inode->sector == sector) 
120         {
121           inode_reopen (inode);
122           return inode; 
123         }
124     }
125
126   /* Allocate memory. */
127   inode = malloc (sizeof *inode);
128   if (inode == NULL)
129     return NULL;
130
131   /* Initialize. */
132   list_push_front (&open_inodes, &inode->elem);
133   inode->sector = sector;
134   inode->open_cnt = 1;
135   inode->deny_write_cnt = 0;
136   inode->removed = false;
137   disk_read (filesys_disk, inode->sector, &inode->data);
138   return inode;
139 }
140
141 /* Reopens and returns INODE. */
142 struct inode *
143 inode_reopen (struct inode *inode) 
144 {
145   if (inode != NULL) 
146     inode->open_cnt++;
147   return inode;
148 }
149
150 /* Closes INODE and writes it to disk.
151    If this was the last reference to INODE, frees its memory.
152    If INODE was also a removed inode, frees its blocks. */
153 void
154 inode_close (struct inode *inode) 
155 {
156   /* Ignore null pointer. */
157   if (inode == NULL)
158     return;
159
160   /* Release resources if this was the last opener. */
161   if (--inode->open_cnt == 0)
162     {
163       /* Remove from inode list and release lock. */
164       list_remove (&inode->elem);
165  
166       /* Deallocate blocks if removed. */
167       if (inode->removed) 
168         {
169           free_map_release (inode->sector, 1);
170           free_map_release (inode->data.start,
171                             bytes_to_sectors (inode->data.length)); 
172         }
173
174       free (inode); 
175     }
176 }
177
178 /* Marks INODE to be deleted when it is closed by the last caller who
179    has it open. */
180 void
181 inode_remove (struct inode *inode) 
182 {
183   ASSERT (inode != NULL);
184   inode->removed = true;
185 }
186
187 /* Reads SIZE bytes from INODE into BUFFER, starting at position OFFSET.
188    Returns the number of bytes actually read, which may be less
189    than SIZE if an error occurs or end of file is reached. */
190 off_t
191 inode_read_at (struct inode *inode, void *buffer_, off_t size, off_t offset) 
192 {
193   uint8_t *buffer = buffer_;
194   off_t bytes_read = 0;
195   uint8_t *bounce = NULL;
196
197   while (size > 0) 
198     {
199       /* Disk sector to read, starting byte offset within sector. */
200       disk_sector_t sector_idx = byte_to_sector (inode, offset);
201       int sector_ofs = offset % DISK_SECTOR_SIZE;
202
203       /* Bytes left in inode, bytes left in sector, lesser of the two. */
204       off_t inode_left = inode_length (inode) - offset;
205       int sector_left = DISK_SECTOR_SIZE - sector_ofs;
206       int min_left = inode_left < sector_left ? inode_left : sector_left;
207
208       /* Number of bytes to actually copy out of this sector. */
209       int chunk_size = size < min_left ? size : min_left;
210       if (chunk_size <= 0)
211         break;
212
213       if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
214         {
215           /* Read full sector directly into caller's buffer. */
216           disk_read (filesys_disk, sector_idx, buffer + bytes_read); 
217         }
218       else 
219         {
220           /* Read sector into bounce buffer, then partially copy
221              into caller's buffer. */
222           if (bounce == NULL) 
223             {
224               bounce = malloc (DISK_SECTOR_SIZE);
225               if (bounce == NULL)
226                 break;
227             }
228           disk_read (filesys_disk, sector_idx, bounce);
229           memcpy (buffer + bytes_read, bounce + sector_ofs, chunk_size);
230         }
231       
232       /* Advance. */
233       size -= chunk_size;
234       offset += chunk_size;
235       bytes_read += chunk_size;
236     }
237   free (bounce);
238
239   return bytes_read;
240 }
241
242 /* Writes SIZE bytes from BUFFER into INODE, starting at OFFSET.
243    Returns the number of bytes actually written, which may be
244    less than SIZE if end of file is reached or an error occurs.
245    (Normally a write at end of file would extend the inode, but
246    growth is not yet implemented.) */
247 off_t
248 inode_write_at (struct inode *inode, const void *buffer_, off_t size,
249                 off_t offset) 
250 {
251   const uint8_t *buffer = buffer_;
252   off_t bytes_written = 0;
253   uint8_t *bounce = NULL;
254
255   if (inode->deny_write_cnt)
256     return 0;
257
258   while (size > 0) 
259     {
260       /* Sector to write, starting byte offset within sector. */
261       off_t sector_idx = byte_to_sector (inode, offset);
262       int sector_ofs = offset % DISK_SECTOR_SIZE;
263
264       /* Bytes left in inode, bytes left in sector, lesser of the two. */
265       off_t inode_left = inode_length (inode) - offset;
266       int sector_left = DISK_SECTOR_SIZE - sector_ofs;
267       int min_left = inode_left < sector_left ? inode_left : sector_left;
268
269       /* Number of bytes to actually write into this sector. */
270       int chunk_size = size < min_left ? size : min_left;
271       if (chunk_size <= 0)
272         break;
273
274       if (sector_ofs == 0 && chunk_size == DISK_SECTOR_SIZE) 
275         {
276           /* Write full sector directly to disk. */
277           disk_write (filesys_disk, sector_idx, buffer + bytes_written); 
278         }
279       else 
280         {
281           /* We need a bounce buffer. */
282           if (bounce == NULL) 
283             {
284               bounce = malloc (DISK_SECTOR_SIZE);
285               if (bounce == NULL)
286                 break;
287             }
288
289           /* If the sector contains data before or after the chunk
290              we're writing, then we need to read in the sector
291              first.  Otherwise we start with a sector of all zeros. */
292           if (sector_ofs > 0 || chunk_size < sector_left) 
293             disk_read (filesys_disk, sector_idx, bounce);
294           else
295             memset (bounce, 0, DISK_SECTOR_SIZE);
296           memcpy (bounce + sector_ofs, buffer + bytes_written, chunk_size);
297           disk_write (filesys_disk, sector_idx, bounce); 
298         }
299
300       /* Advance. */
301       size -= chunk_size;
302       offset += chunk_size;
303       bytes_written += chunk_size;
304     }
305   free (bounce);
306
307   return bytes_written;
308 }
309
310 /* Disables writes to INODE.
311    May be called at most once per inode opener. */
312 void
313 inode_deny_write (struct inode *inode) 
314 {
315   inode->deny_write_cnt++;
316   ASSERT (inode->deny_write_cnt <= inode->open_cnt);
317 }
318
319 /* Re-enables writes to INODE.
320    Must be called once by each inode opener who has called
321    inode_deny_write() on the inode, before closing the inode. */
322 void
323 inode_allow_write (struct inode *inode) 
324 {
325   ASSERT (inode->deny_write_cnt > 0);
326   ASSERT (inode->deny_write_cnt <= inode->open_cnt);
327   inode->deny_write_cnt--;
328 }
329
330 /* Returns the length, in bytes, of INODE's data. */
331 off_t
332 inode_length (const struct inode *inode)
333 {
334   return inode->data.length;
335 }