Whamcloud - gitweb
Merge b_md into HEAD
[fs/lustre-release.git] / lustre / obdclass / lprocfs_status.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5  *   Author: Hariharan Thantry <thantry@users.sourceforge.net>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #define EXPORT_SYMTAB
24 #include <linux/config.h>
25 #include <linux/module.h>
26 #include <linux/version.h>
27 #include <linux/slab.h>
28 #include <linux/types.h>
29
30 #define DEBUG_SUBSYSTEM S_CLASS
31 #include <linux/obd_class.h>
32 #include <linux/lprocfs_status.h>
33
34 #ifdef LPROCFS
35
36 struct proc_dir_entry *lprocfs_srch(struct proc_dir_entry *head,
37                                     const char *name)
38 {
39         struct proc_dir_entry* temp;
40
41         if (!head)
42                 return NULL;
43
44         temp = head->subdir;
45         while (temp != NULL) {
46                 if (!strcmp(temp->name, name))
47                         return temp;
48
49                 temp = temp->next;
50         }
51         return NULL;
52 }
53
54 /* lprocfs API calls */
55
56 int lprocfs_add_vars(struct proc_dir_entry *root, struct lprocfs_vars *list,
57                      void *data)
58 {
59         if ((root == NULL) || (list == NULL))
60                 return -EINVAL;
61
62         while (list->name) {
63                 struct proc_dir_entry *cur_root, *proc;
64                 char *pathcopy, *cur, *next;
65                 int pathsize = strlen(list->name)+1;
66
67                 proc = NULL;
68                 cur_root = root;
69
70                 /* need copy of path for strsep */
71                 OBD_ALLOC(pathcopy, pathsize);
72                 if (!pathcopy)
73                         return -ENOMEM;
74
75                 next = pathcopy;
76                 strcpy(pathcopy, list->name);
77
78                 while (cur_root && (cur = strsep(&next, "/"))) {
79                         if (*cur =='\0') /* skip double/trailing "/" */
80                                 continue;
81
82                         proc = lprocfs_srch(cur_root, cur);
83                         CDEBUG(D_OTHER, "cur_root=%s, cur=%s, next=%s, (%s)\n",
84                                cur_root->name, cur, next,
85                                (proc ? "exists" : "new"));
86                         if (next)
87                                 cur_root = (proc ? proc :
88                                                    proc_mkdir(cur, cur_root));
89                         else if (!proc)
90                                 proc = create_proc_entry(cur, 0444, cur_root);
91                 }
92
93                 OBD_FREE(pathcopy, pathsize);
94
95                 if ((cur_root==NULL) || (proc==NULL)) {
96                         CERROR("LprocFS: No memory to create /proc entry %s",
97                                list->name);
98                         return -ENOMEM;
99                 }
100
101                 proc->read_proc = list->read_fptr;
102                 proc->write_proc = list->write_fptr;
103                 proc->data = (list->data ? list->data : data);
104                 list++;
105         }
106         return 0;
107 }
108
109 void lprocfs_remove(struct proc_dir_entry* root)
110 {
111         struct proc_dir_entry *temp = root;
112         struct proc_dir_entry *rm_entry;
113         struct proc_dir_entry *parent = root->parent;
114
115         while (1) {
116                 while (temp->subdir)
117                         temp = temp->subdir;
118
119                 rm_entry = temp;
120                 temp = temp->parent;
121                 remove_proc_entry(rm_entry->name, rm_entry->parent);
122                 if (temp == parent)
123                         break;
124         }
125 }
126
127 struct proc_dir_entry *lprocfs_register(const char *name,
128                                         struct proc_dir_entry *parent,
129                                         struct lprocfs_vars *list, void *data)
130 {
131         struct proc_dir_entry *newchild;
132
133         newchild = lprocfs_srch(parent, name);
134         if (newchild) {
135                 CERROR(" Lproc: Attempting to register %s more than once \n",
136                                 name);
137                 return NULL;
138         }
139
140         newchild = proc_mkdir(name, parent);
141         if (newchild && list) {
142                 int rc = lprocfs_add_vars(newchild, list, data);
143                 if (rc) {
144                         lprocfs_remove(newchild);
145                         return ERR_PTR(rc);
146                 }
147         }
148         return newchild;
149 }
150
151 /* Generic callbacks */
152
153 int lprocfs_rd_u64(char *page, char **start, off_t off,
154                    int count, int *eof, void *data)
155 {
156         *eof = 1;
157         return snprintf(page, count, LPU64"\n", *(__u64 *)data);
158 }
159
160 int lprocfs_rd_uuid(char* page, char **start, off_t off, int count,
161                     int *eof, void *data)
162 {
163         struct obd_device* dev = (struct obd_device*)data;
164
165         *eof = 1;
166         return snprintf(page, count, "%s\n", dev->obd_uuid.uuid);
167 }
168
169 int lprocfs_rd_name(char *page, char **start, off_t off, int count,
170                     int *eof, void *data)
171 {
172         struct obd_device* dev = (struct obd_device *)data;
173
174         *eof = 1;
175         return snprintf(page, count, "%s\n", dev->obd_name);
176 }
177
178 int lprocfs_rd_blksize(char* page, char **start, off_t off, int count,
179                        int *eof, struct statfs *sfs)
180 {
181         *eof = 1;
182
183         return snprintf(page, count, "%lu\n", sfs->f_bsize);
184 }
185
186 int lprocfs_rd_kbytestotal(char* page, char **start, off_t off, int count,
187                            int *eof, struct statfs *sfs)
188 {
189         __u32 blk_size = sfs->f_bsize >> 10;
190         __u64 result = sfs->f_blocks;
191
192         while (blk_size >>= 1)
193                 result <<= 1;
194
195         *eof = 1;
196         return snprintf(page, count, LPU64"\n", result);
197 }
198
199 int lprocfs_rd_kbytesfree(char* page, char **start, off_t off, int count,
200                           int *eof, struct statfs *sfs)
201 {
202         __u32 blk_size = sfs->f_bsize >> 10;
203         __u64 result = sfs->f_bfree;
204
205         while (blk_size >>= 1)
206                 result <<= 1;
207
208         *eof = 1;
209         return snprintf(page, count, LPU64"\n", result);
210 }
211
212 int lprocfs_rd_filestotal(char* page, char **start, off_t off, int count,
213                           int *eof, struct statfs *sfs)
214 {
215         *eof = 1;
216         return snprintf(page, count, "%ld\n", sfs->f_files);
217 }
218
219 int lprocfs_rd_filesfree(char* page, char **start, off_t off, int count,
220                          int *eof, struct statfs *sfs)
221 {
222         *eof = 1;
223         return snprintf(page, count, "%ld\n", sfs->f_ffree);
224 }
225
226 int lprocfs_rd_filegroups(char* page, char **start, off_t off, int count,
227                           int *eof, struct statfs *sfs)
228 {
229         *eof = 1;
230         return snprintf(page, count, "unimplemented\n");
231 }
232
233 int lprocfs_rd_server_uuid(char* page, char **start, off_t off, int count,
234                            int *eof, void *data)
235 {
236         struct obd_device* obd = (struct obd_device*)data;
237         struct client_obd* cli = &obd->u.cli;
238         return snprintf(page, count, "%s\n", cli->cl_target_uuid.uuid);
239 }
240
241 int lprocfs_rd_conn_uuid(char *page, char **start, off_t off, int count,
242                          int *eof,  void *data)
243 {
244         struct obd_device *obd = (struct obd_device*)data;
245         struct ptlrpc_connection *conn = obd->u.cli.cl_import.imp_connection;
246
247         *eof = 1;
248         return snprintf(page, count, "%s\n", conn->c_remote_uuid.uuid);
249 }
250
251 int lprocfs_rd_numrefs(char *page, char **start, off_t off, int count,
252                        int *eof, void *data)
253 {
254         struct obd_type* class = (struct obd_type*) data;
255
256         *eof = 1;
257         return snprintf(page, count, "%d\n", class->typ_refcnt);
258 }
259
260 int lprocfs_obd_attach(struct obd_device *dev, struct lprocfs_vars *list)
261 {
262         int rc = 0;
263         dev->obd_proc_entry = lprocfs_register(dev->obd_name,
264                                                dev->obd_type->typ_procroot,
265                                                list, dev);
266         if (IS_ERR(dev->obd_proc_entry)) {
267                 rc = PTR_ERR(dev->obd_proc_entry);
268                dev->obd_proc_entry = NULL;
269         }
270         return rc;
271 }
272
273 int lprocfs_obd_detach(struct obd_device *dev)
274 {
275         if (dev && dev->obd_proc_entry) {
276                 lprocfs_remove(dev->obd_proc_entry);
277                 dev->obd_proc_entry = NULL;
278         }
279         return 0;
280 }
281
282 #endif /* LPROCFS*/
283
284 EXPORT_SYMBOL(lprocfs_register);
285 EXPORT_SYMBOL(lprocfs_remove);
286 EXPORT_SYMBOL(lprocfs_add_vars);
287 EXPORT_SYMBOL(lprocfs_obd_attach);
288 EXPORT_SYMBOL(lprocfs_obd_detach);
289
290 EXPORT_SYMBOL(lprocfs_rd_u64);
291 EXPORT_SYMBOL(lprocfs_rd_uuid);
292 EXPORT_SYMBOL(lprocfs_rd_name);
293 EXPORT_SYMBOL(lprocfs_rd_server_uuid);
294 EXPORT_SYMBOL(lprocfs_rd_conn_uuid);
295 EXPORT_SYMBOL(lprocfs_rd_numrefs);
296
297 EXPORT_SYMBOL(lprocfs_rd_blksize);
298 EXPORT_SYMBOL(lprocfs_rd_kbytestotal);
299 EXPORT_SYMBOL(lprocfs_rd_kbytesfree);
300 EXPORT_SYMBOL(lprocfs_rd_filestotal);
301 EXPORT_SYMBOL(lprocfs_rd_filesfree);
302 EXPORT_SYMBOL(lprocfs_rd_filegroups);