Skip to content

Commit bb233be

Browse files
loemrawkdave
authored andcommitted
btrfs-progs: refactor resize argument checking
Extract resize argument parsing logic from check_resize_args() into a separate parse_resize_args() function and makes the parsing logic reusable for future features like offline resize. Signed-off-by: Leo Martins <[email protected]>
1 parent 69eb071 commit bb233be

File tree

1 file changed

+91
-56
lines changed

1 file changed

+91
-56
lines changed

cmds/filesystem.c

Lines changed: 91 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,19 +1290,84 @@ static const char * const cmd_filesystem_resize_usage[] = {
12901290
NULL
12911291
};
12921292

1293+
struct resize_args {
1294+
bool is_cancel;
1295+
bool specified_dev_id;
1296+
u64 devid;
1297+
bool is_max;
1298+
int mod;
1299+
u64 size;
1300+
};
1301+
1302+
static bool parse_resize_args(const char *amount, struct resize_args *ret)
1303+
{
1304+
char amount_dup[BTRFS_VOL_NAME_MAX];
1305+
char *devstr;
1306+
char *sizestr;
1307+
1308+
ret->is_cancel = false;
1309+
if (strcmp("cancel", amount) == 0) {
1310+
ret->is_cancel = true;
1311+
return true;
1312+
}
1313+
1314+
if (strlen(amount) >= BTRFS_VOL_NAME_MAX) {
1315+
error("newsize argument is too long %zu >= %d", strlen(amount),
1316+
BTRFS_VOL_NAME_MAX);
1317+
return false;
1318+
}
1319+
strncpy(amount_dup, amount, BTRFS_VOL_NAME_MAX);
1320+
1321+
sizestr = amount_dup;
1322+
devstr = strchr(sizestr, ':');
1323+
ret->specified_dev_id = false;
1324+
if (devstr) {
1325+
sizestr = devstr + 1;
1326+
*devstr = 0;
1327+
devstr = amount_dup;
1328+
1329+
errno = 0;
1330+
ret->specified_dev_id = true;
1331+
ret->devid = strtoull(devstr, NULL, 10);
1332+
1333+
if (errno) {
1334+
error("failed to parse devid %s: %m", devstr);
1335+
return false;
1336+
}
1337+
}
1338+
1339+
if (strcmp(sizestr, "max") == 0) {
1340+
ret->is_max = true;
1341+
} else {
1342+
ret->is_max = false;
1343+
1344+
ret->mod = 0;
1345+
if (sizestr[0] == '-') {
1346+
ret->mod = -1;
1347+
sizestr++;
1348+
} else if (sizestr[0] == '+') {
1349+
ret->mod = 1;
1350+
sizestr++;
1351+
}
1352+
if (parse_u64_with_suffix(sizestr, &ret->size) < 0) {
1353+
error("failed to parse size %s", sizestr);
1354+
return false;
1355+
}
1356+
}
1357+
1358+
return true;
1359+
}
1360+
12931361
static int check_resize_args(const char *amount, const char *path, u64 *devid_ret)
12941362
{
12951363
struct btrfs_ioctl_fs_info_args fi_args;
12961364
struct btrfs_ioctl_dev_info_args *di_args = NULL;
1365+
struct resize_args args;
12971366
int ret, i, dev_idx = -1;
1298-
u64 devid = 1;
12991367
u64 mindev = (u64)-1;
13001368
int mindev_idx = 0;
13011369
const char *res_str = NULL;
1302-
char *devstr = NULL, *sizestr = NULL;
1303-
u64 new_size = 0, old_size = 0, diff = 0;
1304-
int mod = 0;
1305-
char amount_dup[BTRFS_VOL_NAME_MAX];
1370+
u64 new_size = 0, old_size = 0;
13061371

13071372
*devid_ret = (u64)-1;
13081373
ret = get_fs_info(path, &fi_args, &di_args);
@@ -1317,64 +1382,47 @@ static int check_resize_args(const char *amount, const char *path, u64 *devid_re
13171382
goto out;
13181383
}
13191384

1320-
ret = snprintf(amount_dup, BTRFS_VOL_NAME_MAX, "%s", amount);
1321-
if (strlen(amount) != ret) {
1322-
error("newsize argument is too long");
1385+
if (!parse_resize_args(amount, &args)) {
13231386
ret = 1;
13241387
goto out;
13251388
}
1326-
ret = 0;
13271389

13281390
/* Cancel does not need to determine the device number. */
1329-
if (strcmp(amount, "cancel") == 0) {
1391+
if (args.is_cancel) {
13301392
/* Different format, print and exit */
13311393
pr_verbose(LOG_DEFAULT, "Request to cancel resize\n");
13321394
goto out;
13331395
}
13341396

1335-
sizestr = amount_dup;
1336-
devstr = strchr(sizestr, ':');
1337-
if (devstr) {
1338-
sizestr = devstr + 1;
1339-
*devstr = 0;
1340-
devstr = amount_dup;
1341-
1342-
errno = 0;
1343-
devid = strtoull(devstr, NULL, 10);
1344-
1345-
if (errno) {
1346-
error("failed to parse devid %s: %m", devstr);
1347-
ret = 1;
1348-
goto out;
1349-
}
1350-
}
1397+
if (!args.specified_dev_id)
1398+
args.devid = 1;
13511399

13521400
dev_idx = -1;
13531401
for(i = 0; i < fi_args.num_devices; i++) {
13541402
if (di_args[i].devid < mindev) {
13551403
mindev = di_args[i].devid;
13561404
mindev_idx = i;
13571405
}
1358-
if (di_args[i].devid == devid) {
1406+
if (di_args[i].devid == args.devid) {
13591407
dev_idx = i;
13601408
break;
13611409
}
13621410
}
13631411

1364-
if (devstr && dev_idx < 0) {
1412+
if (args.specified_dev_id && dev_idx < 0) {
13651413
/* Devid specified but not found. */
1366-
error("cannot find devid: %lld", devid);
1414+
error("cannot find devid: %llu", args.devid);
13671415
ret = 1;
13681416
goto out;
1369-
} else if (!devstr && devid == 1 && dev_idx < 0) {
1417+
} else if (!args.specified_dev_id && dev_idx < 0) {
13701418
/*
13711419
* No device specified, assuming implicit 1 but it does not
13721420
* exist. Use minimum device as fallback.
13731421
*/
13741422
warning("no devid specified means devid 1 which does not exist, using\n"
13751423
"\t lowest devid %llu as a fallback", mindev);
13761424
*devid_ret = mindev;
1377-
devid = mindev;
1425+
args.devid = mindev;
13781426
dev_idx = mindev_idx;
13791427
} else {
13801428
/*
@@ -1383,44 +1431,31 @@ static int check_resize_args(const char *amount, const char *path, u64 *devid_re
13831431
*/
13841432
}
13851433

1386-
if (strcmp(sizestr, "max") == 0) {
1434+
if (args.is_max) {
13871435
res_str = "max";
13881436
} else {
1389-
if (sizestr[0] == '-') {
1390-
mod = -1;
1391-
sizestr++;
1392-
} else if (sizestr[0] == '+') {
1393-
mod = 1;
1394-
sizestr++;
1395-
}
1396-
ret = parse_u64_with_suffix(sizestr, &diff);
1397-
if (ret < 0) {
1398-
error("failed to parse size %s", sizestr);
1399-
ret = 1;
1400-
goto out;
1401-
}
14021437
old_size = di_args[dev_idx].total_bytes;
14031438

14041439
/* For target sizes without +/- sign prefix (e.g. 1:150g) */
1405-
if (mod == 0) {
1406-
new_size = diff;
1407-
} else if (mod < 0) {
1408-
if (diff > old_size) {
1440+
if (args.mod == 0) {
1441+
new_size = args.size;
1442+
} else if (args.mod < 0) {
1443+
if (args.size > old_size) {
14091444
error("current size is %s which is smaller than %s",
14101445
pretty_size_mode(old_size, UNITS_DEFAULT),
1411-
pretty_size_mode(diff, UNITS_DEFAULT));
1446+
pretty_size_mode(args.size, UNITS_DEFAULT));
14121447
ret = 1;
14131448
goto out;
14141449
}
1415-
new_size = old_size - diff;
1416-
} else if (mod > 0) {
1417-
if (diff > ULLONG_MAX - old_size) {
1450+
new_size = old_size - args.size;
1451+
} else if (args.mod > 0) {
1452+
if (args.size > ULLONG_MAX - old_size) {
14181453
error("increasing %s is out of range",
1419-
pretty_size_mode(diff, UNITS_DEFAULT));
1454+
pretty_size_mode(args.size, UNITS_DEFAULT));
14201455
ret = 1;
14211456
goto out;
14221457
}
1423-
new_size = old_size + diff;
1458+
new_size = old_size + args.size;
14241459
}
14251460
new_size = round_down(new_size, fi_args.sectorsize);
14261461
res_str = pretty_size_mode(new_size, UNITS_DEFAULT);
@@ -1430,7 +1465,7 @@ static int check_resize_args(const char *amount, const char *path, u64 *devid_re
14301465
new_size, pretty_size_mode(new_size, UNITS_DEFAULT));
14311466
}
14321467

1433-
pr_verbose(LOG_DEFAULT, "Resize device id %lld (%s) from %s to %s\n", devid,
1468+
pr_verbose(LOG_DEFAULT, "Resize device id %llu (%s) from %s to %s\n", args.devid,
14341469
di_args[dev_idx].path,
14351470
pretty_size_mode(di_args[dev_idx].total_bytes, UNITS_DEFAULT),
14361471
res_str);

0 commit comments

Comments
 (0)