aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-08-29 15:44:11 -0400
committerTheodore Ts'o <tytso@mit.edu>2016-08-29 15:44:11 -0400
commitdfa2064b222c901b05c19ec5b7f42a25f7bee0e3 (patch)
treefe588162ed654fbd32187375771f03e78a50f674 /fs/ext4
parent6e0cd088c01023c02b1e887e02c8b6f3f395344f (diff)
ext4: factor out loop for freeing inode xattr space
Move loop to make enough space in the inode from ext4_expand_extra_isize_ea() into a separate function to make that function smaller and better readable and also to avoid delaration of variables inside a loop block. 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.c121
1 files changed, 69 insertions, 52 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 2ef687620205..c15d63389957 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -1417,6 +1417,63 @@ out:
1417 return error; 1417 return error;
1418} 1418}
1419 1419
1420static int ext4_xattr_make_inode_space(handle_t *handle, struct inode *inode,
1421 struct ext4_inode *raw_inode,
1422 int isize_diff, size_t ifree,
1423 size_t bfree, int *total_ino)
1424{
1425 struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode);
1426 struct ext4_xattr_entry *small_entry;
1427 struct ext4_xattr_entry *entry;
1428 struct ext4_xattr_entry *last;
1429 unsigned int entry_size; /* EA entry size */
1430 unsigned int total_size; /* EA entry size + value size */
1431 unsigned int min_total_size;
1432 int error;
1433
1434 while (isize_diff > ifree) {
1435 entry = NULL;
1436 small_entry = NULL;
1437 min_total_size = ~0U;
1438 last = IFIRST(header);
1439 /* Find the entry best suited to be pushed into EA block */
1440 for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
1441 total_size =
1442 EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
1443 EXT4_XATTR_LEN(last->e_name_len);
1444 if (total_size <= bfree &&
1445 total_size < min_total_size) {
1446 if (total_size + ifree < isize_diff) {
1447 small_entry = last;
1448 } else {
1449 entry = last;
1450 min_total_size = total_size;
1451 }
1452 }
1453 }
1454
1455 if (entry == NULL) {
1456 if (small_entry == NULL)
1457 return -ENOSPC;
1458 entry = small_entry;
1459 }
1460
1461 entry_size = EXT4_XATTR_LEN(entry->e_name_len);
1462 total_size = entry_size +
1463 EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
1464 error = ext4_xattr_move_to_block(handle, inode, raw_inode,
1465 entry);
1466 if (error)
1467 return error;
1468
1469 *total_ino -= entry_size;
1470 ifree += total_size;
1471 bfree -= total_size;
1472 }
1473
1474 return 0;
1475}
1476
1420/* 1477/*
1421 * Expand an inode by new_extra_isize bytes when EAs are present. 1478 * Expand an inode by new_extra_isize bytes when EAs are present.
1422 * Returns 0 on success or negative error number on failure. 1479 * Returns 0 on success or negative error number on failure.
@@ -1491,66 +1548,26 @@ retry:
1491 brelse(bh); 1548 brelse(bh);
1492 goto retry; 1549 goto retry;
1493 } 1550 }
1494 error = -1; 1551 error = -ENOSPC;
1495 goto cleanup; 1552 goto cleanup;
1496 } 1553 }
1497 } else { 1554 } else {
1498 bfree = inode->i_sb->s_blocksize; 1555 bfree = inode->i_sb->s_blocksize;
1499 } 1556 }
1500 1557
1501 while (isize_diff > ifree) { 1558 error = ext4_xattr_make_inode_space(handle, inode, raw_inode,
1502 struct ext4_xattr_entry *small_entry = NULL, *entry = NULL; 1559 isize_diff, ifree, bfree,
1503 struct ext4_xattr_entry *last; 1560 &total_ino);
1504 unsigned int entry_size; /* EA entry size */ 1561 if (error) {
1505 unsigned int total_size; /* EA entry size + value size */ 1562 if (error == -ENOSPC && !tried_min_extra_isize &&
1506 unsigned int min_total_size = ~0U; 1563 s_min_extra_isize) {
1507 1564 tried_min_extra_isize++;
1508 last = IFIRST(header); 1565 new_extra_isize = s_min_extra_isize;
1509 /* Find the entry best suited to be pushed into EA block */ 1566 brelse(bh);
1510 for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { 1567 goto retry;
1511 total_size =
1512 EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
1513 EXT4_XATTR_LEN(last->e_name_len);
1514 if (total_size <= bfree &&
1515 total_size < min_total_size) {
1516 if (total_size + ifree < isize_diff) {
1517 small_entry = last;
1518 } else {
1519 entry = last;
1520 min_total_size = total_size;
1521 }
1522 }
1523 }
1524
1525 if (entry == NULL) {
1526 if (small_entry) {
1527 entry = small_entry;
1528 } else {
1529 if (!tried_min_extra_isize &&
1530 s_min_extra_isize) {
1531 tried_min_extra_isize++;
1532 new_extra_isize = s_min_extra_isize;
1533 brelse(bh);
1534 goto retry;
1535 }
1536 error = -1;
1537 goto cleanup;
1538 }
1539 } 1568 }
1540 1569 goto cleanup;
1541 entry_size = EXT4_XATTR_LEN(entry->e_name_len);
1542 total_size = entry_size +
1543 EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
1544 error = ext4_xattr_move_to_block(handle, inode, raw_inode,
1545 entry);
1546 if (error)
1547 goto cleanup;
1548
1549 total_ino -= entry_size;
1550 ifree += total_size;
1551 bfree -= total_size;
1552 } 1570 }
1553
1554shift: 1571shift:
1555 /* Adjust the offsets and shift the remaining entries ahead */ 1572 /* Adjust the offsets and shift the remaining entries ahead */
1556 ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize 1573 ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize