* papers to read https://www.fsl.cs.stonybrook.edu/docs/linux-stacking/linux.pdf https://www.fsl.cs.stonybrook.edu/docs/sipek-ols2007/sipek.pdf Important: read above 2 papers, esp. note the figures. Wrapfs has its own f/s objects Wrapfs: F -> D -> I And the "lower" f/s (eg ext3) also has its own objects: Ext3: F -> D -> I But wrapfs 'stacks' on top of another f/s, or the other f/s F/D/I/etc. objects. Wrapfs: F -> D -> I (called the "upper" f/s) | | | Ext3: F -> D -> I (called the "lower" f/s) Thus, the lower objects have a refcount of +1 b/c wrapfs also adds a link/ptr to those objects. Wrapfs has to manage the refcounts. * wrapfs code in wrapfs-5.15/fs/wrapfs/ Start with wrapfs.h In VFS, functions named getXXX and putXXX, are usually ones that increase and decrease a refcnt on object XXX, respectively. The purpose for "grabbing" a refcount (meaning increasing it by 1 is to ensure that no one else working in parallel is trying to decrease the object's RC by 1, and then try to free it. In wrapfs, there are two kinds of functions: 1. Those that do not create new objects. For every arg passed by the VFS, we find its lower f/s equivalent, then call a vfs utility fxn like vfs_XXX. Then do usual err handling, and synchronizing meta-data (e.g., timestamps, sizes, etc.). 2. Methods that create new objects, like wrapfs_create. Here, we do the same stuff as #1, but in addition, upon success, the lower f/s will return to us a NEW object (dentry, inode, etc.). We need to "stack" on it. Consider wrapfs_create, before we called the lower f/s, we have: Wrapfs: Parent dentry PD, has an inode PI, so PD->PI Lower: Parent dentry PD' has an inode PI', so PD' -> PI' and also PD->PD', and PI->PI' However, when calling wrapfs_create, the named dentry is negative: the dentry has a NULL inode, b/c that inode doesn't yet exist (otherwise, the VFS would not have even called wrapfs_create). So all we have is Wrapfs: D -> NULL inode | Lower: D' -> NULL inode After successfully calling vfs_create() on the LOWER dir inode + lower D', upon return, the lower f/s will make D' a positive dentry: Wrapfs: D -> NULL inode | Lower: D' -> I' So the lower f/s took care of its own D+I, and we (wrapfs) have to take care of our own D+I. We have to create a wrapfs-level inode *and* link it with our own dentry *and* the lower I', and also correctly set refcnts, so the finale structure should look like: Wrapfs: D -> I | | Lower: D' -> I' The wrapfs utility fxn wrapfs_interpose is what allocates I, turns D into positive, and links I -> I'. wrapfs_setattr. In VFS, ->setattr is a single method to handle chmod, chown, chgrp, and utimes -- changing stat(2) data. All "xattr" methods are for handling extended attributes (EAs). Note that ACLs are structured about EAs. In wrapfs/inode.c, we have different inode_operations vectors. That's b/c it's easier to set JUST the right methods on different inodes: directories, symlinks, and all others. For example, for symlinks, we set the inode vector to support only methods that make sense for symlinks. Other methods, like "link" or "create" don't make sense for symlinks. So those methods are left blank (NULL). If you call an invalid syscall on a symlink, the Linux VFS would notice that the method is NULL, and will simply return EINVAL to the user, and won't even bother invoking the f/s.