aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Schmidt <list.btrfs@jan-o-sch.net>2013-04-25 12:04:50 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-05-06 15:55:18 -0400
commit46b665ceb1edd2ac149ff701313c115f52dc0348 (patch)
treef9397bbd80ead3d9afc93039fb72d1c25cc53270 /fs
parent3c76cd84e0c0d3ceb094a1020f8c55c2417e18d3 (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.c253
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
1188static 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
1234static 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
1277static 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;
1403unlock: 1446unlock:
1404 spin_unlock(&fs_info->qgroup_lock); 1447 spin_unlock(&fs_info->qgroup_lock);
1405 ulist_free(roots); 1448 ulist_free(roots);