* [PATCH] Procfs Guide
@ 2001-05-29 23:29 Erik Mouw
2001-05-30 8:30 ` Tim Waugh
0 siblings, 1 reply; 7+ messages in thread
From: Erik Mouw @ 2001-05-29 23:29 UTC (permalink / raw)
To: Linux kernel mailing list; +Cc: Alan Cox
Hi,
A couple of weeks ago I promised Jeff Garzik to write a piece of procfs
documentation, so here it is. This guide is written in DocBook SGML and
it tells you how to use the procfs from within the kernel.
I'm still looking for a proper way to automatically include the example
source into the SGML file, this patch with the same content in two
files is a bit of an ugly hack.
The patch is against linux-2.4.5, but should apply cleanly against
2.4.5-ac* as well.
Erik
--
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Department
of Electrical Engineering, Faculty of Information Technology and Systems,
Delft University of Technology, PO BOX 5031, 2600 GA Delft, The Netherlands
Phone: +31-15-2783635 Fax: +31-15-2781843 Email: J.A.K.Mouw@its.tudelft.nl
WWW: http://www-ict.its.tudelft.nl/~erik/
Index: Documentation/DocBook/Makefile
===================================================================
RCS file: /home/erik/cvsroot/elinux/Documentation/DocBook/Makefile,v
retrieving revision 1.1.1.30
retrieving revision 1.1.1.25.2.1
diff -u -r1.1.1.30 -r1.1.1.25.2.1
--- Documentation/DocBook/Makefile 2001/05/15 12:14:07 1.1.1.30
+++ Documentation/DocBook/Makefile 2001/05/27 00:40:45 1.1.1.25.2.1
@@ -1,7 +1,7 @@
BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
- deviceiobook.sgml
+ deviceiobook.sgml procfs-guide.sgml
PS := $(patsubst %.sgml, %.ps, $(BOOKS))
PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -66,6 +66,9 @@
videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \
<videobook.tmpl >videobook.sgml
+
+procfs-guide.sgml: procfs-guide.tmpl
+ $(TOPDIR)/scripts/docgen <$< >$@
APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
$(TOPDIR)/arch/i386/kernel/irq.c \
Index: Documentation/DocBook/procfs-guide.tmpl
===================================================================
RCS file: procfs-guide.tmpl
diff -N procfs-guide.tmpl
--- /dev/null Thu Mar 22 14:04:47 2001
+++ Documentation/DocBook/procfs-guide.tmpl Sun May 27 02:42:20 2001
@@ -0,0 +1,842 @@
+<!-- -*- sgml -*- -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]>
+
+<book id="LKProcfsGuide">
+ <bookinfo>
+ <title>Linux Kernel Procfs Guide</title>
+
+
+ <authorgroup>
+ <author>
+ <firstname>Erik</firstname>
+ <othername>(J.A.K.)</othername>
+ <surname>Mouw</surname>
+ <affiliation>
+ <orgname>Delft University of Technology</orgname>
+ <orgdiv>Faculty of Information Technology and Systems</orgdiv>
+ <address>
+ <email>J.A.K.Mouw@its.tudelft.nl</email>
+ <pob>PO BOX 5031</pob>
+ <postcode>2600 GA</postcode>
+ <city>Delft</city>
+ <country>The Netherlands</country>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+
+ <copyright>
+ <year>2001</year>
+ <holder>Erik Mouw</holder>
+ </copyright>
+
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ This documentation is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the GNU General Public License for more details.
+ </para>
+
+ <para>
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+
+
+
+ <toc>
+ </toc>
+
+
+
+
+ <preface>
+ <title>Preface</title>
+
+ <para>
+ This guide describes the use of the procfs file system from
+ within the Linux kernel. The idea to write this guide came up on
+ the #kernelnewbies IRC channel (see <ulink
+ url="http://www.kernelnewbies.org/">http://www.kernelnewbies.org/</ulink>),
+ when Jeff Garzik explained the use of procfs and forwarded me a
+ message Alexander Viro wrote to the linux-kernel mailing list. I
+ agreed to write it up nicely, so here it is.
+ </para>
+
+ <para>
+ I'd like to thank Jeff Garzik
+ <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
+ <email>viro@math.psu.edu</email> for their input
+ </para>
+
+ <para>
+ This documentation was written while working on the LART
+ computing board (<ulink
+ url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/</ulink>).
+ The development has been sponsored by the Mobile Multi-media
+ Communications (<ulink
+ url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>)
+ and Ubiquitous Communications (<ulink
+ url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.nl/</ulink>)
+ projects.
+ </para>
+
+ <para>
+ Erik
+ </para>
+ </preface>
+
+
+
+
+ <chapter id="intro">
+ <title>Introduction</title>
+
+ <para>
+ The <filename class="directory">/proc</filename> file system
+ (procfs) is a special file system in the linux kernel. It's a
+ virtual file system: it is not associated with a block device but
+ exists only in memory. The files in the procfs are used to allow
+ userland programs access to certain information from the kernel
+ (like process information in <filename
+ class="directory">/proc/[0-9]+/</filename>), but also for debug
+ purposes (like <filename>/proc/ksyms</filename>).
+ </para>
+
+ <para>
+ This guide describes the use of the procfs file system from
+ within the Linux kernel. It starts by introducing all relevant
+ functions to manage the files within the file system. After that
+ it shows how to communicate with userland, and some tips and
+ tricks will be pointed out. Finally a complete example will be
+ shown.
+ </para>
+ </chapter>
+
+
+
+
+ <chapter id="managing">
+ <title>Managing procfs entries</title>
+
+ <para>
+ This chapter describes the functions that various kernel
+ components use to populate the procfs with files, symlinks,
+ device nodes, and directories.
+ </para>
+
+ <para>
+ A minor note before we start: if you want to use any of the
+ procfs functions, be sure to include the correct header file!
+ This should be one of the first lines in your code:
+ </para>
+
+ <programlisting>
+#include <linux/proc_fs.h>
+ </programlisting>
+
+
+
+
+ <sect1 id="regularfile">
+ <title>Creating a regular file</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>create_proc_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This function creates a regular file with the name
+ <parameter>name</parameter>, file mode
+ <parameter>mode</parameter> in the directory
+ <parameter>parent</parameter>. To create a file in the root of
+ the procfs, use <constant>NULL</constant> as
+ <parameter>parent</parameter> parameter. When successful, the
+ function will return a pointer to the freshly created
+ <structname>struct proc_dir_entry</structname>; otherwise it
+ will return <constant>NULL</constant>. <xref
+ linkend="userland"> describes how to do something useful with
+ regular files.
+ <para>
+
+ <para>
+ Note that it is specifically supported that you can pass a
+ multi-directory path. For example
+ <function>create_proc_entry</function>(<parameter>"drivers/via0/info"</parameter>)
+ will create the <filename class="directory">via0</filename>
+ directory if necessary, with standard
+ <constant>0755</constant> permissions.
+ </para>
+
+ <para>
+ If you only want to be able to read the file, the function
+ <function>create_proc_read_entry</function> described in <xref
+ linkend="convenience"> might be used to create and initialise
+ the procfs entry in one single call.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a symlink</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry*
+ <function>proc_symlink</function></funcdef> <paramdef>const
+ char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry*
+ <parameter>parent</parameter></paramdef> <paramdef>const
+ char* <parameter>dest</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This creates a symlink in the procfs directory
+ <parameter>parent</parameter> that points from
+ <parameter>name</parameter> to
+ <parameter>dest</parameter>. This translates in userland to
+ <literal>ln -s</literal> <parameter>dest</parameter>
+ <parameter>name</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a device</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>proc_mknod</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ <paramdef>kdev_t <parameter>rdev</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Creates a device file <parameter>name</parameter> with mode
+ <parameter>mode</parameter> in the procfs directory
+ <parameter>parent</parameter>. The device file will work on
+ the device <parameter>rdev</parameter>, which can be generated
+ by using the <literal>MKDEV</literal> macro from
+ <literal>linux/kdev_t.h</literal>. The
+ <parameter>mode</parameter> parameter
+ <emphasis>must</emphasis> contain <constant>S_IFBLK</constant>
+ or <constant>S_IFCHR</constant> to create a device
+ node. Compare with userland <literal>mknod
+ --mode=</literal><parameter>mode</parameter>
+ <parameter>name</parameter> <parameter>rdev</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a directory</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>proc_mkdir</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Create a directory <parameter>name</parameter> in the procfs
+ directory <parameter>parent</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Removing an entry</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>void <function>remove_proc_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Removes the entry <parameter>name</parameter> in the directory
+ <parameter>parent</parameter> from the procfs. Note that
+ entries are removed by their <emphasis>name</emphasis>, not by
+ the <structname>struct proc_dir_entry</structname> returned by the
+ various create functions.
+ </para>
+
+ <para>
+ Note that the <structfield>data</structfield> entry from the
+ <structname>struct proc_dir_entry</structname>> has to be freed
+ before this function is called (that is: if there was some
+ <structfield>data</structfield> allocated, of course). See
+ <xref linkend="usingdata"> for more information on using the
+ <structfield>data</structfield> entry.
+ </para>
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="userland">
+ <title>Communicating with userland</title>
+
+ <para>
+ Instead of reading (or writing) the information directly from
+ kernel memory, the procfs works with <emphasis>call back
+ functions</emphasis> for files: functions that are called when
+ a specific file is being read or written. Those functions have
+ to be initialised after the procfs file is created by setting
+ the <structfield>read_proc</structfield> and/or
+ <structfield>write_proc</structfield> fields in the
+ <structname>struct proc_dir_entry*</structname> the function
+ <function>create_proc_entry</function> returned:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->read_proc = read_proc_foo;
+entry->write_proc = write_proc_foo;
+ </programlisting>
+
+ <para>
+ If you only want to use a the
+ <structfield>read_proc</structfield>, the function
+ <function>create_proc_read_entry</function> described in <xref
+ linkend="convenience"> might be used to create and initialise
+ the procfs entry in one single call.
+ </para>
+
+
+
+ <sect1>
+ <title>Reading data</title>
+
+ <para>
+ The read function is a call back function that allows userland
+ processes to read data from the kernel. The read function
+ should have the following format:
+ </para>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>read_func</function></funcdef>
+ <paramdef>char* <parameter>page</parameter></paramdef>
+ <paramdef>char** <parameter>start</parameter></paramdef>
+ <paramdef>off_t <parameter>off</parameter></paramdef>
+ <paramdef>int <parameter>count</parameter></paramdef>
+ <paramdef>int* <parameter>eof</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The read function should write its information into the
+ <parameter>page</parameter>. For proper use, the function
+ should start writing at an offset of
+ <parameter>off</parameter> in <parameter>page</parameter> and
+ write <parameter>count</parameter> bytes at maximum, but
+ because most read functions are quite simple and only return a
+ small amount of information, these two parameters are usually
+ ignored (it breaks pagers like <literal>more</literal> and
+ <literal>less</literal>, but <literal>cat</literal> still
+ works).
+ </para>
+
+ <para>
+ If the <parameter>off</parameter> and
+ <parameter>count</parameter> parameters are properly used,
+ <parameter>eof</parameter> should be used to signal that the
+ end of the file has been reached by writing
+ <literal>1</literal> to the memory location
+ <parameter>eof</parameter> points to.
+ </para>
+
+ <para>
+ The parameter <parameter>start</parameter> doesn't seem to be
+ used anywhere in the kernel. The <parameter>data</parameter>
+ parameter can be used to use a single call back function for
+ several files, see <xref linkend="usingdata">.
+ </para>
+
+ <para>
+ The <function>read_func</function> function must return the
+ number of bytes written into the <parameter>page</parameter>.
+ </para>
+
+ <para>
+ <xref linkend="example"> shows how to use a read call back
+ function.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Writing data</title>
+
+ <para>
+ The write call back function allows a userland process to write
+ data to the kernel, so it has some kind of control over the
+ kernel. The write function should have the following format:
+ </para>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>write_func</function></funcdef>
+ <paramdef>struct file* <parameter>file</parameter></paramdef>
+ <paramdef>const char* <parameter>buffer</parameter></paramdef>
+ <paramdef>unsigned long <parameter>count</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The write function should read <parameter>count</parameter>
+ bytes at maximum from the <parameter>buffer</parameter>. Note
+ that the <parameter>buffer</parameter> doesn't live in the
+ kernel's memory space, so it should first be copied to kernel
+ space with <function>copy_from_user</function>. The
+ <parameter>file</parameter> parameter is usually
+ ignored. <xref linkend="usingdata"> shows how to use the
+ <parameter>data</parameter> parameter.
+ </para>
+
+ <para>
+ Again, <xref linkend="example"> shows how to use this call back
+ function.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1 id="usingdata">
+ <title>A single call back for many files</title>
+
+ <para>
+ When a large number of almost identical files is used, it's
+ quite inconvenient to use a separate call back function for
+ each file. Instead of that, a single call back function can be
+ used that distinguishes between the files by using
+ <structfield>data</structfield> field in <structname>struct
+ proc_dir_entry</structname>. First of all, the
+ <structfield>data</structfield> field has to be initialised:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+struct my_file_data *file_data;
+
+file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL);
+entry->data = file_data;
+ </programlisting>
+
+ <para>
+ The <structfield>data</structfield> field is a <type>void
+ *</type>, so it can be initialised with anything.
+ </para>
+
+ <para>
+ Now that the <structfield>data</structfield> field is set, the
+ <function>read_proc</function> and
+ <function>write_proc</function> can use it to distinguish
+ between files because they get it passed into their
+ <parameter>data</parameter> parameter:
+ </para>
+
+ <programlisting>
+int foo_read_func(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ if(data == file_data) {
+ /* special case for this file */
+ } else {
+ /* normal processing */
+ }
+
+ return len;
+}
+ </programlisting>
+
+ <para>
+ Be sure to free the <structfield>data</structfield> data field
+ when removing the procfs entry.
+ </para>
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="tips">
+ <title>Tips and tricks</title>
+
+
+
+
+ <sect1 id="convenience">
+ <title>Convenience functions</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>create_proc_read_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ <paramdef>read_proc_t* <parameter>read_proc</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This function creates a regular file in exactly the same way
+ as <function>create_proc_entry</function> from <xref
+ linkend="regularfile"> does, but also allows to set the read
+ function <parameter>read_proc</parameter> in one call. This
+ function is also able to set the <parameter>data</parameter>,
+ as explained in <xref linkend="usingdata">.
+ </para>
+ </sect1>
+
+
+
+ <sect1>
+ <title>Modules</title>
+
+ <para>
+ If the procfs is being used from within a module, be sure to
+ set the <structfield>owner</structfield> field in the
+ <structname>struct proc_dir_entry</structname> to
+ <constant>THIS_MODULE</constant>.
+ <para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->owner = THIS_MODULE;
+ </programlisting>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Mode and ownership</title>
+
+ <para>
+ Sometimes it is useful to change the mode and/or ownership of a
+ procfs entry. Here is an example how to achieve that:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH;
+entry->uid = 0;
+entry->gid = 100;
+ </programlisting>
+
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="example">
+ <title>Example</title>
+
+ <programlisting>
+/*
+ * procfs_ecample.c: an example proc interface
+ *
+ * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This file accompanies the procfs-guide in the Linux kernel
+ * source. It's main use is to demonstrate the concepts and
+ * functions described in the guide.
+ *
+ * This software has been developed while working on the LART
+ * computing board (http://www.lart.tudelft.nl/). The
+ * development has been sponsored by the Mobile Multi-media
+ * Communications (http://www.mmc.tudelft.nl/) and Ubiquitous
+ * Communications (http://www.ubicom.tudelft.nl/) projects.
+ *
+ * The author can be reached at:
+ *
+ * Erik Mouw
+ * Information and Communication Theory Group
+ * Faculty of Information Technology and Systems
+ * Delft University of Technology
+ * P.O. Box 5031
+ * 2600 GA Delft
+ * The Netherlands
+ *
+ *
+ * This program is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "procfs_example"
+
+#define FOOBAR_LEN 8
+
+struct fb_data_t {
+ char name[FOOBAR_LEN + 1];
+ char value[FOOBAR_LEN + 1];
+};
+
+
+static struct proc_dir_entry *example_dir, *foo_file,
+ *bar_file, *jiffies_file, *tty_device, *symlink;
+
+
+struct fb_data_t foo_data, bar_data;
+
+
+static int proc_read_jiffies(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "jiffies = %ld\n",
+ jiffies);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_read_foobar(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "%s = '%s'\n",
+ fb_data->name, fb_data->value);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_write_foobar(struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ if(count > FOOBAR_LEN)
+ len = FOOBAR_LEN;
+ else
+ len = count;
+
+ if(copy_from_user(fb_data->value, buffer, len)) {
+ MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+
+ fb_data->value[len] = '\0';
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int __init init_procfs_example(void)
+{
+ int rv = 0;
+
+ /* create directory */
+ example_dir = proc_mkdir(MODULE_NAME, NULL);
+ if(example_dir == NULL) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ example_dir->owner = THIS_MODULE;
+
+ /* create jiffies using convenience function */
+ jiffies_file = create_proc_read_entry("jiffies",
+ 0444, example_dir,
+ proc_read_jiffies,
+ NULL);
+ if(jiffies_file == NULL) {
+ rv = -ENOMEM;
+ goto no_jiffies;
+ }
+
+ jiffies_file->owner = THIS_MODULE;
+
+ /* create foo and bar files using callback functions */
+ foo_file = create_proc_entry("foo", 0644, example_dir);
+ if(foo_file == NULL) {
+ rv = -ENOMEM;
+ goto no_foo;
+ }
+
+ strcpy(foo_data.name, "foo");
+ strcpy(foo_data.value, "foo");
+ foo_file->data = &foo_data;
+ foo_file->read_proc = proc_read_foobar;
+ foo_file->write_proc = proc_write_foobar;
+ foo_file->owner = THIS_MODULE;
+
+ bar_file = create_proc_entry("bar", 0644, example_dir);
+ if(bar_file == NULL) {
+ rv = -ENOMEM;
+ goto no_bar;
+ }
+
+ strcpy(bar_data.name, "bar");
+ strcpy(bar_data.value, "bar");
+ bar_file->data = &bar_data;
+ bar_file->read_proc = proc_read_foobar;
+ bar_file->write_proc = proc_write_foobar;
+ bar_file->owner = THIS_MODULE;
+
+ /* create tty device */
+ tty_device = proc_mknod("tty", S_IFCHR | 0666,
+ example_dir, MKDEV(5, 0));
+ if(tty_device == NULL) {
+ rv = -ENOMEM;
+ goto no_tty;
+ }
+
+ tty_device->owner = THIS_MODULE;
+
+ /* create symlink */
+ symlink = proc_symlink("jiffies_too", example_dir,
+ "jiffies");
+ if(symlink == NULL) {
+ rv = -ENOMEM;
+ goto no_symlink;
+ }
+
+ symlink->owner = THIS_MODULE;
+
+ /* everything OK */
+ printk(KERN_INFO "%s %s initialised\n",
+ MODULE_NAME, MODULE_VERSION);
+ return 0;
+
+no_symlink:
+ remove_proc_entry("tty", example_dir);
+no_tty:
+ remove_proc_entry("bar", example_dir);
+no_bar:
+ remove_proc_entry("foo", example_dir);
+no_foo:
+ remove_proc_entry("jiffies", example_dir);
+no_jiffies:
+ remove_proc_entry(MODULE_NAME, NULL);
+out:
+ return rv;
+}
+
+
+static void __exit cleanup_procfs_example(void)
+{
+ remove_proc_entry("jiffies_too", example_dir);
+ remove_proc_entry("tty", example_dir);
+ remove_proc_entry("bar", example_dir);
+ remove_proc_entry("foo", example_dir);
+ remove_proc_entry("jiffies", example_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+
+ printk(KERN_INFO "%s %s removed\n",
+ MODULE_NAME, MODULE_VERSION);
+}
+
+
+module_init(init_procfs_example);
+module_exit(cleanup_procfs_example);
+
+MODULE_AUTHOR("Erik Mouw");
+MODULE_DESCRIPTION("procfs examples");
+
+EXPORT_NO_SYMBOLS;
+ </programlisting>
+ </chapter>
+</book>
Index: Documentation/DocBook/procfs_example.c
===================================================================
RCS file: procfs_example.c
diff -N procfs_example.c
--- /dev/null Thu Mar 22 14:04:47 2001
+++ Documentation/DocBook/procfs_example.c Sun May 27 02:42:20 2001
@@ -0,0 +1,247 @@
+/*
+ * procfs_ecample.c: an example proc interface
+ *
+ * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This file accompanies the procfs-guide in the Linux kernel
+ * source. It's main use is to demonstrate the concepts and
+ * functions described in the guide.
+ *
+ * This software has been developed while working on the LART
+ * computing board (http://www.lart.tudelft.nl/). The
+ * development has been sponsored by the Mobile Multi-media
+ * Communications (http://www.mmc.tudelft.nl/) and Ubiquitous
+ * Communications (http://www.ubicom.tudelft.nl/) projects.
+ *
+ * The author can be reached at:
+ *
+ * Erik Mouw
+ * Information and Communication Theory Group
+ * Faculty of Information Technology and Systems
+ * Delft University of Technology
+ * P.O. Box 5031
+ * 2600 GA Delft
+ * The Netherlands
+ *
+ *
+ * This program is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "procfs_example"
+
+#define FOOBAR_LEN 8
+
+struct fb_data_t {
+ char name[FOOBAR_LEN + 1];
+ char value[FOOBAR_LEN + 1];
+};
+
+
+static struct proc_dir_entry *example_dir, *foo_file,
+ *bar_file, *jiffies_file, *tty_device, *symlink;
+
+
+struct fb_data_t foo_data, bar_data;
+
+
+static int proc_read_jiffies(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "jiffies = %ld\n",
+ jiffies);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_read_foobar(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "%s = '%s'\n",
+ fb_data->name, fb_data->value);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_write_foobar(struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ if(count > FOOBAR_LEN)
+ len = FOOBAR_LEN;
+ else
+ len = count;
+
+ if(copy_from_user(fb_data->value, buffer, len)) {
+ MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+
+ fb_data->value[len] = '\0';
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int __init init_procfs_example(void)
+{
+ int rv = 0;
+
+ /* create directory */
+ example_dir = proc_mkdir(MODULE_NAME, NULL);
+ if(example_dir == NULL) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ example_dir->owner = THIS_MODULE;
+
+ /* create jiffies using convenience function */
+ jiffies_file = create_proc_read_entry("jiffies",
+ 0444, example_dir,
+ proc_read_jiffies,
+ NULL);
+ if(jiffies_file == NULL) {
+ rv = -ENOMEM;
+ goto no_jiffies;
+ }
+
+ jiffies_file->owner = THIS_MODULE;
+
+ /* create foo and bar files using same callback functions */
+ foo_file = create_proc_entry("foo", 0644, example_dir);
+ if(foo_file == NULL) {
+ rv = -ENOMEM;
+ goto no_foo;
+ }
+
+ strcpy(foo_data.name, "foo");
+ strcpy(foo_data.value, "foo");
+ foo_file->data = &foo_data;
+ foo_file->read_proc = proc_read_foobar;
+ foo_file->write_proc = proc_write_foobar;
+ foo_file->owner = THIS_MODULE;
+
+ bar_file = create_proc_entry("bar", 0644, example_dir);
+ if(bar_file == NULL) {
+ rv = -ENOMEM;
+ goto no_bar;
+ }
+
+ strcpy(bar_data.name, "bar");
+ strcpy(bar_data.value, "bar");
+ bar_file->data = &bar_data;
+ bar_file->read_proc = proc_read_foobar;
+ bar_file->write_proc = proc_write_foobar;
+ bar_file->owner = THIS_MODULE;
+
+ /* create tty device */
+ tty_device = proc_mknod("tty", S_IFCHR | 0666,
+ example_dir, MKDEV(5, 0));
+ if(tty_device == NULL) {
+ rv = -ENOMEM;
+ goto no_tty;
+ }
+
+ tty_device->owner = THIS_MODULE;
+
+ /* create symlink */
+ symlink = proc_symlink("jiffies_too", example_dir,
+ "jiffies");
+ if(symlink == NULL) {
+ rv = -ENOMEM;
+ goto no_symlink;
+ }
+
+ symlink->owner = THIS_MODULE;
+
+ /* everything OK */
+ printk(KERN_INFO "%s %s initialised\n",
+ MODULE_NAME, MODULE_VERSION);
+ return 0;
+
+no_symlink:
+ remove_proc_entry("tty", example_dir);
+no_tty:
+ remove_proc_entry("bar", example_dir);
+no_bar:
+ remove_proc_entry("foo", example_dir);
+no_foo:
+ remove_proc_entry("jiffies", example_dir);
+no_jiffies:
+ remove_proc_entry(MODULE_NAME, NULL);
+out:
+ return rv;
+}
+
+
+static void __exit cleanup_procfs_example(void)
+{
+ remove_proc_entry("jiffies_too", example_dir);
+ remove_proc_entry("tty", example_dir);
+ remove_proc_entry("bar", example_dir);
+ remove_proc_entry("foo", example_dir);
+ remove_proc_entry("jiffies", example_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+
+ printk(KERN_INFO "%s %s removed\n",
+ MODULE_NAME, MODULE_VERSION);
+}
+
+
+module_init(init_procfs_example);
+module_exit(cleanup_procfs_example);
+
+MODULE_AUTHOR("Erik Mouw");
+MODULE_DESCRIPTION("procfs examples");
+
+EXPORT_NO_SYMBOLS;
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Procfs Guide
2001-05-29 23:29 [PATCH] Procfs Guide Erik Mouw
@ 2001-05-30 8:30 ` Tim Waugh
2001-05-30 20:35 ` Erik Mouw
0 siblings, 1 reply; 7+ messages in thread
From: Tim Waugh @ 2001-05-30 8:30 UTC (permalink / raw)
To: Erik Mouw; +Cc: Linux kernel mailing list, Alan Cox
On Wed, May 30, 2001 at 01:29:17AM +0200, Erik Mouw wrote:
> I'm still looking for a proper way to automatically include the example
> source into the SGML file, this patch with the same content in two
> files is a bit of an ugly hack.
Probably your best bet is to get the Makefile to pass a copy of the
real example source through sed to &entity;ify the bits that would
confuse SGML (<, >, etc), and into example.c.sed, make that into an
entity, and include it.
See <URL:http://people.redhat.com/twaugh/docbook/selfdocbook/> for
instance, which does this with its own SGML source.
Tim.
*/
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Procfs Guide
2001-05-30 8:30 ` Tim Waugh
@ 2001-05-30 20:35 ` Erik Mouw
0 siblings, 0 replies; 7+ messages in thread
From: Erik Mouw @ 2001-05-30 20:35 UTC (permalink / raw)
To: Tim Waugh; +Cc: Linux kernel mailing list, Alan Cox
On Wed, May 30, 2001 at 09:30:48AM +0100, Tim Waugh wrote:
> On Wed, May 30, 2001 at 01:29:17AM +0200, Erik Mouw wrote:
> > I'm still looking for a proper way to automatically include the example
> > source into the SGML file, this patch with the same content in two
> > files is a bit of an ugly hack.
>
> Probably your best bet is to get the Makefile to pass a copy of the
> real example source through sed to &entity;ify the bits that would
> confuse SGML (<, >, etc), and into example.c.sed, make that into an
> entity, and include it.
>
> See <URL:http://people.redhat.com/twaugh/docbook/selfdocbook/> for
> instance, which does this with its own SGML source.
Thanks, that was a really helpful example.
So how about this version?
Erik
--
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Department
of Electrical Engineering, Faculty of Information Technology and Systems,
Delft University of Technology, PO BOX 5031, 2600 GA Delft, The Netherlands
Phone: +31-15-2783635 Fax: +31-15-2781843 Email: J.A.K.Mouw@its.tudelft.nl
WWW: http://www-ict.its.tudelft.nl/~erik/
Index: Documentation/DocBook/Makefile
===================================================================
RCS file: /home/erik/cvsroot/elinux/Documentation/DocBook/Makefile,v
retrieving revision 1.1.1.30
retrieving revision 1.1.1.25.2.2
diff -u -r1.1.1.30 -r1.1.1.25.2.2
--- Documentation/DocBook/Makefile 2001/05/15 12:14:07 1.1.1.30
+++ Documentation/DocBook/Makefile 2001/05/30 20:31:18 1.1.1.25.2.2
@@ -1,7 +1,7 @@
BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
- deviceiobook.sgml
+ deviceiobook.sgml procfs-guide.sgml
PS := $(patsubst %.sgml, %.ps, $(BOOKS))
PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -9,6 +9,7 @@
IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig
EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook))
JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook))
+C-procfs-example = procfs_example.sgml
books: $(BOOKS)
@@ -67,6 +68,17 @@
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \
<videobook.tmpl >videobook.sgml
+procfs_example.sgml: procfs_example.c
+ echo "<programlisting>" > $@
+ expand --tabs=8 < $< | \
+ sed -e "s/&/\\&/g" \
+ -e "s/</\\</g" \
+ -e "s/>/\\>/g" >> $@
+ echo "</programlisting>" >> $@
+
+procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml
+ $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
+
APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
$(TOPDIR)/arch/i386/kernel/irq.c \
$(TOPDIR)/arch/i386/kernel/mca.c \
@@ -128,6 +140,7 @@
-$(RM) $(BOOKS)
-$(RM) $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
-$(RM) $(JPG-parportbook) $(EPS-parportbook)
+ -$(RM) $(C-procfs-example)
mrproper: clean
-$(RM) $(PS) $(PDF)
Index: Documentation/DocBook/procfs-guide.tmpl
===================================================================
RCS file: procfs-guide.tmpl
diff -N procfs-guide.tmpl
--- /dev/null Thu Mar 22 14:04:47 2001
+++ Documentation/DocBook/procfs-guide.tmpl Wed May 30 22:32:02 2001
@@ -0,0 +1,603 @@
+<!-- -*- sgml -*- -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[
+<!ENTITY procfsexample SYSTEM "procfs_example.sgml">
+]>
+
+<book id="LKProcfsGuide">
+ <bookinfo>
+ <title>Linux Kernel Procfs Guide</title>
+
+
+ <authorgroup>
+ <author>
+ <firstname>Erik</firstname>
+ <othername>(J.A.K.)</othername>
+ <surname>Mouw</surname>
+ <affiliation>
+ <orgname>Delft University of Technology</orgname>
+ <orgdiv>Faculty of Information Technology and Systems</orgdiv>
+ <address>
+ <email>J.A.K.Mouw@its.tudelft.nl</email>
+ <pob>PO BOX 5031</pob>
+ <postcode>2600 GA</postcode>
+ <city>Delft</city>
+ <country>The Netherlands</country>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+
+ <copyright>
+ <year>2001</year>
+ <holder>Erik Mouw</holder>
+ </copyright>
+
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ This documentation is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the GNU General Public License for more details.
+ </para>
+
+ <para>
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+
+
+
+ <toc>
+ </toc>
+
+
+
+
+ <preface>
+ <title>Preface</title>
+
+ <para>
+ This guide describes the use of the procfs file system from
+ within the Linux kernel. The idea to write this guide came up on
+ the #kernelnewbies IRC channel (see <ulink
+ url="http://www.kernelnewbies.org/">http://www.kernelnewbies.org/</ulink>),
+ when Jeff Garzik explained the use of procfs and forwarded me a
+ message Alexander Viro wrote to the linux-kernel mailing list. I
+ agreed to write it up nicely, so here it is.
+ </para>
+
+ <para>
+ I'd like to thank Jeff Garzik
+ <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
+ <email>viro@math.psu.edu</email> for their input, and Tim Waugh
+ <email>twaugh@redhat.com</email> for his <ulink
+ url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>.
+ </para>
+
+ <para>
+ This documentation was written while working on the LART
+ computing board (<ulink
+ url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/</ulink>).
+ The development has been sponsored by the Mobile Multi-media
+ Communications (<ulink
+ url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>)
+ and Ubiquitous Communications (<ulink
+ url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.nl/</ulink>)
+ projects.
+ </para>
+
+ <para>
+ Erik
+ </para>
+ </preface>
+
+
+
+
+ <chapter id="intro">
+ <title>Introduction</title>
+
+ <para>
+ The <filename class="directory">/proc</filename> file system
+ (procfs) is a special file system in the linux kernel. It's a
+ virtual file system: it is not associated with a block device but
+ exists only in memory. The files in the procfs are used to allow
+ userland programs access to certain information from the kernel
+ (like process information in <filename
+ class="directory">/proc/[0-9]+/</filename>), but also for debug
+ purposes (like <filename>/proc/ksyms</filename>).
+ </para>
+
+ <para>
+ This guide describes the use of the procfs file system from
+ within the Linux kernel. It starts by introducing all relevant
+ functions to manage the files within the file system. After that
+ it shows how to communicate with userland, and some tips and
+ tricks will be pointed out. Finally a complete example will be
+ shown.
+ </para>
+ </chapter>
+
+
+
+
+ <chapter id="managing">
+ <title>Managing procfs entries</title>
+
+ <para>
+ This chapter describes the functions that various kernel
+ components use to populate the procfs with files, symlinks,
+ device nodes, and directories.
+ </para>
+
+ <para>
+ A minor note before we start: if you want to use any of the
+ procfs functions, be sure to include the correct header file!
+ This should be one of the first lines in your code:
+ </para>
+
+ <programlisting>
+#include <linux/proc_fs.h>
+ </programlisting>
+
+
+
+
+ <sect1 id="regularfile">
+ <title>Creating a regular file</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>create_proc_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This function creates a regular file with the name
+ <parameter>name</parameter>, file mode
+ <parameter>mode</parameter> in the directory
+ <parameter>parent</parameter>. To create a file in the root of
+ the procfs, use <constant>NULL</constant> as
+ <parameter>parent</parameter> parameter. When successful, the
+ function will return a pointer to the freshly created
+ <structname>struct proc_dir_entry</structname>; otherwise it
+ will return <constant>NULL</constant>. <xref
+ linkend="userland"> describes how to do something useful with
+ regular files.
+ <para>
+
+ <para>
+ Note that it is specifically supported that you can pass a
+ multi-directory path. For example
+ <function>create_proc_entry</function>(<parameter>"drivers/via0/info"</parameter>)
+ will create the <filename class="directory">via0</filename>
+ directory if necessary, with standard
+ <constant>0755</constant> permissions.
+ </para>
+
+ <para>
+ If you only want to be able to read the file, the function
+ <function>create_proc_read_entry</function> described in <xref
+ linkend="convenience"> might be used to create and initialise
+ the procfs entry in one single call.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a symlink</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry*
+ <function>proc_symlink</function></funcdef> <paramdef>const
+ char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry*
+ <parameter>parent</parameter></paramdef> <paramdef>const
+ char* <parameter>dest</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This creates a symlink in the procfs directory
+ <parameter>parent</parameter> that points from
+ <parameter>name</parameter> to
+ <parameter>dest</parameter>. This translates in userland to
+ <literal>ln -s</literal> <parameter>dest</parameter>
+ <parameter>name</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a device</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>proc_mknod</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ <paramdef>kdev_t <parameter>rdev</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Creates a device file <parameter>name</parameter> with mode
+ <parameter>mode</parameter> in the procfs directory
+ <parameter>parent</parameter>. The device file will work on
+ the device <parameter>rdev</parameter>, which can be generated
+ by using the <literal>MKDEV</literal> macro from
+ <literal>linux/kdev_t.h</literal>. The
+ <parameter>mode</parameter> parameter
+ <emphasis>must</emphasis> contain <constant>S_IFBLK</constant>
+ or <constant>S_IFCHR</constant> to create a device
+ node. Compare with userland <literal>mknod
+ --mode=</literal><parameter>mode</parameter>
+ <parameter>name</parameter> <parameter>rdev</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a directory</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>proc_mkdir</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Create a directory <parameter>name</parameter> in the procfs
+ directory <parameter>parent</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Removing an entry</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>void <function>remove_proc_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Removes the entry <parameter>name</parameter> in the directory
+ <parameter>parent</parameter> from the procfs. Note that
+ entries are removed by their <emphasis>name</emphasis>, not by
+ the <structname>struct proc_dir_entry</structname> returned by the
+ various create functions.
+ </para>
+
+ <para>
+ Note that the <structfield>data</structfield> entry from the
+ <structname>struct proc_dir_entry</structname>> has to be freed
+ before this function is called (that is: if there was some
+ <structfield>data</structfield> allocated, of course). See
+ <xref linkend="usingdata"> for more information on using the
+ <structfield>data</structfield> entry.
+ </para>
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="userland">
+ <title>Communicating with userland</title>
+
+ <para>
+ Instead of reading (or writing) the information directly from
+ kernel memory, the procfs works with <emphasis>call back
+ functions</emphasis> for files: functions that are called when
+ a specific file is being read or written. Those functions have
+ to be initialised after the procfs file is created by setting
+ the <structfield>read_proc</structfield> and/or
+ <structfield>write_proc</structfield> fields in the
+ <structname>struct proc_dir_entry*</structname> the function
+ <function>create_proc_entry</function> returned:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->read_proc = read_proc_foo;
+entry->write_proc = write_proc_foo;
+ </programlisting>
+
+ <para>
+ If you only want to use a the
+ <structfield>read_proc</structfield>, the function
+ <function>create_proc_read_entry</function> described in <xref
+ linkend="convenience"> might be used to create and initialise
+ the procfs entry in one single call.
+ </para>
+
+
+
+ <sect1>
+ <title>Reading data</title>
+
+ <para>
+ The read function is a call back function that allows userland
+ processes to read data from the kernel. The read function
+ should have the following format:
+ </para>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>read_func</function></funcdef>
+ <paramdef>char* <parameter>page</parameter></paramdef>
+ <paramdef>char** <parameter>start</parameter></paramdef>
+ <paramdef>off_t <parameter>off</parameter></paramdef>
+ <paramdef>int <parameter>count</parameter></paramdef>
+ <paramdef>int* <parameter>eof</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The read function should write its information into the
+ <parameter>page</parameter>. For proper use, the function
+ should start writing at an offset of
+ <parameter>off</parameter> in <parameter>page</parameter> and
+ write <parameter>count</parameter> bytes at maximum, but
+ because most read functions are quite simple and only return a
+ small amount of information, these two parameters are usually
+ ignored (it breaks pagers like <literal>more</literal> and
+ <literal>less</literal>, but <literal>cat</literal> still
+ works).
+ </para>
+
+ <para>
+ If the <parameter>off</parameter> and
+ <parameter>count</parameter> parameters are properly used,
+ <parameter>eof</parameter> should be used to signal that the
+ end of the file has been reached by writing
+ <literal>1</literal> to the memory location
+ <parameter>eof</parameter> points to.
+ </para>
+
+ <para>
+ The parameter <parameter>start</parameter> doesn't seem to be
+ used anywhere in the kernel. The <parameter>data</parameter>
+ parameter can be used to use a single call back function for
+ several files, see <xref linkend="usingdata">.
+ </para>
+
+ <para>
+ The <function>read_func</function> function must return the
+ number of bytes written into the <parameter>page</parameter>.
+ </para>
+
+ <para>
+ <xref linkend="example"> shows how to use a read call back
+ function.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Writing data</title>
+
+ <para>
+ The write call back function allows a userland process to write
+ data to the kernel, so it has some kind of control over the
+ kernel. The write function should have the following format:
+ </para>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>write_func</function></funcdef>
+ <paramdef>struct file* <parameter>file</parameter></paramdef>
+ <paramdef>const char* <parameter>buffer</parameter></paramdef>
+ <paramdef>unsigned long <parameter>count</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The write function should read <parameter>count</parameter>
+ bytes at maximum from the <parameter>buffer</parameter>. Note
+ that the <parameter>buffer</parameter> doesn't live in the
+ kernel's memory space, so it should first be copied to kernel
+ space with <function>copy_from_user</function>. The
+ <parameter>file</parameter> parameter is usually
+ ignored. <xref linkend="usingdata"> shows how to use the
+ <parameter>data</parameter> parameter.
+ </para>
+
+ <para>
+ Again, <xref linkend="example"> shows how to use this call back
+ function.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1 id="usingdata">
+ <title>A single call back for many files</title>
+
+ <para>
+ When a large number of almost identical files is used, it's
+ quite inconvenient to use a separate call back function for
+ each file. Instead of that, a single call back function can be
+ used that distinguishes between the files by using
+ <structfield>data</structfield> field in <structname>struct
+ proc_dir_entry</structname>. First of all, the
+ <structfield>data</structfield> field has to be initialised:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+struct my_file_data *file_data;
+
+file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL);
+entry->data = file_data;
+ </programlisting>
+
+ <para>
+ The <structfield>data</structfield> field is a <type>void
+ *</type>, so it can be initialised with anything.
+ </para>
+
+ <para>
+ Now that the <structfield>data</structfield> field is set, the
+ <function>read_proc</function> and
+ <function>write_proc</function> can use it to distinguish
+ between files because they get it passed into their
+ <parameter>data</parameter> parameter:
+ </para>
+
+ <programlisting>
+int foo_read_func(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ if(data == file_data) {
+ /* special case for this file */
+ } else {
+ /* normal processing */
+ }
+
+ return len;
+}
+ </programlisting>
+
+ <para>
+ Be sure to free the <structfield>data</structfield> data field
+ when removing the procfs entry.
+ </para>
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="tips">
+ <title>Tips and tricks</title>
+
+
+
+
+ <sect1 id="convenience">
+ <title>Convenience functions</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>create_proc_read_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ <paramdef>read_proc_t* <parameter>read_proc</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This function creates a regular file in exactly the same way
+ as <function>create_proc_entry</function> from <xref
+ linkend="regularfile"> does, but also allows to set the read
+ function <parameter>read_proc</parameter> in one call. This
+ function is also able to set the <parameter>data</parameter>,
+ as explained in <xref linkend="usingdata">.
+ </para>
+ </sect1>
+
+
+
+ <sect1>
+ <title>Modules</title>
+
+ <para>
+ If the procfs is being used from within a module, be sure to
+ set the <structfield>owner</structfield> field in the
+ <structname>struct proc_dir_entry</structname> to
+ <constant>THIS_MODULE</constant>.
+ <para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->owner = THIS_MODULE;
+ </programlisting>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Mode and ownership</title>
+
+ <para>
+ Sometimes it is useful to change the mode and/or ownership of a
+ procfs entry. Here is an example how to achieve that:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH;
+entry->uid = 0;
+entry->gid = 100;
+ </programlisting>
+
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="example">
+ <title>Example</title>
+
+ <!-- be careful with the example code: it shouldn't be wider than
+ approx. 60 columns, or otherwise it won't fit properly on a page
+ -->
+
+&procfsexample;
+
+ </chapter>
+</book>
Index: Documentation/DocBook/procfs_example.c
===================================================================
RCS file: procfs_example.c
diff -N procfs_example.c
--- /dev/null Thu Mar 22 14:04:47 2001
+++ Documentation/DocBook/procfs_example.c Wed May 30 22:32:02 2001
@@ -0,0 +1,247 @@
+/*
+ * procfs_example.c: an example proc interface
+ *
+ * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This file accompanies the procfs-guide in the Linux kernel
+ * source. It's main use is to demonstrate the concepts and
+ * functions described in the guide.
+ *
+ * This software has been developed while working on the LART
+ * computing board (http://www.lart.tudelft.nl/). The
+ * development has been sponsored by the Mobile Multi-media
+ * Communications (http://www.mmc.tudelft.nl/) and Ubiquitous
+ * Communications (http://www.ubicom.tudelft.nl/) projects.
+ *
+ * The author can be reached at:
+ *
+ * Erik Mouw
+ * Information and Communication Theory Group
+ * Faculty of Information Technology and Systems
+ * Delft University of Technology
+ * P.O. Box 5031
+ * 2600 GA Delft
+ * The Netherlands
+ *
+ *
+ * This program is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "procfs_example"
+
+#define FOOBAR_LEN 8
+
+struct fb_data_t {
+ char name[FOOBAR_LEN + 1];
+ char value[FOOBAR_LEN + 1];
+};
+
+
+static struct proc_dir_entry *example_dir, *foo_file,
+ *bar_file, *jiffies_file, *tty_device, *symlink;
+
+
+struct fb_data_t foo_data, bar_data;
+
+
+static int proc_read_jiffies(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "jiffies = %ld\n",
+ jiffies);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_read_foobar(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "%s = '%s'\n",
+ fb_data->name, fb_data->value);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_write_foobar(struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ if(count > FOOBAR_LEN)
+ len = FOOBAR_LEN;
+ else
+ len = count;
+
+ if(copy_from_user(fb_data->value, buffer, len)) {
+ MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+
+ fb_data->value[len] = '\0';
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int __init init_procfs_example(void)
+{
+ int rv = 0;
+
+ /* create directory */
+ example_dir = proc_mkdir(MODULE_NAME, NULL);
+ if(example_dir == NULL) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ example_dir->owner = THIS_MODULE;
+
+ /* create jiffies using convenience function */
+ jiffies_file = create_proc_read_entry("jiffies",
+ 0444, example_dir,
+ proc_read_jiffies,
+ NULL);
+ if(jiffies_file == NULL) {
+ rv = -ENOMEM;
+ goto no_jiffies;
+ }
+
+ jiffies_file->owner = THIS_MODULE;
+
+ /* create foo and bar files using same callback functions */
+ foo_file = create_proc_entry("foo", 0644, example_dir);
+ if(foo_file == NULL) {
+ rv = -ENOMEM;
+ goto no_foo;
+ }
+
+ strcpy(foo_data.name, "foo");
+ strcpy(foo_data.value, "foo");
+ foo_file->data = &foo_data;
+ foo_file->read_proc = proc_read_foobar;
+ foo_file->write_proc = proc_write_foobar;
+ foo_file->owner = THIS_MODULE;
+
+ bar_file = create_proc_entry("bar", 0644, example_dir);
+ if(bar_file == NULL) {
+ rv = -ENOMEM;
+ goto no_bar;
+ }
+
+ strcpy(bar_data.name, "bar");
+ strcpy(bar_data.value, "bar");
+ bar_file->data = &bar_data;
+ bar_file->read_proc = proc_read_foobar;
+ bar_file->write_proc = proc_write_foobar;
+ bar_file->owner = THIS_MODULE;
+
+ /* create tty device */
+ tty_device = proc_mknod("tty", S_IFCHR | 0666,
+ example_dir, MKDEV(5, 0));
+ if(tty_device == NULL) {
+ rv = -ENOMEM;
+ goto no_tty;
+ }
+
+ tty_device->owner = THIS_MODULE;
+
+ /* create symlink */
+ symlink = proc_symlink("jiffies_too", example_dir,
+ "jiffies");
+ if(symlink == NULL) {
+ rv = -ENOMEM;
+ goto no_symlink;
+ }
+
+ symlink->owner = THIS_MODULE;
+
+ /* everything OK */
+ printk(KERN_INFO "%s %s initialised\n",
+ MODULE_NAME, MODULE_VERSION);
+ return 0;
+
+no_symlink:
+ remove_proc_entry("tty", example_dir);
+no_tty:
+ remove_proc_entry("bar", example_dir);
+no_bar:
+ remove_proc_entry("foo", example_dir);
+no_foo:
+ remove_proc_entry("jiffies", example_dir);
+no_jiffies:
+ remove_proc_entry(MODULE_NAME, NULL);
+out:
+ return rv;
+}
+
+
+static void __exit cleanup_procfs_example(void)
+{
+ remove_proc_entry("jiffies_too", example_dir);
+ remove_proc_entry("tty", example_dir);
+ remove_proc_entry("bar", example_dir);
+ remove_proc_entry("foo", example_dir);
+ remove_proc_entry("jiffies", example_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+
+ printk(KERN_INFO "%s %s removed\n",
+ MODULE_NAME, MODULE_VERSION);
+}
+
+
+module_init(init_procfs_example);
+module_exit(cleanup_procfs_example);
+
+MODULE_AUTHOR("Erik Mouw");
+MODULE_DESCRIPTION("procfs examples");
+
+EXPORT_NO_SYMBOLS;
^ permalink raw reply [flat|nested] 7+ messages in thread
* RE: [PATCH] Procfs Guide
@ 2001-05-30 21:10 hiren_mehta
2001-05-30 21:40 ` Erik Mouw
2001-05-31 12:40 ` Matti Aarnio
0 siblings, 2 replies; 7+ messages in thread
From: hiren_mehta @ 2001-05-30 21:10 UTC (permalink / raw)
Cc: linux-kernel
So where can find the whole docbook ? I could not find under
linux/Documentation directory.
Regards,
-hiren
(408)970-3062
hiren_mehta@agilent.com
> -----Original Message-----
> From: Erik Mouw [mailto:J.A.K.Mouw@ITS.TUDelft.NL]
> Sent: Wednesday, May 30, 2001 1:36 PM
> To: Tim Waugh
> Cc: Linux kernel mailing list; Alan Cox
> Subject: Re: [PATCH] Procfs Guide
>
>
> On Wed, May 30, 2001 at 09:30:48AM +0100, Tim Waugh wrote:
> > On Wed, May 30, 2001 at 01:29:17AM +0200, Erik Mouw wrote:
> > > I'm still looking for a proper way to automatically
> include the example
> > > source into the SGML file, this patch with the same content in two
> > > files is a bit of an ugly hack.
> >
> > Probably your best bet is to get the Makefile to pass a copy of the
> > real example source through sed to &entity;ify the bits that would
> > confuse SGML (<, >, etc), and into example.c.sed, make that into an
> > entity, and include it.
> >
> > See <URL:http://people.redhat.com/twaugh/docbook/selfdocbook/> for
> > instance, which does this with its own SGML source.
>
> Thanks, that was a really helpful example.
>
> So how about this version?
>
>
> Erik
>
> --
> J.A.K. (Erik) Mouw, Information and Communication Theory
> Group, Department
> of Electrical Engineering, Faculty of Information Technology
> and Systems,
> Delft University of Technology, PO BOX 5031, 2600 GA Delft,
> The Netherlands
> Phone: +31-15-2783635 Fax: +31-15-2781843 Email:
> J.A.K.Mouw@its.tudelft.nl
> WWW: http://www-ict.its.tudelft.nl/~erik/
>
>
> Index: Documentation/DocBook/Makefile
> ===================================================================
> RCS file: /home/erik/cvsroot/elinux/Documentation/DocBook/Makefile,v
> retrieving revision 1.1.1.30
> retrieving revision 1.1.1.25.2.2
> diff -u -r1.1.1.30 -r1.1.1.25.2.2
> --- Documentation/DocBook/Makefile 2001/05/15 12:14:07 1.1.1.30
> +++ Documentation/DocBook/Makefile 2001/05/30 20:31:18
> 1.1.1.25.2.2
> @@ -1,7 +1,7 @@
> BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml
> videobook.sgml \
> kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
> kernel-locking.sgml via-audio.sgml mousedrivers.sgml
> sis900.sgml \
> - deviceiobook.sgml
> + deviceiobook.sgml procfs-guide.sgml
>
> PS := $(patsubst %.sgml, %.ps, $(BOOKS))
> PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
> @@ -9,6 +9,7 @@
> IMG-parportbook := parport-share.fig parport-multi.fig
> parport-structure.fig
> EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook))
> JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook))
> +C-procfs-example = procfs_example.sgml
>
> books: $(BOOKS)
>
> @@ -67,6 +68,17 @@
> $(TOPDIR)/scripts/docgen
> $(TOPDIR)/drivers/media/video/videodev.c \
> <videobook.tmpl >videobook.sgml
>
> +procfs_example.sgml: procfs_example.c
> + echo "<programlisting>" > $@
> + expand --tabs=8 < $< | \
> + sed -e "s/&/\\&/g" \
> + -e "s/</\\</g" \
> + -e "s/>/\\>/g" >> $@
> + echo "</programlisting>" >> $@
> +
> +procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml
> + $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
> +
> APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
> $(TOPDIR)/arch/i386/kernel/irq.c \
> $(TOPDIR)/arch/i386/kernel/mca.c \
> @@ -128,6 +140,7 @@
> -$(RM) $(BOOKS)
> -$(RM) $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
> -$(RM) $(JPG-parportbook) $(EPS-parportbook)
> + -$(RM) $(C-procfs-example)
>
> mrproper: clean
> -$(RM) $(PS) $(PDF)
> Index: Documentation/DocBook/procfs-guide.tmpl
> ===================================================================
> RCS file: procfs-guide.tmpl
> diff -N procfs-guide.tmpl
> --- /dev/null Thu Mar 22 14:04:47 2001
> +++ Documentation/DocBook/procfs-guide.tmpl Wed May 30 22:32:02 2001
> @@ -0,0 +1,603 @@
> +<!-- -*- sgml -*- -->
> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[
> +<!ENTITY procfsexample SYSTEM "procfs_example.sgml">
> +]>
> +
> +<book id="LKProcfsGuide">
> + <bookinfo>
> + <title>Linux Kernel Procfs Guide</title>
> +
> +
> + <authorgroup>
> + <author>
> + <firstname>Erik</firstname>
> + <othername>(J.A.K.)</othername>
> + <surname>Mouw</surname>
> + <affiliation>
> + <orgname>Delft University of Technology</orgname>
> + <orgdiv>Faculty of Information Technology and Systems</orgdiv>
> + <address>
> + <email>J.A.K.Mouw@its.tudelft.nl</email>
> + <pob>PO BOX 5031</pob>
> + <postcode>2600 GA</postcode>
> + <city>Delft</city>
> + <country>The Netherlands</country>
> + </address>
> + </affiliation>
> + </author>
> + </authorgroup>
> +
> +
> + <copyright>
> + <year>2001</year>
> + <holder>Erik Mouw</holder>
> + </copyright>
> +
> +
> + <legalnotice>
> + <para>
> + This documentation is free software; you can redistribute it
> + and/or modify it under the terms of the GNU General Public
> + License as published by the Free Software Foundation; either
> + version 2 of the License, or (at your option) any later
> + version.
> + </para>
> +
> + <para>
> + This documentation is distributed in the hope that it will be
> + useful, but WITHOUT ANY WARRANTY; without even the implied
> + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
> + PURPOSE. See the GNU General Public License for
> more details.
> + </para>
> +
> + <para>
> + You should have received a copy of the GNU General Public
> + License along with this program; if not, write to the Free
> + Software Foundation, Inc., 59 Temple Place, Suite
> 330, Boston,
> + MA 02111-1307 USA
> + </para>
> +
> + <para>
> + For more details see the file COPYING in the source
> + distribution of Linux.
> + </para>
> + </legalnotice>
> + </bookinfo>
> +
> +
> +
> +
> + <toc>
> + </toc>
> +
> +
> +
> +
> + <preface>
> + <title>Preface</title>
> +
> + <para>
> + This guide describes the use of the procfs file system from
> + within the Linux kernel. The idea to write this guide
> came up on
> + the #kernelnewbies IRC channel (see <ulink
> +
> url="http://www.kernelnewbies.org/">http://www.kernelnewbies.o
> rg/</ulink>),
> + when Jeff Garzik explained the use of procfs and forwarded me a
> + message Alexander Viro wrote to the linux-kernel
> mailing list. I
> + agreed to write it up nicely, so here it is.
> + </para>
> +
> + <para>
> + I'd like to thank Jeff Garzik
> + <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
> + <email>viro@math.psu.edu</email> for their input, and Tim Waugh
> + <email>twaugh@redhat.com</email> for his <ulink
> +
> url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Sel
> fdocbook</ulink>.
> + </para>
> +
> + <para>
> + This documentation was written while working on the LART
> + computing board (<ulink
> +
> url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/<
> /ulink>).
> + The development has been sponsored by the Mobile Multi-media
> + Communications (<ulink
> +
> url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>)
> + and Ubiquitous Communications (<ulink
> +
> url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.
> nl/</ulink>)
> + projects.
> + </para>
> +
> + <para>
> + Erik
> + </para>
> + </preface>
> +
> +
> +
> +
> + <chapter id="intro">
> + <title>Introduction</title>
> +
> + <para>
> + The <filename class="directory">/proc</filename> file system
> + (procfs) is a special file system in the linux kernel. It's a
> + virtual file system: it is not associated with a block
> device but
> + exists only in memory. The files in the procfs are
> used to allow
> + userland programs access to certain information from the kernel
> + (like process information in <filename
> + class="directory">/proc/[0-9]+/</filename>), but also for debug
> + purposes (like <filename>/proc/ksyms</filename>).
> + </para>
> +
> + <para>
> + This guide describes the use of the procfs file system from
> + within the Linux kernel. It starts by introducing all relevant
> + functions to manage the files within the file system.
> After that
> + it shows how to communicate with userland, and some tips and
> + tricks will be pointed out. Finally a complete example will be
> + shown.
> + </para>
> + </chapter>
> +
> +
> +
> +
> + <chapter id="managing">
> + <title>Managing procfs entries</title>
> +
> + <para>
> + This chapter describes the functions that various kernel
> + components use to populate the procfs with files, symlinks,
> + device nodes, and directories.
> + </para>
> +
> + <para>
> + A minor note before we start: if you want to use any of the
> + procfs functions, be sure to include the correct header file!
> + This should be one of the first lines in your code:
> + </para>
> +
> + <programlisting>
> +#include <linux/proc_fs.h>
> + </programlisting>
> +
> +
> +
> +
> + <sect1 id="regularfile">
> + <title>Creating a regular file</title>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>struct proc_dir_entry*
> <function>create_proc_entry</function></funcdef>
> + <paramdef>const char* <parameter>name</parameter></paramdef>
> + <paramdef>mode_t <parameter>mode</parameter></paramdef>
> + <paramdef>struct proc_dir_entry*
> <parameter>parent</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + This function creates a regular file with the name
> + <parameter>name</parameter>, file mode
> + <parameter>mode</parameter> in the directory
> + <parameter>parent</parameter>. To create a file in
> the root of
> + the procfs, use <constant>NULL</constant> as
> + <parameter>parent</parameter> parameter. When successful, the
> + function will return a pointer to the freshly created
> + <structname>struct proc_dir_entry</structname>; otherwise it
> + will return <constant>NULL</constant>. <xref
> + linkend="userland"> describes how to do something useful with
> + regular files.
> + <para>
> +
> + <para>
> + Note that it is specifically supported that you can pass a
> + multi-directory path. For example
> +
> <function>create_proc_entry</function>(<parameter>"drivers/via
0/info"</parameter>)
> + will create the <filename class="directory">via0</filename>
> + directory if necessary, with standard
> + <constant>0755</constant> permissions.
> + </para>
> +
> + <para>
> + If you only want to be able to read the file, the function
> + <function>create_proc_read_entry</function> described in <xref
> + linkend="convenience"> might be used to create and initialise
> + the procfs entry in one single call.
> + </para>
> + </sect1>
> +
> +
> +
> +
> + <sect1>
> + <title>Creating a symlink</title>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>struct proc_dir_entry*
> + <function>proc_symlink</function></funcdef> <paramdef>const
> + char* <parameter>name</parameter></paramdef>
> + <paramdef>struct proc_dir_entry*
> + <parameter>parent</parameter></paramdef> <paramdef>const
> + char* <parameter>dest</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + This creates a symlink in the procfs directory
> + <parameter>parent</parameter> that points from
> + <parameter>name</parameter> to
> + <parameter>dest</parameter>. This translates in userland to
> + <literal>ln -s</literal> <parameter>dest</parameter>
> + <parameter>name</parameter>.
> + </para>
> + </sect1>
> +
> +
> +
> +
> + <sect1>
> + <title>Creating a device</title>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>struct proc_dir_entry*
> <function>proc_mknod</function></funcdef>
> + <paramdef>const char* <parameter>name</parameter></paramdef>
> + <paramdef>mode_t <parameter>mode</parameter></paramdef>
> + <paramdef>struct proc_dir_entry*
> <parameter>parent</parameter></paramdef>
> + <paramdef>kdev_t <parameter>rdev</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + Creates a device file <parameter>name</parameter> with mode
> + <parameter>mode</parameter> in the procfs directory
> + <parameter>parent</parameter>. The device file will work on
> + the device <parameter>rdev</parameter>, which can be
> generated
> + by using the <literal>MKDEV</literal> macro from
> + <literal>linux/kdev_t.h</literal>. The
> + <parameter>mode</parameter> parameter
> + <emphasis>must</emphasis> contain
> <constant>S_IFBLK</constant>
> + or <constant>S_IFCHR</constant> to create a device
> + node. Compare with userland <literal>mknod
> + --mode=</literal><parameter>mode</parameter>
> + <parameter>name</parameter> <parameter>rdev</parameter>.
> + </para>
> + </sect1>
> +
> +
> +
> +
> + <sect1>
> + <title>Creating a directory</title>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>struct proc_dir_entry*
> <function>proc_mkdir</function></funcdef>
> + <paramdef>const char* <parameter>name</parameter></paramdef>
> + <paramdef>struct proc_dir_entry*
> <parameter>parent</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + Create a directory <parameter>name</parameter> in the procfs
> + directory <parameter>parent</parameter>.
> + </para>
> + </sect1>
> +
> +
> +
> +
> + <sect1>
> + <title>Removing an entry</title>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>void <function>remove_proc_entry</function></funcdef>
> + <paramdef>const char* <parameter>name</parameter></paramdef>
> + <paramdef>struct proc_dir_entry*
> <parameter>parent</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + Removes the entry <parameter>name</parameter> in the
> directory
> + <parameter>parent</parameter> from the procfs. Note that
> + entries are removed by their
> <emphasis>name</emphasis>, not by
> + the <structname>struct proc_dir_entry</structname>
> returned by the
> + various create functions.
> + </para>
> +
> + <para>
> + Note that the <structfield>data</structfield> entry from the
> + <structname>struct proc_dir_entry</structname>> has
> to be freed
> + before this function is called (that is: if there was some
> + <structfield>data</structfield> allocated, of course). See
> + <xref linkend="usingdata"> for more information on using the
> + <structfield>data</structfield> entry.
> + </para>
> + </sect1>
> + </chapter>
> +
> +
> +
> +
> + <chapter id="userland">
> + <title>Communicating with userland</title>
> +
> + <para>
> + Instead of reading (or writing) the information directly from
> + kernel memory, the procfs works with <emphasis>call back
> + functions</emphasis> for files: functions that are called when
> + a specific file is being read or written. Those functions have
> + to be initialised after the procfs file is created by setting
> + the <structfield>read_proc</structfield> and/or
> + <structfield>write_proc</structfield> fields in the
> + <structname>struct proc_dir_entry*</structname> the function
> + <function>create_proc_entry</function> returned:
> + </para>
> +
> + <programlisting>
> +struct proc_dir_entry* entry;
> +
> +entry->read_proc = read_proc_foo;
> +entry->write_proc = write_proc_foo;
> + </programlisting>
> +
> + <para>
> + If you only want to use a the
> + <structfield>read_proc</structfield>, the function
> + <function>create_proc_read_entry</function> described in <xref
> + linkend="convenience"> might be used to create and initialise
> + the procfs entry in one single call.
> + </para>
> +
> +
> +
> + <sect1>
> + <title>Reading data</title>
> +
> + <para>
> + The read function is a call back function that
> allows userland
> + processes to read data from the kernel. The read function
> + should have the following format:
> + </para>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>int <function>read_func</function></funcdef>
> + <paramdef>char* <parameter>page</parameter></paramdef>
> + <paramdef>char** <parameter>start</parameter></paramdef>
> + <paramdef>off_t <parameter>off</parameter></paramdef>
> + <paramdef>int <parameter>count</parameter></paramdef>
> + <paramdef>int* <parameter>eof</parameter></paramdef>
> + <paramdef>void* <parameter>data</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + The read function should write its information into the
> + <parameter>page</parameter>. For proper use, the function
> + should start writing at an offset of
> + <parameter>off</parameter> in <parameter>page</parameter> and
> + write <parameter>count</parameter> bytes at maximum, but
> + because most read functions are quite simple and
> only return a
> + small amount of information, these two parameters are usually
> + ignored (it breaks pagers like <literal>more</literal> and
> + <literal>less</literal>, but <literal>cat</literal> still
> + works).
> + </para>
> +
> + <para>
> + If the <parameter>off</parameter> and
> + <parameter>count</parameter> parameters are properly used,
> + <parameter>eof</parameter> should be used to signal that the
> + end of the file has been reached by writing
> + <literal>1</literal> to the memory location
> + <parameter>eof</parameter> points to.
> + </para>
> +
> + <para>
> + The parameter <parameter>start</parameter> doesn't seem to be
> + used anywhere in the kernel. The <parameter>data</parameter>
> + parameter can be used to use a single call back function for
> + several files, see <xref linkend="usingdata">.
> + </para>
> +
> + <para>
> + The <function>read_func</function> function must return the
> + number of bytes written into the <parameter>page</parameter>.
> + </para>
> +
> + <para>
> + <xref linkend="example"> shows how to use a read call back
> + function.
> + </para>
> + </sect1>
> +
> +
> +
> +
> + <sect1>
> + <title>Writing data</title>
> +
> + <para>
> + The write call back function allows a userland
> process to write
> + data to the kernel, so it has some kind of control over the
> + kernel. The write function should have the following format:
> + </para>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>int <function>write_func</function></funcdef>
> + <paramdef>struct file* <parameter>file</parameter></paramdef>
> + <paramdef>const char* <parameter>buffer</parameter></paramdef>
> + <paramdef>unsigned long
> <parameter>count</parameter></paramdef>
> + <paramdef>void* <parameter>data</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + The write function should read <parameter>count</parameter>
> + bytes at maximum from the <parameter>buffer</parameter>. Note
> + that the <parameter>buffer</parameter> doesn't live in the
> + kernel's memory space, so it should first be copied to kernel
> + space with <function>copy_from_user</function>. The
> + <parameter>file</parameter> parameter is usually
> + ignored. <xref linkend="usingdata"> shows how to use the
> + <parameter>data</parameter> parameter.
> + </para>
> +
> + <para>
> + Again, <xref linkend="example"> shows how to use
> this call back
> + function.
> + </para>
> + </sect1>
> +
> +
> +
> +
> + <sect1 id="usingdata">
> + <title>A single call back for many files</title>
> +
> + <para>
> + When a large number of almost identical files is used, it's
> + quite inconvenient to use a separate call back function for
> + each file. Instead of that, a single call back
> function can be
> + used that distinguishes between the files by using
> + <structfield>data</structfield> field in <structname>struct
> + proc_dir_entry</structname>. First of all, the
> + <structfield>data</structfield> field has to be initialised:
> + </para>
> +
> + <programlisting>
> +struct proc_dir_entry* entry;
> +struct my_file_data *file_data;
> +
> +file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL);
> +entry->data = file_data;
> + </programlisting>
> +
> + <para>
> + The <structfield>data</structfield> field is a <type>void
> + *</type>, so it can be initialised with anything.
> + </para>
> +
> + <para>
> + Now that the <structfield>data</structfield> field
> is set, the
> + <function>read_proc</function> and
> + <function>write_proc</function> can use it to distinguish
> + between files because they get it passed into their
> + <parameter>data</parameter> parameter:
> + </para>
> +
> + <programlisting>
> +int foo_read_func(char *page, char **start, off_t off,
> + int count, int *eof, void *data)
> +{
> + int len;
> +
> + if(data == file_data) {
> + /* special case for this file */
> + } else {
> + /* normal processing */
> + }
> +
> + return len;
> +}
> + </programlisting>
> +
> + <para>
> + Be sure to free the <structfield>data</structfield>
> data field
> + when removing the procfs entry.
> + </para>
> + </sect1>
> + </chapter>
> +
> +
> +
> +
> + <chapter id="tips">
> + <title>Tips and tricks</title>
> +
> +
> +
> +
> + <sect1 id="convenience">
> + <title>Convenience functions</title>
> +
> + <funcsynopsis>
> + <funcprototype>
> + <funcdef>struct proc_dir_entry*
> <function>create_proc_read_entry</function></funcdef>
> + <paramdef>const char* <parameter>name</parameter></paramdef>
> + <paramdef>mode_t <parameter>mode</parameter></paramdef>
> + <paramdef>struct proc_dir_entry*
> <parameter>parent</parameter></paramdef>
> + <paramdef>read_proc_t*
> <parameter>read_proc</parameter></paramdef>
> + <paramdef>void* <parameter>data</parameter></paramdef>
> + </funcprototype>
> + </funcsynopsis>
> +
> + <para>
> + This function creates a regular file in exactly the same way
> + as <function>create_proc_entry</function> from <xref
> + linkend="regularfile"> does, but also allows to set the read
> + function <parameter>read_proc</parameter> in one call. This
> + function is also able to set the <parameter>data</parameter>,
> + as explained in <xref linkend="usingdata">.
> + </para>
> + </sect1>
> +
> +
> +
> + <sect1>
> + <title>Modules</title>
> +
> + <para>
> + If the procfs is being used from within a module, be sure to
> + set the <structfield>owner</structfield> field in the
> + <structname>struct proc_dir_entry</structname> to
> + <constant>THIS_MODULE</constant>.
> + <para>
> +
> + <programlisting>
> +struct proc_dir_entry* entry;
> +
> +entry->owner = THIS_MODULE;
> + </programlisting>
> + </sect1>
> +
> +
> +
> +
> + <sect1>
> + <title>Mode and ownership</title>
> +
> + <para>
> + Sometimes it is useful to change the mode and/or
> ownership of a
> + procfs entry. Here is an example how to achieve that:
> + </para>
> +
> + <programlisting>
> +struct proc_dir_entry* entry;
> +
> +entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH;
> +entry->uid = 0;
> +entry->gid = 100;
> + </programlisting>
> +
> + </sect1>
> + </chapter>
> +
> +
> +
> +
> + <chapter id="example">
> + <title>Example</title>
> +
> + <!-- be careful with the example code: it shouldn't be wider than
> + approx. 60 columns, or otherwise it won't fit properly on a page
> + -->
> +
> +&procfsexample;
> +
> + </chapter>
> +</book>
> Index: Documentation/DocBook/procfs_example.c
> ===================================================================
> RCS file: procfs_example.c
> diff -N procfs_example.c
> --- /dev/null Thu Mar 22 14:04:47 2001
> +++ Documentation/DocBook/procfs_example.c Wed May 30 22:32:02 2001
> @@ -0,0 +1,247 @@
> +/*
> + * procfs_example.c: an example proc interface
> + *
> + * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
> + *
> + * This file accompanies the procfs-guide in the Linux kernel
> + * source. It's main use is to demonstrate the concepts and
> + * functions described in the guide.
> + *
> + * This software has been developed while working on the LART
> + * computing board (http://www.lart.tudelft.nl/). The
> + * development has been sponsored by the Mobile Multi-media
> + * Communications (http://www.mmc.tudelft.nl/) and Ubiquitous
> + * Communications (http://www.ubicom.tudelft.nl/) projects.
> + *
> + * The author can be reached at:
> + *
> + * Erik Mouw
> + * Information and Communication Theory Group
> + * Faculty of Information Technology and Systems
> + * Delft University of Technology
> + * P.O. Box 5031
> + * 2600 GA Delft
> + * The Netherlands
> + *
> + *
> + * This program is free software; you can redistribute
> + * it and/or modify it under the terms of the GNU General
> + * Public License as published by the Free Software
> + * Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + * This program is distributed in the hope that it will be
> + * useful, but WITHOUT ANY WARRANTY; without even the implied
> + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
> + * PURPOSE. See the GNU General Public License for more
> + * details.
> + *
> + * You should have received a copy of the GNU General Public
> + * License along with this program; if not, write to the
> + * Free Software Foundation, Inc., 59 Temple Place,
> + * Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/proc_fs.h>
> +#include <linux/sched.h>
> +#include <asm/uaccess.h>
> +
> +
> +#define MODULE_VERSION "1.0"
> +#define MODULE_NAME "procfs_example"
> +
> +#define FOOBAR_LEN 8
> +
> +struct fb_data_t {
> + char name[FOOBAR_LEN + 1];
> + char value[FOOBAR_LEN + 1];
> +};
> +
> +
> +static struct proc_dir_entry *example_dir, *foo_file,
> + *bar_file, *jiffies_file, *tty_device, *symlink;
> +
> +
> +struct fb_data_t foo_data, bar_data;
> +
> +
> +static int proc_read_jiffies(char *page, char **start,
> + off_t off, int count,
> + int *eof, void *data)
> +{
> + int len;
> +
> + MOD_INC_USE_COUNT;
> +
> + len = sprintf(page, "jiffies = %ld\n",
> + jiffies);
> +
> + MOD_DEC_USE_COUNT;
> +
> + return len;
> +}
> +
> +
> +static int proc_read_foobar(char *page, char **start,
> + off_t off, int count,
> + int *eof, void *data)
> +{
> + int len;
> + struct fb_data_t *fb_data = (struct fb_data_t *)data;
> +
> + MOD_INC_USE_COUNT;
> +
> + len = sprintf(page, "%s = '%s'\n",
> + fb_data->name, fb_data->value);
> +
> + MOD_DEC_USE_COUNT;
> +
> + return len;
> +}
> +
> +
> +static int proc_write_foobar(struct file *file,
> + const char *buffer,
> + unsigned long count,
> + void *data)
> +{
> + int len;
> + struct fb_data_t *fb_data = (struct fb_data_t *)data;
> +
> + MOD_INC_USE_COUNT;
> +
> + if(count > FOOBAR_LEN)
> + len = FOOBAR_LEN;
> + else
> + len = count;
> +
> + if(copy_from_user(fb_data->value, buffer, len)) {
> + MOD_DEC_USE_COUNT;
> + return -EFAULT;
> + }
> +
> + fb_data->value[len] = '\0';
> +
> + MOD_DEC_USE_COUNT;
> +
> + return len;
> +}
> +
> +
> +static int __init init_procfs_example(void)
> +{
> + int rv = 0;
> +
> + /* create directory */
> + example_dir = proc_mkdir(MODULE_NAME, NULL);
> + if(example_dir == NULL) {
> + rv = -ENOMEM;
> + goto out;
> + }
> +
> + example_dir->owner = THIS_MODULE;
> +
> + /* create jiffies using convenience function */
> + jiffies_file = create_proc_read_entry("jiffies",
> + 0444, example_dir,
> + proc_read_jiffies,
> + NULL);
> + if(jiffies_file == NULL) {
> + rv = -ENOMEM;
> + goto no_jiffies;
> + }
> +
> + jiffies_file->owner = THIS_MODULE;
> +
> + /* create foo and bar files using same callback functions */
> + foo_file = create_proc_entry("foo", 0644, example_dir);
> + if(foo_file == NULL) {
> + rv = -ENOMEM;
> + goto no_foo;
> + }
> +
> + strcpy(foo_data.name, "foo");
> + strcpy(foo_data.value, "foo");
> + foo_file->data = &foo_data;
> + foo_file->read_proc = proc_read_foobar;
> + foo_file->write_proc = proc_write_foobar;
> + foo_file->owner = THIS_MODULE;
> +
> + bar_file = create_proc_entry("bar", 0644, example_dir);
> + if(bar_file == NULL) {
> + rv = -ENOMEM;
> + goto no_bar;
> + }
> +
> + strcpy(bar_data.name, "bar");
> + strcpy(bar_data.value, "bar");
> + bar_file->data = &bar_data;
> + bar_file->read_proc = proc_read_foobar;
> + bar_file->write_proc = proc_write_foobar;
> + bar_file->owner = THIS_MODULE;
> +
> + /* create tty device */
> + tty_device = proc_mknod("tty", S_IFCHR | 0666,
> + example_dir, MKDEV(5, 0));
> + if(tty_device == NULL) {
> + rv = -ENOMEM;
> + goto no_tty;
> + }
> +
> + tty_device->owner = THIS_MODULE;
> +
> + /* create symlink */
> + symlink = proc_symlink("jiffies_too", example_dir,
> + "jiffies");
> + if(symlink == NULL) {
> + rv = -ENOMEM;
> + goto no_symlink;
> + }
> +
> + symlink->owner = THIS_MODULE;
> +
> + /* everything OK */
> + printk(KERN_INFO "%s %s initialised\n",
> + MODULE_NAME, MODULE_VERSION);
> + return 0;
> +
> +no_symlink:
> + remove_proc_entry("tty", example_dir);
> +no_tty:
> + remove_proc_entry("bar", example_dir);
> +no_bar:
> + remove_proc_entry("foo", example_dir);
> +no_foo:
> + remove_proc_entry("jiffies", example_dir);
> +no_jiffies:
> + remove_proc_entry(MODULE_NAME, NULL);
> +out:
> + return rv;
> +}
> +
> +
> +static void __exit cleanup_procfs_example(void)
> +{
> + remove_proc_entry("jiffies_too", example_dir);
> + remove_proc_entry("tty", example_dir);
> + remove_proc_entry("bar", example_dir);
> + remove_proc_entry("foo", example_dir);
> + remove_proc_entry("jiffies", example_dir);
> + remove_proc_entry(MODULE_NAME, NULL);
> +
> + printk(KERN_INFO "%s %s removed\n",
> + MODULE_NAME, MODULE_VERSION);
> +}
> +
> +
> +module_init(init_procfs_example);
> +module_exit(cleanup_procfs_example);
> +
> +MODULE_AUTHOR("Erik Mouw");
> +MODULE_DESCRIPTION("procfs examples");
> +
> +EXPORT_NO_SYMBOLS;
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe
> linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Procfs Guide
2001-05-30 21:10 hiren_mehta
@ 2001-05-30 21:40 ` Erik Mouw
2001-05-31 12:40 ` Matti Aarnio
1 sibling, 0 replies; 7+ messages in thread
From: Erik Mouw @ 2001-05-30 21:40 UTC (permalink / raw)
To: hiren_mehta; +Cc: linux-kernel
On Wed, May 30, 2001 at 03:10:32PM -0600, hiren_mehta@agilent.com wrote:
> So where can find the whole docbook ? I could not find under
> linux/Documentation directory.
That's correct, I only submitted it for inclusion into the kernel, so
it's not yet there. Just patch your kernel source with my patch, run
"make psdocs" and you'll have it in your kernel tree as well.
However, because we got a similar procfs question on the kernelnewbies
list, I already put the html and pdf versions online on the
kernelnewbies documentation pages:
http://www.kernelnewbies.org/documents/kdoc/procfs-guide/lkprocfsguide.html
Erik
PS: Was it really necessary to quote my complete message *including*
the patch? Next time quote properly before you post.
--
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Department
of Electrical Engineering, Faculty of Information Technology and Systems,
Delft University of Technology, PO BOX 5031, 2600 GA Delft, The Netherlands
Phone: +31-15-2783635 Fax: +31-15-2781843 Email: J.A.K.Mouw@its.tudelft.nl
WWW: http://www-ict.its.tudelft.nl/~erik/
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Procfs Guide
2001-05-30 21:10 hiren_mehta
2001-05-30 21:40 ` Erik Mouw
@ 2001-05-31 12:40 ` Matti Aarnio
1 sibling, 0 replies; 7+ messages in thread
From: Matti Aarnio @ 2001-05-31 12:40 UTC (permalink / raw)
To: hiren_mehta; +Cc: linux-kernel
On Wed, May 30, 2001 at 03:10:32PM -0600, hiren_mehta@agilent.com wrote:
> So where can find the whole docbook ? I could not find under
> linux/Documentation directory.
The "docbook" is SGML DTD suite. Analogous to "lets write it in HTML.."
See readymade packages needed to convert DOCBOOK style source
text into some redition at RH 7.x:
*docbook*
*sgml*
*jade*
*pdf*
*tex*
I think those are sufficient.
> Regards,
> -hiren
> (408)970-3062
> hiren_mehta@agilent.com
/Matti Aarnio
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] procfs guide
@ 2001-06-03 22:18 Erik Mouw
0 siblings, 0 replies; 7+ messages in thread
From: Erik Mouw @ 2001-06-03 22:18 UTC (permalink / raw)
To: Linux kernel mailing list; +Cc: Alan Cox
Hi,
I got some comments on my procfs guide when I posted it a couple of
days ago, so here is a new version. What's new:
- add revision history (Jonathan Lundel)
- remove_proc_entry() is not recursive (Jonathan Lundel)
- numerous spelling corrections (Marc Joosen)
- /proc/sys files are sysctl, not procfs (John Levon)
- add an implicit .c to .sgml rule to the Makefile (me)
- fixed a too long comment in the example code (me)
The patch is against 2.4.5-ac6, but should apply cleanly to 2.4.5-ac7
as well. Please apply.
Erik
--
J.A.K. (Erik) Mouw, Information and Communication Theory Group, Department
of Electrical Engineering, Faculty of Information Technology and Systems,
Delft University of Technology, PO BOX 5031, 2600 GA Delft, The Netherlands
Phone: +31-15-2783635 Fax: +31-15-2781843 Email: J.A.K.Mouw@its.tudelft.nl
WWW: http://www-ict.its.tudelft.nl/~erik/
Index: Documentation/DocBook/Makefile
===================================================================
RCS file: /home/erik/cvsroot/elinux/Documentation/DocBook/Makefile,v
retrieving revision 1.1.1.30
diff -u -r1.1.1.30 Makefile
--- Documentation/DocBook/Makefile 2001/05/15 12:14:07 1.1.1.30
+++ Documentation/DocBook/Makefile 2001/06/03 21:09:27
@@ -1,7 +1,7 @@
BOOKS := wanbook.sgml z8530book.sgml mcabook.sgml videobook.sgml \
kernel-api.sgml parportbook.sgml kernel-hacking.sgml \
kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \
- deviceiobook.sgml
+ deviceiobook.sgml procfs-guide.sgml
PS := $(patsubst %.sgml, %.ps, $(BOOKS))
PDF := $(patsubst %.sgml, %.pdf, $(BOOKS))
@@ -9,6 +9,7 @@
IMG-parportbook := parport-share.fig parport-multi.fig parport-structure.fig
EPS-parportbook := $(patsubst %.fig, %.eps, $(IMG-parportbook))
JPG-parportbook := $(patsubst %.fig, %.jpeg, $(IMG-parportbook))
+C-procfs-example = procfs_example.sgml
books: $(BOOKS)
@@ -28,6 +29,15 @@
%.jpeg: %.fig
-fig2dev -Ljpeg $< $@
+%.sgml: %.c
+ echo "<programlisting>" > $@
+ expand --tabs=8 < $< | \
+ sed -e "s/&/\\&/g" \
+ -e "s/</\\</g" \
+ -e "s/>/\\>/g" >> $@
+ echo "</programlisting>" >> $@
+
+
$(TOPDIR)/scripts/docproc:
$(MAKE) -C $(TOPDIR)/scripts docproc
@@ -67,6 +77,9 @@
$(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \
<videobook.tmpl >videobook.sgml
+procfs-guide.sgml: procfs-guide.tmpl procfs_example.sgml
+ $(TOPDIR)/scripts/docgen < procfs-guide.tmpl >$@
+
APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \
$(TOPDIR)/arch/i386/kernel/irq.c \
$(TOPDIR)/arch/i386/kernel/mca.c \
@@ -128,6 +141,7 @@
-$(RM) $(BOOKS)
-$(RM) $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
-$(RM) $(JPG-parportbook) $(EPS-parportbook)
+ -$(RM) $(C-procfs-example)
mrproper: clean
-$(RM) $(PS) $(PDF)
Index: Documentation/DocBook/procfs-guide.tmpl
===================================================================
RCS file: procfs-guide.tmpl
diff -N procfs-guide.tmpl
--- /dev/null Thu Mar 22 14:04:47 2001
+++ Documentation/DocBook/procfs-guide.tmpl Sun Jun 3 23:39:23 2001
@@ -0,0 +1,625 @@
+<!-- -*- sgml -*- -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[
+<!ENTITY procfsexample SYSTEM "procfs_example.sgml">
+]>
+
+<book id="LKProcfsGuide">
+ <bookinfo>
+ <title>Linux Kernel Procfs Guide</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Erik</firstname>
+ <othername>(J.A.K.)</othername>
+ <surname>Mouw</surname>
+ <affiliation>
+ <orgname>Delft University of Technology</orgname>
+ <orgdiv>Faculty of Information Technology and Systems</orgdiv>
+ <address>
+ <email>J.A.K.Mouw@its.tudelft.nl</email>
+ <pob>PO BOX 5031</pob>
+ <postcode>2600 GA</postcode>
+ <city>Delft</city>
+ <country>The Netherlands</country>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <revhistory>
+ <revision>
+ <revnumber>1.0 </revnumber>
+ <date>May 30, 2001</date>
+ <revremark>Initial revision posted to linux-kernel</revremark>
+ </revision>
+ <revision>
+ <revnumber>1.1 </revnumber>
+ <date>June 3, 2001</date>
+ <revremark>Revised after comments from linux-kernel</revremark>
+ </revision>
+ </revhistory>
+
+ <copyright>
+ <year>2001</year>
+ <holder>Erik Mouw</holder>
+ </copyright>
+
+
+ <legalnotice>
+ <para>
+ This documentation is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ </para>
+
+ <para>
+ This documentation is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the GNU General Public License for more details.
+ </para>
+
+ <para>
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ MA 02111-1307 USA
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+
+
+
+ <toc>
+ </toc>
+
+
+
+
+ <preface>
+ <title>Preface</title>
+
+ <para>
+ This guide describes the use of the procfs file system from
+ within the Linux kernel. The idea to write this guide came up on
+ the #kernelnewbies IRC channel (see <ulink
+ url="http://www.kernelnewbies.org/">http://www.kernelnewbies.org/</ulink>),
+ when Jeff Garzik explained the use of procfs and forwarded me a
+ message Alexander Viro wrote to the linux-kernel mailing list. I
+ agreed to write it up nicely, so here it is.
+ </para>
+
+ <para>
+ I'd like to thank Jeff Garzik
+ <email>jgarzik@mandrakesoft.com</email> and Alexander Viro
+ <email>viro@math.psu.edu</email> for their input, Tim Waugh
+ <email>twaugh@redhat.com</email> for his <ulink
+ url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
+ and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for
+ proofreading.
+ </para>
+
+ <para>
+ This documentation was written while working on the LART
+ computing board (<ulink
+ url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/</ulink>),
+ which is sponsored by the Mobile Multi-media Communications
+ (<ulink
+ url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>)
+ and Ubiquitous Communications (<ulink
+ url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.nl/</ulink>)
+ projects.
+ </para>
+
+ <para>
+ Erik
+ </para>
+ </preface>
+
+
+
+
+ <chapter id="intro">
+ <title>Introduction</title>
+
+ <para>
+ The <filename class="directory">/proc</filename> file system
+ (procfs) is a special file system in the linux kernel. It's a
+ virtual file system: it is not associated with a block device
+ but exists only in memory. The files in the procfs are there to
+ allow userland programs access to certain information from the
+ kernel (like process information in <filename
+ class="directory">/proc/[0-9]+/</filename>), but also for debug
+ purposes (like <filename>/proc/ksyms</filename>).
+ </para>
+
+ <para>
+ This guide describes the use of the procfs file system from
+ within the Linux kernel. It starts by introducing all relevant
+ functions to manage the files within the file system. After that
+ it shows how to communicate with userland, and some tips and
+ tricks will be pointed out. Finally a complete example will be
+ shown.
+ </para>
+
+ <para>
+ Note that the files in <filename
+ class="directory">/proc/sys</filename> are sysctl files: they
+ don't belong to procfs and are governed by a completely
+ different API described in the Kernel API book.
+ </para>
+ </chapter>
+
+
+
+
+ <chapter id="managing">
+ <title>Managing procfs entries</title>
+
+ <para>
+ This chapter describes the functions that various kernel
+ components use to populate the procfs with files, symlinks,
+ device nodes, and directories.
+ </para>
+
+ <para>
+ A minor note before we start: if you want to use any of the
+ procfs functions, be sure to include the correct header file!
+ This should be one of the first lines in your code:
+ </para>
+
+ <programlisting>
+#include <linux/proc_fs.h>
+ </programlisting>
+
+
+
+
+ <sect1 id="regularfile">
+ <title>Creating a regular file</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>create_proc_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This function creates a regular file with the name
+ <parameter>name</parameter>, file mode
+ <parameter>mode</parameter> in the directory
+ <parameter>parent</parameter>. To create a file in the root of
+ the procfs, use <constant>NULL</constant> as
+ <parameter>parent</parameter> parameter. When successful, the
+ function will return a pointer to the freshly created
+ <structname>struct proc_dir_entry</structname>; otherwise it
+ will return <constant>NULL</constant>. <xref
+ linkend="userland"> describes how to do something useful with
+ regular files.
+ <para>
+
+ <para>
+ Note that it is specifically supported that you can pass a
+ path that spans multiple directories. For example
+ <function>create_proc_entry</function>(<parameter>"drivers/via0/info"</parameter>)
+ will create the <filename class="directory">via0</filename>
+ directory if necessary, with standard
+ <constant>0755</constant> permissions.
+ </para>
+
+ <para>
+ If you only want to be able to read the file, the function
+ <function>create_proc_read_entry</function> described in <xref
+ linkend="convenience"> may be used to create and initialise
+ the procfs entry in one single call.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a symlink</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry*
+ <function>proc_symlink</function></funcdef> <paramdef>const
+ char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry*
+ <parameter>parent</parameter></paramdef> <paramdef>const
+ char* <parameter>dest</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This creates a symlink in the procfs directory
+ <parameter>parent</parameter> that points from
+ <parameter>name</parameter> to
+ <parameter>dest</parameter>. This translates in userland to
+ <literal>ln -s</literal> <parameter>dest</parameter>
+ <parameter>name</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a device</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>proc_mknod</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ <paramdef>kdev_t <parameter>rdev</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Creates a device file <parameter>name</parameter> with mode
+ <parameter>mode</parameter> in the procfs directory
+ <parameter>parent</parameter>. The device file will work on
+ the device <parameter>rdev</parameter>, which can be generated
+ by using the <literal>MKDEV</literal> macro from
+ <literal>linux/kdev_t.h</literal>. The
+ <parameter>mode</parameter> parameter
+ <emphasis>must</emphasis> contain <constant>S_IFBLK</constant>
+ or <constant>S_IFCHR</constant> to create a device
+ node. Compare with userland <literal>mknod
+ --mode=</literal><parameter>mode</parameter>
+ <parameter>name</parameter> <parameter>rdev</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Creating a directory</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>proc_mkdir</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Create a directory <parameter>name</parameter> in the procfs
+ directory <parameter>parent</parameter>.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Removing an entry</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>void <function>remove_proc_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ Removes the entry <parameter>name</parameter> in the directory
+ <parameter>parent</parameter> from the procfs. Entries are
+ removed by their <emphasis>name</emphasis>, not by the
+ <structname>struct proc_dir_entry</structname> returned by the
+ various create functions. Note that this function doesn't
+ recursively remove entries.
+ </para>
+
+ <para>
+ Be sure to free the <structfield>data</structfield> entry from
+ the <structname>struct proc_dir_entry</structname> before
+ <function>remove_proc_entry</function> is called (that is: if
+ there was some <structfield>data</structfield> allocated, of
+ course). See <xref linkend="usingdata"> for more information
+ on using the <structfield>data</structfield> entry.
+ </para>
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="userland">
+ <title>Communicating with userland</title>
+
+ <para>
+ Instead of reading (or writing) information directly from
+ kernel memory, procfs works with <emphasis>call back
+ functions</emphasis> for files: functions that are called when
+ a specific file is being read or written. Such functions have
+ to be initialised after the procfs file is created by setting
+ the <structfield>read_proc</structfield> and/or
+ <structfield>write_proc</structfield> fields in the
+ <structname>struct proc_dir_entry*</structname> that the
+ function <function>create_proc_entry</function> returned:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->read_proc = read_proc_foo;
+entry->write_proc = write_proc_foo;
+ </programlisting>
+
+ <para>
+ If you only want to use a the
+ <structfield>read_proc</structfield>, the function
+ <function>create_proc_read_entry</function> described in <xref
+ linkend="convenience"> may be used to create and initialise the
+ procfs entry in one single call.
+ </para>
+
+
+
+ <sect1>
+ <title>Reading data</title>
+
+ <para>
+ The read function is a call back function that allows userland
+ processes to read data from the kernel. The read function
+ should have the following format:
+ </para>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>read_func</function></funcdef>
+ <paramdef>char* <parameter>page</parameter></paramdef>
+ <paramdef>char** <parameter>start</parameter></paramdef>
+ <paramdef>off_t <parameter>off</parameter></paramdef>
+ <paramdef>int <parameter>count</parameter></paramdef>
+ <paramdef>int* <parameter>eof</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The read function should write its information into the
+ <parameter>page</parameter>. For proper use, the function
+ should start writing at an offset of
+ <parameter>off</parameter> in <parameter>page</parameter> and
+ write at most <parameter>count</parameter> bytes, but because
+ most read functions are quite simple and only return a small
+ amount of information, these two parameters are usually
+ ignored (it breaks pagers like <literal>more</literal> and
+ <literal>less</literal>, but <literal>cat</literal> still
+ works).
+ </para>
+
+ <para>
+ If the <parameter>off</parameter> and
+ <parameter>count</parameter> parameters are properly used,
+ <parameter>eof</parameter> should be used to signal that the
+ end of the file has been reached by writing
+ <literal>1</literal> to the memory location
+ <parameter>eof</parameter> points to.
+ </para>
+
+ <para>
+ The parameter <parameter>start</parameter> doesn't seem to be
+ used anywhere in the kernel. The <parameter>data</parameter>
+ parameter can be used to create a single call back function for
+ several files, see <xref linkend="usingdata">.
+ </para>
+
+ <para>
+ The <function>read_func</function> function must return the
+ number of bytes written into the <parameter>page</parameter>.
+ </para>
+
+ <para>
+ <xref linkend="example"> shows how to use a read call back
+ function.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Writing data</title>
+
+ <para>
+ The write call back function allows a userland process to write
+ data to the kernel, so it has some kind of control over the
+ kernel. The write function should have the following format:
+ </para>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>write_func</function></funcdef>
+ <paramdef>struct file* <parameter>file</parameter></paramdef>
+ <paramdef>const char* <parameter>buffer</parameter></paramdef>
+ <paramdef>unsigned long <parameter>count</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ The write function should read <parameter>count</parameter>
+ bytes at maximum from the <parameter>buffer</parameter>. Note
+ that the <parameter>buffer</parameter> doesn't live in the
+ kernel's memory space, so it should first be copied to kernel
+ space with <function>copy_from_user</function>. The
+ <parameter>file</parameter> parameter is usually
+ ignored. <xref linkend="usingdata"> shows how to use the
+ <parameter>data</parameter> parameter.
+ </para>
+
+ <para>
+ Again, <xref linkend="example"> shows how to use this call back
+ function.
+ </para>
+ </sect1>
+
+
+
+
+ <sect1 id="usingdata">
+ <title>A single call back for many files</title>
+
+ <para>
+ When a large number of almost identical files is used, it's
+ quite inconvenient to use a separate call back function for
+ each file. A better approach is to have a single call back
+ function that distinguishes between the files by using the
+ <structfield>data</structfield> field in <structname>struct
+ proc_dir_entry</structname>. First of all, the
+ <structfield>data</structfield> field has to be initialised:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+struct my_file_data *file_data;
+
+file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL);
+entry->data = file_data;
+ </programlisting>
+
+ <para>
+ The <structfield>data</structfield> field is a <type>void
+ *</type>, so it can be initialised with anything.
+ </para>
+
+ <para>
+ Now that the <structfield>data</structfield> field is set, the
+ <function>read_proc</function> and
+ <function>write_proc</function> can use it to distinguish
+ between files because they get it passed into their
+ <parameter>data</parameter> parameter:
+ </para>
+
+ <programlisting>
+int foo_read_func(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ if(data == file_data) {
+ /* special case for this file */
+ } else {
+ /* normal processing */
+ }
+
+ return len;
+}
+ </programlisting>
+
+ <para>
+ Be sure to free the <structfield>data</structfield> data field
+ when removing the procfs entry.
+ </para>
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="tips">
+ <title>Tips and tricks</title>
+
+
+
+
+ <sect1 id="convenience">
+ <title>Convenience functions</title>
+
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>struct proc_dir_entry* <function>create_proc_read_entry</function></funcdef>
+ <paramdef>const char* <parameter>name</parameter></paramdef>
+ <paramdef>mode_t <parameter>mode</parameter></paramdef>
+ <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
+ <paramdef>read_proc_t* <parameter>read_proc</parameter></paramdef>
+ <paramdef>void* <parameter>data</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+
+ <para>
+ This function creates a regular file in exactly the same way
+ as <function>create_proc_entry</function> from <xref
+ linkend="regularfile"> does, but also allows to set the read
+ function <parameter>read_proc</parameter> in one call. This
+ function can set the <parameter>data</parameter> as well, like
+ explained in <xref linkend="usingdata">.
+ </para>
+ </sect1>
+
+
+
+ <sect1>
+ <title>Modules</title>
+
+ <para>
+ If procfs is being used from within a module, be sure to set
+ the <structfield>owner</structfield> field in the
+ <structname>struct proc_dir_entry</structname> to
+ <constant>THIS_MODULE</constant>.
+ <para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->owner = THIS_MODULE;
+ </programlisting>
+ </sect1>
+
+
+
+
+ <sect1>
+ <title>Mode and ownership</title>
+
+ <para>
+ Sometimes it is useful to change the mode and/or ownership of
+ a procfs entry. Here is an example that shows how to achieve
+ that:
+ </para>
+
+ <programlisting>
+struct proc_dir_entry* entry;
+
+entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH;
+entry->uid = 0;
+entry->gid = 100;
+ </programlisting>
+
+ </sect1>
+ </chapter>
+
+
+
+
+ <chapter id="example">
+ <title>Example</title>
+
+ <!-- be careful with the example code: it shouldn't be wider than
+ approx. 60 columns, or otherwise it won't fit properly on a page
+ -->
+
+&procfsexample;
+
+ </chapter>
+</book>
Index: Documentation/DocBook/procfs_example.c
===================================================================
RCS file: procfs_example.c
diff -N procfs_example.c
--- /dev/null Thu Mar 22 14:04:47 2001
+++ Documentation/DocBook/procfs_example.c Sun Jun 3 23:09:39 2001
@@ -0,0 +1,249 @@
+/*
+ * procfs_example.c: an example proc interface
+ *
+ * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This file accompanies the procfs-guide in the Linux kernel
+ * source. Its main use is to demonstrate the concepts and
+ * functions described in the guide.
+ *
+ * This software has been developed while working on the LART
+ * computing board (http://www.lart.tudelft.nl/), which is
+ * sponsored by the Mobile Multi-media Communications
+ * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
+ * (http://www.ubicom.tudelft.nl/) projects.
+ *
+ * The author can be reached at:
+ *
+ * Erik Mouw
+ * Information and Communication Theory Group
+ * Faculty of Information Technology and Systems
+ * Delft University of Technology
+ * P.O. Box 5031
+ * 2600 GA Delft
+ * The Netherlands
+ *
+ *
+ * This program is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU General
+ * Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+
+
+#define MODULE_VERSION "1.0"
+#define MODULE_NAME "procfs_example"
+
+#define FOOBAR_LEN 8
+
+struct fb_data_t {
+ char name[FOOBAR_LEN + 1];
+ char value[FOOBAR_LEN + 1];
+};
+
+
+static struct proc_dir_entry *example_dir, *foo_file,
+ *bar_file, *jiffies_file, *tty_device, *symlink;
+
+
+struct fb_data_t foo_data, bar_data;
+
+
+static int proc_read_jiffies(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "jiffies = %ld\n",
+ jiffies);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_read_foobar(char *page, char **start,
+ off_t off, int count,
+ int *eof, void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ len = sprintf(page, "%s = '%s'\n",
+ fb_data->name, fb_data->value);
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int proc_write_foobar(struct file *file,
+ const char *buffer,
+ unsigned long count,
+ void *data)
+{
+ int len;
+ struct fb_data_t *fb_data = (struct fb_data_t *)data;
+
+ MOD_INC_USE_COUNT;
+
+ if(count > FOOBAR_LEN)
+ len = FOOBAR_LEN;
+ else
+ len = count;
+
+ if(copy_from_user(fb_data->value, buffer, len)) {
+ MOD_DEC_USE_COUNT;
+ return -EFAULT;
+ }
+
+ fb_data->value[len] = '\0';
+
+ MOD_DEC_USE_COUNT;
+
+ return len;
+}
+
+
+static int __init init_procfs_example(void)
+{
+ int rv = 0;
+
+ /* create directory */
+ example_dir = proc_mkdir(MODULE_NAME, NULL);
+ if(example_dir == NULL) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ example_dir->owner = THIS_MODULE;
+
+ /* create jiffies using convenience function */
+ jiffies_file = create_proc_read_entry("jiffies",
+ 0444, example_dir,
+ proc_read_jiffies,
+ NULL);
+ if(jiffies_file == NULL) {
+ rv = -ENOMEM;
+ goto no_jiffies;
+ }
+
+ jiffies_file->owner = THIS_MODULE;
+
+ /* create foo and bar files using same callback
+ * functions
+ */
+ foo_file = create_proc_entry("foo", 0644, example_dir);
+ if(foo_file == NULL) {
+ rv = -ENOMEM;
+ goto no_foo;
+ }
+
+ strcpy(foo_data.name, "foo");
+ strcpy(foo_data.value, "foo");
+ foo_file->data = &foo_data;
+ foo_file->read_proc = proc_read_foobar;
+ foo_file->write_proc = proc_write_foobar;
+ foo_file->owner = THIS_MODULE;
+
+ bar_file = create_proc_entry("bar", 0644, example_dir);
+ if(bar_file == NULL) {
+ rv = -ENOMEM;
+ goto no_bar;
+ }
+
+ strcpy(bar_data.name, "bar");
+ strcpy(bar_data.value, "bar");
+ bar_file->data = &bar_data;
+ bar_file->read_proc = proc_read_foobar;
+ bar_file->write_proc = proc_write_foobar;
+ bar_file->owner = THIS_MODULE;
+
+ /* create tty device */
+ tty_device = proc_mknod("tty", S_IFCHR | 0666,
+ example_dir, MKDEV(5, 0));
+ if(tty_device == NULL) {
+ rv = -ENOMEM;
+ goto no_tty;
+ }
+
+ tty_device->owner = THIS_MODULE;
+
+ /* create symlink */
+ symlink = proc_symlink("jiffies_too", example_dir,
+ "jiffies");
+ if(symlink == NULL) {
+ rv = -ENOMEM;
+ goto no_symlink;
+ }
+
+ symlink->owner = THIS_MODULE;
+
+ /* everything OK */
+ printk(KERN_INFO "%s %s initialised\n",
+ MODULE_NAME, MODULE_VERSION);
+ return 0;
+
+no_symlink:
+ remove_proc_entry("tty", example_dir);
+no_tty:
+ remove_proc_entry("bar", example_dir);
+no_bar:
+ remove_proc_entry("foo", example_dir);
+no_foo:
+ remove_proc_entry("jiffies", example_dir);
+no_jiffies:
+ remove_proc_entry(MODULE_NAME, NULL);
+out:
+ return rv;
+}
+
+
+static void __exit cleanup_procfs_example(void)
+{
+ remove_proc_entry("jiffies_too", example_dir);
+ remove_proc_entry("tty", example_dir);
+ remove_proc_entry("bar", example_dir);
+ remove_proc_entry("foo", example_dir);
+ remove_proc_entry("jiffies", example_dir);
+ remove_proc_entry(MODULE_NAME, NULL);
+
+ printk(KERN_INFO "%s %s removed\n",
+ MODULE_NAME, MODULE_VERSION);
+}
+
+
+module_init(init_procfs_example);
+module_exit(cleanup_procfs_example);
+
+MODULE_AUTHOR("Erik Mouw");
+MODULE_DESCRIPTION("procfs examples");
+
+EXPORT_NO_SYMBOLS;
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2001-06-03 22:20 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-05-29 23:29 [PATCH] Procfs Guide Erik Mouw
2001-05-30 8:30 ` Tim Waugh
2001-05-30 20:35 ` Erik Mouw
-- strict thread matches above, loose matches on Subject: below --
2001-05-30 21:10 hiren_mehta
2001-05-30 21:40 ` Erik Mouw
2001-05-31 12:40 ` Matti Aarnio
2001-06-03 22:18 [PATCH] procfs guide Erik Mouw
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox