diff options
author | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2013-04-25 12:04:50 -0400 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-05-06 15:55:18 -0400 |
commit | 46b665ceb1edd2ac149ff701313c115f52dc0348 (patch) | |
tree | f9397bbd80ead3d9afc93039fb72d1c25cc53270 /fs | |
parent | 3c76cd84e0c0d3ceb094a1020f8c55c2417e18d3 (diff) |
Btrfs: split btrfs_qgroup_account_ref into four functions
The function is separated into a preparation part and the three accounting
steps mentioned in the qgroups documentation. The goal is to make steps two
and three usable by the rescan functionality. A side effect is that the
function is restructured into readable subunits.
Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/qgroup.c | 253 |
1 files changed, 148 insertions, 105 deletions
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index e5c56238b6c6..1fb7d8da3084 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c | |||
@@ -1185,6 +1185,144 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans, | |||
1185 | return 0; | 1185 | return 0; |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | static int qgroup_account_ref_step1(struct btrfs_fs_info *fs_info, | ||
1189 | struct ulist *roots, struct ulist *tmp, | ||
1190 | u64 seq) | ||
1191 | { | ||
1192 | struct ulist_node *unode; | ||
1193 | struct ulist_iterator uiter; | ||
1194 | struct ulist_node *tmp_unode; | ||
1195 | struct ulist_iterator tmp_uiter; | ||
1196 | struct btrfs_qgroup *qg; | ||
1197 | int ret; | ||
1198 | |||
1199 | ULIST_ITER_INIT(&uiter); | ||
1200 | while ((unode = ulist_next(roots, &uiter))) { | ||
1201 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1202 | if (!qg) | ||
1203 | continue; | ||
1204 | |||
1205 | ulist_reinit(tmp); | ||
1206 | /* XXX id not needed */ | ||
1207 | ret = ulist_add(tmp, qg->qgroupid, | ||
1208 | (u64)(uintptr_t)qg, GFP_ATOMIC); | ||
1209 | if (ret < 0) | ||
1210 | return ret; | ||
1211 | ULIST_ITER_INIT(&tmp_uiter); | ||
1212 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1213 | struct btrfs_qgroup_list *glist; | ||
1214 | |||
1215 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1216 | if (qg->refcnt < seq) | ||
1217 | qg->refcnt = seq + 1; | ||
1218 | else | ||
1219 | ++qg->refcnt; | ||
1220 | |||
1221 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1222 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1223 | (u64)(uintptr_t)glist->group, | ||
1224 | GFP_ATOMIC); | ||
1225 | if (ret < 0) | ||
1226 | return ret; | ||
1227 | } | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | return 0; | ||
1232 | } | ||
1233 | |||
1234 | static int qgroup_account_ref_step2(struct btrfs_fs_info *fs_info, | ||
1235 | struct ulist *roots, struct ulist *tmp, | ||
1236 | u64 seq, int sgn, u64 num_bytes, | ||
1237 | struct btrfs_qgroup *qgroup) | ||
1238 | { | ||
1239 | struct ulist_node *unode; | ||
1240 | struct ulist_iterator uiter; | ||
1241 | struct btrfs_qgroup *qg; | ||
1242 | struct btrfs_qgroup_list *glist; | ||
1243 | int ret; | ||
1244 | |||
1245 | ulist_reinit(tmp); | ||
1246 | ret = ulist_add(tmp, qgroup->qgroupid, (uintptr_t)qgroup, GFP_ATOMIC); | ||
1247 | if (ret < 0) | ||
1248 | return ret; | ||
1249 | |||
1250 | ULIST_ITER_INIT(&uiter); | ||
1251 | while ((unode = ulist_next(tmp, &uiter))) { | ||
1252 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; | ||
1253 | if (qg->refcnt < seq) { | ||
1254 | /* not visited by step 1 */ | ||
1255 | qg->rfer += sgn * num_bytes; | ||
1256 | qg->rfer_cmpr += sgn * num_bytes; | ||
1257 | if (roots->nnodes == 0) { | ||
1258 | qg->excl += sgn * num_bytes; | ||
1259 | qg->excl_cmpr += sgn * num_bytes; | ||
1260 | } | ||
1261 | qgroup_dirty(fs_info, qg); | ||
1262 | } | ||
1263 | WARN_ON(qg->tag >= seq); | ||
1264 | qg->tag = seq; | ||
1265 | |||
1266 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1267 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1268 | (uintptr_t)glist->group, GFP_ATOMIC); | ||
1269 | if (ret < 0) | ||
1270 | return ret; | ||
1271 | } | ||
1272 | } | ||
1273 | |||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | static int qgroup_account_ref_step3(struct btrfs_fs_info *fs_info, | ||
1278 | struct ulist *roots, struct ulist *tmp, | ||
1279 | u64 seq, int sgn, u64 num_bytes) | ||
1280 | { | ||
1281 | struct ulist_node *unode; | ||
1282 | struct ulist_iterator uiter; | ||
1283 | struct btrfs_qgroup *qg; | ||
1284 | struct ulist_node *tmp_unode; | ||
1285 | struct ulist_iterator tmp_uiter; | ||
1286 | int ret; | ||
1287 | |||
1288 | ULIST_ITER_INIT(&uiter); | ||
1289 | while ((unode = ulist_next(roots, &uiter))) { | ||
1290 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1291 | if (!qg) | ||
1292 | continue; | ||
1293 | |||
1294 | ulist_reinit(tmp); | ||
1295 | ret = ulist_add(tmp, qg->qgroupid, (uintptr_t)qg, GFP_ATOMIC); | ||
1296 | if (ret < 0) | ||
1297 | return ret; | ||
1298 | |||
1299 | ULIST_ITER_INIT(&tmp_uiter); | ||
1300 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1301 | struct btrfs_qgroup_list *glist; | ||
1302 | |||
1303 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1304 | if (qg->tag == seq) | ||
1305 | continue; | ||
1306 | |||
1307 | if (qg->refcnt - seq == roots->nnodes) { | ||
1308 | qg->excl -= sgn * num_bytes; | ||
1309 | qg->excl_cmpr -= sgn * num_bytes; | ||
1310 | qgroup_dirty(fs_info, qg); | ||
1311 | } | ||
1312 | |||
1313 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1314 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1315 | (uintptr_t)glist->group, | ||
1316 | GFP_ATOMIC); | ||
1317 | if (ret < 0) | ||
1318 | return ret; | ||
1319 | } | ||
1320 | } | ||
1321 | } | ||
1322 | |||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1188 | /* | 1326 | /* |
1189 | * btrfs_qgroup_account_ref is called for every ref that is added to or deleted | 1327 | * btrfs_qgroup_account_ref is called for every ref that is added to or deleted |
1190 | * from the fs. First, all roots referencing the extent are searched, and | 1328 | * from the fs. First, all roots referencing the extent are searched, and |
@@ -1200,10 +1338,8 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1200 | struct btrfs_root *quota_root; | 1338 | struct btrfs_root *quota_root; |
1201 | u64 ref_root; | 1339 | u64 ref_root; |
1202 | struct btrfs_qgroup *qgroup; | 1340 | struct btrfs_qgroup *qgroup; |
1203 | struct ulist_node *unode; | ||
1204 | struct ulist *roots = NULL; | 1341 | struct ulist *roots = NULL; |
1205 | struct ulist *tmp = NULL; | 1342 | struct ulist *tmp = NULL; |
1206 | struct ulist_iterator uiter; | ||
1207 | u64 seq; | 1343 | u64 seq; |
1208 | int ret = 0; | 1344 | int ret = 0; |
1209 | int sgn; | 1345 | int sgn; |
@@ -1287,119 +1423,26 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans, | |||
1287 | seq = fs_info->qgroup_seq; | 1423 | seq = fs_info->qgroup_seq; |
1288 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ | 1424 | fs_info->qgroup_seq += roots->nnodes + 1; /* max refcnt */ |
1289 | 1425 | ||
1290 | ULIST_ITER_INIT(&uiter); | 1426 | ret = qgroup_account_ref_step1(fs_info, roots, tmp, seq); |
1291 | while ((unode = ulist_next(roots, &uiter))) { | 1427 | if (ret) |
1292 | struct ulist_node *tmp_unode; | 1428 | goto unlock; |
1293 | struct ulist_iterator tmp_uiter; | ||
1294 | struct btrfs_qgroup *qg; | ||
1295 | |||
1296 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1297 | if (!qg) | ||
1298 | continue; | ||
1299 | |||
1300 | ulist_reinit(tmp); | ||
1301 | /* XXX id not needed */ | ||
1302 | ret = ulist_add(tmp, qg->qgroupid, | ||
1303 | (u64)(uintptr_t)qg, GFP_ATOMIC); | ||
1304 | if (ret < 0) | ||
1305 | goto unlock; | ||
1306 | ULIST_ITER_INIT(&tmp_uiter); | ||
1307 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1308 | struct btrfs_qgroup_list *glist; | ||
1309 | |||
1310 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1311 | if (qg->refcnt < seq) | ||
1312 | qg->refcnt = seq + 1; | ||
1313 | else | ||
1314 | ++qg->refcnt; | ||
1315 | |||
1316 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1317 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1318 | (u64)(uintptr_t)glist->group, | ||
1319 | GFP_ATOMIC); | ||
1320 | if (ret < 0) | ||
1321 | goto unlock; | ||
1322 | } | ||
1323 | } | ||
1324 | } | ||
1325 | 1429 | ||
1326 | /* | 1430 | /* |
1327 | * step 2: walk from the new root | 1431 | * step 2: walk from the new root |
1328 | */ | 1432 | */ |
1329 | ulist_reinit(tmp); | 1433 | ret = qgroup_account_ref_step2(fs_info, roots, tmp, seq, sgn, |
1330 | ret = ulist_add(tmp, qgroup->qgroupid, | 1434 | node->num_bytes, qgroup); |
1331 | (uintptr_t)qgroup, GFP_ATOMIC); | 1435 | if (ret) |
1332 | if (ret < 0) | ||
1333 | goto unlock; | 1436 | goto unlock; |
1334 | ULIST_ITER_INIT(&uiter); | ||
1335 | while ((unode = ulist_next(tmp, &uiter))) { | ||
1336 | struct btrfs_qgroup *qg; | ||
1337 | struct btrfs_qgroup_list *glist; | ||
1338 | |||
1339 | qg = (struct btrfs_qgroup *)(uintptr_t)unode->aux; | ||
1340 | if (qg->refcnt < seq) { | ||
1341 | /* not visited by step 1 */ | ||
1342 | qg->rfer += sgn * node->num_bytes; | ||
1343 | qg->rfer_cmpr += sgn * node->num_bytes; | ||
1344 | if (roots->nnodes == 0) { | ||
1345 | qg->excl += sgn * node->num_bytes; | ||
1346 | qg->excl_cmpr += sgn * node->num_bytes; | ||
1347 | } | ||
1348 | qgroup_dirty(fs_info, qg); | ||
1349 | } | ||
1350 | WARN_ON(qg->tag >= seq); | ||
1351 | qg->tag = seq; | ||
1352 | |||
1353 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1354 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1355 | (uintptr_t)glist->group, GFP_ATOMIC); | ||
1356 | if (ret < 0) | ||
1357 | goto unlock; | ||
1358 | } | ||
1359 | } | ||
1360 | 1437 | ||
1361 | /* | 1438 | /* |
1362 | * step 3: walk again from old refs | 1439 | * step 3: walk again from old refs |
1363 | */ | 1440 | */ |
1364 | ULIST_ITER_INIT(&uiter); | 1441 | ret = qgroup_account_ref_step3(fs_info, roots, tmp, seq, sgn, |
1365 | while ((unode = ulist_next(roots, &uiter))) { | 1442 | node->num_bytes); |
1366 | struct btrfs_qgroup *qg; | 1443 | if (ret) |
1367 | struct ulist_node *tmp_unode; | 1444 | goto unlock; |
1368 | struct ulist_iterator tmp_uiter; | ||
1369 | |||
1370 | qg = find_qgroup_rb(fs_info, unode->val); | ||
1371 | if (!qg) | ||
1372 | continue; | ||
1373 | |||
1374 | ulist_reinit(tmp); | ||
1375 | ret = ulist_add(tmp, qg->qgroupid, | ||
1376 | (uintptr_t)qg, GFP_ATOMIC); | ||
1377 | if (ret < 0) | ||
1378 | goto unlock; | ||
1379 | ULIST_ITER_INIT(&tmp_uiter); | ||
1380 | while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { | ||
1381 | struct btrfs_qgroup_list *glist; | ||
1382 | |||
1383 | qg = (struct btrfs_qgroup *)(uintptr_t)tmp_unode->aux; | ||
1384 | if (qg->tag == seq) | ||
1385 | continue; | ||
1386 | |||
1387 | if (qg->refcnt - seq == roots->nnodes) { | ||
1388 | qg->excl -= sgn * node->num_bytes; | ||
1389 | qg->excl_cmpr -= sgn * node->num_bytes; | ||
1390 | qgroup_dirty(fs_info, qg); | ||
1391 | } | ||
1392 | 1445 | ||
1393 | list_for_each_entry(glist, &qg->groups, next_group) { | ||
1394 | ret = ulist_add(tmp, glist->group->qgroupid, | ||
1395 | (uintptr_t)glist->group, | ||
1396 | GFP_ATOMIC); | ||
1397 | if (ret < 0) | ||
1398 | goto unlock; | ||
1399 | } | ||
1400 | } | ||
1401 | } | ||
1402 | ret = 0; | ||
1403 | unlock: | 1446 | unlock: |
1404 | spin_unlock(&fs_info->qgroup_lock); | 1447 | spin_unlock(&fs_info->qgroup_lock); |
1405 | ulist_free(roots); | 1448 | ulist_free(roots); |