Re: sharing a lock between unrelated modules ? [PATCH, RFC]

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

 



On Tue, 2005-06-21 at 15:15, Jim Cromie wrote:
> Jim Cromie wrote:
> 
> >
> > Im working with scx200_gpio driver, and extending it to operate
> > gpio pins on pc87366 chip, present on the soekris net-4801
> >
> > the chip has many functional-units, some of which are driven by
> > i2c/chips/pc87360.c
> >
> > both drivers have keep their own locks, which prevent other
> > uses of the same driver from corrupting operations,
> > but these offer no protection from interference from the other driver.
> >
> > Is that correct ?
> > And if so, how do I resolve it ?
> >
> > 1. 3rd module, which exports a single lock
 You shouldn't need a 3rd module just to contain the exported
semaphores.  We need to think about what we are protecting with the
locks.  Locks are used to protect shared data.  When you replace a 
semaphore that is embedded in a structure with a global semaphore, 
what are you protecting?  What was the problem with how it was
implemented before?  Maybe I'm missing something.  

Bob

More comments below..
> 
> 
> OK - no one home. I guess its ok to talk to myself ;-)
> 
> attached patch compiles, loads, loads its dependencies,
> IOW, it appears somewhat workable. 
> 
> But, Is it sane ?
> Is there a better way ?
> 
> Depending upon responses here, Ill send to lm-sensors next.
> 
> ______________________________________________________________________
> diff -ruN -X exclude-diffs linux-2.6.12-soekris/drivers/char/Makefile i2c/drivers/char/Makefile
> --- linux-2.6.12-soekris/drivers/char/Makefile	2005-06-18 07:04:14.000000000 -0600
> +++ i2c/drivers/char/Makefile	2005-06-21 12:04:41.000000000 -0600
> @@ -12,6 +12,8 @@
>  obj-$(CONFIG_LEGACY_PTYS)	+= pty.o
>  obj-$(CONFIG_UNIX98_PTYS)	+= pty.o
>  obj-y				+= misc.o
> +obj-m				+= sio_lock.o
> +
>  obj-$(CONFIG_VT)		+= vt_ioctl.o vc_screen.o consolemap.o \
>  				   consolemap_deftbl.o selection.o keyboard.o
>  obj-$(CONFIG_HW_CONSOLE)	+= vt.o defkeymap.o
> diff -ruN -X exclude-diffs linux-2.6.12-soekris/drivers/char/sio_lock.c i2c/drivers/char/sio_lock.c
> --- linux-2.6.12-soekris/drivers/char/sio_lock.c	1969-12-31 17:00:00.000000000 -0700
> +++ i2c/drivers/char/sio_lock.c	2005-06-21 12:46:23.000000000 -0600
> @@ -0,0 +1,47 @@
> +
> +
> +#include <linux/config.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +
> +#include <asm-i386/semaphore.h>
> +
> +MODULE_AUTHOR("Jim Cromie");
> +MODULE_LICENSE("Dual BSD/GPL");
> +
> +/** 
> +    a module/container for a lock to be shared between
> +    drivers/i2c/chips/pc87360 and drivers/char/pc87366_gpio.
> +
> +    The 1st module uses semaphores, the 2nd spinlocks.  Im changing
> +    the 2nd, cuz lm-sensors is maintained, and pc87366_gpio is a new
> +    extension (ie mine) of an unmaintained module (scx200, so said
> +    author, privately).
> +    
> +*/
> +
> +//static DEFINE_SPINLOCK(sio_lock);
> +
> +struct semaphore sio_lock;
> +struct semaphore sio_update_lock;
> +

  semaphore structs are not initialized.  should use
DECLARE_MUTEX(sio_lock) to declare and initialize.

> +int sio_lock_init_module(void)
> +{
> +  printk(KERN_NOTICE "sio_lock_init_module\n");
> +  return 0;
> +}
> +
> +void sio_lock_cleanup_module(void)
> +{
> +  printk(KERN_NOTICE "sio_lock_cleanup_module\n");
> +}
> +
> +EXPORT_SYMBOL(sio_lock);
> +EXPORT_SYMBOL(sio_update_lock);
> +
> +module_init(sio_lock_init_module);
> +module_exit(sio_lock_cleanup_module);
> +
> +
> +
> diff -ruN -X exclude-diffs linux-2.6.12-soekris/drivers/i2c/chips/pc87360.c i2c/drivers/i2c/chips/pc87360.c
> --- linux-2.6.12-soekris/drivers/i2c/chips/pc87360.c	2005-06-18 07:04:21.000000000 -0600
> +++ i2c/drivers/i2c/chips/pc87360.c	2005-06-21 12:48:12.000000000 -0600
> @@ -50,6 +50,24 @@
>  static unsigned int extra_isa[3];
>  static u8 confreg[4];
>  
> +#define SHARED_LOCKS 1
> +
> +#if SHARED_LOCKS
> +extern struct semaphore sio_lock;
> +extern struct semaphore sio_update_lock;
> +
> +#define down_lock	down(&sio_lock)
> +#define down_updatelock	down(&sio_update_lock)
> +#define up_lock		up(&sio_lock)
> +#define up_updatelock	up(&sio_update_lock)
> +
> +#else
> +#define down_lock	down(&(data->lock))
> +#define down_updatelock	down(&(data->update_lock))
> +#define up_lock		up(&(data->lock))
> +#define up_updatelock	up(&(data->update_lock))
> +#endif
  
  I do not believe it is recommended to define macros that do specific
function calls like this, as the resulting source code is unclear as 
to what exactly is being locked without looking back at the macro 
definition.  I believe the correct method is to include the function 
call.

> +
>  enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
>  static struct i2c_address_data addr_data = {
>  	.normal_i2c		= normal_i2c,
> @@ -187,8 +205,10 @@
>  
>  struct pc87360_data {
>  	struct i2c_client client;
> +#if ! SHARED_LOCKS
>  	struct semaphore lock;
>  	struct semaphore update_lock;
> +#endif
>  	char valid;		/* !=0 if following fields are valid */
>  	unsigned long last_updated;	/* In jiffies */
>  
> @@ -259,7 +279,7 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client);
>  	long fan_min = simple_strtol(buf, NULL, 10);
>  
> -	down(&data->update_lock);
> +	down_updatelock;
>  	fan_min = FAN_TO_REG(fan_min, FAN_DIV_FROM_REG(data->fan_status[nr]));
>  
>  	/* If it wouldn't fit, change clock divisor */
> @@ -276,7 +296,7 @@
>  	/* Write new divider, preserve alarm bits */
>  	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_FAN_STATUS(nr),
>  			    data->fan_status[nr] & 0xF9);
> -	up(&data->update_lock);
> +	up_updatelock;
>  
>  	return count;
>  }
> @@ -339,12 +359,12 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->pwm[offset-1] = PWM_TO_REG(val, \
>  			      FAN_CONFIG_INVERT(data->fan_conf, offset-1)); \
>  	pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(offset-1), \
>  			    data->pwm[offset-1]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static DEVICE_ATTR(pwm##offset, S_IWUSR | S_IRUGO, \
> @@ -384,11 +404,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->in_min[offset] = IN_TO_REG(val, data->in_vref); \
>  	pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MIN, \
>  			    data->in_min[offset]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static ssize_t set_in##offset##_max(struct device *dev, const char *buf, \
> @@ -398,12 +418,12 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->in_max[offset] = IN_TO_REG(val, \
>  			       data->in_vref); \
>  	pc87360_write_value(data, LD_IN, offset, PC87365_REG_IN_MAX, \
>  			    data->in_max[offset]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
> @@ -463,11 +483,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->in_min[offset+7] = IN_TO_REG(val, data->in_vref); \
>  	pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MIN, \
>  			    data->in_min[offset+7]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
> @@ -477,11 +497,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->in_max[offset+7] = IN_TO_REG(val, data->in_vref); \
>  	pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_MAX, \
>  			    data->in_max[offset+7]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \
> @@ -491,11 +511,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->in_crit[offset-4] = IN_TO_REG(val, data->in_vref); \
>  	pc87360_write_value(data, LD_IN, offset+7, PC87365_REG_TEMP_CRIT, \
>  			    data->in_crit[offset-4]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
> @@ -573,11 +593,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->temp_min[offset-1] = TEMP_TO_REG(val); \
>  	pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MIN, \
>  			    data->temp_min[offset-1]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static ssize_t set_temp##offset##_max(struct device *dev, const char *buf, \
> @@ -587,11 +607,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->temp_max[offset-1] = TEMP_TO_REG(val); \
>  	pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_MAX, \
>  			    data->temp_max[offset-1]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static ssize_t set_temp##offset##_crit(struct device *dev, const char *buf, \
> @@ -601,11 +621,11 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client); \
>  	long val = simple_strtol(buf, NULL, 10); \
>   \
> -	down(&data->update_lock); \
> +	down_updatelock; \
>  	data->temp_crit[offset-1] = TEMP_TO_REG(val); \
>  	pc87360_write_value(data, LD_TEMP, offset-1, PC87365_REG_TEMP_CRIT, \
>  			    data->temp_crit[offset-1]); \
> -	up(&data->update_lock); \
> +	up_updatelock; \
>  	return count; \
>  } \
>  static DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
> @@ -749,7 +769,7 @@
>  	new_client = &data->client;
>  	i2c_set_clientdata(new_client, data);
>  	new_client->addr = address;
> -	init_MUTEX(&data->lock);
> +	init_MUTEX(&sio_lock);
>  	new_client->adapter = adapter;
>  	new_client->driver = &pc87360_driver;
>  	new_client->flags = 0;
> @@ -782,7 +802,7 @@
>  
>  	strcpy(new_client->name, name);
>  	data->valid = 0;
> -	init_MUTEX(&data->update_lock);
> +	init_MUTEX(&sio_update_lock);
>  
>  	for (i = 0; i < 3; i++) {
>  		if (((data->address[i] = extra_isa[i]))
> @@ -1014,11 +1034,11 @@
>  {
>  	int res;
>  
> -	down(&(data->lock));
> +	down_lock;
>  	if (bank != NO_BANK)
>  		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
>  	res = inb_p(data->address[ldi] + reg);
> -	up(&(data->lock));
> +	up_lock;
>  
>  	return res;
>  }
> @@ -1026,11 +1046,11 @@
>  static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
>  				u8 reg, u8 value)
>  {
> -	down(&(data->lock));
> +	down_lock;
>  	if (bank != NO_BANK)
>  		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);
>  	outb_p(value, data->address[ldi] + reg);
> -	up(&(data->lock));
> +	up_lock;
>  }
>  
>  static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
> @@ -1202,7 +1222,7 @@
>  	struct pc87360_data *data = i2c_get_clientdata(client);
>  	u8 i;
>  
> -	down(&data->update_lock);
> +	down_updatelock;
>  
>  	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
>  		dev_dbg(&client->dev, "Data update\n");
> @@ -1302,7 +1322,7 @@
>  		data->valid = 1;
>  	}
>  
> -	up(&data->update_lock);
> +	up_updatelock;
>  
>  	return data;
>  }


--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux