diff options
Diffstat (limited to 'fs/ocfs2/aops.c')
-rw-r--r-- | fs/ocfs2/aops.c | 173 |
1 files changed, 171 insertions, 2 deletions
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index fef0186a91cd..34d10452c56d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -206,8 +206,8 @@ bail: | |||
206 | return err; | 206 | return err; |
207 | } | 207 | } |
208 | 208 | ||
209 | static int ocfs2_read_inline_data(struct inode *inode, struct page *page, | 209 | int ocfs2_read_inline_data(struct inode *inode, struct page *page, |
210 | struct buffer_head *di_bh) | 210 | struct buffer_head *di_bh) |
211 | { | 211 | { |
212 | void *kaddr; | 212 | void *kaddr; |
213 | unsigned int size; | 213 | unsigned int size; |
@@ -1432,6 +1432,130 @@ out: | |||
1432 | return ret; | 1432 | return ret; |
1433 | } | 1433 | } |
1434 | 1434 | ||
1435 | static int ocfs2_write_begin_inline(struct address_space *mapping, | ||
1436 | struct inode *inode, | ||
1437 | struct ocfs2_write_ctxt *wc) | ||
1438 | { | ||
1439 | int ret; | ||
1440 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
1441 | struct page *page; | ||
1442 | handle_t *handle; | ||
1443 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data; | ||
1444 | |||
1445 | page = find_or_create_page(mapping, 0, GFP_NOFS); | ||
1446 | if (!page) { | ||
1447 | ret = -ENOMEM; | ||
1448 | mlog_errno(ret); | ||
1449 | goto out; | ||
1450 | } | ||
1451 | /* | ||
1452 | * If we don't set w_num_pages then this page won't get unlocked | ||
1453 | * and freed on cleanup of the write context. | ||
1454 | */ | ||
1455 | wc->w_pages[0] = wc->w_target_page = page; | ||
1456 | wc->w_num_pages = 1; | ||
1457 | |||
1458 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); | ||
1459 | if (IS_ERR(handle)) { | ||
1460 | ret = PTR_ERR(handle); | ||
1461 | mlog_errno(ret); | ||
1462 | goto out; | ||
1463 | } | ||
1464 | |||
1465 | ret = ocfs2_journal_access(handle, inode, wc->w_di_bh, | ||
1466 | OCFS2_JOURNAL_ACCESS_WRITE); | ||
1467 | if (ret) { | ||
1468 | ocfs2_commit_trans(osb, handle); | ||
1469 | |||
1470 | mlog_errno(ret); | ||
1471 | goto out; | ||
1472 | } | ||
1473 | |||
1474 | if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)) | ||
1475 | ocfs2_set_inode_data_inline(inode, di); | ||
1476 | |||
1477 | if (!PageUptodate(page)) { | ||
1478 | ret = ocfs2_read_inline_data(inode, page, wc->w_di_bh); | ||
1479 | if (ret) { | ||
1480 | ocfs2_commit_trans(osb, handle); | ||
1481 | |||
1482 | goto out; | ||
1483 | } | ||
1484 | } | ||
1485 | |||
1486 | wc->w_handle = handle; | ||
1487 | out: | ||
1488 | return ret; | ||
1489 | } | ||
1490 | |||
1491 | int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size) | ||
1492 | { | ||
1493 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
1494 | |||
1495 | if (new_size < le16_to_cpu(di->id2.i_data.id_count)) | ||
1496 | return 1; | ||
1497 | return 0; | ||
1498 | } | ||
1499 | |||
1500 | static int ocfs2_try_to_write_inline_data(struct address_space *mapping, | ||
1501 | struct inode *inode, loff_t pos, | ||
1502 | unsigned len, struct page *mmap_page, | ||
1503 | struct ocfs2_write_ctxt *wc) | ||
1504 | { | ||
1505 | int ret, written = 0; | ||
1506 | loff_t end = pos + len; | ||
1507 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
1508 | |||
1509 | mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n", | ||
1510 | (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos, | ||
1511 | oi->ip_dyn_features); | ||
1512 | |||
1513 | /* | ||
1514 | * Handle inodes which already have inline data 1st. | ||
1515 | */ | ||
1516 | if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
1517 | if (mmap_page == NULL && | ||
1518 | ocfs2_size_fits_inline_data(wc->w_di_bh, end)) | ||
1519 | goto do_inline_write; | ||
1520 | |||
1521 | /* | ||
1522 | * The write won't fit - we have to give this inode an | ||
1523 | * inline extent list now. | ||
1524 | */ | ||
1525 | ret = ocfs2_convert_inline_data_to_extents(inode, wc->w_di_bh); | ||
1526 | if (ret) | ||
1527 | mlog_errno(ret); | ||
1528 | goto out; | ||
1529 | } | ||
1530 | |||
1531 | /* | ||
1532 | * Check whether the inode can accept inline data. | ||
1533 | */ | ||
1534 | if (oi->ip_clusters != 0 || i_size_read(inode) != 0) | ||
1535 | return 0; | ||
1536 | |||
1537 | /* | ||
1538 | * Check whether the write can fit. | ||
1539 | */ | ||
1540 | if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb)) | ||
1541 | return 0; | ||
1542 | |||
1543 | do_inline_write: | ||
1544 | ret = ocfs2_write_begin_inline(mapping, inode, wc); | ||
1545 | if (ret) { | ||
1546 | mlog_errno(ret); | ||
1547 | goto out; | ||
1548 | } | ||
1549 | |||
1550 | /* | ||
1551 | * This signals to the caller that the data can be written | ||
1552 | * inline. | ||
1553 | */ | ||
1554 | written = 1; | ||
1555 | out: | ||
1556 | return written ? written : ret; | ||
1557 | } | ||
1558 | |||
1435 | /* | 1559 | /* |
1436 | * This function only does anything for file systems which can't | 1560 | * This function only does anything for file systems which can't |
1437 | * handle sparse files. | 1561 | * handle sparse files. |
@@ -1483,6 +1607,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, | |||
1483 | return ret; | 1607 | return ret; |
1484 | } | 1608 | } |
1485 | 1609 | ||
1610 | if (ocfs2_supports_inline_data(osb)) { | ||
1611 | ret = ocfs2_try_to_write_inline_data(mapping, inode, pos, len, | ||
1612 | mmap_page, wc); | ||
1613 | if (ret == 1) { | ||
1614 | ret = 0; | ||
1615 | goto success; | ||
1616 | } | ||
1617 | if (ret < 0) { | ||
1618 | mlog_errno(ret); | ||
1619 | goto out; | ||
1620 | } | ||
1621 | } | ||
1622 | |||
1486 | ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc); | 1623 | ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc); |
1487 | if (ret) { | 1624 | if (ret) { |
1488 | mlog_errno(ret); | 1625 | mlog_errno(ret); |
@@ -1570,6 +1707,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, | |||
1570 | if (meta_ac) | 1707 | if (meta_ac) |
1571 | ocfs2_free_alloc_context(meta_ac); | 1708 | ocfs2_free_alloc_context(meta_ac); |
1572 | 1709 | ||
1710 | success: | ||
1573 | *pagep = wc->w_target_page; | 1711 | *pagep = wc->w_target_page; |
1574 | *fsdata = wc; | 1712 | *fsdata = wc; |
1575 | return 0; | 1713 | return 0; |
@@ -1637,6 +1775,31 @@ out_fail: | |||
1637 | return ret; | 1775 | return ret; |
1638 | } | 1776 | } |
1639 | 1777 | ||
1778 | static void ocfs2_write_end_inline(struct inode *inode, loff_t pos, | ||
1779 | unsigned len, unsigned *copied, | ||
1780 | struct ocfs2_dinode *di, | ||
1781 | struct ocfs2_write_ctxt *wc) | ||
1782 | { | ||
1783 | void *kaddr; | ||
1784 | |||
1785 | if (unlikely(*copied < len)) { | ||
1786 | if (!PageUptodate(wc->w_target_page)) { | ||
1787 | *copied = 0; | ||
1788 | return; | ||
1789 | } | ||
1790 | } | ||
1791 | |||
1792 | kaddr = kmap_atomic(wc->w_target_page, KM_USER0); | ||
1793 | memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied); | ||
1794 | kunmap_atomic(kaddr, KM_USER0); | ||
1795 | |||
1796 | mlog(0, "Data written to inode at offset %llu. " | ||
1797 | "id_count = %u, copied = %u, i_dyn_features = 0x%x\n", | ||
1798 | (unsigned long long)pos, *copied, | ||
1799 | le16_to_cpu(di->id2.i_data.id_count), | ||
1800 | le16_to_cpu(di->i_dyn_features)); | ||
1801 | } | ||
1802 | |||
1640 | int ocfs2_write_end_nolock(struct address_space *mapping, | 1803 | int ocfs2_write_end_nolock(struct address_space *mapping, |
1641 | loff_t pos, unsigned len, unsigned copied, | 1804 | loff_t pos, unsigned len, unsigned copied, |
1642 | struct page *page, void *fsdata) | 1805 | struct page *page, void *fsdata) |
@@ -1650,6 +1813,11 @@ int ocfs2_write_end_nolock(struct address_space *mapping, | |||
1650 | handle_t *handle = wc->w_handle; | 1813 | handle_t *handle = wc->w_handle; |
1651 | struct page *tmppage; | 1814 | struct page *tmppage; |
1652 | 1815 | ||
1816 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
1817 | ocfs2_write_end_inline(inode, pos, len, &copied, di, wc); | ||
1818 | goto out_write_size; | ||
1819 | } | ||
1820 | |||
1653 | if (unlikely(copied < len)) { | 1821 | if (unlikely(copied < len)) { |
1654 | if (!PageUptodate(wc->w_target_page)) | 1822 | if (!PageUptodate(wc->w_target_page)) |
1655 | copied = 0; | 1823 | copied = 0; |
@@ -1687,6 +1855,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping, | |||
1687 | block_commit_write(tmppage, from, to); | 1855 | block_commit_write(tmppage, from, to); |
1688 | } | 1856 | } |
1689 | 1857 | ||
1858 | out_write_size: | ||
1690 | pos += copied; | 1859 | pos += copied; |
1691 | if (pos > inode->i_size) { | 1860 | if (pos > inode->i_size) { |
1692 | i_size_write(inode, pos); | 1861 | i_size_write(inode, pos); |