sendto 函数中的struct iov_iter结构 (linux-5.0)

在看linux-5.0 sendto 函数实现时,__sys_sendto函数中调用了import_single_range函数.

[net/socket.c]
int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
         struct sockaddr __user *addr,  int addr_len)
{
    struct socket *sock;
    struct sockaddr_storage address;
    int err;
    struct msghdr msg;
    struct iovec iov;
    int fput_needed;


    err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter);
    if (unlikely(err))
        return err;
    sock = sockfd_lookup_light(fd, &err, &fput_needed);
    if (!sock)
        goto out;


    msg.msg_name = NULL;
    msg.msg_control = NULL;
    msg.msg_controllen = 0;
    msg.msg_namelen = 0;
    if (addr) {
        err = move_addr_to_kernel(addr, addr_len, &address);
        if (err < 0)
            goto out_put;
        msg.msg_name = (struct sockaddr *)&address;
        msg.msg_namelen = addr_len;
    }
    if (sock->file->f_flags & O_NONBLOCK)
        flags |= MSG_DONTWAIT;
    msg.msg_flags = flags;
    err = sock_sendmsg(sock, &msg);


out_put:
    fput_light(sock->file, fput_needed);
out:
    return err;
}

查看import_single_range实现:

[lib/iov_iter.c]

int import_single_range(int rw, void __user *buf, size_t len,
         struct iovec *iov, struct iov_iter *i)
{
    if (len > MAX_RW_COUNT)
        len = MAX_RW_COUNT;
    if (unlikely(!access_ok(buf, len)))
        return -EFAULT;

    iov->iov_base = buf;
    iov->iov_len = len;
    iov_iter_init(i, rw, iov, 1, len);
    return 0;
}

void iov_iter_init(struct iov_iter *i, unsigned int direction,
            const struct iovec *iov, unsigned long nr_segs,
            size_t count)
{
    WARN_ON(direction & ~(READ | WRITE));
    direction &= READ | WRITE;

    /* It will get better.  Eventually... */
    if (uaccess_kernel()) {
        i->type = ITER_KVEC | direction;
        i->kvec = (struct kvec *)iov;
    } else { //跑到这里
        i->type = ITER_IOVEC | direction;
        i->iov = iov;
    }
    i->nr_segs = nr_segs;
    i->iov_offset = 0;
    i->count = count;
}
-----------------------------------------------------
uaccess_kernel()实现:以arm64为例
[include/linux/uaccess.h]
#define uaccess_kernel() segment_eq(get_fs(), KERNEL_DS)

[arch/arm64/include/asm/uaccess.h]
#define get_fs()    (current_thread_info()->addr_limit)

[arch/arm64/include/asm/uaccess.h]
#define segment_eq(a, b)    ((a) == (b))

[arch/arm64/include/asm/processor.h]
#define KERNEL_DS       UL(-1)
#define USER_DS         ((UL(1) << MAX_USER_VA_BITS) - 1)

[include/linux/thread_info.h]
#define current_thread_info() ((struct thread_info *)current)

[arch/arm64/include/asm/thread_info.h]
struct thread_info {
    unsigned long       flags;      /* low level flags */
    mm_segment_t        addr_limit; /* address limit */
    ......
}

谁赋值给addr_limit?

查找到两处给addr_limit赋值:

1.[arch/arm64/include/asm/uaccess.h]
static inline void set_fs(mm_segment_t fs)
{
    current_thread_info()->addr_limit = fs;
    ....
}

2.[arch/arm64/include/asm/thread_info.h]
#define INIT_THREAD_INFO(tsk)                       \
{                                   \
    .flags      = _TIF_FOREIGN_FPSTATE,             \
    .preempt_count  = INIT_PREEMPT_COUNT,               \
    .addr_limit = KERNEL_DS,                    \
}

调用栈:

el0_svc
    el0_svc_handler
        el0_svc_common
            invoke_syscall
                __invoke_syscall
                    __arm64_sys_sendto
                        __do_sys_sendto
                            __sys_sendto
                                import_single_range
                                    iov_iter_init
                                        uaccess_kernel返回值是false

初始化后的结构体如下:

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byd yes

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值