diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2007-08-05 14:36:11 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.localdomain> | 2007-10-12 14:50:59 -0400 |
commit | 7c07d613d22680f1caf2bd9ee49838ec7730b9da (patch) | |
tree | 61e8161d4ffefec526ad2cfbe0c676072407da4e /drivers/scsi/sg.c | |
parent | 4390e60163979621f59e3a25a260289986eacb85 (diff) |
[SCSI] sg: use idr to replace static arrays
sg uses a scheme to reallocate a single contiguous array of all its
pointers for lookup and management. This didn't matter too much when sg
could only attach 256 nodes, but now the maximum has been bumped up to
32k we're starting to push the limits of the maximum allocatable
contiguous memory. The solution to this is to eliminate the static
array and do everything via idr, which this patch does.
Acked-by: Douglas Gilbert <dougg@torque.net>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 253 |
1 files changed, 112 insertions, 141 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index fdc6618c1f61..f6f5fc7d0cee 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -43,6 +43,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ | |||
43 | #include <linux/poll.h> | 43 | #include <linux/poll.h> |
44 | #include <linux/moduleparam.h> | 44 | #include <linux/moduleparam.h> |
45 | #include <linux/cdev.h> | 45 | #include <linux/cdev.h> |
46 | #include <linux/idr.h> | ||
46 | #include <linux/seq_file.h> | 47 | #include <linux/seq_file.h> |
47 | #include <linux/blkdev.h> | 48 | #include <linux/blkdev.h> |
48 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
@@ -99,12 +100,11 @@ static int scatter_elem_sz_prev = SG_SCATTER_SZ; | |||
99 | #define SG_SECTOR_SZ 512 | 100 | #define SG_SECTOR_SZ 512 |
100 | #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) | 101 | #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1) |
101 | 102 | ||
102 | #define SG_DEV_ARR_LUMP 32 /* amount to over allocate sg_dev_arr by */ | ||
103 | |||
104 | static int sg_add(struct class_device *, struct class_interface *); | 103 | static int sg_add(struct class_device *, struct class_interface *); |
105 | static void sg_remove(struct class_device *, struct class_interface *); | 104 | static void sg_remove(struct class_device *, struct class_interface *); |
106 | 105 | ||
107 | static DEFINE_RWLOCK(sg_dev_arr_lock); /* Also used to lock | 106 | static DEFINE_IDR(sg_index_idr); |
107 | static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock | ||
108 | file descriptor list for device */ | 108 | file descriptor list for device */ |
109 | 109 | ||
110 | static struct class_interface sg_interface = { | 110 | static struct class_interface sg_interface = { |
@@ -162,6 +162,7 @@ typedef struct sg_device { /* holds the state of each scsi generic device */ | |||
162 | struct scsi_device *device; | 162 | struct scsi_device *device; |
163 | wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ | 163 | wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ |
164 | int sg_tablesize; /* adapter's max scatter-gather table size */ | 164 | int sg_tablesize; /* adapter's max scatter-gather table size */ |
165 | u32 index; /* device index number */ | ||
165 | Sg_fd *headfp; /* first open fd belonging to this device */ | 166 | Sg_fd *headfp; /* first open fd belonging to this device */ |
166 | volatile char detached; /* 0->attached, 1->detached pending removal */ | 167 | volatile char detached; /* 0->attached, 1->detached pending removal */ |
167 | volatile char exclude; /* opened for exclusive access */ | 168 | volatile char exclude; /* opened for exclusive access */ |
@@ -209,10 +210,6 @@ static Sg_device *sg_get_dev(int dev); | |||
209 | static int sg_last_dev(void); | 210 | static int sg_last_dev(void); |
210 | #endif | 211 | #endif |
211 | 212 | ||
212 | static Sg_device **sg_dev_arr = NULL; | ||
213 | static int sg_dev_max; | ||
214 | static int sg_nr_dev; | ||
215 | |||
216 | #define SZ_SG_HEADER sizeof(struct sg_header) | 213 | #define SZ_SG_HEADER sizeof(struct sg_header) |
217 | #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) | 214 | #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) |
218 | #define SZ_SG_IOVEC sizeof(sg_iovec_t) | 215 | #define SZ_SG_IOVEC sizeof(sg_iovec_t) |
@@ -1331,40 +1328,35 @@ static struct class *sg_sysfs_class; | |||
1331 | 1328 | ||
1332 | static int sg_sysfs_valid = 0; | 1329 | static int sg_sysfs_valid = 0; |
1333 | 1330 | ||
1334 | static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) | 1331 | static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) |
1335 | { | 1332 | { |
1336 | struct request_queue *q = scsidp->request_queue; | 1333 | struct request_queue *q = scsidp->request_queue; |
1337 | Sg_device *sdp; | 1334 | Sg_device *sdp; |
1338 | unsigned long iflags; | 1335 | unsigned long iflags; |
1339 | void *old_sg_dev_arr = NULL; | 1336 | int error; |
1340 | int k, error; | 1337 | u32 k; |
1341 | 1338 | ||
1342 | sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL); | 1339 | sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL); |
1343 | if (!sdp) { | 1340 | if (!sdp) { |
1344 | printk(KERN_WARNING "kmalloc Sg_device failure\n"); | 1341 | printk(KERN_WARNING "kmalloc Sg_device failure\n"); |
1345 | return -ENOMEM; | 1342 | return ERR_PTR(-ENOMEM); |
1343 | } | ||
1344 | error = -ENOMEM; | ||
1345 | if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) { | ||
1346 | printk(KERN_WARNING "idr expansion Sg_device failure\n"); | ||
1347 | goto out; | ||
1346 | } | 1348 | } |
1347 | 1349 | ||
1348 | write_lock_irqsave(&sg_dev_arr_lock, iflags); | 1350 | write_lock_irqsave(&sg_index_lock, iflags); |
1349 | if (unlikely(sg_nr_dev >= sg_dev_max)) { /* try to resize */ | 1351 | error = idr_get_new(&sg_index_idr, sdp, &k); |
1350 | Sg_device **tmp_da; | 1352 | write_unlock_irqrestore(&sg_index_lock, iflags); |
1351 | int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP; | ||
1352 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | ||
1353 | |||
1354 | tmp_da = kzalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL); | ||
1355 | if (unlikely(!tmp_da)) | ||
1356 | goto expand_failed; | ||
1357 | 1353 | ||
1358 | write_lock_irqsave(&sg_dev_arr_lock, iflags); | 1354 | if (error) { |
1359 | memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *)); | 1355 | printk(KERN_WARNING "idr allocation Sg_device failure: %d\n", |
1360 | old_sg_dev_arr = sg_dev_arr; | 1356 | error); |
1361 | sg_dev_arr = tmp_da; | 1357 | goto out; |
1362 | sg_dev_max = tmp_dev_max; | ||
1363 | } | 1358 | } |
1364 | 1359 | ||
1365 | for (k = 0; k < sg_dev_max; k++) | ||
1366 | if (!sg_dev_arr[k]) | ||
1367 | break; | ||
1368 | if (unlikely(k >= SG_MAX_DEVS)) | 1360 | if (unlikely(k >= SG_MAX_DEVS)) |
1369 | goto overflow; | 1361 | goto overflow; |
1370 | 1362 | ||
@@ -1375,25 +1367,17 @@ static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) | |||
1375 | sdp->device = scsidp; | 1367 | sdp->device = scsidp; |
1376 | init_waitqueue_head(&sdp->o_excl_wait); | 1368 | init_waitqueue_head(&sdp->o_excl_wait); |
1377 | sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); | 1369 | sdp->sg_tablesize = min(q->max_hw_segments, q->max_phys_segments); |
1370 | sdp->index = k; | ||
1378 | 1371 | ||
1379 | sg_nr_dev++; | 1372 | error = 0; |
1380 | sg_dev_arr[k] = sdp; | ||
1381 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | ||
1382 | error = k; | ||
1383 | |||
1384 | out: | 1373 | out: |
1385 | if (error < 0) | 1374 | if (error) { |
1386 | kfree(sdp); | 1375 | kfree(sdp); |
1387 | kfree(old_sg_dev_arr); | 1376 | return ERR_PTR(error); |
1388 | return error; | 1377 | } |
1389 | 1378 | return sdp; | |
1390 | expand_failed: | ||
1391 | printk(KERN_WARNING "sg_alloc: device array cannot be resized\n"); | ||
1392 | error = -ENOMEM; | ||
1393 | goto out; | ||
1394 | 1379 | ||
1395 | overflow: | 1380 | overflow: |
1396 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | ||
1397 | sdev_printk(KERN_WARNING, scsidp, | 1381 | sdev_printk(KERN_WARNING, scsidp, |
1398 | "Unable to attach sg device type=%d, minor " | 1382 | "Unable to attach sg device type=%d, minor " |
1399 | "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1); | 1383 | "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1); |
@@ -1408,7 +1392,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) | |||
1408 | struct gendisk *disk; | 1392 | struct gendisk *disk; |
1409 | Sg_device *sdp = NULL; | 1393 | Sg_device *sdp = NULL; |
1410 | struct cdev * cdev = NULL; | 1394 | struct cdev * cdev = NULL; |
1411 | int error, k; | 1395 | int error; |
1412 | unsigned long iflags; | 1396 | unsigned long iflags; |
1413 | 1397 | ||
1414 | disk = alloc_disk(1); | 1398 | disk = alloc_disk(1); |
@@ -1427,15 +1411,15 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) | |||
1427 | cdev->owner = THIS_MODULE; | 1411 | cdev->owner = THIS_MODULE; |
1428 | cdev->ops = &sg_fops; | 1412 | cdev->ops = &sg_fops; |
1429 | 1413 | ||
1430 | error = sg_alloc(disk, scsidp); | 1414 | sdp = sg_alloc(disk, scsidp); |
1431 | if (error < 0) { | 1415 | if (IS_ERR(sdp)) { |
1432 | printk(KERN_WARNING "sg_alloc failed\n"); | 1416 | printk(KERN_WARNING "sg_alloc failed\n"); |
1417 | error = PTR_ERR(sdp); | ||
1433 | goto out; | 1418 | goto out; |
1434 | } | 1419 | } |
1435 | k = error; | ||
1436 | sdp = sg_dev_arr[k]; | ||
1437 | 1420 | ||
1438 | error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); | 1421 | class_set_devdata(cl_dev, sdp); |
1422 | error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1); | ||
1439 | if (error) | 1423 | if (error) |
1440 | goto cdev_add_err; | 1424 | goto cdev_add_err; |
1441 | 1425 | ||
@@ -1444,8 +1428,8 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) | |||
1444 | struct class_device * sg_class_member; | 1428 | struct class_device * sg_class_member; |
1445 | 1429 | ||
1446 | sg_class_member = class_device_create(sg_sysfs_class, NULL, | 1430 | sg_class_member = class_device_create(sg_sysfs_class, NULL, |
1447 | MKDEV(SCSI_GENERIC_MAJOR, k), | 1431 | MKDEV(SCSI_GENERIC_MAJOR, sdp->index), |
1448 | cl_dev->dev, "%s", | 1432 | cl_dev->dev, "%s", |
1449 | disk->disk_name); | 1433 | disk->disk_name); |
1450 | if (IS_ERR(sg_class_member)) | 1434 | if (IS_ERR(sg_class_member)) |
1451 | printk(KERN_WARNING "sg_add: " | 1435 | printk(KERN_WARNING "sg_add: " |
@@ -1455,21 +1439,21 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) | |||
1455 | &sg_class_member->kobj, "generic"); | 1439 | &sg_class_member->kobj, "generic"); |
1456 | if (error) | 1440 | if (error) |
1457 | printk(KERN_ERR "sg_add: unable to make symlink " | 1441 | printk(KERN_ERR "sg_add: unable to make symlink " |
1458 | "'generic' back to sg%d\n", k); | 1442 | "'generic' back to sg%d\n", sdp->index); |
1459 | } else | 1443 | } else |
1460 | printk(KERN_WARNING "sg_add: sg_sys INvalid\n"); | 1444 | printk(KERN_WARNING "sg_add: sg_sys Invalid\n"); |
1461 | 1445 | ||
1462 | sdev_printk(KERN_NOTICE, scsidp, | 1446 | sdev_printk(KERN_NOTICE, scsidp, |
1463 | "Attached scsi generic sg%d type %d\n", k,scsidp->type); | 1447 | "Attached scsi generic sg%d type %d\n", sdp->index, |
1448 | scsidp->type); | ||
1464 | 1449 | ||
1465 | return 0; | 1450 | return 0; |
1466 | 1451 | ||
1467 | cdev_add_err: | 1452 | cdev_add_err: |
1468 | write_lock_irqsave(&sg_dev_arr_lock, iflags); | 1453 | write_lock_irqsave(&sg_index_lock, iflags); |
1469 | kfree(sg_dev_arr[k]); | 1454 | idr_remove(&sg_index_idr, sdp->index); |
1470 | sg_dev_arr[k] = NULL; | 1455 | write_unlock_irqrestore(&sg_index_lock, iflags); |
1471 | sg_nr_dev--; | 1456 | kfree(sdp); |
1472 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | ||
1473 | 1457 | ||
1474 | out: | 1458 | out: |
1475 | put_disk(disk); | 1459 | put_disk(disk); |
@@ -1482,64 +1466,56 @@ static void | |||
1482 | sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) | 1466 | sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) |
1483 | { | 1467 | { |
1484 | struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); | 1468 | struct scsi_device *scsidp = to_scsi_device(cl_dev->dev); |
1485 | Sg_device *sdp = NULL; | 1469 | Sg_device *sdp = class_get_devdata(cl_dev); |
1486 | unsigned long iflags; | 1470 | unsigned long iflags; |
1487 | Sg_fd *sfp; | 1471 | Sg_fd *sfp; |
1488 | Sg_fd *tsfp; | 1472 | Sg_fd *tsfp; |
1489 | Sg_request *srp; | 1473 | Sg_request *srp; |
1490 | Sg_request *tsrp; | 1474 | Sg_request *tsrp; |
1491 | int k, delay; | 1475 | int delay; |
1492 | 1476 | ||
1493 | if (NULL == sg_dev_arr) | 1477 | if (!sdp) |
1494 | return; | 1478 | return; |
1479 | |||
1495 | delay = 0; | 1480 | delay = 0; |
1496 | write_lock_irqsave(&sg_dev_arr_lock, iflags); | 1481 | write_lock_irqsave(&sg_index_lock, iflags); |
1497 | for (k = 0; k < sg_dev_max; k++) { | 1482 | if (sdp->headfp) { |
1498 | sdp = sg_dev_arr[k]; | 1483 | sdp->detached = 1; |
1499 | if ((NULL == sdp) || (sdp->device != scsidp)) | 1484 | for (sfp = sdp->headfp; sfp; sfp = tsfp) { |
1500 | continue; /* dirty but lowers nesting */ | 1485 | tsfp = sfp->nextfp; |
1501 | if (sdp->headfp) { | 1486 | for (srp = sfp->headrp; srp; srp = tsrp) { |
1502 | sdp->detached = 1; | 1487 | tsrp = srp->nextrp; |
1503 | for (sfp = sdp->headfp; sfp; sfp = tsfp) { | 1488 | if (sfp->closed || (0 == sg_srp_done(srp, sfp))) |
1504 | tsfp = sfp->nextfp; | 1489 | sg_finish_rem_req(srp); |
1505 | for (srp = sfp->headrp; srp; srp = tsrp) { | ||
1506 | tsrp = srp->nextrp; | ||
1507 | if (sfp->closed || (0 == sg_srp_done(srp, sfp))) | ||
1508 | sg_finish_rem_req(srp); | ||
1509 | } | ||
1510 | if (sfp->closed) { | ||
1511 | scsi_device_put(sdp->device); | ||
1512 | __sg_remove_sfp(sdp, sfp); | ||
1513 | } else { | ||
1514 | delay = 1; | ||
1515 | wake_up_interruptible(&sfp->read_wait); | ||
1516 | kill_fasync(&sfp->async_qp, SIGPOLL, | ||
1517 | POLL_HUP); | ||
1518 | } | ||
1519 | } | 1490 | } |
1520 | SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", k)); | 1491 | if (sfp->closed) { |
1521 | if (NULL == sdp->headfp) { | 1492 | scsi_device_put(sdp->device); |
1522 | sg_dev_arr[k] = NULL; | 1493 | __sg_remove_sfp(sdp, sfp); |
1494 | } else { | ||
1495 | delay = 1; | ||
1496 | wake_up_interruptible(&sfp->read_wait); | ||
1497 | kill_fasync(&sfp->async_qp, SIGPOLL, | ||
1498 | POLL_HUP); | ||
1523 | } | 1499 | } |
1524 | } else { /* nothing active, simple case */ | ||
1525 | SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", k)); | ||
1526 | sg_dev_arr[k] = NULL; | ||
1527 | } | 1500 | } |
1528 | sg_nr_dev--; | 1501 | SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d, dirty\n", sdp->index)); |
1529 | break; | 1502 | if (NULL == sdp->headfp) { |
1530 | } | 1503 | idr_remove(&sg_index_idr, sdp->index); |
1531 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | 1504 | } |
1532 | 1505 | } else { /* nothing active, simple case */ | |
1533 | if (sdp) { | 1506 | SCSI_LOG_TIMEOUT(3, printk("sg_remove: dev=%d\n", sdp->index)); |
1534 | sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); | 1507 | idr_remove(&sg_index_idr, sdp->index); |
1535 | class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k)); | 1508 | } |
1536 | cdev_del(sdp->cdev); | 1509 | write_unlock_irqrestore(&sg_index_lock, iflags); |
1537 | sdp->cdev = NULL; | 1510 | |
1538 | put_disk(sdp->disk); | 1511 | sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); |
1539 | sdp->disk = NULL; | 1512 | class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); |
1540 | if (NULL == sdp->headfp) | 1513 | cdev_del(sdp->cdev); |
1541 | kfree((char *) sdp); | 1514 | sdp->cdev = NULL; |
1542 | } | 1515 | put_disk(sdp->disk); |
1516 | sdp->disk = NULL; | ||
1517 | if (NULL == sdp->headfp) | ||
1518 | kfree(sdp); | ||
1543 | 1519 | ||
1544 | if (delay) | 1520 | if (delay) |
1545 | msleep(10); /* dirty detach so delay device destruction */ | 1521 | msleep(10); /* dirty detach so delay device destruction */ |
@@ -1609,9 +1585,7 @@ exit_sg(void) | |||
1609 | sg_sysfs_valid = 0; | 1585 | sg_sysfs_valid = 0; |
1610 | unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), | 1586 | unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), |
1611 | SG_MAX_DEVS); | 1587 | SG_MAX_DEVS); |
1612 | kfree((char *)sg_dev_arr); | 1588 | idr_destroy(&sg_index_idr); |
1613 | sg_dev_arr = NULL; | ||
1614 | sg_dev_max = 0; | ||
1615 | } | 1589 | } |
1616 | 1590 | ||
1617 | static int | 1591 | static int |
@@ -2331,10 +2305,10 @@ sg_get_nth_sfp(Sg_device * sdp, int nth) | |||
2331 | unsigned long iflags; | 2305 | unsigned long iflags; |
2332 | int k; | 2306 | int k; |
2333 | 2307 | ||
2334 | read_lock_irqsave(&sg_dev_arr_lock, iflags); | 2308 | read_lock_irqsave(&sg_index_lock, iflags); |
2335 | for (k = 0, resp = sdp->headfp; resp && (k < nth); | 2309 | for (k = 0, resp = sdp->headfp; resp && (k < nth); |
2336 | ++k, resp = resp->nextfp) ; | 2310 | ++k, resp = resp->nextfp) ; |
2337 | read_unlock_irqrestore(&sg_dev_arr_lock, iflags); | 2311 | read_unlock_irqrestore(&sg_index_lock, iflags); |
2338 | return resp; | 2312 | return resp; |
2339 | } | 2313 | } |
2340 | #endif | 2314 | #endif |
@@ -2361,7 +2335,7 @@ sg_add_sfp(Sg_device * sdp, int dev) | |||
2361 | sfp->cmd_q = SG_DEF_COMMAND_Q; | 2335 | sfp->cmd_q = SG_DEF_COMMAND_Q; |
2362 | sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; | 2336 | sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; |
2363 | sfp->parentdp = sdp; | 2337 | sfp->parentdp = sdp; |
2364 | write_lock_irqsave(&sg_dev_arr_lock, iflags); | 2338 | write_lock_irqsave(&sg_index_lock, iflags); |
2365 | if (!sdp->headfp) | 2339 | if (!sdp->headfp) |
2366 | sdp->headfp = sfp; | 2340 | sdp->headfp = sfp; |
2367 | else { /* add to tail of existing list */ | 2341 | else { /* add to tail of existing list */ |
@@ -2370,7 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev) | |||
2370 | pfp = pfp->nextfp; | 2344 | pfp = pfp->nextfp; |
2371 | pfp->nextfp = sfp; | 2345 | pfp->nextfp = sfp; |
2372 | } | 2346 | } |
2373 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | 2347 | write_unlock_irqrestore(&sg_index_lock, iflags); |
2374 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); | 2348 | SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); |
2375 | if (unlikely(sg_big_buff != def_reserved_size)) | 2349 | if (unlikely(sg_big_buff != def_reserved_size)) |
2376 | sg_big_buff = def_reserved_size; | 2350 | sg_big_buff = def_reserved_size; |
@@ -2431,22 +2405,14 @@ sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) | |||
2431 | if (0 == dirty) { | 2405 | if (0 == dirty) { |
2432 | unsigned long iflags; | 2406 | unsigned long iflags; |
2433 | 2407 | ||
2434 | write_lock_irqsave(&sg_dev_arr_lock, iflags); | 2408 | write_lock_irqsave(&sg_index_lock, iflags); |
2435 | __sg_remove_sfp(sdp, sfp); | 2409 | __sg_remove_sfp(sdp, sfp); |
2436 | if (sdp->detached && (NULL == sdp->headfp)) { | 2410 | if (sdp->detached && (NULL == sdp->headfp)) { |
2437 | int k, maxd; | 2411 | idr_remove(&sg_index_idr, sdp->index); |
2438 | 2412 | kfree(sdp); | |
2439 | maxd = sg_dev_max; | ||
2440 | for (k = 0; k < maxd; ++k) { | ||
2441 | if (sdp == sg_dev_arr[k]) | ||
2442 | break; | ||
2443 | } | ||
2444 | if (k < maxd) | ||
2445 | sg_dev_arr[k] = NULL; | ||
2446 | kfree((char *) sdp); | ||
2447 | res = 1; | 2413 | res = 1; |
2448 | } | 2414 | } |
2449 | write_unlock_irqrestore(&sg_dev_arr_lock, iflags); | 2415 | write_unlock_irqrestore(&sg_index_lock, iflags); |
2450 | } else { | 2416 | } else { |
2451 | /* MOD_INC's to inhibit unloading sg and associated adapter driver */ | 2417 | /* MOD_INC's to inhibit unloading sg and associated adapter driver */ |
2452 | /* only bump the access_count if we actually succeeded in | 2418 | /* only bump the access_count if we actually succeeded in |
@@ -2546,16 +2512,25 @@ sg_allow_access(unsigned char opcode, char dev_type) | |||
2546 | 2512 | ||
2547 | #ifdef CONFIG_SCSI_PROC_FS | 2513 | #ifdef CONFIG_SCSI_PROC_FS |
2548 | static int | 2514 | static int |
2515 | sg_idr_max_id(int id, void *p, void *data) | ||
2516 | { | ||
2517 | int *k = data; | ||
2518 | |||
2519 | if (*k < id) | ||
2520 | *k = id; | ||
2521 | |||
2522 | return 0; | ||
2523 | } | ||
2524 | |||
2525 | static int | ||
2549 | sg_last_dev(void) | 2526 | sg_last_dev(void) |
2550 | { | 2527 | { |
2551 | int k; | 2528 | int k = 0; |
2552 | unsigned long iflags; | 2529 | unsigned long iflags; |
2553 | 2530 | ||
2554 | read_lock_irqsave(&sg_dev_arr_lock, iflags); | 2531 | read_lock_irqsave(&sg_index_lock, iflags); |
2555 | for (k = sg_dev_max - 1; k >= 0; --k) | 2532 | idr_for_each(&sg_index_idr, sg_idr_max_id, &k); |
2556 | if (sg_dev_arr[k] && sg_dev_arr[k]->device) | 2533 | read_unlock_irqrestore(&sg_index_lock, iflags); |
2557 | break; | ||
2558 | read_unlock_irqrestore(&sg_dev_arr_lock, iflags); | ||
2559 | return k + 1; /* origin 1 */ | 2534 | return k + 1; /* origin 1 */ |
2560 | } | 2535 | } |
2561 | #endif | 2536 | #endif |
@@ -2563,15 +2538,13 @@ sg_last_dev(void) | |||
2563 | static Sg_device * | 2538 | static Sg_device * |
2564 | sg_get_dev(int dev) | 2539 | sg_get_dev(int dev) |
2565 | { | 2540 | { |
2566 | Sg_device *sdp = NULL; | 2541 | Sg_device *sdp; |
2567 | unsigned long iflags; | 2542 | unsigned long iflags; |
2568 | 2543 | ||
2569 | if (sg_dev_arr && (dev >= 0)) { | 2544 | read_lock_irqsave(&sg_index_lock, iflags); |
2570 | read_lock_irqsave(&sg_dev_arr_lock, iflags); | 2545 | sdp = idr_find(&sg_index_idr, dev); |
2571 | if (dev < sg_dev_max) | 2546 | read_unlock_irqrestore(&sg_index_lock, iflags); |
2572 | sdp = sg_dev_arr[dev]; | 2547 | |
2573 | read_unlock_irqrestore(&sg_dev_arr_lock, iflags); | ||
2574 | } | ||
2575 | return sdp; | 2548 | return sdp; |
2576 | } | 2549 | } |
2577 | 2550 | ||
@@ -2805,8 +2778,6 @@ static void * dev_seq_start(struct seq_file *s, loff_t *pos) | |||
2805 | if (! it) | 2778 | if (! it) |
2806 | return NULL; | 2779 | return NULL; |
2807 | 2780 | ||
2808 | if (NULL == sg_dev_arr) | ||
2809 | return NULL; | ||
2810 | it->index = *pos; | 2781 | it->index = *pos; |
2811 | it->max = sg_last_dev(); | 2782 | it->max = sg_last_dev(); |
2812 | if (it->index >= it->max) | 2783 | if (it->index >= it->max) |
@@ -2942,8 +2913,8 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) | |||
2942 | Sg_device *sdp; | 2913 | Sg_device *sdp; |
2943 | 2914 | ||
2944 | if (it && (0 == it->index)) { | 2915 | if (it && (0 == it->index)) { |
2945 | seq_printf(s, "dev_max(currently)=%d max_active_device=%d " | 2916 | seq_printf(s, "max_active_device=%d(origin 1)\n", |
2946 | "(origin 1)\n", sg_dev_max, (int)it->max); | 2917 | (int)it->max); |
2947 | seq_printf(s, " def_reserved_size=%d\n", sg_big_buff); | 2918 | seq_printf(s, " def_reserved_size=%d\n", sg_big_buff); |
2948 | } | 2919 | } |
2949 | sdp = it ? sg_get_dev(it->index) : NULL; | 2920 | sdp = it ? sg_get_dev(it->index) : NULL; |