boaz
boaz

Reputation: 900

Linux- copy_to_user not working, always return the buffer size

I have a rather big project in Linux kernel (h.w).

part of needs to use the copy_to_user function, for some reason, no matter what is the buffer size it will alyways return the buffer size (and not 0).

can you please help?

here is part of my code:

asmlinkage int sys_receive_mpi_message(int rank, char *message, ssize_t message_size)
{

    int reader_rank =-10;
    struct task_struct* p = NULL;
    struct my_message_list* tmp;
    struct list_head *pos, *q;
    struct blabla* tmp1;
    int bufSize = 0;
    int res =0;
    int i=0;
    if ((rank < 0) || (rank > counter))
    {
        return -ESRCH;
    }
    list_for_each(pos, &(my_api_list->list))
    {
        tmp1 = list_entry(pos, struct blabla, list);
        if (tmp1->pid == (current->pid))
        {
            reader_rank = tmp1->place;
            p = tmp1->task_struct_p;
            break;
        }
    }
    if (reader_rank == -10)
    {
        return -ESRCH;
    }

    list_for_each_safe(pos,q, &(p->message_list->list))
    {
        tmp=list_entry(pos, struct my_message_list, list);
        if (tmp->sender_rank == rank)
        {
            if (message_size > (tmp->meesage_size))
            {
                bufSize = tmp->meesage_size;
            }
            else
            {       
                bufSize = message_size;
            }

            res = copy_to_user(message,tmp->message,bufSize);
            if(res != 0)
            {
                return -EFAULT;
            }
            kfree(tmp->message);
            list_del(pos);
            kfree(tmp);
            return (bufSize);       
        }
        return -EFAULT; 
    }
    return -EFAULT; 
}

also, I have this struct :

struct my_message_list{

    char* message;
    int meesage_size;
    int sender_rank;
    struct list_head list;
};

Update- I foundout that the message I'm geting from the user points to 0 all the time! does this tells me that the problem is in the wrapper function? here is my rapper function(the relevent part):

#include <errno.h>
int receive_mpi_message(int rank, char* message, int message_size)
{
    int res;
    __asm__ 
    (
        "pushl %%eax;" 
        "pushl %%ebx;" 
        "pushl %%ecx;" 
        "pushl %%edx;"
        "movl $245, %%eax;"
        "movl %1, %%ebx;"
        "int $0x80;"
        "movl %%eax,%0;"
        "popl %%edx;"
        "popl %%ecx;" 
        "popl %%ebx;" 
        "popl %%eax;" 
        : "=m" (res)
        :"m"(rank),"m"(message),"m"(message_size)
    ); 

    if (res >= (unsigned long)(-125))
    {
        errno = -res;
        res = -1;
    }
    return (int) res;
}

Upvotes: 1

Views: 1346

Answers (3)

boaz
boaz

Reputation: 900

I had a problem with my rapper function, forogot to store data to all the registers:

int receive_mpi_message(int rank, char* message, int message_size)
{
    int res;
    __asm__ 
    (
         "pushl %%eax;"
         "pushl %%ebx;"
         "pushl %%ecx;"
         "pushl %%edx;"
         "movl $245, %%eax;"
         "movl %1, %%ebx;"
         "movl %2, %%ecx;"
         "movl %3, %%edx;"
         "int $0x80;"
         "movl %%eax,%0;"
         "popl %%edx;"
         "popl %%ecx;"
         "popl %%ebx;"
         "popl %%eax;"
        : "=m" (res)
        :"m"(rank),"m"(message),"m"(message_size)
    ); 

    if (res >= (unsigned long)(-125))
    {
        errno = -res;
        res = -1;
    }
    return (int) res;
}

Upvotes: 0

Ortwin Angermeier
Ortwin Angermeier

Reputation: 6193

What user-space interface do you use for communication? Regardless what user space interface you use (chardev, ioctl, ...), the signature of the function definitions where you hook in should have a __user attribute.

eg: fs.h

struct file_operations {
    ...
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ...    
}

So the char *message variable should be char __user *message, just take a look at the user space interface you use.

Another thing could be that you are calling the method in the wrong place. As far is i know, the copy_*_user functions are only allowed on invocation from the user space. Please someone correct me if i am wrong.

Upvotes: 1

Breno Leit&#227;o
Breno Leit&#227;o

Reputation: 3677

Somehow the date you want to copy could not be copied, as for example, you cannot read the source or write to destination. It is explained at arch/x86/lib/usercopy_32.c:

/*
 * Returns number of bytes that could not be copied.
 * On success, this will be zero.
 */

Upvotes: 0

Related Questions