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        memcpy(&ipc_table, table, sizeof(ipc_table));
  35        ipc_table.data = get_ipc(table);
  36
  37        return proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
  38}
  39
  40static int proc_ipc_callback_dointvec(ctl_table *table, int write,
  41        void __user *buffer, size_t *lenp, loff_t *ppos)
  42{
  43        struct ctl_table ipc_table;
  44        size_t lenp_bef = *lenp;
  45        int rc;
  46
  47        memcpy(&ipc_table, table, sizeof(ipc_table));
  48        ipc_table.data = get_ipc(table);
  49
  50        rc = proc_dointvec(&ipc_table, write, buffer, lenp, ppos);
  51
  52        if (write && !rc && lenp_bef == *lenp)
  53                /*
  54                 * Tunable has successfully been changed by hand. Disable its
  55                 * automatic adjustment. This simply requires unregistering
  56                 * the notifiers that trigger recalculation.
  57                 */
  58                unregister_ipcns_notifier(current->nsproxy->ipc_ns);
  59
  60        return rc;
  61}
  62
  63static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
  64        void __user *buffer, size_t *lenp, loff_t *ppos)
  65{
  66        struct ctl_table ipc_table;
  67        memcpy(&ipc_table, table, sizeof(ipc_table));
  68        ipc_table.data = get_ipc(table);
  69
  70        return proc_doulongvec_minmax(&ipc_table, write, buffer,
  71                                        lenp, ppos);
  72}
  73
  74/*
  75 * Routine that is called when the file "auto_msgmni" has successfully been
  76 * written.
  77 * Two values are allowed:
  78 * 0: unregister msgmni's callback routine from the ipc namespace notifier
  79 *    chain. This means that msgmni won't be recomputed anymore upon memory
  80 *    add/remove or ipc namespace creation/removal.
  81 * 1: register back the callback routine.
  82 */
  83static void ipc_auto_callback(int val)
  84{
  85        if (!val)
  86                unregister_ipcns_notifier(current->nsproxy->ipc_ns);
  87        else {
  88                /*
  89                 * Re-enable automatic recomputing only if not already
  90                 * enabled.
  91                 */
  92                recompute_msgmni(current->nsproxy->ipc_ns);
  93                cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
  94        }
  95}
  96
  97static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
  98        void __user *buffer, size_t *lenp, loff_t *ppos)
  99{
 100        struct ctl_table ipc_table;
 101        size_t lenp_bef = *lenp;
 102        int oldval;
 103        int rc;
 104
 105        memcpy(&ipc_table, table, sizeof(ipc_table));
 106        ipc_table.data = get_ipc(table);
 107        oldval = *((int *)(ipc_table.data));
 108
 109        rc = proc_dointvec_minmax(&ipc_table, write, buffer, lenp, ppos);
 110
 111        if (write && !rc && lenp_bef == *lenp) {
 112                int newval = *((int *)(ipc_table.data));
 113                /*
 114                 * The file "auto_msgmni" has correctly been set.
 115                 * React by (un)registering the corresponding tunable, if the
 116                 * value has changed.
 117                 */
 118                if (newval != oldval)
 119                        ipc_auto_callback(newval);
 120        }
 121
 122        return rc;
 123}
 124
 125#else
 126#define proc_ipc_doulongvec_minmax NULL
 127#define proc_ipc_dointvec          NULL
 128#define proc_ipc_callback_dointvec NULL
 129#define proc_ipcauto_dointvec_minmax NULL
 130#endif
 131
 132static int zero;
 133static int one = 1;
 134
 135static struct ctl_table ipc_kern_table[] = {
 136        {
 137                .procname       = "shmmax",
 138                .data           = &init_ipc_ns.shm_ctlmax,
 139                .maxlen         = sizeof (init_ipc_ns.shm_ctlmax),
 140                .mode           = 0644,
 141                .proc_handler   = proc_ipc_doulongvec_minmax,
 142        },
 143        {
 144                .procname       = "shmall",
 145                .data           = &init_ipc_ns.shm_ctlall,
 146                .maxlen         = sizeof (init_ipc_ns.shm_ctlall),
 147                .mode           = 0644,
 148                .proc_handler   = proc_ipc_doulongvec_minmax,
 149        },
 150        {
 151                .procname       = "shmmni",
 152                .data           = &init_ipc_ns.shm_ctlmni,
 153                .maxlen         = sizeof (init_ipc_ns.shm_ctlmni),
 154                .mode           = 0644,
 155                .proc_handler   = proc_ipc_dointvec,
 156        },
 157        {
 158                .procname       = "msgmax",
 159                .data           = &init_ipc_ns.msg_ctlmax,
 160                .maxlen         = sizeof (init_ipc_ns.msg_ctlmax),
 161                .mode           = 0644,
 162                .proc_handler   = proc_ipc_dointvec,
 163        },
 164        {
 165                .procname       = "msgmni",
 166                .data           = &init_ipc_ns.msg_ctlmni,
 167                .maxlen         = sizeof (init_ipc_ns.msg_ctlmni),
 168                .mode           = 0644,
 169                .proc_handler   = proc_ipc_callback_dointvec,
 170        },
 171        {
 172                .procname       =  "msgmnb",
 173                .data           = &init_ipc_ns.msg_ctlmnb,
 174                .maxlen         = sizeof (init_ipc_ns.msg_ctlmnb),
 175                .mode           = 0644,
 176                .proc_handler   = proc_ipc_dointvec,
 177        },
 178        {
 179                .procname       = "sem",
 180                .data           = &init_ipc_ns.sem_ctls,
 181                .maxlen         = 4*sizeof (int),
 182                .mode           = 0644,
 183                .proc_handler   = proc_ipc_dointvec,
 184        },
 185        {
 186                .procname       = "auto_msgmni",
 187                .data           = &init_ipc_ns.auto_msgmni,
 188                .maxlen         = sizeof(int),
 189                .mode           = 0644,
 190                .proc_handler   = proc_ipcauto_dointvec_minmax,
 191                .extra1         = &zero,
 192                .extra2         = &one,
 193        },
 194        {}
 195};
 196
 197static struct ctl_table ipc_root_table[] = {
 198        {
 199                .procname       = "kernel",
 200                .mode           = 0555,
 201                .child          = ipc_kern_table,
 202        },
 203        {}
 204};
 205
 206static int __init ipc_sysctl_init(void)
 207{
 208        register_sysctl_table(ipc_root_table);
 209        return 0;
 210}
 211
 212__initcall(ipc_sysctl_init);
 213