vsched.c (10449B)
1 // $Id$ --*- c -*-- 2 3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de> 4 // Copyright (C) 2006 Daniel Hokka Zakrisson <daniel@hozac.com> 5 // 6 // This program is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; version 2 of the License. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 20 #ifdef HAVE_CONFIG_H 21 # include <config.h> 22 #endif 23 24 #include "util.h" 25 #include "vserver.h" 26 27 #include <errno.h> 28 #include <unistd.h> 29 #include <getopt.h> 30 #include <libgen.h> 31 #include <dirent.h> 32 #include <fcntl.h> 33 #include <sys/stat.h> 34 #include <stddef.h> 35 36 #define ENSC_WRAPPERS_PREFIX "vsched: " 37 #define ENSC_WRAPPERS_VSERVER 1 38 #define ENSC_WRAPPERS_UNISTD 1 39 #define ENSC_WRAPPERS_FCNTL 1 40 #define ENSC_WRAPPERS_DIRENT 1 41 #define ENSC_WRAPPERS_STAT 1 42 #include <wrappers.h> 43 44 #define CMD_HELP 0x1000 45 #define CMD_VERSION 0x1001 46 #define CMD_XID 0x4000 47 #define CMD_FRATE 0x4001 48 #define CMD_INTERVAL 0x4002 49 #define CMD_TOKENS 0x4003 50 #define CMD_TOK_MIN 0x4004 51 #define CMD_TOK_MAX 0x4005 52 #define CMD_CPU_MASK 0x4006 53 #define CMD_PRIO_BIAS 0x4007 54 #define CMD_FRATE2 0x4008 55 #define CMD_INTERVAL2 0x4009 56 #define CMD_CPUID 0x400a 57 #define CMD_BUCKETID 0x400b 58 #define CMD_FORCE 0x400c 59 #define CMD_IDLE_TIME 0x400d 60 #define CMD_DIR 0x400e 61 #define CMD_MISSING 0x400f 62 63 int wrapper_exit_code = 255; 64 65 struct option const 66 CMDLINE_OPTIONS[] = { 67 { "help", no_argument, 0, CMD_HELP }, 68 { "version", no_argument, 0, CMD_VERSION }, 69 { "ctx", required_argument, 0, CMD_XID }, 70 { "xid", required_argument, 0, CMD_XID }, 71 { "fill-rate", required_argument, 0, CMD_FRATE }, 72 { "interval", required_argument, 0, CMD_INTERVAL }, 73 { "tokens", required_argument, 0, CMD_TOKENS }, 74 { "tokens_min", required_argument, 0, CMD_TOK_MIN }, 75 { "tokens-min", required_argument, 0, CMD_TOK_MIN }, 76 { "tokens_max", required_argument, 0, CMD_TOK_MAX }, 77 { "tokens-max", required_argument, 0, CMD_TOK_MAX }, 78 { "prio_bias", required_argument, 0, CMD_PRIO_BIAS }, 79 { "prio-bias", required_argument, 0, CMD_PRIO_BIAS }, 80 { "priority_bias", required_argument, 0, CMD_PRIO_BIAS }, 81 { "priority-bias", required_argument, 0, CMD_PRIO_BIAS }, 82 { "cpu_mask", required_argument, 0, CMD_CPU_MASK }, 83 { "fill-rate2", required_argument, 0, CMD_FRATE2 }, 84 { "interval2", required_argument, 0, CMD_INTERVAL2 }, 85 { "cpu-id", required_argument, 0, CMD_CPUID }, 86 { "bucket-id", required_argument, 0, CMD_BUCKETID }, 87 { "force", no_argument, 0, CMD_FORCE }, 88 { "idle-time", no_argument, 0, CMD_IDLE_TIME }, 89 { "dir", required_argument, 0, CMD_DIR }, 90 { "missingok", no_argument, 0, CMD_MISSING }, 91 {0,0,0,0} 92 }; 93 94 struct sched_opt { 95 const char * const name; 96 uint_least32_t mask; 97 size_t offset; 98 }; 99 #define FOPT(NAME,MASK,FIELD) { #NAME, MASK, offsetof(struct vc_set_sched, FIELD) } 100 static struct sched_opt FILE_OPTIONS[] = { 101 FOPT(fill-rate, VC_VXSM_FILL_RATE, fill_rate), 102 FOPT(interval, VC_VXSM_INTERVAL, interval), 103 FOPT(tokens, VC_VXSM_TOKENS, tokens), 104 FOPT(tokens-min, VC_VXSM_TOKENS_MIN, tokens_min), 105 FOPT(tokens-max, VC_VXSM_TOKENS_MAX, tokens_max), 106 FOPT(prio-bias, VC_VXSM_PRIO_BIAS, priority_bias), 107 FOPT(priority-bias, VC_VXSM_PRIO_BIAS, priority_bias), 108 FOPT(fill-rate2, VC_VXSM_FILL_RATE2|VC_VXSM_IDLE_TIME, fill_rate2), 109 FOPT(interval2, VC_VXSM_INTERVAL2|VC_VXSM_IDLE_TIME, interval2), 110 FOPT(cpu-id, VC_VXSM_CPU_ID, cpu_id), 111 FOPT(bucket-id, VC_VXSM_BUCKET_ID, bucket_id), 112 FOPT(idle-time, VC_VXSM_IDLE_TIME, set_mask), 113 {0,0,0} 114 }; 115 116 static void 117 showHelp(int fd, char const *cmd, int res) 118 { 119 VSERVER_DECLARE_CMD(cmd); 120 121 WRITE_MSG(fd, "Usage:\n "); 122 WRITE_STR(fd, cmd); 123 WRITE_MSG(fd, 124 " [--xid <xid>] <sched options>* [--dir <dir>] [--] [<command> <args>*]\n" 125 "\n" 126 "Options:\n" 127 " --fill-rate <rate>\n" 128 " --interval <interval>\n" 129 " --tokens <tokens>\n" 130 " --tokens-min <tokens>\n" 131 " --tokens-max <tokens>\n" 132 " --prio-bias <bias>\n" 133 " --fill-rate2 <rate>\n" 134 " --interval2 <interval>\n" 135 " --cpu-id <CPU id>\n" 136 " --bucket-id <bucket id>\n" 137 " --idle-time ... set the idle time flag; this is required for\n" 138 " all updates to the scheduler to keep it enabled\n" 139 " --force ... force update of all per-CPU schedulers now\n" 140 " --dir <dir> ... read settings from <dir>\n" 141 " --missingok ... do not fail when <dir> does not exist\n" 142 "\nPlease report bugs to " PACKAGE_BUGREPORT "\n"); 143 144 exit(res); 145 } 146 147 static void 148 showVersion() 149 { 150 WRITE_MSG(1, 151 "vsched " VERSION " -- modifies scheduling parameters\n" 152 "This program is part of " PACKAGE_STRING "\n\n" 153 "Copyright (C) 2003,2004 Enrico Scholz\n" 154 "Copyright (C) 2006 Daniel Hokka Zakrisson\n" 155 VERSION_COPYRIGHT_DISCLAIMER); 156 exit(0); 157 } 158 159 static void do_dir_entry(struct vc_set_sched *sched, const char *name) 160 { 161 struct sched_opt *opt; 162 163 for (opt = FILE_OPTIONS; opt->name != 0; opt++) { 164 if (strcmp(name, opt->name) == 0) 165 break; 166 } 167 if (opt->name == 0) 168 return; 169 170 if (opt->offset != offsetof(struct vc_set_sched, set_mask)) { 171 int fd; 172 char buf[128], *newline; 173 signed long val; 174 ssize_t len; 175 176 fd = Eopen(name, O_RDONLY, 0); 177 len = Eread(fd, buf, sizeof(buf)-1); 178 Eclose(fd); 179 buf[len] = '\0'; 180 if ((newline=strchr(buf, '\n')) != NULL) 181 *newline = '\0'; 182 183 if (!isNumber(buf, &val, true)) { 184 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX); 185 WRITE_STR(2, name); 186 WRITE_MSG(2, ": is not an integer\n"); 187 exit(1); 188 } 189 190 *(int_least32_t *)(((char *)sched)+opt->offset) = (int_least32_t) val; 191 } 192 193 sched->set_mask |= opt->mask; 194 } 195 196 static void do_dir(xid_t xid, struct vc_set_sched *sched, const char *dir, int missing_ok, int per_cpu) 197 { 198 DIR *dp; 199 struct dirent *de; 200 int cur_fd = Eopen(".", O_RDONLY, 0); 201 struct stat st; 202 203 if (chdir(dir)!=-1) { 204 dp = Eopendir("."); 205 while ((de = Ereaddir(dp)) != NULL) { 206 if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) 207 continue; 208 Estat(de->d_name, &st); 209 if (S_ISDIR(st.st_mode)) 210 continue; 211 do_dir_entry(sched, de->d_name); 212 } 213 214 /* set the values now */ 215 if (vc_set_sched(xid, sched) == -1) { 216 perror(ENSC_WRAPPERS_PREFIX "vc_set_sched()"); 217 exit(1); 218 } 219 220 if (!per_cpu) { 221 struct vc_set_sched per_cpu_sched; 222 223 rewinddir(dp); 224 while ((de = Ereaddir(dp)) != NULL) { 225 if (de->d_name[0] == '.' && (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))) 226 continue; 227 Estat(de->d_name, &st); 228 if (S_ISDIR(st.st_mode)) { 229 per_cpu_sched.set_mask = sched->set_mask & (VC_VXSM_IDLE_TIME|VC_VXSM_FORCE); 230 do_dir(xid, &per_cpu_sched, de->d_name, 0, 1); 231 } 232 } 233 } 234 235 Eclosedir(dp); 236 } 237 else if (!missing_ok) { 238 perror(ENSC_WRAPPERS_PREFIX "chdir()"); 239 exit(wrapper_exit_code); 240 } 241 242 Efchdir(cur_fd); 243 } 244 245 #define SETVAL(ATTR,MASK) \ 246 if (!isNumber(optarg, &tmp, false)) { \ 247 WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "non-integer value specified for '--" #ATTR "'\n"); \ 248 exit(wrapper_exit_code); \ 249 } \ 250 else { \ 251 sched.ATTR = tmp; \ 252 sched.set_mask |= MASK; \ 253 } 254 255 int main(int argc, char *argv[]) 256 { 257 xid_t xid = VC_NOCTX; 258 signed long tmp; 259 struct vc_set_sched sched = { 260 .set_mask = 0 261 }; 262 const char *dir = NULL; 263 int missing_ok = 0; 264 265 while (1) { 266 int c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0); 267 if (c==-1) break; 268 269 switch (c) { 270 case CMD_HELP : showHelp(1, argv[0], 0); 271 case CMD_VERSION : showVersion(); 272 case CMD_XID : xid = Evc_xidopt2xid(optarg,true); break; 273 case CMD_FRATE : SETVAL(fill_rate, VC_VXSM_FILL_RATE); break; 274 case CMD_INTERVAL : SETVAL(interval, VC_VXSM_INTERVAL); break; 275 case CMD_TOKENS : SETVAL(tokens, VC_VXSM_TOKENS); break; 276 case CMD_TOK_MIN : SETVAL(tokens_min, VC_VXSM_TOKENS_MIN); break; 277 case CMD_TOK_MAX : SETVAL(tokens_max, VC_VXSM_TOKENS_MAX); break; 278 case CMD_PRIO_BIAS: SETVAL(priority_bias, VC_VXSM_PRIO_BIAS); break; 279 case CMD_CPU_MASK : 280 WRITE_MSG(2, "vsched: WARNING: the '--cpu_mask' parameter is deprecated and will not have any effect\n"); 281 break; 282 case CMD_FRATE2 : SETVAL(fill_rate2, VC_VXSM_FILL_RATE2); break; 283 case CMD_INTERVAL2: SETVAL(interval2, VC_VXSM_INTERVAL2); break; 284 case CMD_CPUID : SETVAL(cpu_id, VC_VXSM_CPU_ID); break; 285 case CMD_BUCKETID : SETVAL(bucket_id, VC_VXSM_BUCKET_ID); break; 286 case CMD_DIR : dir = optarg; break; 287 case CMD_MISSING : missing_ok = 1; break; 288 case CMD_FORCE : sched.set_mask |= VC_VXSM_FORCE; break; 289 case CMD_IDLE_TIME: sched.set_mask |= VC_VXSM_IDLE_TIME; break; 290 default : 291 WRITE_MSG(2, "Try '"); 292 WRITE_STR(2, argv[0]); 293 WRITE_MSG(2, " --help' for more information.\n"); 294 return EXIT_FAILURE; 295 break; 296 } 297 } 298 299 if (xid==VC_NOCTX && optind==argc) { 300 WRITE_MSG(2, "Without a program, '--xid' must be used; try '--help' for more information\n"); 301 exit(wrapper_exit_code); 302 } 303 304 if (sched.set_mask==0 && dir==NULL && optind==argc) { 305 WRITE_MSG(2, "Neither an option nor a program was specified; try '--help' for more information\n"); 306 exit(wrapper_exit_code); 307 } 308 309 if (xid==VC_NOCTX) 310 xid = Evc_get_task_xid(0); 311 312 if (dir) { 313 do_dir(xid, &sched, dir, missing_ok, 0); 314 } 315 else { 316 if (sched.set_mask!=0 && sched.set_mask!=VC_VXSM_FORCE && 317 vc_set_sched(xid, &sched)==-1) { 318 perror("vc_set_sched()"); 319 exit(255); 320 } 321 } 322 323 if (optind<argc) 324 EexecvpD(argv[optind],argv+optind); 325 326 return EXIT_SUCCESS; 327 }