Chinaunix

标题: 问个copy_from_user的问题 [打印本页]

作者: star316    时间: 2009-03-12 11:32
标题: 问个copy_from_user的问题
在i2c.dev 中 ioctl 的函数里面有 两次 copy_from_user ,第一次已经从用户空间读取数据了, 但是第二次不是从用户读取数据,为什么还要用copy_from_user?? 请问怎么回事,谢谢!
case I2C_RDWR:
        if (copy_from_user(&rdwr_arg,                      //第一次拷贝到rdwr_arg

                   (struct i2c_rdwr_ioctl_data __user *)arg,
                   sizeof(rdwr_arg)))
            return -EFAULT;

        /* Put an arbitrary limit on the number of messages that can
         * be sent at once */

        if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
            return -EINVAL;

        rdwr_pa = (struct i2c_msg *)
            kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
            GFP_KERNEL);

        if (rdwr_pa == NULL) return -ENOMEM;

    if (copy_from_user(rdwr_pa, rdwr_arg.msgs,   //还从rdwr_arg复制,但是这个是内核的数据

                   rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
            kfree(rdwr_pa);
            return -EFAULT;
        }


[ 本帖最后由 dreamice 于 2009-3-12 14:47 编辑 ]
作者: yidou    时间: 2009-03-12 11:45
star316 最近很活跃, 赞一个.
这个问题明显没有仔细思考, 踩一个.
作者: yidou    时间: 2009-03-12 11:49
贴一下两个结构的定义:

/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
        struct i2c_msg __user *msgs;        /* pointers to i2c_msgs */
        __u32 nmsgs;                        /* number of i2c_msgs */
};


struct i2c_msg {
        __u16 addr;        /* slave address                        */
        __u16 flags;
#define I2C_M_TEN                0x0010        /* this is a ten bit chip address */
#define I2C_M_RD                0x0001        /* read data, from slave to master */
#define I2C_M_NOSTART                0x4000        /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR        0x2000        /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK        0x1000        /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK                0x0800        /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN                0x0400        /* length will be first received byte */
        __u16 len;                /* msg length                                */
        __u8 *buf;                /* pointer to msg data                        */
};

第一次copy了i2c_rdwr_ioctl_data, 第二次copy了i2c_rdwr_ioctl_data->i2c_msg
作者: star316    时间: 2009-03-12 12:43
唉,没办法啊, 东西总得学, 本来不想用系统的框架写驱动,自己写的还容易点, 但是想了想,自己了解一下它们的框架还是蛮好的,说不定以后就用上啦呢?

i2c_rdwr_ioctl_data->i2c_msg 也是里面的元素, 难道第一次没有拷贝内容过去?? 或者拷过去的只是一个指针
作者: yidou    时间: 2009-03-12 12:45
正如你所说, copy i2c_rdwr_ioctl_data时, 里面只是一个指针阿, 并不包括元素本身.
作者: star316    时间: 2009-03-12 13:09
哦,那我第二次拷贝如果是不用 rdwr_arg.msgs  参数, 而用 arg.msgs ,可以么?
作者: garyv    时间: 2009-03-12 14:12
当然可以,注意加指针类型转换。
5楼大天使说的是正确的。
作者: garyv    时间: 2009-03-12 14:13
用arg->msgs
作者: yidou    时间: 2009-03-12 14:14
原帖由 star316 于 2009/3/12 13:09 发表
哦,那我第二次拷贝如果是不用 rdwr_arg.msgs  参数, 而用 arg.msgs ,可以么?


我也不熟悉. 只好你自己分析一下了.
作者: star316    时间: 2009-03-12 14:36
这一功能函数变换的好多,看的卡壳了,再帮我看看最后面一个吧, 谢谢

for( i=0; i<rdwr_arg.nmsgs; i++ ) {
                        /* Limit the size of the message to a sane amount */
                        if (rdwr_pa.len > 8192) {
                                res = -EINVAL;
                                break;
                        }
                        data_ptrs = (u8 __user *)rdwr_pa.buf;
                        rdwr_pa.buf = kmalloc(rdwr_pa.len, GFP_KERNEL);
                        if(rdwr_pa.buf == NULL) {
                                res = -ENOMEM;
                                break;
                        }
                        if(copy_from_user(rdwr_pa.buf,
                                data_ptrs,
                                rdwr_pa.len)) {
                                        ++i; /* Needs to be kfreed too */
                                        res = -EFAULT;
                                break;
                        }
               
这里的(copy_from_user(rdwr_pa.buf,data_ptrs,rdwr_pa.len))  应该是拷贝用户的buf的程序,
但是data_ptrs = (u8 __user *)rdwr_pa.buf  , 这里指针指向自己了, 怎么会拷贝用户数据???
作者: garyv    时间: 2009-03-12 14:48
rdwr_pa.buf = kmalloc(rdwr_pa.len, GFP_KERNEL);
没问题啊,看清楚,这一句让buf重新赋值并指向一片内核空间
作者: star316    时间: 2009-03-12 20:31
不错,这一句是重新分配内存空间,
只是我不明白, 这一句 data_ptrs
= (u8 __user *)rdwr_pa
.buf;  

是如何把用户空间的数据传递过来的???
因为上面只有一句 (copy_from_user(rdwr_pa, rdwr_arg.msgs,   rdwr_arg.nmsgs * sizeof(struct i2c_msg)))
这里拷贝了元素msgs中的内容,但是msgs中的buf 只是一个指针, 那么就是说BUF 中的内容并没有拷贝过来, 那这个BUF 中的内容是什么时候到rdwr_pa
.buf 中的呢?

分析好久了没头绪. 请指教? 谢谢


[ 本帖最后由 star316 于 2009-3-12 20:34 编辑 ]
作者: garyv    时间: 2009-03-13 10:35
原帖由 star316 于 2009-3-12 14:36 发表
这一功能函数变换的好多,看的卡壳了,再帮我看看最后面一个吧, 谢谢

for( i=0; i 8192) {
                                res = -EINVAL;
                                break;
                        }
                        data_ptrs = (u8 __user *)rdwr_pa.buf;
                        rdwr_pa.buf = kmalloc( ...


data_ptrs指针指向用户空间一块数据区啊,后面调用copy_from_user没问题啊,个人感觉你对C里面的指针概念理解还不是很透彻。
作者: star316    时间: 2009-03-13 13:00
呵呵,指针蛮复杂的,谢谢楼上,搞明白了,

看来只要把它当作一般的函数指针传递就可以了, 我总把用户空间与内核空间的指针独立开了。
作者: garyv    时间: 2009-03-13 13:49
八用客气




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2