Re: [PATCH] Improve support for exporting btrfs subvolumes.

2010-06-23 Thread J. Bruce Fields
On Thu, Jun 17, 2010 at 02:54:01PM +1000, Neil Brown wrote:
 
 If you export two subvolumes of a btrfs filesystem, they will both be
 given the same uuid so lookups will be confused.
 blkid cannot differentiate the two, so we must use the fsid from
 statfs64 to identify the filesystem.
 
 We cannot tell if blkid or statfs is best without knowing internal
 details of the filesystem in question, so we need to encode specific
 knowledge of btrfs in mountd.  This is unfortunate.
 
 To ensure smooth handling of this and possible future changes in uuid
 generation, we add infrastructure for multiple different uuids to be
 recognised on old filehandles, but only the preferred on is used on
 new filehandles.

Could you just contatenate the two (or hash them somehow)?  Or does that
just use up too much space in the filehandle?

--b.

 
 Signed-off-by: NeilBrown ne...@suse.de
 
 --
 This is a substantially revised version of a patch I posted a while
 ago.
 I tried to find a way to do it would hard coding knowledge of btrfs in
 nfs-utils, but it isn't possible.  For some filesystems, f_fsid is
 best, for some it is worst.  No way to tell the difference.
 
 This patch add infrastructure so that if we find a better way to get a
 good uuid (e.g. a new syscall), we can slot it in for new filehandles,
 but old filehandles using the old uuid will still work.
 
 I believe this is ready for inclusion upstream.
 Thanks,
 NeilBrown
 
 
 diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
 index caef5b2..85cd829 100644
 --- a/utils/mountd/cache.c
 +++ b/utils/mountd/cache.c
 @@ -170,13 +170,16 @@ void auth_unix_gid(FILE *f)
  #if USE_BLKID
  static const char *get_uuid_blkdev(char *path)
  {
 + /* We set *safe if we know that we need the
 +  * fsid from statfs too.
 +  */
   static blkid_cache cache = NULL;
   struct stat stb;
   char *devname;
   blkid_tag_iterate iter;
   blkid_dev dev;
   const char *type;
 - const char *val = NULL;
 + const char *val, *uuid = NULL;
  
   if (cache == NULL)
   blkid_get_cache(cache, NULL);
 @@ -193,42 +196,29 @@ static const char *get_uuid_blkdev(char *path)
   iter = blkid_tag_iterate_begin(dev);
   if (!iter)
   return NULL;
 - while (blkid_tag_next(iter, type, val) == 0)
 + while (blkid_tag_next(iter, type, val) == 0) {
   if (strcmp(type, UUID) == 0)
 + uuid = val;
 + if (strcmp(type, TYPE) == 0 
 + strcmp(val, btrfs) == 0) {
 + uuid = NULL;
   break;
 + }
 + }
   blkid_tag_iterate_end(iter);
 - return val;
 + return uuid;
  }
  #else
  #define get_uuid_blkdev(path) (NULL)
  #endif
  
 -int get_uuid(char *path, char *uuid, int uuidlen, char *u)
 +int get_uuid(const char *val, int uuidlen, char *u)
  {
   /* extract hex digits from uuidstr and compose a uuid
* of the given length (max 16), xoring bytes to make
 -  * a smaller uuid.  Then compare with uuid
 +  * a smaller uuid.
*/
   int i = 0;
 - const char *val = NULL;
 - char fsid_val[17];
 -
 - if (path) {
 - val = get_uuid_blkdev(path);
 - if (!val) {
 - struct statfs64 st;
 -
 - if (statfs64(path, st))
 - return 0;
 - if (!st.f_fsid.__val[0]  !st.f_fsid.__val[1])
 - return 0;
 - snprintf(fsid_val, 17, %08x%08x,
 -  st.f_fsid.__val[0], st.f_fsid.__val[1]);
 - val = fsid_val;
 - }
 - } else {
 - val = uuid;
 - }
   
   memset(u, 0, uuidlen);
   for ( ; *val ; val++) {
 @@ -252,6 +242,60 @@ int get_uuid(char *path, char *uuid, int uuidlen, char 
 *u)
   return 1;
  }
  
 +int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
 +{
 + /* get a uuid for the filesystem found at 'path'.
 +  * There are several possible ways of generating the
 +  * uuids (types).
 +  * Type 0 is used for new filehandles, while other types
 +  * may be used to interpret old filehandle - to ensure smooth
 +  * forward migration.
 +  * We return 1 if a uuid was found (and it might be worth 
 +  * trying the next type) or 0 if no more uuid types can be
 +  * extracted.
 +  */
 +
 + /* Possible sources of uuid are
 +  * - blkid uuid
 +  * - statfs64 uuid
 +  *
 +  * On some filesystems (e.g. vfat) the statfs64 uuid is simply an
 +  * encoding of the device that the filesystem is mounted from, so
 +  * it we be very bad to use that (as device numbers change).  blkid
 +  * must be preferred.
 +  * On other filesystems (e.g. btrfs) the statfs64 uuid contains
 +  * important info that the blkid uuid cannot contain:  This happens
 +  * when multiple subvolumes are 

Re: [PATCH] Improve support for exporting btrfs subvolumes.

2010-06-23 Thread Neil Brown
On Wed, 23 Jun 2010 14:28:38 -0400
J. Bruce Fields bfie...@fieldses.org wrote:

 On Thu, Jun 17, 2010 at 02:54:01PM +1000, Neil Brown wrote:
  
  If you export two subvolumes of a btrfs filesystem, they will both be
  given the same uuid so lookups will be confused.
  blkid cannot differentiate the two, so we must use the fsid from
  statfs64 to identify the filesystem.
  
  We cannot tell if blkid or statfs is best without knowing internal
  details of the filesystem in question, so we need to encode specific
  knowledge of btrfs in mountd.  This is unfortunate.
  
  To ensure smooth handling of this and possible future changes in uuid
  generation, we add infrastructure for multiple different uuids to be
  recognised on old filehandles, but only the preferred on is used on
  new filehandles.
 
 Could you just contatenate the two (or hash them somehow)?  Or does that
 just use up too much space in the filehandle?

I did consider xoring them together but came to the conclusion that would
actually be a regression.
If you look down at the comment that I included in uuid_by_path, you will see
that some filesystems (e.g. VFAT) just use the major/minor device number for
the f_fsid from statfs.  As you know that is not necessarily stable over
reboots, while the UUID that blkid gives is.
So if we always adding the two uuids somehow, it would be an improvement for
btrfs, no change for e.g. ext3/XFS, and a regression for VFAT (and others I
think).  Not good.

Thanks,
NeilBrown


 
 --b.
 
  
  Signed-off-by: NeilBrown ne...@suse.de
  
  --
  This is a substantially revised version of a patch I posted a while
  ago.
  I tried to find a way to do it would hard coding knowledge of btrfs in
  nfs-utils, but it isn't possible.  For some filesystems, f_fsid is
  best, for some it is worst.  No way to tell the difference.
  
  This patch add infrastructure so that if we find a better way to get a
  good uuid (e.g. a new syscall), we can slot it in for new filehandles,
  but old filehandles using the old uuid will still work.
  
  I believe this is ready for inclusion upstream.
  Thanks,
  NeilBrown
  
  
  diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
  index caef5b2..85cd829 100644
  --- a/utils/mountd/cache.c
  +++ b/utils/mountd/cache.c
  @@ -170,13 +170,16 @@ void auth_unix_gid(FILE *f)
   #if USE_BLKID
   static const char *get_uuid_blkdev(char *path)
   {
  +   /* We set *safe if we know that we need the
  +* fsid from statfs too.
  +*/
  static blkid_cache cache = NULL;
  struct stat stb;
  char *devname;
  blkid_tag_iterate iter;
  blkid_dev dev;
  const char *type;
  -   const char *val = NULL;
  +   const char *val, *uuid = NULL;
   
  if (cache == NULL)
  blkid_get_cache(cache, NULL);
  @@ -193,42 +196,29 @@ static const char *get_uuid_blkdev(char *path)
  iter = blkid_tag_iterate_begin(dev);
  if (!iter)
  return NULL;
  -   while (blkid_tag_next(iter, type, val) == 0)
  +   while (blkid_tag_next(iter, type, val) == 0) {
  if (strcmp(type, UUID) == 0)
  +   uuid = val;
  +   if (strcmp(type, TYPE) == 0 
  +   strcmp(val, btrfs) == 0) {
  +   uuid = NULL;
  break;
  +   }
  +   }
  blkid_tag_iterate_end(iter);
  -   return val;
  +   return uuid;
   }
   #else
   #define get_uuid_blkdev(path) (NULL)
   #endif
   
  -int get_uuid(char *path, char *uuid, int uuidlen, char *u)
  +int get_uuid(const char *val, int uuidlen, char *u)
   {
  /* extract hex digits from uuidstr and compose a uuid
   * of the given length (max 16), xoring bytes to make
  -* a smaller uuid.  Then compare with uuid
  +* a smaller uuid.
   */
  int i = 0;
  -   const char *val = NULL;
  -   char fsid_val[17];
  -
  -   if (path) {
  -   val = get_uuid_blkdev(path);
  -   if (!val) {
  -   struct statfs64 st;
  -
  -   if (statfs64(path, st))
  -   return 0;
  -   if (!st.f_fsid.__val[0]  !st.f_fsid.__val[1])
  -   return 0;
  -   snprintf(fsid_val, 17, %08x%08x,
  -st.f_fsid.__val[0], st.f_fsid.__val[1]);
  -   val = fsid_val;
  -   }
  -   } else {
  -   val = uuid;
  -   }
  
  memset(u, 0, uuidlen);
  for ( ; *val ; val++) {
  @@ -252,6 +242,60 @@ int get_uuid(char *path, char *uuid, int uuidlen, char 
  *u)
  return 1;
   }
   
  +int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
  +{
  +   /* get a uuid for the filesystem found at 'path'.
  +* There are several possible ways of generating the
  +* uuids (types).
  +* Type 0 is used for new filehandles, while other types
  +* may be used to interpret old filehandle - to ensure smooth
  +* forward migration.
  +* We return 1 if a uuid was found (and it 

Re: [PATCH] Improve support for exporting btrfs subvolumes.

2010-06-23 Thread J. Bruce Fields
On Thu, Jun 24, 2010 at 07:31:57AM +1000, Neil Brown wrote:
 On Wed, 23 Jun 2010 14:28:38 -0400
 J. Bruce Fields bfie...@fieldses.org wrote:
 
  On Thu, Jun 17, 2010 at 02:54:01PM +1000, Neil Brown wrote:
   
   If you export two subvolumes of a btrfs filesystem, they will both be
   given the same uuid so lookups will be confused.
   blkid cannot differentiate the two, so we must use the fsid from
   statfs64 to identify the filesystem.
   
   We cannot tell if blkid or statfs is best without knowing internal
   details of the filesystem in question, so we need to encode specific
   knowledge of btrfs in mountd.  This is unfortunate.
   
   To ensure smooth handling of this and possible future changes in uuid
   generation, we add infrastructure for multiple different uuids to be
   recognised on old filehandles, but only the preferred on is used on
   new filehandles.
  
  Could you just contatenate the two (or hash them somehow)?  Or does that
  just use up too much space in the filehandle?
 
 I did consider xoring them together but came to the conclusion that would
 actually be a regression.
 If you look down at the comment that I included in uuid_by_path, you will see
 that some filesystems (e.g. VFAT) just use the major/minor device number for
 the f_fsid from statfs.  As you know that is not necessarily stable over
 reboots, while the UUID that blkid gives is.
 So if we always adding the two uuids somehow, it would be an improvement for
 btrfs, no change for e.g. ext3/XFS, and a regression for VFAT (and others I
 think).  Not good.

OK, got it.

--b.
--
To unsubscribe from this list: send the line unsubscribe linux-btrfs in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] Improve support for exporting btrfs subvolumes.

2010-06-22 Thread Steve Dickson


On 06/17/2010 12:54 AM, Neil Brown wrote:
 
 If you export two subvolumes of a btrfs filesystem, they will both be
 given the same uuid so lookups will be confused.
 blkid cannot differentiate the two, so we must use the fsid from
 statfs64 to identify the filesystem.
 
 We cannot tell if blkid or statfs is best without knowing internal
 details of the filesystem in question, so we need to encode specific
 knowledge of btrfs in mountd.  This is unfortunate.
 
 To ensure smooth handling of this and possible future changes in uuid
 generation, we add infrastructure for multiple different uuids to be
 recognised on old filehandles, but only the preferred on is used on
 new filehandles.
 
 Signed-off-by: NeilBrown ne...@suse.de
 
 --
 This is a substantially revised version of a patch I posted a while
 ago.
 I tried to find a way to do it would hard coding knowledge of btrfs in
 nfs-utils, but it isn't possible.  For some filesystems, f_fsid is
 best, for some it is worst.  No way to tell the difference.
 
 This patch add infrastructure so that if we find a better way to get a
 good uuid (e.g. a new syscall), we can slot it in for new filehandles,
 but old filehandles using the old uuid will still work.
 
 I believe this is ready for inclusion upstream.

Committed...

steved.

--
To unsubscribe from this list: send the line unsubscribe linux-btrfs in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH] Improve support for exporting btrfs subvolumes.

2010-06-16 Thread Neil Brown

If you export two subvolumes of a btrfs filesystem, they will both be
given the same uuid so lookups will be confused.
blkid cannot differentiate the two, so we must use the fsid from
statfs64 to identify the filesystem.

We cannot tell if blkid or statfs is best without knowing internal
details of the filesystem in question, so we need to encode specific
knowledge of btrfs in mountd.  This is unfortunate.

To ensure smooth handling of this and possible future changes in uuid
generation, we add infrastructure for multiple different uuids to be
recognised on old filehandles, but only the preferred on is used on
new filehandles.

Signed-off-by: NeilBrown ne...@suse.de

--
This is a substantially revised version of a patch I posted a while
ago.
I tried to find a way to do it would hard coding knowledge of btrfs in
nfs-utils, but it isn't possible.  For some filesystems, f_fsid is
best, for some it is worst.  No way to tell the difference.

This patch add infrastructure so that if we find a better way to get a
good uuid (e.g. a new syscall), we can slot it in for new filehandles,
but old filehandles using the old uuid will still work.

I believe this is ready for inclusion upstream.
Thanks,
NeilBrown


diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
index caef5b2..85cd829 100644
--- a/utils/mountd/cache.c
+++ b/utils/mountd/cache.c
@@ -170,13 +170,16 @@ void auth_unix_gid(FILE *f)
 #if USE_BLKID
 static const char *get_uuid_blkdev(char *path)
 {
+   /* We set *safe if we know that we need the
+* fsid from statfs too.
+*/
static blkid_cache cache = NULL;
struct stat stb;
char *devname;
blkid_tag_iterate iter;
blkid_dev dev;
const char *type;
-   const char *val = NULL;
+   const char *val, *uuid = NULL;
 
if (cache == NULL)
blkid_get_cache(cache, NULL);
@@ -193,42 +196,29 @@ static const char *get_uuid_blkdev(char *path)
iter = blkid_tag_iterate_begin(dev);
if (!iter)
return NULL;
-   while (blkid_tag_next(iter, type, val) == 0)
+   while (blkid_tag_next(iter, type, val) == 0) {
if (strcmp(type, UUID) == 0)
+   uuid = val;
+   if (strcmp(type, TYPE) == 0 
+   strcmp(val, btrfs) == 0) {
+   uuid = NULL;
break;
+   }
+   }
blkid_tag_iterate_end(iter);
-   return val;
+   return uuid;
 }
 #else
 #define get_uuid_blkdev(path) (NULL)
 #endif
 
-int get_uuid(char *path, char *uuid, int uuidlen, char *u)
+int get_uuid(const char *val, int uuidlen, char *u)
 {
/* extract hex digits from uuidstr and compose a uuid
 * of the given length (max 16), xoring bytes to make
-* a smaller uuid.  Then compare with uuid
+* a smaller uuid.
 */
int i = 0;
-   const char *val = NULL;
-   char fsid_val[17];
-
-   if (path) {
-   val = get_uuid_blkdev(path);
-   if (!val) {
-   struct statfs64 st;
-
-   if (statfs64(path, st))
-   return 0;
-   if (!st.f_fsid.__val[0]  !st.f_fsid.__val[1])
-   return 0;
-   snprintf(fsid_val, 17, %08x%08x,
-st.f_fsid.__val[0], st.f_fsid.__val[1]);
-   val = fsid_val;
-   }
-   } else {
-   val = uuid;
-   }

memset(u, 0, uuidlen);
for ( ; *val ; val++) {
@@ -252,6 +242,60 @@ int get_uuid(char *path, char *uuid, int uuidlen, char *u)
return 1;
 }
 
+int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
+{
+   /* get a uuid for the filesystem found at 'path'.
+* There are several possible ways of generating the
+* uuids (types).
+* Type 0 is used for new filehandles, while other types
+* may be used to interpret old filehandle - to ensure smooth
+* forward migration.
+* We return 1 if a uuid was found (and it might be worth 
+* trying the next type) or 0 if no more uuid types can be
+* extracted.
+*/
+
+   /* Possible sources of uuid are
+* - blkid uuid
+* - statfs64 uuid
+*
+* On some filesystems (e.g. vfat) the statfs64 uuid is simply an
+* encoding of the device that the filesystem is mounted from, so
+* it we be very bad to use that (as device numbers change).  blkid
+* must be preferred.
+* On other filesystems (e.g. btrfs) the statfs64 uuid contains
+* important info that the blkid uuid cannot contain:  This happens
+* when multiple subvolumes are exported (they have the same
+* blkid uuid but different statfs64 uuids).
+* We rely on get_uuid_blkdev *knowing* which is which and not returning
+