What Is The Significance of This_Module in Linux Kernel Module Drivers

What is the significance of THIS_MODULE in Linux kernel module drivers?

file_operation is one of the main structures that used to connect the device numbers and the file operations of a driver.

  • There are lots of function pointer in the structure. The first pointer is struct module *owner which is not a function pointer at all but points to a structure module defined in the <linux/module.h>.
  • On initializing to THIS_MODULE, it holds the ownership of the module.
  • One of the main reasons to initialize struct module *owner to THIS_MODULE to prevent the module from getting unloaded while in use.

Linux Kernel Modules: When to use try_module_get / module_put

You should essentially never have to use try_module_get(THIS_MODULE); pretty much all such uses are unsafe since if you are already in your module, it's too late to bump the reference count -- there will always be a (small) window where you are executing code in your module but haven't incremented the reference count. If someone removes the module exactly in that window, then you're in the bad situation of running code in an unloaded module.

The particular example you linked in LKMPG where the code does try_module_get() in the open() method would be handled in the modern kernel by setting the .owner field in struct file_operations:

struct file_operations fops = {
.owner = THIS_MODULE,
.open = device_open,
//...
};

this will make the VFS code take a reference to the module before calling into it, which eliminates the unsafe window -- either the try_module_get() will succeed before the call to .open(), or the try_module_get() will fail and the VFS will never call into the module. In either case, we never run code from a module that has already been unloaded.

The only good time to use try_module_get() is when you want to take a reference on a different module before calling into it or using it in some way (eg as the file open code does in the example I explained above). There are a number of uses of try_module_get(THIS_MODULE) in the kernel source but most if not all of them are latent bugs that should be cleaned up.

The reason you were not able to unload the sched example is that your

$ tail /proc/sched -f &

command keeps /proc/sched open, and because of

        Our_Proc_File->owner = THIS_MODULE;

in the sched.c code, opening /proc/sched increments the reference count of the sched module, which accounts for the 1 reference that your lsmod shows. From a quick skim of the rest of the code, I think if you release /proc/sched by killing your tail command, you would be able to remove the sched module.

Why is this kernel module marked at permanent on 2.6.39

So, after consultation with Canonical, I know what the problem is:

Ubuntu mainline builds are built with the Hardy tool chain, and the 11.04 and 11.10 tool chains are incompatible for building out-of-tree kernel modules.

Where is the memory allocation of __this_module variable?

According to an obscure and dark spot in the LKML...

Does this mean that the module structure (struct module) and it's various
ubstructures are filled in by insmod?

Regards,
Naren

On Sun, 5 Nov 2000, Tigran Aivazian wrote:

On Sun, 5 Nov 2000, Naren Devaiah wrote:
>
>


I've looked in the 2.4.0-pre10 source tree and found it defined as
extern struct module __this_module;
in module.h (among other files), but where is it actually defined?


it isn't -- it's magic, of course :). The way it works is for insmod to
arrange things in such a manner that &__this_module resolves to point to
the beginning of module's address space, which happens to contain 'struct
module' at the beginning.


Regards,
Tigran

Follow-up...

On Sun, 5 Nov 2000, Naren Devaiah wrote:

Does this mean that the module structure (struct module) and it's various
substructures are filled in by insmod?


Regards,
Naren


Yes, partially, i.e. have a look at sys_create_module() and
sys_init_module() system calls, they are in kernel/module.c

sys_create_module() just allocates the space and links the module into the list but sys_init_module() is passed a 'struct module' from userspace
whose content is harshly validated (trust no one!) and then installed into
a real kernel 'struct module' and module's init_module() routine is
invoked.

Regards,
Tigran

How to find the version of a compiled kernel module?

$ apropos modinfo
modinfo (8) - display information about a kernel module
$ modinfo cpuid.ko
filename: cpuid.ko
author: H. Peter Anvin <hpa@zytor.com>
description: x86 generic CPUID driver
license: GPL
vermagic: 2.6.37 SMP preempt mod_unload PENTIUM4 gcc-4.4.5
depends:

Linux Device Driver -- file operations not working

You should add terminating "\n" at the end of your prints to force their flush into the kernel log buffer. Here is your module with some enhancement suggestions:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>

MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME "device"

static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_read(struct file *, char *, size_t, loff_t *);
static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
static long int device_ioctl(struct file *, unsigned int, unsigned long);

static const struct file_operations fops =
{
.owner= THIS_MODULE,
.read= device_read,
.write=device_write,
.unlocked_ioctl= device_ioctl,
.open= device_open,
.release= device_release

};

struct cdev *device_cdev;
dev_t deviceNumbers;

static int __init init(void) // <------ Add __init keyword for kernel cleanups
{
// This returns the major number chosen dynamically in deviceNumbers
int ret = alloc_chrdev_region(&deviceNumbers, 0, 1, DEVICE_NAME);

if (ret < 0) {
printk(KERN_ALERT "Error registering: %d\n", ret);
return -1;
}

device_cdev = cdev_alloc();

cdev_init(device_cdev, &fops);

ret = cdev_add(device_cdev, deviceNumbers, 1);

printk(KERN_INFO "Device initialized (major number is %d)\n", MAJOR(deviceNumbers));

return 0;
}

static void __exit cleanup(void) // <------ Add __exit keyword for kernel cleanups
{
unregister_chrdev_region(deviceNumbers, 1);

cdev_del(device_cdev);

printk(KERN_INFO "Device unloaded\n");
}

static int device_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device open\n");
return 0;
}

static int device_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device released\n");
return 0;
}

static ssize_t device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device write\n");
return len; // <-------------- To stop the write
}

static ssize_t device_read(struct file *filp, char *buff, size_t len, loff_t * off)
{
printk(KERN_INFO "Device read\n");
return len; // <-------------- To stop the read
}

static long int device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param)
{
printk(KERN_INFO "Device IOCTL\n");
return 0;
}

module_init(init);
module_exit(cleanup);

Check the current settings for the kernel log level.

$ cat /proc/sys/kernel/printk
4 4 1 7

In the preceding, the first column specifies that only messages with a log level lower than 4 will be printed.

The values accepted by printk() are:

   KERN_EMERG             0        System is unusable
KERN_ALERT 1 Action must be taken immediately
KERN_CRIT 2 Critical conditions
KERN_ERR 3 Error conditions
KERN_WARNING 4 Warning conditions
KERN_NOTICE 5 Normal but significant condition
KERN_INFO 6 Informational
KERN_DEBUG 7 Debug-level messages

So, the KERN_INFO level is 6 which is greater than 4!

We modify the configuration:

$ sudo sh -c "echo 7 4 1 7 > /proc/sys/kernel/printk"
$ cat /proc/sys/kernel/printk
7 4 1 7

I built your module with the suggested modifications and tried it on Linux 5.4.0-58:


$ uname -a
Linux xxxx 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
$ sudo insmod ./device.ko
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
$ lsmod
Module Size Used by
device 16384 0
[...]
$ cat /proc/devices
Character devices:
[...]
235 device
$ sudo mknod /dev/device c 235 0
$ ls -l /dev/device
crw-r--r-- 1 root root 235, 0 janv. 3 10:33 /dev/device
$ sudo sh -c "echo foo > /dev/device"
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
[ 7311.507652] Device open
[ 7311.507672] Device write
[ 7311.507677] Device released
$ sudo rmmod device
$ dmesg
[...]
[ 7244.516706] Device initialized (major number is 235)
[ 7311.507652] Device open
[ 7311.507672] Device write
[ 7311.507677] Device released
[ 7361.523964] Device unloaded
$ sudo rm /dev/device

purpose of __devexit_p in driver files

Based on this LXR listing from 2.6.32:

/*
Functions marked as __devexit may be discarded at kernel link time,
depending on config options. Newer versions of binutils detect references
from retained sections to discarded sections and flag an error. Pointers to
__devexit functions must use __devexit_p(function_name), the wrapper will
insert either the function_name or NULL, depending on the config options.
*/

#if defined(MODULE) || defined(CONFIG_HOTPLUG)
#define __devexit_p(x) x
#else
#define __devexit_p(x) NULL
#endif

it seems to be used to conditionally expand it to the given parameter or NULL based on the code being compiled as part of a kernel module (MODULE) and on the CONFIG_HOTPLUG kernel option.

Driver code in kernel module doesn't execute?

If i use module_init and module_exit all works

That short "original" code only consists of the module framework. The init routine is guaranteed to be called when the module is loaded, and the exit routine is called prior to unloading. That "original" code is not a driver.

The longer kernel module is a driver and getting loaded, but since it has the default init and exit code that does nothing (as generated by the expansion of the module_platform_driver() macro), there are no messages. The driver code in the loadable module is not guaranteed to be called when the kernel uses a Device Tree.

Why this kernel module doesn't do anything when i load it?

The probe function of the driver (which would output messages) is probably not getting called because there is nothing in your Device Tree that indicates that this device driver is needed.

The snippet of the board's Device Tree has

    compatible = "dglnt,hello-1.00.a";

but the driver declares that it should specified as

#define DEVICE_NAME "hello-1.00.a"
...
{.compatible = DEVICE_NAME},

These strings should match so that the driver can bind with this referenced device in the Device Tree node.

Also the device node should be declared as

    status = "okay";

to override any default status that could disable the device.

A properly configured node in the Device Tree should get the driver's probe function to be executed as expected.

Get Linux Kernel module name from current module

Inside the code of the kernel module, THIS_MODULE points to the structure representing this module. You may use name field of this structure for extract the current module name:

printk("Current module name: %s\n", THIS_MODULE->name);

If your code could be compiled (depending on configuration) either as a module or as a part of the kernel, then in the latter case THIS_MODULE will be NULL, so you cannot access its fields. For such code you could use module_name macro instead:

printk("Current module name: %s\n", module_name(THIS_MODULE));

Within the kernel core code (not a module) the macro is expanded to the string "kernel".



Related Topics



Leave a reply



Submit