Re: [PATCH v3 12/16] usb/gadget: FunctionFS: add devices management code

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

 



Acked-by: Michal Nazarewicz <mina86@xxxxxxxxxx>

Only some small comments.

On Fri, Nov 22 2013, Andrzej Pietrasiewicz wrote:
> @@ -2465,6 +2474,209 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)
>  }
>  
>  
> +/* Devices management *******************************************************/
> +
> +static LIST_HEAD(ffs_devices);
> +
> +void ffs_dev_lock(void)
> +{
> +	mutex_lock(&ffs_lock);
> +}
> +
> +void ffs_dev_unlock(void)
> +{
> +	mutex_unlock(&ffs_lock);
> +}

Perhaps it will be more efficient to have those as static inlines and
extern ffs_lock in header file instead?

> +
> +static struct ffs_dev *_ffs_find_dev(const char *name)
> +{
> +	struct ffs_dev *dev;
> +
> +	list_for_each_entry(dev, &ffs_devices, entry) {
> +		if (!dev->name || !name)
> +			continue;
> +		if (strcmp(dev->name, name) == 0)
> +			return dev;
> +	}
> +	
> +	return NULL;
> +}
> +
> +/*
> + * ffs_lock must be taken by the caller of this function
> + */
> +static struct ffs_dev *ffs_find_dev(const char *name)
> +{
> +	struct ffs_dev *dev;
> +
> +	if (list_is_singular(&ffs_devices)) {
> +		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
> +		if (dev->single)
> +			return dev;

Wouldn't it be easier to do this check in _ffs_find_dev?  It is possible
to have non-singular list with some devs having dev->single set?
I don't think that it is since ffs_alloc_dev checks whether list is
singular with the only element having dev->single.

> +	}
> +
> +	return _ffs_find_dev(name);
> +}
> +
> +/*
> + * ffs_lock must be taken by the caller of this function
> + */
> +struct ffs_dev *ffs_alloc_dev(void)
> +{
> +	struct ffs_dev *dev;
> +	int ret;
> +
> +	if (list_is_singular(&ffs_devices)) {
> +		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
> +		if (dev->single)
> +			return ERR_PTR(-EBUSY);
> +	}

This condition is used for the second time, perhaps it would be better
to have a function:

static struct ffs_dev *ffs_get_single_dev(void) 
{
	if (list_is_singular(&ffs_devices)) {
		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry);
		if (dev->single)
			return dev;
	}
	return NULL;
}

Then, ffs_find_dev would do:

	dev = ffs_get_single_dev();
	if (dev)
		return dev;

And ffs_alloc_dev would do:

	if (ffs_get_single_dev())
		return ERR_PTR(-EBUSY);

This of course is mutually exclusive with my previous comment.  Also,
it's up to you, I don't have strong opinions.

> +
> +	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
> +	if (!dev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	if (list_empty(&ffs_devices)) {
> +		ret = functionfs_init();
> +		if (ret) {
> +			kfree(dev);
> +			return ERR_PTR(ret);
> +		}
> +	}
> +
> +	list_add(&dev->entry, &ffs_devices);
> +
> +	return dev;
> +}
> +
> +/*
> + * ffs_lock must be taken by the caller of this function
> + * The caller is responsible for "name" being available whenever f_fs needs it
> + */
> +int ffs_name_dev(struct ffs_dev *dev, const char *name)
> +{
> +	struct ffs_dev *existing;
> +
> +	existing = _ffs_find_dev(name);
> +	if (existing)
> +		return -EBUSY;
> +	
> +	dev->name = name;
> +
> +	return 0;
> +}
> +
> +/*
> + * ffs_lock must be taken by the caller of this function
> + */
> +int ffs_single_dev(struct ffs_dev *dev, bool single)
> +{
> +	if (single && !list_is_singular(&ffs_devices))
> +		return -EBUSY;
> +
> +	dev->single = single;
> +
> +	return 0;
> +}
> +
> +/*
> + * ffs_lock must be taken by the caller of this function
> + */
> +void ffs_free_dev(struct ffs_dev *dev)
> +{
> +	list_del(&dev->entry);
> +	if (list_empty(&ffs_devices))
> +		functionfs_cleanup();
> +
> +	kfree(dev);

I'd free before functionfs_cleanup, but up to you.

> +}
> +
> +static void *ffs_acquire_dev(const char *dev_name)
> +{
> +	struct ffs_dev *ffs_dev;
> +
> +	ENTER();
> +	ffs_dev_lock();
> +
> +	ffs_dev = ffs_find_dev(dev_name);
> +	if (!ffs_dev) {
> +		ffs_dev = ERR_PTR(-ENODEV);
> +		goto done;
> +	}
> +
> +	if (ffs_dev->mounted) {
> +		ffs_dev = ERR_PTR(-EBUSY);
> +		goto done;
> +	}
> +	ffs_dev->mounted = true;

This could be rewritten to avoid goto and in fact shorten the code:

	if (!ffs_dev)
		ffs_dev = ERR_PTR(-ENODEV);
	else if (ffs_dev->mounted)
		ffs_dev = ERR_PTR(-EBUSY);
	else
		ffs_dev->mounted = true;

> +
> +done:
> +	ffs_dev_unlock();
> +	return ffs_dev;
> +}
>  /* Misc helper functions ****************************************************/
>  
>  static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock)
> diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
> index 1aaa103..d9d1e66 100644
> --- a/drivers/usb/gadget/g_ffs.c
> +++ b/drivers/usb/gadget/g_ffs.c
> @@ -157,6 +157,8 @@ struct gfs_configuration {
>  #endif
>  };
>  
> +static int functionfs_ready_callback(struct ffs_data *ffs);
> +static void functionfs_closed_callback(struct ffs_data *ffs);
>  static int gfs_bind(struct usb_composite_dev *cdev);
>  static int gfs_unbind(struct usb_composite_dev *cdev);
>  static int gfs_do_config(struct usb_configuration *c);
> @@ -170,172 +172,113 @@ static __refdata struct usb_composite_driver gfs_driver = {
>  	.unbind		= gfs_unbind,
>  };
>  
> -static DEFINE_MUTEX(gfs_lock);
>  static unsigned int missing_funcs;
>  static bool gfs_registered;
>  static bool gfs_single_func;
> -static struct ffs_dev *ffs_tab;
> +static struct ffs_dev **ffs_tab;
>  
>  static int __init gfs_init(void)
>  {
>  	int i;
> +	int ret = 0;
>  
>  	ENTER();
>  
> -	if (!func_num) {
> +	if (func_num < 2) {
>  		gfs_single_func = true;
>  		func_num = 1;
>  	}
>  
> -	ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL);
> +	ffs_tab = kcalloc(func_num, sizeof(*ffs_tab), GFP_KERNEL);
>  	if (!ffs_tab)
>  		return -ENOMEM;
>  
> -	if (!gfs_single_func)
> -		for (i = 0; i < func_num; i++)
> -			ffs_tab[i].name = func_names[i];
> +	ffs_dev_lock();
> +	for (i = 0; i < func_num; i++) {
> +		ffs_tab[i] = ffs_alloc_dev();
> +		if (IS_ERR(ffs_tab[i])) {
> +			ret = PTR_ERR(ffs_tab[i--]);

I'd put the decrement in a separate instruction to be more obvious.

> +			goto no_dev;
> +		}
> +		ret = ffs_single_dev(ffs_tab[i], gfs_single_func);
> +		if (ret)
> +			goto no_dev;
> +		if (!gfs_single_func) {
> +			ret = ffs_name_dev(ffs_tab[i], func_names[i]);
> +			if (ret)
> +				goto no_dev;
> +		}
> +		ffs_tab[i]->ffs_ready_callback = functionfs_ready_callback;
> +		ffs_tab[i]->ffs_closed_callback = functionfs_closed_callback;
> +	}
> +	ffs_dev_unlock();
>  
>  	missing_funcs = func_num;
>  
> -	return functionfs_init();
> +	return 0;
> +no_dev:
> +	while (i >= 0)
> +		ffs_free_dev(ffs_tab[i--]);
> +	ffs_dev_unlock();
> +	kfree(ffs_tab);
> +	return ret;
>  }
>  module_init(gfs_init);

-- 
Best regards,                                         _     _
.o. | Liege of Serenely Enlightened Majesty of      o' \,=./ `o
..o | Computer Science,  Michał “mina86” Nazarewicz    (o o)
ooo +--<mpn@xxxxxxxxxx>--<xmpp:mina86@xxxxxxxxxx>--ooO--(_)--Ooo--

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux