diff options
Diffstat (limited to 'fs/ext4/inline.c')
-rw-r--r-- | fs/ext4/inline.c | 168 |
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 | */ |
1407 | int ext4_read_inline_dir(struct file *filp, | 1407 | int 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 | /* |
1464 | revalidate: | 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 | } |
1562 | out: | 1530 | out: |
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); |