Skip to content

Commit

Permalink
DESIGNDOC completed
Browse files Browse the repository at this point in the history
  • Loading branch information
atuljangra committed May 1, 2013
1 parent f1b6a09 commit 9ea9cea
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 164 deletions.
85 changes: 82 additions & 3 deletions src/filesys/DESIGNDOC
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ both of them,
>> Please cite any offline or online sources you consulted while
>> preparing your submission, other than the Pintos documentation, course
>> text, lecture notes, and course staff.

xv6 code listing.


INDEXED AND EXTENSIBLE FILES
============================
Expand All @@ -29,23 +32,63 @@ both of them,
>> A1: Copy here the declaration of each new or changed `struct' or
>> `struct' member, global or static variable, `typedef', or
>> enumeration. Identify the purpose of each in 25 words or less.

enum
{
T_EMPTY,T_FILE,T_DIR
};
This to identify the type of the disk inode.

/* On-disk inode.
Must be exactly BLOCK_SECTOR_SIZE bytes long. */
struct inode_disk
{
int type; /* type of inode. */
off_t length; /* File size in bytes. */
unsigned magic; /* Magic number. */
block_sector_t addrs[NDIRECT+2]; /* Direct,Indirect and doubly indirect links */
};
First NDIRECT entries (0 to NDIRECT-1) are direct links, addrs[NDIRECT]
is for indirect link and addrs[NDIRECT+1] is for doubly indirect link.


/* In-memory inode. */
struct inode
{
struct list_elem elem; /* Element in inode list. */
block_sector_t sector; /* Sector number of disk location. */
int open_cnt; /* Number of openers. */
bool removed; /* True if deleted, false otherwise. */
int deny_write_cnt; /* 0: writes ok, >0: deny writes. */
//struct inode_disk data; /* Inode content. */
struct lock lk; /* per-inode lock */
};

struct lock open_inode_lock;
This the lock on the list of open inodes to synchronize its access.

>> A2: What is the maximum size of a file supported by your inode
>> structure? Show your work.

No. of direct blocks = 123
No. of indirect blocks = 128
No. of doubly indirect blocks = 128*128
Maximum file size = (123 +128 + 128*128)/2 KB = 8.12 MB

---- SYNCHRONIZATION ----

>> A3: Explain how your code avoids a race if two processes attempt to
>> extend a file at the same time.

We acquire a lock on the inode that is being extended when a process wants
to extend a file. Thus two process can never extend a file at the same time.


>> A4: Suppose processes A and B both have file F open, both
>> positioned at end-of-file. If A reads and B writes F at the same
>> time, A may read all, part, or none of what B writes. However, A
>> may not read data other than what B writes, e.g. if B writes
>> nonzero data, A is not allowed to see all zeros. Explain how your
>> code avoids this race.

We are updating the metadata(only length) of an inode after extending the file. Thus the
length of the file is being changed when we have written to the file. Thus A
would not be able to find out that the length of the file has increased until
Expand All @@ -57,10 +100,12 @@ B has written the metadata of the inode. Thus the above race would not occur.
>> prevent forever another process from writing the file, and many
>> processes writing to a file cannot prevent another process forever
>> from reading the file.

We are not blocking any reader or writer anytime. In the buffer cache, we are
just updating the flags(read or write) when someone accesses a block for write/read.
We are just blocking when a write is made to exten a file. Thus our design
provides "fairness".

---- RATIONALE ----

>> A6: Is your inode structure a multilevel index? If so, why did you
Expand All @@ -69,38 +114,70 @@ provides "fairness".
>> structure, and what advantages and disadvantages does your
>> structure have, compared to a multilevel index?

Yes, our inode structure is a multilevel index. We had to support files
as large as 8MB size.Also the disk inode is constrained to be of 1 block
size. Supporting 8MB files was not possible using only direct links.
Doubly indirect link has to be used to support 8MB file size, but this
slows down the overall file access so only one such indirect and doubly indirect
link is provided so that access time for small files is less.

SUBDIRECTORIES
==============

---- DATA STRUCTURES ----

>> B1: Copy here the declaration of each new or changed `struct' or
>> `struct' member, global or static variable, `typedef', or
>> enumeration. Identify the purpose of each in 25 words or less.
enum
{
T_EMPTY,T_FILE,T_DIR
};
This to identify the type of the disk inode.

---- ALGORITHMS ----

>> B2: Describe your code for traversing a user-specified path. How
>> do traversals of absolute and relative paths differ?

The code for traversing a user-specified path is similar to xv6.
Given the path it is parsed to find the path of the first level
parent and the name of the child in the parent. The parent directory is
looked for the prsence of the child.
If the path begins with '/' then it is absolute otherwise it is relative.
The difference is only in the starting dirctory for searching the entire
path.

---- SYNCHRONIZATION ----

>> B4: How do you prevent races on directory entries? For example,
>> only one of two simultaneous attempts to remove a single file
>> should succeed, as should only one of two simultaneous attempts to
>> create a file with the same name, and so on.

We are acquiring a lock on the inode corresponding to the directory when we want to
remove/create a file. Thus only one of the two processes succeeds.

>> B5: Does your implementation allow a directory to be removed if it
>> is open by a process or if it is in use as a process's current
>> working directory? If so, what happens to that process's future
>> file system operations? If not, how do you prevent it?

Yes our implementation allow a directory to be removed if it is open by a
process or if it is in use as a process's current working directory.
If a directory is removed then no changes can be done in that directory by
any process i.e. new files or directories cannot be created in it.

---- RATIONALE ----

>> B6: Explain why you chose to represent the current directory of a
>> process the way you did.

A directory pointer is saved in the thread structure of every process.
When a new thread is created then the cwd of the parent is reopened
and pointer is saved in the child's thread structure.
Current working directory is private to every process and it is easy to
manage the current working directory if kept in the thread structure itself.

BUFFER CACHE
============

Expand Down Expand Up @@ -214,6 +291,8 @@ access this

>> C7: Describe a file workload likely to benefit from buffer caching,
>> and workloads likely to benefit from read-ahead and write-behind.
Tests like syn-read and syn write, where we are simultaneously reading and writing to the
same file multiple times are havily benefitted from buffer caching, read ahead and write-behind.

SURVEY QUESTIONS
================
Expand Down
101 changes: 7 additions & 94 deletions src/filesys/bcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ void init_bcache ()
temp -> valid = false;
lock_init (&temp -> lock);
bcache[i * sector_per_page+j] = temp;
// printf ("Initialized %d with i: %d, j: %d pointing to %x %d , bcache: %x \n", i * sector_per_page + j, i, j, temp, temp, bcache[ i * sector_per_page+j]);
// free (temp);
}
}

Expand All @@ -59,40 +57,6 @@ void init_bcache ()
// create the bitmap
bcache_table = bitmap_create (BUFFER_CACHE_SIZE);
}
/*
int get_sector (block_sector_t blockid, int flag)
{
lock_acquire (&bcache_lock);
int entry = find_sector (blockid, flag);
if (entry != -1)
{
printf ("get: got the entry for sector %s \n", blockid);
if (flag == FLAG_READ)
bcache[i] -> read++;
if (flag == FLAG_WRITE)
bcache[i] -> write++;
bcache [i] -> valid = false;
lock_release (&bcache_lock);
return entry;
}
// entry was not present int the buffer cache, thus trying to add a new entry
size_t free_entry = bitmap_scan (bcache_table, 0, 1, false);
// we have a free entry, thus use that.
if (free_entry != BITMAP_ERROR)
{
lock_release (&bcache_lock);
// read from the block
block_read (fs_device, blockid, bcache[free_entry] -> kaddr);
}
}
*/

// Finds an entry corresponding to blockid
// flag: either 0(read) or 1(write), increase the corresponding entry of block.
// to avoid race conditions, as done in xv6
Expand Down Expand Up @@ -158,84 +122,50 @@ size_t add_bcache (block_sector_t blockid, int flag)
// If there is no such entry then we need to evict
if (free_entry == BITMAP_ERROR)
{
// printf ("evicting \t");
int evicted = evict_bcache ();

block_write (fs_device, bcache[evicted] -> bsector, bcache[evicted] -> kaddr);
//~ void *dummy = malloc (BLOCK_SECTOR_SIZE);
//~ memcpy (dummy, bcache [evicted] -> kaddr, BLOCK_SECTOR_SIZE);

bcache[evicted] -> dirty = false;
bcache[evicted] -> accessed = false;
bcache[evicted] -> bsector = blockid;
bcache[evicted] -> valid = false;

// Mark the corresponding entry in bitmap table
// bitmap_set (bcache_table, evicted, true);
if (flag == FLAG_READ)
bcache[evicted] -> read ++;
if (flag == FLAG_WRITE)
bcache[evicted] -> write ++;
lock_release (&bcache_lock);
// read from the disk


// read from the disk
block_read (fs_device, blockid, bcache[evicted] -> kaddr);

// mark the buffer as valid
lock_acquire (&bcache[evicted] -> lock);
bcache[evicted] -> valid = true;
lock_release (&bcache[evicted] -> lock);
return evicted;

return evicted;
}

return -1;
//~
//~ ASSERT (free_entry != BITMAP_ERROR);
// printf ("Adding bcache block %d %x kaddr %x %d \n", blockid, blockid, bcache[free_entry] -> kaddr, bcache[free_entry] -> kaddr);
//~ // bcache[free_entry] -> kaddr = (void *)calloc (1, BLOCK_SECTOR_SIZE);
//~ block_read (fs_device, blockid, bcache[free_entry] -> kaddr);
//~ // hex_dump (0, bcache[free_entry] -> kaddr, BLOCK_SECTOR_SIZE, true);
// printf ("add cache: read from disk %s \n", bcache[free_entry] -> kaddr);
//~ bcache[free_entry] -> dirty = false;
//~ bcache[free_entry] -> accessed = false;
//~ bcache[free_entry] -> bsector = blockid;
//~
//~ // Mark the corresponding entry in bitmap table
//~ bitmap_set (bcache_table, free_entry, true);
//~
//~ if (flag == FLAG_READ)
//~ bcache[free_entry] -> read ++;
//~ if (flag == FLAG_WRITE)
//~ bcache[free_entry] -> write ++;
//~
//~ //lock_release (&bcache_lock);
//~ return free_entry;
}

// reads from a block, which is in cache, and stores it in buffer.
void read_bcache (block_sector_t blockid, void *buffer, off_t offset, int size)
{
// sanitychecks
ASSERT (offset < BLOCK_SECTOR_SIZE);
//~ printf ("Reading bcache at %d, offset %d, size %d \n", blockid, offset, size);

lock_acquire(&bcache_lock);
// flag is 0 as it is a read access
int entry = find_sector (blockid, FLAG_READ);

//~ printf ("bcache read: entry is %d \n", entry);

// If no entry is there, then add the cache and increase the reader.
if (entry == -1)
{
entry = add_bcache (blockid, FLAG_READ);
// lock_release(&bcache_lock);
// bcache[entry] -> read++;
//~ printf ("bcache read: new entry is %d \n", entry);

// If we are just getting the data block for this entry from the disk, then
// we need to add the next block to the global readahead list, i.e. we need
// to request a readahead.
// IF this is not the last block, then request readahead
//if (blockid < block_size (fs_device) - 1)
//request_readahead (blockid + 1);
}
else
{
Expand All @@ -249,7 +179,6 @@ void read_bcache (block_sector_t blockid, void *buffer, off_t offset, int size)

// Copying contents into the requested buffer
memcpy (buffer, (bcache[entry] -> kaddr + offset), size);
//~ printf ("sector %d buffer %s odd: %s\n", blockid, buffer, (bcache[entry] -> kaddr + offset));
lock_acquire(&bcache[entry] -> lock);
bcache[entry] -> accessed = true;
bcache[entry] -> read--;
Expand All @@ -262,25 +191,14 @@ void write_bcache (block_sector_t blockid, void *buffer, int offset, int size)
{
//sanity checks
ASSERT (offset < BLOCK_SECTOR_SIZE);
// printf ("Writing bcache at %d, offset %d, size %d buffer %s \n", blockid, offset, size, buffer);

lock_acquire(&bcache_lock);
// flag is 1 as it is a write access
int entry = find_sector (blockid, FLAG_WRITE);

//~ printf ("bcache write : entry is %d \n", entry);
// If no entry is there, then add the cache and increase the reader.
if (entry == -1)
{
//~ printf ("adding while writing \t");
entry = add_bcache (blockid, FLAG_WRITE);
// Register as writer process
// bcache[entry] -> write++;i
// lock_release(&bcache_lock);

//TODO add comment
//if (blockid < block_size (fs_device) - 1)
//request_readahead (blockid + 1);
}
else
{
Expand Down Expand Up @@ -326,25 +244,20 @@ void writeback (int index)
}

// Evict cache to make place for another entry into the cache
// TODO: Currently using second change algorithm, as clock was creating problem
// TODO: Change this to use clock
int evict_bcache ()
{
int i;
int evicted = -1;

while (evicted == -1)
{
// printf (".");
for (i = 0; i < BUFFER_CACHE_SIZE; i++)
// is the entry completely free
if (bcache[i] -> write == 0 && bcache[i] -> read == 0)
{
if (bcache[i] -> accessed == false)
{
evicted = i;
// writeback (evicted);
// bitmap_set (bcache_table, evicted, false);
return evicted;
}
else
Expand Down
Loading

0 comments on commit 9ea9cea

Please sign in to comment.