xref: /f-stack/lib/ff_kern_subr.c (revision 2317ada5)
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