vfs,mount,cmount: use About to return the correct disk total/used/free

Disks total, used, free now shows correctly for mount and cmount (eg
`df` for Unix or in the Windows explorer).
This commit is contained in:
Nick Craig-Wood 2018-04-17 23:19:34 +01:00
parent ef3bcec76c
commit 2b855751fc
4 changed files with 106 additions and 5 deletions

View file

@ -275,6 +275,16 @@ func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
stat.Bsize = blockSize // Block size stat.Bsize = blockSize // Block size
stat.Namemax = 255 // Maximum file name length? stat.Namemax = 255 // Maximum file name length?
stat.Frsize = blockSize // Fragment size, smallest addressable data size in the file system. stat.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
total, used, free := fsys.VFS.Statfs()
if total >= 0 {
stat.Blocks = uint64(total) / blockSize
}
if used >= 0 {
stat.Bfree = stat.Blocks - uint64(used)/blockSize
}
if free >= 0 {
stat.Bavail = uint64(free) / blockSize
}
return 0 return 0
} }

View file

@ -62,6 +62,16 @@ func (f *FS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.Sta
resp.Bsize = blockSize // Block size resp.Bsize = blockSize // Block size
resp.Namelen = 255 // Maximum file name length? resp.Namelen = 255 // Maximum file name length?
resp.Frsize = blockSize // Fragment size, smallest addressable data size in the file system. resp.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
total, used, free := f.VFS.Statfs()
if total >= 0 {
resp.Blocks = uint64(total) / blockSize
}
if used >= 0 {
resp.Bfree = resp.Blocks - uint64(used)/blockSize
}
if free >= 0 {
resp.Bavail = uint64(free) / blockSize
}
return nil return nil
} }

View file

@ -24,6 +24,7 @@ import (
"os" "os"
"path" "path"
"strings" "strings"
"sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -170,6 +171,9 @@ type VFS struct {
Opt Options Opt Options
cache *cache cache *cache
cancel context.CancelFunc cancel context.CancelFunc
usageMu sync.Mutex
usageTime time.Time
usage *fs.Usage
} }
// Options is options for creating the vfs // Options is options for creating the vfs
@ -452,3 +456,40 @@ func (vfs *VFS) Rename(oldName, newName string) error {
} }
return nil return nil
} }
// Statfs returns into about the filing system if known
//
// The values will be -1 if they aren't known
//
// This information is cached for the DirCacheTime interval
func (vfs *VFS) Statfs() (total, used, free int64) {
// defer log.Trace("/", "")("total=%d, used=%d, free=%d", &total, &used, &free)
vfs.usageMu.Lock()
defer vfs.usageMu.Unlock()
total, used, free = -1, -1, -1
doAbout := vfs.f.Features().About
if doAbout == nil {
return
}
if vfs.usageTime.IsZero() || time.Since(vfs.usageTime) >= vfs.Opt.DirCacheTime {
var err error
vfs.usage, err = doAbout()
vfs.usageTime = time.Now()
if err != nil {
fs.Errorf(vfs.f, "Statfs failed: %v", err)
return
}
}
if u := vfs.usage; u != nil {
if u.Total != nil {
total = *u.Total
}
if u.Free != nil {
free = *u.Free
}
if u.Used != nil {
used = *u.Used
}
}
return
}

View file

@ -251,3 +251,43 @@ func TestVFSRename(t *testing.T) {
err = vfs.Rename("file0", "not found/file0") err = vfs.Rename("file0", "not found/file0")
assert.Equal(t, os.ErrNotExist, err) assert.Equal(t, os.ErrNotExist, err)
} }
func TestVFSStatfs(t *testing.T) {
r := fstest.NewRun(t)
defer r.Finalise()
vfs := New(r.Fremote, nil)
// pre-conditions
assert.Nil(t, vfs.usage)
assert.True(t, vfs.usageTime.IsZero())
// read
total, used, free := vfs.Statfs()
require.NotNil(t, vfs.usage)
assert.False(t, vfs.usageTime.IsZero())
if vfs.usage.Total != nil {
assert.Equal(t, *vfs.usage.Total, total)
} else {
assert.Equal(t, -1, total)
}
if vfs.usage.Free != nil {
assert.Equal(t, *vfs.usage.Free, free)
} else {
assert.Equal(t, -1, free)
}
if vfs.usage.Used != nil {
assert.Equal(t, *vfs.usage.Used, used)
} else {
assert.Equal(t, -1, used)
}
// read cached
oldUsage := vfs.usage
oldTime := vfs.usageTime
total2, used2, free2 := vfs.Statfs()
assert.Equal(t, oldUsage, vfs.usage)
assert.Equal(t, total, total2)
assert.Equal(t, used, used2)
assert.Equal(t, free, free2)
assert.Equal(t, oldTime, vfs.usageTime)
}