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