aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inline.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/inline.c')
-rw-r--r--fs/ext4/inline.c168
1 files changed, 68 insertions, 100 deletions
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 3e2bf873e8a8..d9ecbf1113a7 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -72,7 +72,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode,
72 entry = (struct ext4_xattr_entry *) 72 entry = (struct ext4_xattr_entry *)
73 ((void *)raw_inode + EXT4_I(inode)->i_inline_off); 73 ((void *)raw_inode + EXT4_I(inode)->i_inline_off);
74 74
75 free += le32_to_cpu(entry->e_value_size); 75 free += EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
76 goto out; 76 goto out;
77 } 77 }
78 78
@@ -1404,16 +1404,15 @@ out:
1404 * offset as if '.' and '..' really take place. 1404 * offset as if '.' and '..' really take place.
1405 * 1405 *
1406 */ 1406 */
1407int ext4_read_inline_dir(struct file *filp, 1407int ext4_read_inline_dir(struct file *file,
1408 void *dirent, filldir_t filldir, 1408 struct dir_context *ctx,
1409 int *has_inline_data) 1409 int *has_inline_data)
1410{ 1410{
1411 int error = 0;
1412 unsigned int offset, parent_ino; 1411 unsigned int offset, parent_ino;
1413 int i, stored; 1412 int i;
1414 struct ext4_dir_entry_2 *de; 1413 struct ext4_dir_entry_2 *de;
1415 struct super_block *sb; 1414 struct super_block *sb;
1416 struct inode *inode = file_inode(filp); 1415 struct inode *inode = file_inode(file);
1417 int ret, inline_size = 0; 1416 int ret, inline_size = 0;
1418 struct ext4_iloc iloc; 1417 struct ext4_iloc iloc;
1419 void *dir_buf = NULL; 1418 void *dir_buf = NULL;
@@ -1444,9 +1443,8 @@ int ext4_read_inline_dir(struct file *filp,
1444 goto out; 1443 goto out;
1445 1444
1446 sb = inode->i_sb; 1445 sb = inode->i_sb;
1447 stored = 0;
1448 parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); 1446 parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode);
1449 offset = filp->f_pos; 1447 offset = ctx->pos;
1450 1448
1451 /* 1449 /*
1452 * dotdot_offset and dotdot_size is the real offset and 1450 * dotdot_offset and dotdot_size is the real offset and
@@ -1460,104 +1458,74 @@ int ext4_read_inline_dir(struct file *filp,
1460 extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE; 1458 extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE;
1461 extra_size = extra_offset + inline_size; 1459 extra_size = extra_offset + inline_size;
1462 1460
1463 while (!error && !stored && filp->f_pos < extra_size) { 1461 /*
1464revalidate: 1462 * If the version has changed since the last call to
1465 /* 1463 * readdir(2), then we might be pointing to an invalid
1466 * If the version has changed since the last call to 1464 * dirent right now. Scan from the start of the inline
1467 * readdir(2), then we might be pointing to an invalid 1465 * dir to make sure.
1468 * dirent right now. Scan from the start of the inline 1466 */
1469 * dir to make sure. 1467 if (file->f_version != inode->i_version) {
1470 */ 1468 for (i = 0; i < extra_size && i < offset;) {
1471 if (filp->f_version != inode->i_version) { 1469 /*
1472 for (i = 0; i < extra_size && i < offset;) { 1470 * "." is with offset 0 and
1473 /* 1471 * ".." is dotdot_offset.
1474 * "." is with offset 0 and 1472 */
1475 * ".." is dotdot_offset. 1473 if (!i) {
1476 */ 1474 i = dotdot_offset;
1477 if (!i) { 1475 continue;
1478 i = dotdot_offset; 1476 } else if (i == dotdot_offset) {
1479 continue; 1477 i = dotdot_size;
1480 } else if (i == dotdot_offset) {
1481 i = dotdot_size;
1482 continue;
1483 }
1484 /* for other entry, the real offset in
1485 * the buf has to be tuned accordingly.
1486 */
1487 de = (struct ext4_dir_entry_2 *)
1488 (dir_buf + i - extra_offset);
1489 /* It's too expensive to do a full
1490 * dirent test each time round this
1491 * loop, but we do have to test at
1492 * least that it is non-zero. A
1493 * failure will be detected in the
1494 * dirent test below. */
1495 if (ext4_rec_len_from_disk(de->rec_len,
1496 extra_size) < EXT4_DIR_REC_LEN(1))
1497 break;
1498 i += ext4_rec_len_from_disk(de->rec_len,
1499 extra_size);
1500 }
1501 offset = i;
1502 filp->f_pos = offset;
1503 filp->f_version = inode->i_version;
1504 }
1505
1506 while (!error && filp->f_pos < extra_size) {
1507 if (filp->f_pos == 0) {
1508 error = filldir(dirent, ".", 1, 0, inode->i_ino,
1509 DT_DIR);
1510 if (error)
1511 break;
1512 stored++;
1513 filp->f_pos = dotdot_offset;
1514 continue; 1478 continue;
1515 } 1479 }
1480 /* for other entry, the real offset in
1481 * the buf has to be tuned accordingly.
1482 */
1483 de = (struct ext4_dir_entry_2 *)
1484 (dir_buf + i - extra_offset);
1485 /* It's too expensive to do a full
1486 * dirent test each time round this
1487 * loop, but we do have to test at
1488 * least that it is non-zero. A
1489 * failure will be detected in the
1490 * dirent test below. */
1491 if (ext4_rec_len_from_disk(de->rec_len, extra_size)
1492 < EXT4_DIR_REC_LEN(1))
1493 break;
1494 i += ext4_rec_len_from_disk(de->rec_len,
1495 extra_size);
1496 }
1497 offset = i;
1498 ctx->pos = offset;
1499 file->f_version = inode->i_version;
1500 }
1516 1501
1517 if (filp->f_pos == dotdot_offset) { 1502 while (ctx->pos < extra_size) {
1518 error = filldir(dirent, "..", 2, 1503 if (ctx->pos == 0) {
1519 dotdot_offset, 1504 if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
1520 parent_ino, DT_DIR); 1505 goto out;
1521 if (error) 1506 ctx->pos = dotdot_offset;
1522 break; 1507 continue;
1523 stored++; 1508 }
1524 1509
1525 filp->f_pos = dotdot_size; 1510 if (ctx->pos == dotdot_offset) {
1526 continue; 1511 if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR))
1527 } 1512 goto out;
1513 ctx->pos = dotdot_size;
1514 continue;
1515 }
1528 1516
1529 de = (struct ext4_dir_entry_2 *) 1517 de = (struct ext4_dir_entry_2 *)
1530 (dir_buf + filp->f_pos - extra_offset); 1518 (dir_buf + ctx->pos - extra_offset);
1531 if (ext4_check_dir_entry(inode, filp, de, 1519 if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf,
1532 iloc.bh, dir_buf, 1520 extra_size, ctx->pos))
1533 extra_size, filp->f_pos)) { 1521 goto out;
1534 ret = stored; 1522 if (le32_to_cpu(de->inode)) {
1523 if (!dir_emit(ctx, de->name, de->name_len,
1524 le32_to_cpu(de->inode),
1525 get_dtype(sb, de->file_type)))
1535 goto out; 1526 goto out;
1536 }
1537 if (le32_to_cpu(de->inode)) {
1538 /* We might block in the next section
1539 * if the data destination is
1540 * currently swapped out. So, use a
1541 * version stamp to detect whether or
1542 * not the directory has been modified
1543 * during the copy operation.
1544 */
1545 u64 version = filp->f_version;
1546
1547 error = filldir(dirent, de->name,
1548 de->name_len,
1549 filp->f_pos,
1550 le32_to_cpu(de->inode),
1551 get_dtype(sb, de->file_type));
1552 if (error)
1553 break;
1554 if (version != filp->f_version)
1555 goto revalidate;
1556 stored++;
1557 }
1558 filp->f_pos += ext4_rec_len_from_disk(de->rec_len,
1559 extra_size);
1560 } 1527 }
1528 ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size);
1561 } 1529 }
1562out: 1530out:
1563 kfree(dir_buf); 1531 kfree(dir_buf);
@@ -1842,7 +1810,7 @@ int ext4_inline_data_fiemap(struct inode *inode,
1842 if (error) 1810 if (error)
1843 goto out; 1811 goto out;
1844 1812
1845 physical = iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; 1813 physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits;
1846 physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; 1814 physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data;
1847 physical += offsetof(struct ext4_inode, i_block); 1815 physical += offsetof(struct ext4_inode, i_block);
1848 length = i_size_read(inode); 1816 length = i_size_read(inode);