此应用程序执行到最后会出现错误提示“trying to free free page”,这是由于sys_shmget函数在 使用get_free_page函数申请到一个物理页时,将此物理页在mem_map中记录的引用计数设置为1,而再次调 用sys_shmget函数使用key从vector中获取共享的物理页时,没有增加此物理页在mem_map中的引用计数。 所以,当生产者进程和消费者进程退出时,都会调用free_page函数释放此物理页,每调用一次就会将 mem_map中的引用计数减1,导致一个物理页的引用计数被减为了负数,这是Linux物理页管理程序所不允许 的,所以执行了mm/memory.c中free_page函数的最后一行(第310行)代码打印出错信息。请读者改进 sys_shmget函数,当能够使用key从vector中获取共享的物理页时,将此物理页在mem_map中的引用计数增 加1该如何修改。
时间: 2023-06-20 13:04:59 浏览: 289
Warning: session_destroy() : Trying to destroy uninitialized sessionq错误
可以在sys_shmget函数中找到使用get_free_page函数申请到一个物理页的代码,在此代码后面添加mem_map引用计数增加的代码即可。具体实现如下:
```C
unsigned long sys_shmget(key_t key, size_t size, int shmflg)
{
struct shmid_ds *buf;
struct shminfo *inf;
struct shm_file_data *shm_file;
struct page *page;
unsigned long addr;
int shmid, err, temp;
int i;
down(&shm_ids.sem);
// 查找 key 对应的共享内存是否已经存在
for (i = 0; i < SHM_NR; i++) {
if (shm_ids.used_ids[i] &&
shm_ids.shm_file[i]->key == key) {
shm_file = shm_ids.shm_file[i];
break;
}
}
// 如果 key 对应的共享内存不存在,就创建一个新的共享内存
if (i == SHM_NR) {
if (!(shmflg & IPC_CREAT)) { // 如果没有创建新的共享内存的权限
up(&shm_ids.sem);
return -EINVAL;
}
// 查找一个空闲的共享内存结构体
for (i = 0; i < SHM_NR; i++) {
if (!shm_ids.used_ids[i]) {
shm_file = kmalloc(sizeof(struct shm_file_data), GFP_KERNEL);
if (!shm_file) {
up(&shm_ids.sem);
return -ENOMEM;
}
// 申请一个物理页
page = get_free_page();
if (!page) {
up(&shm_ids.sem);
kfree(shm_file);
return -ENOMEM;
}
// 将物理页映射到内核空间
addr = (unsigned long) page_address(page);
if (!addr) {
up(&shm_ids.sem);
free_page((unsigned long) page);
kfree(shm_file);
return -ENOMEM;
}
// 初始化共享内存结构体
shm_file->key = key;
shm_file->page = page;
shm_file->attached = 0;
// 将共享内存结构体添加到 vector 中
temp = find_empty_slot();
if (temp == -1) {
up(&shm_ids.sem);
free_page((unsigned long) page);
kfree(shm_file);
return -EINVAL;
}
shm_ids.used_ids[temp] = 1;
shm_ids.shm_file[temp] = shm_file;
// 设置物理页在 mem_map 中的引用计数
atomic_inc(&mem_map[MAP_NR(page->phys_addr)].count);
buf = (struct shmid_ds *) getname(kernel_stack, (char *) arg2);
if (!buf) {
up(&shm_ids.sem);
free_page((unsigned long) page);
kfree(shm_file);
return -EFAULT;
}
// 初始化共享内存的元信息
buf->shm_nattch = 0;
buf->shm_page = page;
buf->shm_segsz = PAGE_SIZE;
putname((char *) arg2);
up(&shm_ids.sem);
return temp;
}
}
up(&shm_ids.sem);
return -EINVAL;
}
// 如果 key 对应的共享内存已经存在,就返回共享内存的编号
shmid = i;
shm_file = shm_ids.shm_file[shmid];
// 设置物理页在 mem_map 中的引用计数
atomic_inc(&mem_map[MAP_NR(shm_file->page->phys_addr)].count);
up(&shm_ids.sem);
return shmid;
}
```
在上述代码中,我们在申请到物理页后,添加了以下代码:
```C
// 设置物理页在 mem_map 中的引用计数
atomic_inc(&mem_map[MAP_NR(page->phys_addr)].count);
```
这样,在使用key从vector中获取共享的物理页时,就会增加此物理页在mem_map中的引用计数,从而避免了引用计数被减为负数的问题。
阅读全文