diff options
author | George Melikov <[email protected]> | 2017-01-27 22:46:39 +0300 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2017-01-27 11:46:39 -0800 |
commit | a08abc1bb3e354d8c352c91d22cc733a84fafb50 (patch) | |
tree | 5ae2e2dff6f9ee2c2927aabf03a064bb8e6e4fd2 | |
parent | cc9bb3e58e926d4e056a89046301c1349755957b (diff) |
OpenZFS 7301 - zpool export -f should be able to interrupt file freeing
Authored by: Alek Pinchuk <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: Sanjay Nadkarni <[email protected]>
Reviewed by: Saso Kiselkov <[email protected]>
Reviewed by: John Kennedy <[email protected]>
Approved by: Gordon Ross <[email protected]>
Reviewed-by: Tim Chase <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Ported-by: George Melikov <[email protected]>
OpenZFS-issue: https://www.illumos.org/issues/7301
OpenZFS-commit: https://github.com/openzfs/openzfs/commit/eb72182
Closes #5680
-rw-r--r-- | include/sys/zfs_znode.h | 2 | ||||
-rw-r--r-- | module/zfs/dmu.c | 21 | ||||
-rw-r--r-- | module/zfs/zfs_dir.c | 4 | ||||
-rw-r--r-- | module/zfs/zfs_vfsops.c | 26 |
4 files changed, 48 insertions, 5 deletions
diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h index 8be7283a7..a5ecb2842 100644 --- a/include/sys/zfs_znode.h +++ b/include/sys/zfs_znode.h @@ -21,6 +21,7 @@ /* * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2015 by Delphix. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SYS_FS_ZFS_ZNODE_H @@ -311,6 +312,7 @@ extern int zfs_sync(struct super_block *, int, cred_t *); extern dev_t zfs_cmpldev(uint64_t); extern int zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value); extern int zfs_get_stats(objset_t *os, nvlist_t *nv); +extern boolean_t zfs_get_vfs_flag_unmounted(objset_t *os); extern void zfs_znode_dmu_fini(znode_t *); extern int zfs_inode_alloc(struct super_block *, struct inode **ip); extern void zfs_inode_destroy(struct inode *); diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 30c3b2cd0..cdbcfe250 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -23,7 +23,7 @@ * Copyright (c) 2011, 2016 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. - * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2016, Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2015 by Chunwei Chen. All rights reserved. */ @@ -705,6 +705,22 @@ get_next_chunk(dnode_t *dn, uint64_t *start, uint64_t minimum) return (0); } +/* + * If this objset is of type OST_ZFS return true if vfs's unmounted flag is set, + * otherwise return false. + * Used below in dmu_free_long_range_impl() to enable abort when unmounting + */ +/*ARGSUSED*/ +static boolean_t +dmu_objset_zfs_unmounting(objset_t *os) +{ +#ifdef _KERNEL + if (dmu_objset_type(os) == DMU_OST_ZFS) + return (zfs_get_vfs_flag_unmounted(os)); +#endif + return (B_FALSE); +} + static int dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset, uint64_t length) @@ -726,6 +742,9 @@ dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset, uint64_t chunk_end, chunk_begin; dmu_tx_t *tx; + if (dmu_objset_zfs_unmounting(dn->dn_objset)) + return (SET_ERROR(EINTR)); + chunk_end = chunk_begin = offset + length; /* move chunk_begin backwards to the beginning of this chunk */ diff --git a/module/zfs/zfs_dir.c b/module/zfs/zfs_dir.c index b66a9b364..22e64d393 100644 --- a/module/zfs/zfs_dir.c +++ b/module/zfs/zfs_dir.c @@ -644,8 +644,8 @@ zfs_rmnode(znode_t *zp) error = dmu_free_long_range(os, zp->z_id, 0, DMU_OBJECT_END); if (error) { /* - * Not enough space. Leave the file in the unlinked - * set. + * Not enough space or we were interrupted by unmount. + * Leave the file in the unlinked set. */ zfs_znode_dmu_fini(zp); return; diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c index 20ff165d9..85c275822 100644 --- a/module/zfs/zfs_vfsops.c +++ b/module/zfs/zfs_vfsops.c @@ -1263,7 +1263,7 @@ EXPORT_SYMBOL(zfs_sb_prune); /* * Teardown the zfs_sb_t. * - * Note, if 'unmounting' if FALSE, we return with the 'z_teardown_lock' + * Note, if 'unmounting' is FALSE, we return with the 'z_teardown_lock' * and 'z_teardown_inactive_lock' held. */ int @@ -1358,8 +1358,8 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting) */ if (unmounting) { zsb->z_unmounted = B_TRUE; - rrm_exit(&zsb->z_teardown_lock, FTAG); rw_exit(&zsb->z_teardown_inactive_lock); + rrm_exit(&zsb->z_teardown_lock, FTAG); } /* @@ -1906,6 +1906,28 @@ zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value) } EXPORT_SYMBOL(zfs_get_zplprop); +/* + * Return true if the coresponding vfs's unmounted flag is set. + * Otherwise return false. + * If this function returns true we know VFS unmount has been initiated. + */ +boolean_t +zfs_get_vfs_flag_unmounted(objset_t *os) +{ + zfs_sb_t *zfvp; + boolean_t unmounted = B_FALSE; + + ASSERT(dmu_objset_type(os) == DMU_OST_ZFS); + + mutex_enter(&os->os_user_ptr_lock); + zfvp = dmu_objset_get_user(os); + if (zfvp != NULL && zfvp->z_unmounted) + unmounted = B_TRUE; + mutex_exit(&os->os_user_ptr_lock); + + return (unmounted); +} + void zfs_init(void) { |