Mounting and Unmounting

Recall from Chapter 8 that the kernel requires a further structure to hold mount and unmount information when working with filesystems — the information is not provided in any of the structures discussed above. The file_system_type structure is used for this purpose and is defined as follows for the Second Extended File System:

fs/ext2/super.c static struct file_system_type ext2_fs_type = {

.owner = THIS_MODULE,

.kill_sb = kill_block_super,

.fs_flags = FS_REQUIRES_DEV,

Chapter 8 explained that the mount system call invokes the function in get_sb to read the superblock of a filesystem. The Second Extended Filesystem relies on a standard function of the virtual filesystem (get_sb_bdev) to do this:

fs/ext2/super.c static int ext2_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt)

return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt);

A function pointer to ext2_fill_super is passed as a parameter for get_sb_bdev. This function fills a superblock object with data that must be read from the hard disk if there is no suitable superblock object in memory.14 In this section, we need therefore only examine the ext2_fill_super function in fs/ext2/super.c. Its code flow diagram is shown in Figure 9-8.

Figure 9-8: Code flow diagram for ext2_fill_super.

ext2_fill_super starts by setting an initial block size for reading the superblock. Because the block size used in the file system is not yet known, the kernel first attempts to find the minimum possible value with the help of sb_min_blocksize. This function normally sets 1,024 bytes as the block size. If, however, the block device has a larger minimum block size, this is used instead.

14This is naturally only the case when the desired filesystem is already mounted on the system but needs to be mounted somewhere else, a comparatively rare occurrence.

The data block in which the superblock is located is then read by sb_bread. This is a wrapper for the

_bread function described in Chapter 16. A simple typecast converts the raw data returned by the function into an instance of type ext2_super_block.15

A check is now made to establish whether the partition used actually contains a Second Extended Filesystem. The magic number stored in the superblock holds the required information. Its value must match that of the ext2_super_magic constant. If the check fails, the mount operation is aborted, and an error message indicates that an attempt was made to mount a non-Ext2 filesystem.

parse_options analyzes the parameters passed to specify mount options (such as the use of access control lists or enhanced attributes). All values are set to their defaults before this is done to ensure that not specifying an option is equivalent to specifying the default value.

A check of the filesystem features reveals whether the kernel is able to mount the filesystem at all, in Read and Write mode, or in Read mode only (the enhancement features of Ext2 are discussed in Section 9.2.2). The bit strings stored in s_feature_ro_compat and s_feature_incompat are compared with the corresponding kernel constants. Two constants are defined for this purpose: ext2_feature_incompat_supp contains all incompatible features together, while ext2_feature_ro_compat contains all bits for compatible features that can only be handled Read Only. Filesystem mounting is rejected if bits are set whose meaning is not clear to the kernel or if any incompatible bits are set. Mounting is also rejected if any of the bits in ext2_feature_ro_compat are set and the mount options do not specify the Read Only flag.

If the filesystem block size stored in s_blocksize does not match the initially specified minimum value, the hard disk is set to this value using set_blocksize, and the superblock is read again. The work of the kernel is simplified if the same block size is used in the filesystem and for data transfer because filesystem blocks can then be read in a single step.

Meta-information on the filesystem that should always reside in memory is held in the ext2_sb_info data structure (described in Section 9.2.2), which is now filled. Generally, this information comprises simple value allocations that copy data from the hard disk into the corresponding elements of the data structure.

The group descriptors are then read in block-by-block and checked for consistency by ext2_check_descriptors.

The last steps when filling superblock information are performed by ext2_count_free_blocks, ext2_count_free_inodes, and ext2_count_dirs, which count the number of free blocks, the number of free inodes, and the number of directories, respectively. These numbers are needed by the Orlov allocator discussed in Section 9.2.4, for instance. Note that the values are stored in an approximative counter that starts with correct initial values, but can deviate slightly from the proper count during operation.

Control is now transferred to ext2_setup_super, which runs several final checks and outputs appropriate warnings (if, e.g., a filesystem is mounted in an inconsistent state, or if the maximum number of mounts without a consistency check has been exceeded). As a final step, ext2_write_super writes the contents of the superblock back to the underlying storage medium. This is necessary because some superblock values are modified during the mount operation — the mount count and date of last mount, for example.

15An offset must be added if the superblock doesn't start at a hardware sector boundary.

Continue reading here: Reading and Generating Data and Indirection Blocks

Was this article helpful?

0 0