summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/cgroupfs/bitmap.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fsimpl/cgroupfs/bitmap.go')
-rw-r--r--pkg/sentry/fsimpl/cgroupfs/bitmap.go139
1 files changed, 139 insertions, 0 deletions
diff --git a/pkg/sentry/fsimpl/cgroupfs/bitmap.go b/pkg/sentry/fsimpl/cgroupfs/bitmap.go
new file mode 100644
index 000000000..8074641db
--- /dev/null
+++ b/pkg/sentry/fsimpl/cgroupfs/bitmap.go
@@ -0,0 +1,139 @@
+// Copyright 2021 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cgroupfs
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "gvisor.dev/gvisor/pkg/bitmap"
+)
+
+// formatBitmap produces a string representation of b, which lists the indicies
+// of set bits in the bitmap. Indicies are separated by commas and ranges of
+// set bits are abbreviated. Example outputs: "0,2,4", "0,3-7,10", "0-10".
+//
+// Inverse of parseBitmap.
+func formatBitmap(b *bitmap.Bitmap) string {
+ ones := b.ToSlice()
+ if len(ones) == 0 {
+ return ""
+ }
+
+ elems := make([]string, 0, len(ones))
+ runStart := ones[0]
+ lastVal := ones[0]
+ inRun := false
+
+ for _, v := range ones[1:] {
+ last := lastVal
+ lastVal = v
+
+ if last+1 == v {
+ // In a contiguous block of ones.
+ if !inRun {
+ runStart = last
+ inRun = true
+ }
+
+ continue
+ }
+
+ // Non-contiguous bit.
+ if inRun {
+ // Render a run
+ elems = append(elems, fmt.Sprintf("%d-%d", runStart, last))
+ inRun = false
+ continue
+ }
+
+ // Lone non-contiguous bit.
+ elems = append(elems, fmt.Sprintf("%d", last))
+
+ }
+
+ // Process potential final run
+ if inRun {
+ elems = append(elems, fmt.Sprintf("%d-%d", runStart, lastVal))
+ } else {
+ elems = append(elems, fmt.Sprintf("%d", lastVal))
+ }
+
+ return strings.Join(elems, ",")
+}
+
+func parseToken(token string) (start, end uint32, err error) {
+ ts := strings.SplitN(token, "-", 2)
+ switch len(ts) {
+ case 0:
+ return 0, 0, fmt.Errorf("invalid token %q", token)
+ case 1:
+ val, err := strconv.ParseUint(ts[0], 10, 32)
+ if err != nil {
+ return 0, 0, err
+ }
+ return uint32(val), uint32(val), nil
+ case 2:
+ val1, err := strconv.ParseUint(ts[0], 10, 32)
+ if err != nil {
+ return 0, 0, err
+ }
+ val2, err := strconv.ParseUint(ts[1], 10, 32)
+ if err != nil {
+ return 0, 0, err
+ }
+ if val1 >= val2 {
+ return 0, 0, fmt.Errorf("start (%v) must be less than end (%v)", val1, val2)
+ }
+ return uint32(val1), uint32(val2), nil
+ default:
+ panic(fmt.Sprintf("Unreachable: got %d substrs", len(ts)))
+ }
+}
+
+// parseBitmap parses input as a bitmap. input should be a comma separated list
+// of indices, and ranges of set bits may be abbreviated. Examples: "0,2,4",
+// "0,3-7,10", "0-10". Input after the first newline or null byte is discarded.
+//
+// sizeHint sets the initial size of the bitmap, which may prevent reallocation
+// when growing the bitmap during parsing. Ideally sizeHint should be at least
+// as large as the bitmap represented by input, but this is not required.
+//
+// Inverse of formatBitmap.
+func parseBitmap(input string, sizeHint uint32) (*bitmap.Bitmap, error) {
+ b := bitmap.New(sizeHint)
+
+ if termIdx := strings.IndexAny(input, "\n\000"); termIdx != -1 {
+ input = input[:termIdx]
+ }
+ input = strings.TrimSpace(input)
+
+ if len(input) == 0 {
+ return &b, nil
+ }
+ tokens := strings.Split(input, ",")
+
+ for _, t := range tokens {
+ start, end, err := parseToken(strings.TrimSpace(t))
+ if err != nil {
+ return nil, err
+ }
+ for i := start; i <= end; i++ {
+ b.Add(i)
+ }
+ }
+ return &b, nil
+}