python / cpython

The Python programming language
https://www.python.org
Other
63.31k stars 30.3k forks source link

Document that os.path.ismount() returns true for nested btrfs subvolumes #81520

Open 954fe198-6f95-4572-a376-ca7e51597357 opened 5 years ago

954fe198-6f95-4572-a376-ca7e51597357 commented 5 years ago
BPO 37339
Nosy @serhiy-storchaka, @eryksun, @jstasiak, @eike-fokken

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields: ```python assignee = None closed_at = None created_at = labels = ['3.8', '3.9', '3.10', 'type-feature', 'library', 'docs'] title = 'Document that os.path.ismount() returns true for nested btrfs subvolumes' updated_at = user = 'https://github.com/eike-fokken' ``` bugs.python.org fields: ```python activity = actor = 'eryksun' assignee = 'docs@python' closed = False closed_date = None closer = None components = ['Documentation', 'Library (Lib)'] creation = creator = 'eike' dependencies = [] files = [] hgrepos = [] issue_num = 37339 keywords = [] message_count = 7.0 messages = ['346035', '346060', '346063', '346068', '346111', '367028', '368336'] nosy_count = 5.0 nosy_names = ['docs@python', 'serhiy.storchaka', 'eryksun', 'jstasiak', 'eike'] pr_nums = [] priority = 'normal' resolution = None stage = None status = 'open' superseder = None type = 'enhancement' url = 'https://bugs.python.org/issue37339' versions = ['Python 3.8', 'Python 3.9', 'Python 3.10'] ```

954fe198-6f95-4572-a376-ca7e51597357 commented 5 years ago

Lets say, we have a btrfs partion with subvolumes @, mounted at / and home, which was created directly inside @, such that after mounting @, it can be found at /home.

Then os.path.ismount("/home") returns True I would not have expected that, because the program findmnt from the util-linux software package doesn't list it if I run findmnt -A

I think that the two programs should agree on whether it's a mount point or not but am unsure whether findmnt or os.path.ismount should be altered because I don't know a definite definition of a mountpoint.

Note that I agree with the current behaviour for explicitely mounted subvolumes. An example would be if I have the subvolume @ mounted at / and a subvolume @home created at the toplevel of the btrfs filesystem which is then mounted at /home. Here findmnt and os.path.ismount agree that this is a mount point.

serhiy-storchaka commented 5 years ago

What does the mountpoint command returns?

954fe198-6f95-4572-a376-ca7e51597357 commented 5 years ago

mountpoint /nested_subvolume returns /nested_subvolume is not a mountpoint

mountpoint /explicitely_mounted_subvolume returns /explicitely_mounted_subvolume is a mountpoint

so agrees with findmnt.

serhiy-storchaka commented 5 years ago

os.path.ismount() uses the same simple algorithm as a portable version of mountpoint. But mountpoint (and findmnt) from util-linux uses Linux specific methods (reads /proc/mounts or something like). See also bpo-29707.

954fe198-6f95-4572-a376-ca7e51597357 commented 5 years ago

I read the other issue, thanks.

What do you mean by "portable version of mountpoint"? Is there a portable version of mountpoint or was it more a figure of speech?

Concerning the issue itself:

What are the priorities with the behaviour of ismount? Is it more important to be consistent with the system it is run on or is it more important that every python instance on every system would return the same values?

I see merits for both, I'm just curious what the python developers value more.

In case it is the later I propose to change the docs on ismount again to include that it disagrees with Linux on nested btrfs subvolumes.

If you like I can make a pull request for that. My favourite solution would be to have agreement with linux on this but at the moment I have no idea how that could be implemented without resorting to Linux native utilities.

eryksun commented 4 years ago

What do you mean by "portable version of mountpoint"?

posixpath.ismount is based on a portable method to detect a mountpoint in Unix systems, since POSIX lacks a portable function for this. The implementation is simple. A symlink is never a mountpoint. Otherwise compare the lstat of the path and its parent directory. It's a mountpoint if the st_dev fields are different. If not, it's a mountpoint if the st_ino fields are the same (e.g. "/").

The portable method may fail in particular cases. For instance, a bind mount in the Linux kernel (not bindfs) doesn't create a new device. For example, given "/opt" is bound to "opt" in the current directory on the same filesystem, ismount returns a false negative:

    >>> posixpath.ismount('opt')
    False

But it's a mountpoint according to the "/proc/self/mountinfo" table:

    >>> os.system('mountpoint opt')
    opt is a mountpoint
    0

The above false negative is documented, so a precedent exists to simply document the false positive with a btrfs subvolume. Developers can make of it what they will. If it matters to not count this case as a mountpoint, a script will have to implement its own platform-specific solution (e.g. use subprocess to call mountpoint).

954fe198-6f95-4572-a376-ca7e51597357 commented 4 years ago

Ok, this is my proposal for the documentation. I hope you like it.

Is this the correct place to post it or can I make a direct pull request? old: .. function:: ismount(path)

Return ``True`` if pathname *path is a :dfn:`mount point`: a point in a file system where a different file system has been mounted. The function checks whether *path's parent, :file:`path/..`, is on a different device than *path, or whether :file:`path/..` and *path point to the same i-node on the same device --- this should detect mount points for all Unix and POSIX variants.

new: .. function:: ismount(path)

Return ``True`` if pathname *path is a :dfn:`mount point`: a point in a file system where a different file system has been mounted. The function checks whether *path's parent, :file:`path/..`, is on a different device than *path, or whether :file:`path/..` and *path point to the same i-node on the same device --- this should detect mount points for all Unix and POSIX variants. Note that in Linux not all mountpoints as recognized by the kernel are found this way. An example are bind-mounts. Also some directories return ``True`` although Linux doesn't recognize them as mount points. An example are nested subvolumes in the Btrfs filesystem