mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-26 03:31:36 +01:00
seq_file: move doc to README
This commit is contained in:
77
README.adoc
77
README.adoc
@@ -2976,7 +2976,7 @@ This example shows how sysfs is more restricted, as it does not take an arbitrar
|
|||||||
|
|
||||||
So you basically can only do `open`, `close`, `read`, `write`, and `lseek` on sysfs files.
|
So you basically can only do `open`, `close`, `read`, `write`, and `lseek` on sysfs files.
|
||||||
|
|
||||||
It is similar to a `seq_file` file operation, except that write is also implemented.
|
It is similar to a <<seq_file>> file operation, except that write is also implemented.
|
||||||
|
|
||||||
TODO: what are those `kobject` structs? Make a more complex example that shows what they can do.
|
TODO: what are those `kobject` structs? Make a more complex example that shows what they can do.
|
||||||
|
|
||||||
@@ -3024,6 +3024,76 @@ File operations is the main method of userland driver communication.
|
|||||||
|
|
||||||
No, there no official documentation: http://stackoverflow.com/questions/15213932/what-are-the-struct-file-operations-arguments
|
No, there no official documentation: http://stackoverflow.com/questions/15213932/what-are-the-struct-file-operations-arguments
|
||||||
|
|
||||||
|
==== seq_file
|
||||||
|
|
||||||
|
In guest:
|
||||||
|
|
||||||
|
....
|
||||||
|
/seq_file.sh
|
||||||
|
echo $?
|
||||||
|
....
|
||||||
|
|
||||||
|
Outcome: the test passes:
|
||||||
|
|
||||||
|
....
|
||||||
|
0
|
||||||
|
....
|
||||||
|
|
||||||
|
Sources:
|
||||||
|
|
||||||
|
* link:kernel_module/seq_file.c[]
|
||||||
|
* link:rootfs_overlay/seq_file.sh[]
|
||||||
|
|
||||||
|
Writing trivial read <<file-operations>> is repetitive and error prone.
|
||||||
|
|
||||||
|
The `seq_file` API makes the process much easier for those trivial cases.
|
||||||
|
|
||||||
|
In this example we create a debugfs file that behaves just like a file that contains:
|
||||||
|
|
||||||
|
....
|
||||||
|
0
|
||||||
|
1
|
||||||
|
2
|
||||||
|
....
|
||||||
|
|
||||||
|
However, we only store a single integer in memory and calculate the file on the fly in an iterator fashion.
|
||||||
|
|
||||||
|
`seq_file` does not provide `write`: https://stackoverflow.com/questions/30710517/how-to-implement-a-writable-proc-file-by-using-seq-file-in-a-driver-module
|
||||||
|
|
||||||
|
Bibliography:
|
||||||
|
|
||||||
|
* link:https://github.com/torvalds/linux/blob/v4.17/Documentation/filesystems/seq_file.txt[Documentation/filesystems/seq_file.txt]
|
||||||
|
* https://stackoverflow.com/questions/25399112/how-to-use-a-seq-file-in-linux-modules
|
||||||
|
|
||||||
|
===== seq_file single_open
|
||||||
|
|
||||||
|
In guest:
|
||||||
|
|
||||||
|
....
|
||||||
|
/seq_file.sh
|
||||||
|
echo $?
|
||||||
|
....
|
||||||
|
|
||||||
|
Outcome: the test passes:
|
||||||
|
|
||||||
|
....
|
||||||
|
0
|
||||||
|
....
|
||||||
|
|
||||||
|
Sources:
|
||||||
|
|
||||||
|
* link:kernel_module/seq_file_single_open.c[]
|
||||||
|
* link:rootfs_overlay/seq_file_single_open.sh[]
|
||||||
|
|
||||||
|
If you have the entire read output upfront, `single_open` is an even more convenient version of <<seq_file>>.
|
||||||
|
|
||||||
|
This example produces a debugfs file that behaves like a file that contains:
|
||||||
|
|
||||||
|
....
|
||||||
|
ab
|
||||||
|
cd
|
||||||
|
....
|
||||||
|
|
||||||
==== Character devices
|
==== Character devices
|
||||||
|
|
||||||
In guest:
|
In guest:
|
||||||
@@ -3123,10 +3193,9 @@ Sources:
|
|||||||
* link:kernel_module/user/anonymous_inode.c[]
|
* link:kernel_module/user/anonymous_inode.c[]
|
||||||
* link:rootfs_overlay/anonymous_inode.sh[]
|
* link:rootfs_overlay/anonymous_inode.sh[]
|
||||||
|
|
||||||
This example:
|
This example gets an anonymous inode via `ioctl` from a debugfs entry by using `anon_inode_getfd`.
|
||||||
|
|
||||||
* gets an anonymous inode via `ioctl` from a debugfs entry `anon_inode_getfd` from a debugfs file
|
Reads to that inode return the sequence: `1`, `10`, `100`, ... `10000000`, `1`, `100`, ...
|
||||||
* read jiffies from that inode
|
|
||||||
|
|
||||||
Anonymous inodes allow getting multiple file descriptors from a single filesystem entry, which reduces namespace pollution compared to creating multiple device files.
|
Anonymous inodes allow getting multiple file descriptors from a single filesystem entry, which reduces namespace pollution compared to creating multiple device files.
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,6 @@
|
|||||||
.. link:ioctl.c[]
|
.. link:ioctl.c[]
|
||||||
.. link:mmap.c[]
|
.. link:mmap.c[]
|
||||||
.. link:poll.c[]
|
.. link:poll.c[]
|
||||||
.. link:seq_file.c[]
|
|
||||||
.. link:seq_file_inode.c[]
|
|
||||||
. Asynchronous
|
. Asynchronous
|
||||||
.. link:irq.c[]
|
.. link:irq.c[]
|
||||||
.. link:kthread.c[]
|
.. link:kthread.c[]
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off
|
|||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
}
|
}
|
||||||
myval <<= 4;
|
myval <<= 4;
|
||||||
|
if (myval == 0) {
|
||||||
|
myval = 1;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,4 @@
|
|||||||
/*
|
/* https://github.com/cirosantilli/linux-kernel-module-cheat#seq_file */
|
||||||
Adapted from: Documentation/filesystems/seq_file.txt
|
|
||||||
but we limit the count to the max module parameter.
|
|
||||||
|
|
||||||
Writting trivial read fops is repetitive and error prone.
|
|
||||||
|
|
||||||
The seq_file API makes the process much easier for those trivial cases.
|
|
||||||
|
|
||||||
This example is behaves just like a file that contains:
|
|
||||||
|
|
||||||
0
|
|
||||||
1
|
|
||||||
2
|
|
||||||
|
|
||||||
However, we only store a single integer in memory
|
|
||||||
and calculate the file on the fly in an iterator fashion.
|
|
||||||
|
|
||||||
There is not write version, as writes are more complex:
|
|
||||||
https://stackoverflow.com/questions/30710517/how-to-implement-a-writable-proc-file-by-using-seq-file-in-a-driver-module
|
|
||||||
|
|
||||||
Bibliography:
|
|
||||||
|
|
||||||
- Documentation/filesystems/seq_file.txt
|
|
||||||
- https://stackoverflow.com/questions/25399112/how-to-use-a-seq-file-in-linux-modules
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/errno.h> /* EFAULT */
|
#include <linux/errno.h> /* EFAULT */
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
/*
|
/* https://github.com/cirosantilli/linux-kernel-module-cheat#seq_file-single_open */
|
||||||
If you have the entire read output upfront, single_open
|
|
||||||
is an even more convenient version of seq_file.
|
|
||||||
|
|
||||||
This example behaves like a file that contains:
|
|
||||||
|
|
||||||
ab
|
|
||||||
cd
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/errno.h> /* EFAULT */
|
#include <linux/errno.h> /* EFAULT */
|
||||||
@@ -40,8 +32,7 @@ static const struct file_operations fops = {
|
|||||||
|
|
||||||
static int myinit(void)
|
static int myinit(void)
|
||||||
{
|
{
|
||||||
debugfs_file = debugfs_create_file(
|
debugfs_file = debugfs_create_file("lkmc_seq_file_single_open", S_IRUSR, NULL, NULL, &fops);
|
||||||
"lkmc_seq_file_single", S_IRUSR, NULL, NULL, &fops);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,29 +1,10 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
set -ex
|
f=/sys/kernel/debug/lkmc_seq_file
|
||||||
|
|
||||||
insmod /seq_file.ko
|
insmod /seq_file.ko
|
||||||
cd /sys/kernel/debug
|
[ "$(cat "$f")" = "$(printf '0\n1\n2\n')" ]
|
||||||
|
[ "$(cat "$f")" = "$(printf '0\n1\n2\n')" ]
|
||||||
cat 'lkmc_seq_file'
|
[ "$(dd if="$f" bs=1 count=2 skip=0 status=none)" = "$(printf '0\n')" ]
|
||||||
# => 0
|
[ "$(dd if="$f" bs=1 count=2 skip=2 status=none)" = "$(printf '1\n')" ]
|
||||||
# => 1
|
[ "$(dd if="$f" bs=4 count=1 skip=0 status=none)" = "$(printf '0\n1\n')" ]
|
||||||
# => 2
|
|
||||||
|
|
||||||
cat 'lkmc_seq_file'
|
|
||||||
# => 0
|
|
||||||
# => 1
|
|
||||||
# => 2
|
|
||||||
|
|
||||||
dd if='lkmc_seq_file' bs=1 count=2 skip=0 status=none
|
|
||||||
# => 0
|
|
||||||
dd if='lkmc_seq_file' bs=1 count=4 skip=0 status=none
|
|
||||||
# => 0
|
|
||||||
# => 1
|
|
||||||
dd if='lkmc_seq_file' bs=1 count=2 skip=2 status=none
|
|
||||||
# => 1
|
|
||||||
dd if='lkmc_seq_file' bs=4 count=1 skip=0 status=none
|
|
||||||
# => 0
|
|
||||||
# => 1
|
|
||||||
|
|
||||||
rmmod seq_file
|
rmmod seq_file
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -ex
|
|
||||||
insmod /seq_file_single.ko
|
|
||||||
cd /sys/kernel/debug
|
|
||||||
cat 'lkmc_seq_file_single'
|
|
||||||
# => ab
|
|
||||||
# => cd
|
|
||||||
dd if='lkmc_seq_file_single' bs=1 count=3 skip=1
|
|
||||||
# => b
|
|
||||||
# => c
|
|
||||||
|
|
||||||
rmmod seq_file_single
|
|
||||||
7
rootfs_overlay/seq_file_single_open.sh
Executable file
7
rootfs_overlay/seq_file_single_open.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
f=/sys/kernel/debug/lkmc_seq_file_single_open
|
||||||
|
insmod /seq_file_single_open.ko
|
||||||
|
[ "$(cat "$f")" = "$(printf 'ab\ncd\n')" ]
|
||||||
|
[ "$(dd if="$f" bs=1 count=3 skip=1)" = "$(printf "b\nc\n")" ]
|
||||||
|
rmmod seq_file_single_open
|
||||||
@@ -6,8 +6,10 @@ for test in \
|
|||||||
/debugfs.sh \
|
/debugfs.sh \
|
||||||
/fops.sh \
|
/fops.sh \
|
||||||
/procfs.sh \
|
/procfs.sh \
|
||||||
/sysfs.sh
|
/seq_file.sh \
|
||||||
do
|
/seq_file_single_open.sh \
|
||||||
|
/sysfs.sh \
|
||||||
|
; do
|
||||||
if ! "$test"; then
|
if ! "$test"; then
|
||||||
echo "lkmc_test_fail: ${test}"
|
echo "lkmc_test_fail: ${test}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
Reference in New Issue
Block a user