Version 6 (modified by 10 years ago) (diff) | ,
---|
GIET_VM / FAT32 File System
This section describes GIET_VM system calls and user libraries. The multi-threaded applications have been designed to analyse the TSAR manycore architecture scalability.
1) General Principles
This implementation supports only block devices with block_size = 512 bytes.
The max file size is 4 Gbytes. In the context of the FAT32, a cluster is the smallest storage allocation unit on the block device : any file (or directory) occupies at least one cluster, and one cluster cannot be shared by 2 different files.
This implementation supports only one cluster_size = 4 Kbytes (i.e. 8 blocks).
The FAT region on the block device is an array of 32 bits words defining the linked list of clusters allocated to given file in the DATA region of the block device. Each slot in this array contains a cluster_ptr, that is the index of the cluster on the block device. The cluster_ptr value cannot be larger than 0x0FFFFFFF (i.e. 256 M). The max addressable storage capacity in the DATA region on the block device is therefore (256 M * 4 Kbytes) = 1 Tbytes.
This implementation uses define four data structures:
- The File-Cache and Fat-Cache are dynamically allocated memory caches, implemented in the distributed kernel heap.
There is actually one cache per file (File_Cache), and one cache for the FAT itself (called Fat_Cache). The cache size is not fixed: it is dynamically increased from the kernel heap as required by the read / write access to the files or to the FAT itself. The memory allocated to a given cache_file is only released when the file is closed.
- The Inode-Tree is an internal representation of the FAT. It is a sub-tree of the File System tree. Each node define a file or a directory, and contains a pointer on the associated File-Cache. This Inode-Tree is dynamically increased from the distributed kernel heap when a file or a directory is accessed. The memory allocated to the Inode-Tree is only released in case of system crash.
- The File-Descriptor-Array is a statically defined array of file descriptors. According to the UNIX semantic, a private file descriptor is allocated to a task requiring to open a file, and contains mainly the current file pointer (called offset). The max number of file descriptors is defined by the GIET_OPEN_FILES_MAX global variable (in the get_config.h file).
- The global Fat_Descriptor contains general information such as the FAT region lba and size, the DATA region lba and size, and pointers on the Fat-Cache or Inode-Tree.
WARNING 1: A node name (file or directory) cannot be larger than 38 characters.
WARNING 2: There is no rescue mechanism at the moment in case of heap overflow: The system crash with a nice error message on the kernel terminal...
2) Cache Structure
The fat_cache and the file_cache have the same organisation. Each cache contains an integer number of clusters, as the cluster is the smallest unit of data that can be loaded from the block device to the cache. To reduce the access time, this set of clusters is organized as a 64-Tree: each node has one single parent and (up to) 64 children. The leaf nodes are the cluster descriptors. To access a given cluster in a given file, we use the cluster_id (index of cluster inside the file), that is different from the cluster_ptr index of cluster on the block device. This cluster_id must be split in pieces of 6 bits, that are used to access the proper children at a given level in the 64-Tree. The depth (number of levels) of the 64-Tree depends on the file size :
File Size | levels |
up to 256 Kbytes | 1 |
from 256 Kbytes to 16 Mbytes | 2 |
from 16 Mbytes to 1 Gbytes | 3 |
larger than 1 Gbytes | 4 |
3) Write Policy
For the File_Cache, the GIET_VM implements a WRITE-BACK policy. In case of write, the data are always modified in the cache. In case of miss, new clusters are allocated to the target file, the cache is updated from the block device, and the data are modified in the cache, but not on the block device. The modified clusters are written on the block device only when the file is closed, using the dirty flag implemented in each cluster descriptor.
For the Fat_Cache, the GIET_VM implements a WRITE-THROUGH policy. When the FAT content is modified (i.e. when new clusters are allocated to an existing file, or when a new file (or directory) is created, the modifications are written in the fat_cache (that must be updated in case of miss), and are immediately reported to the block device, for each modified block.
4) Block Device Drivers
To support various block device peripheral, this FAT32 implementation defines a generic _fat_ioc_access() function to access the physical block device. This function transfer one or several blocks between the block device and the file_cache by calling the relevant driver.
int _fat_ioc_access( unsigned int use_irq , unsigned int to_mem , unsigned int lba , unsigned int buf_vaddr , unsigned int count )
- use_irq : boolean (use descheduling mode if supported by the IOC driver)
- to_mem : boolean (from block device to memory if non zero)
- lba : logical block address on block device
- buf_vaddr : memory buffer virtual address
- count : number of blocks to be transferred
5) Access Functions
int _fat_init( unsigned int use_irq )
This function initializes the statically defined FAT structures:
- Fat-Descriptor
- File-Descriptors-Array
- Fat_Cache root
- Inode_Tree root
As is called by the boot-loader, and by the kernel_init, it does not use dynamic memory allocation. The polling/descheduling mode is defined by the use_irq argument. It use informations found in the boot sector and FS-INFO sector, that are loaded in the FAT 512 bytes buffer. It returns 0 if success / It returns -1 if failure.
int _fat_open( unsigned int use_irq , char* pathname )
This function implements the giet_fat_open() system call. The semantic is similar to the UNIX open() function, but the UNIX flags and access rights are not supported. If the file does not exist in the specified directory, it is created, and both the Inode-Tree, the Fat-Cache and the FAT region on device true are updated.. If the specified directory does not exist, an error is returned. In case of success, It allocates a private file descriptor to the calling task, and the reference count is updated.
- use_irq : boolean (use descheduling mode if supported by the IOC driver)
- pathname : define both the specified directory and the file name.
It returns the file descriptor index if success / It returns -1 if failure.
int _fat_close( unsigned int fd_id )
This function implements the "giet_fat_close()" system call. The semantic is similar to the UNIX "close()" function. It decrements the inode reference count, and release the fd_id entry in the file descriptors array. If the reference count is zero, it writes all dirty clusters on block device, and releases the memory allocated to the file_cache.
- fd_id : file descriptor index
It returns 0 if success / It returns -1 if failure.