tree: https://github.com/ceph/ceph-client.git wip-fscrypt
head: 55b265c1fd41c55be5e56d9eb4b24da48ac04a8c
commit: 3c062ae4472df769c1a740ed55ccc252f9e104c1 [48/59] ceph: add read/modify/write to ceph_sync_write
config: i386-randconfig-a006 (https://download.01.org/0day-ci/archive/20220706/202207061958.I86cqkif-lkp@xxxxxxxxx/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project f553287b588916de09c66e3e32bf75e5060f967f)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/ceph/ceph-client/commit/3c062ae4472df769c1a740ed55ccc252f9e104c1
git remote add ceph-client https://github.com/ceph/ceph-client.git
git fetch --no-tags ceph-client wip-fscrypt
git checkout 3c062ae4472df769c1a740ed55ccc252f9e104c1
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash fs/ceph/
If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@xxxxxxxxx>
All errors (new ones prefixed by >>):
fs/ceph/file.c:1727:45: error: too many arguments to function call, expected 2, have 3
ret = ceph_osdc_start_request(osdc, req, false);
~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~
include/linux/ceph/osd_client.h:583:6: note: 'ceph_osdc_start_request' declared here
void ceph_osdc_start_request(struct ceph_osd_client *osdc,
^
fs/ceph/file.c:1896:38: error: too many arguments to function call, expected 2, have 3
ceph_osdc_start_request(osdc, req, false);
~~~~~~~~~~~~~~~~~~~~~~~ ^~~~~
include/linux/ceph/osd_client.h:583:6: note: 'ceph_osdc_start_request' declared here
void ceph_osdc_start_request(struct ceph_osd_client *osdc,
^
2 errors generated.
vim +1727 fs/ceph/file.c
1553
1554 /*
1555 * Synchronous write, straight from __user pointer or user pages.
1556 *
1557 * If write spans object boundary, just do multiple writes. (For a
1558 * correct atomic write, we should e.g. take write locks on all
1559 * objects, rollback on failure, etc.)
1560 */
1561 static ssize_t
1562 ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
1563 struct ceph_snap_context *snapc)
1564 {
1565 struct file *file = iocb->ki_filp;
1566 struct inode *inode = file_inode(file);
1567 struct ceph_inode_info *ci = ceph_inode(inode);
1568 struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
1569 struct ceph_osd_client *osdc = &fsc->client->osdc;
1570 struct ceph_osd_request *req;
1571 struct page **pages;
1572 u64 len;
1573 int num_pages;
1574 int written = 0;
1575 int ret;
1576 bool check_caps = false;
1577 struct timespec64 mtime = current_time(inode);
1578 size_t count = iov_iter_count(from);
1579
1580 if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
1581 return -EROFS;
1582
1583 dout("sync_write on file %p %lld~%u snapc %p seq %lld\n",
1584 file, pos, (unsigned)count, snapc, snapc->seq);
1585
1586 ret = filemap_write_and_wait_range(inode->i_mapping,
1587 pos, pos + count - 1);
1588 if (ret < 0)
1589 return ret;
1590
1591 ceph_fscache_invalidate(inode, false);
1592 ret = invalidate_inode_pages2_range(inode->i_mapping,
1593 pos >> PAGE_SHIFT,
1594 (pos + count - 1) >> PAGE_SHIFT);
1595 if (ret < 0)
1596 dout("invalidate_inode_pages2_range returned %d\n", ret);
1597
1598 while ((len = iov_iter_count(from)) > 0) {
1599 size_t left;
1600 int n;
1601 u64 write_pos = pos;
1602 u64 write_len = len;
1603 u64 objnum, objoff;
1604 u32 xlen;
1605 u64 assert_ver = 0;
1606 bool rmw;
1607 bool first, last;
1608 struct iov_iter saved_iter = *from;
1609 size_t off;
1610
1611 ceph_fscrypt_adjust_off_and_len(inode, &write_pos, &write_len);
1612
1613 /* clamp the length to the end of first object */
1614 ceph_calc_file_object_mapping(&ci->i_layout, write_pos,
1615 write_len, &objnum, &objoff,
1616 &xlen);
1617 write_len = xlen;
1618
1619 /* adjust len downward if it goes beyond current object */
1620 if (pos + len > write_pos + write_len)
1621 len = write_pos + write_len - pos;
1622
1623 /*
1624 * If we had to adjust the length or position to align with a
1625 * crypto block, then we must do a read/modify/write cycle. We
1626 * use a version assertion to redrive the thing if something
1627 * changes in between.
1628 */
1629 first = pos != write_pos;
1630 last = (pos + len) != (write_pos + write_len);
1631 rmw = first || last;
1632
1633 dout("sync_write ino %llx %lld~%llu adjusted %lld~%llu -- %srmw\n",
1634 ci->i_vino.ino, pos, len, write_pos, write_len, rmw ? "" : "no ");
1635
1636 /*
1637 * The data is emplaced into the page as it would be if it were in
1638 * an array of pagecache pages.
1639 */
1640 num_pages = calc_pages_for(write_pos, write_len);
1641 pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
1642 if (IS_ERR(pages)) {
1643 ret = PTR_ERR(pages);
1644 break;
1645 }
1646
1647 /* Do we need to preload the pages? */
1648 if (rmw) {
1649 u64 first_pos = write_pos;
1650 u64 last_pos = (write_pos + write_len) - CEPH_FSCRYPT_BLOCK_SIZE;
1651 u64 read_len = CEPH_FSCRYPT_BLOCK_SIZE;
1652 struct ceph_osd_req_op *op;
1653
1654 /* We should only need to do this for encrypted inodes */
1655 WARN_ON_ONCE(!IS_ENCRYPTED(inode));
1656
1657 /* No need to do two reads if first and last blocks are same */
1658 if (first && last_pos == first_pos)
1659 last = false;
1660
1661 /*
1662 * Allocate a read request for one or two extents, depending
1663 * on how the request was aligned.
1664 */
1665 req = ceph_osdc_new_request(osdc, &ci->i_layout,
1666 ci->i_vino, first ? first_pos : last_pos,
1667 &read_len, 0, (first && last) ? 2 : 1,
1668 CEPH_OSD_OP_SPARSE_READ, CEPH_OSD_FLAG_READ,
1669 NULL, ci->i_truncate_seq,
1670 ci->i_truncate_size, false);
1671 if (IS_ERR(req)) {
1672 ceph_release_page_vector(pages, num_pages);
1673 ret = PTR_ERR(req);
1674 break;
1675 }
1676
1677 /* Something is misaligned! */
1678 if (read_len != CEPH_FSCRYPT_BLOCK_SIZE) {
1679 ceph_osdc_put_request(req);
1680 ceph_release_page_vector(pages, num_pages);
1681 ret = -EIO;
1682 break;
1683 }
1684
1685 /* Add extent for first block? */
1686 op = &req->r_ops[0];
1687
1688 if (first) {
1689 osd_req_op_extent_osd_data_pages(req, 0, pages,
1690 CEPH_FSCRYPT_BLOCK_SIZE,
1691 offset_in_page(first_pos),
1692 false, false);
1693 /* We only expect a single extent here */
1694 ret = __ceph_alloc_sparse_ext_map(op, 1);
1695 if (ret) {
1696 ceph_osdc_put_request(req);
1697 ceph_release_page_vector(pages, num_pages);
1698 break;
1699 }
1700 }
1701
1702 /* Add extent for last block */
1703 if (last) {
1704 /* Init the other extent if first extent has been used */
1705 if (first) {
1706 op = &req->r_ops[1];
1707 osd_req_op_extent_init(req, 1, CEPH_OSD_OP_SPARSE_READ,
1708 last_pos, CEPH_FSCRYPT_BLOCK_SIZE,
1709 ci->i_truncate_size,
1710 ci->i_truncate_seq);
1711 }
1712
1713 ret = __ceph_alloc_sparse_ext_map(op, 1);
1714 if (ret) {
1715 ceph_osdc_put_request(req);
1716 ceph_release_page_vector(pages, num_pages);
1717 break;
1718 }
1719
1720 osd_req_op_extent_osd_data_pages(req, first ? 1 : 0,
1721 &pages[num_pages - 1],
1722 CEPH_FSCRYPT_BLOCK_SIZE,
1723 offset_in_page(last_pos),
1724 false, false);
1725 }
1726
1727 ret = ceph_osdc_start_request(osdc, req, false);
1728 if (!ret)
1729 ret = ceph_osdc_wait_request(osdc, req);
1730
1731 /* FIXME: length field is wrong if there are 2 extents */
1732 ceph_update_read_metrics(&fsc->mdsc->metric,
1733 req->r_start_latency,
1734 req->r_end_latency,
1735 read_len, ret);
1736
1737 /* Ok if object is not already present */
1738 if (ret == -ENOENT) {
1739 /*
1740 * If there is no object, then we can't assert
1741 * on its version. Set it to 0, and we'll use an
1742 * exclusive create instead.
1743 */
1744 ceph_osdc_put_request(req);
1745 ret = 0;
1746
1747 /*
1748 * zero out the soon-to-be uncopied parts of the
1749 * first and last pages.
1750 */
1751 if (first)
1752 zero_user_segment(pages[0], 0,
1753 offset_in_page(first_pos));
1754 if (last)
1755 zero_user_segment(pages[num_pages - 1],
1756 offset_in_page(last_pos),
1757 PAGE_SIZE);
1758 } else {
1759 if (ret < 0) {
1760 ceph_osdc_put_request(req);
1761 ceph_release_page_vector(pages, num_pages);
1762 break;
1763 }
1764
1765 op = &req->r_ops[0];
1766 if (op->extent.sparse_ext_cnt == 0) {
1767 if (first)
1768 zero_user_segment(pages[0], 0,
1769 offset_in_page(first_pos));
1770 else
1771 zero_user_segment(pages[num_pages - 1],
1772 offset_in_page(last_pos),
1773 PAGE_SIZE);
1774 } else if (op->extent.sparse_ext_cnt != 1 ||
1775 ceph_sparse_ext_map_end(op) !=
1776 CEPH_FSCRYPT_BLOCK_SIZE) {
1777 ret = -EIO;
1778 ceph_osdc_put_request(req);
1779 ceph_release_page_vector(pages, num_pages);
1780 break;
1781 }
1782
1783 if (first && last) {
1784 op = &req->r_ops[1];
1785 if (op->extent.sparse_ext_cnt == 0) {
1786 zero_user_segment(pages[num_pages - 1],
1787 offset_in_page(last_pos),
1788 PAGE_SIZE);
1789 } else if (op->extent.sparse_ext_cnt != 1 ||
1790 ceph_sparse_ext_map_end(op) !=
1791 CEPH_FSCRYPT_BLOCK_SIZE) {
1792 ret = -EIO;
1793 ceph_osdc_put_request(req);
1794 ceph_release_page_vector(pages, num_pages);
1795 break;
1796 }
1797 }
1798
1799 /* Grab assert version. It must be non-zero. */
1800 assert_ver = req->r_version;
1801 WARN_ON_ONCE(ret > 0 && assert_ver == 0);
1802
1803 ceph_osdc_put_request(req);
1804 if (first) {
1805 ret = ceph_fscrypt_decrypt_block_inplace(inode,
1806 pages[0],
1807 CEPH_FSCRYPT_BLOCK_SIZE,
1808 offset_in_page(first_pos),
1809 first_pos >> CEPH_FSCRYPT_BLOCK_SHIFT);
1810 if (ret < 0) {
1811 ceph_release_page_vector(pages, num_pages);
1812 break;
1813 }
1814 }
1815 if (last) {
1816 ret = ceph_fscrypt_decrypt_block_inplace(inode,
1817 pages[num_pages - 1],
1818 CEPH_FSCRYPT_BLOCK_SIZE,
1819 offset_in_page(last_pos),
1820 last_pos >> CEPH_FSCRYPT_BLOCK_SHIFT);
1821 if (ret < 0) {
1822 ceph_release_page_vector(pages, num_pages);
1823 break;
1824 }
1825 }
1826 }
1827 }
1828
1829 left = len;
1830 off = offset_in_page(pos);
1831 for (n = 0; n < num_pages; n++) {
1832 size_t plen = min_t(size_t, left, PAGE_SIZE - off);
1833
1834 /* copy the data */
1835 ret = copy_page_from_iter(pages[n], off, plen, from);
1836 if (ret != plen) {
1837 ret = -EFAULT;
1838 break;
1839 }
1840 off = 0;
1841 left -= ret;
1842 }
1843 if (ret < 0) {
1844 dout("sync_write write failed with %d\n", ret);
1845 ceph_release_page_vector(pages, num_pages);
1846 break;
1847 }
1848
1849 if (IS_ENCRYPTED(inode)) {
1850 ret = ceph_fscrypt_encrypt_pages(inode, pages,
1851 write_pos, write_len,
1852 GFP_KERNEL);
1853 if (ret < 0) {
1854 dout("encryption failed with %d\n", ret);
1855 ceph_release_page_vector(pages, num_pages);
1856 break;
1857 }
1858 }
1859
1860 req = ceph_osdc_new_request(osdc, &ci->i_layout,
1861 ci->i_vino, write_pos, &write_len,
1862 rmw ? 1 : 0, rmw ? 2 : 1,
1863 CEPH_OSD_OP_WRITE,
1864 CEPH_OSD_FLAG_WRITE,
1865 snapc, ci->i_truncate_seq,
1866 ci->i_truncate_size, false);
1867 if (IS_ERR(req)) {
1868 ret = PTR_ERR(req);
1869 ceph_release_page_vector(pages, num_pages);
1870 break;
1871 }
1872
1873 dout("sync_write write op %lld~%llu\n", write_pos, write_len);
1874 osd_req_op_extent_osd_data_pages(req, rmw ? 1 : 0, pages, write_len,
1875 offset_in_page(write_pos), false,
1876 true);
1877 req->r_inode = inode;
1878 req->r_mtime = mtime;
1879
1880 /* Set up the assertion */
1881 if (rmw) {
1882 /*
1883 * Set up the assertion. If we don't have a version number,
1884 * then the object doesn't exist yet. Use an exclusive create
1885 * instead of a version assertion in that case.
1886 */
1887 if (assert_ver) {
1888 osd_req_op_init(req, 0, CEPH_OSD_OP_ASSERT_VER, 0);
1889 req->r_ops[0].assert_ver.ver = assert_ver;
1890 } else {
1891 osd_req_op_init(req, 0, CEPH_OSD_OP_CREATE,
1892 CEPH_OSD_OP_FLAG_EXCL);
1893 }
1894 }
1895
1896 ceph_osdc_start_request(osdc, req, false);
1897
1898 ceph_update_write_metrics(&fsc->mdsc->metric, req->r_start_latency,
1899 req->r_end_latency, len, ret);
1900 ceph_osdc_put_request(req);
1901 if (ret != 0) {
1902 dout("sync_write osd write returned %d\n", ret);
1903 /* Version changed! Must re-do the rmw cycle */
1904 if ((assert_ver && (ret == -ERANGE || ret == -EOVERFLOW)) ||
1905 (!assert_ver && ret == -EEXIST)) {
1906 /* We should only ever see this on a rmw */
1907 WARN_ON_ONCE(!rmw);
1908
1909 /* The version should never go backward */
1910 WARN_ON_ONCE(ret == -EOVERFLOW);
1911
1912 *from = saved_iter;
1913
1914 /* FIXME: limit number of times we loop? */
1915 continue;
1916 }
1917 ceph_set_error_write(ci);
1918 break;
1919 }
1920 ceph_clear_error_write(ci);
1921 pos += len;
1922 written += len;
1923 dout("sync_write written %d\n", written);
1924 if (pos > i_size_read(inode)) {
1925 check_caps = ceph_inode_set_size(inode, pos);
1926 if (check_caps)
1927 ceph_check_caps(ceph_inode(inode),
1928 CHECK_CAPS_AUTHONLY,
1929 NULL);
1930 }
1931
1932 }
1933
1934 if (ret != -EOLDSNAPC && written > 0) {
1935 ret = written;
1936 iocb->ki_pos = pos;
1937 }
1938 dout("sync_write returning %d\n", ret);
1939 return ret;
1940 }
1941