/* * Attempt to expire an automounted snapshot, unmounts are attempted every * 'zfs_expire_snapshot' seconds until they succeed. The work request is * responsible for rescheduling itself and freeing the zfs_expire_snapshot_t. */ static void zfsctl_expire_snapshot(void *data) { zfs_snapentry_t *sep = (zfs_snapentry_t *)data; zfs_sb_t *zsb = ITOZSB(sep->se_inode); int error; error = zfsctl_unmount_snapshot(zsb, sep->se_name, MNT_EXPIRE); if (error == EBUSY) sep->se_taskqid = taskq_dispatch_delay(zfs_expire_taskq, zfsctl_expire_snapshot, sep, TQ_SLEEP, ddi_get_lbolt() + zfs_expire_snapshot * HZ); }
/* * Attempt to expire an automounted snapshot, unmounts are attempted every * 'zfs_expire_snapshot' seconds until they succeed. The work request is * responsible for rescheduling itself and freeing the zfs_expire_snapshot_t. */ static void zfsctl_expire_snapshot(void *data) { zfs_snapentry_t *sep; zfs_sb_t *zsb; int error; sep = spl_get_work_data(data, zfs_snapentry_t, se_work.work); zsb = ITOZSB(sep->se_inode); error = zfsctl_unmount_snapshot(zsb, sep->se_name, MNT_EXPIRE); if (error == EBUSY) schedule_delayed_work(&sep->se_work, zfs_expire_snapshot * HZ); }
/* ARGSUSED */ int zfsctl_snapdir_remove(struct inode *dip, char *name, cred_t *cr, int flags) { zfs_sb_t *zsb = ITOZSB(dip); char *snapname, *real; int error; ZFS_ENTER(zsb); snapname = kmem_alloc(MAXNAMELEN, KM_SLEEP); real = kmem_alloc(MAXNAMELEN, KM_SLEEP); if (zsb->z_case == ZFS_CASE_INSENSITIVE) { error = dmu_snapshot_realname(zsb->z_os, name, real, MAXNAMELEN, NULL); if (error == 0) { name = real; } else if (error != ENOTSUP) { goto out; } } error = zfsctl_snapshot_zname(dip, name, MAXNAMELEN, snapname); if (!error) error = zfs_secpolicy_destroy_perms(snapname, cr); if (error) goto out; error = zfsctl_unmount_snapshot(zsb, name, MNT_FORCE); if ((error == 0) || (error == ENOENT)) error = dmu_objset_destroy(snapname, B_FALSE); out: kmem_free(snapname, MAXNAMELEN); kmem_free(real, MAXNAMELEN); ZFS_EXIT(zsb); return (error); }