diff options
author | Keith Busch <keith.busch@intel.com> | 2015-04-07 18:57:19 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-04-07 21:11:06 -0400 |
commit | a67a95134ffddd0ca4527c77e86375c3deb2938f (patch) | |
tree | 26981c1df5c40941a9bdcda9dad235cf8a82b4f8 /drivers/block | |
parent | 7f749d9c109223e4d1724e674e7d603082e85839 (diff) |
NVMe: Meta data handling through submit io ioctl
This adds support for the extended metadata formats through the submit
IO ioctl, and simplifies the rest when using a separate metadata format.
Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/nvme-core.c | 123 |
1 files changed, 49 insertions, 74 deletions
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 973c895bd7af..e919de48ff25 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c | |||
@@ -1745,25 +1745,31 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) | |||
1745 | struct nvme_dev *dev = ns->dev; | 1745 | struct nvme_dev *dev = ns->dev; |
1746 | struct nvme_user_io io; | 1746 | struct nvme_user_io io; |
1747 | struct nvme_command c; | 1747 | struct nvme_command c; |
1748 | unsigned length, meta_len; | 1748 | unsigned length, meta_len, prp_len; |
1749 | int status, i; | 1749 | int status, write; |
1750 | struct nvme_iod *iod, *meta_iod = NULL; | 1750 | struct nvme_iod *iod; |
1751 | dma_addr_t meta_dma_addr; | 1751 | dma_addr_t meta_dma = 0; |
1752 | void *meta, *uninitialized_var(meta_mem); | 1752 | void *meta = NULL; |
1753 | 1753 | ||
1754 | if (copy_from_user(&io, uio, sizeof(io))) | 1754 | if (copy_from_user(&io, uio, sizeof(io))) |
1755 | return -EFAULT; | 1755 | return -EFAULT; |
1756 | length = (io.nblocks + 1) << ns->lba_shift; | 1756 | length = (io.nblocks + 1) << ns->lba_shift; |
1757 | meta_len = (io.nblocks + 1) * ns->ms; | 1757 | meta_len = (io.nblocks + 1) * ns->ms; |
1758 | 1758 | ||
1759 | if (meta_len && ((io.metadata & 3) || !io.metadata)) | 1759 | if (meta_len && ((io.metadata & 3) || !io.metadata) && !ns->ext) |
1760 | return -EINVAL; | 1760 | return -EINVAL; |
1761 | else if (meta_len && ns->ext) { | ||
1762 | length += meta_len; | ||
1763 | meta_len = 0; | ||
1764 | } | ||
1765 | |||
1766 | write = io.opcode & 1; | ||
1761 | 1767 | ||
1762 | switch (io.opcode) { | 1768 | switch (io.opcode) { |
1763 | case nvme_cmd_write: | 1769 | case nvme_cmd_write: |
1764 | case nvme_cmd_read: | 1770 | case nvme_cmd_read: |
1765 | case nvme_cmd_compare: | 1771 | case nvme_cmd_compare: |
1766 | iod = nvme_map_user_pages(dev, io.opcode & 1, io.addr, length); | 1772 | iod = nvme_map_user_pages(dev, write, io.addr, length); |
1767 | break; | 1773 | break; |
1768 | default: | 1774 | default: |
1769 | return -EINVAL; | 1775 | return -EINVAL; |
@@ -1772,6 +1778,27 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) | |||
1772 | if (IS_ERR(iod)) | 1778 | if (IS_ERR(iod)) |
1773 | return PTR_ERR(iod); | 1779 | return PTR_ERR(iod); |
1774 | 1780 | ||
1781 | prp_len = nvme_setup_prps(dev, iod, length, GFP_KERNEL); | ||
1782 | if (length != prp_len) { | ||
1783 | status = -ENOMEM; | ||
1784 | goto unmap; | ||
1785 | } | ||
1786 | if (meta_len) { | ||
1787 | meta = dma_alloc_coherent(&dev->pci_dev->dev, meta_len, | ||
1788 | &meta_dma, GFP_KERNEL); | ||
1789 | if (!meta) { | ||
1790 | status = -ENOMEM; | ||
1791 | goto unmap; | ||
1792 | } | ||
1793 | if (write) { | ||
1794 | if (copy_from_user(meta, (void __user *)io.metadata, | ||
1795 | meta_len)) { | ||
1796 | status = -EFAULT; | ||
1797 | goto unmap; | ||
1798 | } | ||
1799 | } | ||
1800 | } | ||
1801 | |||
1775 | memset(&c, 0, sizeof(c)); | 1802 | memset(&c, 0, sizeof(c)); |
1776 | c.rw.opcode = io.opcode; | 1803 | c.rw.opcode = io.opcode; |
1777 | c.rw.flags = io.flags; | 1804 | c.rw.flags = io.flags; |
@@ -1783,75 +1810,21 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) | |||
1783 | c.rw.reftag = cpu_to_le32(io.reftag); | 1810 | c.rw.reftag = cpu_to_le32(io.reftag); |
1784 | c.rw.apptag = cpu_to_le16(io.apptag); | 1811 | c.rw.apptag = cpu_to_le16(io.apptag); |
1785 | c.rw.appmask = cpu_to_le16(io.appmask); | 1812 | c.rw.appmask = cpu_to_le16(io.appmask); |
1786 | |||
1787 | if (meta_len) { | ||
1788 | meta_iod = nvme_map_user_pages(dev, io.opcode & 1, io.metadata, | ||
1789 | meta_len); | ||
1790 | if (IS_ERR(meta_iod)) { | ||
1791 | status = PTR_ERR(meta_iod); | ||
1792 | meta_iod = NULL; | ||
1793 | goto unmap; | ||
1794 | } | ||
1795 | |||
1796 | meta_mem = dma_alloc_coherent(&dev->pci_dev->dev, meta_len, | ||
1797 | &meta_dma_addr, GFP_KERNEL); | ||
1798 | if (!meta_mem) { | ||
1799 | status = -ENOMEM; | ||
1800 | goto unmap; | ||
1801 | } | ||
1802 | |||
1803 | if (io.opcode & 1) { | ||
1804 | int meta_offset = 0; | ||
1805 | |||
1806 | for (i = 0; i < meta_iod->nents; i++) { | ||
1807 | meta = kmap_atomic(sg_page(&meta_iod->sg[i])) + | ||
1808 | meta_iod->sg[i].offset; | ||
1809 | memcpy(meta_mem + meta_offset, meta, | ||
1810 | meta_iod->sg[i].length); | ||
1811 | kunmap_atomic(meta); | ||
1812 | meta_offset += meta_iod->sg[i].length; | ||
1813 | } | ||
1814 | } | ||
1815 | |||
1816 | c.rw.metadata = cpu_to_le64(meta_dma_addr); | ||
1817 | } | ||
1818 | |||
1819 | length = nvme_setup_prps(dev, iod, length, GFP_KERNEL); | ||
1820 | c.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); | 1813 | c.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); |
1821 | c.rw.prp2 = cpu_to_le64(iod->first_dma); | 1814 | c.rw.prp2 = cpu_to_le64(iod->first_dma); |
1822 | 1815 | c.rw.metadata = cpu_to_le64(meta_dma); | |
1823 | if (length != (io.nblocks + 1) << ns->lba_shift) | 1816 | status = nvme_submit_io_cmd(dev, ns, &c, NULL); |
1824 | status = -ENOMEM; | ||
1825 | else | ||
1826 | status = nvme_submit_io_cmd(dev, ns, &c, NULL); | ||
1827 | |||
1828 | if (meta_len) { | ||
1829 | if (status == NVME_SC_SUCCESS && !(io.opcode & 1)) { | ||
1830 | int meta_offset = 0; | ||
1831 | |||
1832 | for (i = 0; i < meta_iod->nents; i++) { | ||
1833 | meta = kmap_atomic(sg_page(&meta_iod->sg[i])) + | ||
1834 | meta_iod->sg[i].offset; | ||
1835 | memcpy(meta, meta_mem + meta_offset, | ||
1836 | meta_iod->sg[i].length); | ||
1837 | kunmap_atomic(meta); | ||
1838 | meta_offset += meta_iod->sg[i].length; | ||
1839 | } | ||
1840 | } | ||
1841 | |||
1842 | dma_free_coherent(&dev->pci_dev->dev, meta_len, meta_mem, | ||
1843 | meta_dma_addr); | ||
1844 | } | ||
1845 | |||
1846 | unmap: | 1817 | unmap: |
1847 | nvme_unmap_user_pages(dev, io.opcode & 1, iod); | 1818 | nvme_unmap_user_pages(dev, write, iod); |
1848 | nvme_free_iod(dev, iod); | 1819 | nvme_free_iod(dev, iod); |
1849 | 1820 | if (meta) { | |
1850 | if (meta_iod) { | 1821 | if (status == NVME_SC_SUCCESS && !write) { |
1851 | nvme_unmap_user_pages(dev, io.opcode & 1, meta_iod); | 1822 | if (copy_to_user((void __user *)io.metadata, meta, |
1852 | nvme_free_iod(dev, meta_iod); | 1823 | meta_len)) |
1824 | status = -EFAULT; | ||
1825 | } | ||
1826 | dma_free_coherent(&dev->pci_dev->dev, meta_len, meta, meta_dma); | ||
1853 | } | 1827 | } |
1854 | |||
1855 | return status; | 1828 | return status; |
1856 | } | 1829 | } |
1857 | 1830 | ||
@@ -2014,7 +1987,8 @@ static int nvme_revalidate_disk(struct gendisk *disk) | |||
2014 | struct nvme_dev *dev = ns->dev; | 1987 | struct nvme_dev *dev = ns->dev; |
2015 | struct nvme_id_ns *id; | 1988 | struct nvme_id_ns *id; |
2016 | dma_addr_t dma_addr; | 1989 | dma_addr_t dma_addr; |
2017 | int lbaf, pi_type, old_ms; | 1990 | u8 lbaf, pi_type; |
1991 | u16 old_ms; | ||
2018 | unsigned short bs; | 1992 | unsigned short bs; |
2019 | 1993 | ||
2020 | id = dma_alloc_coherent(&dev->pci_dev->dev, 4096, &dma_addr, | 1994 | id = dma_alloc_coherent(&dev->pci_dev->dev, 4096, &dma_addr, |
@@ -2035,6 +2009,7 @@ static int nvme_revalidate_disk(struct gendisk *disk) | |||
2035 | lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK; | 2009 | lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK; |
2036 | ns->lba_shift = id->lbaf[lbaf].ds; | 2010 | ns->lba_shift = id->lbaf[lbaf].ds; |
2037 | ns->ms = le16_to_cpu(id->lbaf[lbaf].ms); | 2011 | ns->ms = le16_to_cpu(id->lbaf[lbaf].ms); |
2012 | ns->ext = ns->ms && (id->flbas & NVME_NS_FLBAS_META_EXT); | ||
2038 | 2013 | ||
2039 | /* | 2014 | /* |
2040 | * If identify namespace failed, use default 512 byte block size so | 2015 | * If identify namespace failed, use default 512 byte block size so |
@@ -2051,14 +2026,14 @@ static int nvme_revalidate_disk(struct gendisk *disk) | |||
2051 | if (blk_get_integrity(disk) && (ns->pi_type != pi_type || | 2026 | if (blk_get_integrity(disk) && (ns->pi_type != pi_type || |
2052 | ns->ms != old_ms || | 2027 | ns->ms != old_ms || |
2053 | bs != queue_logical_block_size(disk->queue) || | 2028 | bs != queue_logical_block_size(disk->queue) || |
2054 | (ns->ms && id->flbas & NVME_NS_FLBAS_META_EXT))) | 2029 | (ns->ms && ns->ext))) |
2055 | blk_integrity_unregister(disk); | 2030 | blk_integrity_unregister(disk); |
2056 | 2031 | ||
2057 | ns->pi_type = pi_type; | 2032 | ns->pi_type = pi_type; |
2058 | blk_queue_logical_block_size(ns->queue, bs); | 2033 | blk_queue_logical_block_size(ns->queue, bs); |
2059 | 2034 | ||
2060 | if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) && | 2035 | if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) && |
2061 | !(id->flbas & NVME_NS_FLBAS_META_EXT)) | 2036 | !ns->ext) |
2062 | nvme_init_integrity(ns); | 2037 | nvme_init_integrity(ns); |
2063 | 2038 | ||
2064 | if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk))) | 2039 | if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk))) |