/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (C) 1999 Peter J. Braam * * This file is part of InterMezzo, http://www.inter-mezzo.org. * * InterMezzo is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * InterMezzo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with InterMezzo; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Sysctrl entries for Intermezzo! */ #define __NO_VERSION__ #include /* for CONFIG_PROC_FS */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* /proc entries */ #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_fs_intermezzo; int intermezzo_mount_get_info( char * buffer, char ** start, off_t offset, int length) { int len=0; /* this works as long as we are below 1024 characters! */ *start = buffer + offset; len -= offset; if ( len < 0 ) return -EINVAL; return len; } #endif /* SYSCTL below */ static struct ctl_table_header *intermezzo_table_header = NULL; /* 0x100 to avoid any chance of collisions at any point in the tree with * non-directories */ #define PSDEV_INTERMEZZO (0x100) #define PSDEV_DEBUG 1 /* control debugging */ #define PSDEV_TRACE 2 /* control enter/leave pattern */ #define PSDEV_TIMEOUT 3 /* timeout on upcalls to become intrble */ #define PSDEV_HARD 4 /* mount type "hard" or "soft" */ #define PSDEV_NO_FILTER 5 /* controls presto_chk */ #define PSDEV_NO_JOURNAL 6 /* controls presto_chk */ #define PSDEV_NO_UPCALL 7 /* controls lento_upcall */ #define PSDEV_ERRORVAL 8 /* controls presto_debug_fail_blkdev */ #define PSDEV_EXCL_GID 9 /* which GID is ignored by presto */ #define PSDEV_BYTES_TO_CLOSE 11 /* bytes to write before close */ /* These are global presto control options */ #define PRESTO_PRIMARY_CTLCNT 2 static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] = { {PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec}, {PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec}, }; /* * Intalling the sysctl entries: strategy * - have templates for each /proc/sys/intermezzo/ entry * such an entry exists for each /dev/presto * (proto_channel_entry) * - have a template for the contents of such directories * (proto_psdev_table) * - have the master table (presto_table) * * When installing, malloc, memcpy and fix up the pointers to point to * the appropriate constants in izo_channels[your_minor] */ static ctl_table proto_psdev_table[] = { {PSDEV_HARD, "hard", 0, sizeof(int), 0644, NULL, &proc_dointvec}, {PSDEV_NO_FILTER, "no_filter", 0, sizeof(int), 0644, NULL, &proc_dointvec}, {PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, {PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, #ifdef PRESTO_DEBUG {PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec}, #endif { 0 } }; static ctl_table proto_channel_entry = { PSDEV_INTERMEZZO, 0, NULL, 0, 0555, 0, }; static ctl_table intermezzo_table[2] = { {PSDEV_INTERMEZZO, "intermezzo", NULL, 0, 0555, presto_table}, {0} }; /* support for external setting and getting of opts. */ /* particularly via ioctl. The Right way to do this is via sysctl, * but that will have to wait until intermezzo gets its own nice set of * sysctl IDs */ /* we made these separate as setting may in future be more restricted * than getting */ #ifdef RON_MINNICH int dosetopt(int minor, struct psdev_opt *opt) { int retval = 0; int newval = opt->optval; ENTRY; switch(opt->optname) { case PSDEV_TIMEOUT: izo_channels[minor].uc_timeout = newval; break; case PSDEV_HARD: izo_channels[minor].uc_hard = newval; break; case PSDEV_NO_FILTER: izo_channels[minor].uc_no_filter = newval; break; case PSDEV_NO_JOURNAL: izo_channels[minor].uc_no_journal = newval; break; case PSDEV_NO_UPCALL: izo_channels[minor].uc_no_upcall = newval; break; #ifdef PRESTO_DEBUG case PSDEV_ERRORVAL: { /* If we have a positive arg, set a breakpoint for that * value. If we have a negative arg, make that device * read-only. FIXME It would be much better to only * allow setting the underlying device read-only for the * current presto cache. */ int errorval = izo_channels[minor].uc_errorval; if (errorval < 0) { if (newval == 0) set_device_ro(-errorval, 0); else CERROR("device %s already read only\n", kdevname(-errorval)); } else { if (newval < 0) set_device_ro(-newval, 1); izo_channels[minor].uc_errorval = newval; CDEBUG(D_PSDEV, "setting errorval to %d\n", newval); } break; } #endif case PSDEV_TRACE: case PSDEV_DEBUG: case PSDEV_BYTES_TO_CLOSE: default: CDEBUG(D_PSDEV, "ioctl: dosetopt: minor %d, bad optname 0x%x, \n", minor, opt->optname); retval = -EINVAL; } EXIT; return retval; } int dogetopt(int minor, struct psdev_opt *opt) { int retval = 0; ENTRY; switch(opt->optname) { case PSDEV_TIMEOUT: opt->optval = izo_channels[minor].uc_timeout; break; case PSDEV_HARD: opt->optval = izo_channels[minor].uc_hard; break; case PSDEV_NO_FILTER: opt->optval = izo_channels[minor].uc_no_filter; break; case PSDEV_NO_JOURNAL: opt->optval = izo_channels[minor].uc_no_journal; break; case PSDEV_NO_UPCALL: opt->optval = izo_channels[minor].uc_no_upcall; break; #ifdef PSDEV_DEBUG case PSDEV_ERRORVAL: { int errorval = izo_channels[minor].uc_errorval; if (errorval < 0 && is_read_only(-errorval)) CERROR("device %s has been set read-only\n", kdevname(-errorval)); opt->optval = izo_channels[minor].uc_errorval; break; } #endif case PSDEV_TRACE: case PSDEV_DEBUG: case PSDEV_BYTES_TO_CLOSE: default: CDEBUG(D_PSDEV, "ioctl: dogetopt: minor %d, bad optval 0x%x, \n", minor, opt->optname); retval = -EINVAL; } EXIT; return retval; } #endif /* allocate the tables for the presto devices. We need * sizeof(proto_channel_table)/sizeof(proto_channel_table[0]) * entries for each dev */ int /* __init */ init_intermezzo_sysctl(void) { int i; int total_dev = MAX_CHANNEL; int entries_per_dev = sizeof(proto_psdev_table) / sizeof(proto_psdev_table[0]); int total_entries = entries_per_dev * total_dev; ctl_table *dev_ctl_table; PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries); if (! dev_ctl_table) { CERROR("WARNING: presto couldn't allocate dev_ctl_table\n"); EXIT; return -ENOMEM; } /* now fill in the entries ... we put the individual presto * entries at the end of the table, and the per-presto stuff * starting at the front. We assume that the compiler makes * this code more efficient, but really, who cares ... it * happens once per reboot. */ for(i = 0; i < total_dev; i++) { void *p; /* entry for this /proc/sys/intermezzo/intermezzo"i" */ ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; /* entries for the individual "files" in this "directory" */ ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev]; /* init the psdev and psdev_entries with the prototypes */ *psdev = proto_channel_entry; memcpy(psdev_entries, proto_psdev_table, sizeof(proto_psdev_table)); /* now specialize them ... */ /* the psdev has to point to psdev_entries, and fix the number */ psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */ PRESTO_ALLOC(p, PROCNAME_SIZE); psdev->procname = p; if (!psdev->procname) { PRESTO_FREE(dev_ctl_table, sizeof(ctl_table) * total_entries); return -ENOMEM; } sprintf((char *) psdev->procname, "intermezzo%d", i); /* hook presto into */ psdev->child = psdev_entries; /* now for each psdev entry ... */ psdev_entries[0].data = &(izo_channels[i].uc_hard); psdev_entries[1].data = &(izo_channels[i].uc_no_filter); psdev_entries[2].data = &(izo_channels[i].uc_no_journal); psdev_entries[3].data = &(izo_channels[i].uc_no_upcall); psdev_entries[4].data = &(izo_channels[i].uc_timeout); #ifdef PRESTO_DEBUG psdev_entries[5].data = &(izo_channels[i].uc_errorval); #endif } #ifdef CONFIG_SYSCTL if ( !intermezzo_table_header ) intermezzo_table_header = register_sysctl_table(intermezzo_table, 0); #endif #ifdef CONFIG_PROC_FS proc_fs_intermezzo = proc_mkdir("intermezzo", proc_root_fs); proc_fs_intermezzo->owner = THIS_MODULE; create_proc_info_entry("mounts", 0, proc_fs_intermezzo, intermezzo_mount_get_info); #endif return 0; } void cleanup_intermezzo_sysctl(void) { int total_dev = MAX_CHANNEL; int entries_per_dev = sizeof(proto_psdev_table) / sizeof(proto_psdev_table[0]); int total_entries = entries_per_dev * total_dev; int i; #ifdef CONFIG_SYSCTL if ( intermezzo_table_header ) unregister_sysctl_table(intermezzo_table_header); intermezzo_table_header = NULL; #endif for(i = 0; i < total_dev; i++) { /* entry for this /proc/sys/intermezzo/intermezzo"i" */ ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT]; PRESTO_FREE(psdev->procname, PROCNAME_SIZE); } /* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the * dev_ctl_table previously allocated in init_intermezzo_psdev() */ PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries); #if CONFIG_PROC_FS remove_proc_entry("mounts", proc_fs_intermezzo); remove_proc_entry("intermezzo", proc_root_fs); #endif }