Skip to content
This repository was archived by the owner on Oct 22, 2024. It is now read-only.

Commit 4f1a2d8

Browse files
committed
XFS: fix creating volumes on OpenShift
On OpenShift, the xfs_io command that was used while creating XFS volumes hangs while getting loaded (kernel or container runtime bug?). This problem can be avoided by making the same ioctl calls as in that binary directly from the PMEM-CSI driver. Fixes: #1058
1 parent 70ecb2b commit 4f1a2d8

File tree

4 files changed

+99
-13
lines changed

4 files changed

+99
-13
lines changed

pkg/pmem-csi-driver/nodeserver.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/intel/pmem-csi/pkg/pmem-csi-driver/parameters"
3131
pmdmanager "github.com/intel/pmem-csi/pkg/pmem-device-manager"
3232
"github.com/intel/pmem-csi/pkg/volumepathhandler"
33+
"github.com/intel/pmem-csi/pkg/xfs"
3334
)
3435

3536
const (
@@ -285,12 +286,7 @@ func (ns *nodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
285286
}
286287

287288
if ephemeral && fsType == "xfs" {
288-
// FS was created only in ephemeral case.
289-
// Only if created filesytem and it was XFS:
290-
// Tune XFS file system to serve huge pages:
291-
// Set file system extent size to 2 MiB sized and aligned block allocations.
292-
_, err := pmemexec.RunCommand(ctx, "xfs_io", "-c", "extsize 2m", hostMount)
293-
if err != nil {
289+
if err := xfs.ConfigureFS(hostMount); err != nil {
294290
return nil, status.Error(codes.Internal, err.Error())
295291
}
296292
}
@@ -587,11 +583,8 @@ func (ns *nodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
587583
return nil, status.Error(codes.Internal, err.Error())
588584
}
589585

590-
if existingFsType == "" && requestedFsType == "xfs" {
591-
// Only if created a new filesytem and it was XFS:
592-
// Align XFS file system for hugepages
593-
_, err := pmemexec.RunCommand(ctx, "xfs_io", "-c", "extsize 2m", stagingtargetPath)
594-
if err != nil {
586+
if requestedFsType == "xfs" {
587+
if err := xfs.ConfigureFS(stagingtargetPath); err != nil {
595588
return nil, status.Error(codes.Internal, err.Error())
596589
}
597590
}

pkg/xfs/xfs.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
Copyright 2022 Intel Corporation
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package xfs
8+
9+
// #include <linux/fs.h>
10+
// #include <sys/ioctl.h>
11+
// #include <errno.h>
12+
// #include <string.h>
13+
//
14+
// char *getxattr(int fd, struct fsxattr *arg) {
15+
// return ioctl(fd, FS_IOC_FSGETXATTR, arg) == 0 ? 0 : strerror(errno);
16+
// }
17+
//
18+
// char *setxattr(int fd, struct fsxattr *arg) {
19+
// return ioctl(fd, FS_IOC_FSSETXATTR, arg) == 0 ? 0 : strerror(errno);
20+
// }
21+
import "C"
22+
23+
import (
24+
"fmt"
25+
"os"
26+
)
27+
28+
// ConfigureFS must be called after mkfs.xfs for the mounted
29+
// XFS filesystem to prepare the volume for usage as fsdax.
30+
// It is idempotent.
31+
func ConfigureFS(path string) error {
32+
// Operate on root directory.
33+
file, err := os.Open(path)
34+
if err != nil {
35+
return fmt.Errorf("open %q: %v", path, err)
36+
}
37+
defer file.Close()
38+
fd := C.int(file.Fd())
39+
40+
// Get extended attributes.
41+
var attr C.struct_fsxattr
42+
if errnostr := C.getxattr(fd, &attr); errnostr != nil {
43+
return fmt.Errorf("FS_IOC_FSGETXATTR for %q: %v", path, C.GoString(errnostr))
44+
}
45+
46+
// Set extsize to 2m to enable hugepages in combination with
47+
// fsdax. This is equivalent to the "xfs_io -c 'extsize 2m'" invocation
48+
// mentioned in https://nvdimm.wiki.kernel.org/2mib_fs_dax
49+
attr.fsx_xflags |= C.FS_XFLAG_EXTSZINHERIT
50+
attr.fsx_extsize = 2 * 1024 * 1024
51+
if errnostr := C.setxattr(fd, &attr); errnostr != nil {
52+
return fmt.Errorf("FS_IOC_FSSETXATTR for %q: %v", path, C.GoString(errnostr))
53+
}
54+
55+
return nil
56+
}

pkg/xfs/xfs_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
Copyright 2022 Intel Corporation
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package xfs
8+
9+
import (
10+
"testing"
11+
)
12+
13+
func Test_ConfigureFS(t *testing.T) {
14+
// This is assumed to be backed by tmpfs and thus doesn't support xattr.
15+
tmp := t.TempDir()
16+
err := ConfigureFS(tmp)
17+
if err == nil {
18+
t.Fatal("did not get expected error")
19+
}
20+
t.Logf("got expected error: %v", err)
21+
}

test/e2e/storage/dax/dax.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ func (p *daxTestSuite) DefineTests(driver storageframework.TestDriver, pattern s
123123
init()
124124
defer cleanup()
125125

126-
testDaxInPod(f, l.root, l.resource.Pattern.VolMode, l.resource.VolSource, l.config, withKataContainers, p.daxSupported)
126+
testDaxInPod(f, l.root, l.resource.Pattern.VolMode, l.resource.VolSource, l.config, withKataContainers, p.daxSupported, l.resource.Pattern.FsType)
127127
})
128128
}
129129

@@ -135,6 +135,7 @@ func testDaxInPod(
135135
config *storageframework.PerTestConfig,
136136
withKataContainers bool,
137137
daxSupported bool,
138+
fstype string,
138139
) {
139140
expectDax := daxSupported
140141
if withKataContainers {
@@ -151,11 +152,19 @@ func testDaxInPod(
151152
}
152153
}
153154

155+
// Workaround for https://github.com/kubernetes/kubernetes/issues/107286:
156+
// the storage framework should set FSType but doesn't.
157+
if source.CSI != nil &&
158+
source.CSI.FSType == nil &&
159+
fstype != "" {
160+
source.CSI.FSType = &fstype
161+
}
162+
154163
pod := CreatePod(f, "dax-volume-test", volumeMode, source, config, withKataContainers)
155164
defer func() {
156165
DeletePod(f, pod)
157166
}()
158-
checkWithNormalRuntime := testDax(f, pod, root, volumeMode, source, withKataContainers, expectDax)
167+
checkWithNormalRuntime := testDax(f, pod, root, volumeMode, source, withKataContainers, expectDax, fstype)
159168
DeletePod(f, pod)
160169
if checkWithNormalRuntime {
161170
testDaxOutside(f, pod, root)
@@ -336,6 +345,7 @@ func testDax(
336345
source *v1.VolumeSource,
337346
withKataContainers bool,
338347
expectDax bool,
348+
fstype string,
339349
) bool {
340350
ns := f.Namespace.Name
341351
containerName := pod.Spec.Containers[0].Name
@@ -351,6 +361,12 @@ func testDax(
351361
if expectDax {
352362
By("checking volume for DAX support")
353363
pmempod.RunInPod(f, root, nil, "lsblk; mount | grep /mnt; /usr/local/bin/pmem-dax-check /mnt/daxtest", ns, pod.Name, containerName)
364+
365+
if fstype == "xfs" {
366+
By("checking volume for extsize 2m")
367+
// "xfs_io -c extsize" prints "[2097152] /mnt".
368+
pmempod.RunInPod(f, root, nil, "xfs_io -c extsize /mnt | tee /dev/stderr | grep -q -w 2097152", ns, pod.Name, containerName)
369+
}
354370
} else {
355371
By("checking volume for missing DAX support")
356372
stdout, _ := pmempod.RunInPod(f, root, nil, "ndctl list -NR; lsblk; mount | grep /mnt; /usr/local/bin/pmem-dax-check /mnt/daxtest; if [ $? -ne 1 ]; then echo should have reported missing DAX >&2; exit 1; fi", ns, pod.Name, containerName)

0 commit comments

Comments
 (0)