Add .zfs control directory
[zfs.git] / module / zfs / zpl_inode.c
index 9b55337..d9b918b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <sys/zfs_vfsops.h>
 #include <sys/zfs_vnops.h>
+#include <sys/zfs_znode.h>
 #include <sys/vfs.h>
 #include <sys/zpl.h>
 
@@ -51,7 +52,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
        return d_splice_alias(ip, dentry);
 }
 
-static void
+void
 zpl_vap_init(vattr_t *vap, struct inode *dir, struct dentry *dentry,
     mode_t mode, cred_t *cr)
 {
@@ -171,8 +172,20 @@ zpl_rmdir(struct inode * dir, struct dentry *dentry)
 static int
 zpl_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
+       boolean_t issnap = ITOZSB(dentry->d_inode)->z_issnap;
        int error;
 
+       /*
+        * Ensure MNT_SHRINKABLE is set on snapshots to ensure they are
+        * unmounted automatically with the parent file system.  This
+        * is done on the first getattr because it's not easy to get the
+        * vfsmount structure at mount time.  This call path is explicitly
+        * marked unlikely to avoid any performance impact.  FWIW, ext4
+        * resorts to a similar trick for sysadmin convenience.
+        */
+       if (unlikely(issnap && !(mnt->mnt_flags & MNT_SHRINKABLE)))
+               mnt->mnt_flags |= MNT_SHRINKABLE;
+
        error = -zfs_getattr_fast(dentry->d_inode, stat);
        ASSERT3S(error, <=, 0);