Whamcloud - gitweb
Fix some simple errors and warnings
[fs/lustre-release.git] / lustre / utils / lctl.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Peter J. Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *   Author: Robert Read <rread@clusterfs.com> 
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25
26 #include <stdlib.h>
27 #include <sys/ioctl.h>
28 #include <fcntl.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <signal.h>
36 #define printk printf
37
38
39 #include <linux/lustre_lib.h>
40 #include <linux/lustre_idl.h>
41 #include <linux/lustre_dlm.h>
42
43 #include <unistd.h>
44 #include <sys/un.h>
45 #include <time.h>
46 #include <sys/time.h>
47 #include <netinet/in.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <asm/page.h>   /* needed for PAGE_SIZE - rread*/ 
51
52 #include "lctl.h"
53
54 #define __KERNEL__
55 #include <linux/list.h>
56 #undef __KERNEL__
57
58 int thread;
59
60 command_t cmdlist[];
61
62 static int jt_quit(int argc, char **argv) {
63         Parser_quit(argc, argv);
64         return 0;
65 }
66
67 static int jt_noop(int argc, char **argv) {
68         return 0;
69 }
70
71 command_t cmdlist[] = {
72         /* Metacommands */
73         {"--device", jt_opt_device, 0, "--device <devno> <command [args ...]>"},
74         {"--threads", jt_opt_threads, 0,
75                 "--threads <threads> <devno> <command [args ...]>"},
76
77         /* Network configuration commands */
78         {"==== network config ====", jt_noop, 0, "network config"},
79         {"network", jt_net_network, 0, "commands that follow apply to net\n"
80          "usage: network <tcp/elan/myrinet>"},       
81         {"connect", jt_net_connect, 0, "connect to a remote nid\n"
82          "usage: connect [[<hostname> <port>] | <elan id>]"},
83         {"disconnect", jt_net_disconnect, 0, "disconnect from a remote nid\n"
84          "usage: disconnect <nid>"},
85         {"mynid", jt_net_mynid, 0, "inform the socknal of the local nid. "
86          "The nid defaults to hostname for tcp networks and is automatically "
87          "setup for elan/myrinet networks.\n"
88          "usage: mynid [nid]"},
89         {"add_uuid", jt_net_add_uuid, 0, "associate a uuid with a nid\n"
90          "usage: add_uuid <uuid> <nid>"},
91         {"del_uuid", jt_net_del_uuid, 0, "delete a uuid association\n"
92          "usage: del_uuid <uuid>"},
93         {"add_route", jt_net_add_route, 0,
94          "add an entry to the routing table\n"
95          "usage: add_route <gateway> <target> [target]"},
96         {"del_route", jt_net_del_route, 0,
97          "delete an entry from the routing table\n"
98          "usage: del_route <target>"},
99         {"route_list", jt_net_route_list, 0, "print the routing table\n"
100          "usage: route_list"},
101         {"recv_mem", jt_net_recv_mem, 0, "set socket receive buffer size, "
102          "if size is omited the current size is reported.\n"
103          "usage: recv_mem [size]"},
104         {"send_mem", jt_net_send_mem, 0, "set socket send buffer size, "
105          "if size is omited the current size is reported.\n"
106          "usage: send_mem [size]"},
107         {"nagle", jt_net_nagle, 0, "enable/disable nagle, omiting the "
108          "argument will cause the current nagle setting to be reported.\n" 
109          "usage: nagle [on/off]"},       
110                 
111         /* Device selection commands */
112         {"=== device selection ===", jt_noop, 0, "device selection"},
113         {"newdev", jt_dev_newdev, 0, "create a new device\n"
114          "usage: newdev"},
115         {"uuid2dev", jt_dev_uuid2dev, 0,
116          "find a uuid and make it the current device\n"
117          "usage: uuid2dev <uuid>"},
118         {"name2dev", jt_dev_name2dev, 0,
119          "find a name and make it the current device\n"
120          "usage: name2dev <name>"},
121         {"device", jt_dev_device, 0, "set current device to devno\n"
122          "usage: device <devno>"},
123         {"device_list", jt_dev_list, 0, "show all devices\n"
124          "usage: device_list"},
125          
126         /* Device configuration commands */
127         {"==== device config =====", jt_noop, 0, "device config"},
128         {"attach", jt_dev_attach, 0, "name and type the device\n"
129          "usage: attach type [name [uuid]]"},
130         {"setup", jt_dev_setup, 0,
131          "type specific device configuration information\n"
132          "usage: setup <args...>"},
133         {"cleanup", jt_dev_cleanup, 0, "cleanup setup\n"
134          "usage: cleanup"},
135         {"detach", jt_dev_detach, 0, "un-name a device\n"
136          "usage: detach"},
137         {"lovconfig", jt_dev_lov_config, 0,
138          "write lov configuration to a mds device\n"
139          "usage: lovconfig lov-uuid stripcount stripsize pattern UUID1 [UUID2 ...]"},
140
141         /* Device operations */
142         {"=== device operations ==", jt_noop, 0, "device operations"},
143         {"probe", jt_dev_probe, 0,
144          "build a connection handle to a device.  This command is used too "
145          "suspend configuration until lctl has ensured that the mds and osc "
146          "services are available.  This is to avoid mount failures in a "
147          "rebooting cluster.\n"
148          "usage: probe [<timeout]"},
149         {"close", jt_dev_close, 0, "close the connection handle\n"
150          "usage: close"},
151         {"getattr", jt_dev_getattr, 0, "get attribute for id\n"
152          "usage: getattr <id>"},
153         {"setattr", jt_dev_setattr, 0, "set attribute for id\n"
154          "usage: setattr <id> <mode>"},
155         {"test_getattr", jt_dev_test_getattr, 0,
156          "perform count number of getattr's\n"
157          "usage: test_getattr <count> [verbose]"},
158         {"test_brw", jt_dev_test_brw, 0,
159          "perform count number of bulk read/writes\n"
160          "usage: test_brw <count> [write [verbose [pages [obdos]]]]"},
161         {"test_ldlm", jt_dev_test_ldlm, 0, "perform lock manager test\n"
162          "usage: test_ldlm"},
163
164 #if 0
165         {"create", jt_create, 0, "create [count [mode [verbose]]]"},
166         {"destroy", jt_destroy, 0, "destroy <id>"},
167         {"newconn", jt_newconn, 0, "newconn [newuuid]"},
168 #endif
169         /* Debug commands */
170         {"======== debug =========", jt_noop, 0, "debug"},
171         {"debug_lctl", jt_debug_lctl, 0,
172          "set debug status of lctl "
173          "usage: debug_kernel [file] [raw]"},
174         {"debug_kernel", jt_debug_kernel, 0,
175          "get debug buffer and dump to a file"
176          "usage: debug_kernel [file] [raw]"},
177         {"debug_file", jt_debug_file, 0,
178          "read debug buffer from input and dump to output"
179          "usage: debug_file <input> [output] [raw]"},
180         {"clear", jt_debug_clear, 0, "clear kernel debug buffer\n"
181          "usage: clear"},
182         {"mark", jt_debug_mark, 0,"insert marker text in kernel debug buffer\n"
183          "usage: mark <text>"},
184         {"filter", jt_debug_filter, 0, "filter message type\n"
185          "usage: filter <subsystem id/debug mask>"},
186         {"show", jt_debug_show, 0, "show message type\n"
187          "usage: show <subsystem id/debug mask>"},
188         {"debug_list", jt_debug_list, 0, "list subsystem and debug types\n"
189          "usage: debug_list <subs/types>"},
190         {"modules", jt_debug_modules, 0,
191          "provide gdb-friendly module information\n"
192          "usage: modules <path>"},
193         {"panic", jt_debug_panic, 0, "force the kernel to panic\n"
194          "usage: panic"},
195          
196         /* User interface commands */
197         {"======= control ========", jt_noop, 0, "control commands"},
198         {"help", Parser_help, 0, "help"},
199         {"exit", jt_quit, 0, "quit"},
200         {"quit", jt_quit, 0, "quit"},
201         { 0, 0, 0, NULL }
202 };
203
204 static void signal_server(int sig) {
205         if (sig == SIGINT) {
206                 do_disconnect("sigint", 1);
207                 exit(1);
208         } else {
209                 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
210         }
211 }
212
213 int get_verbose(const char *arg)
214 {
215         int verbose;
216
217         if (!arg || arg[0] == 'v')
218                 verbose = 1;
219         else if (arg[0] == 's' || arg[0] == 'q')
220                 verbose = 0;
221         else
222                 verbose = (int) strtoul(arg, NULL, 0);
223
224         if (verbose < 0)
225                 printf("Print status every %d seconds\n", -verbose);
226         else if (verbose == 1)
227                 printf("Print status every operation\n");
228         else if (verbose > 1)
229                 printf("Print status every %d operations\n", verbose);
230
231         return verbose;
232 }
233
234 int be_verbose(int verbose, struct timeval *next_time,
235                       int num, int *next_num, int num_total)
236 {
237         struct timeval now;
238
239         if (!verbose)
240                 return 0;
241
242         if (next_time != NULL)
243                 gettimeofday(&now, NULL);
244
245         /* A positive verbosity means to print every X iterations */
246         if (verbose > 0 &&
247             (next_num == NULL || num >= *next_num || num >= num_total)) {
248                 *next_num += verbose;
249                 if (next_time) {
250                         next_time->tv_sec = now.tv_sec - verbose;
251                         next_time->tv_usec = now.tv_usec;
252                 }
253                 return 1;
254         }
255
256         /* A negative verbosity means to print at most each X seconds */
257         if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0){
258                 next_time->tv_sec = now.tv_sec - verbose;
259                 next_time->tv_usec = now.tv_usec;
260                 if (next_num)
261                         *next_num = num;
262                 return 1;
263         }
264
265         return 0;
266 }
267
268 int jt_opt_threads(int argc, char **argv)
269 {
270         int threads, next_thread;
271         int verbose;
272         int i, j;
273         int rc = 0;
274
275         if (argc < 5) {
276                 fprintf(stderr,
277                         "usage: %s numthreads verbose devno <cmd [args ...]>\n",
278                         argv[0]);
279                 return -1;
280         }
281
282         threads = strtoul(argv[1], NULL, 0);
283
284         verbose = get_verbose(argv[2]);
285
286         printf("%s: starting %d threads on device %s running %s\n",
287                argv[0], threads, argv[3], argv[4]);
288
289         for (i = 1, next_thread = verbose; i <= threads; i++) {
290                 rc = fork();
291                 if (rc < 0) {
292                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
293                                 strerror(rc = errno));
294                         break;
295                 } else if (rc == 0) {
296                         thread = i;
297                         argv[2] = "--device";
298                         return jt_opt_device(argc - 2, argv + 2);
299                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
300                         printf("%s: thread #%d (PID %d) started\n",
301                                argv[0], i, rc);
302                 rc = 0;
303         }
304
305         if (!thread) { /* parent process */
306                 if (!verbose)
307                         printf("%s: started %d threads\n\n", argv[0], i - 1);
308                 else
309                         printf("\n");
310
311                 for (j = 1; j < i; j++) {
312                         int status;
313                         int ret = wait(&status);
314
315                         if (ret < 0) {
316                                 fprintf(stderr, "error: %s: wait - %s\n",
317                                         argv[0], strerror(errno));
318                                 if (!rc)
319                                         rc = errno;
320                         } else {
321                                 /*
322                                  * This is a hack.  We _should_ be able to use
323                                  * WIFEXITED(status) to see if there was an
324                                  * error, but it appears to be broken and it
325                                  * always returns 1 (OK).  See wait(2).
326                                  */
327                                 int err = WEXITSTATUS(status);
328                                 if (err)
329                                         fprintf(stderr,
330                                                 "%s: PID %d had rc=%d\n",
331                                                 argv[0], ret, err);
332                                 if (!rc)
333                                         rc = err;
334                         }
335                 }
336         }
337
338         return rc;
339 }
340
341 char *cmdname(char *func)
342 {
343         static char buf[512];
344         
345         if (thread) {
346                 sprintf(buf, "%s-%d", func, thread);
347                 return buf;
348         }
349
350         return func;
351 }
352
353 int main(int argc, char **argv) {
354         struct sigaction sigact;
355         int rc;
356
357         sigact.sa_handler = signal_server;
358         sigfillset(&sigact.sa_mask);
359         sigact.sa_flags = SA_RESTART;
360         sigaction(SIGINT, &sigact, NULL);
361
362         if (network_setup(argc, argv) < 0)
363                 exit(1);
364         
365         if (device_setup(argc, argv) < 0)
366                 exit(2);
367
368         if (debug_setup(argc, argv) < 0)
369                 exit(3);
370         
371         if (argc > 1) {
372                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
373         } else {
374                 Parser_init("lctl > ", cmdlist);
375                 rc = Parser_commands();
376         }
377
378         do_disconnect(argv[0], 1);
379         return rc;
380 }
381