2007年9月18日星期二

Proc File System : Introduction

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

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


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 < class="br0">) {
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 < class="br0">) {
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                                        
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;

没有评论: