summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fs/ext/inode.go
diff options
context:
space:
mode:
authorAyush Ranjan <ayushranjan@google.com>2019-07-23 20:34:49 -0700
committergVisor bot <gvisor-bot@google.com>2019-07-23 20:36:04 -0700
commit7e38d643334647fb79c7cc8be35745699de264e6 (patch)
treef6470d9f953dc7274ee98f1af62736a7493ef68c /pkg/sentry/fs/ext/inode.go
parentd7bb79b6f177e8c58d47695e0ee1a072475463c4 (diff)
ext: Inode creation logic.
PiperOrigin-RevId: 259666476
Diffstat (limited to 'pkg/sentry/fs/ext/inode.go')
-rw-r--r--pkg/sentry/fs/ext/inode.go71
1 files changed, 63 insertions, 8 deletions
diff --git a/pkg/sentry/fs/ext/inode.go b/pkg/sentry/fs/ext/inode.go
index 5bf9dbfa3..df1ea0bda 100644
--- a/pkg/sentry/fs/ext/inode.go
+++ b/pkg/sentry/fs/ext/inode.go
@@ -28,12 +28,16 @@ type inode struct {
// refs is a reference count. refs is accessed using atomic memory operations.
refs int64
+ // inodeNum is the inode number of this inode on disk. This is used to
+ // identify inodes within the ext filesystem.
+ inodeNum uint32
+
// diskInode gives us access to the inode struct on disk. Immutable.
diskInode disklayout.Inode
// root is the root extent node. This lives in the 60 byte diskInode.Blocks().
- // Immutable.
- root disklayout.ExtentNode
+ // Immutable. Nil if the inode does not use extents.
+ root *disklayout.ExtentNode
}
// incRef increments the inode ref count.
@@ -54,20 +58,71 @@ func (in *inode) tryIncRef() bool {
}
}
-// decRef decrements the inode ref count.
-func (in *inode) decRef() {
- if refs := atomic.AddInt64(&in.refs, -1); refs < 0 {
+// decRef decrements the inode ref count and releases the inode resources if
+// the ref count hits 0.
+//
+// Preconditions: Must have locked fs.mu.
+func (in *inode) decRef(fs *filesystem) {
+ if refs := atomic.AddInt64(&in.refs, -1); refs == 0 {
+ delete(fs.inodeCache, in.inodeNum)
+ } else if refs < 0 {
panic("ext.inode.decRef() called without holding a reference")
}
}
+// newInode is the inode constructor. Reads the inode off disk. Identifies
+// inodes based on the absolute inode number on disk.
+//
+// Preconditions: Must hold the mutex of the filesystem containing dev.
+func newInode(dev io.ReadSeeker, sb disklayout.SuperBlock, bgs []disklayout.BlockGroup, inodeNum uint32) (*inode, error) {
+ if inodeNum == 0 {
+ panic("inode number 0 on ext filesystems is not possible")
+ }
+
+ in := &inode{refs: 1, inodeNum: inodeNum}
+ inodeRecordSize := sb.InodeSize()
+ if inodeRecordSize == disklayout.OldInodeSize {
+ in.diskInode = &disklayout.InodeOld{}
+ } else {
+ in.diskInode = &disklayout.InodeNew{}
+ }
+
+ // Calculate where the inode is actually placed.
+ inodesPerGrp := sb.InodesPerGroup()
+ blkSize := sb.BlockSize()
+ inodeTableOff := bgs[getBGNum(inodeNum, inodesPerGrp)].InodeTable() * blkSize
+ inodeOff := inodeTableOff + uint64(uint32(inodeRecordSize)*getBGOff(inodeNum, inodesPerGrp))
+
+ // Read it from disk and figure out which type of inode this is.
+ if err := readFromDisk(dev, int64(inodeOff), in.diskInode); err != nil {
+ return nil, err
+ }
+
+ if in.diskInode.Flags().Extents {
+ in.buildExtTree(dev, blkSize)
+ }
+
+ return in, nil
+}
+
+// getBGNum returns the block group number that a given inode belongs to.
+func getBGNum(inodeNum uint32, inodesPerGrp uint32) uint32 {
+ return (inodeNum - 1) / inodesPerGrp
+}
+
+// getBGOff returns the offset at which the given inode lives in the block
+// group's inode table, i.e. the index of the inode in the inode table.
+func getBGOff(inodeNum uint32, inodesPerGrp uint32) uint32 {
+ return (inodeNum - 1) % inodesPerGrp
+}
+
// buildExtTree builds the extent tree by reading it from disk by doing
// running a simple DFS. It first reads the root node from the inode struct in
// memory. Then it recursively builds the rest of the tree by reading it off
// disk.
//
// Preconditions:
-// - Must have mutual exclusion on device fd.
+// - Must hold the mutex of the filesystem containing dev.
// - Inode flag InExtents must be set.
func (in *inode) buildExtTree(dev io.ReadSeeker, blkSize uint64) error {
rootNodeData := in.diskInode.Data()
@@ -106,7 +161,7 @@ func (in *inode) buildExtTree(dev io.ReadSeeker, blkSize uint64) error {
}
}
- in.root = disklayout.ExtentNode{rootHeader, rootEntries}
+ in.root = &disklayout.ExtentNode{rootHeader, rootEntries}
return nil
}
@@ -114,7 +169,7 @@ func (in *inode) buildExtTree(dev io.ReadSeeker, blkSize uint64) error {
// builds the tree. Performs a simple DFS. It returns the ExtentNode pointed to
// by the ExtentEntry.
//
-// Preconditions: Must have mutual exclusion on device fd.
+// Preconditions: Must hold the mutex of the filesystem containing dev.
func buildExtTreeFromDisk(dev io.ReadSeeker, entry disklayout.ExtentEntry, blkSize uint64) (*disklayout.ExtentNode, error) {
var header disklayout.ExtentHeader
off := entry.PhysicalBlock() * blkSize