]> granicus.if.org Git - zfs/commitdiff
Use spa as key besides objsetid for snapentry
authorChunwei Chen <david.chen@osnexus.com>
Mon, 7 Dec 2015 23:43:53 +0000 (15:43 -0800)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Wed, 9 Dec 2015 00:38:56 +0000 (16:38 -0800)
objsetid is not unique across pool, so using it solely as key would cause
panic when automounting two snapshot on different pools with the same
objsetid. We fix this by adding spa pointer as additional key.

Signed-off-by: Chunwei Chen <david.chen@osnexus.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Richard Yao <ryao@gentoo.org>
Issue #3948
Issue #3786
Issue #3887

include/sys/zfs_ctldir.h
module/zfs/zfs_ctldir.c
module/zfs/zpl_inode.c

index 960a9a6291463706cbd41fe15107926c703c3577..65c44f3cca549017bd8d7ba591915810189189a8 100644 (file)
@@ -77,7 +77,8 @@ extern int zfsctl_snapdir_mkdir(struct inode *dip, char *dirname, vattr_t *vap,
 extern void zfsctl_snapdir_inactive(struct inode *ip);
 extern int zfsctl_snapshot_mount(struct path *path, int flags);
 extern int zfsctl_snapshot_unmount(char *snapname, int flags);
-extern int zfsctl_snapshot_unmount_delay(uint64_t objsetid, int delay);
+extern int zfsctl_snapshot_unmount_delay(spa_t *spa, uint64_t objsetid,
+    int delay);
 extern int zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid,
     zfs_sb_t **zsb);
 
index 745a467b708fea9ac6fefc745b62b047a045aa19..b03c4e5d027354d537d476fe1a6357e1d4b97291 100644 (file)
@@ -81,6 +81,7 @@
 #include <sys/zfs_vnops.h>
 #include <sys/stat.h>
 #include <sys/dmu.h>
+#include <sys/dmu_objset.h>
 #include <sys/dsl_destroy.h>
 #include <sys/dsl_deleg.h>
 #include <sys/mount.h>
@@ -117,6 +118,7 @@ static taskq_t *zfs_expire_taskq;
 typedef struct {
        char            *se_name;       /* full snapshot name */
        char            *se_path;       /* full mount path */
+       spa_t           *se_spa;        /* pool spa */
        uint64_t        se_objsetid;    /* snapshot objset id */
        struct dentry   *se_root_dentry; /* snapshot root dentry */
        taskqid_t       se_taskqid;     /* scheduled unmount taskqid */
@@ -132,8 +134,8 @@ static void zfsctl_snapshot_unmount_delay_impl(zfs_snapentry_t *se, int delay);
  * the snapshot name and provided mount point.  No reference is taken.
  */
 static zfs_snapentry_t *
-zfsctl_snapshot_alloc(char *full_name, char *full_path, uint64_t objsetid,
-    struct dentry *root_dentry)
+zfsctl_snapshot_alloc(char *full_name, char *full_path, spa_t *spa,
+    uint64_t objsetid, struct dentry *root_dentry)
 {
        zfs_snapentry_t *se;
 
@@ -141,6 +143,7 @@ zfsctl_snapshot_alloc(char *full_name, char *full_path, uint64_t objsetid,
 
        se->se_name = strdup(full_name);
        se->se_path = strdup(full_path);
+       se->se_spa = spa;
        se->se_objsetid = objsetid;
        se->se_root_dentry = root_dentry;
        se->se_taskqid = -1;
@@ -242,6 +245,9 @@ snapentry_compare_by_objsetid(const void *a, const void *b)
        const zfs_snapentry_t *se_a = a;
        const zfs_snapentry_t *se_b = b;
 
+       if (se_a->se_spa != se_b->se_spa)
+               return ((ulong_t)se_a->se_spa < (ulong_t)se_b->se_spa ? -1 : 1);
+
        if (se_a->se_objsetid < se_b->se_objsetid)
                return (-1);
        else if (se_a->se_objsetid > se_b->se_objsetid)
@@ -278,12 +284,13 @@ zfsctl_snapshot_find_by_name(char *snapname)
  * as zfsctl_snapshot_find_by_name().
  */
 static zfs_snapentry_t *
-zfsctl_snapshot_find_by_objsetid(uint64_t objsetid)
+zfsctl_snapshot_find_by_objsetid(spa_t *spa, uint64_t objsetid)
 {
        zfs_snapentry_t *se, search;
 
        ASSERT(MUTEX_HELD(&zfs_snapshot_lock));
 
+       search.se_spa = spa;
        search.se_objsetid = objsetid;
        se = avl_find(&zfs_snapshots_by_objsetid, &search, NULL);
        if (se)
@@ -323,6 +330,7 @@ static void
 snapentry_expire(void *data)
 {
        zfs_snapentry_t *se = (zfs_snapentry_t *)data;
+       spa_t *spa = se->se_spa;
        uint64_t objsetid = se->se_objsetid;
 
        se->se_taskqid = -1;
@@ -334,7 +342,7 @@ snapentry_expire(void *data)
         * This can occur when the snapshot is busy.
         */
        mutex_enter(&zfs_snapshot_lock);
-       if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
+       if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
                zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
                zfsctl_snapshot_rele(se);
        }
@@ -377,13 +385,13 @@ zfsctl_snapshot_unmount_delay_impl(zfs_snapentry_t *se, int delay)
  * and held until the outstanding task is handled or cancelled.
  */
 int
-zfsctl_snapshot_unmount_delay(uint64_t objsetid, int delay)
+zfsctl_snapshot_unmount_delay(spa_t *spa, uint64_t objsetid, int delay)
 {
        zfs_snapentry_t *se;
        int error = ENOENT;
 
        mutex_enter(&zfs_snapshot_lock);
-       if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
+       if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
                zfsctl_snapshot_unmount_cancel(se);
                zfsctl_snapshot_unmount_delay_impl(se, delay);
                zfsctl_snapshot_rele(se);
@@ -560,10 +568,12 @@ zfsctl_destroy(zfs_sb_t *zsb)
 {
        if (zsb->z_issnap) {
                zfs_snapentry_t *se;
+               spa_t *spa = zsb->z_os->os_spa;
                uint64_t objsetid = dmu_objset_id(zsb->z_os);
 
                mutex_enter(&zfs_snapshot_lock);
-               if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
+               if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid))
+                   != NULL) {
                        zfsctl_snapshot_unmount_cancel(se);
                        zfsctl_snapshot_remove(se);
                        zfsctl_snapshot_rele(se);
@@ -1129,7 +1139,8 @@ zfsctl_snapshot_mount(struct path *path, int flags)
 
                mutex_enter(&zfs_snapshot_lock);
                se = zfsctl_snapshot_alloc(full_name, full_path,
-                   dmu_objset_id(snap_zsb->z_os), dentry);
+                   snap_zsb->z_os->os_spa, dmu_objset_id(snap_zsb->z_os),
+                   dentry);
                zfsctl_snapshot_add(se);
                zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
                mutex_exit(&zfs_snapshot_lock);
@@ -1152,6 +1163,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
 {
        zfs_snapentry_t *se;
        int error;
+       spa_t *spa = ((zfs_sb_t *)(sb->s_fs_info))->z_os->os_spa;
 
        /*
         * Verify that the snapshot is mounted then lookup the mounted root
@@ -1161,7 +1173,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
         * because we hold the zfs_snapshot_lock to prevent the race.
         */
        mutex_enter(&zfs_snapshot_lock);
-       if ((se = zfsctl_snapshot_find_by_objsetid(objsetid)) != NULL) {
+       if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) != NULL) {
                zfs_sb_t *zsb;
 
                zsb = ITOZSB(se->se_root_dentry->d_inode);
@@ -1170,7 +1182,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
                if (time_after(jiffies, zsb->z_snap_defer_time +
                    MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
                        zsb->z_snap_defer_time = jiffies;
-                       zfsctl_snapshot_unmount_delay(objsetid,
+                       zfsctl_snapshot_unmount_delay(spa, objsetid,
                            zfs_expire_snapshot);
                }
 
index 6475c72d710b19c9ff95f59d3369bc65a9824467..e0e8ee3ac58304efd0f013a8d4c180d12d6a0e63 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/zfs_vfsops.h>
 #include <sys/zfs_vnops.h>
 #include <sys/zfs_znode.h>
+#include <sys/dmu_objset.h>
 #include <sys/vfs.h>
 #include <sys/zpl.h>
 
@@ -500,7 +501,7 @@ zpl_revalidate(struct dentry *dentry, unsigned int flags)
                if (time_after(jiffies, zsb->z_snap_defer_time +
                    MAX(zfs_expire_snapshot * HZ / 2, HZ))) {
                        zsb->z_snap_defer_time = jiffies;
-                       zfsctl_snapshot_unmount_delay(
+                       zfsctl_snapshot_unmount_delay(zsb->z_os->os_spa,
                            dmu_objset_id(zsb->z_os), zfs_expire_snapshot);
                }
        }