@@ -28,7 +28,7 @@ use crate::{
2828 abort_mount_propagation, commit_mount_propagation_locked, detach_mount_propagation,
2929 ensure_subtree_shared, inherit_bind_mount_propagation,
3030 prepare_mount_propagation_locked, propagate_umount, propagation_umount_busy,
31- register_peer , register_slave_with_master , MountPropagation ,
31+ MountPropagation ,
3232 } ,
3333 } ,
3434 ProcessManager ,
@@ -362,6 +362,33 @@ pub struct MountFS {
362362 lifecycle : Mutex < MountLifecycle > ,
363363}
364364
365+ /// Capacity reserved for one future mount edge. Creating an empty map entry is
366+ /// topology-neutral; if prepare aborts before the slot is consumed, Drop
367+ /// removes that entry so failed events leave no mountpoint residue.
368+ pub ( crate ) struct MountEdgeReservation {
369+ parent : Arc < MountFS > ,
370+ mountpoint : Arc < MountFSInode > ,
371+ }
372+
373+ impl Drop for MountEdgeReservation {
374+ fn drop ( & mut self ) {
375+ let mut mountpoints = self . parent . mountpoints . lock ( ) ;
376+ let dentry_id = self . mountpoint . dentry . id ;
377+ if mountpoints
378+ . get ( & dentry_id)
379+ . is_some_and ( |stack| stack. is_empty ( ) )
380+ {
381+ mountpoints. remove ( & dentry_id) ;
382+ }
383+ }
384+ }
385+
386+ impl MountEdgeReservation {
387+ pub ( crate ) fn mountpoint ( & self ) -> & Arc < MountFSInode > {
388+ & self . mountpoint
389+ }
390+ }
391+
365392#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
366393enum MountLifecycleState {
367394 Constructing ,
@@ -1248,8 +1275,20 @@ impl MountFS {
12481275 & self ,
12491276 mountpoint : & Arc < MountFSInode > ,
12501277 mount_fs : Arc < MountFS > ,
1278+ ) -> Result < ( ) , SystemError > {
1279+ let cover_mountpoint = mount_fs. mountpoint_root_inode ( ) ;
1280+ self . attach_beneath_prepared ( mountpoint, mount_fs, & cover_mountpoint)
1281+ }
1282+
1283+ pub ( crate ) fn attach_beneath_prepared (
1284+ & self ,
1285+ mountpoint : & Arc < MountFSInode > ,
1286+ mount_fs : Arc < MountFS > ,
1287+ cover_mountpoint : & Arc < MountFSInode > ,
12511288 ) -> Result < ( ) , SystemError > {
12521289 if !Arc :: ptr_eq ( & mountpoint. mount_fs , & self . self_ref ( ) )
1290+ || !Arc :: ptr_eq ( & cover_mountpoint. mount_fs , & mount_fs)
1291+ || cover_mountpoint. dentry . id != mount_fs. root_dentry . id
12531292 || mount_fs
12541293 . self_mountpoint ( )
12551294 . as_ref ( )
@@ -1276,9 +1315,8 @@ impl MountFS {
12761315
12771316 // Linux mnt_set_mountpoint_beneath(): the propagated mount takes the
12781317 // original edge and the previous topper is reparented onto its root.
1279- let cover_mountpoint = mount_fs. mountpoint_root_inode ( ) ;
12801318 covered. relocate_mountpoint ( Some ( cover_mountpoint. clone ( ) ) ) ;
1281- if let Err ( error) = mount_fs. attach_top ( & cover_mountpoint, covered. clone ( ) ) {
1319+ if let Err ( error) = mount_fs. attach_top ( cover_mountpoint, covered. clone ( ) ) {
12821320 covered. relocate_mountpoint ( Some ( mountpoint. clone ( ) ) ) ;
12831321 let mut mountpoints = self . mountpoints . lock ( ) ;
12841322 let stack = mountpoints
@@ -1300,28 +1338,127 @@ impl MountFS {
13001338 mount_fs : & Arc < MountFS > ,
13011339 ) -> Result < Arc < MountFS > , SystemError > {
13021340 let cover_mountpoint = mount_fs. mountpoint_root_inode ( ) ;
1303- let Some ( covered) = mount_fs
1304- . children_at ( & cover_mountpoint)
1305- . into_iter ( )
1306- . find ( |child| child. tucked_under . load ( Ordering :: Acquire ) )
1307- else {
1341+ let covered = mount_fs
1342+ . mountpoints
1343+ . lock ( )
1344+ . get ( & cover_mountpoint. dentry . id )
1345+ . and_then ( |stack| {
1346+ stack
1347+ . iter ( )
1348+ . find ( |child| child. tucked_under . load ( Ordering :: Acquire ) )
1349+ . cloned ( )
1350+ } ) ;
1351+ let Some ( covered) = covered else {
13081352 return self . detach_exact ( mount_fs) ;
13091353 } ;
1354+ self . restore_exact_cover ( mount_fs, & cover_mountpoint, & covered)
1355+ }
1356+
1357+ /// Transaction rollback variant using the exact topper and root wrapper
1358+ /// captured during prepare. It performs no discovery or allocation.
1359+ pub ( crate ) fn detach_exact_restoring_prepared_cover (
1360+ & self ,
1361+ mount_fs : & Arc < MountFS > ,
1362+ cover_mountpoint : Option < & Arc < MountFSInode > > ,
1363+ covered : Option < & Arc < MountFS > > ,
1364+ ) -> Result < Arc < MountFS > , SystemError > {
1365+ match ( cover_mountpoint, covered) {
1366+ ( None , None ) => self . detach_exact ( mount_fs) ,
1367+ ( Some ( cover_mountpoint) , Some ( covered) ) => {
1368+ if !covered. tucked_under . load ( Ordering :: Acquire )
1369+ || !mount_fs
1370+ . mountpoints
1371+ . lock ( )
1372+ . get ( & cover_mountpoint. dentry . id )
1373+ . is_some_and ( |stack| stack. iter ( ) . any ( |child| Arc :: ptr_eq ( child, covered) ) )
1374+ {
1375+ return Err ( SystemError :: ENOENT ) ;
1376+ }
1377+ self . restore_exact_cover ( mount_fs, cover_mountpoint, covered)
1378+ }
1379+ _ => Err ( SystemError :: EINVAL ) ,
1380+ }
1381+ }
1382+
1383+ fn restore_exact_cover (
1384+ & self ,
1385+ mount_fs : & Arc < MountFS > ,
1386+ cover_mountpoint : & Arc < MountFSInode > ,
1387+ covered : & Arc < MountFS > ,
1388+ ) -> Result < Arc < MountFS > , SystemError > {
13101389 let original_mountpoint = mount_fs. self_mountpoint ( ) . ok_or ( SystemError :: EINVAL ) ?;
1311- mount_fs. detach_exact ( & covered) ?;
1390+ // Preserve the clone-root Vec until restoration completes. This is
1391+ // the rollback counterpart of the prepare-time cover reservation.
1392+ let _cover_reservation = mount_fs. reserve_mount_edge ( cover_mountpoint, 0 ) ?;
1393+ mount_fs. detach_exact_keep_slot ( covered) ?;
13121394 covered. relocate_mountpoint ( Some ( original_mountpoint. clone ( ) ) ) ;
1313- let removed = self . detach_exact ( mount_fs) ?;
1314- if let Err ( error) = self . attach_top ( & original_mountpoint, covered. clone ( ) ) {
1315- // All objects remain owned; reconstruct the tuck-under topology.
1316- self . attach_top ( & original_mountpoint, mount_fs. clone ( ) ) ?;
1317- covered. relocate_mountpoint ( Some ( cover_mountpoint. clone ( ) ) ) ;
1318- mount_fs. attach_top ( & cover_mountpoint, covered) ?;
1319- return Err ( error) ;
1320- }
1395+ let removed = match self . replace_exact_edge ( mount_fs, covered. clone ( ) ) {
1396+ Ok ( removed) => removed,
1397+ Err ( error) => {
1398+ // All objects remain owned; reconstruct the tuck-under
1399+ // topology without allocating from the reserved cover slot.
1400+ covered. relocate_mountpoint ( Some ( cover_mountpoint. clone ( ) ) ) ;
1401+ mount_fs. attach_top ( cover_mountpoint, covered. clone ( ) ) ?;
1402+ covered. restore_tucked_under ( true ) ;
1403+ return Err ( error) ;
1404+ }
1405+ } ;
13211406 covered. tucked_under . store ( false , Ordering :: Release ) ;
13221407 Ok ( removed)
13231408 }
13241409
1410+ /// Replace one exact edge in place, preserving the parent stack's key,
1411+ /// capacity, ordering and mount-edge count.
1412+ fn replace_exact_edge (
1413+ & self ,
1414+ old : & Arc < MountFS > ,
1415+ replacement : Arc < MountFS > ,
1416+ ) -> Result < Arc < MountFS > , SystemError > {
1417+ let mountpoint = old. self_mountpoint ( ) . ok_or ( SystemError :: EINVAL ) ?;
1418+ if !Arc :: ptr_eq ( & mountpoint. mount_fs , & self . self_ref ( ) )
1419+ || replacement
1420+ . self_mountpoint ( )
1421+ . as_ref ( )
1422+ . is_none_or ( |replacement_mp| !Arc :: ptr_eq ( replacement_mp, & mountpoint) )
1423+ {
1424+ return Err ( SystemError :: EINVAL ) ;
1425+ }
1426+ let _gate = mountpoint. dentry . mount_gate . lock ( ) ;
1427+ let mut mountpoints = self . mountpoints . lock ( ) ;
1428+ let stack = mountpoints
1429+ . get_mut ( & mountpoint. dentry . id )
1430+ . ok_or ( SystemError :: ENOENT ) ?;
1431+ let index = stack
1432+ . iter ( )
1433+ . position ( |child| Arc :: ptr_eq ( child, old) )
1434+ . ok_or ( SystemError :: ENOENT ) ?;
1435+ Ok ( core:: mem:: replace ( & mut stack[ index] , replacement) )
1436+ }
1437+
1438+ pub ( crate ) fn detach_exact_keep_slot (
1439+ & self ,
1440+ mount_fs : & Arc < MountFS > ,
1441+ ) -> Result < Arc < MountFS > , SystemError > {
1442+ let mountpoint = mount_fs. self_mountpoint ( ) . ok_or ( SystemError :: EINVAL ) ?;
1443+ if !Arc :: ptr_eq ( & mountpoint. mount_fs , & self . self_ref ( ) ) {
1444+ return Err ( SystemError :: EINVAL ) ;
1445+ }
1446+ let _gate = mountpoint. dentry . mount_gate . lock ( ) ;
1447+ let key = mountpoint. dentry . id ;
1448+ let mut mountpoints = self . mountpoints . lock ( ) ;
1449+ let stack = mountpoints. get_mut ( & key) . ok_or ( SystemError :: ENOENT ) ?;
1450+ let index = stack
1451+ . iter ( )
1452+ . position ( |child| Arc :: ptr_eq ( child, mount_fs) )
1453+ . ok_or ( SystemError :: ENOENT ) ?;
1454+ let removed = stack. remove ( index) ;
1455+ mountpoint
1456+ . dentry
1457+ . mount_edges
1458+ . fetch_sub ( 1 , Ordering :: Release ) ;
1459+ Ok ( removed)
1460+ }
1461+
13251462 pub fn lookup_top ( & self , mountpoint : & Arc < MountFSInode > ) -> Option < Arc < MountFS > > {
13261463 self . mountpoints
13271464 . lock ( )
@@ -1377,6 +1514,39 @@ impl MountFS {
13771514 self . propagation . clone ( )
13781515 }
13791516
1517+ /// Reserve the HashMap key and stack capacity needed by a future exact
1518+ /// edge publication. Callers hold `MOUNT_LIFECYCLE_LOCK`, so no topology
1519+ /// writer can consume the reserved slot before commit.
1520+ pub ( crate ) fn reserve_mount_edge (
1521+ & self ,
1522+ mountpoint : & Arc < MountFSInode > ,
1523+ additional : usize ,
1524+ ) -> Result < MountEdgeReservation , SystemError > {
1525+ if !Arc :: ptr_eq ( & mountpoint. mount_fs , & self . self_ref ( ) ) {
1526+ return Err ( SystemError :: EINVAL ) ;
1527+ }
1528+ let key = mountpoint. dentry . id ;
1529+ let mut mountpoints = self . mountpoints . lock ( ) ;
1530+ if let Some ( stack) = mountpoints. get_mut ( & key) {
1531+ stack
1532+ . try_reserve ( additional)
1533+ . map_err ( |_| SystemError :: ENOMEM ) ?;
1534+ } else {
1535+ mountpoints
1536+ . try_reserve ( 1 )
1537+ . map_err ( |_| SystemError :: ENOMEM ) ?;
1538+ let mut stack = Vec :: new ( ) ;
1539+ stack
1540+ . try_reserve ( additional)
1541+ . map_err ( |_| SystemError :: ENOMEM ) ?;
1542+ mountpoints. insert ( key, stack) ;
1543+ }
1544+ Ok ( MountEdgeReservation {
1545+ parent : self . self_ref ( ) ,
1546+ mountpoint : mountpoint. clone ( ) ,
1547+ } )
1548+ }
1549+
13801550 /// Get the mount ID
13811551 pub fn mount_id ( & self ) -> MountId {
13821552 self . mount_id
@@ -2559,17 +2729,6 @@ impl MountFSInode {
25592729 return Err ( error) ;
25602730 }
25612731
2562- let mut pending = vec ! [ new_mount_fs. clone( ) ] ;
2563- while let Some ( mount) = pending. pop ( ) {
2564- pending. extend ( mount. mount_children ( ) ) ;
2565- let propagation = mount. propagation ( ) ;
2566- if propagation. is_shared ( ) {
2567- register_peer ( propagation. peer_group_id ( ) , & mount) ;
2568- }
2569- if propagation. is_slave ( ) {
2570- register_slave_with_master ( & mount) ;
2571- }
2572- }
25732732 Ok ( ( ) )
25742733 }
25752734
0 commit comments