Chương 14 · Hệ thống tệp Chapter 14 · File Systems
Từ đĩa vật lý tới một cây thư mục duy nhất — hệ thống tệp làm việc đó thế nào Máy tính cất dữ liệu trên đĩa và sắp nó thành thư mục ra sao From a physical disk to one directory tree — how file systems do it
Các chương trước dạy lời gọi vào/ra tệp (file I/O); chương này lùi lại một bước để hỏi: dữ liệu thật sự nằm ở đâu và được tổ chức ra sao. Kerrisk đi từ tệp thiết bị (device file), qua đĩa và phân vùng, tới cấu trúc một hệ thống tệp (file system) và i-node, rồi lớp trừu tượng VFS, các hệ tệp ghi nhật ký (journaling), và cuối cùng là cách gắn kết (mount) tất cả vào một cây thư mục duy nhất.1
Chương này không dạy lệnh đọc/ghi tệp. Nó giải thích dữ liệu của bạn nằm ở đâu: trên một cái đĩa, được chia thành phân vùng, mỗi phân vùng chứa một “hệ thống tệp” sắp xếp tệp và thư mục. Rồi Linux ghép hết lại thành một cây thư mục duy nhất để bạn dùng. Nhớ nhé: tệp của bạn nằm trên đĩa, được xếp gọn thành hệ thống tệp, rồi gắn vào một cây chung.
Earlier chapters taught file I/O; this chapter steps back to ask where the data actually lives and how it is organized. Kerrisk works from device files, through disks and partitions, to the structure of a file system and the i-node, then the VFS abstraction layer, journaling file systems, and finally how everything is mounted into a single directory tree.1
Kerrisk dùng hệ tệp ext2 (Second Extended File System) làm ví dụ cụ thể cho các khái niệm chung, dù nhiều năm sau ext2 đã nhường chỗ cho các hệ ghi nhật ký như ext3, ext4. Chương khép lại bằng hai lời gọi hệ thống để gắn/tháo hệ tệp — mount() và umount() — cùng hàm thư viện statvfs() để lấy thông tin về một hệ tệp đã gắn.1
Luận đề của chương: một hệ thống tệp chỉ là một tập hợp có tổ chức gồm tệp và thư mục, đặt trên một phân vùng đĩa; nhờ i-node lưu siêu dữ liệu (metadata) tách khỏi dữ liệu, nhờ VFS che giấu khác biệt giữa các hệ tệp, và nhờ cơ chế mount, Linux hợp mọi thứ thành một cây thư mục duy nhất gốc ở /.1
Ý chính: đĩa được chia thành phân vùng; mỗi phân vùng chứa một hệ thống tệp; hệ tệp dùng “i-node” để ghi thông tin về từng tệp; và Linux gắn mọi hệ tệp vào một cây duy nhất bắt đầu từ dấu gạch chéo /. Nhớ nhé: nhiều đĩa, nhiều hệ tệp, nhưng chỉ một cây thư mục.
The chapter's thesis: a file system is just an organized collection of files and directories on a disk partition; because i-nodes store metadata apart from data, because the VFS hides the differences between file systems, and because of the mount mechanism, Linux unifies everything into one directory tree rooted at /.1
Cụm khái niệm 01 Concept cluster 01
Tệp thiết bị, đĩa và phân vùng — nền phần cứng của hệ tệp Thiết bị, đĩa và phân vùng — chỗ cất dữ liệu Device files, disks and partitions — the hardware beneath
Vì chương bàn nhiều về thiết bị đĩa, Kerrisk mở đầu bằng khái niệm tệp thiết bị đặc biệt (device special file). Một tệp thiết bị tương ứng với một thiết bị trên hệ thống; trong nhân, mỗi loại thiết bị có một trình điều khiển thiết bị (device driver) xử lý mọi yêu cầu vào/ra. API mà trình điều khiển cung cấp là cố định, gồm các thao tác ứng với các lời gọi hệ thống open(), close(), read(), write(), mmap() và ioctl().1
Trong Linux, mỗi thiết bị (bàn phím, đĩa, chuột…) hiện ra như một “tệp” đặc biệt. Muốn nói chuyện với thiết bị, chương trình chỉ cần mở tệp đó rồi đọc/ghi như tệp thường — phần việc thật do một “trình điều khiển” lo. Nhớ nhé: với Linux, thiết bị cũng là một loại tệp.
Because the chapter mentions disk devices often, Kerrisk begins with the idea of a device special file. A device file corresponds to a device on the system; within the kernel, each device type has a device driver that handles all I/O requests for it. The API a driver provides is fixed, consisting of operations corresponding to the open(), close(), read(), write(), mmap() and ioctl() system calls.1
Định nghĩa. Thiết bị chia làm hai loại. Thiết bị ký tự (character device) xử lý dữ liệu theo từng ký tự một — ví dụ terminal và bàn phím. Thiết bị khối (block device) xử lý dữ liệu theo từng khối một; kích thước khối tuỳ loại thiết bị nhưng thường là một bội số của 512 byte — ví dụ đĩa và ổ băng.1 Các tệp thiết bị thường nằm dưới thư mục /dev, và siêu người dùng tạo chúng bằng lệnh mknod hoặc lời gọi mknod().1
Nói đơn giản. Có hai kiểu thiết bị: kiểu “ký tự” đọc/ghi từng chữ một (như bàn phím), và kiểu “khối” đọc/ghi từng cục dữ liệu lớn (như đĩa cứng). Các tệp thiết bị nằm trong thư mục /dev. Nhớ nhé: ký tự thì nhỏ giọt từng chữ, khối thì từng cục to.
Definition. Devices come in two kinds. Character devices handle data character by character — for example, terminals and keyboards. Block devices handle data a block at a time; the block size depends on the device but is typically some multiple of 512 bytes — for example, disks and tape drives.1 Device files usually live under the /dev directory, and the superuser creates them with the mknod command or the mknod() call.1
thiết bị = ký tự | khối
khối vật lý ≈ 512 byte
mỗi tệp dev → (major, minor) ID
2.4: 8 + 8 bit
2.6: 12 + 20 bit
đĩa → phân vùng → /dev/sdaN
đĩa cứng
↓ chia ra
các phân vùng
↓ mỗi phân vùng
một hệ thống tệp
device = character | block
physical block ≈ 512 bytes
each dev file → (major, minor) ID
2.4: 8 + 8 bits
2.6: 12 + 20 bits
disk → partitions → /dev/sdaN
-
major & minor IDs
Mã số major/minor — cách nhân tìm đúng trình điều khiển Mỗi tệp thiết bị có một cặp số định danh Major/minor IDs — how the kernel finds the driver
Mỗi tệp thiết bị mang một mã số major và một mã số minor. Major xác định lớp thiết bị chung và được nhân dùng để tra ra trình điều khiển phù hợp; minor định danh duy nhất một thiết bị cụ thể trong lớp đó. Cặp số này hiện ra trong kết quả lệnh
ls -l, và được ghi ngay trong i-node của tệp thiết bị — nên tên tệp thiết bị không có ý nghĩa gì với nhân khi tìm trình điều khiển.1Mỗi tệp thiết bị có hai con số: số major cho biết “loại” thiết bị, số minor cho biết “đúng cái nào”. Nhân dựa vào cặp số đó, chứ không dựa vào tên tệp, để biết dùng trình điều khiển nào. Nhớ nhé: nhân nhìn cặp số major/minor, không nhìn tên.
Each device file carries a major ID and a minor ID. The major identifies the general class of device and is used by the kernel to look up the appropriate driver; the minor uniquely identifies a particular device within that class. The pair shows up in
ls -loutput and is recorded in the device file's i-node — so the device file's name has no relevance when the kernel looks for the driver.1Bạn gặp nó ở đâuWhere you meet it Trên Linux 2.6, chương trìnhudevtạo các mục trong/devdựa trên hệ tệpsysfsgắn ở/sys— nên/devchỉ chứa thiết bị thực sự có mặt.1 Trên máy hiện đại, chương trìnhudevtự tạo các tệp thiết bị cho bạn trong/dev. On Linux 2.6, theudevprogram creates entries in/devbased on thesysfsfile system mounted at/sys— so/devholds only devices actually present.1Giới hạn bit
Trên Linux 2.4 trở về trước, major và minor mỗi mã chỉ dùng 8 bit, giới hạn tổng số thiết bị. Linux 2.6 nới ra, dùng tới 12 bit cho major và 20 bit cho minor.1
mknod() hiếm dùng
Kerrisk không mô tả kỹ
mknod()vì ngày nay nó gần như chỉ còn dùng để tạo tệp thiết bị — một nhu cầu hiếm với ứng dụng thông thường. Để tạo FIFO nên dùngmkfifo(), tạo thư mục nên dùngmkdir().1 -
disk drives
Đĩa cứng — track, sector và vì sao truy cập đĩa chậm Đĩa cứng quay và vì sao nó chậm hơn CPU Disk drives — tracks, sectors and why disks are slow
Một ổ đĩa cứng là thiết bị cơ, gồm một hay nhiều đĩa (platter) quay rất nhanh. Thông tin trên mặt đĩa nằm trên các vòng tròn đồng tâm gọi là track; mỗi track chia thành các sector, mỗi sector gồm một dãy khối vật lý thường cỡ 512 byte — đơn vị nhỏ nhất mà ổ đọc/ghi được.1 Đọc/ghi mất ba phần thời gian: dịch đầu đọc tới đúng track (seek time), chờ sector quay tới dưới đầu đọc (rotational latency), rồi truyền dữ liệu (transfer time) — tổng cỡ mili-giây, trong khi CPU chạy được hàng triệu lệnh cùng khoảng đó.1
Đĩa cứng là một đĩa tròn quay tít, đầu đọc phải chạy tới đúng chỗ rồi chờ đĩa quay tới. Vì có chuyển động cơ học nên nó chậm hơn nhiều so với CPU — một thao tác đĩa tốn cỡ mili-giây, còn CPU làm xong hàng triệu việc trong chừng ấy. Nhớ nhé: đĩa quay chậm vì phải chạy và chờ máy móc.
A hard disk is a mechanical device of one or more platters spinning at high speed. Information on a platter sits on concentric circles called tracks; each track is divided into sectors, each a series of physical blocks typically 512 bytes in size — the smallest unit the drive can read or write.1 A read or write costs three parts: moving the head to the right track (seek time), waiting for the sector to rotate under the head (rotational latency), then transferring the data (transfer time) — on the order of milliseconds, while a CPU executes millions of instructions in that time.1
Bạn gặp nó ở đâuWhere you meet it Chính độ chậm này là lý do nhân có bộ đệm (buffer cache, Chương 13) và vì sao hệ tệp cố gom các khối của một tệp lại gần nhau để giảm seek.1 Vì đĩa chậm nên máy phải dùng bộ nhớ đệm để đỡ phải chạm đĩa nhiều. This slowness is why the kernel keeps a buffer cache (Chapter 13) and why a file system tries to keep a file's blocks close together to reduce seeking.1 -
partitions
Phân vùng — chia một đĩa thành nhiều thiết bị độc lập Chia đĩa thành nhiều phần riêng Partitions — splitting one disk into separate devices
Mỗi đĩa được chia thành một hay nhiều phân vùng (partition) không chồng lấn; nhân coi mỗi phân vùng như một thiết bị riêng nằm dưới
/dev. Một phân vùng thường chứa một trong ba thứ: một hệ thống tệp giữ tệp và thư mục; một vùng dữ liệu truy cập ở chế độ thô (raw), như vài hệ quản trị cơ sở dữ liệu dùng; hoặc một vùng swap để nhân quản lý bộ nhớ.1Một cái đĩa có thể cắt thành nhiều “miếng” gọi là phân vùng, mỗi miếng dùng vào một việc: chứa hệ thống tệp, chứa dữ liệu thô, hoặc làm chỗ “swap” khi hết RAM. Nhớ nhé: một đĩa, nhiều phân vùng, mỗi phân vùng một nhiệm vụ.
Each disk is divided into one or more non-overlapping partitions; the kernel treats each as a separate device under
/dev. A partition usually holds one of three things: a file system of files and directories; a data area accessed as a raw-mode device, as some database systems use; or a swap area for the kernel's memory management.1Bạn gặp nó ở đâuWhere you meet it Tệp ảo/proc/partitionscủa Linux liệt kê mã major/minor, kích thước và tên của từng phân vùng trên hệ thống.1 Xem/proc/partitionslà thấy danh sách các phân vùng trên máy. The Linux-specific/proc/partitionsfile lists the major/minor IDs, size and name of every partition on the system.1
Cụm khái niệm 02 Concept cluster 02
Cấu trúc hệ tệp và i-node — nơi siêu dữ liệu sống tách khỏi dữ liệu Hệ tệp sắp xếp ra sao, và i-node ghi gì File-system structure and the i-node — metadata apart from data
Một hệ thống tệp là một tập hợp có tổ chức gồm tệp và thư hường, được tạo bằng lệnh mkfs. Một thế mạnh của Linux là nó hỗ trợ rất nhiều hệ tệp: hệ truyền thống ext2; các hệ UNIX bản địa như Minix, System V, BSD; FAT, FAT32 và NTFS của Microsoft; ISO 9660 của CD-ROM; HFS của Apple; một loạt hệ tệp mạng như NFS; và nhiều hệ ghi nhật ký như ext3, ext4, Reiserfs, JFS, XFS, Btrfs.1
“Hệ thống tệp” là cách sắp xếp tệp và thư mục trên một phân vùng; tạo nó bằng lệnh mkfs. Linux hiểu được rất nhiều kiểu sắp xếp khác nhau: ext2, ext4, cả FAT và NTFS của Windows, cả định dạng CD… Nhớ nhé: Linux đọc được nhiều kiểu hệ tệp, không chỉ của riêng nó.
A file system is an organized collection of files and directories, created with the mkfs command. A strength of Linux is that it supports a wide variety: the traditional ext2; native UNIX systems such as Minix, System V and BSD; Microsoft's FAT, FAT32 and NTFS; the ISO 9660 CD-ROM system; Apple's HFS; a range of network file systems such as NFS; and many journaling systems such as ext3, ext4, Reiserfs, JFS, XFS and Btrfs.1
Định nghĩa. Đơn vị cấp phát không gian trong hệ tệp là logical block — một bội số của các khối vật lý liền nhau trên đĩa; với ext2, khối lô-gic là 1024, 2048 hoặc 4096 byte. Một hệ tệp gồm bốn phần: boot block (khối đầu, dành cho khởi động), superblock (một khối chứa tham số: cỡ bảng i-node, cỡ khối lô-gic, cỡ hệ tệp), bảng i-node (i-node table, mỗi tệp một mục), và data blocks (chiếm phần lớn không gian, chứa dữ liệu thật).15
Nói đơn giản. Một hệ tệp chia làm bốn phần: một khối khởi động, một khối “superblock” ghi thông số chung, một bảng “i-node” ghi thông tin từng tệp, và phần lớn nhất là các khối chứa dữ liệu. Nhớ nhé: thông tin về tệp nằm ở i-node, còn nội dung tệp nằm ở data blocks.
Definition. The unit for allocating space is the logical block — some multiple of contiguous physical blocks; on ext2 it is 1024, 2048 or 4096 bytes. A file system has four parts: a boot block (first block, for booting), a superblock (one block of parameters: i-node table size, logical block size, file-system size), the i-node table (one entry per file), and the data blocks (the great majority of space, holding the real data).15
[boot][super][i-node table][data...]
i-node ext2 = 15 con trỏ
12 trực tiếp + 1 gián tiếp
+ 1 kép + 1 ba lớp
khối 4096B → 1024 con trỏ/khối
cỡ tệp tối đa ≈ 4 TB
boot → super → i-node → data
i-node = “thẻ lý lịch” của tệp
data = nội dung thật của tệp
[boot][super][i-node table][data...]
ext2 i-node = 15 pointers
12 direct + 1 indirect
+ 1 double + 1 triple
4096B block → 1024 pointers/block
max file size ≈ 4 TB
-
the i-node
I-node — tấm thẻ lý lịch của mỗi tệp I-node — “thẻ” ghi thông tin về tệp The i-node — each file's record card
I-node (viết tắt của index node) là mục trong bảng i-node ứng với mỗi tệp; i-node được định danh bằng số thứ tự của nó — i-node number — là trường đầu tiên mà
ls -lihiển thị. Một i-node ghi: kiểu tệp (tệp thường, thư mục, liên kết tượng trưng, thiết bị ký tự…); chủ sở hữu (UID) và nhóm (GID); quyền truy cập cho ba hạng người dùng; ba mốc thời gian; số liên kết cứng (hard link) tới tệp; kích thước tệp tính theo byte; số khối thực cấp cho tệp (đo theo đơn vị 512 byte); và các con trỏ tới data blocks.15Mỗi tệp có một “thẻ lý lịch” gọi là i-node, ghi: tệp thuộc loại gì, của ai, ai được đọc/ghi, tạo/sửa lúc nào, lớn bao nhiêu, và nội dung nằm ở những khối nào. Mỗi thẻ có một số thứ tự riêng. Nhớ nhé: tên tệp nằm trong thư mục, còn lý lịch tệp nằm trong i-node.
The i-node (short for index node) is the i-node-table entry for each file; an i-node is identified by its sequential i-node number, the first field shown by
ls -li. An i-node records: the file type (regular file, directory, symbolic link, character device…); owner (UID) and group (GID); access permissions for three categories of user; three timestamps; the number of hard links to the file; the file size in bytes; the number of blocks actually allocated (in 512-byte units); and the pointers to data blocks.15Bạn gặp nó ở đâuWhere you meet it Chương 15 sẽ dùngstat()để đọc đúng những trường này ra một cấu trúc; i-node là nguồn của hầu hết thông tin đó.1 Lệnhls -lhiện quyền, chủ, kích thước — tất cả lấy từ i-node. Chapter 15 usesstat()to read exactly these fields into a structure; the i-node is the source of most of that information.1Không có thời điểm tạo tệp
Ba mốc thời gian là: lần truy cập cuối (
ls -lu), lần sửa nội dung cuối (ls -l), và lần đổi thông tin i-node cuối (ls -lc). Như hầu hết hệ tệp UNIX, các hệ tệp Linux đáng chú ý là không ghi thời điểm tạo tệp.15Số khối có thể lệch kích thước
Số khối cấp cho tệp không nhất thiết khớp với kích thước byte, vì tệp có thể chứa “lỗ” (hole, Mục 4.7): vùng toàn 0 không được cấp khối thật, nên tệp dùng ít khối hơn kích thước danh nghĩa.1
-
block pointers
Con trỏ khối của ext2 — 12 trực tiếp và ba lớp gián tiếp Cách i-node chỉ tới nội dung tệp ext2 block pointers — 12 direct and three indirect levels
ext2 không cất các khối của một tệp liền kề hay theo thứ tự; để tìm chúng, nhân giữ một tập con trỏ trong i-node. Mỗi i-node ext2 chứa 15 con trỏ: 12 con trỏ đầu trỏ thẳng tới 12 khối dữ liệu đầu tiên; con trỏ thứ 13 là con trỏ gián tiếp trỏ tới một khối chứa thêm con trỏ; con trỏ thứ 14 là gián tiếp kép; và con trỏ thứ 15 là gián tiếp ba lớp.1 Số con trỏ trong một khối gián tiếp phụ thuộc cỡ khối: với khối 4096 byte, mỗi con trỏ 4 byte cho ra 1024 con trỏ một khối.1
Nội dung một tệp không nằm liền một dải, mà rải khắp đĩa. I-node giữ một “danh sách địa chỉ” tới các khối đó: 12 địa chỉ đầu trỏ thẳng tới dữ liệu; nếu tệp lớn hơn, nó dùng thêm các địa chỉ “gián tiếp” trỏ tới bảng địa chỉ khác, nhiều lớp. Nhớ nhé: tệp nhỏ tra nhanh qua 12 con trỏ thẳng; tệp lớn mới cần các lớp gián tiếp.
ext2 does not store a file's blocks contiguously or in order; to locate them, the kernel keeps a set of pointers in the i-node. Each ext2 i-node holds 15 pointers: the first 12 point directly to the first 12 data blocks; the 13th is an indirect pointer to a block of further pointers; the 14th is double indirect; and the 15th is triple indirect.1 The number of pointers in an indirect block depends on block size: with a 4096-byte block, each 4-byte pointer yields 1024 pointers per block.1
Bạn gặp nó ở đâuWhere you meet it Nhờ kiểu đánh địa chỉ này, truy cập ngẫu nhiên bằnglseek()chỉ cần tính xem phải theo con trỏ nào — và tệp nhỏ (đa số tệp) đọc rất nhanh qua 12 con trỏ trực tiếp.1 Vì có danh sách địa chỉ, máy nhảy thẳng tới chỗ cần trong tệp mà không phải đọc từ đầu. Thanks to this addressing, random access vialseek()only needs to compute which pointer to follow — and small files (most files) are read quickly through the 12 direct pointers.1Cỡ tệp tối đa
Thiết kế này cho phép tệp rất lớn: với khối 4096 byte, kích thước tệp lý thuyết lớn nhất là hơi nhiều hơn 1024×1024×1024×4096 byte, tức xấp xỉ 4 terabyte (4096 GB) — phần “hơi nhiều hơn” đến từ các khối trỏ bởi con trỏ trực tiếp, gián tiếp và gián tiếp kép, không đáng kể so với lớp ba.1
Một lưu ý về con số
Con số ≈4 TB là giới hạn lý thuyết của riêng ext2 với khối 4096 byte theo sách; các hệ tệp khác (ext4, XFS, Btrfs) có giới hạn khác nhờ cơ chế địa chỉ khác. Phần thân này giữ đúng con số sách nêu cho ext2.1
-
ext2 & other types
ext2 và các hệ tệp khác — một ví dụ, nhiều biến thể ext2 — hệ tệp dùng làm ví dụ chung ext2 and other types — one example, many variants
Trong nhiều năm, ext2 (Second Extended File System, kế thừa hệ ext gốc) là hệ tệp phổ biến nhất trên Linux; mã nguồn ext2 nhỏ (cỡ 5000 dòng C) và làm mẫu cho nhiều hiện thực hệ tệp khác. Gần đây việc dùng ext2 giảm dần, nhường chỗ cho các hệ ghi nhật ký. Dù vậy, vì ext2 đơn giản, nó vẫn là ví dụ tốt để nói về khái niệm chung.1 Trong hiện thực riêng của ext2, sau boot block, hệ tệp được chia thành các block group bằng nhau, mỗi nhóm có bản sao superblock và phần i-node + data riêng, nhằm gom khối của một tệp trong cùng nhóm để giảm seek.1
ext2 là hệ tệp Linux kiểu cũ, đơn giản và nhỏ gọn, nên sách lấy nó làm ví dụ. Ngày nay người ta chuộng các hệ mới hơn (ext4…), nhưng ý tưởng cơ bản thì giống nhau. Nhớ nhé: hiểu ext2 là hiểu khung xương của hầu hết hệ tệp.
For many years ext2 (the Second Extended File System, successor to the original ext) was the most widely used Linux file system; its source is small (around 5000 lines of C) and modelled many other implementations. Lately its use has declined in favour of journaling systems. Still, because ext2 is simple, it remains a good example for the general concepts.1 In ext2's own implementation, after the boot block the file system is split into equal-sized block groups, each with a superblock copy and its own i-node and data area, to keep a file's blocks within one group and reduce seeking.1
Bạn gặp nó ở đâuWhere you meet it Các kiểu hệ tệp nhân hiện biết liệt kê trong tệp Linux-riêng/proc/filesystems; từ Linux 2.6.14, FUSE còn cho hiện thực nguyên một hệ tệp trong không gian người dùng.1 Xem/proc/filesystemslà biết máy bạn hiểu được những kiểu hệ tệp nào. The file-system types the kernel knows are listed in the Linux-specific/proc/filesystems; since Linux 2.6.14, FUSE even lets a whole file system be implemented in user space.1
Cụm khái niệm 03 Concept cluster 03
VFS, journaling và gắn kết — hợp mọi hệ tệp thành một cây VFS, ghi nhật ký và cách gắn hệ tệp vào cây The VFS, journaling and mounting — one tree from many
Phần cuối chương ghép ba mảnh. VFS (virtual file system) là một tính năng của nhân tạo lớp trừu tượng cho các thao tác hệ tệp, nên chương trình chỉ cần hiểu giao diện VFS. Journaling giúp hệ tệp hồi phục nhanh sau sự cố. Và cơ chế mount — qua mount()/umount() — gắn hoặc tháo một hệ tệp khỏi cây thư mục duy nhất gốc ở /.1
Phần cuối gộp ba ý: VFS là lớp chung giúp mọi hệ tệp trông như nhau với chương trình; journaling là “cuốn sổ nhật ký” giúp hệ tệp không hỏng khi mất điện; còn mount là thao tác gắn một hệ tệp vào cây thư mục để bạn truy cập. Nhớ nhé: VFS che khác biệt, journaling chống hỏng, mount gắn vào cây.
The final part joins three pieces. The VFS (virtual file system) is a kernel feature that creates an abstraction layer for file-system operations, so programs need only understand the VFS interface. Journaling lets a file system recover quickly after a crash. And the mount mechanism — through mount()/umount() — attaches or detaches a file system from the single directory tree rooted at /.1
Định nghĩa. Trên Linux, như trên các hệ UNIX, mọi tệp từ mọi hệ tệp nằm dưới một cây thư mục duy nhất, gốc là thư mục /. Các hệ tệp khác được mount (gắn) dưới gốc và hiện ra như các cây con. Siêu người dùng gắn bằng lệnh dạng mount thiết-bị thư-mục; thư mục đó gọi là mount point (điểm gắn).17
Nói đơn giản. Linux không có “ổ C, ổ D” riêng biệt. Mọi hệ tệp đều treo vào một cây thư mục chung, bắt đầu từ dấu /. “Mount” là việc gắn một hệ tệp vào một thư mục trên cây đó. Nhớ nhé: Linux chỉ có một cây, hệ tệp mới thì gắn thêm vào một nhánh.
Definition. On Linux, as on other UNIX systems, all files from all file systems reside under one directory tree, rooted at the / directory. Other file systems are mounted under the root and appear as subtrees. The superuser mounts with a command of the form mount device directory; that directory is the mount point.17
VFS: open/read/write/stat/
mount/umount/mkdir/link/rename
mount(source,target,fstype,
mountflags,data)
umount(target)
umount2(target,flags)
statvfs(path,buf) · fstatvfs(fd,buf)
VFS = lớp chung
mount = gắn hệ tệp vào cây
umount = tháo ra
statvfs = hỏi “còn trống bao nhiêu?”
VFS: open/read/write/stat/
mount/umount/mkdir/link/rename
mount(source,target,fstype,
mountflags,data)
umount(target)
umount2(target,flags)
statvfs(path,buf) · fstatvfs(fd,buf)
-
the VFS
VFS — một giao diện chung cho mọi hệ tệp VFS — lớp giúp mọi hệ tệp trông giống nhau The VFS — one interface for all file systems
Ý tưởng VFS rất gọn: VFS định nghĩa một giao diện chung cho các thao tác hệ tệp — mọi chương trình nói chuyện với tệp qua giao diện này; và mỗi hệ tệp cung cấp một hiện thực cho giao diện đó. Nhờ vậy chương trình chỉ cần hiểu VFS và bỏ qua chi tiết từng hệ.19 Giao diện VFS gồm các thao tác ứng với những lời gọi quen thuộc:
open(),read(),write(),close(),stat(),mount(),mkdir(),link(),unlink(),symlink(),rename()…1VFS giống một “phích cắm chuẩn”: chương trình cắm vào VFS là dùng được mọi hệ tệp, dù bên dưới là ext4 hay NTFS hay NFS. Mỗi hệ tệp tự lo phần việc riêng phía sau phích cắm đó. Nhớ nhé: VFS là ổ cắm chung cho mọi loại hệ tệp.
The VFS idea is simple: the VFS defines a generic interface for file-system operations — every program talks to files through it; and each file system provides an implementation of that interface. So programs need only understand the VFS and can ignore each system's details.19 The VFS interface includes operations matching the familiar calls:
open(),read(),write(),close(),stat(),mount(),mkdir(),link(),unlink(),symlink(),rename()…1Bạn gặp nó ở đâuWhere you meet it Khi một hệ tệp không hỗ trợ một thao tác (ví dụ VFAT không có liên kết tượng trưng quasymlink()), hệ tệp trả về mã lỗi và VFS chuyển mã lỗi đó về cho ứng dụng.1 Nếu hệ tệp không làm được một việc, bạn sẽ nhận một mã lỗi — đó là VFS báo lại. When a file system does not support an operation (e.g. VFAT has no symbolic links viasymlink()), it returns an error code and the VFS passes that error back to the application.1 -
journaling
Journaling — cuốn nhật ký giúp khỏi cần fsck dài Journaling — sổ nhật ký chống hỏng khi mất điện Journaling — a log that avoids the long fsck
ext2 có một hạn chế kinh điển: sau sự cố (mất điện, treo máy), phải chạy kiểm tra nhất quán (
fsck) khi khởi động lại để sửa siêu dữ liệu có thể đã cập nhật dở dang; với hệ tệp lớn việc này có thể mất hàng giờ. Hệ tệp journaling loại bỏ nhu cầu đó: nó ghi (nhật ký) mọi cập nhật siêu dữ liệu vào một tệp nhật ký trước khi thực hiện thật, theo từng nhóm gọi là transaction; sau sự cố, nhật ký được dùng để làm lại nhanh các cập nhật dở, đưa hệ tệp về trạng thái nhất quán trong vài giây.1Nếu mất điện giữa chừng, hệ tệp cũ (ext2) phải dò lại toàn bộ đĩa để sửa — rất lâu. Hệ tệp journaling ghi trước “mình sắp làm gì” vào một cuốn sổ; khi bật lại, nó chỉ cần đọc sổ để hoàn tất, nên hồi phục trong vài giây. Nhớ nhé: ghi dự định vào sổ trước, nên hỏng cũng sửa được nhanh.
ext2 has a classic limitation: after a crash (power loss, hang), a consistency check (
fsck) must run at reboot to repair metadata that may have been updated partway; on a large file system this can take hours. A journaling file system removes that need: it logs every metadata update to a journal file before actually carrying it out, in groups called transactions; after a crash, the log is used to quickly redo incomplete updates and bring the file system to a consistent state within seconds.1Bạn gặp nó ở đâuWhere you meet it Mỗi hệ journaling vào nhân ở một bản khác nhau: Reiserfs (2.4.1), ext3 (2.4.15), JFS (2.4.20), XFS (2.4.24), ext4 (2.6.19) và Btrfs (2.6.29).1 Các hệ như ext3, ext4, XFS, Btrfs đều là hệ tệp journaling. Each journaling system entered the kernel at a different version: Reiserfs (2.4.1), ext3 (2.4.15), JFS (2.4.20), XFS (2.4.24), ext4 (2.6.19) and Btrfs (2.6.29).1Chỉ nhật ký siêu dữ liệu
Một số hệ journaling chỉ bảo đảm nhất quán của siêu dữ liệu. Vì không ghi nhật ký dữ liệu tệp, dữ liệu vẫn có thể mất khi sự cố. ext3, ext4 và Reiserfs cho tuỳ chọn ghi nhật ký cả dữ liệu, nhưng tuỳ khối lượng công việc, điều này có thể làm chậm vào/ra.1
Cái giá phải trả
Nhược điểm chính của journaling là nó thêm thời gian cho mỗi lần cập nhật tệp, dù thiết kế tốt giữ phần phụ trội này ở mức thấp. Đổi lại, ngay cả hệ tệp rất lớn cũng sẵn sàng lại trong vài giây sau sự cố — rất hợp cho hệ cần tính sẵn sàng cao.1
-
mount() / umount()
mount() và umount() — gắn và tháo hệ tệp Lệnh gắn và tháo một hệ tệp mount() and umount() — attach and detach
Lời gọi
mount(source, target, fstype, mountflags, data)gắn hệ tệp trên thiết bị source vào điểm gắn target, với kiểu fstype (nhưext4haybtrfs) và một bitmask mountflags;umount(target)tháo nó ra. Cả hai cần đặc quyềnCAP_SYS_ADMIN, và không được chuẩn hoá trong SUSv3.123 Không thể tháo một hệ tệp đang bận (có tệp đang mở, hoặc là thư mục làm việc của một tiến trình):umount()sẽ trả về lỗiEBUSY.13Muốn dùng một hệ tệp, bạn “gắn” nó vào một thư mục bằng
mount; xong việc thì “tháo” bằngumount. Chỉ người quản trị mới làm được. Nếu đang có ai dùng hệ tệp đó thì không tháo được, máy báo bận. Nhớ nhé: gắn trước khi dùng, tháo khi xong, và không tháo được nếu còn đang bận.The call
mount(source, target, fstype, mountflags, data)attaches the file system on device source at mount point target, with type fstype (such asext4orbtrfs) and a mountflags bitmask;umount(target)detaches it. Both require theCAP_SYS_ADMINcapability and are not standardized in SUSv3.123 You cannot unmount a busy file system (with open files, or that holds a process's working directory):umount()returns the errorEBUSY.13Bạn gặp nó ở đâuWhere you meet it Danh sách hệ tệp đang gắn đọc từ/proc/mounts(một symlink tới/proc/self/mounts); các tệp/etc/mtabvà/etc/fstabcùng khuôn dạng, mỗi dòng sáu trường.16 Muốn xem đang gắn gì, đọc/proc/mounts. The list of mounted file systems is read from/proc/mounts(a symlink to/proc/self/mounts); the/etc/mtaband/etc/fstabfiles share the format, six fields per line.16 -
tmpfs & statvfs()
tmpfs và statvfs() — hệ tệp trong RAM và cách hỏi dung lượng tmpfs (trong RAM) và cách hỏi còn trống bao nhiêu tmpfs & statvfs() — a RAM file system and querying it
tmpfs là hệ tệp dựa trên bộ nhớ, xuất hiện từ Linux 2.4; khác các hệ RAM khác, nó là virtual — dùng cả RAM lẫn swap khi RAM cạn. Tạo bằng
mount -t tmpfs source target; không cầnmkfsvì nhân tự dựng hệ tệp. Mặc định tmpfs được phép lớn tới nửa dung lượng RAM, chỉnh bằng tuỳ chọnsize=nbytes; tháo tmpfs hay tắt máy là mất sạch dữ liệu — nên mới có tên tmp.18 Để hỏi thông tin một hệ tệp đã gắn, dùngstatvfs(pathname, buf)hoặcfstatvfs(fd, buf).14tmpfs là hệ tệp nằm trong bộ nhớ RAM nên rất nhanh, nhưng tắt máy là mất hết — hợp để chứa tệp tạm. Còn muốn biết một hệ tệp còn trống bao nhiêu, dùng hàm
statvfs(). Nhớ nhé: tmpfs nhanh nhưng tạm thời; statvfs() cho biết còn bao nhiêu chỗ.tmpfs is a memory-based file system, present since Linux 2.4; unlike other RAM systems it is virtual — using both RAM and swap when RAM runs out. Create it with
mount -t tmpfs source target; nomkfsis needed since the kernel builds the system itself. By default tmpfs may grow to half of RAM, tunable with thesize=nbytesoption; unmounting tmpfs or shutting down loses all its data — hence the name tmp.18 To query a mounted file system, usestatvfs(pathname, buf)orfstatvfs(fd, buf).14Bạn gặp nó ở đâuWhere you meet it Cấu trúcstatvfscho biết cỡ khối (f_bsize), tổng số khối (f_blocks), số khối trống (f_bfree) và số khối người dùng thường còn dùng được (f_bavail) — đúng những gì lệnhdfhiển thị.14 Lệnhdfbáo dung lượng trống chính là nhờ số liệu kiểu nhưstatvfs()trả về. Thestatvfsstructure reports block size (f_bsize), total blocks (f_blocks), free blocks (f_bfree) and blocks available to an unprivileged process (f_bavail) — just whatdfshows.14Hai mục đích đặc biệt của tmpfs
Ngoài dùng cho ứng dụng, tmpfs còn phục vụ hai việc trong nhân: một tmpfs vô hình, gắn nội bộ, hiện thực bộ nhớ chia sẻ System V (Chương 48) và ánh xạ ẩn danh chia sẻ (Chương 49); và một tmpfs gắn ở
/dev/shmcho glibc hiện thực bộ nhớ chia sẻ và semaphore POSIX.1
Ba ngộ nhận thường gặp Three common misconceptions
“Tên tệp thiết bị quyết định trình điều khiển” “The device file's name picks the driver”
Ngộ nhận: nhân nhìn tên tệp trong /dev để biết dùng trình điều khiển nào.
Thực tế: cặp mã major/minor ghi trong i-node mới là thứ nhân dùng; tên tệp không có ý nghĩa gì khi nhân tìm trình điều khiển.1
Myth: the kernel reads the file's name in /dev to pick the driver.
Reality: the major/minor pair recorded in the i-node is what the kernel uses; the name has no relevance when it looks for the driver.1
“Journaling bảo đảm không mất dữ liệu” “Journaling guarantees no data loss”
Ngộ nhận: hệ tệp journaling thì sự cố không bao giờ mất dữ liệu.
Thực tế: nhiều hệ chỉ ghi nhật ký siêu dữ liệu; dữ liệu tệp vẫn có thể mất. Journal data là tuỳ chọn riêng (ext3/ext4/Reiserfs) và phải trả giá hiệu năng.1
Myth: with journaling, a crash never loses data.
Reality: many systems journal only metadata; file data may still be lost. Journaling data is a separate option (ext3/ext4/Reiserfs) with a performance cost.1
“umount() nhận tên thiết bị” “umount() takes the device name”
Ngộ nhận: tháo hệ tệp bằng cách đưa tên thiết bị cho umount().
Thực tế: từ nhân 2.4, một thiết bị gắn được ở nhiều điểm, nên tên thiết bị sẽ nhập nhằng; umount() phải nhận điểm gắn (target).13
Myth: you unmount by passing the device name to umount().
Reality: since kernel 2.4 a device can be mounted at several points, so a device name is ambiguous; umount() must take the mount point (target).13
Tự kiểm Self-check
Năm câu hỏi để biết bạn đã nắm chương hệ thống tệp Năm câu hỏi kiểm tra nhanh Five questions to check you grasped file systems
Trả lời được những câu này nghĩa là bạn đã theo trọn mạch từ tệp thiết bị, qua đĩa và i-node, tới VFS, journaling và cách gắn hệ tệp vào một cây duy nhất.
Nếu trả lời được, nghĩa là bạn đã hiểu chương này.
Answering these means you followed the whole line from device files, through disks and the i-node, to the VFS, journaling and mounting into a single tree.
-
Phân biệt thiết bị ký tự và thiết bị khối; nhân dựa vào gì — tên tệp hay cặp major/minor — để tìm trình điều khiển?
Gợi ý sâu hơn: cặp major/minor được ghi ở đâu, và Linux 2.6 nới giới hạn bit ra sao?
-
Một hệ tệp gồm bốn phần nào, và i-node lưu những thông tin gì về một tệp?
Gợi ý sâu hơn: vì sao số khối cấp cho tệp có thể không khớp với kích thước byte của nó?
-
ext2 dùng 15 con trỏ ra sao để địa chỉ hoá dữ liệu, và vì sao tệp nhỏ được đọc rất nhanh?
Gợi ý sâu hơn: với khối 4096 byte, cỡ tệp tối đa lý thuyết của ext2 là bao nhiêu, và con số đó chỉ đúng cho hệ tệp nào?
-
VFS giải quyết vấn đề gì, và điều gì xảy ra khi một hệ tệp không hỗ trợ một thao tác?
Gợi ý sâu hơn: journaling khác fsck ở chỗ nào, và vì sao nó không bảo đảm khỏi mất dữ liệu tệp?
-
mount() và umount() cần đặc quyền gì, và vì sao umount() phải nhận điểm gắn chứ không phải tên thiết bị?
Gợi ý sâu hơn: tmpfs khác các hệ RAM khác ở điểm nào, và statvfs() trả về những trường nào mà lệnh df cần?
Thiết bị “ký tự” và “khối” khác nhau thế nào?
“Hệ thống tệp” là gì, và i-node dùng để làm gì?
Vì sao đĩa cứng chậm hơn CPU rất nhiều?
Journaling giúp ích gì khi máy mất điện giữa chừng?
“Mount” một hệ tệp nghĩa là làm gì?
How do character and block devices differ, and does the kernel use the file name or the major/minor pair to find the driver?
What four parts make up a file system, and what does an i-node store about a file?
How does ext2 use its 15 pointers to address data, and why are small files read so quickly?
What problem does the VFS solve, and what happens when a file system lacks an operation?
What privilege do mount() and umount() need, and why must umount() take the mount point rather than the device name?
Khép lại chương Closing the chapter
Dữ liệu bắt đầu ở một đĩa quay, được cắt thành phân vùng; mỗi phân vùng mang một hệ tệp với i-node giữ lý lịch tách khỏi dữ liệu. VFS che khác biệt giữa các hệ tệp, journaling giữ chúng an toàn qua sự cố, và mount hợp tất cả thành một cây gốc ở dấu gạch chéo.1
Dữ liệu nằm trên đĩa, đĩa chia thành phân vùng, mỗi phân vùng là một hệ tệp dùng i-node ghi lý lịch từng tệp; rồi Linux gắn hết vào một cây thư mục chung. Nhớ nhé: nhiều đĩa, nhiều hệ tệp, nhưng chỉ một cây.
Data begins on a spinning disk, cut into partitions; each partition carries a file system whose i-nodes keep the record apart from the data. The VFS hides differences between file systems, journaling keeps them safe across crashes, and mount joins everything into one tree rooted at slash.1