1# SPDX-License-Identifier: GPL-2.0 2 3import os 4 5ksft_skip=4 6 7sysfs_root = None 8with open('/proc/mounts', 'r') as f: 9 for line in f: 10 dev_name, mount_point, dev_fs = line.split()[:3] 11 if dev_fs == 'sysfs': 12 sysfs_root = '%s/kernel/mm/damon/admin' % mount_point 13 break 14if sysfs_root is None: 15 print('Seems sysfs not mounted?') 16 exit(ksft_skip) 17 18if not os.path.exists(sysfs_root): 19 print('Seems DAMON disabled?') 20 exit(ksft_skip) 21 22def write_file(path, string): 23 "Returns error string if failed, or None otherwise" 24 string = '%s' % string 25 try: 26 with open(path, 'w') as f: 27 f.write(string) 28 except Exception as e: 29 return '%s' % e 30 return None 31 32def read_file(path): 33 '''Returns the read content and error string. The read content is None if 34 the reading failed''' 35 try: 36 with open(path, 'r') as f: 37 return f.read(), None 38 except Exception as e: 39 return None, '%s' % e 40 41class DamosAccessPattern: 42 size = None 43 nr_accesses = None 44 age = None 45 scheme = None 46 47 def __init__(self, size=None, nr_accesses=None, age=None): 48 self.size = size 49 self.nr_accesses = nr_accesses 50 self.age = age 51 52 if self.size is None: 53 self.size = [0, 2**64 - 1] 54 if self.nr_accesses is None: 55 self.nr_accesses = [0, 2**32 - 1] 56 if self.age is None: 57 self.age = [0, 2**32 - 1] 58 59 def sysfs_dir(self): 60 return os.path.join(self.scheme.sysfs_dir(), 'access_pattern') 61 62 def stage(self): 63 err = write_file( 64 os.path.join(self.sysfs_dir(), 'sz', 'min'), self.size[0]) 65 if err is not None: 66 return err 67 err = write_file( 68 os.path.join(self.sysfs_dir(), 'sz', 'max'), self.size[1]) 69 if err is not None: 70 return err 71 err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'min'), 72 self.nr_accesses[0]) 73 if err is not None: 74 return err 75 err = write_file(os.path.join(self.sysfs_dir(), 'nr_accesses', 'max'), 76 self.nr_accesses[1]) 77 if err is not None: 78 return err 79 err = write_file( 80 os.path.join(self.sysfs_dir(), 'age', 'min'), self.age[0]) 81 if err is not None: 82 return err 83 err = write_file( 84 os.path.join(self.sysfs_dir(), 'age', 'max'), self.age[1]) 85 if err is not None: 86 return err 87 88qgoal_metric_user_input = 'user_input' 89qgoal_metric_some_mem_psi_us = 'some_mem_psi_us' 90qgoal_metrics = [qgoal_metric_user_input, qgoal_metric_some_mem_psi_us] 91 92class DamosQuotaGoal: 93 metric = None 94 target_value = None 95 current_value = None 96 nid = None 97 effective_bytes = None 98 quota = None # owner quota 99 idx = None 100 101 def __init__(self, metric, target_value=10000, current_value=0, nid=0): 102 self.metric = metric 103 self.target_value = target_value 104 self.current_value = current_value 105 self.nid = nid 106 107 def sysfs_dir(self): 108 return os.path.join(self.quota.sysfs_dir(), 'goals', '%d' % self.idx) 109 110 def stage(self): 111 err = write_file(os.path.join(self.sysfs_dir(), 'target_metric'), 112 self.metric) 113 if err is not None: 114 return err 115 err = write_file(os.path.join(self.sysfs_dir(), 'target_value'), 116 self.target_value) 117 if err is not None: 118 return err 119 err = write_file(os.path.join(self.sysfs_dir(), 'current_value'), 120 self.current_value) 121 if err is not None: 122 return err 123 err = write_file(os.path.join(self.sysfs_dir(), 'nid'), self.nid) 124 if err is not None: 125 return err 126 127 return None 128 129class DamosQuota: 130 sz = None # size quota, in bytes 131 ms = None # time quota 132 goals = None # quota goals 133 reset_interval_ms = None # quota reset interval 134 weight_sz_permil = None 135 weight_nr_accesses_permil = None 136 weight_age_permil = None 137 scheme = None # owner scheme 138 139 def __init__(self, sz=0, ms=0, goals=None, reset_interval_ms=0, 140 weight_sz_permil=0, weight_nr_accesses_permil=0, 141 weight_age_permil=0): 142 self.sz = sz 143 self.ms = ms 144 self.reset_interval_ms = reset_interval_ms 145 self.weight_sz_permil = weight_sz_permil 146 self.weight_nr_accesses_permil = weight_nr_accesses_permil 147 self.weight_age_permil = weight_age_permil 148 self.goals = goals if goals is not None else [] 149 for idx, goal in enumerate(self.goals): 150 goal.idx = idx 151 goal.quota = self 152 153 def sysfs_dir(self): 154 return os.path.join(self.scheme.sysfs_dir(), 'quotas') 155 156 def stage(self): 157 err = write_file(os.path.join(self.sysfs_dir(), 'bytes'), self.sz) 158 if err is not None: 159 return err 160 err = write_file(os.path.join(self.sysfs_dir(), 'ms'), self.ms) 161 if err is not None: 162 return err 163 err = write_file(os.path.join(self.sysfs_dir(), 'reset_interval_ms'), 164 self.reset_interval_ms) 165 if err is not None: 166 return err 167 168 err = write_file(os.path.join( 169 self.sysfs_dir(), 'weights', 'sz_permil'), self.weight_sz_permil) 170 if err is not None: 171 return err 172 err = write_file(os.path.join( 173 self.sysfs_dir(), 'weights', 'nr_accesses_permil'), 174 self.weight_nr_accesses_permil) 175 if err is not None: 176 return err 177 err = write_file(os.path.join( 178 self.sysfs_dir(), 'weights', 'age_permil'), self.weight_age_permil) 179 if err is not None: 180 return err 181 182 nr_goals_file = os.path.join(self.sysfs_dir(), 'goals', 'nr_goals') 183 content, err = read_file(nr_goals_file) 184 if err is not None: 185 return err 186 if int(content) != len(self.goals): 187 err = write_file(nr_goals_file, len(self.goals)) 188 if err is not None: 189 return err 190 for goal in self.goals: 191 err = goal.stage() 192 if err is not None: 193 return err 194 return None 195 196class DamosWatermarks: 197 metric = None 198 interval = None 199 high = None 200 mid = None 201 low = None 202 scheme = None # owner scheme 203 204 def __init__(self, metric='none', interval=0, high=0, mid=0, low=0): 205 self.metric = metric 206 self.interval = interval 207 self.high = high 208 self.mid = mid 209 self.low = low 210 211 def sysfs_dir(self): 212 return os.path.join(self.scheme.sysfs_dir(), 'watermarks') 213 214 def stage(self): 215 err = write_file(os.path.join(self.sysfs_dir(), 'metric'), self.metric) 216 if err is not None: 217 return err 218 err = write_file(os.path.join(self.sysfs_dir(), 'interval_us'), 219 self.interval) 220 if err is not None: 221 return err 222 err = write_file(os.path.join(self.sysfs_dir(), 'high'), self.high) 223 if err is not None: 224 return err 225 err = write_file(os.path.join(self.sysfs_dir(), 'mid'), self.mid) 226 if err is not None: 227 return err 228 err = write_file(os.path.join(self.sysfs_dir(), 'low'), self.low) 229 if err is not None: 230 return err 231 232class DamosFilter: 233 type_ = None 234 matching = None 235 allow = None 236 memcg_path = None 237 addr_start = None 238 addr_end = None 239 target_idx = None 240 min_ = None 241 max_ = None 242 idx = None 243 filters = None # owner filters 244 245 def __init__(self, type_='anon', matching=False, allow=False, 246 memcg_path='', addr_start=0, addr_end=0, target_idx=0, min_=0, 247 max_=0): 248 self.type_ = type_ 249 self.matching = matching 250 self.allow = allow 251 self.memcg_path = memcg_path, 252 self.addr_start = addr_start 253 self.addr_end = addr_end 254 self.target_idx = target_idx 255 self.min_ = min_ 256 self.max_ = max_ 257 258 def sysfs_dir(self): 259 return os.path.join(self.filters.sysfs_dir(), '%d' % self.idx) 260 261 def stage(self): 262 err = write_file(os.path.join(self.sysfs_dir(), 'type'), self.type_) 263 if err is not None: 264 return err 265 err = write_file(os.path.join(self.sysfs_dir(), 'matching'), 266 self.matching) 267 if err is not None: 268 return err 269 err = write_file(os.path.join(self.sysfs_dir(), 'allow'), self.allow) 270 if err is not None: 271 return err 272 err = write_file(os.path.join(self.sysfs_dir(), 'memcg_path'), 273 self.memcg_path) 274 if err is not None: 275 return err 276 err = write_file(os.path.join(self.sysfs_dir(), 'addr_start'), 277 self.addr_start) 278 if err is not None: 279 return err 280 err = write_file(os.path.join(self.sysfs_dir(), 'addr_end'), 281 self.addr_end) 282 if err is not None: 283 return err 284 err = write_file(os.path.join(self.sysfs_dir(), 'damon_target_idx'), 285 self.target_idx) 286 if err is not None: 287 return err 288 err = write_file(os.path.join(self.sysfs_dir(), 'min'), self.min_) 289 if err is not None: 290 return err 291 err = write_file(os.path.join(self.sysfs_dir(), 'max'), self.max_) 292 if err is not None: 293 return err 294 return None 295 296class DamosFilters: 297 name = None 298 filters = None 299 scheme = None # owner scheme 300 301 def __init__(self, name, filters=[]): 302 self.name = name 303 self.filters = filters 304 for idx, filter_ in enumerate(self.filters): 305 filter_.idx = idx 306 filter_.filters = self 307 308 def sysfs_dir(self): 309 return os.path.join(self.scheme.sysfs_dir(), self.name) 310 311 def stage(self): 312 err = write_file(os.path.join(self.sysfs_dir(), 'nr_filters'), 313 len(self.filters)) 314 if err is not None: 315 return err 316 for filter_ in self.filters: 317 err = filter_.stage() 318 if err is not None: 319 return err 320 return None 321 322class DamosDest: 323 id = None 324 weight = None 325 idx = None 326 dests = None # owner dests 327 328 def __init__(self, id=0, weight=0): 329 self.id = id 330 self.weight = weight 331 332 def sysfs_dir(self): 333 return os.path.join(self.dests.sysfs_dir(), '%d' % self.idx) 334 335 def stage(self): 336 err = write_file(os.path.join(self.sysfs_dir(), 'id'), self.id) 337 if err is not None: 338 return err 339 err = write_file(os.path.join(self.sysfs_dir(), 'weight'), self.weight) 340 if err is not None: 341 return err 342 return None 343 344class DamosDests: 345 dests = None 346 scheme = None # owner scheme 347 348 def __init__(self, dests=[]): 349 self.dests = dests 350 for idx, dest in enumerate(self.dests): 351 dest.idx = idx 352 dest.dests = self 353 354 def sysfs_dir(self): 355 return os.path.join(self.scheme.sysfs_dir(), 'dests') 356 357 def stage(self): 358 err = write_file(os.path.join(self.sysfs_dir(), 'nr_dests'), 359 len(self.dests)) 360 if err is not None: 361 return err 362 for dest in self.dests: 363 err = dest.stage() 364 if err is not None: 365 return err 366 return None 367 368class DamosStats: 369 nr_tried = None 370 sz_tried = None 371 nr_applied = None 372 sz_applied = None 373 qt_exceeds = None 374 375 def __init__(self, nr_tried, sz_tried, nr_applied, sz_applied, qt_exceeds): 376 self.nr_tried = nr_tried 377 self.sz_tried = sz_tried 378 self.nr_applied = nr_applied 379 self.sz_applied = sz_applied 380 self.qt_exceeds = qt_exceeds 381 382class DamosTriedRegion: 383 def __init__(self, start, end, nr_accesses, age): 384 self.start = start 385 self.end = end 386 self.nr_accesses = nr_accesses 387 self.age = age 388 389class Damos: 390 action = None 391 access_pattern = None 392 quota = None 393 watermarks = None 394 core_filters = None 395 ops_filters = None 396 filters = None 397 apply_interval_us = None 398 target_nid = None 399 dests = None 400 idx = None 401 context = None 402 tried_bytes = None 403 stats = None 404 tried_regions = None 405 406 def __init__(self, action='stat', access_pattern=DamosAccessPattern(), 407 quota=DamosQuota(), watermarks=DamosWatermarks(), 408 core_filters=[], ops_filters=[], filters=[], target_nid=0, 409 dests=DamosDests(), apply_interval_us=0): 410 self.action = action 411 self.access_pattern = access_pattern 412 self.access_pattern.scheme = self 413 self.quota = quota 414 self.quota.scheme = self 415 self.watermarks = watermarks 416 self.watermarks.scheme = self 417 418 self.core_filters = DamosFilters(name='core_filters', 419 filters=core_filters) 420 self.core_filters.scheme = self 421 self.ops_filters = DamosFilters(name='ops_filters', 422 filters=ops_filters) 423 self.ops_filters.scheme = self 424 self.filters = DamosFilters(name='filters', filters=filters) 425 self.filters.scheme = self 426 427 self.target_nid = target_nid 428 self.dests = dests 429 self.dests.scheme = self 430 431 self.apply_interval_us = apply_interval_us 432 433 def sysfs_dir(self): 434 return os.path.join( 435 self.context.sysfs_dir(), 'schemes', '%d' % self.idx) 436 437 def stage(self): 438 err = write_file(os.path.join(self.sysfs_dir(), 'action'), self.action) 439 if err is not None: 440 return err 441 err = self.access_pattern.stage() 442 if err is not None: 443 return err 444 err = write_file(os.path.join(self.sysfs_dir(), 'apply_interval_us'), 445 '%d' % self.apply_interval_us) 446 if err is not None: 447 return err 448 449 err = self.quota.stage() 450 if err is not None: 451 return err 452 453 err = self.watermarks.stage() 454 if err is not None: 455 return err 456 457 err = self.core_filters.stage() 458 if err is not None: 459 return err 460 err = self.ops_filters.stage() 461 if err is not None: 462 return err 463 err = self.filters.stage() 464 if err is not None: 465 return err 466 467 err = write_file(os.path.join(self.sysfs_dir(), 'target_nid'), '%d' % 468 self.target_nid) 469 if err is not None: 470 return err 471 472 err = self.dests.stage() 473 if err is not None: 474 return err 475 476class DamonTarget: 477 pid = None 478 # todo: Support target regions if test is made 479 idx = None 480 context = None 481 482 def __init__(self, pid): 483 self.pid = pid 484 485 def sysfs_dir(self): 486 return os.path.join( 487 self.context.sysfs_dir(), 'targets', '%d' % self.idx) 488 489 def stage(self): 490 err = write_file( 491 os.path.join(self.sysfs_dir(), 'regions', 'nr_regions'), '0') 492 if err is not None: 493 return err 494 return write_file( 495 os.path.join(self.sysfs_dir(), 'pid_target'), self.pid) 496 497class IntervalsGoal: 498 access_bp = None 499 aggrs = None 500 min_sample_us = None 501 max_sample_us = None 502 attrs = None # owner DamonAttrs 503 504 def __init__(self, access_bp=0, aggrs=0, min_sample_us=0, max_sample_us=0): 505 self.access_bp = access_bp 506 self.aggrs = aggrs 507 self.min_sample_us = min_sample_us 508 self.max_sample_us = max_sample_us 509 510 def sysfs_dir(self): 511 return os.path.join(self.attrs.interval_sysfs_dir(), 'intervals_goal') 512 513 def stage(self): 514 err = write_file( 515 os.path.join(self.sysfs_dir(), 'access_bp'), self.access_bp) 516 if err is not None: 517 return err 518 err = write_file(os.path.join(self.sysfs_dir(), 'aggrs'), self.aggrs) 519 if err is not None: 520 return err 521 err = write_file(os.path.join(self.sysfs_dir(), 'min_sample_us'), 522 self.min_sample_us) 523 if err is not None: 524 return err 525 err = write_file(os.path.join(self.sysfs_dir(), 'max_sample_us'), 526 self.max_sample_us) 527 if err is not None: 528 return err 529 return None 530 531class DamonAttrs: 532 sample_us = None 533 aggr_us = None 534 intervals_goal = None 535 update_us = None 536 min_nr_regions = None 537 max_nr_regions = None 538 context = None 539 540 def __init__(self, sample_us=5000, aggr_us=100000, 541 intervals_goal=IntervalsGoal(), update_us=1000000, 542 min_nr_regions=10, max_nr_regions=1000): 543 self.sample_us = sample_us 544 self.aggr_us = aggr_us 545 self.intervals_goal = intervals_goal 546 self.intervals_goal.attrs = self 547 self.update_us = update_us 548 self.min_nr_regions = min_nr_regions 549 self.max_nr_regions = max_nr_regions 550 551 def interval_sysfs_dir(self): 552 return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs', 553 'intervals') 554 555 def nr_regions_range_sysfs_dir(self): 556 return os.path.join(self.context.sysfs_dir(), 'monitoring_attrs', 557 'nr_regions') 558 559 def stage(self): 560 err = write_file(os.path.join(self.interval_sysfs_dir(), 'sample_us'), 561 self.sample_us) 562 if err is not None: 563 return err 564 err = write_file(os.path.join(self.interval_sysfs_dir(), 'aggr_us'), 565 self.aggr_us) 566 if err is not None: 567 return err 568 err = self.intervals_goal.stage() 569 if err is not None: 570 return err 571 err = write_file(os.path.join(self.interval_sysfs_dir(), 'update_us'), 572 self.update_us) 573 if err is not None: 574 return err 575 576 err = write_file( 577 os.path.join(self.nr_regions_range_sysfs_dir(), 'min'), 578 self.min_nr_regions) 579 if err is not None: 580 return err 581 582 err = write_file( 583 os.path.join(self.nr_regions_range_sysfs_dir(), 'max'), 584 self.max_nr_regions) 585 if err is not None: 586 return err 587 588class DamonCtx: 589 ops = None 590 monitoring_attrs = None 591 targets = None 592 schemes = None 593 kdamond = None 594 idx = None 595 596 def __init__(self, ops='paddr', monitoring_attrs=DamonAttrs(), targets=[], 597 schemes=[]): 598 self.ops = ops 599 self.monitoring_attrs = monitoring_attrs 600 self.monitoring_attrs.context = self 601 602 self.targets = targets 603 for idx, target in enumerate(self.targets): 604 target.idx = idx 605 target.context = self 606 607 self.schemes = schemes 608 for idx, scheme in enumerate(self.schemes): 609 scheme.idx = idx 610 scheme.context = self 611 612 def sysfs_dir(self): 613 return os.path.join(self.kdamond.sysfs_dir(), 'contexts', 614 '%d' % self.idx) 615 616 def stage(self): 617 err = write_file( 618 os.path.join(self.sysfs_dir(), 'operations'), self.ops) 619 if err is not None: 620 return err 621 err = self.monitoring_attrs.stage() 622 if err is not None: 623 return err 624 625 nr_targets_file = os.path.join( 626 self.sysfs_dir(), 'targets', 'nr_targets') 627 content, err = read_file(nr_targets_file) 628 if err is not None: 629 return err 630 if int(content) != len(self.targets): 631 err = write_file(nr_targets_file, '%d' % len(self.targets)) 632 if err is not None: 633 return err 634 for target in self.targets: 635 err = target.stage() 636 if err is not None: 637 return err 638 639 nr_schemes_file = os.path.join( 640 self.sysfs_dir(), 'schemes', 'nr_schemes') 641 content, err = read_file(nr_schemes_file) 642 if err is not None: 643 return err 644 if int(content) != len(self.schemes): 645 err = write_file(nr_schemes_file, '%d' % len(self.schemes)) 646 if err is not None: 647 return err 648 for scheme in self.schemes: 649 err = scheme.stage() 650 if err is not None: 651 return err 652 return None 653 654class Kdamond: 655 state = None 656 pid = None 657 contexts = None 658 idx = None # index of this kdamond between siblings 659 kdamonds = None # parent 660 661 def __init__(self, contexts=[]): 662 self.contexts = contexts 663 for idx, context in enumerate(self.contexts): 664 context.idx = idx 665 context.kdamond = self 666 667 def sysfs_dir(self): 668 return os.path.join(self.kdamonds.sysfs_dir(), '%d' % self.idx) 669 670 def start(self): 671 nr_contexts_file = os.path.join(self.sysfs_dir(), 672 'contexts', 'nr_contexts') 673 content, err = read_file(nr_contexts_file) 674 if err is not None: 675 return err 676 if int(content) != len(self.contexts): 677 err = write_file(nr_contexts_file, '%d' % len(self.contexts)) 678 if err is not None: 679 return err 680 681 for context in self.contexts: 682 err = context.stage() 683 if err is not None: 684 return err 685 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'on') 686 if err is not None: 687 return err 688 self.pid, err = read_file(os.path.join(self.sysfs_dir(), 'pid')) 689 return err 690 691 def stop(self): 692 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'off') 693 return err 694 695 def update_schemes_tried_regions(self): 696 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 697 'update_schemes_tried_regions') 698 if err is not None: 699 return err 700 for context in self.contexts: 701 for scheme in context.schemes: 702 tried_regions = [] 703 tried_regions_dir = os.path.join( 704 scheme.sysfs_dir(), 'tried_regions') 705 region_indices = [] 706 for filename in os.listdir( 707 os.path.join(scheme.sysfs_dir(), 'tried_regions')): 708 tried_region_dir = os.path.join(tried_regions_dir, filename) 709 if not os.path.isdir(tried_region_dir): 710 continue 711 region_indices.append(int(filename)) 712 for region_idx in sorted(region_indices): 713 tried_region_dir = os.path.join(tried_regions_dir, 714 '%d' % region_idx) 715 region_values = [] 716 for f in ['start', 'end', 'nr_accesses', 'age']: 717 content, err = read_file( 718 os.path.join(tried_region_dir, f)) 719 if err is not None: 720 return err 721 region_values.append(int(content)) 722 tried_regions.append(DamosTriedRegion(*region_values)) 723 scheme.tried_regions = tried_regions 724 725 def update_schemes_tried_bytes(self): 726 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 727 'update_schemes_tried_bytes') 728 if err is not None: 729 return err 730 for context in self.contexts: 731 for scheme in context.schemes: 732 content, err = read_file(os.path.join(scheme.sysfs_dir(), 733 'tried_regions', 'total_bytes')) 734 if err is not None: 735 return err 736 scheme.tried_bytes = int(content) 737 738 def update_schemes_stats(self): 739 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 740 'update_schemes_stats') 741 if err is not None: 742 return err 743 for context in self.contexts: 744 for scheme in context.schemes: 745 stat_values = [] 746 for stat in ['nr_tried', 'sz_tried', 'nr_applied', 747 'sz_applied', 'qt_exceeds']: 748 content, err = read_file( 749 os.path.join(scheme.sysfs_dir(), 'stats', stat)) 750 if err is not None: 751 return err 752 stat_values.append(int(content)) 753 scheme.stats = DamosStats(*stat_values) 754 755 def update_schemes_effective_quotas(self): 756 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 757 'update_schemes_effective_quotas') 758 if err is not None: 759 return err 760 for context in self.contexts: 761 for scheme in context.schemes: 762 for goal in scheme.quota.goals: 763 content, err = read_file( 764 os.path.join(scheme.quota.sysfs_dir(), 765 'effective_bytes')) 766 if err is not None: 767 return err 768 goal.effective_bytes = int(content) 769 return None 770 771 def commit(self): 772 nr_contexts_file = os.path.join(self.sysfs_dir(), 773 'contexts', 'nr_contexts') 774 content, err = read_file(nr_contexts_file) 775 if err is not None: 776 return err 777 if int(content) != len(self.contexts): 778 err = write_file(nr_contexts_file, '%d' % len(self.contexts)) 779 if err is not None: 780 return err 781 782 for context in self.contexts: 783 err = context.stage() 784 if err is not None: 785 return err 786 err = write_file(os.path.join(self.sysfs_dir(), 'state'), 'commit') 787 return err 788 789 790 def commit_schemes_quota_goals(self): 791 for context in self.contexts: 792 for scheme in context.schemes: 793 for goal in scheme.quota.goals: 794 err = goal.stage() 795 if err is not None: 796 print('commit_schemes_quota_goals failed stagign: %s'% 797 err) 798 exit(1) 799 return write_file(os.path.join(self.sysfs_dir(), 'state'), 800 'commit_schemes_quota_goals') 801 802class Kdamonds: 803 kdamonds = [] 804 805 def __init__(self, kdamonds=[]): 806 self.kdamonds = kdamonds 807 for idx, kdamond in enumerate(self.kdamonds): 808 kdamond.idx = idx 809 kdamond.kdamonds = self 810 811 def sysfs_dir(self): 812 return os.path.join(sysfs_root, 'kdamonds') 813 814 def start(self): 815 err = write_file(os.path.join(self.sysfs_dir(), 'nr_kdamonds'), 816 '%s' % len(self.kdamonds)) 817 if err is not None: 818 return err 819 for kdamond in self.kdamonds: 820 err = kdamond.start() 821 if err is not None: 822 return err 823 return None 824 825 def stop(self): 826 for kdamond in self.kdamonds: 827 err = kdamond.stop() 828 if err is not None: 829 return err 830 return None 831