Changeset View
Standalone View
sys/compat/linuxkpi/common/src/linux_compat.c
Show First 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | |||||
static struct timeval lkpi_net_lastlog; | static struct timeval lkpi_net_lastlog; | ||||
static int lkpi_net_curpps; | static int lkpi_net_curpps; | ||||
static int lkpi_net_maxpps = 99; | static int lkpi_net_maxpps = 99; | ||||
SYSCTL_INT(_compat_linuxkpi, OID_AUTO, net_ratelimit, CTLFLAG_RWTUN, | SYSCTL_INT(_compat_linuxkpi, OID_AUTO, net_ratelimit, CTLFLAG_RWTUN, | ||||
&lkpi_net_maxpps, 0, "Limit number of LinuxKPI net messages per second."); | &lkpi_net_maxpps, 0, "Limit number of LinuxKPI net messages per second."); | ||||
MALLOC_DEFINE(M_KMALLOC, "lkpikmalloc", "Linux kmalloc compat"); | MALLOC_DEFINE(M_KMALLOC, "lkpikmalloc", "Linux kmalloc compat"); | ||||
hselasky: Just use the Linux allocator, kalloc(GFP_KERNEL) ?
The function is very small and leaks are… | |||||
#include <linux/rbtree.h> | #include <linux/rbtree.h> | ||||
/* Undo Linux compat changes. */ | /* Undo Linux compat changes. */ | ||||
#undef RB_ROOT | #undef RB_ROOT | ||||
#undef file | #undef file | ||||
#undef cdev | #undef cdev | ||||
#define RB_ROOT(head) (head)->rbh_root | #define RB_ROOT(head) (head)->rbh_root | ||||
static void linux_destroy_dev(struct linux_cdev *); | static void linux_destroy_dev(struct linux_cdev *); | ||||
▲ Show 20 Lines • Show All 2,593 Lines • ▼ Show 20 Lines | io_mapping_create_wc(resource_size_t base, unsigned long size) | ||||
struct io_mapping *mapping; | struct io_mapping *mapping; | ||||
mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); | mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); | ||||
if (mapping == NULL) | if (mapping == NULL) | ||||
return (NULL); | return (NULL); | ||||
return (io_mapping_init_wc(mapping, base, size)); | return (io_mapping_init_wc(mapping, base, size)); | ||||
} | } | ||||
static struct sx lkpi_charp_lock; | |||||
SX_SYSINIT(lkpi_charp, &lkpi_charp_lock, "lkpi charp module param lock"); | |||||
int | |||||
lkpi_sysctl_handle_charp(SYSCTL_HANDLER_ARGS) | |||||
{ | |||||
char **charp = arg1; | |||||
int error = 0; | |||||
sx_xlock(&lkpi_charp_lock); | |||||
Not Done Inline ActionsTake this lock exclusively right here. Otherwise SYSCTL_IN and SYSCTL_OUT gets a great chance to see different versions of *charp when try_upgrade is failed wulf: Take this lock exclusively right here. Otherwise SYSCTL_IN and SYSCTL_OUT gets a great chance… | |||||
if (req->oldptr != NULL) { | |||||
error = SYSCTL_OUT_STR(req, *charp == NULL ? "" : *charp); | |||||
Not Done Inline ActionsSYSCTL_OUT can sleep. You should call sysctl_wire_old_buffer() before taking lkpi_charp_lock wulf: SYSCTL_OUT can sleep. You should call sysctl_wire_old_buffer() before taking lkpi_charp_lock | |||||
} else { | |||||
error = SYSCTL_OUT(req, NULL, *charp == NULL ? 1 : strlen(*charp) + 1); | |||||
} | |||||
if (error || !req->newptr) { | |||||
goto end; | |||||
} | |||||
kfree(*charp); | |||||
Not Done Inline ActionsIMO charp should be freed only after successfull SYSCTL_IN(). I think *charp should not be reseted after e.g. EFAULT wulf: IMO charp should be freed only after successfull SYSCTL_IN(). I think *charp should not be… | |||||
Done Inline Actionshmm well, I put it here because if (req->newlen == 0) I replace it with NULL without doing SYSCTL_IN val_packett.cool: hmm well, I put it here because `if (req->newlen == 0)` I replace it with NULL without doing… | |||||
if (req->newlen == 0) { | |||||
*charp = NULL; | |||||
goto end; | |||||
} | |||||
*charp = kzalloc(req->newlen + 1, GFP_KERNEL); | |||||
error = SYSCTL_IN(req, *charp, req->newlen); | |||||
if (error) { | |||||
kfree(*charp); | |||||
*charp = NULL; | |||||
} else { | |||||
(*charp)[req->newlen] = '\0'; | |||||
} | |||||
Not Done Inline ActionsYou cannot do malloc(M_WAITOK) with non-sleepable lock held. wulf: You cannot do malloc(M_WAITOK) with non-sleepable lock held. | |||||
end: | |||||
sx_xunlock(&lkpi_charp_lock); | |||||
return (error); | |||||
Not Done Inline ActionsHow these operations on *charp are synchronized with drm-kmod? Are they protected by external lock? wulf: How these operations on *charp are synchronized with drm-kmod? Are they protected by external… | |||||
Done Inline ActionsIn the kmods we have, charp parameters are only used for boot-only tunables. I'm not sure if they even make sense with things that can change at runtime. There is no synchronization, the module just expects the kernel to modify the pointer on load and reads it when initializing the hardware. val_packett.cool: In the kmods we have, charp parameters are only used for boot-only tunables. I'm not sure if… | |||||
Not Done Inline ActionsOk. It looks that drm-kmod is awared of absence of synchronization and does strdup() before parsing of data referenced by charp. wulf: Ok. It looks that drm-kmod is awared of absence of synchronization and does strdup() before… | |||||
} | |||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
bool linux_cpu_has_clflush; | bool linux_cpu_has_clflush; | ||||
#endif | #endif | ||||
static void | static void | ||||
linux_compat_init(void *arg) | linux_compat_init(void *arg) | ||||
{ | { | ||||
struct sysctl_oid *rootoid; | struct sysctl_oid *rootoid; | ||||
▲ Show 20 Lines • Show All 54 Lines • Show Last 20 Lines |
Just use the Linux allocator, kalloc(GFP_KERNEL) ?
The function is very small and leaks are impossible!