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 exported (they have the same
> +      * blkid uuid but different statfs64 uuids).
> +      * We rely on get_uuid_blkdev *knowing* which is which and not returning
> +      * a uuid for filesystems where the statfs64 uuid is better.
> +      *
> +      */
> +     struct statfs64 st;
> +     char fsid_val[17];
> +     const char *blkid_val;
> +     const char *val;
> +
> +     blkid_val = get_uuid_blkdev(path);
> +
> +     if (statfs64(path, &st) == 0 &&
> +         (st.f_fsid.__val[0] || st.f_fsid.__val[1]))
> +             snprintf(fsid_val, 17, "%08x%08x",
> +                      st.f_fsid.__val[0], st.f_fsid.__val[1]);
> +     else
> +             fsid_val[0] = 0;
> +
> +     if (blkid_val && (type--) == 0)
> +             val = blkid_val;
> +     else if (fsid_val[0] && (type--) == 0)
> +             val = fsid_val;
> +     else
> +             return 0;
> +
> +     get_uuid(val, uuidlen, uuid);
> +     return 1;
> +}
> +
>  /* Iterate through /etc/mtab, finding mountpoints
>   * at or below a given path
>   */
> @@ -398,6 +442,7 @@ void nfsd_fh(FILE *f)
>                       struct stat stb;
>                       char u[16];
>                       char *path;
> +                     int type;
>  
>                       if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
>                               static nfs_export *prev = NULL;
> @@ -461,10 +506,14 @@ void nfsd_fh(FILE *f)
>                                       continue;
>                       check_uuid:
>                               if (exp->m_export.e_uuid)
> -                                     get_uuid(NULL, exp->m_export.e_uuid,
> +                                     get_uuid(exp->m_export.e_uuid,
>                                                uuidlen, u);
> -                             else if (get_uuid(path, NULL, uuidlen, u) == 0)
> -                                     continue;
> +                             else
> +                                     for (type = 0;
> +                                          uuid_by_path(path, type, uuidlen, 
> u);
> +                                          type++)
> +                                             if (memcmp(u, fhuuid, uuidlen) 
> != 0)
> +                                                     break;
>  
>                               if (memcmp(u, fhuuid, uuidlen) != 0)
>                                       continue;
> @@ -600,13 +649,13 @@ static int dump_to_cache(FILE *f, char *domain, char 
> *path, struct exportent *ex
>               write_secinfo(f, exp, flag_mask);
>               if (exp->e_uuid == NULL || different_fs) {
>                       char u[16];
> -                     if (get_uuid(path, NULL, 16, u)) {
> +                     if (uuid_by_path(path, 0, 16, u)) {
>                               qword_print(f, "uuid");
>                               qword_printhex(f, u, 16);
>                       }
>               } else {
>                       char u[16];
> -                     get_uuid(NULL, exp->e_uuid, 16, u);
> +                     get_uuid(exp->e_uuid, 16, u);
>                       qword_print(f, "uuid");
>                       qword_printhex(f, u, 16);
>               }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
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

Reply via email to