patch "w1_therm reference count family data" added to char-misc-testing
Subsystems (2)
This is a note to let you know that I've just added the patch titled
w1_therm reference count family data
to my char-misc git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
in the char-misc-testing branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will be merged to the char-misc-next branch sometime soon, after it passes testing, and the merge window is open.
If you have any questions about this process, please let me know.
Quoted 1 line
From
f7134eea05b2fb4a2c0935f8a540539fff01f3ebMon Sep 17 00:00:00 2001
From: David Fries <[email protected]>
Date: Fri, 8 May 2015 19:51:50 -0500
Subject: w1_therm reference count family data
A temperature conversion can take 750 ms and when possible the w1_therm slave driver drops the bus_mutex to allow other bus operations, but that includes operations such as a periodic slave search, which can remove this slave when it is no longer detected. If that happens the sl->family_data will be freed and set to NULL causing w1_slave_show to crash when it wakes up.
--- drivers/w1/slaves/w1_therm.c | 62 +++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 15 deletions(-)
drivers/w1/slaves/w1_therm.c +47 -15
@@ -59,16 +59,32 @@ MODULE_ALIAS("w1-family-" __stringify(W1_THERM_DS28EA00));static int w1_strong_pullup =1 ;module_param_named (strong_pullup, w1_strong_pullup, int,0 ); +struct w1_therm_family_data { +uint8_t rom[9 ]; +atomic_t refcnt; +}; + +/* return the address of the refcnt in the family data */ +#define THERM_REFCNT (family_data) \ + (&((struct w1_therm_family_data*)family_data)->refcnt) +static int w1_therm_add_slave (struct w1_slave *sl) { - sl->family_data =kzalloc (9 ,GFP_KERNEL ); + sl->family_data =kzalloc (sizeof (struct w1_therm_family_data ), +GFP_KERNEL );if (!sl->family_data)return -ENOMEM ; +atomic_set (THERM_REFCNT (sl->family_data),1 );return 0 ; }static void w1_therm_remove_slave (struct w1_slave *sl) { +int refcnt =atomic_sub_return (1 ,THERM_REFCNT (sl->family_data)); +while (refcnt) { +msleep (1000 ); + refcnt =atomic_read (THERM_REFCNT (sl->family_data)); + }kfree (sl->family_data); sl->family_data =NULL ; }
@@ -194,13 +210,22 @@ static ssize_t w1_slave_show(struct device *device,struct w1_slave *sl =dev_to_w1_slave (device);struct w1_master *dev = sl->master;u8 rom[9 ], crc, verdict, external_power; -int i, max_trying =10 ; +int i, ret, max_trying =10 ;ssize_t c =PAGE_SIZE ; +u8 *family_data = sl->family_data; + + ret =mutex_lock_interruptible (&dev->bus_mutex); +if (ret !=0 ) + goto post_unlock; - i =mutex_lock_interruptible (&dev->bus_mutex); -if (i !=0 ) -return i; +if (!sl->family_data) + { + ret = -ENODEV ; + goto pre_unlock; + } +/* prevent the slave from going away in sleep */ +atomic_inc (THERM_REFCNT (family_data));memset (rom,0 ,sizeof (rom));while (max_trying--) {
@@ -230,17 +255,19 @@ static ssize_t w1_slave_show(struct device *device,mutex_unlock (&dev->bus_mutex); sleep_rem =msleep_interruptible (tm); -if (sleep_rem !=0 ) -return -EINTR ; +if (sleep_rem !=0 ) { + ret = -EINTR ; + goto post_unlock; + } - i =mutex_lock_interruptible (&dev->bus_mutex); -if (i !=0 ) -return i; + ret =mutex_lock_interruptible (&dev->bus_mutex); +if (ret !=0 ) + goto post_unlock; }else if (!w1_strong_pullup) { sleep_rem =msleep_interruptible (tm);if (sleep_rem !=0 ) { -mutex_unlock (&dev->bus_mutex); -return -EINTR ; + ret = -EINTR ; + goto pre_unlock; } }
@@ -269,19 +296,24 @@ static ssize_t w1_slave_show(struct device *device, c -=snprintf (buf +PAGE_SIZE - c, c,": crc=%02x %s\n" , crc, (verdict) ?"YES" :"NO" );if (verdict) -memcpy (sl->family_data, rom,sizeof (rom)); +memcpy (family_data, rom,sizeof (rom));else dev_warn (device,"Read failed CRC check\n" );for (i =0 ; i <9 ; ++i) c -=snprintf (buf +PAGE_SIZE - c, c,"%02x " , - ((u8 *)sl->family_data)[i]); + ((u8 *)family_data)[i]); c -=snprintf (buf +PAGE_SIZE - c, c,"t=%d\n" ,w1_convert_temp (rom, sl->family->fid)); + ret =PAGE_SIZE - c; + +pre_unlock:mutex_unlock (&dev->bus_mutex); -return PAGE_SIZE - c; +post_unlock: +atomic_dec (THERM_REFCNT (family_data)); +return ret; }static int __init w1_therm_init (void )
Signature · 1 line
2.4.1