world leader in high performance signal processing
Trace: » proc_file_system

Proc File System : Introduction

This section introduces the /proc file system:

  • A basic /proc filesystem overview
  • A proc read code example
  • A proc directory entry code example
  • Creating proc read code
  • A proc write code example

The Proc File System

The proc file system provides a means of quick access to core kernel data. What looks like a traditional file system is mounted but in reality the proc file system is entirely code and memory based.

The system uses no disk space and the code associated with it attempts to read / write to regular files but is only executed when a user process attempts to access these files.

This file system is excellent for debugging and device control since, at the basic level, simple cat and echo commands can be used to interface with the kernel.

The /proc Directory

The proc files can be examined using the following command:

ls -l /proc

An example output is shown:

dr-xr-xr-x    5 0        0               0 1
dr-xr-xr-x    5 0        0               0 10
dr-xr-xr-x    5 0        0               0 9
-r--r--r--    1 0        0               0 buddyinfo
dr-xr-xr-x    2 0        0               0 bus
-r--r--r--    1 0        0               0 cmdline
-r--r--r--    1 0        0               0 cplbinfo
-r--r--r--    1 0        0               0 cpuinfo
-r--r--r--    1 0        0               0 devices
-r--r--r--    1 0        0               0 diskstats
dr-xr-xr-x    2 0        0               0 driver
-r--r--r--    1 0        0               0 execdomains
-r--r--r--    1 0        0               0 filesystems
dr-xr-xr-x    3 0        0               0 fs
-r--r--r--    1 0        0               0 interrupts
-r--r--r--    1 0        0               0 iomem
-r--r--r--    1 0        0               0 ioports
-r--r--r--    1 0        0               0 kallsyms
-r--------    1 0        0               0 kmsg
-r--r--r--    1 0        0               0 loadavg
-r--r--r--    1 0        0               0 locks
-r--r--r--    1 0        0               0 maps
-r--r--r--    1 0        0               0 meminfo
-r--r--r--    1 0        0               0 misc
lrwxrwxrwx    1 0        0              11 mounts -> self/mounts
-r--r--r--    1 0        0               0 mtd
dr-xr-xr-x    3 0        0               0 net
-r--r--r--    1 0        0               0 partitions
lrwxrwxrwx    1 0        0              64 self -> 35
-rw-r--r--    1 0        0               0 slabinfo
-r--r--r--    1 0        0               0 stat
dr-xr-xr-x    4 0        0               0 tty
-r--r--r--    1 0        0               0 uptime
-r--r--r--    1 0        0               0 version
-r--r--r--    1 0        0               0 vmstat 

Individual files can be simply read using the cat command.

cat /proc/interrupts

An example output on the Blackfin/uClinux:

  6:          0   BFIN Timer Tick
 14:          0   rtc
 21:          0   BFIN_UART_RX
 22:       5856   BFIN_UART_TX
 27:         61   eth0
Err:          0

on a x86 PC running Linux, it looks like:

           CPU0       CPU1
  0:  924059703  925864605    IO-APIC-edge  timer
  1:     101211     108432    IO-APIC-edge  i8042
  4:     555597     702548    IO-APIC-edge  serial
  8:       3082       3086    IO-APIC-edge  rtc
  9:          0          0   IO-APIC-level  acpi
 12:    1761518    1813890    IO-APIC-edge  i8042
 14:   15420700   15475179    IO-APIC-edge  ide0
169:  200276170          0   IO-APIC-level  eth1, nvidia
177:   14610420   14509225   IO-APIC-level  libata
193:      85016      87685   IO-APIC-level  Intel ICH6, uhci_hcd
201:          0          0   IO-APIC-level  uhci_hcd, ehci_hcd
209:          0          0   IO-APIC-level  uhci_hcd
217:          0          0   IO-APIC-level  uhci_hcd
NMI: 1849924375 1849924333
LOC: 1849863422 1849863597
ERR:          0
MIS:          0           

In addition to reading data the proc file system can be used to set up or alter data in the kernel. There are many system tuning parameters that can be set up by writing data to the specified /proc device.

Writing a string to a file /proc/sys/kernel/domainname will set up the system's domain name.

echo -n "myblackfin.com" >/proc/sys/kernel/domainname
cat /proc/sys/kernel/domainname                  
myblackfin.com                                       

A few more details can be found in the file linux/Documentation/filesystems/proc.txt

A Proc Read function

The core of the proc file system is a proc_read function.

This function provides the data shown when a proc file is opened and read for example with cat.

An example of the code for generating the data seen in a proc file read is shown here:

  #include <linux/proc_fs.h>                                                
 
  int scmd_proc_read(char *buf,     /* this is the buffer we write to       */                                                                        
                     char **start,  /* this is used for larger data access  */                                                                        
                     off_t offset,  /* same as above                        */                                                                        
                     int count,     /* this is the expected number of bytes */                                                                        
                     int *eof,      /* set this to 1 to indicate end if file*/                                                                        
                     void * data    /* optional user data                   */                                                                        
                     )                                                      
  {                                                                         
      int i;                                                                
 
      scmd_dev * dev;                                                       
      int len = 0;                                                          
 
      /* get the data structure for unit 0 ( fixed later )*/                
      dev = &scmd[0];                                                       
      /* write up to 4096 bytes to buf                                      
         return bytes written in len */                                     
      /* only write when offset == 1 */                                                                            
      /* print a header */                                                  
      if ( offset == 1 ) {                                                  
         len += sprintf (&buf[len], "Scmd proc %d\n", len);                 
 
         /* print some data */                                              
         for ( i = 0; i < 16 i++ ) {                                        
            len += sprintf (&buf[len],                                      
                "Index %d:, data = %d , \n",                                
                i,dev->data[i]                                              
                 );                                                         
         }                                                                  
      }                                                                     
      *eof = 1;                                                             
      return len;                                                           
  }                                                                         

Note that the scmd_proc_read function is given a buffer buf to place its data in. The max size of this buffer is normally one page, 4096 bytes. The data pointer can be used to point to our private data structure which is set up when the read function is setup.

Creating a Proc Directory Entry

You can create directory entries as well as regular file in a proc file system.

These are the code fragments required to create a directory entry in the proc file system:

 
      #include <linux/proc_fs.h>                          
 
 
      struct proc_dir_entry *scmd_proc_dir = NULL;        
 
      /* add this in module_init */                    
      struct proc_dir_entry *ptr =                        
 
      create_proc_entry("scmd",S_IFREG | S_IRUGO, NULL);  
 
      ptr->read_proc = scmd_proc_read ;                   
 
 
      /****** add this in module_exit */                    
      remove_proc_entry("scmd", &proc_root);              
 
      /* ********** do this for a dir entry               
       create_proc_entry("scmd",S_IFDIR | S_IWUGO, NULL); 
     ******** */                                          
 
 

Multiple Entries

The simple driver you are using, however, may have multiple minor numbers associated with the device. This will require a special directory to be generated and a sub directory for each minor device.

Consider the revised code:

      struct proc_dir_entry *scmd_proc_dir;                           
      /* add to module_init */                                          
      scmd_proc_dir = create_proc_entry("scmd", S_IFDIR, 0);          
      for (i = 0 ; i < SCMD_MAX_MINOR ; i++ ) {                       
          sprintf(sbuff,"scmd/%d",i);                                 
          create_proc_read_entry(sbuff, 0,                            
                    scmd_proc_dir, scmd_read_proc, &scmd[i]);
      }                                                               
 
 
  /* proc file system deletion is then performed in this manner */    
      /* add to module_exit */                                          
 
      for (i = 0 ; i < SCMD_MAX_MINOR ; i++ ) {                       
          sprintf(sbuff,"scmd/%d",i);                                 
          remove_proc_entry(sbuff, &proc_root);                       
      }                                                               
      remove_proc_entry("scmd", &proc_root);                          

| The proc_read function will be recoded to use the data parameter to point to the correct device buffer for the device node minor number.

  int scmd_proc_read(char *buf, char **start, off_t offset, int count,
                     int *eof, void * data ) {                        
      int i;    char * sp;                                            
      scmd_dev * dev;                                                 
      int len;                                                        
      //dev = &scmd[0];                                               
      dev = data;                                                     
      len = 0;

A Proc Write function

The proc write function is very similar to a normal device driver write function.

The user can “write” data to the device using the user mode echo command or from within some user code.

An example of the code for handling a proc write is shown here:

  #include <linux/proc_fs.h>                                       
  static int scmd_proc_write(struct file *file, const char *buffer,
                             unsigned long count, void *data) 
{    
      scmd_dev * dev;                                              
      int num;                                                     
      dev = data;                                                  
 
      num = count;                                                 
      if (count > SCMD_SIZE ) num = SCMD_SIZE;                     
      if (copy_from_user(dev->data,buffer,num))                    
         return -EINVAL;                                           
      printk(" copied %d bytes \n", num );                         
      return count;                                                
  }                                                                
 

The write function is set up as the proc dir is created.

      sptr= create_proc_read_entry(sbuff, S_IFREG | S_IWUGO, scmd_proc_dir,
                                     scmd_proc_read, &scmd[j] );           
      sptr->write_proc = scmd_proc_write;