Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ As noted in [GCP PD documentation](https://cloud.google.com/kubernetes-engine/do

`btrfs` filesystem accepts the following "special" mount options and the sysfs paths they target:

- `btrfs-data-bg_reclaim_threshold`: `/sys/fs/btrfs/FS-UUID/allocation/data/bg_reclaim_threshold`.
- `btrfs-metadata-bg_reclaim_thresho: `/sys/fs/btrfs/FS-UUID/allocation/metadata/bg_reclaim_threshold`.
- `btrfs-bdi-read_ahead_kb`: `/sys/fs/btrfs/FS-UUID/bdi/read_ahead_kb`.
| Setting | Sysfs path | Value | Default | Supported on Linux versions | Notes |
|--------------------------------------------------|-------------------------------------------------------------------|----------------|-------------------------|-----------------------------|-------|
| `btrfs-allocation-data-bg_reclaim_threshold` | `/sys/fs/btrfs/FS-UUID/allocation/data/bg_reclaim_threshold` | 0–99 (percent) | 0 (off) | v5.19+ | Triggers background reclaim for DATA block groups when usage drops to the threshold. |
| `btrfs-allocation-metadata-bg_reclaim_threshold` | `/sys/fs/btrfs/FS-UUID/allocation/metadata/bg_reclaim_threshold` | 0–99 (percent) | 0 (off) | v5.19+ | Same as above, for METADATA block groups. |
| `btrfs-allocation-data-dynamic_reclaim` | `/sys/fs/btrfs/FS-UUID/allocation/data/dynamic_reclaim` | `0` or `1` | 0 (off) | v6.11+ | Heuristic reclaim that addresses [some concerns](https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f5ff64ccf7bb7274ed66b0d835b2f6ae10af5d7a) of `bg_reclaim_threshold`. |
| `btrfs-allocation-metadata-dynamic_reclaim` | `/sys/fs/btrfs/FS-UUID/allocation/metadata/dynamic_reclaim` | `0` or `1` | 0 (off) | v6.11+ | Same as above, for METADATA block groups. |
| `btrfs-bdi-read_ahead_kb` | `/sys/fs/btrfs/FS-UUID/bdi/read_ahead_kb` | integer kB ≥ 0 | kernel/device dependent | v5.9+ | Per-BDI readahead. Powers of two are commonly used. |

See more in the [in btrfs docs](https://btrfs.readthedocs.io/en/latest/ch-sysfs.html#uuid-allocations-data-metadata-system).

Expand Down
66 changes: 44 additions & 22 deletions pkg/gce-pd-csi-driver/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,31 @@ const (
fsTypeExt3 = "ext3"
fsTypeBtrfs = "btrfs"

readAheadKBMountFlagRegexPattern = "^read_ahead_kb=(.+)$"
btrfsReclaimDataRegexPattern = "^btrfs-allocation-data-bg_reclaim_threshold=(\\d{1,2})$" // 0-99 are valid, incl. 00
btrfsReclaimMetadataRegexPattern = "^btrfs-allocation-metadata-bg_reclaim_threshold=(\\d{1,2})$" // ditto ^
btrfsReadAheadKBRegexPattern = "^btrfs-bdi-read_ahead_kb=(\\d+)$"
readAheadKBMountFlagRegexPattern = "^read_ahead_kb=(.+)$"
btrfsReclaimDataRegexPattern = "^btrfs-allocation-data-bg_reclaim_threshold=(\\d{1,2})$" // 0-99 are valid, incl. 00
btrfsReclaimMetadataRegexPattern = "^btrfs-allocation-metadata-bg_reclaim_threshold=(\\d{1,2})$" // ditto ^
btrfsDynamicReclaimDataRegexPattern = "^btrfs-allocation-data-dynamic_reclaim=(0|1)$" // boolean in kernel, so accepting 0 or 1
btrfsDynamicReclaimMetadataRegexPattern = "^btrfs-allocation-metadata-dynamic_reclaim=(0|1)$" // ditto ^
btrfsReadAheadKBRegexPattern = "^btrfs-bdi-read_ahead_kb=(\\d+)$"
)

var (
readAheadKBMountFlagRegex = regexp.MustCompile(readAheadKBMountFlagRegexPattern)
btrfsReclaimDataRegex = regexp.MustCompile(btrfsReclaimDataRegexPattern)
btrfsReclaimMetadataRegex = regexp.MustCompile(btrfsReclaimMetadataRegexPattern)
btrfsReadAheadKBRegex = regexp.MustCompile(btrfsReadAheadKBRegexPattern)
readAheadKBMountFlagRegex = regexp.MustCompile(readAheadKBMountFlagRegexPattern)
btrfsReclaimDataRegex = regexp.MustCompile(btrfsReclaimDataRegexPattern)
btrfsReclaimMetadataRegex = regexp.MustCompile(btrfsReclaimMetadataRegexPattern)
btrfsDynamicReclaimDataRegex = regexp.MustCompile(btrfsDynamicReclaimDataRegexPattern)
btrfsDynamicReclaimMetadataRegex = regexp.MustCompile(btrfsDynamicReclaimMetadataRegexPattern)
btrfsReadAheadKBRegex = regexp.MustCompile(btrfsReadAheadKBRegexPattern)
)

type btrfsFlags struct {
reclaimData,
reclaimMetadata,
dynamicReclaimData,
dynamicReclaimMetadata,
readAheadKb string
}

func getDefaultFsType() string {
if runtime.GOOS == "windows" {
return defaultWindowsFsType
Expand Down Expand Up @@ -404,7 +416,7 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage
// Part 3: Mount device to stagingTargetPath
fstype := getDefaultFsType()

var btrfsReclaimData, btrfsReclaimMetadata, btrfsReadAheadKb string
var btrfsFlags btrfsFlags
shouldUpdateReadAhead := false
var readAheadKB int64
options := []string{}
Expand All @@ -420,7 +432,7 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage
}

if mnt.FsType == fsTypeBtrfs {
btrfsReclaimData, btrfsReclaimMetadata, btrfsReadAheadKb = extractBtrfsFlags(mnt.MountFlags)
btrfsFlags = extractBtrfsFlags(mnt.MountFlags)
}
} else if blk := volumeCapability.GetBlock(); blk != nil {
// Noop for Block NodeStageVolume
Expand Down Expand Up @@ -476,16 +488,22 @@ func (ns *GCENodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStage

btrfsSysfs := map[string]string{}

if btrfsReadAheadKb != "" {
btrfsSysfs["bdi/read_ahead_kb"] = btrfsReadAheadKb
if btrfsFlags.readAheadKb != "" {
btrfsSysfs["bdi/read_ahead_kb"] = btrfsFlags.readAheadKb
}

if !readonly {
if btrfsReclaimData != "" {
btrfsSysfs["allocation/data/bg_reclaim_threshold"] = btrfsReclaimData
if btrfsFlags.reclaimData != "" {
btrfsSysfs["allocation/data/bg_reclaim_threshold"] = btrfsFlags.reclaimData
}
if btrfsFlags.reclaimMetadata != "" {
btrfsSysfs["allocation/metadata/bg_reclaim_threshold"] = btrfsFlags.reclaimMetadata
}
if btrfsFlags.dynamicReclaimData != "" {
btrfsSysfs["allocation/data/dynamic_reclaim"] = btrfsFlags.dynamicReclaimData
}
if btrfsReclaimMetadata != "" {
btrfsSysfs["allocation/metadata/bg_reclaim_threshold"] = btrfsReclaimMetadata
if btrfsFlags.dynamicReclaimMetadata != "" {
btrfsSysfs["allocation/metadata/dynamic_reclaim"] = btrfsFlags.dynamicReclaimMetadata
}
}

Expand Down Expand Up @@ -552,18 +570,22 @@ func (ns *GCENodeServer) updateReadAhead(devicePath string, readAheadKB int64) e
return nil
}

func extractBtrfsFlags(mountFlags []string) (string, string, string) {
var reclaimData, reclaimMetadata, readAheadKb string
func extractBtrfsFlags(mountFlags []string) btrfsFlags {
var flags btrfsFlags
for _, mountFlag := range mountFlags {
if got := btrfsReclaimDataRegex.FindStringSubmatch(mountFlag); len(got) == 2 {
reclaimData = got[1]
flags.reclaimData = got[1]
} else if got := btrfsReclaimMetadataRegex.FindStringSubmatch(mountFlag); len(got) == 2 {
reclaimMetadata = got[1]
flags.reclaimMetadata = got[1]
} else if got := btrfsReadAheadKBRegex.FindStringSubmatch(mountFlag); len(got) == 2 {
readAheadKb = got[1]
flags.readAheadKb = got[1]
} else if got := btrfsDynamicReclaimDataRegex.FindStringSubmatch(mountFlag); len(got) == 2 {
flags.dynamicReclaimData = got[1]
} else if got := btrfsDynamicReclaimMetadataRegex.FindStringSubmatch(mountFlag); len(got) == 2 {
flags.dynamicReclaimMetadata = got[1]
}
}
return reclaimData, reclaimMetadata, readAheadKb
return flags
}

func extractReadAheadKBMountFlag(mountFlags []string) (int64, bool, error) {
Expand Down
58 changes: 35 additions & 23 deletions pkg/gce-pd-csi-driver/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,9 @@ func TestNodeStageVolume(t *testing.T) {
btrfsPrefix = fmt.Sprintf("%s/sys/fs/btrfs/%s", tempDir, btrfsUUID)
btrfsFixtures = map[string]string{
"allocation/data/bg_reclaim_threshold": "0\n",
"allocation/data/dynamic_reclaim": "0\n",
"allocation/metadata/bg_reclaim_threshold": "0\n",
"allocation/metadata/dynamic_reclaim": "0\n",
"bdi/read_ahead_kb": "4096\n",
}
)
Expand All @@ -648,22 +650,24 @@ func TestNodeStageVolume(t *testing.T) {
}

testCases := []struct {
name string
req *csi.NodeStageVolumeRequest
deviceSize int
blockExtSize int
readonlyBit string
expResize bool
expReadAheadUpdate bool
expReadAheadKB string
expReadOnlyRemount bool
expCommandList []fakeCmd
readAheadSectors string
btrfsReclaimData string
btrfsReclaimMetadata string
btrfsReadAheadKb string
sectorSizeInBytes int
expErrCode codes.Code
name string
req *csi.NodeStageVolumeRequest
deviceSize int
blockExtSize int
readonlyBit string
expResize bool
expReadAheadUpdate bool
expReadAheadKB string
expReadOnlyRemount bool
expCommandList []fakeCmd
readAheadSectors string
btrfsReclaimData string
btrfsReclaimMetadata string
btrfsDynamicReclaimData string
btrfsDynamicReclaimMetadata string
btrfsReadAheadKb string
sectorSizeInBytes int
expErrCode codes.Code
}{
{
name: "Valid request, resize even though block and filesystem sizes match",
Expand Down Expand Up @@ -927,6 +931,8 @@ func TestNodeStageVolume(t *testing.T) {
MountFlags: []string{
"btrfs-allocation-data-bg_reclaim_threshold=90",
"btrfs-allocation-metadata-bg_reclaim_threshold=91",
"btrfs-allocation-data-dynamic_reclaim=1",
"btrfs-allocation-metadata-dynamic_reclaim=1",
"btrfs-bdi-read_ahead_kb=128",
},
},
Expand All @@ -936,12 +942,14 @@ func TestNodeStageVolume(t *testing.T) {
},
},
},
deviceSize: 1,
blockExtSize: 1,
readonlyBit: "0",
btrfsReclaimData: "90",
btrfsReclaimMetadata: "91",
btrfsReadAheadKb: "128",
deviceSize: 1,
blockExtSize: 1,
readonlyBit: "0",
btrfsReclaimData: "90",
btrfsReclaimMetadata: "91",
btrfsDynamicReclaimData: "1",
btrfsDynamicReclaimMetadata: "1",
btrfsReadAheadKb: "128",
expCommandList: []fakeCmd{
{
cmd: "blkid",
Expand Down Expand Up @@ -1267,13 +1275,17 @@ func TestNodeStageVolume(t *testing.T) {
if tc.expReadAheadUpdate == false && readAheadUpdateCalled == true {
t.Fatalf("Test updated read ahead, but it was not expected.")
}
if tc.btrfsReclaimData == "" && tc.btrfsReclaimMetadata == "" && tc.btrfsReadAheadKb == "" && blkidCalled {
if tc.btrfsReclaimData == "" && tc.btrfsReclaimMetadata == "" &&
tc.btrfsDynamicReclaimData == "" && tc.btrfsDynamicReclaimMetadata == "" &&
tc.btrfsReadAheadKb == "" && blkidCalled {
t.Fatalf("blkid was called, but was not expected.")
}

btrfsProps := map[string]string{
"/allocation/data/bg_reclaim_threshold": tc.btrfsReclaimData,
"/allocation/metadata/bg_reclaim_threshold": tc.btrfsReclaimMetadata,
"/allocation/data/dynamic_reclaim": tc.btrfsDynamicReclaimData,
"/allocation/metadata/dynamic_reclaim": tc.btrfsDynamicReclaimMetadata,
"/bdi/read_ahead_kb": tc.btrfsReadAheadKb,
}

Expand Down
6 changes: 6 additions & 0 deletions pkg/gce-pd-csi-driver/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,12 @@ func collectMountOptions(fsType string, mntFlags []string) []string {
if btrfsReclaimMetadataRegex.FindString(opt) != "" {
continue
}
if btrfsDynamicReclaimDataRegex.FindString(opt) != "" {
continue
}
if btrfsDynamicReclaimMetadataRegex.FindString(opt) != "" {
continue
}
if btrfsReadAheadKBRegex.FindString(opt) != "" {
continue
}
Expand Down