X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=ipc%2Fshm.c;h=11bec626c228c98d5f3e0512f9c6f0dd40f424dc;hb=17a1b5e3748f2d890d24c7eb3b1c11de2e0b9a00;hp=b125b560240ec1ceb204f5ed0ff6f63ba97081d8;hpb=e8148f7588064e45080bf1120883380a2efe5c9b;p=safe%2Fjmp%2Flinux-2.6 diff --git a/ipc/shm.c b/ipc/shm.c index b125b56..11bec62 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -54,7 +55,7 @@ struct shm_file_data { #define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data)) static const struct file_operations shm_file_operations; -static struct vm_operations_struct shm_vm_ops; +static const struct vm_operations_struct shm_vm_ops; #define shm_ids(ns) ((ns)->ids[IPC_SHM_IDS]) @@ -173,7 +174,7 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) shm_unlock(shp); if (!is_file_hugepages(shp->shm_file)) shmem_lock(shp->shm_file, 0, shp->mlock_user); - else + else if (shp->mlock_user) user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size, shp->mlock_user); fput (shp->shm_file); @@ -289,29 +290,29 @@ static unsigned long shm_get_unmapped_area(struct file *file, unsigned long flags) { struct shm_file_data *sfd = shm_file_data(file); - return get_unmapped_area(sfd->file, addr, len, pgoff, flags); -} - -int is_file_shm_hugepages(struct file *file) -{ - int ret = 0; - - if (file->f_op == &shm_file_operations) { - struct shm_file_data *sfd; - sfd = shm_file_data(file); - ret = is_file_hugepages(sfd->file); - } - return ret; + return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, + pgoff, flags); } static const struct file_operations shm_file_operations = { .mmap = shm_mmap, .fsync = shm_fsync, .release = shm_release, +}; + +static const struct file_operations shm_file_operations_huge = { + .mmap = shm_mmap, + .fsync = shm_fsync, + .release = shm_release, .get_unmapped_area = shm_get_unmapped_area, }; -static struct vm_operations_struct shm_vm_ops = { +int is_file_shm_hugepages(struct file *file) +{ + return file->f_op == &shm_file_operations_huge; +} + +static const 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 */ .fault = shm_fault, @@ -340,6 +341,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) struct file * file; char name[13]; int id; + int acctflag = 0; if (size < SHMMIN || size > ns->shm_ctlmax) return -EINVAL; @@ -364,18 +366,19 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) sprintf (name, "SYSV%08x", key); if (shmflg & SHM_HUGETLB) { - /* hugetlb_file_setup takes care of mlock user accounting */ - file = hugetlb_file_setup(name, size); - shp->mlock_user = current_user(); + /* hugetlb_file_setup applies strict accounting */ + if (shmflg & SHM_NORESERVE) + acctflag = VM_NORESERVE; + file = hugetlb_file_setup(name, size, acctflag, + &shp->mlock_user, HUGETLB_SHMFS_INODE); } else { - int acctflag = VM_ACCOUNT; /* * Do not allow no accounting for OVERCOMMIT_NEVER, even * if it's asked for. */ if ((shmflg & SHM_NORESERVE) && sysctl_overcommit_memory != OVERCOMMIT_NEVER) - acctflag = 0; + acctflag = VM_NORESERVE; file = shmem_file_setup(name, size, acctflag); } error = PTR_ERR(file); @@ -407,6 +410,8 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params) return error; no_id: + if (is_file_hugepages(file) && shp->mlock_user) + user_shm_unlock(size, shp->mlock_user); fput(file); no_file: security_shm_free(shp); @@ -440,7 +445,7 @@ static inline int shm_more_checks(struct kern_ipc_perm *ipcp, return 0; } -asmlinkage long sys_shmget (key_t key, size_t size, int shmflg) +SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg) { struct ipc_namespace *ns; struct ipc_ops shm_ops; @@ -551,12 +556,14 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, in_use = shm_ids(ns).in_use; for (total = 0, next_id = 0; total < in_use; next_id++) { + struct kern_ipc_perm *ipc; struct shmid_kernel *shp; struct inode *inode; - shp = idr_find(&shm_ids(ns).ipcs_idr, next_id); - if (shp == NULL) + ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id); + if (ipc == NULL) continue; + shp = container_of(ipc, struct shmid_kernel, shm_perm); inode = shp->shm_file->f_path.dentry->d_inode; @@ -565,11 +572,15 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, struct hstate *h = hstate_file(shp->shm_file); *rss += pages_per_huge_page(h) * mapping->nrpages; } else { +#ifdef CONFIG_SHMEM struct shmem_inode_info *info = SHMEM_I(inode); spin_lock(&info->lock); *rss += inode->i_mapping->nrpages; *swp += info->swapped; spin_unlock(&info->lock); +#else + *rss += inode->i_mapping->nrpages; +#endif } total++; @@ -621,7 +632,7 @@ out_up: return err; } -asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf) +SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf) { struct shmid_kernel *shp; int err, version; @@ -878,9 +889,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) if (!sfd) goto out_put_dentry; - file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); + file = alloc_file(path.mnt, path.dentry, f_mode, + is_file_hugepages(shp->shm_file) ? + &shm_file_operations_huge : + &shm_file_operations); if (!file) goto out_free; + ima_counts_get(file); file->private_data = sfd; file->f_mapping = shp->shm_file->f_mapping; @@ -939,7 +954,7 @@ out_put_dentry: goto out_nattch; } -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) +SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg) { unsigned long ret; long err; @@ -955,13 +970,16 @@ asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) * detach and kill segment if marked destroyed. * The work is done in shm_close. */ -asmlinkage long sys_shmdt(char __user *shmaddr) +SYSCALL_DEFINE1(shmdt, char __user *, shmaddr) { struct mm_struct *mm = current->mm; - struct vm_area_struct *vma, *next; + struct vm_area_struct *vma; unsigned long addr = (unsigned long)shmaddr; - loff_t size = 0; int retval = -EINVAL; +#ifdef CONFIG_MMU + loff_t size = 0; + struct vm_area_struct *next; +#endif if (addr & ~PAGE_MASK) return retval; @@ -990,6 +1008,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr) */ vma = find_vma(mm, addr); +#ifdef CONFIG_MMU while (vma) { next = vma->vm_next; @@ -1034,6 +1053,17 @@ asmlinkage long sys_shmdt(char __user *shmaddr) vma = next; } +#else /* CONFIG_MMU */ + /* under NOMMU conditions, the exact address to be destroyed must be + * given */ + retval = -EINVAL; + if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) { + do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); + retval = 0; + } + +#endif + up_write(&mm->mmap_sem); return retval; }