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
 162static struct ctl_table ipc_kern_table[] = {
 163        {
 164                .procname       = "shmmax",
 165                .data           = &init_ipc_ns.shm_ctlmax,
 166                .maxlen         = sizeof (init_ipc_ns.shm_ctlmax),
 167                .mode           = 0644,
 168                .proc_handler   = proc_ipc_doulongvec_minmax,
 169        },
 170        {
 171                .procname       = "shmall",
 172                .data           = &init_ipc_ns.shm_ctlall,
 173                .maxlen         = sizeof (init_ipc_ns.shm_ctlall),
 174                .mode           = 0644,
 175                .proc_handler   = proc_ipc_doulongvec_minmax,
 176        },
 177        {
 178                .procname       = "shmmni",
 179                .data           = &init_ipc_ns.shm_ctlmni,
 180                .maxlen         = sizeof (init_ipc_ns.shm_ctlmni),
 181                .mode           = 0644,
 182                .proc_handler   = proc_ipc_dointvec,
 183        },
 184        {
 185                .procname       = "shm_rmid_forced",
 186                .data           = &init_ipc_ns.shm_rmid_forced,
 187                .maxlen         = sizeof(init_ipc_ns.shm_rmid_forced),
 188                .mode           = 0644,
 189                .proc_handler   = proc_ipc_dointvec_minmax_orphans,
 190                .extra1         = &zero,
 191                .extra2         = &one,
 192        },
 193        {
 194                .procname       = "msgmax",
 195                .data           = &init_ipc_ns.msg_ctlmax,
 196                .maxlen         = sizeof (init_ipc_ns.msg_ctlmax),
 197                .mode           = 0644,
 198                .proc_handler   = proc_ipc_dointvec,
 199        },
 200        {
 201                .procname       = "msgmni",
 202                .data           = &init_ipc_ns.msg_ctlmni,
 203                .maxlen         = sizeof (init_ipc_ns.msg_ctlmni),
 204                .mode           = 0644,
 205                .proc_handler   = proc_ipc_callback_dointvec,
 206        },
 207        {
 208                .procname       =  "msgmnb",
 209                .data           = &init_ipc_ns.msg_ctlmnb,
 210                .maxlen         = sizeof (init_ipc_ns.msg_ctlmnb),
 211                .mode           = 0644,
 212                .proc_handler   = proc_ipc_dointvec,
 213        },
 214        {
 215                .procname       = "sem",
 216                .data           = &init_ipc_ns.sem_ctls,
 217                .maxlen         = 4*sizeof (int),
 218                .mode           = 0644,
 219                .proc_handler   = proc_ipc_dointvec,
 220        },
 221        {
 222                .procname       = "auto_msgmni",
 223                .data           = &init_ipc_ns.auto_msgmni,
 224                .maxlen         = sizeof(int),
 225                .mode           = 0644,
 226                .proc_handler   = proc_ipcauto_dointvec_minmax,
 227                .extra1         = &zero,
 228                .extra2         = &one,
 229        },
 230        {}
 231};
 232
 233static struct ctl_table ipc_root_table[] = {
 234        {
 235                .procname       = "kernel",
 236                .mode           = 0555,
 237                .child          = ipc_kern_table,
 238        },
 239        {}
 240};
 241
 242static int __init ipc_sysctl_init(void)
 243{
 244        register_sysctl_table(ipc_root_table);
 245        return 0;
 246}
 247
 248__initcall(ipc_sysctl_init);
 249