summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/fsutil
diff options
context:
space:
mode:
authorFabricio Voznika <fvoznika@google.com>2019-05-09 15:34:44 -0700
committerShentubot <shentubot@google.com>2019-05-09 15:35:49 -0700
commit1bee43be13549b01e18d87df194ac219845de5cf (patch)
tree4b93064a7ec8b7de2cd515a692f11f0fc311b483 /pkg/sentry/fs/fsutil
parent0f4be95a336bd5dbf214bc40eb5d1bbb5fce36a4 (diff)
Implement fallocate(2)
Closes #225 PiperOrigin-RevId: 247508791 Change-Id: I04f47cf2770b30043e5a272aba4ba6e11d0476cc
Diffstat (limited to 'pkg/sentry/fs/fsutil')
-rw-r--r--pkg/sentry/fs/fsutil/BUILD1
-rw-r--r--pkg/sentry/fs/fsutil/host_mappable.go10
-rw-r--r--pkg/sentry/fs/fsutil/inode.go25
-rw-r--r--pkg/sentry/fs/fsutil/inode_cached.go28
-rw-r--r--pkg/sentry/fs/fsutil/inode_cached_test.go9
5 files changed, 72 insertions, 1 deletions
diff --git a/pkg/sentry/fs/fsutil/BUILD b/pkg/sentry/fs/fsutil/BUILD
index 01098675d..44f43b965 100644
--- a/pkg/sentry/fs/fsutil/BUILD
+++ b/pkg/sentry/fs/fsutil/BUILD
@@ -113,5 +113,6 @@ go_test(
"//pkg/sentry/memmap",
"//pkg/sentry/safemem",
"//pkg/sentry/usermem",
+ "//pkg/syserror",
],
)
diff --git a/pkg/sentry/fs/fsutil/host_mappable.go b/pkg/sentry/fs/fsutil/host_mappable.go
index 28686f3b3..ad0518b8f 100644
--- a/pkg/sentry/fs/fsutil/host_mappable.go
+++ b/pkg/sentry/fs/fsutil/host_mappable.go
@@ -149,7 +149,7 @@ func (h *HostMappable) Truncate(ctx context.Context, newSize int64) error {
}
// Invalidate COW mappings that may exist beyond the new size in case the file
- // is being shrunk. Other mappinsg don't need to be invalidated because
+ // is being shrunk. Other mappings don't need to be invalidated because
// translate will just return identical mappings after invalidation anyway,
// and SIGBUS will be raised and handled when the mappings are touched.
//
@@ -167,6 +167,14 @@ func (h *HostMappable) Truncate(ctx context.Context, newSize int64) error {
return nil
}
+// Allocate reserves space in the backing file.
+func (h *HostMappable) Allocate(ctx context.Context, offset int64, length int64) error {
+ h.truncateMu.RLock()
+ err := h.backingFile.Allocate(ctx, offset, length)
+ h.truncateMu.RUnlock()
+ return err
+}
+
// Write writes to the file backing this mappable.
func (h *HostMappable) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
h.truncateMu.RLock()
diff --git a/pkg/sentry/fs/fsutil/inode.go b/pkg/sentry/fs/fsutil/inode.go
index b6366d906..151be1d0d 100644
--- a/pkg/sentry/fs/fsutil/inode.go
+++ b/pkg/sentry/fs/fsutil/inode.go
@@ -34,6 +34,7 @@ type SimpleFileInode struct {
InodeNoExtendedAttributes `state:"nosave"`
InodeNoopRelease `state:"nosave"`
InodeNoopWriteOut `state:"nosave"`
+ InodeNotAllocatable `state:"nosave"`
InodeNotDirectory `state:"nosave"`
InodeNotMappable `state:"nosave"`
InodeNotOpenable `state:"nosave"`
@@ -61,6 +62,7 @@ type NoReadWriteFileInode struct {
InodeNoExtendedAttributes `state:"nosave"`
InodeNoopRelease `state:"nosave"`
InodeNoopWriteOut `state:"nosave"`
+ InodeNotAllocatable `state:"nosave"`
InodeNotDirectory `state:"nosave"`
InodeNotMappable `state:"nosave"`
InodeNotSocket `state:"nosave"`
@@ -465,3 +467,26 @@ func (InodeDenyWriteChecker) Check(ctx context.Context, inode *fs.Inode, p fs.Pe
}
return fs.ContextCanAccessFile(ctx, inode, p)
}
+
+//InodeNotAllocatable can be used by Inodes that do not support Allocate().
+type InodeNotAllocatable struct{}
+
+func (InodeNotAllocatable) Allocate(_ context.Context, _ *fs.Inode, _, _ int64) error {
+ return syserror.EOPNOTSUPP
+}
+
+// InodeNoopAllocate implements fs.InodeOperations.Allocate as a noop.
+type InodeNoopAllocate struct{}
+
+// Allocate implements fs.InodeOperations.Allocate.
+func (InodeNoopAllocate) Allocate(_ context.Context, _ *fs.Inode, _, _ int64) error {
+ return nil
+}
+
+// InodeIsDirAllocate implements fs.InodeOperations.Allocate for directories.
+type InodeIsDirAllocate struct{}
+
+// Allocate implements fs.InodeOperations.Allocate.
+func (InodeIsDirAllocate) Allocate(_ context.Context, _ *fs.Inode, _, _ int64) error {
+ return syserror.EISDIR
+}
diff --git a/pkg/sentry/fs/fsutil/inode_cached.go b/pkg/sentry/fs/fsutil/inode_cached.go
index 76644e69d..03cad37f3 100644
--- a/pkg/sentry/fs/fsutil/inode_cached.go
+++ b/pkg/sentry/fs/fsutil/inode_cached.go
@@ -135,6 +135,10 @@ type CachedFileObject interface {
// the file was opened.
SetMaskedAttributes(ctx context.Context, mask fs.AttrMask, attr fs.UnstableAttr) error
+ // Allocate allows the caller to reserve disk space for the inode.
+ // It's equivalent to fallocate(2) with 'mode=0'.
+ Allocate(ctx context.Context, offset int64, length int64) error
+
// Sync instructs the remote filesystem to sync the file to stable storage.
Sync(ctx context.Context) error
@@ -336,6 +340,30 @@ func (c *CachingInodeOperations) Truncate(ctx context.Context, inode *fs.Inode,
return nil
}
+// Allocate implements fs.InodeOperations.Allocate.
+func (c *CachingInodeOperations) Allocate(ctx context.Context, offset, length int64) error {
+ newSize := offset + length
+
+ // c.attr.Size is protected by both c.attrMu and c.dataMu.
+ c.attrMu.Lock()
+ defer c.attrMu.Unlock()
+ c.dataMu.Lock()
+ defer c.dataMu.Unlock()
+
+ if newSize <= c.attr.Size {
+ return nil
+ }
+
+ now := ktime.NowFromContext(ctx)
+ if err := c.backingFile.Allocate(ctx, offset, length); err != nil {
+ return err
+ }
+
+ c.attr.Size = newSize
+ c.touchModificationTimeLocked(now)
+ return nil
+}
+
// WriteOut implements fs.InodeOperations.WriteOut.
func (c *CachingInodeOperations) WriteOut(ctx context.Context, inode *fs.Inode) error {
c.attrMu.Lock()
diff --git a/pkg/sentry/fs/fsutil/inode_cached_test.go b/pkg/sentry/fs/fsutil/inode_cached_test.go
index 3f10efc12..be3d4b6fc 100644
--- a/pkg/sentry/fs/fsutil/inode_cached_test.go
+++ b/pkg/sentry/fs/fsutil/inode_cached_test.go
@@ -26,6 +26,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/memmap"
"gvisor.googlesource.com/gvisor/pkg/sentry/safemem"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
+ "gvisor.googlesource.com/gvisor/pkg/syserror"
)
type noopBackingFile struct{}
@@ -50,6 +51,10 @@ func (noopBackingFile) FD() int {
return -1
}
+func (noopBackingFile) Allocate(ctx context.Context, offset int64, length int64) error {
+ return nil
+}
+
func TestSetPermissions(t *testing.T) {
ctx := contexttest.Context(t)
@@ -237,6 +242,10 @@ func (*sliceBackingFile) FD() int {
return -1
}
+func (f *sliceBackingFile) Allocate(ctx context.Context, offset int64, length int64) error {
+ return syserror.EOPNOTSUPP
+}
+
type noopMappingSpace struct{}
// Invalidate implements memmap.MappingSpace.Invalidate.