Skip to content

Commit 943b003

Browse files
authored
vmbus_server: revert to creating interrupts before channel open (#1850)
This change reverts the changes made by #649. While the model used by that change was better, it was discovered that some channels, notably some IC channels, begin communicating as soon as the device is notified of the open. This leads to the possibility of the guest attempting to send an interrupt before the synic event port was created, so the interrupt would be lost. This change therefore moves the creation of the guest-to-host event port back to when the open request is received. Note that this is not a straight-forward revert of the original commit, as the code had diverged too much, particularly because the synic handling for vmbus_relay was moved into vmbus_client. This is therefore essentially a new change that reverts to the same functionality as before.
1 parent 89ba9c3 commit 943b003

File tree

12 files changed

+187
-308
lines changed

12 files changed

+187
-308
lines changed

vm/devices/net/netvsp/src/test.rs

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ use vmbus_channel::bus::OfferInput;
5757
use vmbus_channel::bus::OfferResources;
5858
use vmbus_channel::bus::OpenData;
5959
use vmbus_channel::bus::OpenRequest;
60-
use vmbus_channel::bus::OpenResult;
6160
use vmbus_channel::bus::ParentBus;
6261
use vmbus_channel::channel::ChannelHandle;
6362
use vmbus_channel::channel::VmbusDevice;
@@ -87,7 +86,7 @@ use zerocopy::KnownLayout;
8786
const VMNIC_CHANNEL_TYPE_GUID: Guid = guid::guid!("f8615163-df3e-46c5-913f-f2d2f965ed0e");
8887

8988
enum ChannelResponse {
90-
Open(Option<OpenResult>),
89+
Open(bool),
9190
Close,
9291
Gpadl(bool),
9392
// TeardownGpadl(GpadlId),
@@ -576,18 +575,19 @@ impl TestNicDevice {
576575
.await
577576
.expect("open successful");
578577

579-
let ChannelResponse::Open(Some(result)) = open_response else {
578+
let ChannelResponse::Open(true) = open_response else {
580579
panic!("Unexpected return value");
581580
};
582581

583582
let mem = self.mock_vmbus.memory.clone();
583+
let guest_to_host_interrupt = self.offer_input.event.clone();
584584
TestNicChannel::new(
585585
self,
586586
&mem,
587587
gpadl_map,
588588
ring_gpadl_id,
589589
host_to_guest_event,
590-
result.guest_to_host_interrupt,
590+
guest_to_host_interrupt,
591591
)
592592
}
593593

@@ -631,16 +631,17 @@ impl TestNicDevice {
631631
.await
632632
.expect("open successful");
633633

634-
let ChannelResponse::Open(Some(result)) = open_response else {
634+
let ChannelResponse::Open(true) = open_response else {
635635
panic!("Unexpected return value");
636636
};
637637

638+
let guest_to_host_interrupt = self.offer_input.event.clone();
638639
TestNicSubchannel::new(
639640
&self.mock_vmbus.memory,
640641
gpadl_map,
641642
ring_gpadl_id,
642643
host_to_guest_event,
643-
result.guest_to_host_interrupt,
644+
guest_to_host_interrupt,
644645
)
645646
}
646647

@@ -690,7 +691,7 @@ impl TestNicDevice {
690691
next_avail_guest_page: usize,
691692
next_avail_gpadl_id: u32,
692693
host_to_guest_interrupt: Interrupt,
693-
) -> anyhow::Result<Option<Interrupt>> {
694+
) -> anyhow::Result<()> {
694695
// Restore the previous memory settings
695696
assert_eq!(self.next_avail_gpadl_id, 1);
696697
self.next_avail_gpadl_id = next_avail_gpadl_id;
@@ -709,7 +710,6 @@ impl TestNicDevice {
709710
})
710711
.collect::<Vec<(GpadlId, MultiPagedRangeBuf<Vec<u64>>)>>();
711712

712-
let mut guest_to_host_interrupt = None;
713713
mesh::CancelContext::new()
714714
.with_timeout(Duration::from_millis(1000))
715715
.until_cancelled(async {
@@ -732,8 +732,7 @@ impl TestNicDevice {
732732
accepted: true,
733733
}
734734
}).collect::<Vec<vmbus_channel::bus::RestoredGpadl>>();
735-
rpc.handle_sync(|open| {
736-
guest_to_host_interrupt = open.map(|open| open.guest_to_host_interrupt);
735+
rpc.handle_sync(|_open| {
737736
Ok(vmbus_channel::bus::RestoreResult {
738737
open_request: Some(OpenRequest {
739738
open_data: OpenData {
@@ -761,7 +760,7 @@ impl TestNicDevice {
761760
.await
762761
.unwrap()?;
763762

764-
Ok(guest_to_host_interrupt)
763+
Ok(())
765764
}
766765
}
767766

@@ -1275,6 +1274,7 @@ impl<'a> TestNicChannel<'a> {
12751274
buffer: SavedStateBlob,
12761275
) -> anyhow::Result<TestNicChannel<'_>> {
12771276
let mem = self.nic.mock_vmbus.memory.clone();
1277+
let guest_to_host_interrupt = nic.offer_input.event.clone();
12781278
let host_to_guest_interrupt = {
12791279
let event = self.host_to_guest_event.clone();
12801280
Interrupt::from_fn(move || event.signal())
@@ -1285,17 +1285,15 @@ impl<'a> TestNicChannel<'a> {
12851285
let next_avail_guest_page = self.nic.next_avail_guest_page;
12861286
let next_avail_gpadl_id = self.nic.next_avail_gpadl_id;
12871287

1288-
let guest_to_host_interrupt = nic
1289-
.restore(
1290-
buffer,
1291-
gpadl_map.clone(),
1292-
channel_id,
1293-
next_avail_guest_page,
1294-
next_avail_gpadl_id,
1295-
host_to_guest_interrupt,
1296-
)
1297-
.await?
1298-
.expect("should be open");
1288+
nic.restore(
1289+
buffer,
1290+
gpadl_map.clone(),
1291+
channel_id,
1292+
next_avail_guest_page,
1293+
next_avail_gpadl_id,
1294+
host_to_guest_interrupt,
1295+
)
1296+
.await?;
12991297

13001298
Ok(TestNicChannel::new(
13011299
nic,

vm/devices/vmbus/vmbus_channel/src/bus.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use vmcore::interrupt::Interrupt;
2323
pub struct OfferInput {
2424
/// Parameters describing the offer.
2525
pub params: OfferParams,
26+
/// The event to signal when the guest needs attention.
27+
pub event: Interrupt,
2628
/// A mesh channel to send channel-related requests to.
2729
pub request_send: mesh::Sender<ChannelRequest>,
2830
/// A mesh channel to receive channel-related requests to.
@@ -79,7 +81,7 @@ impl OfferResources {
7981
#[derive(Debug, MeshPayload)]
8082
pub enum ChannelRequest {
8183
/// Open the channel.
82-
Open(Rpc<OpenRequest, Option<OpenResult>>),
84+
Open(Rpc<OpenRequest, bool>),
8385
/// Close the channel.
8486
///
8587
/// Although there is no response from the host, this is still modeled as an
@@ -94,14 +96,6 @@ pub enum ChannelRequest {
9496
Modify(Rpc<ModifyRequest, i32>),
9597
}
9698

97-
/// The successful result of an open request.
98-
#[derive(Debug, MeshPayload)]
99-
pub struct OpenResult {
100-
/// The interrupt object vmbus should signal when the guest signals the
101-
/// host.
102-
pub guest_to_host_interrupt: Interrupt,
103-
}
104-
10599
/// GPADL information from the guest.
106100
#[derive(Debug, MeshPayload)]
107101
pub struct GpadlRequest {
@@ -128,8 +122,8 @@ pub enum ModifyRequest {
128122
pub enum ChannelServerRequest {
129123
/// A request to restore the channel.
130124
///
131-
/// The input parameter provides the open result if the channel was saved open.
132-
Restore(FailableRpc<Option<OpenResult>, RestoreResult>),
125+
/// The input parameter indicates if the channel was saved open.
126+
Restore(FailableRpc<bool, RestoreResult>),
133127
/// A request to revoke the channel.
134128
///
135129
/// A channel can also be revoked by dropping it. This request is only necessary if you need to
@@ -176,8 +170,7 @@ pub trait ParentBus: Send + Sync {
176170
/// time.
177171
fn clone_bus(&self) -> Box<dyn ParentBus>;
178172

179-
/// Returns whether [`OpenResult::guest_to_host_interrupt`] needs to be
180-
/// backed by an OS event.
173+
/// Returns whether [`OfferInput::event`] needs to be backed by an OS event.
181174
///
182175
/// TODO: Remove this and just return the appropriate notify type directly
183176
/// once subchannel creation and enable are separated.

vm/devices/vmbus/vmbus_channel/src/channel.rs

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::bus::OfferInput;
1010
use crate::bus::OfferParams;
1111
use crate::bus::OfferResources;
1212
use crate::bus::OpenRequest;
13-
use crate::bus::OpenResult;
1413
use crate::bus::ParentBus;
1514
use crate::gpadl::GpadlMap;
1615
use crate::gpadl::GpadlMapView;
@@ -334,6 +333,7 @@ async fn offer_generic(
334333

335334
let request = OfferInput {
336335
params: offer,
336+
event: events[0].clone().interrupt(),
337337
request_send,
338338
server_request_recv,
339339
};
@@ -592,22 +592,21 @@ impl Device {
592592
channel: &mut dyn VmbusDevice,
593593
channel_idx: usize,
594594
open_request: OpenRequest,
595-
) -> Option<OpenResult> {
595+
) -> bool {
596596
assert!(!self.open[channel_idx]);
597597
// N.B. Any asynchronous GPADL requests will block while in
598598
// open(). This should be fine for all known devices.
599-
let opened = if let Err(error) = channel.open(channel_idx as u16, &open_request).await {
600-
tracelimit::error_ratelimited!(
601-
error = error.as_ref() as &dyn std::error::Error,
602-
"failed to open channel"
603-
);
604-
None
605-
} else {
606-
Some(OpenResult {
607-
guest_to_host_interrupt: self.events[channel_idx].clone().interrupt(),
599+
let opened = channel
600+
.open(channel_idx as u16, &open_request)
601+
.await
602+
.inspect_err(|error| {
603+
tracelimit::error_ratelimited!(
604+
error = error.as_ref() as &dyn std::error::Error,
605+
"failed to open channel"
606+
);
608607
})
609-
};
610-
self.open[channel_idx] = opened.is_some();
608+
.is_ok();
609+
self.open[channel_idx] = opened;
611610
opened
612611
}
613612

@@ -764,6 +763,7 @@ impl Device {
764763
subchannel_index: subchannel_idx as u16,
765764
..offer.clone()
766765
},
766+
event: self.events[subchannel_idx].clone().interrupt(),
767767
request_send,
768768
server_request_recv,
769769
};
@@ -800,12 +800,9 @@ impl Device {
800800
.map_err(ChannelRestoreError::EnablingSubchannels)?;
801801

802802
let mut results = Vec::with_capacity(states.len());
803-
for (channel_idx, (open, event)) in states.iter().copied().zip(&self.events).enumerate() {
804-
let open_result = open.then(|| OpenResult {
805-
guest_to_host_interrupt: event.clone().interrupt(),
806-
});
803+
for (channel_idx, open) in states.iter().copied().enumerate() {
807804
let result = self.server_requests[channel_idx]
808-
.call_failable(ChannelServerRequest::Restore, open_result)
805+
.call_failable(ChannelServerRequest::Restore, open)
809806
.await
810807
.map_err(|err| ChannelRestoreError::RestoreError(err.into()))?;
811808

vm/devices/vmbus/vmbus_channel/src/offer.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use crate::bus::OfferInput;
1212
use crate::bus::OfferParams;
1313
use crate::bus::OfferResources;
1414
use crate::bus::OpenRequest;
15-
use crate::bus::OpenResult;
1615
use crate::bus::ParentBus;
1716
use crate::gpadl::GpadlMap;
1817
use crate::gpadl::GpadlMapView;
@@ -71,6 +70,7 @@ impl Offer {
7170
let result = bus
7271
.add_child(OfferInput {
7372
params: offer_params,
73+
event: Interrupt::from_event(event.clone()),
7474
request_send,
7575
server_request_recv,
7676
})
@@ -181,9 +181,7 @@ impl Offer {
181181
channel,
182182
gpadl_map: self.gpadl_map.clone(),
183183
};
184-
message.response.respond(Some(OpenResult {
185-
guest_to_host_interrupt: self.event.clone().interrupt(),
186-
}));
184+
message.response.respond(true);
187185
Ok(resources)
188186
}
189187

@@ -222,18 +220,18 @@ struct OpenMessage {
222220
response: OpenResponse,
223221
}
224222

225-
struct OpenResponse(Option<Rpc<(), Option<OpenResult>>>);
223+
struct OpenResponse(Option<Rpc<(), bool>>);
226224

227225
impl OpenResponse {
228-
fn respond(mut self, result: Option<OpenResult>) {
229-
self.0.take().unwrap().complete(result)
226+
fn respond(mut self, open: bool) {
227+
self.0.take().unwrap().complete(open)
230228
}
231229
}
232230

233231
impl Drop for OpenResponse {
234232
fn drop(&mut self) {
235233
if let Some(rpc) = self.0.take() {
236-
rpc.complete(None);
234+
rpc.complete(false);
237235
}
238236
}
239237
}

vm/devices/vmbus/vmbus_client/src/driver.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impl<D: SpawnDriver> ChannelWorker<D> {
8888
&mut self,
8989
input: OpenParams,
9090
close_send: mesh::OneshotSender<()>,
91+
guest_to_host: Interrupt,
9192
host_to_guest: pal_event::Event,
9293
revoked: Arc<AtomicBool>,
9394
) -> anyhow::Result<RawAsyncChannel<MemoryBlockRingMem>> {
@@ -109,8 +110,7 @@ impl<D: SpawnDriver> ChannelWorker<D> {
109110

110111
self.is_gpadl_created = true;
111112

112-
let open = self
113-
.request_send
113+
self.request_send
114114
.call_failable(
115115
ChannelRequest::Open,
116116
OpenRequest {
@@ -143,7 +143,7 @@ impl<D: SpawnDriver> ChannelWorker<D> {
143143
};
144144

145145
let signal = ClientSignaller {
146-
guest_to_host: open.guest_to_host_signal,
146+
guest_to_host,
147147
host_to_guest: Notify::from_event(host_to_guest).pollable(&self.driver)?,
148148
revoked: revoked.clone(),
149149
_close: close_send,
@@ -196,7 +196,13 @@ impl<D: SpawnDriver> ChannelWorker<D> {
196196
let (close_send, close_recv) = mesh::oneshot();
197197
let host_to_guest = pal_event::Event::new();
198198
match worker
199-
.open(input, close_send, host_to_guest.clone(), revoked.clone())
199+
.open(
200+
input,
201+
close_send,
202+
offer_info.guest_to_host_interrupt,
203+
host_to_guest.clone(),
204+
revoked.clone(),
205+
)
200206
.await
201207
{
202208
Ok(channel) => {

vm/devices/vmbus/vmbus_client/src/filter.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ impl Inspect for Filters {
240240

241241
impl FilterWorker {
242242
async fn run(&mut self, req: mesh::Receiver<FilterRequest>, offers: mesh::Receiver<OfferInfo>) {
243+
#[allow(clippy::large_enum_variant)]
243244
enum Event {
244245
Request(FilterRequest),
245246
Done,

0 commit comments

Comments
 (0)