How to set errno in Linux device driver? - linux

I am designing a Linux character device driver. I want to set errno when error occurs in ioctl() system call.
long my_own_ioctl(struct file *file, unsigned int req, unsigned long arg)
{
long ret = 0;
BOOL isErr = FALSE;
// some operation
// ...
if (isErr) {
// set errno
// ... <--- What should I do?
ret = -1;
}
return ret;
}
What should I do to achieve that? Thank you at advance!
Please allow me to explain my application with more detail.
My device is located in /dev/myCharDev. My user space application is like this:
#define _COMMAND (1)
#define _ERROR_COMMAND_PARAMETER (-1)
int main()
{
int fd = open("/dev/myCharDec", O_RDONLY);
int errnoCopy;
if (fd) {
if (ioctl(fd, _COMMAND, _ERROR_COMMAND_PARAMETER) < 0) { // should cause error in ioctl()
errnoCopy = errno;
printf("Oops, error occurred: %s\n", strerr(errnoCopy)); // I want this "errno" printed correctly
}
close(fd);
}
return 0;
}
As I mentioned in the comments above, How should I set the "errno" in my own device driver codes and make it readable by user space application?

Nice question!
Ok, you could think of errno as global variable (to be honnest, it is an extern int). errno has plenty of pre-defined macros for errorcodes in the errno.h library. You can have a look here. It is very likely that some of these errorcodes describe what you want to show. Pick up the right one, set it like if it was a variable you defined, and (important!) exit immediately!
You may ask yourself though if setting errno is the right approach to your problem. You can always define an (*int) and develop your own error codes, and error handling mechanism. Errno's purpose is to show and explain system errors. Do u consider your code part of the "system" (as I can see you develop your own system call, so this might be the case) ? So go on and use errno to explain your "system error".
Edit (On question update): Ok more info. As i said errno is an extern int and is set by the kernel. The value at which errno is set is simply the return value of the system call. Linux kernel then interprets this negative value through the library errno.h. So an example error message is set simply by returning (EBUSY is just an example - you can use all of the predifined error types) the error message you want from your system call. Example:
return -EBUSY
Hope it helps

Return the negative error number from the ioctl. The c library interprets this and gives a -1 return code and sets errno to the positive error. For instance your original example will set errno to 1.
As an aside your prototype for an ioctl function in the kernel looks wrong. Which kernel version are you using?

if (isErr)
{
printk(KERN_ALERT "Error %d: your description\n", errno);
ret = errno;
}
where, errno is the return value of some function.
Your device driver should always return a status for a request it received.
It is advocated you always use enumerated return codes as well as normal return
codes. Returning 0 = pass 1 or -1 = failed is vague and could be misleading.
Read section 3.1 Efficient error handling, reporting and recovery: for more information

Related

mutex unlocking and request_module() behaviour

I've observed the following code pattern in the Linux kernel, for example net/sched/act_api.c or many other places as well :
rtnl_lock();
rtnetlink_rcv_msg(skb, ...);
replay:
ret = process_msg(skb);
...
/* try to obtain symbol which is in module. */
/* if fail, try to load the module, otherwise use the symbol */
a = get_symbol();
if (a == NULL) {
rtnl_unlock();
request_module();
rtnl_lock();
/* now verify that we can obtain symbols from requested module and return EAGAIN.*/
a = get_symbol();
module_put();
return -EAGAIN;
}
...
if (ret == -EAGAIN)
goto replay;
...
rtnl_unlock();
After request_module has succeeded, the symbol we are interested in, becomes available in kernel memory space, and we can use it. However I don't understand why return EAGAIN and re-read the symbol, why can't just continue right after request_module()?
If you look at the current implementation in the Linux kernel, there is a comment right after the 2nd call equivalent to get_symbol() in your above code (it is tc_lookup_action_n()) that explains exactly why:
rtnl_unlock();
request_module("act_%s", act_name);
rtnl_lock();
a_o = tc_lookup_action_n(act_name);
/* We dropped the RTNL semaphore in order to
* perform the module load. So, even if we
* succeeded in loading the module we have to
* tell the caller to replay the request. We
* indicate this using -EAGAIN.
*/
if (a_o != NULL) {
err = -EAGAIN;
goto err_mod;
}
Even though the module could be requested and loaded, since the semaphore was dropped in order to load the module which is an operation that can sleep (and is not the "standard way" this function is executed, the function returns EAGAIN to signal it.
EDIT for clarification:
If we look at the call sequence when a new action is added (which could cause a required module to be loaded) we have this sequence: tc_ctl_action() -> tcf_action_add() -> tcf_action_init() -> tcf_action_init_1().
Now if "move back" the EAGAIN error back up to tc_ctl_action() in the case RTM_NEWACTION:, we see that with the EAGAIN ret value the call to tcf_action_add is repeated.

Linux equivalent of FreeBSD's cpu_set_syscall_retval()

The title pretty much says it all. Looking for the Linux equivalent of cpu_set_syscall_retval() found in /usr/src/sys/amd64/amd64/vm_machdep.c. Not sure if there is even such a thing in Linux but I thought I'd ask anyway.
cpu_set_syscall_retval(struct thread *td, int error)
{
switch (error) {
case 0:
td->td_frame->tf_rax = td->td_retval[0];
td->td_frame->tf_rdx = td->td_retval[1];
td->td_frame->tf_rflags &= ~PSL_C;
break;
case ERESTART:
/*
* Reconstruct pc, we know that 'syscall' is 2 bytes,
* lcall $X,y is 7 bytes, int 0x80 is 2 bytes.
* We saved this in tf_err.
* %r10 (which was holding the value of %rcx) is restored
* for the next iteration.
* %r10 restore is only required for freebsd/amd64 processes,
* but shall be innocent for any ia32 ABI.
*/
td->td_frame->tf_rip -= td->td_frame->tf_err;
td->td_frame->tf_r10 = td->td_frame->tf_rcx;
break;
case EJUSTRETURN:
break;
default:
if (td->td_proc->p_sysent->sv_errsize) {
if (error >= td->td_proc->p_sysent->sv_errsize)
error = -1; /* XXX */
else
error = td->td_proc->p_sysent->sv_errtbl[error];
}
td->td_frame->tf_rax = error;
td->td_frame->tf_rflags |= PSL_C;
break;
}
}
There's no way to do the equivalent in linux. The return value of system calls is propagated via return value from whatever functions are called internally to implement the function all the way back to user-mode. The general convention is that a non-negative return value means success and a negative value indicates an error (with the errno being the negated return value: for example, a "-2" indicates an error with an errno value of 2 [ENOENT]).
You could look up the stored register values that will be popped on return to user-mode and replace one of them (what the BSD code here is doing), but the critical one that contains the return value will just be overwritten by the normal return-from-system-call path anyway, just prior to returning to user mode.

How to get errno when epoll_wait returns EPOLLERR?

Is there a way to find out the errno when epoll_wait returns EPOLLERR for a particular fd?
Is there any further information about the nature of the error?
Edit:
Adding more information to prevent ambiguity
epoll_wait waits on a number of file descriptors. When you call epoll_wait you pass it an array of epoll_event structures:
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
The epoll_data_t structure has the same details as the one you used with epoll_ctl to add a file descriptor to epoll:
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
What I'm looking for is what happens when there is an error on one of the file descriptors that epoll is waiting on.
ie: (epoll_event.events & EPOLLERR) == 1 - is there a way to find out more details of the error on the file descriptor?
Use getsockopt and SO_ERROR to get the pending error on the socket
int error = 0;
socklen_t errlen = sizeof(error);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == 0)
{
printf("error = %s\n", strerror(error));
}
Just a minor point: Your test won't work correctly, for two reasons. If EPOLLERR is defined as, say, 0x8, then your test will be comparing 8 with one (since == has higher precedence than &), giving you a zero, then anding that with the event mask.
What you want is: (epoll_event.events & EPOLLERR) != 0 to test for the EPOLLERR bit being set.
epoll_wait returns -1 when an error occurs and sets errno appropriately. See "man 2 epoll_wait" for more info.
Include errno.h and use perror to see the error message.
Basically error is from the epfd or interupt, it will not arise from the file descriptor in your set.
include "errno.h"
if(epoll_wait() == -1)
{
perror("Epoll error : ");
}

write a kld in FreeBSD

I'm writing a new KLD in FreeBSD.
I have a C file like this:
Question about writing my own system call in FreeBSD -- but my code's functionality is a bit different. I'm initializing a variable in kernelspace and my function name is my_KLD.
I can load it without problem with "kldload", but I have a problem: I'm going to use this kld through another C file.
The file structure is like this:
int
main(int argc, char **argv)
{
f ( atoi(argv[1]) ;
}
f ( int x) {
printf("hi\n");
int syscall_num ;
struct module_stat stat ;
stat.version = sizeof(stat) ;
modstat (modfind("my_KLD") , &stat) ;
syscall_num = stat.data.intval ;
return syscall (syscall_num , x ) ;
}
But when I call this file with argument x
the result is :
hi
Bad System call (core dumped)
What else should I do?
In addition to the comment from Srh BlueOcean, you should also check the value returned by modfind(). You're assuming it can find your KLD and that's a big assumption. The KLD may not be loaded for whatever reason.
I find smaller steps are better, so call modfind and print out the integer ID to see if it is positive or negative (-1 is an error).
Something like this:
int modid;
if ((modid = modfind("my_KLD")) < 0) {
perror("modfind failed");
exit(1);
}
if (modstat(modid, &stat) < 0) {
perror("modstat failed");
exit(1);
}
The perror() function will provide you with an error message and you can check the man-page to determine what caused the error. For example, ENOENT is "The module was not found (probably not loaded)."

write() returns error:invalid argument when using serial port

I am trying to send data using the serial port but the write command always returns -1.
This is the code for the write command.
int WriteComm( int Comid, void *buf, int nobtw )
{
unsigned long nobw;
nobw = write(Comid, buf, nobtw);
move(10,5);
perror("");
sleep(10);
return nobw;
}
and this is the code that calls it
gnobw = WriteComm(theApp.idComDev[Seg],&head[1],1); //send network address
I am getting invalid argument as the error but after looking on google I cant find anything explaning what this means or how to fix it. the closes thing I found was this but it uses st0 not ttyS0 so im not sure if its even the same thing.
can anyone explain what i am doing wrong to get this error and how to fix it ?
You should only be examining errno (this includes calling perror()) if the write call failed, which it indicates by returning -1. If the write succeeds, it leaves errno unchanged.
In order to test for this you should really be assigning the return value to a variable with a signed type - preferably ssize_t - not an unsigned long.
You're getting EINVAL back from write( ). That means one of your arguments to the function is invalid: EINVAL = *E*rror, *INVAL*id argument. There are three arguments to the function:
arg your variable
---------------------- -------------
int file descriptor: Comid
void *buf: buf
size_t size: nobtw
write( ) puked when it saw one of those three. So one of those three is wrong.
So put a printf( ) before the call to write( ) and see which one (or two; or three) is wrong.
Where is the actual code (not your memory of the code) that does the open( )? Is the file descriptor returned by open( ) the same one (Comid) you are trying to write( ) onto? If not, there's your problem.
That is the likely error in this mashup.
EINVAL from write(3) means:
The STREAM or multiplexer referenced by fildes is linked (directly or indirectly) downstream from a multiplexer.
What this basically means is that something else has your serial port open for writing at the same time -- at least intermittently. USB to serial converters seem to be particularly vulnerable to this. Other serial drivers will generally only allow you to open them once.
Source:
http://linux.die.net/man/3/write

Resources