Skip to content

Commit dd22578

Browse files
authored
Merge branch 'main' into fix-ext4-partial-last-block-group
2 parents 6788e25 + 03280f3 commit dd22578

11 files changed

Lines changed: 211 additions & 16 deletions

File tree

Sources/Containerization/LinuxContainer.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,7 @@ extension LinuxContainer {
551551
var modifiedRootfs = self.rootfs
552552
modifiedRootfs.options.removeAll(where: { $0 == "ro" })
553553

554-
let mib: UInt64 = 1.mib()
555-
let vmMemory = (self.memoryInBytes + self.config.memoryOverhead + mib - 1) & ~(mib - 1)
554+
let vmMemory = self.memoryInBytes + self.config.memoryOverhead
556555

557556
let vmCpus = self.cpus + self.config.cpuOverhead
558557

Sources/Containerization/Signal.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,35 @@ extension Signal {
254254

255255
#endif
256256

257+
extension Signal {
258+
private static let platformToName: [Int32: String] =
259+
Dictionary(Signal.platform.map { ($0.value, $0.key) }, uniquingKeysWith: { first, _ in first })
260+
261+
/// Returns the canonical name for this signal on the current platform.
262+
public func platformName() -> String? {
263+
Self.platformName(self.rawValue)
264+
}
265+
266+
/// Returns the canonical name for a signal number on the current platform.
267+
public static func platformName(_ signal: Int32) -> String? {
268+
platformToName[signal]
269+
}
270+
}
271+
272+
#if os(macOS)
273+
extension Signal {
274+
/// Converts a macOS signal to the equivalent Linux signal.
275+
public func linuxSignal() -> Signal? {
276+
guard let name = Self.platformToName[self.rawValue],
277+
let linuxNumber = Signal.linux[name]
278+
else {
279+
return nil
280+
}
281+
return Signal(rawValue: linuxNumber)
282+
}
283+
}
284+
#endif
285+
257286
extension Signal: ExpressibleByIntegerLiteral {
258287
public init(integerLiteral value: Int32) {
259288
self.rawValue = value

Sources/Containerization/VZVirtualMachineInstance.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,8 @@ extension VZVirtualMachineInstance.Configuration {
315315
var config = VZVirtualMachineConfiguration()
316316

317317
config.cpuCount = self.cpus
318-
config.memorySize = self.memoryInBytes
318+
let mib: UInt64 = 1 << 20
319+
config.memorySize = (self.memoryInBytes + mib - 1) & ~(mib - 1)
319320
config.entropyDevices = [VZVirtioEntropyDeviceConfiguration()]
320321
config.socketDevices = [VZVirtioSocketDeviceConfiguration()]
321322

Sources/ContainerizationOS/AsyncSignalHandler.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ public final class AsyncSignalHandler: Sendable {
7878

7979
private let state: Mutex<State> = .init(State())
8080

81+
/// Create a new `AsyncSignalHandler` that catches all signals.
82+
public static func catchAll() -> AsyncSignalHandler {
83+
#if os(macOS)
84+
let range = 1...31
85+
#else
86+
let range = 1...64
87+
#endif
88+
return create(notify: range.map { Int32($0) })
89+
}
90+
8191
/// Create a new `AsyncSignalHandler` for the list of given signals `notify`.
8292
/// The default signal handlers for these signals are removed and async handlers
8393
/// added in their place. The async signal handlers that are installed simply

Sources/Integration/ContainerTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ extension IntegrationSuite {
3333
let bs = try await bootstrap(id)
3434
let container = try LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm) { config in
3535
config.process.arguments = ["/bin/true"]
36+
config.memoryInBytes = 250_000_000
3637
config.bootLog = bs.bootLog
3738
}
3839

Sources/Integration/PodTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ extension IntegrationSuite {
495495
let bs = try await bootstrap(id)
496496
let pod = try LinuxPod(id, vmm: bs.vmm) { config in
497497
config.cpus = 4
498-
config.memoryInBytes = 1024.mib()
498+
config.memoryInBytes = 1_000_000_000
499499
config.bootLog = bs.bootLog
500500
}
501501

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//===----------------------------------------------------------------------===//
2+
// Copyright © 2026 Apple Inc. and the Containerization project authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//===----------------------------------------------------------------------===//
16+
17+
import Foundation
18+
import Testing
19+
20+
@testable import ContainerizationExtras
21+
22+
private final class Unprotected: @unchecked Sendable {
23+
var value: Int
24+
init(_ value: Int) { self.value = value }
25+
}
26+
27+
final class AsyncLockTests {
28+
@Test
29+
func testBasicModification() async throws {
30+
let lock = AsyncLock()
31+
let counter = Unprotected(0)
32+
33+
let result = await lock.withLock { _ in
34+
counter.value += 1
35+
return counter.value
36+
}
37+
38+
#expect(result == 1)
39+
}
40+
41+
@Test
42+
func testSequentialReturnValues() async throws {
43+
let lock = AsyncLock()
44+
45+
let first = await lock.withLock { _ in 1 }
46+
let second = await lock.withLock { _ in first + 1 }
47+
let third = await lock.withLock { _ in second + 1 }
48+
49+
#expect(third == 3)
50+
}
51+
52+
@Test
53+
func testMultipleModifications() async throws {
54+
let lock = AsyncLock()
55+
let counter = Unprotected(0)
56+
57+
await lock.withLock { _ in
58+
counter.value += 5
59+
}
60+
61+
let result = await lock.withLock { value in
62+
counter.value += 10
63+
return counter.value
64+
}
65+
66+
#expect(result == 15)
67+
}
68+
69+
@Test
70+
func testMutualExclusion() async throws {
71+
let lock = AsyncLock()
72+
let counter = Unprotected(0)
73+
let iterations = 100
74+
75+
await withTaskGroup(of: Void.self) { group in
76+
for _ in 0..<iterations {
77+
group.addTask {
78+
await lock.withLock { _ in
79+
let current = counter.value
80+
try? await Task.sleep(for: .milliseconds(10))
81+
counter.value = current + 1
82+
}
83+
}
84+
}
85+
}
86+
87+
#expect(counter.value == iterations)
88+
}
89+
90+
@Test
91+
func testThrowingClosure() async throws {
92+
let lock = AsyncLock()
93+
let counter = Unprotected(0)
94+
95+
await #expect(throws: POSIXError.self) {
96+
try await lock.withLock { _ in
97+
counter.value = 1
98+
throw POSIXError(.ENOENT)
99+
}
100+
}
101+
102+
// Value should still be modified even though closure threw
103+
#expect(counter.value == 1)
104+
105+
// Lock should still be usable even though the previous closure threw
106+
await lock.withLock { _ in
107+
counter.value = 2
108+
}
109+
110+
#expect(counter.value == 2)
111+
}
112+
}

kernel/config-arm64

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3503,7 +3503,15 @@ CONFIG_RPCSEC_GSS_KRB5=y
35033503
# CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set
35043504
# CONFIG_SUNRPC_DEBUG is not set
35053505
# CONFIG_CEPH_FS is not set
3506-
# CONFIG_CIFS is not set
3506+
CONFIG_CIFS=y
3507+
# CONFIG_CIFS_STATS2 is not set
3508+
CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y
3509+
CONFIG_CIFS_UPCALL=y
3510+
CONFIG_CIFS_XATTR=y
3511+
CONFIG_CIFS_POSIX=y
3512+
# CONFIG_CIFS_DEBUG is not set
3513+
CONFIG_CIFS_DFS_UPCALL=y
3514+
# CONFIG_CIFS_SMB_DIRECT is not set
35073515
# CONFIG_SMB_SERVER is not set
35083516
# CONFIG_CODA_FS is not set
35093517
# CONFIG_AFS_FS is not set

vminitd/Sources/VminitdCore/IOCloser.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,15 @@ protocol IOCloser: Sendable {
1919

2020
func close() throws
2121
}
22+
23+
struct UnownedIOCloser: IOCloser {
24+
private let inner: IOCloser
25+
26+
var fileDescriptor: Int32 { inner.fileDescriptor }
27+
28+
init(_ inner: IOCloser) {
29+
self.inner = inner
30+
}
31+
32+
func close() throws {}
33+
}

vminitd/Sources/VminitdCore/IOPair.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ final class IOPair: Sendable {
3030
let to: IOCloser
3131
let buffer: UnsafeMutableBufferPointer<UInt8>
3232
var closed: Bool
33+
var registeredFd: Int32?
3334

3435
func drain() {
3536
let readFrom = OSFile(fd: from.fileDescriptor)
@@ -67,11 +68,13 @@ final class IOPair: Sendable {
6768
self.drain()
6869

6970
// Remove the fd from our global epoll instance first.
70-
let readFromFd = self.from.fileDescriptor
71-
do {
72-
try ProcessSupervisor.default.unregisterFd(readFromFd)
73-
} catch {
74-
logger?.error("failed to delete fd from epoll \(readFromFd): \(error)")
71+
if let fd = self.registeredFd {
72+
do {
73+
try ProcessSupervisor.default.unregisterFd(fd)
74+
} catch {
75+
logger?.error("failed to delete fd from epoll \(fd): \(error)")
76+
}
77+
self.registeredFd = nil
7578
}
7679

7780
do {
@@ -102,7 +105,8 @@ final class IOPair: Sendable {
102105
from: readFrom,
103106
to: writeTo,
104107
buffer: buffer,
105-
closed: false
108+
closed: false,
109+
registeredFd: nil
106110
))
107111
self.reason = reason
108112
self.logger = logger
@@ -112,7 +116,8 @@ final class IOPair: Sendable {
112116
self.logger?.info("setting up relay for \(reason)")
113117

114118
let (readFromFd, writeToFd) = self.io.withLock { io in
115-
(io.from.fileDescriptor, io.to.fileDescriptor)
119+
io.registeredFd = io.from.fileDescriptor
120+
return (io.from.fileDescriptor, io.to.fileDescriptor)
116121
}
117122

118123
let readFrom = OSFile(fd: readFromFd)

0 commit comments

Comments
 (0)