diff options
author | Jan Kara <jack@suse.cz> | 2016-08-29 15:42:11 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2016-08-29 15:42:11 -0400 |
commit | 3f2571c1f91f2de729562344b4956786a2c74d73 (patch) | |
tree | c0cea783b582ec2741716741923ed677022c44eb /fs/ext4 | |
parent | 94405713889d4a9d341b4ad92956e4e2ec8ec2c2 (diff) |
ext4: factor out xattr moving
Factor out function for moving xattrs from inode into external xattr
block from ext4_expand_extra_isize_ea(). That function is already quite
long and factoring out this rather standalone functionality helps
readability.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/xattr.c | 159 |
1 files changed, 85 insertions, 74 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 82b025c977fc..8f582ae1032d 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -1340,6 +1340,84 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry, | |||
1340 | } | 1340 | } |
1341 | 1341 | ||
1342 | /* | 1342 | /* |
1343 | * Move xattr pointed to by 'entry' from inode into external xattr block | ||
1344 | */ | ||
1345 | static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode, | ||
1346 | struct ext4_inode *raw_inode, | ||
1347 | struct ext4_xattr_entry *entry) | ||
1348 | { | ||
1349 | struct ext4_xattr_ibody_find *is = NULL; | ||
1350 | struct ext4_xattr_block_find *bs = NULL; | ||
1351 | char *buffer = NULL, *b_entry_name = NULL; | ||
1352 | size_t value_offs, value_size; | ||
1353 | struct ext4_xattr_info i = { | ||
1354 | .value = NULL, | ||
1355 | .value_len = 0, | ||
1356 | .name_index = entry->e_name_index, | ||
1357 | }; | ||
1358 | struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode); | ||
1359 | int error; | ||
1360 | |||
1361 | value_offs = le16_to_cpu(entry->e_value_offs); | ||
1362 | value_size = le32_to_cpu(entry->e_value_size); | ||
1363 | |||
1364 | is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS); | ||
1365 | bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS); | ||
1366 | buffer = kmalloc(value_size, GFP_NOFS); | ||
1367 | b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS); | ||
1368 | if (!is || !bs || !buffer || !b_entry_name) { | ||
1369 | error = -ENOMEM; | ||
1370 | goto out; | ||
1371 | } | ||
1372 | |||
1373 | is->s.not_found = -ENODATA; | ||
1374 | bs->s.not_found = -ENODATA; | ||
1375 | is->iloc.bh = NULL; | ||
1376 | bs->bh = NULL; | ||
1377 | |||
1378 | /* Save the entry name and the entry value */ | ||
1379 | memcpy(buffer, (void *)IFIRST(header) + value_offs, value_size); | ||
1380 | memcpy(b_entry_name, entry->e_name, entry->e_name_len); | ||
1381 | b_entry_name[entry->e_name_len] = '\0'; | ||
1382 | i.name = b_entry_name; | ||
1383 | |||
1384 | error = ext4_get_inode_loc(inode, &is->iloc); | ||
1385 | if (error) | ||
1386 | goto out; | ||
1387 | |||
1388 | error = ext4_xattr_ibody_find(inode, &i, is); | ||
1389 | if (error) | ||
1390 | goto out; | ||
1391 | |||
1392 | /* Remove the chosen entry from the inode */ | ||
1393 | error = ext4_xattr_ibody_set(handle, inode, &i, is); | ||
1394 | if (error) | ||
1395 | goto out; | ||
1396 | |||
1397 | i.name = b_entry_name; | ||
1398 | i.value = buffer; | ||
1399 | i.value_len = value_size; | ||
1400 | error = ext4_xattr_block_find(inode, &i, bs); | ||
1401 | if (error) | ||
1402 | goto out; | ||
1403 | |||
1404 | /* Add entry which was removed from the inode into the block */ | ||
1405 | error = ext4_xattr_block_set(handle, inode, &i, bs); | ||
1406 | if (error) | ||
1407 | goto out; | ||
1408 | error = 0; | ||
1409 | out: | ||
1410 | kfree(b_entry_name); | ||
1411 | kfree(buffer); | ||
1412 | if (is) | ||
1413 | brelse(is->iloc.bh); | ||
1414 | kfree(is); | ||
1415 | kfree(bs); | ||
1416 | |||
1417 | return error; | ||
1418 | } | ||
1419 | |||
1420 | /* | ||
1343 | * Expand an inode by new_extra_isize bytes when EAs are present. | 1421 | * Expand an inode by new_extra_isize bytes when EAs are present. |
1344 | * Returns 0 on success or negative error number on failure. | 1422 | * Returns 0 on success or negative error number on failure. |
1345 | */ | 1423 | */ |
@@ -1349,9 +1427,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, | |||
1349 | struct ext4_xattr_ibody_header *header; | 1427 | struct ext4_xattr_ibody_header *header; |
1350 | struct ext4_xattr_entry *entry, *last, *first; | 1428 | struct ext4_xattr_entry *entry, *last, *first; |
1351 | struct buffer_head *bh = NULL; | 1429 | struct buffer_head *bh = NULL; |
1352 | struct ext4_xattr_ibody_find *is = NULL; | ||
1353 | struct ext4_xattr_block_find *bs = NULL; | ||
1354 | char *buffer = NULL, *b_entry_name = NULL; | ||
1355 | size_t min_offs; | 1430 | size_t min_offs; |
1356 | size_t ifree, bfree; | 1431 | size_t ifree, bfree; |
1357 | int total_ino; | 1432 | int total_ino; |
@@ -1427,27 +1502,11 @@ retry: | |||
1427 | } | 1502 | } |
1428 | 1503 | ||
1429 | while (isize_diff > ifree) { | 1504 | while (isize_diff > ifree) { |
1430 | size_t offs, size, entry_size; | ||
1431 | struct ext4_xattr_entry *small_entry = NULL; | 1505 | struct ext4_xattr_entry *small_entry = NULL; |
1432 | struct ext4_xattr_info i = { | 1506 | unsigned int entry_size; /* EA entry size */ |
1433 | .value = NULL, | 1507 | unsigned int total_size; /* EA entry size + value size */ |
1434 | .value_len = 0, | ||
1435 | }; | ||
1436 | unsigned int total_size; /* EA entry size + value size */ | ||
1437 | unsigned int min_total_size = ~0U; | 1508 | unsigned int min_total_size = ~0U; |
1438 | 1509 | ||
1439 | is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS); | ||
1440 | bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS); | ||
1441 | if (!is || !bs) { | ||
1442 | error = -ENOMEM; | ||
1443 | goto cleanup; | ||
1444 | } | ||
1445 | |||
1446 | is->s.not_found = -ENODATA; | ||
1447 | bs->s.not_found = -ENODATA; | ||
1448 | is->iloc.bh = NULL; | ||
1449 | bs->bh = NULL; | ||
1450 | |||
1451 | last = IFIRST(header); | 1510 | last = IFIRST(header); |
1452 | /* Find the entry best suited to be pushed into EA block */ | 1511 | /* Find the entry best suited to be pushed into EA block */ |
1453 | entry = NULL; | 1512 | entry = NULL; |
@@ -1474,8 +1533,6 @@ retry: | |||
1474 | s_min_extra_isize) { | 1533 | s_min_extra_isize) { |
1475 | tried_min_extra_isize++; | 1534 | tried_min_extra_isize++; |
1476 | new_extra_isize = s_min_extra_isize; | 1535 | new_extra_isize = s_min_extra_isize; |
1477 | kfree(is); is = NULL; | ||
1478 | kfree(bs); bs = NULL; | ||
1479 | brelse(bh); | 1536 | brelse(bh); |
1480 | goto retry; | 1537 | goto retry; |
1481 | } | 1538 | } |
@@ -1483,58 +1540,18 @@ retry: | |||
1483 | goto cleanup; | 1540 | goto cleanup; |
1484 | } | 1541 | } |
1485 | } | 1542 | } |
1486 | offs = le16_to_cpu(entry->e_value_offs); | ||
1487 | size = le32_to_cpu(entry->e_value_size); | ||
1488 | entry_size = EXT4_XATTR_LEN(entry->e_name_len); | ||
1489 | total_size = entry_size + EXT4_XATTR_SIZE(size); | ||
1490 | i.name_index = entry->e_name_index, | ||
1491 | buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS); | ||
1492 | b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS); | ||
1493 | if (!buffer || !b_entry_name) { | ||
1494 | error = -ENOMEM; | ||
1495 | goto cleanup; | ||
1496 | } | ||
1497 | /* Save the entry name and the entry value */ | ||
1498 | memcpy(buffer, (void *)IFIRST(header) + offs, | ||
1499 | EXT4_XATTR_SIZE(size)); | ||
1500 | memcpy(b_entry_name, entry->e_name, entry->e_name_len); | ||
1501 | b_entry_name[entry->e_name_len] = '\0'; | ||
1502 | i.name = b_entry_name; | ||
1503 | |||
1504 | error = ext4_get_inode_loc(inode, &is->iloc); | ||
1505 | if (error) | ||
1506 | goto cleanup; | ||
1507 | 1543 | ||
1508 | error = ext4_xattr_ibody_find(inode, &i, is); | 1544 | entry_size = EXT4_XATTR_LEN(entry->e_name_len); |
1545 | total_size = entry_size + | ||
1546 | EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); | ||
1547 | error = ext4_xattr_move_to_block(handle, inode, raw_inode, | ||
1548 | entry); | ||
1509 | if (error) | 1549 | if (error) |
1510 | goto cleanup; | 1550 | goto cleanup; |
1511 | 1551 | ||
1512 | /* Remove the chosen entry from the inode */ | ||
1513 | error = ext4_xattr_ibody_set(handle, inode, &i, is); | ||
1514 | if (error) | ||
1515 | goto cleanup; | ||
1516 | total_ino -= entry_size; | 1552 | total_ino -= entry_size; |
1517 | ifree += total_size; | 1553 | ifree += total_size; |
1518 | bfree -= total_size; | 1554 | bfree -= total_size; |
1519 | |||
1520 | i.name = b_entry_name; | ||
1521 | i.value = buffer; | ||
1522 | i.value_len = size; | ||
1523 | error = ext4_xattr_block_find(inode, &i, bs); | ||
1524 | if (error) | ||
1525 | goto cleanup; | ||
1526 | |||
1527 | /* Add entry which was removed from the inode into the block */ | ||
1528 | error = ext4_xattr_block_set(handle, inode, &i, bs); | ||
1529 | if (error) | ||
1530 | goto cleanup; | ||
1531 | kfree(b_entry_name); | ||
1532 | kfree(buffer); | ||
1533 | b_entry_name = NULL; | ||
1534 | buffer = NULL; | ||
1535 | brelse(is->iloc.bh); | ||
1536 | kfree(is); | ||
1537 | kfree(bs); | ||
1538 | } | 1555 | } |
1539 | 1556 | ||
1540 | shift: | 1557 | shift: |
@@ -1552,12 +1569,6 @@ out: | |||
1552 | return 0; | 1569 | return 0; |
1553 | 1570 | ||
1554 | cleanup: | 1571 | cleanup: |
1555 | kfree(b_entry_name); | ||
1556 | kfree(buffer); | ||
1557 | if (is) | ||
1558 | brelse(is->iloc.bh); | ||
1559 | kfree(is); | ||
1560 | kfree(bs); | ||
1561 | brelse(bh); | 1572 | brelse(bh); |
1562 | /* | 1573 | /* |
1563 | * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode | 1574 | * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode |