Pourquoi le montage se produit-il sur un répertoire existant?

52

Un répertoire existant est nécessaire en tant que point de montage .

$ ls
$ sudo mount /dev/sdb2 ./datadisk
mount: mount point ./datadisk does not exist
$ mkdir datadisk
$ sudo mount /dev/sdb2 ./datadisk
$

Je trouve cela déroutant car il recouvre le contenu existant du répertoire. Il existe deux contenus possibles du répertoire du point de montage qui peuvent être modifiés de manière inattendue (pour un utilisateur qui n'effectue pas le montage).

Pourquoi ne se mountpasse- t-il pas dans un répertoire nouvellement créé? C'est ainsi que les systèmes d'exploitation graphiques affichent les supports amovibles. Il serait clair si le répertoire est monté (existe) ou non monté (n'existe pas). Je suis presque sûr qu'il y a une bonne raison mais je n'ai pas encore réussi à le découvrir.

Melebius
la source
1
Si vous voulez ce comportement, utilisez udisksctl. Pourquoi utiliser mount?
Muru
1
Parce que c'est la manière d'Unix. Parce que de cette façon, il est plus flexible et vous pouvez monter n'importe où. Parce que les monter n'importe où vous permet d'étendre vos serveurs selon vos besoins, par exemple, obtenir un nouveau disque pour la partition de base de données, déplacer les données de la partition de base de données sur le nouveau disque et les monter au bon endroit pour permettre aux données de la base de données grandir plus.
Rui F Ribeiro
8
Pour rappel, avant que Windows et Linux n'écrase essentiellement tous les autres systèmes d'exploitation, il existait une société appelée Apollo. Ils ont écrit un système d’exploitation semblable à Unix (meilleur design que Unix!). Il a créé les répertoires sur lesquels les exportations NFS sont montées automatiquement. En fait, vous ne pouvez pas monter sur un répertoire préexistant. HP a acheté Apollo, jeté le système d’exploitation et utilisé le processeur 64 bits d’Apollo en tant que HP-PA. Le système d'appels à distance de procédures d'Apollo est devenu le DCE d'OSF, qui vit apparemment à l'intérieur de Windows. Savoir, c'est la moitié de la bataille!
Bruce Ediger
En quelque sorte, cela se produit sur mon système Ubuntu 14.04,3. Je n'ai pas encore enquêté. Lorsque ma carte SD est montée, elle se termine sur un chemin dépourvu de dessous. Si je le démonte et que je tente de le remonter manuellement, l'erreur que j'obtiens est qu'il n'y a pas de répertoire au point de montage.
Skaperen
2
@BruceEdiger better design than Unix![citation nécessaire]
Ruslan

Réponses:

51

Il s’agit d’un détail de mise en oeuvre qui a filtré.

Dans un système UNIX, chaque répertoire est constitué d'une liste de noms mappés sur des numéros d' inode . Un inode contient des métadonnées qui indiquent au système s'il s'agit d'un fichier, d'un répertoire, d'un périphérique spécial, d'un canal nommé, etc. S'il s'agit d'un fichier ou d'un répertoire, il indique également au système où trouver le contenu du fichier ou du répertoire sur le disque. La plupart des inodes sont des fichiers ou des répertoires. L' -ioption to lslistera les numéros d'inode.

Monter un système de fichiers prend un inode de répertoire et définit un indicateur sur la copie en mémoire du noyau pour dire "réellement, lorsque vous recherchez le contenu de ce répertoire, regardez plutôt cet autre système de fichiers" (voir la diapositive 10 de cette présentation ). C'est relativement facile, car cela modifie un seul élément de données.

Pourquoi ne crée-t-il pas une entrée de répertoire pour vous pointant vers le nouvel inode? Vous pouvez mettre cela en œuvre de deux manières, qui présentent toutes deux des inconvénients. L'une consiste à écrire physiquement un nouveau répertoire dans le système de fichiers - mais cela échoue si le système de fichiers est en lecture seule! L'autre consiste à ajouter à chaque processus de liste de répertoires une liste d'éléments "supplémentaires" qui ne sont pas réellement présents. Cela est fastidieux et risque potentiellement d’entraîner une petite perte de performances lors de chaque opération de fichier.

Si vous souhaitez créer des points de montage créés dynamiquement, le automountsystème peut le faire. Spéciaux non-systèmes de fichiers disque peuvent également créer des répertoires à volonté, par exemple proc, sys, devfset ainsi de suite.

Éditer: voir aussi la réponse à Que se passe-t-il lorsque vous «montez» sur un dossier existant avec du contenu?

pjc50
la source
Sauf que cela ne met pas un drapeau sur l'inode. sudo mount --bind / /mnt ; ls /mnt/proc-> vide. Je me demande comment ça marche.
sourcejedi
L'opération exacte est fs/namespace.c, je pense; Je ne connais pas la source et je ne voulais pas passer trop de temps à percer jusqu'au détail. Le "drapeau sur l'inode" que j'ai obtenu de la présentation liée.
pjc50
2
@sourcejedi: bind mounts ne lie que le système de fichiers auquel vous faites référence. Ils ne lient pas récursivement les autres systèmes de fichiers montés sous celui-ci. C'est un moyen pratique de trouver de la malbouffe cachée par des montures. (Par exemple, si certains éléments ont fini sur le système d' /var/cacheexploitation racine à un moment ou un autre /varn'a pas pu être monté.) Voir aussi path_resolution(7). (Les anciennes pages de manuel linux-man avaient cette page de manuel dans la section 2, comme die.net) IDK comment Linux fonctionne réellement en interne, afin d’optimiser la vérification de chaque composant du répertoire comme montage possible. Peut-être épingler cette entrée VFS dans le cache?
Peter Cordes
2
C'est ce que je veux dire ... Donc fs/namei.c(path -> inode lookup) appelle cependant dans namespace.c lookup_mnt(). Il y a un drapeau sur le dentry (entrée de cache de répertoire). Mais ce n'est qu'une optimisation, c'est-à-dire une implémentation. Il ne vous dit pas quel système de fichiers est monté là-bas; vous devez regarder dans la table de montage. (Voir m_hash (), pour plus de détails sur l'implémentation. Linux évite au moins les comparaisons de chaînes supplémentaires, et AFAICS parvient en même temps à réutiliser des dentry dans des montages de liaisons, par exemple, car il est écrit par des assistants).
sourcejedi
1
@PeterCordes man 8 mount:: mount --bind foo foo. L' mountappel de liaison attache seulement (une partie de) un système de fichiers unique, pas de sous-montages possibles. Toute la hiérarchie des fichiers, y compris les sous-montages, est attachée à la deuxième place en utilisant :mount --rbind olddir newdir
mikeserv
19

Si mount(2) nécessaire la création d'un nouveau répertoire pour être le point de montage, on ne pouvait pas monter quoi que ce soit dans un système de fichiers en lecture seule. Ce serait stupide, alors nous pouvons l'exclure.

Si mount créait éventuellement un nouveau répertoire comme point de montage, ce serait étrange. Ce n'est pas comme si le montage / démontage se produisait tout le temps, donc ajouter une logique supplémentaire dans le noyau pour effectuer ces deux étapes avec un seul appel système ne constituerait pas une accélération importante. Il suffit de laisser à l’espace utilisateur le pouvoir de faire un mkdir(2)appel système s’il le souhaite. La réponse de Dmitry indique qu'avoir mount(2)fait les deux choses le rendrait non atomique. Et vous voulez un argument supplémentaire pour mount(2)avec des drapeaux de mode comme open(2)prend, pour O_CREAT, O_EXCLetc. Il serait tout simplement ridicule par rapport à laisser l'espace utilisateur le faire.

Ou peut-être demandez-vous si mount(8)(le programme traditionnel qui effectue des mount(2)appels système) le fait? Ce serait possible, mais il y a déjà un très bon mkdir(1)travail, et la conception d'Unix est basée sur de bons petits outils pouvant être combinés. Si vous voulez un outil qui fait les deux, il est facile d'écrire un script shell pour le construire à partir de deux outils plus simples. (Ou, comme le dit muru, le fait udisksctldéjà, vous n'avez donc pas à l'écrire.) De plus, Linux utilise normalement la syntaxe mount(8)d'util-linux mount -o x-mount.mkdir[=mode]avec sa x-syntaxe pour les options de l'espace utilisateur, plutôt que les options à transmettre au système de fichiers.


Maintenant la question la plus intéressante: pourquoi faut-il un répertoire sur le système de fichiers parent?

Comme le souligne la réponse de pjc50 (aucune relation, même s'il a mes initiales!), L'affichage des points de montage dans les listes de répertoires exigerait un contrôle supplémentaire à chaque passage readdir().

Disposer de points de montage en tant que répertoires dans le répertoire qui les contient (sur le système de fichiers parent) est une bonne astuce. readdir()ne doit pas remarquer que c'est un point de montage du tout. Cela ne se produit que si le point de montage est utilisé comme composant de chemin. La résolution du chemin doit bien sûr vérifier la table de montage pour chaque composant de répertoire d'un chemin.

Peter Cordes
la source
1
If mount(2) required the creation of a new directory to be the mount point, you couldn't mount anything under a read-only filesystem. That would be dumb- Je dirais plus intelligemment: du point de vue de l'utilisateur, un système de fichiers en lecture seule ne devrait pas changer, mais autoriser les montages signifie qu'il le peut
Izkata
2
@ Izkata: Créer un système de fichiers en lecture seule ne signifie pas que toute la sous-arborescence du VFS est gelée. Il pourrait y avoir des liens symboliques pointant vers des répertoires en lecture-écriture ou déjà des points de montage en lecture-écriture lors du remontage du fs parent ro. Il existe de nombreux cas d'utilisation de systèmes de fichiers en lecture seule pour lesquels votre argument n'a pas de sens.
Peter Cordes
2
man 8 mount: x-mount.mkdir[=mode] Permet de créer un répertoire cible (point de montage). L'argument optionnel mode spécifie le mode d'accès au système de fichiers utilisé pour la mkdir(2)notation octale. Le mode par défaut est 0755. Cette fonctionnalité est prise en charge uniquement par les utilisateurs root.
mikeserv
Je ne vois pas de cas d'utilisation important de systèmes de fichiers en lecture seule avec des systèmes de fichiers montés en lecture-écriture, en particulier pas dans les premiers Unix. @PeterCordes
kubanczyk
@kubanczyk: système de fichiers racine en lecture seule, avec une lecture-écriture /tmpet /home. Ou monté en NFS en lecture seule /usravec un local /usr/localmonté dessus. Ou plus généralement, toute image partagée en lecture seule avec une partie modifiable montée dessus. (Les mods locaux d'une image en lecture seule peuvent également être effectués fichier par fichier avec des systèmes de fichiers personnalisés tels que les superpositions ou d'autres systèmes de fichiers d'union pour Linux, utilisés sur des images de démarrage LiveCD.) boot, mais le faire rw peut arriver avant d’autres montages.
Peter Cordes
12

Monter sur un répertoire existant appelle mountpratiquement atomique: il réussit ou échoue, du moins du point de vue de l'utilisateur. S'il mountdevait créer le point de montage lui-même, il aurait deux points de défaillance, rendant impossible la garantie d'un retour en arrière propre. Imaginez le scénario suivant:

  1. mount crée avec succès le point de montage
  2. mount tente de monter un nouveau système de fichiers dans ce répertoire, mais échoue
  3. mount tente de supprimer le point de montage, mais échoue

Le système finit par avoir un effet secondaire d'échec mount.

En voici un autre:

  1. umount démonte avec succès un système de fichiers
  2. umount tente de supprimer le point de montage, mais échoue

Maintenant, faut-il umountretourner le succès ou l'échec?

Dmitry Grigoryev
la source
5
mounta 8 codes de retour différents pour les erreurs qui peuvent également être combinés. Il pourrait simplement en ajouter un autre lorsque la suppression du répertoire échoue. man7.org/linux/man-pages/man8/mount.8.html#RETURN_CODES
chaos
8
Je pense que l'OP demande pourquoi le point de montage doit être un répertoire existant, pas pourquoi l' mountappel système ne le crée pas. Bien que cela soit peut-être juste mon interprétation / attente de ce que je pensais que le PO voulait dire, ou ce que j’aurais demandé si j’avais demandé.
Peter Cordes
3

Un autre cas qui peut se produire:

Lorsque vous démarrez, une image de base en lecture seule est chargée dans le répertoire racine. Vous souhaitez donc le remplacer lorsque vous souhaitez créer une racine réelle. Vous pouvez donc imaginer que mount syscall permute simplement le ropoint de montage rw.

Ici, imaginons que vous ayez un problème de système de fichiers sur le point de montage racine, vous voudriez pouvoir essayer de le réparer. Avec le montage en chevauchement, vous pouvez démonter le système de fichiers et utiliser fsckl’image fournie dans l’image de base pour le résoudre.

Cette fonctionnalité peut également être utile dans les systèmes nécessitant une sécurité renforcée pour pouvoir suivre le changement entre une ropartition et une rwautre.

alexis
la source
1
Je ne sais pas comment cela répond à la question. Faites-vous remarquer que, si mount nécessaire, en créant un nouveau répertoire à l'emplacement du point de montage, vous ne pouvez rien monter sur un système de fichiers en lecture seule? Le paragraphe d'ouverture est déroutant: ce n'est pas comme ça que initrd Linux fonctionne. Il utilise l' pivot_rootappel système pour changer le fs racine, pas seulement monter plus de choses dessus. Cela vous empêchait de suivre votre logique dans les paragraphes suivants, car je pensais que vous en parliez pivot_root(2).
Peter Cordes
2
@PeterCordes - linux n'a pas utilisé d'initrd depuis de nombreuses années : lors du changement d'un autre périphérique racine, initrd le ferait pivot_root, puis umountle disque mémoire. Mais initramfs est rootfs: vous ne pouvez ni pivot_rootrootfs, ni le démonter . Au lieu de tout supprimer de rootfs pour libérer de l'espace ( find -xdev / -exec rm {} \;), superposez les rootfs avec la nouvelle racine ( cd /newmount; mount --move . /; chroot .), attachez stdin / stdout / stderr à la nouvelle / dev / console, et à execla nouvelleinit
mikeserv
@mikeserv: Neat! Je n'avais pas réalisé que le mécanisme de base pour la commutation de racines avait changé lorsque nous avons commencé à utiliser initramfs au lieu d'initrd. D'un point de vue administrateur "assurez-vous que les bons modules du noyau y aboutissent", ils sont identiques>. <. Je pense toujours que cela ne répond pas vraiment à la question . Il semble supposer que l'interprétation "monter sous un rofs est impossible" et donne un cas très spécifique (ce qui semble peu probable car initramfs n'est pas monté en lecture seule au démarrage. Même s'il l'est, il peut simplement être remonté en lecture -écrire sans affecter l'image cpio.gz.)
Peter Cordes
@PeterCordes - Je ne comprends pas vraiment cette réponse. Je viens de voir votre commentaire - initramfs est un système de fichiers - il ne peut vraiment jamais être en lecture seule - son cache fs est incarné.
mikeserv
2

Je me suis toujours demandé cela aussi.

Un simple emballage tel que:

#!/bin/sh
eval "mkdir -p \"\$$#\"" 
/bin/mount "$@"  

sauvegardé en tant que script exécutable nommé mountdans un répertoire remplaçant /bindans votre PATH devrait s'en occuper s'il vous dérange trop

(Avant d'exécuter le mountbinaire réel , il crée un répertoire nommé d'après le dernier argument de mount, si ce répertoire n'existe pas déjà.)


Alternativement, si vous ne voulez pas que les invocations échouées du mountwrapper créent des répertoires, vous pouvez faire:

#!/bin/sh
set -e
eval "lastArg=\"\$$#\""
test -d "$lastArg" || { mkdir "$lastArg"; madeDir=1; }
/bin/mount "$@"  ||  {  test -z "$madeDir" || rmdir "$lastArg"; }
PSkocik
la source
La mountcommande ne devrait-elle pas alors utiliser le répertoire ainsi créé?
muru
1
@muru C'est ce que fait la dernière ligne.
PSkocik
Oh, vous voulez dire que cela devrait être utilisé ainsi mount /dev/foo /some/path:? J'ai supposé que cela fonctionnerait comme udisksctlsi, alors vous courriez mount /dev/foo.
muru
4
Vous pouvez obtenir le dernier argument de cmdline sans evaldévelopper $#, en utilisant "${@:-1}". J'ai testé cela avec DASH, car je pense qu'il ne supporte rien de plus que ce que POSIX sh est requis de supporter. /bin/dash -c 'echo ${@:-1}' foo barimpressions bar.
Peter Cordes
1
vous pouvez utiliser man -o x-mount.mkdir...
mikeserv