91eff5755b7ac798bd647b17b5bd788b1f51bbb3
[dragonfly.git] / usr.sbin / dschedctl / dschedctl.c
1 /*
2  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #include <sys/types.h>
36 #include <sys/cdefs.h>
37 #include <sys/syslimits.h>
38 #include <sys/ioctl.h>
39 #include <sys/device.h>
40 #include <sys/queue.h>
41 #include <sys/stat.h>
42 #include <sys/dsched.h>
43
44 #include <err.h>
45 #include <fcntl.h>
46 #include <libgen.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #define DSCHED_FOREACH_DISK(dev_fd, diocp)              \
53         for ((diocp)->num_elem = 0;                     \
54              (ioctl((dev_fd),                           \
55                  DSCHED_LIST_DISKS, (diocp)) != -1);    \
56              ++(diocp)->num_elem)
57
58 #define DSCHED_FOREACH_POLICY(dev_fd, diocp)            \
59         for ((diocp)->num_elem = 0;                     \
60              (ioctl((dev_fd),                           \
61                  DSCHED_LIST_POLICIES, (diocp)) != -1); \
62              ++(diocp)->num_elem)
63
64 static int dev_fd;
65 static int verbose = 0;
66
67 static void
68 usage(void)
69 {
70         fprintf(stderr,
71             "Usage: dschedctl <commands>\n"
72             "Valid commands are:\n"
73             " -l [disk]\n"
74             "\t Lists all disks and their policies, or just for [disk]\n"
75             " -p\n"
76             "\t Lists all available I/O scheduling policies\n"
77             " -s <policy> [disk]\n"
78             "\t Switches the policy of [disk] or otherwise all disks to "
79             "<policy>\n");
80
81         exit(1);
82 }
83
84 static int
85 dsched_ioctl(unsigned long cmd, struct dsched_ioctl *pdioc)
86 {
87         if (ioctl(dev_fd, cmd, pdioc) == -1)
88                 err(1, "ioctl");
89
90         return 0;
91 }
92
93 static int
94 dsched_set_disk_policy(char *disk_name, char *policy)
95 {
96         struct dsched_ioctl     dioc;
97         int error;
98
99         bzero(&dioc, sizeof(dioc));
100         strncpy(dioc.dev_name, disk_name, DSCHED_NAME_LENGTH);
101         strncpy(dioc.pol_name, policy, DSCHED_NAME_LENGTH);
102         error = dsched_ioctl(DSCHED_SET_DEVICE_POLICY, &dioc);
103
104         if ((!error) && verbose) {
105                 printf("Switched scheduler policy of %s successfully to %s\n",
106                     disk_name, policy);
107         }
108
109         return error;
110 }
111
112 int
113 main(int argc, char *argv[])
114 {
115         struct dsched_ioctl     dioc;
116         char    *disk_name = NULL;
117         char    *policy = NULL;
118         int     dflag = 0, lflag = 0, pflag = 0, sflag = 0;
119         int     ch, error = 0, found;
120
121         while ((ch = getopt(argc, argv, "hlps:v")) != -1) {
122                 switch (ch) {
123                 case 'l':
124                         lflag = 1;
125                         break;
126                 case 'p':
127                         pflag = 1;
128                         break;
129                 case 's':
130                         sflag = 1;
131                         policy = optarg;
132                         break;
133                 case 'v':
134                         verbose = 1;
135                         break;
136                 case 'h':
137                 case '?':
138                 default:
139                         usage();
140                         /* NOT REACHED */
141                 }
142         }
143
144         argc -= optind;
145         argv += optind;
146
147         if (argc == 1) {
148                 dflag = 1;
149                 disk_name = basename(argv[0]);
150                 if (!disk_name)
151                         err(1, "basename");
152         } else if (argc > 1) {
153                 usage();
154                 /* NOT REACHED */
155         }
156
157         /*
158          * Check arguments:
159          * - need to use at least one mode
160          */
161         if (!(lflag || pflag || sflag)) {
162                 usage();
163                 /* NOT REACHED */
164         }
165
166         dev_fd = open("/dev/dsched", O_RDWR);
167         if (dev_fd == -1)
168                 err(1, "open(/dev/dsched)");
169
170         if (lflag) {
171                 if (dflag) {
172                         strncpy(dioc.dev_name, disk_name, DSCHED_NAME_LENGTH);
173                         error = dsched_ioctl(DSCHED_LIST_DISK, &dioc);
174                         if (!error) {
175                                 printf("%s\t=>\t%s\n",
176                                     disk_name, dioc.pol_name);
177                         }
178                 } else {
179                         DSCHED_FOREACH_DISK(dev_fd, &dioc) {
180                                 printf("%s\t=>\t%s\n",
181                                     dioc.dev_name, dioc.pol_name);
182                         }
183                 }
184         }
185
186         if (pflag) {
187                 DSCHED_FOREACH_POLICY(dev_fd, &dioc) {
188                         printf("%s\n", dioc.pol_name);
189                 }
190         }
191
192         if (sflag) {
193                 found = 0;
194                 DSCHED_FOREACH_POLICY(dev_fd, &dioc) {
195                         if (strcmp(policy, dioc.pol_name) == 0) {
196                                 found = 1;
197                                 break;
198                         }
199                 }
200                 if (!found)
201                         errx(1, "Policy '%s' not available", policy);
202
203                 if (dflag) {
204                         error = dsched_set_disk_policy(disk_name, policy);
205                 } else {
206                         DSCHED_FOREACH_DISK(dev_fd, &dioc) {
207                                 error = dsched_set_disk_policy(dioc.dev_name,
208                                     policy);
209                         }
210                 }
211         }
212
213         close(dev_fd);
214
215         return (error);
216 }