1/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- 2 * vim:expandtab:shiftwidth=8:tabstop=8: 3 * 4 * Copyright (C) 1999 Peter J. Braam <braam@clusterfs.com> 5 * 6 * This file is part of InterMezzo, http://www.inter-mezzo.org. 7 * 8 * InterMezzo is free software; you can redistribute it and/or 9 * modify it under the terms of version 2 of the GNU General Public 10 * License as published by the Free Software Foundation. 11 * 12 * InterMezzo is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with InterMezzo; if not, write to the Free Software 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * 21 * Sysctrl entries for Intermezzo! 22 */ 23 24#define __NO_VERSION__ 25#include <linux/config.h> /* for CONFIG_PROC_FS */ 26#include <linux/module.h> 27#include <linux/sched.h> 28#include <linux/mm.h> 29#include <linux/sysctl.h> 30#include <linux/swapctl.h> 31#include <linux/proc_fs.h> 32#include <linux/slab.h> 33#include <linux/vmalloc.h> 34#include <linux/stat.h> 35#include <linux/ctype.h> 36#include <linux/init.h> 37#include <asm/bitops.h> 38#include <asm/segment.h> 39#include <asm/uaccess.h> 40#include <linux/utsname.h> 41#include <linux/blk.h> 42 43 44#include <linux/intermezzo_fs.h> 45#include <linux/intermezzo_psdev.h> 46 47/* /proc entries */ 48 49#ifdef CONFIG_PROC_FS 50struct proc_dir_entry *proc_fs_intermezzo; 51int intermezzo_mount_get_info( char * buffer, char ** start, off_t offset, 52 int length) 53{ 54 int len=0; 55 56 /* this works as long as we are below 1024 characters! */ 57 *start = buffer + offset; 58 len -= offset; 59 60 if ( len < 0 ) 61 return -EINVAL; 62 63 return len; 64} 65 66#endif 67 68 69/* SYSCTL below */ 70 71static struct ctl_table_header *intermezzo_table_header = NULL; 72/* 0x100 to avoid any chance of collisions at any point in the tree with 73 * non-directories 74 */ 75#define PSDEV_INTERMEZZO (0x100) 76 77#define PSDEV_DEBUG 1 /* control debugging */ 78#define PSDEV_TRACE 2 /* control enter/leave pattern */ 79#define PSDEV_TIMEOUT 3 /* timeout on upcalls to become intrble */ 80#define PSDEV_HARD 4 /* mount type "hard" or "soft" */ 81#define PSDEV_NO_FILTER 5 /* controls presto_chk */ 82#define PSDEV_NO_JOURNAL 6 /* controls presto_chk */ 83#define PSDEV_NO_UPCALL 7 /* controls lento_upcall */ 84#define PSDEV_ERRORVAL 8 /* controls presto_debug_fail_blkdev */ 85#define PSDEV_EXCL_GID 9 /* which GID is ignored by presto */ 86#define PSDEV_BYTES_TO_CLOSE 11 /* bytes to write before close */ 87 88/* These are global presto control options */ 89#define PRESTO_PRIMARY_CTLCNT 2 90static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] = 91{ 92 {PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec}, 93 {PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec}, 94}; 95 96/* 97 * Intalling the sysctl entries: strategy 98 * - have templates for each /proc/sys/intermezzo/ entry 99 * such an entry exists for each /dev/presto 100 * (proto_channel_entry) 101 * - have a template for the contents of such directories 102 * (proto_psdev_table) 103 * - have the master table (presto_table) 104 * 105 * When installing, malloc, memcpy and fix up the pointers to point to 106 * the appropriate constants in izo_channels[your_minor] 107 */ 108 109static ctl_table proto_psdev_table[] = { 110 {PSDEV_HARD, "hard", 0, sizeof(int), 0644, NULL, &proc_dointvec}, 111 {PSDEV_NO_FILTER, "no_filter", 0, sizeof(int), 0644, NULL, &proc_dointvec}, 112 {PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, 113 {PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, 114 {PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, 115#ifdef PRESTO_DEBUG 116 {PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, 117#endif 118 { 0 } 119}; 120 121static ctl_table proto_channel_entry = { 122 PSDEV_INTERMEZZO, 0, NULL, 0, 0555, 0, 123}; 124 125static ctl_table intermezzo_table[2] = { 126 {PSDEV_INTERMEZZO, "intermezzo", NULL, 0, 0555, presto_table}, 127 {0} 128}; 129 130/* support for external setting and getting of opts. */ 131/* particularly via ioctl. The Right way to do this is via sysctl, 132 * but that will have to wait until intermezzo gets its own nice set of 133 * sysctl IDs 134 */ 135/* we made these separate as setting may in future be more restricted 136 * than getting 137 */ 138#ifdef RON_MINNICH 139int dosetopt(int minor, struct psdev_opt *opt) 140{ 141 int retval = 0; 142 int newval = opt->optval; 143 144 ENTRY; 145 146 switch(opt->optname) { 147 148 case PSDEV_TIMEOUT: 149 izo_channels[minor].uc_timeout = newval; 150 break; 151 152 case PSDEV_HARD: 153 izo_channels[minor].uc_hard = newval; 154 break; 155 156 case PSDEV_NO_FILTER: 157 izo_channels[minor].uc_no_filter = newval; 158 break; 159 160 case PSDEV_NO_JOURNAL: 161 izo_channels[minor].uc_no_journal = newval; 162 break; 163 164 case PSDEV_NO_UPCALL: 165 izo_channels[minor].uc_no_upcall = newval; 166 break; 167 168#ifdef PRESTO_DEBUG 169 case PSDEV_ERRORVAL: { 170 int errorval = izo_channels[minor].uc_errorval; 171 if (errorval < 0) { 172 if (newval == 0) 173 set_device_ro(-errorval, 0); 174 else 175 CERROR("device %s already read only\n", 176 kdevname(-errorval)); 177 } else { 178 if (newval < 0) 179 set_device_ro(-newval, 1); 180 izo_channels[minor].uc_errorval = newval; 181 CDEBUG(D_PSDEV, "setting errorval to %d\n", newval); 182 } 183 184 break; 185 } 186#endif 187 188 case PSDEV_TRACE: 189 case PSDEV_DEBUG: 190 case PSDEV_BYTES_TO_CLOSE: 191 default: 192 CDEBUG(D_PSDEV, 193 "ioctl: dosetopt: minor %d, bad optname 0x%x, \n", 194 minor, opt->optname); 195 196 retval = -EINVAL; 197 } 198 199 EXIT; 200 return retval; 201} 202 203int dogetopt(int minor, struct psdev_opt *opt) 204{ 205 int retval = 0; 206 207 ENTRY; 208 209 switch(opt->optname) { 210 211 case PSDEV_TIMEOUT: 212 opt->optval = izo_channels[minor].uc_timeout; 213 break; 214 215 case PSDEV_HARD: 216 opt->optval = izo_channels[minor].uc_hard; 217 break; 218 219 case PSDEV_NO_FILTER: 220 opt->optval = izo_channels[minor].uc_no_filter; 221 break; 222 223 case PSDEV_NO_JOURNAL: 224 opt->optval = izo_channels[minor].uc_no_journal; 225 break; 226 227 case PSDEV_NO_UPCALL: 228 opt->optval = izo_channels[minor].uc_no_upcall; 229 break; 230 231#ifdef PSDEV_DEBUG 232 case PSDEV_ERRORVAL: { 233 int errorval = izo_channels[minor].uc_errorval; 234 if (errorval < 0 && is_read_only(-errorval)) 235 CERROR("device %s has been set read-only\n", 236 kdevname(-errorval)); 237 opt->optval = izo_channels[minor].uc_errorval; 238 break; 239 } 240#endif 241 242 case PSDEV_TRACE: 243 case PSDEV_DEBUG: 244 case PSDEV_BYTES_TO_CLOSE: 245 default: 246 CDEBUG(D_PSDEV, 247 "ioctl: dogetopt: minor %d, bad optval 0x%x, \n", 248 minor, opt->optname); 249 250 retval = -EINVAL; 251 } 252 253 EXIT; 254 return retval; 255} 256#endif 257 258 259/* allocate the tables for the presto devices. We need 260 * sizeof(proto_channel_table)/sizeof(proto_channel_table[0]) 261 * entries for each dev 262 */ 263int /* __init */ init_intermezzo_sysctl(void) 264{ 265 int i; 266 int total_dev = MAX_CHANNEL; 267 int entries_per_dev = sizeof(proto_psdev_table) / 268 sizeof(proto_psdev_table[0]); 269 int total_entries = entries_per_dev * total_dev; 270 ctl_table *dev_ctl_table; 271 272 PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries); 273 274 if (! dev_ctl_table) { 275 CERROR("WARNING: presto couldn't allocate dev_ctl_table\n"); 276 EXIT; 277 return -ENOMEM; 278 } 279 280 /* now fill in the entries ... we put the individual presto<x> 281 * entries at the end of the table, and the per-presto stuff 282 * starting at the front. We assume that the compiler makes 283 * this code more efficient, but really, who cares ... it 284 * happens once per reboot. 285 */ 286 for(i = 0; i < total_dev; i++) { 287 /* entry for this /proc/sys/intermezzo/intermezzo"i" */ 288 ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; 289 /* entries for the individual "files" in this "directory" */ 290 ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev]; 291 /* init the psdev and psdev_entries with the prototypes */ 292 *psdev = proto_channel_entry; 293 memcpy(psdev_entries, proto_psdev_table, 294 sizeof(proto_psdev_table)); 295 /* now specialize them ... */ 296 /* the psdev has to point to psdev_entries, and fix the number */ 297 psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */ 298 299 PRESTO_ALLOC((void*)psdev->procname, PROCNAME_SIZE); 300 if (!psdev->procname) { 301 PRESTO_FREE(dev_ctl_table, 302 sizeof(ctl_table) * total_entries); 303 return -ENOMEM; 304 } 305 sprintf((char *) psdev->procname, "intermezzo%d", i); 306 /* hook presto into */ 307 psdev->child = psdev_entries; 308 309 /* now for each psdev entry ... */ 310 psdev_entries[0].data = &(izo_channels[i].uc_hard); 311 psdev_entries[1].data = &(izo_channels[i].uc_no_filter); 312 psdev_entries[2].data = &(izo_channels[i].uc_no_journal); 313 psdev_entries[3].data = &(izo_channels[i].uc_no_upcall); 314 psdev_entries[4].data = &(izo_channels[i].uc_timeout); 315#ifdef PRESTO_DEBUG 316 psdev_entries[5].data = &(izo_channels[i].uc_errorval); 317#endif 318 } 319 320 321#ifdef CONFIG_SYSCTL 322 if ( !intermezzo_table_header ) 323 intermezzo_table_header = 324 register_sysctl_table(intermezzo_table, 0); 325#endif 326#ifdef CONFIG_PROC_FS 327 proc_fs_intermezzo = proc_mkdir("intermezzo", proc_root_fs); 328 proc_fs_intermezzo->owner = THIS_MODULE; 329 create_proc_info_entry("mounts", 0, proc_fs_intermezzo, 330 intermezzo_mount_get_info); 331#endif 332 return 0; 333} 334 335void cleanup_intermezzo_sysctl(void) 336{ 337 int total_dev = MAX_CHANNEL; 338 int entries_per_dev = sizeof(proto_psdev_table) / 339 sizeof(proto_psdev_table[0]); 340 int total_entries = entries_per_dev * total_dev; 341 int i; 342 343#ifdef CONFIG_SYSCTL 344 if ( intermezzo_table_header ) 345 unregister_sysctl_table(intermezzo_table_header); 346 intermezzo_table_header = NULL; 347#endif 348 for(i = 0; i < total_dev; i++) { 349 /* entry for this /proc/sys/intermezzo/intermezzo"i" */ 350 ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; 351 PRESTO_FREE(psdev->procname, PROCNAME_SIZE); 352 } 353 /* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the 354 * dev_ctl_table previously allocated in init_intermezzo_psdev() 355 */ 356 PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries); 357 358#if CONFIG_PROC_FS 359 remove_proc_entry("mounts", proc_fs_intermezzo); 360 remove_proc_entry("intermezzo", proc_root_fs); 361#endif 362} 363 364