From 1b87e0f53249a17f2fbb1d5ca725e65add391ace Mon Sep 17 00:00:00 2001 From: Roman Strashkin Date: Tue, 12 Jul 2016 20:53:53 +0300 Subject: [PATCH] Fix filesystem destroy with receive_resume_token It is possible that the given DS may have hidden child (%recv) datasets - "leftovers" resulting from the previously interrupted 'zfs receieve'. Try to remove the hidden child (%recv) and after that try to remove the target dataset. If the hidden child (%recv) does not exist the original error (EEXIST) will be returned. Signed-off-by: Roman Strashkin Signed-off-by: Brian Behlendorf Closes #4818 --- module/zfs/zfs_ioctl.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 37104fb9f..3cd3628ce 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -25,7 +25,7 @@ * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved. * Portions Copyright 2012 Pawel Jakub Dawidek * Copyright (c) 2012, Joyent, Inc. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright (c) 2011, 2015 by Delphix. All rights reserved. * Copyright (c) 2013 by Saso Kiselkov. All rights reserved. @@ -3568,10 +3568,37 @@ zfs_ioc_destroy(zfs_cmd_t *zc) return (err); } - if (strchr(zc->zc_name, '@')) + if (strchr(zc->zc_name, '@')) { err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy); - else + } else { err = dsl_destroy_head(zc->zc_name); + if (err == EEXIST) { + /* + * It is possible that the given DS may have + * hidden child (%recv) datasets - "leftovers" + * resulting from the previously interrupted + * 'zfs receive'. + * + * 6 extra bytes for /%recv + */ + char namebuf[ZFS_MAX_DATASET_NAME_LEN + 6]; + + (void) snprintf(namebuf, sizeof (namebuf), + "%s/%s", zc->zc_name, recv_clone_name); + + /* + * Try to remove the hidden child (%recv) and after + * that try to remove the target dataset. + * If the hidden child (%recv) does not exist + * the original error (EEXIST) will be returned + */ + err = dsl_destroy_head(namebuf); + if (err == 0) + err = dsl_destroy_head(zc->zc_name); + else if (err == ENOENT) + err = EEXIST; + } + } return (err); }