diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2011-07-31 16:08:04 -0400 |
---|---|---|
committer | Jens Axboe <jaxboe@fusionio.com> | 2011-07-31 16:08:04 -0400 |
commit | 34dd82afd27da2537199d7f71f1542501c6f96e7 (patch) | |
tree | 35688ccd99d99e16f3c82829eb824703e7460822 /drivers | |
parent | aa387cc895672b00f807ad7c734a2defaf677712 (diff) |
loop: replace linked list of allocated devices with an idr index
Replace the linked list, that keeps track of allocated devices, with an
idr index to allow a more efficient lookup of devices.
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/loop.c | 152 |
1 files changed, 80 insertions, 72 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 76c8da78212b..f58532e77777 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c | |||
@@ -78,8 +78,8 @@ | |||
78 | 78 | ||
79 | #include <asm/uaccess.h> | 79 | #include <asm/uaccess.h> |
80 | 80 | ||
81 | static LIST_HEAD(loop_devices); | 81 | static DEFINE_IDR(loop_index_idr); |
82 | static DEFINE_MUTEX(loop_devices_mutex); | 82 | static DEFINE_MUTEX(loop_index_mutex); |
83 | 83 | ||
84 | static int max_part; | 84 | static int max_part; |
85 | static int part_shift; | 85 | static int part_shift; |
@@ -722,17 +722,10 @@ static inline int is_loop_device(struct file *file) | |||
722 | static ssize_t loop_attr_show(struct device *dev, char *page, | 722 | static ssize_t loop_attr_show(struct device *dev, char *page, |
723 | ssize_t (*callback)(struct loop_device *, char *)) | 723 | ssize_t (*callback)(struct loop_device *, char *)) |
724 | { | 724 | { |
725 | struct loop_device *l, *lo = NULL; | 725 | struct gendisk *disk = dev_to_disk(dev); |
726 | 726 | struct loop_device *lo = disk->private_data; | |
727 | mutex_lock(&loop_devices_mutex); | ||
728 | list_for_each_entry(l, &loop_devices, lo_list) | ||
729 | if (disk_to_dev(l->lo_disk) == dev) { | ||
730 | lo = l; | ||
731 | break; | ||
732 | } | ||
733 | mutex_unlock(&loop_devices_mutex); | ||
734 | 727 | ||
735 | return lo ? callback(lo, page) : -EIO; | 728 | return callback(lo, page); |
736 | } | 729 | } |
737 | 730 | ||
738 | #define LOOP_ATTR_RO(_name) \ | 731 | #define LOOP_ATTR_RO(_name) \ |
@@ -1557,40 +1550,64 @@ int loop_register_transfer(struct loop_func_table *funcs) | |||
1557 | return 0; | 1550 | return 0; |
1558 | } | 1551 | } |
1559 | 1552 | ||
1553 | static int unregister_transfer_cb(int id, void *ptr, void *data) | ||
1554 | { | ||
1555 | struct loop_device *lo = ptr; | ||
1556 | struct loop_func_table *xfer = data; | ||
1557 | |||
1558 | mutex_lock(&lo->lo_ctl_mutex); | ||
1559 | if (lo->lo_encryption == xfer) | ||
1560 | loop_release_xfer(lo); | ||
1561 | mutex_unlock(&lo->lo_ctl_mutex); | ||
1562 | return 0; | ||
1563 | } | ||
1564 | |||
1560 | int loop_unregister_transfer(int number) | 1565 | int loop_unregister_transfer(int number) |
1561 | { | 1566 | { |
1562 | unsigned int n = number; | 1567 | unsigned int n = number; |
1563 | struct loop_device *lo; | ||
1564 | struct loop_func_table *xfer; | 1568 | struct loop_func_table *xfer; |
1565 | 1569 | ||
1566 | if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL) | 1570 | if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL) |
1567 | return -EINVAL; | 1571 | return -EINVAL; |
1568 | 1572 | ||
1569 | xfer_funcs[n] = NULL; | 1573 | xfer_funcs[n] = NULL; |
1570 | 1574 | idr_for_each(&loop_index_idr, &unregister_transfer_cb, xfer); | |
1571 | list_for_each_entry(lo, &loop_devices, lo_list) { | ||
1572 | mutex_lock(&lo->lo_ctl_mutex); | ||
1573 | |||
1574 | if (lo->lo_encryption == xfer) | ||
1575 | loop_release_xfer(lo); | ||
1576 | |||
1577 | mutex_unlock(&lo->lo_ctl_mutex); | ||
1578 | } | ||
1579 | |||
1580 | return 0; | 1575 | return 0; |
1581 | } | 1576 | } |
1582 | 1577 | ||
1583 | EXPORT_SYMBOL(loop_register_transfer); | 1578 | EXPORT_SYMBOL(loop_register_transfer); |
1584 | EXPORT_SYMBOL(loop_unregister_transfer); | 1579 | EXPORT_SYMBOL(loop_unregister_transfer); |
1585 | 1580 | ||
1586 | static struct loop_device *loop_alloc(int i) | 1581 | static int loop_add(struct loop_device **l, int i) |
1587 | { | 1582 | { |
1588 | struct loop_device *lo; | 1583 | struct loop_device *lo; |
1589 | struct gendisk *disk; | 1584 | struct gendisk *disk; |
1585 | int err; | ||
1590 | 1586 | ||
1591 | lo = kzalloc(sizeof(*lo), GFP_KERNEL); | 1587 | lo = kzalloc(sizeof(*lo), GFP_KERNEL); |
1592 | if (!lo) | 1588 | if (!lo) { |
1589 | err = -ENOMEM; | ||
1593 | goto out; | 1590 | goto out; |
1591 | } | ||
1592 | |||
1593 | err = idr_pre_get(&loop_index_idr, GFP_KERNEL); | ||
1594 | if (err < 0) | ||
1595 | goto out_free_dev; | ||
1596 | |||
1597 | if (i >= 0) { | ||
1598 | int m; | ||
1599 | |||
1600 | /* create specific i in the index */ | ||
1601 | err = idr_get_new_above(&loop_index_idr, lo, i, &m); | ||
1602 | if (err >= 0 && i != m) { | ||
1603 | idr_remove(&loop_index_idr, m); | ||
1604 | err = -EEXIST; | ||
1605 | } | ||
1606 | } else { | ||
1607 | err = -EINVAL; | ||
1608 | } | ||
1609 | if (err < 0) | ||
1610 | goto out_free_dev; | ||
1594 | 1611 | ||
1595 | lo->lo_queue = blk_alloc_queue(GFP_KERNEL); | 1612 | lo->lo_queue = blk_alloc_queue(GFP_KERNEL); |
1596 | if (!lo->lo_queue) | 1613 | if (!lo->lo_queue) |
@@ -1611,56 +1628,54 @@ static struct loop_device *loop_alloc(int i) | |||
1611 | disk->private_data = lo; | 1628 | disk->private_data = lo; |
1612 | disk->queue = lo->lo_queue; | 1629 | disk->queue = lo->lo_queue; |
1613 | sprintf(disk->disk_name, "loop%d", i); | 1630 | sprintf(disk->disk_name, "loop%d", i); |
1614 | return lo; | 1631 | add_disk(disk); |
1632 | *l = lo; | ||
1633 | return lo->lo_number; | ||
1615 | 1634 | ||
1616 | out_free_queue: | 1635 | out_free_queue: |
1617 | blk_cleanup_queue(lo->lo_queue); | 1636 | blk_cleanup_queue(lo->lo_queue); |
1618 | out_free_dev: | 1637 | out_free_dev: |
1619 | kfree(lo); | 1638 | kfree(lo); |
1620 | out: | 1639 | out: |
1621 | return NULL; | 1640 | return err; |
1622 | } | 1641 | } |
1623 | 1642 | ||
1624 | static void loop_free(struct loop_device *lo) | 1643 | static void loop_remove(struct loop_device *lo) |
1625 | { | 1644 | { |
1645 | del_gendisk(lo->lo_disk); | ||
1626 | blk_cleanup_queue(lo->lo_queue); | 1646 | blk_cleanup_queue(lo->lo_queue); |
1627 | put_disk(lo->lo_disk); | 1647 | put_disk(lo->lo_disk); |
1628 | list_del(&lo->lo_list); | ||
1629 | kfree(lo); | 1648 | kfree(lo); |
1630 | } | 1649 | } |
1631 | 1650 | ||
1632 | static struct loop_device *loop_init_one(int i) | 1651 | static int loop_lookup(struct loop_device **l, int i) |
1633 | { | 1652 | { |
1634 | struct loop_device *lo; | 1653 | struct loop_device *lo; |
1654 | int ret = -ENODEV; | ||
1635 | 1655 | ||
1636 | list_for_each_entry(lo, &loop_devices, lo_list) { | 1656 | lo = idr_find(&loop_index_idr, i); |
1637 | if (lo->lo_number == i) | ||
1638 | return lo; | ||
1639 | } | ||
1640 | |||
1641 | lo = loop_alloc(i); | ||
1642 | if (lo) { | 1657 | if (lo) { |
1643 | add_disk(lo->lo_disk); | 1658 | *l = lo; |
1644 | list_add_tail(&lo->lo_list, &loop_devices); | 1659 | ret = lo->lo_number; |
1645 | } | 1660 | } |
1646 | return lo; | 1661 | return ret; |
1647 | } | ||
1648 | |||
1649 | static void loop_del_one(struct loop_device *lo) | ||
1650 | { | ||
1651 | del_gendisk(lo->lo_disk); | ||
1652 | loop_free(lo); | ||
1653 | } | 1662 | } |
1654 | 1663 | ||
1655 | static struct kobject *loop_probe(dev_t dev, int *part, void *data) | 1664 | static struct kobject *loop_probe(dev_t dev, int *part, void *data) |
1656 | { | 1665 | { |
1657 | struct loop_device *lo; | 1666 | struct loop_device *lo; |
1658 | struct kobject *kobj; | 1667 | struct kobject *kobj; |
1668 | int err; | ||
1659 | 1669 | ||
1660 | mutex_lock(&loop_devices_mutex); | 1670 | mutex_lock(&loop_index_mutex); |
1661 | lo = loop_init_one(MINOR(dev) >> part_shift); | 1671 | err = loop_lookup(&lo, MINOR(dev) >> part_shift); |
1662 | kobj = lo ? get_disk(lo->lo_disk) : ERR_PTR(-ENOMEM); | 1672 | if (err < 0) |
1663 | mutex_unlock(&loop_devices_mutex); | 1673 | err = loop_add(&lo, MINOR(dev) >> part_shift); |
1674 | if (err < 0) | ||
1675 | kobj = ERR_PTR(err); | ||
1676 | else | ||
1677 | kobj = get_disk(lo->lo_disk); | ||
1678 | mutex_unlock(&loop_index_mutex); | ||
1664 | 1679 | ||
1665 | *part = 0; | 1680 | *part = 0; |
1666 | return kobj; | 1681 | return kobj; |
@@ -1670,7 +1685,7 @@ static int __init loop_init(void) | |||
1670 | { | 1685 | { |
1671 | int i, nr; | 1686 | int i, nr; |
1672 | unsigned long range; | 1687 | unsigned long range; |
1673 | struct loop_device *lo, *next; | 1688 | struct loop_device *lo; |
1674 | 1689 | ||
1675 | /* | 1690 | /* |
1676 | * loop module now has a feature to instantiate underlying device | 1691 | * loop module now has a feature to instantiate underlying device |
@@ -1719,43 +1734,36 @@ static int __init loop_init(void) | |||
1719 | if (register_blkdev(LOOP_MAJOR, "loop")) | 1734 | if (register_blkdev(LOOP_MAJOR, "loop")) |
1720 | return -EIO; | 1735 | return -EIO; |
1721 | 1736 | ||
1722 | for (i = 0; i < nr; i++) { | ||
1723 | lo = loop_alloc(i); | ||
1724 | if (!lo) | ||
1725 | goto Enomem; | ||
1726 | list_add_tail(&lo->lo_list, &loop_devices); | ||
1727 | } | ||
1728 | |||
1729 | /* point of no return */ | ||
1730 | |||
1731 | list_for_each_entry(lo, &loop_devices, lo_list) | ||
1732 | add_disk(lo->lo_disk); | ||
1733 | |||
1734 | blk_register_region(MKDEV(LOOP_MAJOR, 0), range, | 1737 | blk_register_region(MKDEV(LOOP_MAJOR, 0), range, |
1735 | THIS_MODULE, loop_probe, NULL, NULL); | 1738 | THIS_MODULE, loop_probe, NULL, NULL); |
1736 | 1739 | ||
1740 | /* pre-create number devices of devices given by config or max_loop */ | ||
1741 | mutex_lock(&loop_index_mutex); | ||
1742 | for (i = 0; i < nr; i++) | ||
1743 | loop_add(&lo, i); | ||
1744 | mutex_unlock(&loop_index_mutex); | ||
1745 | |||
1737 | printk(KERN_INFO "loop: module loaded\n"); | 1746 | printk(KERN_INFO "loop: module loaded\n"); |
1738 | return 0; | 1747 | return 0; |
1748 | } | ||
1739 | 1749 | ||
1740 | Enomem: | 1750 | static int loop_exit_cb(int id, void *ptr, void *data) |
1741 | printk(KERN_INFO "loop: out of memory\n"); | 1751 | { |
1742 | 1752 | struct loop_device *lo = ptr; | |
1743 | list_for_each_entry_safe(lo, next, &loop_devices, lo_list) | ||
1744 | loop_free(lo); | ||
1745 | 1753 | ||
1746 | unregister_blkdev(LOOP_MAJOR, "loop"); | 1754 | loop_remove(lo); |
1747 | return -ENOMEM; | 1755 | return 0; |
1748 | } | 1756 | } |
1749 | 1757 | ||
1750 | static void __exit loop_exit(void) | 1758 | static void __exit loop_exit(void) |
1751 | { | 1759 | { |
1752 | unsigned long range; | 1760 | unsigned long range; |
1753 | struct loop_device *lo, *next; | ||
1754 | 1761 | ||
1755 | range = max_loop ? max_loop << part_shift : 1UL << MINORBITS; | 1762 | range = max_loop ? max_loop << part_shift : 1UL << MINORBITS; |
1756 | 1763 | ||
1757 | list_for_each_entry_safe(lo, next, &loop_devices, lo_list) | 1764 | idr_for_each(&loop_index_idr, &loop_exit_cb, NULL); |
1758 | loop_del_one(lo); | 1765 | idr_remove_all(&loop_index_idr); |
1766 | idr_destroy(&loop_index_idr); | ||
1759 | 1767 | ||
1760 | blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range); | 1768 | blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range); |
1761 | unregister_blkdev(LOOP_MAJOR, "loop"); | 1769 | unregister_blkdev(LOOP_MAJOR, "loop"); |