pcmcia: pcmcia_dev_present bugfix

pcmcia_dev_present is in and by itself buggy. Add a note specifying
why it is broken, and replace the broken locking -- taking a mutex
is a bad idea in IRQ context, from which this function is rarely
called -- by an atomic_t.

Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>

+20 -42
+14 -33
drivers/pcmcia/ds.c
··· 335 335 336 336 mutex_lock(&s->ops_mutex); 337 337 list_del(&p_dev->socket_device_list); 338 - p_dev->_removed = 1; 339 338 mutex_unlock(&s->ops_mutex); 340 339 341 340 dev_dbg(&p_dev->dev, "unregistering device\n"); ··· 653 654 654 655 static void pcmcia_requery(struct pcmcia_socket *s) 655 656 { 656 - int present, has_pfc; 657 - 658 - mutex_lock(&s->ops_mutex); 659 - present = s->pcmcia_state.present; 660 - mutex_unlock(&s->ops_mutex); 661 - 662 - if (!present) 663 - return; 657 + int has_pfc; 664 658 665 659 if (s->functions == 0) { 666 660 pcmcia_card_add(s); ··· 1252 1260 1253 1261 switch (event) { 1254 1262 case CS_EVENT_CARD_REMOVAL: 1255 - mutex_lock(&s->ops_mutex); 1256 - s->pcmcia_state.present = 0; 1257 - mutex_unlock(&s->ops_mutex); 1263 + atomic_set(&skt->present, 0); 1258 1264 pcmcia_card_remove(skt, NULL); 1259 1265 handle_event(skt, event); 1260 1266 mutex_lock(&s->ops_mutex); ··· 1261 1271 break; 1262 1272 1263 1273 case CS_EVENT_CARD_INSERTION: 1274 + atomic_set(&skt->present, 1); 1264 1275 mutex_lock(&s->ops_mutex); 1265 1276 s->pcmcia_state.has_pfc = 0; 1266 - s->pcmcia_state.present = 1; 1267 1277 destroy_cis_cache(s); /* to be on the safe side... */ 1268 1278 mutex_unlock(&s->ops_mutex); 1269 1279 pcmcia_card_add(skt); ··· 1303 1313 return 0; 1304 1314 } /* ds_event */ 1305 1315 1306 - 1316 + /* 1317 + * NOTE: This is racy. There's no guarantee the card will still be 1318 + * physically present, even if the call to this function returns 1319 + * non-NULL. Furthermore, the device driver most likely is unbound 1320 + * almost immediately, so the timeframe where pcmcia_dev_present 1321 + * returns NULL is probably really really small. 1322 + */ 1307 1323 struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev) 1308 1324 { 1309 1325 struct pcmcia_device *p_dev; ··· 1319 1323 if (!p_dev) 1320 1324 return NULL; 1321 1325 1322 - mutex_lock(&p_dev->socket->ops_mutex); 1323 - if (!p_dev->socket->pcmcia_state.present) 1324 - goto out; 1326 + if (atomic_read(&p_dev->socket->present) != 0) 1327 + ret = p_dev; 1325 1328 1326 - if (p_dev->socket->pcmcia_state.dead) 1327 - goto out; 1328 - 1329 - if (p_dev->_removed) 1330 - goto out; 1331 - 1332 - if (p_dev->suspended) 1333 - goto out; 1334 - 1335 - ret = p_dev; 1336 - out: 1337 - mutex_unlock(&p_dev->socket->ops_mutex); 1338 1329 pcmcia_put_dev(p_dev); 1339 1330 return ret; 1340 1331 } ··· 1371 1388 return ret; 1372 1389 } 1373 1390 1391 + atomic_set(&socket->present, 0); 1392 + 1374 1393 return 0; 1375 1394 } 1376 1395 ··· 1383 1398 1384 1399 if (!socket) 1385 1400 return; 1386 - 1387 - mutex_lock(&socket->ops_mutex); 1388 - socket->pcmcia_state.dead = 1; 1389 - mutex_unlock(&socket->ops_mutex); 1390 1401 1391 1402 pccard_register_pcmcia(socket, NULL); 1392 1403
+3 -4
include/pcmcia/ds.h
··· 26 26 #ifdef __KERNEL__ 27 27 #include <linux/device.h> 28 28 #include <pcmcia/ss.h> 29 + #include <asm/atomic.h> 29 30 30 31 /* 31 32 * PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus ··· 95 94 config_req_t conf; 96 95 window_handle_t win; 97 96 98 - /* Is the device suspended, or in the process of 99 - * being removed? */ 97 + /* Is the device suspended? */ 100 98 u16 suspended:1; 101 - u16 _removed:1; 102 99 103 100 /* Flags whether io, irq, win configurations were 104 101 * requested, and whether the configuration is "locked" */ ··· 114 115 u16 has_card_id:1; 115 116 u16 has_func_id:1; 116 117 117 - u16 reserved:3; 118 + u16 reserved:4; 118 119 119 120 u8 func_id; 120 121 u16 manf_id;
+3 -5
include/pcmcia/ss.h
··· 224 224 225 225 /* 16-bit state: */ 226 226 struct { 227 - /* PCMCIA card is present in socket */ 228 - u8 present:1; 229 227 /* "master" ioctl is used */ 230 228 u8 busy:1; 231 - /* pcmcia module is being unloaded */ 232 - u8 dead:1; 233 229 /* the PCMCIA card consists of two pseudo devices */ 234 230 u8 has_pfc:1; 235 231 236 - u8 reserved:4; 232 + u8 reserved:6; 237 233 } pcmcia_state; 238 234 235 + /* non-zero if PCMCIA card is present */ 236 + atomic_t present; 239 237 240 238 #ifdef CONFIG_PCMCIA_IOCTL 241 239 struct user_info_t *user;