1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
39 # define EXPORT_SYMTAB
42 # define DEBUG_SUBSYSTEM S_LNET
44 #include <libcfs/libcfs.h>
45 #include "tracefile.h"
46 #include <lustre_lib.h>
52 * /proc emulator routines ...
55 /* The root node of the proc fs emulation: / */
56 cfs_proc_entry_t * cfs_proc_root = NULL;
58 /* The root node of the proc fs emulation: /proc */
59 cfs_proc_entry_t * cfs_proc_proc = NULL;
61 /* The fs sys directory: /proc/fs */
62 cfs_proc_entry_t * cfs_proc_fs = NULL;
64 /* The sys root: /proc/sys */
65 cfs_proc_entry_t * cfs_proc_sys = NULL;
67 /* The sys root: /proc/dev | to implement misc device */
68 cfs_proc_entry_t * cfs_proc_dev = NULL;
71 /* SLAB object for cfs_proc_entry_t allocation */
72 cfs_mem_cache_t * proc_entry_cache = NULL;
74 /* root node for sysctl table */
75 cfs_sysctl_table_header_t root_table_header;
77 /* The global lock to protect all the access */
79 #if LIBCFS_PROCFS_SPINLOCK
80 cfs_spinlock_t proc_fs_lock;
82 #define INIT_PROCFS_LOCK() cfs_spin_lock_init(&proc_fs_lock)
83 #define LOCK_PROCFS() cfs_spin_lock(&proc_fs_lock)
84 #define UNLOCK_PROCFS() cfs_spin_unlock(&proc_fs_lock)
88 cfs_mutex_t proc_fs_lock;
90 #define INIT_PROCFS_LOCK() cfs_init_mutex(&proc_fs_lock)
91 #define LOCK_PROCFS() cfs_mutex_down(&proc_fs_lock)
92 #define UNLOCK_PROCFS() cfs_mutex_up(&proc_fs_lock)
97 proc_file_read(struct file * file, const char * buf, size_t nbytes, loff_t *ppos)
104 cfs_proc_entry_t * dp;
106 dp = (cfs_proc_entry_t *) file->f_inode->i_priv;
107 if (!(page = (char*) cfs_alloc(CFS_PAGE_SIZE, 0)))
110 while ((nbytes > 0) && !eof) {
112 count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
116 n = dp->read_proc( page, &start, (long)*ppos,
117 count, &eof, dp->data);
123 * For proc files that are less than 4k
125 start = page + *ppos;
126 n -= (ssize_t)(*ppos);
133 break; /* End of file */
140 n -= cfs_copy_to_user((void *)buf, start, n);
158 proc_file_write(struct file * file, const char * buffer,
159 size_t count, loff_t *ppos)
161 cfs_proc_entry_t * dp;
163 dp = (cfs_proc_entry_t *) file->f_inode->i_priv;
168 /* FIXME: does this routine need ppos? probably... */
169 return dp->write_proc(file, buffer, count, dp->data);
172 struct file_operations proc_file_operations = {
173 /*owner*/ THIS_MODULE,
174 /*lseek:*/ NULL, //proc_file_lseek,
175 /*read:*/ proc_file_read,
176 /*write:*/ proc_file_write,
182 /* allocate proc entry block */
187 cfs_proc_entry_t * entry = NULL;
189 entry = cfs_mem_cache_alloc(proc_entry_cache, 0);
194 memset(entry, 0, sizeof(cfs_proc_entry_t));
196 entry->magic = CFS_PROC_ENTRY_MAGIC;
197 RtlInitializeSplayLinks(&(entry->s_link));
198 entry->proc_fops = &proc_file_operations;
203 /* free the proc entry block */
206 proc_free_entry(cfs_proc_entry_t * entry)
209 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
211 cfs_mem_cache_free(proc_entry_cache, entry);
214 /* dissect the path string for a given full proc path */
224 int i = 0, j = 0, len = 0;
226 *first = *remain = NULL;
231 while (i < len && (path[i] == '/')) i++;
235 *first = (char *)path + i;
236 while (i < len && (path[i] != '/')) i++;
237 *first_len = (int)(path + i - *first);
240 *remain = (char *)path + i + 1;
245 /* search the children entries of the parent entry */
249 cfs_proc_entry_t * parent,
253 cfs_proc_entry_t * node;
254 PRTL_SPLAY_LINKS link;
256 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
257 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
263 ANSI_STRING ename,nname;
266 node = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
268 ASSERT(node->magic == CFS_PROC_ENTRY_MAGIC);
270 /* Compare the prefix in the tree with the full name */
272 RtlInitAnsiString(&ename, name);
273 RtlInitAnsiString(&nname, node->name);
275 result = RtlCompareString(&nname, &ename,TRUE);
279 /* The prefix is greater than the full name
280 so we go down the left child */
282 link = RtlLeftChild(link);
284 } else if (result < 0) {
286 /* The prefix is less than the full name
287 so we go down the right child */
289 link = RtlRightChild(link);
293 /* We got the entry in the splay tree and
294 make it root node instead */
296 parent->root = RtlSplay(link);
301 /* we need continue searching down the tree ... */
304 /* There's no the exptected entry in the splay tree */
311 cfs_proc_entry_t * parent,
312 cfs_proc_entry_t * child
315 cfs_proc_entry_t * entry;
317 ASSERT(parent != NULL && child != NULL);
318 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
319 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
320 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
323 parent->root = &(child->s_link);
325 entry = CONTAINING_RECORD(parent->root, cfs_proc_entry_t, s_link);
328 ANSI_STRING ename, cname;
330 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
332 RtlInitAnsiString(&ename, entry->name);
333 RtlInitAnsiString(&cname, child->name);
335 result = RtlCompareString(&ename, &cname,TRUE);
338 cfs_enter_debugger();
339 if (entry == child) {
346 if (RtlLeftChild(&entry->s_link) == NULL) {
347 RtlInsertAsLeftChild(&entry->s_link, &child->s_link);
350 entry = CONTAINING_RECORD( RtlLeftChild(&entry->s_link),
351 cfs_proc_entry_t, s_link);
354 if (RtlRightChild(&entry->s_link) == NULL) {
355 RtlInsertAsRightChild(&entry->s_link, &child->s_link);
358 entry = CONTAINING_RECORD( RtlRightChild(&entry->s_link),
359 cfs_proc_entry_t, s_link );
365 cfs_set_flag(child->flags, CFS_PROC_FLAG_ATTACHED);
367 child->parent = parent;
373 /* remove a child entry from the splay tree */
376 cfs_proc_entry_t * parent,
377 cfs_proc_entry_t * child
380 cfs_proc_entry_t * entry = NULL;
382 ASSERT(parent != NULL && child != NULL);
383 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
384 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
385 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
386 ASSERT(cfs_is_flag_set(child->flags, CFS_PROC_FLAG_ATTACHED));
387 ASSERT(child->parent == parent);
389 entry = proc_search_splay(parent, child->name);
392 ASSERT(entry == child);
393 parent->root = RtlDelete(&(entry->s_link));
396 cfs_enter_debugger();
404 /* search a node inside the proc fs tree */
409 cfs_proc_entry_t * root
412 cfs_proc_entry_t * entry;
413 cfs_proc_entry_t * parent;
414 char *first, *remain;
421 ename = cfs_alloc(0x21, CFS_ALLOC_ZERO);
429 /* dissect the file name string */
430 proc_dissect_name(name, &first, &flen, &remain);
435 cfs_enter_debugger();
440 memset(ename, 0, 0x20);
441 memcpy(ename, first, flen);
443 entry = proc_search_splay(parent, ename);
466 /* insert the path nodes to the proc fs tree */
471 cfs_proc_entry_t * root
474 cfs_proc_entry_t *entry;
475 cfs_proc_entry_t *parent;
476 char *first, *remain;
485 proc_dissect_name(name, &first, &flen, &remain);
493 memset(ename, 0, 0x20);
494 memcpy(ename, first, flen);
496 entry = proc_search_splay(parent, ename);
499 entry = proc_alloc_entry();
500 memcpy(entry->name, ename, flen);
503 if(!proc_insert_splay(parent, entry)) {
504 proc_free_entry(entry);
515 entry->mode |= S_IFDIR | S_IRUGO | S_IXUGO;
516 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
526 /* remove the path nodes from the proc fs tree */
531 cfs_proc_entry_t * root
534 cfs_proc_entry_t *entry;
535 char *first, *remain;
541 proc_dissect_name(name, &first, &flen, &remain);
545 memset(ename, 0, 0x20);
546 memcpy(ename, first, flen);
548 entry = proc_search_splay(root, ename);
553 ASSERT(S_ISDIR(entry->mode));
554 proc_remove_entry(remain, entry);
558 proc_remove_splay(root, entry);
559 proc_free_entry(entry);
563 cfs_enter_debugger();
567 /* create proc entry and insert it into the proc fs */
573 cfs_proc_entry_t * parent
576 cfs_proc_entry_t *entry = NULL;
579 if ((mode & S_IALLUGO) == 0)
580 mode |= S_IRUGO | S_IXUGO;
582 if ((mode & S_IFMT) == 0)
584 if ((mode & S_IALLUGO) == 0)
589 ASSERT(NULL != cfs_proc_root);
592 if (name[0] == '/') {
593 parent = cfs_proc_root;
595 ASSERT(NULL != cfs_proc_proc);
596 parent = cfs_proc_proc;
600 entry = proc_search_entry(name, parent);
603 entry = proc_insert_entry(name, parent);
605 /* Failed to create/insert the splay node ... */
606 cfs_enter_debugger();
609 /* Initializing entry ... */
613 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
625 /* search the specified entry form the proc fs */
630 cfs_proc_entry_t * root
633 cfs_proc_entry_t * entry;
636 ASSERT(cfs_proc_root != NULL);
638 if (name[0] == '/') {
639 root = cfs_proc_root;
641 ASSERT(cfs_proc_proc != NULL);
642 root = cfs_proc_proc;
645 entry = proc_search_entry(name, root);
651 /* remove the entry from the proc fs */
656 cfs_proc_entry_t * parent
660 ASSERT(cfs_proc_root != NULL);
661 if (parent == NULL) {
662 if (name[0] == '/') {
663 parent = cfs_proc_root;
665 ASSERT(cfs_proc_proc != NULL);
666 parent = cfs_proc_proc;
669 proc_remove_entry(name, parent);
674 void proc_destroy_splay(cfs_proc_entry_t * entry)
676 cfs_proc_entry_t * node;
678 if (S_ISDIR(entry->mode)) {
680 while (entry->root) {
681 node = CONTAINING_RECORD(entry->root, cfs_proc_entry_t, s_link);
682 entry->root = RtlDelete(&(node->s_link));
683 proc_destroy_splay(node);
687 proc_free_entry(entry);
690 cfs_proc_entry_t *proc_symlink(
692 cfs_proc_entry_t *parent,
696 cfs_enter_debugger();
700 cfs_proc_entry_t *proc_mkdir(
702 cfs_proc_entry_t *parent)
704 return create_proc_entry((char *)name, S_IFDIR, parent);
707 void proc_destory_subtree(cfs_proc_entry_t *entry)
711 proc_destroy_splay(entry);
715 /* destory the whole proc fs tree */
717 void proc_destroy_fs()
722 proc_destroy_splay(cfs_proc_root);
725 if (proc_entry_cache) {
726 cfs_mem_cache_destroy(proc_entry_cache);
732 static char proc_item_path[512];
735 void proc_show_tree(cfs_proc_entry_t * node);
736 void proc_print_node(cfs_proc_entry_t * node)
738 if (node != cfs_proc_root) {
739 if (S_ISDIR(node->mode)) {
740 printk("%s/%s/\n", proc_item_path, node->name);
742 printk("%s/%s\n", proc_item_path, node->name);
745 printk("%s\n", node->name);
748 if (S_ISDIR(node->mode)) {
749 proc_show_tree(node);
753 void proc_show_child(PRTL_SPLAY_LINKS link)
755 cfs_proc_entry_t * entry = NULL;
761 proc_show_child(link->LeftChild);
762 entry = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
763 proc_print_node(entry);
764 proc_show_child(link->RightChild);
767 void proc_show_tree(cfs_proc_entry_t * node)
769 PRTL_SPLAY_LINKS link = NULL;
770 cfs_proc_entry_t * entry = NULL;
774 i = strlen(proc_item_path);
775 ASSERT(S_ISDIR(node->mode));
776 if (node != cfs_proc_root) {
777 strcat(proc_item_path, "/");
778 strcat(proc_item_path, node->name);
780 proc_show_child(link);
781 proc_item_path[i] = 0;
784 void proc_print_splay()
786 printk("=================================================\n");
787 printk("Lustre virtual proc entries:\n");
788 printk("-------------------------------------------------\n");
790 proc_show_tree(cfs_proc_root);
792 printk("=================================================\n");
796 /* initilaize / build the proc fs tree */
799 cfs_proc_entry_t * root = NULL;
801 memset(&(root_table_header), 0, sizeof(struct ctl_table_header));
802 CFS_INIT_LIST_HEAD(&(root_table_header.ctl_entry));
805 proc_entry_cache = cfs_mem_cache_create(
807 sizeof(cfs_proc_entry_t),
812 if (!proc_entry_cache) {
816 root = proc_alloc_entry();
821 root->magic = CFS_PROC_ENTRY_MAGIC;
822 root->flags = CFS_PROC_FLAG_DIRECTORY;
823 root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
824 root->nlink = 3; // root should never be deleted.
827 cfs_proc_root = root;
829 cfs_proc_dev = create_proc_entry("dev", S_IFDIR, root);
833 cfs_proc_dev->nlink = 1;
835 cfs_proc_proc = create_proc_entry("proc", S_IFDIR, root);
836 if (!cfs_proc_proc) {
839 cfs_proc_proc->nlink = 1;
841 cfs_proc_fs = create_proc_entry("fs", S_IFDIR, cfs_proc_proc);
845 cfs_proc_fs->nlink = 1;
847 cfs_proc_sys = create_proc_entry("sys", S_IFDIR, cfs_proc_proc);
851 cfs_proc_sys->nlink = 1;
863 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
864 size_t count, loff_t *ppos)
867 cfs_proc_entry_t *de;
868 struct ctl_table *table;
872 de = (cfs_proc_entry_t *) file->proc_dentry;
874 if (!de || !de->data)
876 table = (struct ctl_table *) de->data;
877 if (!table || !table->proc_handler)
879 op = (write ? 002 : 004);
884 * FIXME: we need to pass on ppos to the handler.
887 error = (*table->proc_handler) (table, write, file, buf, &res);
893 static ssize_t proc_readsys(struct file * file, char * buf,
894 size_t count, loff_t *ppos)
896 return do_rw_proc(0, file, buf, count, ppos);
899 static ssize_t proc_writesys(struct file * file, const char * buf,
900 size_t count, loff_t *ppos)
902 return do_rw_proc(1, file, (char *) buf, count, ppos);
906 struct file_operations proc_sys_file_operations = {
907 /*owner*/ THIS_MODULE,
909 /*read:*/ proc_readsys,
910 /*write:*/ proc_writesys,
917 /* Scan the sysctl entries in table and add them all into /proc */
918 void register_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t * root)
920 cfs_proc_entry_t * de;
924 for (; table->ctl_name; table++) {
925 /* Can't do anything without a proc name. */
926 if (!table->procname)
928 /* Maybe we can't do anything with it... */
929 if (!table->proc_handler && !table->child) {
930 printk(CFS_KERN_WARNING "SYSCTL: Can't register %s\n",
935 len = strlen(table->procname);
939 if (table->proc_handler)
942 de = search_proc_entry(table->procname, root);
946 /* If the subdir exists already, de is non-NULL */
951 de = create_proc_entry((char *)table->procname, mode, root);
954 de->data = (void *) table;
955 if (table->proc_handler) {
956 de->proc_fops = &proc_sys_file_operations;
960 if (de->mode & S_IFDIR)
961 register_proc_table(table->child, de);
967 * Unregister a /proc sysctl table and any subdirectories.
969 void unregister_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t *root)
971 cfs_proc_entry_t *de;
972 for (; table->ctl_name; table++) {
973 if (!(de = table->de))
975 if (de->mode & S_IFDIR) {
977 printk (CFS_KERN_ALERT "Help- malformed sysctl tree on free\n");
980 unregister_proc_table(table->child, de);
982 /* Don't unregister directories which still have entries.. */
987 /* Don't unregister proc entries that are still being used.. */
992 remove_proc_entry((char *)table->procname, root);
996 /* The generic string strategy routine: */
997 int sysctl_string(cfs_sysctl_table_t *table, int *name, int nlen,
998 void *oldval, size_t *oldlenp,
999 void *newval, size_t newlen, void **context)
1003 if (!table->data || !table->maxlen)
1006 if (oldval && oldlenp) {
1007 if(get_user(len, oldlenp))
1010 l = strlen(table->data);
1011 if (len > l) len = l;
1012 if (len >= table->maxlen)
1013 len = table->maxlen;
1014 if(cfs_copy_to_user(oldval, table->data, len))
1016 if(put_user(0, ((char *) oldval) + len))
1018 if(put_user(len, oldlenp))
1022 if (newval && newlen) {
1024 if (len > table->maxlen)
1025 len = table->maxlen;
1026 if(cfs_copy_from_user(table->data, newval, len))
1028 if (len == table->maxlen)
1030 ((char *) table->data)[len] = 0;
1036 * simple_strtoul - convert a string to an unsigned long
1037 * @cp: The start of the string
1038 * @endp: A pointer to the end of the parsed string will be placed here
1039 * @base: The number base to use
1041 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
1043 unsigned long result = 0, value;
1050 if ((*cp == 'x') && cfs_isxdigit(cp[1])) {
1056 while (cfs_isxdigit(*cp) &&
1057 (value = cfs_isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
1058 result = result*base + value;
1073 static int do_proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1074 void *buffer, size_t *lenp, int conv, int op)
1076 int *i, vleft, first=1, neg, val;
1079 #define TMPBUFLEN 20
1080 char buf[TMPBUFLEN], *p;
1082 if (!table->data || !table->maxlen || !*lenp)
1088 i = (int *) table->data;
1089 vleft = table->maxlen / sizeof(int);
1092 for (; left && vleft--; i++, first=0) {
1096 if(get_user(c,(char *) buffer))
1101 ((char *) buffer)++;
1107 if (len > TMPBUFLEN-1)
1109 if(cfs_copy_from_user(buf, buffer, len))
1113 if (*p == '-' && left > 1) {
1117 if (*p < '0' || *p > '9')
1119 val = simple_strtoul(p, &p, 0) * conv;
1121 if ((len < left) && *p && !isspace(*p))
1125 (char *)buffer += len;
1128 case OP_SET: *i = val; break;
1129 case OP_AND: *i &= val; break;
1130 case OP_OR: *i |= val; break;
1131 case OP_MAX: if(*i < val)
1134 case OP_MIN: if(*i > val)
1142 sprintf(p, "%d", (*i) / conv);
1146 if(cfs_copy_to_user(buffer, buf, len))
1149 (char *)buffer += len;
1153 if (!write && !first && left) {
1154 if(put_user('\n', (char *) buffer))
1156 left--, ((char *)buffer)++;
1159 p = (char *) buffer;
1162 if(get_user(c, p++))
1172 memset(&(filp->f_pos) , 0, sizeof(loff_t));
1173 filp->f_pos += (loff_t)(*lenp);
1178 * proc_dointvec - read a vector of integers
1179 * @table: the sysctl table
1180 * @write: %TRUE if this is a write to the sysctl file
1181 * @filp: the file structure
1182 * @buffer: the user buffer
1183 * @lenp: the size of the user buffer
1185 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1186 * values from/to the user buffer, treated as an ASCII string.
1188 * Returns 0 on success.
1190 int proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1191 void *buffer, size_t *lenp)
1193 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1198 * proc_dostring - read a string sysctl
1199 * @table: the sysctl table
1200 * @write: %TRUE if this is a write to the sysctl file
1201 * @filp: the file structure
1202 * @buffer: the user buffer
1203 * @lenp: the size of the user buffer
1205 * Reads/writes a string from/to the user buffer. If the kernel
1206 * buffer provided is not large enough to hold the string, the
1207 * string is truncated. The copied string is %NULL-terminated.
1208 * If the string is being read by the user process, it is copied
1209 * and a newline '\n' is added. It is truncated if the buffer is
1212 * Returns 0 on success.
1214 int proc_dostring(cfs_sysctl_table_t *table, int write, struct file *filp,
1215 void *buffer, size_t *lenp)
1220 if (!table->data || !table->maxlen || !*lenp ||
1221 (filp->f_pos && !write)) {
1229 while (len < *lenp) {
1230 if(get_user(c, p++))
1232 if (c == 0 || c == '\n')
1236 if (len >= (size_t)table->maxlen)
1237 len = (size_t)table->maxlen-1;
1238 if(cfs_copy_from_user(table->data, buffer, len))
1240 ((char *) table->data)[len] = 0;
1241 filp->f_pos += *lenp;
1243 len = (size_t)strlen(table->data);
1244 if (len > (size_t)table->maxlen)
1245 len = (size_t)table->maxlen;
1249 if(cfs_copy_to_user(buffer, table->data, len))
1252 if(put_user('\n', ((char *) buffer) + len))
1262 /* Perform the actual read/write of a sysctl table entry. */
1263 int do_sysctl_strategy (cfs_sysctl_table_t *table,
1264 int *name, int nlen,
1265 void *oldval, size_t *oldlenp,
1266 void *newval, size_t newlen, void **context)
1276 if (table->strategy) {
1277 rc = table->strategy(table, name, nlen, oldval, oldlenp,
1278 newval, newlen, context);
1285 /* If there is no strategy routine, or if the strategy returns
1286 * zero, proceed with automatic r/w */
1287 if (table->data && table->maxlen) {
1288 if (oldval && oldlenp) {
1289 get_user(len, oldlenp);
1291 if (len > (size_t)table->maxlen)
1292 len = (size_t)table->maxlen;
1293 if(cfs_copy_to_user(oldval, table->data, len))
1295 if(put_user(len, oldlenp))
1299 if (newval && newlen) {
1301 if (len > (size_t)table->maxlen)
1302 len = (size_t)table->maxlen;
1303 if(cfs_copy_from_user(table->data, newval, len))
1310 static int parse_table(int *name, int nlen,
1311 void *oldval, size_t *oldlenp,
1312 void *newval, size_t newlen,
1313 cfs_sysctl_table_t *table, void **context)
1321 if (get_user(n, name))
1323 for ( ; table->ctl_name; table++) {
1324 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1328 if (ctl_perm(table, 001))
1331 if (table->strategy) {
1332 error = table->strategy(
1335 newval, newlen, context);
1341 table = table->child;
1344 error = do_sysctl_strategy(table, name, nlen,
1346 newval, newlen, context);
1353 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1354 void *newval, size_t newlen)
1358 if (nlen <= 0 || nlen >= CTL_MAXNAME)
1362 if (!oldlenp || get_user(old_len, oldlenp))
1365 tmp = &root_table_header.ctl_entry;
1367 struct ctl_table_header *head =
1368 cfs_list_entry(tmp, struct ctl_table_header, ctl_entry);
1369 void *context = NULL;
1370 int error = parse_table(name, nlen, oldval, oldlenp,
1371 newval, newlen, head->ctl_table,
1375 if (error != -ENOTDIR)
1378 } while (tmp != &root_table_header.ctl_entry);
1383 * register_sysctl_table - register a sysctl heirarchy
1384 * @table: the top-level table structure
1385 * @insert_at_head: whether the entry should be inserted in front or at the end
1387 * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1388 * array. An entry with a ctl_name of 0 terminates the table.
1390 * The members of the &ctl_table structure are used as follows:
1392 * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1393 * must be unique within that level of sysctl
1395 * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1396 * enter a sysctl file
1398 * data - a pointer to data for use by proc_handler
1400 * maxlen - the maximum size in bytes of the data
1402 * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1404 * child - a pointer to the child sysctl table if this entry is a directory, or
1407 * proc_handler - the text handler routine (described below)
1409 * strategy - the strategy routine (described below)
1411 * de - for internal use by the sysctl routines
1413 * extra1, extra2 - extra pointers usable by the proc handler routines
1415 * Leaf nodes in the sysctl tree will be represented by a single file
1416 * under /proc; non-leaf nodes will be represented by directories.
1418 * sysctl(2) can automatically manage read and write requests through
1419 * the sysctl table. The data and maxlen fields of the ctl_table
1420 * struct enable minimal validation of the values being written to be
1421 * performed, and the mode field allows minimal authentication.
1423 * More sophisticated management can be enabled by the provision of a
1424 * strategy routine with the table entry. This will be called before
1425 * any automatic read or write of the data is performed.
1427 * The strategy routine may return
1429 * < 0 - Error occurred (error is passed to user process)
1431 * 0 - OK - proceed with automatic read or write.
1433 * > 0 - OK - read or write has been done by the strategy routine, so
1434 * return immediately.
1436 * There must be a proc_handler routine for any terminal nodes
1437 * mirrored under /proc/sys (non-terminals are handled by a built-in
1438 * directory handler). Several default handlers are available to
1439 * cover common cases -
1441 * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1442 * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1443 * proc_doulongvec_minmax()
1445 * It is the handler's job to read the input buffer from user memory
1446 * and process it. The handler should return 0 on success.
1448 * This routine returns %NULL on a failure to register, and a pointer
1449 * to the table header on success.
1451 struct ctl_table_header *register_sysctl_table(cfs_sysctl_table_t * table,
1454 struct ctl_table_header *tmp;
1455 tmp = cfs_alloc(sizeof(struct ctl_table_header), 0);
1458 tmp->ctl_table = table;
1460 CFS_INIT_LIST_HEAD(&tmp->ctl_entry);
1462 cfs_list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
1464 cfs_list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1465 #ifdef CONFIG_PROC_FS
1466 register_proc_table(table, cfs_proc_sys);
1472 * unregister_sysctl_table - unregister a sysctl table heirarchy
1473 * @header: the header returned from register_sysctl_table
1475 * Unregisters the sysctl table and all children. proc entries may not
1476 * actually be removed until they are no longer used by anyone.
1478 void unregister_sysctl_table(struct ctl_table_header * header)
1480 cfs_list_del(&header->ctl_entry);
1481 #ifdef CONFIG_PROC_FS
1482 unregister_proc_table(header->ctl_table, cfs_proc_sys);
1488 int cfs_psdev_register(cfs_psdev_t * psdev)
1490 cfs_proc_entry_t * entry;
1492 entry = create_proc_entry (
1493 (char *)psdev->name,
1502 entry->flags |= CFS_PROC_FLAG_MISCDEV;
1504 entry->proc_fops = psdev->fops;
1505 entry->data = (void *)psdev;
1510 int cfs_psdev_deregister(cfs_psdev_t * psdev)
1512 cfs_proc_entry_t * entry;
1514 entry = search_proc_entry (
1515 (char *)psdev->name,
1521 ASSERT(entry->data == (void *)psdev);
1522 ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1525 (char *)psdev->name,
1533 #define PSDEV_LNET (0x100)
1535 PSDEV_DEBUG = 1, /* control debugging */
1536 PSDEV_SUBSYSTEM_DEBUG, /* control debugging */
1537 PSDEV_PRINTK, /* force all messages to console */
1538 PSDEV_CONSOLE_RATELIMIT, /* rate limit console messages */
1539 PSDEV_DEBUG_PATH, /* crashdump log location */
1540 PSDEV_DEBUG_DUMP_PATH, /* crashdump tracelog location */
1541 PSDEV_LIBCFS_MEMUSED, /* bytes currently PORTAL_ALLOCated */
1544 static struct ctl_table lnet_table[] = {
1545 {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1547 {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1548 sizeof(int), 0644, NULL, &proc_dointvec},
1549 {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1551 {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit,
1552 sizeof(int), 0644, NULL, &proc_dointvec},
1554 {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1555 sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1558 {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1559 sizeof(int), 0644, NULL, &proc_dointvec},
1563 static struct ctl_table top_table[2] = {
1564 {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1569 int trace_write_dump_kernel(struct file *file, const char *buffer,
1570 unsigned long count, void *data)
1572 int rc = cfs_trace_dump_debug_buffer_usrstr((void *)buffer, count);
1574 return (rc < 0) ? rc : count;
1577 int trace_write_daemon_file(struct file *file, const char *buffer,
1578 unsigned long count, void *data)
1580 int rc = cfs_trace_daemon_command_usrstr((void *)buffer, count);
1582 return (rc < 0) ? rc : count;
1585 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1586 int *eof, void *data)
1589 cfs_tracefile_read_lock();
1590 rc = cfs_trace_copyout_string(page, count, cfs_tracefile, "\n");
1591 cfs_tracefile_read_unlock();
1595 int trace_write_debug_mb(struct file *file, const char *buffer,
1596 unsigned long count, void *data)
1598 int rc = 0; /*trace_set_debug_mb_userstr((void *)buffer, count);*/
1600 return (rc < 0) ? rc : count;
1603 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1604 int *eof, void *data)
1608 snprintf(str, sizeof(str), "%d\n", cfs_trace_get_debug_mb());
1610 return cfs_trace_copyout_string(page, count, str, NULL);
1613 int insert_proc(void)
1615 cfs_proc_entry_t *ent;
1617 ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1619 CERROR("couldn't register dump_kernel\n");
1622 ent->write_proc = trace_write_dump_kernel;
1624 ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1626 CERROR("couldn't register daemon_file\n");
1629 ent->write_proc = trace_write_daemon_file;
1630 ent->read_proc = trace_read_daemon_file;
1632 ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1634 CERROR("couldn't register debug_mb\n");
1637 ent->write_proc = trace_write_debug_mb;
1638 ent->read_proc = trace_read_debug_mb;
1643 void remove_proc(void)
1645 remove_proc_entry("sys/lnet/dump_kernel", NULL);
1646 remove_proc_entry("sys/lnet/daemon_file", NULL);
1647 remove_proc_entry("sys/lnet/debug_mb", NULL);
1652 * proc process routines of kernel space
1656 lustre_open_file(char * filename)
1659 cfs_file_t * fh = NULL;
1660 cfs_proc_entry_t * fp = NULL;
1662 fp = search_proc_entry(filename, cfs_proc_root);
1667 fh = cfs_alloc(sizeof(cfs_file_t), CFS_ALLOC_ZERO);
1672 fh->f_inode = cfs_alloc(sizeof(struct inode), CFS_ALLOC_ZERO);
1678 fh->f_inode->i_priv = (void *)fp;
1679 fh->f_op = fp->proc_fops;
1681 if (fh->f_op->open) {
1682 rc = (fh->f_op->open)(fh->f_inode, fh);
1688 cfs_free(fh->f_inode);
1697 lustre_close_file(cfs_file_t * fh)
1700 cfs_proc_entry_t * fp = NULL;
1702 fp = (cfs_proc_entry_t *) fh->f_inode->i_priv;
1703 if (fh->f_op->release) {
1704 rc = (fh->f_op->release)(fh->f_inode, fh);
1709 cfs_free(fh->f_inode);
1716 lustre_do_ioctl( cfs_file_t * fh,
1722 if (fh->f_op->ioctl) {
1723 rc = (fh->f_op->ioctl)(fh, cmd, arg);
1730 lustre_ioctl_file(cfs_file_t * fh, PCFS_PROC_IOCTL devctl)
1735 data = (ulong_ptr_t)devctl + sizeof(CFS_PROC_IOCTL);
1737 CLASSERT(sizeof(struct obd_ioctl_data) == 528);
1739 CLASSERT(sizeof(struct obd_ioctl_data) == 576);
1742 /* obd ioctl code */
1743 if (_IOC_TYPE(devctl->cmd) == 'f') {
1745 struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1747 if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE &&
1748 devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1750 unsigned long off = obd->ioc_len;
1752 if (obd->ioc_plen1) {
1753 obd->ioc_pbuf1 = (char *)(data + off);
1754 off += cfs_size_round(obd->ioc_plen1);
1756 obd->ioc_pbuf1 = NULL;
1759 if (obd->ioc_plen2) {
1760 obd->ioc_pbuf2 = (char *)(data + off);
1761 off += cfs_size_round(obd->ioc_plen2);
1763 obd->ioc_pbuf2 = NULL;
1768 rc = lustre_do_ioctl(fh, devctl->cmd, data);
1786 high = (off_t)(off >> 32);
1788 if (fh->f_op->read) {
1789 rc = (fh->f_op->read) (fh, buf, size, &off);
1793 fh->f_pos = off + rc;
1810 if (fh->f_op->write) {
1811 rc = (fh->f_op->write)(fh, buf, size, &off);
1823 * seq_open - initialize sequential file
1824 * @file: file we initialize
1825 * @op: method table describing the sequence
1827 * seq_open() sets @file, associating it with a sequence described
1828 * by @op. @op->start() sets the iterator up and returns the first
1829 * element of sequence. @op->stop() shuts it down. @op->next()
1830 * returns the next element of sequence. @op->show() prints element
1831 * into the buffer. In case of error ->start() and ->next() return
1832 * ERR_PTR(error). In the end of sequence they return %NULL. ->show()
1833 * returns 0 in case of success and negative number in case of error.
1835 int seq_open(struct file *file, const struct seq_operations *op)
1837 struct seq_file *p = file->private_data;
1840 p = kmalloc(sizeof(*p), GFP_KERNEL);
1843 file->private_data = p;
1845 memset(p, 0, sizeof(*p));
1846 cfs_mutex_init(&p->lock);
1850 * Wrappers around seq_open(e.g. swaps_open) need to be
1851 * aware of this. If they set f_version themselves, they
1852 * should call seq_open first and then set f_version.
1854 file->f_version = 0;
1856 /* SEQ files support lseek, but not pread/pwrite */
1857 file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
1860 EXPORT_SYMBOL(seq_open);
1863 * seq_read - ->read() method for sequential files.
1864 * @file: the file to read from
1865 * @buf: the buffer to read to
1866 * @size: the maximum number of bytes to read
1867 * @ppos: the current position in the file
1869 * Ready-made ->f_op->read()
1871 ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
1873 struct seq_file *m = (struct seq_file *)file->private_data;
1880 cfs_mutex_lock(&m->lock);
1882 * seq_file->op->..m_start/m_stop/m_next may do special actions
1883 * or optimisations based on the file->f_version, so we want to
1884 * pass the file->f_version to those methods.
1886 * seq_file->version is just copy of f_version, and seq_file
1887 * methods can treat it simply as file version.
1888 * It is copied in first and copied out after all operations.
1889 * It is convenient to have it as part of structure to avoid the
1890 * need of passing another argument to all the seq_file methods.
1892 m->version = file->f_version;
1893 /* grab buffer if we didn't have one */
1895 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
1899 /* if not empty - flush it first */
1901 n = min(m->count, size);
1902 err = cfs_copy_to_user(buf, m->buf + m->from, n);
1915 /* we need at least one record in buffer */
1918 p = m->op->start(m, &pos);
1920 if (!p || IS_ERR(p))
1922 err = m->op->show(m, p);
1925 if (m->count < m->size)
1929 m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
1939 /* they want more? let's try to get some more */
1940 while (m->count < size) {
1941 size_t offs = m->count;
1943 p = m->op->next(m, p, &next);
1944 if (!p || IS_ERR(p)) {
1948 err = m->op->show(m, p);
1949 if (err || m->count == m->size) {
1956 n = min(m->count, size);
1957 err = cfs_copy_to_user(buf, m->buf, n);
1972 file->f_version = m->version;
1973 cfs_mutex_unlock(&m->lock);
1982 EXPORT_SYMBOL(seq_read);
1984 static int traverse(struct seq_file *m, loff_t offset)
1986 loff_t pos = 0, index;
1992 m->count = m->from = 0;
1998 m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
2002 p = m->op->start(m, &index);
2007 error = m->op->show(m, p);
2010 if (m->count == m->size)
2012 if (pos + (loff_t)(m->count) > offset) {
2013 m->from = (size_t)(offset - pos);
2014 m->count -= m->from;
2020 if (pos == offset) {
2025 p = m->op->next(m, p, &index);
2033 m->buf = cfs_alloc(m->size <<= 1, GFP_KERNEL | CFS_ALLOC_ZERO);
2034 return !m->buf ? -ENOMEM : -EAGAIN;
2038 * seq_lseek - ->llseek() method for sequential files.
2039 * @file: the file in question
2040 * @offset: new position
2041 * @origin: 0 for absolute, 1 for relative position
2043 * Ready-made ->f_op->llseek()
2045 loff_t seq_lseek(struct file *file, loff_t offset, int origin)
2047 struct seq_file *m = (struct seq_file *)file->private_data;
2048 long long retval = -EINVAL;
2050 cfs_mutex_lock(&m->lock);
2051 m->version = file->f_version;
2054 offset += file->f_pos;
2059 if (offset != file->f_pos) {
2060 while ((retval=traverse(m, offset)) == -EAGAIN)
2063 /* with extreme prejudice... */
2069 retval = file->f_pos = offset;
2073 file->f_version = m->version;
2074 cfs_mutex_unlock(&m->lock);
2077 EXPORT_SYMBOL(seq_lseek);
2080 * seq_release - free the structures associated with sequential file.
2081 * @file: file in question
2082 * @inode: file->f_path.dentry->d_inode
2084 * Frees the structures associated with sequential file; can be used
2085 * as ->f_op->release() if you don't have private data to destroy.
2087 int seq_release(struct inode *inode, struct file *file)
2089 struct seq_file *m = (struct seq_file *)file->private_data;
2097 EXPORT_SYMBOL(seq_release);
2100 * seq_escape - print string into buffer, escaping some characters
2103 * @esc: set of characters that need escaping
2105 * Puts string into buffer, replacing each occurrence of character from
2106 * @esc with usual octal escape. Returns 0 in case of success, -1 - in
2109 int seq_escape(struct seq_file *m, const char *s, const char *esc)
2111 char *end = m->buf + m->size;
2115 for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
2116 if (!strchr(esc, c)) {
2122 *p++ = '0' + ((c & 0300) >> 6);
2123 *p++ = '0' + ((c & 070) >> 3);
2124 *p++ = '0' + (c & 07);
2130 m->count = p - m->buf;
2133 EXPORT_SYMBOL(seq_escape);
2135 int seq_printf(struct seq_file *m, const char *f, ...)
2140 if (m->count < m->size) {
2142 len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
2144 if (m->count + len < m->size) {
2152 EXPORT_SYMBOL(seq_printf);
2154 char *d_path(struct path *p, char *buffer, int buflen)
2156 cfs_enter_debugger();
2157 return ERR_PTR(-ENAMETOOLONG);
2160 int seq_path(struct seq_file *m, struct path *path, char *esc)
2162 if (m->count < m->size) {
2163 char *s = m->buf + m->count;
2164 char *p = d_path(path, s, m->size - m->count);
2169 p = m->buf + m->count;
2170 m->count = s - m->buf;
2171 return (int)(s - p);
2172 } else if (!strchr(esc, c)) {
2174 } else if (s + 4 > p) {
2178 *s++ = '0' + ((c & 0300) >> 6);
2179 *s++ = '0' + ((c & 070) >> 3);
2180 *s++ = '0' + (c & 07);
2188 EXPORT_SYMBOL(seq_path);
2190 static void *single_start(struct seq_file *p, loff_t *pos)
2192 return (void *) (INT_PTR) (*pos == 0);
2195 static void *single_next(struct seq_file *p, void *v, loff_t *pos)
2201 static void single_stop(struct seq_file *p, void *v)
2205 int single_open(struct file *file, int (*show)(struct seq_file *, void *),
2208 struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL);
2212 op->start = single_start;
2213 op->next = single_next;
2214 op->stop = single_stop;
2216 res = seq_open(file, op);
2218 ((struct seq_file *)file->private_data)->private = data;
2224 EXPORT_SYMBOL(single_open);
2226 int single_release(struct inode *inode, struct file *file)
2228 const struct seq_operations *op = ((struct seq_file *)file->private_data)->op;
2229 int res = seq_release(inode, file);
2230 cfs_free((void *)op);
2233 EXPORT_SYMBOL(single_release);
2235 int seq_release_private(struct inode *inode, struct file *file)
2237 struct seq_file *seq = file->private_data;
2239 cfs_free(seq->private);
2240 seq->private = NULL;
2241 return seq_release(inode, file);
2243 EXPORT_SYMBOL(seq_release_private);
2245 void *__seq_open_private(struct file *f, const struct seq_operations *ops,
2250 struct seq_file *seq;
2252 private = cfs_alloc(psize, GFP_KERNEL | CFS_ALLOC_ZERO);
2253 if (private == NULL)
2256 rc = seq_open(f, ops);
2260 seq = f->private_data;
2261 seq->private = private;
2269 EXPORT_SYMBOL(__seq_open_private);
2271 int seq_open_private(struct file *filp, const struct seq_operations *ops,
2274 return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM;
2276 EXPORT_SYMBOL(seq_open_private);
2278 int seq_putc(struct seq_file *m, char c)
2280 if (m->count < m->size) {
2281 m->buf[m->count++] = c;
2286 EXPORT_SYMBOL(seq_putc);
2288 int seq_puts(struct seq_file *m, const char *s)
2290 int len = strlen(s);
2291 if (m->count + len < m->size) {
2292 memcpy(m->buf + m->count, s, len);
2299 EXPORT_SYMBOL(seq_puts);
2301 cfs_list_t *seq_list_start(cfs_list_t *head, loff_t pos)
2305 cfs_list_for_each(lh, head)
2312 EXPORT_SYMBOL(seq_list_start);
2314 cfs_list_t *seq_list_start_head(cfs_list_t *head,
2320 return seq_list_start(head, pos - 1);
2323 EXPORT_SYMBOL(seq_list_start_head);
2325 cfs_list_t *seq_list_next(void *v, cfs_list_t *head,
2330 lh = ((cfs_list_t *)v)->next;
2332 return lh == head ? NULL : lh;
2335 EXPORT_SYMBOL(seq_list_next);
2337 struct proc_dir_entry *PDE(const struct inode *inode)
2339 return (struct proc_dir_entry *)inode->i_priv;
2343 #endif /* __KERNEL__ */