Project

General

Profile

Bug #1346

zfs incremental receive may leave behind temporary clones

Added by Martin Matuška about 8 years ago. Updated almost 8 years ago.

Status:
Resolved
Priority:
Normal
Category:
zfs - Zettabyte File System
Start date:
2011-08-07
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
needs-triage

Description

When doing incremental zfs receive, zfs may leave behind temporary clones.
The attempt to destroy the temporary clone is in dmu_send.c, dmu_recv_existing_end():

out:
    mutex_exit(&ds->ds_recvlock);
    if (err == 0 && drc->drc_guid_to_ds_map != NULL)
        (void) add_ds_to_guidmap(drc->drc_guid_to_ds_map, ds);
    dsl_dataset_disown(ds, dmu_recv_tag);
    (void) dsl_dataset_destroy(drc->drc_real_ds, dmu_recv_tag, B_FALSE);
    return (err);

As you can see, return code of dsl_dataset_destroy() is not verified.
If you run at the same time a direct (on the temporary clone) or recursive "zfs list" or "zfs get", this places an additional hold on the temporary clone during prefetch in zfs_ioctl.c, zfs_ioc_dataset_list_next().

    /*
     * Pre-fetch the datasets.  dmu_objset_prefetch() always returns 0
     * but is not declared void because its called by dmu_objset_find().
     */
    if (zc->zc_cookie == 0) {
        uint64_t cookie = 0;
        int len = sizeof (zc->zc_name) - (p - zc->zc_name);

        while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0)
            (void) dmu_objset_prefetch(p, NULL);
    }

The additional hold causes dsl_dataset_destroy() to return EBUSY and the temporary clone is not deleted.
This error is quite hard to trigger on Illumos (or Solaris), because to correctly prefetch, dmu_objset_prefetch() should be called with the entire dataset name (zc->zc_name) (fix by Pawel Jakub Dawidek).

The following patch fixes the prefetch code and doesn't prefetch hidden datasets.

diff -r a4e1558c0599 usr/src/uts/common/fs/zfs/zfs_ioctl.c
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c    Fri Jul 22 09:27:57 2011 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c    Sun Aug 07 13:22:18 2011 +0200
@@ -1944,7 +1944,8 @@ zfs_ioc_dataset_list_next()
         int len = sizeof (zc->zc_name) - (p - zc->zc_name);

         while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0)
-            (void) dmu_objset_prefetch(p, NULL);
+            if (dataset_name_hidden(zc->zc_name) == B_FALSE)
+                (void) dmu_objset_prefetch(zc->zc_name, NULL);
     }

     do {

Another solution to this problem would be rewriting dmu_recv_existing_end() to prevent the possible race (and still fix the prefetch code, too).


Files

zfs_ioctl.c.patch (619 Bytes) zfs_ioctl.c.patch Martin Matuška, 2011-08-18 01:03 PM

History

#1

Updated by Martin Matuška about 8 years ago

I have submitted a better solution for this problem in #1356. Please close.

#2

Updated by Martin Matuška about 8 years ago

We have finally used this patch in FreeBSD:

diff -r a4e1558c0599 usr/src/uts/common/fs/zfs/zfs_ioctl.c
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c    Fri Jul 22 09:27:57 2011 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c    Thu Aug 18 15:01:11 2011 +0200
@@ -1943,8 +1943,10 @@ zfs_ioc_dataset_list_next()
         uint64_t cookie = 0;
         int len = sizeof (zc->zc_name) - (p - zc->zc_name);

-        while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0)
-            (void) dmu_objset_prefetch(p, NULL);
+        while (dmu_dir_list_next(os, len, p, NULL, &cookie) == 0) {
+            if (!dataset_name_hidden(zc->zc_name))
+                (void) dmu_objset_prefetch(zc->zc_name, NULL);
+        }
     }

     do {

#3

Updated by Martin Matuška almost 8 years ago

To explain the link with this issue and issue #1356:
You have you fix the prefetch code to make this bug triggerable.
The prefetch code alone is fixed just by changing:

(void) dmu_objset_prefetch(p, NULL);
to
(void) dmu_objset_prefetch(zc->zc_name, NULL);

#4

Updated by Gordon Ross almost 8 years ago

  • Status changed from New to Resolved
  • Assignee set to Martin Matuška
changeset:   13492:83d135508f56
user:        Martin Matuska <mm@FreeBSD.org>
date:        Fri Oct 21 11:49:36 2011 -0400
description:
    1346 zfs incremental receive may leave behind temporary clones
    1356 zfs dataset prefetch code not working
    Reviewed by: Matthew Ahrens <matt@delphix.com>
    Reviewed by: Dan McDonald <danmcd@nexenta.com>
    Approved by: Gordon Ross <gwr@nexenta.com>

Also available in: Atom PDF