@@ -974,24 +974,24 @@ impl Block {
974974 }
975975 }
976976
977- fn update_writeback ( & mut self ) {
978- // Use writeback from config if VIRTIO_BLK_F_CONFIG_WCE
979- let writeback = if self . common . feature_acked ( VIRTIO_BLK_F_CONFIG_WCE . into ( ) ) {
980- self . config . writeback == 1
981- } else {
982- // Else check if VIRTIO_BLK_F_FLUSH negotiated
983- self . common . feature_acked ( VIRTIO_BLK_F_FLUSH . into ( ) )
984- } ;
977+ /// The virtio v1.2 spec says "If VIRTIO_BLK_F_CONFIG_WCE was not
978+ /// negotiated but VIRTIO_BLK_F_FLUSH was, the driver SHOULD assume
979+ /// presence of a writeback cache." It also says "If
980+ /// VIRTIO_BLK_F_CONFIG_WCE is negotiated but VIRTIO_BLK_F_FLUSH is not,
981+ /// the device MUST initialize writeback to 0."
982+ fn is_writeback_enabled ( & self , desired : bool ) -> bool {
983+ let flush = self . common . feature_acked ( VIRTIO_BLK_F_FLUSH . into ( ) ) ;
984+ let wce = self . common . feature_acked ( VIRTIO_BLK_F_CONFIG_WCE . into ( ) ) ;
985+ if wce { flush && desired } else { flush }
986+ }
985987
988+ fn set_writeback_mode ( & mut self , enabled : bool ) {
989+ self . config . writeback = enabled as u8 ;
990+ self . writeback . store ( enabled, Ordering :: Release ) ;
986991 info ! (
987992 "Changing cache mode to {}" ,
988- if writeback {
989- "writeback"
990- } else {
991- "writethrough"
992- }
993+ if enabled { "writeback" } else { "writethrough" }
993994 ) ;
994- self . writeback . store ( writeback, Ordering :: Release ) ;
995995 }
996996
997997 pub fn resize ( & mut self , new_size : u64 ) -> Result < ( ) > {
@@ -1073,8 +1073,8 @@ impl VirtioDevice for Block {
10731073 return ;
10741074 }
10751075
1076- self . config . writeback = data[ 0 ] ;
1077- self . update_writeback ( ) ;
1076+ let writeback = self . is_writeback_enabled ( data[ 0 ] == 1 ) ;
1077+ self . set_writeback_mode ( writeback ) ;
10781078 }
10791079
10801080 fn activate ( & mut self , context : crate :: device:: ActivationContext ) -> ActivateResult {
@@ -1097,7 +1097,8 @@ impl VirtioDevice for Block {
10971097 // Recompute the barrier size from the queues that are actually activated.
10981098 self . common . paused_sync = Some ( Arc :: new ( Barrier :: new ( queues. len ( ) + 1 ) ) ) ;
10991099
1100- self . update_writeback ( ) ;
1100+ let writeback = self . is_writeback_enabled ( self . config . writeback == 1 ) ;
1101+ self . set_writeback_mode ( writeback) ;
11011102
11021103 let mut epoll_threads = Vec :: new ( ) ;
11031104 let event_idx = self . common . feature_acked ( VIRTIO_RING_F_EVENT_IDX . into ( ) ) ;
@@ -1167,6 +1168,7 @@ impl VirtioDevice for Block {
11671168
11681169 fn reset ( & mut self ) -> Option < Arc < dyn VirtioInterrupt > > {
11691170 let result = self . common . reset ( ) ;
1171+ self . set_writeback_mode ( true ) ;
11701172 event ! ( "virtio-device" , "reset" , "id" , & self . id) ;
11711173 result
11721174 }
0 commit comments