一、库函数shmget()--共享内存区的创建与寻找
asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
{
struct shmid_kernel *shp;
int err, id = 0;
down(&shm_ids.sem);
if (key == IPC_PRIVATE) {
err = newseg(key, shmflg, size);//分配一个共享内存区供本进程专用,最后返回的是一体化的标示号
} else if ((id = ipc_findkey(&shm_ids, key)) == -1) {//在shm_ids寻找shmid_kernel结构(共享内存区),如果没有找到,id为-1。如果找到了id为标示号。
if (!(shmflg & IPC_CREAT))//没有找到也不允许创建,那么就出错返回
err = -ENOENT;
else
err = newseg(key, shmflg, size);//否则创建一个共享内存区
} else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {//如果找到了,但是要求的是创建,那么也返回出错
err = -EEXIST;
} else {//如果找到了,也不要求创建,就是正常情况下了
shp = shm_lock(id);//通过标示号id,获取共享内存区
if(shp==NULL)
BUG();
if (shp->shm_segsz < size)
err = -EINVAL;
else if (ipcperms(&shp->shm_perm, shmflg))
err = -EACCES;
else
err = shm_buildid(id, shp->shm_perm.seq);//最后返回的还是一体化参数
shm_unlock(id);
}
up(&shm_ids.sem);
return err;//无论是创建还是查找,最后都返回的是一体化的标示号
}
键值IPC_PRIVATE,即0,是特殊的,它表示要分配一个共享内存区供本进程专用。其他键值则表示要创建或寻找的是"共享"内存区。而标志位IPC_CREAT则表示目的在于创建。
1、当键值是IPC_PRIVATE时,会调用newseg,分配一个共享内存区供本进程专用,代码如下:
static int newseg (key_t key, int shmflg, size_t size)
{
int error;
struct shmid_kernel *shp;
int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
struct file * file;
char name[13];
int id;
if (size < SHMMIN || size > shm_ctlmax)
return -EINVAL;
if (shm_tot + numpages >= shm_ctlall)
return -ENOSPC;
shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_USER);//分配shmid_kernel结构
if (!shp)
return -ENOMEM;
sprintf (name, "SYSV%08x", key);
file = shmem_file_setup(name, size);//在特殊文件系统"shm"中建立映射文件
error = PTR_ERR(file);
if (IS_ERR(file))
goto no_file;
error = -ENOSPC;
id = shm_addid(shp);//将shmid_kernel结构链入shm_ids
if(id == -1)
goto no_id;
shp->shm_perm.key = key;
shp->shm_flags = (shmflg & S_IRWXUGO);
shp->shm_cprid = current->pid;
shp->shm_lprid = 0;
shp->shm_atim = shp->shm_dtim = 0;
shp->shm_ctim = CURRENT_TIME;
shp->shm_segsz = size;
shp->shm_nattch = 0;
shp->id = shm_buildid(id,shp->shm_perm.seq);//将这个标识号转换成一个一体化的标示号
shp->shm_file = file;//指向新建立的file
file->f_dentry->d_inode->i_ino = shp->id;
file->f_op = &shm_file_operations;//最后又重新设置了一遍f_op,这里是shm_file_operations,而不是shmem_file_operations
shm_tot += numpages;
shm_unlock (id);
return shp->id;//返回的是一体化的标示号
no_id:
fput(file);
no_file:
kfree(shp);
return error;
}
shmid_kernel结构如下:
struct shmid_kernel /* private to the kernel */
{
struct kern_ipc_perm shm_perm;
struct file * shm_file;
int id;
unsigned long shm_nattch;
unsigned long shm_segsz;
time_t shm_atim;
time_t shm_dtim;
time_t shm_ctim;
pid_t shm_cprid;
pid_t shm_lprid;
};
shmem_file_setup,在特殊文件系统"shm"中建立映射文件,代码如下:
struct file *shmem_file_setup(char * name, loff_t size)
{
int error;
struct file *file;
struct inode * inode;
struct dentry *dentry, *root;
struct qstr this;
int vm_enough_memory(long pages);
error = -ENOMEM;
if (!vm_enough_memory((size) >> PAGE_SHIFT))
goto out;
this.name = name;
this.len = strlen(name);
this.hash = 0; /* will go */
root = shmem_fs_type.kern_mnt->mnt_root;//shm特殊文件系统的根节点的dentry结构
dentry = d_alloc(root, &this);//分配shm节点的dentry结构
if (!dentry)
goto out;
error = -ENFILE;
file = get_empty_filp();
if (!file)
goto put_dentry;
error = -ENOSPC;
inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);//分配shm节点的inode结构
if (!inode)
goto close_file;
d_instantiate(dentry, inode);//shm节点的dentry结构和shm节点的inode结构相关联
dentry->d_inode->i_size = size;
file->f_vfsmnt = mntget(shmem_fs_type.kern_mnt);
file->f_dentry = dentry;//指向刚刚的dentry
file->f_op = &shmem_file_operations;//设置如下
file->f_mode = FMODE_WRITE | FMODE_READ;
inode->i_nlink = 0; /* It is unlinked */
return(file);
close_file:
put_filp(file);
put_dentry:
dput (dentry);
out:
return ERR_PTR(error);
}
其中shmem_fs_type.kern_mnt->mnt_root是在init_shmem_fs中建立的。
static DECLARE_FSTYPE(shmem_fs_type, "shm", shmem_read_super, FS_LITTER);
static int __init init_shmem_fs(void)
{
int error;
struct vfsmount * res;
if ((error = register_filesystem(&shmem_fs_type))) {
printk (KERN_ERR "Could not register shmem fs\n");
return error;
}
res = kern_mount(&shmem_fs_type);
if (IS_ERR (res)) {
printk (KERN_ERR "could not kern_mount shmem fs\n");
unregister_filesystem(&shmem_fs_type);
return PTR_ERR(res);
}
devfs_mk_dir (NULL, "shm", NULL);
return 0;
}
shmem_get_inode,分配shm节点的inode结构,代码如下:
struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev)
{
struct inode * inode;
spin_lock (&sb->u.shmem_sb.stat_lock);
if (!sb->u.shmem_sb.free_inodes) {
spin_unlock (&sb->u.shmem_sb.stat_lock);
return NULL;
}
sb->u.shmem_sb.free_inodes--;
spin_unlock (&sb->u.shmem_sb.stat_lock);
inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_rdev = to_kdev_t(dev);
inode->i_mapping->a_ops = &shmem_aops;//shmem_aops设置如下
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
spin_lock_init (&inode->u.shmem_i.lock);
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
break;
case S_IFREG://i_op和i_fop设置如下
inode->i_op = &shmem_inode_operations;
inode->i_fop = &shmem_file_operations;
break;
case S_IFDIR:
inode->i_op = &shmem_dir_inode_operations;
inode->i_fop = &shmem_dir_operations;
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
break;
}
spin_lock (&shmem_ilock);
list_add (&inode->u.shmem_i.list, &shmem_inodes);
spin_unlock (&shmem_ilock);
}
return inode;
}
inode->i_op = &shmem_inode_operations,代码如下:
static struct inode_operations shmem_inode_operations = {
truncate: shmem_truncate,
};
inode->i_fop = &shmem_file_operations,代码如下:
static struct file_operations shmem_file_operations = {
mmap: shmem_mmap
};
inode->i_mapping->a_ops = &shmem_aops,代码如下:
static struct address_space_operations shmem_aops = {
writepage: shmem_writepage
};
返回到
shmem_file_setup,file->f_op = &shmem_file_operations,如下:
static struct file_operations shmem_file_operations = {
mmap: shmem_mmap
};
返回到newseg,shm_addid,将shmid_kernel结构链入shm_ids,代码如下:
static inline int sh