Khi bắt đầu tìm hiểu về Linux, mình từng gặp khá nhiều khó khăn trong việc phân biệt Symlinks / Hard Links và cách sử dụng của hai loại file này trong thực tế1. Đây cũng là bài đầu tiên trong Seri Linux mà mình định làm.
Nên trong bài này mình sẽ viết về Symlink, Hard Link trong Linux và các khái niệm quan trọng liên quan như Inode. Đồng thời cũng sẽ nói về một số phép Ẩn dụ trong cuộc sống thường ngày, mà mình hay dùng để hiểu các khái niệm này một cách trực quan hơn.
Một số lưu ý cho bạn đọc trước khi kéo xuống tiếp phía dưới:
- Bài này dài, sorry :(.
- Bài này không nói về ứng dụng thực tế của Symlink và Hard Link, tuy nhiên không ai đánh thuế việc bạn search Google 🙂 Bài viết mặc định bạn đã hiểu về cách sử dụng thực tế của Links trong Linux.
- Hiểu biết của mình về Linux đa phần dừng lại trong phạm vi người dùng cuối, vì thế sẽ có những thiếu xót liên quan đến internal (kernel) concept. Rất mong nhận được góp ý từ mọi người.
- Các bạn có thể đọc bài này theo thứ tự phù hợp với các tiếp cận của bản thân nhé. Ở mỗi phần khái niệm trong “sách giáo khoa2” được trình bày trước khi đưa ra ví dụ minh hoạ. Tuy việc này gây nhàm chán, nhưng hy vọng sẽ giúp các bạn hiểu khái niệm một cách đúng đắn trước khi ánh xạ chúng với các sự vật trong đời sống.
Inode
Sách giáo khoa
Để hiểu về Links hay bất cứ một loại file nào trong Linux, chúng ta cần hiểu qua về khái niệm Inode.
Hiểu một cách đơn giản nhất, Inode chứa toàn bộ những gì Hệ điều hành (OS) cần để truy cập vào một file nào đó. Hay nói cách khác Inode lưu trữ metadata của một file, ví dụ:
- Kích thước file
- Quyền try cập
- Địa chỉ vật lý của file trên ổ đĩa3: Dữ liệu của một file có thể được lưu một cách liên tiếp hoặc rời rạc ở các vùng nhớ vật lý khác nhau. Một trong những nhiệm vụ của Inodes là giúp cho OS biết tất cả các vị trí lưu dữ liệu của một file trên disk, để tương tác với file đó.
- …
Tóm lại, mỗi file thông thường (regular file) sẽ được đại diện bởi một inode. Nếu file đó được copy sang nơi khác, chúng ta sẽ có hai file, với hai inode riêng biệt.
Minh hoạ
Inode giống như chiếc Sổ đỏ nhà bạn, File giống như mảnh đất có thông tin ghi trong sổ đỏ.
Còn dữ liệu thật của một File chính là mảnh đất ba mặt tiền của bạn bằng thật ở Ngã năm Ô Chợ Dừa mà bạn có thể sờ bằng tay, nhìn bằng mắt được.
Trên sổ đỏ (inode) có ghi các thông tin chi tiết liên quan đến mảnh đất như: Diện tích (file size), loại hình đất (file type), chủ sở hữu (file owner), v.v.
Trừ trường hợp ngoại lệ (nhiều chủ sở hữu), mỗi mảnh đất (file) chỉ được cấp một sổ đỏ duy nhất.
Và mỗi khi chuyển nhượng quyền sử dụng đất (chạy lệnh chown), thay vì phải xuống tận vị trí khu đất (physical data), thì chính quyền (OS) và các bên liên quan sẽ thực hiện các thủ tục để cập nhật lại thông tin trên sổ đỏ (inode) hợp pháp của khu đất đó (file).
Qua đó chúng ta dễ dàng thấy được, Inode được sinh ra như một abstraction layer, giúp OS có thể thao tác, quản lý file, mà không cần phải thao tác trực tiếp vùng nhớ vật lý của file trên disk (trong một số trường hợp nhất định).
Hard Link
Okie giờ chúng ta sẽ đến với hard link.
Có thể ban đầu bạn sẽ thấy hard link và các khái niệm liên quan tới directory trong Linux hơi “xoắn não” (twist), đó là vì “góc nhìn” của chúng ta về file và directory trên Linux chưa đúng lắm. Hy vọng phần Minh hoạ phía dưới sẽ giúp bạn thấy các khái niệm này trực quan hơn phần nào. Phần này sẽ hơi dài một chút…
Sách giáo khoa
Chúng ta hãy bắt đầu từ một số góc nhìn mà mọi người dễ bị hiểu sai, để từ đó hiểu dữ khái niệm hard link một cách dễ dàng hơn.
View – File không hẳn “nằm trong” directory
Khi mới tìm hiểu Linux, bản thân mình bị nhầm tưởng mối quan hệ giữa Directory và (Regular) File theo kiểu: Directory giống như một cái tủ, bên trong đó đựng toàn dữ liệu của File. Đây là một cách hiểu sai về Directory – File, và gây nhiều khó khăn trong việc tiếp cận/hiểu khái niệm Hard Link.
Thực trên thực tế, Linux không tổ chức Files theo cấu trúc cây (tree structure), “cây thư mục” mà chúng ta hay thấy chỉ là nhìn từ góc độ logic (logical view). File trên Linux vẫn được “chống lưng” bởi inode, và thông tin inode được lưu trong (on disk) inode table – cấu trúc phẳng, các file ngang hàng (flat).
Nếu các inode có quan hệ ngang hàng, vậy tại sao từ góc độ người dùng, directory và file lại có cấu trúc phân tầng (cây, cha con,…)? Phần tiếp theo chúng ta sẽ đi tìm câu trả lời.
Fact – Directory có nhiệm vụ mapping từ tên file sang inode
Trên Linux, gần như mọi thứ đều có thể xuất hiện dưới ‘hình hài‘ của file, Directory cũng không ngoại lệ, cũng có inode và cũng “trỏ tới” phần dữ liệu cụ thể.
Thay vì chứa dữ liệu của các file “trong” nó, directory chỉ lưu thông tin giúp mapping từ tên file sang inode. Thông tin này được lưu trong một cấu trúc dữ liệu gọi là dentry (directory entry).
Trong hình phía trên, directory root /
sẽ gồm các dentry:
- name: bin, inode: 13
- bin lại chứa các dentry của riêng nó
- name: bash, inode: 13763146
- name: vim, inode: 13766787
- …
- bin lại chứa các dentry của riêng nó
- name: boot, inode: 9043969
- …
- name: swapfile, inode: 12
Như đã trình bày ở đầu bài viết, các inode này sẽ lưu địa chỉ vật lý (hoặc gián tiếp) của file trên ổ đĩa.
Như vậy, Directory chỉ chứa các “chỉ mục” giúp trỏ đến một hoặc nhiều inode cụ thể, giúp tạo ra một cấu trúc cây “ảo” nhìn từ view người dùng.
Điều này đồng nghĩa với hai điều:
- một inode bất kỳ có thể được trỏ tới từ nhiều hơn một directory.
- tên file chỉ đơn giản là một trong những thông tin được lưu trong dentry của directory, dùng để tạo nên cấu trúc phân tầng của cây thư mục.
- điều này dẫn tới fact phía dưới – cơ chế bên dưới của Hard Link
Fact – Một inode trong Linux có thể có nhiều tên khác nhau, thuộc nhiều directory khác nhau
Trong hình dưới đây, file1
, file11
, file12
đều trỏ đến cùng một inode. Bản chất file1
, file11
là dentry trong dir1
, và file12
là dentry trong trong dir2
.
Mỗi inode đều là duy nhất, nhưng có thể có nhiều dentry cùng trỏ tới một inode, do đó một inode có thể có nhiều “đường dẫn” khác nhau.
Trong ví dụ trên, file11
, file12
là hard link của file1
, và được tạo ra bởi lệnh dưới đây:
ln dir1/file11
ln dir2/file12
Thực tế, hard link chỉ là cách gọi tương đối. Chúng mình có thể gọi:
file1
,file12
là hard link củafile11
- hay
file11
,file1
là hard link củafile12
Minh hoạ
Chúng mình hãy tiếp tục coi inode giống như một khu đất, nhưng khu đất này là Bệnh viện Việt Đức :), và có nhiều cổng khác nhau:
Lúc này, file names (hard links) sẽ là địa chỉ khác nhau của các cổng Bệnh viện: 40 Tràng Thi
, 16-18 Phủ Doãn
, 8 Phủ Doãn
.
Tadaaa! Phần minh hoạ này chỉ ngắn vậy thôi.
Câu hỏi thường gặp
Thay đổi dữ liệu Hardlink có làm thay đổi dữ liệu file gốc không?
Tất cả các hard link đều có dữ liệu giống với file gốc.
Như đã trình bày ở phần trước, symlink / file gốc chỉ là những khái niệm tương đối. Cả hai đối tượng này đều là những dentry cùng trỏ tới một inode. Vì vậy thao tác thay đổi dữ liệu của hard link, thực tế là thay đổi dữ liệu được quản lý bởi inode mà hard link đang trỏ tới, và do đó dữ liệu của các hard link (dentry) khác cũng sẽ thay đổi theo.
Điều gì xảy ra nếu hard link bị xoá?
Nếu một inodes có nhiều hard link, việc xoá một hard link sẽ không làm ảnh hưởng với các link còn lại. Dữ liệu và inode quản lý dữ liệu sẽ chỉ bị xoá khi không còn link nào trỏ đến inode đó nữa.
$ ln file1 file1_hardlink
$ ls *
file1 file1_hardlink
$ rm file1_hardlink
$ ls *
file1
Tương tự, vì hard link của một inode chỉ đơn giản là một dentry trỏ đến inode đó, nên việc thay đổi đường dẫn của một hard link cũng sẽ không ảnh hưởng tới các hard link còn lại.
Trong ví dụ về bệnh viện Việt Đức, nếu một cổng bị đóng lại hoặc bị phá huỷ, chúng ta vẫn có thể vào được bệnh viện.4
Làm sao để biết hai file bất kỳ có phải “là một” 🙂 không?
Chúng ta có thể dùng lệnh ls -li
để xem inode number của các file. Nếu hai file có chung inode, chúng “là một” :).
Lệnh stat sẽ show số lượng hard link đang trỏ tới một inode.
Soft/Sym Link
Khi bạn đã hiểu được inode, hard link, việc tiếp cận symlink sẽ đơn giản hơn rất nhiều.
Sách giáo khoa
Nếu như hard links của một file cùng trỏ tới inode của file đó thì symlink lại khác, symlink là một ‘file bình thường’ (ordinary / normal file).
Symlink có inode riêng, chỉ có một điểm symlink khác với file thông thường: dữ liệu thực (actual data) của symlink chính là đường dẫn tới một regular file hoặc directory khác.
Trong hình trên, khi bạn bảo OS in ra nội dung file my-soft-link
, OS sẽ thấy my-soft-link
đang ‘trỏ’ tới một file khác – myfile.txt
(data trong my-soft-link
nói rằng: “nếu muốn lấy thông tin gì, hãy tới tìm tới myfile.txt
“, hay nói cách khác, hãy tìm dữ liệu mà inode
đang quản lý).
$ touch myfile.txt
$ ls -li *
# để ý inode của file gốc và symlink của nó khác nhau
# ↓
273066 lrwxrwxrwx 1 ubuntu ubuntu 10 Jul 2 16:52 my-soft-link -> myfile.txt
273065 -rw-rw-r-- 1 ubuntu ubuntu 0 Jul 2 16:51 myfile.txt
Chúng ta hãy cùng xem thông tin lưu trong inode của my-soft-link
.
$ stat my-soft-link
File: my-soft-link -> myfile.txt
Size: 10 Blocks: 0 IO Block: 4096 symbolic link
Device: fc01h/64513d Inode: 273066 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
Access: 2024-07-02 16:52:23.673744413 +0000
Modify: 2024-07-02 16:52:17.437703268 +0000
Change: 2024-07-02 16:52:17.437703268 +0000
Birth: 2024-07-02 16:52:17.437703268 +0000
Mọi thứ giống hệt một file thông thường, trừ file type: symbolic link
. Thông tin này giúp OS biết rằng, data lưu trong inode này (273066
) chỉ là đường dẫn đến một file khác.
Symlink trong Linux gần giống với Shortcut trong Windows.
Minh hoạ
Hùm rất yêu thích cuốn “500 bài tập vật lý Olympics” nên đã cất nó cẩn thận trong một giá sách lớn ở phòng ngủ. Tuy nhiên vì là người đãng trí, Hùm đã phải viết một tờ giấy note ghi lại vị trí của cuốn sách trên giá sách, và đặt tờ note trong phòng khách.
Trong ví dụ trên:
- Cuốn “500 bài tập vật lý Olympics” là file gốc.
- Tờ giấy note ghi lại vị trí của cuốn sách là symlink của file đó.
- Phòng ngủ, phòng khách lần lượt là directory của file gốc và của symlink.
Câu hỏi thường gặp
Xoá / Di chuyển file gốc có làm ảnh hưởng tới symlinks của file đó không?
Có.
Khi bạn xoá file gốc, symlink của file đó không bị xoá, tuy nhiên khi đó symlinks sẽ bị “hỏng” – vì nó trỏ tới một file không tồn tại.
$ touch orig_file
$ ln -s orig_file syml
$ ls *
orig_file syml
$ ls -l
total 0
-rw-rw-r-- 1 ubuntu ubuntu 0 Jul 2 17:33 orig_file
lrwxrwxrwx 1 ubuntu ubuntu 9 Jul 2 17:33 syml -> orig_file
$ rm orig_file
$ ls -l
total 0
lrwxrwxrwx 1 ubuntu ubuntu 9 Jul 2 17:33 syml -> orig_file
$ cat syml
cat: syml: No such file or directory
Trong ví dụ minh hoạ phía trên, nếu bạn quyển sách “500 bài tập vật lý Olympics” bị một kẻ yêu vật lý khác đánh cắp, tờ giấy note của bạn vẫn sẽ không ảnh hưởng, tuy nhiên khi lần theo vị trí ghi trên mảnh giấy note, bạn sẽ không thể tìm được cuốn sách ở chỗ cũ nữa.
Xoá / di chuyển symlink có làm ảnh hưởng tới file gốc không?
Không.
Bạn vứt tờ giấy note ở đâu thì cuốn sách “500 bài tập vật lý Olympics” vẫn cứ ở đó thôi.
Tài liệu tham khảo
https://unix.stackexchange.com/questions/4402/what-is-a-superblock-inode-dentry-and-a-file – đọc về dentry, inode và file – có thể bỏ qua khái niệm superblock
https://www.redhat.com/sysadmin/soft-links-linux – seri này của redhat khá hay, ngắn gọn dễ hiểu, các bạn có thể tham khảo thêm các bài viết khác trong seri.
https://litux.nl/mirror/kerneldevelopment/0672327201/ch12lev1sec7.html – giới thiệu về dentry, hơi khô khan một chút…
https://www.google.com/search?client=firefox-b-d&q=hard+link+vs+normal+file – phao #1 khi viết blog này.
https://www.google.com/search?client=firefox-b-d&q=symlink+metaphor – phao #2
- Xin phép nợ cách sử dụng symlink / hard link trong một bài khác ạ. ↩︎
- Mình dùng từ “Sách giáo khoa” cho vui, thực tế nội dung trình bày trong bài này vẫn mang tính thường thức, thiếu tính hàn lâm. ↩︎
- Trên thực tế, với các File lớn, inode có thể lưu địa chỉ gián tiếp (indrect block address) của một file. Tuy nhiên, mình tạm thời bỏ qua phần này vì thấy hơi phức tạp so với phạm vi bài viết. ↩︎
- Mình nhận ra ví dụ bệnh viện có nhiều cổng không hoàn toàn mô tả chính xác về Hard Link, tuy nhiên chưa tìm được ví dụ nào chính xác tuyệt đối. Mọi người có thể góp ý ạ. ↩︎
Noice bro 😘
Thanks bro!