Re: [RFC PATCH v3 1/2] fpga: add an owner field and use it to take the low-level module's refcount

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

 




On 2023-12-25 07:58, Xu Yilun wrote:
> On Mon, Dec 18, 2023 at 09:28:08PM +0100, Marco Pagani wrote:
>> Add a module owner field to the fpga_manager_ops struct and use it to
>> take the low-level control module's refcount instead of relying on the
>> parent device's driver pointer. Low-level control modules should
>> statically set the owner field to THIS_MODULE. To detect when the owner
> 
> Don't be so strict, people could pass in any owner module they think it
> is correct.
>

I'm planning to use a helper macro to set the owner field at registration,
as suggested by Greg K-H. So, I would change this sentence anyway.
 
>> module pointer becomes stale, set the mops pointer to null during
>> fpga_mgr_unregister() (called by the low-level module exit function) and
> 
> No need the side note, people could call fpga_mgr_unregister() at any
> time they think it is correct.
>

Okay, I'll drop this line.

>> test it before taking the module's refcount. Use a mutex to avoid a
>> crash that can happen if __fpga_mgr_get() gets suspended between testing
>> the mops pointer and taking the low-level refcount and then resumes when
>> the low-level module has already been freed.
>>
>> Thanks to Xu Yilun for suggesting the locking pattern.
> 
> I appreciate that but don't put it in changelog. A Suggested-by is
> appropriate.
> 

Okay.

>>
>> Other changes: move put_device() from __fpga_mgr_get() to fpga_mgr_get()
> 
> Opportunistically move put_device() ...
> 
> The point is, try to imply the *Other* changes are simple and relative to
> the main change, or we should split the patch.
> 
> Sorry but seeing the actual change, please split. The whole change is
> small and the put_device() part contributes 40% code ...
> 

Make sense. I would prefer to rephrase the message and do everything in a
single patch since moving put_device() is a small change related to the
mechanism for getting the manager.

Thanks,
Marco

>> and of_fpga_mgr_get() to improve code clarity.
>>
>> Fixes: 654ba4cc0f3e ("fpga manager: ensure lifetime with of_fpga_mgr_get")
>> Signed-off-by: Marco Pagani <marpagan@xxxxxxxxxx>
>> ---
>>  drivers/fpga/fpga-mgr.c       | 50 ++++++++++++++++++++++++-----------
>>  include/linux/fpga/fpga-mgr.h |  4 +++
>>  2 files changed, 38 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
>> index 06651389c592..a32b7d40080d 100644
>> --- a/drivers/fpga/fpga-mgr.c
>> +++ b/drivers/fpga/fpga-mgr.c
>> @@ -664,20 +664,20 @@ static struct attribute *fpga_mgr_attrs[] = {
>>  };
>>  ATTRIBUTE_GROUPS(fpga_mgr);
>>  
>> -static struct fpga_manager *__fpga_mgr_get(struct device *dev)
>> +static struct fpga_manager *__fpga_mgr_get(struct device *mgr_dev)
>>  {
>>  	struct fpga_manager *mgr;
>>  
>> -	mgr = to_fpga_manager(dev);
>> +	mgr = to_fpga_manager(mgr_dev);
>>  
>> -	if (!try_module_get(dev->parent->driver->owner))
>> -		goto err_dev;
>> +	mutex_lock(&mgr->mops_mutex);
>>  
>> -	return mgr;
>> +	if (!mgr->mops || !try_module_get(mgr->mops->owner))
>> +		mgr = ERR_PTR(-ENODEV);
>>  
>> -err_dev:
>> -	put_device(dev);
>> -	return ERR_PTR(-ENODEV);
>> +	mutex_unlock(&mgr->mops_mutex);
>> +
>> +	return mgr;
>>  }
>>  
>>  static int fpga_mgr_dev_match(struct device *dev, const void *data)
>> @@ -693,12 +693,18 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data)
>>   */
>>  struct fpga_manager *fpga_mgr_get(struct device *dev)
>>  {
>> -	struct device *mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev,
>> -						   fpga_mgr_dev_match);
>> +	struct fpga_manager *mgr;
>> +	struct device *mgr_dev;
>> +
>> +	mgr_dev = class_find_device(&fpga_mgr_class, NULL, dev, fpga_mgr_dev_match);
>>  	if (!mgr_dev)
>>  		return ERR_PTR(-ENODEV);
>>  
>> -	return __fpga_mgr_get(mgr_dev);
>> +	mgr = __fpga_mgr_get(mgr_dev);
>> +	if (IS_ERR(mgr))
>> +		put_device(mgr_dev);
>> +
>> +	return mgr;
>>  }
>>  EXPORT_SYMBOL_GPL(fpga_mgr_get);
>>  
>> @@ -711,13 +717,18 @@ EXPORT_SYMBOL_GPL(fpga_mgr_get);
>>   */
>>  struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
>>  {
>> -	struct device *dev;
>> +	struct fpga_manager *mgr;
>> +	struct device *mgr_dev;
>>  
>> -	dev = class_find_device_by_of_node(&fpga_mgr_class, node);
>> -	if (!dev)
>> +	mgr_dev = class_find_device_by_of_node(&fpga_mgr_class, node);
>> +	if (!mgr_dev)
>>  		return ERR_PTR(-ENODEV);
>>  
>> -	return __fpga_mgr_get(dev);
>> +	mgr = __fpga_mgr_get(mgr_dev);
>> +	if (IS_ERR(mgr))
>> +		put_device(mgr_dev);
>> +
>> +	return mgr;
>>  }
>>  EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
>>  
>> @@ -727,7 +738,7 @@ EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
>>   */
>>  void fpga_mgr_put(struct fpga_manager *mgr)
>>  {
>> -	module_put(mgr->dev.parent->driver->owner);
>> +	module_put(mgr->mops->owner);
>>  	put_device(&mgr->dev);
>>  }
>>  EXPORT_SYMBOL_GPL(fpga_mgr_put);
>> @@ -803,6 +814,7 @@ fpga_mgr_register_full(struct device *parent, const struct fpga_manager_info *in
>>  	}
>>  
>>  	mutex_init(&mgr->ref_mutex);
>> +	mutex_init(&mgr->mops_mutex);
>>  
>>  	mgr->name = info->name;
>>  	mgr->mops = info->mops;
>> @@ -888,6 +900,12 @@ void fpga_mgr_unregister(struct fpga_manager *mgr)
>>  	 */
>>  	fpga_mgr_fpga_remove(mgr);
>>  
>> +	mutex_lock(&mgr->mops_mutex);
>> +
>> +	mgr->mops = NULL;
>> +
>> +	mutex_unlock(&mgr->mops_mutex);
>> +
>>  	device_unregister(&mgr->dev);
>>  }
>>  EXPORT_SYMBOL_GPL(fpga_mgr_unregister);
>> diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h
>> index 54f63459efd6..b4d9413cb444 100644
>> --- a/include/linux/fpga/fpga-mgr.h
>> +++ b/include/linux/fpga/fpga-mgr.h
>> @@ -162,6 +162,7 @@ struct fpga_manager_info {
>>   * @write_complete: set FPGA to operating state after writing is done
>>   * @fpga_remove: optional: Set FPGA into a specific state during driver remove
>>   * @groups: optional attribute groups.
>> + * @owner: owner module containing the ops.
>>   *
>>   * fpga_manager_ops are the low level functions implemented by a specific
>>   * fpga manager driver.  The optional ones are tested for NULL before being
>> @@ -184,6 +185,7 @@ struct fpga_manager_ops {
>>  			      struct fpga_image_info *info);
>>  	void (*fpga_remove)(struct fpga_manager *mgr);
>>  	const struct attribute_group **groups;
>> +	struct module *owner;
>>  };
>>  
>>  /* FPGA manager status: Partial/Full Reconfiguration errors */
>> @@ -201,6 +203,7 @@ struct fpga_manager_ops {
>>   * @state: state of fpga manager
>>   * @compat_id: FPGA manager id for compatibility check.
>>   * @mops: pointer to struct of fpga manager ops
>> + * @mops_mutex: protects mops from low-level module removal
>>   * @priv: low level driver private date
>>   */
>>  struct fpga_manager {
>> @@ -209,6 +212,7 @@ struct fpga_manager {
>>  	struct mutex ref_mutex;
>>  	enum fpga_mgr_states state;
>>  	struct fpga_compat_id *compat_id;
>> +	struct mutex mops_mutex;
>>  	const struct fpga_manager_ops *mops;
>>  	void *priv;
>>  };
>> -- 
>> 2.43.0
>>
>>
> 





[Index of Archives]     [LM Sensors]     [Linux Sound]     [ALSA Users]     [ALSA Devel]     [Linux Audio Users]     [Linux Media]     [Kernel]     [Gimp]     [Yosemite News]     [Linux Media]

  Powered by Linux