Table of Contents

Lecture 12 Scribe Notes: File Systems I

By Giancarlo de la Cruz, Dashiell Nash, and Marcell Ortutay.

File Systems Overview

File systems are designed to provide "GE Robustness"--that means that even if GE cuts out the power to a hard disk, our data will be safe. They provide persistent data independent of power. This is in contrast to computer memory, which depends on continuous power. There are several issues in designing a file system:

  1. Performance:
    • How fast can we get data from the file system?
    • How fast can we store data on the file system?
  2. Utilization:
    • What percent of the hard disk is being taken up by user data as opposed to bookkeeping?
  3. Robustness:
    • What happens if the power goes out? Will the disk break?
  4. Generality:
    • How well does the file system adapt to different applications?

A file system is an abstraction of a hard disk.

Here is a diagram of a typical hard drive:

There are several key parts:

Reading from a hard disk

One of the key issues with a hard disk is the time it takes to read data off of it. As an example, consider the Seagate Barracuda 72007. This hard disk stores data at the cost of $.0007 per MB (compared to DRAM, which costs $.09 per MB). Here are it's speeds for finding data:

Caching and Performance Issues

In file systems, the main solution to performance issues stemming from multiple seeks and rotational latency is caching. Caching is keeping a copy of the results of a request "locally" so the work of a request does not need to be performed multiple times.

There are two places where caches (memory where request results are temporarily held) are often implemented with regard to file systems:

  1. Main memory
  2. The disk's I/O controller

Since disk read and write requests are different types of operations, each one requires a different caching strategy.

Reads are best accomplished by prefetching. Prefetching involves having the kernel perform operations automatically in speculation of the future behavior of the application.

Example: An application opens a file, then the operating system reads the entire file into cache preemptively. In this situation, the kernel speculates that the application will eventually want to read from the file it just opened. This improves performance since each read request will not require a (very costly) open request. Cache is much faster and less costly to read from than the disk.

Writes are best accomplished by dallying. Dallying is delaying the execution of requests to create opportunities for caching or repeating executions if new requests are redundant.

The following diagram is an example of a system that uses dallying to reduce the amount of total write requests made to a disk.

This example system features caches at both the disk and the kernel levels. The formal name for this type of cache implementation (where one cache is "stacked" upon another) is multilevel memory.

Analysis of Dallying

Advantage: The number of requests made to the disk is reduced. This greatly improves performance since the process of writing will be made quicker.

Disadvantage: Dallying lacks robustness in that it does not protect data in the event of power loss. Imagine that power is lost while several write requests are stored in the kernel buffer in the above example. Since power was cut before the kernel had the chance to execute a contiguous write request, the data that the application "wrote" to the disk is lost.

File System Layout

The goal of a file system layout is to make caching more effective by preserving locality of reference (see lecture 3 notes: lec3). If locality of reference is not preserved and file data is scattered about the disk rather than continuous, the act of reading from the disk for the purpose of caching will itself cause a performance issue. For this reason, file systems since the early 1970's have been engineered to store data sequentially on disks.

Sequential Sectors (RT-11)

In 1973, astute computer scientists noticed that sequential file access was commonplace. The designers of the RT-11 file system optimized their file system to take advantage of this observation. Each file is stored contiguously in sequential sectors. For example, if a file's first sector is stored at sector s, the next sectors are stored at s+1,s+2,... and so on.

How does this design decision affect utilization? Say we have a series of requests to create and delete new files. For this particular implementation, we can measure utilization (ρ) as:

ρ = amount of disk with data / total disk size

For this file system implementation, what series of reads and writes will result in a worst possible utilization? Say we have a 2MB total disk size, and each sector is 512 bytes:

1. Create a file with a size of 1MB - 1sector
2. Create a file with a size of 1kb (2 sectors)
3. Delete first file
4. Attempt to create a file with a size of 1MB. This attempt will fail

The state of the hard drive after step 4 is depicted in the diagram:

Fragmented Disk

We can calculate ρ: ρ = 1KB / 2MB = 0.005%

This reveals a major issue with contiguous file storage, Fragmentation .

FRAGMENTATION - A situation that exists when space is available on a hard drive that cannot be used by the file system. Fragmentation comes in two flavors, external and internal.
External Fragmentation - The unusable space is between pieces of used space
Internal Fragmentation - The unusable space is allocated to a portion of the used space.

The exercise above is an example of external fragmentation. In order to have the worst possible Internal Fragmentation in this file system, change step 2 in the above sequence to create 2, 1 byte files.
This will cause the utilization to be: ρ = 2B / 2MB

How can we fix External Fragmentation?

We can fix External Fragmentation by allowing files to be moved around the disk to keep the largest contiguous amount of free space on the disk. This is called Compaction. There are serious drawbacks to this technique, however. Since computer systems will most likely not have as much system memory as space on disk, the compaction process will require multiple seeks on the disk, which will result in a big reduction in overall performance.

How can we Prevent External Fragmentation? AKA: When FAT is good for you

We can prevent external fragmentation by allowing files to be split into separate blocks with Uniform allocation size across the disk. While this will greatly increase utilization, Performance could be adversely effected as there will be less locality of reference, reducing the efficiency of any caching that is implemented in the system.

In 1977, Bill Gates and Marc McDonald did just this, and created the FAT (File Allocation Table) File System. In their implemenation, they added a File Allocation Table (FAT for short) to the disk after the super block. The FAT stores "pointers" to each block of data in the system.

A block is an allocation unit of a file system containing 1 or more sectors. Modern block sizes are between 8 - 16 sectors ( 2KB - 8 KB ).

The basic FAT file system layout can be described in the following diagram (not to scale):

Boot Sector Super Block File Allocation Table Data (expands to the end of the partition)

The sections represent

The FAT itself is used as follows:

if ( FAT[b] == 0 )
     // block b is the last block containing the file
else if ( FAT[b] > 0 )
     // FAT[b] is the number of the block containing the next section of data for the file contained in block b
else if ( FAT[b] == -1 )
     // block b is unallocated

This means that if a corresponding block entry in the FAT is equal to or greater than 0, it is allocated and begin used. If an entry is -1, it is unallocated. The Boot Sector, Super Block, and FAT's corresponding entries in the FAT are marked with 0, to prevent being overwritten by the user.

Each block on disk requires its own entry in the FAT, therefore the size of the FAT depends on the size of the disk. For example, in FAT12 (the initial version of FAT), each block would have 12 bits in the FAT to represent itself, FAT16 allocated 16 bits (2 bytes) to each block, and FAT32 allocated 32bits (4 bytes) to each block.

The maximum utilization for a FAT file system can be roughly defined as:

ρ = (# of blocks on disk - (Size of FAT + size of other "Bookkeeping" blocks) ) / (# of blocks on disk)

The size of the FAT (in blocks) can be defined as:

|FAT| = # of blocks on disk / block size

In this case, the only used portions of the disk are the boot sector, the super block, and the FAT.

The performance is O(n), which makes sense as the hard disk must perform a linear scan to find the location of the last block of data for a file. This linear time limitation is solved with the introduction of Inodes, which are covered in the next lecture.