Làm thế nào để Linux phân biệt giữa các tập tin thực và chưa có (ví dụ: thiết bị)?


28

Đây là một câu hỏi cấp độ khá thấp và tôi hiểu rằng nó có thể không phải là nơi tốt nhất để hỏi. Nhưng, nó có vẻ phù hợp hơn bất kỳ trang web SE nào khác, vì vậy hãy đến đây.

Tôi biết rằng trên hệ thống tệp Linux, một số tệp thực sự tồn tại , ví dụ: /usr/bin/bashlà một tệp tồn tại. Tuy nhiên, (như xa như tôi hiểu nó), một số cũng không thực sự tồn tại như vậy và có nhiều ảo file, ví dụ như: /dev/sda, /proc/cpuinfovv Câu hỏi của tôi là (họ là hai, nhưng có liên quan chặt chẽ quá là câu hỏi riêng biệt):

  • Làm thế nào để nhân Linux tìm ra liệu các tệp này là có thật (và do đó đọc chúng từ đĩa) hay không khi lệnh đọc (hoặc như vậy) được ban hành?
  • Nếu tệp không có thật: làm ví dụ, đọc từ /dev/randomsẽ trả về dữ liệu ngẫu nhiên và đọc từ /dev/nullsẽ trả về EOF. Làm thế nào để tìm ra dữ liệu nào cần đọc từ tệp ảo này (và do đó phải làm gì khi / nếu dữ liệu được ghi vào tệp ảo) - có một số loại bản đồ với các con trỏ để tách các lệnh đọc / ghi phù hợp cho từng tệp, hoặc thậm chí cho chính thư mục ảo? Vì vậy, một mục cho /dev/nullđơn giản có thể trả lại một EOF.

1
Khi tệp được tạo, kernel ghi lại kiểu của nó. Các tệp đĩa thông thường sau đó được xử lý khác với các liên kết tượng trưng, ​​thiết bị khối, thiết bị ký tự, thư mục, ổ cắm, FIFO, v.v ... Đó là công việc của hạt nhân cần biết.
Jonathan Leffler

xem người đàn ông cho mknod
Jasen

Điều này giống như hỏi "làm thế nào để một công tắc đèn biết liệu đèn có được bật không?" Công tắc đèn có nhiệm vụ quyết định xem đèn có được bật hay không.
Cuộc đua nhẹ nhàng với Monica

Câu trả lời:


25

Về cơ bản có hai loại khác nhau ở đây:

  1. Các hệ thống tệp thông thường, chứa các tệp trong các thư mục có dữ liệu và siêu dữ liệu, theo cách quen thuộc (bao gồm các liên kết mềm, liên kết cứng, v.v.). Chúng thường, nhưng không phải luôn luôn, được hỗ trợ bởi một thiết bị khối để lưu trữ liên tục (một tmpfs chỉ tồn tại trong RAM, nhưng khác với hệ thống tệp thông thường). Các ngữ nghĩa của những điều này là quen thuộc; đọc, viết, đổi tên, v.v., tất cả đều hoạt động theo cách bạn mong đợi.
  2. Hệ thống tập tin ảo, các loại. /proc/syslà các ví dụ ở đây, cũng như các hệ thống tập tin tùy chỉnh FUSE như sshfshoặc ifuse. Có nhiều sự đa dạng hơn trong số này, bởi vì thực sự họ chỉ đề cập đến một hệ thống tập tin với ngữ nghĩa theo nghĩa nào đó là 'tùy chỉnh'. Do đó, khi bạn đọc từ một tệp bên dưới /proc, bạn không thực sự truy cập vào một phần dữ liệu cụ thể được lưu trữ bởi một thứ khác viết nó trước đó, như trong một hệ thống tệp bình thường. Về cơ bản, bạn đang thực hiện một cuộc gọi kernel, yêu cầu một số thông tin được tạo nhanh chóng. Và mã này có thể làm bất cứ điều gì nó thích, vì nó chỉ là một số chức năng ở đâu đó thực hiện readngữ nghĩa. Do đó, bạn có hành vi kỳ lạ của các tệp bên dưới /proc, ví dụ như giả vờ là liên kết tượng trưng khi chúng phát sinh '

Điều quan trọng là /devthực sự, thông thường, là một trong những loại đầu tiên. Điều bình thường trong các bản phân phối hiện đại /devlà có một cái gì đó giống như một tmpfs, nhưng trong các hệ thống cũ, việc nó là một thư mục đơn giản trên đĩa, không có thuộc tính đặc biệt nào là bình thường. Điều quan trọng là các tệp bên dưới /devlà các nút thiết bị, một loại tệp đặc biệt tương tự như các ổ cắm FIFO hoặc Unix; một nút thiết bị có số chính và số phụ và việc đọc hoặc ghi chúng đang thực hiện cuộc gọi đến trình điều khiển hạt nhân, giống như đọc hoặc viết một FIFO đang gọi kernel để đệm đầu ra của bạn trong một đường ống. Trình điều khiển này có thể làm bất cứ điều gì nó muốn, nhưng nó thường chạm vào phần cứng bằng cách nào đó, ví dụ như để truy cập vào đĩa cứng hoặc phát âm thanh trong loa.

Để trả lời các câu hỏi ban đầu:

  1. Có hai câu hỏi liên quan đến việc 'tập tin tồn tại' hay không; đây là liệu tệp nút thiết bị có tồn tại theo nghĩa đen hay không và liệu mã kernel có sao lưu hay không. Cái trước được giải quyết giống như mọi thứ trên một hệ thống tập tin bình thường. Các hệ thống hiện đại sử dụng udevhoặc một cái gì đó giống như nó để theo dõi các sự kiện phần cứng và tự động tạo và phá hủy các nút thiết bị /devtheo đó. Nhưng các hệ thống cũ hơn, hoặc các bản dựng tùy chỉnh nhẹ, chỉ có thể có tất cả các nút thiết bị của chúng theo nghĩa đen trên đĩa, được tạo trước thời hạn. Trong khi đó, khi bạn đọc các tệp này, bạn đang thực hiện cuộc gọi đến mã hạt nhân được xác định bởi số thiết bị chính và phụ; nếu những điều này không hợp lý (ví dụ: bạn đang cố đọc một thiết bị khối không tồn tại), bạn sẽ gặp phải một số lỗi I / O.

  2. Cách nó tìm ra mã hạt nhân nào để gọi cho tập tin thiết bị khác nhau. Đối với các hệ thống tệp ảo như /proc, chúng thực hiện các chức năng readwritechức năng riêng của chúng ; hạt nhân chỉ gọi mã đó tùy thuộc vào điểm gắn kết của nó và việc triển khai hệ thống tập tin sẽ giải quyết phần còn lại. Đối với các tệp thiết bị, nó được gửi dựa trên số thiết bị chính và phụ.


Vì vậy, nếu, giả sử, một hệ thống cũ bị mất điện, các tệp trong /devđó vẫn ở đó, nhưng tôi đoán chúng sẽ bị xóa khi hệ thống khởi động?
Joe

2
Nếu một hệ thống cũ (một hệ thống không có bất kỳ tạo thiết bị động nào) bị tắt, bình thường hoặc bất thường, các nút thiết bị sẽ vẫn ở trên đĩa giống như bất kỳ tệp nào. Sau đó, khi khởi động tiếp theo xảy ra, chúng cũng sẽ vẫn còn trên đĩa và bạn có thể sử dụng chúng như bình thường. Chỉ trong các hệ thống hiện đại, bất cứ điều gì đặc biệt xảy ra đều tạo ra và phá hủy các nút thiết bị.
Tom Hunt

Vì vậy, một hệ thống hiện đại hơn không sử dụng tmpfssẽ tự động tạo và xóa chúng khi cần, ví dụ: khởi động và tắt máy?
Joe

3
devtmpfs, /devhệ thống tập tin trong Linux hiện đại, tương tự như a tmpfs, nhưng có một số khác biệt để hỗ trợ udev. (Các kernel hiện một số sáng tạo nút tự động trên riêng của mình trước khi bàn giao đi đến udev, để làm cho khởi động ít phức tạp.) Trong tất cả các trường hợp, các nút thiết bị chỉ sống trong RAM và được tạo ra và phá hủy động như phần cứng đòi hỏi họ. Có lẽ bạn cũng có thể sử dụng udevtrên một đĩa thông thường /dev, nhưng tôi chưa bao giờ thấy điều này được thực hiện và dường như không có bất kỳ lý do chính đáng nào.
Tom Hunt

17

Đây là danh sách tệp /dev/sda1trên máy chủ Arch Linux gần như cập nhật của tôi:

% ls -li /dev/sda1
1294 brw-rw---- 1 root disk 8, 1 Nov  9 13:26 /dev/sda1

Vì vậy, các thư mục trong /dev/cho sdacó một số inode, 1294. Đó là một tập tin thực trên đĩa.

Nhìn vào nơi kích thước tập tin thường xuất hiện. "8, 1" xuất hiện thay thế. Đây là một số thiết bị lớn và nhỏ. Cũng lưu ý 'b' trong các quyền của tập tin.

Các tập tin /usr/include/ext2fs/ext2_fs.hcó chứa cấu trúc C (đoạn) này:

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
    __u16   i_mode;     /* File mode */

Cấu trúc đó cho chúng ta thấy cấu trúc trên đĩa của inode của tệp. Rất nhiều thứ thú vị nằm trong cấu trúc đó; hãy nhìn vào nó

Phần i_modetử struct ext2_inodecó 16 bit và nó chỉ sử dụng 9 cho người dùng / nhóm / người khác, quyền đọc / ghi / thực thi và 3 phần khác cho setuid, setgid và stick. Nó có 4 bit để phân biệt giữa các loại như "tệp đơn giản", "liên kết", "thư mục", "ống có tên", "ổ cắm gia đình Unix" và "thiết bị khối".

Nhân Linux có thể theo thuật toán tra cứu thư mục thông thường, sau đó đưa ra quyết định dựa trên các quyền và cờ trong i_modephần tử. Đối với 'b', chặn các tệp thiết bị, nó có thể tìm thấy số thiết bị chính và phụ, và theo truyền thống, sử dụng số thiết bị chính để tìm kiếm một con trỏ tới một số chức năng hạt nhân (trình điều khiển thiết bị) liên quan đến đĩa. Số thiết bị nhỏ thường được sử dụng như nói, số thiết bị bus SCSI hoặc số thiết bị EIDE hoặc đại loại như thế.

Một số quyết định khác về cách xử lý một tệp như /proc/cpuinfođược đưa ra dựa trên loại hệ thống tệp. Nếu bạn làm một:

% mount | grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

bạn có thể thấy rằng /proccó loại hệ thống tập tin của "Proc". Việc đọc từ một tệp /prockhiến cho kernel làm điều gì đó khác biệt dựa trên loại hệ thống tệp, giống như việc mở tệp trên hệ thống tệp ReiserFS hoặc DOS sẽ khiến kernel sử dụng các chức năng khác nhau để định vị tệp và định vị dữ liệu của các tập tin.


Bạn có chắc chắn rằng chỉ "các tập tin thực trên đĩa" có số inode được hiển thị? Tôi nhận được 4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstatmà rõ ràng không phải là một "tập tin thực sự".
guntbert

7

Vào cuối ngày, tất cả chúng đều là các tệp cho Unix, đó là vẻ đẹp của sự trừu tượng.

Cách các tập tin được xử lý bởi kernel, bây giờ đó là một câu chuyện khác nhau.

/ Proc và ngày nay / dev và / run (aka / var / run) là các hệ thống tệp ảo trong RAM. / Proc là một giao diện / cửa sổ cho các biến và cấu trúc kernel.

Tôi khuyên bạn nên đọc Kernel Linux http://tldp.org/LDP/tlk/tlk.html và Trình điều khiển thiết bị Linux, Phiên bản thứ ba https://lwn.net/Kernel/LDD3/ .

Tôi cũng rất thích Thiết kế và triển khai Hệ điều hành FreeBSD http://www.amazon.com/Design-Imcellenceation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

Hãy nhìn vào trang có liên quan đến câu hỏi của bạn.

http://www.tldp.org/LDP/tlk/dd/drivers.html


cảm ơn, tôi hơi thay đổi câu hỏi đầu tiên sau khi bạn nhận xét điều đó.
Joe

Đọc bình luận cuối cùng xin vui lòng.
Rui F Ribeiro

5

Ngoài câu trả lời của @ RuiFRibeiro và @ BruceEdiger, sự khác biệt mà bạn tạo ra không chính xác là sự khác biệt mà hạt nhân tạo ra. Trên thực tế, bạn có nhiều loại tệp khác nhau: tệp thông thường, thư mục, liên kết tượng trưng, ​​thiết bị, ổ cắm (và tôi luôn quên một số vì vậy tôi sẽ không cố gắng tạo một danh sách đầy đủ). Bạn có thể có thông tin về loại tệp với ls: đó là ký tự đầu tiên trên dòng. Ví dụ:

$ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 17 nov.  08:29 /dev/sda

'B' ngay từ đầu báo hiệu rằng tệp này là một thiết bị khối. Dấu gạch ngang, có nghĩa là một tệp thông thường, 'l' một liên kết tượng trưng, ​​v.v. Thông tin này được lưu trữ trong siêu dữ liệu của tệp và có thể truy cập thông qua lệnh gọi hệ thống stat, do đó, hạt nhân có thể đọc khác một tệp và một liên kết tượng trưng chẳng hạn.

Sau đó, bạn thực hiện một phân biệt khác giữa "tệp thực" /bin/bashvà "tệp ảo" thích /proc/cpuinfonhưng lsbáo cáo cả hai dưới dạng tệp thông thường để sự khác biệt là một loại khác:

ls -la /proc/cpuinfo /bin/bash
-rwxr-xr-x 1 root root  829792 24 août  10:58 /bin/bash
-r--r--r-- 1 root wheel      0 20 nov.  16:50 /proc/cpuinfo

Điều gì xảy ra là chúng thuộc các hệ thống tập tin khác nhau. /proclà điểm gắn kết của một hệ thống tập tin giả procfstrong khi đó /bin/bashlà trên một hệ thống tập tin đĩa thông thường. Khi Linux mở một tệp (nó khác nhau tùy theo hệ thống tệp), nó sẽ tạo ra một cấu trúc dữ liệu file, trong số các thuộc tính khác, cấu trúc của một số con trỏ hàm mô tả cách sử dụng tệp này. Do đó, nó có thể thực hiện các hành vi khác nhau cho các loại tệp khác nhau.

Ví dụ: đây là các hoạt động được quảng cáo bởi /proc/meminfo:

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

static const struct file_operations meminfo_proc_fops = {
    .open       = meminfo_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

Nếu bạn nhìn vào định nghĩa của meminfo_proc_open, bạn có thể thấy rằng hàm này chứa một bộ đệm trong bộ nhớ với thông tin được trả về bởi hàm meminfo_proc_show, có nhiệm vụ là thu thập dữ liệu về việc sử dụng bộ nhớ. Thông tin này sau đó có thể được đọc bình thường. Mỗi khi bạn mở tệp, chức năng meminfo_proc_opensẽ được gọi và thông tin về bộ nhớ được làm mới.


3

Tất cả các tệp trong một hệ thống tệp là "thực" theo nghĩa là chúng cho phép tệp I / O. Khi bạn mở một tệp, kernel sẽ tạo một bộ mô tả tệp, là một đối tượng (theo nghĩa lập trình hướng đối tượng) hoạt động như một tệp. Nếu bạn đọc tệp, bộ mô tả tệp thực thi phương thức đọc của nó, lần lượt sẽ yêu cầu hệ thống tệp (sysfs, ext4, nfs, v.v.) cho dữ liệu từ tệp. Các hệ thống tệp trình bày một giao diện thống nhất cho không gian người dùng và biết phải làm gì để xử lý việc đọc và ghi. Các hệ thống tập tin lần lượt yêu cầu các lớp khác xử lý các yêu cầu của chúng. Đối với một tệp thông thường trên hệ thống tệp ext4, điều này sẽ liên quan đến việc tra cứu cấu trúc dữ liệu của hệ thống tệp (có thể liên quan đến việc đọc đĩa) và cuối cùng là đọc từ đĩa (hoặc bộ đệm) để sao chép dữ liệu vào bộ đệm đọc. Đối với một tập tin trong sysfs, nó thường chỉ là sprintf () s một cái gì đó vào bộ đệm. Đối với một nút dev khối, nó sẽ yêu cầu trình điều khiển đĩa đọc một số khối và sao chép chúng vào bộ đệm (các số chính và phụ cho hệ thống tệp biết trình điều khiển nào sẽ yêu cầu).

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.