kern/157728: [zfs] zfs (v28) incremental receive may leave behind temporary clones

Borja Marcos borjam at sarenet.es
Thu Aug 4 11:00:26 UTC 2011


The following reply was made to PR kern/157728; it has been noted by GNATS.

From: Borja Marcos <borjam at sarenet.es>
To: bug-followup at FreeBSD.org,
 mm at FreeBSD.org
Cc:  
Subject: Re: kern/157728: [zfs] zfs (v28) incremental receive may leave behind temporary clones
Date: Thu, 4 Aug 2011 12:39:58 +0200

 I have a clue. I've tried a partial fix and so far seems to work. Now I =
 have a loop doing zfs sends of a dataset with a make buildworld  =
 running, each 30 seconds, and receiving them onto a different pool, on =
 which I have a while ( 1 ) ; zfs list ; end loop running.
 
 So far I haven't had issues. The only side effect is that temporary =
 datasets can appear in the zfs list output.=20
 
 Read below for the explanation.
 
 After reading Martin's analysis, seemed quite clear to me that the =
 scenario was due to the necessity of getting a consistent snapshot of =
 the state of a complex data structure. In this case, I imagined that the =
 "list" service would traverse the data structures holding the datasets =
 descriptions, and that it would place temporary locks on the elements in =
 order to prevent them from being altered while the structure is being =
 traversed.
 
 So, a generic "list" service in a fine-grained locking environment and =
 rendering a consistent response would be something like that:
 
 - traverse data structure, building a list.
   (each time we get an element, a temporary lock is placed on it)
 - get next element, etc.
 
 - With the complete and consistent list ready, prepare the response.
 
 - Once the response has been built, traverse the grabbed results and =
 release the locks.
 
 
 So, where's the problem? In the special treatment of the "hidden" =
 datasets.
 
 Looking at =
 /usr/src/sys/cddl/contrib/opensolaris/common/fs/zfs/zfs_ioctl.c, at the =
 function zfs_ioc_dataset_list_next(zfs_cmd_t *zc)
 
 I see something resembling this idea:
 
 while (error =3D=3D 0 && dataset_name_hidden(zc->zc_name) &&
             !(zc->zc_iflags & FKIOCTL));
         dmu_objset_rele(os, FTAG);
 
 So, wondering if the problem is this, giving a special treatment to the =
 hidden dataset, I've edited the dataset_name_hidden() function so that =
 it ignores the "%" datasets.
 
 boolean_t
 dataset_name_hidden(const char *name)
 {
         /*
          * Skip over datasets that are not visible in this zone,
          * internal datasets (which have a $ in their name), and
          * temporary datasets (which have a % in their name).
          */
         if (strchr(name, '$') !=3D NULL)
                 return (B_TRUE);
 /*      if (strchr(name, '%') !=3D NULL)
                 return (B_TRUE); */
         if (!INGLOBALZONE(curthread) && !zone_dataset_visible(name, =
 NULL))
                 return (B_TRUE);
         return (B_FALSE);
 }
                =20
 
 I was expecting just a side-effect: a "zfs list" would list the =
 "%"datasets.
 
 Done this, I've compiled the kernel, started the test again, and, voila! =
 it works.
 
 Of course, now I see the "%" datasets while the zfs receive is running,
 
 pruebazfs3# zfs list -t all
 NAME                            USED  AVAIL  REFER  MOUNTPOINT
 rpool                          1.22G  6.61G  41.3K  /rpool
 rpool/newsrc                   1.22G  6.61G   565M  /rpool/newsrc
 rpool/newsrc at anteshidden        149M      -   973M  -
 rpool/newsrc at parcheteoria1     1.09M      -   973M  -
 rpool/newsrc at 20110804_113700       0      -   565M  -
 rpool/newsrc/%20110804_113730  1.31M  6.61G   566M  =
 /rpool/newsrc/%20110804_113730
 
 
 but after zfs receive finishes they are correctly cleaned up
 
 NAME                           USED  AVAIL  REFER  MOUNTPOINT
 rpool                         1.22G  6.61G  41.3K  /rpool
 rpool/newsrc                  1.22G  6.61G   566M  /rpool/newsrc
 rpool/newsrc at anteshidden       149M      -   973M  -
 rpool/newsrc at parcheteoria1    1.09M      -   973M  -
 rpool/newsrc at 20110804_113730      0      -   566M  -
 
 
 So: Seems to me that these datasets are a sort of afterthought. The =
 ioctl "list" service should not discard them when building the dataset =
 list. Instead it should not "print" them, so to speak.
 
 I'm sure this temporary fix can be refined, and I'm wondering if a =
 similar issue is lurking somewhere else....
 
 
 
 
 
 
 Borja.
 
 


More information about the freebsd-fs mailing list