aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2011-07-31 16:08:04 -0400
committerJens Axboe <jaxboe@fusionio.com>2011-07-31 16:08:04 -0400
commit770fe30a46a12b6fb6b63fbe1737654d28e84844 (patch)
treee8a35712602ca086c41f94d191579ac2dc365cf5 /drivers
parent34dd82afd27da2537199d7f71f1542501c6f96e7 (diff)
loop: add management interface for on-demand device allocation
Loop devices today have a fixed pre-allocated number of usually 8. The number can only be changed at module init time. To find a free device to use, /dev/loop%i needs to be scanned, and all devices need to be opened until a free one is possibly found. This adds a new /dev/loop-control device node, that allows to dynamically find or allocate a free device, and to add and remove loop devices from the running system: LOOP_CTL_ADD adds a specific device. Arg is the number of the device. It returns the device i or a negative error code. LOOP_CTL_REMOVE removes a specific device, Arg is the number the device. It returns the device i or a negative error code. LOOP_CTL_GET_FREE finds the next unbound device or allocates a new one. No arg is given. It returns the device i or a negative error code. The loop kernel module gets automatically loaded when /dev/loop-control is accessed the first time. The alias specified in the module, instructs udev to create this 'dead' device node, even when the module is not loaded. Example: cfd = open("/dev/loop-control", O_RDWR); # add a new specific loop device err = ioctl(cfd, LOOP_CTL_ADD, devnr); # remove a specific loop device err = ioctl(cfd, LOOP_CTL_REMOVE, devnr); # find or allocate a free loop device to use devnr = ioctl(cfd, LOOP_CTL_GET_FREE); sprintf(loopname, "/dev/loop%i", devnr); ffd = open("backing-file", O_RDWR); lfd = open(loopname, O_RDWR); err = ioctl(lfd, LOOP_SET_FD, ffd); Cc: Tejun Heo <tj@kernel.org> Cc: Karel Zak <kzak@redhat.com> 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.c120
1 files changed, 116 insertions, 4 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f58532e7777..5c9edf94487 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -75,7 +75,7 @@
75#include <linux/kthread.h> 75#include <linux/kthread.h>
76#include <linux/splice.h> 76#include <linux/splice.h>
77#include <linux/sysfs.h> 77#include <linux/sysfs.h>
78 78#include <linux/miscdevice.h>
79#include <asm/uaccess.h> 79#include <asm/uaccess.h>
80 80
81static DEFINE_IDR(loop_index_idr); 81static DEFINE_IDR(loop_index_idr);
@@ -1478,13 +1478,22 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
1478 1478
1479static int lo_open(struct block_device *bdev, fmode_t mode) 1479static int lo_open(struct block_device *bdev, fmode_t mode)
1480{ 1480{
1481 struct loop_device *lo = bdev->bd_disk->private_data; 1481 struct loop_device *lo;
1482 int err = 0;
1483
1484 mutex_lock(&loop_index_mutex);
1485 lo = bdev->bd_disk->private_data;
1486 if (!lo) {
1487 err = -ENXIO;
1488 goto out;
1489 }
1482 1490
1483 mutex_lock(&lo->lo_ctl_mutex); 1491 mutex_lock(&lo->lo_ctl_mutex);
1484 lo->lo_refcnt++; 1492 lo->lo_refcnt++;
1485 mutex_unlock(&lo->lo_ctl_mutex); 1493 mutex_unlock(&lo->lo_ctl_mutex);
1486 1494out:
1487 return 0; 1495 mutex_unlock(&loop_index_mutex);
1496 return err;
1488} 1497}
1489 1498
1490static int lo_release(struct gendisk *disk, fmode_t mode) 1499static int lo_release(struct gendisk *disk, fmode_t mode)
@@ -1603,6 +1612,13 @@ static int loop_add(struct loop_device **l, int i)
1603 idr_remove(&loop_index_idr, m); 1612 idr_remove(&loop_index_idr, m);
1604 err = -EEXIST; 1613 err = -EEXIST;
1605 } 1614 }
1615 } else if (i == -1) {
1616 int m;
1617
1618 /* get next free nr */
1619 err = idr_get_new(&loop_index_idr, lo, &m);
1620 if (err >= 0)
1621 i = m;
1606 } else { 1622 } else {
1607 err = -EINVAL; 1623 err = -EINVAL;
1608 } 1624 }
@@ -1648,16 +1664,41 @@ static void loop_remove(struct loop_device *lo)
1648 kfree(lo); 1664 kfree(lo);
1649} 1665}
1650 1666
1667static int find_free_cb(int id, void *ptr, void *data)
1668{
1669 struct loop_device *lo = ptr;
1670 struct loop_device **l = data;
1671
1672 if (lo->lo_state == Lo_unbound) {
1673 *l = lo;
1674 return 1;
1675 }
1676 return 0;
1677}
1678
1651static int loop_lookup(struct loop_device **l, int i) 1679static int loop_lookup(struct loop_device **l, int i)
1652{ 1680{
1653 struct loop_device *lo; 1681 struct loop_device *lo;
1654 int ret = -ENODEV; 1682 int ret = -ENODEV;
1655 1683
1684 if (i < 0) {
1685 int err;
1686
1687 err = idr_for_each(&loop_index_idr, &find_free_cb, &lo);
1688 if (err == 1) {
1689 *l = lo;
1690 ret = lo->lo_number;
1691 }
1692 goto out;
1693 }
1694
1695 /* lookup and return a specific i */
1656 lo = idr_find(&loop_index_idr, i); 1696 lo = idr_find(&loop_index_idr, i);
1657 if (lo) { 1697 if (lo) {
1658 *l = lo; 1698 *l = lo;
1659 ret = lo->lo_number; 1699 ret = lo->lo_number;
1660 } 1700 }
1701out:
1661 return ret; 1702 return ret;
1662} 1703}
1663 1704
@@ -1681,11 +1722,76 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
1681 return kobj; 1722 return kobj;
1682} 1723}
1683 1724
1725static long loop_control_ioctl(struct file *file, unsigned int cmd,
1726 unsigned long parm)
1727{
1728 struct loop_device *lo;
1729 int ret = -ENOSYS;
1730
1731 mutex_lock(&loop_index_mutex);
1732 switch (cmd) {
1733 case LOOP_CTL_ADD:
1734 ret = loop_lookup(&lo, parm);
1735 if (ret >= 0) {
1736 ret = -EEXIST;
1737 break;
1738 }
1739 ret = loop_add(&lo, parm);
1740 break;
1741 case LOOP_CTL_REMOVE:
1742 ret = loop_lookup(&lo, parm);
1743 if (ret < 0)
1744 break;
1745 mutex_lock(&lo->lo_ctl_mutex);
1746 if (lo->lo_state != Lo_unbound) {
1747 ret = -EBUSY;
1748 mutex_unlock(&lo->lo_ctl_mutex);
1749 break;
1750 }
1751 if (lo->lo_refcnt > 0) {
1752 ret = -EBUSY;
1753 mutex_unlock(&lo->lo_ctl_mutex);
1754 break;
1755 }
1756 lo->lo_disk->private_data = NULL;
1757 mutex_unlock(&lo->lo_ctl_mutex);
1758 idr_remove(&loop_index_idr, lo->lo_number);
1759 loop_remove(lo);
1760 break;
1761 case LOOP_CTL_GET_FREE:
1762 ret = loop_lookup(&lo, -1);
1763 if (ret >= 0)
1764 break;
1765 ret = loop_add(&lo, -1);
1766 }
1767 mutex_unlock(&loop_index_mutex);
1768
1769 return ret;
1770}
1771
1772static const struct file_operations loop_ctl_fops = {
1773 .open = nonseekable_open,
1774 .unlocked_ioctl = loop_control_ioctl,
1775 .compat_ioctl = loop_control_ioctl,
1776 .owner = THIS_MODULE,
1777 .llseek = noop_llseek,
1778};
1779
1780static struct miscdevice loop_misc = {
1781 .minor = LOOP_CTRL_MINOR,
1782 .name = "loop-control",
1783 .fops = &loop_ctl_fops,
1784};
1785
1786MODULE_ALIAS_MISCDEV(LOOP_CTRL_MINOR);
1787MODULE_ALIAS("devname:loop-control");
1788
1684static int __init loop_init(void) 1789static int __init loop_init(void)
1685{ 1790{
1686 int i, nr; 1791 int i, nr;
1687 unsigned long range; 1792 unsigned long range;
1688 struct loop_device *lo; 1793 struct loop_device *lo;
1794 int err;
1689 1795
1690 /* 1796 /*
1691 * loop module now has a feature to instantiate underlying device 1797 * loop module now has a feature to instantiate underlying device
@@ -1702,6 +1808,10 @@ static int __init loop_init(void)
1702 * device on-demand. 1808 * device on-demand.
1703 */ 1809 */
1704 1810
1811 err = misc_register(&loop_misc);
1812 if (err < 0)
1813 return err;
1814
1705 part_shift = 0; 1815 part_shift = 0;
1706 if (max_part > 0) { 1816 if (max_part > 0) {
1707 part_shift = fls(max_part); 1817 part_shift = fls(max_part);
@@ -1767,6 +1877,8 @@ static void __exit loop_exit(void)
1767 1877
1768 blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range); 1878 blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
1769 unregister_blkdev(LOOP_MAJOR, "loop"); 1879 unregister_blkdev(LOOP_MAJOR, "loop");
1880
1881 misc_deregister(&loop_misc);
1770} 1882}
1771 1883
1772module_init(loop_init); 1884module_init(loop_init);