Use the/proc file system to access the content of the Linux Kernel

Source: Internet
Author: User

Introduction to using the/proc file system to access the Linux kernel:/proc file system is a virtual file system, through which you can use a new method in Linux®The kernel space communicates with the user space. In the/proc file system, we can read and write virtual files as a means to communicate with the kernel entity, but unlike normal files, the contents of these virtual files are dynamically created. This article introduces the/proc Virtual File System and shows its usage. The/proc file system was initially developed to provide information about processes in the system. However, because this file system is very useful, many elements in the kernel also start to use it to report information or enable dynamic runtime configuration. The/proc file system contains directories (used as the organization information) and virtual files. Virtual files can present some information in the kernel to users, and can also be used as a means to send information from the user space to the kernel. In fact, we do not need to implement these two points at the same time, but this article will show you how to configure the file system for input and output. Although a short article like this article cannot detail all the usage of/proc, it still shows the usage of these two methods, so that we can understand how powerful/proc is. Listing 1 is the result of an interactive query on some elements in/proc. It displays the content in the root directory of the/proc file system. Note: On the left is a series of numbers. Each is actually a directory, indicating a process in the system. Since the first process created in GNU/Linux is the init process, its process-id is 1. Then execute an ls command on this Directory, which will display many files. Each file provides detailed information about this special process. For example, to view the content of the command-line item of init, you only need to execute the cat command on the cmdline file. Other interesting files in/proc include cpuinfo, which identifies the processor type and speed; pci, which indicates the devices found on the PCI bus; modules, identifies the module currently loaded to the kernel. Listing 1. interaction Process on/proc [root @ plato] # ls/proc 1 2040 2347 2874 474 fb mdstat sys104 2061 2356 2930 2073 9 filesystems meminfo sysrq-trigger113 2375 2933 2409 acpi fs misc sysvipc1375 21 2934 buddyinfo ide modules tty1395 2189 2445 2935 bus interrupts mounts uptime1706 2201 2514 2938 running line iomem mtrr version179 2211 2515 2947 cpuinfo ioports net vmstat180 2223 2607 3 crypto irq partitions181 2278 26 08 3004 devices kallsyms pci182 2291 2609 3008 diskstats kcore self2 2301 263 3056 dma kmsg slabinfo2015 2311 2805 394 driver loadavg stat2019 2337 2821 4 execdomains locks swaps [root @ plato 1] # ls/proc/ 1 auxv cwd exe loginuid mem oom_adj root statm task1_line environ fd maps mounts oom_score stat status wchan [root @ plato] # cat/proc/1/cmdline init [5] [root @ plato] # Listing 2 shows the process of reading and writing a virtual file in/proc. In this example, check the current settings of IP Forwarding in the kernel's TCP/IP stack, and then enable this function. List 2. read/write/proc (configure the kernel) [root @ plato] # cat/proc/sys/net/ipv4/ip_forward 0 [root @ plato] # echo "1">/proc/sys/net/ipv4/ip_forward [root @ plato] # cat/proc/sys/net/ipv4/ip_forward 1 [root @ plato] # In addition, we can also use sysctl to configure these kernel entries. For more information about this issue, see references. By the way, the/proc file system is not the only Virtual File System in the GNU/Linux system. In this system, sysfs is a file system similar to/proc, but it is better organized (a lot of lessons learned from/proc ). However,/proc has established its own position, so even if sysfs has some advantages over/proc,/proc will still exist. There is also a debugfs file system, but (as the name suggests) it provides more debugging interfaces. One advantage of debugfs is that it is very easy to export a value to the user space (in fact, this is just a call ). Kernel module Introduction: The loadable kernel module (LKM) is a simple method for displaying/proc file systems, this is because this is a new way to dynamically add or delete code to or from the Linux kernel. LKM is also a popular mechanism used in Linux kernel for device drivers and file systems. If you have re-compiled the Linux kernel, you may find that many device drivers and other kernel elements are compiled into modules during Kernel configuration. If a driver is directly compiled into the kernel, its code and static data occupy part of the space even if the driver is not running. However, if the driver is compiled into a module, the memory space will be occupied only when the memory is required and loaded into the kernel. Interestingly, for LKM, we will not notice any performance differences, so this is a powerful means to create a kernel suitable for your environment, in this way, the corresponding modules can be loaded based on the available hardware and connected devices. The following is a simple LKM that helps you understand the difference between it and the standard (non-Dynamically Loaded) code seen in the Linux kernel. Listing 3 shows the simplest LKM. (You can download this code from the download section of this article ). Listing 3 includes the required module header (which defines the module's APIs, types, and macros ). Then the le_license is used to define the license used by this module. Here, we define GPL to prevent contamination to the kernel. Listing 3 then defines the init and cleanup functions of this module. The my_module_init function is called when the module is loaded and used for initialization. The my_module_cleanup function is called when the module is detached. It is used to release memory and clear traces of this module. Note the usage of printk: This is the kernel's printf function. The KERN_INFO symbol is a string that can be used to filter information that enters the kernel loop buffer (very similar to syslog ). Finally, listing 3 uses the module_init and module_exit macros to declare the entry and exit functions. In this way, we can name the init and cleanup functions of this module according to our own wishes, but we will eventually tell the kernel that the maintenance functions are these functions. Listing 3. A simple but working LKM (simple-lkm.c) # include <linux/module. h>/* Defines the license for this LKM */MODULE_LICENSE ("GPL");/* Init function called on module entry */int my_module_init (void) {printk (KERN_INFO "my_module_init called. module is now loaded. \ n "); return 0;}/* Cleanup function called on module exit */void my_module_cleanup (void) {printk (KERN_INFO" my_module_cleanup called. module I S now unloaded. \ n "); return;}/* Declare entry and exit functions */module_init (my_module_init); module_exit (my_module_cleanup); Listing 3 is very simple, but it is a real LKM. Now let's compile it and test it on a 2.6 kernel. The kernel version 2.6 introduces a new method for kernel module compilation. I found this method is much easier than the original method. For the file simple-lkm.c, we can create a makefile with the only content as follows: obj-m + = simple-lkm.o to compile LKM, use the make command, as shown in Listing 4. Listing 4. compile LKM [root @ plato] # make-C/usr/src/linux-'uname-R' SUBDIRS = $ PWD modules make: entering directory '/usr/src/linux-2.6.11' CC [M]/root/projects/misc/module2.6/simple/simple-lkm.o Building modules, stage 2. modpost cc/root/projects/misc/module2.6/simple/simple-lkm.mod.o LD [M]/root/projects/misc/module2.6/simple/simple-lkm.komake: leaving directory '/usr/src/linux-2.6.11' [root @ plato] # result Generates a simple-lkm.ko file. This new naming convention can help distinguish these kernel objects (LKM) from standard objects. Now you can load or Uninstall this module and view its output. To load this module, run the insmod command. To uninstall this module, run the rmmod command. Lsmod displays the currently loaded LKM (see listing 5 ). Listing 5. insert, check, and delete LKM [root @ plato] # insmod simple-lkm.ko [root @ plato] # lsmod Module Size Used bysimple_lkm 1536 0autofs4 26244 0 video 13956 0 button 5264 0 battery 7684 0ac 3716 0yenta_socket 18952 3rsrc_nonstatic 9472 1 yenta_socketuhci_hcd 32144 0i2c_piix4 7824 0dm_mod 56468 3 [root @ plato] # rmmod simple-lkm [root @ plato] # note, the output of the kernel is included in the kernel loop buffer instead of being printed to stdout, because stdout is a process-specific environment. To view messages in the kernel loop buffer, you can use the dmesg tool (or use the cat/proc/kmsg command through/proc itself ). Listing 6 shows the last few messages displayed by dmesg. Listing 6. view kernel output from LKM [root @ plato] # dmesg | tail-5 cs: IO port probe 0xa00-0xaff: clean. eth0: Link is downeth0: Link is up, running at 100 Mbit half-duplexmy_module_init called. module is now loaded. my_module_cleanup called. module is now unloaded. [root @ plato] # You can view the message of this module in the kernel output. Now let's leave this simple example to look at a few kernel APIs that can be used to develop LKM. Standard APIs that can be used by kernel programmers integrated into the/proc file system, and can also be used by LKM programmers. LKM can even export new variables and functions used by the kernel. The complete introduction to APIS is beyond the scope of this article. Therefore, we will briefly introduce the several elements used to demonstrate a more useful LKM. Use the create_proc_entry function to create and delete/proc items and create a virtual file in the/proc file system. This function can receive a file name, a set of permissions, and the location where the file appears in the/proc file system. The returned value of create_proc_entry is a proc_dir_entry pointer (or NULL, indicating an error occurred in create ). Then, you can use the returned pointer to configure other parameters of the virtual file, for example, the function that should be called during the read operation on the file. The prototype of create_proc_entry and a part of the proc_dir_entry structure are shown in listing 7. Listing 7. struct proc_dir_entry * create_proc_entry (const char * name, mode_t mode, struct proc_dir_entry * parent); struct proc_dir_entry {const char * name; // virtual file namemode_t mode; // mode permissionsuid_t uid; // File's user idgid_t gid; // File's group idstruct inode_operations * proc_iops; // Inode operations functionsstruct file_operations * proc_fops; // File operations Functionsstruct proc_dir_entry * parent; // Parent directory... read_proc_t * read_proc; // proc read functionwrite_proc_t * write_proc; // proc write functionvoid * data; // Pointer to private dataatomic_t count; // use count ...}; void remove_proc_entry (const char * name, struct proc_dir_entry * parent); later we can see how to use the read_proc and write_proc commands to insert functions for reading and writing the Virtual File. To delete an object from/proc, you can use the remove_proc_entry function. To use this function, we need to provide the file name string and the location of the file in the/proc file system (parent ). The function prototype is shown in listing 7. The parent parameter can be NULL (indicating the/proc root directory) or many other values, depending on where we want to put the file. Table 1 lists other parent proc_dir_entry that can be used and their locations in the file system. Table 1. proc_dir_entry: Specifies the position of proc_root_fs/procproc_net/proc/netproc_bus/proc/busproc_root_driver/proc/driver in the file system. You can use the write_proc function to write an item to/proc. The prototype of this function is as follows: int mod_write (struct file * filp, const char _ user * buff, unsigned long len, void * data ); the filp parameter is actually an open file structure (we can ignore this parameter ). The buff parameter is the string data that is passed to you. The buffer address is actually a user space buffer, so we cannot directly read it. The len parameter defines how much data is written into the buff. The data parameter is a pointer to private data (see listing 7 ). In this module, we declare a function of this type to process the incoming data. Linux provides a set of APIs to move data between the user space and the kernel space. For write_proc, we use the copy_from_user function to maintain user space data. The read callback function can be used to read data from A/proc entry (from the kernel space to the user space ). The prototype of this function is as follows: int mod_read (char * page, char ** start, off_t off, int count, int * eof, void * data ); the page parameter is the location where the data is written. count defines the maximum number of characters that can be written. When returning multi-page data (usually a page is 4 kb), we need to use the start and off parameters. After all data is written, you need to set the eof parameter ). Similar to write, data indicates private data. The page buffer provided here is in the kernel space. Therefore, we can directly write data without calling copy_to_user. You can also use proc_mkdir, symlinks, and proc_symlink to create directories in the/proc file system. For simple/proc items that only require one read function, you can use create_proc_read_entry to create a/proc item and initialize the read_proc function in a call. The prototype of these functions is shown in listing 8. Listing 8. other useful/proc functions/* Create a directory in the proc filesystem */struct proc_dir_entry * proc_mkdir (const char * name, struct proc_dir_entry * parent ); /* Create a symlink in the proc filesystem */struct proc_dir_entry * proc_symlink (const char * name, struct proc_dir_entry * parent, const char * dest ); /* Create a proc_dir_entry with a read_proc_t in one call */struct proc_dir_entry * create_proc_re Ad_entry (const char * name, mode_t mode, struct proc_dir_entry * base, read_proc_t * read_proc, void * data ); /* Copy buffer to user-space from kernel-space */unsigned long copy_to_user (void _ user * to, const void * from, unsigned long n ); /* Copy buffer to kernel-space from user-space */unsigned long copy_from_user (void * to, const void _ user * from, unsigned long n ); /* Allocate a 'equalally 'conti Guous block of memory */void * vmalloc (unsigned long size);/* Free a vmalloc 'd block of memory */void vfree (void * addr ); /* Export a symbol to the kernel (make it visible to the kernel) */EXPORT_SYMBOL (symbol);/* Export all symbols in a file to the kernel (declare before module. h) */EXPORT_SYMTAB implements fortune distribution through the/proc file system. The following is an LKM that supports reading and writing. This simple app provides a fortune dessert distribution. After loading this module, you can use the echo command to import text wealth to it, and then use the cat command to read it one by one. Listing 9 provides basic module functions and variables. The init function (init_fortune_module) is responsible for allocating space for this vertex Tank Using vmalloc, and then clearing all of it using memset. Using the allocated and cleared cookie_pot memory, we created a proc_dir_entry in/proc and called it fortune. After proc_entry is successfully created, the local variables and the proc_entry structure are initialized. We loaded the/proc read and write Functions (as shown in listing 9 and 10) and determined the owner of the module. The cleanup function simply removes this item from the/proc file system and then releases the memory occupied by cookie_pot. Cookie_pot is a fixed size (4 kb) page that uses two indexes for management. The first one is cookie_index, which identifies where to write the next cookie. The next_fortune variable identifies where the next cookie should be read for output. After all the fortune items are read, we simply return to next_fortune. Listing 9. module init/cleanup and variable # include <linux/module. h> # include <linux/kernel. h> # include <linux/proc_fs.h> # include <linux/string. h> # include <linux/vmalloc. h> # include <asm/uaccess. h> MODULE_LICENSE ("GPL"); MODULE_DESCRIPTION ("Fortune Cookie Kernel Module"); MODULE_AUTHOR ("M. tim Jones "); # define MAX_COOKIE_LENGTH PAGE_SIZEstatic struct proc_dir_entry * proc_entry; static char * cookie_pot; // Space for fo Rtune stringsstatic int cookie_index; // Index to write next fortunestatic int next_fortune; // Index to read next fortuneint init_fortune_module (void) {int ret = 0; cookie_pot = (char *) vmalloc (MAX_COOKIE_LENGTH); if (! Cookie_pot) {ret =-ENOMEM;} else {memset (cookie_pot, 0, MAX_COOKIE_LENGTH); proc_entry = create_proc_entry ("fortune", 0644, NULL); if (proc_entry = NULL) {ret =-ENOMEM; vfree (cookie_pot); printk (KERN_INFO "fortune: Couldn't create proc entry \ n");} else {cookie_index = 0; next_fortune = 0; proc_entry-> read_proc = fortune_read; proc_entry-> write_proc = fortune_write; proc_entry-> owner = THIS_MODULE; printk (KERN_INFO "fortune: Module loaded. \ n ") ;}} return ret;} void cleanup_fortune_module (void) {remove_proc_entry (" fortune ", & proc_root); vfree (cookie_pot); printk (KERN_INFO" fortune: module unloaded. \ n ");} module_init (init_fortune_module); module_exit (cleanup_fortune_module); it is very easy to write a cookie to this can (as shown in listing 10 ). With the length of the cookie, we can check whether there is so much space available. If not,-ENOSPC is returned, Which is returned to the user space. Otherwise, the space exists. We use copy_from_user to directly copy the data in the user buffer to cookie_pot. Then increase cookie_index (based on the length of the user buffer) and end the string with NULL. Finally, return the number of characters actually written into cookie_pot. It will return to the user process. Listing 10. the function ssize_t fortune_write used to write fortune (struct file * filp, const char _ user * buff, unsigned long len, void * data) {int space_available = (MAX_COOKIE_LENGTH-cookie_index) + 1; if (len> space_available) {printk (KERN_INFO "fortune: cookie pot is full! \ N "); return-ENOSPC;} if (copy_from_user (& cookie_pot [cookie_index], buff, len) {return-EFAULT;} cookie_index + = len; cookie_pot [cookie_index-1] = 0; return len;} reading fortune is also very simple, as shown in listing 11. Since the buffer (page) for data writing is already in the kernel space, you can directly operate on it and use sprintf to write it to the next fortune. If the next_fortune index is greater than cookie_index (the next location to be written), we will return next_fortune as 0, which is the first fortune index. After writing the fortune into the user buffer, add the length of the fortune just written to the next_fortune index. In this way, it becomes the next available fortune index. The fortune length will be returned and passed to the user. Listing 11. int fortune_read (char * page, char ** start, off_t off, int count, int * eof, void * data) {int len; if (off> 0) {* eof = 1; return 0;}/* Wrap-around */if (next_fortune> = cookie_index) next_fortune = 0; len = sprintf (page, "% s \ n", & cookie_pot [next_fortune]); next_fortune + = len; return len;} in this simple example, we can see that it is very simple to communicate with the kernel through the/proc file system. Now let's take a look at the usage of this fortune module (see listing 12 ). List 12. demonstrate fortune cookie LKM usage [root @ plato] # insmod fortune. ko [root @ plato] # echo "Success is an individual proposition. thomas Watson ">/proc/fortune [root @ plato] # echo" If a man does his best, what else is there? Gen. patton ">/proc/fortune [root @ plato] # echo" Cats: All your base are belong to us. zero Wing ">/proc/fortune [root @ plato] # cat/proc/fortune Success is an individual proposition. thomas Watson [root @ plato] # cat/proc/fortune If a man does his best, what else is there? General Patton [root @ plato] #/proc the Virtual File System can be widely used to report kernel information or perform dynamic configuration.
 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.