Re: [PATCH 10/16] usb/gadget: FunctionFS: Remove VLAIS usage from gadget code

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

 



On Wed, Oct 23 2013, Andrzej Pietrasiewicz wrote:
> From: Mark Charlebois <charlebm@xxxxxxxxx>
>
> The use of variable length arrays in structs (VLAIS) in the Linux Kernel code
> precludes the use of compilers which don't implement VLAIS (for instance the
> Clang compiler). This alternate patch calculates offsets into the kmalloc-ed
> memory buffer using macros. The previous patch required multiple kmalloc and
> kfree calls. This version uses "group" vs "struct" since it really is not a
> struct and is essentially a group of VLA in a common allocated block. This
> version also fixes the issues pointed out by Andrzej Pietrasiewicz.
>
> Signed-off-by: Mark Charlebois <charlebm@xxxxxxxxx>
> Signed-off-by: Behan Webster <behanw@xxxxxxxxxxxxxxxxxx>
>
> [elimination of miexed declaration and code, checkpatch cleanup]
> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxx>
> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
> ---
>  drivers/usb/gadget/f_fs.c |  110 +++++++++++++++++++++++++++++----------------
>  1 files changed, 71 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
> index 0658908..9ccda73 100644
> --- a/drivers/usb/gadget/f_fs.c
> +++ b/drivers/usb/gadget/f_fs.c
> @@ -30,6 +30,21 @@
>  
>  #define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */

I think something more explicit with fewer automatically declared
variables cloud be more readable:

> +/* Variable Length Array Macros **********************************************/
> +#define vla_group(groupname) size_t groupname##__##next = 0
> +#define vla_group_size(groupname) groupname##__##next

#define vla_group(groupname) size_t groupname##__next = 0
#define vla_group_size(groupname) groupname##__next

> +
> +#define vla_item(groupname, type, name, n) \
> +	size_t groupname##_##name##__##offset = \
> +		(groupname##__##next + __alignof__(type) - 1) & \
> +		~(__alignof__(type) - 1); \
> +	size_t groupname##_##name##__##sz = (n) * sizeof(type); \
> +	type *groupname##_##name = ({ \
> +	groupname##__##next = groupname##_##name##__##offset + \
> +		groupname##_##name##__##sz; NULL; })

#define vla_item(groupname, type, name, n)                                     \
	size_t groupname##_##name##__offset = ({                               \
		size_t align_mask = __alignof__(type) - 1;                     \
		size_t offset = (groupname##__next + align_mask) & align_mask; \
		size_t size = (n) * sizeof(type);                              \
		groupname##__next = offset + size;                             \
		offset;
	})

> +
> +#define vla_ptr(ptr, groupname, name) (groupname##_##name = \
> +	(__typeof__(groupname##_##name))&ptr[groupname##_##name##__##offset])
>  

#define vla_ptr(ptr, groupname, name)
	((void *) ((char *)ptr + groupname##_##name##__offset))


>  /* Debugging ****************************************************************/
>  
> @@ -1901,30 +1916,38 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
>  
>  	/* Allocate everything in one chunk so there's less maintenance. */
>  	{
> -		struct {
> -			struct usb_gadget_strings *stringtabs[lang_count + 1];
> -			struct usb_gadget_strings stringtab[lang_count];
> -			struct usb_string strings[lang_count*(needed_count+1)];
> -		} *d;
>  		unsigned i = 0;
> +		vla_group(d);
> +		vla_item(d, struct usb_gadget_strings *, stringtabs,
> +			lang_count + 1);
> +		vla_item(d, struct usb_gadget_strings, stringtab, lang_count);
> +		vla_item(d, struct usb_string, strings,
> +			lang_count*(needed_count+1));
>  
> -		d = kmalloc(sizeof *d, GFP_KERNEL);
> -		if (unlikely(!d)) {
> +		char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
> +
> +		if (unlikely(!vlabuf)) {
>  			kfree(_data);
>  			return -ENOMEM;
>  		}
>  
> -		stringtabs = d->stringtabs;
> -		t = d->stringtab;
> +		/* Initialize the VLA pointers */
> +		vla_ptr(vlabuf, d, stringtabs);
> +		vla_ptr(vlabuf, d, stringtab);
> +		vla_ptr(vlabuf, d, strings);
> +
> +		stringtabs = d_stringtabs;
> +		t = d_stringtab;

stringtabs = vla_ptr(vlabuf, d, stringtabs);
t = vla_ptr(vlabuf, d, stringtab);

>  		i = lang_count;
>  		do {
>  			*stringtabs++ = t++;
>  		} while (--i);
>  		*stringtabs = NULL;
>  
> -		stringtabs = d->stringtabs;
> -		t = d->stringtab;
> -		s = d->strings;
> +		/* stringtabs = vlabuf = d_stringtabs for later kfree */
> +		stringtabs = d_stringtabs;
> +		t = d_stringtab;
> +		s = d_strings;

stringtabs = vla_ptr(vlabuf, d, stringtabs);
t = vla_ptr(vlabuf, d, stringtab);
s = vla_ptr(vlabuf, d, strings);

>  		strings = s;
>  	}

And similarly below:

> @@ -2200,16 +2223,16 @@ static int ffs_func_bind(struct usb_configuration *c,
>  	int ret;
>  
>  	/* Make it a single chunk, less management later on */
> -	struct {
> -		struct ffs_ep eps[ffs->eps_count];
> -		struct usb_descriptor_header
> -			*fs_descs[full ? ffs->fs_descs_count + 1 : 0];
> -		struct usb_descriptor_header
> -			*hs_descs[high ? ffs->hs_descs_count + 1 : 0];
> -		short inums[ffs->interfaces_count];
> -		char raw_descs[high ? ffs->raw_descs_length
> -				    : ffs->raw_fs_descs_length];
> -	} *data;
> +	vla_group(d);
> +	vla_item(d, struct ffs_ep, eps, ffs->eps_count);
> +	vla_item(d, struct usb_descriptor_header *, fs_descs,
> +		full ? ffs->fs_descs_count + 1 : 0);
> +	vla_item(d, struct usb_descriptor_header *, hs_descs,
> +		high ? ffs->hs_descs_count + 1 : 0);
> +	vla_item(d, short, inums, ffs->interfaces_count);
> +	vla_item(d, char, raw_descs,
> +		high ? ffs->raw_descs_length : ffs->raw_fs_descs_length);
> +	char *vlabuf;
>  
>  	ENTER();
>  
> @@ -2217,21 +2240,30 @@ static int ffs_func_bind(struct usb_configuration *c,
>  	if (unlikely(!(full | high)))
>  		return -ENOTSUPP;
>  
> -	/* Allocate */
> -	data = kmalloc(sizeof *data, GFP_KERNEL);
> -	if (unlikely(!data))
> +	/* Allocate a single chunk, less management later on */
> +	vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL);
> +	if (unlikely(!vlabuf))
>  		return -ENOMEM;
>  
> +	/* Initialize each struct member pointer in the allocated memory */
> +	vla_ptr(vlabuf, d, eps);
> +	vla_ptr(vlabuf, d, fs_descs);
> +	vla_ptr(vlabuf, d, hs_descs);
> +	vla_ptr(vlabuf, d, inums);
> +	vla_ptr(vlabuf, d, raw_descs);
> +
>  	/* Zero */
> -	memset(data->eps, 0, sizeof data->eps);
> -	memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs);
> -	memset(data->inums, 0xff, sizeof data->inums);
> +	memset(d_eps, 0, d_eps__sz);
> +	memcpy(d_raw_descs, ffs->raw_descs + 16, d_raw_descs__sz);
> +	memset(d_inums, 0xff, d_inums__sz);
>  	for (ret = ffs->eps_count; ret; --ret)
> -		data->eps[ret].num = -1;
> +		d_eps[ret].num = -1;
>  
> -	/* Save pointers */
> -	func->eps             = data->eps;
> -	func->interfaces_nums = data->inums;
> +	/* Save pointers
> +	 * d_eps == vlabuf, func->eps used to kfree vlabuf later
> +	*/
> +	func->eps             = d_eps;
> +	func->interfaces_nums = d_inums;
>  
>  	/*
>  	 * Go through all the endpoint descriptors and allocate
> @@ -2239,10 +2271,10 @@ static int ffs_func_bind(struct usb_configuration *c,
>  	 * numbers without worrying that it may be described later on.
>  	 */
>  	if (likely(full)) {
> -		func->function.fs_descriptors = data->fs_descs;
> +		func->function.fs_descriptors = d_fs_descs;
>  		ret = ffs_do_descs(ffs->fs_descs_count,
> -				   data->raw_descs,
> -				   sizeof data->raw_descs,
> +				   d_raw_descs,
> +				   d_raw_descs__sz,
>  				   __ffs_func_bind_do_descs, func);
>  		if (unlikely(ret < 0))
>  			goto error;
> @@ -2251,10 +2283,10 @@ static int ffs_func_bind(struct usb_configuration *c,
>  	}
>  
>  	if (likely(high)) {
> -		func->function.hs_descriptors = data->hs_descs;
> +		func->function.hs_descriptors = d_hs_descs;
>  		ret = ffs_do_descs(ffs->hs_descs_count,
> -				   data->raw_descs + ret,
> -				   (sizeof data->raw_descs) - ret,
> +				   d_raw_descs + ret,
> +				   d_raw_descs__sz - ret,
>  				   __ffs_func_bind_do_descs, func);
>  	}
>  
> @@ -2265,7 +2297,7 @@ static int ffs_func_bind(struct usb_configuration *c,
>  	 */
>  	ret = ffs_do_descs(ffs->fs_descs_count +
>  			   (high ? ffs->hs_descs_count : 0),
> -			   data->raw_descs, sizeof data->raw_descs,
> +			   d_raw_descs, d_raw_descs__sz,
>  			   __ffs_func_bind_do_nums, func);
>  	if (unlikely(ret < 0))
>  		goto error;
> -- 
> 1.7.0.4

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