init: init nachos hw01, should pass jenkins os_group_20_hw job but fail on os_group_20_ta job

This commit is contained in:
TA
2024-09-19 18:59:13 +08:00
commit 6ad2fa368f
267 changed files with 71977 additions and 0 deletions

196
code/filesys/directory.cc Normal file
View File

@@ -0,0 +1,196 @@
// directory.cc
// Routines to manage a directory of file names.
//
// The directory is a table of fixed length entries; each
// entry represents a single file, and contains the file name,
// and the location of the file header on disk. The fixed size
// of each directory entry means that we have the restriction
// of a fixed maximum size for file names.
//
// The constructor initializes an empty directory of a certain size;
// we use ReadFrom/WriteBack to fetch the contents of the directory
// from disk, and to write back any modifications back to disk.
//
// Also, this implementation has the restriction that the size
// of the directory cannot expand. In other words, once all the
// entries in the directory are used, no more files can be created.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "utility.h"
#include "filehdr.h"
#include "directory.h"
//----------------------------------------------------------------------
// Directory::Directory
// Initialize a directory; initially, the directory is completely
// empty. If the disk is being formatted, an empty directory
// is all we need, but otherwise, we need to call FetchFrom in order
// to initialize it from disk.
//
// "size" is the number of entries in the directory
//----------------------------------------------------------------------
Directory::Directory(int size)
{
table = new DirectoryEntry[size];
tableSize = size;
for (int i = 0; i < tableSize; i++)
table[i].inUse = FALSE;
}
//----------------------------------------------------------------------
// Directory::~Directory
// De-allocate directory data structure.
//----------------------------------------------------------------------
Directory::~Directory()
{
delete [] table;
}
//----------------------------------------------------------------------
// Directory::FetchFrom
// Read the contents of the directory from disk.
//
// "file" -- file containing the directory contents
//----------------------------------------------------------------------
void
Directory::FetchFrom(OpenFile *file)
{
(void) file->ReadAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}
//----------------------------------------------------------------------
// Directory::WriteBack
// Write any modifications to the directory back to disk
//
// "file" -- file to contain the new directory contents
//----------------------------------------------------------------------
void
Directory::WriteBack(OpenFile *file)
{
(void) file->WriteAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}
//----------------------------------------------------------------------
// Directory::FindIndex
// Look up file name in directory, and return its location in the table of
// directory entries. Return -1 if the name isn't in the directory.
//
// "name" -- the file name to look up
//----------------------------------------------------------------------
int
Directory::FindIndex(char *name)
{
for (int i = 0; i < tableSize; i++)
if (table[i].inUse && !strncmp(table[i].name, name, FileNameMaxLen))
return i;
return -1; // name not in directory
}
//----------------------------------------------------------------------
// Directory::Find
// Look up file name in directory, and return the disk sector number
// where the file's header is stored. Return -1 if the name isn't
// in the directory.
//
// "name" -- the file name to look up
//----------------------------------------------------------------------
int
Directory::Find(char *name)
{
int i = FindIndex(name);
if (i != -1)
return table[i].sector;
return -1;
}
//----------------------------------------------------------------------
// Directory::Add
// Add a file into the directory. Return TRUE if successful;
// return FALSE if the file name is already in the directory, or if
// the directory is completely full, and has no more space for
// additional file names.
//
// "name" -- the name of the file being added
// "newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------
bool
Directory::Add(char *name, int newSector)
{
if (FindIndex(name) != -1)
return FALSE;
for (int i = 0; i < tableSize; i++)
if (!table[i].inUse) {
table[i].inUse = TRUE;
strncpy(table[i].name, name, FileNameMaxLen);
table[i].sector = newSector;
return TRUE;
}
return FALSE; // no space. Fix when we have extensible files.
}
//----------------------------------------------------------------------
// Directory::Remove
// Remove a file name from the directory. Return TRUE if successful;
// return FALSE if the file isn't in the directory.
//
// "name" -- the file name to be removed
//----------------------------------------------------------------------
bool
Directory::Remove(char *name)
{
int i = FindIndex(name);
if (i == -1)
return FALSE; // name not in directory
table[i].inUse = FALSE;
return TRUE;
}
//----------------------------------------------------------------------
// Directory::List
// List all the file names in the directory.
//----------------------------------------------------------------------
void
Directory::List()
{
for (int i = 0; i < tableSize; i++)
if (table[i].inUse)
printf("%s\n", table[i].name);
}
//----------------------------------------------------------------------
// Directory::Print
// List all the file names in the directory, their FileHeader locations,
// and the contents of each file. For debugging.
//----------------------------------------------------------------------
void
Directory::Print()
{
FileHeader *hdr = new FileHeader;
printf("Directory contents:\n");
for (int i = 0; i < tableSize; i++)
if (table[i].inUse) {
printf("Name: %s, Sector: %d\n", table[i].name, table[i].sector);
hdr->FetchFrom(table[i].sector);
hdr->Print();
}
printf("\n");
delete hdr;
}

83
code/filesys/directory.h Normal file
View File

@@ -0,0 +1,83 @@
// directory.h
// Data structures to manage a UNIX-like directory of file names.
//
// A directory is a table of pairs: <file name, sector #>,
// giving the name of each file in the directory, and
// where to find its file header (the data structure describing
// where to find the file's data blocks) on disk.
//
// We assume mutual exclusion is provided by the caller.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#ifndef DIRECTORY_H
#define DIRECTORY_H
#include "openfile.h"
#define FileNameMaxLen 9 // for simplicity, we assume
// file names are <= 9 characters long
// The following class defines a "directory entry", representing a file
// in the directory. Each entry gives the name of the file, and where
// the file's header is to be found on disk.
//
// Internal data structures kept public so that Directory operations can
// access them directly.
class DirectoryEntry {
public:
bool inUse; // Is this directory entry in use?
int sector; // Location on disk to find the
// FileHeader for this file
char name[FileNameMaxLen + 1]; // Text name for file, with +1 for
// the trailing '\0'
};
// The following class defines a UNIX-like "directory". Each entry in
// the directory describes a file, and where to find it on disk.
//
// The directory data structure can be stored in memory, or on disk.
// When it is on disk, it is stored as a regular Nachos file.
//
// The constructor initializes a directory structure in memory; the
// FetchFrom/WriteBack operations shuffle the directory information
// from/to disk.
class Directory {
public:
Directory(int size); // Initialize an empty directory
// with space for "size" files
~Directory(); // De-allocate the directory
void FetchFrom(OpenFile *file); // Init directory contents from disk
void WriteBack(OpenFile *file); // Write modifications to
// directory contents back to disk
int Find(char *name); // Find the sector number of the
// FileHeader for file: "name"
bool Add(char *name, int newSector); // Add a file name into the directory
bool Remove(char *name); // Remove a file from the directory
void List(); // Print the names of all the files
// in the directory
void Print(); // Verbose print of the contents
// of the directory -- all the file
// names and their contents.
private:
int tableSize; // Number of directory entries
DirectoryEntry *table; // Table of pairs:
// <file name, file header location>
int FindIndex(char *name); // Find the index into the directory
// table corresponding to "name"
};
#endif // DIRECTORY_H

156
code/filesys/filehdr.cc Normal file
View File

@@ -0,0 +1,156 @@
// filehdr.cc
// Routines for managing the disk file header (in UNIX, this
// would be called the i-node).
//
// The file header is used to locate where on disk the
// file's data is stored. We implement this as a fixed size
// table of pointers -- each entry in the table points to the
// disk sector containing that portion of the file data
// (in other words, there are no indirect or doubly indirect
// blocks). The table size is chosen so that the file header
// will be just big enough to fit in one disk sector,
//
// Unlike in a real system, we do not keep track of file permissions,
// ownership, last modification date, etc., in the file header.
//
// A file header can be initialized in two ways:
// for a new file, by modifying the in-memory data structure
// to point to the newly allocated data blocks
// for a file already on disk, by reading the file header from disk
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "filehdr.h"
#include "debug.h"
#include "synchdisk.h"
#include "main.h"
//----------------------------------------------------------------------
// FileHeader::Allocate
// Initialize a fresh file header for a newly created file.
// Allocate data blocks for the file out of the map of free disk blocks.
// Return FALSE if there are not enough free blocks to accomodate
// the new file.
//
// "freeMap" is the bit map of free disk sectors
// "fileSize" is the bit map of free disk sectors
//----------------------------------------------------------------------
bool
FileHeader::Allocate(PersistentBitmap *freeMap, int fileSize)
{
numBytes = fileSize;
numSectors = divRoundUp(fileSize, SectorSize);
if (freeMap->NumClear() < numSectors)
return FALSE; // not enough space
for (int i = 0; i < numSectors; i++) {
dataSectors[i] = freeMap->FindAndSet();
// since we checked that there was enough free space,
// we expect this to succeed
ASSERT(dataSectors[i] >= 0);
}
return TRUE;
}
//----------------------------------------------------------------------
// FileHeader::Deallocate
// De-allocate all the space allocated for data blocks for this file.
//
// "freeMap" is the bit map of free disk sectors
//----------------------------------------------------------------------
void
FileHeader::Deallocate(PersistentBitmap *freeMap)
{
for (int i = 0; i < numSectors; i++) {
ASSERT(freeMap->Test((int) dataSectors[i])); // ought to be marked!
freeMap->Clear((int) dataSectors[i]);
}
}
//----------------------------------------------------------------------
// FileHeader::FetchFrom
// Fetch contents of file header from disk.
//
// "sector" is the disk sector containing the file header
//----------------------------------------------------------------------
void
FileHeader::FetchFrom(int sector)
{
kernel->synchDisk->ReadSector(sector, (char *)this);
}
//----------------------------------------------------------------------
// FileHeader::WriteBack
// Write the modified contents of the file header back to disk.
//
// "sector" is the disk sector to contain the file header
//----------------------------------------------------------------------
void
FileHeader::WriteBack(int sector)
{
kernel->synchDisk->WriteSector(sector, (char *)this);
}
//----------------------------------------------------------------------
// FileHeader::ByteToSector
// Return which disk sector is storing a particular byte within the file.
// This is essentially a translation from a virtual address (the
// offset in the file) to a physical address (the sector where the
// data at the offset is stored).
//
// "offset" is the location within the file of the byte in question
//----------------------------------------------------------------------
int
FileHeader::ByteToSector(int offset)
{
return(dataSectors[offset / SectorSize]);
}
//----------------------------------------------------------------------
// FileHeader::FileLength
// Return the number of bytes in the file.
//----------------------------------------------------------------------
int
FileHeader::FileLength()
{
return numBytes;
}
//----------------------------------------------------------------------
// FileHeader::Print
// Print the contents of the file header, and the contents of all
// the data blocks pointed to by the file header.
//----------------------------------------------------------------------
void
FileHeader::Print()
{
int i, j, k;
char *data = new char[SectorSize];
printf("FileHeader contents. File size: %d. File blocks:\n", numBytes);
for (i = 0; i < numSectors; i++)
printf("%d ", dataSectors[i]);
printf("\nFile contents:\n");
for (i = k = 0; i < numSectors; i++) {
kernel->synchDisk->ReadSector(dataSectors[i], data);
for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {
if ('\040' <= data[j] && data[j] <= '\176') // isprint(data[j])
printf("%c", data[j]);
else
printf("\\%x", (unsigned char)data[j]);
}
printf("\n");
}
delete [] data;
}

66
code/filesys/filehdr.h Normal file
View File

@@ -0,0 +1,66 @@
// filehdr.h
// Data structures for managing a disk file header.
//
// A file header describes where on disk to find the data in a file,
// along with other information about the file (for instance, its
// length, owner, etc.)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#ifndef FILEHDR_H
#define FILEHDR_H
#include "disk.h"
#include "pbitmap.h"
#define NumDirect ((SectorSize - 2 * sizeof(int)) / sizeof(int))
#define MaxFileSize (NumDirect * SectorSize)
// The following class defines the Nachos "file header" (in UNIX terms,
// the "i-node"), describing where on disk to find all of the data in the file.
// The file header is organized as a simple table of pointers to
// data blocks.
//
// The file header data structure can be stored in memory or on disk.
// When it is on disk, it is stored in a single sector -- this means
// that we assume the size of this data structure to be the same
// as one disk sector. Without indirect addressing, this
// limits the maximum file length to just under 4K bytes.
//
// There is no constructor; rather the file header can be initialized
// by allocating blocks for the file (if it is a new file), or by
// reading it from disk.
class FileHeader {
public:
bool Allocate(PersistentBitmap *bitMap, int fileSize);// Initialize a file header,
// including allocating space
// on disk for the file data
void Deallocate(PersistentBitmap *bitMap); // De-allocate this file's
// data blocks
void FetchFrom(int sectorNumber); // Initialize file header from disk
void WriteBack(int sectorNumber); // Write modifications to file header
// back to disk
int ByteToSector(int offset); // Convert a byte offset into the file
// to the disk sector containing
// the byte
int FileLength(); // Return the length of the file
// in bytes
void Print(); // Print the contents of the file.
private:
int numBytes; // Number of bytes in the file
int numSectors; // Number of data sectors in the file
int dataSectors[NumDirect]; // Disk sector numbers for each data
// block in the file
};
#endif // FILEHDR_H

340
code/filesys/filesys.cc Normal file
View File

@@ -0,0 +1,340 @@
// filesys.cc
// Routines to manage the overall operation of the file system.
// Implements routines to map from textual file names to files.
//
// Each file in the file system has:
// A file header, stored in a sector on disk
// (the size of the file header data structure is arranged
// to be precisely the size of 1 disk sector)
// A number of data blocks
// An entry in the file system directory
//
// The file system consists of several data structures:
// A bitmap of free disk sectors (cf. bitmap.h)
// A directory of file names and file headers
//
// Both the bitmap and the directory are represented as normal
// files. Their file headers are located in specific sectors
// (sector 0 and sector 1), so that the file system can find them
// on bootup.
//
// The file system assumes that the bitmap and directory files are
// kept "open" continuously while Nachos is running.
//
// For those operations (such as Create, Remove) that modify the
// directory and/or bitmap, if the operation succeeds, the changes
// are written immediately back to disk (the two files are kept
// open during all this time). If the operation fails, and we have
// modified part of the directory and/or bitmap, we simply discard
// the changed version, without writing it back to disk.
//
// Our implementation at this point has the following restrictions:
//
// there is no synchronization for concurrent accesses
// files have a fixed size, set when the file is created
// files cannot be bigger than about 3KB in size
// there is no hierarchical directory structure, and only a limited
// number of files can be added to the system
// there is no attempt to make the system robust to failures
// (if Nachos exits in the middle of an operation that modifies
// the file system, it may corrupt the disk)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef FILESYS_STUB
#include "copyright.h"
#include "debug.h"
#include "disk.h"
#include "pbitmap.h"
#include "directory.h"
#include "filehdr.h"
#include "filesys.h"
// Sectors containing the file headers for the bitmap of free sectors,
// and the directory of files. These file headers are placed in well-known
// sectors, so that they can be located on boot-up.
#define FreeMapSector 0
#define DirectorySector 1
// Initial file sizes for the bitmap and directory; until the file system
// supports extensible files, the directory size sets the maximum number
// of files that can be loaded onto the disk.
#define FreeMapFileSize (NumSectors / BitsInByte)
#define NumDirEntries 10
#define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries)
//----------------------------------------------------------------------
// FileSystem::FileSystem
// Initialize the file system. If format = TRUE, the disk has
// nothing on it, and we need to initialize the disk to contain
// an empty directory, and a bitmap of free sectors (with almost but
// not all of the sectors marked as free).
//
// If format = FALSE, we just have to open the files
// representing the bitmap and the directory.
//
// "format" -- should we initialize the disk?
//----------------------------------------------------------------------
FileSystem::FileSystem(bool format)
{
DEBUG(dbgFile, "Initializing the file system.");
if (format) {
PersistentBitmap *freeMap = new PersistentBitmap(NumSectors);
Directory *directory = new Directory(NumDirEntries);
FileHeader *mapHdr = new FileHeader;
FileHeader *dirHdr = new FileHeader;
DEBUG(dbgFile, "Formatting the file system.");
// First, allocate space for FileHeaders for the directory and bitmap
// (make sure no one else grabs these!)
freeMap->Mark(FreeMapSector);
freeMap->Mark(DirectorySector);
// Second, allocate space for the data blocks containing the contents
// of the directory and bitmap files. There better be enough space!
ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize));
ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize));
// Flush the bitmap and directory FileHeaders back to disk
// We need to do this before we can "Open" the file, since open
// reads the file header off of disk (and currently the disk has garbage
// on it!).
DEBUG(dbgFile, "Writing headers back to disk.");
mapHdr->WriteBack(FreeMapSector);
dirHdr->WriteBack(DirectorySector);
// OK to open the bitmap and directory files now
// The file system operations assume these two files are left open
// while Nachos is running.
freeMapFile = new OpenFile(FreeMapSector);
directoryFile = new OpenFile(DirectorySector);
// Once we have the files "open", we can write the initial version
// of each file back to disk. The directory at this point is completely
// empty; but the bitmap has been changed to reflect the fact that
// sectors on the disk have been allocated for the file headers and
// to hold the file data for the directory and bitmap.
DEBUG(dbgFile, "Writing bitmap and directory back to disk.");
freeMap->WriteBack(freeMapFile); // flush changes to disk
directory->WriteBack(directoryFile);
if (debug->IsEnabled('f')) {
freeMap->Print();
directory->Print();
}
delete freeMap;
delete directory;
delete mapHdr;
delete dirHdr;
} else {
// if we are not formatting the disk, just open the files representing
// the bitmap and directory; these are left open while Nachos is running
freeMapFile = new OpenFile(FreeMapSector);
directoryFile = new OpenFile(DirectorySector);
}
}
//----------------------------------------------------------------------
// FileSystem::Create
// Create a file in the Nachos file system (similar to UNIX create).
// Since we can't increase the size of files dynamically, we have
// to give Create the initial size of the file.
//
// The steps to create a file are:
// Make sure the file doesn't already exist
// Allocate a sector for the file header
// Allocate space on disk for the data blocks for the file
// Add the name to the directory
// Store the new file header on disk
// Flush the changes to the bitmap and the directory back to disk
//
// Return TRUE if everything goes ok, otherwise, return FALSE.
//
// Create fails if:
// file is already in directory
// no free space for file header
// no free entry for file in directory
// no free space for data blocks for the file
//
// Note that this implementation assumes there is no concurrent access
// to the file system!
//
// "name" -- name of file to be created
// "initialSize" -- size of file to be created
//----------------------------------------------------------------------
bool
FileSystem::Create(char *name, int initialSize)
{
Directory *directory;
PersistentBitmap *freeMap;
FileHeader *hdr;
int sector;
bool success;
DEBUG(dbgFile, "Creating file " << name << " size " << initialSize);
directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
if (directory->Find(name) != -1)
success = FALSE; // file is already in directory
else {
freeMap = new PersistentBitmap(freeMapFile,NumSectors);
sector = freeMap->FindAndSet(); // find a sector to hold the file header
if (sector == -1)
success = FALSE; // no free block for file header
else if (!directory->Add(name, sector))
success = FALSE; // no space in directory
else {
hdr = new FileHeader;
if (!hdr->Allocate(freeMap, initialSize))
success = FALSE; // no space on disk for data
else {
success = TRUE;
// everthing worked, flush all changes back to disk
hdr->WriteBack(sector);
directory->WriteBack(directoryFile);
freeMap->WriteBack(freeMapFile);
}
delete hdr;
}
delete freeMap;
}
delete directory;
return success;
}
//----------------------------------------------------------------------
// FileSystem::Open
// Open a file for reading and writing.
// To open a file:
// Find the location of the file's header, using the directory
// Bring the header into memory
//
// "name" -- the text name of the file to be opened
//----------------------------------------------------------------------
OpenFile *
FileSystem::Open(char *name)
{
Directory *directory = new Directory(NumDirEntries);
OpenFile *openFile = NULL;
int sector;
DEBUG(dbgFile, "Opening file" << name);
directory->FetchFrom(directoryFile);
sector = directory->Find(name);
if (sector >= 0)
openFile = new OpenFile(sector); // name was found in directory
delete directory;
return openFile; // return NULL if not found
}
//----------------------------------------------------------------------
// FileSystem::Remove
// Delete a file from the file system. This requires:
// Remove it from the directory
// Delete the space for its header
// Delete the space for its data blocks
// Write changes to directory, bitmap back to disk
//
// Return TRUE if the file was deleted, FALSE if the file wasn't
// in the file system.
//
// "name" -- the text name of the file to be removed
//----------------------------------------------------------------------
bool
FileSystem::Remove(char *name)
{
Directory *directory;
PersistentBitmap *freeMap;
FileHeader *fileHdr;
int sector;
directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
sector = directory->Find(name);
if (sector == -1) {
delete directory;
return FALSE; // file not found
}
fileHdr = new FileHeader;
fileHdr->FetchFrom(sector);
freeMap = new PersistentBitmap(freeMapFile,NumSectors);
fileHdr->Deallocate(freeMap); // remove data blocks
freeMap->Clear(sector); // remove header block
directory->Remove(name);
freeMap->WriteBack(freeMapFile); // flush to disk
directory->WriteBack(directoryFile); // flush to disk
delete fileHdr;
delete directory;
delete freeMap;
return TRUE;
}
//----------------------------------------------------------------------
// FileSystem::List
// List all the files in the file system directory.
//----------------------------------------------------------------------
void
FileSystem::List()
{
Directory *directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
directory->List();
delete directory;
}
//----------------------------------------------------------------------
// FileSystem::Print
// Print everything about the file system:
// the contents of the bitmap
// the contents of the directory
// for each file in the directory,
// the contents of the file header
// the data in the file
//----------------------------------------------------------------------
void
FileSystem::Print()
{
FileHeader *bitHdr = new FileHeader;
FileHeader *dirHdr = new FileHeader;
PersistentBitmap *freeMap = new PersistentBitmap(freeMapFile,NumSectors);
Directory *directory = new Directory(NumDirEntries);
printf("Bit map file header:\n");
bitHdr->FetchFrom(FreeMapSector);
bitHdr->Print();
printf("Directory file header:\n");
dirHdr->FetchFrom(DirectorySector);
dirHdr->Print();
freeMap->Print();
directory->FetchFrom(directoryFile);
directory->Print();
delete bitHdr;
delete dirHdr;
delete freeMap;
delete directory;
}
#endif // FILESYS_STUB

98
code/filesys/filesys.h Normal file
View File

@@ -0,0 +1,98 @@
// filesys.h
// Data structures to represent the Nachos file system.
//
// A file system is a set of files stored on disk, organized
// into directories. Operations on the file system have to
// do with "naming" -- creating, opening, and deleting files,
// given a textual file name. Operations on an individual
// "open" file (read, write, close) are to be found in the OpenFile
// class (openfile.h).
//
// We define two separate implementations of the file system.
// The "STUB" version just re-defines the Nachos file system
// operations as operations on the native UNIX file system on the machine
// running the Nachos simulation.
//
// The other version is a "real" file system, built on top of
// a disk simulator. The disk is simulated using the native UNIX
// file system (in a file named "DISK").
//
// In the "real" implementation, there are two key data structures used
// in the file system. There is a single "root" directory, listing
// all of the files in the file system; unlike UNIX, the baseline
// system does not provide a hierarchical directory structure.
// In addition, there is a bitmap for allocating
// disk sectors. Both the root directory and the bitmap are themselves
// stored as files in the Nachos file system -- this causes an interesting
// bootstrap problem when the simulated disk is initialized.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef FS_H
#define FS_H
#include "copyright.h"
#include "sysdep.h"
#include "openfile.h"
#ifdef FILESYS_STUB // Temporarily implement file system calls as
// calls to UNIX, until the real file system
// implementation is available
class FileSystem {
public:
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
bool Create(char *name) {
int fileDescriptor = OpenForWrite(name);
if (fileDescriptor == -1) return FALSE;
Close(fileDescriptor);
return TRUE;
}
OpenFile* Open(char *name) {
int fileDescriptor = OpenForReadWrite(name, FALSE);
if (fileDescriptor == -1) return NULL;
return new OpenFile(fileDescriptor);
}
bool Remove(char *name) { return Unlink(name) == 0; }
OpenFile *fileDescriptorTable[20];
};
#else // FILESYS
class FileSystem {
public:
FileSystem(bool format); // Initialize the file system.
// Must be called *after* "synchDisk"
// has been initialized.
// If "format", there is nothing on
// the disk, so initialize the directory
// and the bitmap of free blocks.
bool Create(char *name, int initialSize);
// Create a file (UNIX creat)
OpenFile* Open(char *name); // Open a file (UNIX open)
bool Remove(char *name); // Delete a file (UNIX unlink)
void List(); // List all the files in the file system
void Print(); // List all the files and their contents
private:
OpenFile* freeMapFile; // Bit map of free disk blocks,
// represented as a file
OpenFile* directoryFile; // "Root" directory -- list of
// file names, represented as a file
};
#endif // FILESYS
#endif // FS_H

196
code/filesys/openfile.cc Normal file
View File

@@ -0,0 +1,196 @@
// openfile.cc
// Routines to manage an open Nachos file. As in UNIX, a
// file must be open before we can read or write to it.
// Once we're all done, we can close it (in Nachos, by deleting
// the OpenFile data structure).
//
// Also as in UNIX, for convenience, we keep the file header in
// memory while the file is open.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef FILESYS_STUB
#include "copyright.h"
#include "main.h"
#include "filehdr.h"
#include "openfile.h"
#include "synchdisk.h"
//----------------------------------------------------------------------
// OpenFile::OpenFile
// Open a Nachos file for reading and writing. Bring the file header
// into memory while the file is open.
//
// "sector" -- the location on disk of the file header for this file
//----------------------------------------------------------------------
OpenFile::OpenFile(int sector)
{
hdr = new FileHeader;
hdr->FetchFrom(sector);
seekPosition = 0;
}
//----------------------------------------------------------------------
// OpenFile::~OpenFile
// Close a Nachos file, de-allocating any in-memory data structures.
//----------------------------------------------------------------------
OpenFile::~OpenFile()
{
delete hdr;
}
//----------------------------------------------------------------------
// OpenFile::Seek
// Change the current location within the open file -- the point at
// which the next Read or Write will start from.
//
// "position" -- the location within the file for the next Read/Write
//----------------------------------------------------------------------
void
OpenFile::Seek(int position)
{
seekPosition = position;
}
//----------------------------------------------------------------------
// OpenFile::Read/Write
// Read/write a portion of a file, starting from seekPosition.
// Return the number of bytes actually written or read, and as a
// side effect, increment the current position within the file.
//
// Implemented using the more primitive ReadAt/WriteAt.
//
// "into" -- the buffer to contain the data to be read from disk
// "from" -- the buffer containing the data to be written to disk
// "numBytes" -- the number of bytes to transfer
//----------------------------------------------------------------------
int
OpenFile::Read(char *into, int numBytes)
{
int result = ReadAt(into, numBytes, seekPosition);
seekPosition += result;
return result;
}
int
OpenFile::Write(char *into, int numBytes)
{
int result = WriteAt(into, numBytes, seekPosition);
seekPosition += result;
return result;
}
//----------------------------------------------------------------------
// OpenFile::ReadAt/WriteAt
// Read/write a portion of a file, starting at "position".
// Return the number of bytes actually written or read, but has
// no side effects (except that Write modifies the file, of course).
//
// There is no guarantee the request starts or ends on an even disk sector
// boundary; however the disk only knows how to read/write a whole disk
// sector at a time. Thus:
//
// For ReadAt:
// We read in all of the full or partial sectors that are part of the
// request, but we only copy the part we are interested in.
// For WriteAt:
// We must first read in any sectors that will be partially written,
// so that we don't overwrite the unmodified portion. We then copy
// in the data that will be modified, and write back all the full
// or partial sectors that are part of the request.
//
// "into" -- the buffer to contain the data to be read from disk
// "from" -- the buffer containing the data to be written to disk
// "numBytes" -- the number of bytes to transfer
// "position" -- the offset within the file of the first byte to be
// read/written
//----------------------------------------------------------------------
int
OpenFile::ReadAt(char *into, int numBytes, int position)
{
int fileLength = hdr->FileLength();
int i, firstSector, lastSector, numSectors;
char *buf;
if ((numBytes <= 0) || (position >= fileLength))
return 0; // check request
if ((position + numBytes) > fileLength)
numBytes = fileLength - position;
DEBUG(dbgFile, "Reading " << numBytes << " bytes at " << position << " from file of length " << fileLength);
firstSector = divRoundDown(position, SectorSize);
lastSector = divRoundDown(position + numBytes - 1, SectorSize);
numSectors = 1 + lastSector - firstSector;
// read in all the full and partial sectors that we need
buf = new char[numSectors * SectorSize];
for (i = firstSector; i <= lastSector; i++)
kernel->synchDisk->ReadSector(hdr->ByteToSector(i * SectorSize),
&buf[(i - firstSector) * SectorSize]);
// copy the part we want
bcopy(&buf[position - (firstSector * SectorSize)], into, numBytes);
delete [] buf;
return numBytes;
}
int
OpenFile::WriteAt(char *from, int numBytes, int position)
{
int fileLength = hdr->FileLength();
int i, firstSector, lastSector, numSectors;
bool firstAligned, lastAligned;
char *buf;
if ((numBytes <= 0) || (position >= fileLength))
return 0; // check request
if ((position + numBytes) > fileLength)
numBytes = fileLength - position;
DEBUG(dbgFile, "Writing " << numBytes << " bytes at " << position << " from file of length " << fileLength);
firstSector = divRoundDown(position, SectorSize);
lastSector = divRoundDown(position + numBytes - 1, SectorSize);
numSectors = 1 + lastSector - firstSector;
buf = new char[numSectors * SectorSize];
firstAligned = (position == (firstSector * SectorSize));
lastAligned = ((position + numBytes) == ((lastSector + 1) * SectorSize));
// read in first and last sector, if they are to be partially modified
if (!firstAligned)
ReadAt(buf, SectorSize, firstSector * SectorSize);
if (!lastAligned && ((firstSector != lastSector) || firstAligned))
ReadAt(&buf[(lastSector - firstSector) * SectorSize],
SectorSize, lastSector * SectorSize);
// copy in the bytes we want to change
bcopy(from, &buf[position - (firstSector * SectorSize)], numBytes);
// write modified sectors back
for (i = firstSector; i <= lastSector; i++)
kernel->synchDisk->WriteSector(hdr->ByteToSector(i * SectorSize),
&buf[(i - firstSector) * SectorSize]);
delete [] buf;
return numBytes;
}
//----------------------------------------------------------------------
// OpenFile::Length
// Return the number of bytes in the file.
//----------------------------------------------------------------------
int
OpenFile::Length()
{
return hdr->FileLength();
}
#endif //FILESYS_STUB

97
code/filesys/openfile.h Normal file
View File

@@ -0,0 +1,97 @@
// openfile.h
// Data structures for opening, closing, reading and writing to
// individual files. The operations supported are similar to
// the UNIX ones -- type 'man open' to the UNIX prompt.
//
// There are two implementations. One is a "STUB" that directly
// turns the file operations into the underlying UNIX operations.
// (cf. comment in filesys.h).
//
// The other is the "real" implementation, that turns these
// operations into read and write disk sector requests.
// In this baseline implementation of the file system, we don't
// worry about concurrent accesses to the file system
// by different threads.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef OPENFILE_H
#define OPENFILE_H
#include "copyright.h"
#include "utility.h"
#include "sysdep.h"
#ifdef FILESYS_STUB // Temporarily implement calls to
// Nachos file system as calls to UNIX!
// See definitions listed under #else
class OpenFile {
public:
OpenFile(int f) { file = f; currentOffset = 0; } // open the file
~OpenFile() { Close(file); } // close the file
int ReadAt(char *into, int numBytes, int position) {
Lseek(file, position, 0);
return ReadPartial(file, into, numBytes);
}
int WriteAt(char *from, int numBytes, int position) {
Lseek(file, position, 0);
WriteFile(file, from, numBytes);
return numBytes;
}
int Read(char *into, int numBytes) {
int numRead = ReadAt(into, numBytes, currentOffset);
currentOffset += numRead;
return numRead;
}
int Write(char *from, int numBytes) {
int numWritten = WriteAt(from, numBytes, currentOffset);
currentOffset += numWritten;
return numWritten;
}
int Length() { Lseek(file, 0, 2); return Tell(file); }
private:
int file;
int currentOffset;
};
#else // FILESYS
class FileHeader;
class OpenFile {
public:
OpenFile(int sector); // Open a file whose header is located
// at "sector" on the disk
~OpenFile(); // Close the file
void Seek(int position); // Set the position from which to
// start reading/writing -- UNIX lseek
int Read(char *into, int numBytes); // Read/write bytes from the file,
// starting at the implicit position.
// Return the # actually read/written,
// and increment position in file.
int Write(char *from, int numBytes);
int ReadAt(char *into, int numBytes, int position);
// Read/write bytes from the file,
// bypassing the implicit position.
int WriteAt(char *from, int numBytes, int position);
int Length(); // Return the number of bytes in the
// file (this interface is simpler
// than the UNIX idiom -- lseek to
// end of file, tell, lseek back
private:
FileHeader *hdr; // Header for this file
int seekPosition; // Current position within the file
};
#endif // FILESYS
#endif // OPENFILE_H

79
code/filesys/pbitmap.cc Normal file
View File

@@ -0,0 +1,79 @@
// pbitmap.c
// Routines to manage a persistent bitmap -- a bitmap that is
// stored on disk.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "pbitmap.h"
//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(int)
// Initialize a bitmap with "numItems" bits, so that every bit is clear.
// it can be added somewhere on a list.
//
// "numItems" is the number of bits in the bitmap.
//
// This constructor does not initialize the bitmap from a disk file
//----------------------------------------------------------------------
PersistentBitmap::PersistentBitmap(int numItems):Bitmap(numItems)
{
}
//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(OpenFile*,int)
// Initialize a persistent bitmap with "numItems" bits,
// so that every bit is clear.
//
// "numItems" is the number of bits in the bitmap.
// "file" refers to an open file containing the bitmap (written
// by a previous call to PersistentBitmap::WriteBack
//
// This constructor initializes the bitmap from a disk file
//----------------------------------------------------------------------
PersistentBitmap::PersistentBitmap(OpenFile *file, int numItems):Bitmap(numItems)
{
// map has already been initialized by the BitMap constructor,
// but we will just overwrite that with the contents of the
// map found in the file
file->ReadAt((char *)map, numWords * sizeof(unsigned), 0);
}
//----------------------------------------------------------------------
// PersistentBitmap::~PersistentBitmap
// De-allocate a persistent bitmap.
//----------------------------------------------------------------------
PersistentBitmap::~PersistentBitmap()
{
}
//----------------------------------------------------------------------
// PersistentBitmap::FetchFrom
// Initialize the contents of a persistent bitmap from a Nachos file.
//
// "file" is the place to read the bitmap from
//----------------------------------------------------------------------
void
PersistentBitmap::FetchFrom(OpenFile *file)
{
file->ReadAt((char *)map, numWords * sizeof(unsigned), 0);
}
//----------------------------------------------------------------------
// PersistentBitmap::WriteBack
// Store the contents of a persistent bitmap to a Nachos file.
//
// "file" is the place to write the bitmap to
//----------------------------------------------------------------------
void
PersistentBitmap::WriteBack(OpenFile *file)
{
file->WriteAt((char *)map, numWords * sizeof(unsigned), 0);
}

35
code/filesys/pbitmap.h Normal file
View File

@@ -0,0 +1,35 @@
// pbitmap.h
// Data structures defining a "persistent" bitmap -- a bitmap
// that can be stored and fetched off of disk
//
// A persistent bitmap can either be initialized from the disk
// when it is created, or it can be initialized later using
// the FetchFrom method
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef PBITMAP_H
#define PBITMAP_H
#include "copyright.h"
#include "bitmap.h"
#include "openfile.h"
// The following class defines a persistent bitmap. It inherits all
// the behavior of a bitmap (see bitmap.h), adding the ability to
// be read from and stored to the disk.
class PersistentBitmap : public Bitmap {
public:
PersistentBitmap(OpenFile *file,int numItems); //initialize bitmap from disk
PersistentBitmap(int numItems); // or don't...
~PersistentBitmap(); // deallocate bitmap
void FetchFrom(OpenFile *file); // read bitmap from the disk
void WriteBack(OpenFile *file); // write bitmap contents to disk
};
#endif // PBITMAP_H

94
code/filesys/synchdisk.cc Normal file
View File

@@ -0,0 +1,94 @@
// synchdisk.cc
// Routines to synchronously access the disk. The physical disk
// is an asynchronous device (disk requests return immediately, and
// an interrupt happens later on). This is a layer on top of
// the disk providing a synchronous interface (requests wait until
// the request completes).
//
// Use a semaphore to synchronize the interrupt handlers with the
// pending requests. And, because the physical disk can only
// handle one operation at a time, use a lock to enforce mutual
// exclusion.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "synchdisk.h"
//----------------------------------------------------------------------
// SynchDisk::SynchDisk
// Initialize the synchronous interface to the physical disk, in turn
// initializing the physical disk.
//
//----------------------------------------------------------------------
SynchDisk::SynchDisk()
{
semaphore = new Semaphore("synch disk", 0);
lock = new Lock("synch disk lock");
disk = new Disk(this);
}
//----------------------------------------------------------------------
// SynchDisk::~SynchDisk
// De-allocate data structures needed for the synchronous disk
// abstraction.
//----------------------------------------------------------------------
SynchDisk::~SynchDisk()
{
delete disk;
delete lock;
delete semaphore;
}
//----------------------------------------------------------------------
// SynchDisk::ReadSector
// Read the contents of a disk sector into a buffer. Return only
// after the data has been read.
//
// "sectorNumber" -- the disk sector to read
// "data" -- the buffer to hold the contents of the disk sector
//----------------------------------------------------------------------
void
SynchDisk::ReadSector(int sectorNumber, char* data)
{
lock->Acquire(); // only one disk I/O at a time
disk->ReadRequest(sectorNumber, data);
semaphore->P(); // wait for interrupt
lock->Release();
}
//----------------------------------------------------------------------
// SynchDisk::WriteSector
// Write the contents of a buffer into a disk sector. Return only
// after the data has been written.
//
// "sectorNumber" -- the disk sector to be written
// "data" -- the new contents of the disk sector
//----------------------------------------------------------------------
void
SynchDisk::WriteSector(int sectorNumber, char* data)
{
lock->Acquire(); // only one disk I/O at a time
disk->WriteRequest(sectorNumber, data);
semaphore->P(); // wait for interrupt
lock->Release();
}
//----------------------------------------------------------------------
// SynchDisk::CallBack
// Disk interrupt handler. Wake up any thread waiting for the disk
// request to finish.
//----------------------------------------------------------------------
void
SynchDisk::CallBack()
{
semaphore->V();
}

55
code/filesys/synchdisk.h Normal file
View File

@@ -0,0 +1,55 @@
// synchdisk.h
// Data structures to export a synchronous interface to the raw
// disk device.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#ifndef SYNCHDISK_H
#define SYNCHDISK_H
#include "disk.h"
#include "synch.h"
#include "callback.h"
// The following class defines a "synchronous" disk abstraction.
// As with other I/O devices, the raw physical disk is an asynchronous device --
// requests to read or write portions of the disk return immediately,
// and an interrupt occurs later to signal that the operation completed.
// (Also, the physical characteristics of the disk device assume that
// only one operation can be requested at a time).
//
// This class provides the abstraction that for any individual thread
// making a request, it waits around until the operation finishes before
// returning.
class SynchDisk : public CallBackObj {
public:
SynchDisk(); // Initialize a synchronous disk,
// by initializing the raw Disk.
~SynchDisk(); // De-allocate the synch disk data
void ReadSector(int sectorNumber, char* data);
// Read/write a disk sector, returning
// only once the data is actually read
// or written. These call
// Disk::ReadRequest/WriteRequest and
// then wait until the request is done.
void WriteSector(int sectorNumber, char* data);
void CallBack(); // Called by the disk device interrupt
// handler, to signal that the
// current disk operation is complete.
private:
Disk *disk; // Raw disk device
Semaphore *semaphore; // To synchronize requesting thread
// with the interrupt handler
Lock *lock; // Only one read/write request
// can be sent to the disk at a time
};
#endif // SYNCHDISK_H