Return non-zero size for tmpfs statfs(2).

This does not implement accepting or enforcing any size limit, which will be
more complex and has performance implications; it just returns a fixed non-zero
size.

Updates #1936

PiperOrigin-RevId: 328428588
This commit is contained in:
Jamie Liu
2020-08-25 16:40:02 -07:00
committed by gVisor bot
parent cb573c8e0b
commit 247dcd62d4
4 changed files with 41 additions and 18 deletions
+6 -5
View File
@@ -44,17 +44,18 @@ type Statfs struct {
// Type is one of the filesystem magic values, defined above.
Type uint64
// BlockSize is the data block size.
// BlockSize is the optimal transfer block size in bytes.
BlockSize int64
// Blocks is the number of data blocks in use.
// Blocks is the maximum number of data blocks the filesystem may store, in
// units of BlockSize.
Blocks uint64
// BlocksFree is the number of free blocks.
// BlocksFree is the number of free data blocks, in units of BlockSize.
BlocksFree uint64
// BlocksAvailable is the number of blocks free for use by
// unprivileged users.
// BlocksAvailable is the number of data blocks free for use by
// unprivileged users, in units of BlockSize.
BlocksAvailable uint64
// Files is the number of used file nodes on the filesystem.
+10 -2
View File
@@ -16,6 +16,8 @@
package tmpfs
import (
"math"
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/sentry/fs"
@@ -32,9 +34,15 @@ import (
var fsInfo = fs.Info{
Type: linux.TMPFS_MAGIC,
// tmpfs currently does not support configurable size limits. In Linux,
// such a tmpfs mount will return f_blocks == f_bfree == f_bavail == 0 from
// statfs(2). However, many applications treat this as having a size limit
// of 0. To work around this, claim to have a very large but non-zero size,
// chosen to ensure that BlockSize * Blocks does not overflow int64 (which
// applications may also handle incorrectly).
// TODO(b/29637826): allow configuring a tmpfs size and enforce it.
TotalBlocks: 0,
FreeBlocks: 0,
TotalBlocks: math.MaxInt64 / usermem.PageSize,
FreeBlocks: math.MaxInt64 / usermem.PageSize,
}
// rename implements fs.InodeOperations.Rename for tmpfs nodes.
+1 -11
View File
@@ -25,7 +25,6 @@ import (
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
"gvisor.dev/gvisor/pkg/sentry/vfs"
"gvisor.dev/gvisor/pkg/syserror"
"gvisor.dev/gvisor/pkg/usermem"
)
// Sync implements vfs.FilesystemImpl.Sync.
@@ -706,16 +705,7 @@ func (fs *filesystem) StatFSAt(ctx context.Context, rp *vfs.ResolvingPath) (linu
if _, err := resolveLocked(ctx, rp); err != nil {
return linux.Statfs{}, err
}
statfs := linux.Statfs{
Type: linux.TMPFS_MAGIC,
BlockSize: usermem.PageSize,
FragmentSize: usermem.PageSize,
NameLength: linux.NAME_MAX,
// TODO(b/29637826): Allow configuring a tmpfs size and enforce it.
Blocks: 0,
BlocksFree: 0,
}
return statfs, nil
return globalStatfs, nil
}
// SymlinkAt implements vfs.FilesystemImpl.SymlinkAt.
+24
View File
@@ -201,6 +201,25 @@ func (fs *filesystem) Release(ctx context.Context) {
fs.vfsfs.VirtualFilesystem().PutAnonBlockDevMinor(fs.devMinor)
}
// immutable
var globalStatfs = linux.Statfs{
Type: linux.TMPFS_MAGIC,
BlockSize: usermem.PageSize,
FragmentSize: usermem.PageSize,
NameLength: linux.NAME_MAX,
// tmpfs currently does not support configurable size limits. In Linux,
// such a tmpfs mount will return f_blocks == f_bfree == f_bavail == 0 from
// statfs(2). However, many applications treat this as having a size limit
// of 0. To work around this, claim to have a very large but non-zero size,
// chosen to ensure that BlockSize * Blocks does not overflow int64 (which
// applications may also handle incorrectly).
// TODO(b/29637826): allow configuring a tmpfs size and enforce it.
Blocks: math.MaxInt64 / usermem.PageSize,
BlocksFree: math.MaxInt64 / usermem.PageSize,
BlocksAvailable: math.MaxInt64 / usermem.PageSize,
}
// dentry implements vfs.DentryImpl.
type dentry struct {
vfsd vfs.Dentry
@@ -698,6 +717,11 @@ func (fd *fileDescription) SetStat(ctx context.Context, opts vfs.SetStatOptions)
return nil
}
// StatFS implements vfs.FileDescriptionImpl.StatFS.
func (fd *fileDescription) StatFS(ctx context.Context) (linux.Statfs, error) {
return globalStatfs, nil
}
// Listxattr implements vfs.FileDescriptionImpl.Listxattr.
func (fd *fileDescription) Listxattr(ctx context.Context, size uint64) ([]string, error) {
return fd.inode().listxattr(size)