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 <libcfs/kp30.h>
29 #include "tracefile.h"
35 * /proc emulator routines ...
38 /* The root node of the proc fs emulation: /proc */
39 cfs_proc_entry_t * proc_fs_root = NULL;
42 /* The sys root: /proc/sys */
43 cfs_proc_entry_t * proc_sys_root = NULL;
46 /* The sys root: /proc/dev | to implement misc device */
48 cfs_proc_entry_t * proc_dev_root = NULL;
51 /* SLAB object for cfs_proc_entry_t allocation */
53 cfs_mem_cache_t * proc_entry_cache = NULL;
55 /* root node for sysctl table */
57 cfs_sysctl_table_header_t root_table_header;
59 /* The global lock to protect all the access */
61 #if LIBCFS_PROCFS_SPINLOCK
62 spinlock_t proc_fs_lock;
64 #define INIT_PROCFS_LOCK() spin_lock_init(&proc_fs_lock)
65 #define LOCK_PROCFS() spin_lock(&proc_fs_lock)
66 #define UNLOCK_PROCFS() spin_unlock(&proc_fs_lock)
72 #define INIT_PROCFS_LOCK() init_mutex(&proc_fs_lock)
73 #define LOCK_PROCFS() mutex_down(&proc_fs_lock)
74 #define UNLOCK_PROCFS() mutex_up(&proc_fs_lock)
79 proc_file_read(struct file * file, const char * buf, size_t nbytes, loff_t *ppos)
86 cfs_proc_entry_t * dp;
88 dp = (cfs_proc_entry_t *) file->private_data;
89 if (!(page = (char*) cfs_alloc(CFS_PAGE_SIZE, 0)))
92 while ((nbytes > 0) && !eof) {
94 count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
98 n = dp->read_proc( page, &start, (long)*ppos,
99 count, &eof, dp->data);
105 * For proc files that are less than 4k
107 start = page + *ppos;
108 n -= (ssize_t)(*ppos);
115 break; /* End of file */
122 n -= copy_to_user((void *)buf, start, n);
140 proc_file_write(struct file * file, const char * buffer,
141 size_t count, loff_t *ppos)
143 cfs_proc_entry_t * dp;
145 dp = (cfs_proc_entry_t *) file->private_data;
150 /* FIXME: does this routine need ppos? probably... */
151 return dp->write_proc(file, buffer, count, dp->data);
154 struct file_operations proc_file_operations = {
155 /*lseek:*/ NULL, //proc_file_lseek,
156 /*read:*/ proc_file_read,
157 /*write:*/ proc_file_write,
163 /* allocate proc entry block */
168 cfs_proc_entry_t * entry = NULL;
170 entry = cfs_mem_cache_alloc(proc_entry_cache, 0);
175 memset(entry, 0, sizeof(cfs_proc_entry_t));
177 entry->magic = CFS_PROC_ENTRY_MAGIC;
178 RtlInitializeSplayLinks(&(entry->s_link));
179 entry->proc_fops = &proc_file_operations;
184 /* free the proc entry block */
187 proc_free_entry(cfs_proc_entry_t * entry)
190 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
192 cfs_mem_cache_free(proc_entry_cache, entry);
195 /* dissect the path string for a given full proc path */
205 int i = 0, j = 0, len = 0;
207 *first = *remain = NULL;
212 while (i < len && (path[i] == '/')) i++;
217 while (i < len && (path[i] != '/')) i++;
218 *first_len = (path + i - *first);
221 *remain = path + i + 1;
226 /* search the children entries of the parent entry */
230 cfs_proc_entry_t * parent,
234 cfs_proc_entry_t * node;
235 PRTL_SPLAY_LINKS link;
237 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
238 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
244 ANSI_STRING ename,nname;
247 node = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
249 ASSERT(node->magic == CFS_PROC_ENTRY_MAGIC);
251 /* Compare the prefix in the tree with the full name */
253 RtlInitAnsiString(&ename, name);
254 RtlInitAnsiString(&nname, node->name);
256 result = RtlCompareString(&nname, &ename,TRUE);
260 /* The prefix is greater than the full name
261 so we go down the left child */
263 link = RtlLeftChild(link);
265 } else if (result < 0) {
267 /* The prefix is less than the full name
268 so we go down the right child */
271 link = RtlRightChild(link);
275 /* We got the entry in the splay tree and
276 make it root node instead */
278 parent->root = RtlSplay(link);
283 /* we need continue searching down the tree ... */
286 /* There's no the exptected entry in the splay tree */
293 cfs_proc_entry_t * parent,
294 cfs_proc_entry_t * child
297 cfs_proc_entry_t * entry;
299 ASSERT(parent != NULL && child != NULL);
300 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
301 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
302 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
305 parent->root = &(child->s_link);
307 entry = CONTAINING_RECORD(parent->root, cfs_proc_entry_t, s_link);
310 ANSI_STRING ename, cname;
312 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
314 RtlInitAnsiString(&ename, entry->name);
315 RtlInitAnsiString(&cname, child->name);
317 result = RtlCompareString(&ename, &cname,TRUE);
320 cfs_enter_debugger();
321 if (entry == child) {
328 if (RtlLeftChild(&entry->s_link) == NULL) {
329 RtlInsertAsLeftChild(&entry->s_link, &child->s_link);
332 entry = CONTAINING_RECORD( RtlLeftChild(&entry->s_link),
333 cfs_proc_entry_t, s_link);
336 if (RtlRightChild(&entry->s_link) == NULL) {
337 RtlInsertAsRightChild(&entry->s_link, &child->s_link);
340 entry = CONTAINING_RECORD( RtlRightChild(&entry->s_link),
341 cfs_proc_entry_t, s_link );
347 cfs_set_flag(child->flags, CFS_PROC_FLAG_ATTACHED);
354 /* remove a child entry from the splay tree */
357 cfs_proc_entry_t * parent,
358 cfs_proc_entry_t * child
361 cfs_proc_entry_t * entry = NULL;
363 ASSERT(parent != NULL && child != NULL);
364 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
365 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
366 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
367 ASSERT(cfs_is_flag_set(child->flags, CFS_PROC_FLAG_ATTACHED));
369 entry = proc_search_splay(parent, child->name);
372 ASSERT(entry == child);
373 parent->root = RtlDelete(&(entry->s_link));
376 cfs_enter_debugger();
384 /* search a node inside the proc fs tree */
389 cfs_proc_entry_t * root
392 cfs_proc_entry_t * entry;
393 cfs_proc_entry_t * parent;
394 char *first, *remain;
401 ename = cfs_alloc(0x21, CFS_ALLOC_ZERO);
409 /* dissect the file name string */
410 proc_dissect_name(name, &first, &flen, &remain);
415 cfs_enter_debugger();
420 memset(ename, 0, 0x20);
421 memcpy(ename, first, flen);
423 entry = proc_search_splay(parent, ename);
446 /* insert the path nodes to the proc fs tree */
451 cfs_proc_entry_t * root
454 cfs_proc_entry_t *entry;
455 cfs_proc_entry_t *parent;
456 char *first, *remain;
465 proc_dissect_name(name, &first, &flen, &remain);
473 memset(ename, 0, 0x20);
474 memcpy(ename, first, flen);
476 entry = proc_search_splay(parent, ename);
479 entry = proc_alloc_entry();
480 memcpy(entry->name, ename, flen);
483 if(!proc_insert_splay(parent, entry)) {
484 proc_free_entry(entry);
495 entry->mode |= S_IFDIR | S_IRUGO | S_IXUGO;
496 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
506 /* remove the path nodes from the proc fs tree */
511 cfs_proc_entry_t * root
514 cfs_proc_entry_t *entry;
515 char *first, *remain;
521 proc_dissect_name(name, &first, &flen, &remain);
525 memset(ename, 0, 0x20);
526 memcpy(ename, first, flen);
528 entry = proc_search_splay(root, ename);
533 ASSERT(S_ISDIR(entry->mode));
534 proc_remove_entry(remain, entry);
538 proc_remove_splay(root, entry);
539 proc_free_entry(entry);
543 cfs_enter_debugger();
547 /* create proc entry and insert it into the proc fs */
553 cfs_proc_entry_t * root
556 cfs_proc_entry_t *parent = root;
557 cfs_proc_entry_t *entry = NULL;
560 if ((mode & S_IALLUGO) == 0)
561 mode |= S_IRUGO | S_IXUGO;
563 if ((mode & S_IFMT) == 0)
565 if ((mode & S_IALLUGO) == 0)
571 ASSERT(NULL != proc_fs_root);
574 parent = proc_fs_root;
577 entry = proc_search_entry(name, parent);
580 entry = proc_insert_entry(name, parent);
582 /* Failed to create/insert the splay node ... */
583 cfs_enter_debugger();
586 /* Initializing entry ... */
590 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
602 /* search the specified entry form the proc fs */
607 cfs_proc_entry_t * root
610 cfs_proc_entry_t * entry;
616 entry = proc_search_entry(name, root);
622 /* remove the entry from the proc fs */
627 cfs_proc_entry_t * parent
631 if (parent == NULL) {
632 parent = proc_fs_root;
634 proc_remove_entry(name, parent);
639 void proc_destroy_splay(cfs_proc_entry_t * entry)
641 cfs_proc_entry_t * node;
643 if (S_ISDIR(entry->mode)) {
645 while (entry->root) {
646 node = CONTAINING_RECORD(entry->root, cfs_proc_entry_t, s_link);
647 entry->root = RtlDelete(&(node->s_link));
648 proc_destroy_splay(node);
652 proc_free_entry(entry);
656 /* destory the whole proc fs tree */
658 void proc_destroy_fs()
663 proc_destroy_splay(proc_fs_root);
666 if (proc_entry_cache) {
667 cfs_mem_cache_destroy(proc_entry_cache);
673 /* initilaize / build the proc fs tree */
677 cfs_proc_entry_t * root = NULL;
679 memset(&(root_table_header), 0, sizeof(struct ctl_table_header));
680 INIT_LIST_HEAD(&(root_table_header.ctl_entry));
683 proc_entry_cache = cfs_mem_cache_create(
685 sizeof(cfs_proc_entry_t),
690 if (!proc_entry_cache) {
694 root = proc_alloc_entry();
701 root->magic = CFS_PROC_ENTRY_MAGIC;
702 root->flags = CFS_PROC_FLAG_DIRECTORY;
703 root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
704 root->nlink = 3; // root should never be deleted.
713 proc_sys_root = create_proc_entry("sys", S_IFDIR, root);
715 if (!proc_sys_root) {
716 proc_free_entry(root);
722 proc_sys_root->nlink = 1;
724 proc_dev_root = create_proc_entry("dev", S_IFDIR, root);
726 if (!proc_dev_root) {
727 proc_free_entry(proc_sys_root);
728 proc_sys_root = NULL;
729 proc_free_entry(proc_fs_root);
735 proc_dev_root->nlink = 1;
741 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
742 size_t count, loff_t *ppos)
745 cfs_proc_entry_t *de;
746 struct ctl_table *table;
750 de = (cfs_proc_entry_t *) file->proc_dentry;
752 if (!de || !de->data)
754 table = (struct ctl_table *) de->data;
755 if (!table || !table->proc_handler)
757 op = (write ? 002 : 004);
759 // if (ctl_perm(table, op))
765 * FIXME: we need to pass on ppos to the handler.
768 error = (*table->proc_handler) (table, write, file, buf, &res);
774 static ssize_t proc_readsys(struct file * file, char * buf,
775 size_t count, loff_t *ppos)
777 return do_rw_proc(0, file, buf, count, ppos);
780 static ssize_t proc_writesys(struct file * file, const char * buf,
781 size_t count, loff_t *ppos)
783 return do_rw_proc(1, file, (char *) buf, count, ppos);
787 struct file_operations proc_sys_file_operations = {
789 /*read:*/ proc_readsys,
790 /*write:*/ proc_writesys,
797 /* Scan the sysctl entries in table and add them all into /proc */
798 void register_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t * root)
800 cfs_proc_entry_t * de;
804 for (; table->ctl_name; table++) {
805 /* Can't do anything without a proc name. */
806 if (!table->procname)
808 /* Maybe we can't do anything with it... */
809 if (!table->proc_handler && !table->child) {
810 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
815 len = strlen(table->procname);
819 if (table->proc_handler)
822 de = search_proc_entry(table->procname, root);
826 /* If the subdir exists already, de is non-NULL */
831 de = create_proc_entry((char *)table->procname, mode, root);
834 de->data = (void *) table;
835 if (table->proc_handler) {
836 de->proc_fops = &proc_sys_file_operations;
840 if (de->mode & S_IFDIR)
841 register_proc_table(table->child, de);
847 * Unregister a /proc sysctl table and any subdirectories.
849 void unregister_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t *root)
851 cfs_proc_entry_t *de;
852 for (; table->ctl_name; table++) {
853 if (!(de = table->de))
855 if (de->mode & S_IFDIR) {
857 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
860 unregister_proc_table(table->child, de);
862 /* Don't unregister directories which still have entries.. */
867 /* Don't unregister proc entries that are still being used.. */
872 remove_proc_entry((char *)table->procname, root);
876 /* The generic string strategy routine: */
877 int sysctl_string(cfs_sysctl_table_t *table, int *name, int nlen,
878 void *oldval, size_t *oldlenp,
879 void *newval, size_t newlen, void **context)
883 if (!table->data || !table->maxlen)
886 if (oldval && oldlenp) {
887 if(get_user(len, oldlenp))
890 l = strlen(table->data);
891 if (len > l) len = l;
892 if (len >= table->maxlen)
894 if(copy_to_user(oldval, table->data, len))
896 if(put_user(0, ((char *) oldval) + len))
898 if(put_user(len, oldlenp))
902 if (newval && newlen) {
904 if (len > table->maxlen)
906 if(copy_from_user(table->data, newval, len))
908 if (len == table->maxlen)
910 ((char *) table->data)[len] = 0;
916 * simple_strtoul - convert a string to an unsigned long
917 * @cp: The start of the string
918 * @endp: A pointer to the end of the parsed string will be placed here
919 * @base: The number base to use
921 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
923 unsigned long result = 0, value;
930 if ((*cp == 'x') && isxdigit(cp[1])) {
936 while (isxdigit(*cp) &&
937 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
938 result = result*base + value;
953 static int do_proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
954 void *buffer, size_t *lenp, int conv, int op)
956 int *i, vleft, first=1, neg, val;
960 char buf[TMPBUFLEN], *p;
962 if (!table->data || !table->maxlen || !*lenp)
968 i = (int *) table->data;
969 vleft = table->maxlen / sizeof(int);
972 for (; left && vleft--; i++, first=0) {
976 if(get_user(c,(char *) buffer))
987 if (len > TMPBUFLEN-1)
989 if(copy_from_user(buf, buffer, len))
993 if (*p == '-' && left > 1) {
997 if (*p < '0' || *p > '9')
999 val = simple_strtoul(p, &p, 0) * conv;
1001 if ((len < left) && *p && !isspace(*p))
1005 (char *)buffer += len;
1008 case OP_SET: *i = val; break;
1009 case OP_AND: *i &= val; break;
1010 case OP_OR: *i |= val; break;
1011 case OP_MAX: if(*i < val)
1014 case OP_MIN: if(*i > val)
1022 sprintf(p, "%d", (*i) / conv);
1026 if(copy_to_user(buffer, buf, len))
1029 (char *)buffer += len;
1033 if (!write && !first && left) {
1034 if(put_user('\n', (char *) buffer))
1036 left--, ((char *)buffer)++;
1039 p = (char *) buffer;
1042 if(get_user(c, p++))
1052 memset(&(filp->f_pos) , 0, sizeof(loff_t));
1053 filp->f_pos += (loff_t)(*lenp);
1058 * proc_dointvec - read a vector of integers
1059 * @table: the sysctl table
1060 * @write: %TRUE if this is a write to the sysctl file
1061 * @filp: the file structure
1062 * @buffer: the user buffer
1063 * @lenp: the size of the user buffer
1065 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1066 * values from/to the user buffer, treated as an ASCII string.
1068 * Returns 0 on success.
1070 int proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1071 void *buffer, size_t *lenp)
1073 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1078 * proc_dostring - read a string sysctl
1079 * @table: the sysctl table
1080 * @write: %TRUE if this is a write to the sysctl file
1081 * @filp: the file structure
1082 * @buffer: the user buffer
1083 * @lenp: the size of the user buffer
1085 * Reads/writes a string from/to the user buffer. If the kernel
1086 * buffer provided is not large enough to hold the string, the
1087 * string is truncated. The copied string is %NULL-terminated.
1088 * If the string is being read by the user process, it is copied
1089 * and a newline '\n' is added. It is truncated if the buffer is
1092 * Returns 0 on success.
1094 int proc_dostring(cfs_sysctl_table_t *table, int write, struct file *filp,
1095 void *buffer, size_t *lenp)
1100 if (!table->data || !table->maxlen || !*lenp ||
1101 (filp->f_pos && !write)) {
1109 while (len < *lenp) {
1110 if(get_user(c, p++))
1112 if (c == 0 || c == '\n')
1116 if (len >= (size_t)table->maxlen)
1117 len = (size_t)table->maxlen-1;
1118 if(copy_from_user(table->data, buffer, len))
1120 ((char *) table->data)[len] = 0;
1121 filp->f_pos += *lenp;
1123 len = (size_t)strlen(table->data);
1124 if (len > (size_t)table->maxlen)
1125 len = (size_t)table->maxlen;
1129 if(copy_to_user(buffer, table->data, len))
1132 if(put_user('\n', ((char *) buffer) + len))
1142 /* Perform the actual read/write of a sysctl table entry. */
1143 int do_sysctl_strategy (cfs_sysctl_table_t *table,
1144 int *name, int nlen,
1145 void *oldval, size_t *oldlenp,
1146 void *newval, size_t newlen, void **context)
1156 if (table->strategy) {
1157 rc = table->strategy(table, name, nlen, oldval, oldlenp,
1158 newval, newlen, context);
1165 /* If there is no strategy routine, or if the strategy returns
1166 * zero, proceed with automatic r/w */
1167 if (table->data && table->maxlen) {
1168 if (oldval && oldlenp) {
1169 get_user(len, oldlenp);
1171 if (len > (size_t)table->maxlen)
1172 len = (size_t)table->maxlen;
1173 if(copy_to_user(oldval, table->data, len))
1175 if(put_user(len, oldlenp))
1179 if (newval && newlen) {
1181 if (len > (size_t)table->maxlen)
1182 len = (size_t)table->maxlen;
1183 if(copy_from_user(table->data, newval, len))
1190 static int parse_table(int *name, int nlen,
1191 void *oldval, size_t *oldlenp,
1192 void *newval, size_t newlen,
1193 cfs_sysctl_table_t *table, void **context)
1201 if (get_user(n, name))
1203 for ( ; table->ctl_name; table++) {
1204 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1208 if (ctl_perm(table, 001))
1211 if (table->strategy) {
1212 error = table->strategy(
1215 newval, newlen, context);
1221 table = table->child;
1224 error = do_sysctl_strategy(table, name, nlen,
1226 newval, newlen, context);
1233 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1234 void *newval, size_t newlen)
1236 struct list_head *tmp;
1238 if (nlen <= 0 || nlen >= CTL_MAXNAME)
1242 if (!oldlenp || get_user(old_len, oldlenp))
1245 tmp = &root_table_header.ctl_entry;
1247 struct ctl_table_header *head =
1248 list_entry(tmp, struct ctl_table_header, ctl_entry);
1249 void *context = NULL;
1250 int error = parse_table(name, nlen, oldval, oldlenp,
1251 newval, newlen, head->ctl_table,
1255 if (error != -ENOTDIR)
1258 } while (tmp != &root_table_header.ctl_entry);
1263 * register_sysctl_table - register a sysctl heirarchy
1264 * @table: the top-level table structure
1265 * @insert_at_head: whether the entry should be inserted in front or at the end
1267 * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1268 * array. An entry with a ctl_name of 0 terminates the table.
1270 * The members of the &ctl_table structure are used as follows:
1272 * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1273 * must be unique within that level of sysctl
1275 * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1276 * enter a sysctl file
1278 * data - a pointer to data for use by proc_handler
1280 * maxlen - the maximum size in bytes of the data
1282 * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1284 * child - a pointer to the child sysctl table if this entry is a directory, or
1287 * proc_handler - the text handler routine (described below)
1289 * strategy - the strategy routine (described below)
1291 * de - for internal use by the sysctl routines
1293 * extra1, extra2 - extra pointers usable by the proc handler routines
1295 * Leaf nodes in the sysctl tree will be represented by a single file
1296 * under /proc; non-leaf nodes will be represented by directories.
1298 * sysctl(2) can automatically manage read and write requests through
1299 * the sysctl table. The data and maxlen fields of the ctl_table
1300 * struct enable minimal validation of the values being written to be
1301 * performed, and the mode field allows minimal authentication.
1303 * More sophisticated management can be enabled by the provision of a
1304 * strategy routine with the table entry. This will be called before
1305 * any automatic read or write of the data is performed.
1307 * The strategy routine may return
1309 * < 0 - Error occurred (error is passed to user process)
1311 * 0 - OK - proceed with automatic read or write.
1313 * > 0 - OK - read or write has been done by the strategy routine, so
1314 * return immediately.
1316 * There must be a proc_handler routine for any terminal nodes
1317 * mirrored under /proc/sys (non-terminals are handled by a built-in
1318 * directory handler). Several default handlers are available to
1319 * cover common cases -
1321 * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1322 * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1323 * proc_doulongvec_minmax()
1325 * It is the handler's job to read the input buffer from user memory
1326 * and process it. The handler should return 0 on success.
1328 * This routine returns %NULL on a failure to register, and a pointer
1329 * to the table header on success.
1331 struct ctl_table_header *register_sysctl_table(cfs_sysctl_table_t * table,
1334 struct ctl_table_header *tmp;
1335 tmp = cfs_alloc(sizeof(struct ctl_table_header), 0);
1338 tmp->ctl_table = table;
1340 INIT_LIST_HEAD(&tmp->ctl_entry);
1342 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
1344 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1345 #ifdef CONFIG_PROC_FS
1346 register_proc_table(table, proc_sys_root);
1352 * unregister_sysctl_table - unregister a sysctl table heirarchy
1353 * @header: the header returned from register_sysctl_table
1355 * Unregisters the sysctl table and all children. proc entries may not
1356 * actually be removed until they are no longer used by anyone.
1358 void unregister_sysctl_table(struct ctl_table_header * header)
1360 list_del(&header->ctl_entry);
1361 #ifdef CONFIG_PROC_FS
1362 unregister_proc_table(header->ctl_table, proc_sys_root);
1368 int cfs_psdev_register(cfs_psdev_t * psdev)
1370 cfs_proc_entry_t * entry;
1372 entry = create_proc_entry (
1373 (char *)psdev->name,
1382 entry->flags |= CFS_PROC_FLAG_MISCDEV;
1384 entry->proc_fops = psdev->fops;
1385 entry->data = (void *)psdev;
1390 int cfs_psdev_deregister(cfs_psdev_t * psdev)
1392 cfs_proc_entry_t * entry;
1394 entry = search_proc_entry (
1395 (char *)psdev->name,
1401 ASSERT(entry->data == (void *)psdev);
1402 ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1405 (char *)psdev->name,
1413 extern char debug_file_path[1024];
1415 #define PSDEV_LNET (0x100)
1417 PSDEV_DEBUG = 1, /* control debugging */
1418 PSDEV_SUBSYSTEM_DEBUG, /* control debugging */
1419 PSDEV_PRINTK, /* force all messages to console */
1420 PSDEV_CONSOLE_RATELIMIT, /* rate limit console messages */
1421 PSDEV_DEBUG_PATH, /* crashdump log location */
1422 PSDEV_DEBUG_DUMP_PATH, /* crashdump tracelog location */
1423 PSDEV_LIBCFS_MEMUSED, /* bytes currently PORTAL_ALLOCated */
1426 static struct ctl_table lnet_table[] = {
1427 {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1429 {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1430 sizeof(int), 0644, NULL, &proc_dointvec},
1431 {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1433 {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit,
1434 sizeof(int), 0644, NULL, &proc_dointvec},
1435 {PSDEV_DEBUG_PATH, "debug_path", debug_file_path,
1436 sizeof(debug_file_path), 0644, NULL, &proc_dostring, &sysctl_string},
1438 {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1439 sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1442 {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1443 sizeof(int), 0644, NULL, &proc_dointvec},
1447 static struct ctl_table top_table[2] = {
1448 {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1453 int trace_write_dump_kernel(struct file *file, const char *buffer,
1454 unsigned long count, void *data)
1456 int rc = trace_dump_debug_buffer_usrstr(buffer, count);
1458 return (rc < 0) ? rc : count;
1461 int trace_write_daemon_file(struct file *file, const char *buffer,
1462 unsigned long count, void *data)
1464 int rc = trace_daemon_command_usrstr(buffer, count);
1466 return (rc < 0) ? rc : count;
1469 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1470 int *eof, void *data)
1474 tracefile_read_lock();
1476 rc = trace_copyout_string(page, count, tracefile, "\n");
1478 tracefile_read_unlock();
1483 int trace_write_debug_mb(struct file *file, const char *buffer,
1484 unsigned long count, void *data)
1486 int rc = trace_set_debug_mb_userstr(buffer, count);
1488 return (rc < 0) ? rc : count;
1491 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1492 int *eof, void *data)
1496 snprintf(str, sizeof(str), "%d\n", trace_get_debug_mb());
1498 return trace_copyout_string(page, count, str, NULL);
1501 int insert_proc(void)
1503 cfs_proc_entry_t *ent;
1505 ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1507 CERROR(("couldn't register dump_kernel\n"));
1510 ent->write_proc = trace_write_dump_kernel;
1512 ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1514 CERROR(("couldn't register daemon_file\n"));
1517 ent->write_proc = trace_write_daemon_file;
1518 ent->read_proc = trace_read_daemon_file;
1520 ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1522 CERROR(("couldn't register debug_mb\n"));
1525 ent->write_proc = trace_write_debug_mb;
1526 ent->read_proc = trace_read_debug_mb;
1531 void remove_proc(void)
1533 remove_proc_entry("sys/portals/dump_kernel", NULL);
1534 remove_proc_entry("sys/portals/daemon_file", NULL);
1535 remove_proc_entry("sys/portals/debug_mb", NULL);
1537 #ifdef CONFIG_SYSCTL
1538 if (portals_table_header)
1539 unregister_sysctl_table(portals_table_header);
1540 portals_table_header = NULL;
1546 * proc process routines of kernel space
1550 lustre_open_file(char * filename)
1553 cfs_file_t * fh = NULL;
1554 cfs_proc_entry_t * fp = NULL;
1556 fp = search_proc_entry(filename, proc_fs_root);
1563 fh = cfs_alloc(sizeof(cfs_file_t), CFS_ALLOC_ZERO);
1570 fh->private_data = (void *)fp;
1571 fh->f_op = fp->proc_fops;
1573 if (fh->f_op->open) {
1574 rc = (fh->f_op->open)(fh);
1588 lustre_close_file(cfs_file_t * fh)
1591 cfs_proc_entry_t * fp = NULL;
1593 fp = (cfs_proc_entry_t *) fh->private_data;
1595 if (fh->f_op->release) {
1596 rc = (fh->f_op->release)(fh);
1607 lustre_do_ioctl( cfs_file_t * fh,
1613 if (fh->f_op->ioctl) {
1614 rc = (fh->f_op->ioctl)(fh, cmd, arg);
1618 printk("lustre_do_ioctl: fialed: cmd = %xh arg = %xh rc = %d\n",
1626 lustre_ioctl_file(cfs_file_t * fh, PCFS_PROC_IOCTL devctl)
1631 data = (ulong_ptr)devctl + sizeof(CFS_PROC_IOCTL);
1633 /* obd ioctl code */
1634 if (_IOC_TYPE(devctl->cmd) == 'f') {
1636 struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1638 if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE &&
1639 devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1641 unsigned long off = obd->ioc_len;
1643 if (obd->ioc_pbuf1) {
1644 obd->ioc_pbuf1 = (char *)(data + off);
1645 off += size_round(obd->ioc_plen1);
1648 if (obd->ioc_pbuf2) {
1649 obd->ioc_pbuf2 = (char *)(data + off);
1655 rc = lustre_do_ioctl(fh, devctl->cmd, data);
1671 if (fh->f_op->read) {
1672 rc = (fh->f_op->read) (fh, buf, size, &off);
1689 if (fh->f_op->write) {
1690 rc = (fh->f_op->write)(fh, buf, size, &off);
1696 #else /* !__KERNEL__ */
1698 #include <lnet/api-support.h>
1699 #include <liblustre.h>
1700 #include <lustre_lib.h>
1703 * proc process routines of user space
1706 HANDLE cfs_proc_open (char * filename, int oflag)
1709 IO_STATUS_BLOCK iosb;
1712 HANDLE FileHandle = INVALID_HANDLE_VALUE;
1713 OBJECT_ATTRIBUTES ObjectAttributes;
1714 ACCESS_MASK DesiredAccess;
1715 ULONG CreateDisposition;
1717 ULONG CreateOptions;
1718 UNICODE_STRING UnicodeName;
1721 PFILE_FULL_EA_INFORMATION Ea = NULL;
1723 UCHAR EaBuffer[EA_MAX_LENGTH];
1725 /* Check the filename: should start with "/proc" or "/dev" */
1726 NameLength = (USHORT)strlen(filename);
1727 if (NameLength > 0x05) {
1728 if (_strnicmp(filename, "/proc/", 6) == 0) {
1731 if (NameLength <= 0) {
1735 } else if (_strnicmp(filename, "/dev/", 5) == 0) {
1745 /* Analyze the flags settings */
1747 if (cfs_is_flag_set(oflag, O_WRONLY)) {
1748 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
1750 } else if (cfs_is_flag_set(oflag, O_RDWR)) {
1751 DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
1752 ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
1754 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
1755 ShareAccess = FILE_SHARE_READ;
1758 if (cfs_is_flag_set(oflag, O_CREAT)) {
1759 if (cfs_is_flag_set(oflag, O_EXCL)) {
1760 CreateDisposition = FILE_CREATE;
1764 CreateDisposition = FILE_OPEN_IF;
1767 CreateDisposition = FILE_OPEN;
1770 if (cfs_is_flag_set(oflag, O_TRUNC)) {
1771 if (cfs_is_flag_set(oflag, O_EXCL)) {
1772 CreateDisposition = FILE_OVERWRITE;
1774 CreateDisposition = FILE_OVERWRITE_IF;
1780 if (cfs_is_flag_set(oflag, O_DIRECTORY)) {
1781 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
1784 if (cfs_is_flag_set(oflag, O_SYNC)) {
1785 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
1788 if (cfs_is_flag_set(oflag, O_DIRECT)) {
1789 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
1792 /* Initialize the unicode path name for the specified file */
1793 RtlInitUnicodeString(&UnicodeName, LUSTRE_PROC_SYMLNK);
1795 /* Setup the object attributes structure for the file. */
1796 InitializeObjectAttributes(
1799 OBJ_CASE_INSENSITIVE,
1803 /* building EA for the proc entry ... */
1804 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1805 Ea->NextEntryOffset = 0;
1807 Ea->EaNameLength = (UCHAR)NameLength;
1808 Ea->EaValueLength = 0;
1814 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
1815 Ea->EaNameLength + 1;
1817 /* Now to open or create the file now */
1818 status = ZwCreateFile(
1824 FILE_ATTRIBUTE_NORMAL,
1831 /* Check the returned status of Iosb ... */
1833 if (!NT_SUCCESS(status)) {
1834 rc = cfs_error_code(status);
1843 int cfs_proc_close(HANDLE handle)
1846 NtClose((HANDLE)handle);
1852 int cfs_proc_read(HANDLE handle, void *buffer, unsigned int count)
1855 IO_STATUS_BLOCK iosb;
1856 LARGE_INTEGER offset;
1859 offset.QuadPart = 0;
1861 /* read file data */
1862 status = NtReadFile(
1873 /* check the return status */
1874 if (!NT_SUCCESS(status)) {
1875 printf("NtReadFile request failed 0x%0x\n", status);
1881 if (NT_SUCCESS(status)) {
1882 return iosb.Information;
1885 return cfs_error_code(status);
1889 int cfs_proc_write(HANDLE handle, void *buffer, unsigned int count)
1892 IO_STATUS_BLOCK iosb;
1893 LARGE_INTEGER offset;
1895 offset.QuadPart = -1;
1897 /* write buffer to the opened file */
1898 status = NtWriteFile(
1909 /* check the return status */
1910 if (!NT_SUCCESS(status)) {
1911 printf("NtWriteFile request failed 0x%0x\n", status);
1917 if (NT_SUCCESS(status)) {
1918 return iosb.Information;
1921 return cfs_error_code(status);
1924 int cfs_proc_ioctl(HANDLE handle, int cmd, void *buffer)
1926 PUCHAR procdat = NULL;
1927 CFS_PROC_IOCTL procctl;
1932 IO_STATUS_BLOCK iosb;
1936 if(_IOC_TYPE(cmd) == IOC_LIBCFS_TYPE) {
1937 struct libcfs_ioctl_data * portal;
1938 portal = (struct libcfs_ioctl_data *) buffer;
1939 length = portal->ioc_len;
1940 } else if (_IOC_TYPE(cmd) == 'f') {
1941 struct obd_ioctl_data * obd;
1942 obd = (struct obd_ioctl_data *) buffer;
1943 length = obd->ioc_len;
1944 extra = size_round(obd->ioc_plen1) + size_round(obd->ioc_plen2);
1945 } else if(_IOC_TYPE(cmd) == 'u') {
1949 printf("user:winnt-proc:cfs_proc_ioctl: un-supported ioctl type ...\n");
1950 cfs_enter_debugger();
1951 status = STATUS_INVALID_PARAMETER;
1955 procctl.len = length + extra;
1956 procdat = malloc(length + extra + sizeof(CFS_PROC_IOCTL));
1958 if (NULL == procdat) {
1959 printf("user:winnt-proc:cfs_proc_ioctl: no enough memory ...\n");
1960 status = STATUS_INSUFFICIENT_RESOURCES;
1961 cfs_enter_debugger();
1964 memset(procdat, 0, length + extra + sizeof(CFS_PROC_IOCTL));
1965 memcpy(procdat, &procctl, sizeof(CFS_PROC_IOCTL));
1966 memcpy(&procdat[sizeof(CFS_PROC_IOCTL)], buffer, length);
1967 length += sizeof(CFS_PROC_IOCTL);
1969 if (_IOC_TYPE(cmd) == 'f') {
1972 struct obd_ioctl_data * data;
1973 struct obd_ioctl_data * obd;
1975 data = (struct obd_ioctl_data *) buffer;
1976 obd = (struct obd_ioctl_data *) (procdat + sizeof(CFS_PROC_IOCTL));
1977 ptr = obd->ioc_bulk;
1979 if (data->ioc_inlbuf1) {
1980 obd->ioc_inlbuf1 = ptr;
1981 LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
1984 if (data->ioc_inlbuf2) {
1985 obd->ioc_inlbuf2 = ptr;
1986 LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
1988 if (data->ioc_inlbuf3) {
1989 obd->ioc_inlbuf3 = ptr;
1990 LOGL(data->ioc_inlbuf3, data->ioc_inllen3, ptr);
1992 if (data->ioc_inlbuf4) {
1993 obd->ioc_inlbuf4 = ptr;
1994 LOGL(data->ioc_inlbuf4, data->ioc_inllen4, ptr);
1997 if ( cmd != (ULONG)OBD_IOC_BRW_WRITE &&
1998 cmd != (ULONG)OBD_IOC_BRW_READ ) {
2000 if (data->ioc_pbuf1 && data->ioc_plen1) {
2001 obd->ioc_pbuf1 = &procdat[length];
2002 memcpy(obd->ioc_pbuf1, data->ioc_pbuf1, data->ioc_plen1);
2003 length += size_round(data->ioc_plen1);
2006 if (data->ioc_pbuf2 && data->ioc_plen2) {
2007 obd->ioc_pbuf2 = &procdat[length];
2008 memcpy(obd->ioc_pbuf2, data->ioc_pbuf2, data->ioc_plen2);
2009 length += size_round(data->ioc_plen2);
2013 if (obd_ioctl_is_invalid(obd)) {
2014 cfs_enter_debugger();
2018 status = NtDeviceIoControlFile(
2020 NULL, NULL, NULL, &iosb,
2026 if (NT_SUCCESS(status)) {
2027 memcpy(buffer, &procdat[sizeof(CFS_PROC_IOCTL)], procctl.len);
2036 return cfs_error_code(status);
2039 #endif /* __KERNEL__ */