X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Ffilesys%2Finode.c;h=be1df576dd1a52343a103ee8303c8ac36964c1f8;hb=07ee003af55dc3aab779e95ef2a4f095f6b65964;hp=1535c7a009253140fb0f3da5fb3a519b4c463747;hpb=3f5f7cb024e74d96e9175a0f9e59557148f9a0a4;p=pintos-anon diff --git a/src/filesys/inode.c b/src/filesys/inode.c index 1535c7a..be1df57 100644 --- a/src/filesys/inode.c +++ b/src/filesys/inode.c @@ -2,23 +2,28 @@ #include #include #include +#include #include #include "filesys/filesys.h" #include "threads/malloc.h" -/* Number of direct sector pointers in an inode. */ -#define DIRECT_CNT ((DISK_SECTOR_SIZE - sizeof (off_t) - sizeof (size_t)) \ - / sizeof (disk_sector_t)) - /* On-disk inode. - It is exactly DISK_SECTOR_SIZE bytes long. */ + Must be exactly DISK_SECTOR_SIZE bytes long. */ struct inode_disk { off_t length; /* File size in bytes. */ - size_t sector_cnt; /* File size in sectors. */ - disk_sector_t sectors[DIRECT_CNT]; /* Sectors allocated for file. */ + disk_sector_t start; /* Starting sector. */ + uint32_t unused[126]; /* Unused padding. */ }; +/* Returns the number of sectors to allocate for a file SIZE + bytes long. */ +static inline size_t +bytes_to_sectors (off_t size) +{ + return DIV_ROUND_UP (size, DISK_SECTOR_SIZE); +} + /* In-memory inode. */ struct inode { @@ -31,9 +36,9 @@ struct inode /* List of open inodes, so that opening a single inode twice returns the same `struct inode'. */ -struct list open_inodes; +static struct list open_inodes; -static struct inode *alloc_inode (disk_sector_t); +static void deallocate_inode (const struct inode *); /* Initializes the inode module. */ void @@ -42,63 +47,42 @@ inode_init (void) list_init (&open_inodes); } -/* Allocates sectors from bitmap B for the content of a file - whose size is LENGTH bytes, and returns a new `struct inode' - properly initialized for the file. - It is the caller's responsible to write the inode to disk with - inode_commit(), as well as the bitmap. - If memory or disk allocation fails, returns a null pointer, - leaving bitmap B is unchanged. */ -struct inode * -inode_create (struct bitmap *b, disk_sector_t sector, off_t length) +/* Initializes an inode for a file LENGTH bytes in size and + writes the new inode to sector SECTOR on the file system + disk. Allocates sectors for the file from FREE_MAP. + Returns true if successful. + Returns false if memory or disk allocation fails. FREE_MAP + may be modified regardless. */ +bool +inode_create (struct bitmap *free_map, disk_sector_t sector, off_t length) { - struct inode *idx; - size_t sector_cnt; + static const char zero_sector[DISK_SECTOR_SIZE]; + struct inode_disk *idx; + size_t start; + size_t i; - ASSERT (b != NULL); + ASSERT (free_map != NULL); ASSERT (length >= 0); - /* Calculate number of sectors to allocate for file data. */ - sector_cnt = (length / DISK_SECTOR_SIZE) + (length % DISK_SECTOR_SIZE > 0); - if (sector_cnt > DIRECT_CNT) - return NULL; + /* Allocate sectors. */ + start = bitmap_scan_and_flip (free_map, 0, bytes_to_sectors (length), false); + if (start == BITMAP_ERROR) + return false; - /* Allocate inode. */ - idx = alloc_inode (sector); + /* Create inode. */ + idx = calloc (sizeof *idx, 1); if (idx == NULL) - return NULL; + return false; + idx->length = length; + idx->start = start; - /* Allocate disk sectors. */ - idx->data.length = length; - while (idx->data.sector_cnt < sector_cnt) - { - size_t sector = bitmap_scan_and_flip (b, 0, 1, false); - if (sector == BITMAP_ERROR) - goto error; + /* Commit to disk. */ + disk_write (filesys_disk, sector, idx); + for (i = 0; i < bytes_to_sectors (length); i++) + disk_write (filesys_disk, idx->start + i, zero_sector); - idx->data.sectors[idx->data.sector_cnt++] = sector; - } - - /* Zero out the file contents. */ - if (sector_cnt > 0) - { - void *zero_sector; - size_t i; - - zero_sector = calloc (1, DISK_SECTOR_SIZE); - if (zero_sector == NULL) - goto error; - for (i = 0; i < sector_cnt; i++) - disk_write (filesys_disk, idx->data.sectors[i], zero_sector); - free (zero_sector); - } - - return idx; - - error: - inode_remove (idx); - inode_close (idx); - return NULL; + free (idx); + return true; } /* Reads an inode from SECTOR @@ -110,7 +94,10 @@ inode_open (disk_sector_t sector) list_elem *e; struct inode *idx; - /* Check whether this inode is already open. */ + /* Check whether this inode is already open. + (A hash table would be better, but the Pintos base code + avoids using the hash table so that users are free to modify + it at will.) */ for (e = list_begin (&open_inodes); e != list_end (&open_inodes); e = list_next (e)) { @@ -122,11 +109,17 @@ inode_open (disk_sector_t sector) } } - /* Allocate inode. */ - idx = alloc_inode (sector); + /* Allocate memory. */ + idx = calloc (1, sizeof *idx); if (idx == NULL) return NULL; + /* Initialize. */ + list_push_front (&open_inodes, &idx->elem); + idx->sector = sector; + idx->open_cnt = 1; + idx->removed = false; + /* Read from disk. */ ASSERT (sizeof idx->data == DISK_SECTOR_SIZE); disk_read (filesys_disk, sector, &idx->data); @@ -140,43 +133,39 @@ inode_open (disk_sector_t sector) void inode_close (struct inode *idx) { + /* Ignore null pointer. */ if (idx == NULL) return; + /* Release resources if this was the last opener. */ if (--idx->open_cnt == 0) { - if (idx->removed) - { - struct bitmap *free_map; - size_t i; - - free_map = bitmap_create (disk_size (filesys_disk)); - if (free_map != NULL) - { - bitmap_read (free_map, free_map_file); - - bitmap_reset (free_map, idx->sector); - for (i = 0; i < idx->data.sector_cnt; i++) - bitmap_reset (free_map, idx->data.sectors[i]); - - bitmap_write (free_map, free_map_file); - bitmap_destroy (free_map); - } - else - printf ("inode_close(): can't free blocks"); - } + /* Deallocate blocks if removed. */ + if (idx->removed) + deallocate_inode (idx); + + /* Remove from inode list and free memory. */ list_remove (&idx->elem); free (idx); } } -/* Writes IDX to disk. */ -void -inode_commit (const struct inode *idx) +/* Deallocates the blocks allocated for IDX. */ +static void +deallocate_inode (const struct inode *idx) { - ASSERT (idx != NULL); - ASSERT (sizeof idx->data == DISK_SECTOR_SIZE); - disk_write (filesys_disk, idx->sector, &idx->data); + struct bitmap *free_map = bitmap_create (disk_size (filesys_disk)); + if (free_map != NULL) + { + bitmap_read (free_map, free_map_file); + bitmap_reset (free_map, idx->sector); + bitmap_set_multiple (free_map, idx->data.start, + bytes_to_sectors (idx->data.length), false); + bitmap_write (free_map, free_map_file); + bitmap_destroy (free_map); + } + else + printf ("inode_close(): can't free blocks"); } /* Marks IDX to be deleted when it is closed by the last caller who @@ -195,12 +184,9 @@ inode_remove (struct inode *idx) disk_sector_t inode_byte_to_sector (const struct inode *idx, off_t pos) { - size_t i; - ASSERT (idx != NULL); - - i = pos / DISK_SECTOR_SIZE; - return i < idx->data.sector_cnt ? idx->data.sectors[i] : (disk_sector_t) -1; + ASSERT (pos < idx->data.length); + return idx->data.start + pos / DISK_SECTOR_SIZE; } /* Returns the length, in bytes, of the file with inode IDX. */ @@ -215,36 +201,10 @@ inode_length (const struct inode *idx) void inode_print (const struct inode *idx) { - size_t i; - - printf ("Inode %"PRDSNu": %"PRDSNu" bytes, %zu sectors (", - idx->sector, idx->data.length, idx->data.sector_cnt); - - /* This loop could be unsafe for large idx->data.sector_cnt, can - you see why? */ - for (i = 0; i < idx->data.sector_cnt; i++) - { - if (i != 0) - printf (", "); - printf ("%"PRDSNu, idx->data.sectors[i]); - } - printf (")\n"); -} - -/* Returns a newly allocated and initialized inode. */ -static struct inode * -alloc_inode (disk_sector_t sector) -{ - /* Allocate memory. */ - struct inode *idx = calloc (1, sizeof *idx); - if (idx == NULL) - return NULL; - - /* Initialize. */ - list_push_front (&open_inodes, &idx->elem); - idx->sector = sector; - idx->open_cnt = 1; - idx->removed = false; - - return idx; + ASSERT (idx != NULL); + printf ("Inode %"PRDSNu": %"PRDSNu" bytes, " + "%zu sectors starting at %"PRDSNu"\n", + idx->sector, idx->data.length, + (size_t) DIV_ROUND_UP (idx->data.length, DISK_SECTOR_SIZE), + idx->data.start); }