diff options
Diffstat (limited to 'block/as-iosched.c')
-rw-r--r-- | block/as-iosched.c | 144 |
1 files changed, 49 insertions, 95 deletions
diff --git a/block/as-iosched.c b/block/as-iosched.c index 8da3cf66894c..296708ceceb2 100644 --- a/block/as-iosched.c +++ b/block/as-iosched.c | |||
@@ -182,6 +182,9 @@ struct as_rq { | |||
182 | 182 | ||
183 | static kmem_cache_t *arq_pool; | 183 | static kmem_cache_t *arq_pool; |
184 | 184 | ||
185 | static atomic_t ioc_count = ATOMIC_INIT(0); | ||
186 | static struct completion *ioc_gone; | ||
187 | |||
185 | static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq); | 188 | static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq); |
186 | static void as_antic_stop(struct as_data *ad); | 189 | static void as_antic_stop(struct as_data *ad); |
187 | 190 | ||
@@ -193,6 +196,15 @@ static void as_antic_stop(struct as_data *ad); | |||
193 | static void free_as_io_context(struct as_io_context *aic) | 196 | static void free_as_io_context(struct as_io_context *aic) |
194 | { | 197 | { |
195 | kfree(aic); | 198 | kfree(aic); |
199 | if (atomic_dec_and_test(&ioc_count) && ioc_gone) | ||
200 | complete(ioc_gone); | ||
201 | } | ||
202 | |||
203 | static void as_trim(struct io_context *ioc) | ||
204 | { | ||
205 | if (ioc->aic) | ||
206 | free_as_io_context(ioc->aic); | ||
207 | ioc->aic = NULL; | ||
196 | } | 208 | } |
197 | 209 | ||
198 | /* Called when the task exits */ | 210 | /* Called when the task exits */ |
@@ -220,6 +232,7 @@ static struct as_io_context *alloc_as_io_context(void) | |||
220 | ret->seek_total = 0; | 232 | ret->seek_total = 0; |
221 | ret->seek_samples = 0; | 233 | ret->seek_samples = 0; |
222 | ret->seek_mean = 0; | 234 | ret->seek_mean = 0; |
235 | atomic_inc(&ioc_count); | ||
223 | } | 236 | } |
224 | 237 | ||
225 | return ret; | 238 | return ret; |
@@ -1696,11 +1709,6 @@ static int as_init_queue(request_queue_t *q, elevator_t *e) | |||
1696 | /* | 1709 | /* |
1697 | * sysfs parts below | 1710 | * sysfs parts below |
1698 | */ | 1711 | */ |
1699 | struct as_fs_entry { | ||
1700 | struct attribute attr; | ||
1701 | ssize_t (*show)(struct as_data *, char *); | ||
1702 | ssize_t (*store)(struct as_data *, const char *, size_t); | ||
1703 | }; | ||
1704 | 1712 | ||
1705 | static ssize_t | 1713 | static ssize_t |
1706 | as_var_show(unsigned int var, char *page) | 1714 | as_var_show(unsigned int var, char *page) |
@@ -1717,8 +1725,9 @@ as_var_store(unsigned long *var, const char *page, size_t count) | |||
1717 | return count; | 1725 | return count; |
1718 | } | 1726 | } |
1719 | 1727 | ||
1720 | static ssize_t as_est_show(struct as_data *ad, char *page) | 1728 | static ssize_t est_time_show(elevator_t *e, char *page) |
1721 | { | 1729 | { |
1730 | struct as_data *ad = e->elevator_data; | ||
1722 | int pos = 0; | 1731 | int pos = 0; |
1723 | 1732 | ||
1724 | pos += sprintf(page+pos, "%lu %% exit probability\n", | 1733 | pos += sprintf(page+pos, "%lu %% exit probability\n", |
@@ -1734,21 +1743,23 @@ static ssize_t as_est_show(struct as_data *ad, char *page) | |||
1734 | } | 1743 | } |
1735 | 1744 | ||
1736 | #define SHOW_FUNCTION(__FUNC, __VAR) \ | 1745 | #define SHOW_FUNCTION(__FUNC, __VAR) \ |
1737 | static ssize_t __FUNC(struct as_data *ad, char *page) \ | 1746 | static ssize_t __FUNC(elevator_t *e, char *page) \ |
1738 | { \ | 1747 | { \ |
1748 | struct as_data *ad = e->elevator_data; \ | ||
1739 | return as_var_show(jiffies_to_msecs((__VAR)), (page)); \ | 1749 | return as_var_show(jiffies_to_msecs((__VAR)), (page)); \ |
1740 | } | 1750 | } |
1741 | SHOW_FUNCTION(as_readexpire_show, ad->fifo_expire[REQ_SYNC]); | 1751 | SHOW_FUNCTION(as_read_expire_show, ad->fifo_expire[REQ_SYNC]); |
1742 | SHOW_FUNCTION(as_writeexpire_show, ad->fifo_expire[REQ_ASYNC]); | 1752 | SHOW_FUNCTION(as_write_expire_show, ad->fifo_expire[REQ_ASYNC]); |
1743 | SHOW_FUNCTION(as_anticexpire_show, ad->antic_expire); | 1753 | SHOW_FUNCTION(as_antic_expire_show, ad->antic_expire); |
1744 | SHOW_FUNCTION(as_read_batchexpire_show, ad->batch_expire[REQ_SYNC]); | 1754 | SHOW_FUNCTION(as_read_batch_expire_show, ad->batch_expire[REQ_SYNC]); |
1745 | SHOW_FUNCTION(as_write_batchexpire_show, ad->batch_expire[REQ_ASYNC]); | 1755 | SHOW_FUNCTION(as_write_batch_expire_show, ad->batch_expire[REQ_ASYNC]); |
1746 | #undef SHOW_FUNCTION | 1756 | #undef SHOW_FUNCTION |
1747 | 1757 | ||
1748 | #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ | 1758 | #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ |
1749 | static ssize_t __FUNC(struct as_data *ad, const char *page, size_t count) \ | 1759 | static ssize_t __FUNC(elevator_t *e, const char *page, size_t count) \ |
1750 | { \ | 1760 | { \ |
1751 | int ret = as_var_store(__PTR, (page), count); \ | 1761 | struct as_data *ad = e->elevator_data; \ |
1762 | int ret = as_var_store(__PTR, (page), count); \ | ||
1752 | if (*(__PTR) < (MIN)) \ | 1763 | if (*(__PTR) < (MIN)) \ |
1753 | *(__PTR) = (MIN); \ | 1764 | *(__PTR) = (MIN); \ |
1754 | else if (*(__PTR) > (MAX)) \ | 1765 | else if (*(__PTR) > (MAX)) \ |
@@ -1756,90 +1767,26 @@ static ssize_t __FUNC(struct as_data *ad, const char *page, size_t count) \ | |||
1756 | *(__PTR) = msecs_to_jiffies(*(__PTR)); \ | 1767 | *(__PTR) = msecs_to_jiffies(*(__PTR)); \ |
1757 | return ret; \ | 1768 | return ret; \ |
1758 | } | 1769 | } |
1759 | STORE_FUNCTION(as_readexpire_store, &ad->fifo_expire[REQ_SYNC], 0, INT_MAX); | 1770 | STORE_FUNCTION(as_read_expire_store, &ad->fifo_expire[REQ_SYNC], 0, INT_MAX); |
1760 | STORE_FUNCTION(as_writeexpire_store, &ad->fifo_expire[REQ_ASYNC], 0, INT_MAX); | 1771 | STORE_FUNCTION(as_write_expire_store, &ad->fifo_expire[REQ_ASYNC], 0, INT_MAX); |
1761 | STORE_FUNCTION(as_anticexpire_store, &ad->antic_expire, 0, INT_MAX); | 1772 | STORE_FUNCTION(as_antic_expire_store, &ad->antic_expire, 0, INT_MAX); |
1762 | STORE_FUNCTION(as_read_batchexpire_store, | 1773 | STORE_FUNCTION(as_read_batch_expire_store, |
1763 | &ad->batch_expire[REQ_SYNC], 0, INT_MAX); | 1774 | &ad->batch_expire[REQ_SYNC], 0, INT_MAX); |
1764 | STORE_FUNCTION(as_write_batchexpire_store, | 1775 | STORE_FUNCTION(as_write_batch_expire_store, |
1765 | &ad->batch_expire[REQ_ASYNC], 0, INT_MAX); | 1776 | &ad->batch_expire[REQ_ASYNC], 0, INT_MAX); |
1766 | #undef STORE_FUNCTION | 1777 | #undef STORE_FUNCTION |
1767 | 1778 | ||
1768 | static struct as_fs_entry as_est_entry = { | 1779 | #define AS_ATTR(name) \ |
1769 | .attr = {.name = "est_time", .mode = S_IRUGO }, | 1780 | __ATTR(name, S_IRUGO|S_IWUSR, as_##name##_show, as_##name##_store) |
1770 | .show = as_est_show, | 1781 | |
1771 | }; | 1782 | static struct elv_fs_entry as_attrs[] = { |
1772 | static struct as_fs_entry as_readexpire_entry = { | 1783 | __ATTR_RO(est_time), |
1773 | .attr = {.name = "read_expire", .mode = S_IRUGO | S_IWUSR }, | 1784 | AS_ATTR(read_expire), |
1774 | .show = as_readexpire_show, | 1785 | AS_ATTR(write_expire), |
1775 | .store = as_readexpire_store, | 1786 | AS_ATTR(antic_expire), |
1776 | }; | 1787 | AS_ATTR(read_batch_expire), |
1777 | static struct as_fs_entry as_writeexpire_entry = { | 1788 | AS_ATTR(write_batch_expire), |
1778 | .attr = {.name = "write_expire", .mode = S_IRUGO | S_IWUSR }, | 1789 | __ATTR_NULL |
1779 | .show = as_writeexpire_show, | ||
1780 | .store = as_writeexpire_store, | ||
1781 | }; | ||
1782 | static struct as_fs_entry as_anticexpire_entry = { | ||
1783 | .attr = {.name = "antic_expire", .mode = S_IRUGO | S_IWUSR }, | ||
1784 | .show = as_anticexpire_show, | ||
1785 | .store = as_anticexpire_store, | ||
1786 | }; | ||
1787 | static struct as_fs_entry as_read_batchexpire_entry = { | ||
1788 | .attr = {.name = "read_batch_expire", .mode = S_IRUGO | S_IWUSR }, | ||
1789 | .show = as_read_batchexpire_show, | ||
1790 | .store = as_read_batchexpire_store, | ||
1791 | }; | ||
1792 | static struct as_fs_entry as_write_batchexpire_entry = { | ||
1793 | .attr = {.name = "write_batch_expire", .mode = S_IRUGO | S_IWUSR }, | ||
1794 | .show = as_write_batchexpire_show, | ||
1795 | .store = as_write_batchexpire_store, | ||
1796 | }; | ||
1797 | |||
1798 | static struct attribute *default_attrs[] = { | ||
1799 | &as_est_entry.attr, | ||
1800 | &as_readexpire_entry.attr, | ||
1801 | &as_writeexpire_entry.attr, | ||
1802 | &as_anticexpire_entry.attr, | ||
1803 | &as_read_batchexpire_entry.attr, | ||
1804 | &as_write_batchexpire_entry.attr, | ||
1805 | NULL, | ||
1806 | }; | ||
1807 | |||
1808 | #define to_as(atr) container_of((atr), struct as_fs_entry, attr) | ||
1809 | |||
1810 | static ssize_t | ||
1811 | as_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | ||
1812 | { | ||
1813 | elevator_t *e = container_of(kobj, elevator_t, kobj); | ||
1814 | struct as_fs_entry *entry = to_as(attr); | ||
1815 | |||
1816 | if (!entry->show) | ||
1817 | return -EIO; | ||
1818 | |||
1819 | return entry->show(e->elevator_data, page); | ||
1820 | } | ||
1821 | |||
1822 | static ssize_t | ||
1823 | as_attr_store(struct kobject *kobj, struct attribute *attr, | ||
1824 | const char *page, size_t length) | ||
1825 | { | ||
1826 | elevator_t *e = container_of(kobj, elevator_t, kobj); | ||
1827 | struct as_fs_entry *entry = to_as(attr); | ||
1828 | |||
1829 | if (!entry->store) | ||
1830 | return -EIO; | ||
1831 | |||
1832 | return entry->store(e->elevator_data, page, length); | ||
1833 | } | ||
1834 | |||
1835 | static struct sysfs_ops as_sysfs_ops = { | ||
1836 | .show = as_attr_show, | ||
1837 | .store = as_attr_store, | ||
1838 | }; | ||
1839 | |||
1840 | static struct kobj_type as_ktype = { | ||
1841 | .sysfs_ops = &as_sysfs_ops, | ||
1842 | .default_attrs = default_attrs, | ||
1843 | }; | 1790 | }; |
1844 | 1791 | ||
1845 | static struct elevator_type iosched_as = { | 1792 | static struct elevator_type iosched_as = { |
@@ -1860,9 +1807,10 @@ static struct elevator_type iosched_as = { | |||
1860 | .elevator_may_queue_fn = as_may_queue, | 1807 | .elevator_may_queue_fn = as_may_queue, |
1861 | .elevator_init_fn = as_init_queue, | 1808 | .elevator_init_fn = as_init_queue, |
1862 | .elevator_exit_fn = as_exit_queue, | 1809 | .elevator_exit_fn = as_exit_queue, |
1810 | .trim = as_trim, | ||
1863 | }, | 1811 | }, |
1864 | 1812 | ||
1865 | .elevator_ktype = &as_ktype, | 1813 | .elevator_attrs = as_attrs, |
1866 | .elevator_name = "anticipatory", | 1814 | .elevator_name = "anticipatory", |
1867 | .elevator_owner = THIS_MODULE, | 1815 | .elevator_owner = THIS_MODULE, |
1868 | }; | 1816 | }; |
@@ -1893,7 +1841,13 @@ static int __init as_init(void) | |||
1893 | 1841 | ||
1894 | static void __exit as_exit(void) | 1842 | static void __exit as_exit(void) |
1895 | { | 1843 | { |
1844 | DECLARE_COMPLETION(all_gone); | ||
1896 | elv_unregister(&iosched_as); | 1845 | elv_unregister(&iosched_as); |
1846 | ioc_gone = &all_gone; | ||
1847 | barrier(); | ||
1848 | if (atomic_read(&ioc_count)) | ||
1849 | complete(ioc_gone); | ||
1850 | synchronize_rcu(); | ||
1897 | kmem_cache_destroy(arq_pool); | 1851 | kmem_cache_destroy(arq_pool); |
1898 | } | 1852 | } |
1899 | 1853 | ||