aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-08-29 15:42:11 -0400
committerTheodore Ts'o <tytso@mit.edu>2016-08-29 15:42:11 -0400
commit3f2571c1f91f2de729562344b4956786a2c74d73 (patch)
treec0cea783b582ec2741716741923ed677022c44eb /fs/ext4
parent94405713889d4a9d341b4ad92956e4e2ec8ec2c2 (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.c159
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 */
1345static 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;
1409out:
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
1540shift: 1557shift:
@@ -1552,12 +1569,6 @@ out:
1552 return 0; 1569 return 0;
1553 1570
1554cleanup: 1571cleanup:
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