当前位置: 首页 > news >正文

Linux ipc_alloc_permm ipc权限结构体分配与refcnt

Linux ipc_alloc_permm ipc权限结构体分配与refcnt

ipc_alloc_permm是ipc/util.c中的关键辅助函数,负责为System V IPC对象分配包含struct kern_ipc_perm权限结构体的内存块。该函数被semget、msgget、shmget三个路径的通用分配器ipc_addid调用,返回已清零的权限结构体指针。

函数签名:

```c
struct kern_ipc_perm *ipc_alloc_permm(struct ipc_namespace *ns,
size_t total_size, int id_shift)
{
struct kern_ipc_perm *perm;
int i;

perm = kvmalloc(total_size, GFP_KERNEL_ACCOUNT);
if (!perm)
return NULL;

memset(perm, 0, total_size);

/* 初始化公用部分 */
spin_lock_init(&perm->lock);
perm->deleted = false;
perm->id_shift = id_shift;
perm->ns = ns;
refcount_set(&perm->refcount, 1);

/* 初始化key哈希节点 */
INIT_LIST_NODE(&perm->key_list);

return perm;
}
```

total_size参数由各IPC对象决定:
- 信号量:sizeof(struct sem_array) + nsems * sizeof(struct sem)
- 消息队列:sizeof(struct msg_queue)
- 共享内存:sizeof(struct shmid_kernel)

ipc_alloc_permm使用kvmalloc分配,允许在需要时通过vmalloc后备,避免物理连续内存压力下的分配失败。GFP_KERNEL_ACCOUNT表示该内存计入当前cgroup的内存账户。

struct kern_ipc_perm是所有IPC对象权限结构体的基类:

```c
struct kern_ipc_perm {
spinlock_t lock; /* 保护IPC对象的自旋锁 */
bool deleted; /* 标记是否已被删除 */
int id_shift; /* ID生成移位 */
struct ipc_namespace *ns; /* 所属命名空间 */
refcount_t refcount; /* 引用计数 */
struct list_head key_list; /* 挂入rhashtable的key链 */
/* 以下字段用于权限校验 */
key_t key; /* IPC key */
kuid_t uid; /* 所有者uid */
kgid_t gid; /* 所有者gid */
kuid_t cuid; /* 创建者uid */
kgid_t cgid; /* 创建者gid */
umode_t mode; /* 访问权限模式 */
unsigned short seq; /* 序列号 */
unsigned short size; /* 用于信号量时存储sem_nsems */
};
```

refcount_t是内核引入的原子引用计数器,替换了早期atomic_t。refcount_t提供的溢出保护可以检测refcount_inc/dec的不匹配使用:

```c
void ipc_rcu_getref(struct kern_ipc_perm *perm)
{
refcount_inc(&perm->refcount);
}

void ipc_rcu_putref(struct kern_ipc_perm *perm,
void (*free_func)(struct rcu_head *head))
{
if (refcount_dec_and_test(&perm->refcount)) {
call_rcu(&perm->rcu, free_func);
}
}
```

ipc_rcu_putref在引用计数降为零时通过call_rcu将释放操作推迟到RCU宽限期之后。free_func函数释放整个IPC对象内存,例如sem_rcu_free、msg_rcu_free、shm_rcu_free。这种设计确保了读者在RCU读锁保护下安全访问IPC对象后,对象不会在释放途中被并发读取:

```c
static void sem_rcu_free(struct rcu_head *head)
{
struct kern_ipc_perm *p = container_of(head,
struct kern_ipc_perm, rcu);
kvfree(p);
}
```

refcount的递增发生在以下场景:
1. ipc_addid中分配成功后设为1(初始引用)
2. ipc_rcu_getref在ipc_lock和ipc_obtain_object_idr时被调用,持有锁期间增加引用防止释放
3. shmat增加shm_file引用但不直接增加kern_ipc_perm引用,通过file结构间接管理
4. semop和msgrcv/msgsnd在操作期间通过ipc_lock获取引用

ipc_addid是分配新IPC对象的公共入口,在ipc_alloc_permm之后将结构体加入idr和key哈希表:

```c
int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new,
int max_id)
{
int idx;
int id;

idr_preload(GFP_KERNEL);

/* 在idr中分配ID */
idx = idr_alloc_cyclic(&ids->ipcs_idr, new, 0, max_id,
GFP_NOWAIT);
idr_preload_end();
if (idx < 0)
return idx;

/* 计算外界可见的IPC ID */
id = (idx + SEQ_MULTIPLIER * new->seq);
new->id = id;

/* 将key插入哈希表 */
if (new->key != IPC_PRIVATE)
rhltable_insert(&ids->key_ht, &new->key_list,
ipc_kht_params);

ids->in_use++;
new->deleted = false;

return id;
}
```

ID计算使用序列号seq和索引idx组合,避免重用同一索引时发生ID冲突:ipc_id = (idx + seq * SEQ_MULTIPLIER),SEQ_MULTIPLIER为IPCMNI(32768)。这种设计确保IPC ID不因连续创建/销毁而迅速回绕。

ipc_findkey利用rhashtable在O(1)时间内查找key对应的IPC对象。如果多个IPC对象共享相同key(在IPC_PRIVATE之外不允许),key_list链表会保存多个条目。rhashtable的查找进入RCU域,因此refcount的递增必须保证对象不被并行删除。

http://www.cnnetsun.cn/news/2901071.html

相关文章:

  • Linux ipcns_notify ipc命名空间变更与sysctl接口
  • 如何5分钟搞定B站视频转文字:免费高效解决方案全攻略
  • 不只是科研:手把手教你用Python把‘图片放大镜’玩出花,从产品截图到教程标注都能用
  • H3C交换机端口流量监控实战:用display counters rate命令排查网络卡顿
  • 2026河北油管厂家排行揭秘,这样选才不踩坑
  • 计算机毕业设计之基于Python的校园书院预约系统的设计与实现
  • 人类最后考试已不够用,Agent最后考试来了!
  • WebSocket 行情脚本最怕的不是断线,是“看起来还在跑”
  • 如何快速获取百度网盘资源:终极提取码查询工具完整指南
  • 从“滋滋”声到清晰通话:一个移动端音频工程师的AEC避坑实战录
  • 别再只用矢量数据了!一文讲透ArcGIS中哪些栅格数据有属性表,以及如何利用
  • 豹女红三速开 目前1min57s
  • 深度解析CANN昇腾AI处理器算子开发中的调试工具链与性能调优实战指南
  • 三步解锁《鸣潮》极致体验:WaveTools工具箱实战指南
  • 2026 APMCM 亚太地区大学生数学建模竞赛 ABC
  • 51单片机矩阵键盘密码锁实战:从硬件连线到代码调试,手把手教你避开蜂鸣器干扰
  • 一文看懂 AI 编程智能体工程化新范式:Loop Engineering
  • Python周刊2026W23 | Polars 1.41、PyPy v7.3.23、Python 3.15、httpx2、dj-lite-tenant
  • 手把手教你用MTK DWS配置GPIO驱动LED和按键(基于MT6765平台)
  • 用Scrapy搭建基础网络文本爬虫的完整实践指南
  • 手把手教你优化STM32H7性能:把关键代码和数据塞进ITCM/DTCM的完整流程
  • GOT-JEPA:通用目标跟踪的创新架构与遮挡处理技术
  • 告别单体应用:用SpringCloudAlibaba快速拆分出你的第一个微服务(Order/Stock实战)
  • Centos7.9搭建IPV6银河麒麟SP2系统PXE
  • 别再死记公式了!用STM32CubeMX配置ADC测芯片内部温度,附F0/F1系列校准值查找与代码实战
  • 保姆级教程:在Win10上用Docker Desktop搞定ChirpStack服务器,手把手连接Ra-08H收发MQTT数据
  • 从零到封装:用Logisim搭建你的第一个可复用LED计数器模块
  • 如何3步免费解锁123云盘VIP功能?完整实用教程
  • WinForm程序运行中实时编译C#代码并调用方法的完整示例
  • ESP32开发效率翻倍:详解VSCode中ESP-IDF插件的7个隐藏技巧与idf.py命令组合