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