Re: [patch 17/30] NTB/msi: Use irq_has_action()
On 2020-12-10 12:25 p.m., Thomas Gleixner wrote: > Use the proper core function. > > Signed-off-by: Thomas Gleixner > Cc: Jon Mason > Cc: Dave Jiang > Cc: Allen Hubbe > Cc: linux-...@googlegroups.com Looks good to me. Reviewed-by: Logan Gunthorpe > --- > drivers/ntb/msi.c |4 +--- > 1 file changed, 1 insertion(+), 3 deletions(-) > > --- a/drivers/ntb/msi.c > +++ b/drivers/ntb/msi.c > @@ -282,15 +282,13 @@ int ntbm_msi_request_threaded_irq(struct > struct ntb_msi_desc *msi_desc) > { > struct msi_desc *entry; > - struct irq_desc *desc; > int ret; > > if (!ntb->msi) > return -EINVAL; > > for_each_pci_msi_entry(entry, ntb->pdev) { > - desc = irq_to_desc(entry->irq); > - if (desc->action) > + if (irq_has_action(entry->irq)) > continue; > > ret = devm_request_threaded_irq(&ntb->dev, entry->irq, handler, >
Re: nvmet with cxgb4 is broken in v4.12-rc1
On 17/05/17 01:22 PM, Steve Wise wrote: > Hey Logan, this is with 1.16.43.0 firmware? Yes, that's correct. Logan
BUG: nvmet with cxgb4 is broken in v4.12-rc1
Hello, Another cxgb4 bug report for you. Testing nvmet over our T62100-LP-CR stopped working in v4.12-rc1. We are seeing two oopses: a general protection fault in nvmet_rdma_free_rsps and a WQ_MEM_RECLAIM warning. These occur after a suspect cxgb4 message. Please see the full dmesg log which is attached. > [ 41.093555] cxgb4 :07:00.4: AE qpid 1034 opcode 0 status 0x1 type 1 > len 0x0 wrid.hi 0x0 wrid.lo 0x0 > [ 41.093673] nvmet_rdma: received IB QP event: QP access error (3) I've bisected to find this commit is the culprit: bb58d079: cxgb4: Update IngPad and IngPack values A bisect log is also attached. Reverting that commit also fixes the issue. Thanks, Logan git bisect start # good: [a351e9b9fc24e982ec2f0e76379a49826036da12] Linux 4.11 git bisect good a351e9b9fc24e982ec2f0e76379a49826036da12 # bad: [2ea659a9ef488125eb46da6eb571de5eae5c43f6] Linux 4.12-rc1 git bisect bad 2ea659a9ef488125eb46da6eb571de5eae5c43f6 # bad: [221656e7c4ce342b99c31eca96c1cbb6d1dce45f] Merge tag 'sound-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound git bisect bad 221656e7c4ce342b99c31eca96c1cbb6d1dce45f # bad: [8d65b08debc7e62b2c6032d7fe7389d895b92cbc] Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next git bisect bad 8d65b08debc7e62b2c6032d7fe7389d895b92cbc # bad: [cec381919818a9a0cb85600b3c82404bdd38cf36] Merge tag 'mac80211-next-for-davem-2017-04-28' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next git bisect bad cec381919818a9a0cb85600b3c82404bdd38cf36 # bad: [5cd8985a19090f2b0ce8700ae3ec19e06a4fc5e9] net-next: dsa: add Mediatek tag RX/TX handler git bisect bad 5cd8985a19090f2b0ce8700ae3ec19e06a4fc5e9 # bad: [b4f0a66155564aaf7e98492e027efad9f797c244] net: stmmac: fix dma operation mode config for older versions git bisect bad b4f0a66155564aaf7e98492e027efad9f797c244 # good: [6689da155bdcd17abfe4d3a8b1e245d9ed4b5f2c] net: bcmgenet: manage dma interrupts in napi code git bisect good 6689da155bdcd17abfe4d3a8b1e245d9ed4b5f2c # good: [41e95736b30833710c1e77a2877c2d71133450f7] Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next git bisect good 41e95736b30833710c1e77a2877c2d71133450f7 # good: [cccf6f5cdc96ef6fa02f27ecd8073406a402929a] qed: Make qed_iov_mark_vf_flr() return bool git bisect good cccf6f5cdc96ef6fa02f27ecd8073406a402929a # bad: [33e85b8dd69e7f2fbf77f04bfc97ea7c76bccf9b] net: stmmac: Restore DT backwards-compatibility git bisect bad 33e85b8dd69e7f2fbf77f04bfc97ea7c76bccf9b # bad: [c7cd4c9bf8df87027e739fe66d0a55951f6875d8] mlxsw: spectrum: fix swapped order of arguments packets and bytes git bisect bad c7cd4c9bf8df87027e739fe66d0a55951f6875d8 # good: [f22913d0b5560ae621e8a7391e9547d5a6fd8893] ixgb: use new API ethtool_{get|set}_link_ksettings git bisect good f22913d0b5560ae621e8a7391e9547d5a6fd8893 # good: [7ada7ca562714632d0fc9abb24e27cab67bdbf0d] Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue git bisect good 7ada7ca562714632d0fc9abb24e27cab67bdbf0d # good: [424fa00ea325b0153c321667f39643f68ae9d1b0] net: dwc-xlgmac: include dcbnl.h git bisect good 424fa00ea325b0153c321667f39643f68ae9d1b0 # bad: [bb58d07964f2f09e133b46541447c567a7306dc1] cxgb4: Update IngPad and IngPack values git bisect bad bb58d07964f2f09e133b46541447c567a7306dc1 # good: [3588f29e061cef19ac0092e4f6917717fed5b1d4] net: dwc-xlgmac: add module license git bisect good 3588f29e061cef19ac0092e4f6917717fed5b1d4 # first bad commit: [bb58d07964f2f09e133b46541447c567a7306dc1] cxgb4: Update IngPad and IngPack values [0.00] Linux version 4.12.0-rc1.spreadpfn (gunthorp@cgy1-donard) (gcc version 4.9.2 (Debian 4.9.2-10) ) #340 SMP Wed May 17 11:27:02 MDT 2017 [0.00] Command line: BOOT_IMAGE=/vmlinuz-4.11.0-next-20170510.spread-pfn+ root=/dev/mapper/cgy1--donard-root ro memmap=2G!14G quiet [0.00] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers' [0.00] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers' [0.00] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers' [0.00] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256 [0.00] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format. [0.00] e820: BIOS-provided physical RAM map: [0.00] BIOS-e820: [mem 0x-0x0008dbff] usable [0.00] BIOS-e820: [mem 0x0008dc00-0x0009] reserved [0.00] BIOS-e820: [mem 0x000e-0x000f] reserved [0.00] BIOS-e820: [mem 0x0010-0x7dd14fff] usable [0.00] BIOS-e820: [mem 0x7dd15000-0x7dda3fff] reserved [0.00] BIOS-e820: [mem 0x7dda4000-0x7deadfff] ACPI data [0.00] BIOS-e820: [mem 0x7deae000-0x7e0cafff] ACPI NVS [0.00] BIOS-e820: [mem 0x7e0cb000-0x7f36bfff] reserved [0.00] BIOS-e820: [mem 0x7f36c000-0x7f7f]
Re: cxgb4 is broken in v4.12-rc1
Hey, Ok, yes with the latest firmware the issue seems to have gone away. Still, it's probably not a great idea to break peoples hardware with a kernel update even if their firmware is old. Thanks, Logan On 16/05/17 09:19 AM, Ganesh GR wrote: > > Hi Logan, > > The latest firmware available is 1.16.43.0 kindly update your firmware and > give a try, 1.16.29.4 have no support for autoneg. > > Thanks > Ganesh > > > > > > > From: Logan Gunthorpe > Sent: Tuesday, May 16, 2017 7:20 AM > To: Ganesh GR > Cc: David S. Miller; Stephen Bates; SWise OGC; netdev@vger.kernel.org > Subject: Re: cxgb4 is broken in v4.12-rc1 > > Hi, > > Thanks for looking into it. The version information of the card is: > > [5.235956] cxgb4 :07:00.4: Chelsio T62100-LP-CR rev 0 > [5.235957] cxgb4 :07:00.4: S/N: PT51160053, P/N: 11012106004 > [5.235959] cxgb4 :07:00.4: Firmware version: 1.16.29.4 > [5.235960] cxgb4 :07:00.4: Bootstrap version: 255.255.255.255 > [5.235961] cxgb4 :07:00.4: TP Microcode version: 0.1.23.2 > > Logan > > > On 15/05/17 07:00 PM, Ganesh GR wrote: >> >> Hi Logan, >> >> Thanks for reporting the issue I will try to reproduce this, btw what is the >> firmware version >> on your setup?. >> >> Regards >> Ganesh >> >> >> >> >> From: Logan Gunthorpe >> Sent: Tuesday, May 16, 2017 4:06 AM >> To: Ganesh GR >> Cc: David S. Miller; Stephen Bates; SWise OGC; netdev@vger.kernel.org >> Subject: BUG: cxgb4 is broken in v4.12-rc1 >> >> Hi, >> >> With rc1 my T62100-LP-CR no longer functions correctly. Everything >> appears fine but the link never goes into the UP state. I have one peer >> with an older (functioning) kernel and the other peer on rc1. >> >> I've bisected to find this is the offending commit: >> >> 3bb4858fd: cxgb4: avoid disabling FEC by default >> >> I've also attached a bisect log. >> >> Let me know if you need anything else. >> >> Thanks, >> >> Logan >> >> > >
Re: cxgb4 is broken in v4.12-rc1
Hi, Thanks for looking into it. The version information of the card is: [5.235956] cxgb4 :07:00.4: Chelsio T62100-LP-CR rev 0 [5.235957] cxgb4 :07:00.4: S/N: PT51160053, P/N: 11012106004 [5.235959] cxgb4 :07:00.4: Firmware version: 1.16.29.4 [5.235960] cxgb4 :07:00.4: Bootstrap version: 255.255.255.255 [5.235961] cxgb4 :07:00.4: TP Microcode version: 0.1.23.2 Logan On 15/05/17 07:00 PM, Ganesh GR wrote: > > Hi Logan, > > Thanks for reporting the issue I will try to reproduce this, btw what is the > firmware version > on your setup?. > > Regards > Ganesh > > > > > From: Logan Gunthorpe > Sent: Tuesday, May 16, 2017 4:06 AM > To: Ganesh GR > Cc: David S. Miller; Stephen Bates; SWise OGC; netdev@vger.kernel.org > Subject: BUG: cxgb4 is broken in v4.12-rc1 > > Hi, > > With rc1 my T62100-LP-CR no longer functions correctly. Everything > appears fine but the link never goes into the UP state. I have one peer > with an older (functioning) kernel and the other peer on rc1. > > I've bisected to find this is the offending commit: > > 3bb4858fd: cxgb4: avoid disabling FEC by default > > I've also attached a bisect log. > > Let me know if you need anything else. > > Thanks, > > Logan > >
BUG: cxgb4 is broken in v4.12-rc1
Hi, With rc1 my T62100-LP-CR no longer functions correctly. Everything appears fine but the link never goes into the UP state. I have one peer with an older (functioning) kernel and the other peer on rc1. I've bisected to find this is the offending commit: 3bb4858fd: cxgb4: avoid disabling FEC by default I've also attached a bisect log. Let me know if you need anything else. Thanks, Logan git bisect start # bad: [2ea659a9ef488125eb46da6eb571de5eae5c43f6] Linux 4.12-rc1 git bisect bad 2ea659a9ef488125eb46da6eb571de5eae5c43f6 # good: [c02ed2e75ef4c74e41e421acb4ef1494671585e8] Linux 4.11-rc4 git bisect good c02ed2e75ef4c74e41e421acb4ef1494671585e8 # good: [2f34c1231bfc9f2550f934acb268ac7315fb3837] Merge tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux git bisect good 2f34c1231bfc9f2550f934acb268ac7315fb3837 # good: [c6a677c6f37bb7abc85ba7e3465e82b9f7eb1d91] Merge tag 'staging-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging git bisect good c6a677c6f37bb7abc85ba7e3465e82b9f7eb1d91 # good: [0ff4c01b279a590a2826ade9321ad8c7ca5a1b6c] Merge tag 'armsoc-arm64' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc git bisect good 0ff4c01b279a590a2826ade9321ad8c7ca5a1b6c # bad: [c70422f760c120480fee4de6c38804c72aa26bc1] Merge tag 'nfsd-4.12' of git://linux-nfs.org/~bfields/linux git bisect bad c70422f760c120480fee4de6c38804c72aa26bc1 # bad: [56868a460b83c0f93d339256a81064d89aadae8e] Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/ide git bisect bad 56868a460b83c0f93d339256a81064d89aadae8e # good: [ae706bebd6a172a6adf9f63d1a77b8ed49e998a6] Merge tag 'juno-fixes-4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/dt64 git bisect good ae706bebd6a172a6adf9f63d1a77b8ed49e998a6 # good: [ecc721a72c121e8b641d68efd24a225abedb9a30] Merge tag 'pwm/for-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm git bisect good ecc721a72c121e8b641d68efd24a225abedb9a30 # bad: [657831ffc38e30092a2d5f03d385d710eb88b09a] dccp/tcp: do not inherit mc_list from parent git bisect bad 657831ffc38e30092a2d5f03d385d710eb88b09a # bad: [b210aeaedfc47ab8a86fbdcad46caf1e49cc0e37] Merge branch 'stmmac-pci-fix-crash-on-Intel-Galileo-Gen2' git bisect bad b210aeaedfc47ab8a86fbdcad46caf1e49cc0e37 # good: [ac45bd93a5035c2f39c9862b8b6ed692db0fdc87] bnxt_en: allocate enough space for ->ntp_fltr_bmap git bisect good ac45bd93a5035c2f39c9862b8b6ed692db0fdc87 # bad: [0d0e57697f162da4aa218b5feafe614fb666db07] bpf: don't let ldimm64 leak map addresses on unprivileged git bisect bad 0d0e57697f162da4aa218b5feafe614fb666db07 # bad: [3bb4858fda1cac2ae677edb5134932af4c7f8ff8] cxgb4: avoid disabling FEC by default git bisect bad 3bb4858fda1cac2ae677edb5134932af4c7f8ff8 # good: [8ce79797f944ad2f50e5160c8a20a473aedf] net: dsa: loop: Check for memory allocation failure git bisect good 8ce79797f944ad2f50e5160c8a20a473aedf # first bad commit: [3bb4858fda1cac2ae677edb5134932af4c7f8ff8] cxgb4: avoid disabling FEC by default
Re: [PATCH v2 07/21] crypto: shash, caam: Make use of the new sg_map helper function
On 28/04/17 11:51 AM, Herbert Xu wrote: > On Fri, Apr 28, 2017 at 10:53:45AM -0600, Logan Gunthorpe wrote: >> >> >> On 28/04/17 12:30 AM, Herbert Xu wrote: >>> You are right. Indeed the existing code looks buggy as they >>> don't take sg->offset into account when doing the kmap. Could >>> you send me some patches that fix these problems first so that >>> they can be easily backported? >> >> Ok, I think the only buggy one in crypto is hifn_795x. Shash and caam >> both do have the sg->offset accounted for. I'll send a patch for the >> buggy one shortly. > > I think they're all buggy when sg->offset is greater than PAGE_SIZE. Yes, technically. But that's a _very_ common mistake. Pretty nearly every case I looked at did not take that into account. I don't think sg's that point to more than one continuous page are all that common. Fixing all those cases without making a common function is a waste of time IMO. Logan
Re: [PATCH v2 07/21] crypto: shash, caam: Make use of the new sg_map helper function
On 28/04/17 12:30 AM, Herbert Xu wrote: > You are right. Indeed the existing code looks buggy as they > don't take sg->offset into account when doing the kmap. Could > you send me some patches that fix these problems first so that > they can be easily backported? Ok, I think the only buggy one in crypto is hifn_795x. Shash and caam both do have the sg->offset accounted for. I'll send a patch for the buggy one shortly. Logan
Re: [PATCH v2 15/21] xen-blkfront: Make use of the new sg_map helper function
On 27/04/17 05:20 PM, Jason Gunthorpe wrote: > It seems the most robust: test for iomem, and jump to a slow path > copy, otherwise inline the kmap and memcpy > > Every place doing memcpy from sgl will need that pattern to be > correct. Ok, sounds like a good place to start to me. I'll see what I can do for a v3 of this set. Though, I probably won't send anything until after the merge window. >>> sg_miter will still fail when the sg contains __iomem, however I would >>> expect that the sg_copy will work with iomem, by using the __iomem >>> memcpy variant. >> >> Yes, that's true. Any sg_miters that ever see iomem will need to be >> converted to support it. This isn't much different than the other >> kmap(sg_page()) users I was converting that will also fail if they see >> iomem. Though, I suspect an sg_miter user would be easier to convert to >> iomem than a random kmap user. > > How? sg_miter seems like the next nightmare down this path, what is > sg_miter_next supposed to do when something hits an iomem sgl? My proposal is roughly included in the draft I sent upthread. We add an sg_miter flag indicating the iteratee supports iomem and if miter finds iomem (with the support flag set) it sets ioaddr which is __iomem. The iteratee then just needs to null check addr and ioaddr and perform the appropriate action. Logan
Re: [PATCH v2 15/21] xen-blkfront: Make use of the new sg_map helper function
On 27/04/17 04:11 PM, Jason Gunthorpe wrote: > On Thu, Apr 27, 2017 at 03:53:37PM -0600, Logan Gunthorpe wrote: > Well, that is in the current form, with more users it would make sense > to optimize for the single page case, eg by providing the existing > call, providing a faster single-page-only variant of the copy, perhaps > even one that is inlined. Ok, does it make sense then to have an sg_copy_page_to_buffer (or some such... I'm having trouble thinking of a sane name that isn't too long). That just does k(un)map_atomic and memcpy? I could try that if it makes sense to people. >> Switching the for_each_sg to sg_miter is probably the nicer solution as >> it takes care of the mapping and the offset/length accounting for you >> and will have similar performance. > > sg_miter will still fail when the sg contains __iomem, however I would > expect that the sg_copy will work with iomem, by using the __iomem > memcpy variant. Yes, that's true. Any sg_miters that ever see iomem will need to be converted to support it. This isn't much different than the other kmap(sg_page()) users I was converting that will also fail if they see iomem. Though, I suspect an sg_miter user would be easier to convert to iomem than a random kmap user. Logan
Re: [PATCH v2 15/21] xen-blkfront: Make use of the new sg_map helper function
On 27/04/17 02:53 PM, Jason Gunthorpe wrote: > blkfront is one of the drivers I looked at, and it appears to only be > memcpying with the bvec_data pointer, so I wonder why it does not use > sg_copy_X_buffer instead.. Yes, sort of... But you'd potentially end up calling sg_copy_to_buffer multiple times per page within the sg (given that gnttab_foreach_grant_in_range might call blkif_copy_from_grant/blkif_setup_rw_req_grant multiple times). Even calling sg_copy_to_buffer once per page seems rather inefficient as it uses sg_miter internally. Switching the for_each_sg to sg_miter is probably the nicer solution as it takes care of the mapping and the offset/length accounting for you and will have similar performance. But, yes, if performance is not an issue, switching it to sg_copy_to_buffer would be a less invasive change than sg_miter. Which the same might be said about a lot of these cases. Unfortunately, changing from kmap_atomic (which is a null operation in a lot of cases) to sg_copy_X_buffer is a pretty big performance hit. Logan
Re: [PATCH v2 15/21] xen-blkfront: Make use of the new sg_map helper function
On 26/04/17 01:37 AM, Roger Pau Monné wrote: > On Tue, Apr 25, 2017 at 12:21:02PM -0600, Logan Gunthorpe wrote: >> Straightforward conversion to the new helper, except due to the lack >> of error path, we have to use SG_MAP_MUST_NOT_FAIL which may BUG_ON in >> certain cases in the future. >> >> Signed-off-by: Logan Gunthorpe >> Cc: Boris Ostrovsky >> Cc: Juergen Gross >> Cc: Konrad Rzeszutek Wilk >> Cc: "Roger Pau Monné" >> --- >> drivers/block/xen-blkfront.c | 20 +++- >> 1 file changed, 11 insertions(+), 9 deletions(-) >> >> diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c >> index 3945963..ed62175 100644 >> --- a/drivers/block/xen-blkfront.c >> +++ b/drivers/block/xen-blkfront.c >> @@ -816,8 +816,9 @@ static int blkif_queue_rw_req(struct request *req, >> struct blkfront_ring_info *ri >> BUG_ON(sg->offset + sg->length > PAGE_SIZE); >> >> if (setup.need_copy) { >> -setup.bvec_off = sg->offset; >> -setup.bvec_data = kmap_atomic(sg_page(sg)); >> +setup.bvec_off = 0; >> +setup.bvec_data = sg_map(sg, 0, SG_KMAP_ATOMIC | >> + SG_MAP_MUST_NOT_FAIL); > > I assume that sg_map already adds sg->offset to the address? Correct. > Also wondering whether we can get rid of bvec_off and just increment > bvec_data, > adding Julien who IIRC added this code. bvec_off is used to keep track of the offset within the current mapping so it's not a great idea given that you'd want to kunmap_atomic the original address and not something with an offset. It would be nice if this could be converted to use the sg_miter interface but that's a much more invasive change that would require someone who knows this code and can properly test it. I'd be very grateful if someone actually took that on. Logan
Re: [PATCH v2 01/21] scatterlist: Introduce sg_map helper functions
On 26/04/17 01:44 AM, Christoph Hellwig wrote: > I think we'll at least need a draft of those to make sense of these > patches. Otherwise they just look very clumsy. Ok, what follows is a draft patch attempting to show where I'm thinking of going with this. Obviously it will not compile because it assumes the users throughout the kernel are a bit different than they are today. Notably, there is no sg_page anymore. There's also likely a ton of issues and arguments to have over a bunch of the specifics below and I'd expect the concept to evolve more as cleanup occurs. This itself is an evolution of the draft I posted replying to you in my last RFC thread. Also, before any of this is truly useful to us, pfn_t would have to infect a few other places in the kernel. Thanks, Logan diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index fad170b..85ef928 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -6,13 +6,14 @@ #include #include #include +#include #include struct scatterlist { #ifdef CONFIG_DEBUG_SG unsigned long sg_magic; #endif - unsigned long page_link; + pfn_t pfn; unsigned intoffset; unsigned intlength; dma_addr_t dma_address; @@ -60,15 +61,68 @@ struct sg_table { #define SG_MAGIC 0x87654321 -/* - * We overload the LSB of the page pointer to indicate whether it's - * a valid sg entry, or whether it points to the start of a new scatterlist. - * Those low bits are there for everyone! (thanks mason :-) - */ -#define sg_is_chain(sg)((sg)->page_link & 0x01) -#define sg_is_last(sg) ((sg)->page_link & 0x02) -#define sg_chain_ptr(sg) \ - ((struct scatterlist *) ((sg)->page_link & ~0x03)) +static inline bool sg_is_chain(struct scatterlist *sg) +{ + return sg->pfn.val & PFN_SG_CHAIN; +} + +static inline bool sg_is_last(struct scatterlist *sg) +{ + return sg->pfn.val & PFN_SG_LAST; +} + +static inline struct scatterlist *sg_chain_ptr(struct scatterlist *sg) +{ + unsigned long sgl = pfn_t_to_pfn(sg->pfn); + return (struct scatterlist *)(sgl << PAGE_SHIFT); +} + +static inline bool sg_is_iomem(struct scatterlist *sg) +{ + return pfn_t_is_iomem(sg->pfn); +} + +/** + * sg_assign_pfn - Assign a given pfn_t to an SG entry + * @sg:SG entry + * @pfn: The pfn + * + * Description: + * Assign a pfn to sg entry. Also see sg_set_pfn(), the most commonly used + * variant.w + * + **/ +static inline void sg_assign_pfn(struct scatterlist *sg, pfn_t pfn) +{ +#ifdef CONFIG_DEBUG_SG + BUG_ON(sg->sg_magic != SG_MAGIC); + BUG_ON(sg_is_chain(sg)); + BUG_ON(pfn.val & (PFN_SG_CHAIN | PFN_SG_LAST)); +#endif + + sg->pfn = pfn; +} + +/** + * sg_set_pfn - Set sg entry to point at given pfn + * @sg: SG entry + * @pfn:The page + * @len:Length of data + * @offset: Offset into page + * + * Description: + * Use this function to set an sg entry pointing at a pfn, never assign + * the page directly. We encode sg table information in the lower bits + * of the page pointer. See sg_pfn_t for looking up the pfn_t belonging + * to an sg entry. + **/ +static inline void sg_set_pfn(struct scatterlist *sg, pfn_t pfn, + unsigned int len, unsigned int offset) +{ + sg_assign_pfn(sg, pfn); + sg->offset = offset; + sg->length = len; +} /** * sg_assign_page - Assign a given page to an SG entry @@ -82,18 +136,13 @@ struct sg_table { **/ static inline void sg_assign_page(struct scatterlist *sg, struct page *page) { - unsigned long page_link = sg->page_link & 0x3; + if (!page) { + pfn_t null_pfn = {0}; + sg_assign_pfn(sg, null_pfn); + return; + } - /* -* In order for the low bit stealing approach to work, pages -* must be aligned at a 32-bit boundary as a minimum. -*/ - BUG_ON((unsigned long) page & 0x03); -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); - BUG_ON(sg_is_chain(sg)); -#endif - sg->page_link = page_link | (unsigned long) page; + sg_assign_pfn(sg, page_to_pfn_t(page)); } /** @@ -106,8 +155,7 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page) * Description: * Use this function to set an sg entry pointing at a page, never assign * the page directly. We encode sg table information in the lower bits - * of the page pointer. See sg_page() for looking up the page belonging - * to an sg entry. + * of the page pointer. * **/ static inline void sg_set_page(struct scatterlist *sg, struct page *page, @@ -118,13 +166,53 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page, sg->length = len; } -static inline struct page *sg_page(struct scatterlist *sg) +/** + * sg_pfn_t - Return the pfn_
Re: [PATCH v2 01/21] scatterlist: Introduce sg_map helper functions
On 27/04/17 09:27 AM, Jason Gunthorpe wrote: > On Thu, Apr 27, 2017 at 08:53:38AM +0200, Christoph Hellwig wrote: > How about first switching as many call sites as possible to use > sg_copy_X_buffer instead of kmap? Yeah, I could look at doing that first. One problem is we might get more Naks of the form of Herbert Xu's who might be concerned with the performance implications. These are definitely a bit more invasive changes than thin wrappers around kmap calls. > A random audit of Logan's series suggests this is actually a fairly > common thing. It's not _that_ common but there are a significant fraction. One of my patches actually did this to two places that seemed to be reimplementing the sg_copy_X_buffer logic. Thanks, Logan
Re: [PATCH v2 07/21] crypto: shash, caam: Make use of the new sg_map helper function
On 26/04/17 09:56 PM, Herbert Xu wrote: > On Tue, Apr 25, 2017 at 12:20:54PM -0600, Logan Gunthorpe wrote: >> Very straightforward conversion to the new function in the caam driver >> and shash library. >> >> Signed-off-by: Logan Gunthorpe >> Cc: Herbert Xu >> Cc: "David S. Miller" >> --- >> crypto/shash.c| 9 ++--- >> drivers/crypto/caam/caamalg.c | 8 +++- >> 2 files changed, 9 insertions(+), 8 deletions(-) >> >> diff --git a/crypto/shash.c b/crypto/shash.c >> index 5e31c8d..5914881 100644 >> --- a/crypto/shash.c >> +++ b/crypto/shash.c >> @@ -283,10 +283,13 @@ int shash_ahash_digest(struct ahash_request *req, >> struct shash_desc *desc) >> if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { >> void *data; >> >> -data = kmap_atomic(sg_page(sg)); >> -err = crypto_shash_digest(desc, data + offset, nbytes, >> +data = sg_map(sg, 0, SG_KMAP_ATOMIC); >> +if (IS_ERR(data)) >> +return PTR_ERR(data); >> + >> +err = crypto_shash_digest(desc, data, nbytes, >>req->result); >> -kunmap_atomic(data); >> +sg_unmap(sg, data, 0, SG_KMAP_ATOMIC); >> crypto_yield(desc->flags); >> } else >> err = crypto_shash_init(desc) ?: > > Nack. This is an optimisation for the special case of a single > SG list entry. In fact in the common case the kmap_atomic should > disappear altogether in the no-highmem case. So replacing it > with sg_map is not acceptable. What you seem to have missed is that sg_map is just a thin wrapper around kmap_atomic. Perhaps with a future check for a mappable page. This change should have zero impact on performance. Logan
Re: [PATCH v2 01/21] scatterlist: Introduce sg_map helper functions
On 27/04/17 12:53 AM, Christoph Hellwig wrote: > I think you'll need to follow the existing kmap semantics and never > fail the iomem version either. Otherwise you'll have a special case > that's almost never used that has a different error path. > > Again, wrong way. Suddenly making things fail for your special case > that normally don't fail is a receipe for bugs. I don't disagree but these restrictions make the problem impossible to solve? If there is iomem behind a page in an SGL and someone tries to map it, we either have to fail or we break iomem safety which was your original concern. Logan
Re: [PATCH v2 01/21] scatterlist: Introduce sg_map helper functions
On 26/04/17 02:59 AM, wrote: > Good to know that somebody is working on this. Those problems troubled > us as well. Thanks Christian. It's a daunting problem and a there's a lot of work to do before we will ever be where we need to be so any help, even an ack, is greatly appreciated. Logan
Re: [PATCH v2 01/21] scatterlist: Introduce sg_map helper functions
On 26/04/17 01:44 AM, Christoph Hellwig wrote: > I think we'll at least need a draft of those to make sense of these > patches. Otherwise they just look very clumsy. Ok, I'll work up a draft proposal and send it in a couple days. But without a lot of cleanup such as this series it's not going to even be able to compile. > I'm sorry but this API is just a trainwreck. Right now we have the > nice little kmap_atomic API, which never fails and has a very nice > calling convention where we just pass back the return address, but does > not support sleeping inside the critical section. > > And kmap, whіch may fail and requires the original page to be passed > back. Anything that mixes these two concepts up is simply a non-starter. Ok, well for starters I think you are mistaken about kmap being able to fail. I'm having a hard time finding many users of that function that bother to check for an error when calling it. The main difficulty we have now is that neither of those functions are expected to fail and we need them to be able to in cases where the page doesn't map to system RAM. This patch series is trying to address it for users of scatterlist. I'm certainly open to other suggestions. I also have to disagree that kmap and kmap_atomic are all that "nice". Except for the sleeping restriction and performance, they effectively do the same thing. And it was necessary to write a macro wrapper around kunmap_atomic to ensure that users of that function don't screw it up. (See 597781f3e5.) I'd say the kmap/kmap_atomic functions are the trainwreck and I'm trying to do my best to cleanup a few cases. There are a fair number of cases in the kernel that do something like: if (something) x = kmap(page); else x = kmap_atomic(page); ... if (something) kunmap(page) else kunmap_atomic(x) Which just seems cumbersome to me. In any case, if you can accept an sg_kmap and sg_kmap_atomic api just say so and I'll make the change. But I'll still need a flags variable for SG_MAP_MUST_NOT_FAIL to support legacy cases that have no fail path and both of those functions will need to be pretty nearly replicas of each other. Logan
[PATCH v2 00/21] Introduce common scatterlist map function
Changes since v1: * Rebased onto next-20170424 * Removed the _offset version of these functions per Christoph's suggestion * Added an SG_MAP_MUST_NOT_FAIL flag which will BUG_ON in future cases that can't gracefully fail. This removes a bunch of the noise added in v1 to a couple of the drivers. (Per David Laight's suggestion) This flag is only meant for old code * Split the libiscsi patch into two (per Christoph's suggestion) the prep patch (patch 2 in this series) has already been sent separately * Fixed a locking mistake in the target patch (pointed out by a bot) * Dropped the nvmet patch and handled it with a different patch that has been sent separately * Dropped the chcr patch as they have already removed the code that needed to be changed I'm still hoping to only get Patch 1 in the series merged. (Any volunteers?) I'm willing to chase down the maintainers for the remaining patches separately after the first patch is in. The patchset is based on next-20170424 and can be found in the sg_map_v2 branch from this git tree: https://github.com/sbates130272/linux-p2pmem.git -- Hi Everyone, As part of my effort to enable P2P DMA transactions with PCI cards, we've identified the need to be able to safely put IO memory into scatterlists (and eventually other spots). This probably involves a conversion from struct page to pfn_t but that migration is a ways off and those decisions are yet to be made. As an initial step in that direction, I've started cleaning up some of the scatterlist code by trying to carve out a better defined layer between it and it's users. The longer term goal would be to remove sg_page or replace it with something that can potentially fail. This patchset is the first step in that effort. I've introduced a common function to map scatterlist memory and converted all the common kmap(sg_page()) cases. This removes about 66 sg_page calls (of ~331). Seeing this is a fairly large cleanup set that touches a wide swath of the kernel I have limited the people I've sent this to. I'd suggest we look toward merging the first patch and then I can send the individual subsystem patches on to their respective maintainers and get them merged independantly. (This is to avoid the conflicts I created with my last cleanup set... Sorry) Though, I'm certainly open to other suggestions to get it merged. Logan Gunthorpe (21): scatterlist: Introduce sg_map helper functions libiscsi: Add an internal error code libiscsi: Make use of new the sg_map helper function target: Make use of the new sg_map function at 16 call sites drm/i915: Make use of the new sg_map helper function crypto: hifn_795x: Make use of the new sg_map helper function crypto: shash, caam: Make use of the new sg_map helper function dm-crypt: Make use of the new sg_map helper in 4 call sites staging: unisys: visorbus: Make use of the new sg_map helper function RDS: Make use of the new sg_map helper function scsi: ipr, pmcraid, isci: Make use of the new sg_map helper scsi: hisi_sas, mvsas, gdth: Make use of the new sg_map helper function scsi: arcmsr, ips, megaraid: Make use of the new sg_map helper function scsi: libfc, csiostor: Change to sg_copy_buffer in two drivers xen-blkfront: Make use of the new sg_map helper function mmc: sdhci: Make use of the new sg_map helper function mmc: spi: Make use of the new sg_map helper function mmc: tmio: Make use of the new sg_map helper function mmc: sdricoh_cs: Make use of the new sg_map helper function mmc: tifm_sd: Make use of the new sg_map helper function memstick: Make use of the new sg_map helper function crypto/shash.c | 9 ++- drivers/block/xen-blkfront.c| 20 ++--- drivers/crypto/caam/caamalg.c | 8 +- drivers/crypto/hifn_795x.c | 32 +--- drivers/gpu/drm/i915/i915_gem.c | 27 --- drivers/md/dm-crypt.c | 39 ++--- drivers/memstick/host/jmb38x_ms.c | 11 +-- drivers/memstick/host/tifm_ms.c | 11 +-- drivers/mmc/host/mmc_spi.c | 26 -- drivers/mmc/host/sdhci.c| 14 ++-- drivers/mmc/host/sdricoh_cs.c | 14 ++-- drivers/mmc/host/tifm_sd.c | 50 +++- drivers/mmc/host/tmio_mmc.h | 7 +- drivers/mmc/host/tmio_mmc_pio.c | 12 +++ drivers/scsi/arcmsr/arcmsr_hba.c| 16 +++- drivers/scsi/csiostor/csio_scsi.c | 54 + drivers/scsi/cxgbi/libcxgbi.c | 5 ++ drivers/scsi/gdth.c | 9 ++- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 14 ++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 ++- drivers/scsi/ipr.c | 27 ---
[PATCH v2 07/21] crypto: shash, caam: Make use of the new sg_map helper function
Very straightforward conversion to the new function in the caam driver and shash library. Signed-off-by: Logan Gunthorpe Cc: Herbert Xu Cc: "David S. Miller" --- crypto/shash.c| 9 ++--- drivers/crypto/caam/caamalg.c | 8 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/crypto/shash.c b/crypto/shash.c index 5e31c8d..5914881 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -283,10 +283,13 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { void *data; - data = kmap_atomic(sg_page(sg)); - err = crypto_shash_digest(desc, data + offset, nbytes, + data = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(data)) + return PTR_ERR(data); + + err = crypto_shash_digest(desc, data, nbytes, req->result); - kunmap_atomic(data); + sg_unmap(sg, data, 0, SG_KMAP_ATOMIC); crypto_yield(desc->flags); } else err = crypto_shash_init(desc) ?: diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 398807d..62d2f5d 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -89,7 +89,6 @@ static void dbg_dump_sg(const char *level, const char *prefix_str, struct scatterlist *sg, size_t tlen, bool ascii) { struct scatterlist *it; - void *it_page; size_t len; void *buf; @@ -98,19 +97,18 @@ static void dbg_dump_sg(const char *level, const char *prefix_str, * make sure the scatterlist's page * has a valid virtual memory mapping */ - it_page = kmap_atomic(sg_page(it)); - if (unlikely(!it_page)) { + buf = sg_map(it, 0, SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { printk(KERN_ERR "dbg_dump_sg: kmap failed\n"); return; } - buf = it_page + it->offset; len = min_t(size_t, tlen, it->length); print_hex_dump(level, prefix_str, prefix_type, rowsize, groupsize, buf, len, ascii); tlen -= len; - kunmap_atomic(it_page); + sg_unmap(it, buf, 0, SG_KMAP_ATOMIC); } } #endif -- 2.1.4
[PATCH v2 03/21] libiscsi: Make use of new the sg_map helper function
Convert the kmap and kmap_atomic uses to the sg_map function. We now store the flags for the kmap instead of a boolean to indicate atomicitiy. We use ISCSI_TCP_INTERNAL_ERR error type that was prepared earlier for this. Signed-off-by: Logan Gunthorpe Cc: Lee Duncan Cc: Chris Leech --- drivers/scsi/libiscsi_tcp.c | 32 include/scsi/libiscsi_tcp.h | 2 +- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 63a1d69..a34e25c 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -133,25 +133,23 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) if (page_count(sg_page(sg)) >= 1 && !recv) return; - if (recv) { - segment->atomic_mapped = true; - segment->sg_mapped = kmap_atomic(sg_page(sg)); - } else { - segment->atomic_mapped = false; - /* the xmit path can sleep with the page mapped so use kmap */ - segment->sg_mapped = kmap(sg_page(sg)); + /* the xmit path can sleep with the page mapped so don't use atomic */ + segment->sg_map_flags = recv ? SG_KMAP_ATOMIC : SG_KMAP; + segment->sg_mapped = sg_map(sg, 0, segment->sg_map_flags); + + if (IS_ERR(segment->sg_mapped)) { + segment->sg_mapped = NULL; + return; } - segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; + segment->data = segment->sg_mapped + segment->sg_offset; } void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { if (segment->sg_mapped) { - if (segment->atomic_mapped) - kunmap_atomic(segment->sg_mapped); - else - kunmap(sg_page(segment->sg)); + sg_unmap(segment->sg, segment->sg_mapped, 0, +segment->sg_map_flags); segment->sg_mapped = NULL; segment->data = NULL; } @@ -304,6 +302,9 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, break; } + if (segment->data) + return -EFAULT; + copy = min(len - copied, segment->size - segment->copied); ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy); memcpy(segment->data + segment->copied, ptr + copied, copy); @@ -927,6 +928,13 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, avail); rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail); BUG_ON(rc == 0); + if (rc < 0) { + ISCSI_DBG_TCP(conn, "memory fault. Consumed %d\n", + consumed); + *status = ISCSI_TCP_INTERNAL_ERR; + goto skb_done; + } + consumed += rc; if (segment->total_copied >= segment->total_size) { diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index 90691ad..58c79af 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h @@ -47,7 +47,7 @@ struct iscsi_segment { struct scatterlist *sg; void*sg_mapped; unsigned intsg_offset; - boolatomic_mapped; + int sg_map_flags; iscsi_segment_done_fn_t *done; }; -- 2.1.4
[PATCH v2 18/21] mmc: tmio: Make use of the new sg_map helper function
Straightforward conversion to sg_map helper. Seeing there is no cleare error path, SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases in the future. Signed-off-by: Logan Gunthorpe Cc: Wolfram Sang Cc: Ulf Hansson --- drivers/mmc/host/tmio_mmc.h | 7 +-- drivers/mmc/host/tmio_mmc_pio.c | 12 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index d0edb57..bc43eb0 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -202,17 +202,20 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); +/* Note: this function may return PTR_ERR and must be checked! */ static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { + void *ret; + local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; + return sg_map(sg, 0, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) { - kunmap_atomic(virt - sg->offset); + sg_unmap(sg, virt, 0, SG_KMAP_ATOMIC); local_irq_restore(*flags); } diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index a2d92f1..bbb4f19 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -506,6 +506,18 @@ static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) if (host->sg_ptr == &host->bounce_sg) { unsigned long flags; void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); + if (IS_ERR(sg_vaddr)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return; + } + memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); } -- 2.1.4
[PATCH v2 16/21] mmc: sdhci: Make use of the new sg_map helper function
Straightforward conversion, except due to the lack of an error path we have to use SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases in the future. Signed-off-by: Logan Gunthorpe Cc: Adrian Hunter Cc: Ulf Hansson --- drivers/mmc/host/sdhci.c | 14 +- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ecd0d43..239507f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -513,15 +513,19 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, return sg_count; } +/* + * Note this function may return PTR_ERR and must be checked. + */ static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; + return sg_map(sg, 0, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); } -static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) +static void sdhci_kunmap_atomic(struct scatterlist *sg, void *buffer, + unsigned long *flags) { - kunmap_atomic(buffer); + sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC); local_irq_restore(*flags); } @@ -585,7 +589,7 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); memcpy(align, buffer, offset); - sdhci_kunmap_atomic(buffer, &flags); + sdhci_kunmap_atomic(sg, buffer, &flags); } /* tran, valid */ @@ -663,7 +667,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host, buffer = sdhci_kmap_atomic(sg, &flags); memcpy(buffer, align, size); - sdhci_kunmap_atomic(buffer, &flags); + sdhci_kunmap_atomic(sg, buffer, &flags); align += SDHCI_ADMA2_ALIGN; } -- 2.1.4
[PATCH v2 14/21] scsi: libfc, csiostor: Change to sg_copy_buffer in two drivers
These two drivers appear to duplicate the functionality of sg_copy_buffer. So we clean them up to use the common code. This helps us remove a couple of instances that would otherwise be slightly tricky sg_map usages. Signed-off-by: Logan Gunthorpe Cc: Johannes Thumshirn --- drivers/scsi/csiostor/csio_scsi.c | 54 +++ drivers/scsi/libfc/fc_libfc.c | 49 --- 2 files changed, 14 insertions(+), 89 deletions(-) diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index a1ff75f..bd9d062 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -1489,60 +1489,14 @@ static inline uint32_t csio_scsi_copy_to_sgl(struct csio_hw *hw, struct csio_ioreq *req) { struct scsi_cmnd *scmnd = (struct scsi_cmnd *)csio_scsi_cmnd(req); - struct scatterlist *sg; - uint32_t bytes_left; - uint32_t bytes_copy; - uint32_t buf_off = 0; - uint32_t start_off = 0; - uint32_t sg_off = 0; - void *sg_addr; - void *buf_addr; struct csio_dma_buf *dma_buf; + size_t copied; - bytes_left = scsi_bufflen(scmnd); - sg = scsi_sglist(scmnd); dma_buf = (struct csio_dma_buf *)csio_list_next(&req->gen_list); + copied = sg_copy_from_buffer(scsi_sglist(scmnd), scsi_sg_count(scmnd), +dma_buf->vaddr, scsi_bufflen(scmnd)); - /* Copy data from driver buffer to SGs of SCSI CMD */ - while (bytes_left > 0 && sg && dma_buf) { - if (buf_off >= dma_buf->len) { - buf_off = 0; - dma_buf = (struct csio_dma_buf *) - csio_list_next(dma_buf); - continue; - } - - if (start_off >= sg->length) { - start_off -= sg->length; - sg = sg_next(sg); - continue; - } - - buf_addr = dma_buf->vaddr + buf_off; - sg_off = sg->offset + start_off; - bytes_copy = min((dma_buf->len - buf_off), - sg->length - start_off); - bytes_copy = min((uint32_t)(PAGE_SIZE - (sg_off & ~PAGE_MASK)), -bytes_copy); - - sg_addr = kmap_atomic(sg_page(sg) + (sg_off >> PAGE_SHIFT)); - if (!sg_addr) { - csio_err(hw, "failed to kmap sg:%p of ioreq:%p\n", - sg, req); - break; - } - - csio_dbg(hw, "copy_to_sgl:sg_addr %p sg_off %d buf %p len %d\n", - sg_addr, sg_off, buf_addr, bytes_copy); - memcpy(sg_addr + (sg_off & ~PAGE_MASK), buf_addr, bytes_copy); - kunmap_atomic(sg_addr); - - start_off += bytes_copy; - buf_off += bytes_copy; - bytes_left -= bytes_copy; - } - - if (bytes_left > 0) + if (copied != scsi_bufflen(scmnd)) return DID_ERROR; else return DID_OK; diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index d623d08..ce0805a 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -113,45 +113,16 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, u32 *nents, size_t *offset, u32 *crc) { - size_t remaining = len; - u32 copy_len = 0; - - while (remaining > 0 && sg) { - size_t off, sg_bytes; - void *page_addr; - - if (*offset >= sg->length) { - /* -* Check for end and drop resources -* from the last iteration. -*/ - if (!(*nents)) - break; - --(*nents); - *offset -= sg->length; - sg = sg_next(sg); - continue; - } - sg_bytes = min(remaining, sg->length - *offset); - - /* -* The scatterlist item may be bigger than PAGE_SIZE, -* but we are limited to mapping PAGE_SIZE at a time. -*/ - off = *offset + sg->offset; - sg_bytes = min(sg_bytes, - (size_t)(PAGE_SIZE - (off & ~PAGE_MASK))); - page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT)); - if (crc) - *crc = crc32(*crc, buf, sg_bytes); - memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes); -
[PATCH v2 04/21] target: Make use of the new sg_map function at 16 call sites
Fairly straightforward conversions in all spots. In a couple of cases any error gets propogated up should sg_map fail. In other cases a warning is issued if the kmap fails seeing there's no clear error path. This should not be an issue until someone tries to use unmappable memory in the sgl with this driver. Signed-off-by: Logan Gunthorpe Cc: "Nicholas A. Bellinger" --- drivers/target/iscsi/iscsi_target.c| 29 +++--- drivers/target/target_core_rd.c| 3 +- drivers/target/target_core_sbc.c | 103 + drivers/target/target_core_transport.c | 18 -- drivers/target/target_core_user.c | 45 +- include/target/target_core_backend.h | 4 +- 6 files changed, 134 insertions(+), 68 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index e3f9ed3..3ab8d21 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -578,7 +578,7 @@ iscsit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, } static int iscsit_map_iovec(struct iscsi_cmd *, struct kvec *, u32, u32); -static void iscsit_unmap_iovec(struct iscsi_cmd *); +static void iscsit_unmap_iovec(struct iscsi_cmd *, struct kvec *); static u32 iscsit_do_crypto_hash_sg(struct ahash_request *, struct iscsi_cmd *, u32, u32, u32, u8 *); static int @@ -645,7 +645,7 @@ iscsit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ret = iscsit_fe_sendpage_sg(cmd, conn); - iscsit_unmap_iovec(cmd); + iscsit_unmap_iovec(cmd, &cmd->iov_data[1]); if (ret < 0) { iscsit_tx_thread_wait_for_tcp(conn); @@ -924,7 +924,10 @@ static int iscsit_map_iovec( while (data_length) { u32 cur_len = min_t(u32, data_length, sg->length - page_off); - iov[i].iov_base = kmap(sg_page(sg)) + sg->offset + page_off; + iov[i].iov_base = sg_map(sg, page_off, SG_KMAP); + if (IS_ERR(iov[i].iov_base)) + goto map_err; + iov[i].iov_len = cur_len; data_length -= cur_len; @@ -936,17 +939,25 @@ static int iscsit_map_iovec( cmd->kmapped_nents = i; return i; + +map_err: + cmd->kmapped_nents = i - 1; + iscsit_unmap_iovec(cmd, iov); + return -1; } -static void iscsit_unmap_iovec(struct iscsi_cmd *cmd) +static void iscsit_unmap_iovec(struct iscsi_cmd *cmd, struct kvec *iov) { u32 i; struct scatterlist *sg; + unsigned int page_off = cmd->first_data_sg_off; sg = cmd->first_data_sg; - for (i = 0; i < cmd->kmapped_nents; i++) - kunmap(sg_page(&sg[i])); + for (i = 0; i < cmd->kmapped_nents; i++) { + sg_unmap(&sg[i], iov[i].iov_base, page_off, SG_KMAP); + page_off = 0; + } } static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) @@ -1609,7 +1620,7 @@ iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); - iscsit_unmap_iovec(cmd); + iscsit_unmap_iovec(cmd, iov); if (rx_got != rx_size) return -1; @@ -1710,7 +1721,7 @@ int iscsit_setup_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, if (!cmd) return iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, (unsigned char *)hdr); - + return iscsit_reject_cmd(cmd, ISCSI_REASON_PROTOCOL_ERROR, (unsigned char *)hdr); } @@ -2625,7 +2636,7 @@ static int iscsit_handle_immediate_data( rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); - iscsit_unmap_iovec(cmd); + iscsit_unmap_iovec(cmd, cmd->iov_data); if (rx_got != rx_size) { iscsit_rx_thread_wait_for_tcp(conn); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 5f23f34..348211c 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -432,7 +432,8 @@ static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, bool is_read) cmd->t_prot_sg, 0); } if (!rc) - sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, prot_offset); + rc = sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, + prot_offset); return rc; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index ee35c90..8ac07c6 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -420,17 +420,17 @@ static sense_re
[PATCH v2 11/21] scsi: ipr, pmcraid, isci: Make use of the new sg_map helper
Very straightforward conversion of three scsi drivers. Signed-off-by: Logan Gunthorpe Cc: Brian King Cc: Artur Paszkiewicz --- drivers/scsi/ipr.c | 27 ++- drivers/scsi/isci/request.c | 42 +- drivers/scsi/pmcraid.c | 19 --- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b0c68d2..b2324e1 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3895,7 +3895,7 @@ static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, u8 *buffer, u32 len) { - int bsize_elem, i, result = 0; + int bsize_elem, i; struct scatterlist *scatterlist; void *kaddr; @@ -3905,32 +3905,33 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, scatterlist = sglist->scatterlist; for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + kaddr = sg_map(&scatterlist[i], 0, SG_KMAP); + if (IS_ERR(kaddr)) { + ipr_trace; + return PTR_ERR(kaddr); + } - kaddr = kmap(page); memcpy(kaddr, buffer, bsize_elem); - kunmap(page); + sg_unmap(&scatterlist[i], kaddr, 0, SG_KMAP); scatterlist[i].length = bsize_elem; - - if (result != 0) { - ipr_trace; - return result; - } } if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + kaddr = sg_map(&scatterlist[i], 0, SG_KMAP); + if (IS_ERR(kaddr)) { + ipr_trace; + return PTR_ERR(kaddr); + } - kaddr = kmap(page); memcpy(kaddr, buffer, len % bsize_elem); - kunmap(page); + sg_unmap(&scatterlist[i], kaddr, 0, SG_KMAP); scatterlist[i].length = len % bsize_elem; } sglist->buffer_len = len; - return result; + return 0; } /** diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 47f66e9..6f5521b 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1424,12 +1424,14 @@ sci_stp_request_pio_data_in_copy_data_buffer(struct isci_stp_request *stp_req, sg = task->scatter; while (total_len > 0) { - struct page *page = sg_page(sg); - copy_len = min_t(int, total_len, sg_dma_len(sg)); - kaddr = kmap_atomic(page); - memcpy(kaddr + sg->offset, src_addr, copy_len); - kunmap_atomic(kaddr); + kaddr = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(kaddr)) + return SCI_FAILURE; + + memcpy(kaddr, src_addr, copy_len); + sg_unmap(sg, kaddr, 0, SG_KMAP_ATOMIC); + total_len -= copy_len; src_addr += copy_len; sg = sg_next(sg); @@ -1771,14 +1773,16 @@ sci_io_request_frame_handler(struct isci_request *ireq, case SCI_REQ_SMP_WAIT_RESP: { struct sas_task *task = isci_request_access_task(ireq); struct scatterlist *sg = &task->smp_task.smp_resp; - void *frame_header, *kaddr; + void *frame_header; u8 *rsp; sci_unsolicited_frame_control_get_header(&ihost->uf_control, frame_index, &frame_header); - kaddr = kmap_atomic(sg_page(sg)); - rsp = kaddr + sg->offset; + rsp = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(rsp)) + return SCI_FAILURE; + sci_swab32_cpy(rsp, frame_header, 1); if (rsp[0] == SMP_RESPONSE) { @@ -1814,7 +1818,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); } - kunmap_atomic(kaddr); + sg_unmap(sg, rsp, 0, SG_KMAP_ATOMIC); sci_controller_release_frame(ihost, frame_index); @@ -2919,15 +2923,18 @@ static void isci_request_io_request_complete(struct isci_host *ihost, case SAS_PROTOCOL_SMP: { struct scatterlist *sg = &task->smp_ta
[PATCH v2 06/21] crypto: hifn_795x: Make use of the new sg_map helper function
Conversion of a couple kmap_atomic instances to the sg_map helper function. However, it looks like there was a bug in the original code: the source scatter lists offset (t->offset) was passed to ablkcipher_get which added it to the destination address. This doesn't make a lot of sense, but t->offset is likely always zero anyway. So, this patch cleans that brokeness up. Also, a change to the error path: if ablkcipher_get failed, everything seemed to proceed as if it hadn't. Setting 'error' should hopefully clear that up. Signed-off-by: Logan Gunthorpe Cc: Herbert Xu Cc: "David S. Miller" --- drivers/crypto/hifn_795x.c | 32 +--- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index e09d405..34b1870 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -1619,7 +1619,7 @@ static int hifn_start_device(struct hifn_device *dev) return 0; } -static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset, +static int ablkcipher_get(void *saddr, unsigned int *srestp, struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) { unsigned int srest = *srestp, nbytes = *nbytesp, copy; @@ -1632,15 +1632,17 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset while (size) { copy = min3(srest, dst->length, size); - daddr = kmap_atomic(sg_page(dst)); - memcpy(daddr + dst->offset + offset, saddr, copy); - kunmap_atomic(daddr); + daddr = sg_map(dst, 0, SG_KMAP_ATOMIC); + if (IS_ERR(daddr)) + return PTR_ERR(daddr); + + memcpy(daddr, saddr, copy); + sg_unmap(dst, daddr, 0, SG_KMAP_ATOMIC); nbytes -= copy; size -= copy; srest -= copy; saddr += copy; - offset = 0; pr_debug("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n", __func__, copy, size, srest, nbytes); @@ -1671,11 +1673,12 @@ static inline void hifn_complete_sa(struct hifn_device *dev, int i) static void hifn_process_ready(struct ablkcipher_request *req, int error) { + int err; struct hifn_request_context *rctx = ablkcipher_request_ctx(req); if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { unsigned int nbytes = req->nbytes; - int idx = 0, err; + int idx = 0; struct scatterlist *dst, *t; void *saddr; @@ -1695,17 +1698,24 @@ static void hifn_process_ready(struct ablkcipher_request *req, int error) continue; } - saddr = kmap_atomic(sg_page(t)); + saddr = sg_map(t, 0, SG_KMAP_ATOMIC); + if (IS_ERR(saddr)) { + if (!error) + error = PTR_ERR(saddr); + break; + } + + err = ablkcipher_get(saddr, &t->length, +dst, nbytes, &nbytes); + sg_unmap(t, saddr, 0, SG_KMAP_ATOMIC); - err = ablkcipher_get(saddr, &t->length, t->offset, - dst, nbytes, &nbytes); if (err < 0) { - kunmap_atomic(saddr); + if (!error) + error = err; break; } idx += err; - kunmap_atomic(saddr); } hifn_cipher_walk_exit(&rctx->walk); -- 2.1.4
[PATCH v2 17/21] mmc: spi: Make use of the new sg_map helper function
We use the sg_map helper but it's slightly more complicated as we only check for the error when the mapping actually gets used. Such that if the mapping failed but wasn't needed then no error occurs. Signed-off-by: Logan Gunthorpe Cc: Ulf Hansson --- drivers/mmc/host/mmc_spi.c | 26 +++--- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 476e53d..d614f36 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -676,9 +676,15 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, struct scratch *scratch = host->data; u32 pattern; - if (host->mmc->use_spi_crc) + if (host->mmc->use_spi_crc) { + if (IS_ERR(t->tx_buf)) + return PTR_ERR(t->tx_buf); + scratch->crc_val = cpu_to_be16( crc_itu_t(0, t->tx_buf, t->len)); + t->tx_buf += t->len; + } + if (host->dma_dev) dma_sync_single_for_device(host->dma_dev, host->data_dma, sizeof(*scratch), @@ -743,7 +749,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, return status; } - t->tx_buf += t->len; if (host->dma_dev) t->tx_dma += t->len; @@ -809,6 +814,11 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, } leftover = status << 1; + if (bitshift || host->mmc->use_spi_crc) { + if (IS_ERR(t->rx_buf)) + return PTR_ERR(t->rx_buf); + } + if (host->dma_dev) { dma_sync_single_for_device(host->dma_dev, host->data_dma, sizeof(*scratch), @@ -860,9 +870,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, scratch->crc_val, crc, t->len); return -EILSEQ; } + + t->rx_buf += t->len; } - t->rx_buf += t->len; if (host->dma_dev) t->rx_dma += t->len; @@ -933,11 +944,11 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, } /* allow pio too; we don't allow highmem */ - kmap_addr = kmap(sg_page(sg)); + kmap_addr = sg_map(sg, 0, SG_KMAP); if (direction == DMA_TO_DEVICE) - t->tx_buf = kmap_addr + sg->offset; + t->tx_buf = kmap_addr; else - t->rx_buf = kmap_addr + sg->offset; + t->rx_buf = kmap_addr; /* transfer each block, and update request status */ while (length) { @@ -967,7 +978,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, /* discard mappings */ if (direction == DMA_FROM_DEVICE) flush_kernel_dcache_page(sg_page(sg)); - kunmap(sg_page(sg)); + if (!IS_ERR(kmap_addr)) + sg_unmap(sg, kmap_addr, 0, SG_KMAP); if (dma_dev) dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir); -- 2.1.4
[PATCH v2 21/21] memstick: Make use of the new sg_map helper function
Straightforward conversion, but we have to make use of SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases in the future. Signed-off-by: Logan Gunthorpe Cc: Alex Dubov --- drivers/memstick/host/jmb38x_ms.c | 11 ++- drivers/memstick/host/tifm_ms.c | 11 ++- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 48db922..9019e37 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -303,7 +303,6 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) unsigned int off; unsigned int t_size, p_cnt; unsigned char *buf; - struct page *pg; unsigned long flags = 0; if (host->req->long_data) { @@ -318,14 +317,14 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) unsigned int uninitialized_var(p_off); if (host->req->long_data) { - pg = nth_page(sg_page(&host->req->sg), - off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, length); local_irq_save(flags); - buf = kmap_atomic(pg) + p_off; + buf = sg_map(&host->req->sg, +off - host->req->sg.offset, +SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); } else { buf = host->req->data + host->block_pos; p_cnt = host->req->data_len - host->block_pos; @@ -341,7 +340,9 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) : jmb38x_ms_read_reg_data(host, buf, p_cnt); if (host->req->long_data) { - kunmap_atomic(buf - p_off); + sg_unmap(&host->req->sg, buf, +off - host->req->sg.offset, +SG_KMAP_ATOMIC); local_irq_restore(flags); } diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 7bafa72..304985d 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -186,7 +186,6 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) unsigned int off; unsigned int t_size, p_cnt; unsigned char *buf; - struct page *pg; unsigned long flags = 0; if (host->req->long_data) { @@ -203,14 +202,14 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) unsigned int uninitialized_var(p_off); if (host->req->long_data) { - pg = nth_page(sg_page(&host->req->sg), - off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, length); local_irq_save(flags); - buf = kmap_atomic(pg) + p_off; + buf = sg_map(&host->req->sg, +off - host->req->sg.offset, +SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); } else { buf = host->req->data + host->block_pos; p_cnt = host->req->data_len - host->block_pos; @@ -221,7 +220,9 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) : tifm_ms_read_data(host, buf, p_cnt); if (host->req->long_data) { - kunmap_atomic(buf - p_off); + sg_unmap(&host->req->sg, buf, +off - host->req->sg.offset, +SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); local_irq_restore(flags); } -- 2.1.4
[PATCH v2 09/21] staging: unisys: visorbus: Make use of the new sg_map helper function
Straightforward conversion to the new function. Signed-off-by: Logan Gunthorpe Acked-by: David Kershner --- drivers/staging/unisys/visorhba/visorhba_main.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index d372115..c77426c 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -843,7 +843,6 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) struct scatterlist *sg; unsigned int i; char *this_page; - char *this_page_orig; int bufind = 0; struct visordisk_info *vdisk; struct visorhba_devdata *devdata; @@ -870,11 +869,14 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) sg = scsi_sglist(scsicmd); for (i = 0; i < scsi_sg_count(scsicmd); i++) { - this_page_orig = kmap_atomic(sg_page(sg + i)); - this_page = (void *)((unsigned long)this_page_orig | -sg[i].offset); + this_page = sg_map(sg + i, 0, SG_KMAP_ATOMIC); + if (IS_ERR(this_page)) { + scsicmd->result = DID_ERROR << 16; + return; + } + memcpy(this_page, buf + bufind, sg[i].length); - kunmap_atomic(this_page_orig); + sg_unmap(sg + i, this_page, 0, SG_KMAP_ATOMIC); } } else { devdata = (struct visorhba_devdata *)scsidev->host->hostdata; -- 2.1.4
[PATCH v2 15/21] xen-blkfront: Make use of the new sg_map helper function
Straightforward conversion to the new helper, except due to the lack of error path, we have to use SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases in the future. Signed-off-by: Logan Gunthorpe Cc: Boris Ostrovsky Cc: Juergen Gross Cc: Konrad Rzeszutek Wilk Cc: "Roger Pau Monné" --- drivers/block/xen-blkfront.c | 20 +++- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 3945963..ed62175 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -816,8 +816,9 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri BUG_ON(sg->offset + sg->length > PAGE_SIZE); if (setup.need_copy) { - setup.bvec_off = sg->offset; - setup.bvec_data = kmap_atomic(sg_page(sg)); + setup.bvec_off = 0; + setup.bvec_data = sg_map(sg, 0, SG_KMAP_ATOMIC | +SG_MAP_MUST_NOT_FAIL); } gnttab_foreach_grant_in_range(sg_page(sg), @@ -827,7 +828,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri &setup); if (setup.need_copy) - kunmap_atomic(setup.bvec_data); + sg_unmap(sg, setup.bvec_data, 0, SG_KMAP_ATOMIC); } if (setup.segments) kunmap_atomic(setup.segments); @@ -1053,7 +1054,7 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) case XEN_SCSI_DISK5_MAJOR: case XEN_SCSI_DISK6_MAJOR: case XEN_SCSI_DISK7_MAJOR: - *offset = (*minor / PARTS_PER_DISK) + + *offset = (*minor / PARTS_PER_DISK) + ((major - XEN_SCSI_DISK1_MAJOR + 1) * 16) + EMULATED_SD_DISK_NAME_OFFSET; *minor = *minor + @@ -1068,7 +1069,7 @@ static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) case XEN_SCSI_DISK13_MAJOR: case XEN_SCSI_DISK14_MAJOR: case XEN_SCSI_DISK15_MAJOR: - *offset = (*minor / PARTS_PER_DISK) + + *offset = (*minor / PARTS_PER_DISK) + ((major - XEN_SCSI_DISK8_MAJOR + 8) * 16) + EMULATED_SD_DISK_NAME_OFFSET; *minor = *minor + @@ -1119,7 +1120,7 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, if (!VDEV_IS_EXTENDED(info->vdevice)) { err = xen_translate_vdev(info->vdevice, &minor, &offset); if (err) - return err; + return err; nr_parts = PARTS_PER_DISK; } else { minor = BLKIF_MINOR_EXT(info->vdevice); @@ -1483,8 +1484,9 @@ static bool blkif_completion(unsigned long *id, for_each_sg(s->sg, sg, num_sg, i) { BUG_ON(sg->offset + sg->length > PAGE_SIZE); - data.bvec_offset = sg->offset; - data.bvec_data = kmap_atomic(sg_page(sg)); + data.bvec_offset = 0; + data.bvec_data = sg_map(sg, 0, SG_KMAP_ATOMIC | + SG_MAP_MUST_NOT_FAIL); gnttab_foreach_grant_in_range(sg_page(sg), sg->offset, @@ -1492,7 +1494,7 @@ static bool blkif_completion(unsigned long *id, blkif_copy_from_grant, &data); - kunmap_atomic(data.bvec_data); + sg_unmap(sg, data.bvec_data, 0, SG_KMAP_ATOMIC); } } /* Add the persistent grant into the list of free grants */ -- 2.1.4
[PATCH v2 10/21] RDS: Make use of the new sg_map helper function
Straightforward conversion except there's no error path, so we make use of SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases in the future. Signed-off-by: Logan Gunthorpe Cc: Santosh Shilimkar Cc: "David S. Miller" --- net/rds/ib_recv.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index e10624a..c665689 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -800,10 +800,10 @@ static void rds_ib_cong_recv(struct rds_connection *conn, to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off); BUG_ON(to_copy & 7); /* Must be 64bit aligned. */ + addr = sg_map(&frag->f_sg, 0, + SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); - addr = kmap_atomic(sg_page(&frag->f_sg)); - - src = addr + frag->f_sg.offset + frag_off; + src = addr + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; for (k = 0; k < to_copy; k += 8) { /* Record ports that became uncongested, ie @@ -811,7 +811,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, uncongested |= ~(*src) & *dst; *dst++ = *src++; } - kunmap_atomic(addr); + sg_unmap(&frag->f_sg, addr, 0, SG_KMAP_ATOMIC); copied += to_copy; -- 2.1.4
[PATCH v2 19/21] mmc: sdricoh_cs: Make use of the new sg_map helper function
This is a straightforward conversion to the new function. Signed-off-by: Logan Gunthorpe Cc: Sascha Sommer Cc: Ulf Hansson --- drivers/mmc/host/sdricoh_cs.c | 14 +- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 5ff26ab..03225c3 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -319,16 +319,20 @@ static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) for (i = 0; i < data->blocks; i++) { size_t len = data->blksz; u8 *buf; - struct page *page; int result; - page = sg_page(data->sg); - buf = kmap(page) + data->sg->offset + (len * i); + buf = sg_map(data->sg, (len * i), SG_KMAP); + if (IS_ERR(buf)) { + cmd->error = PTR_ERR(buf); + break; + } + result = sdricoh_blockio(host, data->flags & MMC_DATA_READ, buf, len); - kunmap(page); - flush_dcache_page(page); + sg_unmap(data->sg, buf, (len * i), SG_KMAP); + + flush_dcache_page(sg_page(data->sg)); if (result) { dev_err(dev, "sdricoh_request: cmd %i " "block transfer failed\n", cmd->opcode); -- 2.1.4
[PATCH v2 20/21] mmc: tifm_sd: Make use of the new sg_map helper function
This conversion is a bit complicated. We modiy the read_fifo, write_fifo and copy_page functions to take a scatterlist instead of a page. Thus we can use sg_map instead of kmap_atomic. There's a bit of accounting that needed to be done for the offset for this to work. (Seeing sg_map takes care of the offset but it's already added and used earlier in the code.) There's also no error path, so we use SG_MAP_MUST_NOT_FAIL which may BUG_ON in certain cases in the future. Signed-off-by: Logan Gunthorpe Cc: Alex Dubov Cc: Ulf Hansson --- drivers/mmc/host/tifm_sd.c | 50 +++--- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 93c4b40..e64345a 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -111,14 +111,16 @@ struct tifm_sd { }; /* for some reason, host won't respond correctly to readw/writew */ -static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, +static void tifm_sd_read_fifo(struct tifm_sd *host, struct scatterlist *sg, unsigned int off, unsigned int cnt) { struct tifm_dev *sock = host->dev; unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = sg_map(sg, off - sg->offset, +SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); + if (host->cmd_flags & DATA_CARRY) { buf[pos++] = host->bounce_buf_data[0]; host->cmd_flags &= ~DATA_CARRY; @@ -134,17 +136,19 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, } buf[pos++] = (val >> 8) & 0xff; } - kunmap_atomic(buf - off); + sg_unmap(sg, buf, off - sg->offset, SG_KMAP_ATOMIC); } -static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, +static void tifm_sd_write_fifo(struct tifm_sd *host, struct scatterlist *sg, unsigned int off, unsigned int cnt) { struct tifm_dev *sock = host->dev; unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = sg_map(sg, off - sg->offset, +SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL); + if (host->cmd_flags & DATA_CARRY) { val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); writel(val, sock->addr + SOCK_MMCSD_DATA); @@ -161,7 +165,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, val |= (buf[pos++] << 8) & 0xff00; writel(val, sock->addr + SOCK_MMCSD_DATA); } - kunmap_atomic(buf - off); + sg_unmap(sg, buf, off - sg->offset, SG_KMAP_ATOMIC); } static void tifm_sd_transfer_data(struct tifm_sd *host) @@ -170,7 +174,6 @@ static void tifm_sd_transfer_data(struct tifm_sd *host) struct scatterlist *sg = r_data->sg; unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2; unsigned int p_off, p_cnt; - struct page *pg; if (host->sg_pos == host->sg_len) return; @@ -192,33 +195,39 @@ static void tifm_sd_transfer_data(struct tifm_sd *host) } off = sg[host->sg_pos].offset + host->block_pos; - pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, cnt); p_cnt = min(p_cnt, t_size); if (r_data->flags & MMC_DATA_READ) - tifm_sd_read_fifo(host, pg, p_off, p_cnt); + tifm_sd_read_fifo(host, &sg[host->sg_pos], p_off, + p_cnt); else if (r_data->flags & MMC_DATA_WRITE) - tifm_sd_write_fifo(host, pg, p_off, p_cnt); + tifm_sd_write_fifo(host, &sg[host->sg_pos], p_off, + p_cnt); t_size -= p_cnt; host->block_pos += p_cnt; } } -static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off, - struct page *src, unsigned int src_off, +static void tifm_sd_copy_page(struct scatterlist *dst, unsigned int dst_off, + struct scatterlist *src, unsigned int src_off, unsigned int count) { - unsigned char *src_buf = kmap_atomic(src) + src_off; - unsigned char *dst_buf = kmap_atomic(dst) + dst_off; + unsigned char *src_buf, *dst_buf; + + src_off -= src->offset; + dst_off -= dst->offset; + + src_buf = sg_map(src, src_off, SG_KMAP_ATOMIC | SG_MAP_MUST_NOT_FAIL
[PATCH v2 12/21] scsi: hisi_sas, mvsas, gdth: Make use of the new sg_map helper function
Very straightforward conversion of three scsi drivers. Signed-off-by: Logan Gunthorpe Cc: Achim Leubner Cc: John Garry --- drivers/scsi/gdth.c| 9 +++-- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 14 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 + drivers/scsi/mvsas/mv_sas.c| 10 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index d020a13..c70248a2 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -2301,10 +2301,15 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, return; } local_irq_save(flags); -address = kmap_atomic(sg_page(sl)) + sl->offset; +address = sg_map(sl, 0, SG_KMAP_ATOMIC); +if (IS_ERR(address)) { +scp->result = DID_ERROR << 16; +return; + } + memcpy(address, buffer, cpnow); flush_dcache_page(sg_page(sl)); -kunmap_atomic(address); +sg_unmap(sl, address, 0, SG_KMAP_ATOMIC); local_irq_restore(flags); if (cpsum == cpcount) break; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index fc1c1b2..b3953e3 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1381,18 +1381,22 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, void *to; struct scatterlist *sg_resp = &task->smp_task.smp_resp; - ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); + to = sg_map(sg_resp, 0, SG_KMAP_ATOMIC); + if (IS_ERR(to)) { + dev_err(dev, "slot complete: error mapping memory"); + ts->stat = SAS_SG_ERR; + break; + } + ts->stat = SAM_STAT_GOOD; dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); - memcpy(to + sg_resp->offset, - slot->status_buffer + + memcpy(to, slot->status_buffer + sizeof(struct hisi_sas_err_record), sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_unmap(sg_resp, to, 0, SG_KMAP_ATOMIC); break; } case SAS_PROTOCOL_SATA: diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index e241921..3e674a4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2307,18 +2307,23 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) struct scatterlist *sg_resp = &task->smp_task.smp_resp; void *to; + to = sg_map(sg_resp, 0, SG_KMAP_ATOMIC); + if (IS_ERR(to)) { + dev_err(dev, "slot complete: error mapping memory"); + ts->stat = SAS_SG_ERR; + break; + } + ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); - memcpy(to + sg_resp->offset, - slot->status_buffer + + memcpy(to, slot->status_buffer + sizeof(struct hisi_sas_err_record), sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_unmap(sg_resp, to, 0, SG_KMAP_ATOMIC); break; } case SAS_PROTOCOL_SATA: diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index c7cc803..a72e0ce 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1798,11 +1798,11 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) case SAS_PROTOCOL_SMP: { struct scatterlist *sg_resp = &task->smp_task.smp_resp; tstat->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); - memcpy(to + sg_resp->offset, - slot->response + sizeof(struct mvs_err_info), - sg_dma_len(sg_resp)); - kunmap_atomic(to); + to = sg_map(sg_resp, 0, SG_KMAP_ATOMIC); + memcpy(to, +
[PATCH v2 13/21] scsi: arcmsr, ips, megaraid: Make use of the new sg_map helper function
Very straightforward conversion of three scsi drivers Signed-off-by: Logan Gunthorpe Cc: Adaptec OEM Raid Solutions Cc: Kashyap Desai Cc: Sumit Saxena Cc: Shivasharan S --- drivers/scsi/arcmsr/arcmsr_hba.c | 16 drivers/scsi/ips.c | 8 drivers/scsi/megaraid.c | 9 +++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index af032c4..8c2de17 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -2306,7 +2306,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, use_sg = scsi_sg_count(cmd); sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; + buffer = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(buffer)) + return ARCMSR_MESSAGE_FAIL; + if (use_sg > 1) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; @@ -2539,7 +2542,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, message_out: if (use_sg) { struct scatterlist *sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); + sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC); } return retvalue; } @@ -2590,11 +2593,16 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, strncpy(&inqdata[32], "R001", 4); /* Product Revision */ sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; + buffer = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(buffer)) { + cmd->result = (DID_ERROR << 16); + cmd->scsi_done(cmd); + return; + } memcpy(buffer, inqdata, sizeof(inqdata)); sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); + sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC); cmd->scsi_done(cmd); } diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 3419e1b..6e91729 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1506,14 +1506,14 @@ static int ips_is_passthru(struct scsi_cmnd *SC) /* kmap_atomic() ensures addressability of the user buffer.*/ /* local_irq_save() protects the KM_IRQ0 address slot. */ local_irq_save(flags); -buffer = kmap_atomic(sg_page(sg)) + sg->offset; -if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && +buffer = sg_map(sg, 0, SG_KMAP_ATOMIC); +if (!IS_ERR(buffer) && buffer[0] == 'C' && buffer[1] == 'O' && buffer[2] == 'P' && buffer[3] == 'P') { -kunmap_atomic(buffer - sg->offset); +sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC); local_irq_restore(flags); return 1; } -kunmap_atomic(buffer - sg->offset); +sg_unmap(sg, buffer, 0, SG_KMAP_ATOMIC); local_irq_restore(flags); } return 0; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 3c63c29..f8aee59 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -663,10 +663,15 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) struct scatterlist *sg; sg = scsi_sglist(cmd); - buf = kmap_atomic(sg_page(sg)) + sg->offset; + buf = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { +cmd->result = (DID_ERROR << 16); + cmd->scsi_done(cmd); + return NULL; + } memset(buf, 0, cmd->cmnd[4]); - kunmap_atomic(buf - sg->offset); + sg_unmap(sg, buf, 0, SG_KMAP_ATOMIC); cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); -- 2.1.4
[PATCH v2 01/21] scatterlist: Introduce sg_map helper functions
This patch introduces functions which kmap the pages inside an sgl. These functions replace a common pattern of kmap(sg_page(sg)) that is used in more than 50 places within the kernel. The motivation for this work is to eventually safely support sgls that contain io memory. In order for that to work, any access to the contents of an iomem SGL will need to be done with iomemcpy or hit some warning. (The exact details of how this will work have yet to be worked out.) Having all the kmaps in one place is just a first step in that direction. Additionally, seeing this helps cut down the users of sg_page, it should make any effort to go to struct-page-less DMAs a little easier (should that idea ever swing back into favour again). A flags option is added to select between a regular or atomic mapping so these functions can replace kmap(sg_page or kmap_atomic(sg_page. Future work may expand this to have flags for using page_address or vmap. We include a flag to require the function not to fail to support legacy code that has no easy error path. Much further in the future, there may be a flag to allocate memory and copy the data from/to iomem. We also add the semantic that sg_map can fail to create a mapping, despite the fact that the current code this is replacing is assumed to never fail and the current version of these functions cannot fail. This is to support iomem which may either have to fail to create the mapping or allocate memory as a bounce buffer which itself can fail. Also, in terms of cleanup, a few of the existing kmap(sg_page) users play things a bit loose in terms of whether they apply sg->offset so using these helper functions should help avoid such issues. Signed-off-by: Logan Gunthorpe --- include/linux/scatterlist.h | 85 + 1 file changed, 85 insertions(+) diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index cb3c8fe..fad170b 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -5,6 +5,7 @@ #include #include #include +#include #include struct scatterlist { @@ -126,6 +127,90 @@ static inline struct page *sg_page(struct scatterlist *sg) return (struct page *)((sg)->page_link & ~0x3); } +#define SG_KMAP (1 << 0) /* create a mapping with kmap */ +#define SG_KMAP_ATOMIC (1 << 1) /* create a mapping with kmap_atomic */ +#define SG_MAP_MUST_NOT_FAIL (1 << 2) /* indicate sg_map should not fail */ + +/** + * sg_map - kmap a page inside an sgl + * @sg:SG entry + * @offset:Offset into entry + * @flags: Flags for creating the mapping + * + * Description: + * Use this function to map a page in the scatterlist at the specified + * offset. sg->offset is already added for you. Note: the semantics of + * this function are that it may fail. Thus, its output should be checked + * with IS_ERR and PTR_ERR. Otherwise, a pointer to the specified offset + * in the mapped page is returned. + * + * Flags can be any of: + * * SG_KMAP - Use kmap to create the mapping + * * SG_KMAP_ATOMIC- Use kmap_atomic to map the page atommically. + * Thus, the rules of that function apply: the + * cpu may not sleep until it is unmaped. + * * SG_MAP_MUST_NOT_FAIL - Indicate that sg_map must not fail. + * If it does, it will issue a BUG_ON instead. + * This is intended for legacy code only, it + * is not to be used in new code. + * + * Also, consider carefully whether this function is appropriate. It is + * largely not recommended for new code and if the sgl came from another + * subsystem and you don't know what kind of memory might be in the list + * then you definitely should not call it. Non-mappable memory may be in + * the sgl and thus this function may fail unexpectedly. Consider using + * sg_copy_to_buffer instead. + **/ +static inline void *sg_map(struct scatterlist *sg, size_t offset, int flags) +{ + struct page *pg; + unsigned int pg_off; + void *ret; + + offset += sg->offset; + pg = nth_page(sg_page(sg), offset >> PAGE_SHIFT); + pg_off = offset_in_page(offset); + + if (flags & SG_KMAP_ATOMIC) + ret = kmap_atomic(pg) + pg_off; + else if (flags & SG_KMAP) + ret = kmap(pg) + pg_off; + else + ret = ERR_PTR(-EINVAL); + + /* +* In theory, this can't happen yet. Once we start adding +* unmapable memory, it also shouldn't happen unless developers +* start putting unmappable struct pages in sgls and passing +* it to code that doesn't support it. +*/ + BUG_ON(flags & SG_MAP_MUST_NOT_FAIL && IS_ERR(ret)); + + return ret;
[PATCH v2 05/21] drm/i915: Make use of the new sg_map helper function
This is a single straightforward conversion from kmap to sg_map. We also create the i915_gem_object_unmap function to common up the unmap code. Signed-off-by: Logan Gunthorpe Acked-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 27 --- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 07e9b27..2c33000 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2202,6 +2202,15 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj) radix_tree_delete(&obj->mm.get_page.radix, iter.index); } +static void i915_gem_object_unmap(const struct drm_i915_gem_object *obj, + void *ptr) +{ + if (is_vmalloc_addr(ptr)) + vunmap(ptr); + else + sg_unmap(obj->mm.pages->sgl, ptr, 0, SG_KMAP); +} + void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, enum i915_mm_subclass subclass) { @@ -2229,10 +2238,7 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, void *ptr; ptr = ptr_mask_bits(obj->mm.mapping); - if (is_vmalloc_addr(ptr)) - vunmap(ptr); - else - kunmap(kmap_to_page(ptr)); + i915_gem_object_unmap(obj, ptr); obj->mm.mapping = NULL; } @@ -2499,8 +2505,11 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj, void *addr; /* A single page can always be kmapped */ - if (n_pages == 1 && type == I915_MAP_WB) - return kmap(sg_page(sgt->sgl)); + if (n_pages == 1 && type == I915_MAP_WB) { + addr = sg_map(sgt->sgl, 0, SG_KMAP); + if (IS_ERR(addr)) + return NULL; + } if (n_pages > ARRAY_SIZE(stack_pages)) { /* Too big for stack -- allocate temporary array instead */ @@ -2567,11 +2576,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, goto err_unpin; } - if (is_vmalloc_addr(ptr)) - vunmap(ptr); - else - kunmap(kmap_to_page(ptr)); - + i915_gem_object_unmap(obj, ptr); ptr = obj->mm.mapping = NULL; } -- 2.1.4
[PATCH v2 02/21] libiscsi: Add an internal error code
This is a prep patch to add a new error code to libiscsi. We want to rework some kmap calls to be able to fail. When we do, we'd like to use this error code. This patch simply introduces ISCSI_TCP_INTERNAL_ERR and prints "Internal Error." when it gets hit. Signed-off-by: Logan Gunthorpe --- drivers/scsi/cxgbi/libcxgbi.c | 5 + include/scsi/libiscsi_tcp.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index bd7d39e..e38d0c1 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1556,6 +1556,11 @@ static inline int read_pdu_skb(struct iscsi_conn *conn, */ iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); return -EFAULT; + case ISCSI_TCP_INTERNAL_ERR: + pr_info("skb 0x%p, off %u, %d, TCP_INTERNAL_ERR.\n", + skb, offset, offloaded); + iscsi_conn_printk(KERN_ERR, conn, "Internal error."); + return -EFAULT; case ISCSI_TCP_SEGMENT_DONE: log_debug(1 << CXGBI_DBG_PDU_RX, "skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n", diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index 30520d5..90691ad 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h @@ -92,6 +92,7 @@ enum { ISCSI_TCP_SKB_DONE, /* skb is out of data */ ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */ ISCSI_TCP_SUSPENDED,/* conn is suspended */ + ISCSI_TCP_INTERNAL_ERR, /* an internal error occurred */ }; extern void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn); -- 2.1.4
[PATCH v2 08/21] dm-crypt: Make use of the new sg_map helper in 4 call sites
Very straightforward conversion to the new function in all four spots. Signed-off-by: Logan Gunthorpe Cc: Alasdair Kergon Cc: Mike Snitzer --- drivers/md/dm-crypt.c | 39 ++- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 8dbecf1..841f1fc 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -635,9 +635,12 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) { sg = crypt_get_sg_data(cc, dmreq->sg_in); - src = kmap_atomic(sg_page(sg)); - r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset); - kunmap_atomic(src); + src = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(src)) + return PTR_ERR(src); + + r = crypt_iv_lmk_one(cc, iv, dmreq, src); + sg_unmap(sg, src, 0, SG_KMAP_ATOMIC); } else memset(iv, 0, cc->iv_size); @@ -655,14 +658,18 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, return 0; sg = crypt_get_sg_data(cc, dmreq->sg_out); - dst = kmap_atomic(sg_page(sg)); - r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset); + dst = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(dst)) + return PTR_ERR(dst); + + r = crypt_iv_lmk_one(cc, iv, dmreq, dst); /* Tweak the first block of plaintext sector */ if (!r) - crypto_xor(dst + sg->offset, iv, cc->iv_size); + crypto_xor(dst, iv, cc->iv_size); + + sg_unmap(sg, dst, 0, SG_KMAP_ATOMIC); - kunmap_atomic(dst); return r; } @@ -786,9 +793,12 @@ static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 *iv, /* Remove whitening from ciphertext */ if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) { sg = crypt_get_sg_data(cc, dmreq->sg_in); - src = kmap_atomic(sg_page(sg)); - r = crypt_iv_tcw_whitening(cc, dmreq, src + sg->offset); - kunmap_atomic(src); + src = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(src)) + return PTR_ERR(src); + + r = crypt_iv_tcw_whitening(cc, dmreq, src); + sg_unmap(sg, src, 0, SG_KMAP_ATOMIC); } /* Calculate IV */ @@ -812,9 +822,12 @@ static int crypt_iv_tcw_post(struct crypt_config *cc, u8 *iv, /* Apply whitening on ciphertext */ sg = crypt_get_sg_data(cc, dmreq->sg_out); - dst = kmap_atomic(sg_page(sg)); - r = crypt_iv_tcw_whitening(cc, dmreq, dst + sg->offset); - kunmap_atomic(dst); + dst = sg_map(sg, 0, SG_KMAP_ATOMIC); + if (IS_ERR(dst)) + return PTR_ERR(dst); + + r = crypt_iv_tcw_whitening(cc, dmreq, dst); + sg_unmap(sg, dst, 0, SG_KMAP_ATOMIC); return r; } -- 2.1.4
Re: [PATCH 16/22] xen-blkfront: Make use of the new sg_map helper function
On 18/04/17 09:50 AM, Konrad Rzeszutek Wilk wrote: > I am not sure if you know, but you can add on each patch the respective > maintainer via 'CC'. That way you can have certain maintainers CCed only > on the subsystems they cover. You put it after (or before) your SoB and > git send-email happilly picks it up. Yes, but I've seen some maintainers complain when they receive a patch with no context (ie. cover letter and first patch). So I chose to do it this way. I expect in this situation, no matter what you do, someone is going to complain about the approach chosen. Thanks anyway for the tip. Logan
Re: [PATCH 05/22] drm/i915: Make use of the new sg_map helper function
On 18/04/17 12:44 AM, Daniel Vetter wrote: > On Thu, Apr 13, 2017 at 04:05:18PM -0600, Logan Gunthorpe wrote: >> This is a single straightforward conversion from kmap to sg_map. >> >> Signed-off-by: Logan Gunthorpe > > Acked-by: Daniel Vetter > > Probably makes sense to merge through some other tree, but please be aware > of the considerable churn rate in i915 (i.e. make sure your tree is in > linux-next before you send a pull request for this). Plane B would be to > get the prep patch in first and then merge the i915 conversion one kernel > release later. Yes, as per what I said in my cover letter, I was leaning towards a "Plan B" style approach. Logan
Re: [PATCH 16/22] xen-blkfront: Make use of the new sg_map helper function
On 18/04/17 08:27 AM, Konrad Rzeszutek Wilk wrote: > Interesting that you didn't CC any of the maintainers. Could you > do that in the future please? Please read the cover letter. The distribution list for the patchset would have been way too large to cc every maintainer (even as limited as it was, I had mailing lists yelling at me). My plan was to get buy in for the first patch, get it merged and resend the rest independently to their respective maintainers. Of course, though, I'd be open to other suggestions. >>> >>> Signed-off-by: Logan Gunthorpe >>> --- >>> drivers/block/xen-blkfront.c | 33 +++-- >>> 1 file changed, 27 insertions(+), 6 deletions(-) >>> >>> diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c >>> index 5067a0a..7dcf41d 100644 >>> --- a/drivers/block/xen-blkfront.c >>> +++ b/drivers/block/xen-blkfront.c >>> @@ -807,8 +807,19 @@ static int blkif_queue_rw_req(struct request *req, >>> struct blkfront_ring_info *ri >>> BUG_ON(sg->offset + sg->length > PAGE_SIZE); >>> >>> if (setup.need_copy) { >>> - setup.bvec_off = sg->offset; >>> - setup.bvec_data = kmap_atomic(sg_page(sg)); >>> + setup.bvec_off = 0; >>> + setup.bvec_data = sg_map(sg, SG_KMAP_ATOMIC); >>> + if (IS_ERR(setup.bvec_data)) { >>> + /* >>> +* This should really never happen unless >>> +* the code is changed to use memory that is >>> +* not mappable in the sg. Seeing there is a >>> +* questionable error path out of here, >>> +* we WARN. >>> +*/ >>> + WARN(1, "Non-mappable memory used in sg!"); >>> + return 1; >>> + } >> ... >> >> Perhaps add a flag to mark failure as 'unexpected' and trace (and panic?) >> inside sg_map(). Thanks, that's a good suggestion. I'll make the change for v2. Logan
Re: [PATCH 10/22] staging: unisys: visorbus: Make use of the new sg_map helper function
Great, thanks! Logan On 14/04/17 10:07 AM, Kershner, David A wrote: > Can you add Acked-by for this patch? > > Acked-by: David Kershner > > Tested on s-Par and no problems. > > Thanks, > David Kershner > >> --- >> drivers/staging/unisys/visorhba/visorhba_main.c | 12 +++- >> 1 file changed, 7 insertions(+), 5 deletions(-) >> >> diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c >> b/drivers/staging/unisys/visorhba/visorhba_main.c >> index 0ce92c8..2d8c8bc 100644 >> --- a/drivers/staging/unisys/visorhba/visorhba_main.c >> +++ b/drivers/staging/unisys/visorhba/visorhba_main.c >> @@ -842,7 +842,6 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct >> scsi_cmnd *scsicmd) >> struct scatterlist *sg; >> unsigned int i; >> char *this_page; >> -char *this_page_orig; >> int bufind = 0; >> struct visordisk_info *vdisk; >> struct visorhba_devdata *devdata; >> @@ -869,11 +868,14 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, >> struct scsi_cmnd *scsicmd) >> >> sg = scsi_sglist(scsicmd); >> for (i = 0; i < scsi_sg_count(scsicmd); i++) { >> -this_page_orig = kmap_atomic(sg_page(sg + i)); >> -this_page = (void *)((unsigned long)this_page_orig | >> - sg[i].offset); >> +this_page = sg_map(sg + i, SG_KMAP_ATOMIC); >> +if (IS_ERR(this_page)) { >> +scsicmd->result = DID_ERROR << 16; >> +return; >> +} >> + >> memcpy(this_page, buf + bufind, sg[i].length); >> -kunmap_atomic(this_page_orig); >> +sg_unmap(sg + i, this_page, SG_KMAP_ATOMIC); >> } >> } else { >> devdata = (struct visorhba_devdata *)scsidev->host- >>> hostdata; >> -- >> 2.1.4 >
Re: [PATCH 04/22] target: Make use of the new sg_map function at 16 call sites (fwd)
Thanks Julia. I missed that and I'll fix it in my series. Logan On 14/04/17 09:19 AM, Julia Lawall wrote: > It looks like &udev->cmdr_lock should be released at line 512 if it has > not been released otherwise. The lock was taken at line 438. > > julia > > -- Forwarded message -- > Date: Fri, 14 Apr 2017 22:21:44 +0800 > From: kbuild test robot > To: kbu...@01.org > Cc: Julia Lawall > Subject: Re: [PATCH 04/22] target: Make use of the new sg_map function at 16 > call sites > > Hi Logan, > > [auto build test WARNING on scsi/for-next] > [also build test WARNING on v4.11-rc6] > [cannot apply to next-20170413] > [if your patch is applied to the wrong git tree, please drop us a note to > help improve the system] > > url: > https://github.com/0day-ci/linux/commits/Logan-Gunthorpe/Introduce-common-scatterlist-map-function/20170414-142518 > base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next > :: branch date: 8 hours ago > :: commit date: 8 hours ago > >>> drivers/target/target_core_user.c:512:2-8: preceding lock on line 438 >drivers/target/target_core_user.c:512:2-8: preceding lock on line 471 > > git remote add linux-review https://github.com/0day-ci/linux > git remote update linux-review > git checkout 78082134e7afdc59d744eb8d2def5c588e89c378 > vim +512 drivers/target/target_core_user.c > > 7c9e7a6f Andy Grover 2014-10-01 432 > sizeof(struct tcmu_cmd_entry)); > 7c9e7a6f Andy Grover 2014-10-01 433 command_size = base_command_size > 7c9e7a6f Andy Grover 2014-10-01 434 + > round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE); > 7c9e7a6f Andy Grover 2014-10-01 435 > 7c9e7a6f Andy Grover 2014-10-01 436 WARN_ON(command_size & > (TCMU_OP_ALIGN_SIZE-1)); > 7c9e7a6f Andy Grover 2014-10-01 437 > 7c9e7a6f Andy Grover 2014-10-01 @438 spin_lock_irq(&udev->cmdr_lock); > 7c9e7a6f Andy Grover 2014-10-01 439 > 7c9e7a6f Andy Grover 2014-10-01 440 mb = udev->mb_addr; > 7c9e7a6f Andy Grover 2014-10-01 441 cmd_head = mb->cmd_head % > udev->cmdr_size; /* UAM */ > 26418649 Sheng Yang 2016-02-26 442 data_length = > se_cmd->data_length; > 26418649 Sheng Yang 2016-02-26 443 if (se_cmd->se_cmd_flags & > SCF_BIDI) { > 26418649 Sheng Yang 2016-02-26 444 > BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); > 26418649 Sheng Yang 2016-02-26 445 data_length += > se_cmd->t_bidi_data_sg->length; > 26418649 Sheng Yang 2016-02-26 446 } > 554617b2 Andy Grover 2016-08-25 447 if ((command_size > > (udev->cmdr_size / 2)) || > 554617b2 Andy Grover 2016-08-25 448 data_length > > udev->data_size) { > 554617b2 Andy Grover 2016-08-25 449 pr_warn("TCMU: Request > of size %zu/%zu is too big for %u/%zu " > 3d9b9555 Andy Grover 2016-08-25 450 "cmd ring/data > area\n", command_size, data_length, > 7c9e7a6f Andy Grover 2014-10-01 451 > udev->cmdr_size, udev->data_size); > 554617b2 Andy Grover 2016-08-25 452 > spin_unlock_irq(&udev->cmdr_lock); > 554617b2 Andy Grover 2016-08-25 453 return > TCM_INVALID_CDB_FIELD; > 554617b2 Andy Grover 2016-08-25 454 } > 7c9e7a6f Andy Grover 2014-10-01 455 > 26418649 Sheng Yang 2016-02-26 456 while > (!is_ring_space_avail(udev, command_size, data_length)) { > 7c9e7a6f Andy Grover 2014-10-01 457 int ret; > 7c9e7a6f Andy Grover 2014-10-01 458 DEFINE_WAIT(__wait); > 7c9e7a6f Andy Grover 2014-10-01 459 > 7c9e7a6f Andy Grover 2014-10-01 460 > prepare_to_wait(&udev->wait_cmdr, &__wait, TASK_INTERRUPTIBLE); > 7c9e7a6f Andy Grover 2014-10-01 461 > 7c9e7a6f Andy Grover 2014-10-01 462 pr_debug("sleeping for > ring space\n"); > 7c9e7a6f Andy Grover 2014-10-01 463 > spin_unlock_irq(&udev->cmdr_lock); > 7c9e7a6f Andy Grover 2014-10-01 464 ret = > schedule_timeout(msecs_to_jiffies(TCMU_TIME_OUT)); > 7c9e7a6f Andy Grover 2014-10-01 465 > finish_wait(&udev->wait_cmdr, &__wait); > 7c9e7a6f Andy Grover 2014-10-01 466 if (!ret) { > 7c9e7a6f Andy Grover 2014-10-01 467 pr_warn("tcmu: > command timed out\n"); > 02eb924f Andy Grover 2016-10-06 468
Re: [PATCH 09/22] dm-crypt: Make use of the new sg_map helper in 4 call sites
On 14/04/17 02:39 AM, Christoph Hellwig wrote: > On Thu, Apr 13, 2017 at 04:05:22PM -0600, Logan Gunthorpe wrote: >> Very straightforward conversion to the new function in all four spots. > > I think the right fix here is to switch dm-crypt to the ahash API > that takes a scatterlist. Hmm, well I'm not sure I understand the code enough to make that conversion. But I was looking at it. One tricky bit seems to be that crypt_iv_lmk_one adds a seed, skips the first 16 bytes in the page and then hashes another 16 bytes from other data. What would you do construct a new sgl for it and pass it to the ahash api? The other thing is crypt_iv_lmk_post also seems to modify the page after the hash with a crypto_xor so you'd still need at least one kmap in there. Logan
Re: [PATCH 03/22] libiscsi: Make use of new the sg_map helper function
On 14/04/17 02:36 AM, Christoph Hellwig wrote: > On Thu, Apr 13, 2017 at 04:05:16PM -0600, Logan Gunthorpe wrote: >> Convert the kmap and kmap_atomic uses to the sg_map function. We now >> store the flags for the kmap instead of a boolean to indicate >> atomicitiy. We also propogate a possible kmap error down and create >> a new ISCSI_TCP_INTERNAL_ERR error type for this. > > Can you split out the new error handling into a separate prep patch > which should go to the iscsi maintainers ASAP? > Yes, I can do that. I'd just have thought they'd want to see the use case for the new error before accepting a patch like that... Logan
Re: [PATCH 01/22] scatterlist: Introduce sg_map helper functions
On 14/04/17 02:35 AM, Christoph Hellwig wrote: >> + >> static inline int is_dma_buf_file(struct file *); >> >> struct dma_buf_list { > > I think the right fix here is to rename the operation to unmap_atomic > and send out a little patch for that ASAP. Ok, I can do that next week. > I'd rather have separate functions for kmap vs kmap_atomic instead of > the flags parameter. And while you're at it just always pass the 0 > offset parameter instead of adding a wrapper.. > > Otherwise this looks good to me. I settled on the flags because I thought the interface could be expanded to do more things like automatically copy iomem to a bounce buffer (with a flag). It'd also be possible to add things like vmap and physical_address to the interface which would cover even more sg_page users. All the implementations would then share the common offset calculations, and switching between them becomes a matter of changing a couple flags. If you're still not convinced by the above arguments then I'll change it but I did have reasons for choosing to do it this way. I am fine with removing the offset versions. I will make that change. Thanks, Logan
Re: [PATCH 02/22] nvmet: Make use of the new sg_map helper function
On 13/04/17 10:59 PM, Christoph Hellwig wrote: > On Thu, Apr 13, 2017 at 04:05:15PM -0600, Logan Gunthorpe wrote: >> This is a straight forward conversion in two places. Should kmap fail, >> the code will return an INVALD_DATA error in the completion. > > It really should be using nvmet_copy_from_sgl to make things safer, > as we don't want to rely on any particular SG list layout. In fact > I'm pretty sure I did the conversion at some point, but it must never > have made it upstream. Ha, I did the conversion too a couple times for my RFC series. I can change this patch to do that. Or maybe I'll just send a patch for that separately seeing it doesn't depend on anything and is pretty simple. I can do that next week. Thanks, Logan
[PATCH 15/22] scsi: libfc, csiostor: Change to sg_copy_buffer in two drivers
These two drivers appear to duplicate the functionality of sg_copy_buffer. So we clean them up to use the common code. This helps us remove a couple of instances that would otherwise be slightly tricky sg_map usages. Signed-off-by: Logan Gunthorpe --- drivers/scsi/csiostor/csio_scsi.c | 54 +++ drivers/scsi/libfc/fc_libfc.c | 49 --- 2 files changed, 14 insertions(+), 89 deletions(-) diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index a1ff75f..bd9d062 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -1489,60 +1489,14 @@ static inline uint32_t csio_scsi_copy_to_sgl(struct csio_hw *hw, struct csio_ioreq *req) { struct scsi_cmnd *scmnd = (struct scsi_cmnd *)csio_scsi_cmnd(req); - struct scatterlist *sg; - uint32_t bytes_left; - uint32_t bytes_copy; - uint32_t buf_off = 0; - uint32_t start_off = 0; - uint32_t sg_off = 0; - void *sg_addr; - void *buf_addr; struct csio_dma_buf *dma_buf; + size_t copied; - bytes_left = scsi_bufflen(scmnd); - sg = scsi_sglist(scmnd); dma_buf = (struct csio_dma_buf *)csio_list_next(&req->gen_list); + copied = sg_copy_from_buffer(scsi_sglist(scmnd), scsi_sg_count(scmnd), +dma_buf->vaddr, scsi_bufflen(scmnd)); - /* Copy data from driver buffer to SGs of SCSI CMD */ - while (bytes_left > 0 && sg && dma_buf) { - if (buf_off >= dma_buf->len) { - buf_off = 0; - dma_buf = (struct csio_dma_buf *) - csio_list_next(dma_buf); - continue; - } - - if (start_off >= sg->length) { - start_off -= sg->length; - sg = sg_next(sg); - continue; - } - - buf_addr = dma_buf->vaddr + buf_off; - sg_off = sg->offset + start_off; - bytes_copy = min((dma_buf->len - buf_off), - sg->length - start_off); - bytes_copy = min((uint32_t)(PAGE_SIZE - (sg_off & ~PAGE_MASK)), -bytes_copy); - - sg_addr = kmap_atomic(sg_page(sg) + (sg_off >> PAGE_SHIFT)); - if (!sg_addr) { - csio_err(hw, "failed to kmap sg:%p of ioreq:%p\n", - sg, req); - break; - } - - csio_dbg(hw, "copy_to_sgl:sg_addr %p sg_off %d buf %p len %d\n", - sg_addr, sg_off, buf_addr, bytes_copy); - memcpy(sg_addr + (sg_off & ~PAGE_MASK), buf_addr, bytes_copy); - kunmap_atomic(sg_addr); - - start_off += bytes_copy; - buf_off += bytes_copy; - bytes_left -= bytes_copy; - } - - if (bytes_left > 0) + if (copied != scsi_bufflen(scmnd)) return DID_ERROR; else return DID_OK; diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index d623d08..ce0805a 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -113,45 +113,16 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, u32 *nents, size_t *offset, u32 *crc) { - size_t remaining = len; - u32 copy_len = 0; - - while (remaining > 0 && sg) { - size_t off, sg_bytes; - void *page_addr; - - if (*offset >= sg->length) { - /* -* Check for end and drop resources -* from the last iteration. -*/ - if (!(*nents)) - break; - --(*nents); - *offset -= sg->length; - sg = sg_next(sg); - continue; - } - sg_bytes = min(remaining, sg->length - *offset); - - /* -* The scatterlist item may be bigger than PAGE_SIZE, -* but we are limited to mapping PAGE_SIZE at a time. -*/ - off = *offset + sg->offset; - sg_bytes = min(sg_bytes, - (size_t)(PAGE_SIZE - (off & ~PAGE_MASK))); - page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT)); - if (crc) - *crc = crc32(*crc, buf, sg_bytes); - memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes); -
[PATCH 12/22] scsi: ipr, pmcraid, isci: Make use of the new sg_map helper in 4 call sites
Very straightforward conversion of three scsi drivers. Signed-off-by: Logan Gunthorpe --- drivers/scsi/ipr.c | 27 ++- drivers/scsi/isci/request.c | 42 +- drivers/scsi/pmcraid.c | 19 --- 3 files changed, 51 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b29afaf..f98f251 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3853,7 +3853,7 @@ static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, u8 *buffer, u32 len) { - int bsize_elem, i, result = 0; + int bsize_elem, i; struct scatterlist *scatterlist; void *kaddr; @@ -3863,32 +3863,33 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, scatterlist = sglist->scatterlist; for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + kaddr = sg_map(&scatterlist[i], SG_KMAP); + if (IS_ERR(kaddr)) { + ipr_trace; + return PTR_ERR(kaddr); + } - kaddr = kmap(page); memcpy(kaddr, buffer, bsize_elem); - kunmap(page); + sg_unmap(&scatterlist[i], kaddr, SG_KMAP); scatterlist[i].length = bsize_elem; - - if (result != 0) { - ipr_trace; - return result; - } } if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + kaddr = sg_map(&scatterlist[i], SG_KMAP); + if (IS_ERR(kaddr)) { + ipr_trace; + return PTR_ERR(kaddr); + } - kaddr = kmap(page); memcpy(kaddr, buffer, len % bsize_elem); - kunmap(page); + sg_unmap(&scatterlist[i], kaddr, SG_KMAP); scatterlist[i].length = len % bsize_elem; } sglist->buffer_len = len; - return result; + return 0; } /** diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 47f66e9..66d6596 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1424,12 +1424,14 @@ sci_stp_request_pio_data_in_copy_data_buffer(struct isci_stp_request *stp_req, sg = task->scatter; while (total_len > 0) { - struct page *page = sg_page(sg); - copy_len = min_t(int, total_len, sg_dma_len(sg)); - kaddr = kmap_atomic(page); - memcpy(kaddr + sg->offset, src_addr, copy_len); - kunmap_atomic(kaddr); + kaddr = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(kaddr)) + return SCI_FAILURE; + + memcpy(kaddr, src_addr, copy_len); + sg_unmap(sg, kaddr, SG_KMAP_ATOMIC); + total_len -= copy_len; src_addr += copy_len; sg = sg_next(sg); @@ -1771,14 +1773,16 @@ sci_io_request_frame_handler(struct isci_request *ireq, case SCI_REQ_SMP_WAIT_RESP: { struct sas_task *task = isci_request_access_task(ireq); struct scatterlist *sg = &task->smp_task.smp_resp; - void *frame_header, *kaddr; + void *frame_header; u8 *rsp; sci_unsolicited_frame_control_get_header(&ihost->uf_control, frame_index, &frame_header); - kaddr = kmap_atomic(sg_page(sg)); - rsp = kaddr + sg->offset; + rsp = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(rsp)) + return SCI_FAILURE; + sci_swab32_cpy(rsp, frame_header, 1); if (rsp[0] == SMP_RESPONSE) { @@ -1814,7 +1818,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); } - kunmap_atomic(kaddr); + sg_unmap(sg, rsp, SG_KMAP_ATOMIC); sci_controller_release_frame(ihost, frame_index); @@ -2919,15 +2923,18 @@ static void isci_request_io_request_complete(struct isci_host *ihost, case SAS_PROTOCOL_SMP: { struct scatterlist *sg = &task->smp_task.smp_req; struct smp_req *smp_req; - voi
[PATCH 10/22] staging: unisys: visorbus: Make use of the new sg_map helper function
Straightforward conversion to the new function. Signed-off-by: Logan Gunthorpe --- drivers/staging/unisys/visorhba/visorhba_main.c | 12 +++- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 0ce92c8..2d8c8bc 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -842,7 +842,6 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) struct scatterlist *sg; unsigned int i; char *this_page; - char *this_page_orig; int bufind = 0; struct visordisk_info *vdisk; struct visorhba_devdata *devdata; @@ -869,11 +868,14 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) sg = scsi_sglist(scsicmd); for (i = 0; i < scsi_sg_count(scsicmd); i++) { - this_page_orig = kmap_atomic(sg_page(sg + i)); - this_page = (void *)((unsigned long)this_page_orig | -sg[i].offset); + this_page = sg_map(sg + i, SG_KMAP_ATOMIC); + if (IS_ERR(this_page)) { + scsicmd->result = DID_ERROR << 16; + return; + } + memcpy(this_page, buf + bufind, sg[i].length); - kunmap_atomic(this_page_orig); + sg_unmap(sg + i, this_page, SG_KMAP_ATOMIC); } } else { devdata = (struct visorhba_devdata *)scsidev->host->hostdata; -- 2.1.4
[PATCH 03/22] libiscsi: Make use of new the sg_map helper function
Convert the kmap and kmap_atomic uses to the sg_map function. We now store the flags for the kmap instead of a boolean to indicate atomicitiy. We also propogate a possible kmap error down and create a new ISCSI_TCP_INTERNAL_ERR error type for this. Signed-off-by: Logan Gunthorpe --- drivers/scsi/cxgbi/libcxgbi.c | 5 + drivers/scsi/libiscsi_tcp.c | 32 include/scsi/libiscsi_tcp.h | 3 ++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index bd7d39e..e38d0c1 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1556,6 +1556,11 @@ static inline int read_pdu_skb(struct iscsi_conn *conn, */ iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); return -EFAULT; + case ISCSI_TCP_INTERNAL_ERR: + pr_info("skb 0x%p, off %u, %d, TCP_INTERNAL_ERR.\n", + skb, offset, offloaded); + iscsi_conn_printk(KERN_ERR, conn, "Internal error."); + return -EFAULT; case ISCSI_TCP_SEGMENT_DONE: log_debug(1 << CXGBI_DBG_PDU_RX, "skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n", diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 63a1d69..a2427699 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -133,25 +133,23 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) if (page_count(sg_page(sg)) >= 1 && !recv) return; - if (recv) { - segment->atomic_mapped = true; - segment->sg_mapped = kmap_atomic(sg_page(sg)); - } else { - segment->atomic_mapped = false; - /* the xmit path can sleep with the page mapped so use kmap */ - segment->sg_mapped = kmap(sg_page(sg)); + /* the xmit path can sleep with the page mapped so don't use atomic */ + segment->sg_map_flags = recv ? SG_KMAP_ATOMIC : SG_KMAP; + segment->sg_mapped = sg_map(sg, segment->sg_map_flags); + + if (IS_ERR(segment->sg_mapped)) { + segment->sg_mapped = NULL; + return; } - segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; + segment->data = segment->sg_mapped + segment->sg_offset; } void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { if (segment->sg_mapped) { - if (segment->atomic_mapped) - kunmap_atomic(segment->sg_mapped); - else - kunmap(sg_page(segment->sg)); + sg_unmap(segment->sg, segment->sg_mapped, + segment->sg_map_flags); segment->sg_mapped = NULL; segment->data = NULL; } @@ -304,6 +302,9 @@ iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, break; } + if (segment->data) + return -EFAULT; + copy = min(len - copied, segment->size - segment->copied); ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy); memcpy(segment->data + segment->copied, ptr + copied, copy); @@ -927,6 +928,13 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, avail); rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail); BUG_ON(rc == 0); + if (rc < 0) { + ISCSI_DBG_TCP(conn, "memory fault. Consumed %d\n", + consumed); + *status = ISCSI_TCP_INTERNAL_ERR; + goto skb_done; + } + consumed += rc; if (segment->total_copied >= segment->total_size) { diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index 30520d5..58c79af 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h @@ -47,7 +47,7 @@ struct iscsi_segment { struct scatterlist *sg; void*sg_mapped; unsigned intsg_offset; - boolatomic_mapped; + int sg_map_flags; iscsi_segment_done_fn_t *done; }; @@ -92,6 +92,7 @@ enum { ISCSI_TCP_SKB_DONE, /* skb is out of data */ ISCSI_TCP_CONN_ERR, /* iscsi layer has fired a conn err */ ISCSI_TCP_SUSPENDED,/* conn is suspended */ + ISCSI_TCP_INTERNAL_ERR, /* an internal error occurred */ }; extern void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn); -- 2.1.4
[PATCH 07/22] crypto: shash, caam: Make use of the new sg_map helper function
Very straightforward conversion to the new function in two crypto drivers. Signed-off-by: Logan Gunthorpe --- crypto/shash.c| 9 ++--- drivers/crypto/caam/caamalg.c | 8 +++- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/crypto/shash.c b/crypto/shash.c index 5e31c8d..2b7de94 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -283,10 +283,13 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { void *data; - data = kmap_atomic(sg_page(sg)); - err = crypto_shash_digest(desc, data + offset, nbytes, + data = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(data)) + return PTR_ERR(data); + + err = crypto_shash_digest(desc, data, nbytes, req->result); - kunmap_atomic(data); + sg_unmap(sg, data, SG_KMAP_ATOMIC); crypto_yield(desc->flags); } else err = crypto_shash_init(desc) ?: diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 9bc80eb..76b97de 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -89,7 +89,6 @@ static void dbg_dump_sg(const char *level, const char *prefix_str, struct scatterlist *sg, size_t tlen, bool ascii) { struct scatterlist *it; - void *it_page; size_t len; void *buf; @@ -98,19 +97,18 @@ static void dbg_dump_sg(const char *level, const char *prefix_str, * make sure the scatterlist's page * has a valid virtual memory mapping */ - it_page = kmap_atomic(sg_page(it)); - if (unlikely(!it_page)) { + buf = sg_map(it, SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { printk(KERN_ERR "dbg_dump_sg: kmap failed\n"); return; } - buf = it_page + it->offset; len = min_t(size_t, tlen, it->length); print_hex_dump(level, prefix_str, prefix_type, rowsize, groupsize, buf, len, ascii); tlen -= len; - kunmap_atomic(it_page); + sg_unmap(it, buf, SG_KMAP_ATOMIC); } } #endif -- 2.1.4
[PATCH 04/22] target: Make use of the new sg_map function at 16 call sites
Fairly straightforward conversions in all spots. In a couple of cases any error gets propogated up should sg_map fail. In other cases a warning is issued if the kmap fails seeing there's no clear error path. This should not be an issue until someone tries to use unmappable memory in the sgl with this driver. Signed-off-by: Logan Gunthorpe --- drivers/target/iscsi/iscsi_target.c| 27 +--- drivers/target/target_core_rd.c| 3 +- drivers/target/target_core_sbc.c | 122 +++-- drivers/target/target_core_transport.c | 18 +++-- drivers/target/target_core_user.c | 43 include/target/target_core_backend.h | 4 +- 6 files changed, 149 insertions(+), 68 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index a918024..e3e0d8f 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -579,7 +579,7 @@ iscsit_xmit_nondatain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, } static int iscsit_map_iovec(struct iscsi_cmd *, struct kvec *, u32, u32); -static void iscsit_unmap_iovec(struct iscsi_cmd *); +static void iscsit_unmap_iovec(struct iscsi_cmd *, struct kvec *); static u32 iscsit_do_crypto_hash_sg(struct ahash_request *, struct iscsi_cmd *, u32, u32, u32, u8 *); static int @@ -646,7 +646,7 @@ iscsit_xmit_datain_pdu(struct iscsi_conn *conn, struct iscsi_cmd *cmd, ret = iscsit_fe_sendpage_sg(cmd, conn); - iscsit_unmap_iovec(cmd); + iscsit_unmap_iovec(cmd, &cmd->iov_data[1]); if (ret < 0) { iscsit_tx_thread_wait_for_tcp(conn); @@ -925,7 +925,10 @@ static int iscsit_map_iovec( while (data_length) { u32 cur_len = min_t(u32, data_length, sg->length - page_off); - iov[i].iov_base = kmap(sg_page(sg)) + sg->offset + page_off; + iov[i].iov_base = sg_map_offset(sg, page_off, SG_KMAP); + if (IS_ERR(iov[i].iov_base)) + goto map_err; + iov[i].iov_len = cur_len; data_length -= cur_len; @@ -937,17 +940,25 @@ static int iscsit_map_iovec( cmd->kmapped_nents = i; return i; + +map_err: + cmd->kmapped_nents = i - 1; + iscsit_unmap_iovec(cmd, iov); + return -1; } -static void iscsit_unmap_iovec(struct iscsi_cmd *cmd) +static void iscsit_unmap_iovec(struct iscsi_cmd *cmd, struct kvec *iov) { u32 i; struct scatterlist *sg; + unsigned int page_off = cmd->first_data_sg_off; sg = cmd->first_data_sg; - for (i = 0; i < cmd->kmapped_nents; i++) - kunmap(sg_page(&sg[i])); + for (i = 0; i < cmd->kmapped_nents; i++) { + sg_unmap_offset(&sg[i], iov[i].iov_base, page_off, SG_KMAP); + page_off = 0; + } } static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) @@ -1610,7 +1621,7 @@ iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); - iscsit_unmap_iovec(cmd); + iscsit_unmap_iovec(cmd, iov); if (rx_got != rx_size) return -1; @@ -2626,7 +2637,7 @@ static int iscsit_handle_immediate_data( rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); - iscsit_unmap_iovec(cmd); + iscsit_unmap_iovec(cmd, cmd->iov_data); if (rx_got != rx_size) { iscsit_rx_thread_wait_for_tcp(conn); diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index ddc216c..22c5ad5 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -431,7 +431,8 @@ static sense_reason_t rd_do_prot_rw(struct se_cmd *cmd, bool is_read) cmd->t_prot_sg, 0); if (!rc) - sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, prot_offset); + rc = sbc_dif_copy_prot(cmd, sectors, is_read, prot_sg, + prot_offset); return rc; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index c194063..67cb420 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -420,17 +420,17 @@ static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success, offset = 0; for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { - addr = kmap_atomic(sg_page(sg)); - if (!addr) { + addr = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(addr)) { ret = TCM_OUT_OF_RESOURCES; goto out; } for (i = 0; i < sg-&g
[PATCH 18/22] mmc: spi: Make use of the new sg_map helper function
We use the sg_map helper but it's slightly more complicated as we only check for the error when the mapping actually gets used. Such that if the mapping failed but wasn't needed then no error occurs. Signed-off-by: Logan Gunthorpe --- drivers/mmc/host/mmc_spi.c | 26 +++--- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index e77d79c..82f786d 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -676,9 +676,15 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, struct scratch *scratch = host->data; u32 pattern; - if (host->mmc->use_spi_crc) + if (host->mmc->use_spi_crc) { + if (IS_ERR(t->tx_buf)) + return PTR_ERR(t->tx_buf); + scratch->crc_val = cpu_to_be16( crc_itu_t(0, t->tx_buf, t->len)); + t->tx_buf += t->len; + } + if (host->dma_dev) dma_sync_single_for_device(host->dma_dev, host->data_dma, sizeof(*scratch), @@ -743,7 +749,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t, return status; } - t->tx_buf += t->len; if (host->dma_dev) t->tx_dma += t->len; @@ -809,6 +814,11 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, } leftover = status << 1; + if (bitshift || host->mmc->use_spi_crc) { + if (IS_ERR(t->rx_buf)) + return PTR_ERR(t->rx_buf); + } + if (host->dma_dev) { dma_sync_single_for_device(host->dma_dev, host->data_dma, sizeof(*scratch), @@ -860,9 +870,10 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t, scratch->crc_val, crc, t->len); return -EILSEQ; } + + t->rx_buf += t->len; } - t->rx_buf += t->len; if (host->dma_dev) t->rx_dma += t->len; @@ -936,11 +947,11 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, } /* allow pio too; we don't allow highmem */ - kmap_addr = kmap(sg_page(sg)); + kmap_addr = sg_map(sg, SG_KMAP); if (direction == DMA_TO_DEVICE) - t->tx_buf = kmap_addr + sg->offset; + t->tx_buf = kmap_addr; else - t->rx_buf = kmap_addr + sg->offset; + t->rx_buf = kmap_addr; /* transfer each block, and update request status */ while (length) { @@ -970,7 +981,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, /* discard mappings */ if (direction == DMA_FROM_DEVICE) flush_kernel_dcache_page(sg_page(sg)); - kunmap(sg_page(sg)); + if (!IS_ERR(kmap_addr)) + sg_unmap(sg, kmap_addr, SG_KMAP); if (dma_dev) dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir); -- 2.1.4
[PATCH 22/22] memstick: Make use of the new sg_map helper function
Straightforward conversion, but we have to WARN if unmappable memory finds its way into the sgl. Signed-off-by: Logan Gunthorpe --- drivers/memstick/host/jmb38x_ms.c | 23 ++- drivers/memstick/host/tifm_ms.c | 22 +- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c index 48db922..256cf41 100644 --- a/drivers/memstick/host/jmb38x_ms.c +++ b/drivers/memstick/host/jmb38x_ms.c @@ -303,7 +303,6 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) unsigned int off; unsigned int t_size, p_cnt; unsigned char *buf; - struct page *pg; unsigned long flags = 0; if (host->req->long_data) { @@ -318,14 +317,26 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) unsigned int uninitialized_var(p_off); if (host->req->long_data) { - pg = nth_page(sg_page(&host->req->sg), - off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, length); local_irq_save(flags); - buf = kmap_atomic(pg) + p_off; + buf = sg_map_offset(&host->req->sg, +off - host->req->sg.offset, +SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + break; + } + } else { buf = host->req->data + host->block_pos; p_cnt = host->req->data_len - host->block_pos; @@ -341,7 +352,9 @@ static int jmb38x_ms_transfer_data(struct jmb38x_ms_host *host) : jmb38x_ms_read_reg_data(host, buf, p_cnt); if (host->req->long_data) { - kunmap_atomic(buf - p_off); + sg_unmap_offset(&host->req->sg, buf, +off - host->req->sg.offset, +SG_KMAP_ATOMIC); local_irq_restore(flags); } diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index 7bafa72..c0bc40e 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -186,7 +186,6 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) unsigned int off; unsigned int t_size, p_cnt; unsigned char *buf; - struct page *pg; unsigned long flags = 0; if (host->req->long_data) { @@ -203,14 +202,25 @@ static unsigned int tifm_ms_transfer_data(struct tifm_ms *host) unsigned int uninitialized_var(p_off); if (host->req->long_data) { - pg = nth_page(sg_page(&host->req->sg), - off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, length); local_irq_save(flags); - buf = kmap_atomic(pg) + p_off; + buf = sg_map_offset(&host->req->sg, +off - host->req->sg.offset, +SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + break; + } } else { buf = host->req->data + host->block_pos; p_cnt = host->req->d
[PATCH 16/22] xen-blkfront: Make use of the new sg_map helper function
Straightforward conversion to the new helper, except due to the lack of error path, we have to warn if unmapable memory is ever present in the sgl. Signed-off-by: Logan Gunthorpe --- drivers/block/xen-blkfront.c | 33 +++-- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 5067a0a..7dcf41d 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -807,8 +807,19 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri BUG_ON(sg->offset + sg->length > PAGE_SIZE); if (setup.need_copy) { - setup.bvec_off = sg->offset; - setup.bvec_data = kmap_atomic(sg_page(sg)); + setup.bvec_off = 0; + setup.bvec_data = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(setup.bvec_data)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there is a +* questionable error path out of here, +* we WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return 1; + } } gnttab_foreach_grant_in_range(sg_page(sg), @@ -818,7 +829,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri &setup); if (setup.need_copy) - kunmap_atomic(setup.bvec_data); + sg_unmap(sg, setup.bvec_data, SG_KMAP_ATOMIC); } if (setup.segments) kunmap_atomic(setup.segments); @@ -1468,8 +1479,18 @@ static bool blkif_completion(unsigned long *id, for_each_sg(s->sg, sg, num_sg, i) { BUG_ON(sg->offset + sg->length > PAGE_SIZE); - data.bvec_offset = sg->offset; - data.bvec_data = kmap_atomic(sg_page(sg)); + data.bvec_offset = 0; + data.bvec_data = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(data.bvec_data)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there is no +* clear error path, we WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return 1; + } gnttab_foreach_grant_in_range(sg_page(sg), sg->offset, @@ -1477,7 +1498,7 @@ static bool blkif_completion(unsigned long *id, blkif_copy_from_grant, &data); - kunmap_atomic(data.bvec_data); + sg_unmap(sg, data.bvec_data, SG_KMAP_ATOMIC); } } /* Add the persistent grant into the list of free grants */ -- 2.1.4
[PATCH 19/22] mmc: tmio: Make use of the new sg_map helper function
Straightforward conversion to sg_map helper. A couple paths will WARN if the memory does not end up being mappable. Signed-off-by: Logan Gunthorpe --- drivers/mmc/host/tmio_mmc.h | 12 ++-- drivers/mmc/host/tmio_mmc_dma.c | 5 + drivers/mmc/host/tmio_mmc_pio.c | 24 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 2b349d4..ba68c9fed 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -198,17 +198,25 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); +/* Note: this function may return PTR_ERR and must be checked! */ static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { + void *ret; + local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; + ret = sg_map(sg, SG_KMAP_ATOMIC); + + if (IS_ERR(ret)) + local_irq_restore(*flags); + + return ret; } static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg, unsigned long *flags, void *virt) { - kunmap_atomic(virt - sg->offset); + sg_unmap(sg, virt, SG_KMAP_ATOMIC); local_irq_restore(*flags); } diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index fa8a936..07531f7 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -149,6 +149,11 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) if (!aligned) { unsigned long flags; void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags); + if (IS_ERR(sg_vaddr)) { + ret = PTR_ERR(sg_vaddr); + goto pio; + } + sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length); tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 6b789a7..d6fdbf6 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -479,6 +479,18 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host) } sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags); + if (IS_ERR(sg_virt)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return; + } + buf = (unsigned short *)(sg_virt + host->sg_off); count = host->sg_ptr->length - host->sg_off; @@ -506,6 +518,18 @@ static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host) if (host->sg_ptr == &host->bounce_sg) { unsigned long flags; void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags); + if (IS_ERR(sg_vaddr)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return; + } + memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length); tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr); } -- 2.1.4
[PATCH 05/22] drm/i915: Make use of the new sg_map helper function
This is a single straightforward conversion from kmap to sg_map. Signed-off-by: Logan Gunthorpe --- drivers/gpu/drm/i915/i915_gem.c | 27 --- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 67b1fc5..1b1b91a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2188,6 +2188,15 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj) radix_tree_delete(&obj->mm.get_page.radix, iter.index); } +static void i915_gem_object_unmap(const struct drm_i915_gem_object *obj, + void *ptr) +{ + if (is_vmalloc_addr(ptr)) + vunmap(ptr); + else + sg_unmap(obj->mm.pages->sgl, ptr, SG_KMAP); +} + void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, enum i915_mm_subclass subclass) { @@ -2215,10 +2224,7 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj, void *ptr; ptr = ptr_mask_bits(obj->mm.mapping); - if (is_vmalloc_addr(ptr)) - vunmap(ptr); - else - kunmap(kmap_to_page(ptr)); + i915_gem_object_unmap(obj, ptr); obj->mm.mapping = NULL; } @@ -2475,8 +2481,11 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj, void *addr; /* A single page can always be kmapped */ - if (n_pages == 1 && type == I915_MAP_WB) - return kmap(sg_page(sgt->sgl)); + if (n_pages == 1 && type == I915_MAP_WB) { + addr = sg_map(sgt->sgl, SG_KMAP); + if (IS_ERR(addr)) + return NULL; + } if (n_pages > ARRAY_SIZE(stack_pages)) { /* Too big for stack -- allocate temporary array instead */ @@ -2543,11 +2552,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, goto err_unpin; } - if (is_vmalloc_addr(ptr)) - vunmap(ptr); - else - kunmap(kmap_to_page(ptr)); - + i915_gem_object_unmap(obj, ptr); ptr = obj->mm.mapping = NULL; } -- 2.1.4
[PATCH 01/22] scatterlist: Introduce sg_map helper functions
This patch introduces functions which kmap the pages inside an sgl. Two variants are provided: one if an offset is required and one if the offset is zero. These functions replace a common pattern of kmap(sg_page(sg)) that is used in about 50 places within the kernel. The motivation for this work is to eventually safely support sgls that contain io memory. In order for that to work, any access to the contents of an iomem SGL will need to be done with iomemcpy or hit some warning. (The exact details of how this will work have yet to be worked out.) Having all the kmaps in one place is just a first step in that direction. Additionally, seeing this helps cut down the users of sg_page, it should make any effort to go to struct-page-less DMAs a little easier (should that idea ever swing back into favour again). A flags option is added to select between a regular or atomic mapping so these functions can replace kmap(sg_page or kmap_atomic(sg_page. Future work may expand this to have flags for using page_address or vmap. Much further in the future, there may be a flag to allocate memory and copy the data from/to iomem. We also add the semantic that sg_map can fail to create a mapping, despite the fact that the current code this is replacing is assumed to never fail and the current version of these functions cannot fail. This is to support iomem which either have to fail to create the mapping or allocate memory as a bounce buffer which itself can fail. Also, in terms of cleanup, a few of the existing kmap(sg_page) users play things a bit loose in terms of whether they apply sg->offset so using these helper functions should help avoid such issues. Signed-off-by: Logan Gunthorpe --- drivers/dma-buf/dma-buf.c | 3 ++ include/linux/scatterlist.h | 97 + 2 files changed, 100 insertions(+) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 0007b79..b95934b 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -37,6 +37,9 @@ #include +/* Prevent the highmem.h macro from aliasing ops->kunmap_atomic */ +#undef kunmap_atomic + static inline int is_dma_buf_file(struct file *); struct dma_buf_list { diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index cb3c8fe..acd4d73 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -5,6 +5,7 @@ #include #include #include +#include #include struct scatterlist { @@ -126,6 +127,102 @@ static inline struct page *sg_page(struct scatterlist *sg) return (struct page *)((sg)->page_link & ~0x3); } +#define SG_KMAP(1 << 0)/* create a mapping with kmap */ +#define SG_KMAP_ATOMIC (1 << 1)/* create a mapping with kmap_atomic */ + +/** + * sg_map_offset - kmap a page inside an sgl + * @sg:SG entry + * @offset:Offset into entry + * @flags: Flags for creating the mapping + * + * Description: + * Use this function to map a page in the scatterlist at the specified + * offset. sg->offset is already added for you. Note: the semantics of + * this function are that it may fail. Thus, its output should be checked + * with IS_ERR and PTR_ERR. Otherwise, a pointer to the specified offset + * in the mapped page is returned. + * + * Flags can be any of: + * * SG_KMAP- Use kmap to create the mapping + * * SG_KMAP_ATOMIC - Use kmap_atomic to map the page atommically. + *Thus, the rules of that function apply: the cpu + *may not sleep until it is unmaped. + * + * Also, consider carefully whether this function is appropriate. It is + * largely not recommended for new code and if the sgl came from another + * subsystem and you don't know what kind of memory might be in the list + * then you definitely should not call it. Non-mappable memory may be in + * the sgl and thus this function may fail unexpectedly. + **/ +static inline void *sg_map_offset(struct scatterlist *sg, size_t offset, + int flags) +{ + struct page *pg; + unsigned int pg_off; + + offset += sg->offset; + pg = nth_page(sg_page(sg), offset >> PAGE_SHIFT); + pg_off = offset_in_page(offset); + + if (flags & SG_KMAP_ATOMIC) + return kmap_atomic(pg) + pg_off; + else + return kmap(pg) + pg_off; +} + +/** + * sg_unkmap_offset - unmap a page that was mapped with sg_map_offset + * @sg:SG entry + * @addr: address returned by sg_map_offset + * @offset:Offset into entry (same as specified for sg_map_offset) + * @flags: Flags, which are the same specified for sg_map_offset + * + * Description: + * Unmap the page that was mapped with sg_map_offset + * + **/ +static inline void sg_unmap_offset(struct scatterlist *sg, void *addr, + size_t
[PATCH 00/22] Introduce common scatterlist map function
Hi Everyone, As part of my effort to enable P2P DMA transactions with PCI cards, we've identified the need to be able to safely put IO memory into scatterlists (and eventually other spots). This probably involves a conversion from struct page to pfn_t but that migration is a ways off and those decisions are yet to be made. As an initial step in that direction, I've started cleaning up some of the scatterlist code by trying to carve out a better defined layer between it and it's users. The longer term goal would be to remove sg_page or replace it with something that can potentially fail. This patchset is the first step in that effort. I've introduced a common function to map scatterlist memory and converted all the common kmap(sg_page()) cases. This removes about 66 sg_page calls (of ~331). Seeing this is a fairly large cleanup set that touches a wide swath of the kernel I have limited the people I've sent this to. I'd suggest we look toward merging the first patch and then I can send the individual subsystem patches on to their respective maintainers and get them merged independantly. (This is to avoid the conflicts I created with my last cleanup set... Sorry) Though, I'm certainly open to other suggestions to get it merged. The patchset is based on v4.11-rc6 and can be found in the sg_map branch from this git tree: https://github.com/sbates130272/linux-p2pmem.git Thanks, Logan Logan Gunthorpe (22): scatterlist: Introduce sg_map helper functions nvmet: Make use of the new sg_map helper function libiscsi: Make use of new the sg_map helper function target: Make use of the new sg_map function at 16 call sites drm/i915: Make use of the new sg_map helper function crypto: hifn_795x: Make use of the new sg_map helper function crypto: shash, caam: Make use of the new sg_map helper function crypto: chcr: Make use of the new sg_map helper function dm-crypt: Make use of the new sg_map helper in 4 call sites staging: unisys: visorbus: Make use of the new sg_map helper function RDS: Make use of the new sg_map helper function scsi: ipr, pmcraid, isci: Make use of the new sg_map helper in 4 call sites scsi: hisi_sas, mvsas, gdth: Make use of the new sg_map helper function scsi: arcmsr, ips, megaraid: Make use of the new sg_map helper function scsi: libfc, csiostor: Change to sg_copy_buffer in two drivers xen-blkfront: Make use of the new sg_map helper function mmc: sdhci: Make use of the new sg_map helper function mmc: spi: Make use of the new sg_map helper function mmc: tmio: Make use of the new sg_map helper function mmc: sdricoh_cs: Make use of the new sg_map helper function mmc: tifm_sd: Make use of the new sg_map helper function memstick: Make use of the new sg_map helper function crypto/shash.c | 9 +- drivers/block/xen-blkfront.c| 33 +-- drivers/crypto/caam/caamalg.c | 8 +- drivers/crypto/chelsio/chcr_algo.c | 28 +++--- drivers/crypto/hifn_795x.c | 32 --- drivers/dma-buf/dma-buf.c | 3 + drivers/gpu/drm/i915/i915_gem.c | 27 +++--- drivers/md/dm-crypt.c | 38 +--- drivers/memstick/host/jmb38x_ms.c | 23 - drivers/memstick/host/tifm_ms.c | 22 - drivers/mmc/host/mmc_spi.c | 26 +++-- drivers/mmc/host/sdhci.c| 35 ++- drivers/mmc/host/sdricoh_cs.c | 14 ++- drivers/mmc/host/tifm_sd.c | 88 + drivers/mmc/host/tmio_mmc.h | 12 ++- drivers/mmc/host/tmio_mmc_dma.c | 5 + drivers/mmc/host/tmio_mmc_pio.c | 24 + drivers/nvme/target/fabrics-cmd.c | 16 +++- drivers/scsi/arcmsr/arcmsr_hba.c| 16 +++- drivers/scsi/csiostor/csio_scsi.c | 54 +-- drivers/scsi/cxgbi/libcxgbi.c | 5 + drivers/scsi/gdth.c | 9 +- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 14 ++- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 ++- drivers/scsi/ipr.c | 27 +++--- drivers/scsi/ips.c | 8 +- drivers/scsi/isci/request.c | 42 drivers/scsi/libfc/fc_libfc.c | 49 ++ drivers/scsi/libiscsi_tcp.c | 32 --- drivers/scsi/megaraid.c | 9 +- drivers/scsi/mvsas/mv_sas.c | 10 +- drivers/scsi/pmcraid.c | 19 ++-- drivers/staging/unisys/visorhba/visorhba_main.c | 12 ++- drivers/target/iscsi/iscsi_target.c | 27 -- drivers/target/target_core_rd.c | 3 +- drivers/target/tar
[PATCH 08/22] crypto: chcr: Make use of the new sg_map helper function
The get_page in this area looks *highly* suspect due to there being no corresponding put_page. However, I've left that as is to avoid breaking things. I've also removed the KMAP_ATOMIC_ARGS check as it appears to be dead code that dates back to when it was first committed... Signed-off-by: Logan Gunthorpe --- drivers/crypto/chelsio/chcr_algo.c | 28 +++- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 41bc7f4..a993d1d 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -1489,22 +1489,21 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, return ERR_PTR(-EINVAL); } -static void aes_gcm_empty_pld_pad(struct scatterlist *sg, - unsigned short offset) +static int aes_gcm_empty_pld_pad(struct scatterlist *sg, +unsigned short offset) { - struct page *spage; unsigned char *addr; - spage = sg_page(sg); - get_page(spage); /* so that it is not freed by NIC */ -#ifdef KMAP_ATOMIC_ARGS - addr = kmap_atomic(spage, KM_SOFTIRQ0); -#else - addr = kmap_atomic(spage); -#endif - memset(addr + sg->offset, 0, offset + 1); + get_page(sg_page(sg)); /* so that it is not freed by NIC */ + + addr = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(addr)) + return PTR_ERR(addr); + + memset(addr, 0, offset + 1); + sg_unmap(sg, addr, SG_KMAP_ATOMIC); - kunmap_atomic(addr); + return 0; } static int set_msg_len(u8 *block, unsigned int msglen, int csize) @@ -1940,7 +1939,10 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, if (req->cryptlen) { write_sg_to_skb(skb, &frags, src, req->cryptlen); } else { - aes_gcm_empty_pld_pad(req->dst, authsize - 1); + err = aes_gcm_empty_pld_pad(req->dst, authsize - 1); + if (err) + goto dstmap_fail; + write_sg_to_skb(skb, &frags, reqctx->dst, crypt_len); } -- 2.1.4
[PATCH 17/22] mmc: sdhci: Make use of the new sg_map helper function
Straightforward conversion, except due to the lack of error path we have to WARN if the memory in the SGL is not mappable. Signed-off-by: Logan Gunthorpe --- drivers/mmc/host/sdhci.c | 35 ++- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 63bc33a..af0c107 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -497,15 +497,34 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, return sg_count; } +/* + * Note this function may return PTR_ERR and must be checked. + */ static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags) { + void *ret; + local_irq_save(*flags); - return kmap_atomic(sg_page(sg)) + sg->offset; + + ret = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(ret)) { + /* +* This should really never happen unless the code is changed +* to use memory that is not mappable in the sg. Seeing there +* doesn't seem to be any error path out of here, we can only +* WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + local_irq_restore(*flags); + } + + return ret; } -static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags) +static void sdhci_kunmap_atomic(struct scatterlist *sg, void *buffer, + unsigned long *flags) { - kunmap_atomic(buffer); + sg_unmap(sg, buffer, SG_KMAP_ATOMIC); local_irq_restore(*flags); } @@ -568,8 +587,11 @@ static void sdhci_adma_table_pre(struct sdhci_host *host, if (offset) { if (data->flags & MMC_DATA_WRITE) { buffer = sdhci_kmap_atomic(sg, &flags); + if (IS_ERR(buffer)) + return; + memcpy(align, buffer, offset); - sdhci_kunmap_atomic(buffer, &flags); + sdhci_kunmap_atomic(sg, buffer, &flags); } /* tran, valid */ @@ -646,8 +668,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, (sg_dma_address(sg) & SDHCI_ADMA2_MASK); buffer = sdhci_kmap_atomic(sg, &flags); + if (IS_ERR(buffer)) + return; + memcpy(buffer, align, size); - sdhci_kunmap_atomic(buffer, &flags); + sdhci_kunmap_atomic(sg, buffer, &flags); align += SDHCI_ADMA2_ALIGN; } -- 2.1.4
[PATCH 21/22] mmc: tifm_sd: Make use of the new sg_map helper function
This conversion is a bit complicated. We modiy the read_fifo, write_fifo and copy_page functions to take a scatterlist instead of a page. Thus we can use sg_map instead of kmap_atomic. There's a bit of accounting that needed to be done for the offset for this to work. (Seeing sg_map takes care of the offset but it's already added and used earlier in the code. There's also no error path, so if unmappable memory finds its way into the sgl we can only WARN. Signed-off-by: Logan Gunthorpe --- drivers/mmc/host/tifm_sd.c | 88 +++--- 1 file changed, 67 insertions(+), 21 deletions(-) diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 93c4b40..75b0d74 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -111,14 +111,26 @@ struct tifm_sd { }; /* for some reason, host won't respond correctly to readw/writew */ -static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, +static void tifm_sd_read_fifo(struct tifm_sd *host, struct scatterlist *sg, unsigned int off, unsigned int cnt) { struct tifm_dev *sock = host->dev; unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = sg_map_offset(sg, off - sg->offset, SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return; + } + if (host->cmd_flags & DATA_CARRY) { buf[pos++] = host->bounce_buf_data[0]; host->cmd_flags &= ~DATA_CARRY; @@ -134,17 +146,29 @@ static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg, } buf[pos++] = (val >> 8) & 0xff; } - kunmap_atomic(buf - off); + sg_unmap_offset(sg, buf, off - sg->offset, SG_KMAP_ATOMIC); } -static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, +static void tifm_sd_write_fifo(struct tifm_sd *host, struct scatterlist *sg, unsigned int off, unsigned int cnt) { struct tifm_dev *sock = host->dev; unsigned char *buf; unsigned int pos = 0, val; - buf = kmap_atomic(pg) + off; + buf = sg_map_offset(sg, off - sg->offset, SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return; + } + if (host->cmd_flags & DATA_CARRY) { val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00); writel(val, sock->addr + SOCK_MMCSD_DATA); @@ -161,7 +185,7 @@ static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg, val |= (buf[pos++] << 8) & 0xff00; writel(val, sock->addr + SOCK_MMCSD_DATA); } - kunmap_atomic(buf - off); + sg_unmap_offset(sg, buf, off - sg->offset, SG_KMAP_ATOMIC); } static void tifm_sd_transfer_data(struct tifm_sd *host) @@ -170,7 +194,6 @@ static void tifm_sd_transfer_data(struct tifm_sd *host) struct scatterlist *sg = r_data->sg; unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2; unsigned int p_off, p_cnt; - struct page *pg; if (host->sg_pos == host->sg_len) return; @@ -192,33 +215,57 @@ static void tifm_sd_transfer_data(struct tifm_sd *host) } off = sg[host->sg_pos].offset + host->block_pos; - pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT); p_off = offset_in_page(off); p_cnt = PAGE_SIZE - p_off; p_cnt = min(p_cnt, cnt); p_cnt = min(p_cnt, t_size); if (r_data->flags & MMC_DATA_READ) - tifm_sd_read_fifo(host, pg, p_off, p_cnt); + tifm_sd_read_fifo(host, &sg[host->sg_pos], p_off, + p_cnt); else if (r_data->flags & MMC_DATA_WRITE) - tifm_sd_write_fifo(host, pg, p_off, p_cnt); + tifm_sd_write_fifo(host, &sg[host->sg_pos], p_off, +
[PATCH 09/22] dm-crypt: Make use of the new sg_map helper in 4 call sites
Very straightforward conversion to the new function in all four spots. Signed-off-by: Logan Gunthorpe --- drivers/md/dm-crypt.c | 38 +- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 389a363..6bd0ffc 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -589,9 +589,12 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv, int r = 0; if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) { - src = kmap_atomic(sg_page(&dmreq->sg_in)); - r = crypt_iv_lmk_one(cc, iv, dmreq, src + dmreq->sg_in.offset); - kunmap_atomic(src); + src = sg_map(&dmreq->sg_in, SG_KMAP_ATOMIC); + if (IS_ERR(src)) + return PTR_ERR(src); + + r = crypt_iv_lmk_one(cc, iv, dmreq, src); + sg_unmap(&dmreq->sg_in, src, SG_KMAP_ATOMIC); } else memset(iv, 0, cc->iv_size); @@ -607,14 +610,17 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv, if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) return 0; - dst = kmap_atomic(sg_page(&dmreq->sg_out)); - r = crypt_iv_lmk_one(cc, iv, dmreq, dst + dmreq->sg_out.offset); + dst = sg_map(&dmreq->sg_out, SG_KMAP_ATOMIC); + if (IS_ERR(dst)) + return PTR_ERR(dst); + + r = crypt_iv_lmk_one(cc, iv, dmreq, dst); /* Tweak the first block of plaintext sector */ if (!r) - crypto_xor(dst + dmreq->sg_out.offset, iv, cc->iv_size); + crypto_xor(dst, iv, cc->iv_size); - kunmap_atomic(dst); + sg_unmap(&dmreq->sg_out, dst, SG_KMAP_ATOMIC); return r; } @@ -731,9 +737,12 @@ static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 *iv, /* Remove whitening from ciphertext */ if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) { - src = kmap_atomic(sg_page(&dmreq->sg_in)); - r = crypt_iv_tcw_whitening(cc, dmreq, src + dmreq->sg_in.offset); - kunmap_atomic(src); + src = sg_map(&dmreq->sg_in, SG_KMAP_ATOMIC); + if (IS_ERR(src)) + return PTR_ERR(src); + + r = crypt_iv_tcw_whitening(cc, dmreq, src); + sg_unmap(&dmreq->sg_in, src, SG_KMAP_ATOMIC); } /* Calculate IV */ @@ -755,9 +764,12 @@ static int crypt_iv_tcw_post(struct crypt_config *cc, u8 *iv, return 0; /* Apply whitening on ciphertext */ - dst = kmap_atomic(sg_page(&dmreq->sg_out)); - r = crypt_iv_tcw_whitening(cc, dmreq, dst + dmreq->sg_out.offset); - kunmap_atomic(dst); + dst = sg_map(&dmreq->sg_out, SG_KMAP_ATOMIC); + if (IS_ERR(dst)) + return PTR_ERR(dst); + + r = crypt_iv_tcw_whitening(cc, dmreq, dst); + sg_unmap(&dmreq->sg_out, dst, SG_KMAP_ATOMIC); return r; } -- 2.1.4
[PATCH 20/22] mmc: sdricoh_cs: Make use of the new sg_map helper function
This is a straightforward conversion to the new function. Signed-off-by: Logan Gunthorpe --- drivers/mmc/host/sdricoh_cs.c | 14 +- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 5ff26ab..7eeed23 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -319,16 +319,20 @@ static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq) for (i = 0; i < data->blocks; i++) { size_t len = data->blksz; u8 *buf; - struct page *page; int result; - page = sg_page(data->sg); - buf = kmap(page) + data->sg->offset + (len * i); + buf = sg_map_offset(data->sg, (len * i), SG_KMAP); + if (IS_ERR(buf)) { + cmd->error = PTR_ERR(buf); + break; + } + result = sdricoh_blockio(host, data->flags & MMC_DATA_READ, buf, len); - kunmap(page); - flush_dcache_page(page); + sg_unmap_offset(data->sg, buf, (len * i), SG_KMAP); + + flush_dcache_page(sg_page(data->sg)); if (result) { dev_err(dev, "sdricoh_request: cmd %i " "block transfer failed\n", cmd->opcode); -- 2.1.4
[PATCH 14/22] scsi: arcmsr, ips, megaraid: Make use of the new sg_map helper function
Very straightforward conversion of three scsi drivers Signed-off-by: Logan Gunthorpe --- drivers/scsi/arcmsr/arcmsr_hba.c | 16 drivers/scsi/ips.c | 8 drivers/scsi/megaraid.c | 9 +++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index af032c4..3cd485c 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -2306,7 +2306,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, use_sg = scsi_sg_count(cmd); sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; + buffer = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(buffer)) + return ARCMSR_MESSAGE_FAIL; + if (use_sg > 1) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; @@ -2539,7 +2542,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, message_out: if (use_sg) { struct scatterlist *sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); + sg_unmap(sg, buffer, SG_KMAP_ATOMIC); } return retvalue; } @@ -2590,11 +2593,16 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, strncpy(&inqdata[32], "R001", 4); /* Product Revision */ sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; + buffer = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(buffer)) { + cmd->result = (DID_ERROR << 16); + cmd->scsi_done(cmd); + return; + } memcpy(buffer, inqdata, sizeof(inqdata)); sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); + sg_unmap(sg, buffer, SG_KMAP_ATOMIC); cmd->scsi_done(cmd); } diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 3419e1b..a44291d 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -1506,14 +1506,14 @@ static int ips_is_passthru(struct scsi_cmnd *SC) /* kmap_atomic() ensures addressability of the user buffer.*/ /* local_irq_save() protects the KM_IRQ0 address slot. */ local_irq_save(flags); -buffer = kmap_atomic(sg_page(sg)) + sg->offset; -if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && +buffer = sg_map(sg, SG_KMAP_ATOMIC); +if (!IS_ERR(buffer) && buffer[0] == 'C' && buffer[1] == 'O' && buffer[2] == 'P' && buffer[3] == 'P') { -kunmap_atomic(buffer - sg->offset); +sg_unmap(sg, buffer, SG_KMAP_ATOMIC); local_irq_restore(flags); return 1; } -kunmap_atomic(buffer - sg->offset); +sg_unmap(sg, buffer, SG_KMAP_ATOMIC); local_irq_restore(flags); } return 0; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 3c63c29..0b66e50 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -663,10 +663,15 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) struct scatterlist *sg; sg = scsi_sglist(cmd); - buf = kmap_atomic(sg_page(sg)) + sg->offset; + buf = sg_map(sg, SG_KMAP_ATOMIC); + if (IS_ERR(buf)) { +cmd->result = (DID_ERROR << 16); + cmd->scsi_done(cmd); + return NULL; + } memset(buf, 0, cmd->cmnd[4]); - kunmap_atomic(buf - sg->offset); + sg_unmap(sg, buf, SG_KMAP_ATOMIC); cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); -- 2.1.4
[PATCH 02/22] nvmet: Make use of the new sg_map helper function
This is a straight forward conversion in two places. Should kmap fail, the code will return an INVALD_DATA error in the completion. Signed-off-by: Logan Gunthorpe --- drivers/nvme/target/fabrics-cmd.c | 16 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c index 8bd022af..f62a634 100644 --- a/drivers/nvme/target/fabrics-cmd.c +++ b/drivers/nvme/target/fabrics-cmd.c @@ -122,7 +122,11 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) struct nvmet_ctrl *ctrl = NULL; u16 status = 0; - d = kmap(sg_page(req->sg)) + req->sg->offset; + d = sg_map(req->sg, SG_KMAP); + if (IS_ERR(d)) { + status = NVME_SC_SGL_INVALID_DATA; + goto out; + } /* zero out initial completion result, assign values as needed */ req->rsp->result.u32 = 0; @@ -158,7 +162,7 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) req->rsp->result.u16 = cpu_to_le16(ctrl->cntlid); out: - kunmap(sg_page(req->sg)); + sg_unmap(req->sg, d, SG_KMAP); nvmet_req_complete(req, status); } @@ -170,7 +174,11 @@ static void nvmet_execute_io_connect(struct nvmet_req *req) u16 qid = le16_to_cpu(c->qid); u16 status = 0; - d = kmap(sg_page(req->sg)) + req->sg->offset; + d = sg_map(req->sg, SG_KMAP); + if (IS_ERR(d)) { + status = NVME_SC_SGL_INVALID_DATA; + goto out; + } /* zero out initial completion result, assign values as needed */ req->rsp->result.u32 = 0; @@ -205,7 +213,7 @@ static void nvmet_execute_io_connect(struct nvmet_req *req) pr_info("adding queue %d to ctrl %d.\n", qid, ctrl->cntlid); out: - kunmap(sg_page(req->sg)); + sg_unmap(req->sg, d, SG_KMAP); nvmet_req_complete(req, status); return; -- 2.1.4
[PATCH 13/22] scsi: hisi_sas, mvsas, gdth: Make use of the new sg_map helper function
Very straightforward conversion of three scsi drivers. Signed-off-by: Logan Gunthorpe --- drivers/scsi/gdth.c| 9 +++-- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 14 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 + drivers/scsi/mvsas/mv_sas.c| 10 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index d020a13..82c9fba 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -2301,10 +2301,15 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, return; } local_irq_save(flags); -address = kmap_atomic(sg_page(sl)) + sl->offset; +address = sg_map(sl, SG_KMAP_ATOMIC); +if (IS_ERR(address)) { +scp->result = DID_ERROR << 16; +return; + } + memcpy(address, buffer, cpnow); flush_dcache_page(sg_page(sl)); -kunmap_atomic(address); +sg_unmap(sl, address, SG_KMAP_ATOMIC); local_irq_restore(flags); if (cpsum == cpcount) break; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 854fbea..30408f8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1377,18 +1377,22 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, void *to; struct scatterlist *sg_resp = &task->smp_task.smp_resp; - ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); + to = sg_map(sg_resp, SG_KMAP_ATOMIC); + if (IS_ERR(to)) { + dev_err(dev, "slot complete: error mapping memory"); + ts->stat = SAS_SG_ERR; + break; + } + ts->stat = SAM_STAT_GOOD; dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); - memcpy(to + sg_resp->offset, - slot->status_buffer + + memcpy(to, slot->status_buffer + sizeof(struct hisi_sas_err_record), sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_unmap(sg_resp, to, SG_KMAP_ATOMIC); break; } case SAS_PROTOCOL_SATA: diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 1b21445..0907947 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -1796,18 +1796,23 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, struct scatterlist *sg_resp = &task->smp_task.smp_resp; void *to; + to = sg_map(sg_resp, SG_KMAP_ATOMIC); + if (IS_ERR(to)) { + dev_err(dev, "slot complete: error mapping memory"); + ts->stat = SAS_SG_ERR; + break; + } + ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); - memcpy(to + sg_resp->offset, - slot->status_buffer + + memcpy(to, slot->status_buffer + sizeof(struct hisi_sas_err_record), sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_unmap(sg_resp, to, SG_KMAP_ATOMIC); break; } case SAS_PROTOCOL_SATA: diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index c7cc803..374d0e0 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1798,11 +1798,11 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) case SAS_PROTOCOL_SMP: { struct scatterlist *sg_resp = &task->smp_task.smp_resp; tstat->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); - memcpy(to + sg_resp->offset, - slot->response + sizeof(struct mvs_err_info), - sg_dma_len(sg_resp)); - kunmap_atomic(to); + to = sg_map(sg_resp, SG_KMAP_ATOMIC); + memcpy(to, + slot->response +
[PATCH 11/22] RDS: Make use of the new sg_map helper function
Straightforward conversion except there's no error path, so we WARN if the sg_map fails. Signed-off-by: Logan Gunthorpe --- net/rds/ib_recv.c | 17 ++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index e10624a..7f8fa99 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -801,9 +801,20 @@ static void rds_ib_cong_recv(struct rds_connection *conn, to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off); BUG_ON(to_copy & 7); /* Must be 64bit aligned. */ - addr = kmap_atomic(sg_page(&frag->f_sg)); + addr = sg_map(&frag->f_sg, SG_KMAP_ATOMIC); + if (IS_ERR(addr)) { + /* +* This should really never happen unless +* the code is changed to use memory that is +* not mappable in the sg. Seeing there doesn't +* seem to be any error path out of here, +* we can only WARN. +*/ + WARN(1, "Non-mappable memory used in sg!"); + return; + } - src = addr + frag->f_sg.offset + frag_off; + src = addr + frag_off; dst = (void *)map->m_page_addrs[map_page] + map_off; for (k = 0; k < to_copy; k += 8) { /* Record ports that became uncongested, ie @@ -811,7 +822,7 @@ static void rds_ib_cong_recv(struct rds_connection *conn, uncongested |= ~(*src) & *dst; *dst++ = *src++; } - kunmap_atomic(addr); + sg_unmap(&frag->f_sg, addr, SG_KMAP_ATOMIC); copied += to_copy; -- 2.1.4
[PATCH 06/22] crypto: hifn_795x: Make use of the new sg_map helper function
Conversion of a couple kmap_atomic instances to the sg_map helper function. However, it looks like there was a bug in the original code: the source scatter lists offset (t->offset) was passed to ablkcipher_get which added it to the destination address. This doesn't make a lot of sense, but t->offset is likely always zero anyway. So, this patch cleans that brokeness up. Also, a change to the error path: if ablkcipher_get failed, everything seemed to proceed as if it hadn't. Setting 'error' should hopefully clear that up. Signed-off-by: Logan Gunthorpe --- drivers/crypto/hifn_795x.c | 32 +--- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index e09d405..8e2c6a9 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -1619,7 +1619,7 @@ static int hifn_start_device(struct hifn_device *dev) return 0; } -static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset, +static int ablkcipher_get(void *saddr, unsigned int *srestp, struct scatterlist *dst, unsigned int size, unsigned int *nbytesp) { unsigned int srest = *srestp, nbytes = *nbytesp, copy; @@ -1632,15 +1632,17 @@ static int ablkcipher_get(void *saddr, unsigned int *srestp, unsigned int offset while (size) { copy = min3(srest, dst->length, size); - daddr = kmap_atomic(sg_page(dst)); - memcpy(daddr + dst->offset + offset, saddr, copy); - kunmap_atomic(daddr); + daddr = sg_map(dst, SG_KMAP_ATOMIC); + if (IS_ERR(daddr)) + return PTR_ERR(daddr); + + memcpy(daddr, saddr, copy); + sg_unmap(dst, daddr, SG_KMAP_ATOMIC); nbytes -= copy; size -= copy; srest -= copy; saddr += copy; - offset = 0; pr_debug("%s: copy: %u, size: %u, srest: %u, nbytes: %u.\n", __func__, copy, size, srest, nbytes); @@ -1671,11 +1673,12 @@ static inline void hifn_complete_sa(struct hifn_device *dev, int i) static void hifn_process_ready(struct ablkcipher_request *req, int error) { + int err; struct hifn_request_context *rctx = ablkcipher_request_ctx(req); if (rctx->walk.flags & ASYNC_FLAGS_MISALIGNED) { unsigned int nbytes = req->nbytes; - int idx = 0, err; + int idx = 0; struct scatterlist *dst, *t; void *saddr; @@ -1695,17 +1698,24 @@ static void hifn_process_ready(struct ablkcipher_request *req, int error) continue; } - saddr = kmap_atomic(sg_page(t)); + saddr = sg_map(t, SG_KMAP_ATOMIC); + if (IS_ERR(saddr)) { + if (!error) + error = PTR_ERR(saddr); + break; + } + + err = ablkcipher_get(saddr, &t->length, +dst, nbytes, &nbytes); + sg_unmap(t, saddr, SG_KMAP_ATOMIC); - err = ablkcipher_get(saddr, &t->length, t->offset, - dst, nbytes, &nbytes); if (err < 0) { - kunmap_atomic(saddr); + if (!error) + error = err; break; } idx += err; - kunmap_atomic(saddr); } hifn_cipher_walk_exit(&rctx->walk); -- 2.1.4