Fix zfsctl_expire_snapshot() deadlock
[zfs.git] / module / zfs / zfs_ctldir.c
index b5c4510..168f853 100644 (file)
@@ -197,6 +197,7 @@ zfsctl_inode_alloc(zfs_sb_t *zsb, uint64_t id,
        zp->z_is_mapped = B_FALSE;
        zp->z_is_ctldir = B_TRUE;
        zp->z_is_sa = B_FALSE;
+       zp->z_is_stale = B_FALSE;
        ip->i_ino = id;
        ip->i_mode = (S_IFDIR | S_IRUGO | S_IXUGO);
        ip->i_uid = 0;
@@ -442,7 +443,7 @@ zfsctl_snapdir_lookup(struct inode *dip, char *name, struct inode **ipp,
 
        ZFS_ENTER(zsb);
 
-       error = dmu_snapshot_id(zsb->z_os, name, &id);
+       error = dmu_snapshot_lookup(zsb->z_os, name, &id);
        if (error) {
                ZFS_EXIT(zsb);
                return (error);
@@ -685,7 +686,7 @@ zfsctl_snapdir_inactive(struct inode *ip)
        "exec 0</dev/null " \
        "     1>/dev/null " \
        "     2>/dev/null; " \
-       "umount -t zfs -n '%s%s'"
+       "umount -t zfs -n %s'%s'"
 
 static int
 __zfsctl_unmount_snapshot(zfs_snapentry_t *sep, int flags)
@@ -731,7 +732,11 @@ zfsctl_unmount_snapshot(zfs_sb_t *zsb, char *name, int flags)
        sep = avl_find(&zsb->z_ctldir_snaps, &search, NULL);
        if (sep) {
                avl_remove(&zsb->z_ctldir_snaps, sep);
+               mutex_exit(&zsb->z_ctldir_lock);
+
                error = __zfsctl_unmount_snapshot(sep, flags);
+
+               mutex_enter(&zsb->z_ctldir_lock);
                if (error == EBUSY)
                        avl_add(&zsb->z_ctldir_snaps, sep);
                else
@@ -766,7 +771,11 @@ zfsctl_unmount_snapshots(zfs_sb_t *zsb, int flags, int *count)
        while (sep != NULL) {
                next = AVL_NEXT(&zsb->z_ctldir_snaps, sep);
                avl_remove(&zsb->z_ctldir_snaps, sep);
+               mutex_exit(&zsb->z_ctldir_lock);
+
                error = __zfsctl_unmount_snapshot(sep, flags);
+
+               mutex_enter(&zsb->z_ctldir_lock);
                if (error == EBUSY) {
                        avl_add(&zsb->z_ctldir_snaps, sep);
                        (*count)++;
@@ -908,7 +917,7 @@ zfsctl_lookup_objset(struct super_block *sb, uint64_t objsetid, zfs_sb_t **zsbp)
         */
        sep = avl_first(&zsb->z_ctldir_snaps);
        while (sep != NULL) {
-               error = dmu_snapshot_id(zsb->z_os, sep->se_name, &id);
+               error = dmu_snapshot_lookup(zsb->z_os, sep->se_name, &id);
                if (error)
                        goto out;