Bug#554790: This breaks device.map on upgrade

Vladimir 'φ-coder/phcoder' Serbinenko phcoder at gmail.com
Tue Jul 20 13:02:47 UTC 2010


On 07/12/2010 12:38 PM, Colin Watson wrote:
> [Re-sending with full quoting and from my @ubuntu.com account so that it
> doesn't get stuck in the grub-devel moderation queue.]
>
> On Mon, Jul 12, 2010 at 12:26:21AM +0100, Colin Watson wrote:
>   
>> On Fri, Jul 09, 2010 at 08:01:12AM +0400, Vadim Solomin wrote:
>>     
>>> This fix, at least in its current form, has a potential to break grub for 
>>> users having more than one drive, unless they are careful enough to check and 
>>> fix their device.map after upgrade.
>>>
>>> Old mkdevicemaps assigned grub device numbers in the sort order of kernel 
>>> device names, which was right more often than not. On the other hand, the sort 
>>> order of (pretty much random) stable names, used by new version, is extremely 
>>> unlikely to have any correlation to grub device order.
>>>
>>> Included is a rough patch which preserves the kernel-name order for grub 
>>> devices when generating device.map.
>>>       
>> I like this idea; it seems that it ought to minimise the likelihood of
>> upheaval due to the change in device.map generation.  I agree that
>> nothing is particularly guaranteed here but it would be nice to try to
>> minimise the chances of problems, if only to try to reduce the number of
>> people who find they need to ask for help on #grub ...
>>
>> Vladimir, would this patch need a copyright assignment?  Most of it
>> seems pretty straightforward; in fact I doubt that it would come out
>> very much different if I'd written it from scratch.
>>     
>   
No need of copyright assignment for this patch.
> I've made a number of changes to this patch to fix up formatting and to
> behave a bit closer to the way I expect; in particular it's necessary to
> compare by ->stable if comparing by ->kernel returns zero, for the
> reasons previously explained in a comment.
>
> Vadim's original patch is quoted here, followed by my amended version
> with a ChangeLog entry.
>
>   
>
> 2010-07-12  Vadim Solomin  <vadic052 at gmail.com>
> 2010-07-12  Colin Watson  <cjwatson at ubuntu.com>
>
> 	Generate device.map in something closer to the old ordering.
>
> 	* util/deviceiter.c (struct device): New declaration.
> 	(compare_file_names): Rename to ...
> 	(compare_devices): ... this.  Sort by kernel name in preference
> 	to the stable by-id name, but keep the latter as a fallback
> 	comparison.  Update header comment.
> 	(grub_util_iterate_devices) [__linux__]: Construct and sort an
> 	array of `struct device' rather than of plain file names.
>
>   
Go ahead.
> === modified file 'util/deviceiter.c'
> --- util/deviceiter.c	2010-07-06 14:10:36 +0000
> +++ util/deviceiter.c	2010-07-12 10:34:16 +0000
> @@ -467,13 +467,30 @@ clear_seen_devices (void)
>  }
>  
>  #ifdef __linux__
> -/* Like strcmp, but doesn't require a cast for use as a qsort comparator.  */
> +struct device
> +{
> +	char *stable;
> +	char *kernel;
> +};
> +
> +/* Sort by the kernel name for preference since that most closely matches
> +   older device.map files, but sort by stable by-id names as a fallback.
> +   This is because /dev/disk/by-id/ usually has a few alternative
> +   identifications of devices (e.g. ATA vs. SATA).
> +   check_device_readable_unique will ensure that we only get one for any
> +   given disk, but sort the list so that the choice of which one we get is
> +   stable.  */
>  static int
> -compare_file_names (const void *a, const void *b)
> +compare_devices (const void *a, const void *b)
>  {
> -  const char *left = *(const char **) a;
> -  const char *right = *(const char **) b;
> -  return strcmp (left, right);
> +  const struct device *left = (const struct device *) a;
> +  const struct device *right = (const struct device *) b;
> +  int ret;
> +  ret = strcmp (left->kernel, right->kernel);
> +  if (ret)
> +    return ret;
> +  else
> +    return strcmp (left->stable, right->stable);
>  }
>  #endif /* __linux__ */
>  
> @@ -507,10 +524,10 @@ grub_util_iterate_devices (int NESTED_FU
>      if (dir)
>        {
>  	struct dirent *entry;
> -	char **names;
> -	size_t names_len = 0, names_max = 1024, i;
> +	struct device *devs;
> +	size_t devs_len = 0, devs_max = 1024, i;
>  
> -	names = xmalloc (names_max * sizeof (*names));
> +	devs = xmalloc (devs_max * sizeof (*devs));
>  
>  	/* Dump all the directory entries into names, resizing if
>  	   necessary.  */
> @@ -526,35 +543,34 @@ grub_util_iterate_devices (int NESTED_FU
>  	    /* Skip RAID entries; they are handled by upper layers.  */
>  	    if (strncmp (entry->d_name, "md-", sizeof ("md-") - 1) == 0)
>  	      continue;
> -	    if (names_len >= names_max)
> +	    if (devs_len >= devs_max)
>  	      {
> -		names_max *= 2;
> -		names = xrealloc (names, names_max * sizeof (*names));
> +		devs_max *= 2;
> +		devs = xrealloc (devs, devs_max * sizeof (*devs));
>  	      }
> -	    names[names_len++] = xasprintf (entry->d_name);
> +	    devs[devs_len].stable =
> +	      xasprintf ("/dev/disk/by-id/%s", entry->d_name);
> +	    devs[devs_len].kernel =
> +	      canonicalize_file_name (devs[devs_len].stable);
> +	    devs_len++;
>  	  }
>  
> -	/* /dev/disk/by-id/ usually has a few alternative identifications of
> -	   devices (e.g. ATA vs. SATA).  check_device_readable_unique will
> -	   ensure that we only get one for any given disk, but sort the list
> -	   so that the choice of which one we get is stable.  */
> -	qsort (names, names_len, sizeof (*names), &compare_file_names);
> +	qsort (devs, devs_len, sizeof (*devs), &compare_devices);
>  
>  	closedir (dir);
>  
>  	/* Now add all the devices in sorted order.  */
> -	for (i = 0; i < names_len; ++i)
> +	for (i = 0; i < devs_len; ++i)
>  	  {
> -	    char *path = xasprintf ("/dev/disk/by-id/%s", names[i]);
> -	    if (check_device_readable_unique (path))
> +	    if (check_device_readable_unique (devs[i].stable))
>  	      {
> -		if (hook (path, 0))
> +		if (hook (devs[i].stable, 0))
>  		  goto out;
>  	      }
> -	    free (path);
> -	    free (names[i]);
> +	    free (devs[i].stable);
> +	    free (devs[i].kernel);
>  	  }
> -	free (names);
> +	free (devs);
>        }
>    }
>  
>
> Thanks,
>
>   


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 294 bytes
Desc: OpenPGP digital signature
URL: <http://lists.alioth.debian.org/pipermail/pkg-grub-devel/attachments/20100720/a5c19b9a/attachment.pgp>


More information about the Pkg-grub-devel mailing list