linux/ipc/ipc_sysctl.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2007
   3 *
   4 *  Author: Eric Biederman <ebiederm@xmision.com>
   5 *
   6 *  This program is free software; you can redistribute it and/or
   7 *  modify it under the terms of the GNU General Public License as
   8 *  published by the Free Software Foundation, version 2 of the
   9 *  License.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/ipc.h>
  14#include <linux/nsproxy.h>
  15#include <linux/sysctl.h>
  16#include <linux/uaccess.h>
  17#include <linux/ipc_namespace.h>
  18#include <linux/msg.h>
  19#include "util.h"
  20
  21static void *get_ipc(ctl_table *table)
  22{
  23        char *which = table->data;
  24        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
  25        which = (which - (char *)&init_ipc_ns) + (char *)ipc_ns;
  26        return which;
  27}
  28
  29#ifdef CONFIG_PROC_SYSCTL
  30static int proc_ipc_dointvec(ctl_table *table, int write,
  31        void __user *buffer, size_t *lenp, loff_t *ppos)
  32{
  33        struct ctl_table ipc_table;
  34
  35        memcpy(&ipc_table, table, sizeof(ipc_table));
  36        ipc_table.data = get_ipc(table);
  37
  38        return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
  39}
  40
  41static int proc_ipc_dointvec_minmax(ctl_table *table, int write,
  42        void __user *buffer, size_t *lenp, loff_t *ppos)
  43{
  44        struct ctl_table ipc_table;
  45
  46        memcpy(&ipc_table, table, sizeof(ipc_table));
  47        ipc_table.data = get_ipc(table);
  48
  49        return proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
  50}
  51
  52static int proc_ipc_dointvec_minmax_orphans(ctl_table *table, int write,
  53        void __user *buffer, size_t *lenp, loff_t *ppos)
  54{
  55        struct ipc_namespace *ns = current->nsproxy->ipc_ns;
  56        int err = proc_ipc_dointvec_minmax(table, write, buffer, lenp, ppos);
  57
  58        if (err < 0)
  59                return err;
  60        if (ns->shm_rmid_forced)
  61                shm_destroy_orphaned(ns);
  62        return err;
  63}
  64
  65static int proc_ipc_callback_dointvec(ctl_table *table, int write,
  66        void __user *buffer, size_t *lenp, loff_t *ppos)
  67{
  68        struct ctl_table ipc_table;
  69        size_t lenp_bef = *lenp;
  70        int rc;
  71
  72        memcpy(&ipc_table, table, sizeof(ipc_table));
  73        ipc_table.data = get_ipc(table);
  74
  75        rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
  76
  77        if (write && !rc && lenp_bef == *lenp)
  78                /*
  79                 * Tunable has successfully been changed by hand. Disable its
  80                 * automatic adjustment. This simply requires unregistering
  81                 * the notifiers that trigger recalculation.
  82                 */
  83                unregister_ipcns_notifier(current->nsproxy->ipc_ns);
  84
  85        return rc;
  86}
  87
  88static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
  89        void __user *buffer, size_t *lenp, loff_t *ppos)
  90{
  91        struct ctl_table ipc_table;
  92        memcpy(&ipc_table, table, sizeof(ipc_table));
  93        ipc_table.data = get_ipc(table);
  94
  95        return proc_doulongvec_minmax(&ipc_table, write, buffer,
  96                                        lenp, ppos);
  97}
  98
  99/*
 100 * Routine that is called when the file "auto_msgmni" has successfully been
 101 * written.
 102 * Two values are allowed:
 103 * 0: unregister msgmni's callback routine from the ipc namespace notifier
 104 *    chain. This means that msgmni won't be recomputed anymore upon memory
 105 *    add/remove or ipc namespace creation/removal.
 106 * 1: register back the callback routine.
 107 */
 108static void ipc_auto_callback(int val)
 109{
 110        if (!val)
 111                unregister_ipcns_notifier(current->nsproxy->ipc_ns);
 112        else {
 113                /*
 114                 * Re-enable automatic recomputing only if not already
 115                 * enabled.
 116                 */
 117                recompute_msgmni(current->nsproxy->ipc_ns);
 118                cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
 119        }
 120}
 121
 122static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
 123        void __user *buffer, size_t *lenp, loff_t *ppos)
 124{
 125        struct ctl_table ipc_table;
 126        size_t lenp_bef = *lenp;
 127        int oldval;
 128        int rc;
 129
 130        memcpy(&ipc_table, table, sizeof(ipc_table));
 131        ipc_table.data = get_ipc(table);
 132        oldval = *((int *)(ipc_table.data));
 133
 134        rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 135
 136        if (write && !rc && lenp_bef == *lenp) {
 137                int newval = *((int *)(ipc_table.data));
 138                /*
 139                 * The file "auto_msgmni" has correctly been set.
 140                 * React by (un)registering the corresponding tunable, if the
 141                 * value has changed.
 142                 */
 143                if (newval != oldval)
 144                        ipc_auto_callback(newval);
 145        }
 146
 147        return rc;
 148}
 149
 150#else
 151#define proc_ipc_doulongvec_minmax NULL
 152#define proc_ipc_dointvec          NULL
 153#define proc_ipc_dointvec_minmax   NULL
 154#define proc_ipc_dointvec_minmax_orphans   NULL
 155#define proc_ipc_callback_dointvec NULL
 156#define proc_ipcauto_dointvec_minmax NULL
 157#endif
 158
 159static int zero;
 160static int one = 1;
 161#ifdef CONFIG_CHECKPOINT_RESTORE
 162static int int_max = INT_MAX;
 163#endif
 164
 165static struct ctl_table ipc_kern_table[] = {
 166        {
 167                .procname       = "shmmax",
 168                .data           = &init_ipc_ns.shm_ctlmax,
 169                .maxlen         = sizeof (init_ipc_ns.shm_ctlmax),
 170                .mode           = 0644,
 171                .proc_handler   = proc_ipc_doulongvec_minmax,
 172        },
 173        {
 174                .procname       = "shmall",
 175                .data           = &init_ipc_ns.shm_ctlall,
 176                .maxlen         = sizeof (init_ipc_ns.shm_ctlall),
 177                .mode           = 0644,
 178                .proc_handler   = proc_ipc_doulongvec_minmax,
 179        },
 180        {
 181                .procname       = "shmmni",
 182                .data           = &init_ipc_ns.shm_ctlmni,
 183                .maxlen         = sizeof (init_ipc_ns.shm_ctlmni),
 184                .mode           = 0644,
 185                .proc_handler   = proc_ipc_dointvec,
 186        },
 187        {
 188                .procname       = "shm_rmid_forced",
 189                .data           = &init_ipc_ns.shm_rmid_forced,
 190                .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
 191                .mode           = 0644,
 192                .proc_handler   = proc_ipc_dointvec_minmax_orphans,
 193                .extra1         = &zero,
 194                .extra2         = &one,
 195        },
 196        {
 197                .procname       = "msgmax",
 198                .data           = &init_ipc_ns.msg_ctlmax,
 199                .maxlen         = sizeof (init_ipc_ns.msg_ctlmax),
 200                .mode           = 0644,
 201                .proc_handler   = proc_ipc_dointvec,
 202        },
 203        {
 204                .procname       = "msgmni",
 205                .data           = &init_ipc_ns.msg_ctlmni,
 206                .maxlen         = sizeof (init_ipc_ns.msg_ctlmni),
 207                .mode           = 0644,
 208                .proc_handler   = proc_ipc_callback_dointvec,
 209        },
 210        {
 211                .procname       =  "msgmnb",
 212                .data           = &init_ipc_ns.msg_ctlmnb,
 213                .maxlen         = sizeof (init_ipc_ns.msg_ctlmnb),
 214                .mode           = 0644,
 215                .proc_handler   = proc_ipc_dointvec,
 216        },
 217        {
 218                .procname       = "sem",
 219                .data           = &init_ipc_ns.sem_ctls,
 220                .maxlen         = 4*sizeof (int),
 221                .mode           = 0644,
 222                .proc_handler   = proc_ipc_dointvec,
 223        },
 224        {
 225                .procname       = "auto_msgmni",
 226                .data           = &init_ipc_ns.auto_msgmni,
 227                .maxlen         = sizeof(int),
 228                .mode           = 0644,
 229                .proc_handler   = proc_ipcauto_dointvec_minmax,
 230                .extra1         = &zero,
 231                .extra2         = &one,
 232        },
 233#ifdef CONFIG_CHECKPOINT_RESTORE
 234        {
 235                .procname       = "sem_next_id",
 236                .data           = &init_ipc_ns.ids[IPC_SEM_IDS].next_id,
 237                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SEM_IDS].next_id),
 238                .mode           = 0644,
 239                .proc_handler   = proc_ipc_dointvec_minmax,
 240                .extra1         = &zero,
 241                .extra2         = &int_max,
 242        },
 243        {
 244                .procname       = "msg_next_id",
 245                .data           = &init_ipc_ns.ids[IPC_MSG_IDS].next_id,
 246                .maxlen         = sizeof(init_ipc_ns.ids[IPC_MSG_IDS].next_id),
 247                .mode           = 0644,
 248                .proc_handler   = proc_ipc_dointvec_minmax,
 249                .extra1         = &zero,
 250                .extra2         = &int_max,
 251        },
 252        {
 253                .procname       = "shm_next_id",
 254                .data           = &init_ipc_ns.ids[IPC_SHM_IDS].next_id,
 255                .maxlen         = sizeof(init_ipc_ns.ids[IPC_SHM_IDS].next_id),
 256                .mode           = 0644,
 257                .proc_handler   = proc_ipc_dointvec_minmax,
 258                .extra1         = &zero,
 259                .extra2         = &int_max,
 260        },
 261#endif
 262        {}
 263};
 264
 265static struct ctl_table ipc_root_table[] = {
 266        {
 267                .procname       = "kernel",
 268                .mode           = 0555,
 269                .child          = ipc_kern_table,
 270        },
 271        {}
 272};
 273
 274static int __init ipc_sysctl_init(void)
 275{
 276        register_sysctl_table(ipc_root_table);
 277        return 0;
 278}
 279
 280__initcall(ipc_sysctl_init);
 281
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.