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 [sun.com URL with a
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 2008 Sun Microsystems, Inc. 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"
51 * /proc emulator routines ...
54 /* The root node of the proc fs emulation: /proc */
55 cfs_proc_entry_t * proc_fs_root = NULL;
58 /* The sys root: /proc/sys */
59 cfs_proc_entry_t * proc_sys_root = NULL;
62 /* The sys root: /proc/dev | to implement misc device */
64 cfs_proc_entry_t * proc_dev_root = NULL;
67 /* SLAB object for cfs_proc_entry_t allocation */
69 cfs_mem_cache_t * proc_entry_cache = NULL;
71 /* root node for sysctl table */
73 cfs_sysctl_table_header_t root_table_header;
75 /* The global lock to protect all the access */
77 #if LIBCFS_PROCFS_SPINLOCK
78 spinlock_t proc_fs_lock;
80 #define INIT_PROCFS_LOCK() spin_lock_init(&proc_fs_lock)
81 #define LOCK_PROCFS() spin_lock(&proc_fs_lock)
82 #define UNLOCK_PROCFS() spin_unlock(&proc_fs_lock)
88 #define INIT_PROCFS_LOCK() init_mutex(&proc_fs_lock)
89 #define LOCK_PROCFS() mutex_down(&proc_fs_lock)
90 #define UNLOCK_PROCFS() mutex_up(&proc_fs_lock)
95 proc_file_read(struct file * file, const char * buf, size_t nbytes, loff_t *ppos)
102 cfs_proc_entry_t * dp;
104 dp = (cfs_proc_entry_t *) file->private_data;
105 if (!(page = (char*) cfs_alloc(CFS_PAGE_SIZE, 0)))
108 while ((nbytes > 0) && !eof) {
110 count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
114 n = dp->read_proc( page, &start, (long)*ppos,
115 count, &eof, dp->data);
121 * For proc files that are less than 4k
123 start = page + *ppos;
124 n -= (ssize_t)(*ppos);
131 break; /* End of file */
138 n -= copy_to_user((void *)buf, start, n);
156 proc_file_write(struct file * file, const char * buffer,
157 size_t count, loff_t *ppos)
159 cfs_proc_entry_t * dp;
161 dp = (cfs_proc_entry_t *) file->private_data;
166 /* FIXME: does this routine need ppos? probably... */
167 return dp->write_proc(file, buffer, count, dp->data);
170 struct file_operations proc_file_operations = {
171 /*lseek:*/ NULL, //proc_file_lseek,
172 /*read:*/ proc_file_read,
173 /*write:*/ proc_file_write,
179 /* allocate proc entry block */
184 cfs_proc_entry_t * entry = NULL;
186 entry = cfs_mem_cache_alloc(proc_entry_cache, 0);
191 memset(entry, 0, sizeof(cfs_proc_entry_t));
193 entry->magic = CFS_PROC_ENTRY_MAGIC;
194 RtlInitializeSplayLinks(&(entry->s_link));
195 entry->proc_fops = &proc_file_operations;
200 /* free the proc entry block */
203 proc_free_entry(cfs_proc_entry_t * entry)
206 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
208 cfs_mem_cache_free(proc_entry_cache, entry);
211 /* dissect the path string for a given full proc path */
221 int i = 0, j = 0, len = 0;
223 *first = *remain = NULL;
228 while (i < len && (path[i] == '/')) i++;
233 while (i < len && (path[i] != '/')) i++;
234 *first_len = (path + i - *first);
237 *remain = path + i + 1;
242 /* search the children entries of the parent entry */
246 cfs_proc_entry_t * parent,
250 cfs_proc_entry_t * node;
251 PRTL_SPLAY_LINKS link;
253 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
254 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
260 ANSI_STRING ename,nname;
263 node = CONTAINING_RECORD(link, cfs_proc_entry_t, s_link);
265 ASSERT(node->magic == CFS_PROC_ENTRY_MAGIC);
267 /* Compare the prefix in the tree with the full name */
269 RtlInitAnsiString(&ename, name);
270 RtlInitAnsiString(&nname, node->name);
272 result = RtlCompareString(&nname, &ename,TRUE);
276 /* The prefix is greater than the full name
277 so we go down the left child */
279 link = RtlLeftChild(link);
281 } else if (result < 0) {
283 /* The prefix is less than the full name
284 so we go down the right child */
287 link = RtlRightChild(link);
291 /* We got the entry in the splay tree and
292 make it root node instead */
294 parent->root = RtlSplay(link);
299 /* we need continue searching down the tree ... */
302 /* There's no the exptected entry in the splay tree */
309 cfs_proc_entry_t * parent,
310 cfs_proc_entry_t * child
313 cfs_proc_entry_t * entry;
315 ASSERT(parent != NULL && child != NULL);
316 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
317 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
318 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
321 parent->root = &(child->s_link);
323 entry = CONTAINING_RECORD(parent->root, cfs_proc_entry_t, s_link);
326 ANSI_STRING ename, cname;
328 ASSERT(entry->magic == CFS_PROC_ENTRY_MAGIC);
330 RtlInitAnsiString(&ename, entry->name);
331 RtlInitAnsiString(&cname, child->name);
333 result = RtlCompareString(&ename, &cname,TRUE);
336 cfs_enter_debugger();
337 if (entry == child) {
344 if (RtlLeftChild(&entry->s_link) == NULL) {
345 RtlInsertAsLeftChild(&entry->s_link, &child->s_link);
348 entry = CONTAINING_RECORD( RtlLeftChild(&entry->s_link),
349 cfs_proc_entry_t, s_link);
352 if (RtlRightChild(&entry->s_link) == NULL) {
353 RtlInsertAsRightChild(&entry->s_link, &child->s_link);
356 entry = CONTAINING_RECORD( RtlRightChild(&entry->s_link),
357 cfs_proc_entry_t, s_link );
363 cfs_set_flag(child->flags, CFS_PROC_FLAG_ATTACHED);
370 /* remove a child entry from the splay tree */
373 cfs_proc_entry_t * parent,
374 cfs_proc_entry_t * child
377 cfs_proc_entry_t * entry = NULL;
379 ASSERT(parent != NULL && child != NULL);
380 ASSERT(parent->magic == CFS_PROC_ENTRY_MAGIC);
381 ASSERT(child->magic == CFS_PROC_ENTRY_MAGIC);
382 ASSERT(cfs_is_flag_set(parent->flags, CFS_PROC_FLAG_DIRECTORY));
383 ASSERT(cfs_is_flag_set(child->flags, CFS_PROC_FLAG_ATTACHED));
385 entry = proc_search_splay(parent, child->name);
388 ASSERT(entry == child);
389 parent->root = RtlDelete(&(entry->s_link));
392 cfs_enter_debugger();
400 /* search a node inside the proc fs tree */
405 cfs_proc_entry_t * root
408 cfs_proc_entry_t * entry;
409 cfs_proc_entry_t * parent;
410 char *first, *remain;
417 ename = cfs_alloc(0x21, CFS_ALLOC_ZERO);
425 /* dissect the file name string */
426 proc_dissect_name(name, &first, &flen, &remain);
431 cfs_enter_debugger();
436 memset(ename, 0, 0x20);
437 memcpy(ename, first, flen);
439 entry = proc_search_splay(parent, ename);
462 /* insert the path nodes to the proc fs tree */
467 cfs_proc_entry_t * root
470 cfs_proc_entry_t *entry;
471 cfs_proc_entry_t *parent;
472 char *first, *remain;
481 proc_dissect_name(name, &first, &flen, &remain);
489 memset(ename, 0, 0x20);
490 memcpy(ename, first, flen);
492 entry = proc_search_splay(parent, ename);
495 entry = proc_alloc_entry();
496 memcpy(entry->name, ename, flen);
499 if(!proc_insert_splay(parent, entry)) {
500 proc_free_entry(entry);
511 entry->mode |= S_IFDIR | S_IRUGO | S_IXUGO;
512 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
522 /* remove the path nodes from the proc fs tree */
527 cfs_proc_entry_t * root
530 cfs_proc_entry_t *entry;
531 char *first, *remain;
537 proc_dissect_name(name, &first, &flen, &remain);
541 memset(ename, 0, 0x20);
542 memcpy(ename, first, flen);
544 entry = proc_search_splay(root, ename);
549 ASSERT(S_ISDIR(entry->mode));
550 proc_remove_entry(remain, entry);
554 proc_remove_splay(root, entry);
555 proc_free_entry(entry);
559 cfs_enter_debugger();
563 /* create proc entry and insert it into the proc fs */
569 cfs_proc_entry_t * root
572 cfs_proc_entry_t *parent = root;
573 cfs_proc_entry_t *entry = NULL;
576 if ((mode & S_IALLUGO) == 0)
577 mode |= S_IRUGO | S_IXUGO;
579 if ((mode & S_IFMT) == 0)
581 if ((mode & S_IALLUGO) == 0)
587 ASSERT(NULL != proc_fs_root);
590 parent = proc_fs_root;
593 entry = proc_search_entry(name, parent);
596 entry = proc_insert_entry(name, parent);
598 /* Failed to create/insert the splay node ... */
599 cfs_enter_debugger();
602 /* Initializing entry ... */
606 cfs_set_flag(entry->flags, CFS_PROC_FLAG_DIRECTORY);
618 /* search the specified entry form the proc fs */
623 cfs_proc_entry_t * root
626 cfs_proc_entry_t * entry;
632 entry = proc_search_entry(name, root);
638 /* remove the entry from the proc fs */
643 cfs_proc_entry_t * parent
647 if (parent == NULL) {
648 parent = proc_fs_root;
650 proc_remove_entry(name, parent);
655 void proc_destroy_splay(cfs_proc_entry_t * entry)
657 cfs_proc_entry_t * node;
659 if (S_ISDIR(entry->mode)) {
661 while (entry->root) {
662 node = CONTAINING_RECORD(entry->root, cfs_proc_entry_t, s_link);
663 entry->root = RtlDelete(&(node->s_link));
664 proc_destroy_splay(node);
668 proc_free_entry(entry);
672 /* destory the whole proc fs tree */
674 void proc_destroy_fs()
679 proc_destroy_splay(proc_fs_root);
682 if (proc_entry_cache) {
683 cfs_mem_cache_destroy(proc_entry_cache);
689 /* initilaize / build the proc fs tree */
693 cfs_proc_entry_t * root = NULL;
695 memset(&(root_table_header), 0, sizeof(struct ctl_table_header));
696 INIT_LIST_HEAD(&(root_table_header.ctl_entry));
699 proc_entry_cache = cfs_mem_cache_create(
701 sizeof(cfs_proc_entry_t),
706 if (!proc_entry_cache) {
710 root = proc_alloc_entry();
717 root->magic = CFS_PROC_ENTRY_MAGIC;
718 root->flags = CFS_PROC_FLAG_DIRECTORY;
719 root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
720 root->nlink = 3; // root should never be deleted.
729 proc_sys_root = create_proc_entry("sys", S_IFDIR, root);
731 if (!proc_sys_root) {
732 proc_free_entry(root);
738 proc_sys_root->nlink = 1;
740 proc_dev_root = create_proc_entry("dev", S_IFDIR, root);
742 if (!proc_dev_root) {
743 proc_free_entry(proc_sys_root);
744 proc_sys_root = NULL;
745 proc_free_entry(proc_fs_root);
751 proc_dev_root->nlink = 1;
757 static ssize_t do_rw_proc(int write, struct file * file, char * buf,
758 size_t count, loff_t *ppos)
761 cfs_proc_entry_t *de;
762 struct ctl_table *table;
766 de = (cfs_proc_entry_t *) file->proc_dentry;
768 if (!de || !de->data)
770 table = (struct ctl_table *) de->data;
771 if (!table || !table->proc_handler)
773 op = (write ? 002 : 004);
775 // if (ctl_perm(table, op))
781 * FIXME: we need to pass on ppos to the handler.
784 error = (*table->proc_handler) (table, write, file, buf, &res);
790 static ssize_t proc_readsys(struct file * file, char * buf,
791 size_t count, loff_t *ppos)
793 return do_rw_proc(0, file, buf, count, ppos);
796 static ssize_t proc_writesys(struct file * file, const char * buf,
797 size_t count, loff_t *ppos)
799 return do_rw_proc(1, file, (char *) buf, count, ppos);
803 struct file_operations proc_sys_file_operations = {
805 /*read:*/ proc_readsys,
806 /*write:*/ proc_writesys,
813 /* Scan the sysctl entries in table and add them all into /proc */
814 void register_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t * root)
816 cfs_proc_entry_t * de;
820 for (; table->ctl_name; table++) {
821 /* Can't do anything without a proc name. */
822 if (!table->procname)
824 /* Maybe we can't do anything with it... */
825 if (!table->proc_handler && !table->child) {
826 printk(KERN_WARNING "SYSCTL: Can't register %s\n",
831 len = strlen(table->procname);
835 if (table->proc_handler)
838 de = search_proc_entry(table->procname, root);
842 /* If the subdir exists already, de is non-NULL */
847 de = create_proc_entry((char *)table->procname, mode, root);
850 de->data = (void *) table;
851 if (table->proc_handler) {
852 de->proc_fops = &proc_sys_file_operations;
856 if (de->mode & S_IFDIR)
857 register_proc_table(table->child, de);
863 * Unregister a /proc sysctl table and any subdirectories.
865 void unregister_proc_table(cfs_sysctl_table_t * table, cfs_proc_entry_t *root)
867 cfs_proc_entry_t *de;
868 for (; table->ctl_name; table++) {
869 if (!(de = table->de))
871 if (de->mode & S_IFDIR) {
873 printk (KERN_ALERT "Help - malformed sysctl tree on free\n");
876 unregister_proc_table(table->child, de);
878 /* Don't unregister directories which still have entries.. */
883 /* Don't unregister proc entries that are still being used.. */
888 remove_proc_entry((char *)table->procname, root);
892 /* The generic string strategy routine: */
893 int sysctl_string(cfs_sysctl_table_t *table, int *name, int nlen,
894 void *oldval, size_t *oldlenp,
895 void *newval, size_t newlen, void **context)
899 if (!table->data || !table->maxlen)
902 if (oldval && oldlenp) {
903 if(get_user(len, oldlenp))
906 l = strlen(table->data);
907 if (len > l) len = l;
908 if (len >= table->maxlen)
910 if(copy_to_user(oldval, table->data, len))
912 if(put_user(0, ((char *) oldval) + len))
914 if(put_user(len, oldlenp))
918 if (newval && newlen) {
920 if (len > table->maxlen)
922 if(copy_from_user(table->data, newval, len))
924 if (len == table->maxlen)
926 ((char *) table->data)[len] = 0;
932 * simple_strtoul - convert a string to an unsigned long
933 * @cp: The start of the string
934 * @endp: A pointer to the end of the parsed string will be placed here
935 * @base: The number base to use
937 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
939 unsigned long result = 0, value;
946 if ((*cp == 'x') && isxdigit(cp[1])) {
952 while (isxdigit(*cp) &&
953 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
954 result = result*base + value;
969 static int do_proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
970 void *buffer, size_t *lenp, int conv, int op)
972 int *i, vleft, first=1, neg, val;
976 char buf[TMPBUFLEN], *p;
978 if (!table->data || !table->maxlen || !*lenp)
984 i = (int *) table->data;
985 vleft = table->maxlen / sizeof(int);
988 for (; left && vleft--; i++, first=0) {
992 if(get_user(c,(char *) buffer))
1003 if (len > TMPBUFLEN-1)
1005 if(copy_from_user(buf, buffer, len))
1009 if (*p == '-' && left > 1) {
1013 if (*p < '0' || *p > '9')
1015 val = simple_strtoul(p, &p, 0) * conv;
1017 if ((len < left) && *p && !isspace(*p))
1021 (char *)buffer += len;
1024 case OP_SET: *i = val; break;
1025 case OP_AND: *i &= val; break;
1026 case OP_OR: *i |= val; break;
1027 case OP_MAX: if(*i < val)
1030 case OP_MIN: if(*i > val)
1038 sprintf(p, "%d", (*i) / conv);
1042 if(copy_to_user(buffer, buf, len))
1045 (char *)buffer += len;
1049 if (!write && !first && left) {
1050 if(put_user('\n', (char *) buffer))
1052 left--, ((char *)buffer)++;
1055 p = (char *) buffer;
1058 if(get_user(c, p++))
1068 memset(&(filp->f_pos) , 0, sizeof(loff_t));
1069 filp->f_pos += (loff_t)(*lenp);
1074 * proc_dointvec - read a vector of integers
1075 * @table: the sysctl table
1076 * @write: %TRUE if this is a write to the sysctl file
1077 * @filp: the file structure
1078 * @buffer: the user buffer
1079 * @lenp: the size of the user buffer
1081 * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
1082 * values from/to the user buffer, treated as an ASCII string.
1084 * Returns 0 on success.
1086 int proc_dointvec(cfs_sysctl_table_t *table, int write, struct file *filp,
1087 void *buffer, size_t *lenp)
1089 return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET);
1094 * proc_dostring - read a string sysctl
1095 * @table: the sysctl table
1096 * @write: %TRUE if this is a write to the sysctl file
1097 * @filp: the file structure
1098 * @buffer: the user buffer
1099 * @lenp: the size of the user buffer
1101 * Reads/writes a string from/to the user buffer. If the kernel
1102 * buffer provided is not large enough to hold the string, the
1103 * string is truncated. The copied string is %NULL-terminated.
1104 * If the string is being read by the user process, it is copied
1105 * and a newline '\n' is added. It is truncated if the buffer is
1108 * Returns 0 on success.
1110 int proc_dostring(cfs_sysctl_table_t *table, int write, struct file *filp,
1111 void *buffer, size_t *lenp)
1116 if (!table->data || !table->maxlen || !*lenp ||
1117 (filp->f_pos && !write)) {
1125 while (len < *lenp) {
1126 if(get_user(c, p++))
1128 if (c == 0 || c == '\n')
1132 if (len >= (size_t)table->maxlen)
1133 len = (size_t)table->maxlen-1;
1134 if(copy_from_user(table->data, buffer, len))
1136 ((char *) table->data)[len] = 0;
1137 filp->f_pos += *lenp;
1139 len = (size_t)strlen(table->data);
1140 if (len > (size_t)table->maxlen)
1141 len = (size_t)table->maxlen;
1145 if(copy_to_user(buffer, table->data, len))
1148 if(put_user('\n', ((char *) buffer) + len))
1158 /* Perform the actual read/write of a sysctl table entry. */
1159 int do_sysctl_strategy (cfs_sysctl_table_t *table,
1160 int *name, int nlen,
1161 void *oldval, size_t *oldlenp,
1162 void *newval, size_t newlen, void **context)
1172 if (table->strategy) {
1173 rc = table->strategy(table, name, nlen, oldval, oldlenp,
1174 newval, newlen, context);
1181 /* If there is no strategy routine, or if the strategy returns
1182 * zero, proceed with automatic r/w */
1183 if (table->data && table->maxlen) {
1184 if (oldval && oldlenp) {
1185 get_user(len, oldlenp);
1187 if (len > (size_t)table->maxlen)
1188 len = (size_t)table->maxlen;
1189 if(copy_to_user(oldval, table->data, len))
1191 if(put_user(len, oldlenp))
1195 if (newval && newlen) {
1197 if (len > (size_t)table->maxlen)
1198 len = (size_t)table->maxlen;
1199 if(copy_from_user(table->data, newval, len))
1206 static int parse_table(int *name, int nlen,
1207 void *oldval, size_t *oldlenp,
1208 void *newval, size_t newlen,
1209 cfs_sysctl_table_t *table, void **context)
1217 if (get_user(n, name))
1219 for ( ; table->ctl_name; table++) {
1220 if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
1224 if (ctl_perm(table, 001))
1227 if (table->strategy) {
1228 error = table->strategy(
1231 newval, newlen, context);
1237 table = table->child;
1240 error = do_sysctl_strategy(table, name, nlen,
1242 newval, newlen, context);
1249 int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
1250 void *newval, size_t newlen)
1252 struct list_head *tmp;
1254 if (nlen <= 0 || nlen >= CTL_MAXNAME)
1258 if (!oldlenp || get_user(old_len, oldlenp))
1261 tmp = &root_table_header.ctl_entry;
1263 struct ctl_table_header *head =
1264 list_entry(tmp, struct ctl_table_header, ctl_entry);
1265 void *context = NULL;
1266 int error = parse_table(name, nlen, oldval, oldlenp,
1267 newval, newlen, head->ctl_table,
1271 if (error != -ENOTDIR)
1274 } while (tmp != &root_table_header.ctl_entry);
1279 * register_sysctl_table - register a sysctl heirarchy
1280 * @table: the top-level table structure
1281 * @insert_at_head: whether the entry should be inserted in front or at the end
1283 * Register a sysctl table heirarchy. @table should be a filled in ctl_table
1284 * array. An entry with a ctl_name of 0 terminates the table.
1286 * The members of the &ctl_table structure are used as follows:
1288 * ctl_name - This is the numeric sysctl value used by sysctl(2). The number
1289 * must be unique within that level of sysctl
1291 * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not
1292 * enter a sysctl file
1294 * data - a pointer to data for use by proc_handler
1296 * maxlen - the maximum size in bytes of the data
1298 * mode - the file permissions for the /proc/sys file, and for sysctl(2)
1300 * child - a pointer to the child sysctl table if this entry is a directory, or
1303 * proc_handler - the text handler routine (described below)
1305 * strategy - the strategy routine (described below)
1307 * de - for internal use by the sysctl routines
1309 * extra1, extra2 - extra pointers usable by the proc handler routines
1311 * Leaf nodes in the sysctl tree will be represented by a single file
1312 * under /proc; non-leaf nodes will be represented by directories.
1314 * sysctl(2) can automatically manage read and write requests through
1315 * the sysctl table. The data and maxlen fields of the ctl_table
1316 * struct enable minimal validation of the values being written to be
1317 * performed, and the mode field allows minimal authentication.
1319 * More sophisticated management can be enabled by the provision of a
1320 * strategy routine with the table entry. This will be called before
1321 * any automatic read or write of the data is performed.
1323 * The strategy routine may return
1325 * < 0 - Error occurred (error is passed to user process)
1327 * 0 - OK - proceed with automatic read or write.
1329 * > 0 - OK - read or write has been done by the strategy routine, so
1330 * return immediately.
1332 * There must be a proc_handler routine for any terminal nodes
1333 * mirrored under /proc/sys (non-terminals are handled by a built-in
1334 * directory handler). Several default handlers are available to
1335 * cover common cases -
1337 * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(),
1338 * proc_dointvec_minmax(), proc_doulongvec_ms_jiffies_minmax(),
1339 * proc_doulongvec_minmax()
1341 * It is the handler's job to read the input buffer from user memory
1342 * and process it. The handler should return 0 on success.
1344 * This routine returns %NULL on a failure to register, and a pointer
1345 * to the table header on success.
1347 struct ctl_table_header *register_sysctl_table(cfs_sysctl_table_t * table,
1350 struct ctl_table_header *tmp;
1351 tmp = cfs_alloc(sizeof(struct ctl_table_header), 0);
1354 tmp->ctl_table = table;
1356 INIT_LIST_HEAD(&tmp->ctl_entry);
1358 list_add(&tmp->ctl_entry, &root_table_header.ctl_entry);
1360 list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
1361 #ifdef CONFIG_PROC_FS
1362 register_proc_table(table, proc_sys_root);
1368 * unregister_sysctl_table - unregister a sysctl table heirarchy
1369 * @header: the header returned from register_sysctl_table
1371 * Unregisters the sysctl table and all children. proc entries may not
1372 * actually be removed until they are no longer used by anyone.
1374 void unregister_sysctl_table(struct ctl_table_header * header)
1376 list_del(&header->ctl_entry);
1377 #ifdef CONFIG_PROC_FS
1378 unregister_proc_table(header->ctl_table, proc_sys_root);
1384 int cfs_psdev_register(cfs_psdev_t * psdev)
1386 cfs_proc_entry_t * entry;
1388 entry = create_proc_entry (
1389 (char *)psdev->name,
1398 entry->flags |= CFS_PROC_FLAG_MISCDEV;
1400 entry->proc_fops = psdev->fops;
1401 entry->data = (void *)psdev;
1406 int cfs_psdev_deregister(cfs_psdev_t * psdev)
1408 cfs_proc_entry_t * entry;
1410 entry = search_proc_entry (
1411 (char *)psdev->name,
1417 ASSERT(entry->data == (void *)psdev);
1418 ASSERT(entry->flags & CFS_PROC_FLAG_MISCDEV);
1421 (char *)psdev->name,
1429 extern char debug_file_path[1024];
1431 #define PSDEV_LNET (0x100)
1433 PSDEV_DEBUG = 1, /* control debugging */
1434 PSDEV_SUBSYSTEM_DEBUG, /* control debugging */
1435 PSDEV_PRINTK, /* force all messages to console */
1436 PSDEV_CONSOLE_RATELIMIT, /* rate limit console messages */
1437 PSDEV_DEBUG_PATH, /* crashdump log location */
1438 PSDEV_DEBUG_DUMP_PATH, /* crashdump tracelog location */
1439 PSDEV_LIBCFS_MEMUSED, /* bytes currently PORTAL_ALLOCated */
1442 static struct ctl_table lnet_table[] = {
1443 {PSDEV_DEBUG, "debug", &libcfs_debug, sizeof(int), 0644, NULL,
1445 {PSDEV_SUBSYSTEM_DEBUG, "subsystem_debug", &libcfs_subsystem_debug,
1446 sizeof(int), 0644, NULL, &proc_dointvec},
1447 {PSDEV_PRINTK, "printk", &libcfs_printk, sizeof(int), 0644, NULL,
1449 {PSDEV_CONSOLE_RATELIMIT, "console_ratelimit", &libcfs_console_ratelimit,
1450 sizeof(int), 0644, NULL, &proc_dointvec},
1451 {PSDEV_DEBUG_PATH, "debug_path", debug_file_path,
1452 sizeof(debug_file_path), 0644, NULL, &proc_dostring, &sysctl_string},
1454 {PSDEV_PORTALS_UPCALL, "upcall", portals_upcall,
1455 sizeof(portals_upcall), 0644, NULL, &proc_dostring,
1458 {PSDEV_LIBCFS_MEMUSED, "memused", (int *)&libcfs_kmemory.counter,
1459 sizeof(int), 0644, NULL, &proc_dointvec},
1463 static struct ctl_table top_table[2] = {
1464 {PSDEV_LNET, "lnet", NULL, 0, 0555, lnet_table},
1469 int trace_write_dump_kernel(struct file *file, const char *buffer,
1470 unsigned long count, void *data)
1472 int rc = trace_dump_debug_buffer_usrstr(buffer, count);
1474 return (rc < 0) ? rc : count;
1477 int trace_write_daemon_file(struct file *file, const char *buffer,
1478 unsigned long count, void *data)
1480 int rc = trace_daemon_command_usrstr(buffer, count);
1482 return (rc < 0) ? rc : count;
1485 int trace_read_daemon_file(char *page, char **start, off_t off, int count,
1486 int *eof, void *data)
1490 tracefile_read_lock();
1492 rc = trace_copyout_string(page, count, tracefile, "\n");
1494 tracefile_read_unlock();
1499 int trace_write_debug_mb(struct file *file, const char *buffer,
1500 unsigned long count, void *data)
1502 int rc = trace_set_debug_mb_userstr(buffer, count);
1504 return (rc < 0) ? rc : count;
1507 int trace_read_debug_mb(char *page, char **start, off_t off, int count,
1508 int *eof, void *data)
1512 snprintf(str, sizeof(str), "%d\n", trace_get_debug_mb());
1514 return trace_copyout_string(page, count, str, NULL);
1517 int insert_proc(void)
1519 cfs_proc_entry_t *ent;
1521 ent = create_proc_entry("sys/lnet/dump_kernel", 0, NULL);
1523 CERROR(("couldn't register dump_kernel\n"));
1526 ent->write_proc = trace_write_dump_kernel;
1528 ent = create_proc_entry("sys/lnet/daemon_file", 0, NULL);
1530 CERROR(("couldn't register daemon_file\n"));
1533 ent->write_proc = trace_write_daemon_file;
1534 ent->read_proc = trace_read_daemon_file;
1536 ent = create_proc_entry("sys/lnet/debug_mb", 0, NULL);
1538 CERROR(("couldn't register debug_mb\n"));
1541 ent->write_proc = trace_write_debug_mb;
1542 ent->read_proc = trace_read_debug_mb;
1547 void remove_proc(void)
1549 remove_proc_entry("sys/portals/dump_kernel", NULL);
1550 remove_proc_entry("sys/portals/daemon_file", NULL);
1551 remove_proc_entry("sys/portals/debug_mb", NULL);
1553 #ifdef CONFIG_SYSCTL
1554 if (portals_table_header)
1555 unregister_sysctl_table(portals_table_header);
1556 portals_table_header = NULL;
1562 * proc process routines of kernel space
1566 lustre_open_file(char * filename)
1569 cfs_file_t * fh = NULL;
1570 cfs_proc_entry_t * fp = NULL;
1572 fp = search_proc_entry(filename, proc_fs_root);
1579 fh = cfs_alloc(sizeof(cfs_file_t), CFS_ALLOC_ZERO);
1586 fh->private_data = (void *)fp;
1587 fh->f_op = fp->proc_fops;
1589 if (fh->f_op->open) {
1590 rc = (fh->f_op->open)(fh);
1604 lustre_close_file(cfs_file_t * fh)
1607 cfs_proc_entry_t * fp = NULL;
1609 fp = (cfs_proc_entry_t *) fh->private_data;
1611 if (fh->f_op->release) {
1612 rc = (fh->f_op->release)(fh);
1623 lustre_do_ioctl( cfs_file_t * fh,
1629 if (fh->f_op->ioctl) {
1630 rc = (fh->f_op->ioctl)(fh, cmd, arg);
1634 printk("lustre_do_ioctl: fialed: cmd = %xh arg = %xh rc = %d\n",
1642 lustre_ioctl_file(cfs_file_t * fh, PCFS_PROC_IOCTL devctl)
1647 data = (ulong_ptr)devctl + sizeof(CFS_PROC_IOCTL);
1649 /* obd ioctl code */
1650 if (_IOC_TYPE(devctl->cmd) == 'f') {
1652 struct obd_ioctl_data * obd = (struct obd_ioctl_data *) data;
1654 if ( devctl->cmd != (ULONG)OBD_IOC_BRW_WRITE &&
1655 devctl->cmd != (ULONG)OBD_IOC_BRW_READ ) {
1657 unsigned long off = obd->ioc_len;
1659 if (obd->ioc_pbuf1) {
1660 obd->ioc_pbuf1 = (char *)(data + off);
1661 off += size_round(obd->ioc_plen1);
1664 if (obd->ioc_pbuf2) {
1665 obd->ioc_pbuf2 = (char *)(data + off);
1671 rc = lustre_do_ioctl(fh, devctl->cmd, data);
1687 if (fh->f_op->read) {
1688 rc = (fh->f_op->read) (fh, buf, size, &off);
1705 if (fh->f_op->write) {
1706 rc = (fh->f_op->write)(fh, buf, size, &off);
1712 #else /* !__KERNEL__ */
1714 #include <lnet/api-support.h>
1715 #include <liblustre.h>
1716 #include <lustre_lib.h>
1719 * proc process routines of user space
1722 HANDLE cfs_proc_open (char * filename, int oflag)
1725 IO_STATUS_BLOCK iosb;
1728 HANDLE FileHandle = INVALID_HANDLE_VALUE;
1729 OBJECT_ATTRIBUTES ObjectAttributes;
1730 ACCESS_MASK DesiredAccess;
1731 ULONG CreateDisposition;
1733 ULONG CreateOptions;
1734 UNICODE_STRING UnicodeName;
1737 PFILE_FULL_EA_INFORMATION Ea = NULL;
1739 UCHAR EaBuffer[EA_MAX_LENGTH];
1741 /* Check the filename: should start with "/proc" or "/dev" */
1742 NameLength = (USHORT)strlen(filename);
1743 if (NameLength > 0x05) {
1744 if (_strnicmp(filename, "/proc/", 6) == 0) {
1747 if (NameLength <= 0) {
1751 } else if (_strnicmp(filename, "/dev/", 5) == 0) {
1761 /* Analyze the flags settings */
1763 if (cfs_is_flag_set(oflag, O_WRONLY)) {
1764 DesiredAccess = (GENERIC_WRITE | SYNCHRONIZE);
1766 } else if (cfs_is_flag_set(oflag, O_RDWR)) {
1767 DesiredAccess = (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE);
1768 ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
1770 DesiredAccess = (GENERIC_READ | SYNCHRONIZE);
1771 ShareAccess = FILE_SHARE_READ;
1774 if (cfs_is_flag_set(oflag, O_CREAT)) {
1775 if (cfs_is_flag_set(oflag, O_EXCL)) {
1776 CreateDisposition = FILE_CREATE;
1780 CreateDisposition = FILE_OPEN_IF;
1783 CreateDisposition = FILE_OPEN;
1786 if (cfs_is_flag_set(oflag, O_TRUNC)) {
1787 if (cfs_is_flag_set(oflag, O_EXCL)) {
1788 CreateDisposition = FILE_OVERWRITE;
1790 CreateDisposition = FILE_OVERWRITE_IF;
1796 if (cfs_is_flag_set(oflag, O_DIRECTORY)) {
1797 cfs_set_flag(CreateOptions, FILE_DIRECTORY_FILE);
1800 if (cfs_is_flag_set(oflag, O_SYNC)) {
1801 cfs_set_flag(CreateOptions, FILE_WRITE_THROUGH);
1804 if (cfs_is_flag_set(oflag, O_DIRECT)) {
1805 cfs_set_flag(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING);
1808 /* Initialize the unicode path name for the specified file */
1809 RtlInitUnicodeString(&UnicodeName, LUSTRE_PROC_SYMLNK);
1811 /* Setup the object attributes structure for the file. */
1812 InitializeObjectAttributes(
1815 OBJ_CASE_INSENSITIVE,
1819 /* building EA for the proc entry ... */
1820 Ea = (PFILE_FULL_EA_INFORMATION)EaBuffer;
1821 Ea->NextEntryOffset = 0;
1823 Ea->EaNameLength = (UCHAR)NameLength;
1824 Ea->EaValueLength = 0;
1830 EaLength = sizeof(FILE_FULL_EA_INFORMATION) - 1 +
1831 Ea->EaNameLength + 1;
1833 /* Now to open or create the file now */
1834 status = ZwCreateFile(
1840 FILE_ATTRIBUTE_NORMAL,
1847 /* Check the returned status of Iosb ... */
1849 if (!NT_SUCCESS(status)) {
1850 rc = cfs_error_code(status);
1859 int cfs_proc_close(HANDLE handle)
1862 NtClose((HANDLE)handle);
1868 int cfs_proc_read(HANDLE handle, void *buffer, unsigned int count)
1871 IO_STATUS_BLOCK iosb;
1872 LARGE_INTEGER offset;
1875 offset.QuadPart = 0;
1877 /* read file data */
1878 status = NtReadFile(
1889 /* check the return status */
1890 if (!NT_SUCCESS(status)) {
1891 printf("NtReadFile request failed 0x%0x\n", status);
1897 if (NT_SUCCESS(status)) {
1898 return iosb.Information;
1901 return cfs_error_code(status);
1905 int cfs_proc_write(HANDLE handle, void *buffer, unsigned int count)
1908 IO_STATUS_BLOCK iosb;
1909 LARGE_INTEGER offset;
1911 offset.QuadPart = -1;
1913 /* write buffer to the opened file */
1914 status = NtWriteFile(
1925 /* check the return status */
1926 if (!NT_SUCCESS(status)) {
1927 printf("NtWriteFile request failed 0x%0x\n", status);
1933 if (NT_SUCCESS(status)) {
1934 return iosb.Information;
1937 return cfs_error_code(status);
1940 int cfs_proc_ioctl(HANDLE handle, int cmd, void *buffer)
1942 PUCHAR procdat = NULL;
1943 CFS_PROC_IOCTL procctl;
1948 IO_STATUS_BLOCK iosb;
1952 if(_IOC_TYPE(cmd) == IOC_LIBCFS_TYPE) {
1953 struct libcfs_ioctl_data * portal;
1954 portal = (struct libcfs_ioctl_data *) buffer;
1955 length = portal->ioc_len;
1956 } else if (_IOC_TYPE(cmd) == 'f') {
1957 struct obd_ioctl_data * obd;
1958 obd = (struct obd_ioctl_data *) buffer;
1959 length = obd->ioc_len;
1960 extra = size_round(obd->ioc_plen1) + size_round(obd->ioc_plen2);
1961 } else if(_IOC_TYPE(cmd) == 'u') {
1965 printf("user:winnt-proc:cfs_proc_ioctl: un-supported ioctl type ...\n");
1966 cfs_enter_debugger();
1967 status = STATUS_INVALID_PARAMETER;
1971 procctl.len = length + extra;
1972 procdat = malloc(length + extra + sizeof(CFS_PROC_IOCTL));
1974 if (NULL == procdat) {
1975 printf("user:winnt-proc:cfs_proc_ioctl: no enough memory ...\n");
1976 status = STATUS_INSUFFICIENT_RESOURCES;
1977 cfs_enter_debugger();
1980 memset(procdat, 0, length + extra + sizeof(CFS_PROC_IOCTL));
1981 memcpy(procdat, &procctl, sizeof(CFS_PROC_IOCTL));
1982 memcpy(&procdat[sizeof(CFS_PROC_IOCTL)], buffer, length);
1983 length += sizeof(CFS_PROC_IOCTL);
1985 if (_IOC_TYPE(cmd) == 'f') {
1988 struct obd_ioctl_data * data;
1989 struct obd_ioctl_data * obd;
1991 data = (struct obd_ioctl_data *) buffer;
1992 obd = (struct obd_ioctl_data *) (procdat + sizeof(CFS_PROC_IOCTL));
1993 ptr = obd->ioc_bulk;
1995 if (data->ioc_inlbuf1) {
1996 obd->ioc_inlbuf1 = ptr;
1997 LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
2000 if (data->ioc_inlbuf2) {
2001 obd->ioc_inlbuf2 = ptr;
2002 LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
2004 if (data->ioc_inlbuf3) {
2005 obd->ioc_inlbuf3 = ptr;
2006 LOGL(data->ioc_inlbuf3, data->ioc_inllen3, ptr);
2008 if (data->ioc_inlbuf4) {
2009 obd->ioc_inlbuf4 = ptr;
2010 LOGL(data->ioc_inlbuf4, data->ioc_inllen4, ptr);
2013 if ( cmd != (ULONG)OBD_IOC_BRW_WRITE &&
2014 cmd != (ULONG)OBD_IOC_BRW_READ ) {
2016 if (data->ioc_pbuf1 && data->ioc_plen1) {
2017 obd->ioc_pbuf1 = &procdat[length];
2018 memcpy(obd->ioc_pbuf1, data->ioc_pbuf1, data->ioc_plen1);
2019 length += size_round(data->ioc_plen1);
2022 if (data->ioc_pbuf2 && data->ioc_plen2) {
2023 obd->ioc_pbuf2 = &procdat[length];
2024 memcpy(obd->ioc_pbuf2, data->ioc_pbuf2, data->ioc_plen2);
2025 length += size_round(data->ioc_plen2);
2029 if (obd_ioctl_is_invalid(obd)) {
2030 cfs_enter_debugger();
2034 status = NtDeviceIoControlFile(
2036 NULL, NULL, NULL, &iosb,
2042 if (NT_SUCCESS(status)) {
2043 memcpy(buffer, &procdat[sizeof(CFS_PROC_IOCTL)], procctl.len);
2052 return cfs_error_code(status);
2055 #endif /* __KERNEL__ */