上一篇
参考文章:
tmpfs-基于内存的文件系统
浅析Linux的共享内存与tmpfs文件系统
一、System V 共享内存
1. shmget 源码分析
SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
{
struct ipc_namespace *ns = current->nsproxy->ipc_ns;;
static const struct ipc_ops shm_ops = {
.getnew = newseg,
... ...
};
struct ipc_params shm_params;
shm_params.key = key;
... ...
return ipcget(ns, ...);
}
static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
{
struct shmid_kernel *shp;
... ...
shp = kvmalloc(sizeof(*shp), GFP_KERNEL);
file = shmem_kernel_file_setup(name, size, acctflag);
... ...
error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
list_add(&shp->shm_clist, ¤t->sysvshm.shm_clist);
... ...
return error;
}
2. shmat 源码分析
SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
{
... ...
err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
}
long do_shmat(int shmid, char __user *shmaddr, int shmflg,
ulong *raddr, unsigned long shmlba)
{
shp = shm_obtain_object_check(ns, shmid);
... ...
sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
file = alloc_file(&path, f_mode,
is_file_hugepages(shp->shm_file) ?
&shm_file_operations_huge :
&shm_file_operations);
addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate, NULL);
}
二、System V 信号量
1. semget 源码分析
SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
{
struct ipc_namespace *ns;
static const struct ipc_ops sem_ops = {
.getnew = newary,
};
... ...
return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
}
static int newary(struct ipc_namespace *ns, struct ipc_params *params)
{
... ...
sma = sem_alloc(nsems);
... ...
for (i = 0; i < nsems; i++) {
INIT_LIST_HEAD(&sma->sems[i].pending_alter);
INIT_LIST_HEAD(&sma->sems[i].pending_const);
spin_lock_init(&sma->sems[i].lock);
}
... ...
retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
... ...
}
2. semctl 源码分析
SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
{
int version;
struct ipc_namespace *ns;
void __user *p = (void __user *)arg;
... ...
switch (cmd) {
... ...
case SETALL:
return semctl_main(ns, semid, semnum, cmd, p);
case SETVAL:
return semctl_setval(ns, semid, semnum, arg);
... ...
}
2.1 SETALL --> semctl_main
union semun {
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
int cmd, void __user *p)
{
struct sem_array *sma;
sma = sem_obtain_object_check(ns, semid);
... ...
case SETALL: {
if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
ipc_rcu_putref(&sma->sem_perm, sem_rcu_free);
err = -EFAULT;
goto out_free;
}
for (i = 0; i < nsems; i++) {
sma->sems[i].semval = sem_io[i];
sma->sems[i].sempid = task_tgid_vnr(current);
}
}
... ...
2.2 SETVAL --> semctl_setval
static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
unsigned long arg)
{
struct sem_array *sma;
struct sem *curr;
int err, val;
val = arg;
sma = sem_obtain_object_check(ns, semid);
curr = &sma->sems[semnum];
curr->semval = val;
curr->sempid = task_tgid_vnr(current);
... ...
}
3. semop 源码分析
struct sembuf {
unsigned short sem_num;
short sem_op;
short sem_flg;
};
SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops,
unsigned, nsops)
{
return sys_semtimedop(semid, tsops, nsops, NULL);
}
SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
unsigned, nsops, const struct timespec __user *, timeout)
{
struct sem_array *sma;
struct sembuf fast_sops[SEMOPM_FAST];
struct sembuf *sops = fast_sops, *sop;
struct sem_queue queue;
if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) {
... ...
if (timeout) {
... ...
sma = sem_obtain_object_check(ns, semid);
queue.sops = sops;
queue.nsops = nsops;
... ...
error = perform_atomic_semop(sma, &queue);
if (error == 0) {
DEFINE_WAKE_Q(wake_q);
do_smart_update(sma, sops, nsops, 1, &wake_q);
wake_up_q(&wake_q);
... ...
goto out_free;
}
if (nsops == 1) {
struct sem *curr;
curr = &sma->sems[sops->sem_num];
if (alter) {
if (sma->complex_count) {
list_add_tail(&queue.list,
&sma->pending_alter);
... ...
} else {
... ...
}