• 从Linux的tty_struct指针获取驱动上下文


    背景

    问题

    前段时间开发一个tty驱动,用途是实现仪器对GPIB消息的接收、处理和上报。对于上报场景,下位机应用将上报内容写入一个驱动创建的tty设备,tty子系统将应用的输入转发给tty驱动,tty驱动将其转换成对SPI从设备(即GPIB扩展板)的写入,SPI从设备再将收到的SPI消息转换成GPIB消息发送给上位机
    GPIB拓扑

    实现tty_operationswrite接口时,我是这么获取驱动上下文的:

    struct gpib_tty_ctx {
        struct tty_port port;
        struct tty_struct mgr;  // 其实是无效的成员
        struct tty_driver *tty_drv;
        struct spi_device *spi_dev;
        struct gpib_spi_ctx *spi_ctx;
        struct mutex tty_lock;
        u32 activated:1;
        const u8 *pend_tx_buf;
        u32 pend_tx_len;
    };
    
    static int gpib_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
    {
        struct gpib_tty_ctx *ctx = container_of(tty, struct gpib_tty_ctx, mgr);
        // 通过ctx指针访问上下文结构体gpib_tty_ctx的驱动私有字段,完成write功能
        return count;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    但是实际执行的时候,触发了空指针异常,且空指针的值并不是0x0这种典型值,而是带一点偏移。

    问题定位

    经定位,是我对tty子系统的理解有问题,write方法的第一个入参tty,并不是gpib_tty_ctxstruct tty_struct mgr成员的地址,而是tty子系统在运行时自动创建的一个匿名tty_struct对象的地址!因此我用container_of宏获取到的gpib_tty_ctx对象地址也是一个无效地址!

    解决

    注意到tty_struct结构体包含一个类型为struct tty_port的指针port

    struct tty_struct {
        struct kref kref;
        int index;
        struct device *dev;
        struct tty_driver *driver;
        struct tty_port *port;   // 指向用户驱动创建并初始化的tty_port对象
        const struct tty_operations *ops;
        struct tty_ldisc *ldisc;
        struct ld_semaphore ldisc_sem;
        // ...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    它应该就是指向驱动之前创建并初始化的gpib_tty_ctx.port对象,这个对象本身是没有被复制的,因此我可以将这个指针传递给container_of宏:

    struct gpib_tty_ctx *ctx = container_of(tty->port, struct gpib_tty_ctx, port);
    
    • 1

    经测试,新的container_of宏返回了正确的驱动上下文地址。

    总结

    1. tty_struct指针类似于file_operations接口的open方法的输出参数file指针,都对应内核自动分配的一个对象,其地址是不可以用于container_of宏的,但是它的成员private_data可以用于container_of宏,因为后者的值是驱动填写的。
    2. container_of宏的第一个参数是结构体成员地址,这个结构体成员一般是个对象,不建议选地址类成员,因为如果是地址,则该成员很可能是复制过的,那么你通过给container_of宏提供二级指针(指针成员的地址就是二级指针)获取的ctx对象,很可能是错的。
  • 相关阅读:
    《快速掌握QML》第五章 组件
    软件测试的未来?为什么越来越多的公司选择模糊测试
    SveletJs学习——逻辑处理
    jQuery 入门-----第三节:jQuery事件
    Hadoop-28 ZooKeeper集群 ZNode简介概念和测试 数据结构与监听机制 持久性节点 持久顺序节点 事务ID Watcher机制
    网络安全-IP地址信息收集
    2022山东健博会,济南国际大健康产业博览会,中国营养健康展
    使用JS简单实现一下apply、call和bind方法
    密码加密传输
    笔试题之指针结合数组的精讲2
  • 原文地址:https://blog.csdn.net/happen23/article/details/133958139