Writing Filesystems - Opening/Closing files
From Genunix
| This article has been identified as a draft. It is currently undergoing a community review. Please add your comments to the discussion page.
Do not quote any text on this page! It is still a draft! |
Unlike character/block device drivers, where the open(9e) entry point is responsible for setting up a new "connection" to the device, vnodes are already accessible at the time VOP_OPEN() is called - they have been created by VFS_VGET(), usually as a consequence of a filename lookup via VOP_LOOKUP(). See Livecycle of a vnode for details on that.
So what is the task of VOP_OPEN() then ? Well - simple: To succeed. Most filesystems will get away having just a routine like this:
/* ARGSUSED */
static int
fat_open(struct vnode **vpp, int flag, struct cred *cr)
{
return (0);
}
Don't you believe it ? Well, if not, check zfs_open(), ufs_open(), hsfs_open(), or pcfs_open(). It's indeed somewhat surprising that the fs_subr.c "glue code" does not provide a function fs_open() which would be the default if a filesystem wouldn't register a vnode op for VOP_OPEN().
Who needs a nontrivial VOP_OPEN() ? Only implementations that need to keep more complex state for an "open file" than the framework guaranteeing existance of a vnode for it. NFS is the prime example of that in OpenSolaris, see nfs3_open() and nfs4_open(), but lofs, cachefs or autofs also do have a non-empty routine there.
Now since VOP_OPEN() is so simple, it's not surprising that VOP_CLOSE() is trivial as well:
/* ARGSUSED1 */
static int
fat_close(struct vnode *vp, int flag, int count, offset_t offset,
struct cred *cr)
{
/*
* dump locking state still associated with this process/file.
*/
cleanlocks(vp, ddi_get_pid(), 0);
cleanshares(vp, ddi_get_pid());
return (0);
}
Not completely empty but simple enough - it dumps advisory/mandatory file locks and shares (as set on the file via fcntl(2) calls of F_SETLK of F_SHARE type). Again, only filesystems like NFS need to perform more complicated cleanup here.
You can also see another characteristic difference between filesystem drivers' VOP_OPEN()/VOP_CLOSE() and character/block device drivers' open(9e) and close(9e) entry points. VOP_OPEN()/VOP_CLOSE() is strictly paired, i.e. there'll be one VOP_CLOSE() for every call to VOP_OPEN(), while for character/block drivers, close(9e) is only called on the last close of the device, after a possibly-long sequence of calls to this driver's open(9e).
