[port] Count ephemeral packets from default arena
If a port packet is allocated from an arena that is not the default, it
should not be counted towards the default arena limit.
ZX-4220 #done
Change-Id: I46dc0f5eb683dfd80cc7affa8fa71a59a19372ea
diff --git a/zircon/kernel/object/port_dispatcher.cpp b/zircon/kernel/object/port_dispatcher.cpp
index 0c0bfef..f5c935e 100644
--- a/zircon/kernel/object/port_dispatcher.cpp
+++ b/zircon/kernel/object/port_dispatcher.cpp
@@ -58,6 +58,10 @@
// TODO(maniscalco): Enforce this limit per process via the job policy.
constexpr size_t kMaxAllocatedPacketCountPerPort = kMaxAllocatedPacketCount / 8;
ArenaPortAllocator port_allocator;
+
+bool IsDefaultAllocatedEphemeral(const PortPacket& port_packet) {
+ return port_packet.allocator == &port_allocator && port_packet.is_ephemeral();
+}
} // namespace.
zx_status_t ArenaPortAllocator::Init() {
@@ -215,7 +219,7 @@
// If the packet is ephemeral, free it outside of the lock. Otherwise,
// reset the observer if it is present.
- if (packet->is_ephemeral()) {
+ if (IsDefaultAllocatedEphemeral(*packet)) {
--num_ephemeral_packets_;
guard.CallUnlocked([packet]() {
packet->Free();
@@ -300,7 +304,8 @@
if (zero_handles_)
return ZX_ERR_BAD_STATE;
- if (port_packet->is_ephemeral() && num_ephemeral_packets_ > kMaxAllocatedPacketCountPerPort) {
+ if (IsDefaultAllocatedEphemeral(*port_packet) &&
+ num_ephemeral_packets_ > kMaxAllocatedPacketCountPerPort) {
kcounter_add(port_full_count, 1);
return ZX_ERR_SHOULD_WAIT;
}
@@ -315,7 +320,7 @@
port_packet->packet.signal.count = count;
}
packets_.push_back(port_packet);
- if (port_packet->is_ephemeral()) {
+ if (IsDefaultAllocatedEphemeral(*port_packet)) {
++num_ephemeral_packets_;
}
// This Disable() call must come before Post() to be useful, but doing
@@ -347,7 +352,7 @@
Guard<fbl::Mutex> guard{get_lock()};
PortPacket* port_packet = packets_.pop_front();
if (port_packet != nullptr) {
- if (port_packet->is_ephemeral()) {
+ if (IsDefaultAllocatedEphemeral(*port_packet)) {
--num_ephemeral_packets_;
}
*out_packet = port_packet->packet;
@@ -478,7 +483,7 @@
for (auto it = packets_.begin(); it != packets_.end();) {
if ((it->handle == handle) && (it->key() == key)) {
auto to_remove = it++;
- if (to_remove->is_ephemeral()) {
+ if (IsDefaultAllocatedEphemeral(*to_remove)) {
--num_ephemeral_packets_;
}
// Destroyed as we go around the loop.
@@ -499,7 +504,7 @@
Guard<fbl::Mutex> guard{get_lock()};
if (port_packet->InContainer()) {
- if (port_packet->is_ephemeral()) {
+ if (IsDefaultAllocatedEphemeral(*port_packet)) {
--num_ephemeral_packets_;
}
packets_.erase(*port_packet)->observer.reset();
diff --git a/zircon/system/utest/hypervisor/guest.cpp b/zircon/system/utest/hypervisor/guest.cpp
index f75c2d7..6886e30 100644
--- a/zircon/system/utest/hypervisor/guest.cpp
+++ b/zircon/system/utest/hypervisor/guest.cpp
@@ -521,6 +521,37 @@
END_TEST;
}
+// Test for ZX-4220.
+static bool guest_set_trap_with_bell_and_max_user() {
+ BEGIN_TEST;
+
+ zx::port port;
+ ASSERT_EQ(zx::port::create(0, &port), ZX_OK);
+
+ // Keep queueing packets until we receive ZX_ERR_SHOULD_WAIT.
+ zx_port_packet packet = {};
+ packet.type = ZX_PKT_TYPE_USER;
+ zx_status_t status = ZX_OK;
+ while ((status = port.queue(&packet)) == ZX_OK) {}
+ ASSERT_EQ(status, ZX_ERR_SHOULD_WAIT);
+
+ test_t test;
+ ASSERT_TRUE(setup(&test, guest_set_trap_start, guest_set_trap_end));
+ if (!test.supported) {
+ // The hypervisor isn't supported, so don't run the test.
+ return true;
+ }
+
+ // Trap on access of TRAP_ADDR.
+ ASSERT_EQ(test.guest.set_trap(ZX_GUEST_TRAP_BELL, TRAP_ADDR, PAGE_SIZE, port, kTrapKey), ZX_OK);
+
+ ASSERT_EQ(test.vcpu.resume(&packet), ZX_OK);
+ EXPECT_EQ(packet.type, ZX_PKT_TYPE_GUEST_MEM);
+ EXPECT_EQ(packet.guest_mem.addr, EXIT_TEST_ADDR);
+
+ END_TEST;
+}
+
#ifdef __aarch64__
static bool vcpu_wfi() {
@@ -941,6 +972,7 @@
RUN_TEST(guest_set_trap_with_bell)
RUN_TEST(guest_set_trap_with_bell_drop)
RUN_TEST(guest_set_trap_with_bell_and_user)
+RUN_TEST(guest_set_trap_with_bell_and_max_user)
#if __aarch64__
RUN_TEST(vcpu_wfi)
RUN_TEST(vcpu_wfi_pending_interrupt)