[SCSI] block: add sg buffer copy helper functions
This patch adds new three helper functions to copy data between an SG list and a linear buffer. - sg_copy_from_buffer copies data from linear buffer to an SG list - sg_copy_to_buffer copies data from an SG list to a linear buffer When the APIs copy data from a linear buffer to an SG list, flush_kernel_dcache_page is called. It's not necessary for everyone but it's a no-op on most architectures and in general the API is not used in performance critical path. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Acked-by: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
		
					parent
					
						
							
								78b4b05db5
							
						
					
				
			
			
				commit
				
					
						b1adaf65ba
					
				
			
		
					 2 changed files with 107 additions and 0 deletions
				
			
		|  | @ -213,6 +213,11 @@ int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, gfp_t, | ||||||
| 		     sg_alloc_fn *); | 		     sg_alloc_fn *); | ||||||
| int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); | int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); | ||||||
| 
 | 
 | ||||||
|  | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, | ||||||
|  | 			   void *buf, size_t buflen); | ||||||
|  | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | ||||||
|  | 			 void *buf, size_t buflen); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Maximum number of entries that will be allocated in one piece, if |  * Maximum number of entries that will be allocated in one piece, if | ||||||
|  * a list larger than this is required then chaining will be utilized. |  * a list larger than this is required then chaining will be utilized. | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
|  */ |  */ | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/scatterlist.h> | #include <linux/scatterlist.h> | ||||||
|  | #include <linux/highmem.h> | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * sg_next - return the next scatterlist entry in a list |  * sg_next - return the next scatterlist entry in a list | ||||||
|  | @ -292,3 +293,104 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(sg_alloc_table); | EXPORT_SYMBOL(sg_alloc_table); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * sg_copy_buffer - Copy data between a linear buffer and an SG list | ||||||
|  |  * @sgl:		 The SG list | ||||||
|  |  * @nents:		 Number of SG entries | ||||||
|  |  * @buf:		 Where to copy from | ||||||
|  |  * @buflen:		 The number of bytes to copy | ||||||
|  |  * @to_buffer: 		 transfer direction (non zero == from an sg list to a | ||||||
|  |  * 			 buffer, 0 == from a buffer to an sg list | ||||||
|  |  * | ||||||
|  |  * Returns the number of copied bytes. | ||||||
|  |  * | ||||||
|  |  **/ | ||||||
|  | static size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, | ||||||
|  | 			     void *buf, size_t buflen, int to_buffer) | ||||||
|  | { | ||||||
|  | 	struct scatterlist *sg; | ||||||
|  | 	size_t buf_off = 0; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	WARN_ON(!irqs_disabled()); | ||||||
|  | 
 | ||||||
|  | 	for_each_sg(sgl, sg, nents, i) { | ||||||
|  | 		struct page *page; | ||||||
|  | 		int n = 0; | ||||||
|  | 		unsigned int sg_off = sg->offset; | ||||||
|  | 		unsigned int sg_copy = sg->length; | ||||||
|  | 
 | ||||||
|  | 		if (sg_copy > buflen) | ||||||
|  | 			sg_copy = buflen; | ||||||
|  | 		buflen -= sg_copy; | ||||||
|  | 
 | ||||||
|  | 		while (sg_copy > 0) { | ||||||
|  | 			unsigned int page_copy; | ||||||
|  | 			void *p; | ||||||
|  | 
 | ||||||
|  | 			page_copy = PAGE_SIZE - sg_off; | ||||||
|  | 			if (page_copy > sg_copy) | ||||||
|  | 				page_copy = sg_copy; | ||||||
|  | 
 | ||||||
|  | 			page = nth_page(sg_page(sg), n); | ||||||
|  | 			p = kmap_atomic(page, KM_BIO_SRC_IRQ); | ||||||
|  | 
 | ||||||
|  | 			if (to_buffer) | ||||||
|  | 				memcpy(buf + buf_off, p + sg_off, page_copy); | ||||||
|  | 			else { | ||||||
|  | 				memcpy(p + sg_off, buf + buf_off, page_copy); | ||||||
|  | 				flush_kernel_dcache_page(page); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			kunmap_atomic(p, KM_BIO_SRC_IRQ); | ||||||
|  | 
 | ||||||
|  | 			buf_off += page_copy; | ||||||
|  | 			sg_off += page_copy; | ||||||
|  | 			if (sg_off == PAGE_SIZE) { | ||||||
|  | 				sg_off = 0; | ||||||
|  | 				n++; | ||||||
|  | 			} | ||||||
|  | 			sg_copy -= page_copy; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!buflen) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return buf_off; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * sg_copy_from_buffer - Copy from a linear buffer to an SG list | ||||||
|  |  * @sgl:		 The SG list | ||||||
|  |  * @nents:		 Number of SG entries | ||||||
|  |  * @buf:		 Where to copy from | ||||||
|  |  * @buflen:		 The number of bytes to copy | ||||||
|  |  * | ||||||
|  |  * Returns the number of copied bytes. | ||||||
|  |  * | ||||||
|  |  **/ | ||||||
|  | size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, | ||||||
|  | 			   void *buf, size_t buflen) | ||||||
|  | { | ||||||
|  | 	return sg_copy_buffer(sgl, nents, buf, buflen, 0); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(sg_copy_from_buffer); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * sg_copy_to_buffer - Copy from an SG list to a linear buffer | ||||||
|  |  * @sgl:		 The SG list | ||||||
|  |  * @nents:		 Number of SG entries | ||||||
|  |  * @buf:		 Where to copy to | ||||||
|  |  * @buflen:		 The number of bytes to copy | ||||||
|  |  * | ||||||
|  |  * Returns the number of copied bytes. | ||||||
|  |  * | ||||||
|  |  **/ | ||||||
|  | size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, | ||||||
|  | 			 void *buf, size_t buflen) | ||||||
|  | { | ||||||
|  | 	return sg_copy_buffer(sgl, nents, buf, buflen, 1); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(sg_copy_to_buffer); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 FUJITA Tomonori
				FUJITA Tomonori