I read about this in APUE 3rd, 4.21: If one or more processes have the directory open when the link count reaches 0, the last link is removed and the dot and dot-dot entries are removed before this function returns. I just can't understand this, I think the "link count reaches 0" should be "link count reaches 2", a empty directory have at least 2 link count. What I want to know is how rmdir deal with link count?

  • 1
    Looks like . and .. are really removed,see: mkdir /tmp/TESTD; cd /tmp/TESTD; ls -la .; rmdir /tmp/TESTD; ls -la .; The last ls does not show the dots. Interestingly the dot still worked as argument for ls. – rudimeier Oct 20 '16 at 12:23
  • @rudimeier, another confusion,ls -la .. works correctly. – cong Oct 20 '16 at 12:37
  • And even ls -la ./. :) – rudimeier Oct 20 '16 at 12:44
  • @rudimeier, do you know someone who may konw the anwser?Just invite him or her please, thanks. – cong Oct 20 '16 at 15:31
  • No, the empty directory does have 0 link count. ls -ld . -> drwxrwxr-x. 0 alan alan 0 Oct 20 20:01 – sourcejedi Oct 20 '16 at 19:04

You're confused. rmdir simply doesn't care about link counts. The logic is quite straightforward.

Once a file has a link count of 0, and additionally, no running processes with a reference (file descriptor or current directory), it will be truly deleted. That's the point when the disk space can be re-used for something else [*].

Directories are a file. But unlinking (removing them from their parent) requires more consideration than other types of file. We must make sure each child of the directory is unlinked as well. Otherwise, we could lose the chance to update the children's link count. We would lose that disk space permanently.

So we don't let users call unlink on a directory. Instead, they must use the special-purpose rmdir. Calling rmdir differs from unlink in just two ways

  1. It requires that the directory is "empty", which means that its only children are the standard . and .. entries.
  2. It makes sure to unlink these two remaining entries, before it runs unlink on the directory itself.

That's it. There is no other magic. rmdir is not deferred until the condition in point 1 holds. rmdir either succeeds or fails at the time it is called. Nor is the condition based on link count in any way.

I find the effect of the . entry on link counts interesting, even though it's not a special case. It's a hard-link to the parent directory, and therefore increases it's link count. This is the explanation for why a newly created directory DIR has a link count of 2. If you then call rmdir DIR, the link count falls back to 0, because it removes both links DIR/. and DIR.

Linux actually allows you to observe the above by running a shell inside the directory, and running ls -ld after the directory has been unlinked (removed from its parent).

Of course ls -ld is shorthand for ls -ld .. . and .. keep working even after the directory entry is removed; in fact modern Linux does not really rely on these on-disk directory entries. I expect the original Unix implementation would not support this. However I believe the reference counts still worked as described above, and did not have a special-case for the removal of a directory.

(How .. continues to work is even more interesting. Discussed in comment below).

In fact it would be very easy for you to look at the original Unix code for rmdir. It was implemented as a user program running with special privileges. Historical unix code is easy to find online. It's one reason I'm so confident about this.

[*] So you can see whether a file has been deleted by looking for a difference in used disk blocks in df . (or i-nodes in df -i .). This approach works nicely in filesystems like Linux ext4. Less traditional filesystems may have more complex optimizations though, which can make it harder to observe.

  • Could you please explain "pathname has .. as its final component"? – cong Oct 21 '16 at 0:55
  • rmdir TEST1/TEST2/.. will fail. I don't know why this is specified explicitly though. – sourcejedi Oct 21 '16 at 9:11
  • ah, if you look at the context I think it's more to specify which error code happens in this case (ENOTEMPTY). If the last component is ., the error code is EINVAL. – sourcejedi Oct 21 '16 at 9:15
  • ok, thanks, even though I don't know when the . or .. will be the final component of a directory, rmdir . or rmdir .. will never succeed, thank anyway. Another confusion, mkdir mytest, cd mytest ,rm ../mytest, then ls -al .. will work correctly, why? – cong Oct 21 '16 at 11:25
  • hah, yes, the answer that it is synthesized by the VFS doesn't entirely explain that. The answer involves the VFS "dentry" object, holding a reference to its parent dentry. Each dentry must also hold a reference to the inode, so the parent will stay alive even if it too is unlinked. Easy way to see this lifetime issue is to look at the destructor :). lxr.free-electrons.com/source/fs/dcache.c?v=4.7#L767 – sourcejedi Oct 21 '16 at 12:45

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.