Re: [BUG] propagate_umount() breakage

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, May 11, 2025 at 11:50:40PM -0500, Eric W. Biederman wrote:

> This is there be dragons talk.
> 
> With out care it is easy to get the code to go non-linear in
> the number of mounts.
> 
> That said I don't see any immediate problem with a first pass
> without my __propgate_umount.
> 
> As I read the current code the __propagate_umount loop is just
> about propagating the information up from the leaves.
> 
> > After the set is collected, we could go through it, doing the
> > something along the lines of
> > 	how = 0
> > 	for each child in children(m)
> > 		if child in set
> > 			continue
> > 		how = 1
> > 		if child is not mounted on root
> > 			how = 2
> > 			break
> > 	if how == 2
> > 		kick_out_ancestors(m)
> > 		remove m itself from set // needs to cooperate with outer loop
> > 	else if how == 1
> > 		for (p = m; p in set && p is mounted on root; p = p->mnt_parent)
> > 			;
> > 		if p in set
> > 			kick_out_ancestors(p)
> > 	else if children(m) is empty && m is not locked	// to optimize things a bit
> > 		commit to unmounting m (again, needs to cooperate with the outer loop)

Misses some valid candidates, unfortunately.  It's not hard to fix -
handle_overmounts(m)
        remove_it = false;
        non_vanishing = NULL; // something non-vanishing there
        for each child in m->mnt_mounts
                if child not in Candidates
                        non_vanishing = child;
                        if (!overmounts_root(child)) {
                                remove_it = true;
                                break;
                        }
        if (non_vanishing) {
                for (p = m; p in Candidates && !marked(p); p = p->mnt_parent) {
                        if (!overmounts_root(non_vanishing) && p != m)
                                Candidates -= {p}
			else
				mark(p);
                        non_vanishing = p;
                }
        } else if m->mnt_mounts is empty && m is not locked { // optimize a bit
                commit_to_unmounting(m);
                remove_it = true;
        }
        res = next(m) // NULL if at the end of Candidates
        if (remove_it) {
		unmark(m);
                Candidates -= {m}
	}
        return res
will do the right thing and it's linear by the number of mounts we must
look at.

And yes, it's going to be posted along with the proof of correctness -
I've had it with the amount of subtle corner cases in that area ;-/




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux