@@ -445,7 +445,8 @@ enum CommitResult {
445445 /// A reference to existing page.
446446 Ref ( PhysAddr ) ,
447447 /// A new page copied-on-write.
448- CopyOnWrite ( PhysFrame ) ,
448+ /// the bool value indicate should we unmap the page after the copy
449+ CopyOnWrite ( PhysFrame , bool ) ,
449450 /// A new zero page.
450451 NewPage ( PhysFrame ) ,
451452}
@@ -539,6 +540,7 @@ impl VMObjectPagedInner {
539540 } else {
540541 ( self . parent_offset + page_idx * PAGE_SIZE ) >= self . parent_limit
541542 } ;
543+ let mut need_unmap = false ;
542544 if no_frame {
543545 // if out_of_range
544546 if out_of_range || no_parent {
@@ -565,16 +567,25 @@ impl VMObjectPagedInner {
565567 CommitResult :: NewPage ( frame) if !self . type_ . is_hidden ( ) => {
566568 self . frames . insert ( page_idx, PageState :: new ( frame) ) ;
567569 }
568- CommitResult :: CopyOnWrite ( frame) => {
570+ CommitResult :: CopyOnWrite ( frame, unmap ) => {
569571 let mut new_frame = PageState :: new ( frame) ;
570572 // Cloning a contiguous vmo: original frames are stored in hidden parent nodes.
571573 // In order to make sure original vmo (now is a child of hidden parent)
572574 // owns physically contiguous frames, swap the new frame with the original
573575 if self . contiguous {
574- let mut parent_inner = parent;
575- if let Some ( par_frame) = parent_inner. frames . get_mut ( & parent_idx) {
576+ if let Some ( par_frame) = parent. frames . get_mut ( & parent_idx) {
576577 par_frame. swap ( & mut new_frame) ;
577578 }
579+ let sibling = parent. type_ . get_tag_and_other ( & self . self_ref ) . 1 ;
580+ let arc_sibling = sibling. upgrade ( ) . unwrap ( ) ;
581+ let sibling_inner = arc_sibling. inner . borrow ( ) ;
582+ sibling_inner. range_change (
583+ parent_idx * PAGE_SIZE ,
584+ ( parent_idx + 1 ) * PAGE_SIZE ,
585+ RangeChangeOp :: Unmap ,
586+ )
587+ } else {
588+ need_unmap = need_unmap || unmap;
578589 }
579590 self . frames . insert ( page_idx, new_frame) ;
580591 }
@@ -594,20 +605,33 @@ impl VMObjectPagedInner {
594605 } ;
595606 if !in_range {
596607 let frame = self . frames . remove ( & page_idx) . unwrap ( ) . take ( ) ;
597- return Ok ( CommitResult :: CopyOnWrite ( frame) ) ;
608+ return Ok ( CommitResult :: CopyOnWrite ( frame, need_unmap) ) ;
609+ } else if need_unmap {
610+ other_inner. range_change (
611+ page_idx * PAGE_SIZE ,
612+ ( 1 + page_idx) * PAGE_SIZE ,
613+ RangeChangeOp :: Unmap ,
614+ )
615+ }
616+ }
617+ if need_unmap {
618+ for map in self . mappings . iter ( ) {
619+ if let Some ( map) = map. upgrade ( ) {
620+ map. range_change ( page_idx, 1 , RangeChangeOp :: Unmap ) ;
621+ }
598622 }
599623 }
600624 let frame = self . frames . get_mut ( & page_idx) . unwrap ( ) ;
601625 if frame. tag . is_split ( ) {
602626 // has split, take out
603627 let target_frame = self . frames . remove ( & page_idx) . unwrap ( ) . take ( ) ;
604- return Ok ( CommitResult :: CopyOnWrite ( target_frame) ) ;
628+ return Ok ( CommitResult :: CopyOnWrite ( target_frame, need_unmap ) ) ;
605629 } else if flags. contains ( MMUFlags :: WRITE ) && child_tag. is_split ( ) {
606630 // copy-on-write
607631 let target_frame = PhysFrame :: alloc ( ) . ok_or ( ZxError :: NO_MEMORY ) ?;
608632 kernel_hal:: frame_copy ( frame. frame . addr ( ) , target_frame. addr ( ) ) ;
609633 frame. tag = child_tag;
610- return Ok ( CommitResult :: CopyOnWrite ( target_frame) ) ;
634+ return Ok ( CommitResult :: CopyOnWrite ( target_frame, true ) ) ;
611635 }
612636 // otherwise already committed
613637 Ok ( CommitResult :: Ref ( frame. frame . addr ( ) ) )
@@ -617,7 +641,6 @@ impl VMObjectPagedInner {
617641 self . frames . remove ( & page_idx) ;
618642 }
619643
620- #[ allow( dead_code) ]
621644 fn range_change ( & self , parent_offset : usize , parent_limit : usize , op : RangeChangeOp ) {
622645 let mut start = self . parent_offset . max ( parent_offset) ;
623646 let mut end = self . parent_limit . min ( parent_limit) ;
@@ -628,7 +651,7 @@ impl VMObjectPagedInner {
628651 end -= self . parent_offset ;
629652 for map in self . mappings . iter ( ) {
630653 if let Some ( map) = map. upgrade ( ) {
631- map. range_change ( pages ( start) , pages ( end) , op) ;
654+ map. range_change ( pages ( start) , pages ( end) - pages ( start ) , op) ;
632655 }
633656 }
634657 if let VMOType :: Hidden { left, right, .. } = & self . type_ {
0 commit comments