The Linux file system architecture is an interesting example of abstracting complexity. Using a common set of API functions, a large variety of file systems can be supported on a large variety of storage devices. Take, for example, the
readfunction call, which allows some number of bytes to be read from a given file descriptor. The
readfunction is unaware of file system types, such as ext3 or NFS. It is also unaware of the particular storage medium upon which the file system is mounted, such as AT Attachment Packet Interface (ATAPI) disk, Serial-Attached SCSI (SAS) disk, or Serial Advanced Technology Attachment (SATA) disk. Yet, when the
readfunction is called for an open file, the data is returned as expected. This article explores how this is done and investigates the major structures of the Linux file system layer.
A file system is an organization of data and metadata on a storage device. With a vague definition like that, you know that the code required to support this will be interesting. As I mentioned, there are many types of file systems and media. With all of this variation, you can expect that the Linux file system interface is implemented as a layered architecture, separating the user interface layer from the file system implementation from the drivers that manipulate the storage devices.
File systems as protocols
Associating a file system to a storage device in Linux is a process called mounting. The
mountcommand is used to attach a file system to the current file system hierarchy (root). During a mount, you provide a file system type, a file system, and a mount point.
To illustrate the capabilities of the Linux file system layer (and the use of mount), create a file system in a file within the current file system. This is accomplished first by creating a file of a given size using
dd(copy a file using /dev/zero as the source) -- in other words, a file initialized with zeros, as shown in Listing 1.
$ dd if=/dev/zero of=file.img bs=1k count=10000 10000+0 records in 10000+0 records out $
You now have a file called file.img that's 10MB. Use the
losetupcommand to associate a loop device with the file (making it look like a block device instead of just a regular file within the file system):
$ losetup /dev/loop0 file.img $
With the file now appearing as a block device (represented by /dev/loop0), create a file system on the device with
mke2fs. This command creates a new second ext2 file system of the defined size, as shown in Listing 2.
$ mke2fs -c /dev/loop0 10000 mke2fs 1.35 (28-Feb-2004) max_blocks 1024000, rsv_groups = 1250, rsv_gdb = 39 Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 2512 inodes, 10000 blocks 500 blocks (5.00%) reserved for the super user ... $
The file.img file, represented by the loop device (
/dev/loop0), is now mounted to the mount point /mnt/point1 using the
mountcommand. Note the specification of the file system as
ext2. When mounted, you can treat this mount point as a new file system by doing using an
lscommand, as shown in Listing 3.
$ mkdir /mnt/point1 $ mount -t ext2 /dev/loop0 /mnt/point1 $ ls /mnt/point1 lost+found $
As shown in Listing 4, you can continue this process by creating a new file within the new mounted file system, associating it with a loop device, and creating another file system on it.
$ dd if=/dev/zero of=/mnt/point1/file.img bs=1k count=1000 1000+0 records in 1000+0 records out $ losetup /dev/loop1 /mnt/point1/file.img $ mke2fs -c /dev/loop1 1000 mke2fs 1.35 (28-Feb-2004) max_blocks 1024000, rsv_groups = 125, rsv_gdb = 3 Filesystem label= ... $ mkdir /mnt/point2 $ mount -t ext2 /dev/loop1 /mnt/point2 $ ls /mnt/point2 lost+found $ ls /mnt/point1 file.img lost+found $
From this simple demonstration, it's easy to see how powerful the Linux file system (and the loop device) can be. You can use this same approach to create encrypted file systems with the loop device on a file. This is useful to protect your data by transiently mounting your file using the loop device when needed.
|badblocks||Used to search a disk or partition for badblocks.|
|cfdisk||Similar to fdisk but with a nicer interface.|
|debugfs||Allows direct access to filesystems data structure.|
|df||Shows the disk free space on one or more filesystems.|
|dosfsck||Check and repair MS-Dos filesystems.|
|du||Shows how much disk space a directory and all its files contain.|
|dump||Used to back up an ext2 filesystem. Complement is restore.|
|dumpe2fs||Dump filesystem superblock and blocks group information. Ex: dumpe2fs /dev/hda2|
|e2fsck||Check a Linux second extended filesystem.|
|e2label||Change the label on an ext2 filesystem.|
|exportfs||Used to set up filesystems to export for nfs (network file sharing).|
|fdisk||Used to fix or create partitions on a hard drive.|
|fdformat||Formats a floppy disk.|
|fsck||Used to add new blocks to a filesystem. Must not be run on a mounted file system.|
|hdparm||Get/set hard disk geometry parameters, cylinders, heads, sectors.|
|mkfs||Initializes a Linux filesystem. This is a front end that runs a separate program depending on the filesystem's type.|
|mke2fs||Create a Linux second extended filesystem.|
|mkswap||Sets up a Linux swap area on a device or file.|
|mount||Used to mount a filesystem. Complement is umount.|
|rdev||Query/set image root device, swap device, RAM disk size of video mode. What this does is code the device containing the root filesystem into the kernel image specified.|
|rdump||Same as dump.|
|rmt||Remote magtape protocol module.|
|restore||Used to restore an ext2 filesystem.|
|setfdprm||Set floppy drive parameters.|
|swapoff(8)||Used to de-activate a swap partition.|
|swapon(8)||Used to activate a swap partition.|
|sync||Forces all unwritten blocks in the buffer cache to be written to disk.|
|tune2fs||Adjust tunable filesystem parameters on second extended filesystems.|
|umount||Unmounts a filesystem. Complement is mount.|