Чому монтаж відбувається через існуючий каталог?


52

Існуючий каталог потрібен як точка монтажу .

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

Я вважаю це заплутаним, оскільки він накладає наявний вміст каталогу. Існує два можливих вмісту каталогу точок монтування, які можуть несподівано переключитися (для користувача, який не виконує монтаж).

Чому не mountтрапляється в новостворений каталог? Це спосіб, яким графічні операційні системи відображають знімні носії. Було б зрозуміло, встановлений каталог (існує) чи не змонтований (не існує). Я впевнений, що є вагома причина, але я поки не змогла її виявити.


1
Якщо ви хочете такої поведінки, використовуйте udisksctl. Навіщо використовувати mount?
муру

1
Тому що це шлях Unix. Тому що таким чином він є більш гнучким, і ви зможете змонтувати його в будь-якому місці. Оскільки встановлення їх в будь-якому місці дозволяє розширити ваші сервери так, як вам потрібно, наприклад, отримати новий диск для розділу баз даних, перемістити дані в розділі БД на новий диск і встановити його в потрібному місці, щоб дозволити дані БД рости більше.
Rui F Ribeiro

8
Як історична примітка, перш ніж Windows і LInux по суті розбили всі інші ОС, існувала компанія під назвою Apollo. Вони написали однакову (кращу конструкцію, ніж Unix!) Операційну систему. Він створив каталоги, в які експорт NFS встановлювався автоматично. Насправді ви не змогли встановитись на попередньо існуючий каталог. HP купила Apollo, викинула операційну систему і використовувала 64-бітний процесор Apollo як HP-PA. Система віддалених процедурних дзвінків Apollo стала DCE OSF, який, очевидно, живе всередині Windows. Знати - це половина битви!
Брюс Едігер

так чи інакше це відбувається в моїй системі ubuntu 14.04,3. я ще не досліджував. коли моя SD-карта встановлюється, вона закінчується на шляху, під яким немає нічого. якщо я подумаю про це і спробую вручну встановити його назад, я отримую помилку, що в точці монтажу немає каталогу.
Скаперен

2
@BruceEdiger better design than Unix![потрібна цитата]
Руслан

Відповіді:


51

Це випадок детальної реалізації, яка просочилася.

У системі UNIX кожен каталог складається зі списку імен, відображених на номери inode . В inode є метадані, які повідомляють системі, чи це файл, каталог, спеціальний пристрій, названа труба тощо. Якщо це файл чи каталог, він також повідомляє системі, де знайти вміст файлу чи каталогу на диску. Більшість індексів - це файли чи каталоги. -iВаріант lsбуде список номерів індексних дескрипторів.

Встановлення файлової системи займає inode каталогу і встановлює прапор на копії пам’яті ядра, щоб сказати «насправді, шукаючи вміст цього каталогу, замість цього перегляньте іншу файлову систему» ​​(див. Слайд 10 цієї презентації ). Це порівняно просто, оскільки це змінює один елемент даних.

Чому він не створює для вас запис каталогу, вказуючи на новий inode? Ви можете це здійснити двома способами, обидва з яких мають недоліки. Одне полягає в тому, щоб фізично записати новий каталог у файлову систему - але це не вдасться, якщо файлова система читається тільки! Інше - додати до кожного каталогу переліку список "зайвих" речей, яких насправді немає. Це хитро і, можливо, спричиняє невеликий показник продуктивності для кожної файлової операції.

Якщо ви хочете динамічно створені точки монтажу, automountсистема може це зробити. Спеціальні файлові системи без диска можуть також створювати каталоги за бажанням, наприклад proc, sys, devfsі так далі.

Редагувати: див. Також відповідь на те, що відбувається, коли ви перейдете на наявну папку із вмістом?


За винятком того, що він не встановлює прапор на inode. sudo mount --bind / /mnt ; ls /mnt/proc-> порожній. Цікаво, як це працює.
sourcejedi

Точна операція в fs/namespace.c, я думаю; Я не знайомий з джерелом і не хотів витрачати занадто довго на буріння до деталей. "Прапор на inode" я отримав із пов'язаної презентації.
pjc50

2
@sourcejedi: прив'язувати кріплення пов'язує лише файлову систему, на яку ви фактично посилаєтесь. Вони не пов'язують інші файлові системи, встановлені під нею. Це зручний спосіб знайти мотлох, прихований кріпленнями. (наприклад, якщо якийсь матеріал потрапив у FS за /var/cacheпевний час, коли його /varне вдалося встановити.) Дивіться також path_resolution(7). (Старіші Linux-manpages мали цю сторінку в розділі 2, як die.net) IDK про те, як Linux насправді працює внутрішньо, щоб оптимізувати перевірку кожного компонента каталогу як можливого кріплення. Може бути зафіксувати цей запис VFS у кеші?
Пітер Кордес

2
Так, це моя думка ... Тож fs/namei.c(path -> inode search) дзвонить у namespace.c, хоча lookup_mnt(). На стоматології є прапор (запис у кеш-каталог). Але це лише детальна оптимізація. Це не говорить вам, яка файлова система там змонтована; ви повинні шукати в таблиці кріплення. (Див. M_hash (), щоб отримати докладніші відомості про впровадження. Linux, принаймні, уникає додаткових порівнянь рядків, і AFAICS одночасно вдається повторно використовувати зубні ряди, наприклад, прив'язувати кріплення, тому що це написано майстрами).
sourcejedi

1
@PeterCordes man 8 mount:: mount --bind foo foo. mountВиклик прив'язки приєднує лише (частину) однієї файлової системи, а не можливі підмножини. Уся ієрархія файлів, включаючи додаткові кріплення, приєднується до другого місця, використовуючи :mount --rbind olddir newdir
mikeserv

19

Якщо mount(2) потрібно було створити новий каталог, який буде точкою монтування, ви не змогли нічого змонтувати під файловою системою лише для читання. Це було б глупо, тому ми можемо це виключити.

Якщо при монтажі необов'язково створено новий каталог, який буде точкою кріплення , це було б дивно. Це не так, як mount / unmount трапляються постійно, тому введення додаткової логіки в ядро ​​для виконання цих двох кроків за допомогою одного системного виклику не буде важливим прискоренням. Просто залиште його на просторі користувача, щоб здійснити mkdir(2)системний дзвінок, якщо він хоче. У відповіді Дмитра вказується, що mount(2)робити обидві речі це зробило б це не атомним. І ви хочете отримати додатковий аргумент mount(2)з прапорами режиму, як " open(2)take", " O_CREAT," O_EXCLі т.д.

Або, можливо, ви запитували про те, щоб mount(8)(традиційна програма, яка робить mount(2)системні дзвінки) робити це? Це було б можливо, але там вже ідеально добре mkdir(1)для роботи, і дизайн Unix - це все про хороші невеликі інструменти, які можна комбінувати. Якщо ви хочете, щоб інструмент робив і те, і інше, легко написати сценарій оболонки, щоб створити цей інструмент з двох простих інструментів. (Або, як зауважив Муру, це udisksctlвже робиться, тому вам не доведеться писати це.) Також, звичайний Linux mount(8)від util-linux підтримує mount -o x-mount.mkdir[=mode]його x-синтаксис для параметрів для простору користувачів, а не для передачі параметрів у файлову систему.


Тепер цікавіше питання: чому взагалі повинен бути каталог у батьківській файловій системі?

Як і вказує відповідь pjc50 (жодного відношення, хоча у нього є мої ініціали!), Якщо точки монтажу відображатись у списках каталогів, тоді знадобиться додаткова перевірка на кожен readdir().

Наявність точок монтажу як каталогів у каталозі, що містить їх (на батьківському FS) - приємний трюк. readdir()зовсім не потрібно помічати, що це точка кріплення. Це відбувається лише в тому випадку, якщо точка монтажу використовується як компонент шляху. Дозвіл доріжки, звичайно, повинен перевіряти таблицю кріплення для кожного компонента каталогу шляху.


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- Я б стверджував, що це розумніше: з точки зору користувача файлова система лише для читання не повинна змінюватися, але якщо дозволити монтажі, це означає, що це може
Izkata

2
@Izkata: Здійснення файлової системи лише для читання не означає, що все піддірення VFS заморожене. Це може мати символьні посилання, що вказують на каталоги читання-запису, або вже мати під ним точки монтажу читання-запису, коли переглянуто батьківське fs ro. Існує багато випадків використання файлових систем, доступних лише для читання, де ваш аргумент не має сенсу.
Пітер Кордес

2
man 8 mount: x-mount.mkdir[=mode] Дозволити скласти цільовий каталог (pointpoint). Необов’язковий режим аргументу визначає режим доступу до файлової системи, який використовується для mkdir(2)восьмеричних позначень. Режим за замовчуванням - 0755. Цей функціонал підтримується лише для користувачів root.
mikeserv

Я не бачу жодних важливих випадків використання файлових систем лише для читання з встановленими файловими системами для читання і запису, особливо не в ранньому Unix. @PeterCordes
kubanczyk

@kubanczyk: коренева файлова система лише для читання, із читанням-записом /tmpта /home. Або тільки для читання NFS монтажу /usrз локальним /usr/localвстановленим на ньому. Або загалом, будь-яке спільне зображення, доступне лише для читання, із зміненою частиною, змонтованою над ним. (локальні моди на зображення, доступне лише для читання, можна також робити на основі файлів за допомогою спеціальних файлових систем, таких як накладення файлів або інших файлових систем об'єднання для Linux, використовуваних для завантажувальних зображень LiveCD.) Спочатку я думав про початково встановлений корінний FS на RO завантаження, але зробити це rw може і раніше, ніж інші кріплення.
Пітер Кордес

12

Якщо встановити існуючий каталог, виклик mountпрактично атомний: він або успішний, або невдалий, принаймні з точки зору користувача. Якщо б mountдовелося створити саму точку кріплення, у неї виникли б дві точки відмови, що унеможливлювало гарантування чистого відкоту назад. Уявіть такий сценарій:

  1. mount успішно створює точку кріплення
  2. mount намагається встановити нову файлову систему до цього каталогу, але не вдається
  3. mount намагається зняти точку кріплення, але не вдається

Система закінчується побічним ефектом відмови mount.

Ось ще один:

  1. umount успішно відключається файлова система
  2. umount намагається зняти точку кріплення, але не вдається

Тепер варто umountповернути успіх чи невдачу?


5
mountмає 8 різних кодів повернення помилок, які також можна комбінувати. Він може просто додати ще один, коли не вдалося видалити каталог. man7.org/linux/man-pages/man8/mount.8.html#RETURN_CODES
хаос

8
Я думаю, що ОП задає питання, чому монтовою точкою взагалі повинен бути існуючий каталог, а не чому mountсистемний виклик не створює його. Хоча, можливо, це була лише моя інтерпретація / очікування того, що я вважав, що ОП має на меті запитати, або те, що я б запитав, якби я питав.
Пітер Кордес

3

Ще один випадок, який може статися:

Під час завантаження основне зображення, лише для читання, завантажується в кореневий каталог. Тож ви хотіли б її замінити, коли хотіли б насипати справжній корінь. Таким чином, ви можете уявити, що система ssscall для монтування просто поміняє місце roмонтування rw.

Тут давайте уявимо, що у вас є проблема з файловою системою на кореневій точці монтажу, ви хотіли б спробувати її відновити. За допомогою перекриття кріплення ви можете відключити файлову систему та використовувати fsckнадане в базовому зображенні для її вирішення.

Ця функція також може бути корисною в системах, які потребують сильної безпеки, щоб відслідковувати зміни між roрозділом і rwодним.


1
Я не впевнений, як це відповідає на питання. Ви вказуєте на те, що при mount необхідності створення нового каталогу в місці монтажу, що ви не змогли нічого встановити поверх файлової системи, що використовується лише для читання? Вступний параграф заплутаний: це не так, як працює Linux initrd. Він використовує pivot_rootсистемний виклик, щоб змінити кореневий fs, а не просто монтувати більше речей над ним. Це важко було слідувати вашій логіці в наступних параграфах, тому що я думав, що ти говориш pivot_root(2).
Пітер Кордес

2
@PeterCordes - Linux вже багато років не використовує initrd : При переключенні іншого кореневого пристрою initrd буде, pivot_rootа потім umountramdisk. Але initramfs - це rootfs: ви не можете ні pivot_rootrootfs, ні демонтувати його . Замість цього видаліть усе із find -xdev / -exec rm {} \;кореневих файлів, щоб звільнити простір ( ), переставте корені з новим коренем ( cd /newmount; mount --move . /; chroot .), додайте stdin / stdout / stderr до нової / dev / console, а execnewinit
mikeserv

@mikeserv: Акуратно! Я не розумів, що основний механізм перемикання коренів змінився, коли ми почали використовувати initramfs замість initrd. З точки зору адміністратора "переконайтеся, що праві модулі ядра опиняються в ньому", вони однакові>. <. Я все ще думаю, що це насправді не дуже добре відповідає на питання . Схоже, припускається, що інтерпретація "кріплення під рофс неможлива" і дає дуже специфічний проблемний випадок (що здається малоймовірним, оскільки initramfs не монтується лише для читання під час завантаження. І навіть якщо це так, його можна просто перерахувати прочитаним -пишіть, не впливаючи на зображення cpio.gz.)
Пітер Кордес

@PeterCordes - я не дуже розумію цю відповідь. Я щойно побачив ваш коментар - initramfs - це файлова система - вона насправді ніколи не може бути лише для читання - її кеш-файлом fs втілено.
mikeserv

2

Мені завжди це було цікаво.

Проста обгортка, така як:

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

збережений як виконавчий скрипт, іменований mountу директорії, що переосмислює /binваш PATH, повинен подбати про це, якщо він занадто турбує вас

(Перед запуском фактичного mountдвійкового файлу він створює каталог, названий за останнім аргументом mount, якщо такий каталог вже не існує.)


Крім того, якщо ви не хочете, щоб невдалі виклики mountобгортки створювали каталоги, ви можете зробити:

#!/bin/sh
set -e
eval "lastArg=\"\$$#\""
test -d "$lastArg" || { mkdir "$lastArg"; madeDir=1; }
/bin/mount "$@"  ||  {  test -z "$madeDir" || rmdir "$lastArg"; }

Чи не повинна mountкоманда використовувати створений таким чином каталог?
муру

1
@muru Ось що робить останній рядок.
PSkocik

Ах, ви маєте в виду , що слід використовувати таким чином: mount /dev/foo /some/path? Я припускав, що так буде працювати udisksctl, так що ти біжиш mount /dev/foo.
муру

4
Можна отримати останній аргумент cmdline без evalрозширення $#, використовуючи "${@:-1}". Я перевірив це за допомогою DASH, оскільки я думаю, що він не підтримує нічого, крім того, що потрібно підтримувати POSIX sh. /bin/dash -c 'echo ${@:-1}' foo barвідбитки bar.
Пітер Кордес

1
ви можете використовувати man -o x-mount.mkdir...
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.