2020-04-14 18:36:28 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* $FreeBSD$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _OPENSOLARIS_SYS_KMEM_H_
|
|
|
|
#define _OPENSOLARIS_SYS_KMEM_H_
|
|
|
|
|
2020-10-14 04:05:49 +00:00
|
|
|
#ifdef _KERNEL
|
2020-04-14 18:36:28 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/vmem.h>
|
2020-08-01 04:30:31 +00:00
|
|
|
#include <sys/counter.h>
|
2020-04-14 18:36:28 +00:00
|
|
|
|
|
|
|
#include <vm/uma.h>
|
|
|
|
#include <vm/vm.h>
|
|
|
|
#include <vm/vm_extern.h>
|
|
|
|
|
|
|
|
MALLOC_DECLARE(M_SOLARIS);
|
|
|
|
|
|
|
|
#define POINTER_IS_VALID(p) (!((uintptr_t)(p) & 0x3))
|
|
|
|
#define POINTER_INVALIDATE(pp) (*(pp) = (void *)((uintptr_t)(*(pp)) | 0x1))
|
|
|
|
|
|
|
|
#define KM_SLEEP M_WAITOK
|
|
|
|
#define KM_PUSHPAGE M_WAITOK
|
|
|
|
#define KM_NOSLEEP M_NOWAIT
|
|
|
|
#define KM_NORMALPRI 0
|
|
|
|
#define KMC_NODEBUG UMA_ZONE_NODUMP
|
|
|
|
|
|
|
|
typedef struct vmem vmem_t;
|
|
|
|
|
Reduce false positives from Static Analyzers
Both Clang's Static Analyzer and Synopsys' Coverity would ignore
assertions. Following Clang's advice, we annotate our assertions:
https://clang-analyzer.llvm.org/annotations.html#custom_assertions
This makes both Clang's Static Analyzer and Coverity properly identify
assertions. This change reduced Clang's reported defects from 246 to
180. It also reduced the false positives reported by Coverityi by 10,
while enabling Coverity to find 9 more defects that previously were
false negatives.
A couple examples of this would be CID-1524417 and CID-1524423. After
submitting a build to coverity with the modified assertions, CID-1524417
disappeared while the report for CID-1524423 no longer claimed that the
assertion tripped.
Coincidentally, it turns out that it is possible to more accurately
annotate our headers than the Coverity modelling file permits in the
case of format strings. Since we can do that and this patch annotates
headers whenever `__coverity_panic__()` would have been used in the
model file, we drop all models that use `__coverity_panic__()` from the
model file.
Upon seeing the success in eliminating false positives involving
assertions, it occurred to me that we could also modify our headers to
eliminate coverity's false positives involving byte swaps. We now have
coverity specific byteswap macros, that do nothing, to disable
Coverity's false positives when we do byte swaps. This allowed us to
also drop the byteswap definitions from the model file.
Lastly, a model file update has been done beyond the mentioned
deletions:
* The definitions of `umem_alloc_aligned()`, `umem_alloc()` andi
`umem_zalloc()` were originally implemented in a way that was
intended to inform coverity that when KM_SLEEP has been passed these
functions, they do not return NULL. A small error in how this was
done was found, so we correct it.
* Definitions for umem_cache_alloc() and umem_cache_free() have been
added.
In practice, no false positives were avoided by making these changes,
but in the interest of correctness from future coverity builds, we make
them anyway.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #13902
2022-09-30 22:30:12 +00:00
|
|
|
extern char *kmem_asprintf(const char *, ...)
|
|
|
|
__attribute__((format(printf, 1, 2)));
|
|
|
|
extern char *kmem_vasprintf(const char *fmt, va_list ap)
|
|
|
|
__attribute__((format(printf, 1, 0)));
|
2020-04-14 18:36:28 +00:00
|
|
|
|
Introduce kmem_scnprintf()
`snprintf()` is meant to protect against buffer overflows, but operating
on the buffer using its return value, possibly by calling it again, can
cause a buffer overflow, because it will return how many characters it
would have written if it had enough space even when it did not. In a
number of places, we repeatedly call snprintf() by successively
incrementing a buffer offset and decrementing a buffer length, by its
return value. This is a potentially unsafe usage of `snprintf()`
whenever the buffer length is reached. CodeQL complained about this.
To fix this, we introduce `kmem_scnprintf()`, which will return 0 when
the buffer is zero or the number of written characters, minus 1 to
exclude the NULL character, when the buffer was too small. In all other
cases, it behaves like snprintf(). The name is inspired by the Linux and
XNU kernels' `scnprintf()`. The implementation was written before I
thought to look at `scnprintf()` and had a good name for it, but it
turned out to have identical semantics to the Linux kernel version.
That lead to the name, `kmem_scnprintf()`.
CodeQL only catches this issue in loops, so repeated use of snprintf()
outside of a loop was not caught. As a result, a thorough audit of the
codebase was done to examine all instances of `snprintf()` usage for
potential problems and a few were caught. Fixes for them are included in
this patch.
Unfortunately, ZED is one of the places where `snprintf()` is
potentially used incorrectly. Since using `kmem_scnprintf()` in it would
require changing how it is linked, we modify its usage to make it safe,
no matter what buffer length is used. In addition, there was a bug in
the use of the return value where the NULL format character was not
being written by pwrite(). That has been fixed.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #14098
2022-10-27 18:16:04 +00:00
|
|
|
extern int kmem_scnprintf(char *restrict str, size_t size,
|
|
|
|
const char *restrict fmt, ...);
|
|
|
|
|
2020-04-14 18:36:28 +00:00
|
|
|
typedef struct kmem_cache {
|
|
|
|
char kc_name[32];
|
|
|
|
#if !defined(KMEM_DEBUG)
|
|
|
|
uma_zone_t kc_zone;
|
|
|
|
#else
|
|
|
|
size_t kc_size;
|
|
|
|
#endif
|
|
|
|
int (*kc_constructor)(void *, void *, int);
|
|
|
|
void (*kc_destructor)(void *, void *);
|
|
|
|
void *kc_private;
|
|
|
|
} kmem_cache_t;
|
|
|
|
|
|
|
|
extern uint64_t spl_kmem_cache_inuse(kmem_cache_t *cache);
|
|
|
|
extern uint64_t spl_kmem_cache_entry_size(kmem_cache_t *cache);
|
|
|
|
|
Reduce false positives from Static Analyzers
Both Clang's Static Analyzer and Synopsys' Coverity would ignore
assertions. Following Clang's advice, we annotate our assertions:
https://clang-analyzer.llvm.org/annotations.html#custom_assertions
This makes both Clang's Static Analyzer and Coverity properly identify
assertions. This change reduced Clang's reported defects from 246 to
180. It also reduced the false positives reported by Coverityi by 10,
while enabling Coverity to find 9 more defects that previously were
false negatives.
A couple examples of this would be CID-1524417 and CID-1524423. After
submitting a build to coverity with the modified assertions, CID-1524417
disappeared while the report for CID-1524423 no longer claimed that the
assertion tripped.
Coincidentally, it turns out that it is possible to more accurately
annotate our headers than the Coverity modelling file permits in the
case of format strings. Since we can do that and this patch annotates
headers whenever `__coverity_panic__()` would have been used in the
model file, we drop all models that use `__coverity_panic__()` from the
model file.
Upon seeing the success in eliminating false positives involving
assertions, it occurred to me that we could also modify our headers to
eliminate coverity's false positives involving byte swaps. We now have
coverity specific byteswap macros, that do nothing, to disable
Coverity's false positives when we do byte swaps. This allowed us to
also drop the byteswap definitions from the model file.
Lastly, a model file update has been done beyond the mentioned
deletions:
* The definitions of `umem_alloc_aligned()`, `umem_alloc()` andi
`umem_zalloc()` were originally implemented in a way that was
intended to inform coverity that when KM_SLEEP has been passed these
functions, they do not return NULL. A small error in how this was
done was found, so we correct it.
* Definitions for umem_cache_alloc() and umem_cache_free() have been
added.
In practice, no false positives were avoided by making these changes,
but in the interest of correctness from future coverity builds, we make
them anyway.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Signed-off-by: Richard Yao <richard.yao@alumni.stonybrook.edu>
Closes #13902
2022-09-30 22:30:12 +00:00
|
|
|
__attribute__((alloc_size(1)))
|
2020-04-14 18:36:28 +00:00
|
|
|
void *zfs_kmem_alloc(size_t size, int kmflags);
|
|
|
|
void zfs_kmem_free(void *buf, size_t size);
|
|
|
|
uint64_t kmem_size(void);
|
2022-04-19 18:38:30 +00:00
|
|
|
kmem_cache_t *kmem_cache_create(const char *name, size_t bufsize, size_t align,
|
2020-04-14 18:36:28 +00:00
|
|
|
int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
|
|
|
|
void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags);
|
|
|
|
void kmem_cache_destroy(kmem_cache_t *cache);
|
|
|
|
void *kmem_cache_alloc(kmem_cache_t *cache, int flags);
|
|
|
|
void kmem_cache_free(kmem_cache_t *cache, void *buf);
|
|
|
|
boolean_t kmem_cache_reap_active(void);
|
|
|
|
void kmem_cache_reap_soon(kmem_cache_t *);
|
|
|
|
void kmem_reap(void);
|
|
|
|
int kmem_debugging(void);
|
|
|
|
void *calloc(size_t n, size_t s);
|
|
|
|
|
|
|
|
|
|
|
|
#define kmem_cache_reap_now kmem_cache_reap_soon
|
|
|
|
#define freemem vm_free_count()
|
|
|
|
#define minfree vm_cnt.v_free_min
|
|
|
|
#define kmem_alloc(size, kmflags) zfs_kmem_alloc((size), (kmflags))
|
|
|
|
#define kmem_zalloc(size, kmflags) \
|
|
|
|
zfs_kmem_alloc((size), (kmflags) | M_ZERO)
|
|
|
|
#define kmem_free(buf, size) zfs_kmem_free((buf), (size))
|
|
|
|
|
2020-10-14 04:05:49 +00:00
|
|
|
#endif /* _KERNEL */
|
|
|
|
|
|
|
|
#ifdef _STANDALONE
|
|
|
|
/*
|
|
|
|
* At the moment, we just need it for the type. We redirect the alloc/free
|
|
|
|
* routines to the usual Free and Malloc in that environment.
|
|
|
|
*/
|
|
|
|
typedef int kmem_cache_t;
|
|
|
|
#endif /* _STANDALONE */
|
2020-04-14 18:36:28 +00:00
|
|
|
|
|
|
|
#endif /* _OPENSOLARIS_SYS_KMEM_H_ */
|