📄 procfs-guide.tmpl
字号:
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>buffer</parameter></paramdef> <paramdef>char** <parameter>start</parameter></paramdef> <paramdef>off_t <parameter>off</parameter></paramdef> <paramdef>int <parameter>count</parameter></paramdef> <paramdef>int* <parameter>peof</parameter></paramdef> <paramdef>void* <parameter>data</parameter></paramdef> </funcprototype> </funcsynopsis> <para> The read function should write its information into the <parameter>buffer</parameter>, which will be exactly <literal>PAGE_SIZE</literal> bytes long. </para> <para> The parameter <parameter>peof</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>peof</parameter> points to. </para> <para> 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 rest of the parameters and the return value are described by a comment in <filename>fs/proc/generic.c</filename> as follows: </para> <blockquote> <para> You have three ways to return data: </para> <orderedlist> <listitem> <para> Leave <literal>*start = NULL</literal>. (This is the default.) Put the data of the requested offset at that offset within the buffer. Return the number (<literal>n</literal>) of bytes there are from the beginning of the buffer up to the last byte of data. If the number of supplied bytes (<literal>= n - offset</literal>) is greater than zero and you didn't signal eof and the reader is prepared to take more data you will be called again with the requested offset advanced by the number of bytes absorbed. This interface is useful for files no larger than the buffer. </para> </listitem> <listitem> <para> Set <literal>*start</literal> to an unsigned long value less than the buffer address but greater than zero. Put the data of the requested offset at the beginning of the buffer. Return the number of bytes of data placed there. If this number is greater than zero and you didn't signal eof and the reader is prepared to take more data you will be called again with the requested offset advanced by <literal>*start</literal>. This interface is useful when you have a large file consisting of a series of blocks which you want to count and return as wholes. (Hack by Paul.Russell@rustcorp.com.au) </para> </listitem> <listitem> <para> Set <literal>*start</literal> to an address within the buffer. Put the data of the requested offset at <literal>*start</literal>. Return the number of bytes of data placed there. If this number is greater than zero and you didn't signal eof and the reader is prepared to take more data you will be called again with the requested offset advanced by the number of bytes absorbed. </para> </listitem> </orderedlist> </blockquote> <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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -