Have you ever seen "VFS: file-max limit XXX reached" and proceeded to hunt for file descriptor consumers? Does this prompt you to lsof -u joe | wc -l to find out how many file descriptors joe uses? If so, this post is for you.
Aforementioned message is not about file descriptors and lsof - u joe shows way more than just file descriptors anyway.
So what is limited by RLIMIT_NOFILE?
The biggest number that can be assigned to a file descriptor in given process.
I repeat: the biggest number that can be assigned to a file descriptor. Of course from the moment the limit is applied. This has a side effect of limiting the number of file descriptors a process can open from this point on.
1. process sets RLIMIT_NOFILE to 20 on its own. How many file descriptors can it have opened?
Impossible
 to tell. No new file descriptor will be bigger than 20, but there may 
be a huge number of already opened file descriptors with higher number.
2.
 There is only one process owned by joe. It has the following file 
descriptors opened: 0, 1, 2. It sets its own RLIMIT_NOFILE to 20 and 
creates a new process. How many file descriptors can be opened in each 
of them?
nofile
 limit is per process, thus the fact that one of these processes created
 the other one is irrelevant. Either can open 18 more file descriptors.
You may have encountered the following:
VFS: file-max limit $BIGNUM reached
What's the relationship between file descriptors and 'file' (struct file) limit?
So what is struct file? It is an object which contains some state related to an open entity like an on-disk file, pipe etc.
struct file may be used internally by the kernel and not be associated with any file descritor.
Each file descriptor has to be associated with exactly one struct file.
Each struct file has an unlimited number of associated file descriptors.
On clone() file descriptors are copied, i.e. they reference the same 'struct file' their counterparts in parent process do.
Opening a file typically boils down to the following:
lookup the file
allocate new file descriptor
allocate struct file
tie up an inode with struct file
set file descriptor to 'point' to struct file
3.
 Process has the following file descriptors open: 0, 1, 2. Now it calls 
clone(). How many new 'struct file' are allocated in order to satisfy 
this request?
None. 0, 1, 2 in the new process use struct file from 0, 1, 2 from the parent.
4. Process has the folowing file descriptors open: 0, 1, 2. Now it exits. How many 'struct file' will be freed as a result?
Impossible
 to tell. First, it is possible that all file descriptors were 
associated with the same 'struct file'. Not only that, these file 
descriptors could be inherited from parent process which is still alive 
and didn't modify its descriptors. As such, it is possible that struct 
file(s) in question are still in use.
5. No process has /etc/passwd open. Now one process opens it 3 times. How many 'struct file' were allocated as a result?
Three, one for each open request.
With that established let's take a look at related errors (man errno):
ENFILE          Too many open files in system (POSIX.1)
EMFILE          Too many open files (POSIX.1)
First one signals the kernel ran out of 'struct file', the other one that given process cannot have more file descriptors.
When the kernel prints "VFS: file-max limit XXX reached" it says it won't allocate any new struct file.
6.
 Let's assume the kernel reached the limit of 'struct file'. Now joe's 
process tried to obtain a new file descriptor. Can this operation 
succeed? Which error is returned on failure?
If the new file descriptor would have new 'struct file', the error would be ENFILE.
But
 it may be that this file descriptors is going to reuse already existing
 'struct file', in which case it does not matter that the kernel hit the
 limit. In can fail with EMFILE, or it can succeed, depending on 
rlimits.
lsof | wc -l vs number of open descriptors
Apart
 from file descriptors, lsof shows other stuff (e.g. in-memory file 
mappings, current working directory). As such, output from mere 
'lsof' invocations cannot be used to check file descriptors.
7. An administrator does `lsof -p 8888 | wc -l` and receives 10000. How many file descriptors are in use this process?
As noted earlier, impossible to tell due to other fields printed by lsof.
Current amount of open file descriptors by given process can be obtained by counting symlinks in /proc/<pid>/fd.
8. `ls /proc/<pid>/fd | wc -l`  returns 9000. How many 'struct file' are in use by this process?
Anything between 1 and 9000 (including both).
9. We get result as previous one. What can you say about 'nofile' rlimit set on this process?
Nothing. Not only we don't know the biggest open fd, even if we did the fd could be open before the limit was applied.