Re: [PATCH v2 02/13] PCI: prevent duplicate slot names

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Sep 09, 2008 at 04:00:12AM -0600, Alex Chiang wrote:
> If firmware assigns the name N to multiple slots, then:
> 
> 	The first registered slot is assigned N
> 	The second registered slot is assigned N-1
> 	The third registered slot is assigned N-2
> 	The Mth registered slot becomes N-M

Not quite true ... the Mth registered slot becomes N-(M-1).  With the
first '-' being a literal and the second being a minus sign ;-)

> -	 * Allow pcihp drivers to override the ACPI_PCI_SLOT name.
> +	 * Allow pcihp drivers to override existing slot name.

I would leave "the" in here.

> +static char *make_slot_name(const char *name)
> +{
> +	char *new_name;
> +	int len, width, dup = 1;
> +	struct kobject *dup_slot;
> +
> +	new_name = kstrdup(name, GFP_KERNEL);
> +	if (!new_name)
> +		goto out;
> +
> +	/*
> +	 * Start off allocating enough room for "name-X"
> +	 */
> +	len = strlen(name) + 2;
> +	width = 1;
> +
> +try_again:
> +	dup_slot = kset_find_obj(pci_slots_kset, new_name);
> +	if (!dup_slot)
> +		goto out;
> +	kobject_put(dup_slot);
> +
> +	/*
> +	 * We hit this the first time through, which gives us
> +	 * space for terminating NULL, and then every power of 10
> +	 * afterwards, which gives us space to add another digit
> +	 * to "name-XX..."
> +	 */
> +	if (dup % width == 0) {
> +		len++;
> +		width *= 10;
> +	}
> +
> +	new_name = krealloc(new_name, len, GFP_KERNEL);
> +	if (!new_name)
> +		goto out;
> +
> +	memset(new_name, 0, len);
> +	scnprintf(new_name, len, "%s-%d", name, dup++);
> +	goto try_again;
> +
> +out:
> +	return new_name;
> +}

I don't like the goto-loop style (yes, I know we do it elsewhere), and I
think we only need to krealloc inside the 'if' condition.  Something
like this, perhaps:

static char *make_slot_name(const char *name)
{
	char *new_name;
	int len, max, dup;

	new_name = kstrdup(name, GFP_KERNEL);
	if (!new_name)
		return NULL;

	/*
	 * Make sure we hit the realloc case the first time through the
	 * loop.  'len' will be strlen(name) + 3 at that point which is
	 * enough space for "name-X" and the trailing NUL.
	 */
	len = strlen(name) + 2;
	max = 1;
	dup = 1;

	for (;;) {
		struct kobject *dup_slot;
		dup_slot = kset_find_obj(pci_slots_kset, new_name);
		if (!dup_slot)
			break;
		kobject_put(dup_slot);
		if (dup == max) {
			len++;
			max *= 10;
			new_name = krealloc(new_name, len, GFP_KERNEL);
			if (!new_name)
				break;
		}
		sprintf(new_name, "%s-%d", name, dup++);
	}

	return new_name;
}
	

> @@ -89,7 +134,19 @@ static struct kobj_type pci_slot_ktype = {
>   * either return a new &struct pci_slot to the caller, or if the pci_slot
>   * already exists, its refcount will be incremented.
>   *
> - * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple.
> + * Slots are uniquely identified by a @pci_bus, @slot_nr tuple.
> + *
> + * The kobject API imposes a restriction on us, and does not allow sysfs
> + * entries with duplicate names. There are known platforms with broken
> + * firmware that assign the same name to multiple slots.
> + *
> + * We workaround these broken platforms by renaming the slots on behalf
> + * of the caller. If firmware assigns name N to multiple slots:
> + *
> + * The first slot is assigned N
> + * The second slot is assigned N-1
> + * The third slot is assigned N-2
> + * The Mth slot is assigned N-M

How about simply replacing this last line with:

> + * etc.

>  struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
>  				 const char *name)
>  {
>  	struct pci_dev *dev;
>  	struct pci_slot *slot;
> -	int err;
> +	int err = 0;
> +	char *slot_name = NULL;
>  
>  	down_write(&pci_bus_sem);
>  
> @@ -144,12 +201,18 @@ placeholder:
>  
>  	slot->bus = parent;
>  	slot->number = slot_nr;
> -
>  	slot->kobj.kset = pci_slots_kset;
> +
> +	slot_name = make_slot_name(name);
> +	if (!slot_name) {
> +		slot = ERR_PTR(-ENOMEM);
> +		goto err;
> +	}

I think you need to kfree() slot before you assign an ERR_PTR to it.
Actually, since the 'err' label does that, just make that:

	if (!slot_name) {
		err = -ENOMEM;
		goto err;
	}

> -void pci_update_slot_number(struct pci_slot *slot, int slot_nr)
> +void pci_renumber_slot(struct pci_slot *slot, int slot_nr)
>  {
> -	int name_count = 0;
>  	struct pci_slot *tmp;
>  
>  	down_write(&pci_bus_sem);
>  
> -	list_for_each_entry(tmp, &slot->bus->slots, list) {
> +	list_for_each_entry(tmp, &slot->bus->slots, list)
>  		WARN_ON(tmp->number == slot_nr);
> -		if (!strcmp(kobject_name(&tmp->kobj), kobject_name(&slot->kobj)))
> -			name_count++;
> -	}
> -
> -	if (name_count > 1)
> -		printk(KERN_WARNING "pci_update_slot_number found %d slots with the same name: %s\n", name_count, kobject_name(&slot->kobj));

Are you going to get enough information to debug problems with just this
WARN_ON?  And do we want to decline to renumber a slot to the same
number as an existing one?

Anyway, looks good, and I really like the name-change for this function.

-- 
Matthew Wilcox				Intel Open Source Technology Centre
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours.  We can't possibly take such
a retrograde step."
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux