1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=4:tabstop=4:
5 * Copyright (c) 2004 Cluster File Systems, Inc.
7 * This file is part of Lustre, http://www.lustre.org.
9 * Lustre is free software; you can redistribute it and/or modify it under
10 * the terms of version 2 of the GNU General Public License as published by
11 * the Free Software Foundation. Lustre is distributed in the hope that it
12 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. You should have received a
15 * copy of the GNU General Public License along with Lustre; if not, write
16 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
22 # define EXPORT_SYMTAB
25 # define DEBUG_SUBSYSTEM S_LNET
27 #include <libcfs/libcfs.h>
28 #include "tracefile.h"
34 * /proc emulator routines ...
37 /* The root node of the proc fs emulation: /proc */
38 cfs_proc_entry_t * proc_fs_root = NULL;
41 /* The sys root: /proc/sys */
42 cfs_proc_entry_t * proc_sys_root = NULL;
45 /* The sys root: /proc/dev | to implement misc device */
47 cfs_proc_entry_t * proc_dev_root = NULL;
50 /* SLAB object for cfs_proc_entry_t allocation */
52 cfs_mem_cache_t * proc_entry_cache = NULL;
54 /* root node for sysctl table */
56 cfs_sysctl_table_header_t root_table_header;
58 /* The global lock to protect all the access */
60 #if LIBCFS_PROCFS_SPINLOCK
61 spinlock_t proc_fs_lock;
63 #define INIT_PROCFS_LOCK() spin_lock_init(&proc_fs_lock)
64 #define LOCK_PROCFS() spin_lock(&proc_fs_lock)
65 #define UNLOCK_PROCFS() spin_unlock(&proc_fs_lock)
71 #define INIT_PROCFS_LOCK() init_mutex(&proc_fs_lock)
72 #define LOCK_PROCFS() mutex_down(&proc_fs_lock)
73 #define UNLOCK_PROCFS() mutex_up(&proc_fs_lock)
78 proc_file_read(struct file * file, const char * buf, size_t nbytes, loff_t *ppos)
85 cfs_proc_entry_t * dp;
87 dp = (cfs_proc_entry_t *) file->private_data;
88 if (!(page = (char*) cfs_alloc(CFS_PAGE_SIZE, 0)))
91 while ((nbytes > 0) && !eof) {
93 count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
97 n = dp->read_proc( page, &start, (long)*ppos,
98 count, &eof, dp->data);
104 * For proc files that are less than 4k
106 start = page + *ppos;
107 n -= (ssize_t)(*ppos);
114 break; /* End of file */
121 n -= copy_to_user((void *)buf, start, n);
139 proc_file_write(struct file * file, const char * buffer,
140 size_t count, loff_t *ppos)
142 cfs_proc_entry_t * dp;
144 dp = (cfs_proc_entry_t *) file->private_data;
149 /* FIXME: does this routine need ppos? probably... */
150 return dp->write_proc(file, buffer, count, dp->data);
153 struct file_operations proc_file_operations = {
154 /*lseek:*/ NULL, //proc_file_lseek,
155 /*read:*/ proc_file_read,
156 /*write:*/ proc_file_write,
162 /* allocate proc entry block */
167 cfs_proc_entry_t * entry = NULL;
169 entry = cfs_mem_cache_alloc(proc_entry_cache, 0);
174 memset(entry, 0, sizeof(cfs_proc_entry_t));
176 entry->magic = CFS_PROC_ENTRY_MAGIC;
177 RtlInitializeSplayLinks(&(entry->s_link));
178 entry->proc_fops = &proc_file_operations;
183 /* free the proc entry block */
186 proc_free_entry(cfs_proc_entry_t * entry)
189 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
191 cfs_mem_cache_free(proc_entry_cache, entry);
194 /* dissect the path string for a given full proc path */
204 int i = 0, j = 0, len = 0;
206 *first = *remain = NULL;
211 while (i < len && (path[i] == '/')) i++;
216 while (i < len && (path[i] != '/')) i++;
217 *first_len = (path + i - *first);
220 *remain = path + i + 1;
225 /* search the children entries of the parent entry */
229 cfs_proc_entry_t * parent,
233 cfs_proc_entry_t * node;
234 PRTL_SPLAY_LINKS link;
236 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
237 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
243 ANSI_STRING ename,nname;
246 node = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
248 ASSERT(node->magic == CFS_PROC_ENTRY_MAGIC);
250 /* Compare the prefix in the tree with the full name */
252 RtlInitAnsiString(&ename, name);
253 RtlInitAnsiString(&nname, node->name);
255 result = RtlCompareString(&nname, &ename,TRUE);
259 /* The prefix is greater than the full name
260 so we go down the left child */
262 link = RtlLeftChild(link);
264 } else if (result < 0) {
266 /* The prefix is less than the full name
267 so we go down the right child */
270 link = RtlRightChild(link);
274 /* We got the entry in the splay tree and
275 make it root node instead */
277 parent->root = RtlSplay(link);
282 /* we need continue searching down the tree ... */
285 /* There's no the exptected entry in the splay tree */
292 cfs_proc_entry_t * parent,
293 cfs_proc_entry_t * child
296 cfs_proc_entry_t * entry;
298 ASSERT(parent != NULL && child != NULL);
299 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
300 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
301 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
304 parent->root = &(child->s_link);
306 entry = CONTAINING_RECORD(parent->root, cfs_proc_entry_t, s_link);
309 ANSI_STRING ename, cname;
311 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
313 RtlInitAnsiString(&ename, entry->name);
314 RtlInitAnsiString(&cname, child->name);
316 result = RtlCompareString(&ename, &cname,TRUE);
319 cfs_enter_debugger();
320 if (entry == child) {
327 if (RtlLeftChild(&entry->s_link) == NULL) {
328 RtlInsertAsLeftChild(&entry->s_link, &child->s_link);
331 entry = CONTAINING_RECORD( RtlLeftChild(&entry->s_link),
332 cfs_proc_entry_t, s_link);
335 if (RtlRightChild(&entry->s_link) == NULL) {
336 RtlInsertAsRightChild(&entry->s_link, &child->s_link);
339 entry = CONTAINING_RECORD( RtlRightChild(&entry->s_link),
340 cfs_proc_entry_t, s_link );
346 cfs_set_flag(child->flags, CFS_PROC_FLAG_ATTACHED);
353 /* remove a child entry from the splay tree */
356 cfs_proc_entry_t * parent,
357 cfs_proc_entry_t * child
360 cfs_proc_entry_t * entry = NULL;
362 ASSERT(parent != NULL && child != NULL);
363 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
364 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
365 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
366 ASSERT(cfs_is_flag_set(child->flags, CFS_PROC_FLAG_ATTACHED));
368 entry = proc_search_splay(parent, child->name);
371 ASSERT(entry == child);
372 parent->root = RtlDelete(&(entry->s_link));
375 cfs_enter_debugger();
383 /* search a node inside the proc fs tree */
388 cfs_proc_entry_t * root
391 cfs_proc_entry_t * entry;
392 cfs_proc_entry_t * parent;
393 char *first, *remain;
400 ename = cfs_alloc(0x21, CFS_ALLOC_ZERO);
408 /* dissect the file name string */
409 proc_dissect_name(name, &first, &flen, &remain);
414 cfs_enter_debugger();
419 memset(ename, 0, 0x20);
420 memcpy(ename, first, flen);
422 entry = proc_search_splay(parent, ename);
445 /* insert the path nodes to the proc fs tree */
450 cfs_proc_entry_t * root
453 cfs_proc_entry_t *entry;
454 cfs_proc_entry_t *parent;
455 char *first, *remain;
464 proc_dissect_name(name, &first, &flen, &remain);
472 memset(ename, 0, 0x20);
473 memcpy(ename, first, flen);
475 entry = proc_search_splay(parent, ename);
478 entry = proc_alloc_entry();
479 memcpy(entry->name, ename, flen);
482 if(!proc_insert_splay(parent, entry)) {
483 proc_free_entry(entry);
494 entry->mode |= S_IFDIR | S_IRUGO | S_IXUGO;
495 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
505 /* remove the path nodes from the proc fs tree */
510 cfs_proc_entry_t * root
513 cfs_proc_entry_t *entry;
514 char *first, *remain;
520 proc_dissect_name(name, &first, &flen, &remain);
524 memset(ename, 0, 0x20);
525 memcpy(ename, first, flen);
527 entry = proc_search_splay(root, ename);
532 ASSERT(S_ISDIR(entry->mode));
533 proc_remove_entry(remain, entry);
537 proc_remove_splay(root, entry);
538 proc_free_entry(entry);
542 cfs_enter_debugger();
546 /* create proc entry and insert it into the proc fs */
552 cfs_proc_entry_t * root
555 cfs_proc_entry_t *parent = root;
556 cfs_proc_entry_t *entry = NULL;
559 if ((mode & S_IALLUGO) == 0)
560 mode |= S_IRUGO | S_IXUGO;
562 if ((mode & S_IFMT) == 0)
564 if ((mode & S_IALLUGO) == 0)
570 ASSERT(NULL != proc_fs_root);
573 parent = proc_fs_root;
576 entry = proc_search_entry(name, parent);
579 entry = proc_insert_entry(name, parent);
581 /* Failed to create/insert the splay node ... */
582 cfs_enter_debugger();
585 /* Initializing entry ... */
589 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
601 /* search the specified entry form the proc fs */
606 cfs_proc_entry_t * root
609 cfs_proc_entry_t * entry;
615 entry = proc_search_entry(name, root);
621 /* remove the entry from the proc fs */
626 cfs_proc_entry_t * parent
630 if (parent == NULL) {
631 parent = proc_fs_root;
633 proc_remove_entry(name, parent);
638 void proc_destroy_splay(cfs_proc_entry_t * entry)
640 cfs_proc_entry_t * node;
642 if (S_ISDIR(entry->mode)) {
644 while (entry->root) {
645 node = CONTAINING_RECORD(entry->root, cfs_proc_entry_t, s_link);
646 entry->root = RtlDelete(&(node->s_link));
647 proc_destroy_splay(node);
651 proc_free_entry(entry);
655 /* destory the whole proc fs tree */
657 void proc_destroy_fs()
662 proc_destroy_splay(proc_fs_root);
665 if (proc_entry_cache) {
666 cfs_mem_cache_destroy(proc_entry_cache);
672 /* initilaize / build the proc fs tree */
676 cfs_proc_entry_t * root = NULL;
678 memset(&(root_table_header), 0, sizeof(struct ctl_table_header));
679 INIT_LIST_HEAD(&(root_table_header.ctl_entry));
682 proc_entry_cache = cfs_mem_cache_create(
684 sizeof(cfs_proc_entry_t),
689 if (!proc_entry_cache) {
693 root = proc_alloc_entry();
700 root->magic = CFS_PROC_ENTRY_MAGIC;
701 root->flags = CFS_PROC_FLAG_DIRECTORY;
702 root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
703 root->nlink = 3; // root should never be deleted.
712 proc_sys_root = create_proc_entry("sys", S_IFDIR, root);
714 if (!proc_sys_root) {
715 proc_free_entry(root);
721 proc_sys_root->nlink = 1;
723 proc_dev_root = create_proc_entry("dev", S_IFDIR, root);
725 if (!proc_dev_root) {
726 proc_free_entry(proc_sys_root);
727 proc_sys_root = NULL;
728 proc_free_entry(proc_fs_root);
734 proc_dev_root->nlink = 1;
740 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
741 size_t count, loff_t *ppos)
744 cfs_proc_entry_t *de;
745 struct ctl_table *table;
749 de = (cfs_proc_entry_t *) file->proc_dentry;
751 if (!de || !de->data)
753 table = (struct ctl_table *) de->data;
754 if (!table || !table->proc_handler)
756 op = (write ? 002 : 004);
758 // if (ctl_perm(table, op))
764 * FIXME: we need to pass on ppos to the handler.
767 error = (*table->proc_handler) (table, write, file, buf, &res);
773 static ssize_t proc_readsys(struct file * file, char * buf,
774 size_t count, loff_t *ppos)
776 return do_rw_proc(0, file, buf, count, ppos);
779 static ssize_t proc_writesys(struct file * file, const char * buf,
780 size_t count, loff_t *ppos)
782 return do_rw_proc(1, file, (char *) buf, count, ppos);
786 struct file_operations proc_sys_file_operations = {
788 /*read:*/ proc_readsys,
789 /*write:*/ proc_writesys,
796 /* Scan the sysctl entries in table and add them all into /proc */
797 void register_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t * root)
799 cfs_proc_entry_t * de;
803 for (; table->ctl_name; table++) {
804 /* Can't do anything without a proc name. */
805 if (!table->procname)
807 /* Maybe we can't do anything with it... */
808 if (!table->proc_handler && !table->child) {
809 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
814 len = strlen(table->procname);
818 if (table->proc_handler)
821 de = search_proc_entry(table->procname, root);
825 /* If the subdir exists already, de is non-NULL */
830 de = create_proc_entry((char *)table->procname, mode, root);
833 de->data = (void *) table;
834 if (table->proc_handler) {
835 de->proc_fops = &proc_sys_file_operations;
839 if (de->mode & S_IFDIR)
840 register_proc_table(table->child, de);
846 * Unregister a /proc sysctl table and any subdirectories.
848 void unregister_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t *root)
850 cfs_proc_entry_t *de;
851 for (; table->ctl_name; table++) {
852 if (!(de = table->de))
854 if (de->mode & S_IFDIR) {
856 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
859 unregister_proc_table(table->child, de);
861 /* Don't unregister directories which still have entries.. */
866 /* Don't unregister proc entries that are still being used.. */
871 remove_proc_entry((char *)table->procname, root);
875 /* The generic string strategy routine: */
876 int sysctl_string(cfs_sysctl_table_t *table, int *name, int nlen,
877 void *oldval, size_t *oldlenp,
878 void *newval, size_t newlen, void **context)
882 if (!table->data || !table->maxlen)
885 if (oldval && oldlenp) {
886 if(get_user(len, oldlenp))
889 l = strlen(table->data);
890 if (len > l) len = l;
891 if (len >= table->maxlen)
893 if(copy_to_user(oldval, table->data, len))
895 if(put_user(0, ((char *) oldval) + len))
897 if(put_user(len, oldlenp))
901 if (newval && newlen) {
903 if (len > table->maxlen)
905 if(copy_from_user(table->data, newval, len))
907 if (len == table->maxlen)
909 ((char *) table->data)[len] = 0;
915 * simple_strtoul - convert a string to an unsigned long
916 * @cp: The start of the string
917 * @endp: A pointer to the end of the parsed string will be placed here
918 * @base: The number base to use
920 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
922 unsigned long result = 0, value;
929 if ((*cp == 'x') && isxdigit(cp[1])) {
935 while (isxdigit(*cp) &&
936 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
937 result = result*base + value;
952 static int do_proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
953 void *buffer, size_t *lenp, int conv, int op)
955 int *i, vleft, first=1, neg, val;
959 char buf[TMPBUFLEN], *p;
961 if (!table->data || !table->maxlen || !*lenp)
967 i = (int *) table->data;
968 vleft = table->maxlen / sizeof(int);
971 for (; left && vleft--; i++, first=0) {
975 if(get_user(c,(char *) buffer))
986 if (len > TMPBUFLEN-1)
988 if(copy_from_user(buf, buffer, len))
992 if (*p == '-' && left > 1) {
996 if (*p < '0' || *p > '9')
998 val = simple_strtoul(p, &p, 0) * conv;
1000 if ((len < left) && *p && !isspace(*p))
1004 (char *)buffer += len;
1007 case OP_SET: *i = val; break;
1008 case OP_AND: *i &= val; break;
1009 case OP_OR: *i |= val; break;
1010 case OP_MAX: if(*i < val)
1013 case OP_MIN: if(*i > val)
1021 sprintf(p, "%d", (*i) / conv);
1025 if(copy_to_user(buffer, buf, len))
1028 (char *)buffer += len;
1032 if (!write && !first && left) {
1033 if(put_user('\n', (char *) buffer))
1035 left--, ((char *)buffer)++;
1038 p = (char *) buffer;
1041 if(get_user(c, p++))
1051 memset(&(filp->f_pos) , 0, sizeof(loff_t));
1052 filp->f_pos += (loff_t)(*lenp);
1057 * proc_dointvec - read a vector of integers
1058 * @table: the sysctl table
1059 * @write: %TRUE if this is a write to the sysctl file
1060 * @filp: the file structure
1061 * @buffer: the user buffer
1062 * @lenp: the size of the user buffer
1064 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1065 * values from/to the user buffer, treated as an ASCII string.
1067 * Returns 0 on success.
1069 int proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1070 void *buffer, size_t *lenp)
1072 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1077 * proc_dostring - read a string sysctl
1078 * @table: the sysctl table
1079 * @write: %TRUE if this is a write to the sysctl file
1080 * @filp: the file structure
1081 * @buffer: the user buffer
1082 * @lenp: the size of the user buffer
1084 * Reads/writes a string from/to the user buffer. If the kernel
1085 * buffer provided is not large enough to hold the string, the
1086 * string is truncated. The copied string is %NULL-terminated.
1087 * If the string is being read by the user process, it is copied
1088 * and a newline '\n' is added. It is truncated if the buffer is
1091 * Returns 0 on success.
1093 int proc_dostring(cfs_sysctl_table_t *table, int write, struct file *filp,
1094 void *buffer, size_t *lenp)
1099 if (!table->data || !table->maxlen || !*lenp ||
1100 (filp->f_pos && !write)) {
1108 while (len < *lenp) {
1109 if(get_user(c, p++))
1111 if (c == 0 || c == '\n')
1115 if (len >= (size_t)table->maxlen)
1116 len = (size_t)table->maxlen-1;
1117 if(copy_from_user(table->data, buffer, len))
1119 ((char *) table->data)[len] = 0;
1120 filp->f_pos += *lenp;
1122 len = (size_t)strlen(table->data);
1123 if (len > (size_t)table->maxlen)
1124 len = (size_t)table->maxlen;
1128 if(copy_to_user(buffer, table->data, len))
1131 if(put_user('\n', ((char *) buffer) + len))
1141 /* Perform the actual read/write of a sysctl table entry. */
1142 int do_sysctl_strategy (cfs_sysctl_table_t *table,
1143 int *name, int nlen,
1144 void *oldval, size_t *oldlenp,
1145 void *newval, size_t newlen, void **context)
1155 if (table->strategy) {
1156 rc = table->strategy(table, name, nlen, oldval, oldlenp,
1157 newval, newlen, context);
1164 /* If there is no strategy routine, or if the strategy returns
1165 * zero, proceed with automatic r/w */
1166 if (table->data && table->maxlen) {
1167 if (oldval && oldlenp) {
1168 get_user(len, oldlenp);
1170 if (len > (size_t)table->maxlen)
1171 len = (size_t)table->maxlen;
1172 if(copy_to_user(oldval, table->data, len))
1174 if(put_user(len, oldlenp))
1178 if (newval && newlen) {
1180 if (len > (size_t)table->maxlen)
1181 len = (size_t)table->maxlen;
1182 if(copy_from_user(table->data, newval, len))
1189 static int parse_table(int *name, int nlen,
1190 void *oldval, size_t *oldlenp,
1191 void *newval, size_t newlen,
1192 cfs_sysctl_table_t *table, void **context)
1200 if (get_user(n, name))
1202 for ( ; table->ctl_name; table++) {
1203 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1207 if (ctl_perm(table, 001))
1210 if (table->strategy) {
1211 error = table->strategy(
1214 newval, newlen, context);
1220 table = table->child;
1223 error = do_sysctl_strategy(table, name, nlen,
1225 newval, newlen, context);
1232 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1233 void *newval, size_t newlen)
1235 struct list_head *tmp;
1237 if (nlen <= 0 || nlen >= CTL_MAXNAME)
1241 if (!oldlenp || get_user(old_len, oldlenp))
1244 tmp = &root_table_header.ctl_entry;
1246 struct ctl_table_header *head =
1247 list_entry(tmp, struct ctl_table_header, ctl_entry);
1248 void *context = NULL;
1249 int error = parse_table(name, nlen, oldval, oldlenp,
1250 newval, newlen, head->ctl_table,
1254 if (error != -ENOTDIR)
1257 } while (tmp != &root_table_header.ctl_entry);
1262 * register_sysctl_table - register a sysctl heirarchy
1263 * @table: the top-level table structure
1264 * @insert_at_head: whether the entry should be inserted in front or at the end
1266 * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1267 * array. An entry with a ctl_name of 0 terminates the table.
1269 * The members of the &ctl_table structure are used as follows:
1271 * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1272 * must be unique within that level of sysctl
1274 * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1275 * enter a sysctl file
1277 * data - a pointer to data for use by proc_handler
1279 * maxlen - the maximum size in bytes of the data
1281 * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1283 * child - a pointer to the child sysctl table if this entry is a directory, or
1286 * proc_handler - the text handler routine (described below)
1288 * strategy - the strategy routine (described below)
1290 * de - for internal use by the sysctl routines
1292 * extra1, extra2 - extra pointers usable by the proc handler routines
1294 * Leaf nodes in the sysctl tree will be represented by a single file
1295 * under /proc; non-leaf nodes will be represented by directories.
1297 * sysctl(2) can automatically manage read and write requests through
1298 * the sysctl table. The data and maxlen fields of the ctl_table
1299 * struct enable minimal validation of the values being written to be
1300 * performed, and the mode field allows minimal authentication.
1302 * More sophisticated management can be enabled by the provision of a
1303 * strategy routine with the table entry. This will be called before
1304 * any automatic read or write of the data is performed.
1306 * The strategy routine may return
1308 * < 0 - Error occurred (error is passed to user process)
1310 * 0 - OK - proceed with automatic read or write.
1312 * > 0 - OK - read or write has been done by the strategy routine, so
1313 * return immediately.
1315 * There must be a proc_handler routine for any terminal nodes
1316 * mirrored under /proc/sys (non-terminals are handled by a built-in
1317 * directory handler). Several default handlers are available to
1318 * cover common cases -
1320 * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1321 * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1322 * proc_doulongvec_minmax()
1324 * It is the handler's job to read the input buffer from user memory
1325 * and process it. The handler should return 0 on success.
1327 * This routine returns %NULL on a failure to register, and a pointer
1328 * to the table header on success.
1330 struct ctl_table_header *register_sysctl_table(cfs_sysctl_table_t * table,
1333 struct ctl_table_header *tmp;
1334 tmp = cfs_alloc(sizeof(struct ctl_table_header), 0);
1337 tmp->ctl_table = table;
1339 INIT_LIST_HEAD(&tmp->ctl_entry);
1341 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
1343 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1344 #ifdef CONFIG_PROC_FS
1345 register_proc_table(table, proc_sys_root);
1351 * unregister_sysctl_table - unregister a sysctl table heirarchy
1352 * @header: the header returned from register_sysctl_table
1354 * Unregisters the sysctl table and all children. proc entries may not
1355 * actually be removed until they are no longer used by anyone.
1357 void unregister_sysctl_table(struct ctl_table_header * header)
1359 list_del(&header->ctl_entry);
1360 #ifdef CONFIG_PROC_FS
1361 unregister_proc_table(header->ctl_table, proc_sys_root);
1367 int cfs_psdev_register(cfs_psdev_t * psdev)
1369 cfs_proc_entry_t * entry;
1371 entry = create_proc_entry (
1372 (char *)psdev->name,
1381 entry->flags |= CFS_PROC_FLAG_MISCDEV;
1383 entry->proc_fops = psdev->fops;
1384 entry->data = (void *)psdev;
1389 int cfs_psdev_deregister(cfs_psdev_t * psdev)
1391 cfs_proc_entry_t * entry;
1393 entry = search_proc_entry (
1394 (char *)psdev->name,
1400 ASSERT(entry->data == (void *)psdev);
1401 ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1404 (char *)psdev->name,
1412 extern char debug_file_path[1024];
1414 #define PSDEV_LNET (0x100)
1416 PSDEV_DEBUG = 1, /* control debugging */
1417 PSDEV_SUBSYSTEM_DEBUG, /* control debugging */
1418 PSDEV_PRINTK, /* force all messages to console */
1419 PSDEV_CONSOLE_RATELIMIT, /* rate limit console messages */
1420 PSDEV_DEBUG_PATH, /* crashdump log location */
1421 PSDEV_DEBUG_DUMP_PATH, /* crashdump tracelog location */
1422 PSDEV_LIBCFS_MEMUSED, /* bytes currently PORTAL_ALLOCated */
1425 static struct ctl_table lnet_table[] = {
1426 {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1428 {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1429 sizeof(int), 0644, NULL, &proc_dointvec},
1430 {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1432 {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit,
1433 sizeof(int), 0644, NULL, &proc_dointvec},
1434 {PSDEV_DEBUG_PATH, "debug_path", debug_file_path,
1435 sizeof(debug_file_path), 0644, NULL, &proc_dostring, &sysctl_string},
1437 {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1438 sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1441 {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1442 sizeof(int), 0644, NULL, &proc_dointvec},
1446 static struct ctl_table top_table[2] = {
1447 {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1452 int trace_write_dump_kernel(struct file *file, const char *buffer,
1453 unsigned long count, void *data)
1455 int rc = trace_dump_debug_buffer_usrstr(buffer, count);
1457 return (rc < 0) ? rc : count;
1460 int trace_write_daemon_file(struct file *file, const char *buffer,
1461 unsigned long count, void *data)
1463 int rc = trace_daemon_command_usrstr(buffer, count);
1465 return (rc < 0) ? rc : count;
1468 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1469 int *eof, void *data)
1473 tracefile_read_lock();
1475 rc = trace_copyout_string(page, count, tracefile, "\n");
1477 tracefile_read_unlock();
1482 int trace_write_debug_mb(struct file *file, const char *buffer,
1483 unsigned long count, void *data)
1485 int rc = trace_set_debug_mb_userstr(buffer, count);
1487 return (rc < 0) ? rc : count;
1490 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1491 int *eof, void *data)
1495 snprintf(str, sizeof(str), "%d\n", trace_get_debug_mb());
1497 return trace_copyout_string(page, count, str, NULL);
1500 int insert_proc(void)
1502 cfs_proc_entry_t *ent;
1504 ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1506 CERROR(("couldn't register dump_kernel\n"));
1509 ent->write_proc = trace_write_dump_kernel;
1511 ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1513 CERROR(("couldn't register daemon_file\n"));
1516 ent->write_proc = trace_write_daemon_file;
1517 ent->read_proc = trace_read_daemon_file;
1519 ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1521 CERROR(("couldn't register debug_mb\n"));
1524 ent->write_proc = trace_write_debug_mb;
1525 ent->read_proc = trace_read_debug_mb;
1530 void remove_proc(void)
1532 remove_proc_entry("sys/portals/dump_kernel", NULL);
1533 remove_proc_entry("sys/portals/daemon_file", NULL);
1534 remove_proc_entry("sys/portals/debug_mb", NULL);
1536 #ifdef CONFIG_SYSCTL
1537 if (portals_table_header)
1538 unregister_sysctl_table(portals_table_header);
1539 portals_table_header = NULL;
1545 * proc process routines of kernel space
1549 lustre_open_file(char * filename)
1552 cfs_file_t * fh = NULL;
1553 cfs_proc_entry_t * fp = NULL;
1555 fp = search_proc_entry(filename, proc_fs_root);
1562 fh = cfs_alloc(sizeof(cfs_file_t), CFS_ALLOC_ZERO);
1569 fh->private_data = (void *)fp;
1570 fh->f_op = fp->proc_fops;
1572 if (fh->f_op->open) {
1573 rc = (fh->f_op->open)(fh);
1587 lustre_close_file(cfs_file_t * fh)
1590 cfs_proc_entry_t * fp = NULL;
1592 fp = (cfs_proc_entry_t *) fh->private_data;
1594 if (fh->f_op->release) {
1595 rc = (fh->f_op->release)(fh);
1606 lustre_do_ioctl( cfs_file_t * fh,
1612 if (fh->f_op->ioctl) {
1613 rc = (fh->f_op->ioctl)(fh, cmd, arg);
1617 printk("lustre_do_ioctl: fialed: cmd = %xh arg = %xh rc = %d\n",
1625 lustre_ioctl_file(cfs_file_t * fh, PCFS_PROC_IOCTL devctl)
1630 data = (ulong_ptr)devctl + sizeof(CFS_PROC_IOCTL);
1632 /* obd ioctl code */
1633 if (_IOC_TYPE(devctl->cmd) == 'f') {
1635 struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1637 if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE &&
1638 devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1640 unsigned long off = obd->ioc_len;
1642 if (obd->ioc_pbuf1) {
1643 obd->ioc_pbuf1 = (char *)(data + off);
1644 off += size_round(obd->ioc_plen1);
1647 if (obd->ioc_pbuf2) {
1648 obd->ioc_pbuf2 = (char *)(data + off);
1654 rc = lustre_do_ioctl(fh, devctl->cmd, data);
1670 if (fh->f_op->read) {
1671 rc = (fh->f_op->read) (fh, buf, size, &off);
1688 if (fh->f_op->write) {
1689 rc = (fh->f_op->write)(fh, buf, size, &off);
1695 #else /* !__KERNEL__ */
1697 #include <lnet/api-support.h>
1698 #include <liblustre.h>
1699 #include <lustre_lib.h>
1702 * proc process routines of user space
1705 HANDLE cfs_proc_open (char * filename, int oflag)
1708 IO_STATUS_BLOCK iosb;
1711 HANDLE FileHandle = INVALID_HANDLE_VALUE;
1712 OBJECT_ATTRIBUTES ObjectAttributes;
1713 ACCESS_MASK DesiredAccess;
1714 ULONG CreateDisposition;
1716 ULONG CreateOptions;
1717 UNICODE_STRING UnicodeName;
1720 PFILE_FULL_EA_INFORMATION Ea = NULL;
1722 UCHAR EaBuffer[EA_MAX_LENGTH];
1724 /* Check the filename: should start with "/proc" or "/dev" */
1725 NameLength = (USHORT)strlen(filename);
1726 if (NameLength > 0x05) {
1727 if (_strnicmp(filename, "/proc/", 6) == 0) {
1730 if (NameLength <= 0) {
1734 } else if (_strnicmp(filename, "/dev/", 5) == 0) {
1744 /* Analyze the flags settings */
1746 if (cfs_is_flag_set(oflag, O_WRONLY)) {
1747 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
1749 } else if (cfs_is_flag_set(oflag, O_RDWR)) {
1750 DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
1751 ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
1753 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
1754 ShareAccess = FILE_SHARE_READ;
1757 if (cfs_is_flag_set(oflag, O_CREAT)) {
1758 if (cfs_is_flag_set(oflag, O_EXCL)) {
1759 CreateDisposition = FILE_CREATE;
1763 CreateDisposition = FILE_OPEN_IF;
1766 CreateDisposition = FILE_OPEN;
1769 if (cfs_is_flag_set(oflag, O_TRUNC)) {
1770 if (cfs_is_flag_set(oflag, O_EXCL)) {
1771 CreateDisposition = FILE_OVERWRITE;
1773 CreateDisposition = FILE_OVERWRITE_IF;
1779 if (cfs_is_flag_set(oflag, O_DIRECTORY)) {
1780 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
1783 if (cfs_is_flag_set(oflag, O_SYNC)) {
1784 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
1787 if (cfs_is_flag_set(oflag, O_DIRECT)) {
1788 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
1791 /* Initialize the unicode path name for the specified file */
1792 RtlInitUnicodeString(&UnicodeName, LUSTRE_PROC_SYMLNK);
1794 /* Setup the object attributes structure for the file. */
1795 InitializeObjectAttributes(
1798 OBJ_CASE_INSENSITIVE,
1802 /* building EA for the proc entry ... */
1803 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1804 Ea->NextEntryOffset = 0;
1806 Ea->EaNameLength = (UCHAR)NameLength;
1807 Ea->EaValueLength = 0;
1813 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
1814 Ea->EaNameLength + 1;
1816 /* Now to open or create the file now */
1817 status = ZwCreateFile(
1823 FILE_ATTRIBUTE_NORMAL,
1830 /* Check the returned status of Iosb ... */
1832 if (!NT_SUCCESS(status)) {
1833 rc = cfs_error_code(status);
1842 int cfs_proc_close(HANDLE handle)
1845 NtClose((HANDLE)handle);
1851 int cfs_proc_read(HANDLE handle, void *buffer, unsigned int count)
1854 IO_STATUS_BLOCK iosb;
1855 LARGE_INTEGER offset;
1858 offset.QuadPart = 0;
1860 /* read file data */
1861 status = NtReadFile(
1872 /* check the return status */
1873 if (!NT_SUCCESS(status)) {
1874 printf("NtReadFile request failed 0x%0x\n", status);
1880 if (NT_SUCCESS(status)) {
1881 return iosb.Information;
1884 return cfs_error_code(status);
1888 int cfs_proc_write(HANDLE handle, void *buffer, unsigned int count)
1891 IO_STATUS_BLOCK iosb;
1892 LARGE_INTEGER offset;
1894 offset.QuadPart = -1;
1896 /* write buffer to the opened file */
1897 status = NtWriteFile(
1908 /* check the return status */
1909 if (!NT_SUCCESS(status)) {
1910 printf("NtWriteFile request failed 0x%0x\n", status);
1916 if (NT_SUCCESS(status)) {
1917 return iosb.Information;
1920 return cfs_error_code(status);
1923 int cfs_proc_ioctl(HANDLE handle, int cmd, void *buffer)
1925 PUCHAR procdat = NULL;
1926 CFS_PROC_IOCTL procctl;
1931 IO_STATUS_BLOCK iosb;
1935 if(_IOC_TYPE(cmd) == IOC_LIBCFS_TYPE) {
1936 struct libcfs_ioctl_data * portal;
1937 portal = (struct libcfs_ioctl_data *) buffer;
1938 length = portal->ioc_len;
1939 } else if (_IOC_TYPE(cmd) == 'f') {
1940 struct obd_ioctl_data * obd;
1941 obd = (struct obd_ioctl_data *) buffer;
1942 length = obd->ioc_len;
1943 extra = size_round(obd->ioc_plen1) + size_round(obd->ioc_plen2);
1944 } else if(_IOC_TYPE(cmd) == 'u') {
1948 printf("user:winnt-proc:cfs_proc_ioctl: un-supported ioctl type ...\n");
1949 cfs_enter_debugger();
1950 status = STATUS_INVALID_PARAMETER;
1954 procctl.len = length + extra;
1955 procdat = malloc(length + extra + sizeof(CFS_PROC_IOCTL));
1957 if (NULL == procdat) {
1958 printf("user:winnt-proc:cfs_proc_ioctl: no enough memory ...\n");
1959 status = STATUS_INSUFFICIENT_RESOURCES;
1960 cfs_enter_debugger();
1963 memset(procdat, 0, length + extra + sizeof(CFS_PROC_IOCTL));
1964 memcpy(procdat, &procctl, sizeof(CFS_PROC_IOCTL));
1965 memcpy(&procdat[sizeof(CFS_PROC_IOCTL)], buffer, length);
1966 length += sizeof(CFS_PROC_IOCTL);
1968 if (_IOC_TYPE(cmd) == 'f') {
1971 struct obd_ioctl_data * data;
1972 struct obd_ioctl_data * obd;
1974 data = (struct obd_ioctl_data *) buffer;
1975 obd = (struct obd_ioctl_data *) (procdat + sizeof(CFS_PROC_IOCTL));
1976 ptr = obd->ioc_bulk;
1978 if (data->ioc_inlbuf1) {
1979 obd->ioc_inlbuf1 = ptr;
1980 LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
1983 if (data->ioc_inlbuf2) {
1984 obd->ioc_inlbuf2 = ptr;
1985 LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
1987 if (data->ioc_inlbuf3) {
1988 obd->ioc_inlbuf3 = ptr;
1989 LOGL(data->ioc_inlbuf3, data->ioc_inllen3, ptr);
1991 if (data->ioc_inlbuf4) {
1992 obd->ioc_inlbuf4 = ptr;
1993 LOGL(data->ioc_inlbuf4, data->ioc_inllen4, ptr);
1996 if ( cmd != (ULONG)OBD_IOC_BRW_WRITE &&
1997 cmd != (ULONG)OBD_IOC_BRW_READ ) {
1999 if (data->ioc_pbuf1 && data->ioc_plen1) {
2000 obd->ioc_pbuf1 = &procdat[length];
2001 memcpy(obd->ioc_pbuf1, data->ioc_pbuf1, data->ioc_plen1);
2002 length += size_round(data->ioc_plen1);
2005 if (data->ioc_pbuf2 && data->ioc_plen2) {
2006 obd->ioc_pbuf2 = &procdat[length];
2007 memcpy(obd->ioc_pbuf2, data->ioc_pbuf2, data->ioc_plen2);
2008 length += size_round(data->ioc_plen2);
2012 if (obd_ioctl_is_invalid(obd)) {
2013 cfs_enter_debugger();
2017 status = NtDeviceIoControlFile(
2019 NULL, NULL, NULL, &iosb,
2025 if (NT_SUCCESS(status)) {
2026 memcpy(buffer, &procdat[sizeof(CFS_PROC_IOCTL)], procctl.len);
2035 return cfs_error_code(status);
2038 #endif /* __KERNEL__ */