C SC 340 Lecture 10: File Systems

[ previous | schedule | next ]

Part One: File Systems Interface

Introduction

A file is the logical unit of secondary storage. It is a named collection of related information on secondary storage. Secondary storage includes most magnetic and optical media such as disks, CDs, and tapes.

We will focus on disk storage. All user data on secondary storage must reside in a file. The OS also uses secondary storage for process/memory/storage management such as process swapping space. We will focus on user files.

A file system is the logical collection of files. We call it logical because a single device may contain multiple files systems (e.g. partitions); likewise a single file system may occupy multiple devices (e.g. Unix device mounting).

File and File System Management Issues

We will cover a number of issues relevant to files and file systems. First we focus on file issues: Then we introduce directories as special types of files, and the same issues. Finally, we look at file systems and in particular file system organization and storage allocation.

The OS View of File Types

Files of different types are created by different programs: word processors, compilers, etc. Should the OS recognize file types as a service to the user?

The OS View of File Structure

A file's internal structure depends on the program that created it. A similar question applies here: Should the OS know anything about a file's structure?

Process analogy (we will do this frequently): A process has a particular data structure including text segment, data segment, stack segment, and process management variables. The OS knows a lot about the process structure! Segmented memory management techniques organize the process in memory based on its segmented structure.

File Attributes (data)

Certain file management information must be stored with the file. It is not normally stored in the file itself, but in a directory structure. The kinds of data stored include name, type (sometimes), disk location (for OS use), size, protection, ownership, usage times (creation, last modification, last use).

File Operations

The OS provides system calls through which programmers can work with files. Typical operations include create, delete, rename, execute, open, close, read, write, append, seek, and truncate.

The typical life-cycle of a file goes something like this:

Every read and write operation makes use of the current-file-position pointer.

The Unix system calls for basic file I/O are creat(), open(), read(), write(), lseek(), and close(). Open is the most complex of these, with options for read-only, write-only, read-write, append, truncate, create-if-not-found, and more.

When a file is opened, an entry is added to an OS open-file table.

The OS limits the number of open files a process can have. To test this limit in Unix, write a program containing an infinite loop that opens a file without closing it. The open() system call returns an error value (-1) when your limit is reached.

File Access Methods

File data are accessed either sequentially or directly (randomly).

Addresses in a file may be specified in different units: records, blocks, or bytes.

Directory Structures

Mere mortal users would not be able to effectively manage files were they not organized by partitions and directories (called folders in the Windows world).

The top level of organization is partitions, which are logical storage devices. A physical device may contain one or more partitions; a partition may cover more than one physical device. Sometimes also called volumes.

Each partition contains a device directory, a table with information about all the files it contains. We will also assume the directory can contain other directories, called subdirectories. The directory entry is where file attributes are stored.

Like files, directories have certain defined structures, attributes and operations. Unlike a regular file, it is essential for the OS to be familiar with the internal structure of a directory (its table). Operations such as creating, deleting, reading and writing are applied to a directory but they must be implemented in a special way.

Consider directory deletion. Deleting a non-empty directory requires OS policy -- should the files it contains be deleted too? If not, who should adopt them? Windows deletes them; Unix allows the deletion of a non-empty directory but only through a special command switch which deletes both the directory and its files; DOS prohibits the deletion of a non-empty directory.

Directory operations include:

We assume the directories in a file system form a tree structure. This means the file system has a single root directory which contains files and subdirectories, and the subdirectories in turn contain other files and other subdirectories. Any given file or subdirectory is contained in exactly one directory. A sketch that shows directories and folders as nodes and the "contains" relationship as links would thus resemble a tree.

While working with a file system, each user has a current directory. These contain the files of current interest.

The location of every file can be specified using a pathname which lists each directory in the unique path through the tree to its location. The pathname can either be relative starting from the current directory or absolute starting from the root directory.

The user can traverse the file system using appropriate commands or actions. If commands are used, the absolute or relative pathname of the destination directory can be specified directly.

The problem with tree-structured directories is they do not allow files to be shared among multiple directories. Such shared files would allow all members of a group project to have shared files listed in directories that they individually own. A file system that allows such sharing forms an acyclic graph instead of a tree -- there can be more than one directory path to a given file.

Such sharing is implemented through links. There is one physical copy of the file plus one or more links to it. There are two approaches to implementing links:

Each approach has its issues, particularly where file movements and deletions are concerned.

File System Mounting

One of the OS responsibilities in maintaining a file system is mounting, which maps a physical device to one or more logical partitions (file system entities). This is necessary before a user process can reference the partition. Mounting is done at boot time and may also be done "on the fly" as devices are attached and removed.

File Protection

The protection of files refers to assuring they cannot be "improperly" accessed. This includes assuring that only authorized users may access the file, and assuring that only authorized operations can be performed. The term controlled access refers to allowing access to some users but not others and allowing some operations but not others.

Access controls can be defined for any of the file operations listed above.

Limiting access to authorized users is accomplished by defining an access list for each file that the OS checks before allowing access. Two approaches to implementing the access list are:

The first approach is very precise but is variable length and slow to use and maintain. The second approach is less precise but is fixed length and quick to use and maintain.

File Access Control in Windows

To see Windows file protection, right-click on a file icon and select "Properties". Check the resulting window for the "General" and "Security" tabs. The General tab implements some protections, such as read-only access. The Security tab details which users or groups of users are allowed access, and what access is allowed for them.

File Access Control in Unix/Linux

To see Unix/Linux protection, type the "ls -l" command to produce a detailed listing of files in the current directory. The leftmost column will contain a string of 10 characters consisting of the following characters: -, r, w, x, d. The string actually represents 4 groups of information:

  1. The first character indicates what kind of file it is: - for regular file, d for directory, and a couple others more rarely seen such as l for link and s for socket.
  2. The next 3 characters represent access rights for the file owner. Every file has a owner ID as one of its attributes. There are 3 kinds of access: read, write, and execute. The first of the three characters indicates whether read access is allowed (r) or not (-). The second indicates whether write access is allowed (w) or not (-). The third indicates whether execute access is allowed (x) or not (-).
  3. The next 3 characters represent access rights for the file group. A named group containing a list of its members is separately maintained. Every file has a group ID as one of its attributes. The 3 access rights are defined the same as for owner.
  4. The last 3 characters represent access rights for everyone else, the world. The 3 access rights are defined the same as for owner.
For example, a Unix file with protection code "-rw-r--r--" is a regular file to which everyone has read access but only the owner has write access. A Unix file with protection code "-rwx--x--x" is a regular file which anyone can execute (it is an executable program or script), but only the owner can read or write it. File protection values are set when the file is created, and changed by an authorized user with the chmod (change mode) command or system call.

Part Two: File Systems Implementation

Introduction

OSs provide consistent control and access to secondary storage through a file system. Design of a file system involves multiple layers of concern, here listed from the top-down:

Application programs then interface with the API to use the file system. Examples include Unix command shells, Windows Explorer, word processors, compilers.

We have already covered a significant portion of the file system API: operations for files and directories.

File System Storage Allocation

File space is allocated in logical units called blocks. These are ultimately translated into physical storage locations. In the case of disks, the physical location of a block is an ordered triple: < cylinder, track, sector >. The logical-physical translation is non-trivial. We'll limit our discussion to logical blocks, which are typically 512 or 1024 bytes long.

Assume that disk blocks, like file blocks, are a linear resource numbered sequentially starting at 0. This is analogous to memory frames and process pages; both are numbered sequentially starting at 0.

There are 3 basic strategies for allocating disk blocks to files:

Contiguous allocation

Contiguous allocation has the same properties, advantages and disadvantages as its memory counterpart. Overhead is low (directory entry need only store starting block and length) and both sequential and direct access are fast but finding the right hole (e.g. first fit, best fit) is expensive and external fragmentation results. Files that dynamically grow are also bothersome.

Linked allocation

Any available disk block can be allocated to a file block. There is additional overhead. Directory entry needs only store starting block at minimum, but each data block must contain link to next block. This means the file block and disk block cannot be the same size. The link overhead can be reduced by allocating blocks in multi-block clusters. This however increases internal fragmentation.

Linked allocation supports sequential access well (traversing the linked list) but is dismal for direct access (reduces almost to the mag tape model).

Both the link overhead and direct access problems can be reduced by collecting all links into a single file allocation table (FAT) stored at the beginning of a partition. The FAT contains one entry per disk block and is indexed by disk block number. Each entry contains the link that would otherwise occupy part of the disk block. If the FAT is cached in main memory, direct access becomes considerably faster.

Indexed allocation

Any available disk block can be allocated to a file block. Instead of organizing the blocks into a linked list or collecting the list pointers into a per-partition FAT, the indexed organization collects the list pointers into a per-file table, indexed by the file's block number, called the index block. Each entry contains the corresponding disk block. The index block is kept in the file's directory entry. This is analogous to a process page table.

This solves the direct access problem of linked allocation, since the index block entry of any file block can be reached in one access.

The problem with indexed allocation is how to organize the index block -- the number of entries needed is the same as the file length in blocks. But a file can be as small as one block or as large as the partition itself! This is analogous to the page table size problem. Here are approaches to that problem:

Unix combines direct and indirect indexing. The index block is contained in the inode (short for index node). The inode contains: This supports about 4.2 billion block numbers, and each block is 1K bytes long. The maximum file size is thus 4 terabytes!

How important is this?

The choice of allocation and indexing method is critical to OS performance simply because secondary storage devices are SO SLOW compared to the memory and processing units. Nearly any performance improvement will have significant impact on overall system performance. Suppose an indexing improvement saves 1 millisecond per disk access. During 1 millisecond, the processor possibly executes over 100,000 machine instructions. So even if the improvement requires an additional say 10,000 lines of C code, it is probably worthwhile.

File System Free Space Management

A file system's free-space list organizes (disk) blocks that are available to be allocated to growing files. As with any disk operation, performance issues are critical because the devices are so slow.

Note that the FAT method of linked allocation incorporates the free-space list; it is just one additional linked list.

The greatest performance benefit comes from caching the free-space list in main memory. Coherency is an obvious issue, but there is also the issue of memory requirements. If each block is 1K and a drive's capacity is 60 GB, the drive contains 60 million blocks and thus a drive could easily have a free-space list 50 million or more blocks long!

Note that allocating blocks in clusters cuts the memory requirements considerably.

The free-space list may be implemented as a bit vector. The block number (0 to n) is bit position index into a bit string. If a bit position contains 0, the corresponding block is available (if 1, it is occupied). Advantages is small space required, disadvantage is the variable length of time to find an available block (have to search the vector).

An alternative is to maintain a linked list of free blocks. This is what the FAT does. It could be organized either as a stack or a queue. Either one limits access only to the ends and thus access time is constant.


[ C SC 340 | Peter Sanderson | Math Sciences server  | Math Sciences home page | Otterbein ]

Last updated:
Peter Sanderson (PSanderson@otterbein.edu)