1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 1999 Peter J. Braam <braam@clusterfs.com>
6 * This file is part of InterMezzo, http://www.inter-mezzo.org.
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.
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.
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.
21 * Sysctrl entries for Intermezzo!
24 #include <linux/config.h> /* for CONFIG_PROC_FS */
25 #include <linux/module.h>
26 #include <linux/sched.h>
28 #include <linux/sysctl.h>
29 #include <linux/proc_fs.h>
30 #include <linux/slab.h>
31 #include <linux/vmalloc.h>
32 #include <linux/stat.h>
33 #include <linux/ctype.h>
34 #include <linux/init.h>
35 #include <asm/bitops.h>
36 #include <asm/segment.h>
37 #include <asm/uaccess.h>
38 #include <linux/utsname.h>
40 #include "intermezzo_fs.h"
41 #include "intermezzo_psdev.h"
46 struct proc_dir_entry *proc_fs_intermezzo;
47 int intermezzo_mount_get_info( char * buffer, char ** start, off_t offset,
52 /* this works as long as we are below 1024 characters! */
53 *start = buffer + offset;
67 static struct ctl_table_header *intermezzo_table_header = NULL;
68 /* 0x100 to avoid any chance of collisions at any point in the tree with
71 #define PSDEV_INTERMEZZO (0x100)
73 #define PSDEV_DEBUG 1 /* control debugging */
74 #define PSDEV_TRACE 2 /* control enter/leave pattern */
75 #define PSDEV_TIMEOUT 3 /* timeout on upcalls to become intrble */
76 #define PSDEV_HARD 4 /* mount type "hard" or "soft" */
77 #define PSDEV_NO_FILTER 5 /* controls presto_chk */
78 #define PSDEV_NO_JOURNAL 6 /* controls presto_chk */
79 #define PSDEV_NO_UPCALL 7 /* controls lento_upcall */
80 #define PSDEV_ERRORVAL 8 /* controls presto_debug_fail_blkdev */
81 #define PSDEV_EXCL_GID 9 /* which GID is ignored by presto */
82 #define PSDEV_BYTES_TO_CLOSE 11 /* bytes to write before close */
84 /* These are global presto control options */
85 #define PRESTO_PRIMARY_CTLCNT 2
86 static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] =
88 {PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec},
89 {PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
93 * Intalling the sysctl entries: strategy
94 * - have templates for each /proc/sys/intermezzo/ entry
95 * such an entry exists for each /dev/presto
96 * (proto_channel_entry)
97 * - have a template for the contents of such directories
99 * - have the master table (presto_table)
101 * When installing, malloc, memcpy and fix up the pointers to point to
102 * the appropriate constants in izo_channels[your_minor]
105 static ctl_table proto_psdev_table[] = {
106 {PSDEV_HARD, "hard", 0, sizeof(int), 0644, NULL, &proc_dointvec},
107 {PSDEV_NO_FILTER, "no_filter", 0, sizeof(int), 0644, NULL, &proc_dointvec},
108 {PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
109 {PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
110 {PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
112 {PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
117 static ctl_table proto_channel_entry = {
118 PSDEV_INTERMEZZO, 0, NULL, 0, 0555, 0,
121 static ctl_table intermezzo_table[2] = {
122 {PSDEV_INTERMEZZO, "intermezzo", NULL, 0, 0555, presto_table},
126 /* support for external setting and getting of opts. */
127 /* particularly via ioctl. The Right way to do this is via sysctl,
128 * but that will have to wait until intermezzo gets its own nice set of
131 /* we made these separate as setting may in future be more restricted
135 int dosetopt(int minor, struct psdev_opt *opt)
138 int newval = opt->optval;
142 switch(opt->optname) {
145 izo_channels[minor].uc_timeout = newval;
149 izo_channels[minor].uc_hard = newval;
152 case PSDEV_NO_FILTER:
153 izo_channels[minor].uc_no_filter = newval;
156 case PSDEV_NO_JOURNAL:
157 izo_channels[minor].uc_no_journal = newval;
160 case PSDEV_NO_UPCALL:
161 izo_channels[minor].uc_no_upcall = newval;
165 case PSDEV_ERRORVAL: {
166 /* If we have a positive arg, set a breakpoint for that
167 * value. If we have a negative arg, make that device
168 * read-only. FIXME It would be much better to only
169 * allow setting the underlying device read-only for the
170 * current presto cache.
172 int errorval = izo_channels[minor].uc_errorval;
175 set_device_ro(-errorval, 0);
177 CERROR("device %s already read only\n",
178 kdevname(-errorval));
181 set_device_ro(-newval, 1);
182 izo_channels[minor].uc_errorval = newval;
183 CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
192 case PSDEV_BYTES_TO_CLOSE:
195 "ioctl: dosetopt: minor %d, bad optname 0x%x, \n",
196 minor, opt->optname);
205 int dogetopt(int minor, struct psdev_opt *opt)
211 switch(opt->optname) {
214 opt->optval = izo_channels[minor].uc_timeout;
218 opt->optval = izo_channels[minor].uc_hard;
221 case PSDEV_NO_FILTER:
222 opt->optval = izo_channels[minor].uc_no_filter;
225 case PSDEV_NO_JOURNAL:
226 opt->optval = izo_channels[minor].uc_no_journal;
229 case PSDEV_NO_UPCALL:
230 opt->optval = izo_channels[minor].uc_no_upcall;
234 case PSDEV_ERRORVAL: {
235 int errorval = izo_channels[minor].uc_errorval;
236 if (errorval < 0 && is_read_only(-errorval))
237 CERROR("device %s has been set read-only\n",
238 kdevname(-errorval));
239 opt->optval = izo_channels[minor].uc_errorval;
246 case PSDEV_BYTES_TO_CLOSE:
249 "ioctl: dogetopt: minor %d, bad optval 0x%x, \n",
250 minor, opt->optname);
261 /* allocate the tables for the presto devices. We need
262 * sizeof(proto_channel_table)/sizeof(proto_channel_table[0])
263 * entries for each dev
265 int /* __init */ init_intermezzo_sysctl(void)
268 int total_dev = MAX_CHANNEL;
269 int entries_per_dev = sizeof(proto_psdev_table) /
270 sizeof(proto_psdev_table[0]);
271 int total_entries = entries_per_dev * total_dev;
272 ctl_table *dev_ctl_table;
274 PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries);
276 if (! dev_ctl_table) {
277 CERROR("WARNING: presto couldn't allocate dev_ctl_table\n");
282 /* now fill in the entries ... we put the individual presto<x>
283 * entries at the end of the table, and the per-presto stuff
284 * starting at the front. We assume that the compiler makes
285 * this code more efficient, but really, who cares ... it
286 * happens once per reboot.
288 for(i = 0; i < total_dev; i++) {
291 /* entry for this /proc/sys/intermezzo/intermezzo"i" */
292 ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
293 /* entries for the individual "files" in this "directory" */
294 ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev];
295 /* init the psdev and psdev_entries with the prototypes */
296 *psdev = proto_channel_entry;
297 memcpy(psdev_entries, proto_psdev_table,
298 sizeof(proto_psdev_table));
299 /* now specialize them ... */
300 /* the psdev has to point to psdev_entries, and fix the number */
301 psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */
303 PRESTO_ALLOC(p, PROCNAME_SIZE);
305 if (!psdev->procname) {
306 PRESTO_FREE(dev_ctl_table,
307 sizeof(ctl_table) * total_entries);
310 sprintf((char *) psdev->procname, "intermezzo%d", i);
311 /* hook presto into */
312 psdev->child = psdev_entries;
314 /* now for each psdev entry ... */
315 psdev_entries[0].data = &(izo_channels[i].uc_hard);
316 psdev_entries[1].data = &(izo_channels[i].uc_no_filter);
317 psdev_entries[2].data = &(izo_channels[i].uc_no_journal);
318 psdev_entries[3].data = &(izo_channels[i].uc_no_upcall);
319 psdev_entries[4].data = &(izo_channels[i].uc_timeout);
321 psdev_entries[5].data = &(izo_channels[i].uc_errorval);
327 if ( !intermezzo_table_header )
328 intermezzo_table_header =
329 register_sysctl_table(intermezzo_table, 0);
331 #ifdef CONFIG_PROC_FS
332 proc_fs_intermezzo = proc_mkdir("intermezzo", proc_root_fs);
333 proc_fs_intermezzo->owner = THIS_MODULE;
334 create_proc_info_entry("mounts", 0, proc_fs_intermezzo,
335 intermezzo_mount_get_info);
340 void cleanup_intermezzo_sysctl(void)
342 int total_dev = MAX_CHANNEL;
343 int entries_per_dev = sizeof(proto_psdev_table) /
344 sizeof(proto_psdev_table[0]);
345 int total_entries = entries_per_dev * total_dev;
349 if ( intermezzo_table_header )
350 unregister_sysctl_table(intermezzo_table_header);
351 intermezzo_table_header = NULL;
353 for(i = 0; i < total_dev; i++) {
354 /* entry for this /proc/sys/intermezzo/intermezzo"i" */
355 ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
356 PRESTO_FREE(psdev->procname, PROCNAME_SIZE);
358 /* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the
359 * dev_ctl_table previously allocated in init_intermezzo_psdev()
361 PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries);
363 #ifdef CONFIG_PROC_FS
364 remove_proc_entry("mounts", proc_fs_intermezzo);
365 remove_proc_entry("intermezzo", proc_root_fs);