diff options
Diffstat (limited to 'fs/btrfs/qgroup.c')
-rw-r--r-- | fs/btrfs/qgroup.c | 283 |
1 files changed, 181 insertions, 102 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 9d49c586995a..1280eff8af56 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c | |||
@@ -98,13 +98,10 @@ struct btrfs_qgroup_list { | |||
98 | struct btrfs_qgroup *member; | 98 | struct btrfs_qgroup *member; |
99 | }; | 99 | }; |
100 | 100 | ||
101 | struct qgroup_rescan { | 101 | static int |
102 | struct btrfs_work work; | 102 | qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, |
103 | struct btrfs_fs_info *fs_info; | 103 | int init_flags); |
104 | }; | 104 | static void qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info); |
105 | |||
106 | static void qgroup_rescan_start(struct btrfs_fs_info *fs_info, | ||
107 | struct qgroup_rescan *qscan); | ||
108 | 105 | ||
109 | /* must be called with qgroup_ioctl_lock held */ | 106 | /* must be called with qgroup_ioctl_lock held */ |
110 | static struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, | 107 | static struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, |
@@ -255,10 +252,17 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) | |||
255 | int slot; | 252 | int slot; |
256 | int ret = 0; | 253 | int ret = 0; |
257 | u64 flags = 0; | 254 | u64 flags = 0; |
255 | u64 rescan_progress = 0; | ||
258 | 256 | ||
259 | if (!fs_info->quota_enabled) | 257 | if (!fs_info->quota_enabled) |
260 | return 0; | 258 | return 0; |
261 | 259 | ||
260 | fs_info->qgroup_ulist = ulist_alloc(GFP_NOFS); | ||
261 | if (!fs_info->qgroup_ulist) { | ||
262 | ret = -ENOMEM; | ||
263 | goto out; | ||
264 | } | ||
265 | |||
262 | path = btrfs_alloc_path(); | 266 | path = btrfs_alloc_path(); |
263 | if (!path) { | 267 | if (!path) { |
264 | ret = -ENOMEM; | 268 | ret = -ENOMEM; |
@@ -306,20 +310,7 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) | |||
306 | } | 310 | } |
307 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, | 311 | fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, |
308 | ptr); | 312 | ptr); |
309 | fs_info->qgroup_rescan_progress.objectid = | 313 | rescan_progress = btrfs_qgroup_status_rescan(l, ptr); |
310 | btrfs_qgroup_status_rescan(l, ptr); | ||
311 | if (fs_info->qgroup_flags & | ||
312 | BTRFS_QGROUP_STATUS_FLAG_RESCAN) { | ||
313 | struct qgroup_rescan *qscan = | ||
314 | kmalloc(sizeof(*qscan), GFP_NOFS); | ||
315 | if (!qscan) { | ||
316 | ret = -ENOMEM; | ||
317 | goto out; | ||
318 | } | ||
319 | fs_info->qgroup_rescan_progress.type = 0; | ||
320 | fs_info->qgroup_rescan_progress.offset = 0; | ||
321 | qgroup_rescan_start(fs_info, qscan); | ||
322 | } | ||
323 | goto next1; | 314 | goto next1; |
324 | } | 315 | } |
325 | 316 | ||
@@ -421,9 +412,18 @@ out: | |||
421 | if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) { | 412 | if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) { |
422 | fs_info->quota_enabled = 0; | 413 | fs_info->quota_enabled = 0; |
423 | fs_info->pending_quota_state = 0; | 414 | fs_info->pending_quota_state = 0; |
415 | } else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN && | ||
416 | ret >= 0) { | ||
417 | ret = qgroup_rescan_init(fs_info, rescan_progress, 0); | ||
424 | } | 418 | } |
425 | btrfs_free_path(path); | 419 | btrfs_free_path(path); |
426 | 420 | ||
421 | if (ret < 0) { | ||
422 | ulist_free(fs_info->qgroup_ulist); | ||
423 | fs_info->qgroup_ulist = NULL; | ||
424 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
425 | } | ||
426 | |||
427 | return ret < 0 ? ret : 0; | 427 | return ret < 0 ? ret : 0; |
428 | } | 428 | } |
429 | 429 | ||
@@ -460,6 +460,7 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) | |||
460 | } | 460 | } |
461 | kfree(qgroup); | 461 | kfree(qgroup); |
462 | } | 462 | } |
463 | ulist_free(fs_info->qgroup_ulist); | ||
463 | } | 464 | } |
464 | 465 | ||
465 | static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, | 466 | static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, |
@@ -819,6 +820,12 @@ int btrfs_quota_enable(struct btrfs_trans_handle *trans, | |||
819 | goto out; | 820 | goto out; |
820 | } | 821 | } |
821 | 822 | ||
823 | fs_info->qgroup_ulist = ulist_alloc(GFP_NOFS); | ||
824 | if (!fs_info->qgroup_ulist) { | ||
825 | ret = -ENOMEM; | ||
826 | goto out; | ||
827 | } | ||
828 | |||
822 | /* | 829 | /* |
823 | * initially create the quota tree | 830 | * initially create the quota tree |
824 | */ | 831 | */ |
@@ -916,6 +923,10 @@ out_free_root: | |||
916 | kfree(quota_root); | 923 | kfree(quota_root); |
917 | } | 924 | } |
918 | out: | 925 | out: |
926 | if (ret) { | ||
927 | ulist_free(fs_info->qgroup_ulist); | ||
928 | fs_info->qgroup_ulist = NULL; | ||
929 | } | ||
919 | mutex_unlock(&fs_info->qgroup_ioctl_lock); | 930 | mutex_unlock(&fs_info->qgroup_ioctl_lock); |
920 | return ret; | 931 | return ret; |
921 | } | 932 | } |
@@ -1355,7 +1366,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1355 | u64 ref_root; | 1366 | u64 ref_root; |
1356 | struct btrfs_qgroup *qgroup; | 1367 | struct btrfs_qgroup *qgroup; |
1357 | struct ulist *roots = NULL; | 1368 | struct ulist *roots = NULL; |
1358 | struct ulist *tmp = NULL; | ||
1359 | u64 seq; | 1369 | u64 seq; |
1360 | int ret = 0; | 1370 | int ret = 0; |
1361 | int sgn; | 1371 | int sgn; |
@@ -1428,14 +1438,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1428 | if (ret < 0) | 1438 | if (ret < 0) |
1429 | return ret; | 1439 | return ret; |
1430 | 1440 | ||
1431 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
1432 | spin_lock(&fs_info->qgroup_lock); | 1441 | spin_lock(&fs_info->qgroup_lock); |
1433 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { | ||
1434 | if (fs_info->qgroup_rescan_progress.objectid <= node->bytenr) { | ||
1435 | ret = 0; | ||
1436 | goto unlock; | ||
1437 | } | ||
1438 | } | ||
1439 | 1442 | ||
1440 | quota_root = fs_info->quota_root; | 1443 | quota_root = fs_info->quota_root; |
1441 | if (!quota_root) | 1444 | if (!quota_root) |
@@ -1448,39 +1451,34 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1448 | /* | 1451 | /* |
1449 | * step 1: for each old ref, visit all nodes once and inc refcnt | 1452 | * step 1: for each old ref, visit all nodes once and inc refcnt |
1450 | */ | 1453 | */ |
1451 | tmp = ulist_alloc(GFP_ATOMIC); | 1454 | ulist_reinit(fs_info->qgroup_ulist); |
1452 | if (!tmp) { | ||
1453 | ret = -ENOMEM; | ||
1454 | goto unlock; | ||
1455 | } | ||
1456 | seq = fs_info->qgroup_seq; | 1455 | seq = fs_info->qgroup_seq; |
1457 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ | 1456 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ |
1458 | 1457 | ||
1459 | ret = qgroup_account_ref_step1(fs_info, roots, tmp, seq); | 1458 | ret = qgroup_account_ref_step1(fs_info, roots, fs_info->qgroup_ulist, |
1459 | seq); | ||
1460 | if (ret) | 1460 | if (ret) |
1461 | goto unlock; | 1461 | goto unlock; |
1462 | 1462 | ||
1463 | /* | 1463 | /* |
1464 | * step 2: walk from the new root | 1464 | * step 2: walk from the new root |
1465 | */ | 1465 | */ |
1466 | ret = qgroup_account_ref_step2(fs_info, roots, tmp, seq, sgn, | 1466 | ret = qgroup_account_ref_step2(fs_info, roots, fs_info->qgroup_ulist, |
1467 | node->num_bytes, qgroup); | 1467 | seq, sgn, node->num_bytes, qgroup); |
1468 | if (ret) | 1468 | if (ret) |
1469 | goto unlock; | 1469 | goto unlock; |
1470 | 1470 | ||
1471 | /* | 1471 | /* |
1472 | * step 3: walk again from old refs | 1472 | * step 3: walk again from old refs |
1473 | */ | 1473 | */ |
1474 | ret = qgroup_account_ref_step3(fs_info, roots, tmp, seq, sgn, | 1474 | ret = qgroup_account_ref_step3(fs_info, roots, fs_info->qgroup_ulist, |
1475 | node->num_bytes); | 1475 | seq, sgn, node->num_bytes); |
1476 | if (ret) | 1476 | if (ret) |
1477 | goto unlock; | 1477 | goto unlock; |
1478 | 1478 | ||
1479 | unlock: | 1479 | unlock: |
1480 | spin_unlock(&fs_info->qgroup_lock); | 1480 | spin_unlock(&fs_info->qgroup_lock); |
1481 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
1482 | ulist_free(roots); | 1481 | ulist_free(roots); |
1483 | ulist_free(tmp); | ||
1484 | 1482 | ||
1485 | return ret; | 1483 | return ret; |
1486 | } | 1484 | } |
@@ -1527,9 +1525,12 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans, | |||
1527 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; | 1525 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; |
1528 | 1526 | ||
1529 | if (!ret && start_rescan_worker) { | 1527 | if (!ret && start_rescan_worker) { |
1530 | ret = btrfs_qgroup_rescan(fs_info); | 1528 | ret = qgroup_rescan_init(fs_info, 0, 1); |
1531 | if (ret) | 1529 | if (!ret) { |
1532 | pr_err("btrfs: start rescan quota failed: %d\n", ret); | 1530 | qgroup_rescan_zero_tracking(fs_info); |
1531 | btrfs_queue_worker(&fs_info->qgroup_rescan_workers, | ||
1532 | &fs_info->qgroup_rescan_work); | ||
1533 | } | ||
1533 | ret = 0; | 1534 | ret = 0; |
1534 | } | 1535 | } |
1535 | 1536 | ||
@@ -1720,7 +1721,6 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1720 | struct btrfs_fs_info *fs_info = root->fs_info; | 1721 | struct btrfs_fs_info *fs_info = root->fs_info; |
1721 | u64 ref_root = root->root_key.objectid; | 1722 | u64 ref_root = root->root_key.objectid; |
1722 | int ret = 0; | 1723 | int ret = 0; |
1723 | struct ulist *ulist = NULL; | ||
1724 | struct ulist_node *unode; | 1724 | struct ulist_node *unode; |
1725 | struct ulist_iterator uiter; | 1725 | struct ulist_iterator uiter; |
1726 | 1726 | ||
@@ -1743,17 +1743,13 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1743 | * in a first step, we check all affected qgroups if any limits would | 1743 | * in a first step, we check all affected qgroups if any limits would |
1744 | * be exceeded | 1744 | * be exceeded |
1745 | */ | 1745 | */ |
1746 | ulist = ulist_alloc(GFP_ATOMIC); | 1746 | ulist_reinit(fs_info->qgroup_ulist); |
1747 | if (!ulist) { | 1747 | ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, |
1748 | ret = -ENOMEM; | ||
1749 | goto out; | ||
1750 | } | ||
1751 | ret = ulist_add(ulist, qgroup->qgroupid, | ||
1752 | (uintptr_t)qgroup, GFP_ATOMIC); | 1748 | (uintptr_t)qgroup, GFP_ATOMIC); |
1753 | if (ret < 0) | 1749 | if (ret < 0) |
1754 | goto out; | 1750 | goto out; |
1755 | ULIST_ITER_INIT(&uiter); | 1751 | ULIST_ITER_INIT(&uiter); |
1756 | while ((unode = ulist_next(ulist, &uiter))) { | 1752 | while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { |
1757 | struct btrfs_qgroup *qg; | 1753 | struct btrfs_qgroup *qg; |
1758 | struct btrfs_qgroup_list *glist; | 1754 | struct btrfs_qgroup_list *glist; |
1759 | 1755 | ||
@@ -1774,7 +1770,8 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1774 | } | 1770 | } |
1775 | 1771 | ||
1776 | list_for_each_entry(glist, &qg->groups, next_group) { | 1772 | list_for_each_entry(glist, &qg->groups, next_group) { |
1777 | ret = ulist_add(ulist, glist->group->qgroupid, | 1773 | ret = ulist_add(fs_info->qgroup_ulist, |
1774 | glist->group->qgroupid, | ||
1778 | (uintptr_t)glist->group, GFP_ATOMIC); | 1775 | (uintptr_t)glist->group, GFP_ATOMIC); |
1779 | if (ret < 0) | 1776 | if (ret < 0) |
1780 | goto out; | 1777 | goto out; |
@@ -1785,7 +1782,7 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1785 | * no limits exceeded, now record the reservation into all qgroups | 1782 | * no limits exceeded, now record the reservation into all qgroups |
1786 | */ | 1783 | */ |
1787 | ULIST_ITER_INIT(&uiter); | 1784 | ULIST_ITER_INIT(&uiter); |
1788 | while ((unode = ulist_next(ulist, &uiter))) { | 1785 | while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { |
1789 | struct btrfs_qgroup *qg; | 1786 | struct btrfs_qgroup *qg; |
1790 | 1787 | ||
1791 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; | 1788 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; |
@@ -1795,8 +1792,6 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes) | |||
1795 | 1792 | ||
1796 | out: | 1793 | out: |
1797 | spin_unlock(&fs_info->qgroup_lock); | 1794 | spin_unlock(&fs_info->qgroup_lock); |
1798 | ulist_free(ulist); | ||
1799 | |||
1800 | return ret; | 1795 | return ret; |
1801 | } | 1796 | } |
1802 | 1797 | ||
@@ -1805,7 +1800,6 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1805 | struct btrfs_root *quota_root; | 1800 | struct btrfs_root *quota_root; |
1806 | struct btrfs_qgroup *qgroup; | 1801 | struct btrfs_qgroup *qgroup; |
1807 | struct btrfs_fs_info *fs_info = root->fs_info; | 1802 | struct btrfs_fs_info *fs_info = root->fs_info; |
1808 | struct ulist *ulist = NULL; | ||
1809 | struct ulist_node *unode; | 1803 | struct ulist_node *unode; |
1810 | struct ulist_iterator uiter; | 1804 | struct ulist_iterator uiter; |
1811 | u64 ref_root = root->root_key.objectid; | 1805 | u64 ref_root = root->root_key.objectid; |
@@ -1827,17 +1821,13 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1827 | if (!qgroup) | 1821 | if (!qgroup) |
1828 | goto out; | 1822 | goto out; |
1829 | 1823 | ||
1830 | ulist = ulist_alloc(GFP_ATOMIC); | 1824 | ulist_reinit(fs_info->qgroup_ulist); |
1831 | if (!ulist) { | 1825 | ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, |
1832 | btrfs_std_error(fs_info, -ENOMEM); | ||
1833 | goto out; | ||
1834 | } | ||
1835 | ret = ulist_add(ulist, qgroup->qgroupid, | ||
1836 | (uintptr_t)qgroup, GFP_ATOMIC); | 1826 | (uintptr_t)qgroup, GFP_ATOMIC); |
1837 | if (ret < 0) | 1827 | if (ret < 0) |
1838 | goto out; | 1828 | goto out; |
1839 | ULIST_ITER_INIT(&uiter); | 1829 | ULIST_ITER_INIT(&uiter); |
1840 | while ((unode = ulist_next(ulist, &uiter))) { | 1830 | while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { |
1841 | struct btrfs_qgroup *qg; | 1831 | struct btrfs_qgroup *qg; |
1842 | struct btrfs_qgroup_list *glist; | 1832 | struct btrfs_qgroup_list *glist; |
1843 | 1833 | ||
@@ -1846,7 +1836,8 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1846 | qg->reserved -= num_bytes; | 1836 | qg->reserved -= num_bytes; |
1847 | 1837 | ||
1848 | list_for_each_entry(glist, &qg->groups, next_group) { | 1838 | list_for_each_entry(glist, &qg->groups, next_group) { |
1849 | ret = ulist_add(ulist, glist->group->qgroupid, | 1839 | ret = ulist_add(fs_info->qgroup_ulist, |
1840 | glist->group->qgroupid, | ||
1850 | (uintptr_t)glist->group, GFP_ATOMIC); | 1841 | (uintptr_t)glist->group, GFP_ATOMIC); |
1851 | if (ret < 0) | 1842 | if (ret < 0) |
1852 | goto out; | 1843 | goto out; |
@@ -1855,7 +1846,6 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes) | |||
1855 | 1846 | ||
1856 | out: | 1847 | out: |
1857 | spin_unlock(&fs_info->qgroup_lock); | 1848 | spin_unlock(&fs_info->qgroup_lock); |
1858 | ulist_free(ulist); | ||
1859 | } | 1849 | } |
1860 | 1850 | ||
1861 | void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) | 1851 | void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) |
@@ -1874,12 +1864,11 @@ void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) | |||
1874 | * returns 1 when done, 2 when done and FLAG_INCONSISTENT was cleared. | 1864 | * returns 1 when done, 2 when done and FLAG_INCONSISTENT was cleared. |
1875 | */ | 1865 | */ |
1876 | static int | 1866 | static int |
1877 | qgroup_rescan_leaf(struct qgroup_rescan *qscan, struct btrfs_path *path, | 1867 | qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, |
1878 | struct btrfs_trans_handle *trans, struct ulist *tmp, | 1868 | struct btrfs_trans_handle *trans, struct ulist *tmp, |
1879 | struct extent_buffer *scratch_leaf) | 1869 | struct extent_buffer *scratch_leaf) |
1880 | { | 1870 | { |
1881 | struct btrfs_key found; | 1871 | struct btrfs_key found; |
1882 | struct btrfs_fs_info *fs_info = qscan->fs_info; | ||
1883 | struct ulist *roots = NULL; | 1872 | struct ulist *roots = NULL; |
1884 | struct ulist_node *unode; | 1873 | struct ulist_node *unode; |
1885 | struct ulist_iterator uiter; | 1874 | struct ulist_iterator uiter; |
@@ -2007,11 +1996,10 @@ out: | |||
2007 | 1996 | ||
2008 | static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) | 1997 | static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) |
2009 | { | 1998 | { |
2010 | struct qgroup_rescan *qscan = container_of(work, struct qgroup_rescan, | 1999 | struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, |
2011 | work); | 2000 | qgroup_rescan_work); |
2012 | struct btrfs_path *path; | 2001 | struct btrfs_path *path; |
2013 | struct btrfs_trans_handle *trans = NULL; | 2002 | struct btrfs_trans_handle *trans = NULL; |
2014 | struct btrfs_fs_info *fs_info = qscan->fs_info; | ||
2015 | struct ulist *tmp = NULL; | 2003 | struct ulist *tmp = NULL; |
2016 | struct extent_buffer *scratch_leaf = NULL; | 2004 | struct extent_buffer *scratch_leaf = NULL; |
2017 | int err = -ENOMEM; | 2005 | int err = -ENOMEM; |
@@ -2036,7 +2024,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) | |||
2036 | if (!fs_info->quota_enabled) { | 2024 | if (!fs_info->quota_enabled) { |
2037 | err = -EINTR; | 2025 | err = -EINTR; |
2038 | } else { | 2026 | } else { |
2039 | err = qgroup_rescan_leaf(qscan, path, trans, | 2027 | err = qgroup_rescan_leaf(fs_info, path, trans, |
2040 | tmp, scratch_leaf); | 2028 | tmp, scratch_leaf); |
2041 | } | 2029 | } |
2042 | if (err > 0) | 2030 | if (err > 0) |
@@ -2049,7 +2037,6 @@ out: | |||
2049 | kfree(scratch_leaf); | 2037 | kfree(scratch_leaf); |
2050 | ulist_free(tmp); | 2038 | ulist_free(tmp); |
2051 | btrfs_free_path(path); | 2039 | btrfs_free_path(path); |
2052 | kfree(qscan); | ||
2053 | 2040 | ||
2054 | mutex_lock(&fs_info->qgroup_rescan_lock); | 2041 | mutex_lock(&fs_info->qgroup_rescan_lock); |
2055 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; | 2042 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; |
@@ -2068,47 +2055,74 @@ out: | |||
2068 | } else { | 2055 | } else { |
2069 | pr_err("btrfs: qgroup scan failed with %d\n", err); | 2056 | pr_err("btrfs: qgroup scan failed with %d\n", err); |
2070 | } | 2057 | } |
2071 | } | ||
2072 | 2058 | ||
2073 | static void | 2059 | complete_all(&fs_info->qgroup_rescan_completion); |
2074 | qgroup_rescan_start(struct btrfs_fs_info *fs_info, struct qgroup_rescan *qscan) | ||
2075 | { | ||
2076 | memset(&qscan->work, 0, sizeof(qscan->work)); | ||
2077 | qscan->work.func = btrfs_qgroup_rescan_worker; | ||
2078 | qscan->fs_info = fs_info; | ||
2079 | |||
2080 | pr_info("btrfs: qgroup scan started\n"); | ||
2081 | btrfs_queue_worker(&fs_info->qgroup_rescan_workers, &qscan->work); | ||
2082 | } | 2060 | } |
2083 | 2061 | ||
2084 | int | 2062 | /* |
2085 | btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) | 2063 | * Checks that (a) no rescan is running and (b) quota is enabled. Allocates all |
2064 | * memory required for the rescan context. | ||
2065 | */ | ||
2066 | static int | ||
2067 | qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, | ||
2068 | int init_flags) | ||
2086 | { | 2069 | { |
2087 | int ret = 0; | 2070 | int ret = 0; |
2088 | struct rb_node *n; | ||
2089 | struct btrfs_qgroup *qgroup; | ||
2090 | struct qgroup_rescan *qscan = kmalloc(sizeof(*qscan), GFP_NOFS); | ||
2091 | 2071 | ||
2092 | if (!qscan) | 2072 | if (!init_flags && |
2093 | return -ENOMEM; | 2073 | (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) || |
2074 | !(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON))) { | ||
2075 | ret = -EINVAL; | ||
2076 | goto err; | ||
2077 | } | ||
2094 | 2078 | ||
2095 | mutex_lock(&fs_info->qgroup_rescan_lock); | 2079 | mutex_lock(&fs_info->qgroup_rescan_lock); |
2096 | spin_lock(&fs_info->qgroup_lock); | 2080 | spin_lock(&fs_info->qgroup_lock); |
2097 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) | 2081 | |
2098 | ret = -EINPROGRESS; | 2082 | if (init_flags) { |
2099 | else if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) | 2083 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) |
2100 | ret = -EINVAL; | 2084 | ret = -EINPROGRESS; |
2101 | if (ret) { | 2085 | else if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) |
2102 | spin_unlock(&fs_info->qgroup_lock); | 2086 | ret = -EINVAL; |
2103 | mutex_unlock(&fs_info->qgroup_rescan_lock); | 2087 | |
2104 | kfree(qscan); | 2088 | if (ret) { |
2105 | return ret; | 2089 | spin_unlock(&fs_info->qgroup_lock); |
2090 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
2091 | goto err; | ||
2092 | } | ||
2093 | |||
2094 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2106 | } | 2095 | } |
2107 | 2096 | ||
2108 | fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2109 | memset(&fs_info->qgroup_rescan_progress, 0, | 2097 | memset(&fs_info->qgroup_rescan_progress, 0, |
2110 | sizeof(fs_info->qgroup_rescan_progress)); | 2098 | sizeof(fs_info->qgroup_rescan_progress)); |
2099 | fs_info->qgroup_rescan_progress.objectid = progress_objectid; | ||
2100 | |||
2101 | spin_unlock(&fs_info->qgroup_lock); | ||
2102 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
2103 | |||
2104 | init_completion(&fs_info->qgroup_rescan_completion); | ||
2105 | |||
2106 | memset(&fs_info->qgroup_rescan_work, 0, | ||
2107 | sizeof(fs_info->qgroup_rescan_work)); | ||
2108 | fs_info->qgroup_rescan_work.func = btrfs_qgroup_rescan_worker; | ||
2109 | |||
2110 | if (ret) { | ||
2111 | err: | ||
2112 | pr_info("btrfs: qgroup_rescan_init failed with %d\n", ret); | ||
2113 | return ret; | ||
2114 | } | ||
2115 | |||
2116 | return 0; | ||
2117 | } | ||
2118 | |||
2119 | static void | ||
2120 | qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info) | ||
2121 | { | ||
2122 | struct rb_node *n; | ||
2123 | struct btrfs_qgroup *qgroup; | ||
2111 | 2124 | ||
2125 | spin_lock(&fs_info->qgroup_lock); | ||
2112 | /* clear all current qgroup tracking information */ | 2126 | /* clear all current qgroup tracking information */ |
2113 | for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) { | 2127 | for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) { |
2114 | qgroup = rb_entry(n, struct btrfs_qgroup, node); | 2128 | qgroup = rb_entry(n, struct btrfs_qgroup, node); |
@@ -2118,9 +2132,74 @@ btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) | |||
2118 | qgroup->excl_cmpr = 0; | 2132 | qgroup->excl_cmpr = 0; |
2119 | } | 2133 | } |
2120 | spin_unlock(&fs_info->qgroup_lock); | 2134 | spin_unlock(&fs_info->qgroup_lock); |
2121 | mutex_unlock(&fs_info->qgroup_rescan_lock); | 2135 | } |
2136 | |||
2137 | int | ||
2138 | btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) | ||
2139 | { | ||
2140 | int ret = 0; | ||
2141 | struct btrfs_trans_handle *trans; | ||
2122 | 2142 | ||
2123 | qgroup_rescan_start(fs_info, qscan); | 2143 | ret = qgroup_rescan_init(fs_info, 0, 1); |
2144 | if (ret) | ||
2145 | return ret; | ||
2146 | |||
2147 | /* | ||
2148 | * We have set the rescan_progress to 0, which means no more | ||
2149 | * delayed refs will be accounted by btrfs_qgroup_account_ref. | ||
2150 | * However, btrfs_qgroup_account_ref may be right after its call | ||
2151 | * to btrfs_find_all_roots, in which case it would still do the | ||
2152 | * accounting. | ||
2153 | * To solve this, we're committing the transaction, which will | ||
2154 | * ensure we run all delayed refs and only after that, we are | ||
2155 | * going to clear all tracking information for a clean start. | ||
2156 | */ | ||
2157 | |||
2158 | trans = btrfs_join_transaction(fs_info->fs_root); | ||
2159 | if (IS_ERR(trans)) { | ||
2160 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2161 | return PTR_ERR(trans); | ||
2162 | } | ||
2163 | ret = btrfs_commit_transaction(trans, fs_info->fs_root); | ||
2164 | if (ret) { | ||
2165 | fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2166 | return ret; | ||
2167 | } | ||
2168 | |||
2169 | qgroup_rescan_zero_tracking(fs_info); | ||
2170 | |||
2171 | btrfs_queue_worker(&fs_info->qgroup_rescan_workers, | ||
2172 | &fs_info->qgroup_rescan_work); | ||
2124 | 2173 | ||
2125 | return 0; | 2174 | return 0; |
2126 | } | 2175 | } |
2176 | |||
2177 | int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info) | ||
2178 | { | ||
2179 | int running; | ||
2180 | int ret = 0; | ||
2181 | |||
2182 | mutex_lock(&fs_info->qgroup_rescan_lock); | ||
2183 | spin_lock(&fs_info->qgroup_lock); | ||
2184 | running = fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN; | ||
2185 | spin_unlock(&fs_info->qgroup_lock); | ||
2186 | mutex_unlock(&fs_info->qgroup_rescan_lock); | ||
2187 | |||
2188 | if (running) | ||
2189 | ret = wait_for_completion_interruptible( | ||
2190 | &fs_info->qgroup_rescan_completion); | ||
2191 | |||
2192 | return ret; | ||
2193 | } | ||
2194 | |||
2195 | /* | ||
2196 | * this is only called from open_ctree where we're still single threaded, thus | ||
2197 | * locking is omitted here. | ||
2198 | */ | ||
2199 | void | ||
2200 | btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info) | ||
2201 | { | ||
2202 | if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) | ||
2203 | btrfs_queue_worker(&fs_info->qgroup_rescan_workers, | ||
2204 | &fs_info->qgroup_rescan_work); | ||
2205 | } | ||