1

This is regarding generic UFS.

From what I understand when an absolute path is given (eg: /home/userU/file.txt) the disk is accessed for each directory and the file. Hence in this case the disk is accessed 4 times

1 For /, 1 for home/, 1 for /userU, 1 for file.txt

My questions are

  1. If a hard link /hL is given, pointing to the inode of the above file, in what order is the disk accessed?
  2. If a soft link /sL is given, pointing to the above file, in what order is the disk accessed?

Assume that no inodes or any other data are cached initially in all three cases.

1

Background

Say we have the following directory setup:

$ ll
total 0
-rw-r--r-- 2 root root 0 Jul 29 23:36 afile.txt
-rw-r--r-- 2 root root 0 Jul 29 23:36 hL
lrwxrwxrwx 1 root root 9 Jul 30 01:22 sL -> afile.txt

Now let's look at your 2 questions.


Questions

  1. If a hard link /hL is given, pointing to the inode of the above file, in what order is the disk accessed?

With hardlinks, they possess the same inode reference as the original file/directory that they're pointing to. So there is no additional HDD access to read them.

For example:

$ stat hL | head -3
  File: ‘hL’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 667668      Links: 2

vs.

$ stat afile.txt | head -3
  File: ‘afile.txt’
  Size: 0           Blocks: 0          IO Block: 4096   regular empty file
Device: fd00h/64768d    Inode: 667668      Links: 2

The only difference between these 2 is the name. So either path will incur the same number of HDD accesses.

  1. If a soft link /sL is given, pointing to the above file, in what order is the disk accessed?

With soft links however, there is an additional HDD access. This additional access would be against the directory's metadata, where the file sL resides. This would then return details stating that this file is in fact a symbolic link, and it's pointing to another file/directory.

For example:

$ stat sL | head -3
  File: ‘sL’ -> ‘afile.txt’
  Size: 9           Blocks: 0          IO Block: 4096   symbolic link
Device: fd00h/64768d    Inode: 681295      Links: 1

Here we can see it's of type 'symbolic link' and it's pointing to afile.txt. Notice too that it has a different inode (681295 vs. 667668), further proof that it's going to cost an additional read.

So what's the read orders?

If you use strace against the Bash shell itself where you're running commands against these files/directories you can get an idea of how things work.

[pid 18098] stat("/tmp/adir/hL", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
[pid 18098] open("/tmp/adir/hL", O_RDONLY) = 3
[pid 18098] fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0

Here's output from the command more /tmp/adir/hL.

For /tmp/adir/hL:

  • stat/open (/) → stat/open (tmp) → stat/open (adir) → stat/open (hL)

For /tmp/adir/sL:

  • stat/open (/) → stat/open (tmp) → stat/open (adir) → stat/open (sL) → stat/open (afile.txt)

Further details

The Wikipedia page on Symbolic links eludes to all this as well:

Although storing the link value inside the inode saves a disk block and a disk read, the operating system still needs to parse the path name in the link, which always requires reading additional inodes and generally requires reading other, and potentially many, directories, processing both the list of files and the inodes of each of them until it finds a match with the link's path components. Only when a link points to a file in the same directory do "fast symlinks" provide significantly better performance than other symlinks.

References

1

Both asked questions are in fact the question: "How path_resolution works?", so just look at the whole process from this point of view.

From PATH_RESOLUTION(7) we read:

A filename (or pathname) is resolved as follows.

And afterwards we see that the first step is common for both hardlinks and symlinks (where system decides what is the starting point of path resolution: root directory /, chrooted directory or current directory).

If the pathname starts with the '/' character, the starting lookup directory is the root directory of the calling process. (A process inherits its root directory from its parent. Usually this will be the root directory of the file hierarchy. A process may get a different root directory by use of the chroot(2) system call. A process may get an entirely private mount namespace in case it—or one of its ancestors—was started by an invocation of the clone(2) system call that had the CLONE_NEWNS flag set.) This handles the '/' part of the pathname.

If the pathname does not start with the '/' character, the starting lookup directory of the resolution process is the current working directory of the process. (This is also inherited from the parent. It can be changed by use of the chdir(2) system call.)

Pathnames starting with a '/' character are called absolute pathnames. Pathnames not starting with a '/' are called relative pathnames.

As we see no difference to the starting point between hard- and symlinks. But, a difference does appear on the next step when walking the path begins:

Set the current lookup directory to the starting lookup directory. Now, for each nonfinal component of the pathname, where a component is a substring delimited by '/' characters, this component is looked up in the current lookup directory.

If the process does not have search permission on the current lookup directory, an EACCES error is returned ("Permission denied").

If the component is not found, an ENOENT error is returned ("No such file or directory"). If the component is found, but is neither a directory nor a symbolic link, an ENOTDIR error is returned ("Not a directory").

If the component is found and is a directory, we set the current lookup directory to that directory, and go to the next component.

As the description indicates there is no difference in path resolution for files and hardlinks - the process is the same. And what about symlinks? We read further:

If the component is found and is a symbolic link (symlink), we first resolve this symbolic link (with the current lookup directory as starting lookup directory). Upon error, that error is returned. If the result is not a directory, an ENOTDIR error is returned. If the resolution of the symlink is successful and returns a directory, we set the current lookup directory to that directory, and go to the next component. Note that the resolution process here can involve recursion if the prefix ('dirname') component of a pathname contains a filename that is a symbolic link that resolves to a directory (where the prefix component of that directory may contain a symbolic link, and so on). In order to protect the kernel against stack overflow, and also to protect against denial of service, there are limits on the maximum recursion depth, and on the maximum number of symbolic links followed. An ELOOP error is returned when the maximum is exceeded ("Too many levels of symbolic links").

As it's indicated above, symlinks resolution requires additional disk access operations, so answering both questions:

If a hard link /hL is given, pointing to the inode of the above file, in what order is the disk accessed?

and

If a soft link /sL is given, pointing to the above file, in what order is the disk accessed?

we can conclude, that hardlinks access doesn't differ from ordinary file access, but symlinks resolution requires additional disk access operations, namely, symbolic link resolution.

Additional reading:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.