Skip to content

Commit

Permalink
PCI/P2PDMA: Introduce pci_p2pdmae_submit_bio() helper
Browse files Browse the repository at this point in the history
Seeing we don't want to impose the cost of additional checks for on
the majority of submit_bio() we add some checks for P2P bios in a
separate wrapper function called pci_p2pdma_submit_bio().

This is a tradeoff between safety and speed: if we added the checks
to the common submit_bio(), driver authors would be forced to always
do the right thing. However, that would impose a small cost on the
majority of submit_bio() users who don't care about P2P.

Instead, we will rely on review to ensure code that is using P2PDMA
and the block layer use the new helper. Those drivers that don't
will be very subtly wrong and will have subtle bugs especially
on non-x86 architectures.

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
  • Loading branch information
lsgunth committed Sep 6, 2018
1 parent 93b9de4 commit eeabe0b
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
35 changes: 35 additions & 0 deletions drivers/pci/p2pdma.c
Expand Up @@ -9,6 +9,7 @@
*/

#define pr_fmt(fmt) "pci-p2pdma: " fmt
#include <linux/blkdev.h>
#include <linux/ctype.h>
#include <linux/pci-p2pdma.h>
#include <linux/module.h>
Expand Down Expand Up @@ -939,3 +940,37 @@ ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev,
return sprintf(page, "%s\n", pci_name(p2p_dev));
}
EXPORT_SYMBOL_GPL(pci_p2pdma_enable_show);

#ifdef CONFIG_BLOCK

/**
* pci_p2pdma_submit_bio - submit a bio that may contain peer-to-peer memory
* @bio: bio to validate
*
* This function wraps submit_bio() and must be called for any bio that
* might contain P2P memory. It prepends additional checks for P2P memory
* and sets the NO_MERGE flag appropriately to ensure that such bios are not
* merged with those that have regular memory.
*/
blk_qc_t pci_p2pdma_submit_bio(struct bio *bio)
{
if (bio->bi_vcnt && is_pci_p2pdma_page(bio->bi_io_vec->bv_page)) {
/*
* This should never happen if the higher layers using
* P2PDMA do the right thing and use the proper P2PDMA
* client infrastructure.
*/
if (WARN_ON_ONCE(!blk_queue_pci_p2pdma(bio->bi_disk->queue))) {
bio->bi_status = BLK_STS_NOTSUPP;
bio_endio(bio);
return BLK_QC_T_NONE;
}

bio->bi_opf |= REQ_NOMERGE;
}

return submit_bio(bio);
}
EXPORT_SYMBOL_GPL(pci_p2pdma_submit_bio);

#endif
10 changes: 10 additions & 0 deletions include/linux/pci-p2pdma.h
Expand Up @@ -13,6 +13,7 @@
#define _LINUX_PCI_P2PDMA_H

#include <linux/pci.h>
#include <linux/bio.h>

struct block_device;
struct scatterlist;
Expand Down Expand Up @@ -42,6 +43,9 @@ int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev,
bool *use_p2pdma);
ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev,
bool use_p2pdma);
#ifdef CONFIG_BLOCK
blk_qc_t pci_p2pdma_submit_bio(struct bio *bio);
#endif
#else /* CONFIG_PCI_P2PDMA */
static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar,
size_t size, u64 offset)
Expand Down Expand Up @@ -120,5 +124,11 @@ static inline ssize_t pci_p2pdma_enable_show(char *page,
{
return sprintf(page, "none\n");
}
#ifdef CONFIG_BLOCK
static inline blk_qc_t pci_p2pdma_submit_bio(struct bio *bio)
{
return submit_bio(bio);
}
#endif
#endif /* CONFIG_PCI_P2PDMA */
#endif /* _LINUX_PCI_P2P_H */

0 comments on commit eeabe0b

Please sign in to comment.