Pheonix File System

Physical Media Abstraction Layer - This layer abstracts the physical format of the media into equal-sized logical allocation units called Logical Sectors using the following guidelines:

The Physical Media Abstraction Layer determines Logical Sector size, LogicalSectorSize, which is the number of 8-bit bytes each Logical Sector represents of the physical media. In addition, the Physical Media Abstraction layer determines the number of Logical Sectors used to represent the physical media, NumLogicalSectors; it also determines the function which maps Logical Sectors to physical regions of the media.

It is the sole responsibility of this layer to translate Logical Sectors, used by all higher layer of abstraction and functionality, to physical regions of the media. This is the only layer that should have to concern itself with the details of accessing the physical media. All higher layers have no idea of the working of the hardware nor the physical layout of the media, but rather perform all operations in terms of Logical Sectors assuming the above guidelines for Logical Sector properties.

Logical Sector Allocation - This layer exists to keep track of which logical sectors have been allocated to hold data, which are available, and which are unusable (bad).

Single logical sectors called Free Space Descriptors are used to determine whether a number of sectors are in use or available for use. This is done by using each bit in the Free Space Descriptor to represent whether a single successive logical sector is in use or not (0 indicates the respective logical sector is in use, 1 indicates it is not). The number of logical sectors accounted for per Free Space Descriptor depends on the size of a logical sector (since a Free Space Descriptor is exactly one logical sector in size), but can be determined using the formula

SectorsPerFSD = LogicalSectorSize * 8
Traditionally, PCs have used 512-byte sectors implying that 512*8, or 4096, sectors could be accounted for per Free Space Descriptor. In addition, it needs to be noted that the logical sectors which are used to hold Free Space Descriptors themselves have to be accounted for like any other logical sector. The number of Free Space Descriptors varies based on the number of logical sectors, NumLogicalSectors. Every logical sector MUST be accounted for using a Free Space Descriptor, and it is not possible for the sectors account for by Free Space Descriptors to overlap. Logical sectors used by the Free Space Descriptor Location Table and by the Free Space Descriptors are considered in use and therefore are not available for allocation.

The location of each of the Free Space Descriptors is stored as a series of 64-bit Logical Sector numbers in a consecutive series of sectors ideally stored near the beginning of the storage media. This series of sectors is called the Free Space Descriptor Location Table and each 64-bit entry is the Logical Sector number of the Free Space Descriptor which accounts for a successive series of logical sectors. For example, if LogicalSectorSize is equal to 512 bytes, SectorsPerFSD would then be 4096, as such the first entry in the Free Space Descriptor Location Table (FSDLT) would hold the Logical Sector number of the Free Space Descriptor accountable for the first 4096 sectors (numbered 0 through 4095) and the next entry would hol the Logical Sector number of the Free Space Descriptor accountable for the next 4096 sectors (numbered 4096 through 8091), etc.
      FSDLT         Free Space Descriptors (FSDs)
      .----.
    1 |  o--------->|100010010...100101|  Allocation map for sectors 0 - 4095
      |----|
    2 |  o--------->|000010101...110001|  Allocation map for sectors 4096 - 8091
      |----|
    3 |  o--------->|100100101...001000|  Allocation map for sectors 8092 - 12287
      |----|
      .    .
      .    .
      |----|
    N |  o--------->|001001000...001001|  Allocation map for sectors 4096*N - 4096*(N-1)-1
      `----'
Where N is the number of entries in the Free Space Descriptor table (equal to NumLogicalSectors / SectorsPerFSD, or in this example, NumLogicalSectors / 4096).

The Free Space Descriptor Location Table may span as many sectors as it needs in order to hold the location of all of the Free Space Descriptors, but the sectors must be contiguous. As shown in the table below, the Free Space Descriptor Location Table is very efficient at describing the media and therefore the FSDLT will be relatively small (for example, only 4 kilobytes per gigabyte of capacity given a LogicalSectorSize of 512 bytes). For this reason, it is suggested that any OS implementing the Phoenix File System load and store a copy of the entire Free Space Descriptor Location table in memory for quick reference.

LogicalSectorSize SectorsPerFSD Bytes accounted for per FSD FSD location entries per sector of Free Space Descriptor Location Table Sectors accountable per sector of Free Space Descriptor Location Table Bytes accountable per sector of Free Space Descriptor Location Table
256 bytes2048 sectors16,384 bytes32 entries65,536 sectors16,777,216 bytes
512 bytes4096 sectors32,768 bytes64 entries262,144 sectors134,217,728 bytes
1024 bytes8192 sectors65,536 bytes128 entries1,048,576 sectors1,073,741,824 bytes
2048 bytes16384 sectors131,072 bytes256 entries4,194,304 sectors8,589,934,592 bytes
4096 bytes32768 sectors262,144 bytes512 entries16,777,216 sectors68,719,476,736 bytes
8192 bytes65536 sectors524,288 bytes1024 entries67,108,864 sectors549,755,813,888 bytes


The suggested arangement for the Free Space Descriptors in relation to the logical sectors they describe is that for even indexed Free Space Descriptors the Free Space Descriptor is located in the first sector it describes and for odd indexed Free Space Descriptor the Free Space Descriptor is located in the last sector it describes; this maximizes the number of contiguous sectors for allocation and minimizes the distance, and thus the seek time, between Free Space descriptors and the data they describe. This is by no means the only way to arrange the Free Space Descriptors, Free Space Descriptors need not even reside in the region they describe, but whenever possible it would be considered desireable to place Free Space Descriptors near the sectors they account for in order to minimize access times.

Bad Sector Recovery: when a given media is first formatted, the Free Space Descriptors are located only in "good" sectors (ie. not bad) and bad sectors are marked as used and recorded in a special Bad Sector List described below. Should a sector be found to be bad after formatting, the given sector should be marked as in use in the appropriate Free Space Descriptor and added to the Bad Sector List. However, if the bad sector is detected at the location of a Free Space Descriptor then major error recovery methods need to be employed resulting in the sector being added to the Bad Sector List and the Free Space Descriptor being moved to the a free good sector (or possibly moving data from a used sector to a free sector and then locating the Free Space Descriptor there so as to minimize the distance between the Free Space Descriptor and the data it describes).

File Allocation Layer - This layer exists to group logical sectors into units called files, a file is a collection of information that logically related. In the Phoenix File System, files are described using a tree structure where that tree leafs hold the actual file information. Each node and leaf of the data tree is described using a Tree Node Descriptor:

  Structure of a Tree Node Descriptor:
  Offset   Size         Field Name     Description
    0h     QWORD        
             bit     0: Type	       (1) Descriptor refers to SubTree block (internal node)
				       (0) Descriptor refers to data block (leaf)
             bits 1-63: Location       Logical Sector number for block location
    8h	   QWORD	Length	       If Type is 1, is total number of bytes described by SubTree
				       If Type is 0, is number of bytes in data block
  ----------------
  Total: 16 bytes
Where each block of information is exactly 1 logical sector in size and can hold information either about the files contents (a tree leaf) or about the location of additional blocks (a tree node). If a sector is a data block, Length bytes of the sector are considered to be part of the file's contents. If a sector is a SubTree block, it is simply a consecutive list of Tree Node Descriptors and the Length field represents the total number of bytes of the file's information that is described by all data blocks in or under the SubTree.

Sparse files: a portion of a file is considered 'sparse' when information is stored after a region, but not explicitly in the given region. This can occur, for example, if a new file is created, then a seek if performed to 1000 bytes into the file, and then a single byte is written and the file is closed. The total length of the file would be 1001 bytes, even though only 1 byte of information is actually stored in the file; the first 1000 bytes are considered sparse. The Phoenix File System is efficient is storing files with sparse data by making note of the condition using a Tree Node Descriptor. The Type indicates the region of the file is a data block since it actually refers to the file's contents. The Length is the number of bytes in the sparse region, and the Location has the special reserved value of 0. (Location value 0 is considered reserved in the File Allocation Layer because logical sector 0 will always hold the Media Descriptor Block for the device). There cannot exist a sparse subtree as it would be illogical. Any information read from a sparse file region will always be 0. A sparse region 0 bytes in length is used to indicate a Tree Node Descriptor is not in use (entire Tree Node Descriptor is all zeros).

The basic properties of a file are described using a File Node with the following structure:
  Structure of a File Node:
  Offset   Size         Field Name     Description
   00h     DWORD	MagicNumber    Special number to help discern a File Node from other
				       data should the file system become corrupt, equal to
                                       31534650h
   04h	   DWORD	HardLinks      Number of references made from Directories to this file
   08h     DWORD	Flags	       Low-level file flags
             bits 0,1 : InternalFlag   Indicates what file information, if any, is stored
				       internally if the File Node
				         00 = no internal data
				         01 = internal rights information
					 10 = internal extended attributes
					 11 = internal file data
             bits 2,3 : (reserved)     must be 0
             bit    4 : NodeSize       Indicates whether or not the File Node occupies the full
				       logical sector
                                          0 = File Node is half the size of the logical sector
				          1 = File Node occupies the entire logical sector
             bits 5-63: (reserved)     must be 0
   0Ch	   DWORD	(reserved)     must be 0
   10h     QWORD	FileSize       Total length of file data
   18h     1 TND        Rights         Rights list data tree
   28h     2 TNDs       EAs            Extended Attributes data tree
   48h     7 TNDs       FileData       File contents data tree
   B8h     x BYTES      InternalData   minimum of 72 bytes of space specifically set aside for
				       storing small amounts of data inside the File Node
				       without using data trees. The InternalFlag determines
				       which information, if any, is stored internally.
A file node is always at most 1 logical sector in size and at least 256 bytes in size, as such, the amount of space reserved for internal data with a File Node can vary from 72 bytes to LogicalSectorSize-184 bytes in size. A File Node may occupy an entire sector or only half of a sector, the latter only being valid for LogicalSectorSizes of 512-bytes or more (since one half of 512 bytes is 256 bytes, the minimum size of a File Node). Furthermore, each File Node is identified using a File Node Number of which bits 1-63 indicate the logical sector number the File Node resides in, and bit 0 is clear if the File Node is in the first half of the sector and is 1 if the File Node is in the second half of the sector. The following table summarizes the minimum and maximum sizes of File Nodes and the amount of space reserved in each File Node for internal data, based on the size of a logical sector.

LogicalSectorSize Supports halfing logical sector Minimum File Node Size Maximum File Node Size Minimum Internal Data Reserve Maximum Internal Data Reserve
256 bytesNo256 bytes256 bytes72 bytes72 bytes
512 bytesYes256 bytes512 bytes72 bytes328 bytes
1024 bytesYes512 bytes1024 bytes328 bytes840 bytes
2048 bytesYes1024 bytes2048 bytes840 bytes1864 bytes
4096 bytesYes2048 bytes4096 bytes1864 bytes3912 bytes
8192 bytesYes4096 bytes8192 bytes3912 bytes8008 bytes


When data is stored internally, the field(s) that would ordinarilly used to store Tree Node Descriptor(s) for the given data are instead overwritten with a portion of the internal data. This can be safely done since the InternalFlag identifies which data is stored internally, and if the data is being stored internally, then the external data Tree Node Descriptor field(s) are not used, thereby leaving them available to store additional internal data. The space normally reserved for the Tree Node Descriptors is first used in the storage of internal data before utilizing the space specifically reserved for internal data. If the Rights List or Extended Attributes are stored internally, the first two bytes of the internal data are the length of the remaining internal data in bytes; the remainder of the internal data is the actual information to be stored internally. In the case of internal file data, the FileSize field can be consulted to determine the amount of internal data, and as such two bytes are not prepended to the internal data. The following table shows the maximum amount of internal data that can be stored in a File Node utilizing this optimization; it should be noted that this efficient use of File Node space is not a feature that can be optionally implemented, but is a standard component of the Phoenix File System.

LogicalSectorSize Maximum Internal Data Reserve Maximum Internal Rights Info Maximum Internal Extended Attributes Minimum Internal File Data
256 bytes72 bytes86 bytes (88 total)102 bytes (104 total)184 bytes
512 bytes328 bytes342 bytes (344 total)358 bytes (360 total)440 bytes
1024 bytes840 bytes854 bytes (856 total)870 bytes (872 total)952 bytes
2048 bytes1864 bytes1878 bytes (1880 total)1894 bytes (1896 total)1976 bytes
4096 bytes3912 bytes3926 bytes (3928 total)3942 bytes (3944 total)4024 bytes
8192 bytes8008 bytes8022 bytes (8024 total)8038 bytes (8040 total)8120 bytes


Of the three sets of information stored per file, the Rights list and Extended Attributes formats are operating system defined and not directly visible to user software, however the file data is not operating system defined. This makes sense since the primary purpose of a file is to store information relavent to the user and therefore is not necessarilly of interest to the function of the operating system, such information can include executables, word processor documents, configuration files, etc. A Rights list is maintained to determine which users or groups of users have access to that information, and Extended Attributes are maintained to give system add-ons a storage area for additional file properties.

Rights list format: blah blah blah

Extended Attributes format: blah blah blah