summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ANDROID_3.4.5/ipc')
-rw-r--r--ANDROID_3.4.5/ipc/Makefile12
-rw-r--r--ANDROID_3.4.5/ipc/compat.c745
-rw-r--r--ANDROID_3.4.5/ipc/compat_mq.c151
-rw-r--r--ANDROID_3.4.5/ipc/ipc_sysctl.c248
-rw-r--r--ANDROID_3.4.5/ipc/ipcns_notifier.c92
-rw-r--r--ANDROID_3.4.5/ipc/mq_sysctl.c115
-rw-r--r--ANDROID_3.4.5/ipc/mqueue.c1302
-rw-r--r--ANDROID_3.4.5/ipc/msg.c944
-rw-r--r--ANDROID_3.4.5/ipc/msgutil.c144
-rw-r--r--ANDROID_3.4.5/ipc/namespace.c179
-rw-r--r--ANDROID_3.4.5/ipc/sem.c1695
-rw-r--r--ANDROID_3.4.5/ipc/shm.c1237
-rw-r--r--ANDROID_3.4.5/ipc/syscall.c99
-rw-r--r--ANDROID_3.4.5/ipc/util.c987
-rw-r--r--ANDROID_3.4.5/ipc/util.h178
15 files changed, 0 insertions, 8128 deletions
diff --git a/ANDROID_3.4.5/ipc/Makefile b/ANDROID_3.4.5/ipc/Makefile
deleted file mode 100644
index 9075e172..00000000
--- a/ANDROID_3.4.5/ipc/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for the linux ipc.
-#
-
-obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
-obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o syscall.o
-obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
-obj_mq-$(CONFIG_COMPAT) += compat_mq.o
-obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
-obj-$(CONFIG_IPC_NS) += namespace.o
-obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
-
diff --git a/ANDROID_3.4.5/ipc/compat.c b/ANDROID_3.4.5/ipc/compat.c
deleted file mode 100644
index a6df704f..00000000
--- a/ANDROID_3.4.5/ipc/compat.c
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * 32 bit compatibility code for System V IPC
- *
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
- * Copyright (C) 2000 VA Linux Co
- * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
- * Copyright (C) 2000 Hewlett-Packard Co.
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 2000 Gerhard Tonn (ton@de.ibm.com)
- * Copyright (C) 2000-2002 Andi Kleen, SuSE Labs (x86-64 port)
- * Copyright (C) 2000 Silicon Graphics, Inc.
- * Copyright (C) 2001 IBM
- * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Copyright (C) 2004 Arnd Bergmann (arnd@arndb.de)
- *
- * This code is collected from the versions for sparc64, mips64, s390x, ia64,
- * ppc64 and x86_64, all of which are based on the original sparc64 version
- * by Jakub Jelinek.
- *
- */
-#include <linux/compat.h>
-#include <linux/errno.h>
-#include <linux/highuid.h>
-#include <linux/init.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/syscalls.h>
-#include <linux/ptrace.h>
-
-#include <linux/mutex.h>
-#include <asm/uaccess.h>
-
-#include "util.h"
-
-struct compat_msgbuf {
- compat_long_t mtype;
- char mtext[1];
-};
-
-struct compat_ipc_perm {
- key_t key;
- __compat_uid_t uid;
- __compat_gid_t gid;
- __compat_uid_t cuid;
- __compat_gid_t cgid;
- compat_mode_t mode;
- unsigned short seq;
-};
-
-struct compat_semid_ds {
- struct compat_ipc_perm sem_perm;
- compat_time_t sem_otime;
- compat_time_t sem_ctime;
- compat_uptr_t sem_base;
- compat_uptr_t sem_pending;
- compat_uptr_t sem_pending_last;
- compat_uptr_t undo;
- unsigned short sem_nsems;
-};
-
-struct compat_msqid_ds {
- struct compat_ipc_perm msg_perm;
- compat_uptr_t msg_first;
- compat_uptr_t msg_last;
- compat_time_t msg_stime;
- compat_time_t msg_rtime;
- compat_time_t msg_ctime;
- compat_ulong_t msg_lcbytes;
- compat_ulong_t msg_lqbytes;
- unsigned short msg_cbytes;
- unsigned short msg_qnum;
- unsigned short msg_qbytes;
- compat_ipc_pid_t msg_lspid;
- compat_ipc_pid_t msg_lrpid;
-};
-
-struct compat_shmid_ds {
- struct compat_ipc_perm shm_perm;
- int shm_segsz;
- compat_time_t shm_atime;
- compat_time_t shm_dtime;
- compat_time_t shm_ctime;
- compat_ipc_pid_t shm_cpid;
- compat_ipc_pid_t shm_lpid;
- unsigned short shm_nattch;
- unsigned short shm_unused;
- compat_uptr_t shm_unused2;
- compat_uptr_t shm_unused3;
-};
-
-struct compat_ipc_kludge {
- compat_uptr_t msgp;
- compat_long_t msgtyp;
-};
-
-struct compat_shminfo64 {
- compat_ulong_t shmmax;
- compat_ulong_t shmmin;
- compat_ulong_t shmmni;
- compat_ulong_t shmseg;
- compat_ulong_t shmall;
- compat_ulong_t __unused1;
- compat_ulong_t __unused2;
- compat_ulong_t __unused3;
- compat_ulong_t __unused4;
-};
-
-struct compat_shm_info {
- compat_int_t used_ids;
- compat_ulong_t shm_tot, shm_rss, shm_swp;
- compat_ulong_t swap_attempts, swap_successes;
-};
-
-extern int sem_ctls[];
-#define sc_semopm (sem_ctls[2])
-
-static inline int compat_ipc_parse_version(int *cmd)
-{
-#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
- int version = *cmd & IPC_64;
-
- /* this is tricky: architectures that have support for the old
- * ipc structures in 64 bit binaries need to have IPC_64 set
- * in cmd, the others need to have it cleared */
-#ifndef ipc_parse_version
- *cmd |= IPC_64;
-#else
- *cmd &= ~IPC_64;
-#endif
- return version;
-#else
- /* With the asm-generic APIs, we always use the 64-bit versions. */
- return IPC_64;
-#endif
-}
-
-static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64,
- struct compat_ipc64_perm __user *up64)
-{
- int err;
-
- err = __get_user(p64->uid, &up64->uid);
- err |= __get_user(p64->gid, &up64->gid);
- err |= __get_user(p64->mode, &up64->mode);
- return err;
-}
-
-static inline int __get_compat_ipc_perm(struct ipc64_perm *p,
- struct compat_ipc_perm __user *up)
-{
- int err;
-
- err = __get_user(p->uid, &up->uid);
- err |= __get_user(p->gid, &up->gid);
- err |= __get_user(p->mode, &up->mode);
- return err;
-}
-
-static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64,
- struct compat_ipc64_perm __user *up64)
-{
- int err;
-
- err = __put_user(p64->key, &up64->key);
- err |= __put_user(p64->uid, &up64->uid);
- err |= __put_user(p64->gid, &up64->gid);
- err |= __put_user(p64->cuid, &up64->cuid);
- err |= __put_user(p64->cgid, &up64->cgid);
- err |= __put_user(p64->mode, &up64->mode);
- err |= __put_user(p64->seq, &up64->seq);
- return err;
-}
-
-static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
- struct compat_ipc_perm __user *up)
-{
- int err;
- __compat_uid_t u;
- __compat_gid_t g;
-
- err = __put_user(p->key, &up->key);
- SET_UID(u, p->uid);
- err |= __put_user(u, &up->uid);
- SET_GID(g, p->gid);
- err |= __put_user(g, &up->gid);
- SET_UID(u, p->cuid);
- err |= __put_user(u, &up->cuid);
- SET_GID(g, p->cgid);
- err |= __put_user(g, &up->cgid);
- err |= __put_user(p->mode, &up->mode);
- err |= __put_user(p->seq, &up->seq);
- return err;
-}
-
-static inline int get_compat_semid64_ds(struct semid64_ds *s64,
- struct compat_semid64_ds __user *up64)
-{
- if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
- return -EFAULT;
- return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
-}
-
-static inline int get_compat_semid_ds(struct semid64_ds *s,
- struct compat_semid_ds __user *up)
-{
- if (!access_ok (VERIFY_READ, up, sizeof(*up)))
- return -EFAULT;
- return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
-}
-
-static inline int put_compat_semid64_ds(struct semid64_ds *s64,
- struct compat_semid64_ds __user *up64)
-{
- int err;
-
- if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
- return -EFAULT;
- err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
- err |= __put_user(s64->sem_otime, &up64->sem_otime);
- err |= __put_user(s64->sem_ctime, &up64->sem_ctime);
- err |= __put_user(s64->sem_nsems, &up64->sem_nsems);
- return err;
-}
-
-static inline int put_compat_semid_ds(struct semid64_ds *s,
- struct compat_semid_ds __user *up)
-{
- int err;
-
- if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
- return -EFAULT;
- err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
- err |= __put_user(s->sem_otime, &up->sem_otime);
- err |= __put_user(s->sem_ctime, &up->sem_ctime);
- err |= __put_user(s->sem_nsems, &up->sem_nsems);
- return err;
-}
-
-static long do_compat_semctl(int first, int second, int third, u32 pad)
-{
- union semun fourth;
- int err, err2;
- struct semid64_ds s64;
- struct semid64_ds __user *up64;
- int version = compat_ipc_parse_version(&third);
-
- memset(&s64, 0, sizeof(s64));
-
- if ((third & (~IPC_64)) == SETVAL)
- fourth.val = (int) pad;
- else
- fourth.__pad = compat_ptr(pad);
- switch (third & (~IPC_64)) {
- case IPC_INFO:
- case IPC_RMID:
- case SEM_INFO:
- case GETVAL:
- case GETPID:
- case GETNCNT:
- case GETZCNT:
- case GETALL:
- case SETVAL:
- case SETALL:
- err = sys_semctl(first, second, third, fourth);
- break;
-
- case IPC_STAT:
- case SEM_STAT:
- up64 = compat_alloc_user_space(sizeof(s64));
- fourth.__pad = up64;
- err = sys_semctl(first, second, third, fourth);
- if (err < 0)
- break;
- if (copy_from_user(&s64, up64, sizeof(s64)))
- err2 = -EFAULT;
- else if (version == IPC_64)
- err2 = put_compat_semid64_ds(&s64, compat_ptr(pad));
- else
- err2 = put_compat_semid_ds(&s64, compat_ptr(pad));
- if (err2)
- err = -EFAULT;
- break;
-
- case IPC_SET:
- if (version == IPC_64) {
- err = get_compat_semid64_ds(&s64, compat_ptr(pad));
- } else {
- err = get_compat_semid_ds(&s64, compat_ptr(pad));
- }
- up64 = compat_alloc_user_space(sizeof(s64));
- if (copy_to_user(up64, &s64, sizeof(s64)))
- err = -EFAULT;
- if (err)
- break;
-
- fourth.__pad = up64;
- err = sys_semctl(first, second, third, fourth);
- break;
-
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
-long compat_sys_semctl(int first, int second, int third, void __user *uptr)
-{
- u32 pad;
-
- if (!uptr)
- return -EINVAL;
- if (get_user(pad, (u32 __user *) uptr))
- return -EFAULT;
- return do_compat_semctl(first, second, third, pad);
-}
-
-long compat_sys_msgsnd(int first, int second, int third, void __user *uptr)
-{
- struct compat_msgbuf __user *up = uptr;
- long type;
-
- if (first < 0)
- return -EINVAL;
- if (second < 0)
- return -EINVAL;
-
- if (get_user(type, &up->mtype))
- return -EFAULT;
-
- return do_msgsnd(first, type, up->mtext, second, third);
-}
-
-long compat_sys_msgrcv(int first, int second, int msgtyp, int third,
- int version, void __user *uptr)
-{
- struct compat_msgbuf __user *up;
- long type;
- int err;
-
- if (first < 0)
- return -EINVAL;
- if (second < 0)
- return -EINVAL;
-
- if (!version) {
- struct compat_ipc_kludge ipck;
- err = -EINVAL;
- if (!uptr)
- goto out;
- err = -EFAULT;
- if (copy_from_user (&ipck, uptr, sizeof(ipck)))
- goto out;
- uptr = compat_ptr(ipck.msgp);
- msgtyp = ipck.msgtyp;
- }
- up = uptr;
- err = do_msgrcv(first, &type, up->mtext, second, msgtyp, third);
- if (err < 0)
- goto out;
- if (put_user(type, &up->mtype))
- err = -EFAULT;
-out:
- return err;
-}
-#else
-long compat_sys_semctl(int semid, int semnum, int cmd, int arg)
-{
- return do_compat_semctl(semid, semnum, cmd, arg);
-}
-
-long compat_sys_msgsnd(int msqid, struct compat_msgbuf __user *msgp,
- size_t msgsz, int msgflg)
-{
- compat_long_t mtype;
-
- if (get_user(mtype, &msgp->mtype))
- return -EFAULT;
- return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
-}
-
-long compat_sys_msgrcv(int msqid, struct compat_msgbuf __user *msgp,
- size_t msgsz, long msgtyp, int msgflg)
-{
- long err, mtype;
-
- err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
- if (err < 0)
- goto out;
-
- if (put_user(mtype, &msgp->mtype))
- err = -EFAULT;
- out:
- return err;
-}
-#endif
-
-static inline int get_compat_msqid64(struct msqid64_ds *m64,
- struct compat_msqid64_ds __user *up64)
-{
- int err;
-
- if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
- return -EFAULT;
- err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
- err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes);
- return err;
-}
-
-static inline int get_compat_msqid(struct msqid64_ds *m,
- struct compat_msqid_ds __user *up)
-{
- int err;
-
- if (!access_ok(VERIFY_READ, up, sizeof(*up)))
- return -EFAULT;
- err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
- err |= __get_user(m->msg_qbytes, &up->msg_qbytes);
- return err;
-}
-
-static inline int put_compat_msqid64_ds(struct msqid64_ds *m64,
- struct compat_msqid64_ds __user *up64)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
- return -EFAULT;
- err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm);
- err |= __put_user(m64->msg_stime, &up64->msg_stime);
- err |= __put_user(m64->msg_rtime, &up64->msg_rtime);
- err |= __put_user(m64->msg_ctime, &up64->msg_ctime);
- err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes);
- err |= __put_user(m64->msg_qnum, &up64->msg_qnum);
- err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes);
- err |= __put_user(m64->msg_lspid, &up64->msg_lspid);
- err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid);
- return err;
-}
-
-static inline int put_compat_msqid_ds(struct msqid64_ds *m,
- struct compat_msqid_ds __user *up)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
- return -EFAULT;
- err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm);
- err |= __put_user(m->msg_stime, &up->msg_stime);
- err |= __put_user(m->msg_rtime, &up->msg_rtime);
- err |= __put_user(m->msg_ctime, &up->msg_ctime);
- err |= __put_user(m->msg_cbytes, &up->msg_cbytes);
- err |= __put_user(m->msg_qnum, &up->msg_qnum);
- err |= __put_user(m->msg_qbytes, &up->msg_qbytes);
- err |= __put_user(m->msg_lspid, &up->msg_lspid);
- err |= __put_user(m->msg_lrpid, &up->msg_lrpid);
- return err;
-}
-
-long compat_sys_msgctl(int first, int second, void __user *uptr)
-{
- int err, err2;
- struct msqid64_ds m64;
- int version = compat_ipc_parse_version(&second);
- void __user *p;
-
- memset(&m64, 0, sizeof(m64));
-
- switch (second & (~IPC_64)) {
- case IPC_INFO:
- case IPC_RMID:
- case MSG_INFO:
- err = sys_msgctl(first, second, uptr);
- break;
-
- case IPC_SET:
- if (version == IPC_64) {
- err = get_compat_msqid64(&m64, uptr);
- } else {
- err = get_compat_msqid(&m64, uptr);
- }
- if (err)
- break;
- p = compat_alloc_user_space(sizeof(m64));
- if (copy_to_user(p, &m64, sizeof(m64)))
- err = -EFAULT;
- else
- err = sys_msgctl(first, second, p);
- break;
-
- case IPC_STAT:
- case MSG_STAT:
- p = compat_alloc_user_space(sizeof(m64));
- err = sys_msgctl(first, second, p);
- if (err < 0)
- break;
- if (copy_from_user(&m64, p, sizeof(m64)))
- err2 = -EFAULT;
- else if (version == IPC_64)
- err2 = put_compat_msqid64_ds(&m64, uptr);
- else
- err2 = put_compat_msqid_ds(&m64, uptr);
- if (err2)
- err = -EFAULT;
- break;
-
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-#ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC
-long compat_sys_shmat(int first, int second, compat_uptr_t third, int version,
- void __user *uptr)
-{
- int err;
- unsigned long raddr;
- compat_ulong_t __user *uaddr;
-
- if (version == 1)
- return -EINVAL;
- err = do_shmat(first, uptr, second, &raddr);
- if (err < 0)
- return err;
- uaddr = compat_ptr(third);
- return put_user(raddr, uaddr);
-}
-#else
-long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg)
-{
- unsigned long ret;
- long err;
-
- err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret);
- if (err)
- return err;
- force_successful_syscall_return();
- return (long)ret;
-}
-#endif
-
-static inline int get_compat_shmid64_ds(struct shmid64_ds *s64,
- struct compat_shmid64_ds __user *up64)
-{
- if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
- return -EFAULT;
- return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
-}
-
-static inline int get_compat_shmid_ds(struct shmid64_ds *s,
- struct compat_shmid_ds __user *up)
-{
- if (!access_ok(VERIFY_READ, up, sizeof(*up)))
- return -EFAULT;
- return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
-}
-
-static inline int put_compat_shmid64_ds(struct shmid64_ds *s64,
- struct compat_shmid64_ds __user *up64)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
- return -EFAULT;
- err = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm);
- err |= __put_user(s64->shm_atime, &up64->shm_atime);
- err |= __put_user(s64->shm_dtime, &up64->shm_dtime);
- err |= __put_user(s64->shm_ctime, &up64->shm_ctime);
- err |= __put_user(s64->shm_segsz, &up64->shm_segsz);
- err |= __put_user(s64->shm_nattch, &up64->shm_nattch);
- err |= __put_user(s64->shm_cpid, &up64->shm_cpid);
- err |= __put_user(s64->shm_lpid, &up64->shm_lpid);
- return err;
-}
-
-static inline int put_compat_shmid_ds(struct shmid64_ds *s,
- struct compat_shmid_ds __user *up)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
- return -EFAULT;
- err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm);
- err |= __put_user(s->shm_atime, &up->shm_atime);
- err |= __put_user(s->shm_dtime, &up->shm_dtime);
- err |= __put_user(s->shm_ctime, &up->shm_ctime);
- err |= __put_user(s->shm_segsz, &up->shm_segsz);
- err |= __put_user(s->shm_nattch, &up->shm_nattch);
- err |= __put_user(s->shm_cpid, &up->shm_cpid);
- err |= __put_user(s->shm_lpid, &up->shm_lpid);
- return err;
-}
-
-static inline int put_compat_shminfo64(struct shminfo64 *smi,
- struct compat_shminfo64 __user *up64)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
- return -EFAULT;
- if (smi->shmmax > INT_MAX)
- smi->shmmax = INT_MAX;
- err = __put_user(smi->shmmax, &up64->shmmax);
- err |= __put_user(smi->shmmin, &up64->shmmin);
- err |= __put_user(smi->shmmni, &up64->shmmni);
- err |= __put_user(smi->shmseg, &up64->shmseg);
- err |= __put_user(smi->shmall, &up64->shmall);
- return err;
-}
-
-static inline int put_compat_shminfo(struct shminfo64 *smi,
- struct shminfo __user *up)
-{
- int err;
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
- return -EFAULT;
- if (smi->shmmax > INT_MAX)
- smi->shmmax = INT_MAX;
- err = __put_user(smi->shmmax, &up->shmmax);
- err |= __put_user(smi->shmmin, &up->shmmin);
- err |= __put_user(smi->shmmni, &up->shmmni);
- err |= __put_user(smi->shmseg, &up->shmseg);
- err |= __put_user(smi->shmall, &up->shmall);
- return err;
-}
-
-static inline int put_compat_shm_info(struct shm_info __user *ip,
- struct compat_shm_info __user *uip)
-{
- int err;
- struct shm_info si;
-
- if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) ||
- copy_from_user(&si, ip, sizeof(si)))
- return -EFAULT;
- err = __put_user(si.used_ids, &uip->used_ids);
- err |= __put_user(si.shm_tot, &uip->shm_tot);
- err |= __put_user(si.shm_rss, &uip->shm_rss);
- err |= __put_user(si.shm_swp, &uip->shm_swp);
- err |= __put_user(si.swap_attempts, &uip->swap_attempts);
- err |= __put_user(si.swap_successes, &uip->swap_successes);
- return err;
-}
-
-long compat_sys_shmctl(int first, int second, void __user *uptr)
-{
- void __user *p;
- struct shmid64_ds s64;
- struct shminfo64 smi;
- int err, err2;
- int version = compat_ipc_parse_version(&second);
-
- memset(&s64, 0, sizeof(s64));
-
- switch (second & (~IPC_64)) {
- case IPC_RMID:
- case SHM_LOCK:
- case SHM_UNLOCK:
- err = sys_shmctl(first, second, uptr);
- break;
-
- case IPC_INFO:
- p = compat_alloc_user_space(sizeof(smi));
- err = sys_shmctl(first, second, p);
- if (err < 0)
- break;
- if (copy_from_user(&smi, p, sizeof(smi)))
- err2 = -EFAULT;
- else if (version == IPC_64)
- err2 = put_compat_shminfo64(&smi, uptr);
- else
- err2 = put_compat_shminfo(&smi, uptr);
- if (err2)
- err = -EFAULT;
- break;
-
-
- case IPC_SET:
- if (version == IPC_64) {
- err = get_compat_shmid64_ds(&s64, uptr);
- } else {
- err = get_compat_shmid_ds(&s64, uptr);
- }
- if (err)
- break;
- p = compat_alloc_user_space(sizeof(s64));
- if (copy_to_user(p, &s64, sizeof(s64)))
- err = -EFAULT;
- else
- err = sys_shmctl(first, second, p);
- break;
-
- case IPC_STAT:
- case SHM_STAT:
- p = compat_alloc_user_space(sizeof(s64));
- err = sys_shmctl(first, second, p);
- if (err < 0)
- break;
- if (copy_from_user(&s64, p, sizeof(s64)))
- err2 = -EFAULT;
- else if (version == IPC_64)
- err2 = put_compat_shmid64_ds(&s64, uptr);
- else
- err2 = put_compat_shmid_ds(&s64, uptr);
- if (err2)
- err = -EFAULT;
- break;
-
- case SHM_INFO:
- p = compat_alloc_user_space(sizeof(struct shm_info));
- err = sys_shmctl(first, second, p);
- if (err < 0)
- break;
- err2 = put_compat_shm_info(p, uptr);
- if (err2)
- err = -EFAULT;
- break;
-
- default:
- err = -EINVAL;
- break;
- }
- return err;
-}
-
-long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
- unsigned nsops, const struct compat_timespec __user *timeout)
-{
- struct timespec __user *ts64 = NULL;
- if (timeout) {
- struct timespec ts;
- ts64 = compat_alloc_user_space(sizeof(*ts64));
- if (get_compat_timespec(&ts, timeout))
- return -EFAULT;
- if (copy_to_user(ts64, &ts, sizeof(ts)))
- return -EFAULT;
- }
- return sys_semtimedop(semid, tsems, nsops, ts64);
-}
diff --git a/ANDROID_3.4.5/ipc/compat_mq.c b/ANDROID_3.4.5/ipc/compat_mq.c
deleted file mode 100644
index 380ea4fe..00000000
--- a/ANDROID_3.4.5/ipc/compat_mq.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * ipc/compat_mq.c
- * 32 bit emulation for POSIX message queue system calls
- *
- * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author: Arnd Bergmann <arnd@arndb.de>
- */
-
-#include <linux/compat.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/mqueue.h>
-#include <linux/syscalls.h>
-
-#include <asm/uaccess.h>
-
-struct compat_mq_attr {
- compat_long_t mq_flags; /* message queue flags */
- compat_long_t mq_maxmsg; /* maximum number of messages */
- compat_long_t mq_msgsize; /* maximum message size */
- compat_long_t mq_curmsgs; /* number of messages currently queued */
- compat_long_t __reserved[4]; /* ignored for input, zeroed for output */
-};
-
-static inline int get_compat_mq_attr(struct mq_attr *attr,
- const struct compat_mq_attr __user *uattr)
-{
- if (!access_ok(VERIFY_READ, uattr, sizeof *uattr))
- return -EFAULT;
-
- return __get_user(attr->mq_flags, &uattr->mq_flags)
- | __get_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
- | __get_user(attr->mq_msgsize, &uattr->mq_msgsize)
- | __get_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
-}
-
-static inline int put_compat_mq_attr(const struct mq_attr *attr,
- struct compat_mq_attr __user *uattr)
-{
- if (clear_user(uattr, sizeof *uattr))
- return -EFAULT;
-
- return __put_user(attr->mq_flags, &uattr->mq_flags)
- | __put_user(attr->mq_maxmsg, &uattr->mq_maxmsg)
- | __put_user(attr->mq_msgsize, &uattr->mq_msgsize)
- | __put_user(attr->mq_curmsgs, &uattr->mq_curmsgs);
-}
-
-asmlinkage long compat_sys_mq_open(const char __user *u_name,
- int oflag, compat_mode_t mode,
- struct compat_mq_attr __user *u_attr)
-{
- void __user *p = NULL;
- if (u_attr && oflag & O_CREAT) {
- struct mq_attr attr;
-
- memset(&attr, 0, sizeof(attr));
-
- p = compat_alloc_user_space(sizeof(attr));
- if (get_compat_mq_attr(&attr, u_attr) ||
- copy_to_user(p, &attr, sizeof(attr)))
- return -EFAULT;
- }
- return sys_mq_open(u_name, oflag, mode, p);
-}
-
-static int compat_prepare_timeout(struct timespec __user * *p,
- const struct compat_timespec __user *u)
-{
- struct timespec ts;
- if (!u) {
- *p = NULL;
- return 0;
- }
- *p = compat_alloc_user_space(sizeof(ts));
- if (get_compat_timespec(&ts, u) || copy_to_user(*p, &ts, sizeof(ts)))
- return -EFAULT;
- return 0;
-}
-
-asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes,
- const char __user *u_msg_ptr,
- size_t msg_len, unsigned int msg_prio,
- const struct compat_timespec __user *u_abs_timeout)
-{
- struct timespec __user *u_ts;
-
- if (compat_prepare_timeout(&u_ts, u_abs_timeout))
- return -EFAULT;
-
- return sys_mq_timedsend(mqdes, u_msg_ptr, msg_len,
- msg_prio, u_ts);
-}
-
-asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes,
- char __user *u_msg_ptr,
- size_t msg_len, unsigned int __user *u_msg_prio,
- const struct compat_timespec __user *u_abs_timeout)
-{
- struct timespec __user *u_ts;
- if (compat_prepare_timeout(&u_ts, u_abs_timeout))
- return -EFAULT;
-
- return sys_mq_timedreceive(mqdes, u_msg_ptr, msg_len,
- u_msg_prio, u_ts);
-}
-
-asmlinkage long compat_sys_mq_notify(mqd_t mqdes,
- const struct compat_sigevent __user *u_notification)
-{
- struct sigevent __user *p = NULL;
- if (u_notification) {
- struct sigevent n;
- p = compat_alloc_user_space(sizeof(*p));
- if (get_compat_sigevent(&n, u_notification))
- return -EFAULT;
- if (n.sigev_notify == SIGEV_THREAD)
- n.sigev_value.sival_ptr = compat_ptr(n.sigev_value.sival_int);
- if (copy_to_user(p, &n, sizeof(*p)))
- return -EFAULT;
- }
- return sys_mq_notify(mqdes, p);
-}
-
-asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
- const struct compat_mq_attr __user *u_mqstat,
- struct compat_mq_attr __user *u_omqstat)
-{
- struct mq_attr mqstat;
- struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
- long ret;
-
- memset(&mqstat, 0, sizeof(mqstat));
-
- if (u_mqstat) {
- if (get_compat_mq_attr(&mqstat, u_mqstat) ||
- copy_to_user(p, &mqstat, sizeof(mqstat)))
- return -EFAULT;
- }
- ret = sys_mq_getsetattr(mqdes,
- u_mqstat ? p : NULL,
- u_omqstat ? p + 1 : NULL);
- if (ret)
- return ret;
- if (u_omqstat) {
- if (copy_from_user(&mqstat, p + 1, sizeof(mqstat)) ||
- put_compat_mq_attr(&mqstat, u_omqstat))
- return -EFAULT;
- }
- return 0;
-}
diff --git a/ANDROID_3.4.5/ipc/ipc_sysctl.c b/ANDROID_3.4.5/ipc/ipc_sysctl.c
deleted file mode 100644
index 00fba2ba..00000000
--- a/ANDROID_3.4.5/ipc/ipc_sysctl.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2007
- *
- * Author: Eric Biederman <ebiederm@xmision.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- */
-
-#include <linux/module.h>
-#include <linux/ipc.h>
-#include <linux/nsproxy.h>
-#include <linux/sysctl.h>
-#include <linux/uaccess.h>
-#include <linux/ipc_namespace.h>
-#include <linux/msg.h>
-#include "util.h"
-
-static void *get_ipc(ctl_table *table)
-{
- char *which = table->data;
- struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
- which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
- return which;
-}
-
-#ifdef CONFIG_PROC_SYSCTL
-static int proc_ipc_dointvec(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table ipc_table;
-
- memcpy(&ipc_table, table, sizeof(ipc_table));
- ipc_table.data = get_ipc(table);
-
- return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
-}
-
-static int proc_ipc_dointvec_minmax(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table ipc_table;
-
- memcpy(&ipc_table, table, sizeof(ipc_table));
- ipc_table.data = get_ipc(table);
-
- return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
-}
-
-static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ipc_namespace *ns = current->nsproxy->ipc_ns;
- int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
-
- if (err < 0)
- return err;
- if (ns->shm_rmid_forced)
- shm_destroy_orphaned(ns);
- return err;
-}
-
-static int proc_ipc_callback_dointvec(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table ipc_table;
- size_t lenp_bef = *lenp;
- int rc;
-
- memcpy(&ipc_table, table, sizeof(ipc_table));
- ipc_table.data = get_ipc(table);
-
- rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
-
- if (write && !rc && lenp_bef == *lenp)
- /*
- * Tunable has successfully been changed by hand. Disable its
- * automatic adjustment. This simply requires unregistering
- * the notifiers that trigger recalculation.
- */
- unregister_ipcns_notifier(current->nsproxy->ipc_ns);
-
- return rc;
-}
-
-static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table ipc_table;
- memcpy(&ipc_table, table, sizeof(ipc_table));
- ipc_table.data = get_ipc(table);
-
- return proc_doulongvec_minmax(&ipc_table, write, buffer,
- lenp, ppos);
-}
-
-/*
- * Routine that is called when the file "auto_msgmni" has successfully been
- * written.
- * Two values are allowed:
- * 0: unregister msgmni's callback routine from the ipc namespace notifier
- * chain. This means that msgmni won't be recomputed anymore upon memory
- * add/remove or ipc namespace creation/removal.
- * 1: register back the callback routine.
- */
-static void ipc_auto_callback(int val)
-{
- if (!val)
- unregister_ipcns_notifier(current->nsproxy->ipc_ns);
- else {
- /*
- * Re-enable automatic recomputing only if not already
- * enabled.
- */
- recompute_msgmni(current->nsproxy->ipc_ns);
- cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
- }
-}
-
-static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table ipc_table;
- size_t lenp_bef = *lenp;
- int oldval;
- int rc;
-
- memcpy(&ipc_table, table, sizeof(ipc_table));
- ipc_table.data = get_ipc(table);
- oldval = *((int *)(ipc_table.data));
-
- rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
-
- if (write && !rc && lenp_bef == *lenp) {
- int newval = *((int *)(ipc_table.data));
- /*
- * The file "auto_msgmni" has correctly been set.
- * React by (un)registering the corresponding tunable, if the
- * value has changed.
- */
- if (newval != oldval)
- ipc_auto_callback(newval);
- }
-
- return rc;
-}
-
-#else
-#define proc_ipc_doulongvec_minmax NULL
-#define proc_ipc_dointvec NULL
-#define proc_ipc_dointvec_minmax NULL
-#define proc_ipc_dointvec_minmax_orphans NULL
-#define proc_ipc_callback_dointvec NULL
-#define proc_ipcauto_dointvec_minmax NULL
-#endif
-
-static int zero;
-static int one = 1;
-
-static struct ctl_table ipc_kern_table[] = {
- {
- .procname = "shmmax",
- .data = &init_ipc_ns.shm_ctlmax,
- .maxlen = sizeof (init_ipc_ns.shm_ctlmax),
- .mode = 0644,
- .proc_handler = proc_ipc_doulongvec_minmax,
- },
- {
- .procname = "shmall",
- .data = &init_ipc_ns.shm_ctlall,
- .maxlen = sizeof (init_ipc_ns.shm_ctlall),
- .mode = 0644,
- .proc_handler = proc_ipc_doulongvec_minmax,
- },
- {
- .procname = "shmmni",
- .data = &init_ipc_ns.shm_ctlmni,
- .maxlen = sizeof (init_ipc_ns.shm_ctlmni),
- .mode = 0644,
- .proc_handler = proc_ipc_dointvec,
- },
- {
- .procname = "shm_rmid_forced",
- .data = &init_ipc_ns.shm_rmid_forced,
- .maxlen = sizeof(init_ipc_ns.shm_rmid_forced),
- .mode = 0644,
- .proc_handler = proc_ipc_dointvec_minmax_orphans,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {
- .procname = "msgmax",
- .data = &init_ipc_ns.msg_ctlmax,
- .maxlen = sizeof (init_ipc_ns.msg_ctlmax),
- .mode = 0644,
- .proc_handler = proc_ipc_dointvec,
- },
- {
- .procname = "msgmni",
- .data = &init_ipc_ns.msg_ctlmni,
- .maxlen = sizeof (init_ipc_ns.msg_ctlmni),
- .mode = 0644,
- .proc_handler = proc_ipc_callback_dointvec,
- },
- {
- .procname = "msgmnb",
- .data = &init_ipc_ns.msg_ctlmnb,
- .maxlen = sizeof (init_ipc_ns.msg_ctlmnb),
- .mode = 0644,
- .proc_handler = proc_ipc_dointvec,
- },
- {
- .procname = "sem",
- .data = &init_ipc_ns.sem_ctls,
- .maxlen = 4*sizeof (int),
- .mode = 0644,
- .proc_handler = proc_ipc_dointvec,
- },
- {
- .procname = "auto_msgmni",
- .data = &init_ipc_ns.auto_msgmni,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_ipcauto_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {}
-};
-
-static struct ctl_table ipc_root_table[] = {
- {
- .procname = "kernel",
- .mode = 0555,
- .child = ipc_kern_table,
- },
- {}
-};
-
-static int __init ipc_sysctl_init(void)
-{
- register_sysctl_table(ipc_root_table);
- return 0;
-}
-
-__initcall(ipc_sysctl_init);
diff --git a/ANDROID_3.4.5/ipc/ipcns_notifier.c b/ANDROID_3.4.5/ipc/ipcns_notifier.c
deleted file mode 100644
index b9b31a4f..00000000
--- a/ANDROID_3.4.5/ipc/ipcns_notifier.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * linux/ipc/ipcns_notifier.c
- * Copyright (C) 2007 BULL SA. Nadia Derbey
- *
- * Notification mechanism for ipc namespaces:
- * The callback routine registered in the memory chain invokes the ipcns
- * notifier chain with the IPCNS_MEMCHANGED event.
- * Each callback routine registered in the ipcns namespace recomputes msgmni
- * for the owning namespace.
- */
-
-#include <linux/msg.h>
-#include <linux/rcupdate.h>
-#include <linux/notifier.h>
-#include <linux/nsproxy.h>
-#include <linux/ipc_namespace.h>
-
-#include "util.h"
-
-
-
-static BLOCKING_NOTIFIER_HEAD(ipcns_chain);
-
-
-static int ipcns_callback(struct notifier_block *self,
- unsigned long action, void *arg)
-{
- struct ipc_namespace *ns;
-
- switch (action) {
- case IPCNS_MEMCHANGED: /* amount of lowmem has changed */
- case IPCNS_CREATED:
- case IPCNS_REMOVED:
- /*
- * It's time to recompute msgmni
- */
- ns = container_of(self, struct ipc_namespace, ipcns_nb);
- /*
- * No need to get a reference on the ns: the 1st job of
- * free_ipc_ns() is to unregister the callback routine.
- * blocking_notifier_chain_unregister takes the wr lock to do
- * it.
- * When this callback routine is called the rd lock is held by
- * blocking_notifier_call_chain.
- * So the ipc ns cannot be freed while we are here.
- */
- recompute_msgmni(ns);
- break;
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-int register_ipcns_notifier(struct ipc_namespace *ns)
-{
- int rc;
-
- memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
- ns->ipcns_nb.notifier_call = ipcns_callback;
- ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
- rc = blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
- if (!rc)
- ns->auto_msgmni = 1;
- return rc;
-}
-
-int cond_register_ipcns_notifier(struct ipc_namespace *ns)
-{
- int rc;
-
- memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
- ns->ipcns_nb.notifier_call = ipcns_callback;
- ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
- rc = blocking_notifier_chain_cond_register(&ipcns_chain,
- &ns->ipcns_nb);
- if (!rc)
- ns->auto_msgmni = 1;
- return rc;
-}
-
-void unregister_ipcns_notifier(struct ipc_namespace *ns)
-{
- blocking_notifier_chain_unregister(&ipcns_chain, &ns->ipcns_nb);
- ns->auto_msgmni = 0;
-}
-
-int ipcns_notify(unsigned long val)
-{
- return blocking_notifier_call_chain(&ipcns_chain, val, NULL);
-}
diff --git a/ANDROID_3.4.5/ipc/mq_sysctl.c b/ANDROID_3.4.5/ipc/mq_sysctl.c
deleted file mode 100644
index 0c09366b..00000000
--- a/ANDROID_3.4.5/ipc/mq_sysctl.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2007 IBM Corporation
- *
- * Author: Cedric Le Goater <clg@fr.ibm.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2 of the
- * License.
- */
-
-#include <linux/nsproxy.h>
-#include <linux/ipc_namespace.h>
-#include <linux/sysctl.h>
-
-/*
- * Define the ranges various user-specified maximum values can
- * be set to.
- */
-#define MIN_MSGMAX 1 /* min value for msg_max */
-#define MAX_MSGMAX HARD_MSGMAX /* max value for msg_max */
-#define MIN_MSGSIZEMAX 128 /* min value for msgsize_max */
-#define MAX_MSGSIZEMAX (8192*128) /* max value for msgsize_max */
-
-#ifdef CONFIG_PROC_SYSCTL
-static void *get_mq(ctl_table *table)
-{
- char *which = table->data;
- struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
- which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
- return which;
-}
-
-static int proc_mq_dointvec(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table mq_table;
- memcpy(&mq_table, table, sizeof(mq_table));
- mq_table.data = get_mq(table);
-
- return proc_dointvec(&mq_table, write, buffer, lenp, ppos);
-}
-
-static int proc_mq_dointvec_minmax(ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- struct ctl_table mq_table;
- memcpy(&mq_table, table, sizeof(mq_table));
- mq_table.data = get_mq(table);
-
- return proc_dointvec_minmax(&mq_table, write, buffer,
- lenp, ppos);
-}
-#else
-#define proc_mq_dointvec NULL
-#define proc_mq_dointvec_minmax NULL
-#endif
-
-static int msg_max_limit_min = MIN_MSGMAX;
-static int msg_max_limit_max = MAX_MSGMAX;
-
-static int msg_maxsize_limit_min = MIN_MSGSIZEMAX;
-static int msg_maxsize_limit_max = MAX_MSGSIZEMAX;
-
-static ctl_table mq_sysctls[] = {
- {
- .procname = "queues_max",
- .data = &init_ipc_ns.mq_queues_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_mq_dointvec,
- },
- {
- .procname = "msg_max",
- .data = &init_ipc_ns.mq_msg_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_mq_dointvec_minmax,
- .extra1 = &msg_max_limit_min,
- .extra2 = &msg_max_limit_max,
- },
- {
- .procname = "msgsize_max",
- .data = &init_ipc_ns.mq_msgsize_max,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_mq_dointvec_minmax,
- .extra1 = &msg_maxsize_limit_min,
- .extra2 = &msg_maxsize_limit_max,
- },
- {}
-};
-
-static ctl_table mq_sysctl_dir[] = {
- {
- .procname = "mqueue",
- .mode = 0555,
- .child = mq_sysctls,
- },
- {}
-};
-
-static ctl_table mq_sysctl_root[] = {
- {
- .procname = "fs",
- .mode = 0555,
- .child = mq_sysctl_dir,
- },
- {}
-};
-
-struct ctl_table_header *mq_register_sysctl_table(void)
-{
- return register_sysctl_table(mq_sysctl_root);
-}
diff --git a/ANDROID_3.4.5/ipc/mqueue.c b/ANDROID_3.4.5/ipc/mqueue.c
deleted file mode 100644
index 28bd64dd..00000000
--- a/ANDROID_3.4.5/ipc/mqueue.c
+++ /dev/null
@@ -1,1302 +0,0 @@
-/*
- * POSIX message queues filesystem for Linux.
- *
- * Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi@mat.uni.torun.pl)
- * Michal Wronski (michal.wronski@gmail.com)
- *
- * Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com)
- * Lockless receive & send, fd based notify:
- * Manfred Spraul (manfred@colorfullife.com)
- *
- * Audit: George Wilson (ltcgcw@us.ibm.com)
- *
- * This file is released under the GPL.
- */
-
-#include <linux/capability.h>
-#include <linux/init.h>
-#include <linux/pagemap.h>
-#include <linux/file.h>
-#include <linux/mount.h>
-#include <linux/namei.h>
-#include <linux/sysctl.h>
-#include <linux/poll.h>
-#include <linux/mqueue.h>
-#include <linux/msg.h>
-#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <linux/syscalls.h>
-#include <linux/audit.h>
-#include <linux/signal.h>
-#include <linux/mutex.h>
-#include <linux/nsproxy.h>
-#include <linux/pid.h>
-#include <linux/ipc_namespace.h>
-#include <linux/user_namespace.h>
-#include <linux/slab.h>
-
-#include <net/sock.h>
-#include "util.h"
-
-#define MQUEUE_MAGIC 0x19800202
-#define DIRENT_SIZE 20
-#define FILENT_SIZE 80
-
-#define SEND 0
-#define RECV 1
-
-#define STATE_NONE 0
-#define STATE_PENDING 1
-#define STATE_READY 2
-
-struct ext_wait_queue { /* queue of sleeping tasks */
- struct task_struct *task;
- struct list_head list;
- struct msg_msg *msg; /* ptr of loaded message */
- int state; /* one of STATE_* values */
-};
-
-struct mqueue_inode_info {
- spinlock_t lock;
- struct inode vfs_inode;
- wait_queue_head_t wait_q;
-
- struct msg_msg **messages;
- struct mq_attr attr;
-
- struct sigevent notify;
- struct pid* notify_owner;
- struct user_struct *user; /* user who created, for accounting */
- struct sock *notify_sock;
- struct sk_buff *notify_cookie;
-
- /* for tasks waiting for free space and messages, respectively */
- struct ext_wait_queue e_wait_q[2];
-
- unsigned long qsize; /* size of queue in memory (sum of all msgs) */
-};
-
-static const struct inode_operations mqueue_dir_inode_operations;
-static const struct file_operations mqueue_file_operations;
-static const struct super_operations mqueue_super_ops;
-static void remove_notification(struct mqueue_inode_info *info);
-
-static struct kmem_cache *mqueue_inode_cachep;
-
-static struct ctl_table_header * mq_sysctl_table;
-
-static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
-{
- return container_of(inode, struct mqueue_inode_info, vfs_inode);
-}
-
-/*
- * This routine should be called with the mq_lock held.
- */
-static inline struct ipc_namespace *__get_ns_from_inode(struct inode *inode)
-{
- return get_ipc_ns(inode->i_sb->s_fs_info);
-}
-
-static struct ipc_namespace *get_ns_from_inode(struct inode *inode)
-{
- struct ipc_namespace *ns;
-
- spin_lock(&mq_lock);
- ns = __get_ns_from_inode(inode);
- spin_unlock(&mq_lock);
- return ns;
-}
-
-static struct inode *mqueue_get_inode(struct super_block *sb,
- struct ipc_namespace *ipc_ns, umode_t mode,
- struct mq_attr *attr)
-{
- struct user_struct *u = current_user();
- struct inode *inode;
- int ret = -ENOMEM;
-
- inode = new_inode(sb);
- if (!inode)
- goto err;
-
- inode->i_ino = get_next_ino();
- inode->i_mode = mode;
- inode->i_uid = current_fsuid();
- inode->i_gid = current_fsgid();
- inode->i_mtime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
-
- if (S_ISREG(mode)) {
- struct mqueue_inode_info *info;
- unsigned long mq_bytes, mq_msg_tblsz;
-
- inode->i_fop = &mqueue_file_operations;
- inode->i_size = FILENT_SIZE;
- /* mqueue specific info */
- info = MQUEUE_I(inode);
- spin_lock_init(&info->lock);
- init_waitqueue_head(&info->wait_q);
- INIT_LIST_HEAD(&info->e_wait_q[0].list);
- INIT_LIST_HEAD(&info->e_wait_q[1].list);
- info->notify_owner = NULL;
- info->qsize = 0;
- info->user = NULL; /* set when all is ok */
- memset(&info->attr, 0, sizeof(info->attr));
- info->attr.mq_maxmsg = ipc_ns->mq_msg_max;
- info->attr.mq_msgsize = ipc_ns->mq_msgsize_max;
- if (attr) {
- info->attr.mq_maxmsg = attr->mq_maxmsg;
- info->attr.mq_msgsize = attr->mq_msgsize;
- }
- mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
- info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
- if (!info->messages)
- goto out_inode;
-
- mq_bytes = (mq_msg_tblsz +
- (info->attr.mq_maxmsg * info->attr.mq_msgsize));
-
- spin_lock(&mq_lock);
- if (u->mq_bytes + mq_bytes < u->mq_bytes ||
- u->mq_bytes + mq_bytes > rlimit(RLIMIT_MSGQUEUE)) {
- spin_unlock(&mq_lock);
- /* mqueue_evict_inode() releases info->messages */
- ret = -EMFILE;
- goto out_inode;
- }
- u->mq_bytes += mq_bytes;
- spin_unlock(&mq_lock);
-
- /* all is ok */
- info->user = get_uid(u);
- } else if (S_ISDIR(mode)) {
- inc_nlink(inode);
- /* Some things misbehave if size == 0 on a directory */
- inode->i_size = 2 * DIRENT_SIZE;
- inode->i_op = &mqueue_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
- }
-
- return inode;
-out_inode:
- iput(inode);
-err:
- return ERR_PTR(ret);
-}
-
-static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
-{
- struct inode *inode;
- struct ipc_namespace *ns = data;
-
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = MQUEUE_MAGIC;
- sb->s_op = &mqueue_super_ops;
-
- inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL);
- if (IS_ERR(inode))
- return PTR_ERR(inode);
-
- sb->s_root = d_make_root(inode);
- if (!sb->s_root)
- return -ENOMEM;
- return 0;
-}
-
-static struct dentry *mqueue_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data)
-{
- if (!(flags & MS_KERNMOUNT))
- data = current->nsproxy->ipc_ns;
- return mount_ns(fs_type, flags, data, mqueue_fill_super);
-}
-
-static void init_once(void *foo)
-{
- struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
-
- inode_init_once(&p->vfs_inode);
-}
-
-static struct inode *mqueue_alloc_inode(struct super_block *sb)
-{
- struct mqueue_inode_info *ei;
-
- ei = kmem_cache_alloc(mqueue_inode_cachep, GFP_KERNEL);
- if (!ei)
- return NULL;
- return &ei->vfs_inode;
-}
-
-static void mqueue_i_callback(struct rcu_head *head)
-{
- struct inode *inode = container_of(head, struct inode, i_rcu);
- kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode));
-}
-
-static void mqueue_destroy_inode(struct inode *inode)
-{
- call_rcu(&inode->i_rcu, mqueue_i_callback);
-}
-
-static void mqueue_evict_inode(struct inode *inode)
-{
- struct mqueue_inode_info *info;
- struct user_struct *user;
- unsigned long mq_bytes;
- int i;
- struct ipc_namespace *ipc_ns;
-
- end_writeback(inode);
-
- if (S_ISDIR(inode->i_mode))
- return;
-
- ipc_ns = get_ns_from_inode(inode);
- info = MQUEUE_I(inode);
- spin_lock(&info->lock);
- for (i = 0; i < info->attr.mq_curmsgs; i++)
- free_msg(info->messages[i]);
- kfree(info->messages);
- spin_unlock(&info->lock);
-
- /* Total amount of bytes accounted for the mqueue */
- mq_bytes = info->attr.mq_maxmsg * (sizeof(struct msg_msg *)
- + info->attr.mq_msgsize);
- user = info->user;
- if (user) {
- spin_lock(&mq_lock);
- user->mq_bytes -= mq_bytes;
- /*
- * get_ns_from_inode() ensures that the
- * (ipc_ns = sb->s_fs_info) is either a valid ipc_ns
- * to which we now hold a reference, or it is NULL.
- * We can't put it here under mq_lock, though.
- */
- if (ipc_ns)
- ipc_ns->mq_queues_count--;
- spin_unlock(&mq_lock);
- free_uid(user);
- }
- if (ipc_ns)
- put_ipc_ns(ipc_ns);
-}
-
-static int mqueue_create(struct inode *dir, struct dentry *dentry,
- umode_t mode, struct nameidata *nd)
-{
- struct inode *inode;
- struct mq_attr *attr = dentry->d_fsdata;
- int error;
- struct ipc_namespace *ipc_ns;
-
- spin_lock(&mq_lock);
- ipc_ns = __get_ns_from_inode(dir);
- if (!ipc_ns) {
- error = -EACCES;
- goto out_unlock;
- }
- if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max &&
- !capable(CAP_SYS_RESOURCE)) {
- error = -ENOSPC;
- goto out_unlock;
- }
- ipc_ns->mq_queues_count++;
- spin_unlock(&mq_lock);
-
- inode = mqueue_get_inode(dir->i_sb, ipc_ns, mode, attr);
- if (IS_ERR(inode)) {
- error = PTR_ERR(inode);
- spin_lock(&mq_lock);
- ipc_ns->mq_queues_count--;
- goto out_unlock;
- }
-
- put_ipc_ns(ipc_ns);
- dir->i_size += DIRENT_SIZE;
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
-
- d_instantiate(dentry, inode);
- dget(dentry);
- return 0;
-out_unlock:
- spin_unlock(&mq_lock);
- if (ipc_ns)
- put_ipc_ns(ipc_ns);
- return error;
-}
-
-static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
-
- dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
- dir->i_size -= DIRENT_SIZE;
- drop_nlink(inode);
- dput(dentry);
- return 0;
-}
-
-/*
-* This is routine for system read from queue file.
-* To avoid mess with doing here some sort of mq_receive we allow
-* to read only queue size & notification info (the only values
-* that are interesting from user point of view and aren't accessible
-* through std routines)
-*/
-static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
- size_t count, loff_t *off)
-{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
- char buffer[FILENT_SIZE];
- ssize_t ret;
-
- spin_lock(&info->lock);
- snprintf(buffer, sizeof(buffer),
- "QSIZE:%-10lu NOTIFY:%-5d SIGNO:%-5d NOTIFY_PID:%-6d\n",
- info->qsize,
- info->notify_owner ? info->notify.sigev_notify : 0,
- (info->notify_owner &&
- info->notify.sigev_notify == SIGEV_SIGNAL) ?
- info->notify.sigev_signo : 0,
- pid_vnr(info->notify_owner));
- spin_unlock(&info->lock);
- buffer[sizeof(buffer)-1] = '\0';
-
- ret = simple_read_from_buffer(u_data, count, off, buffer,
- strlen(buffer));
- if (ret <= 0)
- return ret;
-
- filp->f_path.dentry->d_inode->i_atime = filp->f_path.dentry->d_inode->i_ctime = CURRENT_TIME;
- return ret;
-}
-
-static int mqueue_flush_file(struct file *filp, fl_owner_t id)
-{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
-
- spin_lock(&info->lock);
- if (task_tgid(current) == info->notify_owner)
- remove_notification(info);
-
- spin_unlock(&info->lock);
- return 0;
-}
-
-static unsigned int mqueue_poll_file(struct file *filp, struct poll_table_struct *poll_tab)
-{
- struct mqueue_inode_info *info = MQUEUE_I(filp->f_path.dentry->d_inode);
- int retval = 0;
-
- poll_wait(filp, &info->wait_q, poll_tab);
-
- spin_lock(&info->lock);
- if (info->attr.mq_curmsgs)
- retval = POLLIN | POLLRDNORM;
-
- if (info->attr.mq_curmsgs < info->attr.mq_maxmsg)
- retval |= POLLOUT | POLLWRNORM;
- spin_unlock(&info->lock);
-
- return retval;
-}
-
-/* Adds current to info->e_wait_q[sr] before element with smaller prio */
-static void wq_add(struct mqueue_inode_info *info, int sr,
- struct ext_wait_queue *ewp)
-{
- struct ext_wait_queue *walk;
-
- ewp->task = current;
-
- list_for_each_entry(walk, &info->e_wait_q[sr].list, list) {
- if (walk->task->static_prio <= current->static_prio) {
- list_add_tail(&ewp->list, &walk->list);
- return;
- }
- }
- list_add_tail(&ewp->list, &info->e_wait_q[sr].list);
-}
-
-/*
- * Puts current task to sleep. Caller must hold queue lock. After return
- * lock isn't held.
- * sr: SEND or RECV
- */
-static int wq_sleep(struct mqueue_inode_info *info, int sr,
- ktime_t *timeout, struct ext_wait_queue *ewp)
-{
- int retval;
- signed long time;
-
- wq_add(info, sr, ewp);
-
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_unlock(&info->lock);
- time = schedule_hrtimeout_range_clock(timeout, 0,
- HRTIMER_MODE_ABS, CLOCK_REALTIME);
-
- while (ewp->state == STATE_PENDING)
- cpu_relax();
-
- if (ewp->state == STATE_READY) {
- retval = 0;
- goto out;
- }
- spin_lock(&info->lock);
- if (ewp->state == STATE_READY) {
- retval = 0;
- goto out_unlock;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- if (time == 0) {
- retval = -ETIMEDOUT;
- break;
- }
- }
- list_del(&ewp->list);
-out_unlock:
- spin_unlock(&info->lock);
-out:
- return retval;
-}
-
-/*
- * Returns waiting task that should be serviced first or NULL if none exists
- */
-static struct ext_wait_queue *wq_get_first_waiter(
- struct mqueue_inode_info *info, int sr)
-{
- struct list_head *ptr;
-
- ptr = info->e_wait_q[sr].list.prev;
- if (ptr == &info->e_wait_q[sr].list)
- return NULL;
- return list_entry(ptr, struct ext_wait_queue, list);
-}
-
-/* Auxiliary functions to manipulate messages' list */
-static void msg_insert(struct msg_msg *ptr, struct mqueue_inode_info *info)
-{
- int k;
-
- k = info->attr.mq_curmsgs - 1;
- while (k >= 0 && info->messages[k]->m_type >= ptr->m_type) {
- info->messages[k + 1] = info->messages[k];
- k--;
- }
- info->attr.mq_curmsgs++;
- info->qsize += ptr->m_ts;
- info->messages[k + 1] = ptr;
-}
-
-static inline struct msg_msg *msg_get(struct mqueue_inode_info *info)
-{
- info->qsize -= info->messages[--info->attr.mq_curmsgs]->m_ts;
- return info->messages[info->attr.mq_curmsgs];
-}
-
-static inline void set_cookie(struct sk_buff *skb, char code)
-{
- ((char*)skb->data)[NOTIFY_COOKIE_LEN-1] = code;
-}
-
-/*
- * The next function is only to split too long sys_mq_timedsend
- */
-static void __do_notify(struct mqueue_inode_info *info)
-{
- /* notification
- * invoked when there is registered process and there isn't process
- * waiting synchronously for message AND state of queue changed from
- * empty to not empty. Here we are sure that no one is waiting
- * synchronously. */
- if (info->notify_owner &&
- info->attr.mq_curmsgs == 1) {
- struct siginfo sig_i;
- switch (info->notify.sigev_notify) {
- case SIGEV_NONE:
- break;
- case SIGEV_SIGNAL:
- /* sends signal */
-
- sig_i.si_signo = info->notify.sigev_signo;
- sig_i.si_errno = 0;
- sig_i.si_code = SI_MESGQ;
- sig_i.si_value = info->notify.sigev_value;
- /* map current pid/uid into info->owner's namespaces */
- rcu_read_lock();
- sig_i.si_pid = task_tgid_nr_ns(current,
- ns_of_pid(info->notify_owner));
- sig_i.si_uid = user_ns_map_uid(info->user->user_ns,
- current_cred(), current_uid());
- rcu_read_unlock();
-
- kill_pid_info(info->notify.sigev_signo,
- &sig_i, info->notify_owner);
- break;
- case SIGEV_THREAD:
- set_cookie(info->notify_cookie, NOTIFY_WOKENUP);
- netlink_sendskb(info->notify_sock, info->notify_cookie);
- break;
- }
- /* after notification unregisters process */
- put_pid(info->notify_owner);
- info->notify_owner = NULL;
- }
- wake_up(&info->wait_q);
-}
-
-static int prepare_timeout(const struct timespec __user *u_abs_timeout,
- ktime_t *expires, struct timespec *ts)
-{
- if (copy_from_user(ts, u_abs_timeout, sizeof(struct timespec)))
- return -EFAULT;
- if (!timespec_valid(ts))
- return -EINVAL;
-
- *expires = timespec_to_ktime(*ts);
- return 0;
-}
-
-static void remove_notification(struct mqueue_inode_info *info)
-{
- if (info->notify_owner != NULL &&
- info->notify.sigev_notify == SIGEV_THREAD) {
- set_cookie(info->notify_cookie, NOTIFY_REMOVED);
- netlink_sendskb(info->notify_sock, info->notify_cookie);
- }
- put_pid(info->notify_owner);
- info->notify_owner = NULL;
-}
-
-static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
-{
- if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0)
- return 0;
- if (capable(CAP_SYS_RESOURCE)) {
- if (attr->mq_maxmsg > HARD_MSGMAX)
- return 0;
- } else {
- if (attr->mq_maxmsg > ipc_ns->mq_msg_max ||
- attr->mq_msgsize > ipc_ns->mq_msgsize_max)
- return 0;
- }
- /* check for overflow */
- if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
- return 0;
- if ((unsigned long)(attr->mq_maxmsg * (attr->mq_msgsize
- + sizeof (struct msg_msg *))) <
- (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
- return 0;
- return 1;
-}
-
-/*
- * Invoked when creating a new queue via sys_mq_open
- */
-static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
- struct dentry *dentry, int oflag, umode_t mode,
- struct mq_attr *attr)
-{
- const struct cred *cred = current_cred();
- struct file *result;
- int ret;
-
- if (attr) {
- if (!mq_attr_ok(ipc_ns, attr)) {
- ret = -EINVAL;
- goto out;
- }
- /* store for use during create */
- dentry->d_fsdata = attr;
- }
-
- mode &= ~current_umask();
- ret = mnt_want_write(ipc_ns->mq_mnt);
- if (ret)
- goto out;
- ret = vfs_create(dir->d_inode, dentry, mode, NULL);
- dentry->d_fsdata = NULL;
- if (ret)
- goto out_drop_write;
-
- result = dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
- /*
- * dentry_open() took a persistent mnt_want_write(),
- * so we can now drop this one.
- */
- mnt_drop_write(ipc_ns->mq_mnt);
- return result;
-
-out_drop_write:
- mnt_drop_write(ipc_ns->mq_mnt);
-out:
- dput(dentry);
- mntput(ipc_ns->mq_mnt);
- return ERR_PTR(ret);
-}
-
-/* Opens existing queue */
-static struct file *do_open(struct ipc_namespace *ipc_ns,
- struct dentry *dentry, int oflag)
-{
- int ret;
- const struct cred *cred = current_cred();
-
- static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
- MAY_READ | MAY_WRITE };
-
- if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
- ret = -EINVAL;
- goto err;
- }
-
- if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
- ret = -EACCES;
- goto err;
- }
-
- return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
-
-err:
- dput(dentry);
- mntput(ipc_ns->mq_mnt);
- return ERR_PTR(ret);
-}
-
-SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
- struct mq_attr __user *, u_attr)
-{
- struct dentry *dentry;
- struct file *filp;
- char *name;
- struct mq_attr attr;
- int fd, error;
- struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
-
- if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr)))
- return -EFAULT;
-
- audit_mq_open(oflag, mode, u_attr ? &attr : NULL);
-
- if (IS_ERR(name = getname(u_name)))
- return PTR_ERR(name);
-
- fd = get_unused_fd_flags(O_CLOEXEC);
- if (fd < 0)
- goto out_putname;
-
- mutex_lock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
- dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
- if (IS_ERR(dentry)) {
- error = PTR_ERR(dentry);
- goto out_putfd;
- }
- mntget(ipc_ns->mq_mnt);
-
- if (oflag & O_CREAT) {
- if (dentry->d_inode) { /* entry already exists */
- audit_inode(name, dentry);
- if (oflag & O_EXCL) {
- error = -EEXIST;
- goto out;
- }
- filp = do_open(ipc_ns, dentry, oflag);
- } else {
- filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root,
- dentry, oflag, mode,
- u_attr ? &attr : NULL);
- }
- } else {
- if (!dentry->d_inode) {
- error = -ENOENT;
- goto out;
- }
- audit_inode(name, dentry);
- filp = do_open(ipc_ns, dentry, oflag);
- }
-
- if (IS_ERR(filp)) {
- error = PTR_ERR(filp);
- goto out_putfd;
- }
-
- fd_install(fd, filp);
- goto out_upsem;
-
-out:
- dput(dentry);
- mntput(ipc_ns->mq_mnt);
-out_putfd:
- put_unused_fd(fd);
- fd = error;
-out_upsem:
- mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
-out_putname:
- putname(name);
- return fd;
-}
-
-SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
-{
- int err;
- char *name;
- struct dentry *dentry;
- struct inode *inode = NULL;
- struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
-
- name = getname(u_name);
- if (IS_ERR(name))
- return PTR_ERR(name);
-
- mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex,
- I_MUTEX_PARENT);
- dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
- if (IS_ERR(dentry)) {
- err = PTR_ERR(dentry);
- goto out_unlock;
- }
-
- if (!dentry->d_inode) {
- err = -ENOENT;
- goto out_err;
- }
-
- inode = dentry->d_inode;
- if (inode)
- ihold(inode);
- err = mnt_want_write(ipc_ns->mq_mnt);
- if (err)
- goto out_err;
- err = vfs_unlink(dentry->d_parent->d_inode, dentry);
- mnt_drop_write(ipc_ns->mq_mnt);
-out_err:
- dput(dentry);
-
-out_unlock:
- mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
- putname(name);
- if (inode)
- iput(inode);
-
- return err;
-}
-
-/* Pipelined send and receive functions.
- *
- * If a receiver finds no waiting message, then it registers itself in the
- * list of waiting receivers. A sender checks that list before adding the new
- * message into the message array. If there is a waiting receiver, then it
- * bypasses the message array and directly hands the message over to the
- * receiver.
- * The receiver accepts the message and returns without grabbing the queue
- * spinlock. Therefore an intermediate STATE_PENDING state and memory barriers
- * are necessary. The same algorithm is used for sysv semaphores, see
- * ipc/sem.c for more details.
- *
- * The same algorithm is used for senders.
- */
-
-/* pipelined_send() - send a message directly to the task waiting in
- * sys_mq_timedreceive() (without inserting message into a queue).
- */
-static inline void pipelined_send(struct mqueue_inode_info *info,
- struct msg_msg *message,
- struct ext_wait_queue *receiver)
-{
- receiver->msg = message;
- list_del(&receiver->list);
- receiver->state = STATE_PENDING;
- wake_up_process(receiver->task);
- smp_wmb();
- receiver->state = STATE_READY;
-}
-
-/* pipelined_receive() - if there is task waiting in sys_mq_timedsend()
- * gets its message and put to the queue (we have one free place for sure). */
-static inline void pipelined_receive(struct mqueue_inode_info *info)
-{
- struct ext_wait_queue *sender = wq_get_first_waiter(info, SEND);
-
- if (!sender) {
- /* for poll */
- wake_up_interruptible(&info->wait_q);
- return;
- }
- msg_insert(sender->msg, info);
- list_del(&sender->list);
- sender->state = STATE_PENDING;
- wake_up_process(sender->task);
- smp_wmb();
- sender->state = STATE_READY;
-}
-
-SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
- size_t, msg_len, unsigned int, msg_prio,
- const struct timespec __user *, u_abs_timeout)
-{
- struct file *filp;
- struct inode *inode;
- struct ext_wait_queue wait;
- struct ext_wait_queue *receiver;
- struct msg_msg *msg_ptr;
- struct mqueue_inode_info *info;
- ktime_t expires, *timeout = NULL;
- struct timespec ts;
- int ret;
-
- if (u_abs_timeout) {
- int res = prepare_timeout(u_abs_timeout, &expires, &ts);
- if (res)
- return res;
- timeout = &expires;
- }
-
- if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
- return -EINVAL;
-
- audit_mq_sendrecv(mqdes, msg_len, msg_prio, timeout ? &ts : NULL);
-
- filp = fget(mqdes);
- if (unlikely(!filp)) {
- ret = -EBADF;
- goto out;
- }
-
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
- ret = -EBADF;
- goto out_fput;
- }
- info = MQUEUE_I(inode);
- audit_inode(NULL, filp->f_path.dentry);
-
- if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
- ret = -EBADF;
- goto out_fput;
- }
-
- if (unlikely(msg_len > info->attr.mq_msgsize)) {
- ret = -EMSGSIZE;
- goto out_fput;
- }
-
- /* First try to allocate memory, before doing anything with
- * existing queues. */
- msg_ptr = load_msg(u_msg_ptr, msg_len);
- if (IS_ERR(msg_ptr)) {
- ret = PTR_ERR(msg_ptr);
- goto out_fput;
- }
- msg_ptr->m_ts = msg_len;
- msg_ptr->m_type = msg_prio;
-
- spin_lock(&info->lock);
-
- if (info->attr.mq_curmsgs == info->attr.mq_maxmsg) {
- if (filp->f_flags & O_NONBLOCK) {
- spin_unlock(&info->lock);
- ret = -EAGAIN;
- } else {
- wait.task = current;
- wait.msg = (void *) msg_ptr;
- wait.state = STATE_NONE;
- ret = wq_sleep(info, SEND, timeout, &wait);
- }
- if (ret < 0)
- free_msg(msg_ptr);
- } else {
- receiver = wq_get_first_waiter(info, RECV);
- if (receiver) {
- pipelined_send(info, msg_ptr, receiver);
- } else {
- /* adds message to the queue */
- msg_insert(msg_ptr, info);
- __do_notify(info);
- }
- inode->i_atime = inode->i_mtime = inode->i_ctime =
- CURRENT_TIME;
- spin_unlock(&info->lock);
- ret = 0;
- }
-out_fput:
- fput(filp);
-out:
- return ret;
-}
-
-SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
- size_t, msg_len, unsigned int __user *, u_msg_prio,
- const struct timespec __user *, u_abs_timeout)
-{
- ssize_t ret;
- struct msg_msg *msg_ptr;
- struct file *filp;
- struct inode *inode;
- struct mqueue_inode_info *info;
- struct ext_wait_queue wait;
- ktime_t expires, *timeout = NULL;
- struct timespec ts;
-
- if (u_abs_timeout) {
- int res = prepare_timeout(u_abs_timeout, &expires, &ts);
- if (res)
- return res;
- timeout = &expires;
- }
-
- audit_mq_sendrecv(mqdes, msg_len, 0, timeout ? &ts : NULL);
-
- filp = fget(mqdes);
- if (unlikely(!filp)) {
- ret = -EBADF;
- goto out;
- }
-
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
- ret = -EBADF;
- goto out_fput;
- }
- info = MQUEUE_I(inode);
- audit_inode(NULL, filp->f_path.dentry);
-
- if (unlikely(!(filp->f_mode & FMODE_READ))) {
- ret = -EBADF;
- goto out_fput;
- }
-
- /* checks if buffer is big enough */
- if (unlikely(msg_len < info->attr.mq_msgsize)) {
- ret = -EMSGSIZE;
- goto out_fput;
- }
-
- spin_lock(&info->lock);
- if (info->attr.mq_curmsgs == 0) {
- if (filp->f_flags & O_NONBLOCK) {
- spin_unlock(&info->lock);
- ret = -EAGAIN;
- } else {
- wait.task = current;
- wait.state = STATE_NONE;
- ret = wq_sleep(info, RECV, timeout, &wait);
- msg_ptr = wait.msg;
- }
- } else {
- msg_ptr = msg_get(info);
-
- inode->i_atime = inode->i_mtime = inode->i_ctime =
- CURRENT_TIME;
-
- /* There is now free space in queue. */
- pipelined_receive(info);
- spin_unlock(&info->lock);
- ret = 0;
- }
- if (ret == 0) {
- ret = msg_ptr->m_ts;
-
- if ((u_msg_prio && put_user(msg_ptr->m_type, u_msg_prio)) ||
- store_msg(u_msg_ptr, msg_ptr, msg_ptr->m_ts)) {
- ret = -EFAULT;
- }
- free_msg(msg_ptr);
- }
-out_fput:
- fput(filp);
-out:
- return ret;
-}
-
-/*
- * Notes: the case when user wants us to deregister (with NULL as pointer)
- * and he isn't currently owner of notification, will be silently discarded.
- * It isn't explicitly defined in the POSIX.
- */
-SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
- const struct sigevent __user *, u_notification)
-{
- int ret;
- struct file *filp;
- struct sock *sock;
- struct inode *inode;
- struct sigevent notification;
- struct mqueue_inode_info *info;
- struct sk_buff *nc;
-
- if (u_notification) {
- if (copy_from_user(&notification, u_notification,
- sizeof(struct sigevent)))
- return -EFAULT;
- }
-
- audit_mq_notify(mqdes, u_notification ? &notification : NULL);
-
- nc = NULL;
- sock = NULL;
- if (u_notification != NULL) {
- if (unlikely(notification.sigev_notify != SIGEV_NONE &&
- notification.sigev_notify != SIGEV_SIGNAL &&
- notification.sigev_notify != SIGEV_THREAD))
- return -EINVAL;
- if (notification.sigev_notify == SIGEV_SIGNAL &&
- !valid_signal(notification.sigev_signo)) {
- return -EINVAL;
- }
- if (notification.sigev_notify == SIGEV_THREAD) {
- long timeo;
-
- /* create the notify skb */
- nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL);
- if (!nc) {
- ret = -ENOMEM;
- goto out;
- }
- if (copy_from_user(nc->data,
- notification.sigev_value.sival_ptr,
- NOTIFY_COOKIE_LEN)) {
- ret = -EFAULT;
- goto out;
- }
-
- /* TODO: add a header? */
- skb_put(nc, NOTIFY_COOKIE_LEN);
- /* and attach it to the socket */
-retry:
- filp = fget(notification.sigev_signo);
- if (!filp) {
- ret = -EBADF;
- goto out;
- }
- sock = netlink_getsockbyfilp(filp);
- fput(filp);
- if (IS_ERR(sock)) {
- ret = PTR_ERR(sock);
- sock = NULL;
- goto out;
- }
-
- timeo = MAX_SCHEDULE_TIMEOUT;
- ret = netlink_attachskb(sock, nc, &timeo, NULL);
- if (ret == 1)
- goto retry;
- if (ret) {
- sock = NULL;
- nc = NULL;
- goto out;
- }
- }
- }
-
- filp = fget(mqdes);
- if (!filp) {
- ret = -EBADF;
- goto out;
- }
-
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
- ret = -EBADF;
- goto out_fput;
- }
- info = MQUEUE_I(inode);
-
- ret = 0;
- spin_lock(&info->lock);
- if (u_notification == NULL) {
- if (info->notify_owner == task_tgid(current)) {
- remove_notification(info);
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
- }
- } else if (info->notify_owner != NULL) {
- ret = -EBUSY;
- } else {
- switch (notification.sigev_notify) {
- case SIGEV_NONE:
- info->notify.sigev_notify = SIGEV_NONE;
- break;
- case SIGEV_THREAD:
- info->notify_sock = sock;
- info->notify_cookie = nc;
- sock = NULL;
- nc = NULL;
- info->notify.sigev_notify = SIGEV_THREAD;
- break;
- case SIGEV_SIGNAL:
- info->notify.sigev_signo = notification.sigev_signo;
- info->notify.sigev_value = notification.sigev_value;
- info->notify.sigev_notify = SIGEV_SIGNAL;
- break;
- }
-
- info->notify_owner = get_pid(task_tgid(current));
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
- }
- spin_unlock(&info->lock);
-out_fput:
- fput(filp);
-out:
- if (sock) {
- netlink_detachskb(sock, nc);
- } else if (nc) {
- dev_kfree_skb(nc);
- }
- return ret;
-}
-
-SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
- const struct mq_attr __user *, u_mqstat,
- struct mq_attr __user *, u_omqstat)
-{
- int ret;
- struct mq_attr mqstat, omqstat;
- struct file *filp;
- struct inode *inode;
- struct mqueue_inode_info *info;
-
- if (u_mqstat != NULL) {
- if (copy_from_user(&mqstat, u_mqstat, sizeof(struct mq_attr)))
- return -EFAULT;
- if (mqstat.mq_flags & (~O_NONBLOCK))
- return -EINVAL;
- }
-
- filp = fget(mqdes);
- if (!filp) {
- ret = -EBADF;
- goto out;
- }
-
- inode = filp->f_path.dentry->d_inode;
- if (unlikely(filp->f_op != &mqueue_file_operations)) {
- ret = -EBADF;
- goto out_fput;
- }
- info = MQUEUE_I(inode);
-
- spin_lock(&info->lock);
-
- omqstat = info->attr;
- omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
- if (u_mqstat) {
- audit_mq_getsetattr(mqdes, &mqstat);
- spin_lock(&filp->f_lock);
- if (mqstat.mq_flags & O_NONBLOCK)
- filp->f_flags |= O_NONBLOCK;
- else
- filp->f_flags &= ~O_NONBLOCK;
- spin_unlock(&filp->f_lock);
-
- inode->i_atime = inode->i_ctime = CURRENT_TIME;
- }
-
- spin_unlock(&info->lock);
-
- ret = 0;
- if (u_omqstat != NULL && copy_to_user(u_omqstat, &omqstat,
- sizeof(struct mq_attr)))
- ret = -EFAULT;
-
-out_fput:
- fput(filp);
-out:
- return ret;
-}
-
-static const struct inode_operations mqueue_dir_inode_operations = {
- .lookup = simple_lookup,
- .create = mqueue_create,
- .unlink = mqueue_unlink,
-};
-
-static const struct file_operations mqueue_file_operations = {
- .flush = mqueue_flush_file,
- .poll = mqueue_poll_file,
- .read = mqueue_read_file,
- .llseek = default_llseek,
-};
-
-static const struct super_operations mqueue_super_ops = {
- .alloc_inode = mqueue_alloc_inode,
- .destroy_inode = mqueue_destroy_inode,
- .evict_inode = mqueue_evict_inode,
- .statfs = simple_statfs,
-};
-
-static struct file_system_type mqueue_fs_type = {
- .name = "mqueue",
- .mount = mqueue_mount,
- .kill_sb = kill_litter_super,
-};
-
-int mq_init_ns(struct ipc_namespace *ns)
-{
- ns->mq_queues_count = 0;
- ns->mq_queues_max = DFLT_QUEUESMAX;
- ns->mq_msg_max = DFLT_MSGMAX;
- ns->mq_msgsize_max = DFLT_MSGSIZEMAX;
-
- ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
- if (IS_ERR(ns->mq_mnt)) {
- int err = PTR_ERR(ns->mq_mnt);
- ns->mq_mnt = NULL;
- return err;
- }
- return 0;
-}
-
-void mq_clear_sbinfo(struct ipc_namespace *ns)
-{
- ns->mq_mnt->mnt_sb->s_fs_info = NULL;
-}
-
-void mq_put_mnt(struct ipc_namespace *ns)
-{
- kern_unmount(ns->mq_mnt);
-}
-
-static int __init init_mqueue_fs(void)
-{
- int error;
-
- mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
- sizeof(struct mqueue_inode_info), 0,
- SLAB_HWCACHE_ALIGN, init_once);
- if (mqueue_inode_cachep == NULL)
- return -ENOMEM;
-
- /* ignore failures - they are not fatal */
- mq_sysctl_table = mq_register_sysctl_table();
-
- error = register_filesystem(&mqueue_fs_type);
- if (error)
- goto out_sysctl;
-
- spin_lock_init(&mq_lock);
-
- error = mq_init_ns(&init_ipc_ns);
- if (error)
- goto out_filesystem;
-
- return 0;
-
-out_filesystem:
- unregister_filesystem(&mqueue_fs_type);
-out_sysctl:
- if (mq_sysctl_table)
- unregister_sysctl_table(mq_sysctl_table);
- kmem_cache_destroy(mqueue_inode_cachep);
- return error;
-}
-
-__initcall(init_mqueue_fs);
diff --git a/ANDROID_3.4.5/ipc/msg.c b/ANDROID_3.4.5/ipc/msg.c
deleted file mode 100644
index 7385de25..00000000
--- a/ANDROID_3.4.5/ipc/msg.c
+++ /dev/null
@@ -1,944 +0,0 @@
-/*
- * linux/ipc/msg.c
- * Copyright (C) 1992 Krishna Balasubramanian
- *
- * Removed all the remaining kerneld mess
- * Catch the -EFAULT stuff properly
- * Use GFP_KERNEL for messages as in 1.2
- * Fixed up the unchecked user space derefs
- * Copyright (C) 1998 Alan Cox & Andi Kleen
- *
- * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
- *
- * mostly rewritten, threaded and wake-one semantics added
- * MSGMAX limit removed, sysctl's added
- * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
- *
- * support for audit of ipc object properties and permission changes
- * Dustin Kirkland <dustin.kirkland@us.ibm.com>
- *
- * namespaces support
- * OpenVZ, SWsoft Inc.
- * Pavel Emelianov <xemul@openvz.org>
- */
-
-#include <linux/capability.h>
-#include <linux/msg.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/list.h>
-#include <linux/security.h>
-#include <linux/sched.h>
-#include <linux/syscalls.h>
-#include <linux/audit.h>
-#include <linux/seq_file.h>
-#include <linux/rwsem.h>
-#include <linux/nsproxy.h>
-#include <linux/ipc_namespace.h>
-
-#include <asm/current.h>
-#include <asm/uaccess.h>
-#include "util.h"
-
-/*
- * one msg_receiver structure for each sleeping receiver:
- */
-struct msg_receiver {
- struct list_head r_list;
- struct task_struct *r_tsk;
-
- int r_mode;
- long r_msgtype;
- long r_maxsize;
-
- struct msg_msg *volatile r_msg;
-};
-
-/* one msg_sender for each sleeping sender */
-struct msg_sender {
- struct list_head list;
- struct task_struct *tsk;
-};
-
-#define SEARCH_ANY 1
-#define SEARCH_EQUAL 2
-#define SEARCH_NOTEQUAL 3
-#define SEARCH_LESSEQUAL 4
-
-#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
-
-#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
-
-static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
-static int newque(struct ipc_namespace *, struct ipc_params *);
-#ifdef CONFIG_PROC_FS
-static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
-#endif
-
-/*
- * Scale msgmni with the available lowmem size: the memory dedicated to msg
- * queues should occupy at most 1/MSG_MEM_SCALE of lowmem.
- * Also take into account the number of nsproxies created so far.
- * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range.
- */
-void recompute_msgmni(struct ipc_namespace *ns)
-{
- struct sysinfo i;
- unsigned long allowed;
- int nb_ns;
-
- si_meminfo(&i);
- allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit)
- / MSGMNB;
- nb_ns = atomic_read(&nr_ipc_ns);
- allowed /= nb_ns;
-
- if (allowed < MSGMNI) {
- ns->msg_ctlmni = MSGMNI;
- return;
- }
-
- if (allowed > IPCMNI / nb_ns) {
- ns->msg_ctlmni = IPCMNI / nb_ns;
- return;
- }
-
- ns->msg_ctlmni = allowed;
-}
-
-void msg_init_ns(struct ipc_namespace *ns)
-{
- ns->msg_ctlmax = MSGMAX;
- ns->msg_ctlmnb = MSGMNB;
-
- recompute_msgmni(ns);
-
- atomic_set(&ns->msg_bytes, 0);
- atomic_set(&ns->msg_hdrs, 0);
- ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
-}
-
-#ifdef CONFIG_IPC_NS
-void msg_exit_ns(struct ipc_namespace *ns)
-{
- free_ipcs(ns, &msg_ids(ns), freeque);
- idr_destroy(&ns->ids[IPC_MSG_IDS].ipcs_idr);
-}
-#endif
-
-void __init msg_init(void)
-{
- msg_init_ns(&init_ipc_ns);
-
- printk(KERN_INFO "msgmni has been set to %d\n",
- init_ipc_ns.msg_ctlmni);
-
- ipc_init_proc_interface("sysvipc/msg",
- " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
- IPC_MSG_IDS, sysvipc_msg_proc_show);
-}
-
-/*
- * msg_lock_(check_) routines are called in the paths where the rw_mutex
- * is not held.
- */
-static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct msg_queue *)ipcp;
-
- return container_of(ipcp, struct msg_queue, q_perm);
-}
-
-static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
- int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct msg_queue *)ipcp;
-
- return container_of(ipcp, struct msg_queue, q_perm);
-}
-
-static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
-{
- ipc_rmid(&msg_ids(ns), &s->q_perm);
-}
-
-/**
- * newque - Create a new msg queue
- * @ns: namespace
- * @params: ptr to the structure that contains the key and msgflg
- *
- * Called with msg_ids.rw_mutex held (writer)
- */
-static int newque(struct ipc_namespace *ns, struct ipc_params *params)
-{
- struct msg_queue *msq;
- int id, retval;
- key_t key = params->key;
- int msgflg = params->flg;
-
- msq = ipc_rcu_alloc(sizeof(*msq));
- if (!msq)
- return -ENOMEM;
-
- msq->q_perm.mode = msgflg & S_IRWXUGO;
- msq->q_perm.key = key;
-
- msq->q_perm.security = NULL;
- retval = security_msg_queue_alloc(msq);
- if (retval) {
- ipc_rcu_putref(msq);
- return retval;
- }
-
- /*
- * ipc_addid() locks msq
- */
- id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
- if (id < 0) {
- security_msg_queue_free(msq);
- ipc_rcu_putref(msq);
- return id;
- }
-
- msq->q_stime = msq->q_rtime = 0;
- msq->q_ctime = get_seconds();
- msq->q_cbytes = msq->q_qnum = 0;
- msq->q_qbytes = ns->msg_ctlmnb;
- msq->q_lspid = msq->q_lrpid = 0;
- INIT_LIST_HEAD(&msq->q_messages);
- INIT_LIST_HEAD(&msq->q_receivers);
- INIT_LIST_HEAD(&msq->q_senders);
-
- msg_unlock(msq);
-
- return msq->q_perm.id;
-}
-
-static inline void ss_add(struct msg_queue *msq, struct msg_sender *mss)
-{
- mss->tsk = current;
- current->state = TASK_INTERRUPTIBLE;
- list_add_tail(&mss->list, &msq->q_senders);
-}
-
-static inline void ss_del(struct msg_sender *mss)
-{
- if (mss->list.next != NULL)
- list_del(&mss->list);
-}
-
-static void ss_wakeup(struct list_head *h, int kill)
-{
- struct list_head *tmp;
-
- tmp = h->next;
- while (tmp != h) {
- struct msg_sender *mss;
-
- mss = list_entry(tmp, struct msg_sender, list);
- tmp = tmp->next;
- if (kill)
- mss->list.next = NULL;
- wake_up_process(mss->tsk);
- }
-}
-
-static void expunge_all(struct msg_queue *msq, int res)
-{
- struct list_head *tmp;
-
- tmp = msq->q_receivers.next;
- while (tmp != &msq->q_receivers) {
- struct msg_receiver *msr;
-
- msr = list_entry(tmp, struct msg_receiver, r_list);
- tmp = tmp->next;
- msr->r_msg = NULL;
- wake_up_process(msr->r_tsk);
- smp_mb();
- msr->r_msg = ERR_PTR(res);
- }
-}
-
-/*
- * freeque() wakes up waiters on the sender and receiver waiting queue,
- * removes the message queue from message queue ID IDR, and cleans up all the
- * messages associated with this queue.
- *
- * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held
- * before freeque() is called. msg_ids.rw_mutex remains locked on exit.
- */
-static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
-{
- struct list_head *tmp;
- struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
-
- expunge_all(msq, -EIDRM);
- ss_wakeup(&msq->q_senders, 1);
- msg_rmid(ns, msq);
- msg_unlock(msq);
-
- tmp = msq->q_messages.next;
- while (tmp != &msq->q_messages) {
- struct msg_msg *msg = list_entry(tmp, struct msg_msg, m_list);
-
- tmp = tmp->next;
- atomic_dec(&ns->msg_hdrs);
- free_msg(msg);
- }
- atomic_sub(msq->q_cbytes, &ns->msg_bytes);
- security_msg_queue_free(msq);
- ipc_rcu_putref(msq);
-}
-
-/*
- * Called with msg_ids.rw_mutex and ipcp locked.
- */
-static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
-{
- struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
-
- return security_msg_queue_associate(msq, msgflg);
-}
-
-SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
-{
- struct ipc_namespace *ns;
- struct ipc_ops msg_ops;
- struct ipc_params msg_params;
-
- ns = current->nsproxy->ipc_ns;
-
- msg_ops.getnew = newque;
- msg_ops.associate = msg_security;
- msg_ops.more_checks = NULL;
-
- msg_params.key = key;
- msg_params.flg = msgflg;
-
- return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
-}
-
-static inline unsigned long
-copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
-{
- switch(version) {
- case IPC_64:
- return copy_to_user(buf, in, sizeof(*in));
- case IPC_OLD:
- {
- struct msqid_ds out;
-
- memset(&out, 0, sizeof(out));
-
- ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);
-
- out.msg_stime = in->msg_stime;
- out.msg_rtime = in->msg_rtime;
- out.msg_ctime = in->msg_ctime;
-
- if (in->msg_cbytes > USHRT_MAX)
- out.msg_cbytes = USHRT_MAX;
- else
- out.msg_cbytes = in->msg_cbytes;
- out.msg_lcbytes = in->msg_cbytes;
-
- if (in->msg_qnum > USHRT_MAX)
- out.msg_qnum = USHRT_MAX;
- else
- out.msg_qnum = in->msg_qnum;
-
- if (in->msg_qbytes > USHRT_MAX)
- out.msg_qbytes = USHRT_MAX;
- else
- out.msg_qbytes = in->msg_qbytes;
- out.msg_lqbytes = in->msg_qbytes;
-
- out.msg_lspid = in->msg_lspid;
- out.msg_lrpid = in->msg_lrpid;
-
- return copy_to_user(buf, &out, sizeof(out));
- }
- default:
- return -EINVAL;
- }
-}
-
-static inline unsigned long
-copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
-{
- switch(version) {
- case IPC_64:
- if (copy_from_user(out, buf, sizeof(*out)))
- return -EFAULT;
- return 0;
- case IPC_OLD:
- {
- struct msqid_ds tbuf_old;
-
- if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
- return -EFAULT;
-
- out->msg_perm.uid = tbuf_old.msg_perm.uid;
- out->msg_perm.gid = tbuf_old.msg_perm.gid;
- out->msg_perm.mode = tbuf_old.msg_perm.mode;
-
- if (tbuf_old.msg_qbytes == 0)
- out->msg_qbytes = tbuf_old.msg_lqbytes;
- else
- out->msg_qbytes = tbuf_old.msg_qbytes;
-
- return 0;
- }
- default:
- return -EINVAL;
- }
-}
-
-/*
- * This function handles some msgctl commands which require the rw_mutex
- * to be held in write mode.
- * NOTE: no locks must be held, the rw_mutex is taken inside this function.
- */
-static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
- struct msqid_ds __user *buf, int version)
-{
- struct kern_ipc_perm *ipcp;
- struct msqid64_ds uninitialized_var(msqid64);
- struct msg_queue *msq;
- int err;
-
- if (cmd == IPC_SET) {
- if (copy_msqid_from_user(&msqid64, buf, version))
- return -EFAULT;
- }
-
- ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
- &msqid64.msg_perm, msqid64.msg_qbytes);
- if (IS_ERR(ipcp))
- return PTR_ERR(ipcp);
-
- msq = container_of(ipcp, struct msg_queue, q_perm);
-
- err = security_msg_queue_msgctl(msq, cmd);
- if (err)
- goto out_unlock;
-
- switch (cmd) {
- case IPC_RMID:
- freeque(ns, ipcp);
- goto out_up;
- case IPC_SET:
- if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
- !capable(CAP_SYS_RESOURCE)) {
- err = -EPERM;
- goto out_unlock;
- }
-
- msq->q_qbytes = msqid64.msg_qbytes;
-
- ipc_update_perm(&msqid64.msg_perm, ipcp);
- msq->q_ctime = get_seconds();
- /* sleeping receivers might be excluded by
- * stricter permissions.
- */
- expunge_all(msq, -EAGAIN);
- /* sleeping senders might be able to send
- * due to a larger queue size.
- */
- ss_wakeup(&msq->q_senders, 0);
- break;
- default:
- err = -EINVAL;
- }
-out_unlock:
- msg_unlock(msq);
-out_up:
- up_write(&msg_ids(ns).rw_mutex);
- return err;
-}
-
-SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
-{
- struct msg_queue *msq;
- int err, version;
- struct ipc_namespace *ns;
-
- if (msqid < 0 || cmd < 0)
- return -EINVAL;
-
- version = ipc_parse_version(&cmd);
- ns = current->nsproxy->ipc_ns;
-
- switch (cmd) {
- case IPC_INFO:
- case MSG_INFO:
- {
- struct msginfo msginfo;
- int max_id;
-
- if (!buf)
- return -EFAULT;
- /*
- * We must not return kernel stack data.
- * due to padding, it's not enough
- * to set all member fields.
- */
- err = security_msg_queue_msgctl(NULL, cmd);
- if (err)
- return err;
-
- memset(&msginfo, 0, sizeof(msginfo));
- msginfo.msgmni = ns->msg_ctlmni;
- msginfo.msgmax = ns->msg_ctlmax;
- msginfo.msgmnb = ns->msg_ctlmnb;
- msginfo.msgssz = MSGSSZ;
- msginfo.msgseg = MSGSEG;
- down_read(&msg_ids(ns).rw_mutex);
- if (cmd == MSG_INFO) {
- msginfo.msgpool = msg_ids(ns).in_use;
- msginfo.msgmap = atomic_read(&ns->msg_hdrs);
- msginfo.msgtql = atomic_read(&ns->msg_bytes);
- } else {
- msginfo.msgmap = MSGMAP;
- msginfo.msgpool = MSGPOOL;
- msginfo.msgtql = MSGTQL;
- }
- max_id = ipc_get_maxid(&msg_ids(ns));
- up_read(&msg_ids(ns).rw_mutex);
- if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
- return -EFAULT;
- return (max_id < 0) ? 0 : max_id;
- }
- case MSG_STAT: /* msqid is an index rather than a msg queue id */
- case IPC_STAT:
- {
- struct msqid64_ds tbuf;
- int success_return;
-
- if (!buf)
- return -EFAULT;
-
- if (cmd == MSG_STAT) {
- msq = msg_lock(ns, msqid);
- if (IS_ERR(msq))
- return PTR_ERR(msq);
- success_return = msq->q_perm.id;
- } else {
- msq = msg_lock_check(ns, msqid);
- if (IS_ERR(msq))
- return PTR_ERR(msq);
- success_return = 0;
- }
- err = -EACCES;
- if (ipcperms(ns, &msq->q_perm, S_IRUGO))
- goto out_unlock;
-
- err = security_msg_queue_msgctl(msq, cmd);
- if (err)
- goto out_unlock;
-
- memset(&tbuf, 0, sizeof(tbuf));
-
- kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
- tbuf.msg_stime = msq->q_stime;
- tbuf.msg_rtime = msq->q_rtime;
- tbuf.msg_ctime = msq->q_ctime;
- tbuf.msg_cbytes = msq->q_cbytes;
- tbuf.msg_qnum = msq->q_qnum;
- tbuf.msg_qbytes = msq->q_qbytes;
- tbuf.msg_lspid = msq->q_lspid;
- tbuf.msg_lrpid = msq->q_lrpid;
- msg_unlock(msq);
- if (copy_msqid_to_user(buf, &tbuf, version))
- return -EFAULT;
- return success_return;
- }
- case IPC_SET:
- case IPC_RMID:
- err = msgctl_down(ns, msqid, cmd, buf, version);
- return err;
- default:
- return -EINVAL;
- }
-
-out_unlock:
- msg_unlock(msq);
- return err;
-}
-
-static int testmsg(struct msg_msg *msg, long type, int mode)
-{
- switch(mode)
- {
- case SEARCH_ANY:
- return 1;
- case SEARCH_LESSEQUAL:
- if (msg->m_type <=type)
- return 1;
- break;
- case SEARCH_EQUAL:
- if (msg->m_type == type)
- return 1;
- break;
- case SEARCH_NOTEQUAL:
- if (msg->m_type != type)
- return 1;
- break;
- }
- return 0;
-}
-
-static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
-{
- struct list_head *tmp;
-
- tmp = msq->q_receivers.next;
- while (tmp != &msq->q_receivers) {
- struct msg_receiver *msr;
-
- msr = list_entry(tmp, struct msg_receiver, r_list);
- tmp = tmp->next;
- if (testmsg(msg, msr->r_msgtype, msr->r_mode) &&
- !security_msg_queue_msgrcv(msq, msg, msr->r_tsk,
- msr->r_msgtype, msr->r_mode)) {
-
- list_del(&msr->r_list);
- if (msr->r_maxsize < msg->m_ts) {
- msr->r_msg = NULL;
- wake_up_process(msr->r_tsk);
- smp_mb();
- msr->r_msg = ERR_PTR(-E2BIG);
- } else {
- msr->r_msg = NULL;
- msq->q_lrpid = task_pid_vnr(msr->r_tsk);
- msq->q_rtime = get_seconds();
- wake_up_process(msr->r_tsk);
- smp_mb();
- msr->r_msg = msg;
-
- return 1;
- }
- }
- }
- return 0;
-}
-
-long do_msgsnd(int msqid, long mtype, void __user *mtext,
- size_t msgsz, int msgflg)
-{
- struct msg_queue *msq;
- struct msg_msg *msg;
- int err;
- struct ipc_namespace *ns;
-
- ns = current->nsproxy->ipc_ns;
-
- if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
- return -EINVAL;
- if (mtype < 1)
- return -EINVAL;
-
- msg = load_msg(mtext, msgsz);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->m_type = mtype;
- msg->m_ts = msgsz;
-
- msq = msg_lock_check(ns, msqid);
- if (IS_ERR(msq)) {
- err = PTR_ERR(msq);
- goto out_free;
- }
-
- for (;;) {
- struct msg_sender s;
-
- err = -EACCES;
- if (ipcperms(ns, &msq->q_perm, S_IWUGO))
- goto out_unlock_free;
-
- err = security_msg_queue_msgsnd(msq, msg, msgflg);
- if (err)
- goto out_unlock_free;
-
- if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
- 1 + msq->q_qnum <= msq->q_qbytes) {
- break;
- }
-
- /* queue full, wait: */
- if (msgflg & IPC_NOWAIT) {
- err = -EAGAIN;
- goto out_unlock_free;
- }
- ss_add(msq, &s);
- ipc_rcu_getref(msq);
- msg_unlock(msq);
- schedule();
-
- ipc_lock_by_ptr(&msq->q_perm);
- ipc_rcu_putref(msq);
- if (msq->q_perm.deleted) {
- err = -EIDRM;
- goto out_unlock_free;
- }
- ss_del(&s);
-
- if (signal_pending(current)) {
- err = -ERESTARTNOHAND;
- goto out_unlock_free;
- }
- }
-
- msq->q_lspid = task_tgid_vnr(current);
- msq->q_stime = get_seconds();
-
- if (!pipelined_send(msq, msg)) {
- /* no one is waiting for this message, enqueue it */
- list_add_tail(&msg->m_list, &msq->q_messages);
- msq->q_cbytes += msgsz;
- msq->q_qnum++;
- atomic_add(msgsz, &ns->msg_bytes);
- atomic_inc(&ns->msg_hdrs);
- }
-
- err = 0;
- msg = NULL;
-
-out_unlock_free:
- msg_unlock(msq);
-out_free:
- if (msg != NULL)
- free_msg(msg);
- return err;
-}
-
-SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
- int, msgflg)
-{
- long mtype;
-
- if (get_user(mtype, &msgp->mtype))
- return -EFAULT;
- return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
-}
-
-static inline int convert_mode(long *msgtyp, int msgflg)
-{
- /*
- * find message of correct type.
- * msgtyp = 0 => get first.
- * msgtyp > 0 => get first message of matching type.
- * msgtyp < 0 => get message with least type must be < abs(msgtype).
- */
- if (*msgtyp == 0)
- return SEARCH_ANY;
- if (*msgtyp < 0) {
- *msgtyp = -*msgtyp;
- return SEARCH_LESSEQUAL;
- }
- if (msgflg & MSG_EXCEPT)
- return SEARCH_NOTEQUAL;
- return SEARCH_EQUAL;
-}
-
-long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
- size_t msgsz, long msgtyp, int msgflg)
-{
- struct msg_queue *msq;
- struct msg_msg *msg;
- int mode;
- struct ipc_namespace *ns;
-
- if (msqid < 0 || (long) msgsz < 0)
- return -EINVAL;
- mode = convert_mode(&msgtyp, msgflg);
- ns = current->nsproxy->ipc_ns;
-
- msq = msg_lock_check(ns, msqid);
- if (IS_ERR(msq))
- return PTR_ERR(msq);
-
- for (;;) {
- struct msg_receiver msr_d;
- struct list_head *tmp;
-
- msg = ERR_PTR(-EACCES);
- if (ipcperms(ns, &msq->q_perm, S_IRUGO))
- goto out_unlock;
-
- msg = ERR_PTR(-EAGAIN);
- tmp = msq->q_messages.next;
- while (tmp != &msq->q_messages) {
- struct msg_msg *walk_msg;
-
- walk_msg = list_entry(tmp, struct msg_msg, m_list);
- if (testmsg(walk_msg, msgtyp, mode) &&
- !security_msg_queue_msgrcv(msq, walk_msg, current,
- msgtyp, mode)) {
-
- msg = walk_msg;
- if (mode == SEARCH_LESSEQUAL &&
- walk_msg->m_type != 1) {
- msg = walk_msg;
- msgtyp = walk_msg->m_type - 1;
- } else {
- msg = walk_msg;
- break;
- }
- }
- tmp = tmp->next;
- }
- if (!IS_ERR(msg)) {
- /*
- * Found a suitable message.
- * Unlink it from the queue.
- */
- if ((msgsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {
- msg = ERR_PTR(-E2BIG);
- goto out_unlock;
- }
- list_del(&msg->m_list);
- msq->q_qnum--;
- msq->q_rtime = get_seconds();
- msq->q_lrpid = task_tgid_vnr(current);
- msq->q_cbytes -= msg->m_ts;
- atomic_sub(msg->m_ts, &ns->msg_bytes);
- atomic_dec(&ns->msg_hdrs);
- ss_wakeup(&msq->q_senders, 0);
- msg_unlock(msq);
- break;
- }
- /* No message waiting. Wait for a message */
- if (msgflg & IPC_NOWAIT) {
- msg = ERR_PTR(-ENOMSG);
- goto out_unlock;
- }
- list_add_tail(&msr_d.r_list, &msq->q_receivers);
- msr_d.r_tsk = current;
- msr_d.r_msgtype = msgtyp;
- msr_d.r_mode = mode;
- if (msgflg & MSG_NOERROR)
- msr_d.r_maxsize = INT_MAX;
- else
- msr_d.r_maxsize = msgsz;
- msr_d.r_msg = ERR_PTR(-EAGAIN);
- current->state = TASK_INTERRUPTIBLE;
- msg_unlock(msq);
-
- schedule();
-
- /* Lockless receive, part 1:
- * Disable preemption. We don't hold a reference to the queue
- * and getting a reference would defeat the idea of a lockless
- * operation, thus the code relies on rcu to guarantee the
- * existence of msq:
- * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
- * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
- * rcu_read_lock() prevents preemption between reading r_msg
- * and the spin_lock() inside ipc_lock_by_ptr().
- */
- rcu_read_lock();
-
- /* Lockless receive, part 2:
- * Wait until pipelined_send or expunge_all are outside of
- * wake_up_process(). There is a race with exit(), see
- * ipc/mqueue.c for the details.
- */
- msg = (struct msg_msg*)msr_d.r_msg;
- while (msg == NULL) {
- cpu_relax();
- msg = (struct msg_msg *)msr_d.r_msg;
- }
-
- /* Lockless receive, part 3:
- * If there is a message or an error then accept it without
- * locking.
- */
- if (msg != ERR_PTR(-EAGAIN)) {
- rcu_read_unlock();
- break;
- }
-
- /* Lockless receive, part 3:
- * Acquire the queue spinlock.
- */
- ipc_lock_by_ptr(&msq->q_perm);
- rcu_read_unlock();
-
- /* Lockless receive, part 4:
- * Repeat test after acquiring the spinlock.
- */
- msg = (struct msg_msg*)msr_d.r_msg;
- if (msg != ERR_PTR(-EAGAIN))
- goto out_unlock;
-
- list_del(&msr_d.r_list);
- if (signal_pending(current)) {
- msg = ERR_PTR(-ERESTARTNOHAND);
-out_unlock:
- msg_unlock(msq);
- break;
- }
- }
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msgsz = (msgsz > msg->m_ts) ? msg->m_ts : msgsz;
- *pmtype = msg->m_type;
- if (store_msg(mtext, msg, msgsz))
- msgsz = -EFAULT;
-
- free_msg(msg);
-
- return msgsz;
-}
-
-SYSCALL_DEFINE5(msgrcv, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
- long, msgtyp, int, msgflg)
-{
- long err, mtype;
-
- err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
- if (err < 0)
- goto out;
-
- if (put_user(mtype, &msgp->mtype))
- err = -EFAULT;
-out:
- return err;
-}
-
-#ifdef CONFIG_PROC_FS
-static int sysvipc_msg_proc_show(struct seq_file *s, void *it)
-{
- struct msg_queue *msq = it;
-
- return seq_printf(s,
- "%10d %10d %4o %10lu %10lu %5u %5u %5u %5u %5u %5u %10lu %10lu %10lu\n",
- msq->q_perm.key,
- msq->q_perm.id,
- msq->q_perm.mode,
- msq->q_cbytes,
- msq->q_qnum,
- msq->q_lspid,
- msq->q_lrpid,
- msq->q_perm.uid,
- msq->q_perm.gid,
- msq->q_perm.cuid,
- msq->q_perm.cgid,
- msq->q_stime,
- msq->q_rtime,
- msq->q_ctime);
-}
-#endif
diff --git a/ANDROID_3.4.5/ipc/msgutil.c b/ANDROID_3.4.5/ipc/msgutil.c
deleted file mode 100644
index 26143d37..00000000
--- a/ANDROID_3.4.5/ipc/msgutil.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * linux/ipc/msgutil.c
- * Copyright (C) 1999, 2004 Manfred Spraul
- *
- * This file is released under GNU General Public Licence version 2 or
- * (at your option) any later version.
- *
- * See the file COPYING for more details.
- */
-
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/security.h>
-#include <linux/slab.h>
-#include <linux/ipc.h>
-#include <linux/msg.h>
-#include <linux/ipc_namespace.h>
-#include <linux/utsname.h>
-#include <asm/uaccess.h>
-
-#include "util.h"
-
-DEFINE_SPINLOCK(mq_lock);
-
-/*
- * The next 2 defines are here bc this is the only file
- * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
- * and not CONFIG_IPC_NS.
- */
-struct ipc_namespace init_ipc_ns = {
- .count = ATOMIC_INIT(1),
- .user_ns = &init_user_ns,
-};
-
-atomic_t nr_ipc_ns = ATOMIC_INIT(1);
-
-struct msg_msgseg {
- struct msg_msgseg* next;
- /* the next part of the message follows immediately */
-};
-
-#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
-#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
-
-struct msg_msg *load_msg(const void __user *src, int len)
-{
- struct msg_msg *msg;
- struct msg_msgseg **pseg;
- int err;
- int alen;
-
- alen = len;
- if (alen > DATALEN_MSG)
- alen = DATALEN_MSG;
-
- msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
- if (msg == NULL)
- return ERR_PTR(-ENOMEM);
-
- msg->next = NULL;
- msg->security = NULL;
-
- if (copy_from_user(msg + 1, src, alen)) {
- err = -EFAULT;
- goto out_err;
- }
-
- len -= alen;
- src = ((char __user *)src) + alen;
- pseg = &msg->next;
- while (len > 0) {
- struct msg_msgseg *seg;
- alen = len;
- if (alen > DATALEN_SEG)
- alen = DATALEN_SEG;
- seg = kmalloc(sizeof(*seg) + alen,
- GFP_KERNEL);
- if (seg == NULL) {
- err = -ENOMEM;
- goto out_err;
- }
- *pseg = seg;
- seg->next = NULL;
- if (copy_from_user(seg + 1, src, alen)) {
- err = -EFAULT;
- goto out_err;
- }
- pseg = &seg->next;
- len -= alen;
- src = ((char __user *)src) + alen;
- }
-
- err = security_msg_msg_alloc(msg);
- if (err)
- goto out_err;
-
- return msg;
-
-out_err:
- free_msg(msg);
- return ERR_PTR(err);
-}
-
-int store_msg(void __user *dest, struct msg_msg *msg, int len)
-{
- int alen;
- struct msg_msgseg *seg;
-
- alen = len;
- if (alen > DATALEN_MSG)
- alen = DATALEN_MSG;
- if (copy_to_user(dest, msg + 1, alen))
- return -1;
-
- len -= alen;
- dest = ((char __user *)dest) + alen;
- seg = msg->next;
- while (len > 0) {
- alen = len;
- if (alen > DATALEN_SEG)
- alen = DATALEN_SEG;
- if (copy_to_user(dest, seg + 1, alen))
- return -1;
- len -= alen;
- dest = ((char __user *)dest) + alen;
- seg = seg->next;
- }
- return 0;
-}
-
-void free_msg(struct msg_msg *msg)
-{
- struct msg_msgseg *seg;
-
- security_msg_msg_free(msg);
-
- seg = msg->next;
- kfree(msg);
- while (seg != NULL) {
- struct msg_msgseg *tmp = seg->next;
- kfree(seg);
- seg = tmp;
- }
-}
diff --git a/ANDROID_3.4.5/ipc/namespace.c b/ANDROID_3.4.5/ipc/namespace.c
deleted file mode 100644
index ce0a6478..00000000
--- a/ANDROID_3.4.5/ipc/namespace.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * linux/ipc/namespace.c
- * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc.
- */
-
-#include <linux/ipc.h>
-#include <linux/msg.h>
-#include <linux/ipc_namespace.h>
-#include <linux/rcupdate.h>
-#include <linux/nsproxy.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/user_namespace.h>
-#include <linux/proc_fs.h>
-
-#include "util.h"
-
-static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
- struct ipc_namespace *old_ns)
-{
- struct ipc_namespace *ns;
- int err;
-
- ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
- if (ns == NULL)
- return ERR_PTR(-ENOMEM);
-
- atomic_set(&ns->count, 1);
- err = mq_init_ns(ns);
- if (err) {
- kfree(ns);
- return ERR_PTR(err);
- }
- atomic_inc(&nr_ipc_ns);
-
- sem_init_ns(ns);
- msg_init_ns(ns);
- shm_init_ns(ns);
-
- /*
- * msgmni has already been computed for the new ipc ns.
- * Thus, do the ipcns creation notification before registering that
- * new ipcns in the chain.
- */
- ipcns_notify(IPCNS_CREATED);
- register_ipcns_notifier(ns);
-
- ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
-
- return ns;
-}
-
-struct ipc_namespace *copy_ipcs(unsigned long flags,
- struct task_struct *tsk)
-{
- struct ipc_namespace *ns = tsk->nsproxy->ipc_ns;
-
- if (!(flags & CLONE_NEWIPC))
- return get_ipc_ns(ns);
- return create_ipc_ns(tsk, ns);
-}
-
-/*
- * free_ipcs - free all ipcs of one type
- * @ns: the namespace to remove the ipcs from
- * @ids: the table of ipcs to free
- * @free: the function called to free each individual ipc
- *
- * Called for each kind of ipc when an ipc_namespace exits.
- */
-void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
- void (*free)(struct ipc_namespace *, struct kern_ipc_perm *))
-{
- struct kern_ipc_perm *perm;
- int next_id;
- int total, in_use;
-
- down_write(&ids->rw_mutex);
-
- in_use = ids->in_use;
-
- for (total = 0, next_id = 0; total < in_use; next_id++) {
- perm = idr_find(&ids->ipcs_idr, next_id);
- if (perm == NULL)
- continue;
- ipc_lock_by_ptr(perm);
- free(ns, perm);
- total++;
- }
- up_write(&ids->rw_mutex);
-}
-
-static void free_ipc_ns(struct ipc_namespace *ns)
-{
- /*
- * Unregistering the hotplug notifier at the beginning guarantees
- * that the ipc namespace won't be freed while we are inside the
- * callback routine. Since the blocking_notifier_chain_XXX routines
- * hold a rw lock on the notifier list, unregister_ipcns_notifier()
- * won't take the rw lock before blocking_notifier_call_chain() has
- * released the rd lock.
- */
- unregister_ipcns_notifier(ns);
- sem_exit_ns(ns);
- msg_exit_ns(ns);
- shm_exit_ns(ns);
- atomic_dec(&nr_ipc_ns);
-
- /*
- * Do the ipcns removal notification after decrementing nr_ipc_ns in
- * order to have a correct value when recomputing msgmni.
- */
- ipcns_notify(IPCNS_REMOVED);
- put_user_ns(ns->user_ns);
- kfree(ns);
-}
-
-/*
- * put_ipc_ns - drop a reference to an ipc namespace.
- * @ns: the namespace to put
- *
- * If this is the last task in the namespace exiting, and
- * it is dropping the refcount to 0, then it can race with
- * a task in another ipc namespace but in a mounts namespace
- * which has this ipcns's mqueuefs mounted, doing some action
- * with one of the mqueuefs files. That can raise the refcount.
- * So dropping the refcount, and raising the refcount when
- * accessing it through the VFS, are protected with mq_lock.
- *
- * (Clearly, a task raising the refcount on its own ipc_ns
- * needn't take mq_lock since it can't race with the last task
- * in the ipcns exiting).
- */
-void put_ipc_ns(struct ipc_namespace *ns)
-{
- if (atomic_dec_and_lock(&ns->count, &mq_lock)) {
- mq_clear_sbinfo(ns);
- spin_unlock(&mq_lock);
- mq_put_mnt(ns);
- free_ipc_ns(ns);
- }
-}
-
-static void *ipcns_get(struct task_struct *task)
-{
- struct ipc_namespace *ns = NULL;
- struct nsproxy *nsproxy;
-
- rcu_read_lock();
- nsproxy = task_nsproxy(task);
- if (nsproxy)
- ns = get_ipc_ns(nsproxy->ipc_ns);
- rcu_read_unlock();
-
- return ns;
-}
-
-static void ipcns_put(void *ns)
-{
- return put_ipc_ns(ns);
-}
-
-static int ipcns_install(struct nsproxy *nsproxy, void *ns)
-{
- /* Ditch state from the old ipc namespace */
- exit_sem(current);
- put_ipc_ns(nsproxy->ipc_ns);
- nsproxy->ipc_ns = get_ipc_ns(ns);
- return 0;
-}
-
-const struct proc_ns_operations ipcns_operations = {
- .name = "ipc",
- .type = CLONE_NEWIPC,
- .get = ipcns_get,
- .put = ipcns_put,
- .install = ipcns_install,
-};
diff --git a/ANDROID_3.4.5/ipc/sem.c b/ANDROID_3.4.5/ipc/sem.c
deleted file mode 100644
index 5215a814..00000000
--- a/ANDROID_3.4.5/ipc/sem.c
+++ /dev/null
@@ -1,1695 +0,0 @@
-/*
- * linux/ipc/sem.c
- * Copyright (C) 1992 Krishna Balasubramanian
- * Copyright (C) 1995 Eric Schenk, Bruno Haible
- *
- * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
- *
- * SMP-threaded, sysctl's added
- * (c) 1999 Manfred Spraul <manfred@colorfullife.com>
- * Enforced range limit on SEM_UNDO
- * (c) 2001 Red Hat Inc
- * Lockless wakeup
- * (c) 2003 Manfred Spraul <manfred@colorfullife.com>
- * Further wakeup optimizations, documentation
- * (c) 2010 Manfred Spraul <manfred@colorfullife.com>
- *
- * support for audit of ipc object properties and permission changes
- * Dustin Kirkland <dustin.kirkland@us.ibm.com>
- *
- * namespaces support
- * OpenVZ, SWsoft Inc.
- * Pavel Emelianov <xemul@openvz.org>
- *
- * Implementation notes: (May 2010)
- * This file implements System V semaphores.
- *
- * User space visible behavior:
- * - FIFO ordering for semop() operations (just FIFO, not starvation
- * protection)
- * - multiple semaphore operations that alter the same semaphore in
- * one semop() are handled.
- * - sem_ctime (time of last semctl()) is updated in the IPC_SET, SETVAL and
- * SETALL calls.
- * - two Linux specific semctl() commands: SEM_STAT, SEM_INFO.
- * - undo adjustments at process exit are limited to 0..SEMVMX.
- * - namespace are supported.
- * - SEMMSL, SEMMNS, SEMOPM and SEMMNI can be configured at runtine by writing
- * to /proc/sys/kernel/sem.
- * - statistics about the usage are reported in /proc/sysvipc/sem.
- *
- * Internals:
- * - scalability:
- * - all global variables are read-mostly.
- * - semop() calls and semctl(RMID) are synchronized by RCU.
- * - most operations do write operations (actually: spin_lock calls) to
- * the per-semaphore array structure.
- * Thus: Perfect SMP scaling between independent semaphore arrays.
- * If multiple semaphores in one array are used, then cache line
- * trashing on the semaphore array spinlock will limit the scaling.
- * - semncnt and semzcnt are calculated on demand in count_semncnt() and
- * count_semzcnt()
- * - the task that performs a successful semop() scans the list of all
- * sleeping tasks and completes any pending operations that can be fulfilled.
- * Semaphores are actively given to waiting tasks (necessary for FIFO).
- * (see update_queue())
- * - To improve the scalability, the actual wake-up calls are performed after
- * dropping all locks. (see wake_up_sem_queue_prepare(),
- * wake_up_sem_queue_do())
- * - All work is done by the waker, the woken up task does not have to do
- * anything - not even acquiring a lock or dropping a refcount.
- * - A woken up task may not even touch the semaphore array anymore, it may
- * have been destroyed already by a semctl(RMID).
- * - The synchronizations between wake-ups due to a timeout/signal and a
- * wake-up due to a completed semaphore operation is achieved by using an
- * intermediate state (IN_WAKEUP).
- * - UNDO values are stored in an array (one per process and per
- * semaphore array, lazily allocated). For backwards compatibility, multiple
- * modes for the UNDO variables are supported (per process, per thread)
- * (see copy_semundo, CLONE_SYSVSEM)
- * - There are two lists of the pending operations: a per-array list
- * and per-semaphore list (stored in the array). This allows to achieve FIFO
- * ordering without always scanning all pending operations.
- * The worst-case behavior is nevertheless O(N^2) for N wakeups.
- */
-
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/time.h>
-#include <linux/security.h>
-#include <linux/syscalls.h>
-#include <linux/audit.h>
-#include <linux/capability.h>
-#include <linux/seq_file.h>
-#include <linux/rwsem.h>
-#include <linux/nsproxy.h>
-#include <linux/ipc_namespace.h>
-
-#include <asm/uaccess.h>
-#include "util.h"
-
-/* One semaphore structure for each semaphore in the system. */
-struct sem {
- int semval; /* current value */
- int sempid; /* pid of last operation */
- struct list_head sem_pending; /* pending single-sop operations */
-};
-
-/* One queue for each sleeping process in the system. */
-struct sem_queue {
- struct list_head simple_list; /* queue of pending operations */
- struct list_head list; /* queue of pending operations */
- struct task_struct *sleeper; /* this process */
- struct sem_undo *undo; /* undo structure */
- int pid; /* process id of requesting process */
- int status; /* completion status of operation */
- struct sembuf *sops; /* array of pending operations */
- int nsops; /* number of operations */
- int alter; /* does *sops alter the array? */
-};
-
-/* Each task has a list of undo requests. They are executed automatically
- * when the process exits.
- */
-struct sem_undo {
- struct list_head list_proc; /* per-process list: *
- * all undos from one process
- * rcu protected */
- struct rcu_head rcu; /* rcu struct for sem_undo */
- struct sem_undo_list *ulp; /* back ptr to sem_undo_list */
- struct list_head list_id; /* per semaphore array list:
- * all undos for one array */
- int semid; /* semaphore set identifier */
- short *semadj; /* array of adjustments */
- /* one per semaphore */
-};
-
-/* sem_undo_list controls shared access to the list of sem_undo structures
- * that may be shared among all a CLONE_SYSVSEM task group.
- */
-struct sem_undo_list {
- atomic_t refcnt;
- spinlock_t lock;
- struct list_head list_proc;
-};
-
-
-#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS])
-
-#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
-#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid)
-
-static int newary(struct ipc_namespace *, struct ipc_params *);
-static void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
-#ifdef CONFIG_PROC_FS
-static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
-#endif
-
-#define SEMMSL_FAST 256 /* 512 bytes on stack */
-#define SEMOPM_FAST 64 /* ~ 372 bytes on stack */
-
-/*
- * linked list protection:
- * sem_undo.id_next,
- * sem_array.sem_pending{,last},
- * sem_array.sem_undo: sem_lock() for read/write
- * sem_undo.proc_next: only "current" is allowed to read/write that field.
- *
- */
-
-#define sc_semmsl sem_ctls[0]
-#define sc_semmns sem_ctls[1]
-#define sc_semopm sem_ctls[2]
-#define sc_semmni sem_ctls[3]
-
-void sem_init_ns(struct ipc_namespace *ns)
-{
- ns->sc_semmsl = SEMMSL;
- ns->sc_semmns = SEMMNS;
- ns->sc_semopm = SEMOPM;
- ns->sc_semmni = SEMMNI;
- ns->used_sems = 0;
- ipc_init_ids(&ns->ids[IPC_SEM_IDS]);
-}
-
-#ifdef CONFIG_IPC_NS
-void sem_exit_ns(struct ipc_namespace *ns)
-{
- free_ipcs(ns, &sem_ids(ns), freeary);
- idr_destroy(&ns->ids[IPC_SEM_IDS].ipcs_idr);
-}
-#endif
-
-void __init sem_init (void)
-{
- sem_init_ns(&init_ipc_ns);
- ipc_init_proc_interface("sysvipc/sem",
- " key semid perms nsems uid gid cuid cgid otime ctime\n",
- IPC_SEM_IDS, sysvipc_sem_proc_show);
-}
-
-/*
- * sem_lock_(check_) routines are called in the paths where the rw_mutex
- * is not held.
- */
-static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct sem_array *)ipcp;
-
- return container_of(ipcp, struct sem_array, sem_perm);
-}
-
-static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns,
- int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct sem_array *)ipcp;
-
- return container_of(ipcp, struct sem_array, sem_perm);
-}
-
-static inline void sem_lock_and_putref(struct sem_array *sma)
-{
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
-}
-
-static inline void sem_getref_and_unlock(struct sem_array *sma)
-{
- ipc_rcu_getref(sma);
- ipc_unlock(&(sma)->sem_perm);
-}
-
-static inline void sem_putref(struct sem_array *sma)
-{
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- ipc_unlock(&(sma)->sem_perm);
-}
-
-static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
-{
- ipc_rmid(&sem_ids(ns), &s->sem_perm);
-}
-
-/*
- * Lockless wakeup algorithm:
- * Without the check/retry algorithm a lockless wakeup is possible:
- * - queue.status is initialized to -EINTR before blocking.
- * - wakeup is performed by
- * * unlinking the queue entry from sma->sem_pending
- * * setting queue.status to IN_WAKEUP
- * This is the notification for the blocked thread that a
- * result value is imminent.
- * * call wake_up_process
- * * set queue.status to the final value.
- * - the previously blocked thread checks queue.status:
- * * if it's IN_WAKEUP, then it must wait until the value changes
- * * if it's not -EINTR, then the operation was completed by
- * update_queue. semtimedop can return queue.status without
- * performing any operation on the sem array.
- * * otherwise it must acquire the spinlock and check what's up.
- *
- * The two-stage algorithm is necessary to protect against the following
- * races:
- * - if queue.status is set after wake_up_process, then the woken up idle
- * thread could race forward and try (and fail) to acquire sma->lock
- * before update_queue had a chance to set queue.status
- * - if queue.status is written before wake_up_process and if the
- * blocked process is woken up by a signal between writing
- * queue.status and the wake_up_process, then the woken up
- * process could return from semtimedop and die by calling
- * sys_exit before wake_up_process is called. Then wake_up_process
- * will oops, because the task structure is already invalid.
- * (yes, this happened on s390 with sysv msg).
- *
- */
-#define IN_WAKEUP 1
-
-/**
- * newary - Create a new semaphore set
- * @ns: namespace
- * @params: ptr to the structure that contains key, semflg and nsems
- *
- * Called with sem_ids.rw_mutex held (as a writer)
- */
-
-static int newary(struct ipc_namespace *ns, struct ipc_params *params)
-{
- int id;
- int retval;
- struct sem_array *sma;
- int size;
- key_t key = params->key;
- int nsems = params->u.nsems;
- int semflg = params->flg;
- int i;
-
- if (!nsems)
- return -EINVAL;
- if (ns->used_sems + nsems > ns->sc_semmns)
- return -ENOSPC;
-
- size = sizeof (*sma) + nsems * sizeof (struct sem);
- sma = ipc_rcu_alloc(size);
- if (!sma) {
- return -ENOMEM;
- }
- memset (sma, 0, size);
-
- sma->sem_perm.mode = (semflg & S_IRWXUGO);
- sma->sem_perm.key = key;
-
- sma->sem_perm.security = NULL;
- retval = security_sem_alloc(sma);
- if (retval) {
- ipc_rcu_putref(sma);
- return retval;
- }
-
- id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
- if (id < 0) {
- security_sem_free(sma);
- ipc_rcu_putref(sma);
- return id;
- }
- ns->used_sems += nsems;
-
- sma->sem_base = (struct sem *) &sma[1];
-
- for (i = 0; i < nsems; i++)
- INIT_LIST_HEAD(&sma->sem_base[i].sem_pending);
-
- sma->complex_count = 0;
- INIT_LIST_HEAD(&sma->sem_pending);
- INIT_LIST_HEAD(&sma->list_id);
- sma->sem_nsems = nsems;
- sma->sem_ctime = get_seconds();
- sem_unlock(sma);
-
- return sma->sem_perm.id;
-}
-
-
-/*
- * Called with sem_ids.rw_mutex and ipcp locked.
- */
-static inline int sem_security(struct kern_ipc_perm *ipcp, int semflg)
-{
- struct sem_array *sma;
-
- sma = container_of(ipcp, struct sem_array, sem_perm);
- return security_sem_associate(sma, semflg);
-}
-
-/*
- * Called with sem_ids.rw_mutex and ipcp locked.
- */
-static inline int sem_more_checks(struct kern_ipc_perm *ipcp,
- struct ipc_params *params)
-{
- struct sem_array *sma;
-
- sma = container_of(ipcp, struct sem_array, sem_perm);
- if (params->u.nsems > sma->sem_nsems)
- return -EINVAL;
-
- return 0;
-}
-
-SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
-{
- struct ipc_namespace *ns;
- struct ipc_ops sem_ops;
- struct ipc_params sem_params;
-
- ns = current->nsproxy->ipc_ns;
-
- if (nsems < 0 || nsems > ns->sc_semmsl)
- return -EINVAL;
-
- sem_ops.getnew = newary;
- sem_ops.associate = sem_security;
- sem_ops.more_checks = sem_more_checks;
-
- sem_params.key = key;
- sem_params.flg = semflg;
- sem_params.u.nsems = nsems;
-
- return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
-}
-
-/*
- * Determine whether a sequence of semaphore operations would succeed
- * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
- */
-
-static int try_atomic_semop (struct sem_array * sma, struct sembuf * sops,
- int nsops, struct sem_undo *un, int pid)
-{
- int result, sem_op;
- struct sembuf *sop;
- struct sem * curr;
-
- for (sop = sops; sop < sops + nsops; sop++) {
- curr = sma->sem_base + sop->sem_num;
- sem_op = sop->sem_op;
- result = curr->semval;
-
- if (!sem_op && result)
- goto would_block;
-
- result += sem_op;
- if (result < 0)
- goto would_block;
- if (result > SEMVMX)
- goto out_of_range;
- if (sop->sem_flg & SEM_UNDO) {
- int undo = un->semadj[sop->sem_num] - sem_op;
- /*
- * Exceeding the undo range is an error.
- */
- if (undo < (-SEMAEM - 1) || undo > SEMAEM)
- goto out_of_range;
- }
- curr->semval = result;
- }
-
- sop--;
- while (sop >= sops) {
- sma->sem_base[sop->sem_num].sempid = pid;
- if (sop->sem_flg & SEM_UNDO)
- un->semadj[sop->sem_num] -= sop->sem_op;
- sop--;
- }
-
- return 0;
-
-out_of_range:
- result = -ERANGE;
- goto undo;
-
-would_block:
- if (sop->sem_flg & IPC_NOWAIT)
- result = -EAGAIN;
- else
- result = 1;
-
-undo:
- sop--;
- while (sop >= sops) {
- sma->sem_base[sop->sem_num].semval -= sop->sem_op;
- sop--;
- }
-
- return result;
-}
-
-/** wake_up_sem_queue_prepare(q, error): Prepare wake-up
- * @q: queue entry that must be signaled
- * @error: Error value for the signal
- *
- * Prepare the wake-up of the queue entry q.
- */
-static void wake_up_sem_queue_prepare(struct list_head *pt,
- struct sem_queue *q, int error)
-{
- if (list_empty(pt)) {
- /*
- * Hold preempt off so that we don't get preempted and have the
- * wakee busy-wait until we're scheduled back on.
- */
- preempt_disable();
- }
- q->status = IN_WAKEUP;
- q->pid = error;
-
- list_add_tail(&q->simple_list, pt);
-}
-
-/**
- * wake_up_sem_queue_do(pt) - do the actual wake-up
- * @pt: list of tasks to be woken up
- *
- * Do the actual wake-up.
- * The function is called without any locks held, thus the semaphore array
- * could be destroyed already and the tasks can disappear as soon as the
- * status is set to the actual return code.
- */
-static void wake_up_sem_queue_do(struct list_head *pt)
-{
- struct sem_queue *q, *t;
- int did_something;
-
- did_something = !list_empty(pt);
- list_for_each_entry_safe(q, t, pt, simple_list) {
- wake_up_process(q->sleeper);
- /* q can disappear immediately after writing q->status. */
- smp_wmb();
- q->status = q->pid;
- }
- if (did_something)
- preempt_enable();
-}
-
-static void unlink_queue(struct sem_array *sma, struct sem_queue *q)
-{
- list_del(&q->list);
- if (q->nsops == 1)
- list_del(&q->simple_list);
- else
- sma->complex_count--;
-}
-
-/** check_restart(sma, q)
- * @sma: semaphore array
- * @q: the operation that just completed
- *
- * update_queue is O(N^2) when it restarts scanning the whole queue of
- * waiting operations. Therefore this function checks if the restart is
- * really necessary. It is called after a previously waiting operation
- * was completed.
- */
-static int check_restart(struct sem_array *sma, struct sem_queue *q)
-{
- struct sem *curr;
- struct sem_queue *h;
-
- /* if the operation didn't modify the array, then no restart */
- if (q->alter == 0)
- return 0;
-
- /* pending complex operations are too difficult to analyse */
- if (sma->complex_count)
- return 1;
-
- /* we were a sleeping complex operation. Too difficult */
- if (q->nsops > 1)
- return 1;
-
- curr = sma->sem_base + q->sops[0].sem_num;
-
- /* No-one waits on this queue */
- if (list_empty(&curr->sem_pending))
- return 0;
-
- /* the new semaphore value */
- if (curr->semval) {
- /* It is impossible that someone waits for the new value:
- * - q is a previously sleeping simple operation that
- * altered the array. It must be a decrement, because
- * simple increments never sleep.
- * - The value is not 0, thus wait-for-zero won't proceed.
- * - If there are older (higher priority) decrements
- * in the queue, then they have observed the original
- * semval value and couldn't proceed. The operation
- * decremented to value - thus they won't proceed either.
- */
- BUG_ON(q->sops[0].sem_op >= 0);
- return 0;
- }
- /*
- * semval is 0. Check if there are wait-for-zero semops.
- * They must be the first entries in the per-semaphore simple queue
- */
- h = list_first_entry(&curr->sem_pending, struct sem_queue, simple_list);
- BUG_ON(h->nsops != 1);
- BUG_ON(h->sops[0].sem_num != q->sops[0].sem_num);
-
- /* Yes, there is a wait-for-zero semop. Restart */
- if (h->sops[0].sem_op == 0)
- return 1;
-
- /* Again - no-one is waiting for the new value. */
- return 0;
-}
-
-
-/**
- * update_queue(sma, semnum): Look for tasks that can be completed.
- * @sma: semaphore array.
- * @semnum: semaphore that was modified.
- * @pt: list head for the tasks that must be woken up.
- *
- * update_queue must be called after a semaphore in a semaphore array
- * was modified. If multiple semaphore were modified, then @semnum
- * must be set to -1.
- * The tasks that must be woken up are added to @pt. The return code
- * is stored in q->pid.
- * The function return 1 if at least one semop was completed successfully.
- */
-static int update_queue(struct sem_array *sma, int semnum, struct list_head *pt)
-{
- struct sem_queue *q;
- struct list_head *walk;
- struct list_head *pending_list;
- int offset;
- int semop_completed = 0;
-
- /* if there are complex operations around, then knowing the semaphore
- * that was modified doesn't help us. Assume that multiple semaphores
- * were modified.
- */
- if (sma->complex_count)
- semnum = -1;
-
- if (semnum == -1) {
- pending_list = &sma->sem_pending;
- offset = offsetof(struct sem_queue, list);
- } else {
- pending_list = &sma->sem_base[semnum].sem_pending;
- offset = offsetof(struct sem_queue, simple_list);
- }
-
-again:
- walk = pending_list->next;
- while (walk != pending_list) {
- int error, restart;
-
- q = (struct sem_queue *)((char *)walk - offset);
- walk = walk->next;
-
- /* If we are scanning the single sop, per-semaphore list of
- * one semaphore and that semaphore is 0, then it is not
- * necessary to scan the "alter" entries: simple increments
- * that affect only one entry succeed immediately and cannot
- * be in the per semaphore pending queue, and decrements
- * cannot be successful if the value is already 0.
- */
- if (semnum != -1 && sma->sem_base[semnum].semval == 0 &&
- q->alter)
- break;
-
- error = try_atomic_semop(sma, q->sops, q->nsops,
- q->undo, q->pid);
-
- /* Does q->sleeper still need to sleep? */
- if (error > 0)
- continue;
-
- unlink_queue(sma, q);
-
- if (error) {
- restart = 0;
- } else {
- semop_completed = 1;
- restart = check_restart(sma, q);
- }
-
- wake_up_sem_queue_prepare(pt, q, error);
- if (restart)
- goto again;
- }
- return semop_completed;
-}
-
-/**
- * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue
- * @sma: semaphore array
- * @sops: operations that were performed
- * @nsops: number of operations
- * @otime: force setting otime
- * @pt: list head of the tasks that must be woken up.
- *
- * do_smart_update() does the required called to update_queue, based on the
- * actual changes that were performed on the semaphore array.
- * Note that the function does not do the actual wake-up: the caller is
- * responsible for calling wake_up_sem_queue_do(@pt).
- * It is safe to perform this call after dropping all locks.
- */
-static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsops,
- int otime, struct list_head *pt)
-{
- int i;
-
- if (sma->complex_count || sops == NULL) {
- if (update_queue(sma, -1, pt))
- otime = 1;
- goto done;
- }
-
- for (i = 0; i < nsops; i++) {
- if (sops[i].sem_op > 0 ||
- (sops[i].sem_op < 0 &&
- sma->sem_base[sops[i].sem_num].semval == 0))
- if (update_queue(sma, sops[i].sem_num, pt))
- otime = 1;
- }
-done:
- if (otime)
- sma->sem_otime = get_seconds();
-}
-
-
-/* The following counts are associated to each semaphore:
- * semncnt number of tasks waiting on semval being nonzero
- * semzcnt number of tasks waiting on semval being zero
- * This model assumes that a task waits on exactly one semaphore.
- * Since semaphore operations are to be performed atomically, tasks actually
- * wait on a whole sequence of semaphores simultaneously.
- * The counts we return here are a rough approximation, but still
- * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
- */
-static int count_semncnt (struct sem_array * sma, ushort semnum)
-{
- int semncnt;
- struct sem_queue * q;
-
- semncnt = 0;
- list_for_each_entry(q, &sma->sem_pending, list) {
- struct sembuf * sops = q->sops;
- int nsops = q->nsops;
- int i;
- for (i = 0; i < nsops; i++)
- if (sops[i].sem_num == semnum
- && (sops[i].sem_op < 0)
- && !(sops[i].sem_flg & IPC_NOWAIT))
- semncnt++;
- }
- return semncnt;
-}
-
-static int count_semzcnt (struct sem_array * sma, ushort semnum)
-{
- int semzcnt;
- struct sem_queue * q;
-
- semzcnt = 0;
- list_for_each_entry(q, &sma->sem_pending, list) {
- struct sembuf * sops = q->sops;
- int nsops = q->nsops;
- int i;
- for (i = 0; i < nsops; i++)
- if (sops[i].sem_num == semnum
- && (sops[i].sem_op == 0)
- && !(sops[i].sem_flg & IPC_NOWAIT))
- semzcnt++;
- }
- return semzcnt;
-}
-
-/* Free a semaphore set. freeary() is called with sem_ids.rw_mutex locked
- * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex
- * remains locked on exit.
- */
-static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
-{
- struct sem_undo *un, *tu;
- struct sem_queue *q, *tq;
- struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
- struct list_head tasks;
-
- /* Free the existing undo structures for this semaphore set. */
- assert_spin_locked(&sma->sem_perm.lock);
- list_for_each_entry_safe(un, tu, &sma->list_id, list_id) {
- list_del(&un->list_id);
- spin_lock(&un->ulp->lock);
- un->semid = -1;
- list_del_rcu(&un->list_proc);
- spin_unlock(&un->ulp->lock);
- kfree_rcu(un, rcu);
- }
-
- /* Wake up all pending processes and let them fail with EIDRM. */
- INIT_LIST_HEAD(&tasks);
- list_for_each_entry_safe(q, tq, &sma->sem_pending, list) {
- unlink_queue(sma, q);
- wake_up_sem_queue_prepare(&tasks, q, -EIDRM);
- }
-
- /* Remove the semaphore set from the IDR */
- sem_rmid(ns, sma);
- sem_unlock(sma);
-
- wake_up_sem_queue_do(&tasks);
- ns->used_sems -= sma->sem_nsems;
- security_sem_free(sma);
- ipc_rcu_putref(sma);
-}
-
-static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
-{
- switch(version) {
- case IPC_64:
- return copy_to_user(buf, in, sizeof(*in));
- case IPC_OLD:
- {
- struct semid_ds out;
-
- memset(&out, 0, sizeof(out));
-
- ipc64_perm_to_ipc_perm(&in->sem_perm, &out.sem_perm);
-
- out.sem_otime = in->sem_otime;
- out.sem_ctime = in->sem_ctime;
- out.sem_nsems = in->sem_nsems;
-
- return copy_to_user(buf, &out, sizeof(out));
- }
- default:
- return -EINVAL;
- }
-}
-
-static int semctl_nolock(struct ipc_namespace *ns, int semid,
- int cmd, int version, union semun arg)
-{
- int err;
- struct sem_array *sma;
-
- switch(cmd) {
- case IPC_INFO:
- case SEM_INFO:
- {
- struct seminfo seminfo;
- int max_id;
-
- err = security_sem_semctl(NULL, cmd);
- if (err)
- return err;
-
- memset(&seminfo,0,sizeof(seminfo));
- seminfo.semmni = ns->sc_semmni;
- seminfo.semmns = ns->sc_semmns;
- seminfo.semmsl = ns->sc_semmsl;
- seminfo.semopm = ns->sc_semopm;
- seminfo.semvmx = SEMVMX;
- seminfo.semmnu = SEMMNU;
- seminfo.semmap = SEMMAP;
- seminfo.semume = SEMUME;
- down_read(&sem_ids(ns).rw_mutex);
- if (cmd == SEM_INFO) {
- seminfo.semusz = sem_ids(ns).in_use;
- seminfo.semaem = ns->used_sems;
- } else {
- seminfo.semusz = SEMUSZ;
- seminfo.semaem = SEMAEM;
- }
- max_id = ipc_get_maxid(&sem_ids(ns));
- up_read(&sem_ids(ns).rw_mutex);
- if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
- return -EFAULT;
- return (max_id < 0) ? 0: max_id;
- }
- case IPC_STAT:
- case SEM_STAT:
- {
- struct semid64_ds tbuf;
- int id;
-
- if (cmd == SEM_STAT) {
- sma = sem_lock(ns, semid);
- if (IS_ERR(sma))
- return PTR_ERR(sma);
- id = sma->sem_perm.id;
- } else {
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma))
- return PTR_ERR(sma);
- id = 0;
- }
-
- err = -EACCES;
- if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
- goto out_unlock;
-
- err = security_sem_semctl(sma, cmd);
- if (err)
- goto out_unlock;
-
- memset(&tbuf, 0, sizeof(tbuf));
-
- kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
- tbuf.sem_otime = sma->sem_otime;
- tbuf.sem_ctime = sma->sem_ctime;
- tbuf.sem_nsems = sma->sem_nsems;
- sem_unlock(sma);
- if (copy_semid_to_user (arg.buf, &tbuf, version))
- return -EFAULT;
- return id;
- }
- default:
- return -EINVAL;
- }
-out_unlock:
- sem_unlock(sma);
- return err;
-}
-
-static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
- int cmd, int version, union semun arg)
-{
- struct sem_array *sma;
- struct sem* curr;
- int err;
- ushort fast_sem_io[SEMMSL_FAST];
- ushort* sem_io = fast_sem_io;
- int nsems;
- struct list_head tasks;
-
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma))
- return PTR_ERR(sma);
-
- INIT_LIST_HEAD(&tasks);
- nsems = sma->sem_nsems;
-
- err = -EACCES;
- if (ipcperms(ns, &sma->sem_perm,
- (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO))
- goto out_unlock;
-
- err = security_sem_semctl(sma, cmd);
- if (err)
- goto out_unlock;
-
- err = -EACCES;
- switch (cmd) {
- case GETALL:
- {
- ushort __user *array = arg.array;
- int i;
-
- if(nsems > SEMMSL_FAST) {
- sem_getref_and_unlock(sma);
-
- sem_io = ipc_alloc(sizeof(ushort)*nsems);
- if(sem_io == NULL) {
- sem_putref(sma);
- return -ENOMEM;
- }
-
- sem_lock_and_putref(sma);
- if (sma->sem_perm.deleted) {
- sem_unlock(sma);
- err = -EIDRM;
- goto out_free;
- }
- }
-
- for (i = 0; i < sma->sem_nsems; i++)
- sem_io[i] = sma->sem_base[i].semval;
- sem_unlock(sma);
- err = 0;
- if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
- err = -EFAULT;
- goto out_free;
- }
- case SETALL:
- {
- int i;
- struct sem_undo *un;
-
- sem_getref_and_unlock(sma);
-
- if(nsems > SEMMSL_FAST) {
- sem_io = ipc_alloc(sizeof(ushort)*nsems);
- if(sem_io == NULL) {
- sem_putref(sma);
- return -ENOMEM;
- }
- }
-
- if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
- sem_putref(sma);
- err = -EFAULT;
- goto out_free;
- }
-
- for (i = 0; i < nsems; i++) {
- if (sem_io[i] > SEMVMX) {
- sem_putref(sma);
- err = -ERANGE;
- goto out_free;
- }
- }
- sem_lock_and_putref(sma);
- if (sma->sem_perm.deleted) {
- sem_unlock(sma);
- err = -EIDRM;
- goto out_free;
- }
-
- for (i = 0; i < nsems; i++)
- sma->sem_base[i].semval = sem_io[i];
-
- assert_spin_locked(&sma->sem_perm.lock);
- list_for_each_entry(un, &sma->list_id, list_id) {
- for (i = 0; i < nsems; i++)
- un->semadj[i] = 0;
- }
- sma->sem_ctime = get_seconds();
- /* maybe some queued-up processes were waiting for this */
- do_smart_update(sma, NULL, 0, 0, &tasks);
- err = 0;
- goto out_unlock;
- }
- /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */
- }
- err = -EINVAL;
- if(semnum < 0 || semnum >= nsems)
- goto out_unlock;
-
- curr = &sma->sem_base[semnum];
-
- switch (cmd) {
- case GETVAL:
- err = curr->semval;
- goto out_unlock;
- case GETPID:
- err = curr->sempid;
- goto out_unlock;
- case GETNCNT:
- err = count_semncnt(sma,semnum);
- goto out_unlock;
- case GETZCNT:
- err = count_semzcnt(sma,semnum);
- goto out_unlock;
- case SETVAL:
- {
- int val = arg.val;
- struct sem_undo *un;
-
- err = -ERANGE;
- if (val > SEMVMX || val < 0)
- goto out_unlock;
-
- assert_spin_locked(&sma->sem_perm.lock);
- list_for_each_entry(un, &sma->list_id, list_id)
- un->semadj[semnum] = 0;
-
- curr->semval = val;
- curr->sempid = task_tgid_vnr(current);
- sma->sem_ctime = get_seconds();
- /* maybe some queued-up processes were waiting for this */
- do_smart_update(sma, NULL, 0, 0, &tasks);
- err = 0;
- goto out_unlock;
- }
- }
-out_unlock:
- sem_unlock(sma);
- wake_up_sem_queue_do(&tasks);
-
-out_free:
- if(sem_io != fast_sem_io)
- ipc_free(sem_io, sizeof(ushort)*nsems);
- return err;
-}
-
-static inline unsigned long
-copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
-{
- switch(version) {
- case IPC_64:
- if (copy_from_user(out, buf, sizeof(*out)))
- return -EFAULT;
- return 0;
- case IPC_OLD:
- {
- struct semid_ds tbuf_old;
-
- if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
- return -EFAULT;
-
- out->sem_perm.uid = tbuf_old.sem_perm.uid;
- out->sem_perm.gid = tbuf_old.sem_perm.gid;
- out->sem_perm.mode = tbuf_old.sem_perm.mode;
-
- return 0;
- }
- default:
- return -EINVAL;
- }
-}
-
-/*
- * This function handles some semctl commands which require the rw_mutex
- * to be held in write mode.
- * NOTE: no locks must be held, the rw_mutex is taken inside this function.
- */
-static int semctl_down(struct ipc_namespace *ns, int semid,
- int cmd, int version, union semun arg)
-{
- struct sem_array *sma;
- int err;
- struct semid64_ds semid64;
- struct kern_ipc_perm *ipcp;
-
- if(cmd == IPC_SET) {
- if (copy_semid_from_user(&semid64, arg.buf, version))
- return -EFAULT;
- }
-
- ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
- &semid64.sem_perm, 0);
- if (IS_ERR(ipcp))
- return PTR_ERR(ipcp);
-
- sma = container_of(ipcp, struct sem_array, sem_perm);
-
- err = security_sem_semctl(sma, cmd);
- if (err)
- goto out_unlock;
-
- switch(cmd){
- case IPC_RMID:
- freeary(ns, ipcp);
- goto out_up;
- case IPC_SET:
- ipc_update_perm(&semid64.sem_perm, ipcp);
- sma->sem_ctime = get_seconds();
- break;
- default:
- err = -EINVAL;
- }
-
-out_unlock:
- sem_unlock(sma);
-out_up:
- up_write(&sem_ids(ns).rw_mutex);
- return err;
-}
-
-SYSCALL_DEFINE(semctl)(int semid, int semnum, int cmd, union semun arg)
-{
- int err = -EINVAL;
- int version;
- struct ipc_namespace *ns;
-
- if (semid < 0)
- return -EINVAL;
-
- version = ipc_parse_version(&cmd);
- ns = current->nsproxy->ipc_ns;
-
- switch(cmd) {
- case IPC_INFO:
- case SEM_INFO:
- case IPC_STAT:
- case SEM_STAT:
- err = semctl_nolock(ns, semid, cmd, version, arg);
- return err;
- case GETALL:
- case GETVAL:
- case GETPID:
- case GETNCNT:
- case GETZCNT:
- case SETVAL:
- case SETALL:
- err = semctl_main(ns,semid,semnum,cmd,version,arg);
- return err;
- case IPC_RMID:
- case IPC_SET:
- err = semctl_down(ns, semid, cmd, version, arg);
- return err;
- default:
- return -EINVAL;
- }
-}
-#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
-asmlinkage long SyS_semctl(int semid, int semnum, int cmd, union semun arg)
-{
- return SYSC_semctl((int) semid, (int) semnum, (int) cmd, arg);
-}
-SYSCALL_ALIAS(sys_semctl, SyS_semctl);
-#endif
-
-/* If the task doesn't already have a undo_list, then allocate one
- * here. We guarantee there is only one thread using this undo list,
- * and current is THE ONE
- *
- * If this allocation and assignment succeeds, but later
- * portions of this code fail, there is no need to free the sem_undo_list.
- * Just let it stay associated with the task, and it'll be freed later
- * at exit time.
- *
- * This can block, so callers must hold no locks.
- */
-static inline int get_undo_list(struct sem_undo_list **undo_listp)
-{
- struct sem_undo_list *undo_list;
-
- undo_list = current->sysvsem.undo_list;
- if (!undo_list) {
- undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL);
- if (undo_list == NULL)
- return -ENOMEM;
- spin_lock_init(&undo_list->lock);
- atomic_set(&undo_list->refcnt, 1);
- INIT_LIST_HEAD(&undo_list->list_proc);
-
- current->sysvsem.undo_list = undo_list;
- }
- *undo_listp = undo_list;
- return 0;
-}
-
-static struct sem_undo *__lookup_undo(struct sem_undo_list *ulp, int semid)
-{
- struct sem_undo *un;
-
- list_for_each_entry_rcu(un, &ulp->list_proc, list_proc) {
- if (un->semid == semid)
- return un;
- }
- return NULL;
-}
-
-static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
-{
- struct sem_undo *un;
-
- assert_spin_locked(&ulp->lock);
-
- un = __lookup_undo(ulp, semid);
- if (un) {
- list_del_rcu(&un->list_proc);
- list_add_rcu(&un->list_proc, &ulp->list_proc);
- }
- return un;
-}
-
-/**
- * find_alloc_undo - Lookup (and if not present create) undo array
- * @ns: namespace
- * @semid: semaphore array id
- *
- * The function looks up (and if not present creates) the undo structure.
- * The size of the undo structure depends on the size of the semaphore
- * array, thus the alloc path is not that straightforward.
- * Lifetime-rules: sem_undo is rcu-protected, on success, the function
- * performs a rcu_read_lock().
- */
-static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
-{
- struct sem_array *sma;
- struct sem_undo_list *ulp;
- struct sem_undo *un, *new;
- int nsems;
- int error;
-
- error = get_undo_list(&ulp);
- if (error)
- return ERR_PTR(error);
-
- rcu_read_lock();
- spin_lock(&ulp->lock);
- un = lookup_undo(ulp, semid);
- spin_unlock(&ulp->lock);
- if (likely(un!=NULL))
- goto out;
- rcu_read_unlock();
-
- /* no undo structure around - allocate one. */
- /* step 1: figure out the size of the semaphore array */
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma))
- return ERR_CAST(sma);
-
- nsems = sma->sem_nsems;
- sem_getref_and_unlock(sma);
-
- /* step 2: allocate new undo structure */
- new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
- if (!new) {
- sem_putref(sma);
- return ERR_PTR(-ENOMEM);
- }
-
- /* step 3: Acquire the lock on semaphore array */
- sem_lock_and_putref(sma);
- if (sma->sem_perm.deleted) {
- sem_unlock(sma);
- kfree(new);
- un = ERR_PTR(-EIDRM);
- goto out;
- }
- spin_lock(&ulp->lock);
-
- /*
- * step 4: check for races: did someone else allocate the undo struct?
- */
- un = lookup_undo(ulp, semid);
- if (un) {
- kfree(new);
- goto success;
- }
- /* step 5: initialize & link new undo structure */
- new->semadj = (short *) &new[1];
- new->ulp = ulp;
- new->semid = semid;
- assert_spin_locked(&ulp->lock);
- list_add_rcu(&new->list_proc, &ulp->list_proc);
- assert_spin_locked(&sma->sem_perm.lock);
- list_add(&new->list_id, &sma->list_id);
- un = new;
-
-success:
- spin_unlock(&ulp->lock);
- rcu_read_lock();
- sem_unlock(sma);
-out:
- return un;
-}
-
-
-/**
- * get_queue_result - Retrieve the result code from sem_queue
- * @q: Pointer to queue structure
- *
- * Retrieve the return code from the pending queue. If IN_WAKEUP is found in
- * q->status, then we must loop until the value is replaced with the final
- * value: This may happen if a task is woken up by an unrelated event (e.g.
- * signal) and in parallel the task is woken up by another task because it got
- * the requested semaphores.
- *
- * The function can be called with or without holding the semaphore spinlock.
- */
-static int get_queue_result(struct sem_queue *q)
-{
- int error;
-
- error = q->status;
- while (unlikely(error == IN_WAKEUP)) {
- cpu_relax();
- error = q->status;
- }
-
- return error;
-}
-
-
-SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
- unsigned, nsops, const struct timespec __user *, timeout)
-{
- int error = -EINVAL;
- struct sem_array *sma;
- struct sembuf fast_sops[SEMOPM_FAST];
- struct sembuf* sops = fast_sops, *sop;
- struct sem_undo *un;
- int undos = 0, alter = 0, max;
- struct sem_queue queue;
- unsigned long jiffies_left = 0;
- struct ipc_namespace *ns;
- struct list_head tasks;
-
- ns = current->nsproxy->ipc_ns;
-
- if (nsops < 1 || semid < 0)
- return -EINVAL;
- if (nsops > ns->sc_semopm)
- return -E2BIG;
- if(nsops > SEMOPM_FAST) {
- sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
- if(sops==NULL)
- return -ENOMEM;
- }
- if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
- error=-EFAULT;
- goto out_free;
- }
- if (timeout) {
- struct timespec _timeout;
- if (copy_from_user(&_timeout, timeout, sizeof(*timeout))) {
- error = -EFAULT;
- goto out_free;
- }
- if (_timeout.tv_sec < 0 || _timeout.tv_nsec < 0 ||
- _timeout.tv_nsec >= 1000000000L) {
- error = -EINVAL;
- goto out_free;
- }
- jiffies_left = timespec_to_jiffies(&_timeout);
- }
- max = 0;
- for (sop = sops; sop < sops + nsops; sop++) {
- if (sop->sem_num >= max)
- max = sop->sem_num;
- if (sop->sem_flg & SEM_UNDO)
- undos = 1;
- if (sop->sem_op != 0)
- alter = 1;
- }
-
- if (undos) {
- un = find_alloc_undo(ns, semid);
- if (IS_ERR(un)) {
- error = PTR_ERR(un);
- goto out_free;
- }
- } else
- un = NULL;
-
- INIT_LIST_HEAD(&tasks);
-
- sma = sem_lock_check(ns, semid);
- if (IS_ERR(sma)) {
- if (un)
- rcu_read_unlock();
- error = PTR_ERR(sma);
- goto out_free;
- }
-
- /*
- * semid identifiers are not unique - find_alloc_undo may have
- * allocated an undo structure, it was invalidated by an RMID
- * and now a new array with received the same id. Check and fail.
- * This case can be detected checking un->semid. The existence of
- * "un" itself is guaranteed by rcu.
- */
- error = -EIDRM;
- if (un) {
- if (un->semid == -1) {
- rcu_read_unlock();
- goto out_unlock_free;
- } else {
- /*
- * rcu lock can be released, "un" cannot disappear:
- * - sem_lock is acquired, thus IPC_RMID is
- * impossible.
- * - exit_sem is impossible, it always operates on
- * current (or a dead task).
- */
-
- rcu_read_unlock();
- }
- }
-
- error = -EFBIG;
- if (max >= sma->sem_nsems)
- goto out_unlock_free;
-
- error = -EACCES;
- if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
- goto out_unlock_free;
-
- error = security_sem_semop(sma, sops, nsops, alter);
- if (error)
- goto out_unlock_free;
-
- error = try_atomic_semop (sma, sops, nsops, un, task_tgid_vnr(current));
- if (error <= 0) {
- if (alter && error == 0)
- do_smart_update(sma, sops, nsops, 1, &tasks);
-
- goto out_unlock_free;
- }
-
- /* We need to sleep on this operation, so we put the current
- * task into the pending queue and go to sleep.
- */
-
- queue.sops = sops;
- queue.nsops = nsops;
- queue.undo = un;
- queue.pid = task_tgid_vnr(current);
- queue.alter = alter;
- if (alter)
- list_add_tail(&queue.list, &sma->sem_pending);
- else
- list_add(&queue.list, &sma->sem_pending);
-
- if (nsops == 1) {
- struct sem *curr;
- curr = &sma->sem_base[sops->sem_num];
-
- if (alter)
- list_add_tail(&queue.simple_list, &curr->sem_pending);
- else
- list_add(&queue.simple_list, &curr->sem_pending);
- } else {
- INIT_LIST_HEAD(&queue.simple_list);
- sma->complex_count++;
- }
-
- queue.status = -EINTR;
- queue.sleeper = current;
-
-sleep_again:
- current->state = TASK_INTERRUPTIBLE;
- sem_unlock(sma);
-
- if (timeout)
- jiffies_left = schedule_timeout(jiffies_left);
- else
- schedule();
-
- error = get_queue_result(&queue);
-
- if (error != -EINTR) {
- /* fast path: update_queue already obtained all requested
- * resources.
- * Perform a smp_mb(): User space could assume that semop()
- * is a memory barrier: Without the mb(), the cpu could
- * speculatively read in user space stale data that was
- * overwritten by the previous owner of the semaphore.
- */
- smp_mb();
-
- goto out_free;
- }
-
- sma = sem_lock(ns, semid);
-
- /*
- * Wait until it's guaranteed that no wakeup_sem_queue_do() is ongoing.
- */
- error = get_queue_result(&queue);
-
- /*
- * Array removed? If yes, leave without sem_unlock().
- */
- if (IS_ERR(sma)) {
- goto out_free;
- }
-
-
- /*
- * If queue.status != -EINTR we are woken up by another process.
- * Leave without unlink_queue(), but with sem_unlock().
- */
-
- if (error != -EINTR) {
- goto out_unlock_free;
- }
-
- /*
- * If an interrupt occurred we have to clean up the queue
- */
- if (timeout && jiffies_left == 0)
- error = -EAGAIN;
-
- /*
- * If the wakeup was spurious, just retry
- */
- if (error == -EINTR && !signal_pending(current))
- goto sleep_again;
-
- unlink_queue(sma, &queue);
-
-out_unlock_free:
- sem_unlock(sma);
-
- wake_up_sem_queue_do(&tasks);
-out_free:
- if(sops != fast_sops)
- kfree(sops);
- return error;
-}
-
-SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops,
- unsigned, nsops)
-{
- return sys_semtimedop(semid, tsops, nsops, NULL);
-}
-
-/* If CLONE_SYSVSEM is set, establish sharing of SEM_UNDO state between
- * parent and child tasks.
- */
-
-int copy_semundo(unsigned long clone_flags, struct task_struct *tsk)
-{
- struct sem_undo_list *undo_list;
- int error;
-
- if (clone_flags & CLONE_SYSVSEM) {
- error = get_undo_list(&undo_list);
- if (error)
- return error;
- atomic_inc(&undo_list->refcnt);
- tsk->sysvsem.undo_list = undo_list;
- } else
- tsk->sysvsem.undo_list = NULL;
-
- return 0;
-}
-
-/*
- * add semadj values to semaphores, free undo structures.
- * undo structures are not freed when semaphore arrays are destroyed
- * so some of them may be out of date.
- * IMPLEMENTATION NOTE: There is some confusion over whether the
- * set of adjustments that needs to be done should be done in an atomic
- * manner or not. That is, if we are attempting to decrement the semval
- * should we queue up and wait until we can do so legally?
- * The original implementation attempted to do this (queue and wait).
- * The current implementation does not do so. The POSIX standard
- * and SVID should be consulted to determine what behavior is mandated.
- */
-void exit_sem(struct task_struct *tsk)
-{
- struct sem_undo_list *ulp;
-
- ulp = tsk->sysvsem.undo_list;
- if (!ulp)
- return;
- tsk->sysvsem.undo_list = NULL;
-
- if (!atomic_dec_and_test(&ulp->refcnt))
- return;
-
- for (;;) {
- struct sem_array *sma;
- struct sem_undo *un;
- struct list_head tasks;
- int semid;
- int i;
-
- rcu_read_lock();
- un = list_entry_rcu(ulp->list_proc.next,
- struct sem_undo, list_proc);
- if (&un->list_proc == &ulp->list_proc)
- semid = -1;
- else
- semid = un->semid;
- rcu_read_unlock();
-
- if (semid == -1)
- break;
-
- sma = sem_lock_check(tsk->nsproxy->ipc_ns, un->semid);
-
- /* exit_sem raced with IPC_RMID, nothing to do */
- if (IS_ERR(sma))
- continue;
-
- un = __lookup_undo(ulp, semid);
- if (un == NULL) {
- /* exit_sem raced with IPC_RMID+semget() that created
- * exactly the same semid. Nothing to do.
- */
- sem_unlock(sma);
- continue;
- }
-
- /* remove un from the linked lists */
- assert_spin_locked(&sma->sem_perm.lock);
- list_del(&un->list_id);
-
- spin_lock(&ulp->lock);
- list_del_rcu(&un->list_proc);
- spin_unlock(&ulp->lock);
-
- /* perform adjustments registered in un */
- for (i = 0; i < sma->sem_nsems; i++) {
- struct sem * semaphore = &sma->sem_base[i];
- if (un->semadj[i]) {
- semaphore->semval += un->semadj[i];
- /*
- * Range checks of the new semaphore value,
- * not defined by sus:
- * - Some unices ignore the undo entirely
- * (e.g. HP UX 11i 11.22, Tru64 V5.1)
- * - some cap the value (e.g. FreeBSD caps
- * at 0, but doesn't enforce SEMVMX)
- *
- * Linux caps the semaphore value, both at 0
- * and at SEMVMX.
- *
- * Manfred <manfred@colorfullife.com>
- */
- if (semaphore->semval < 0)
- semaphore->semval = 0;
- if (semaphore->semval > SEMVMX)
- semaphore->semval = SEMVMX;
- semaphore->sempid = task_tgid_vnr(current);
- }
- }
- /* maybe some queued-up processes were waiting for this */
- INIT_LIST_HEAD(&tasks);
- do_smart_update(sma, NULL, 0, 1, &tasks);
- sem_unlock(sma);
- wake_up_sem_queue_do(&tasks);
-
- kfree_rcu(un, rcu);
- }
- kfree(ulp);
-}
-
-#ifdef CONFIG_PROC_FS
-static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
-{
- struct sem_array *sma = it;
-
- return seq_printf(s,
- "%10d %10d %4o %10u %5u %5u %5u %5u %10lu %10lu\n",
- sma->sem_perm.key,
- sma->sem_perm.id,
- sma->sem_perm.mode,
- sma->sem_nsems,
- sma->sem_perm.uid,
- sma->sem_perm.gid,
- sma->sem_perm.cuid,
- sma->sem_perm.cgid,
- sma->sem_otime,
- sma->sem_ctime);
-}
-#endif
diff --git a/ANDROID_3.4.5/ipc/shm.c b/ANDROID_3.4.5/ipc/shm.c
deleted file mode 100644
index 406c5b20..00000000
--- a/ANDROID_3.4.5/ipc/shm.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/*
- * linux/ipc/shm.c
- * Copyright (C) 1992, 1993 Krishna Balasubramanian
- * Many improvements/fixes by Bruno Haible.
- * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
- * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
- *
- * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
- * BIGMEM support, Andrea Arcangeli <andrea@suse.de>
- * SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
- * HIGHMEM support, Ingo Molnar <mingo@redhat.com>
- * Make shmmax, shmall, shmmni sysctl'able, Christoph Rohland <cr@sap.com>
- * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
- * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
- *
- * support for audit of ipc object properties and permission changes
- * Dustin Kirkland <dustin.kirkland@us.ibm.com>
- *
- * namespaces support
- * OpenVZ, SWsoft Inc.
- * Pavel Emelianov <xemul@openvz.org>
- */
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/hugetlb.h>
-#include <linux/shm.h>
-#include <linux/init.h>
-#include <linux/file.h>
-#include <linux/mman.h>
-#include <linux/shmem_fs.h>
-#include <linux/security.h>
-#include <linux/syscalls.h>
-#include <linux/audit.h>
-#include <linux/capability.h>
-#include <linux/ptrace.h>
-#include <linux/seq_file.h>
-#include <linux/rwsem.h>
-#include <linux/nsproxy.h>
-#include <linux/mount.h>
-#include <linux/ipc_namespace.h>
-
-#include <asm/uaccess.h>
-
-#include "util.h"
-
-struct shm_file_data {
- int id;
- struct ipc_namespace *ns;
- struct file *file;
- const struct vm_operations_struct *vm_ops;
-};
-
-#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
-
-static const struct file_operations shm_file_operations;
-static const struct vm_operations_struct shm_vm_ops;
-
-#define shm_ids(ns) ((ns)->ids[IPC_SHM_IDS])
-
-#define shm_unlock(shp) \
- ipc_unlock(&(shp)->shm_perm)
-
-static int newseg(struct ipc_namespace *, struct ipc_params *);
-static void shm_open(struct vm_area_struct *vma);
-static void shm_close(struct vm_area_struct *vma);
-static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
-#ifdef CONFIG_PROC_FS
-static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
-#endif
-
-void shm_init_ns(struct ipc_namespace *ns)
-{
- ns->shm_ctlmax = SHMMAX;
- ns->shm_ctlall = SHMALL;
- ns->shm_ctlmni = SHMMNI;
- ns->shm_rmid_forced = 0;
- ns->shm_tot = 0;
- ipc_init_ids(&shm_ids(ns));
-}
-
-/*
- * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
- * Only shm_ids.rw_mutex remains locked on exit.
- */
-static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
-{
- struct shmid_kernel *shp;
- shp = container_of(ipcp, struct shmid_kernel, shm_perm);
-
- if (shp->shm_nattch){
- shp->shm_perm.mode |= SHM_DEST;
- /* Do not find it any more */
- shp->shm_perm.key = IPC_PRIVATE;
- shm_unlock(shp);
- } else
- shm_destroy(ns, shp);
-}
-
-#ifdef CONFIG_IPC_NS
-void shm_exit_ns(struct ipc_namespace *ns)
-{
- free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
- idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr);
-}
-#endif
-
-static int __init ipc_ns_init(void)
-{
- shm_init_ns(&init_ipc_ns);
- return 0;
-}
-
-pure_initcall(ipc_ns_init);
-
-void __init shm_init (void)
-{
- ipc_init_proc_interface("sysvipc/shm",
-#if BITS_PER_LONG <= 32
- " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
-#else
- " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
-#endif
- IPC_SHM_IDS, sysvipc_shm_proc_show);
-}
-
-/*
- * shm_lock_(check_) routines are called in the paths where the rw_mutex
- * is not necessarily held.
- */
-static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct shmid_kernel *)ipcp;
-
- return container_of(ipcp, struct shmid_kernel, shm_perm);
-}
-
-static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
-{
- rcu_read_lock();
- spin_lock(&ipcp->shm_perm.lock);
-}
-
-static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
- int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct shmid_kernel *)ipcp;
-
- return container_of(ipcp, struct shmid_kernel, shm_perm);
-}
-
-static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
-{
- ipc_rmid(&shm_ids(ns), &s->shm_perm);
-}
-
-
-/* This is called by fork, once for every shm attach. */
-static void shm_open(struct vm_area_struct *vma)
-{
- struct file *file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
- struct shmid_kernel *shp;
-
- shp = shm_lock(sfd->ns, sfd->id);
- BUG_ON(IS_ERR(shp));
- shp->shm_atim = get_seconds();
- shp->shm_lprid = task_tgid_vnr(current);
- shp->shm_nattch++;
- shm_unlock(shp);
-}
-
-/*
- * shm_destroy - free the struct shmid_kernel
- *
- * @ns: namespace
- * @shp: struct to free
- *
- * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
- * but returns with shp unlocked and freed.
- */
-static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
-{
- ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
- shm_rmid(ns, shp);
- shm_unlock(shp);
- if (!is_file_hugepages(shp->shm_file))
- shmem_lock(shp->shm_file, 0, shp->mlock_user);
- 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);
- security_shm_free(shp);
- ipc_rcu_putref(shp);
-}
-
-/*
- * shm_may_destroy - identifies whether shm segment should be destroyed now
- *
- * Returns true if and only if there are no active users of the segment and
- * one of the following is true:
- *
- * 1) shmctl(id, IPC_RMID, NULL) was called for this shp
- *
- * 2) sysctl kernel.shm_rmid_forced is set to 1.
- */
-static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
-{
- return (shp->shm_nattch == 0) &&
- (ns->shm_rmid_forced ||
- (shp->shm_perm.mode & SHM_DEST));
-}
-
-/*
- * remove the attach descriptor vma.
- * free memory for segment if it is marked destroyed.
- * The descriptor has already been removed from the current->mm->mmap list
- * and will later be kfree()d.
- */
-static void shm_close(struct vm_area_struct *vma)
-{
- struct file * file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
- struct shmid_kernel *shp;
- struct ipc_namespace *ns = sfd->ns;
-
- down_write(&shm_ids(ns).rw_mutex);
- /* remove from the list of attaches of the shm segment */
- shp = shm_lock(ns, sfd->id);
- BUG_ON(IS_ERR(shp));
- shp->shm_lprid = task_tgid_vnr(current);
- shp->shm_dtim = get_seconds();
- shp->shm_nattch--;
- if (shm_may_destroy(ns, shp))
- shm_destroy(ns, shp);
- else
- shm_unlock(shp);
- up_write(&shm_ids(ns).rw_mutex);
-}
-
-/* Called with ns->shm_ids(ns).rw_mutex locked */
-static int shm_try_destroy_current(int id, void *p, void *data)
-{
- struct ipc_namespace *ns = data;
- struct kern_ipc_perm *ipcp = p;
- struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
-
- if (shp->shm_creator != current)
- return 0;
-
- /*
- * Mark it as orphaned to destroy the segment when
- * kernel.shm_rmid_forced is changed.
- * It is noop if the following shm_may_destroy() returns true.
- */
- shp->shm_creator = NULL;
-
- /*
- * Don't even try to destroy it. If shm_rmid_forced=0 and IPC_RMID
- * is not set, it shouldn't be deleted here.
- */
- if (!ns->shm_rmid_forced)
- return 0;
-
- if (shm_may_destroy(ns, shp)) {
- shm_lock_by_ptr(shp);
- shm_destroy(ns, shp);
- }
- return 0;
-}
-
-/* Called with ns->shm_ids(ns).rw_mutex locked */
-static int shm_try_destroy_orphaned(int id, void *p, void *data)
-{
- struct ipc_namespace *ns = data;
- struct kern_ipc_perm *ipcp = p;
- struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
-
- /*
- * We want to destroy segments without users and with already
- * exit'ed originating process.
- *
- * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
- */
- if (shp->shm_creator != NULL)
- return 0;
-
- if (shm_may_destroy(ns, shp)) {
- shm_lock_by_ptr(shp);
- shm_destroy(ns, shp);
- }
- return 0;
-}
-
-void shm_destroy_orphaned(struct ipc_namespace *ns)
-{
- down_write(&shm_ids(ns).rw_mutex);
- if (shm_ids(ns).in_use)
- idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
- up_write(&shm_ids(ns).rw_mutex);
-}
-
-
-void exit_shm(struct task_struct *task)
-{
- struct ipc_namespace *ns = task->nsproxy->ipc_ns;
-
- if (shm_ids(ns).in_use == 0)
- return;
-
- /* Destroy all already created segments, but not mapped yet */
- down_write(&shm_ids(ns).rw_mutex);
- if (shm_ids(ns).in_use)
- idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
- up_write(&shm_ids(ns).rw_mutex);
-}
-
-static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
-{
- struct file *file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
-
- return sfd->vm_ops->fault(vma, vmf);
-}
-
-#ifdef CONFIG_NUMA
-static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
-{
- struct file *file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
- int err = 0;
- if (sfd->vm_ops->set_policy)
- err = sfd->vm_ops->set_policy(vma, new);
- return err;
-}
-
-static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
- unsigned long addr)
-{
- struct file *file = vma->vm_file;
- struct shm_file_data *sfd = shm_file_data(file);
- struct mempolicy *pol = NULL;
-
- if (sfd->vm_ops->get_policy)
- pol = sfd->vm_ops->get_policy(vma, addr);
- else if (vma->vm_policy)
- pol = vma->vm_policy;
-
- return pol;
-}
-#endif
-
-static int shm_mmap(struct file * file, struct vm_area_struct * vma)
-{
- struct shm_file_data *sfd = shm_file_data(file);
- int ret;
-
- ret = sfd->file->f_op->mmap(sfd->file, vma);
- if (ret != 0)
- return ret;
- sfd->vm_ops = vma->vm_ops;
-#ifdef CONFIG_MMU
- BUG_ON(!sfd->vm_ops->fault);
-#endif
- vma->vm_ops = &shm_vm_ops;
- shm_open(vma);
-
- return ret;
-}
-
-static int shm_release(struct inode *ino, struct file *file)
-{
- struct shm_file_data *sfd = shm_file_data(file);
-
- put_ipc_ns(sfd->ns);
- shm_file_data(file) = NULL;
- kfree(sfd);
- return 0;
-}
-
-static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
-{
- struct shm_file_data *sfd = shm_file_data(file);
-
- if (!sfd->file->f_op->fsync)
- return -EINVAL;
- return sfd->file->f_op->fsync(sfd->file, start, end, datasync);
-}
-
-static unsigned long shm_get_unmapped_area(struct file *file,
- unsigned long addr, unsigned long len, unsigned long pgoff,
- unsigned long flags)
-{
- struct shm_file_data *sfd = shm_file_data(file);
- 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,
-#ifndef CONFIG_MMU
- .get_unmapped_area = shm_get_unmapped_area,
-#endif
- .llseek = noop_llseek,
-};
-
-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,
- .llseek = noop_llseek,
-};
-
-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,
-#if defined(CONFIG_NUMA)
- .set_policy = shm_set_policy,
- .get_policy = shm_get_policy,
-#endif
-};
-
-/**
- * newseg - Create a new shared memory segment
- * @ns: namespace
- * @params: ptr to the structure that contains key, size and shmflg
- *
- * Called with shm_ids.rw_mutex held as a writer.
- */
-
-static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
-{
- key_t key = params->key;
- int shmflg = params->flg;
- size_t size = params->u.size;
- int error;
- struct shmid_kernel *shp;
- int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
- struct file * file;
- char name[13];
- int id;
- vm_flags_t acctflag = 0;
-
- if (size < SHMMIN || size > ns->shm_ctlmax)
- return -EINVAL;
-
- if (ns->shm_tot + numpages > ns->shm_ctlall)
- return -ENOSPC;
-
- shp = ipc_rcu_alloc(sizeof(*shp));
- if (!shp)
- return -ENOMEM;
-
- shp->shm_perm.key = key;
- shp->shm_perm.mode = (shmflg & S_IRWXUGO);
- shp->mlock_user = NULL;
-
- shp->shm_perm.security = NULL;
- error = security_shm_alloc(shp);
- if (error) {
- ipc_rcu_putref(shp);
- return error;
- }
-
- sprintf (name, "SYSV%08x", key);
- if (shmflg & SHM_HUGETLB) {
- /* hugetlb_file_setup applies strict accounting */
- if (shmflg & SHM_NORESERVE)
- acctflag = VM_NORESERVE;
- file = hugetlb_file_setup(name, 0, size, acctflag,
- &shp->mlock_user, HUGETLB_SHMFS_INODE);
- } else {
- /*
- * Do not allow no accounting for OVERCOMMIT_NEVER, even
- * if it's asked for.
- */
- if ((shmflg & SHM_NORESERVE) &&
- sysctl_overcommit_memory != OVERCOMMIT_NEVER)
- acctflag = VM_NORESERVE;
- file = shmem_file_setup(name, size, acctflag);
- }
- error = PTR_ERR(file);
- if (IS_ERR(file))
- goto no_file;
-
- id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
- if (id < 0) {
- error = id;
- goto no_id;
- }
-
- shp->shm_cprid = task_tgid_vnr(current);
- shp->shm_lprid = 0;
- shp->shm_atim = shp->shm_dtim = 0;
- shp->shm_ctim = get_seconds();
- shp->shm_segsz = size;
- shp->shm_nattch = 0;
- shp->shm_file = file;
- shp->shm_creator = current;
- /*
- * shmid gets reported as "inode#" in /proc/pid/maps.
- * proc-ps tools use this. Changing this will break them.
- */
- file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
-
- ns->shm_tot += numpages;
- error = shp->shm_perm.id;
- shm_unlock(shp);
- 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);
- ipc_rcu_putref(shp);
- return error;
-}
-
-/*
- * Called with shm_ids.rw_mutex and ipcp locked.
- */
-static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
-{
- struct shmid_kernel *shp;
-
- shp = container_of(ipcp, struct shmid_kernel, shm_perm);
- return security_shm_associate(shp, shmflg);
-}
-
-/*
- * Called with shm_ids.rw_mutex and ipcp locked.
- */
-static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
- struct ipc_params *params)
-{
- struct shmid_kernel *shp;
-
- shp = container_of(ipcp, struct shmid_kernel, shm_perm);
- if (shp->shm_segsz < params->u.size)
- return -EINVAL;
-
- return 0;
-}
-
-SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
-{
- struct ipc_namespace *ns;
- struct ipc_ops shm_ops;
- struct ipc_params shm_params;
-
- ns = current->nsproxy->ipc_ns;
-
- shm_ops.getnew = newseg;
- shm_ops.associate = shm_security;
- shm_ops.more_checks = shm_more_checks;
-
- shm_params.key = key;
- shm_params.flg = shmflg;
- shm_params.u.size = size;
-
- return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
-}
-
-static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
-{
- switch(version) {
- case IPC_64:
- return copy_to_user(buf, in, sizeof(*in));
- case IPC_OLD:
- {
- struct shmid_ds out;
-
- memset(&out, 0, sizeof(out));
- ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
- out.shm_segsz = in->shm_segsz;
- out.shm_atime = in->shm_atime;
- out.shm_dtime = in->shm_dtime;
- out.shm_ctime = in->shm_ctime;
- out.shm_cpid = in->shm_cpid;
- out.shm_lpid = in->shm_lpid;
- out.shm_nattch = in->shm_nattch;
-
- return copy_to_user(buf, &out, sizeof(out));
- }
- default:
- return -EINVAL;
- }
-}
-
-static inline unsigned long
-copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version)
-{
- switch(version) {
- case IPC_64:
- if (copy_from_user(out, buf, sizeof(*out)))
- return -EFAULT;
- return 0;
- case IPC_OLD:
- {
- struct shmid_ds tbuf_old;
-
- if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
- return -EFAULT;
-
- out->shm_perm.uid = tbuf_old.shm_perm.uid;
- out->shm_perm.gid = tbuf_old.shm_perm.gid;
- out->shm_perm.mode = tbuf_old.shm_perm.mode;
-
- return 0;
- }
- default:
- return -EINVAL;
- }
-}
-
-static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
-{
- switch(version) {
- case IPC_64:
- return copy_to_user(buf, in, sizeof(*in));
- case IPC_OLD:
- {
- struct shminfo out;
-
- if(in->shmmax > INT_MAX)
- out.shmmax = INT_MAX;
- else
- out.shmmax = (int)in->shmmax;
-
- out.shmmin = in->shmmin;
- out.shmmni = in->shmmni;
- out.shmseg = in->shmseg;
- out.shmall = in->shmall;
-
- return copy_to_user(buf, &out, sizeof(out));
- }
- default:
- return -EINVAL;
- }
-}
-
-/*
- * Calculate and add used RSS and swap pages of a shm.
- * Called with shm_ids.rw_mutex held as a reader
- */
-static void shm_add_rss_swap(struct shmid_kernel *shp,
- unsigned long *rss_add, unsigned long *swp_add)
-{
- struct inode *inode;
-
- inode = shp->shm_file->f_path.dentry->d_inode;
-
- if (is_file_hugepages(shp->shm_file)) {
- struct address_space *mapping = inode->i_mapping;
- struct hstate *h = hstate_file(shp->shm_file);
- *rss_add += pages_per_huge_page(h) * mapping->nrpages;
- } else {
-#ifdef CONFIG_SHMEM
- struct shmem_inode_info *info = SHMEM_I(inode);
- spin_lock(&info->lock);
- *rss_add += inode->i_mapping->nrpages;
- *swp_add += info->swapped;
- spin_unlock(&info->lock);
-#else
- *rss_add += inode->i_mapping->nrpages;
-#endif
- }
-}
-
-/*
- * Called with shm_ids.rw_mutex held as a reader
- */
-static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
- unsigned long *swp)
-{
- int next_id;
- int total, in_use;
-
- *rss = 0;
- *swp = 0;
-
- 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;
-
- ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
- if (ipc == NULL)
- continue;
- shp = container_of(ipc, struct shmid_kernel, shm_perm);
-
- shm_add_rss_swap(shp, rss, swp);
-
- total++;
- }
-}
-
-/*
- * This function handles some shmctl commands which require the rw_mutex
- * to be held in write mode.
- * NOTE: no locks must be held, the rw_mutex is taken inside this function.
- */
-static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
- struct shmid_ds __user *buf, int version)
-{
- struct kern_ipc_perm *ipcp;
- struct shmid64_ds shmid64;
- struct shmid_kernel *shp;
- int err;
-
- if (cmd == IPC_SET) {
- if (copy_shmid_from_user(&shmid64, buf, version))
- return -EFAULT;
- }
-
- ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
- &shmid64.shm_perm, 0);
- if (IS_ERR(ipcp))
- return PTR_ERR(ipcp);
-
- shp = container_of(ipcp, struct shmid_kernel, shm_perm);
-
- err = security_shm_shmctl(shp, cmd);
- if (err)
- goto out_unlock;
- switch (cmd) {
- case IPC_RMID:
- do_shm_rmid(ns, ipcp);
- goto out_up;
- case IPC_SET:
- ipc_update_perm(&shmid64.shm_perm, ipcp);
- shp->shm_ctim = get_seconds();
- break;
- default:
- err = -EINVAL;
- }
-out_unlock:
- shm_unlock(shp);
-out_up:
- up_write(&shm_ids(ns).rw_mutex);
- return err;
-}
-
-SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
-{
- struct shmid_kernel *shp;
- int err, version;
- struct ipc_namespace *ns;
-
- if (cmd < 0 || shmid < 0) {
- err = -EINVAL;
- goto out;
- }
-
- version = ipc_parse_version(&cmd);
- ns = current->nsproxy->ipc_ns;
-
- switch (cmd) { /* replace with proc interface ? */
- case IPC_INFO:
- {
- struct shminfo64 shminfo;
-
- err = security_shm_shmctl(NULL, cmd);
- if (err)
- return err;
-
- memset(&shminfo, 0, sizeof(shminfo));
- shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
- shminfo.shmmax = ns->shm_ctlmax;
- shminfo.shmall = ns->shm_ctlall;
-
- shminfo.shmmin = SHMMIN;
- if(copy_shminfo_to_user (buf, &shminfo, version))
- return -EFAULT;
-
- down_read(&shm_ids(ns).rw_mutex);
- err = ipc_get_maxid(&shm_ids(ns));
- up_read(&shm_ids(ns).rw_mutex);
-
- if(err<0)
- err = 0;
- goto out;
- }
- case SHM_INFO:
- {
- struct shm_info shm_info;
-
- err = security_shm_shmctl(NULL, cmd);
- if (err)
- return err;
-
- memset(&shm_info, 0, sizeof(shm_info));
- down_read(&shm_ids(ns).rw_mutex);
- shm_info.used_ids = shm_ids(ns).in_use;
- shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
- shm_info.shm_tot = ns->shm_tot;
- shm_info.swap_attempts = 0;
- shm_info.swap_successes = 0;
- err = ipc_get_maxid(&shm_ids(ns));
- up_read(&shm_ids(ns).rw_mutex);
- if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
- err = -EFAULT;
- goto out;
- }
-
- err = err < 0 ? 0 : err;
- goto out;
- }
- case SHM_STAT:
- case IPC_STAT:
- {
- struct shmid64_ds tbuf;
- int result;
-
- if (cmd == SHM_STAT) {
- shp = shm_lock(ns, shmid);
- if (IS_ERR(shp)) {
- err = PTR_ERR(shp);
- goto out;
- }
- result = shp->shm_perm.id;
- } else {
- shp = shm_lock_check(ns, shmid);
- if (IS_ERR(shp)) {
- err = PTR_ERR(shp);
- goto out;
- }
- result = 0;
- }
- err = -EACCES;
- if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
- goto out_unlock;
- err = security_shm_shmctl(shp, cmd);
- if (err)
- goto out_unlock;
- memset(&tbuf, 0, sizeof(tbuf));
- 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(shp);
- if(copy_shmid_to_user (buf, &tbuf, version))
- err = -EFAULT;
- else
- err = result;
- goto out;
- }
- case SHM_LOCK:
- case SHM_UNLOCK:
- {
- struct file *shm_file;
-
- shp = shm_lock_check(ns, shmid);
- if (IS_ERR(shp)) {
- err = PTR_ERR(shp);
- goto out;
- }
-
- audit_ipc_obj(&(shp->shm_perm));
-
- if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
- uid_t euid = current_euid();
- err = -EPERM;
- if (euid != shp->shm_perm.uid &&
- euid != shp->shm_perm.cuid)
- goto out_unlock;
- if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
- goto out_unlock;
- }
-
- err = security_shm_shmctl(shp, cmd);
- if (err)
- goto out_unlock;
-
- shm_file = shp->shm_file;
- if (is_file_hugepages(shm_file))
- goto out_unlock;
-
- if (cmd == SHM_LOCK) {
- struct user_struct *user = current_user();
- err = shmem_lock(shm_file, 1, user);
- if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
- shp->shm_perm.mode |= SHM_LOCKED;
- shp->mlock_user = user;
- }
- goto out_unlock;
- }
-
- /* SHM_UNLOCK */
- if (!(shp->shm_perm.mode & SHM_LOCKED))
- goto out_unlock;
- shmem_lock(shm_file, 0, shp->mlock_user);
- shp->shm_perm.mode &= ~SHM_LOCKED;
- shp->mlock_user = NULL;
- get_file(shm_file);
- shm_unlock(shp);
- shmem_unlock_mapping(shm_file->f_mapping);
- fput(shm_file);
- goto out;
- }
- case IPC_RMID:
- case IPC_SET:
- err = shmctl_down(ns, shmid, cmd, buf, version);
- return err;
- default:
- return -EINVAL;
- }
-
-out_unlock:
- shm_unlock(shp);
-out:
- return err;
-}
-
-/*
- * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
- *
- * NOTE! Despite the name, this is NOT a direct system call entrypoint. The
- * "raddr" thing points to kernel space, and there has to be a wrapper around
- * this.
- */
-long do_shmat(int shmid, char __user *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;
- int acc_mode;
- unsigned long user_addr;
- struct ipc_namespace *ns;
- struct shm_file_data *sfd;
- struct path path;
- fmode_t f_mode;
-
- err = -EINVAL;
- if (shmid < 0)
- goto out;
- else if ((addr = (ulong)shmaddr)) {
- if (addr & (SHMLBA-1)) {
- if (shmflg & SHM_RND)
- addr &= ~(SHMLBA-1); /* round down */
- else
-#ifndef __ARCH_FORCE_SHMLBA
- if (addr & ~PAGE_MASK)
-#endif
- goto out;
- }
- flags = MAP_SHARED | MAP_FIXED;
- } else {
- if ((shmflg & SHM_REMAP))
- goto out;
-
- flags = MAP_SHARED;
- }
-
- if (shmflg & SHM_RDONLY) {
- prot = PROT_READ;
- acc_mode = S_IRUGO;
- f_mode = FMODE_READ;
- } else {
- prot = PROT_READ | PROT_WRITE;
- acc_mode = S_IRUGO | S_IWUGO;
- f_mode = FMODE_READ | FMODE_WRITE;
- }
- if (shmflg & SHM_EXEC) {
- prot |= PROT_EXEC;
- acc_mode |= S_IXUGO;
- }
-
- /*
- * We cannot rely on the fs check since SYSV IPC does have an
- * additional creator id...
- */
- ns = current->nsproxy->ipc_ns;
- shp = shm_lock_check(ns, shmid);
- if (IS_ERR(shp)) {
- err = PTR_ERR(shp);
- goto out;
- }
-
- err = -EACCES;
- if (ipcperms(ns, &shp->shm_perm, acc_mode))
- goto out_unlock;
-
- err = security_shm_shmat(shp, shmaddr, shmflg);
- if (err)
- goto out_unlock;
-
- path = shp->shm_file->f_path;
- path_get(&path);
- shp->shm_nattch++;
- size = i_size_read(path.dentry->d_inode);
- shm_unlock(shp);
-
- err = -ENOMEM;
- sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
- if (!sfd)
- goto out_put_dentry;
-
- file = alloc_file(&path, f_mode,
- is_file_hugepages(shp->shm_file) ?
- &shm_file_operations_huge :
- &shm_file_operations);
- if (!file)
- goto out_free;
-
- file->private_data = sfd;
- file->f_mapping = shp->shm_file->f_mapping;
- sfd->id = shp->shm_perm.id;
- sfd->ns = get_ipc_ns(ns);
- sfd->file = shp->shm_file;
- sfd->vm_ops = NULL;
-
- down_write(&current->mm->mmap_sem);
- if (addr && !(shmflg & SHM_REMAP)) {
- err = -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 = do_mmap (file, addr, size, prot, flags, 0);
- *raddr = user_addr;
- err = 0;
- if (IS_ERR_VALUE(user_addr))
- err = (long)user_addr;
-invalid:
- up_write(&current->mm->mmap_sem);
-
- fput(file);
-
-out_nattch:
- down_write(&shm_ids(ns).rw_mutex);
- shp = shm_lock(ns, shmid);
- BUG_ON(IS_ERR(shp));
- shp->shm_nattch--;
- if (shm_may_destroy(ns, shp))
- shm_destroy(ns, shp);
- else
- shm_unlock(shp);
- up_write(&shm_ids(ns).rw_mutex);
-
-out:
- return err;
-
-out_unlock:
- shm_unlock(shp);
- goto out;
-
-out_free:
- kfree(sfd);
-out_put_dentry:
- path_put(&path);
- goto out_nattch;
-}
-
-SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
-{
- unsigned long ret;
- long err;
-
- err = do_shmat(shmid, shmaddr, shmflg, &ret);
- if (err)
- return err;
- force_successful_syscall_return();
- return (long)ret;
-}
-
-/*
- * detach and kill segment if marked destroyed.
- * The work is done in shm_close.
- */
-SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- unsigned long addr = (unsigned long)shmaddr;
- int retval = -EINVAL;
-#ifdef CONFIG_MMU
- loff_t size = 0;
- struct vm_area_struct *next;
-#endif
-
- if (addr & ~PAGE_MASK)
- return retval;
-
- down_write(&mm->mmap_sem);
-
- /*
- * This function tries to be smart and unmap shm segments that
- * were modified by partial mlock or munmap calls:
- * - It first determines the size of the shm segment that should be
- * unmapped: It searches for a vma that is backed by shm and that
- * started at address shmaddr. It records it's size and then unmaps
- * it.
- * - Then it unmaps all shm vmas that started at shmaddr and that
- * are within the initially determined size.
- * Errors from do_munmap are ignored: the function only fails if
- * it's called with invalid parameters or if it's called to unmap
- * a part of a vma. Both calls in this function are for full vmas,
- * the parameters are directly copied from the vma itself and always
- * valid - therefore do_munmap cannot fail. (famous last words?)
- */
- /*
- * If it had been mremap()'d, the starting address would not
- * match the usual checks anyway. So assume all vma's are
- * above the starting address given.
- */
- vma = find_vma(mm, addr);
-
-#ifdef CONFIG_MMU
- while (vma) {
- next = vma->vm_next;
-
- /*
- * Check if the starting address would match, i.e. it's
- * a fragment created by mprotect() and/or munmap(), or it
- * otherwise it starts at this address with no hassles.
- */
- if ((vma->vm_ops == &shm_vm_ops) &&
- (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
-
-
- size = vma->vm_file->f_path.dentry->d_inode->i_size;
- do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
- /*
- * We discovered the size of the shm segment, so
- * break out of here and fall through to the next
- * loop that uses the size information to stop
- * searching for matching vma's.
- */
- retval = 0;
- vma = next;
- break;
- }
- vma = next;
- }
-
- /*
- * We need look no further than the maximum address a fragment
- * could possibly have landed at. Also cast things to loff_t to
- * prevent overflows and make comparisons vs. equal-width types.
- */
- size = PAGE_ALIGN(size);
- while (vma && (loff_t)(vma->vm_end - addr) <= size) {
- next = vma->vm_next;
-
- /* finding a matching vma now does not alter retval */
- if ((vma->vm_ops == &shm_vm_ops) &&
- (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
-
- do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
- 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;
-}
-
-#ifdef CONFIG_PROC_FS
-static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
-{
- struct shmid_kernel *shp = it;
- unsigned long rss = 0, swp = 0;
-
- shm_add_rss_swap(shp, &rss, &swp);
-
-#if BITS_PER_LONG <= 32
-#define SIZE_SPEC "%10lu"
-#else
-#define SIZE_SPEC "%21lu"
-#endif
-
- return seq_printf(s,
- "%10d %10d %4o " SIZE_SPEC " %5u %5u "
- "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
- SIZE_SPEC " " SIZE_SPEC "\n",
- shp->shm_perm.key,
- shp->shm_perm.id,
- shp->shm_perm.mode,
- 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,
- rss * PAGE_SIZE,
- swp * PAGE_SIZE);
-}
-#endif
diff --git a/ANDROID_3.4.5/ipc/syscall.c b/ANDROID_3.4.5/ipc/syscall.c
deleted file mode 100644
index 1d6f53f6..00000000
--- a/ANDROID_3.4.5/ipc/syscall.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * sys_ipc() is the old de-multiplexer for the SysV IPC calls.
- *
- * This is really horribly ugly, and new architectures should just wire up
- * the individual syscalls instead.
- */
-#include <linux/unistd.h>
-
-#ifdef __ARCH_WANT_SYS_IPC
-#include <linux/errno.h>
-#include <linux/ipc.h>
-#include <linux/shm.h>
-#include <linux/syscalls.h>
-#include <linux/uaccess.h>
-
-SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, unsigned long, second,
- unsigned long, third, void __user *, ptr, long, fifth)
-{
- int version, ret;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMOP:
- return sys_semtimedop(first, (struct sembuf __user *)ptr,
- second, NULL);
- case SEMTIMEDOP:
- return sys_semtimedop(first, (struct sembuf __user *)ptr,
- second,
- (const struct timespec __user *)fifth);
-
- case SEMGET:
- return sys_semget(first, second, third);
- case SEMCTL: {
- union semun fourth;
- if (!ptr)
- return -EINVAL;
- if (get_user(fourth.__pad, (void __user * __user *) ptr))
- return -EFAULT;
- return sys_semctl(first, second, third, fourth);
- }
-
- case MSGSND:
- return sys_msgsnd(first, (struct msgbuf __user *) ptr,
- second, third);
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
- if (!ptr)
- return -EINVAL;
-
- if (copy_from_user(&tmp,
- (struct ipc_kludge __user *) ptr,
- sizeof(tmp)))
- return -EFAULT;
- return sys_msgrcv(first, tmp.msgp, second,
- tmp.msgtyp, third);
- }
- default:
- return sys_msgrcv(first,
- (struct msgbuf __user *) ptr,
- second, fifth, third);
- }
- case MSGGET:
- return sys_msgget((key_t) first, second);
- case MSGCTL:
- return sys_msgctl(first, second, (struct msqid_ds __user *)ptr);
-
- case SHMAT:
- switch (version) {
- default: {
- unsigned long raddr;
- ret = do_shmat(first, (char __user *)ptr,
- second, &raddr);
- if (ret)
- return ret;
- return put_user(raddr, (unsigned long __user *) third);
- }
- case 1:
- /*
- * This was the entry point for kernel-originating calls
- * from iBCS2 in 2.2 days.
- */
- return -EINVAL;
- }
- case SHMDT:
- return sys_shmdt((char __user *)ptr);
- case SHMGET:
- return sys_shmget(first, second, third);
- case SHMCTL:
- return sys_shmctl(first, second,
- (struct shmid_ds __user *) ptr);
- default:
- return -ENOSYS;
- }
-}
-#endif
diff --git a/ANDROID_3.4.5/ipc/util.c b/ANDROID_3.4.5/ipc/util.c
deleted file mode 100644
index 75261a31..00000000
--- a/ANDROID_3.4.5/ipc/util.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * linux/ipc/util.c
- * Copyright (C) 1992 Krishna Balasubramanian
- *
- * Sep 1997 - Call suser() last after "normal" permission checks so we
- * get BSD style process accounting right.
- * Occurs in several places in the IPC code.
- * Chris Evans, <chris@ferret.lmh.ox.ac.uk>
- * Nov 1999 - ipc helper functions, unified SMP locking
- * Manfred Spraul <manfred@colorfullife.com>
- * Oct 2002 - One lock per IPC id. RCU ipc_free for lock-free grow_ary().
- * Mingming Cao <cmm@us.ibm.com>
- * Mar 2006 - support for audit of ipc object properties
- * Dustin Kirkland <dustin.kirkland@us.ibm.com>
- * Jun 2006 - namespaces ssupport
- * OpenVZ, SWsoft Inc.
- * Pavel Emelianov <xemul@openvz.org>
- */
-
-#include <linux/mm.h>
-#include <linux/shm.h>
-#include <linux/init.h>
-#include <linux/msg.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/capability.h>
-#include <linux/highuid.h>
-#include <linux/security.h>
-#include <linux/rcupdate.h>
-#include <linux/workqueue.h>
-#include <linux/seq_file.h>
-#include <linux/proc_fs.h>
-#include <linux/audit.h>
-#include <linux/nsproxy.h>
-#include <linux/rwsem.h>
-#include <linux/memory.h>
-#include <linux/ipc_namespace.h>
-
-#include <asm/unistd.h>
-
-#include "util.h"
-
-struct ipc_proc_iface {
- const char *path;
- const char *header;
- int ids;
- int (*show)(struct seq_file *, void *);
-};
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-
-static void ipc_memory_notifier(struct work_struct *work)
-{
- ipcns_notify(IPCNS_MEMCHANGED);
-}
-
-static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
-
-
-static int ipc_memory_callback(struct notifier_block *self,
- unsigned long action, void *arg)
-{
- switch (action) {
- case MEM_ONLINE: /* memory successfully brought online */
- case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */
- /*
- * This is done by invoking the ipcns notifier chain with the
- * IPC_MEMCHANGED event.
- * In order not to keep the lock on the hotplug memory chain
- * for too long, queue a work item that will, when waken up,
- * activate the ipcns notification chain.
- * No need to keep several ipc work items on the queue.
- */
- if (!work_pending(&ipc_memory_wq))
- schedule_work(&ipc_memory_wq);
- break;
- case MEM_GOING_ONLINE:
- case MEM_GOING_OFFLINE:
- case MEM_CANCEL_ONLINE:
- case MEM_CANCEL_OFFLINE:
- default:
- break;
- }
-
- return NOTIFY_OK;
-}
-
-#endif /* CONFIG_MEMORY_HOTPLUG */
-
-/**
- * ipc_init - initialise IPC subsystem
- *
- * The various system5 IPC resources (semaphores, messages and shared
- * memory) are initialised
- * A callback routine is registered into the memory hotplug notifier
- * chain: since msgmni scales to lowmem this callback routine will be
- * called upon successful memory add / remove to recompute msmgni.
- */
-
-static int __init ipc_init(void)
-{
- sem_init();
- msg_init();
- shm_init();
- hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
- register_ipcns_notifier(&init_ipc_ns);
- return 0;
-}
-__initcall(ipc_init);
-
-/**
- * ipc_init_ids - initialise IPC identifiers
- * @ids: Identifier set
- *
- * Set up the sequence range to use for the ipc identifier range (limited
- * below IPCMNI) then initialise the ids idr.
- */
-
-void ipc_init_ids(struct ipc_ids *ids)
-{
- init_rwsem(&ids->rw_mutex);
-
- ids->in_use = 0;
- ids->seq = 0;
- {
- int seq_limit = INT_MAX/SEQ_MULTIPLIER;
- if (seq_limit > USHRT_MAX)
- ids->seq_max = USHRT_MAX;
- else
- ids->seq_max = seq_limit;
- }
-
- idr_init(&ids->ipcs_idr);
-}
-
-#ifdef CONFIG_PROC_FS
-static const struct file_operations sysvipc_proc_fops;
-/**
- * ipc_init_proc_interface - Create a proc interface for sysipc types using a seq_file interface.
- * @path: Path in procfs
- * @header: Banner to be printed at the beginning of the file.
- * @ids: ipc id table to iterate.
- * @show: show routine.
- */
-void __init ipc_init_proc_interface(const char *path, const char *header,
- int ids, int (*show)(struct seq_file *, void *))
-{
- struct proc_dir_entry *pde;
- struct ipc_proc_iface *iface;
-
- iface = kmalloc(sizeof(*iface), GFP_KERNEL);
- if (!iface)
- return;
- iface->path = path;
- iface->header = header;
- iface->ids = ids;
- iface->show = show;
-
- pde = proc_create_data(path,
- S_IRUGO, /* world readable */
- NULL, /* parent dir */
- &sysvipc_proc_fops,
- iface);
- if (!pde) {
- kfree(iface);
- }
-}
-#endif
-
-/**
- * ipc_findkey - find a key in an ipc identifier set
- * @ids: Identifier set
- * @key: The key to find
- *
- * Requires ipc_ids.rw_mutex locked.
- * Returns the LOCKED pointer to the ipc structure if found or NULL
- * if not.
- * If key is found ipc points to the owning ipc structure
- */
-
-static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
-{
- struct kern_ipc_perm *ipc;
- int next_id;
- int total;
-
- for (total = 0, next_id = 0; total < ids->in_use; next_id++) {
- ipc = idr_find(&ids->ipcs_idr, next_id);
-
- if (ipc == NULL)
- continue;
-
- if (ipc->key != key) {
- total++;
- continue;
- }
-
- ipc_lock_by_ptr(ipc);
- return ipc;
- }
-
- return NULL;
-}
-
-/**
- * ipc_get_maxid - get the last assigned id
- * @ids: IPC identifier set
- *
- * Called with ipc_ids.rw_mutex held.
- */
-
-int ipc_get_maxid(struct ipc_ids *ids)
-{
- struct kern_ipc_perm *ipc;
- int max_id = -1;
- int total, id;
-
- if (ids->in_use == 0)
- return -1;
-
- if (ids->in_use == IPCMNI)
- return IPCMNI - 1;
-
- /* Look for the last assigned id */
- total = 0;
- for (id = 0; id < IPCMNI && total < ids->in_use; id++) {
- ipc = idr_find(&ids->ipcs_idr, id);
- if (ipc != NULL) {
- max_id = id;
- total++;
- }
- }
- return max_id;
-}
-
-/**
- * ipc_addid - add an IPC identifier
- * @ids: IPC identifier set
- * @new: new IPC permission set
- * @size: limit for the number of used ids
- *
- * Add an entry 'new' to the IPC ids idr. The permissions object is
- * initialised and the first free entry is set up and the id assigned
- * is returned. The 'new' entry is returned in a locked state on success.
- * On failure the entry is not locked and a negative err-code is returned.
- *
- * Called with ipc_ids.rw_mutex held as a writer.
- */
-
-int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
-{
- uid_t euid;
- gid_t egid;
- int id, err;
-
- if (size > IPCMNI)
- size = IPCMNI;
-
- if (ids->in_use >= size)
- return -ENOSPC;
-
- spin_lock_init(&new->lock);
- new->deleted = 0;
- rcu_read_lock();
- spin_lock(&new->lock);
-
- err = idr_get_new(&ids->ipcs_idr, new, &id);
- if (err) {
- spin_unlock(&new->lock);
- rcu_read_unlock();
- return err;
- }
-
- ids->in_use++;
-
- current_euid_egid(&euid, &egid);
- new->cuid = new->uid = euid;
- new->gid = new->cgid = egid;
-
- new->seq = ids->seq++;
- if(ids->seq > ids->seq_max)
- ids->seq = 0;
-
- new->id = ipc_buildid(id, new->seq);
- return id;
-}
-
-/**
- * ipcget_new - create a new ipc object
- * @ns: namespace
- * @ids: IPC identifer set
- * @ops: the actual creation routine to call
- * @params: its parameters
- *
- * This routine is called by sys_msgget, sys_semget() and sys_shmget()
- * when the key is IPC_PRIVATE.
- */
-static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
- struct ipc_ops *ops, struct ipc_params *params)
-{
- int err;
-retry:
- err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
-
- if (!err)
- return -ENOMEM;
-
- down_write(&ids->rw_mutex);
- err = ops->getnew(ns, params);
- up_write(&ids->rw_mutex);
-
- if (err == -EAGAIN)
- goto retry;
-
- return err;
-}
-
-/**
- * ipc_check_perms - check security and permissions for an IPC
- * @ns: IPC namespace
- * @ipcp: ipc permission set
- * @ops: the actual security routine to call
- * @params: its parameters
- *
- * This routine is called by sys_msgget(), sys_semget() and sys_shmget()
- * when the key is not IPC_PRIVATE and that key already exists in the
- * ids IDR.
- *
- * On success, the IPC id is returned.
- *
- * It is called with ipc_ids.rw_mutex and ipcp->lock held.
- */
-static int ipc_check_perms(struct ipc_namespace *ns,
- struct kern_ipc_perm *ipcp,
- struct ipc_ops *ops,
- struct ipc_params *params)
-{
- int err;
-
- if (ipcperms(ns, ipcp, params->flg))
- err = -EACCES;
- else {
- err = ops->associate(ipcp, params->flg);
- if (!err)
- err = ipcp->id;
- }
-
- return err;
-}
-
-/**
- * ipcget_public - get an ipc object or create a new one
- * @ns: namespace
- * @ids: IPC identifer set
- * @ops: the actual creation routine to call
- * @params: its parameters
- *
- * This routine is called by sys_msgget, sys_semget() and sys_shmget()
- * when the key is not IPC_PRIVATE.
- * It adds a new entry if the key is not found and does some permission
- * / security checkings if the key is found.
- *
- * On success, the ipc id is returned.
- */
-static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
- struct ipc_ops *ops, struct ipc_params *params)
-{
- struct kern_ipc_perm *ipcp;
- int flg = params->flg;
- int err;
-retry:
- err = idr_pre_get(&ids->ipcs_idr, GFP_KERNEL);
-
- /*
- * Take the lock as a writer since we are potentially going to add
- * a new entry + read locks are not "upgradable"
- */
- down_write(&ids->rw_mutex);
- ipcp = ipc_findkey(ids, params->key);
- if (ipcp == NULL) {
- /* key not used */
- if (!(flg & IPC_CREAT))
- err = -ENOENT;
- else if (!err)
- err = -ENOMEM;
- else
- err = ops->getnew(ns, params);
- } else {
- /* ipc object has been locked by ipc_findkey() */
-
- if (flg & IPC_CREAT && flg & IPC_EXCL)
- err = -EEXIST;
- else {
- err = 0;
- if (ops->more_checks)
- err = ops->more_checks(ipcp, params);
- if (!err)
- /*
- * ipc_check_perms returns the IPC id on
- * success
- */
- err = ipc_check_perms(ns, ipcp, ops, params);
- }
- ipc_unlock(ipcp);
- }
- up_write(&ids->rw_mutex);
-
- if (err == -EAGAIN)
- goto retry;
-
- return err;
-}
-
-
-/**
- * ipc_rmid - remove an IPC identifier
- * @ids: IPC identifier set
- * @ipcp: ipc perm structure containing the identifier to remove
- *
- * ipc_ids.rw_mutex (as a writer) and the spinlock for this ID are held
- * before this function is called, and remain locked on the exit.
- */
-
-void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
-{
- int lid = ipcid_to_idx(ipcp->id);
-
- idr_remove(&ids->ipcs_idr, lid);
-
- ids->in_use--;
-
- ipcp->deleted = 1;
-
- return;
-}
-
-/**
- * ipc_alloc - allocate ipc space
- * @size: size desired
- *
- * Allocate memory from the appropriate pools and return a pointer to it.
- * NULL is returned if the allocation fails
- */
-
-void* ipc_alloc(int size)
-{
- void* out;
- if(size > PAGE_SIZE)
- out = vmalloc(size);
- else
- out = kmalloc(size, GFP_KERNEL);
- return out;
-}
-
-/**
- * ipc_free - free ipc space
- * @ptr: pointer returned by ipc_alloc
- * @size: size of block
- *
- * Free a block created with ipc_alloc(). The caller must know the size
- * used in the allocation call.
- */
-
-void ipc_free(void* ptr, int size)
-{
- if(size > PAGE_SIZE)
- vfree(ptr);
- else
- kfree(ptr);
-}
-
-/*
- * rcu allocations:
- * There are three headers that are prepended to the actual allocation:
- * - during use: ipc_rcu_hdr.
- * - during the rcu grace period: ipc_rcu_grace.
- * - [only if vmalloc]: ipc_rcu_sched.
- * Their lifetime doesn't overlap, thus the headers share the same memory.
- * Unlike a normal union, they are right-aligned, thus some container_of
- * forward/backward casting is necessary:
- */
-struct ipc_rcu_hdr
-{
- int refcount;
- int is_vmalloc;
- void *data[0];
-};
-
-
-struct ipc_rcu_grace
-{
- struct rcu_head rcu;
- /* "void *" makes sure alignment of following data is sane. */
- void *data[0];
-};
-
-struct ipc_rcu_sched
-{
- struct work_struct work;
- /* "void *" makes sure alignment of following data is sane. */
- void *data[0];
-};
-
-#define HDRLEN_KMALLOC (sizeof(struct ipc_rcu_grace) > sizeof(struct ipc_rcu_hdr) ? \
- sizeof(struct ipc_rcu_grace) : sizeof(struct ipc_rcu_hdr))
-#define HDRLEN_VMALLOC (sizeof(struct ipc_rcu_sched) > HDRLEN_KMALLOC ? \
- sizeof(struct ipc_rcu_sched) : HDRLEN_KMALLOC)
-
-static inline int rcu_use_vmalloc(int size)
-{
- /* Too big for a single page? */
- if (HDRLEN_KMALLOC + size > PAGE_SIZE)
- return 1;
- return 0;
-}
-
-/**
- * ipc_rcu_alloc - allocate ipc and rcu space
- * @size: size desired
- *
- * Allocate memory for the rcu header structure + the object.
- * Returns the pointer to the object.
- * NULL is returned if the allocation fails.
- */
-
-void* ipc_rcu_alloc(int size)
-{
- void* out;
- /*
- * We prepend the allocation with the rcu struct, and
- * workqueue if necessary (for vmalloc).
- */
- if (rcu_use_vmalloc(size)) {
- out = vmalloc(HDRLEN_VMALLOC + size);
- if (out) {
- out += HDRLEN_VMALLOC;
- container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 1;
- container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
- }
- } else {
- out = kmalloc(HDRLEN_KMALLOC + size, GFP_KERNEL);
- if (out) {
- out += HDRLEN_KMALLOC;
- container_of(out, struct ipc_rcu_hdr, data)->is_vmalloc = 0;
- container_of(out, struct ipc_rcu_hdr, data)->refcount = 1;
- }
- }
-
- return out;
-}
-
-void ipc_rcu_getref(void *ptr)
-{
- container_of(ptr, struct ipc_rcu_hdr, data)->refcount++;
-}
-
-static void ipc_do_vfree(struct work_struct *work)
-{
- vfree(container_of(work, struct ipc_rcu_sched, work));
-}
-
-/**
- * ipc_schedule_free - free ipc + rcu space
- * @head: RCU callback structure for queued work
- *
- * Since RCU callback function is called in bh,
- * we need to defer the vfree to schedule_work().
- */
-static void ipc_schedule_free(struct rcu_head *head)
-{
- struct ipc_rcu_grace *grace;
- struct ipc_rcu_sched *sched;
-
- grace = container_of(head, struct ipc_rcu_grace, rcu);
- sched = container_of(&(grace->data[0]), struct ipc_rcu_sched,
- data[0]);
-
- INIT_WORK(&sched->work, ipc_do_vfree);
- schedule_work(&sched->work);
-}
-
-void ipc_rcu_putref(void *ptr)
-{
- if (--container_of(ptr, struct ipc_rcu_hdr, data)->refcount > 0)
- return;
-
- if (container_of(ptr, struct ipc_rcu_hdr, data)->is_vmalloc) {
- call_rcu(&container_of(ptr, struct ipc_rcu_grace, data)->rcu,
- ipc_schedule_free);
- } else {
- kfree_rcu(container_of(ptr, struct ipc_rcu_grace, data), rcu);
- }
-}
-
-/**
- * ipcperms - check IPC permissions
- * @ns: IPC namespace
- * @ipcp: IPC permission set
- * @flag: desired permission set.
- *
- * Check user, group, other permissions for access
- * to ipc resources. return 0 if allowed
- *
- * @flag will most probably be 0 or S_...UGO from <linux/stat.h>
- */
-
-int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
-{
- uid_t euid = current_euid();
- int requested_mode, granted_mode;
-
- audit_ipc_obj(ipcp);
- requested_mode = (flag >> 6) | (flag >> 3) | flag;
- granted_mode = ipcp->mode;
- if (euid == ipcp->cuid ||
- euid == ipcp->uid)
- granted_mode >>= 6;
- else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))
- granted_mode >>= 3;
- /* is there some bit set in requested_mode but not in granted_mode? */
- if ((requested_mode & ~granted_mode & 0007) &&
- !ns_capable(ns->user_ns, CAP_IPC_OWNER))
- return -1;
-
- return security_ipc_permission(ipcp, flag);
-}
-
-/*
- * Functions to convert between the kern_ipc_perm structure and the
- * old/new ipc_perm structures
- */
-
-/**
- * kernel_to_ipc64_perm - convert kernel ipc permissions to user
- * @in: kernel permissions
- * @out: new style IPC permissions
- *
- * Turn the kernel object @in into a set of permissions descriptions
- * for returning to userspace (@out).
- */
-
-
-void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
-{
- out->key = in->key;
- out->uid = in->uid;
- out->gid = in->gid;
- out->cuid = in->cuid;
- out->cgid = in->cgid;
- out->mode = in->mode;
- out->seq = in->seq;
-}
-
-/**
- * ipc64_perm_to_ipc_perm - convert new ipc permissions to old
- * @in: new style IPC permissions
- * @out: old style IPC permissions
- *
- * Turn the new style permissions object @in into a compatibility
- * object and store it into the @out pointer.
- */
-
-void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
-{
- out->key = in->key;
- SET_UID(out->uid, in->uid);
- SET_GID(out->gid, in->gid);
- SET_UID(out->cuid, in->cuid);
- SET_GID(out->cgid, in->cgid);
- out->mode = in->mode;
- out->seq = in->seq;
-}
-
-/**
- * ipc_lock - Lock an ipc structure without rw_mutex held
- * @ids: IPC identifier set
- * @id: ipc id to look for
- *
- * Look for an id in the ipc ids idr and lock the associated ipc object.
- *
- * The ipc object is locked on exit.
- */
-
-struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
-{
- struct kern_ipc_perm *out;
- int lid = ipcid_to_idx(id);
-
- rcu_read_lock();
- out = idr_find(&ids->ipcs_idr, lid);
- if (out == NULL) {
- rcu_read_unlock();
- return ERR_PTR(-EINVAL);
- }
-
- spin_lock(&out->lock);
-
- /* ipc_rmid() may have already freed the ID while ipc_lock
- * was spinning: here verify that the structure is still valid
- */
- if (out->deleted) {
- spin_unlock(&out->lock);
- rcu_read_unlock();
- return ERR_PTR(-EINVAL);
- }
-
- return out;
-}
-
-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
-{
- struct kern_ipc_perm *out;
-
- out = ipc_lock(ids, id);
- if (IS_ERR(out))
- return out;
-
- if (ipc_checkid(out, id)) {
- ipc_unlock(out);
- return ERR_PTR(-EIDRM);
- }
-
- return out;
-}
-
-/**
- * ipcget - Common sys_*get() code
- * @ns : namsepace
- * @ids : IPC identifier set
- * @ops : operations to be called on ipc object creation, permission checks
- * and further checks
- * @params : the parameters needed by the previous operations.
- *
- * Common routine called by sys_msgget(), sys_semget() and sys_shmget().
- */
-int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
- struct ipc_ops *ops, struct ipc_params *params)
-{
- if (params->key == IPC_PRIVATE)
- return ipcget_new(ns, ids, ops, params);
- else
- return ipcget_public(ns, ids, ops, params);
-}
-
-/**
- * ipc_update_perm - update the permissions of an IPC.
- * @in: the permission given as input.
- * @out: the permission of the ipc to set.
- */
-void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
-{
- out->uid = in->uid;
- out->gid = in->gid;
- out->mode = (out->mode & ~S_IRWXUGO)
- | (in->mode & S_IRWXUGO);
-}
-
-/**
- * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
- * @ns: the ipc namespace
- * @ids: the table of ids where to look for the ipc
- * @id: the id of the ipc to retrieve
- * @cmd: the cmd to check
- * @perm: the permission to set
- * @extra_perm: one extra permission parameter used by msq
- *
- * This function does some common audit and permissions check for some IPC_XXX
- * cmd and is called from semctl_down, shmctl_down and msgctl_down.
- * It must be called without any lock held and
- * - retrieves the ipc with the given id in the given table.
- * - performs some audit and permission check, depending on the given cmd
- * - returns the ipc with both ipc and rw_mutex locks held in case of success
- * or an err-code without any lock held otherwise.
- */
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
- struct ipc_ids *ids, int id, int cmd,
- struct ipc64_perm *perm, int extra_perm)
-{
- struct kern_ipc_perm *ipcp;
- uid_t euid;
- int err;
-
- down_write(&ids->rw_mutex);
- ipcp = ipc_lock_check(ids, id);
- if (IS_ERR(ipcp)) {
- err = PTR_ERR(ipcp);
- goto out_up;
- }
-
- audit_ipc_obj(ipcp);
- if (cmd == IPC_SET)
- audit_ipc_set_perm(extra_perm, perm->uid,
- perm->gid, perm->mode);
-
- euid = current_euid();
- if (euid == ipcp->cuid || euid == ipcp->uid ||
- ns_capable(ns->user_ns, CAP_SYS_ADMIN))
- return ipcp;
-
- err = -EPERM;
- ipc_unlock(ipcp);
-out_up:
- up_write(&ids->rw_mutex);
- return ERR_PTR(err);
-}
-
-#ifdef __ARCH_WANT_IPC_PARSE_VERSION
-
-
-/**
- * ipc_parse_version - IPC call version
- * @cmd: pointer to command
- *
- * Return IPC_64 for new style IPC and IPC_OLD for old style IPC.
- * The @cmd value is turned from an encoding command and version into
- * just the command code.
- */
-
-int ipc_parse_version (int *cmd)
-{
- if (*cmd & IPC_64) {
- *cmd ^= IPC_64;
- return IPC_64;
- } else {
- return IPC_OLD;
- }
-}
-
-#endif /* __ARCH_WANT_IPC_PARSE_VERSION */
-
-#ifdef CONFIG_PROC_FS
-struct ipc_proc_iter {
- struct ipc_namespace *ns;
- struct ipc_proc_iface *iface;
-};
-
-/*
- * This routine locks the ipc structure found at least at position pos.
- */
-static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
- loff_t *new_pos)
-{
- struct kern_ipc_perm *ipc;
- int total, id;
-
- total = 0;
- for (id = 0; id < pos && total < ids->in_use; id++) {
- ipc = idr_find(&ids->ipcs_idr, id);
- if (ipc != NULL)
- total++;
- }
-
- if (total >= ids->in_use)
- return NULL;
-
- for ( ; pos < IPCMNI; pos++) {
- ipc = idr_find(&ids->ipcs_idr, pos);
- if (ipc != NULL) {
- *new_pos = pos + 1;
- ipc_lock_by_ptr(ipc);
- return ipc;
- }
- }
-
- /* Out of range - return NULL to terminate iteration */
- return NULL;
-}
-
-static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
-{
- struct ipc_proc_iter *iter = s->private;
- struct ipc_proc_iface *iface = iter->iface;
- struct kern_ipc_perm *ipc = it;
-
- /* If we had an ipc id locked before, unlock it */
- if (ipc && ipc != SEQ_START_TOKEN)
- ipc_unlock(ipc);
-
- return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos);
-}
-
-/*
- * File positions: pos 0 -> header, pos n -> ipc id = n - 1.
- * SeqFile iterator: iterator value locked ipc pointer or SEQ_TOKEN_START.
- */
-static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
-{
- struct ipc_proc_iter *iter = s->private;
- struct ipc_proc_iface *iface = iter->iface;
- struct ipc_ids *ids;
-
- ids = &iter->ns->ids[iface->ids];
-
- /*
- * Take the lock - this will be released by the corresponding
- * call to stop().
- */
- down_read(&ids->rw_mutex);
-
- /* pos < 0 is invalid */
- if (*pos < 0)
- return NULL;
-
- /* pos == 0 means header */
- if (*pos == 0)
- return SEQ_START_TOKEN;
-
- /* Find the (pos-1)th ipc */
- return sysvipc_find_ipc(ids, *pos - 1, pos);
-}
-
-static void sysvipc_proc_stop(struct seq_file *s, void *it)
-{
- struct kern_ipc_perm *ipc = it;
- struct ipc_proc_iter *iter = s->private;
- struct ipc_proc_iface *iface = iter->iface;
- struct ipc_ids *ids;
-
- /* If we had a locked structure, release it */
- if (ipc && ipc != SEQ_START_TOKEN)
- ipc_unlock(ipc);
-
- ids = &iter->ns->ids[iface->ids];
- /* Release the lock we took in start() */
- up_read(&ids->rw_mutex);
-}
-
-static int sysvipc_proc_show(struct seq_file *s, void *it)
-{
- struct ipc_proc_iter *iter = s->private;
- struct ipc_proc_iface *iface = iter->iface;
-
- if (it == SEQ_START_TOKEN)
- return seq_puts(s, iface->header);
-
- return iface->show(s, it);
-}
-
-static const struct seq_operations sysvipc_proc_seqops = {
- .start = sysvipc_proc_start,
- .stop = sysvipc_proc_stop,
- .next = sysvipc_proc_next,
- .show = sysvipc_proc_show,
-};
-
-static int sysvipc_proc_open(struct inode *inode, struct file *file)
-{
- int ret;
- struct seq_file *seq;
- struct ipc_proc_iter *iter;
-
- ret = -ENOMEM;
- iter = kmalloc(sizeof(*iter), GFP_KERNEL);
- if (!iter)
- goto out;
-
- ret = seq_open(file, &sysvipc_proc_seqops);
- if (ret)
- goto out_kfree;
-
- seq = file->private_data;
- seq->private = iter;
-
- iter->iface = PDE(inode)->data;
- iter->ns = get_ipc_ns(current->nsproxy->ipc_ns);
-out:
- return ret;
-out_kfree:
- kfree(iter);
- goto out;
-}
-
-static int sysvipc_proc_release(struct inode *inode, struct file *file)
-{
- struct seq_file *seq = file->private_data;
- struct ipc_proc_iter *iter = seq->private;
- put_ipc_ns(iter->ns);
- return seq_release_private(inode, file);
-}
-
-static const struct file_operations sysvipc_proc_fops = {
- .open = sysvipc_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = sysvipc_proc_release,
-};
-#endif /* CONFIG_PROC_FS */
diff --git a/ANDROID_3.4.5/ipc/util.h b/ANDROID_3.4.5/ipc/util.h
deleted file mode 100644
index 6f5c20be..00000000
--- a/ANDROID_3.4.5/ipc/util.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * linux/ipc/util.h
- * Copyright (C) 1999 Christoph Rohland
- *
- * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com>
- * namespaces support. 2006 OpenVZ, SWsoft Inc.
- * Pavel Emelianov <xemul@openvz.org>
- */
-
-#ifndef _IPC_UTIL_H
-#define _IPC_UTIL_H
-
-#include <linux/unistd.h>
-#include <linux/err.h>
-
-#define SEQ_MULTIPLIER (IPCMNI)
-
-void sem_init (void);
-void msg_init (void);
-void shm_init (void);
-
-struct ipc_namespace;
-
-#ifdef CONFIG_POSIX_MQUEUE
-extern void mq_clear_sbinfo(struct ipc_namespace *ns);
-extern void mq_put_mnt(struct ipc_namespace *ns);
-#else
-static inline void mq_clear_sbinfo(struct ipc_namespace *ns) { }
-static inline void mq_put_mnt(struct ipc_namespace *ns) { }
-#endif
-
-#ifdef CONFIG_SYSVIPC
-void sem_init_ns(struct ipc_namespace *ns);
-void msg_init_ns(struct ipc_namespace *ns);
-void shm_init_ns(struct ipc_namespace *ns);
-
-void sem_exit_ns(struct ipc_namespace *ns);
-void msg_exit_ns(struct ipc_namespace *ns);
-void shm_exit_ns(struct ipc_namespace *ns);
-#else
-static inline void sem_init_ns(struct ipc_namespace *ns) { }
-static inline void msg_init_ns(struct ipc_namespace *ns) { }
-static inline void shm_init_ns(struct ipc_namespace *ns) { }
-
-static inline void sem_exit_ns(struct ipc_namespace *ns) { }
-static inline void msg_exit_ns(struct ipc_namespace *ns) { }
-static inline void shm_exit_ns(struct ipc_namespace *ns) { }
-#endif
-
-/*
- * Structure that holds the parameters needed by the ipc operations
- * (see after)
- */
-struct ipc_params {
- key_t key;
- int flg;
- union {
- size_t size; /* for shared memories */
- int nsems; /* for semaphores */
- } u; /* holds the getnew() specific param */
-};
-
-/*
- * Structure that holds some ipc operations. This structure is used to unify
- * the calls to sys_msgget(), sys_semget(), sys_shmget()
- * . routine to call to create a new ipc object. Can be one of newque,
- * newary, newseg
- * . routine to call to check permissions for a new ipc object.
- * Can be one of security_msg_associate, security_sem_associate,
- * security_shm_associate
- * . routine to call for an extra check if needed
- */
-struct ipc_ops {
- int (*getnew) (struct ipc_namespace *, struct ipc_params *);
- int (*associate) (struct kern_ipc_perm *, int);
- int (*more_checks) (struct kern_ipc_perm *, struct ipc_params *);
-};
-
-struct seq_file;
-struct ipc_ids;
-
-void ipc_init_ids(struct ipc_ids *);
-#ifdef CONFIG_PROC_FS
-void __init ipc_init_proc_interface(const char *path, const char *header,
- int ids, int (*show)(struct seq_file *, void *));
-#else
-#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
-#endif
-
-#define IPC_SEM_IDS 0
-#define IPC_MSG_IDS 1
-#define IPC_SHM_IDS 2
-
-#define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
-
-/* must be called with ids->rw_mutex acquired for writing */
-int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
-
-/* must be called with ids->rw_mutex acquired for reading */
-int ipc_get_maxid(struct ipc_ids *);
-
-/* must be called with both locks acquired. */
-void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
-
-/* must be called with ipcp locked */
-int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
-
-/* for rare, potentially huge allocations.
- * both function can sleep
- */
-void* ipc_alloc(int size);
-void ipc_free(void* ptr, int size);
-
-/*
- * For allocation that need to be freed by RCU.
- * Objects are reference counted, they start with reference count 1.
- * getref increases the refcount, the putref call that reduces the recount
- * to 0 schedules the rcu destruction. Caller must guarantee locking.
- */
-void* ipc_rcu_alloc(int size);
-void ipc_rcu_getref(void *ptr);
-void ipc_rcu_putref(void *ptr);
-
-struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
-
-void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
-void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
-void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
- struct ipc_ids *ids, int id, int cmd,
- struct ipc64_perm *perm, int extra_perm);
-
-#ifndef __ARCH_WANT_IPC_PARSE_VERSION
- /* On IA-64, we always use the "64-bit version" of the IPC structures. */
-# define ipc_parse_version(cmd) IPC_64
-#else
-int ipc_parse_version (int *cmd);
-#endif
-
-extern void free_msg(struct msg_msg *msg);
-extern struct msg_msg *load_msg(const void __user *src, int len);
-extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
-
-extern void recompute_msgmni(struct ipc_namespace *);
-
-static inline int ipc_buildid(int id, int seq)
-{
- return SEQ_MULTIPLIER * seq + id;
-}
-
-/*
- * Must be called with ipcp locked
- */
-static inline int ipc_checkid(struct kern_ipc_perm *ipcp, int uid)
-{
- if (uid / SEQ_MULTIPLIER != ipcp->seq)
- return 1;
- return 0;
-}
-
-static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
-{
- rcu_read_lock();
- spin_lock(&perm->lock);
-}
-
-static inline void ipc_unlock(struct kern_ipc_perm *perm)
-{
- spin_unlock(&perm->lock);
- rcu_read_unlock();
-}
-
-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
-int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
- struct ipc_ops *ops, struct ipc_params *params);
-void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
- void (*free)(struct ipc_namespace *, struct kern_ipc_perm *));
-#endif