Fix inability to destroy snapshot used over NFS

The cache of struct svc_export and struct svc_expkey by nfsd and
rpc.mountd for the snapshot holds references to the mount point.
We need to flush them out before unmounting, otherwise umount
would fail with EBUSY.

Reviewed-by: Don Brady <don.brady@delphix.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Youzhong Yang <yyang@mathworks.com>
Closes #6000 
Closes #10783
This commit is contained in:
youzhongyang 2020-08-24 20:33:02 -04:00 committed by GitHub
parent 184df27eef
commit b900799768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -31,6 +31,7 @@
* Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
* Copyright (c) 2018 George Melikov. All Rights Reserved. * Copyright (c) 2018 George Melikov. All Rights Reserved.
* Copyright (c) 2019 Datto, Inc. All rights reserved. * Copyright (c) 2019 Datto, Inc. All rights reserved.
* Copyright (c) 2020 The MathWorks, Inc. All rights reserved.
*/ */
/* /*
@ -977,6 +978,22 @@ out:
return (error); return (error);
} }
/*
* Flush everything out of the kernel's export table and such.
* This is needed as once the snapshot is used over NFS, its
* entries in svc_export and svc_expkey caches hold reference
* to the snapshot mount point. There is no known way of flushing
* only the entries related to the snapshot.
*/
static void
exportfs_flush(void)
{
char *argv[] = { "/usr/sbin/exportfs", "-f", NULL };
char *envp[] = { NULL };
(void) call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
}
/* /*
* Attempt to unmount a snapshot by making a call to user space. * Attempt to unmount a snapshot by making a call to user space.
* There is no assurance that this can or will succeed, is just a * There is no assurance that this can or will succeed, is just a
@ -999,6 +1016,8 @@ zfsctl_snapshot_unmount(char *snapname, int flags)
} }
rw_exit(&zfs_snapshot_lock); rw_exit(&zfs_snapshot_lock);
exportfs_flush();
if (flags & MNT_FORCE) if (flags & MNT_FORCE)
argv[4] = "-fn"; argv[4] = "-fn";
argv[5] = se->se_path; argv[5] = se->se_path;