| @@ -299,6 +299,10 @@ static __init int sched_init_debug(void) · 298 unmodified lines |
| 299 | 299 | debugfs_create_file("tunable_scaling", 0644, debugfs_sched, NULL, &sched_scaling_fops); |
| 300 | 300 | debugfs_create_u32("migration_cost_ns", 0644, debugfs_sched, &sysctl_sched_migration_cost); |
| 301 | 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 | 306 | #endif |
| 303 | 307 | |
| 304 | 308 | #ifdef CONFIG_NUMA_BALANCING |
| @@ -316,229 +320,88 @@ late_initcall(sched_init_debug); · 11 unmodified lines |
| 316 | 320 | |
| 317 | 321 | #ifdef CONFIG_SMP |
| 318 | 322 | |
| 319 | | −#ifdef CONFIG_SYSCTL |
| 320 | | − |
| 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 | | −} |
| 323 | +static cpumask_var_t sd_sysctl_cpus; |
| 324 | +static struct dentry *sd_dentry; |
| 378 | 325 | |
| 379 | | −static int sd_ctl_doflags(struct ctl_table *table, int write, |
| 380 | | − void *buffer, size_t *lenp, loff_t *ppos) |
| 326 | +static int sd_flags_show(struct seq_file *m, void *v) |
| 381 | 327 | { |
| 382 | | − unsigned long flags = *(unsigned long *)table->data; |
| 383 | | − size_t data_size = 0; |
| 384 | | − size_t len = 0; |
| 385 | | − char *tmp, *buf; |
| 328 | + unsigned long flags = *(unsigned int *)m->private; |
| 386 | 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 | 331 | for_each_set_bit(idx, &flags, __SD_FLAG_CNT) { |
| 408 | | − char *name = sd_flag_debug[idx].name; |
| 409 | | − |
| 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++; |
| 332 | + seq_puts(m, sd_flag_debug[idx].name); |
| 333 | + seq_puts(m, " "); |
| 423 | 334 | } |
| 424 | | − |
| 425 | | − *lenp = len; |
| 426 | | − *ppos += len; |
| 427 | | − |
| 428 | | − kfree(buf); |
| 335 | + seq_puts(m, "\n"); |
| 429 | 336 | |
| 430 | 337 | return 0; |
| 431 | 338 | } |
| 432 | 339 | |
| 433 | | −static struct ctl_table * |
| 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) |
| 340 | +static int sd_flags_open(struct inode *inode, struct file *file) |
| 455 | 341 | { |
| 456 | | − struct ctl_table *entry, *table; |
| 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; |
| 342 | + return single_open(file, sd_flags_show, inode->i_private); |
| 477 | 343 | } |
| 478 | 344 | |
| 479 | | −static cpumask_var_t sd_sysctl_cpus; |
| 480 | | −static struct ctl_table_header *sd_sysctl_header; |
| 345 | +static const struct file_operations sd_flags_fops = { |
| 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; |
| 485 | | − static struct ctl_table **cpu_idx; |
| 486 | | − static bool init_done = false; |
| 487 | | − char buf[32]; |
| 488 | | − int i; |
| 354 | +#define SDM(type, mode, member) \ |
| 355 | + debugfs_create_##type(#member, mode, parent, &sd->member) |
| 489 | 356 | |
| 490 | | − if (!cpu_entries) { |
| 491 | | − cpu_entries = sd_alloc_ctl_entry(num_possible_cpus() + 1); |
| 492 | | − if (!cpu_entries) |
| 493 | | − return; |
| 494 | | − |
| 495 | | − WARN_ON(sd_ctl_dir[0].child); |
| 496 | | − sd_ctl_dir[0].child = cpu_entries; |
| 497 | | − } |
| 357 | + SDM(ulong, 0644, min_interval); |
| 358 | + SDM(ulong, 0644, max_interval); |
| 359 | + SDM(u64, 0644, max_newidle_lb_cost); |
| 360 | + SDM(u32, 0644, busy_factor); |
| 361 | + SDM(u32, 0644, imbalance_pct); |
| 362 | + SDM(u32, 0644, cache_nice_tries); |
| 363 | + SDM(str, 0444, name); |
| 498 | 364 | |
| 499 | | − if (!cpu_idx) { |
| 500 | | − struct ctl_table *e = cpu_entries; |
| 365 | +#undef SDM |
| 501 | 366 | |
| 502 | | − cpu_idx = kcalloc(nr_cpu_ids, sizeof(struct ctl_table*), GFP_KERNEL); |
| 503 | | − if (!cpu_idx) |
| 504 | | − return; |
| 367 | + debugfs_create_file("flags", 0444, parent, &sd->flags, &sd_flags_fops); |
| 368 | +} |
| 505 | 369 | |
| 506 | | − /* deal with sparse possible map */ |
| 507 | | − for_each_possible_cpu(i) { |
| 508 | | − cpu_idx[i] = e; |
| 509 | | − e++; |
| 510 | | − } |
| 511 | | − } |
| 370 | +void update_sched_domain_debugfs(void) |
| 371 | +{ |
| 372 | + int cpu, i; |
| 512 | 373 | |
| 513 | 374 | if (!cpumask_available(sd_sysctl_cpus)) { |
| 514 | 375 | if (!alloc_cpumask_var(&sd_sysctl_cpus, GFP_KERNEL)) |
| 515 | 376 | return; |
| 516 | | − } |
| 517 | | − |
| 518 | | − if (!init_done) { |
| 519 | | − init_done = true; |
| 520 | | − /* init to possible to not have holes in @cpu_entries */ |
| 521 | 377 | cpumask_copy(sd_sysctl_cpus, cpu_possible_mask); |
| 522 | 378 | } |
| 523 | 379 | |
| 524 | | − for_each_cpu(i, sd_sysctl_cpus) { |
| 525 | | − struct ctl_table *e = cpu_idx[i]; |
| 380 | + if (!sd_dentry) |
| 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) |
| 528 | | − sd_free_ctl_entry(&e->child); |
| 392 | + i = 0; |
| 393 | + for_each_domain(cpu, sd) { |
| 394 | + struct dentry *d_sd; |
| 529 | 395 | |
| 530 | | − if (!e->procname) { |
| 531 | | − snprintf(buf, 32, "cpu%d", i); |
| 532 | | − e->procname = kstrdup(buf, GFP_KERNEL); |
| 396 | + snprintf(buf, sizeof(buf), "domain%d", i); |
| 397 | + d_sd = debugfs_create_dir(buf, d_cpu); |
| 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 | 407 | void dirty_sched_domain_sysctl(int cpu) |
| @@ -547,13 +410,6 @@ void dirty_sched_domain_sysctl(int cpu) · 2 unmodified lines |
| 547 | 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 | 413 | #endif /* CONFIG_SMP */ |
| 558 | 414 | |
| 559 | 415 | #ifdef CONFIG_FAIR_GROUP_SCHED |