When discussing persistent objects, it is important to make a distinction between data that generates an object, written on some sort of physical media, and the actual object, which exists only in memory.
A "virtual node" or "vnode" is an object created by an instance of UNIX to represent a particular file's inode, which is the physical manifestation of the file allocation information on disk. There is at most one vnode for each physical "file" accessible to the operating system. So, when UNIX wants to open a particular file (via, say open()), it:
- Traverses the virtual file system directory structure to find a directory entry that matches the path given to it.
- If it finds such an entry, it examines the entry's permissions/access control lists to see if the calling process is allowed to open the file.
- If allowed, it looks through the virtual file system's vnode table for an existing vnode for the file.
- If a vnode already exists, it uses that one. If a vnode doesn't exist, it:
- Creates a new vnode;
- reads the file's inode information from a file system superblock,
- initializes the vnode with the inode information.
- Once the operating system has a vnode available for the file, it creates an entry in the calling process's file entry table returning the familiar int fildes returned by open().
Of course, the above process is complicated by things like NFS and symbolic links, as well as the fact that some vnodes are created automatically for devices. That's the whole point. Your programs, as well as more rarefied parts of UNIX, shouldn't have to deal with all of the details of file systems, and shouldn't have to handle files and other file-like objects differently. Vnodes make that encapsulation possible.
dup() only needs to access the vnode of the process file object given to it, and create a new process file entry.
Some flavors of LINUX confuse the distinction between vnodes and inodes, and you will sometimes hear the terms used interchangeably. Whatever faction of the distro wars you attatch yourself to, try not to make such a mistake.
Vnode structures will vary widely between various implementations of UNIX, but a typical vnode structure1 looks like this:
typedef struct vnode {
kmutex_t v_lock; /* protects vnode fields */
u_short v_flag; /* vnode flags (see below) */
u_long v_count; /* reference count */
struct vfs *v_vfsmountedhere; /* ptr to vfs mounted here */
struct vnodeops *v_op; /* vnode operations */
struct vfs *v_vfsp; /* ptr to containing VFS */
struct stdata *v_stream; /* associated stream */
struct page *v_pages; /* vnode pages list */
enum vtype v_type; /* vnode type */
dev_t v_rdev; /* device (VCHR, VBLK) */
caddr_t v_data; /* private data for fs */
struct filock *v_filocks; /* ptr to filock list */
kcondvar_t v_cv; /* synchronize locking */
} vnode_t;
The vnode's reference count allows the operating system to discard the object when the last process to access it finally closes the file.
UNIX man - fs(5), inode(5) - format of file system volume
vnode(9) - internal representation of a file or directory
both found at FreeBSD man support pages,
http://www.gsp.com/support/man/
1copied shamelessly from http://www1.cs.columbia.edu/~ezk/research/tp/node80.html