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 | } | ||
