Thursday, March 28, 2013

All About inodes, Hard Links and Soft Links

Open your terminal and fire "ls -i" and you will see that each file is associated with a number.
$ ls -i
2889973 users.sh 2889972 fedoraRepo.sh 2889970 sfs.sh
2889969 bigFile.sh 2889971 dbBackup.sh 2889714 tree-clone.py


Ever wondered what this number is?
Ever thought what happens when a file is deleted?
How does the system knows the owner of the file or it's last modification time?
What are hard links?
What is the difference between hard links and soft links?

I'll try to answer these questions and probably more but I want to stress on a point; every thing in Linux is a file including the directories and devices attached.
Also install a package called sleuthkit using yum or apt to obtain a tool called istat.

When a filesystem (considering ext3/ext4 for now) is created on a disk, a special data structure is created. We'll call this inode table (technically it is an array of structure). It is indexed from 1 to n where n is the maximum numbers of inodes in the filesystem. Details like maximum number of inodes are decided while creating the filesystem usually. We can run "df -i" to check out number of inodes used and available.
Now whenever we create a file or a directory, an unallocated inode number is assigned and this is where several details about the file or the directory is stored. POSIX standard requires inode to contain the following information (borrowed from Wikipedia):
  • The size of the file in bytes.
  • Device ID (this identifies the device containing the file).
  • The User ID of the file's owner.
  • The Group ID of the file.
  • The file mode which determines the file type and how the file's owner, its group, and others can access the file.
  • Additional system and user flags to further protect the file (limit its use and modification).
  • Timestamps telling when the inode itself was last modified (ctime, inode change time), the file content last modified (mtime, modification time), and last accessed (atime, access time).
  • A link count telling how many hard links point to the inode.
  • Pointers to the disk blocks that store the file's contents (see inode pointer structure).
Notice that this does not include the filename. Surprised? In fact inodes never hold that information. So an obvious question arises, when we open file, how does the system know what inode it is associated with? To understand this, we need to understand what exactly is a directory. As I have mentioned, everything in Linux is a file which implies that even directory is a file. Every directory consist of a data structure, first part of which holds an inode number and the second part holds the file name. So when we try to perform any operation on a file, a recursive traversal is performed to lookup for inode number against that file name and that is how inode is obtained.

Among the information contained in inode, a link count and size is maintained. When we delete a file the link count is decreased until it reaches zero where the size of the file is also set to zero. See the example:
# ls -i abc
2891791 abc

# istat /dev/sda5 2891791
inode: 2891791
Allocated
Group: 353
Generation Id: 3534721592
uid / gid: 1000 / 1000
mode: rrw-rw-r--
Flags:
size: 6
num of links: 1

Inode Times:
Accessed: 2013-03-29 01:16:46 (IST)
File Modified: 2013-03-29 01:16:46 (IST)
Inode Modified: 2013-03-29 01:16:46 (IST)

Direct Blocks:
127754

# ln abc def
# istat /dev/sda5 2891791
inode: 2891791
Allocated
Group: 353
Generation Id: 3534721592
uid / gid: 1000 / 1000
mode: rrw-rw-r--
Flags:
size: 6
num of links: 2

Inode Times:
Accessed: 2013-03-29 01:18:41 (IST)
File Modified: 2013-03-29 01:16:46 (IST)
Inode Modified: 2013-03-29 01:18:34 (IST)

Direct Blocks:
127754

# rm abc
# istat /dev/sda5 2891791
inode: 2891791
Allocated
Group: 353
Generation Id: 3534721592
uid / gid: 1000 / 1000
mode: rrw-rw-r--
Flags:
size: 6
num of links: 1

Inode Times:
Accessed: 2013-03-29 01:18:41 (IST)
File Modified: 2013-03-29 01:16:46 (IST)
Inode Modified: 2013-03-29 01:18:57 (IST)

Direct Blocks:
127754 


So the "num of links" increased when we created a hardlink using ln command by one. When we deleted the file using rm command, the "num of links" decreased by one. If we delete the def file then the count and size will be set to zero.

# istat /dev/sda5 2891791
inode: 2891791
Not Allocated
Group: 353
Generation Id: 3534721592
uid / gid: 1000 / 1000
mode: rrw-rw-r--
Flags:
size: 0
num of links: 0


Inode Times:
Accessed: 2013-03-29 01:18:41 (IST)
File Modified: 2013-03-29 01:30:10 (IST)
Inode Modified: 2013-03-29 01:30:10 (IST)
Deleted: 2013-03-29 01:30:10 (IST)

Direct Blocks:


This brings us to our next topic of discussion, what are hard links and what are soft links? Simply putting, hard link of a file holds the inode of that file where as the soft link of the file is just a reference to another file. If we delete the original file but have a hard link to it, then we can still access the contents using the hard link. If we delete the original file, the soft link is pretty much useless since all it did was to point to the original name which contained the inode. A crude way to depict what I am saying is below. See how both "Original Name" and "Hard Link" is pointing to the inode but "Soft Link" is not.
Original Name ---------> inode <--------- Hard Link
Soft Link ----------> Original Name -----------> inode

Now, soft links have their own importance. We cannot use hard links to point to files across different filesystems but with soft links we can. This comes really handy when you want to maintain one name regardless of version differences. See how /usr/bin/python actually points to another binary.

# ls -l /usr/bin/python
lrwxrwxrwx. 1 root root 7 Jan 9 22:45 /usr/bin/python -> python2



Honestly, there are many more creative uses of links. If you are interested then I recommend that you check out how BusyBox implements a lot of commands using a single binary.
(Hint: $0 is the name of the script which is passed as a variable to the binary)

Update: As mentioned by reirob on HackerNews, there is a particular case where deleting the file does not set the "num of links" to zero. This usually happens when there is a process which is writing to the file. I have encountered this a few times myself when I delete a log file but the server writing it hasn't been restarted.

10 comments:

  1. Hi Aditya,

    In your "update" you talk briefly about when files have been deleted but are still hanging around because some processes are using them. I wrote a post a while ago about how to find these files. Someone may find it useful:

    http://dustymabe.com/2012/01/22/recover-space-by-finding-deleted-files-that-are-still-held-open/

    Regards,
    Dusty

    ReplyDelete
    Replies
    1. Hi Dusty,

      That is a great post and could really save the day. Thanks for sharing it with us. :)

      Delete
  2. Nice post!

    The line where you create the hard link has a small typo:

    # ln abd def

    should be:

    # ln abc def

    Also there is an output line saying Direct blocks: 127754. A lot of my files have the exact same number. Gonna dig deeper!

    ReplyDelete
    Replies
    1. Thanks for pointing this out. I have corrected it.
      Have a look at inode pointer structure to get to know mroe about the concept of Direct blocks.

      Delete
    2. Hi.. aditya

      Can u get me the shell script for

      Implement the commands for creation and deletion of directory. Write a program to change current working directory and display the node details for each file in the new directory.

      Thanks in advance

      Delete
  3. Someone deletes a filesystem "/u2" and its gone -they panic --wondering how they can get the file system back. How do you determine the idode for "/u2" (that has already been deleted), and know what volume group (vg) it was part of and bring it back/re-mount it?

    ReplyDelete
  4. Wow! Nice information. There is wonderful on "All About inodes, Hard Links and Soft Links". I am intimidated by the value of in succession on this website. There are a lot of excellent assets here. Definitely I will visit this place again soon.
    I think,
    I know something about this same information, to know you can click here.

    ReplyDelete
  5. hi....
    can i get shell script code for

    " Implement the commands for creation and deletion of directory. Write a program to change current working directory and display the node details for each file in the new directory."

    ReplyDelete
  6. it is bad idea store rights (mode/owner) in inode. better way store this in DIR structure, the same as filename. Current way doesn't allow grant different rights to different hard linked file names. workaround is using filesystems with snapshots. examples are btrfs, ocfs, zfs. unfortunately not ext2/3/4 :(.

    ReplyDelete