/* This is called by fork, once for every shm attach. */ static void shm_open (struct vm_area_struct *shmd) { shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino); }
/* 释放shmid_kernel对象 * * It has to be called with shp and shm_ids.sem locked, * but returns with shp unlocked and freed. */ static void shm_close (struct vm_area_struct *shmd) { struct file * file = shmd->vm_file; int id = file->f_dentry->d_inode->i_ino; struct shmid_kernel *shp;
down (&shm_ids.sem); /* remove from the list of attaches of the shm segment */ if(!(shp = shm_lock(id))) BUG(); shp->shm_lprid = current->pid; shp->shm_dtim = CURRENT_TIME; shp->shm_nattch--; if(shp->shm_nattch == 0 && shp->shm_flags & SHM_DEST) shm_destroy (shp); else shm_unlock(id); up (&shm_ids.sem); }
static struct vm_operations_struct shm_vm_ops = { open: shm_open, /* callback for a new vm-area open */ close: shm_close, /* callback for when the vm-area is released */ nopage: shmem_nopage, };
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;
return err < 0 ? 0 : err; } case SHM_STAT: case IPC_STAT: { struct shmid64_ds tbuf; int result; memset(&tbuf, 0, sizeof(tbuf)); shp = shm_lock(shmid); if(shp==NULL) return -EINVAL; if(cmd==SHM_STAT) { err = -EINVAL; if (shmid > shm_ids.max_id) goto out_unlock; result = shm_buildid(shmid, shp->shm_perm.seq); } else { err = shm_checkid(shp,shmid); if(err) goto out_unlock; result = 0; } err=-EACCES; if (ipcperms (&shp->shm_perm, S_IRUGO)) goto out_unlock; kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm); tbuf.shm_segsz = shp->shm_segsz; tbuf.shm_atime = shp->shm_atim; tbuf.shm_dtime = shp->shm_dtim; tbuf.shm_ctime = shp->shm_ctim; tbuf.shm_cpid = shp->shm_cprid; tbuf.shm_lpid = shp->shm_lprid; tbuf.shm_nattch = shp->shm_nattch; shm_unlock(shmid); if(copy_shmid_to_user (buf, &tbuf, version)) return -EFAULT; return result; } case SHM_LOCK: case SHM_UNLOCK: { /* Allow superuser to lock segment in memory */ /* Should the pages be faulted in here or leave it to user? */ /* need to determine interaction with current->swappable */ if (!capable(CAP_IPC_LOCK)) return -EPERM;
shp = shm_lock(shmid); if(shp==NULL) return -EINVAL; err = shm_checkid(shp,shmid); if(err) goto out_unlock; if(cmd==SHM_LOCK) { shmem_lock(shp->shm_file, 1); shp->shm_flags |= SHM_LOCKED; } else { shmem_lock(shp->shm_file, 0); shp->shm_flags &= ~SHM_LOCKED; } shm_unlock(shmid); return err; } case IPC_RMID: { /* * We cannot simply remove the file. The SVID states * that the block remains until the last person * detaches from it, then is deleted. A shmat() on * an RMID segment is legal in older Linux and if * we change it apps break... * * Instead we set a destroyed flag, and then blow * the name away when the usage hits zero. */ down(&shm_ids.sem); shp = shm_lock(shmid); err = -EINVAL; if (shp == NULL) goto out_up; err = shm_checkid(shp, shmid); if(err) goto out_unlock_up; if (current->euid != shp->shm_perm.uid && current->euid != shp->shm_perm.cuid && !capable(CAP_SYS_ADMIN)) { err=-EPERM; goto out_unlock_up; } if (shp->shm_nattch){ shp->shm_flags |= SHM_DEST; /* Do not find it any more */ shp->shm_perm.key = IPC_PRIVATE; shm_unlock(shmid); } else shm_destroy (shp); up(&shm_ids.sem); return err; }
/* * We cannot rely on the fs check since SYSV IPC does have an * additional creator id... */ shp = shm_lock(shmid); if(shp == NULL) return -EINVAL; err = shm_checkid(shp,shmid); if (err) { shm_unlock(shmid); return err; } if (ipcperms(&shp->shm_perm, acc_mode)) { shm_unlock(shmid); return -EACCES; } file = shp->shm_file; size = file->f_dentry->d_inode->i_size; shp->shm_nattch++; shm_unlock(shmid);
down_write(¤t->mm->mmap_sem); if (addr && !(shmflg & SHM_REMAP)) { user_addr = ERR_PTR(-EINVAL); if (find_vma_intersection(current->mm, addr, addr + size)) goto invalid; /* * If shm segment goes below stack, make sure there is some * space left for the stack to grow (at least 4 pages). */ if (addr < current->mm->start_stack && addr > current->mm->start_stack - size - PAGE_SIZE * 5) goto invalid; }
/* * detach and kill segment if marked destroyed. * The work is done in shm_close. */ asmlinkage long sys_shmdt (char *shmaddr) { struct mm_struct *mm = current->mm; struct vm_area_struct *shmd, *shmdnext; int retval = -EINVAL;
#ifdef CONFIG_PROC_FS static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { off_t pos = 0; off_t begin = 0; int i, len = 0;
down(&shm_ids.sem); len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n");