1a9643ea8Slogwang /*
2a9643ea8Slogwang * Copyright (c) 2010 Kip Macy. All rights reserved.
3*2317ada5Sfengbojiang * Copyright (C) 2017-2021 THL A29 Limited, a Tencent company.
4a9643ea8Slogwang * All rights reserved.
5a9643ea8Slogwang *
6a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without
7a9643ea8Slogwang * modification, are permitted provided that the following conditions are met:
8a9643ea8Slogwang *
9a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright notice, this
10a9643ea8Slogwang * list of conditions and the following disclaimer.
11a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright notice,
12a9643ea8Slogwang * this list of conditions and the following disclaimer in the documentation
13a9643ea8Slogwang * and/or other materials provided with the distribution.
14a9643ea8Slogwang *
15a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17a9643ea8Slogwang * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18a9643ea8Slogwang * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19a9643ea8Slogwang * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20a9643ea8Slogwang * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21a9643ea8Slogwang * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22a9643ea8Slogwang * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23a9643ea8Slogwang * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24a9643ea8Slogwang * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a9643ea8Slogwang *
26a9643ea8Slogwang * Derived in part from libplebnet's pn_kern_subr.c.
27a9643ea8Slogwang */
28a9643ea8Slogwang
29a9643ea8Slogwang #include <sys/cdefs.h>
30a9643ea8Slogwang #include <sys/param.h>
31a9643ea8Slogwang #include <sys/systm.h>
32a9643ea8Slogwang #include <sys/kernel.h>
33a9643ea8Slogwang #include <sys/ktr.h>
34a9643ea8Slogwang #include <sys/limits.h>
35a9643ea8Slogwang #include <sys/lock.h>
36a9643ea8Slogwang #include <sys/mutex.h>
37a9643ea8Slogwang #include <sys/proc.h>
38a9643ea8Slogwang #include <sys/malloc.h>
39a9643ea8Slogwang #include <sys/resourcevar.h>
40a9643ea8Slogwang #include <sys/sched.h>
41a9643ea8Slogwang #include <sys/sysctl.h>
42a9643ea8Slogwang #include <sys/uio.h>
43a9643ea8Slogwang
44a9643ea8Slogwang #include "ff_host_interface.h"
45a9643ea8Slogwang
4622ce4affSfengbojiang static __inline int
hash_mflags(int flags)4722ce4affSfengbojiang hash_mflags(int flags)
4822ce4affSfengbojiang {
4922ce4affSfengbojiang return ((flags & HASH_NOWAIT) ? M_NOWAIT : M_WAITOK);
5022ce4affSfengbojiang }
51a9643ea8Slogwang
52a9643ea8Slogwang /*
53a9643ea8Slogwang * General routine to allocate a hash table with control of memory flags.
54a9643ea8Slogwang */
55a9643ea8Slogwang void *
hashinit_flags(int elements,struct malloc_type * type,u_long * hashmask,int flags)56a9643ea8Slogwang hashinit_flags(int elements, struct malloc_type *type, u_long *hashmask,
57a9643ea8Slogwang int flags)
58a9643ea8Slogwang {
59a9643ea8Slogwang long hashsize;
60a9643ea8Slogwang LIST_HEAD(generic, generic) *hashtbl;
61a9643ea8Slogwang int i;
62a9643ea8Slogwang
63a9643ea8Slogwang if (elements <= 0)
64a9643ea8Slogwang panic("hashinit: bad elements");
65a9643ea8Slogwang
66a9643ea8Slogwang /* Exactly one of HASH_WAITOK and HASH_NOWAIT must be set. */
67a9643ea8Slogwang KASSERT((flags & HASH_WAITOK) ^ (flags & HASH_NOWAIT),
68a9643ea8Slogwang ("Bad flags (0x%x) passed to hashinit_flags", flags));
69a9643ea8Slogwang
70a9643ea8Slogwang for (hashsize = 1; hashsize <= elements; hashsize <<= 1)
71a9643ea8Slogwang continue;
72a9643ea8Slogwang hashsize >>= 1;
73a9643ea8Slogwang
7422ce4affSfengbojiang hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type,
7522ce4affSfengbojiang hash_mflags(flags));
76a9643ea8Slogwang
77a9643ea8Slogwang if (hashtbl != NULL) {
78a9643ea8Slogwang for (i = 0; i < hashsize; i++)
79a9643ea8Slogwang LIST_INIT(&hashtbl[i]);
80a9643ea8Slogwang *hashmask = hashsize - 1;
81a9643ea8Slogwang }
82a9643ea8Slogwang return (hashtbl);
83a9643ea8Slogwang }
84a9643ea8Slogwang
85a9643ea8Slogwang /*
86a9643ea8Slogwang * Allocate and initialize a hash table with default flag: may sleep.
87a9643ea8Slogwang */
88a9643ea8Slogwang void *
hashinit(int elements,struct malloc_type * type,u_long * hashmask)89a9643ea8Slogwang hashinit(int elements, struct malloc_type *type, u_long *hashmask)
90a9643ea8Slogwang {
91a9643ea8Slogwang return (hashinit_flags(elements, type, hashmask, HASH_WAITOK));
92a9643ea8Slogwang }
93a9643ea8Slogwang
94a9643ea8Slogwang void
hashdestroy(void * vhashtbl,struct malloc_type * type,u_long hashmask)95a9643ea8Slogwang hashdestroy(void *vhashtbl, struct malloc_type *type, u_long hashmask)
96a9643ea8Slogwang {
97a9643ea8Slogwang LIST_HEAD(generic, generic) *hashtbl, *hp;
98a9643ea8Slogwang
99a9643ea8Slogwang hashtbl = vhashtbl;
100a9643ea8Slogwang for (hp = hashtbl; hp <= &hashtbl[hashmask]; hp++)
1013b2bd0f6Slogwang KASSERT(LIST_EMPTY(hp), ("%s: hashtbl %p not empty "
1023b2bd0f6Slogwang "(malloc type %s)", __func__, hashtbl, type->ks_shortdesc));
103a9643ea8Slogwang free(hashtbl, type);
104a9643ea8Slogwang }
105a9643ea8Slogwang
10622ce4affSfengbojiang static const int primes[] = { 1, 13, 31, 61, 127, 251, 509, 761, 1021, 1531,
10722ce4affSfengbojiang 2039, 2557, 3067, 3583, 4093, 4603, 5119, 5623, 6143,
10822ce4affSfengbojiang 6653, 7159, 7673, 8191, 12281, 16381, 24571, 32749 };
10922ce4affSfengbojiang #define NPRIMES nitems(primes)
11022ce4affSfengbojiang
11122ce4affSfengbojiang /*
11222ce4affSfengbojiang * General routine to allocate a prime number sized hash table with control of
11322ce4affSfengbojiang * memory flags.
11422ce4affSfengbojiang */
11522ce4affSfengbojiang void *
phashinit_flags(int elements,struct malloc_type * type,u_long * nentries,int flags)11622ce4affSfengbojiang phashinit_flags(int elements, struct malloc_type *type, u_long *nentries, int flags)
11722ce4affSfengbojiang {
11822ce4affSfengbojiang long hashsize, i;
11922ce4affSfengbojiang LIST_HEAD(generic, generic) *hashtbl;
12022ce4affSfengbojiang
12122ce4affSfengbojiang KASSERT(elements > 0, ("%s: bad elements", __func__));
12222ce4affSfengbojiang /* Exactly one of HASH_WAITOK and HASH_NOWAIT must be set. */
12322ce4affSfengbojiang KASSERT((flags & HASH_WAITOK) ^ (flags & HASH_NOWAIT),
12422ce4affSfengbojiang ("Bad flags (0x%x) passed to phashinit_flags", flags));
12522ce4affSfengbojiang
12622ce4affSfengbojiang for (i = 1, hashsize = primes[1]; hashsize <= elements;) {
12722ce4affSfengbojiang i++;
12822ce4affSfengbojiang if (i == NPRIMES)
12922ce4affSfengbojiang break;
13022ce4affSfengbojiang hashsize = primes[i];
13122ce4affSfengbojiang }
13222ce4affSfengbojiang hashsize = primes[i - 1];
13322ce4affSfengbojiang
13422ce4affSfengbojiang hashtbl = malloc((u_long)hashsize * sizeof(*hashtbl), type,
13522ce4affSfengbojiang hash_mflags(flags));
13622ce4affSfengbojiang if (hashtbl == NULL)
13722ce4affSfengbojiang return (NULL);
13822ce4affSfengbojiang
13922ce4affSfengbojiang for (i = 0; i < hashsize; i++)
14022ce4affSfengbojiang LIST_INIT(&hashtbl[i]);
14122ce4affSfengbojiang *nentries = hashsize;
14222ce4affSfengbojiang return (hashtbl);
14322ce4affSfengbojiang }
14422ce4affSfengbojiang
14522ce4affSfengbojiang /*
14622ce4affSfengbojiang * Allocate and initialize a prime number sized hash table with default flag:
14722ce4affSfengbojiang * may sleep.
14822ce4affSfengbojiang */
14922ce4affSfengbojiang void *
phashinit(int elements,struct malloc_type * type,u_long * nentries)15022ce4affSfengbojiang phashinit(int elements, struct malloc_type *type, u_long *nentries)
15122ce4affSfengbojiang {
15222ce4affSfengbojiang
15322ce4affSfengbojiang return (phashinit_flags(elements, type, nentries, HASH_WAITOK));
15422ce4affSfengbojiang }
15522ce4affSfengbojiang
156a9643ea8Slogwang static void
uio_yield(void)157a9643ea8Slogwang uio_yield(void)
158a9643ea8Slogwang {
159a9643ea8Slogwang
160a9643ea8Slogwang }
161a9643ea8Slogwang
162a9643ea8Slogwang int
uiomove(void * cp,int n,struct uio * uio)163a9643ea8Slogwang uiomove(void *cp, int n, struct uio *uio)
164a9643ea8Slogwang {
165a9643ea8Slogwang struct thread *td = curthread;
166a9643ea8Slogwang struct iovec *iov;
167a9643ea8Slogwang u_int cnt;
168a9643ea8Slogwang int error = 0;
169a9643ea8Slogwang int save = 0;
170a9643ea8Slogwang
171a9643ea8Slogwang KASSERT(uio->uio_rw == UIO_READ || uio->uio_rw == UIO_WRITE,
172a9643ea8Slogwang ("uiomove: mode"));
173a9643ea8Slogwang KASSERT(uio->uio_segflg != UIO_USERSPACE || uio->uio_td == curthread,
174a9643ea8Slogwang ("uiomove proc"));
175a9643ea8Slogwang WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
176a9643ea8Slogwang "Calling uiomove()");
177a9643ea8Slogwang
178a9643ea8Slogwang save = td->td_pflags & TDP_DEADLKTREAT;
179a9643ea8Slogwang td->td_pflags |= TDP_DEADLKTREAT;
180a9643ea8Slogwang
181a9643ea8Slogwang while (n > 0 && uio->uio_resid) {
182a9643ea8Slogwang iov = uio->uio_iov;
183a9643ea8Slogwang cnt = iov->iov_len;
184a9643ea8Slogwang if (cnt == 0) {
185a9643ea8Slogwang uio->uio_iov++;
186a9643ea8Slogwang uio->uio_iovcnt--;
187a9643ea8Slogwang continue;
188a9643ea8Slogwang }
189a9643ea8Slogwang if (cnt > n)
190a9643ea8Slogwang cnt = n;
191a9643ea8Slogwang
192a9643ea8Slogwang switch (uio->uio_segflg) {
193a9643ea8Slogwang
194a9643ea8Slogwang case UIO_USERSPACE:
195a9643ea8Slogwang if (ticks - PCPU_GET(switchticks) >= hogticks)
196a9643ea8Slogwang uio_yield();
197a9643ea8Slogwang if (uio->uio_rw == UIO_READ)
198a9643ea8Slogwang error = copyout(cp, iov->iov_base, cnt);
199a9643ea8Slogwang else
200a9643ea8Slogwang error = copyin(iov->iov_base, cp, cnt);
201a9643ea8Slogwang if (error)
202a9643ea8Slogwang goto out;
203a9643ea8Slogwang break;
204a9643ea8Slogwang
205a9643ea8Slogwang case UIO_SYSSPACE:
206a9643ea8Slogwang if (uio->uio_rw == UIO_READ)
207a9643ea8Slogwang bcopy(cp, iov->iov_base, cnt);
208a9643ea8Slogwang else
209a9643ea8Slogwang bcopy(iov->iov_base, cp, cnt);
210a9643ea8Slogwang break;
211a9643ea8Slogwang case UIO_NOCOPY:
212a9643ea8Slogwang break;
213a9643ea8Slogwang }
214a9643ea8Slogwang iov->iov_base = (char *)iov->iov_base + cnt;
215a9643ea8Slogwang iov->iov_len -= cnt;
216a9643ea8Slogwang uio->uio_resid -= cnt;
217a9643ea8Slogwang uio->uio_offset += cnt;
218a9643ea8Slogwang cp = (char *)cp + cnt;
219a9643ea8Slogwang n -= cnt;
220a9643ea8Slogwang }
221a9643ea8Slogwang out:
222a9643ea8Slogwang if (save == 0)
223a9643ea8Slogwang td->td_pflags &= ~TDP_DEADLKTREAT;
224a9643ea8Slogwang return (error);
225a9643ea8Slogwang }
226a9643ea8Slogwang
227a9643ea8Slogwang int
copyinuio(const struct iovec * iovp,u_int iovcnt,struct uio ** uiop)228a9643ea8Slogwang copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop)
229a9643ea8Slogwang {
230a9643ea8Slogwang struct iovec *iov;
231a9643ea8Slogwang struct uio *uio;
232a9643ea8Slogwang u_int iovlen;
233a9643ea8Slogwang int error, i;
234a9643ea8Slogwang
235a9643ea8Slogwang *uiop = NULL;
236a9643ea8Slogwang if (iovcnt > UIO_MAXIOV)
237a9643ea8Slogwang return (EINVAL);
238a9643ea8Slogwang iovlen = iovcnt * sizeof (struct iovec);
239a9643ea8Slogwang uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
240a9643ea8Slogwang if (uio == NULL) {
241a9643ea8Slogwang return (ENOMEM);
242a9643ea8Slogwang }
243a9643ea8Slogwang iov = (struct iovec *)(uio + 1);
244a9643ea8Slogwang error = copyin(iovp, iov, iovlen);
245a9643ea8Slogwang if (error) {
246a9643ea8Slogwang free(uio, M_IOV);
247a9643ea8Slogwang return (error);
248a9643ea8Slogwang }
249a9643ea8Slogwang uio->uio_iov = iov;
250a9643ea8Slogwang uio->uio_iovcnt = iovcnt;
251a9643ea8Slogwang uio->uio_segflg = UIO_USERSPACE;
252a9643ea8Slogwang uio->uio_offset = -1;
253a9643ea8Slogwang uio->uio_resid = 0;
254a9643ea8Slogwang for (i = 0; i < iovcnt; i++) {
255a9643ea8Slogwang if (iov->iov_len > INT_MAX - uio->uio_resid) {
256a9643ea8Slogwang free(uio, M_IOV);
257a9643ea8Slogwang return (EINVAL);
258a9643ea8Slogwang }
259a9643ea8Slogwang uio->uio_resid += iov->iov_len;
260a9643ea8Slogwang iov++;
261a9643ea8Slogwang }
262a9643ea8Slogwang *uiop = uio;
263a9643ea8Slogwang return (0);
264a9643ea8Slogwang }
265a9643ea8Slogwang
266a9643ea8Slogwang int
copyout_nofault(const void * kaddr,void * udaddr,size_t len)267a9643ea8Slogwang copyout_nofault(const void *kaddr, void *udaddr, size_t len)
268a9643ea8Slogwang {
269a9643ea8Slogwang return copyout(kaddr, udaddr, len);
270a9643ea8Slogwang }
271a9643ea8Slogwang
272