Repository: ceph/go-ceph
Pull request #332 (2020-07-17 20:47:49)

cephfs: add StatFS implementing ceph_statfs
Implement a wrapper function and data type for ceph_statfs. It's actually pretty useless as a high number of the fields are not filled in with useful values by ceph. When they do, we'll get 'em too.


Fixes: #263 

## Checklist
- [x] Added tests for features and functional changes
- [x] Public functions and types are documented
- [x] Standard formatting is applied to Go code



Patch:
diff --git a/cephfs/statfs.go b/cephfs/statfs.go
new file mode 100644
index 0000000..95df675
--- /dev/null
+++ b/cephfs/statfs.go
@@ -0,0 +1,74 @@
+package cephfs
+
+/*
+#cgo LDFLAGS: -lcephfs
+#cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64
+#include <stdlib.h>
+#include <cephfs/libcephfs.h>
+*/
+import "C"
+
+import (
+	"unsafe"
+)
+
+// CephStatVFS instances are returned from the StatFS call. It reports
+// file-system wide statistics.
+type CephStatVFS struct {
+	// Bsize reports the file system's block size.
+	Bsize int64
+	// Fragment reports the file system's fragment size.
+	Frsize int64
+	// Blocks reports the number of blocks in the file system.
+	Blocks uint64
+	// Bfree reports the number of free blocks.
+	Bfree uint64
+	// Bavail reports the number of free blocks for unprivileged users.
+	Bavail uint64
+	// Files reports the number of inodes in the file system.
+	Files uint64
+	// Ffree reports the number of free indoes.
+	Ffree uint64
+	// Favail reports the number of free indoes for unprivileged users.
+	Favail uint64
+	// Fsid reports the file system ID number.
+	Fsid int64
+	// Flag reports the file system mount flags.
+	Flag int64
+	// Namemax reports the maximum file name length.
+	Namemax int64
+}
+
+// StatFS returns file system wide statistics.
+// NOTE: Many of the statistics fields reported by ceph are not filled in with
+// useful values.
+//
+// Implements:
+//  int ceph_statfs(struct ceph_mount_info *cmount, const char *path, struct statvfs *stbuf);
+func (mount *MountInfo) StatFS(path string) (*CephStatVFS, error) {
+	if err := mount.validate(); err != nil {
+		return nil, err
+	}
+	cPath := C.CString(path)
+	defer C.free(unsafe.Pointer(cPath))
+
+	var statvfs C.struct_statvfs
+	ret := C.ceph_statfs(mount.mount, cPath, &statvfs)
+	if ret != 0 {
+		return nil, getError(ret)
+	}
+	csfs := &CephStatVFS{
+		Bsize:   int64(statvfs.f_bsize),
+		Frsize:  int64(statvfs.f_frsize),
+		Blocks:  uint64(statvfs.f_blocks),
+		Bfree:   uint64(statvfs.f_bfree),
+		Bavail:  uint64(statvfs.f_bavail),
+		Files:   uint64(statvfs.f_files),
+		Ffree:   uint64(statvfs.f_ffree),
+		Favail:  uint64(statvfs.f_favail),
+		Fsid:    int64(statvfs.f_fsid),
+		Flag:    int64(statvfs.f_flag),
+		Namemax: int64(statvfs.f_namemax),
+	}
+	return csfs, nil
+}


Test patch:
diff --git a/cephfs/statfs_test.go b/cephfs/statfs_test.go
new file mode 100644
index 0000000..ab22e61
--- /dev/null
+++ b/cephfs/statfs_test.go
@@ -0,0 +1,34 @@
+package cephfs
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+// TestStatFSRootDir does not assert much about every field as these can vary
+// between runs. Similarly, some stats might vary between sub-trees but we
+// trust the ceph libs to be correct here and just make sure the wrapper code
+// behaves.
+func TestStatFSRootDir(t *testing.T) {
+	t.Run("invalid", func(t *testing.T) {
+		m := &MountInfo{}
+		sfs, err := m.StatFS("/")
+		assert.Error(t, err)
+		assert.Nil(t, sfs)
+	})
+
+	// half the stats as reported by ceph are pretty useless/dummy values.
+	// (see src/client/Client.cc)
+	// some stuff gets filled in only if a quota is set, but we're not
+	// up to that right now, so we don't really check much value-wise.
+	t.Run("valid", func(t *testing.T) {
+		mount := fsConnect(t)
+		defer fsDisconnect(t, mount)
+
+		sfs, err := mount.StatFS("/")
+		assert.NoError(t, err)
+		assert.NotNil(t, sfs)
+		assert.Equal(t, sfs.Namemax, int64(255))
+	})
+}