Lesson 11: Adding "proc" files to your modules -- Part 1

Printer-friendly versionPrinter-friendly version

So what's happening here?

Given the amount of material to be covered in discussing Linux "proc" files, this lesson is going to discuss the creation and usage of an extremely simple example of a proc file, while the next lesson (possibly two) will return to dig into the details and cover the underlying intricacies.

So have no fear if we gloss over a few (or many) details on this page -- it will all be eventually covered in time.

What's the /proc directory about, anyway?

Most Linux users are familiar (at least in passing) with the contents of the /proc directory and some of its useful files. As an example, if you were curious about what version of the kernel you were running, you could simply:

$ cat /proc/version
Linux version 2.6.32-22-generic (buildd@yellow) \
  (gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) ) \
  #36-Ubuntu SMP Thu Jun 3 19:31:57 UTC 2010
$

which suggests that the /proc/version file contains some fixed data corresponding to version information about the running kernel.

As another example, if you wanted to know about your CPU, or current memory usage, you could:

$ cat /proc/cpuinfo
processor	: 0
vendor_id	: AuthenticAMD
cpu family	: 17
model		: 3
model name	: AMD Turion(tm) X2 Dual-Core Mobile RM-72
stepping	: 1
cpu MHz		: 525.000
cache size	: 512 KB
... snip ...
$ cat /proc/meminfo
MemTotal:        3797092 kB
MemFree:         1124736 kB
Buffers:           23804 kB
Cached:          1695152 kB
SwapCached:            0 kB
Active:          1521804 kB
.. snip ...

Again, perhaps some useful information.

Exercise for the student: Poke around under /proc and identify any files that seem to contain useful information you could imagine needing at some point.

/proc as a "pseudo" filesystem

At this point, the most important observation to make about the /proc directory is that, technically, it doesn't exist. By that, I mean that it is not a normal directory containing normal text files that are sitting there, taking up space on the hard disk.

Rather, the /proc directory represents what is the called the proc "pseudo" filesystem, in that all of the files you see there are simply access points (or windows, or whatever you want to call them) onto code running in kernel space, and any user space access of those files translates into a call to kernel space, to the kernel code associated with that proc file, which dynamically generates the output to be handed back to user space that, from your perspective, looks like simple file contents.

Put more succinctly, any access to a proc file maps to some underlying kernel code that's responsible for handling any read or write request for that file, in whatever way it wants. It just looks like a normal file to you.

Actually, it's not hard to see that there's something odd about that directory, Consider the long listing of that version file we listed earlier:

$ ls -l /proc/version
-r--r--r-- 1 root root 0 2010-06-22 09:19 /proc/version
$

That's a bit unusual, wouldn't you say -- a file of size zero that still appears to contain data. The other observation is that the entire /proc directory clearly represents a mount point of type "/proc":

$ mount
...
proc on /proc type proc (rw,noexec,nosuid,nodev)
...
$

which is also a dead giveaway that this is no normal directory. And there's one final (admittedly trivial) observation to make.

Some proc files are expected to return the same string each time, since they represent information that should be constant, such as /proc/version. Other proc files, such as /proc/meminfo, need to generate their "contents" from scratch every time you access them since you expect them to be changing constantly.

As I said, not a deep observation, just something that will affect how complicated the code is for a given proc file. And now, let's look at an actual example.

Let's talk about /proc/version

Many of the simpler proc files are implemented by a single source file under the fs/proc directory in the kernel source tree -- in this case, we can see what code implements the /proc/version file:

$ cat fs/proc/version.c
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <<linux/seq_file.h>
#include <linux/utsname.h>

static int version_proc_show(struct seq_file *m, void *v)
{
	seq_printf(m, linux_proc_banner,
		utsname()->sysname,
		utsname()->release,
		utsname()->version);
	return 0;
}

static int version_proc_open(struct inode *inode, struct file *file)
{
	return single_open(file, version_proc_show, NULL);
}

static const struct file_operations version_proc_fops = {
	.open		= version_proc_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= single_release,
};

static int __init proc_version_init(void)
{
	proc_create("version", 0, NULL, &version_proc_fops);
	return 0;
}
module_init(proc_version_init);

With no further explanation, it actually looks remarkably straightforward, with the dynamically-generated output produced by the routine:

static int version_proc_show(struct seq_file *m, void *v)
{
	seq_printf(m, linux_proc_banner,
		utsname()->sysname,
		utsname()->release,
		utsname()->version);
	return 0;
}

In other words, from within kernel space, the routine seq_printf() is invoked with the destination argument of a given seq_file that just happens to correspond to what you see in user space as the /proc/version file. And the eventual contents are defined by whatever the original kernel programmer decided would be gathered from various places around kernel space and bundled into a single string, printf-style.

Exercise for the student: Take a look at the kernel source file fs/proc/meminfo.c to see how much running around that code must do to generate the contents of the /proc/meminfo file when you list that file.

Is that version stuff module code or not?

Sharp-eyed readers will have noticed the module_init() macro at the bottom of the version code and assumed that this is meant to be loaded as a module. Actually, no. Even code that is built into the kernel can have entry/initialization code. The fact that that's not module code is obvious from the fact that there's no exit routine (remember the trouble you ran into when you tried to load a module with no exit routine?).

But there's another way to tell that that code above is designed to be explicitly built into the kernel and never buildable as a module.

Examine, if you will, the kernel makefile that controls the building of various proc files:

$ cat fs/proc/Makefile
#
# Makefile for the Linux proc filesystem routines.
#

obj-$(CONFIG_PROC_FS) += proc.o

proc-y                  := nommu.o task_nommu.o
proc-$(CONFIG_MMU)      := mmu.o task_mmu.o

proc-y       += inode.o root.o base.o generic.o array.o \
                proc_tty.o
proc-y  += cmdline.o
proc-y  += cpuinfo.o
proc-y  += devices.o
proc-y  += interrupts.o
proc-y  += loadavg.o
proc-y  += meminfo.o
proc-y  += stat.o
proc-y  += uptime.o
proc-y  += version.o
proc-y  += softirqs.o
proc-$(CONFIG_PROC_SYSCTL)      += proc_sysctl.o
proc-$(CONFIG_NET)              += proc_net.o
proc-$(CONFIG_PROC_KCORE)       += kcore.o
proc-$(CONFIG_PROC_VMCORE)      += vmcore.o
proc-$(CONFIG_PROC_DEVICETREE)  += proc_devtree.o
proc-$(CONFIG_PRINTK)   += kmsg.o
proc-$(CONFIG_PROC_PAGE_MONITOR)        += page.o

If you've never seen makefiles like the above before, no problem -- they're easy to explain.

Note that some of the source files in the fs/proc directory are not even configurable and will always be compiled into the kernel (those are the "proc-y" files), while others will be compiled in based on your configuration. The only point we're making here is that, depending on how your kernel was configured and built, you may not have every possible proc file on your system.

Related to our example, it's obvious that you should always have a /proc/version file, which is why the corresponding source file has no exit routine -- that code can't ever be possibly unloaded so we don't need one.

Creating your own trivial proc file

At this point, given that you have a model source file to steal from (fs/proc/version.c), it should be a simple matter to write a loadable module that creates a proc file that allows you to print whatever you want from kernel space. In our case, let's write a module that lets us display the current value of jiffies:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/jiffies.h>

static int
jiffies_proc_show(struct seq_file *m, void *v)
{
    seq_printf(m, "%llu\n",
        (unsigned long long) get_jiffies_64());
    return 0;
}

static int
jiffies_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, jiffies_proc_show, NULL);
}

static const struct file_operations jiffies_proc_fops = {
    .owner      = THIS_MODULE,
    .open       = jiffies_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

static int __init
jiffies_proc_init(void)
{
    proc_create("crash_jiffies", 0, NULL, &jiffies_proc_fops);
    return 0;
}

static void __exit
jiffies_proc_exit(void)
{
    remove_proc_entry("crash_jiffies", NULL);
}

module_init(jiffies_proc_init);
module_exit(jiffies_proc_exit);

MODULE_AUTHOR("Robert P. J. Day, http://crashcourse.ca");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A jiffies /proc file.");

Without getting into major detail (we'll do that next lesson), you should be able to compile the above, and load it, at which point a read-only file named /proc/crash_jiffies should magically appear which allows you to list the jiffies value any time you want until you unload that module.

Exercise for the student: What's the most obvious difference between your module code and the code in version.c? Explain that difference.

Next lesson: Digging into proc files for real.

Comments

Diffs

No version info etc in version.c and, of course, ours is unloadable with an exit routine, while version.c is not meant to be unloaded.

some explaination needed

Hi
please be a bit more elusive on this sentence above
"which dynamically generates the output to be handed back to user space that"

"Elusive"?

What that statement means is that, every time you attempt to list the contents of a /proc file, it's up to the code in kernel space to generate, on the fly, the output to be passed back to user space. It means that the output can change from call to call since the kernel code is responsible for regenerating that output each time. It might pass back the same output each time, or it might not.

difference in my code and version.c

I will write one by one

1) in my code I included module.h was not present in version.c
2) we also inlcuded jiffies.h while in version.c utsname.c
was included
3) utsname seems to be some system call which was used in version.c
4) function proc_create different arguments passed
5) there was no exit code for version.c where as in our was there

Did I miss any thing in above?

functions required to use proc in our programs

As it is clear from the name of functions in your program

to be able to use /proc files in our module one need to have

proc_create (specifying the name of file to be added in /proc)

proc_open (to open proc file)
proc_show or what ever ( to do operation on seq_files)

and a structure as file_operations.

I think any module which will use /proc type of files will have above 3 functions and 1 structure as I mentioned.

Where proc_open will open that file
and proc_show or proc_manipulate_user_defined_operation
will be some thing that programmer would need to do.
Correct me if I am wrong.

Do all modules have proc_open(), etc.

Here's how you can test your hypothesis:

grep -L proc_open *

This lists files that don't have proc_open .

can't find version.c

I am looking for it in the kernel source tree of the downloaded kernel in chapter 1

fs/proc/

and its not there!!.

I can see it in my git clone

I'm looking at my fully-pulled git clone of the kernel source and i can see the source file fs/proc/version.c. I can't imagine how yours could be missing.

Oh good! A mystery.

The two /proc files I've use the most are /proc/meminfo and /proc/cpuinfo (though /proc/kallsyms is going to be getting some use now, too).

Luckily, /proc/cpuinfo is the shortest of fs/proc/*, so I took a look at cpuinfo.c right after I looked at meminfo.c

I have no clue how it could work, since there's not even a proc_show(). A mystery to be revealed in lessons to come.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <br> <pre> <h1> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.