📄 shm.c
字号:
struct shm_setbuf setbuf; struct shmid_kernel *shp; int err, version; if (cmd < 0 || shmid < 0) return -EINVAL; version = ipc_parse_version(&cmd); switch (cmd) { /* replace with proc interface ? */ case IPC_INFO: { struct shminfo64 shminfo; memset(&shminfo,0,sizeof(shminfo)); shminfo.shmmni = shminfo.shmseg = shm_ctlmni; shminfo.shmmax = shm_ctlmax; shminfo.shmall = shm_ctlall; shminfo.shmmin = SHMMIN; if(copy_shminfo_to_user (buf, &shminfo, version)) return -EFAULT; /* reading a integer is always atomic */ err= shm_ids.max_id; if(err<0) err = 0; return err; } case SHM_INFO: { struct shm_info shm_info; memset(&shm_info,0,sizeof(shm_info)); down(&shm_ids.sem); shm_lockall(); shm_info.used_ids = shm_ids.in_use; shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp); shm_info.shm_tot = shm_tot; shm_info.swap_attempts = 0; shm_info.swap_successes = 0; err = shm_ids.max_id; shm_unlockall(); up(&shm_ids.sem); if(copy_to_user (buf, &shm_info, sizeof(shm_info))) return -EFAULT; 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; } else shm_destroy (shp); /* Unlock */ shm_unlock(shmid); up(&shm_ids.sem); return err; } case IPC_SET: { if(copy_shmid_from_user (&setbuf, buf, version)) return -EFAULT; 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; err=-EPERM; if (current->euid != shp->shm_perm.uid && current->euid != shp->shm_perm.cuid && !capable(CAP_SYS_ADMIN)) { goto out_unlock_up; } shp->shm_perm.uid = setbuf.uid; shp->shm_perm.gid = setbuf.gid; shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO) | (setbuf.mode & S_IRWXUGO); shp->shm_ctim = CURRENT_TIME; break; } default: return -EINVAL; } err = 0;out_unlock_up: shm_unlock(shmid);out_up: up(&shm_ids.sem); return err;out_unlock: shm_unlock(shmid); return err;}/* * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. */asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr){ struct shmid_kernel *shp; unsigned long addr; unsigned long size; struct file * file; int err; unsigned long flags; unsigned long prot; unsigned long o_flags; int acc_mode; void *user_addr; if (shmid < 0) return -EINVAL; if ((addr = (ulong)shmaddr)) { if (addr & (SHMLBA-1)) { if (shmflg & SHM_RND) addr &= ~(SHMLBA-1); /* round down */ else return -EINVAL; } flags = MAP_SHARED | MAP_FIXED; } else { if ((shmflg & SHM_REMAP)) return -EINVAL; flags = MAP_SHARED; } if (shmflg & SHM_RDONLY) { prot = PROT_READ; o_flags = O_RDONLY; acc_mode = S_IRUGO; } else { prot = PROT_READ | PROT_WRITE; o_flags = O_RDWR; acc_mode = S_IRUGO | S_IWUGO; } /* * 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; } user_addr = (void*) do_mmap (file, addr, size, prot, flags, 0);invalid: up_write(¤t->mm->mmap_sem); down (&shm_ids.sem); if(!(shp = shm_lock(shmid))) BUG(); shp->shm_nattch--; if(shp->shm_nattch == 0 && shp->shm_flags & SHM_DEST) shm_destroy (shp); shm_unlock(shmid); up (&shm_ids.sem); *raddr = (unsigned long) user_addr; err = 0; if (IS_ERR(user_addr)) err = PTR_ERR(user_addr); return err;}/* * 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; down_write(&mm->mmap_sem); for (shmd = mm->mmap; shmd; shmd = shmdnext) { shmdnext = shmd->vm_next; if (shmd->vm_ops == &shm_vm_ops && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start); } up_write(&mm->mmap_sem); return 0;}#ifdef CONFIG_PROC_FSstatic 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"); for(i = 0; i <= shm_ids.max_id; i++) { struct shmid_kernel* shp; shp = shm_lock(i); if(shp!=NULL) {#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" char *format; if (sizeof(size_t) <= sizeof(int)) format = SMALL_STRING; else format = BIG_STRING; len += sprintf(buffer + len, format, shp->shm_perm.key, shm_buildid(i, shp->shm_perm.seq), shp->shm_flags, shp->shm_segsz, shp->shm_cprid, shp->shm_lprid, shp->shm_nattch, shp->shm_perm.uid, shp->shm_perm.gid, shp->shm_perm.cuid, shp->shm_perm.cgid, shp->shm_atim, shp->shm_dtim, shp->shm_ctim); shm_unlock(i); pos += len; if(pos < offset) { len = 0; begin = pos; } if(pos > offset + length) goto done; } } *eof = 1;done: up(&shm_ids.sem); *start = buffer + (offset - begin); len -= (offset - begin); if(len > length) len = length; if(len < 0) len = 0; return len;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -