How to change value of module_param parameter in the device driver? - linux-device-driver

I wrote a simple program for taking a value through command line into my driver. I used module_param() for this and gave permission argument, i.e third arg of module_param(), as S_IWUSR.
This I guess would allow user to modify the value of that parameter once driver is loaded in the kernel. I tried to modify the value of that parameter by:
echo 1 > /sys/module/ghost/parameters/num
But this shows me Permission denied error every time I try to do this, even when I execute the command with sudo. I also tried changing permission in module_param() to 0770 but still was not able to change the parameter value. Is there a way to change the value of parameter passed while inserting the driver ? Why does the above command shows permission denied, even if I run as sudo ?
After the answer of #Ian Abott I am to change the value of the parameter. Now I tried to define a callback function to notify me any changes in the value of that parameter while my driver is loaded. Here is the code
#include"headers.h"
#include"declarations.h"
static int my_set(const char *val, const struct kernel_param *kp)
{
int n = 0, ret;
ret = kstrtoint(val,10,&n); // Kernel function to convert string to integer
if (ret !=0 || n > 10) {
return -EINVAL;
}
printk(KERN_ALERT "my-set function running\n");
return param_set_int(val,kp);
}
static const struct kernel_param_ops param_ops = {
.set = my_set,
.get = param_get_int,
};
module_param(num,int,0600);
static char *name = "hello";
module_param(name,charp,0770);
static int __init init_func(void)
{
int i;
module_param_cb(callBack, &param_ops, &num, 0770);
printk(KERN_INFO "Value of num is %d\n",num);
for( i=0; i<num; i++)
{
printk(KERN_INFO "%s\n", name);
}
return 0;
}
static void __exit exit_func(void)
{
printk(KERN_INFO "Value of num is %d\n",num);
printk(KERN_ALERT "Module removed successfully\n");
}
module_init(init_func);
module_exit(exit_func);
But it doesn't seem to work because my_set function never runs, even if I change the value. My doubt is
1) Is this correct way to implement callback function for the parameter?
2) What is significance of first argument to the function module_param_cb?

Related

Issue logging within an embedded C function

I'd like to generate logging messages from within a C function embedded in a DML method. Take the example code below where the fib() function is called from the write() method of the regs bank. The log methods available to C all require a pointer to the current device.
Is there a way to get the device that calls the embedded function? Do I need to pass the device pointer into fib()?
dml 1.2;
device simple_embedded;
parameter documentation = "Embedding C code example for"
+ " Model Builder User's Guide";
parameter desc = "example of C code";
extern int fib(int x);
bank regs {
register r0 size 4 #0x0000 {
parameter allocate = false;
parameter configuration = "none";
method write(val) {
log "info": "Fibonacci(%d) = %d.", val, fib(val);
}
method read() -> (value) {
// Must be implemented to compile
}
}
}
header %{
int fib(int x);
%}
footer %{
int fib(int x) {
SIM_LOG_INFO(1, mydev, 0, "Generating Fibonacci for %d", x);
if (x < 2) return 1;
else return fib(x-1) + fib(x-2);
}
%}
I want to log from an embedded C function.
I solved this by passing the Simics conf_object_t pointer along to C. Just like implied in the question.
So you would use:
int fib(conf_object_t *mydev, int x) {
SIM_LOG_INFO(1, mydev, 0, "Generating Fibonacci for %d", x);
}
And
method write(val) {
log "info": "Fibonacci(%d) = %d.", val, fib(dev.obj,val);
}
Jakob's answer is the right one if your purpose is to offload some computations to C code (which makes sense in many situations, like when functionality is implemented by a lib).
However, if you just want a way to pass a callback to an API that asks for a function pointer, then it is easier to keep the implementation within DML and use a method reference, like:
method init() {
SIM_add_notifier(obj, trigger_fib_notifier_type, obj, &trigger_fib,
&dev.regs.r0.val);
}
method trigger_fib(conf_object_t *_, lang_void *aux) {
value = *cast(aux, uint64 *);
local int result = fib(value);
log info: "result: %d", result;
}
method fib(int x) -> (int) {
log info: "Generating Fibonacci for %d", x;
if (x < 2) return 1;
else return fib(x-1) + fib(x-2);
}

ebpf unknown opcode comparing strings

I currently try to filter calls to a function by command. I try to do so with the following code where ##REPLACE_comm## is replaced by python by the command name. The double backslash are cause I am using bcc. The following code throws an error when loading:
if(1){
char filter[TASK_COMM_LEN] = "##REPLACE_comm##";
char command[TASK_COMM_LEN];
bpf_get_current_comm(&command, sizeof(command));
for(u16 i = 0; i<=TASK_COMM_LEN; i++){
if(command[i] == '\\0' && filter[i] == '\\0'){
break;
}
if(command[i] == filter[i]){
continue;
}
return 0;
}
}
The error is:
unknown opcode 70
HINT: The 'unknown opcode' can happen if you reference a global or static variable, or data in read-only section. For example, 'char *p = "hello"' will result in p referencing a read-only section, and 'char p[] = "hello"' will have "hello" stored on the stack.
I feel like I already made sure the variables are on the stack by allocating space and not just having a pointer but it doesnt work. What am I missing?

Linux Kernel Module dev_get_drvdata Function Always Returns NULL

I have the following kernel module probe function (simplified to show the relevant parts):
static int qnap_ec_probe(struct platform_device* platform_dev)
{
// Allocate memory for the custom data and associate with the device
struct qnap_ec_platform_drv_data* platform_drv_data;
platform_drv_data = devm_kzalloc(&platform_dev->dev, sizeof(struct qnap_ec_platform_drv_data),
GFP_KERNEL);
// Add the custom data to the platform device
platform_set_drvdata(platform_dev, platform_drv_data);
// Register the platform device
devm_hwmon_device_register_with_info(&platform_dev->dev, "qnap_ec", NULL,
&qnap_ec_hwmon_chip_info, NULL);
return 0;
}
and the following hwmon read callback function:
static int qnap_ec_hwmon_read(struct device* dev, enum hwmon_sensor_types type, u32 attribute,
int channel, long* value)
{
struct qnap_ec_platform_drv_data* platform_drv_data;
platform_drv_data = dev_get_drvdata(dev);
if (platform_drv_data == NULL)
{
return -1;
}
return 0;
}
Unfortunately the second function always returns -1 because the dev_get_drvdata function always returns NULL. For some reason the data that's associated with the device in the probe function using platform_set_drvdata doesn't make it into the hwmon read callback function. Am I missing a step in associating this data with the device? What could be causing this issue?

PostgreSQL clarification

I have written a function inside PostgreSQL which has the following code:
for (i = 0; i < 4; i++)
{
Datum dat_value = CStringGetDatum(inp->str[0][i]);
values[i] = datumCopy(dat_value,
stats->attrtype->typbyval,
stats->attrtype->typlen);
}
The input strings are {ALGERIA,ARGENTINA,BRAZIL,CANADA}. The code runs for ALGERIA,ARGENTINA but terminates abruptly for BRAZIL. When I investigated I found that inside datumCopy function, the statement after memcpy is not getting printed. I checked if palloc failed with (s == NULL) condition, but that seems to be not the reason. I think memcpy is failing. Any reason why? Thanks!
Datum
datumCopy(Datum value, bool typByVal, int typLen)
{
Datum res;
if (typByVal)
res = value;
else
{
Size realSize;
char *s;
if (DatumGetPointer(value) == NULL)
return PointerGetDatum(NULL);
realSize = datumGetSize(value, typByVal, typLen);
s = (char *) palloc(realSize);
printf ("Value : %s\n",DatumGetPointer(value));
memcpy(s, DatumGetPointer(value), realSize);
printf ("Not printing \n");
res = PointerGetDatum(s);
}
return res;
}
EDITED : Ok this is really wierd. When the input is one of {BRAZIL,PAKISTAN,FRANCE}, the code terminates abruptly. If I have other countries (I haven't tried extensively, but some countries), the code runs correctly.
EDITED 2 : Found the cause and rectified the issue. If we are passing C strings to datumCopy, we have to pass -2 for typLen parameter. I had been passing it incorrectly.
Thanks!
I have found the cause and rectified the issue.
If we are passing C strings to datumCopy, we have to pass -2 for typLen parameter. I had been passing it incorrectly.

order of execution of forked processes

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/sem.h>
#include<sys/ipc.h>
int sem_id;
void update_file(int number)
{
struct sembuf sem_op;
FILE* file;
printf("Inside Update Process\n");
/* wait on the semaphore, unless it's value is non-negative. */
sem_op.sem_num = 0;
sem_op.sem_op = -1; /* <-- Amount by which the value of the semaphore is to be decreased */
sem_op.sem_flg = 0;
semop(sem_id, &sem_op, 1);
/* we "locked" the semaphore, and are assured exclusive access to file. */
/* manipulate the file in some way. for example, write a number into it. */
file = fopen("file.txt", "a+");
if (file) {
fprintf(file, " \n%d\n", number);
fclose(file);
}
/* finally, signal the semaphore - increase its value by one. */
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = 0;
semop( sem_id, &sem_op, 1);
}
void write_file(char* contents)
{
printf("Inside Write Process\n");
struct sembuf sem_op;
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = 0;
semop( sem_id, &sem_op, 1);
FILE *file = fopen("file.txt","w");
if(file)
{
fprintf(file,contents);
fclose(file);
}
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = 0;
semop( sem_id, &sem_op, 1);
}
int main()
{
//key_t key = ftok("file.txt",'E');
sem_id = semget( IPC_PRIVATE, 1, 0600 | IPC_CREAT);
/*here 100 is any arbit number to be assigned as the key of the
semaphore,1 is the number of semaphores in the semaphore set, */
if(sem_id == -1)
{
perror("main : semget");
exit(1);
}
int rc = semctl( sem_id, 0, SETVAL, 1);
pid_t u = fork();
if(u == 0)
{
update_file(100);
exit(0);
}
else
{
wait();
}
pid_t w = fork();
if(w == 0)
{
write_file("Hello!!");
exit(0);
}
else
{
wait();
}
}
If I run the above code as a c code, the write_file() function is called after the update_file () function
Whereas if I run the same code as a c++ code, the order of execution is reverse... why is it so??
Just some suggestions, but it looks to me like it could be caused by a combination of things:
The wait() call is supposed to take a pointer argument (that can
be NULL). Compiler should have caught this, but you must be picking
up another definition somewhere that permits your syntax. You are
also missing an include for sys/wait.h. This might be why the
compiler isn't complaining as I'd expect it to.
Depending on your machine/OS configuration the fork'd process may
not get to run until after the parent yields. Assuming the "wait()"
you are calling isn't working the way we would be expecting, it is
possible for the parent to execute completely before the children
get to run.
Unfortunately, I wasn't able to duplicate the same temporal behavior. However, when I generated assembly files for each of the two cases (C & C++), I noticed that the C++ version is missing the "wait" system call, but the C version is as I would expect. To me, this suggests that somewhere in the C++ headers this special version without an argument is being #defined out of the code. This difference could be the reason behind the behavior you are seeing.
In a nutshell... add the #include, and change your wait calls to "wait(0)"