Mounting the Filesystem

Once all kernel-internal data that describe the structure and contents of the proc filesystem have been initialized, the next step is to mount the filesystem in the directory tree.

In the view of the system administrator in userspace, mounting /proc is almost the same as mounting a non-virtual filesystem. The only difference is that an arbitrary keyword (usually proc or none) is specified as the source instead of a device file:

[email protected] # mount -t proc proc /proc

The VFS-internal processes involved in mounting a new filesystem are described in detail in Chapter 8, but as a reminder are summarized below. When it adds a new filesystem, the kernel uses a linked list that is scanned to find an instance of file_system_type associated with the filesystem. This instance provides information on how to read in the filesystem superblock. For proc, the structure is initialized as follows:

fs/proc/root.c static struct file_system_type proc_fs_type = { .name = "proc",

.kill_sb = kill_anon_super,

The filesystem-specific superblock data are used to fill a vfsmount structure so that the new filesystem can be incorporated in the VFS tree.

As the source code extract above shows, the superblock of the proc filesystem is supplied by proc_get_sb. The function builds on a further kernel auxiliary routine (get_sb_single) that enlists the help of proc_fill_super to fill a new instance of super_block.

proc_fill_super is not very complex and is mainly responsible for filling the super_block elements with defined values that never change:

fs/proc/inode.c int proc_fill_super(struct super_block *s, void *data, int silent) {

struct inode * root_inode;

s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops;

root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); s->s_root = d_alloc_root(root_inode);

return 0;

The block size cannot be set and is always 1,024; as a result, s_blocksize_bits must always be 10 because 210 equals 1,024.

With the help of the pre-processor, the magic number used to recognize the filesystem is defined as 0x9fa0. (This number is not actually needed in the case of proc because data do not reside on a storage medium but are generated dynamically.)

More interesting is the assignment of the proc_sops superblock operations that group together the functions needed by the kernel to manage the filesystem:

fs/proc/inode.c static struct super_operations proc_sops = {

.alloc_inode

.destroy_inode

.read_inode

.drop_inode

.delete_inode

.statfs

.remount fs proc_alloc_inode, proc_destroy_inode, proc_read_inode, generic_delete_inode, proc_delete_inode, simple_statfs, proc_remount,

The next two lines of proc_fill_super create an inode for the root directory and use d_alloc_root to convert it into a dentry that is assigned to the superblock instance; here it is used as the starting point for lookup operations in the mounted filesystem, as described in Chapter 8.

In the main, the proc_get_inode function used to create the root inode fills several inode structure values to define, for example, the owner and the access mode. Of greater interest is the static proc_dir_entry instance called proc_root; when it is initialized, it gives rise to data structures with relevant function pointers:

fs/proc/root.c struct proc_dir_entry proc_root = {

.low_ino = PROC_ROOT_INO,

.proc_iops = &proc_root_inode_operations,

.proc_fops = &proc_root_operations,

.parent = &proc_root,

The root inode differs from all other inodes of the proc file system in that it not only contains "normal" files and directories (even though they are generated dynamically), but also manages the process-specific PID directories that contain detailed information on the individual system processes, as mentioned above. The root inode therefore has its own inode and file operations, which are defined as follows:

fs/proc/root.c

* The root /proc directory is special, as it has the

* <pid> directories. Thus we don't use the generic

* directory handling functions for that..

static struct file_operations proc_root_operations = { .read = generic_read_dir,

.readdir = proc_root_readdir,

* proc root can do almost nothing..

static struct inode_operations proc_root_inode_operations = { .lookup = proc_root_lookup,

.getattr = proc_root_getattr,

generic_read_dir is a standard virtual filesystem function that returns -EISDIR as an error code; this is because directories cannot be handled like normal files in order to get data from them. Section 10.1.5 describes how proc_root_lookup functions.

Continue reading here: Managing proc Entries

Was this article helpful?

0 0