I'm trying to write a kernel module, which prints some information about the objects in the VFS subsystem. That way I want to learn how the VFS works and what structures it uses.
However, I can't manage to iterate the super_blocks list, because of this compiler warning:
WARNING: "super_blocks" [/path/to/module/vfsinfo.ko] undefined!
If I still try to insert the module, insmod fails and returns a similar message.
Here is the relevant part of my code:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/fs.h>
#define PRINT(...) printk(KERN_ALERT __VA_ARGS__)
/*
* Print all super blocks
*/
static void vfsinfo_print_super_blocks(void) {
struct super_block *s;
list_for_each_entry(s, &super_blocks, s_list) {
PRINT("%s\n", s->s_type->name);
}
}
What am I doing wrong?
It seems super_blocks is not exported with EXPORT_SYMBOL() to modules. See
http://www.kernel.org/doc/htmldocs/kernel-hacking.html#symbols
for more information.
Even after some research I couldn't find any helpful list_head or function that is exported for kernel modules. Since this project should just help me to learn the VFS data structures, I decided to create a pointer to a struct list_head and assign it the address to the "real" list_head super_blocks.
For this purpose I first looked up the address in the System.map file.
$ grep super_blocks /boot/System.map-2.6.36
ffffffff81a22650 D super_blocks
Then I set up my list_head and started working with it:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/fs.h>
#define PRINT(...) printk(KERN_ALERT __VA_ARGS__)
/*
* Print all super blocks
*/
static void vfsinfo_print_super_blocks(void) {
struct list_head *super_blocks = 0xffffffff81a22650;
struct super_block *s;
list_for_each_entry(s, super_blocks, s_list) {
PRINT("%s\n", s->s_type->name);
}
}
Now I am able to access all my super blocks :)
[ 1218.356475] sysfs
[ 1218.357066] rootfs
[ 1218.358450] bdev
[ 1218.359600] proc
[ 1218.360368] tmpfs
[ 1218.361612] sockfs
[ 1218.362388] debugfs
[ 1218.363090] pipefs
[ 1218.363752] anon_inodefs
[ 1218.364076] devpts
[ 1218.365077] hugetlbfs
[ 1218.365654] mqueue
[ 1218.366459] selinuxfs
[ 1218.367060] usbfs
[ 1218.367489] ext2
[ 1218.368065] sysfs
[ 1218.369076] tmpfs
Bye
Related
I am debugging a ARMv7 board and I want to know whether a kernel symbol is accessed. So I have to use hw_breakpoint in kernel.
For simplicity, I use kernel sample code:data_breakpoint to test, which locates in samples/hw_breakpoint/data_breakpoint.c.
Then I did the following operation:
insmod data_breakpoint.ko ksym=max
cat /proc/kallsyms | grep max
./read_kmem c06fa128
But this did not trigger the callback function.
If I print the value in that address in any kernel module, callback function will be triggered.
I read the cpu manual and it says that the breakpoint register in my cpu support virtual address matching. But I don't know why it doesn't work while accessing memory from userspace. I think that program does read the right value of kernel symbol.
read_kmem.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#define DEVKMEM "/dev/kmem"
#define PAGE_SIZE 0x1000
#define PAGE_MASK (~(PAGE_SIZE-1))
int main(int argc, char* argv[])
{
int fd;
char *mbase;
char read_buf[10];
unsigned int varAddr;
varAddr = strtoul(argv[1], 0, 16);
unsigned int ptr = varAddr & ~(PAGE_MASK);
fd = open(DEVKMEM, O_RDONLY);
if (fd == -1) {
perror("open");
exit(-1);
}
mbase = mmap(0,PAGE_SIZE,PROT_READ,MAP_SHARED,fd, (varAddr & PAGE_MASK));
if (mbase == MAP_FAILED) {
printf("map failed %s\n",strerror(errno));
}
printf("varAddr = 0x%X \n", varAddr);
printf("mapbase = 0x%X \n", (unsigned int)mbase);
printf("value = 0x%X \n",*(unsigned int*)(mbase+ptr));
close(fd);
munmap(mbase,PAGE_SIZE);
return 0;
}
Your userspace does not access address c06fa128, it accesses a different address - one that that mmap() returned (plus offset). Thus no breakpoint hit.
The fact that virtual address being accessed resolves to same physical address as some other virtual address that has a breapoint, does not matter. CPU executing your userspace code has no idea that different mapping exists.
I am trying to access super block object which is defined in linux/fs.h.
But how to initialize the object so that we can access it's properties.
I found that alloc_super() is used to initialize super but how is it called?
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <linux/fs.h>
int main(){
printf("hello there");
struct super_block *sb;
return 0;
}
The answer is very much file system dependent, since different file systems will have different super block layouts and infact different arrangements of blocks.
For instance, ext2 file systems superblock is in a known location on disk (byte 1024), and has a known size (sizeof(struct superblock) bytes).
So a typical implementation (This is not a working code but with minor modification can be made to work ) of what you want would be:
struct superblock *read_superblock(int fd) {
struct superblock *sb = malloc(sizeof(struct superblock));
assert(sb != NULL);
lseek(fd, (off_t) 1024, SEEK_SET));
read(fd, (void *) sb, sizeof(struct superblock));
return sb;
}
Now, you can alloc superblock using linux/headers, or write your own struct that exactly matches with the ext2/ext3/etc/etc file systems superblock.
Then you must know where to find the superblock (the lseek() comes here).
Also you need to pass the disk file name file_descriptor to the function.
So do a
int fd = open(argv[1], O_RDONLY);
struct superblock * sb = read_superblock(fd);
Constructing multiple objects in shared memory is possible as shown in this example:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <functional>
#include <iostream>
using namespace boost::interprocess;
void construct_objects(managed_shared_memory &managed_shm)
{
managed_shm.construct<int>("Integer")(99);
managed_shm.construct<float>("Float")(3.14);
}
int main()
{
shared_memory_object::remove("Boost");
managed_shared_memory managed_shm{open_or_create, "Boost", 1024};
auto atomic_construct = std::bind(construct_objects,
std::ref(managed_shm));
managed_shm.atomic_func(atomic_construct);
std::cout << *managed_shm.find<int>("Integer").first << '\n';
std::cout << *managed_shm.find<float>("Float").first << '\n';
}
But when I try to create two vectors or a vector and a list, I run into problems with the memory allocation. Is there a way to create multiple containers in a single shared memory in Boost?
I had a look at managed_memory_impl.hpp, but it wasn't of much help either.
This is my code (you have to link it with lib pthread and librt):
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <cstdlib> //std::system
#include <cstddef>
#include <cassert>
#include <utility>
#include <iostream>
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator; //Define an STL compatible allocator of ints that allocates from the managed_shared_memory. This allocator will allow placing containers in the segment
typedef boost::interprocess::vector<int, ShmemAllocator> MyVector; //Alias a vector that uses the previous STL-like allocator so that allocates its values from the segment
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager> ShmemListAllocator;
typedef boost::interprocess::list<int, ShmemListAllocator> MyList;
int main(int argc, char *argv[])
{
//Construct managed shared memory
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "MySharedMemory", 65536);
//const ShmemAllocator alloc_inst(segment.get_segment_manager());
MyVector *instance = segment.construct<MyVector>("MyType instance")(segment.get_segment_manager());
MyVector *instance2 = segment.construct<MyVector>("MyType instance")(segment.get_segment_manager());
MyList *instance3 = segment.construct<MyList>("MyList instance")(segment.get_segment_manager());
return 0;
}//main
You should either use unique names, or you can use the indexed ("array") style of construction.
See the documentation for the Object construction function family:
//!Allocates and constructs an array of objects of type MyType (throwing version)
//!Each object receives the same parameters (par1, par2, ...)
MyType *ptr = managed_memory_segment.construct<MyType>("Name")[count](par1, par2...);
and
//!Tries to find a previously created object. If not present, allocates and
//!constructs an array of objects of type MyType (throwing version). Each object
//!receives the same parameters (par1, par2, ...)
MyType *ptr = managed_memory_segment.find_or_construct<MyType>("Name")[count](par1, par2...);
and
//!Allocates and constructs an array of objects of type MyType (throwing version)
//!Each object receives parameters returned with the expression (*it1++, *it2++,... )
MyType *ptr = managed_memory_segment.construct_it<MyType>("Name")[count](it1, it2...);
and possibly some more. Look for [count].
(I recommend using unique names for simplicity)
Update
To the comments, here's what I meant with "unique name". I've tested it, and itworks fine:
Live1 On Coliru
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <cassert>
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager>
ShmemAllocator; // Define an STL compatible allocator of ints that allocates from the managed_shared_memory. This allocator
// will allow placing containers in the segment
typedef boost::interprocess::vector<int, ShmemAllocator> MyVector; // Alias a vector that uses the previous STL-like allocator so
// that allocates its values from the segment
typedef boost::interprocess::allocator<int, boost::interprocess::managed_shared_memory::segment_manager> ShmemListAllocator;
typedef boost::interprocess::list<int, ShmemListAllocator> MyList;
int main()
{
// Construct managed shared memory
std::remove("/dev/shm/MySharedMemory");
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "MySharedMemory", 65536);
// const ShmemAllocator alloc_inst(segment.get_segment_manager());
MyVector *instance = segment.construct<MyVector>("MyType instance 1")(segment.get_segment_manager());
MyVector *instance2 = segment.construct<MyVector>("MyType instance 2")(segment.get_segment_manager());
MyList *instance3 = segment.construct<MyList> ("MyList instance")(segment.get_segment_manager());
assert(instance);
assert(instance2);
assert(instance3);
assert(!std::equal_to<void*>()(instance, instance2));
assert(!std::equal_to<void*>()(instance, instance3));
assert(!std::equal_to<void*>()(instance2, instance3));
}
1 Of course, SHM is not supported on Coliru. However, identical sample using mapped file: Live On Coliru
I'm developping sample kernel module driver.ko. I want to specify the block size of data_node structure with module parameter BlockSize. when I run insmod driver.ko alone, it works, but when I specify BlockSize insmod driver.ko BlockSize = 10 I get this eror :
Error: could not insert module driver.ko: Invalid parameters
modinfo -p ./driver.ko command give me this :
BlockSize: size of buffer (int)
driver.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/slab.h>
/* parametter */
static int BlockNumber = 8;
static int BlockSize = 512;
module_param( variable name, type, permission); */
module_param(BlockSize, int, S_IRUGO);
MODULE_PARM_DESC(BlockSize , " size of buffer");
/* using 'k' as magic number */
#define SAMPLE_IOC_MAGIC 'k'
#define SAMPLE_IOCRESET _IOWR(SAMPLE_IOC_MAGIC, 0, int)
#define SAMPLE_IOC_MAXNR 0
struct cdev* my_cdev;
dev_t dev;
static int size_to_read;
/* Macro used to compute the minimum */
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
/* data buffer structure */
typedef struct dnode
{
int bufSize;
char *buffer;
struct dnode *next;
} data_node;
/* liste stucture */
typedef struct lnode
{
data_node *head;
data_node *cur_write_node;
data_node *cur_read_node;
int cur_read_offset;
int cur_write_offset;
}liste;
code ..........................
..
It appears that module parameters should be passed without a space between the name and value, ie you should use:
insmod driver.ko BlockSize=10
This makes some sense, as in the command line to insmod itself "BlockSize=10" is a single entry in *argv[] which can be handed off to the kernel as a chunk, while "BlockSize = 10" would be three distinct entries ("BlockSize", "=", "10") which someone would have to write code to re-join.
I am trying to modify the source IP of all packets outcoming from the machine to something I specify in this Kernel Module, but everytime I try to access nh.iph->saddr I get an error in compile time that says Struct sk_buff has no member named nh
What am I doing wrong here?
Have I missed some header or something??
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/skbuff.h>
#include <linux/ip.h> /* For IP header */
#include <linux/inet.h> /* For in_aton(); htonl(); and other related Network utility functions */
static struct nf_hook_ops nfho;
unsigned int hook_func(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *sb = *skb;
struct in_addr masterIP;
masterIP.s_addr = htonl (in_aton("192.168.1.10"));
sb->nh.iph->saddr = masterIP.s_addr;
return NF_ACCEPT;
}
Note that I am running Ubuntu 10.04 LTS 64 bits
Kernel 2.6.32-33
In your kernel version the struct sk_buff has changed. It no longer has those members. To access the ip header you should try:
#include <linux/ip.h>
struct iphdr* iph = ip_hdr(skb);
Then just use the iph variable to change the addresses, something like:
iph->saddr = ....
iph->daddr = ....
Also, don't forget that you might need to recalculate ip and possible transport packets checksums.
You can find the definition of struck sk_buff in 'include/linux/skbuff.h'.
It does not have an nh field, which explains the compilation errors you're seeing. It does have a 'network_header' field, which is probably what you're looking for.