Skip to content

Commit 9ea9ce0

Browse files
committed
iov_iter: Add I/O discard iterator
Add a new iterator, ITER_DISCARD, that can only be used in READ mode and just discards any data copied to it. This is useful in a network filesystem for discarding any unwanted data sent by a server. Signed-off-by: David Howells <dhowells@redhat.com>
1 parent aa563d7 commit 9ea9ce0

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

include/linux/uio.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ enum iter_type {
2626
ITER_KVEC = 2,
2727
ITER_BVEC = 4,
2828
ITER_PIPE = 8,
29+
ITER_DISCARD = 16,
2930
};
3031

3132
struct iov_iter {
@@ -72,6 +73,11 @@ static inline bool iov_iter_is_pipe(const struct iov_iter *i)
7273
return iov_iter_type(i) == ITER_PIPE;
7374
}
7475

76+
static inline bool iov_iter_is_discard(const struct iov_iter *i)
77+
{
78+
return iov_iter_type(i) == ITER_DISCARD;
79+
}
80+
7581
static inline unsigned char iov_iter_rw(const struct iov_iter *i)
7682
{
7783
return i->type & (READ | WRITE);
@@ -220,6 +226,7 @@ void iov_iter_bvec(struct iov_iter *i, unsigned int direction, const struct bio_
220226
unsigned long nr_segs, size_t count);
221227
void iov_iter_pipe(struct iov_iter *i, unsigned int direction, struct pipe_inode_info *pipe,
222228
size_t count);
229+
void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count);
223230
ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages,
224231
size_t maxsize, unsigned maxpages, size_t *start);
225232
ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages,

lib/iov_iter.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
const struct kvec *kvec; \
8484
struct kvec v; \
8585
iterate_kvec(i, n, v, kvec, skip, (K)) \
86+
} else if (unlikely(i->type & ITER_DISCARD)) { \
8687
} else { \
8788
const struct iovec *iov; \
8889
struct iovec v; \
@@ -114,6 +115,8 @@
114115
} \
115116
i->nr_segs -= kvec - i->kvec; \
116117
i->kvec = kvec; \
118+
} else if (unlikely(i->type & ITER_DISCARD)) { \
119+
skip += n; \
117120
} else { \
118121
const struct iovec *iov; \
119122
struct iovec v; \
@@ -838,7 +841,9 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
838841
size_t wanted = copy_to_iter(kaddr + offset, bytes, i);
839842
kunmap_atomic(kaddr);
840843
return wanted;
841-
} else if (likely(!iov_iter_is_pipe(i)))
844+
} else if (unlikely(iov_iter_is_discard(i)))
845+
return bytes;
846+
else if (likely(!iov_iter_is_pipe(i)))
842847
return copy_page_to_iter_iovec(page, offset, bytes, i);
843848
else
844849
return copy_page_to_iter_pipe(page, offset, bytes, i);
@@ -850,7 +855,7 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
850855
{
851856
if (unlikely(!page_copy_sane(page, offset, bytes)))
852857
return 0;
853-
if (unlikely(iov_iter_is_pipe(i))) {
858+
if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
854859
WARN_ON(1);
855860
return 0;
856861
}
@@ -910,7 +915,7 @@ size_t iov_iter_copy_from_user_atomic(struct page *page,
910915
kunmap_atomic(kaddr);
911916
return 0;
912917
}
913-
if (unlikely(iov_iter_is_pipe(i))) {
918+
if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
914919
kunmap_atomic(kaddr);
915920
WARN_ON(1);
916921
return 0;
@@ -978,6 +983,10 @@ void iov_iter_advance(struct iov_iter *i, size_t size)
978983
pipe_advance(i, size);
979984
return;
980985
}
986+
if (unlikely(iov_iter_is_discard(i))) {
987+
i->count -= size;
988+
return;
989+
}
981990
iterate_and_advance(i, size, v, 0, 0, 0)
982991
}
983992
EXPORT_SYMBOL(iov_iter_advance);
@@ -1013,6 +1022,8 @@ void iov_iter_revert(struct iov_iter *i, size_t unroll)
10131022
pipe_truncate(i);
10141023
return;
10151024
}
1025+
if (unlikely(iov_iter_is_discard(i)))
1026+
return;
10161027
if (unroll <= i->iov_offset) {
10171028
i->iov_offset -= unroll;
10181029
return;
@@ -1055,6 +1066,8 @@ size_t iov_iter_single_seg_count(const struct iov_iter *i)
10551066
return i->count; // it is a silly place, anyway
10561067
if (i->nr_segs == 1)
10571068
return i->count;
1069+
if (unlikely(iov_iter_is_discard(i)))
1070+
return i->count;
10581071
else if (iov_iter_is_bvec(i))
10591072
return min(i->count, i->bvec->bv_len - i->iov_offset);
10601073
else
@@ -1103,6 +1116,24 @@ void iov_iter_pipe(struct iov_iter *i, unsigned int direction,
11031116
}
11041117
EXPORT_SYMBOL(iov_iter_pipe);
11051118

1119+
/**
1120+
* iov_iter_discard - Initialise an I/O iterator that discards data
1121+
* @i: The iterator to initialise.
1122+
* @direction: The direction of the transfer.
1123+
* @count: The size of the I/O buffer in bytes.
1124+
*
1125+
* Set up an I/O iterator that just discards everything that's written to it.
1126+
* It's only available as a READ iterator.
1127+
*/
1128+
void iov_iter_discard(struct iov_iter *i, unsigned int direction, size_t count)
1129+
{
1130+
BUG_ON(direction != READ);
1131+
i->type = ITER_DISCARD | READ;
1132+
i->count = count;
1133+
i->iov_offset = 0;
1134+
}
1135+
EXPORT_SYMBOL(iov_iter_discard);
1136+
11061137
unsigned long iov_iter_alignment(const struct iov_iter *i)
11071138
{
11081139
unsigned long res = 0;
@@ -1127,7 +1158,7 @@ unsigned long iov_iter_gap_alignment(const struct iov_iter *i)
11271158
unsigned long res = 0;
11281159
size_t size = i->count;
11291160

1130-
if (unlikely(iov_iter_is_pipe(i))) {
1161+
if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
11311162
WARN_ON(1);
11321163
return ~0U;
11331164
}
@@ -1197,6 +1228,9 @@ ssize_t iov_iter_get_pages(struct iov_iter *i,
11971228

11981229
if (unlikely(iov_iter_is_pipe(i)))
11991230
return pipe_get_pages(i, pages, maxsize, maxpages, start);
1231+
if (unlikely(iov_iter_is_discard(i)))
1232+
return -EFAULT;
1233+
12001234
iterate_all_kinds(i, maxsize, v, ({
12011235
unsigned long addr = (unsigned long)v.iov_base;
12021236
size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
@@ -1274,6 +1308,9 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
12741308

12751309
if (unlikely(iov_iter_is_pipe(i)))
12761310
return pipe_get_pages_alloc(i, pages, maxsize, start);
1311+
if (unlikely(iov_iter_is_discard(i)))
1312+
return -EFAULT;
1313+
12771314
iterate_all_kinds(i, maxsize, v, ({
12781315
unsigned long addr = (unsigned long)v.iov_base;
12791316
size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1));
@@ -1315,7 +1352,7 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
13151352
__wsum sum, next;
13161353
size_t off = 0;
13171354
sum = *csum;
1318-
if (unlikely(iov_iter_is_pipe(i))) {
1355+
if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
13191356
WARN_ON(1);
13201357
return 0;
13211358
}
@@ -1357,7 +1394,7 @@ bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum,
13571394
__wsum sum, next;
13581395
size_t off = 0;
13591396
sum = *csum;
1360-
if (unlikely(iov_iter_is_pipe(i))) {
1397+
if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
13611398
WARN_ON(1);
13621399
return false;
13631400
}
@@ -1402,7 +1439,7 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum,
14021439
__wsum sum, next;
14031440
size_t off = 0;
14041441
sum = *csum;
1405-
if (unlikely(iov_iter_is_pipe(i))) {
1442+
if (unlikely(iov_iter_is_pipe(i) || iov_iter_is_discard(i))) {
14061443
WARN_ON(1); /* for now */
14071444
return 0;
14081445
}
@@ -1444,6 +1481,8 @@ int iov_iter_npages(const struct iov_iter *i, int maxpages)
14441481

14451482
if (!size)
14461483
return 0;
1484+
if (unlikely(iov_iter_is_discard(i)))
1485+
return 0;
14471486

14481487
if (unlikely(iov_iter_is_pipe(i))) {
14491488
struct pipe_inode_info *pipe = i->pipe;
@@ -1487,6 +1526,8 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
14871526
WARN_ON(1);
14881527
return NULL;
14891528
}
1529+
if (unlikely(iov_iter_is_discard(new)))
1530+
return NULL;
14901531
if (iov_iter_is_bvec(new))
14911532
return new->bvec = kmemdup(new->bvec,
14921533
new->nr_segs * sizeof(struct bio_vec),

0 commit comments

Comments
 (0)