Skip to content

Commit 2982c8c

Browse files
dhowellsbrauner
authored andcommitted
cifs: Use iterate_and_advance*() routines directly for hashing
Replace the bespoke cifs iterators of ITER_BVEC and ITER_KVEC to do hashing with iterate_and_advance_kernel() - a variant on iterate_and_advance() that only supports kernel-internal ITER_* types and not UBUF/IOVEC types. The bespoke ITER_XARRAY is left because we don't really want to be calling crypto_shash_update() under the RCU read lock for large amounts of data; besides, ITER_XARRAY is going to be phased out. Signed-off-by: David Howells <[email protected]> cc: Steve French <[email protected]> cc: Paulo Alcantara <[email protected]> cc: Tom Talpey <[email protected]> cc: Enzo Matsumiya <[email protected]> cc: [email protected] Link: https://lore.kernel.org/r/[email protected]/ # v2 Signed-off-by: Christian Brauner <[email protected]>
1 parent 8f246b7 commit 2982c8c

File tree

2 files changed

+70
-86
lines changed

2 files changed

+70
-86
lines changed

fs/smb/client/cifsencrypt.c

Lines changed: 23 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -21,82 +21,10 @@
2121
#include <linux/random.h>
2222
#include <linux/highmem.h>
2323
#include <linux/fips.h>
24+
#include <linux/iov_iter.h>
2425
#include "../common/arc4.h"
2526
#include <crypto/aead.h>
2627

27-
/*
28-
* Hash data from a BVEC-type iterator.
29-
*/
30-
static int cifs_shash_bvec(const struct iov_iter *iter, ssize_t maxsize,
31-
struct shash_desc *shash)
32-
{
33-
const struct bio_vec *bv = iter->bvec;
34-
unsigned long start = iter->iov_offset;
35-
unsigned int i;
36-
void *p;
37-
int ret;
38-
39-
for (i = 0; i < iter->nr_segs; i++) {
40-
size_t off, len;
41-
42-
len = bv[i].bv_len;
43-
if (start >= len) {
44-
start -= len;
45-
continue;
46-
}
47-
48-
len = min_t(size_t, maxsize, len - start);
49-
off = bv[i].bv_offset + start;
50-
51-
p = kmap_local_page(bv[i].bv_page);
52-
ret = crypto_shash_update(shash, p + off, len);
53-
kunmap_local(p);
54-
if (ret < 0)
55-
return ret;
56-
57-
maxsize -= len;
58-
if (maxsize <= 0)
59-
break;
60-
start = 0;
61-
}
62-
63-
return 0;
64-
}
65-
66-
/*
67-
* Hash data from a KVEC-type iterator.
68-
*/
69-
static int cifs_shash_kvec(const struct iov_iter *iter, ssize_t maxsize,
70-
struct shash_desc *shash)
71-
{
72-
const struct kvec *kv = iter->kvec;
73-
unsigned long start = iter->iov_offset;
74-
unsigned int i;
75-
int ret;
76-
77-
for (i = 0; i < iter->nr_segs; i++) {
78-
size_t len;
79-
80-
len = kv[i].iov_len;
81-
if (start >= len) {
82-
start -= len;
83-
continue;
84-
}
85-
86-
len = min_t(size_t, maxsize, len - start);
87-
ret = crypto_shash_update(shash, kv[i].iov_base + start, len);
88-
if (ret < 0)
89-
return ret;
90-
maxsize -= len;
91-
92-
if (maxsize <= 0)
93-
break;
94-
start = 0;
95-
}
96-
97-
return 0;
98-
}
99-
10028
/*
10129
* Hash data from an XARRAY-type iterator.
10230
*/
@@ -145,27 +73,36 @@ static ssize_t cifs_shash_xarray(const struct iov_iter *iter, ssize_t maxsize,
14573
return 0;
14674
}
14775

76+
static size_t cifs_shash_step(void *iter_base, size_t progress, size_t len,
77+
void *priv, void *priv2)
78+
{
79+
struct shash_desc *shash = priv;
80+
int ret, *pret = priv2;
81+
82+
ret = crypto_shash_update(shash, iter_base, len);
83+
if (ret < 0) {
84+
*pret = ret;
85+
return len;
86+
}
87+
return 0;
88+
}
89+
14890
/*
14991
* Pass the data from an iterator into a hash.
15092
*/
15193
static int cifs_shash_iter(const struct iov_iter *iter, size_t maxsize,
15294
struct shash_desc *shash)
15395
{
154-
if (maxsize == 0)
155-
return 0;
96+
struct iov_iter tmp_iter = *iter;
97+
int err = -EIO;
15698

157-
switch (iov_iter_type(iter)) {
158-
case ITER_BVEC:
159-
return cifs_shash_bvec(iter, maxsize, shash);
160-
case ITER_KVEC:
161-
return cifs_shash_kvec(iter, maxsize, shash);
162-
case ITER_XARRAY:
99+
if (iov_iter_type(iter) == ITER_XARRAY)
163100
return cifs_shash_xarray(iter, maxsize, shash);
164-
default:
165-
pr_err("cifs_shash_iter(%u) unsupported\n", iov_iter_type(iter));
166-
WARN_ON_ONCE(1);
167-
return -EIO;
168-
}
101+
102+
if (iterate_and_advance_kernel(&tmp_iter, maxsize, shash, &err,
103+
cifs_shash_step) != maxsize)
104+
return err;
105+
return 0;
169106
}
170107

171108
int __cifs_calc_signature(struct smb_rqst *rqst,

include/linux/iov_iter.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,51 @@ size_t iterate_and_advance(struct iov_iter *iter, size_t len, void *priv,
328328
return iterate_and_advance2(iter, len, priv, NULL, ustep, step);
329329
}
330330

331+
/**
332+
* iterate_and_advance_kernel - Iterate over a kernel-internal iterator
333+
* @iter: The iterator to iterate over.
334+
* @len: The amount to iterate over.
335+
* @priv: Data for the step functions.
336+
* @priv2: More data for the step functions.
337+
* @step: Function for other iterators; given kernel addresses.
338+
*
339+
* Iterate over the next part of an iterator, up to the specified length. The
340+
* buffer is presented in segments, which for kernel iteration are broken up by
341+
* physical pages and mapped, with the mapped address being presented.
342+
*
343+
* [!] Note This will only handle BVEC, KVEC, FOLIOQ, XARRAY and DISCARD-type
344+
* iterators; it will not handle UBUF or IOVEC-type iterators.
345+
*
346+
* A step functions, @step, must be provided, one for handling mapped kernel
347+
* addresses and the other is given user addresses which have the potential to
348+
* fault since no pinning is performed.
349+
*
350+
* The step functions are passed the address and length of the segment, @priv,
351+
* @priv2 and the amount of data so far iterated over (which can, for example,
352+
* be added to @priv to point to the right part of a second buffer). The step
353+
* functions should return the amount of the segment they didn't process (ie. 0
354+
* indicates complete processsing).
355+
*
356+
* This function returns the amount of data processed (ie. 0 means nothing was
357+
* processed and the value of @len means processes to completion).
358+
*/
359+
static __always_inline
360+
size_t iterate_and_advance_kernel(struct iov_iter *iter, size_t len, void *priv,
361+
void *priv2, iov_step_f step)
362+
{
363+
if (unlikely(iter->count < len))
364+
len = iter->count;
365+
if (unlikely(!len))
366+
return 0;
367+
if (iov_iter_is_bvec(iter))
368+
return iterate_bvec(iter, len, priv, priv2, step);
369+
if (iov_iter_is_kvec(iter))
370+
return iterate_kvec(iter, len, priv, priv2, step);
371+
if (iov_iter_is_folioq(iter))
372+
return iterate_folioq(iter, len, priv, priv2, step);
373+
if (iov_iter_is_xarray(iter))
374+
return iterate_xarray(iter, len, priv, priv2, step);
375+
return iterate_discard(iter, len, priv, priv2, step);
376+
}
377+
331378
#endif /* _LINUX_IOV_ITER_H */

0 commit comments

Comments
 (0)