X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Ffilesys%2Ffilesys.c;h=8bd39e80ff52ef82eaf1056117448373daf8b7fa;hb=993c1d9f4452e2edd851f3175dfdf317f18bdb9f;hp=c0e3938d7dcac457be1d5f54afb5b2e83311a39b;hpb=b6b1e6db07a20a0b3025c2ae62a58e80c1af841b;p=pintos-anon diff --git a/src/filesys/filesys.c b/src/filesys/filesys.c index c0e3938..8bd39e8 100644 --- a/src/filesys/filesys.c +++ b/src/filesys/filesys.c @@ -32,47 +32,53 @@ #include #include #include "filesys/file.h" -#include "filesys/filehdr.h" +#include "filesys/inode.h" #include "filesys/directory.h" #include "devices/disk.h" /* Filesystem. + For the purposes of the "user processes" assignment (project + 2), please treat all the code in the filesys directory as a + black box. No changes should be needed. For that project, a + single lock external to the filesystem code suffices. + The filesystem consists of a set of files. Each file has a - header, represented by struct filehdr, that is stored by - itself in a single sector (see filehdr.h). The header - contains the file's length in bytes and an array that lists - the sector numbers for the file's contents. + header called an `index node' or `inode', represented by + struct inode, that is stored by itself in a single sector (see + inode.h). The header contains the file's length in bytes and + an array that lists the sector numbers for the file's + contents. Two files are special. The first special file is the free - map, whose header is always stored in sector 0 + map, whose inode is always stored in sector 0 (FREE_MAP_SECTOR). The free map stores a bitmap (see lib/bitmap.h) that contains one bit for each sector on the disk. Each bit that corresponds to a sector within a file is set to true, and the other bits, which are not part of any file, are set to false. - The second special file is the root directory, whose header is + The second special file is the root directory, whose inode is always stored in sector 1 (ROOT_DIR_SECTOR). The root directory file stores an array of `struct dir_entry' (see directory.h), each of which, if it is in use, associates a - filename with the sector of the file's header. + filename with the sector of the file's inode. The filesystem implemented here has the following limitations: - No synchronization. Concurrent accesses will interfere - with one another. + with one another, so external synchronization is needed. - File size is fixed at creation time. Because the root directory is represented as a file, the number of files that may be created is also limited. - No indirect blocks. This limits maximum file size to the - number of sector pointers that fit in a single sector + number of sector pointers that fit in a single inode times the size of a sector, or 126 * 512 == 63 kB given 32-bit sizes and 512-byte sectors. - - No nested subdirectories. + - No subdirectories. - Filenames limited to 14 characters. @@ -80,27 +86,26 @@ that cannot be repaired automatically. No `fsck' tool is provided in any case. - Note: for the purposes of the "user processes" assignment - (project 2), please treat all the code in the filesys - directory as a black box. No changes should be needed. For - that project, a single lock external to the filesystem code - suffices. */ + However one important feature is included: + + - Unix-like semantics for filesys_remove() are implemented. + That is, if a file is open when it is removed, its blocks + are not deallocated and it may still be accessed by the + threads that have it open until the last one closes it. */ -/* File header sectors for system files. */ -#define FREE_MAP_SECTOR 0 /* Free map file header sector. */ -#define ROOT_DIR_SECTOR 1 /* Root directory file header sector. */ +/* Sectors of system file inodes. */ +#define FREE_MAP_SECTOR 0 /* Free map file inode sector. */ +#define ROOT_DIR_SECTOR 1 /* Root directory file inode sector. */ /* Root directory. */ #define NUM_DIR_ENTRIES 10 /* Maximum number of directory entries. */ -#define ROOT_DIR_FILE_SIZE /* Root directory file size in bytes. */ \ - (sizeof (struct dir_entry) * NUM_DIR_ENTRIES) /* The disk that contains the filesystem. */ struct disk *filesys_disk; /* The free map and root directory files. These files are opened by filesys_init() and never closed. */ -static struct file free_map_file, root_dir_file; +struct file *free_map_file, *root_dir_file; static void do_format (void); @@ -109,6 +114,8 @@ static void do_format (void); void filesys_init (bool format) { + inode_init (); + filesys_disk = disk_get (0, 1); if (filesys_disk == NULL) PANIC ("hd0:1 (hdb) not present, filesystem initialization failed"); @@ -116,9 +123,11 @@ filesys_init (bool format) if (format) do_format (); - if (!file_open (&free_map_file, FREE_MAP_SECTOR)) + free_map_file = file_open (FREE_MAP_SECTOR); + if (free_map_file == NULL) PANIC ("can't open free map file"); - if (!file_open (&root_dir_file, ROOT_DIR_SECTOR)) + root_dir_file = file_open (ROOT_DIR_SECTOR); + if (root_dir_file == NULL) PANIC ("can't open root dir file"); } @@ -129,49 +138,50 @@ filesys_init (bool format) bool filesys_create (const char *name, off_t initial_size) { - struct dir dir; - struct bitmap free_map; - disk_sector_t hdr_sector; - struct filehdr *filehdr; + struct dir *dir = NULL; + struct bitmap *free_map = NULL; + struct inode *inode = NULL; + disk_sector_t inode_sector; bool success = false; /* Read the root directory. */ - if (!dir_init (&dir, NUM_DIR_ENTRIES)) - return false; - dir_read (&dir, &root_dir_file); - if (dir_lookup (&dir, name, NULL)) - goto exit1; - - /* Allocate a block for the file header. */ - if (!bitmap_init (&free_map, disk_size (filesys_disk))) - goto exit1; - bitmap_read (&free_map, &free_map_file); - hdr_sector = bitmap_find_and_set (&free_map); - if (hdr_sector == BITMAP_ERROR) - goto exit2; + dir = dir_create (NUM_DIR_ENTRIES); + if (dir == NULL) + goto done; + dir_read (dir, root_dir_file); + if (dir_lookup (dir, name, NULL)) + goto done; + + /* Allocate a block for the inode. */ + free_map = bitmap_create (disk_size (filesys_disk)); + if (free_map == NULL) + goto done; + bitmap_read (free_map, free_map_file); + inode_sector = bitmap_find_and_set (free_map); + if (inode_sector == BITMAP_ERROR) + goto done; /* Add the file to the directory. */ - if (!dir_add (&dir, name, hdr_sector)) - goto exit2; + if (!dir_add (dir, name, inode_sector)) + goto done; /* Allocate space for the file. */ - filehdr = filehdr_allocate (&free_map, initial_size); - if (filehdr == NULL) - goto exit2; + inode = inode_create (free_map, inode_sector, initial_size); + if (inode == NULL) + goto done; /* Write everything back. */ - filehdr_write (filehdr, hdr_sector); - dir_write (&dir, &root_dir_file); - bitmap_write (&free_map, &free_map_file); + inode_commit (inode); + dir_write (dir, root_dir_file); + bitmap_write (free_map, free_map_file); success = true; /* Clean up. */ - filehdr_destroy (filehdr); - exit2: - bitmap_destroy (&free_map); - exit1: - dir_destroy (&dir); + done: + inode_close (inode); + bitmap_destroy (free_map); + dir_destroy (dir); return success; } @@ -181,21 +191,25 @@ filesys_create (const char *name, off_t initial_size) Returns true if successful, false on failure. Fails if no file named NAME exists, or if an internal memory allocation fails. */ -bool -filesys_open (const char *name, struct file *file) +struct file * +filesys_open (const char *name) { - struct dir dir; - disk_sector_t hdr_sector; - bool success = false; + struct dir *dir = NULL; + struct file *file = NULL; + disk_sector_t inode_sector; - if (!dir_init (&dir, NUM_DIR_ENTRIES)) - return false; - dir_read (&dir, &root_dir_file); - if (dir_lookup (&dir, name, &hdr_sector)) - success = file_open (file, hdr_sector); - - dir_destroy (&dir); - return success; + dir = dir_create (NUM_DIR_ENTRIES); + if (dir == NULL) + goto done; + + dir_read (dir, root_dir_file); + if (dir_lookup (dir, name, &inode_sector)) + file = file_open (inode_sector); + + done: + dir_destroy (dir); + + return file; } /* Deletes the file named NAME. @@ -205,46 +219,36 @@ filesys_open (const char *name, struct file *file) bool filesys_remove (const char *name) { - struct dir dir; - disk_sector_t hdr_sector; - struct filehdr *filehdr; - struct bitmap free_map; + struct dir *dir = NULL; + struct inode *inode; + disk_sector_t inode_sector; bool success = false; /* Read the root directory. */ - if (!dir_init (&dir, NUM_DIR_ENTRIES)) - return false; - dir_read (&dir, &root_dir_file); - if (!dir_lookup (&dir, name, &hdr_sector)) - goto exit1; - - /* Read the file header. */ - filehdr = filehdr_read (hdr_sector); - if (filehdr == NULL) - goto exit1; - - /* Allocate a block for the file header. */ - if (!bitmap_init (&free_map, disk_size (filesys_disk))) - goto exit2; - bitmap_read (&free_map, &free_map_file); - - /* Deallocate. */ - filehdr_deallocate (filehdr, &free_map); - bitmap_reset (&free_map, hdr_sector); - dir_remove (&dir, name); - - /* Write everything back. */ - bitmap_write (&free_map, &free_map_file); - dir_write (&dir, &root_dir_file); + dir = dir_create (NUM_DIR_ENTRIES); + if (dir == NULL) + goto done; + dir_read (dir, root_dir_file); + if (!dir_lookup (dir, name, &inode_sector)) + goto done; + + /* Open the inode and delete it it. */ + inode = inode_open (inode_sector); + if (inode == NULL) + goto done; + inode_remove (inode); + inode_close (inode); + + /* Remove file from root directory and write directory back to + disk. */ + dir_remove (dir, name); + dir_write (dir, root_dir_file); success = true; /* Clean up. */ - bitmap_destroy (&free_map); - exit2: - filehdr_destroy (filehdr); - exit1: - dir_destroy (&dir); + done: + dir_destroy (dir); return success; } @@ -256,13 +260,12 @@ filesys_remove (const char *name) bool filesys_list (void) { - struct dir dir; - - if (!dir_init (&dir, NUM_DIR_ENTRIES)) + struct dir *dir = dir_create (NUM_DIR_ENTRIES); + if (dir == NULL) return false; - dir_read (&dir, &root_dir_file); - dir_list (&dir); - dir_destroy (&dir); + dir_read (dir, root_dir_file); + dir_list (dir); + dir_destroy (dir); return true; } @@ -274,22 +277,24 @@ filesys_list (void) bool filesys_dump (void) { - struct bitmap free_map; - struct dir dir; + struct bitmap *free_map; + struct dir *dir; printf ("Free map:\n"); - if (!bitmap_init (&free_map, disk_size (filesys_disk))) + free_map = bitmap_create (disk_size (filesys_disk)); + if (free_map == NULL) return false; - bitmap_read (&free_map, &free_map_file); - bitmap_dump (&free_map); - bitmap_destroy (&free_map); + bitmap_read (free_map, free_map_file); + bitmap_dump (free_map); + bitmap_destroy (free_map); printf ("\n"); - if (!dir_init (&dir, NUM_DIR_ENTRIES)) + dir = dir_create (NUM_DIR_ENTRIES); + if (dir == NULL) return false; - dir_read (&dir, &root_dir_file); - dir_dump (&dir); - dir_destroy (&dir); + dir_read (dir, root_dir_file); + dir_dump (dir); + dir_destroy (dir); return true; } @@ -304,25 +309,45 @@ void filesys_self_test (void) { static const char s[] = "This is a test string."; - struct file file; + static const char zeros[sizeof s] = {0}; + struct file *file; char s2[sizeof s]; - - MUST_SUCCEED (filesys_create ("foo", sizeof s)); - MUST_SUCCEED (filesys_open ("foo", &file)); - MUST_SUCCEED (file_write (&file, s, sizeof s) == sizeof s); - MUST_SUCCEED (file_tell (&file) == sizeof s); - MUST_SUCCEED (file_length (&file) == sizeof s); - file_close (&file); - - MUST_SUCCEED (filesys_open ("foo", &file)); - MUST_SUCCEED (file_read (&file, s2, sizeof s2) == sizeof s2); - MUST_SUCCEED (memcmp (s, s2, sizeof s) == 0); - MUST_SUCCEED (file_tell (&file) == sizeof s2); - MUST_SUCCEED (file_length (&file) == sizeof s2); - file_close (&file); - - MUST_SUCCEED (filesys_remove ("foo")); - + int i; + + filesys_remove ("foo"); + for (i = 0; i < 2; i++) + { + /* Create file and check that it contains zeros + throughout the created length. */ + MUST_SUCCEED (filesys_create ("foo", sizeof s)); + MUST_SUCCEED ((file = filesys_open ("foo")) != NULL); + MUST_SUCCEED (file_read (file, s2, sizeof s2) == sizeof s2); + MUST_SUCCEED (memcmp (s2, zeros, sizeof s) == 0); + MUST_SUCCEED (file_tell (file) == sizeof s); + MUST_SUCCEED (file_length (file) == sizeof s); + file_close (file); + + /* Reopen file and write to it. */ + MUST_SUCCEED ((file = filesys_open ("foo")) != NULL); + MUST_SUCCEED (file_write (file, s, sizeof s) == sizeof s); + MUST_SUCCEED (file_tell (file) == sizeof s); + MUST_SUCCEED (file_length (file) == sizeof s); + file_close (file); + + /* Reopen file and verify that it reads back correctly. + Delete file while open to check proper semantics. */ + MUST_SUCCEED ((file = filesys_open ("foo")) != NULL); + MUST_SUCCEED (filesys_remove ("foo")); + MUST_SUCCEED (file_read (file, s2, sizeof s) == sizeof s); + MUST_SUCCEED (memcmp (s, s2, sizeof s) == 0); + MUST_SUCCEED (file_tell (file) == sizeof s); + MUST_SUCCEED (file_length (file) == sizeof s); + file_close (file); + + /* Make sure file is deleted. */ + MUST_SUCCEED ((file = filesys_open ("foo")) == NULL); + } + printf ("filesys: self test ok\n"); } @@ -330,51 +355,57 @@ filesys_self_test (void) static void do_format (void) { - struct bitmap free_map; - struct filehdr *map_hdr, *dir_hdr; - struct dir dir; + struct bitmap *free_map; + struct inode *map_inode, *dir_inode; + struct dir *dir; printf ("Formatting filesystem..."); /* Create the initial bitmap and reserve sectors for the - free map and root directory file headers. */ - if (!bitmap_init (&free_map, disk_size (filesys_disk))) + free map and root directory inodes. */ + free_map = bitmap_create (disk_size (filesys_disk)); + if (free_map == NULL) PANIC ("bitmap creation failed--disk is too large"); - bitmap_mark (&free_map, FREE_MAP_SECTOR); - bitmap_mark (&free_map, ROOT_DIR_SECTOR); + bitmap_mark (free_map, FREE_MAP_SECTOR); + bitmap_mark (free_map, ROOT_DIR_SECTOR); /* Allocate data sector(s) for the free map file - and write its file header to disk. */ - map_hdr = filehdr_allocate (&free_map, bitmap_file_size (&free_map)); - if (map_hdr == NULL) + and write its inode to disk. */ + map_inode = inode_create (free_map, FREE_MAP_SECTOR, + bitmap_file_size (free_map)); + if (map_inode == NULL) PANIC ("free map creation failed--disk is too large"); - filehdr_write (map_hdr, FREE_MAP_SECTOR); - filehdr_destroy (map_hdr); + inode_commit (map_inode); + inode_close (map_inode); /* Allocate data sector(s) for the root directory file - and write its file header to disk. */ - dir_hdr = filehdr_allocate (&free_map, ROOT_DIR_FILE_SIZE); - if (dir_hdr == NULL) + and write its inodes to disk. */ + dir_inode = inode_create (free_map, ROOT_DIR_SECTOR, + dir_size (NUM_DIR_ENTRIES)); + if (dir_inode == NULL) PANIC ("root directory creation failed"); - filehdr_write (dir_hdr, ROOT_DIR_SECTOR); - filehdr_destroy (dir_hdr); + inode_commit (dir_inode); + inode_close (dir_inode); /* Write out the free map now that we have space reserved for it. */ - if (!file_open (&free_map_file, FREE_MAP_SECTOR)) + free_map_file = file_open (FREE_MAP_SECTOR); + if (free_map_file == NULL) PANIC ("can't open free map file"); - bitmap_write (&free_map, &free_map_file); - bitmap_destroy (&free_map); - file_close (&free_map_file); + bitmap_write (free_map, free_map_file); + bitmap_destroy (free_map); + file_close (free_map_file); /* Write out the root directory in the same way. */ - if (!file_open (&root_dir_file, ROOT_DIR_SECTOR)) + root_dir_file = file_open (ROOT_DIR_SECTOR); + if (root_dir_file == NULL) PANIC ("can't open root directory"); - if (!dir_init (&dir, NUM_DIR_ENTRIES)) + dir = dir_create (NUM_DIR_ENTRIES); + if (dir == NULL) PANIC ("can't initialize root directory"); - dir_write (&dir, &root_dir_file); - dir_destroy (&dir); - file_close (&free_map_file); + dir_write (dir, root_dir_file); + dir_destroy (dir); + file_close (root_dir_file); printf ("done.\n"); }