Tại sao mount xảy ra trên một thư mục hiện có?


52

Một thư mục hiện có là cần thiết như một điểm gắn kết .

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

Tôi thấy nó khó hiểu vì nó chồng lên các nội dung hiện có của thư mục. Có hai nội dung có thể có của thư mục điểm gắn kết có thể bị chuyển đổi bất ngờ (đối với người dùng không thực hiện gắn kết).

Tại sao không mountxảy ra trong một thư mục mới được tạo? Đây là cách các hệ điều hành đồ họa hiển thị phương tiện di động. Sẽ rõ ràng nếu thư mục được gắn kết (tồn tại) hoặc không được gắn kết (không tồn tại). Tôi khá chắc chắn rằng có một lý do chính đáng nhưng tôi chưa thể khám phá ra nó.


1
Nếu bạn muốn hành vi đó, sử dụng udisksctl. Tại sao nên sử dụng mount?
muru

1
Bởi vì đó là cách của Unix. Bởi vì cách này linh hoạt hơn, và bạn có thể gắn kết ở bất cứ đâu. Ví dụ, vì gắn chúng ở bất cứ đâu cho phép bạn mở rộng máy chủ của mình khi bạn cần, lấy một đĩa mới cho phân vùng cơ sở dữ liệu, di chuyển dữ liệu trong phân vùng DB sang đĩa mới và gắn nó vào đúng nơi để cho phép dữ liệu DB để phát triển hơn
Rui F Ribeiro

8
Như một ghi chú lịch sử, trước khi Windows và LInux về cơ bản nghiền nát tất cả các hệ điều hành khác, đã có một công ty tên là Apollo. Họ đã viết một hệ điều hành unix-alike (thiết kế tốt hơn Unix!). Nó tạo ra các thư mục mà xuất khẩu NFS được gắn tự động. Trong thực tế, bạn không thể gắn kết vào một thư mục có sẵn. HP đã mua Apollo, ném đi hệ điều hành và sử dụng CPU 64 bit của Apollo làm HP-PA. Hệ thống các cuộc gọi thủ tục từ xa của Apollo đã trở thành DCE của OSF, dường như sống bên trong Windows. Biết là một nửa trận chiến!
Bruce Ediger

bằng cách nào đó điều này xảy ra trên hệ thống Ubuntu 14.04,3 ​​của tôi. Tôi chưa điều tra, chưa. khi thẻ SD của tôi được gắn kết, nó kết thúc tại một đường dẫn không có gì bên dưới. Nếu tôi vượt qua nó và cố gắng tự gắn nó trở lại, lỗi tôi nhận được là không có thư mục tại điểm gắn kết.
Skaperen

2
@BruceEdiger better design than Unix![cần dẫn nguồn]
Ruslan

Câu trả lời:


51

Đây là một trường hợp của một chi tiết thực hiện đã bị rò rỉ.

Trong một hệ thống UNIX, mọi thư mục bao gồm một danh sách các tên được ánh xạ tới các số inode . Một inode chứa siêu dữ liệu cho hệ thống biết đó là tệp, thư mục, thiết bị đặc biệt, đường ống có tên, v.v ... Nếu là tệp hoặc thư mục, nó cũng cho hệ thống biết nơi tìm tệp hoặc nội dung thư mục trên đĩa. Hầu hết các nút là tập tin hoặc thư mục. Các -itùy chọn để lssố inode ý danh sách.

Việc gắn hệ thống tệp sẽ lấy một thư mục inode và đặt cờ trên bản sao trong bộ nhớ của hạt nhân để nói "thực sự, khi tìm nội dung của thư mục này, hãy xem hệ thống tệp khác này" (xem slide 10 của bản trình bày này ). Điều này tương đối dễ dàng vì nó thay đổi một mục dữ liệu duy nhất.

Tại sao nó không tạo ra một mục nhập thư mục để bạn chỉ vào nút mới thay thế? Có hai cách bạn có thể thực hiện điều đó, cả hai đều có nhược điểm. Một là viết vật lý một thư mục mới vào hệ thống tập tin - nhưng điều đó không thành công nếu hệ thống tập tin chỉ đọc! Hai là để thêm vào mỗi danh sách quy trình một danh sách những thứ "thêm" không thực sự ở đó. Điều này là khó khăn và có khả năng phát sinh một hiệu suất nhỏ trên mỗi hoạt động tập tin.

Nếu bạn muốn các điểm gắn kết được tạo động, automounthệ thống có thể thực hiện việc này. Hệ thống tập tin không đĩa đặc biệt cũng có thể tạo các thư mục theo ý muốn, ví dụ như proc, sys, devfsvà vân vân.

Chỉnh sửa: xem thêm câu trả lời Điều gì xảy ra khi bạn 'gắn kết' một thư mục hiện có với nội dung?


Ngoại trừ nó không đặt cờ trên nút. sudo mount --bind / /mnt ; ls /mnt/proc-> trống rỗng. Tôi tự hỏi làm thế nào nó hoạt động.
sourcejedi

Các hoạt động chính xác là trong fs/namespace.c, tôi nghĩ rằng; Tôi không quen thuộc với nguồn này và không muốn mất quá nhiều thời gian để khoan chi tiết. "Cờ trên nút" tôi nhận được từ bản trình bày được liên kết.
pjc50

2
@sourcejedi: liên kết gắn kết chỉ liên kết hệ thống tập tin mà bạn thực sự đề cập đến. Họ không liên kết đệ quy các hệ thống tập tin khác được gắn dưới nó. Đây là một cách thuận tiện để tìm rác ẩn bằng thú cưỡi. (ví dụ: nếu một số nội dung kết thúc trên FS gốc trong /var/cachemột số thời điểm khi /varkhông thể gắn kết.) Xem thêm path_resolution(7). (Các trang linux-man cũ hơn có trang man đó trong phần 2, như die.net) IDK cách Linux thực sự hoạt động bên trong, để tối ưu hóa việc kiểm tra mọi thành phần thư mục như một giá trị có thể. Có thể ghim mục VFS đó trong bộ đệm?
Peter Cordes

2
Đúng vậy, đó là quan điểm của tôi ... Vì vậy fs/namei.c(đường dẫn -> tra cứu inode) gọi vào không gian tên lookup_mnt(). Có một cờ trên nha (mục thư mục bộ đệm). Nhưng đó chỉ là một chi tiết tối ưu hóa hay còn gọi là thực hiện. Nó không cho bạn biết hệ thống tập tin được gắn ở đó; bạn phải nhìn vào bảng gắn kết. .
sourcejedi

1
@PeterCordes man 8 mount:: mount --bind foo foo. Cuộc mountgọi liên kết chỉ đính kèm (một phần) một hệ thống tập tin duy nhất, không thể phục hồi. Toàn bộ hệ thống phân cấp tệp bao gồm các giá trị phụ được gắn vào vị trí thứ hai bằng cách sử dụng :mount --rbind olddir newdir
mikeerv

19

Nếu được mount(2) yêu cầu tạo thư mục mới làm điểm gắn kết, bạn không thể gắn kết bất cứ thứ gì trong hệ thống tệp chỉ đọc. Điều đó thật ngu ngốc, vì vậy chúng ta có thể loại trừ điều đó.

Nếu mount tùy ý tạo một thư mục mới làm mountpoint, điều đó thật lạ. Nó không giống như mount / unmount xảy ra mọi lúc, vì vậy việc đưa logic bổ sung vào kernel để thực hiện hai bước này với một cuộc gọi hệ thống duy nhất sẽ không phải là một sự tăng tốc quan trọng. Chỉ cần để nó vào không gian người dùng để thực hiện mkdir(2)cuộc gọi hệ thống nếu nó muốn. Câu trả lời của Dmitry chỉ ra rằng việc mount(2)làm cả hai điều sẽ khiến nó trở thành phi nguyên tử. Và bạn muốn một cuộc tranh cãi thêm để mount(2)với cờ chế độ như open(2)mất, cho O_CREAT, O_EXCLvv Nó sẽ chỉ được ngớ ngẩn so với việc cho phép sử dụng không gian làm điều đó.

Hoặc có thể bạn đang hỏi về việc có mount(8)(chương trình truyền thống thực hiện mount(2)các cuộc gọi hệ thống) làm điều này? Điều đó là có thể, nhưng đã hoàn toàn tốt mkdir(1)cho công việc và thiết kế của Unix là tất cả các công cụ nhỏ tốt có thể kết hợp. Nếu bạn muốn có một công cụ làm cả hai, thật dễ dàng để viết một tập lệnh shell để xây dựng công cụ đó bằng hai công cụ đơn giản hơn. (Hoặc, như muru đã nhận xét, udisksctlđã thực hiện điều này, vì vậy bạn không phải viết nó.) Ngoài ra, Linux thông thường mount(8)từ linux-linux hỗ trợ mount -o x-mount.mkdir[=mode]sử dụng x-cú pháp của nó cho các tùy chọn cho không gian người dùng, thay vì các tùy chọn được chuyển đến hệ thống tệp.


Bây giờ câu hỏi thú vị hơn: tại sao phải có một thư mục trên hệ thống tập tin mẹ?

Giống như câu trả lời của pjc50 chỉ ra (không liên quan, mặc dù anh ấy có tên viết tắt của tôi!), Việc có các điểm gắn kết hiển thị trong danh sách thư mục sau đó sẽ yêu cầu kiểm tra thêm trên mỗi readdir().

Có các điểm gắn kết tồn tại dưới dạng các thư mục trong thư mục chứa chúng (trên FS cha) là một mẹo hay. readdir()không cần phải lưu ý rằng đó là một điểm gắn kết nào cả. Điều đó chỉ xảy ra nếu điểm gắn kết được sử dụng như một thành phần đường dẫn. Tất nhiên, độ phân giải đường dẫn phải kiểm tra bảng mount cho mọi thành phần thư mục của đường dẫn.


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- Tôi cho rằng nó thông minh hơn: Từ góc nhìn của người dùng, một hệ thống tệp chỉ đọc không nên thay đổi, nhưng cho phép gắn kết có nghĩa là nó có thể
Izkata

2
@Izkata: Tạo một hệ thống tập tin chỉ đọc không có nghĩa là toàn bộ cây con của VFS bị đóng băng. Nó có thể có các liên kết tượng trưng trỏ đến các thư mục đọc-ghi hoặc đã có các điểm gắn kết đọc-ghi bên dưới nó khi fs cha được lặp lại ro. Có nhiều trường hợp sử dụng cho các hệ thống tệp chỉ đọc trong đó đối số của bạn không có ý nghĩa.
Peter Cordes

2
man 8 mount: x-mount.mkdir[=mode] Cho phép tạo một thư mục đích (mountpoint). Chế độ đối số tùy chọn chỉ định chế độ truy cập hệ thống tệp được sử dụng cho mkdir(2)ký hiệu bát phân. Chế độ mặc định là 0755. Chức năng này chỉ được hỗ trợ cho người dùng root.
mikeerv

Tôi không thấy bất kỳ trường hợp sử dụng quan trọng nào của các hệ thống tệp chỉ đọc với các hệ thống tệp đọc ghi được gắn kết, đặc biệt là không có trong Unix đầu tiên. @PeterCordes
kubanczyk

@kubanczyk: read-only hệ thống tập tin gốc, với một đọc-ghi /tmp/home. Hoặc NFS chỉ đọc được gắn /usrvới một cục bộ /usr/localđược gắn trên nó. Hay nói chung hơn, bất kỳ hình ảnh chỉ đọc được chia sẻ với một phần có thể sửa đổi được gắn trên nó. (các mod cục bộ thành hình ảnh chỉ đọc cũng có thể được thực hiện trên cơ sở mỗi tệp với các hệ thống tệp tùy chỉnh như lớp phủ hoặc hệ thống tệp kết hợp khác cho Linux, được sử dụng trên hình ảnh có thể khởi động LiveCD.) khởi động, nhưng làm cho nó rw có thể xảy ra trước khi gắn kết khác.
Peter Cordes

12

Việc gắn vào thư mục hiện có thực hiện một cuộc gọi đến mountthực tế nguyên tử: nó thành công hoặc thất bại, ít nhất là từ quan điểm của người dùng. Nếu mountphải tự tạo điểm gắn kết, nó sẽ có hai điểm không thành công, khiến nó không thể đảm bảo khôi phục sạch. Hãy tưởng tượng kịch bản sau đây:

  1. mount tạo thành công đỉnh
  2. mount cố gắng gắn một hệ thống tệp mới vào thư mục đó, nhưng không thành công
  3. mount cố gắng loại bỏ điểm gắn kết, nhưng không thành công

Hệ thống kết thúc với một tác dụng phụ của một thất bại mount.

Đây là một số khác:

  1. umount ngắt kết nối thành công một hệ thống tập tin
  2. umount cố gắng loại bỏ điểm gắn kết, nhưng không thành công

Bây giờ, nên umounttrở về thành công hay thất bại?


5
mountcó 8 mã trả lại khác nhau cho các lỗi cũng có thể được kết hợp. Nó chỉ có thể thêm một cái khác khi thư mục loại bỏ thất bại. man7.org/linux/man-pages/man8/mount.8.html#RETURN_CODES
sự hỗn loạn

8
Tôi nghĩ OP đang hỏi tại sao mountpoint cần phải là một thư mục hiện có chứ không phải tại sao mountcuộc gọi hệ thống không tạo ra nó. Mặc dù có lẽ đó chỉ là sự giải thích / kỳ vọng của tôi về những gì tôi nghĩ OP muốn hỏi, hoặc những gì tôi sẽ hỏi nếu tôi hỏi.
Peter Cordes

3

Một trường hợp khác có thể xảy ra:

Khi bạn khởi động, một hình ảnh chỉ đọc cơ bản được tải vào thư mục gốc. Vì vậy, bạn muốn ghi đè lên nó khi bạn muốn gò gốc. Vì vậy, bạn có thể tưởng tượng rằng tòa nhà gắn kết chỉ cần hoán đổi rođiểm gắn kết rw.

Ở đây, hãy tưởng tượng bạn có một vấn đề về hệ thống tập tin trên root mountpoint, bạn muốn có thể thử sửa nó. Với sự chồng chéo gắn kết, bạn có thể ngắt kết nối hệ thống tập tin và sử dụng fsckđược cung cấp vào hình ảnh cơ bản để giải quyết nó.

Tính năng này cũng có thể hữu ích trong các hệ thống cần bảo mật mạnh mẽ để theo dõi sự thay đổi giữa rophân vùng và phân vùng rw.


1
Tôi không chắc làm thế nào điều này trả lời câu hỏi. Bạn có chỉ ra rằng nếu được mount yêu cầu tạo một thư mục mới tại vị trí của điểm gắn kết mà bạn không thể gắn kết bất cứ thứ gì lên trên một hệ thống tệp chỉ đọc? Đoạn mở đầu khó hiểu: đó không phải là cách Linux initrd hoạt động. Nó sử dụng lệnh pivot_rootgọi hệ thống để thay đổi fs gốc, không chỉ gắn kết nhiều thứ hơn nó. Điều đó làm cho nó khó theo logic của bạn trong các đoạn tiếp theo, bởi vì tôi nghĩ rằng bạn đang nói về pivot_root(2).
Peter Cordes

2
@PeterCordes - linux đã không sử dụng initrd trong nhiều năm : Khi chuyển đổi một thiết bị root khác, initrd sẽ pivot_rootvà sau đó umountlà ramdisk. Nhưng initramfs là rootfs: bạn không thể pivot_rootrootfs, hoặc unmount nó . Thay vào đó, hãy xóa mọi thứ ra khỏi rootfs để giải phóng không gian ( find -xdev / -exec rm {} \;), vượt qua rootfs với root mới ( cd /newmount; mount --move . /; chroot .), đính kèm stdin / stdout / stderr vào new / dev / console và execnewinit
mikeerv

@mikeerv: gọn gàng! Tôi đã nhận ra rằng cơ chế cơ bản để chuyển đổi rễ đã thay đổi khi chúng tôi bắt đầu sử dụng initramfs thay vì initrd. Từ quan điểm quản trị "đảm bảo các mô-đun hạt nhân đúng kết thúc trong đó", chúng giống hệt nhau>. <. Tôi vẫn nghĩ rằng điều này không thực sự trả lời câu hỏi rất tốt . Dường như giả sử cách giải thích "gắn kết dưới rofs là không thể" và đưa ra một trường hợp vấn đề rất cụ thể (điều này dường như không thể xảy ra vì initramfs không được gắn chỉ đọc khi khởi động. -write mà không ảnh hưởng đến hình ảnh cpio.gz.)
Peter Cordes

@PeterCordes - Tôi không thực sự hiểu câu trả lời này. Tôi vừa thấy bình luận của bạn - initramfs là một hệ thống tệp - nó thực sự không thể đọc được - bộ nhớ cache fs của nó hiện thân.
mikeerv

2

Tôi cũng luôn tự hỏi điều đó.

Một trình bao bọc đơn giản như:

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

được lưu dưới dạng tập lệnh thực thi có tên mounttrong thư mục ghi đè /bintrong PATH của bạn nên xử lý việc này nếu nó làm phiền bạn quá nhiều

(Trước khi chạy mountnhị phân thực tế , nó tạo một thư mục được đặt tên theo đối số cuối cùng mount, nếu thư mục đó chưa tồn tại.)


Ngoài ra, nếu bạn không muốn yêu cầu mounttrình bao bọc không thành công để tạo thư mục, bạn có thể thực hiện:

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

Không nên mountsử dụng lệnh sau đó sử dụng thư mục được tạo?
muru

1
@muru Đó là những gì dòng cuối cùng làm.
PSkocik

Oh, vậy bạn có nghĩa là nó nên được sử dụng như vậy : mount /dev/foo /some/path? Tôi giả sử nó sẽ hoạt động như udisksctlvậy, vì vậy bạn sẽ chạy mount /dev/foo.
muru

4
Bạn có thể lấy đối số cmdline cuối cùng mà không cần evalmở rộng $#, sử dụng "${@:-1}". Tôi đã thử nghiệm điều này với DASH, vì tôi nghĩ rằng nó không hỗ trợ bất cứ điều gì ngoài những gì POSIX sh cần có để hỗ trợ. /bin/dash -c 'echo ${@:-1}' foo barin bar.
Peter Cordes

1
bạn có thể sử dụng man -o x-mount.mkdir...
mikeerv
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.