__ATTR引发的编译错误【原创】

本文详细解析了在编译Linux内核模块驱动时遇到的编译错误,特别是关于位字段宽度和权限设置的问题。通过分析__ATTR宏的实现和BUILD_BUG_ON_ZERO函数的作用,提出了两种解决方案,一种是遵循内核的安全设计原则,另一种是自定义宏以保持接口的兼容性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 有一天我编译内核模块驱动的时候发现如下错误

Linux kernel版本:4.1.15

error: negative width in bit-field '<anonymous>'

代码如下:

static struct device_attribute sysfs_keypad_list[] = {
    __ATTR(virt_key, 0666, 
           keypad_show_error, keypad_virt_key_store),                       
};

当我做这样的修改后:

static struct device_attribute sysfs_keypad_list[] = {
    __ATTR(virt_key, 0665, 
           keypad_show_error, keypad_virt_key_store),                       
};

编译就不报错了

这样让我很是奇怪,接下来咱们跟入代码一看究竟

首先我们看下__ATTR的实现:

继续跟入,我们发现如下的算法,显而易见,此版本的内核对权限做了一个小小的算法,如下算法大家可以写一个简单的c代码进行解读

当我传入perms=0x666的时候,BUILD_BUG_ON_ZERO(perms & 2) 这个会报错,因为如下:

为什么 BUILD_BUG_ON_ZERO( (0x666) & 2 )会报错呢?

我们可以写这样的代码来验证一下:

#include <stdio.h>

int main()
{
    struct a {
        int: -1;
    };    
   
    return 0;   
}

运行:

出现了同样的错误,那么我们应该明白了吧,gcc会在编译的时候对位域的定义进行检查,struct {int: -1}这样的定义编译器会认为是错误的

那至于为什么会打印这样的错误呢?这就需要对编译器进行了解了,也就是编译器是如何检查结构体位域的定义的,这块我没有深入研究过

如有人有这块的资料和信息欢迎评论和分享。

如下引用一段话,摘自网上(https://stackoverflow.com/questions/31395602/giving-s-iwugo-permission-to-module-parameter-results-in-compilation-error-whil)

Linux probably refuses to make module parameters world-writable for security reasons.

You should be able to use narrower permissions such as S_IWUSR | S_IWGRP

通俗的理解就是内核希望这样做的安全一点,减少其他组的写权限,体现在 BUILD_BUG_ON_ZERO(perms & 2)这个设计上

那么我们如何修改呢?

有如下两种方式的思路给大家借鉴:

第一种:

 这样设计的思路是为了遵循作者的思想,保障安全(但__ATTR这个宏的用法不同版本是有差别的在这块,比如说3.6.5的版本是不会检查这个权限问题的)

static struct device_attribute sysfs_keypad_list[] = {
    __ATTR(virt_key, 0664, 
           keypad_show_error, keypad_virt_key_store),                       
};

第二种:

这样设计的思路是因为搞驱动开发的相信大家都清楚,如果这个接口是我们曾经释放出去的,开放了这样的权限

那么我们后期开发的时候必须兼容之前的接口设计,不能这样随意的更改权限,因为如果你修改了,某个客户之前有这样子使用权限的话,你改了权限后,他可能就用不了了,

因此我们可以做如下处理,思路就是我们自己定义,不使用内核的设计

#undef __ATTR
#define __ATTR(_name, _mode, _show, _store) {                \
    .attr = {.name = __stringify(_name),                \
         .mode = _mode},        \
    .show    = _show,                        \
    .store    = _store,                        \
}

static struct device_attribute sysfs_keypad_list[] = {
    __ATTR(virt_key, 0666, 
           keypad_show_error, keypad_virt_key_store),                       
};

 

分析如上,如有描述不准确的地方还请告知,Thanks

 

struct ib_qp_attr *attr 是一个指向InfiniBand(IB)队列对(Queue Pair, QP)属性结构体的指针。InfiniBand是一种高性能网络通信技术,广泛应用于高性能计算(HPC)和数据中心。队列对是InfiniBand中用于数据传输的基本单元,包含发送队列和接收队列。 以下是对struct ib_qp_attr *attr的详细介绍: 1. **结构体定义**: struct ib_qp_attr 结构体用于描述队列对的属性,包括状态、路径、优先级等信息。该结构体通常包含以下成员: - qp_state:队列对的状态,如RESET, INIT, RTR, RTS等。 - path_mtu:路径的最大传输单元(MTU)。 - dest_qp_num:目标队列对的编号。 - qkey:QKey,用于标识数据包的类型和优先级。 - sq_psn:发送队列的Packet Sequence Number(PSN)。 - rq_psn:接收队列的PSN。 - max_dest_rd_atomic:目标队列对的最大RDMA读/原子操作数。 - max_rd_atomic:本地队列对的最大RDMA读/原子操作数。 - port_num:使用的端口号。 - timeout:超时时间。 - retry_cnt:重试次数。 - rnr_retry:RNR(Receiver Not Ready)重试次数。 - pkey_index:PKey索引。 - alt_dest_qp_num:备用目标队列对的编号。 - alt_port_num:备用端口号。 2. **用途**: 该结构体用于配置和查询队列对的属性。通过设置attr指针指向的struct ib_qp_attr结构体的成员,可以配置队列对的各种属性,如状态、路径、优先级等。 3. **使用示例**: ```c struct ib_qp_attr attr; struct ib_qp_init_attr init_attr; struct ib_qp *qp; // 初始化队列对属性 memset(&attr, 0, sizeof(attr)); attr.qp_state = IB_QPS_INIT; attr.pkey_index = 0; attr.port_num = 1; attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | IB_ACCESS_REMOTE_WRITE; // 创建队列对 ib_qp = ib_create_qp(pd, &init_attr); // 修改队列对属性 ib_modify_qp(qp, &attr, IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值