[RFC PATCH] ipc: add shm_locked for IPC shm

From: Hiroshi Shimamoto
Date: Wed Apr 09 2008 - 17:31:19 EST


From: Hiroshi Shimamoto <h-shimamoto@xxxxxxxxxxxxx>

Shared memory users probably don't think the shared memory is
swapped out. But actually shared memory could be swapped out under
memory pressure.
Linux has SHM_LOCK feature for prevent shared memory swapping,
and it can be used by shmctl() after create the shared memory.
There are some needs that SHM_LOCK is default behavior.

This patch adds shm_locked sysctl to turn SHM_LOCK on when creating.
kernel.shm_locked = 0, is default and the behavior is not changed.
kernel.shm_locked = 1, means shared memory will be locked when
it's created.

Signed-off-by: Hiroshi Shimamoto <h-shimamoto@xxxxxxxxxxxxx>
---
include/linux/ipc_namespace.h | 1 +
include/linux/sysctl.h | 1 +
ipc/ipc_sysctl.c | 9 +++++
ipc/shm.c | 70 ++++++++++++++++++++++++----------------
kernel/sysctl_check.c | 2 +
5 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index e4451d1..1323985 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -29,6 +29,7 @@ struct ipc_namespace {
size_t shm_ctlmax;
size_t shm_ctlall;
int shm_ctlmni;
+ int shm_ctllocked;
int shm_tot;
};

diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 571f01d..434c207 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -163,6 +163,7 @@ enum
KERN_MAX_LOCK_DEPTH=74,
KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
+ KERN_SHMLOCKED=77, /* int: make shared memory locked */
};


diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index 7f4235b..00d43b2 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -123,6 +123,15 @@ static struct ctl_table ipc_kern_table[] = {
.strategy = sysctl_ipc_data,
},
{
+ .ctl_name = KERN_SHMLOCKED,
+ .procname = "shm_locked",
+ .data = &init_ipc_ns.shm_ctllocked,
+ .maxlen = sizeof (init_ipc_ns.shm_ctllocked),
+ .mode = 0644,
+ .proc_handler = proc_ipc_dointvec,
+ .strategy = sysctl_ipc_data,
+ },
+ {
.ctl_name = KERN_MSGMAX,
.procname = "msgmax",
.data = &init_ipc_ns.msg_ctlmax,
diff --git a/ipc/shm.c b/ipc/shm.c
index cc63fae..6078477 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -66,6 +66,7 @@ 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);
+static int do_shmlock(struct shmid_kernel *shp, int cmd);
#ifdef CONFIG_PROC_FS
static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
#endif
@@ -75,6 +76,7 @@ void shm_init_ns(struct ipc_namespace *ns)
ns->shm_ctlmax = SHMMAX;
ns->shm_ctlall = SHMALL;
ns->shm_ctlmni = SHMMNI;
+ ns->shm_ctllocked = 0;
ns->shm_tot = 0;
ipc_init_ids(&ns->ids[IPC_SHM_IDS]);
}
@@ -438,6 +440,9 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
*/
file->f_dentry->d_inode->i_ino = shp->shm_perm.id;

+ if (ns->shm_ctllocked)
+ do_shmlock(shp, SHM_LOCK);
+
ns->shm_tot += numpages;
error = shp->shm_perm.id;
shm_unlock(shp);
@@ -626,6 +631,42 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
}
}

+static int do_shmlock(struct shmid_kernel *shp, int cmd)
+{
+ int err;
+
+ if (!capable(CAP_IPC_LOCK)) {
+ err = -EPERM;
+ if (current->euid != shp->shm_perm.uid &&
+ current->euid != shp->shm_perm.cuid)
+ goto out;
+ if (cmd == SHM_LOCK &&
+ !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
+ goto out;
+ }
+
+ err = security_shm_shmctl(shp, cmd);
+ if (err)
+ goto out;
+
+ if (cmd == SHM_LOCK) {
+ struct user_struct * user = current->user;
+ if (!is_file_hugepages(shp->shm_file)) {
+ err = shmem_lock(shp->shm_file, 1, user);
+ if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
+ shp->shm_perm.mode |= SHM_LOCKED;
+ shp->mlock_user = user;
+ }
+ }
+ } else if (!is_file_hugepages(shp->shm_file)) {
+ shmem_lock(shp->shm_file, 0, shp->mlock_user);
+ shp->shm_perm.mode &= ~SHM_LOCKED;
+ shp->mlock_user = NULL;
+ }
+out:
+ return err;
+}
+
asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
{
struct shm_setbuf setbuf;
@@ -753,34 +794,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
if (err)
goto out_unlock;

- if (!capable(CAP_IPC_LOCK)) {
- err = -EPERM;
- if (current->euid != shp->shm_perm.uid &&
- current->euid != shp->shm_perm.cuid)
- goto out_unlock;
- if (cmd == SHM_LOCK &&
- !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
- goto out_unlock;
- }
-
- err = security_shm_shmctl(shp, cmd);
- if (err)
- goto out_unlock;
-
- if(cmd==SHM_LOCK) {
- struct user_struct * user = current->user;
- if (!is_file_hugepages(shp->shm_file)) {
- err = shmem_lock(shp->shm_file, 1, user);
- if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
- shp->shm_perm.mode |= SHM_LOCKED;
- shp->mlock_user = user;
- }
- }
- } else if (!is_file_hugepages(shp->shm_file)) {
- shmem_lock(shp->shm_file, 0, shp->mlock_user);
- shp->shm_perm.mode &= ~SHM_LOCKED;
- shp->mlock_user = NULL;
- }
+ err = do_shmlock(shp, cmd);
shm_unlock(shp);
goto out;
}
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index c09350d..3d13649 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -104,6 +104,8 @@ static const struct trans_ctl_table trans_kern_table[] = {
{ KERN_MAX_LOCK_DEPTH, "max_lock_depth" },
{ KERN_NMI_WATCHDOG, "nmi_watchdog" },
{ KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" },
+
+ { KERN_SHMLOCKED, "shm_locked" },
{}
};

--
1.5.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/