mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	[iov_iter] new privimitive: iov_iter_revert()
opposite to iov_iter_advance(); the caller is responsible for never using it to move back past the initial position. Cc: stable@vger.kernel.org Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									c02ed2e75e
								
							
						
					
					
						commit
						27c0e3748e
					
				
					 2 changed files with 68 additions and 1 deletions
				
			
		| 
						 | 
					@ -39,7 +39,10 @@ struct iov_iter {
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		unsigned long nr_segs;
 | 
							unsigned long nr_segs;
 | 
				
			||||||
		int idx;
 | 
							struct {
 | 
				
			||||||
 | 
								int idx;
 | 
				
			||||||
 | 
								int start_idx;
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,6 +84,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to);
 | 
				
			||||||
size_t iov_iter_copy_from_user_atomic(struct page *page,
 | 
					size_t iov_iter_copy_from_user_atomic(struct page *page,
 | 
				
			||||||
		struct iov_iter *i, unsigned long offset, size_t bytes);
 | 
							struct iov_iter *i, unsigned long offset, size_t bytes);
 | 
				
			||||||
void iov_iter_advance(struct iov_iter *i, size_t bytes);
 | 
					void iov_iter_advance(struct iov_iter *i, size_t bytes);
 | 
				
			||||||
 | 
					void iov_iter_revert(struct iov_iter *i, size_t bytes);
 | 
				
			||||||
int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
 | 
					int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes);
 | 
				
			||||||
size_t iov_iter_single_seg_count(const struct iov_iter *i);
 | 
					size_t iov_iter_single_seg_count(const struct iov_iter *i);
 | 
				
			||||||
size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
 | 
					size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -786,6 +786,68 @@ void iov_iter_advance(struct iov_iter *i, size_t size)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(iov_iter_advance);
 | 
					EXPORT_SYMBOL(iov_iter_advance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void iov_iter_revert(struct iov_iter *i, size_t unroll)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!unroll)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						i->count += unroll;
 | 
				
			||||||
 | 
						if (unlikely(i->type & ITER_PIPE)) {
 | 
				
			||||||
 | 
							struct pipe_inode_info *pipe = i->pipe;
 | 
				
			||||||
 | 
							int idx = i->idx;
 | 
				
			||||||
 | 
							size_t off = i->iov_offset;
 | 
				
			||||||
 | 
							while (1) {
 | 
				
			||||||
 | 
								size_t n = off - pipe->bufs[idx].offset;
 | 
				
			||||||
 | 
								if (unroll < n) {
 | 
				
			||||||
 | 
									off -= (n - unroll);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								unroll -= n;
 | 
				
			||||||
 | 
								if (!unroll && idx == i->start_idx) {
 | 
				
			||||||
 | 
									off = 0;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (!idx--)
 | 
				
			||||||
 | 
									idx = pipe->buffers - 1;
 | 
				
			||||||
 | 
								off = pipe->bufs[idx].offset + pipe->bufs[idx].len;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i->iov_offset = off;
 | 
				
			||||||
 | 
							i->idx = idx;
 | 
				
			||||||
 | 
							pipe_truncate(i);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (unroll <= i->iov_offset) {
 | 
				
			||||||
 | 
							i->iov_offset -= unroll;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						unroll -= i->iov_offset;
 | 
				
			||||||
 | 
						if (i->type & ITER_BVEC) {
 | 
				
			||||||
 | 
							const struct bio_vec *bvec = i->bvec;
 | 
				
			||||||
 | 
							while (1) {
 | 
				
			||||||
 | 
								size_t n = (--bvec)->bv_len;
 | 
				
			||||||
 | 
								i->nr_segs++;
 | 
				
			||||||
 | 
								if (unroll <= n) {
 | 
				
			||||||
 | 
									i->bvec = bvec;
 | 
				
			||||||
 | 
									i->iov_offset = n - unroll;
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								unroll -= n;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else { /* same logics for iovec and kvec */
 | 
				
			||||||
 | 
							const struct iovec *iov = i->iov;
 | 
				
			||||||
 | 
							while (1) {
 | 
				
			||||||
 | 
								size_t n = (--iov)->iov_len;
 | 
				
			||||||
 | 
								i->nr_segs++;
 | 
				
			||||||
 | 
								if (unroll <= n) {
 | 
				
			||||||
 | 
									i->iov = iov;
 | 
				
			||||||
 | 
									i->iov_offset = n - unroll;
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								unroll -= n;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(iov_iter_revert);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Return the count of just the current iov_iter segment.
 | 
					 * Return the count of just the current iov_iter segment.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -839,6 +901,7 @@ void iov_iter_pipe(struct iov_iter *i, int direction,
 | 
				
			||||||
	i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
 | 
						i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
 | 
				
			||||||
	i->iov_offset = 0;
 | 
						i->iov_offset = 0;
 | 
				
			||||||
	i->count = count;
 | 
						i->count = count;
 | 
				
			||||||
 | 
						i->start_idx = i->idx;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(iov_iter_pipe);
 | 
					EXPORT_SYMBOL(iov_iter_pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue