1 // Copyright (c) 2020 Ant Financial 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use super::Error as DeviceError; 16 use super::{ 17 ActivateError, ActivateResult, DescriptorChain, EpollHelper, EpollHelperError, 18 EpollHelperHandler, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType, 19 EPOLL_HELPER_EVENT_LAST, VIRTIO_F_VERSION_1, 20 }; 21 use crate::seccomp_filters::Thread; 22 use crate::thread_helper::spawn_virtio_thread; 23 use crate::{GuestMemoryMmap, GuestRegionMmap}; 24 use crate::{VirtioInterrupt, VirtioInterruptType}; 25 use anyhow::anyhow; 26 use libc::EFD_NONBLOCK; 27 use seccompiler::SeccompAction; 28 use std::io; 29 use std::mem::size_of; 30 use std::os::unix::io::{AsRawFd, RawFd}; 31 use std::result; 32 use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; 33 use std::sync::mpsc; 34 use std::sync::{Arc, Barrier, Mutex}; 35 use vm_device::dma_mapping::ExternalDmaMapping; 36 use vm_memory::{ 37 Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemoryAtomic, 38 GuestMemoryError, GuestMemoryRegion, 39 }; 40 use vm_migration::{Migratable, MigratableError, Pausable, Snapshottable, Transportable}; 41 use vmm_sys_util::eventfd::EventFd; 42 43 const QUEUE_SIZE: u16 = 128; 44 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE]; 45 46 // 128MiB is the standard memory block size in Linux. A virtio-mem region must 47 // be aligned on this size, and the region size must be a multiple of it. 48 pub const VIRTIO_MEM_ALIGN_SIZE: u64 = 128 << 20; 49 // Use 2 MiB alignment so transparent hugepages can be used by KVM. 50 const VIRTIO_MEM_DEFAULT_BLOCK_SIZE: u64 = 2 << 20; 51 52 // Request processed successfully, applicable for 53 // - VIRTIO_MEM_REQ_PLUG 54 // - VIRTIO_MEM_REQ_UNPLUG 55 // - VIRTIO_MEM_REQ_UNPLUG_ALL 56 // - VIRTIO_MEM_REQ_STATE 57 const VIRTIO_MEM_RESP_ACK: u16 = 0; 58 59 // Request denied - e.g. trying to plug more than requested, applicable for 60 // - VIRTIO_MEM_REQ_PLUG 61 const VIRTIO_MEM_RESP_NACK: u16 = 1; 62 63 // Request cannot be processed right now, try again later, applicable for 64 // - VIRTIO_MEM_REQ_PLUG 65 // - VIRTIO_MEM_REQ_UNPLUG 66 // - VIRTIO_MEM_REQ_UNPLUG_ALL 67 #[allow(unused)] 68 const VIRTIO_MEM_RESP_BUSY: u16 = 2; 69 70 // Error in request (e.g. addresses/alignment), applicable for 71 // - VIRTIO_MEM_REQ_PLUG 72 // - VIRTIO_MEM_REQ_UNPLUG 73 // - VIRTIO_MEM_REQ_STATE 74 const VIRTIO_MEM_RESP_ERROR: u16 = 3; 75 76 // State of memory blocks is "plugged" 77 const VIRTIO_MEM_STATE_PLUGGED: u16 = 0; 78 // State of memory blocks is "unplugged" 79 const VIRTIO_MEM_STATE_UNPLUGGED: u16 = 1; 80 // State of memory blocks is "mixed" 81 const VIRTIO_MEM_STATE_MIXED: u16 = 2; 82 83 // request to plug memory blocks 84 const VIRTIO_MEM_REQ_PLUG: u16 = 0; 85 // request to unplug memory blocks 86 const VIRTIO_MEM_REQ_UNPLUG: u16 = 1; 87 // request to unplug all blocks and shrink the usable size 88 const VIRTIO_MEM_REQ_UNPLUG_ALL: u16 = 2; 89 // request information about the plugged state of memory blocks 90 const VIRTIO_MEM_REQ_STATE: u16 = 3; 91 92 // Get resize event. 93 const RESIZE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1; 94 // New descriptors are pending on the virtio queue. 95 const QUEUE_AVAIL_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2; 96 97 // Virtio features 98 const VIRTIO_MEM_F_ACPI_PXM: u8 = 0; 99 100 #[derive(Debug)] 101 pub enum Error { 102 // Guest gave us bad memory addresses. 103 GuestMemory(GuestMemoryError), 104 // Guest gave us a write only descriptor that protocol says to read from. 105 UnexpectedWriteOnlyDescriptor, 106 // Guest gave us a read only descriptor that protocol says to write to. 107 UnexpectedReadOnlyDescriptor, 108 // Guest gave us too few descriptors in a descriptor chain. 109 DescriptorChainTooShort, 110 // Guest gave us a buffer that was too short to use. 111 BufferLengthTooSmall, 112 // Guest sent us invalid request. 113 InvalidRequest, 114 // Failed to EventFd write. 115 EventFdWriteFail(std::io::Error), 116 // Failed to EventFd try_clone. 117 EventFdTryCloneFail(std::io::Error), 118 // Failed to MpscRecv. 119 MpscRecvFail(mpsc::RecvError), 120 // Resize invalid argument 121 ResizeError(anyhow::Error), 122 // Fail to resize trigger 123 ResizeTriggerFail(DeviceError), 124 // Invalid configuration 125 ValidateError(anyhow::Error), 126 // Failed discarding memory range 127 DiscardMemoryRange(std::io::Error), 128 // Failed DMA mapping. 129 DmaMap(std::io::Error), 130 // Failed DMA unmapping. 131 DmaUnmap(std::io::Error), 132 // Invalid DMA mapping handler 133 InvalidDmaMappingHandler, 134 } 135 136 #[repr(C)] 137 #[derive(Copy, Clone, Debug, Default)] 138 struct VirtioMemReq { 139 req_type: u16, 140 padding: [u16; 3], 141 addr: u64, 142 nb_blocks: u16, 143 padding_1: [u16; 3], 144 } 145 146 // Safe because it only has data and has no implicit padding. 147 unsafe impl ByteValued for VirtioMemReq {} 148 149 #[repr(C)] 150 #[derive(Copy, Clone, Debug, Default)] 151 struct VirtioMemResp { 152 resp_type: u16, 153 padding: [u16; 3], 154 state: u16, 155 } 156 157 // Safe because it only has data and has no implicit padding. 158 unsafe impl ByteValued for VirtioMemResp {} 159 160 #[repr(C)] 161 #[derive(Copy, Clone, Debug, Default)] 162 struct VirtioMemConfig { 163 // Block size and alignment. Cannot change. 164 block_size: u64, 165 // Valid with VIRTIO_MEM_F_ACPI_PXM. Cannot change. 166 node_id: u16, 167 padding: [u8; 6], 168 // Start address of the memory region. Cannot change. 169 addr: u64, 170 // Region size (maximum). Cannot change. 171 region_size: u64, 172 // Currently usable region size. Can grow up to region_size. Can 173 // shrink due to VIRTIO_MEM_REQ_UNPLUG_ALL (in which case no config 174 // update will be sent). 175 usable_region_size: u64, 176 // Currently used size. Changes due to plug/unplug requests, but no 177 // config updates will be sent. 178 plugged_size: u64, 179 // Requested size. New plug requests cannot exceed it. Can change. 180 requested_size: u64, 181 } 182 183 // Safe because it only has data and has no implicit padding. 184 unsafe impl ByteValued for VirtioMemConfig {} 185 186 impl VirtioMemConfig { 187 fn validate(&self) -> result::Result<(), Error> { 188 if self.addr % self.block_size != 0 { 189 return Err(Error::ValidateError(anyhow!( 190 "addr 0x{:x} is not aligned on block_size 0x{:x}", 191 self.addr, 192 self.block_size 193 ))); 194 } 195 if self.region_size % self.block_size != 0 { 196 return Err(Error::ValidateError(anyhow!( 197 "region_size 0x{:x} is not aligned on block_size 0x{:x}", 198 self.region_size, 199 self.block_size 200 ))); 201 } 202 if self.usable_region_size % self.block_size != 0 { 203 return Err(Error::ValidateError(anyhow!( 204 "usable_region_size 0x{:x} is not aligned on block_size 0x{:x}", 205 self.usable_region_size, 206 self.block_size 207 ))); 208 } 209 if self.plugged_size % self.block_size != 0 { 210 return Err(Error::ValidateError(anyhow!( 211 "plugged_size 0x{:x} is not aligned on block_size 0x{:x}", 212 self.plugged_size, 213 self.block_size 214 ))); 215 } 216 if self.requested_size % self.block_size != 0 { 217 return Err(Error::ValidateError(anyhow!( 218 "requested_size 0x{:x} is not aligned on block_size 0x{:x}", 219 self.requested_size, 220 self.block_size 221 ))); 222 } 223 224 Ok(()) 225 } 226 227 fn resize(&mut self, size: u64) -> result::Result<(), Error> { 228 if self.requested_size == size { 229 return Err(Error::ResizeError(anyhow!( 230 "new size 0x{:x} and requested_size are identical", 231 size 232 ))); 233 } else if size > self.region_size { 234 return Err(Error::ResizeError(anyhow!( 235 "new size 0x{:x} is bigger than region_size 0x{:x}", 236 size, 237 self.region_size 238 ))); 239 } else if size % (self.block_size as u64) != 0 { 240 return Err(Error::ResizeError(anyhow!( 241 "new size 0x{:x} is not aligned on block_size 0x{:x}", 242 size, 243 self.block_size 244 ))); 245 } 246 247 self.requested_size = size; 248 249 Ok(()) 250 } 251 252 fn is_valid_range(&self, addr: u64, size: u64) -> bool { 253 // Start address must be aligned on block_size, the size must be 254 // greater than 0, and all blocks covered by the request must be 255 // in the usable region. 256 if addr % self.block_size != 0 257 || size == 0 258 || (addr < self.addr || addr + size >= self.addr + self.usable_region_size) 259 { 260 return false; 261 } 262 263 true 264 } 265 } 266 267 struct Request { 268 req: VirtioMemReq, 269 status_addr: GuestAddress, 270 } 271 272 impl Request { 273 fn parse( 274 avail_desc: &DescriptorChain, 275 mem: &GuestMemoryMmap, 276 ) -> result::Result<Request, Error> { 277 // The head contains the request type which MUST be readable. 278 if avail_desc.is_write_only() { 279 return Err(Error::UnexpectedWriteOnlyDescriptor); 280 } 281 if avail_desc.len as usize != size_of::<VirtioMemReq>() { 282 return Err(Error::InvalidRequest); 283 } 284 let req: VirtioMemReq = mem.read_obj(avail_desc.addr).map_err(Error::GuestMemory)?; 285 286 let status_desc = avail_desc 287 .next_descriptor() 288 .ok_or(Error::DescriptorChainTooShort)?; 289 290 // The status MUST always be writable 291 if !status_desc.is_write_only() { 292 return Err(Error::UnexpectedReadOnlyDescriptor); 293 } 294 295 if (status_desc.len as usize) < size_of::<VirtioMemResp>() { 296 return Err(Error::BufferLengthTooSmall); 297 } 298 299 Ok(Request { 300 req, 301 status_addr: status_desc.addr, 302 }) 303 } 304 305 fn send_response(&self, mem: &GuestMemoryMmap, resp_type: u16, state: u16) -> u32 { 306 let resp = VirtioMemResp { 307 resp_type, 308 state, 309 ..Default::default() 310 }; 311 match mem.write_obj(resp, self.status_addr) { 312 Ok(_) => size_of::<VirtioMemResp>() as u32, 313 Err(e) => { 314 error!("bad guest memory address: {}", e); 315 0 316 } 317 } 318 } 319 } 320 321 pub struct ResizeSender { 322 size: Arc<AtomicU64>, 323 tx: mpsc::Sender<Result<(), Error>>, 324 evt: EventFd, 325 } 326 327 impl ResizeSender { 328 fn size(&self) -> u64 { 329 self.size.load(Ordering::Acquire) 330 } 331 332 fn send(&self, r: Result<(), Error>) -> Result<(), mpsc::SendError<Result<(), Error>>> { 333 self.tx.send(r) 334 } 335 } 336 337 impl Clone for ResizeSender { 338 fn clone(&self) -> Self { 339 ResizeSender { 340 size: self.size.clone(), 341 tx: self.tx.clone(), 342 evt: self 343 .evt 344 .try_clone() 345 .expect("Failed cloning EventFd from ResizeSender"), 346 } 347 } 348 } 349 350 pub struct Resize { 351 size: Arc<AtomicU64>, 352 tx: mpsc::Sender<Result<(), Error>>, 353 rx: mpsc::Receiver<Result<(), Error>>, 354 evt: EventFd, 355 } 356 357 impl Resize { 358 pub fn new() -> io::Result<Self> { 359 let (tx, rx) = mpsc::channel(); 360 361 Ok(Resize { 362 size: Arc::new(AtomicU64::new(0)), 363 tx, 364 rx, 365 evt: EventFd::new(EFD_NONBLOCK)?, 366 }) 367 } 368 369 pub fn new_resize_sender(&self) -> Result<ResizeSender, Error> { 370 Ok(ResizeSender { 371 size: self.size.clone(), 372 tx: self.tx.clone(), 373 evt: self.evt.try_clone().map_err(Error::EventFdTryCloneFail)?, 374 }) 375 } 376 377 pub fn work(&self, size: u64) -> Result<(), Error> { 378 self.size.store(size, Ordering::Release); 379 self.evt.write(1).map_err(Error::EventFdWriteFail)?; 380 self.rx.recv().map_err(Error::MpscRecvFail)? 381 } 382 } 383 384 struct BlocksState(Vec<bool>); 385 386 impl BlocksState { 387 fn is_range_state(&self, first_block_index: usize, nb_blocks: u16, plug: bool) -> bool { 388 for state in self 389 .0 390 .iter() 391 .skip(first_block_index) 392 .take(nb_blocks as usize) 393 { 394 if *state != plug { 395 return false; 396 } 397 } 398 true 399 } 400 401 fn set_range(&mut self, first_block_index: usize, nb_blocks: u16, plug: bool) { 402 for state in self 403 .0 404 .iter_mut() 405 .skip(first_block_index) 406 .take(nb_blocks as usize) 407 { 408 *state = plug; 409 } 410 } 411 412 fn inner(&self) -> &Vec<bool> { 413 &self.0 414 } 415 } 416 417 struct MemEpollHandler { 418 host_addr: u64, 419 host_fd: Option<RawFd>, 420 blocks_state: Arc<Mutex<BlocksState>>, 421 config: Arc<Mutex<VirtioMemConfig>>, 422 resize: ResizeSender, 423 queue: Queue, 424 mem: GuestMemoryAtomic<GuestMemoryMmap>, 425 interrupt_cb: Arc<dyn VirtioInterrupt>, 426 queue_evt: EventFd, 427 kill_evt: EventFd, 428 pause_evt: EventFd, 429 hugepages: bool, 430 dma_mapping_handler: Option<Arc<dyn ExternalDmaMapping>>, 431 } 432 433 impl MemEpollHandler { 434 fn discard_memory_range(&self, offset: u64, size: u64) -> Result<(), Error> { 435 // Use fallocate if the memory region is backed by a file. 436 if let Some(fd) = self.host_fd { 437 let res = unsafe { 438 libc::fallocate64( 439 fd, 440 libc::FALLOC_FL_PUNCH_HOLE | libc::FALLOC_FL_KEEP_SIZE, 441 offset as libc::off64_t, 442 size as libc::off64_t, 443 ) 444 }; 445 if res != 0 { 446 let err = io::Error::last_os_error(); 447 error!("Deallocating file space failed: {}", err); 448 return Err(Error::DiscardMemoryRange(err)); 449 } 450 } 451 452 // Only use madvise if the memory region is not allocated with 453 // hugepages. 454 if !self.hugepages { 455 let res = unsafe { 456 libc::madvise( 457 (self.host_addr + offset) as *mut libc::c_void, 458 size as libc::size_t, 459 libc::MADV_DONTNEED, 460 ) 461 }; 462 if res != 0 { 463 let err = io::Error::last_os_error(); 464 error!("Advising kernel about pages range failed: {}", err); 465 return Err(Error::DiscardMemoryRange(err)); 466 } 467 } 468 469 Ok(()) 470 } 471 472 fn state_change_request(&mut self, addr: u64, nb_blocks: u16, plug: bool) -> u16 { 473 let mut config = self.config.lock().unwrap(); 474 let size: u64 = nb_blocks as u64 * config.block_size; 475 476 if plug && (config.plugged_size + size > config.requested_size) { 477 return VIRTIO_MEM_RESP_NACK; 478 } 479 if !config.is_valid_range(addr, size) { 480 return VIRTIO_MEM_RESP_ERROR; 481 } 482 483 let offset = addr - config.addr; 484 485 let first_block_index = (offset / config.block_size) as usize; 486 if !self 487 .blocks_state 488 .lock() 489 .unwrap() 490 .is_range_state(first_block_index, nb_blocks, !plug) 491 { 492 return VIRTIO_MEM_RESP_ERROR; 493 } 494 495 if !plug { 496 if let Err(e) = self.discard_memory_range(offset, size) { 497 error!("failed discarding memory range: {:?}", e); 498 return VIRTIO_MEM_RESP_ERROR; 499 } 500 } 501 502 self.blocks_state 503 .lock() 504 .unwrap() 505 .set_range(first_block_index, nb_blocks, plug); 506 507 if plug { 508 let mut gpa = addr; 509 for _ in 0..nb_blocks { 510 if let Some(handler) = &self.dma_mapping_handler { 511 if let Err(e) = handler.map(gpa, gpa, config.block_size) { 512 error!( 513 "failed DMA mapping addr 0x{:x} size 0x{:x}: {}", 514 gpa, config.block_size, e 515 ); 516 return VIRTIO_MEM_RESP_ERROR; 517 } 518 } 519 520 gpa += config.block_size; 521 } 522 523 config.plugged_size += size; 524 } else { 525 if let Some(handler) = &self.dma_mapping_handler { 526 if let Err(e) = handler.unmap(addr, size) { 527 error!( 528 "failed DMA unmapping addr 0x{:x} size 0x{:x}: {}", 529 addr, size, e 530 ); 531 return VIRTIO_MEM_RESP_ERROR; 532 } 533 } 534 535 config.plugged_size -= size; 536 } 537 538 VIRTIO_MEM_RESP_ACK 539 } 540 541 fn unplug_all(&mut self) -> u16 { 542 let mut config = self.config.lock().unwrap(); 543 if let Err(e) = self.discard_memory_range(0, config.region_size) { 544 error!("failed discarding memory range: {:?}", e); 545 return VIRTIO_MEM_RESP_ERROR; 546 } 547 548 // Remaining plugged blocks are unmapped. 549 if config.plugged_size > 0 { 550 for (idx, plugged) in self.blocks_state.lock().unwrap().inner().iter().enumerate() { 551 if *plugged { 552 let gpa = config.addr + (idx as u64 * config.block_size); 553 if let Some(handler) = &self.dma_mapping_handler { 554 if let Err(e) = handler.unmap(gpa, config.block_size) { 555 error!( 556 "failed DMA unmapping addr 0x{:x} size 0x{:x}: {}", 557 gpa, config.block_size, e 558 ); 559 return VIRTIO_MEM_RESP_ERROR; 560 } 561 } 562 } 563 } 564 } 565 566 self.blocks_state.lock().unwrap().set_range( 567 0, 568 (config.region_size / config.block_size) as u16, 569 false, 570 ); 571 572 config.plugged_size = 0; 573 574 VIRTIO_MEM_RESP_ACK 575 } 576 577 fn state_request(&self, addr: u64, nb_blocks: u16) -> (u16, u16) { 578 let config = self.config.lock().unwrap(); 579 let size: u64 = nb_blocks as u64 * config.block_size; 580 581 let resp_type = if config.is_valid_range(addr, size) { 582 VIRTIO_MEM_RESP_ACK 583 } else { 584 VIRTIO_MEM_RESP_ERROR 585 }; 586 587 let offset = addr - config.addr; 588 let first_block_index = (offset / config.block_size) as usize; 589 let resp_state = 590 if self 591 .blocks_state 592 .lock() 593 .unwrap() 594 .is_range_state(first_block_index, nb_blocks, true) 595 { 596 VIRTIO_MEM_STATE_PLUGGED 597 } else if self.blocks_state.lock().unwrap().is_range_state( 598 first_block_index, 599 nb_blocks, 600 false, 601 ) { 602 VIRTIO_MEM_STATE_UNPLUGGED 603 } else { 604 VIRTIO_MEM_STATE_MIXED 605 }; 606 607 (resp_type, resp_state) 608 } 609 610 fn signal(&self, int_type: &VirtioInterruptType) -> result::Result<(), DeviceError> { 611 self.interrupt_cb 612 .trigger(int_type, Some(&self.queue)) 613 .map_err(|e| { 614 error!("Failed to signal used queue: {:?}", e); 615 DeviceError::FailedSignalingUsedQueue(e) 616 }) 617 } 618 619 fn process_queue(&mut self) -> bool { 620 let mut request_list = Vec::new(); 621 let mut used_count = 0; 622 let mem = self.mem.memory(); 623 for avail_desc in self.queue.iter(&mem) { 624 request_list.push((avail_desc.index, Request::parse(&avail_desc, &mem))); 625 } 626 627 for (desc_index, request) in request_list.iter() { 628 let len = match request { 629 Err(e) => { 630 error!("failed parse VirtioMemReq: {:?}", e); 631 0 632 } 633 Ok(r) => match r.req.req_type { 634 VIRTIO_MEM_REQ_PLUG => { 635 let resp_type = 636 self.state_change_request(r.req.addr, r.req.nb_blocks, true); 637 r.send_response(&mem, resp_type, 0u16) 638 } 639 VIRTIO_MEM_REQ_UNPLUG => { 640 let resp_type = 641 self.state_change_request(r.req.addr, r.req.nb_blocks, false); 642 r.send_response(&mem, resp_type, 0u16) 643 } 644 VIRTIO_MEM_REQ_UNPLUG_ALL => { 645 let resp_type = self.unplug_all(); 646 r.send_response(&mem, resp_type, 0u16) 647 } 648 VIRTIO_MEM_REQ_STATE => { 649 let (resp_type, resp_state) = 650 self.state_request(r.req.addr, r.req.nb_blocks); 651 r.send_response(&mem, resp_type, resp_state) 652 } 653 _ => { 654 error!("VirtioMemReq unknown request type {:?}", r.req.req_type); 655 0 656 } 657 }, 658 }; 659 660 self.queue.add_used(&mem, *desc_index, len); 661 662 used_count += 1; 663 } 664 665 used_count > 0 666 } 667 668 fn run( 669 &mut self, 670 paused: Arc<AtomicBool>, 671 paused_sync: Arc<Barrier>, 672 ) -> result::Result<(), EpollHelperError> { 673 let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?; 674 helper.add_event(self.resize.evt.as_raw_fd(), RESIZE_EVENT)?; 675 helper.add_event(self.queue_evt.as_raw_fd(), QUEUE_AVAIL_EVENT)?; 676 helper.run(paused, paused_sync, self)?; 677 678 Ok(()) 679 } 680 } 681 682 impl EpollHelperHandler for MemEpollHandler { 683 fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool { 684 let ev_type = event.data as u16; 685 match ev_type { 686 RESIZE_EVENT => { 687 if let Err(e) = self.resize.evt.read() { 688 error!("Failed to get resize event: {:?}", e); 689 return true; 690 } else { 691 let size = self.resize.size(); 692 let mut config = self.config.lock().unwrap(); 693 let mut signal_error = false; 694 let mut r = config.resize(size); 695 r = match r { 696 Err(e) => Err(e), 697 _ => match self.signal(&VirtioInterruptType::Config) { 698 Err(e) => { 699 signal_error = true; 700 Err(Error::ResizeTriggerFail(e)) 701 } 702 _ => Ok(()), 703 }, 704 }; 705 if let Err(e) = self.resize.send(r) { 706 error!("Sending \"resize\" response: {:?}", e); 707 return true; 708 } 709 if signal_error { 710 return true; 711 } 712 } 713 } 714 QUEUE_AVAIL_EVENT => { 715 if let Err(e) = self.queue_evt.read() { 716 error!("Failed to get queue event: {:?}", e); 717 return true; 718 } else if self.process_queue() { 719 if let Err(e) = self.signal(&VirtioInterruptType::Queue) { 720 error!("Failed to signal used queue: {:?}", e); 721 return true; 722 } 723 } 724 } 725 _ => { 726 error!("Unexpected event: {}", ev_type); 727 return true; 728 } 729 } 730 false 731 } 732 } 733 734 // Virtio device for exposing entropy to the guest OS through virtio. 735 pub struct Mem { 736 common: VirtioCommon, 737 id: String, 738 resize: ResizeSender, 739 host_addr: u64, 740 host_fd: Option<RawFd>, 741 config: Arc<Mutex<VirtioMemConfig>>, 742 seccomp_action: SeccompAction, 743 hugepages: bool, 744 dma_mapping_handler: Option<Arc<dyn ExternalDmaMapping>>, 745 blocks_state: Arc<Mutex<BlocksState>>, 746 exit_evt: EventFd, 747 } 748 749 impl Mem { 750 // Create a new virtio-mem device. 751 #[allow(clippy::too_many_arguments)] 752 pub fn new( 753 id: String, 754 region: &Arc<GuestRegionMmap>, 755 resize: ResizeSender, 756 seccomp_action: SeccompAction, 757 numa_node_id: Option<u16>, 758 initial_size: u64, 759 hugepages: bool, 760 exit_evt: EventFd, 761 ) -> io::Result<Mem> { 762 let region_len = region.len(); 763 764 if region_len != region_len / VIRTIO_MEM_ALIGN_SIZE * VIRTIO_MEM_ALIGN_SIZE { 765 return Err(io::Error::new( 766 io::ErrorKind::Other, 767 format!( 768 "Virtio-mem size is not aligned with {}", 769 VIRTIO_MEM_ALIGN_SIZE 770 ), 771 )); 772 } 773 774 let mut avail_features = 1u64 << VIRTIO_F_VERSION_1; 775 776 let mut config = VirtioMemConfig { 777 block_size: VIRTIO_MEM_DEFAULT_BLOCK_SIZE, 778 addr: region.start_addr().raw_value(), 779 region_size: region.len(), 780 usable_region_size: region.len(), 781 plugged_size: 0, 782 requested_size: 0, 783 ..Default::default() 784 }; 785 786 if initial_size != 0 { 787 config.resize(initial_size).map_err(|e| { 788 io::Error::new( 789 io::ErrorKind::Other, 790 format!( 791 "Failed to resize virtio-mem configuration to {}: {:?}", 792 initial_size, e 793 ), 794 ) 795 })?; 796 } 797 798 if let Some(node_id) = numa_node_id { 799 avail_features |= 1u64 << VIRTIO_MEM_F_ACPI_PXM; 800 config.node_id = node_id; 801 } 802 803 // Make sure the virtio-mem configuration complies with the 804 // specification. 805 config.validate().map_err(|e| { 806 io::Error::new( 807 io::ErrorKind::Other, 808 format!("Invalid virtio-mem configuration: {:?}", e), 809 ) 810 })?; 811 812 let host_fd = region 813 .file_offset() 814 .map(|f_offset| f_offset.file().as_raw_fd()); 815 816 Ok(Mem { 817 common: VirtioCommon { 818 device_type: VirtioDeviceType::Mem as u32, 819 avail_features, 820 paused_sync: Some(Arc::new(Barrier::new(2))), 821 queue_sizes: QUEUE_SIZES.to_vec(), 822 min_queues: 1, 823 ..Default::default() 824 }, 825 id, 826 resize, 827 host_addr: region.as_ptr() as u64, 828 host_fd, 829 config: Arc::new(Mutex::new(config)), 830 seccomp_action, 831 hugepages, 832 dma_mapping_handler: None, 833 blocks_state: Arc::new(Mutex::new(BlocksState(vec![ 834 false; 835 (config.region_size / config.block_size) 836 as usize 837 ]))), 838 exit_evt, 839 }) 840 } 841 842 pub fn add_dma_mapping_handler( 843 &mut self, 844 handler: Arc<dyn ExternalDmaMapping>, 845 ) -> result::Result<(), Error> { 846 let config = self.config.lock().unwrap(); 847 848 if config.plugged_size > 0 { 849 for (idx, plugged) in self.blocks_state.lock().unwrap().inner().iter().enumerate() { 850 if *plugged { 851 let gpa = config.addr + (idx as u64 * config.block_size); 852 handler 853 .map(gpa, gpa, config.block_size) 854 .map_err(Error::DmaMap)?; 855 } 856 } 857 } 858 859 self.dma_mapping_handler = Some(handler); 860 861 Ok(()) 862 } 863 } 864 865 impl Drop for Mem { 866 fn drop(&mut self) { 867 if let Some(kill_evt) = self.common.kill_evt.take() { 868 // Ignore the result because there is nothing we can do about it. 869 let _ = kill_evt.write(1); 870 } 871 } 872 } 873 874 impl VirtioDevice for Mem { 875 fn device_type(&self) -> u32 { 876 self.common.device_type 877 } 878 879 fn queue_max_sizes(&self) -> &[u16] { 880 &self.common.queue_sizes 881 } 882 883 fn features(&self) -> u64 { 884 self.common.avail_features 885 } 886 887 fn ack_features(&mut self, value: u64) { 888 self.common.ack_features(value) 889 } 890 891 fn read_config(&self, offset: u64, data: &mut [u8]) { 892 self.read_config_from_slice(self.config.lock().unwrap().as_slice(), offset, data); 893 } 894 895 fn activate( 896 &mut self, 897 mem: GuestMemoryAtomic<GuestMemoryMmap>, 898 interrupt_cb: Arc<dyn VirtioInterrupt>, 899 mut queues: Vec<Queue>, 900 mut queue_evts: Vec<EventFd>, 901 ) -> ActivateResult { 902 self.common.activate(&queues, &queue_evts, &interrupt_cb)?; 903 let (kill_evt, pause_evt) = self.common.dup_eventfds(); 904 let config = self.config.lock().unwrap(); 905 let mut handler = MemEpollHandler { 906 host_addr: self.host_addr, 907 host_fd: self.host_fd, 908 blocks_state: Arc::clone(&self.blocks_state), 909 config: self.config.clone(), 910 resize: self.resize.clone(), 911 queue: queues.remove(0), 912 mem, 913 interrupt_cb, 914 queue_evt: queue_evts.remove(0), 915 kill_evt, 916 pause_evt, 917 hugepages: self.hugepages, 918 dma_mapping_handler: self.dma_mapping_handler.clone(), 919 }; 920 921 handler 922 .discard_memory_range(0, config.region_size) 923 .map_err(|e| { 924 error!("failed discarding memory range: {:?}", e); 925 ActivateError::BadActivate 926 })?; 927 928 let paused = self.common.paused.clone(); 929 let paused_sync = self.common.paused_sync.clone(); 930 let mut epoll_threads = Vec::new(); 931 932 spawn_virtio_thread( 933 &self.id, 934 &self.seccomp_action, 935 Thread::VirtioMem, 936 &mut epoll_threads, 937 &self.exit_evt, 938 move || { 939 if let Err(e) = handler.run(paused, paused_sync.unwrap()) { 940 error!("Error running worker: {:?}", e); 941 } 942 }, 943 )?; 944 self.common.epoll_threads = Some(epoll_threads); 945 946 event!("virtio-device", "activated", "id", &self.id); 947 Ok(()) 948 } 949 950 fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 951 let result = self.common.reset(); 952 event!("virtio-device", "reset", "id", &self.id); 953 result 954 } 955 } 956 957 impl Pausable for Mem { 958 fn pause(&mut self) -> result::Result<(), MigratableError> { 959 self.common.pause() 960 } 961 962 fn resume(&mut self) -> result::Result<(), MigratableError> { 963 self.common.resume() 964 } 965 } 966 967 impl Snapshottable for Mem { 968 fn id(&self) -> String { 969 self.id.clone() 970 } 971 } 972 impl Transportable for Mem {} 973 impl Migratable for Mem {} 974