-
Notifications
You must be signed in to change notification settings - Fork 264
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add logic to stack lcow layers on a single VPMEM device
Signed-off-by: Maksim An <maksiman@microsoft.com>
- Loading branch information
Showing
10 changed files
with
877 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
* HCS API | ||
* | ||
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) | ||
* | ||
* API version: 2.4 | ||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) | ||
*/ | ||
|
||
package hcsschema | ||
|
||
type VirtualPMemMapping struct { | ||
HostPath string `json:"HostPath,omitempty"` | ||
ImageFormat string `json:"ImageFormat,omitempty"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
package uvm | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
) | ||
|
||
const ( | ||
MemCls1MB uint32 = iota | ||
MemCls4MB | ||
MemCls16MB | ||
MemCls64MB | ||
MemCls256MB | ||
MemCls1GB | ||
MemCls4GB | ||
) | ||
|
||
const ( | ||
MegaByte = 1024 * 1024 | ||
MemClsNum = MemCls4GB + 1 | ||
) | ||
|
||
var ( | ||
ErrInvalidMemoryClass = errors.New("invalid memory class") | ||
) | ||
|
||
// getMemoryClassType returns memory class for a given size. The smallest class is 1MB and the | ||
// largest one is 4GB with 2 bit offset intervals in between, for a total of 7 different classes | ||
func getMemoryClassType(s uint64) uint32 { | ||
s = s >> 20 | ||
memCls := uint32(0) | ||
for s > 1 { | ||
s = s >> 2 | ||
memCls++ | ||
} | ||
return memCls | ||
} | ||
|
||
// getMemoryClassSize returns size in bytes for a given memory class | ||
func getMemoryClassSize(memCls uint32) uint64 { | ||
switch memCls { | ||
case MemCls1MB: | ||
return 1 * MegaByte | ||
case MemCls4MB: | ||
return 4 * MegaByte | ||
case MemCls16MB: | ||
return 16 * MegaByte | ||
case MemCls64MB: | ||
return 64 * MegaByte | ||
case MemCls256MB: | ||
return 256 * MegaByte | ||
case MemCls1GB: | ||
return 1024 * MegaByte | ||
case MemCls4GB: | ||
return 4 * 1024 * MegaByte | ||
} | ||
return 0 | ||
} | ||
|
||
type memSlot struct { | ||
memCls uint32 | ||
offset uint64 | ||
size uint64 | ||
next *memSlot | ||
} | ||
|
||
type memoryAllocator struct { | ||
slots [MemClsNum]*memSlot | ||
busy map[uint64]*memSlot | ||
} | ||
|
||
// newDefaultMemoryAllocator returns an allocator with a single 0-offset 4GB memory slot | ||
func newDefaultMemoryAllocator() memoryAllocator { | ||
mem := memoryAllocator{ | ||
busy: make(map[uint64]*memSlot), | ||
} | ||
mem.slots[MemClsNum-1] = &memSlot{ | ||
offset: 0, | ||
size: 4 * 1024 * MegaByte, | ||
} | ||
return mem | ||
} | ||
|
||
func (mc *memoryAllocator) findFreeOffset(memCls uint32) (uint64, error) { | ||
memClsCount := uint32(len(mc.slots)) | ||
if memCls >= MemClsNum { | ||
return 0, ErrInvalidMemoryClass | ||
} | ||
|
||
for i := memCls; i < memClsCount; i++ { | ||
if ms := mc.slots[i]; ms != nil { | ||
return ms.offset, nil | ||
} | ||
} | ||
return 0, ErrNotEnoughSpace | ||
} | ||
|
||
// allocate returns first available memory slot for a given `memCls` size class. If none left, | ||
// expands the existing memCls | ||
func (mc *memoryAllocator) allocate(memCls uint32) (*memSlot, error) { | ||
if memCls >= MemClsNum { | ||
return nil, ErrInvalidMemoryClass | ||
} | ||
|
||
alloc := func() *memSlot { | ||
s := mc.slots[memCls] | ||
if s != nil { | ||
mc.slots[memCls] = s.next | ||
s.next = nil | ||
mc.busy[s.offset] = s | ||
return s | ||
} | ||
return nil | ||
} | ||
|
||
if slot := alloc(); slot != nil { | ||
return slot, nil | ||
} | ||
|
||
if err := mc.expand(memCls); err != nil { | ||
return nil, err | ||
} | ||
|
||
slot := alloc() | ||
if slot != nil { | ||
return slot, nil | ||
} | ||
|
||
return nil, ErrNotEnoughSpace | ||
} | ||
|
||
// release returns resources back, also making sure that the `offset` and `memCls` are valid | ||
func (mc *memoryAllocator) release(memCls uint32, offset uint64) error { | ||
ms, ok := mc.busy[offset] | ||
if !ok { | ||
return errors.Errorf("no memory allocated at offset: %d", offset) | ||
} | ||
|
||
if ms == nil { | ||
return errors.Errorf("expected memory slot at offset: %d, found nil instead", offset) | ||
} | ||
|
||
if memCls != ms.memCls { | ||
return errors.Errorf("invalid release request. memory slot types mismatch: actual=%d, requested=%d", ms.memCls, memCls) | ||
} | ||
|
||
delete(mc.busy, offset) | ||
ms.next = mc.slots[ms.memCls] | ||
mc.slots[ms.memCls] = ms | ||
return nil | ||
} | ||
|
||
// expand breaks down the next memory class into smaller memCls type segments | ||
func (mc *memoryAllocator) expand(memCls uint32) error { | ||
nextMemCls := memCls + 1 | ||
if nextMemCls >= MemClsNum { | ||
return ErrNotEnoughSpace | ||
} | ||
|
||
if mc.slots[nextMemCls] == nil { | ||
err := mc.expand(nextMemCls) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
nextSlot := mc.slots[nextMemCls] | ||
mc.slots[nextMemCls] = nextSlot.next | ||
nextSlot.next = nil | ||
|
||
offset := nextSlot.offset | ||
memClsSize := getMemoryClassSize(memCls) | ||
for i := uint64(0); i < 4; i++ { | ||
n := &memSlot{ | ||
size: memClsSize, | ||
offset: offset + (3-i)*memClsSize, | ||
memCls: memCls, | ||
} | ||
n.next = mc.slots[memCls] | ||
mc.slots[memCls] = n | ||
} | ||
return nil | ||
} |
Oops, something went wrong.