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 đó.
Dentry và Inode
Dentry sẽ được giải thích ở phần sau

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.

Trên máy mình, /etc/hosts có inode 14156291
Thông tin lưu trong inode của /etc/hosts

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.

Ảnh này cũng trên mạng, chứ mình chưa có nha :>

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).

chown phongvq:phongvq yourland 😀

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…

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).

Đây chỉ là view từ phái người dùng.

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ể.

Trên máy mình, /boot có inode là 9043969

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).

Dentry và Inode

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
  • 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
Trong một số file system, / có inode number là 2

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, file12hard 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ủa file11
  • hay file11, file1 là hard link của file12
Inode, Symlink và Hard Link

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

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.

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

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.

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.

Inode, Symlink và Hard Link

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.

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

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.

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


  1. Xin phép nợ cách sử dụng symlink / hard link trong một bài khác ạ. ↩︎
  2. 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. ↩︎
  3. 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. ↩︎
  4. 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 ý ạ. ↩︎

Categorized in: