| @@ -299,6 +299,10 @@ static __init int sched_init_debug(void) · 298 unmodified lines |
| 299 | debugfs_create_file("tunable_scaling", 0644, debugfs_sched, NULL, &sched_scaling_fops); | 299 | debugfs_create_file("tunable_scaling", 0644, debugfs_sched, NULL, &sched_scaling_fops); |
| 300 | debugfs_create_u32("migration_cost_ns", 0644, debugfs_sched, &sysctl_sched_migration_cost); | 300 | debugfs_create_u32("migration_cost_ns", 0644, debugfs_sched, &sysctl_sched_migration_cost); |
| 301 | debugfs_create_u32("nr_migrate", 0644, debugfs_sched, &sysctl_sched_nr_migrate); | 301 | debugfs_create_u32("nr_migrate", 0644, debugfs_sched, &sysctl_sched_nr_migrate); |
| | 302 | |
| | 303 | mutex_lock(&sched_domains_mutex); |
| | 304 | update_sched_domain_debugfs(); |
| | 305 | mutex_unlock(&sched_domains_mutex); |
| 302 | #endif | 306 | #endif |
| 303 | | 307 | |
| 304 | #ifdef CONFIG_NUMA_BALANCING | 308 | #ifdef CONFIG_NUMA_BALANCING |
| @@ -316,229 +320,88 @@ late_initcall(sched_init_debug); · 11 unmodified lines |
| 316 | | 320 | |
| 317 | #ifdef CONFIG_SMP | 321 | #ifdef CONFIG_SMP |
| 318 | | 322 | |
| 319 | #ifdef CONFIG_SYSCTL | 323 | static cpumask_var_t sd_sysctl_cpus; |
| 320 | | 324 | static struct dentry *sd_dentry; |
| 321 | static struct ctl_table sd_ctl_dir[] = { | | |
| 322 | { | | |
| 323 | .procname = "sched_domain", | | |
| 324 | .mode = 0555, | | |
| 325 | }, | | |
| 326 | {} | | |
| 327 | }; | | |
| 328 | | | |
| 329 | static struct ctl_table sd_ctl_root[] = { | | |
| 330 | { | | |
| 331 | .procname = "kernel", | | |
| 332 | .mode = 0555, | | |
| 333 | .child = sd_ctl_dir, | | |
| 334 | }, | | |
| 335 | {} | | |
| 336 | }; | | |
| 337 | | | |
| 338 | static struct ctl_table *sd_alloc_ctl_entry(int n) | | |
| 339 | { | | |
| 340 | struct ctl_table *entry = | | |
| 341 | kcalloc(n, sizeof(struct ctl_table), GFP_KERNEL); | | |
| 342 | | | |
| 343 | return entry; | | |
| 344 | } | | |
| 345 | | | |
| 346 | static void sd_free_ctl_entry(struct ctl_table **tablep) | | |
| 347 | { | | |
| 348 | struct ctl_table *entry; | | |
| 349 | | | |
| 350 | /* | | |
| 351 | * In the intermediate directories, both the child directory and | | |
| 352 | * procname are dynamically allocated and could fail but the mode | | |
| 353 | * will always be set. In the lowest directory the names are | | |
| 354 | * static strings and all have proc handlers. | | |
| 355 | */ | | |
| 356 | for (entry = *tablep; entry->mode; entry++) { | | |
| 357 | if (entry->child) | | |
| 358 | sd_free_ctl_entry(&entry->child); | | |
| 359 | if (entry->proc_handler == NULL) | | |
| 360 | kfree(entry->procname); | | |
| 361 | } | | |
| 362 | | | |
| 363 | kfree(*tablep); | | |
| 364 | *tablep = NULL; | | |
| 365 | } | | |
| 366 | | | |
| 367 | static void | | |
| 368 | set_table_entry(struct ctl_table *entry, | | |
| 369 | const char *procname, void *data, int maxlen, | | |
| 370 | umode_t mode, proc_handler *proc_handler) | | |
| 371 | { | | |
| 372 | entry->procname = procname; | | |
| 373 | entry->data = data; | | |
| 374 | entry->maxlen = maxlen; | | |
| 375 | entry->mode = mode; | | |
| 376 | entry->proc_handler = proc_handler; | | |
| 377 | } | | |
| 378 | | 325 | |
| 379 | static int sd_ctl_doflags(struct ctl_table *table, int write, | 326 | static int sd_flags_show(struct seq_file *m, void *v) |
| 380 | void *buffer, size_t *lenp, loff_t *ppos) | | |
| 381 | { | 327 | { |
| 382 | unsigned long flags = *(unsigned long *)table->data; | 328 | unsigned long flags = *(unsigned int *)m->private; |
| 383 | size_t data_size = 0; | | |
| 384 | size_t len = 0; | | |
| 385 | char *tmp, *buf; | | |
| 386 | int idx; | 329 | int idx; |
| 387 | | 330 | |
| 388 | if (write) | | |
| 389 | return 0; | | |
| 390 | | | |
| 391 | for_each_set_bit(idx, &flags, __SD_FLAG_CNT) { | | |
| 392 | char *name = sd_flag_debug[idx].name; | | |
| 393 | | | |
| 394 | /* Name plus whitespace */ | | |
| 395 | data_size += strlen(name) + 1; | | |
| 396 | } | | |
| 397 | | | |
| 398 | if (*ppos > data_size) { | | |
| 399 | *lenp = 0; | | |
| 400 | return 0; | | |
| 401 | } | | |
| 402 | | | |
| 403 | buf = kcalloc(data_size + 1, sizeof(*buf), GFP_KERNEL); | | |
| 404 | if (!buf) | | |
| 405 | return -ENOMEM; | | |
| 406 | | | |
| 407 | for_each_set_bit(idx, &flags, __SD_FLAG_CNT) { | 331 | for_each_set_bit(idx, &flags, __SD_FLAG_CNT) { |
| 408 | char *name = sd_flag_debug[idx].name; | 332 | seq_puts(m, sd_flag_debug[idx].name); |
| 409 | | 333 | seq_puts(m, " "); |
| 410 | len += snprintf(buf + len, strlen(name) + 2, "%s ", name); | | |
| 411 | } | | |
| 412 | | | |
| 413 | tmp = buf + *ppos; | | |
| 414 | len -= *ppos; | | |
| 415 | | | |
| 416 | if (len > *lenp) | | |
| 417 | len = *lenp; | | |
| 418 | if (len) | | |
| 419 | memcpy(buffer, tmp, len); | | |
| 420 | if (len < *lenp) { | | |
| 421 | ((char *)buffer)[len] = '\n'; | | |
| 422 | len++; | | |
| 423 | } | 334 | } |
| 424 | | 335 | seq_puts(m, "\n"); |
| 425 | *lenp = len; | | |
| 426 | *ppos += len; | | |
| 427 | | | |
| 428 | kfree(buf); | | |
| 429 | | 336 | |
| 430 | return 0; | 337 | return 0; |
| 431 | } | 338 | } |
| 432 | | 339 | |
| 433 | static struct ctl_table * | 340 | static int sd_flags_open(struct inode *inode, struct file *file) |
| 434 | sd_alloc_ctl_domain_table(struct sched_domain *sd) | | |
| 435 | { | | |
| 436 | struct ctl_table *table = sd_alloc_ctl_entry(9); | | |
| 437 | | | |
| 438 | if (table == NULL) | | |
| 439 | return NULL; | | |
| 440 | | | |
| 441 | set_table_entry(&table[0], "min_interval", &sd->min_interval, sizeof(long), 0644, proc_doulongvec_minmax); | | |
| 442 | set_table_entry(&table[1], "max_interval", &sd->max_interval, sizeof(long), 0644, proc_doulongvec_minmax); | | |
| 443 | set_table_entry(&table[2], "busy_factor", &sd->busy_factor, sizeof(int), 0644, proc_dointvec_minmax); | | |
| 444 | set_table_entry(&table[3], "imbalance_pct", &sd->imbalance_pct, sizeof(int), 0644, proc_dointvec_minmax); | | |
| 445 | set_table_entry(&table[4], "cache_nice_tries", &sd->cache_nice_tries, sizeof(int), 0644, proc_dointvec_minmax); | | |
| 446 | set_table_entry(&table[5], "flags", &sd->flags, sizeof(int), 0444, sd_ctl_doflags); | | |
| 447 | set_table_entry(&table[6], "max_newidle_lb_cost", &sd->max_newidle_lb_cost, sizeof(long), 0644, proc_doulongvec_minmax); | | |
| 448 | set_table_entry(&table[7], "name", sd->name, CORENAME_MAX_SIZE, 0444, proc_dostring); | | |
| 449 | /* &table[8] is terminator */ | | |
| 450 | | | |
| 451 | return table; | | |
| 452 | } | | |
| 453 | | | |
| 454 | static struct ctl_table *sd_alloc_ctl_cpu_table(int cpu) | | |
| 455 | { | 341 | { |
| 456 | struct ctl_table *entry, *table; | 342 | return single_open(file, sd_flags_show, inode->i_private); |
| 457 | struct sched_domain *sd; | | |
| 458 | int domain_num = 0, i; | | |
| 459 | char buf[32]; | | |
| 460 | | | |
| 461 | for_each_domain(cpu, sd) | | |
| 462 | domain_num++; | | |
| 463 | entry = table = sd_alloc_ctl_entry(domain_num + 1); | | |
| 464 | if (table == NULL) | | |
| 465 | return NULL; | | |
| 466 | | | |
| 467 | i = 0; | | |
| 468 | for_each_domain(cpu, sd) { | | |
| 469 | snprintf(buf, 32, "domain%d", i); | | |
| 470 | entry->procname = kstrdup(buf, GFP_KERNEL); | | |
| 471 | entry->mode = 0555; | | |
| 472 | entry->child = sd_alloc_ctl_domain_table(sd); | | |
| 473 | entry++; | | |
| 474 | i++; | | |
| 475 | } | | |
| 476 | return table; | | |
| 477 | } | 343 | } |
| 478 | | 344 | |
| 479 | static cpumask_var_t sd_sysctl_cpus; | 345 | static const struct file_operations sd_flags_fops = { |
| 480 | static struct ctl_table_header *sd_sysctl_header; | 346 | .open = sd_flags_open, |
| | 347 | .read = seq_read, |
| | 348 | .llseek = seq_lseek, |
| | 349 | .release = single_release, |
| | 350 | }; |
| 481 | | 351 | |
| 482 | void register_sched_domain_sysctl(void) | 352 | static void register_sd(struct sched_domain *sd, struct dentry *parent) |
| 483 | { | 353 | { |
| 484 | static struct ctl_table *cpu_entries; | 354 | #define SDM(type, mode, member) \ |
| 485 | static struct ctl_table **cpu_idx; | 355 | debugfs_create_##type(#member, mode, parent, &sd->member) |
| 486 | static bool init_done = false; | | |
| 487 | char buf[32]; | | |
| 488 | int i; | | |
| 489 | | 356 | |
| 490 | if (!cpu_entries) { | 357 | SDM(ulong, 0644, min_interval); |
| 491 | cpu_entries = sd_alloc_ctl_entry(num_possible_cpus() + 1); | 358 | SDM(ulong, 0644, max_interval); |
| 492 | if (!cpu_entries) | 359 | SDM(u64, 0644, max_newidle_lb_cost); |
| 493 | return; | 360 | SDM(u32, 0644, busy_factor); |
| 494 | | 361 | SDM(u32, 0644, imbalance_pct); |
| 495 | WARN_ON(sd_ctl_dir[0].child); | 362 | SDM(u32, 0644, cache_nice_tries); |
| 496 | sd_ctl_dir[0].child = cpu_entries; | 363 | SDM(str, 0444, name); |
| 497 | } | | |
| 498 | | 364 | |
| 499 | if (!cpu_idx) { | 365 | #undef SDM |
| 500 | struct ctl_table *e = cpu_entries; | | |
| 501 | | 366 | |
| 502 | cpu_idx = kcalloc(nr_cpu_ids, sizeof(struct ctl_table*), GFP_KERNEL); | 367 | debugfs_create_file("flags", 0444, parent, &sd->flags, &sd_flags_fops); |
| 503 | if (!cpu_idx) | 368 | } |
| 504 | return; | | |
| 505 | | 369 | |
| 506 | /* deal with sparse possible map */ | 370 | void update_sched_domain_debugfs(void) |
| 507 | for_each_possible_cpu(i) { | 371 | { |
| 508 | cpu_idx[i] = e; | 372 | int cpu, i; |
| 509 | e++; | | |
| 510 | } | | |
| 511 | } | | |
| 512 | | 373 | |
| 513 | if (!cpumask_available(sd_sysctl_cpus)) { | 374 | if (!cpumask_available(sd_sysctl_cpus)) { |
| 514 | if (!alloc_cpumask_var(&sd_sysctl_cpus, GFP_KERNEL)) | 375 | if (!alloc_cpumask_var(&sd_sysctl_cpus, GFP_KERNEL)) |
| 515 | return; | 376 | return; |
| 516 | } | | |
| 517 | | | |
| 518 | if (!init_done) { | | |
| 519 | init_done = true; | | |
| 520 | /* init to possible to not have holes in @cpu_entries */ | | |
| 521 | cpumask_copy(sd_sysctl_cpus, cpu_possible_mask); | 377 | cpumask_copy(sd_sysctl_cpus, cpu_possible_mask); |
| 522 | } | 378 | } |
| 523 | | 379 | |
| 524 | for_each_cpu(i, sd_sysctl_cpus) { | 380 | if (!sd_dentry) |
| 525 | struct ctl_table *e = cpu_idx[i]; | 381 | sd_dentry = debugfs_create_dir("domains", debugfs_sched); |
| | 382 | |
| | 383 | for_each_cpu(cpu, sd_sysctl_cpus) { |
| | 384 | struct sched_domain *sd; |
| | 385 | struct dentry *d_cpu; |
| | 386 | char buf[32]; |
| | 387 | |
| | 388 | snprintf(buf, sizeof(buf), "cpu%d", cpu); |
| | 389 | debugfs_remove(debugfs_lookup(buf, sd_dentry)); |
| | 390 | d_cpu = debugfs_create_dir(buf, sd_dentry); |
| 526 | | 391 | |
| 527 | if (e->child) | 392 | i = 0; |
| 528 | sd_free_ctl_entry(&e->child); | 393 | for_each_domain(cpu, sd) { |
| | 394 | struct dentry *d_sd; |
| 529 | | 395 | |
| 530 | if (!e->procname) { | 396 | snprintf(buf, sizeof(buf), "domain%d", i); |
| 531 | snprintf(buf, 32, "cpu%d", i); | 397 | d_sd = debugfs_create_dir(buf, d_cpu); |
| 532 | e->procname = kstrdup(buf, GFP_KERNEL); | 398 | |
| | 399 | register_sd(sd, d_sd); |
| | 400 | i++; |
| 533 | } | 401 | } |
| 534 | e->mode = 0555; | | |
| 535 | e->child = sd_alloc_ctl_cpu_table(i); | | |
| 536 | | 402 | |
| 537 | __cpumask_clear_cpu(i, sd_sysctl_cpus); | 403 | __cpumask_clear_cpu(cpu, sd_sysctl_cpus); |
| 538 | } | 404 | } |
| 539 | | | |
| 540 | WARN_ON(sd_sysctl_header); | | |
| 541 | sd_sysctl_header = register_sysctl_table(sd_ctl_root); | | |
| 542 | } | 405 | } |
| 543 | | 406 | |
| 544 | void dirty_sched_domain_sysctl(int cpu) | 407 | void dirty_sched_domain_sysctl(int cpu) |
| @@ -547,13 +410,6 @@ void dirty_sched_domain_sysctl(int cpu) · 2 unmodified lines |
| 547 | __cpumask_set_cpu(cpu, sd_sysctl_cpus); | 410 | __cpumask_set_cpu(cpu, sd_sysctl_cpus); |
| 548 | } | 411 | } |
| 549 | | 412 | |
| 550 | /* may be called multiple times per register */ | | |
| 551 | void unregister_sched_domain_sysctl(void) | | |
| 552 | { | | |
| 553 | unregister_sysctl_table(sd_sysctl_header); | | |
| 554 | sd_sysctl_header = NULL; | | |
| 555 | } | | |
| 556 | #endif /* CONFIG_SYSCTL */ | | |
| 557 | #endif /* CONFIG_SMP */ | 413 | #endif /* CONFIG_SMP */ |
| 558 | | 414 | |
| 559 | #ifdef CONFIG_FAIR_GROUP_SCHED | 415 | #ifdef CONFIG_FAIR_GROUP_SCHED |