mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
Atomic64 compatibility for 32-bit systems without kernel support.
This patch is another step towards updating the code to handle the 32-bit kernels which I have not been regularly testing. This changes do not really impact the common case I'm expected which is the latest kernel running on an x86_64 arch. Until the linux-2.6.31 kernel the x86 arch did not have support for 64-bit atomic operations. Additionally, the new atomic_compat.h support for this case was wrong because it embedded a spinlock in the atomic variable which must always and only be 64-bits total. To handle these 32-bit issues we now simply fall back to the --enable-atomic-spinlock implementation if the kernel does not provide the 64-bit atomic funcs. The second issue this patch addresses is the DEBUG_KMEM assumption that there will always be atomic64 funcs available. On 32-bit archs this may not be true, and actually that's just fine. In that case the kernel will will never be able to allocate more the 32-bits worth anyway. So just check if atomic64 funcs are available, if they are not it means this is a 32-bit machine and we can safely use atomic_t's instead.
This commit is contained in:
+46
-46
@@ -215,11 +215,19 @@ EXPORT_SYMBOL(vmem_size);
|
||||
* report any memory leaked when the module is unloaded.
|
||||
*/
|
||||
#ifdef DEBUG_KMEM
|
||||
|
||||
/* Shim layer memory accounting */
|
||||
# ifdef HAVE_ATOMIC64_T
|
||||
atomic64_t kmem_alloc_used = ATOMIC64_INIT(0);
|
||||
unsigned long long kmem_alloc_max = 0;
|
||||
atomic64_t vmem_alloc_used = ATOMIC64_INIT(0);
|
||||
unsigned long long vmem_alloc_max = 0;
|
||||
# else
|
||||
atomic_t kmem_alloc_used = ATOMIC_INIT(0);
|
||||
unsigned long long kmem_alloc_max = 0;
|
||||
atomic_t vmem_alloc_used = ATOMIC_INIT(0);
|
||||
unsigned long long vmem_alloc_max = 0;
|
||||
# endif /* _LP64 */
|
||||
int kmem_warning_flag = 1;
|
||||
|
||||
EXPORT_SYMBOL(kmem_alloc_used);
|
||||
@@ -392,7 +400,7 @@ kmem_alloc_track(size_t size, int flags, const char *func, int line,
|
||||
if (unlikely((size) > (PAGE_SIZE * 2)) && kmem_warning_flag)
|
||||
CWARN("Large kmem_alloc(%llu, 0x%x) (%lld/%llu)\n",
|
||||
(unsigned long long) size, flags,
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
|
||||
/* We use kstrdup() below because the string pointed to by
|
||||
* __FUNCTION__ might not be available by the time we want
|
||||
@@ -402,7 +410,7 @@ kmem_alloc_track(size_t size, int flags, const char *func, int line,
|
||||
kfree(dptr);
|
||||
CWARN("kstrdup() failed in kmem_alloc(%llu, 0x%x) "
|
||||
"(%lld/%llu)\n", (unsigned long long) size, flags,
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -421,15 +429,13 @@ kmem_alloc_track(size_t size, int flags, const char *func, int line,
|
||||
kfree(dptr);
|
||||
CWARN("kmem_alloc(%llu, 0x%x) failed (%lld/%llu)\n",
|
||||
(unsigned long long) size, flags,
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
goto out;
|
||||
}
|
||||
|
||||
atomic64_add(size, &kmem_alloc_used);
|
||||
if (unlikely(atomic64_read(&kmem_alloc_used) >
|
||||
kmem_alloc_max))
|
||||
kmem_alloc_max =
|
||||
atomic64_read(&kmem_alloc_used);
|
||||
kmem_alloc_used_add(size);
|
||||
if (unlikely(kmem_alloc_used_read() > kmem_alloc_max))
|
||||
kmem_alloc_max = kmem_alloc_used_read();
|
||||
|
||||
INIT_HLIST_NODE(&dptr->kd_hlist);
|
||||
INIT_LIST_HEAD(&dptr->kd_list);
|
||||
@@ -446,7 +452,7 @@ kmem_alloc_track(size_t size, int flags, const char *func, int line,
|
||||
|
||||
CDEBUG_LIMIT(D_INFO, "kmem_alloc(%llu, 0x%x) = %p "
|
||||
"(%lld/%llu)\n", (unsigned long long) size, flags,
|
||||
ptr, atomic64_read(&kmem_alloc_used),
|
||||
ptr, kmem_alloc_used_read(),
|
||||
kmem_alloc_max);
|
||||
}
|
||||
out:
|
||||
@@ -472,10 +478,9 @@ kmem_free_track(void *ptr, size_t size)
|
||||
"kd_func = %s, kd_line = %d\n", (unsigned long long) dptr->kd_size,
|
||||
(unsigned long long) size, dptr->kd_func, dptr->kd_line);
|
||||
|
||||
atomic64_sub(size, &kmem_alloc_used);
|
||||
|
||||
kmem_alloc_used_sub(size);
|
||||
CDEBUG_LIMIT(D_INFO, "kmem_free(%p, %llu) (%lld/%llu)\n", ptr,
|
||||
(unsigned long long) size, atomic64_read(&kmem_alloc_used),
|
||||
(unsigned long long) size, kmem_alloc_used_read(),
|
||||
kmem_alloc_max);
|
||||
|
||||
kfree(dptr->kd_func);
|
||||
@@ -513,7 +518,7 @@ vmem_alloc_track(size_t size, int flags, const char *func, int line)
|
||||
kfree(dptr);
|
||||
CWARN("kstrdup() failed in vmem_alloc(%llu, 0x%x) "
|
||||
"(%lld/%llu)\n", (unsigned long long) size, flags,
|
||||
atomic64_read(&vmem_alloc_used), vmem_alloc_max);
|
||||
vmem_alloc_used_read(), vmem_alloc_max);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -525,18 +530,16 @@ vmem_alloc_track(size_t size, int flags, const char *func, int line)
|
||||
kfree(dptr);
|
||||
CWARN("vmem_alloc(%llu, 0x%x) failed (%lld/%llu)\n",
|
||||
(unsigned long long) size, flags,
|
||||
atomic64_read(&vmem_alloc_used), vmem_alloc_max);
|
||||
vmem_alloc_used_read(), vmem_alloc_max);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flags & __GFP_ZERO)
|
||||
memset(ptr, 0, size);
|
||||
|
||||
atomic64_add(size, &vmem_alloc_used);
|
||||
if (unlikely(atomic64_read(&vmem_alloc_used) >
|
||||
vmem_alloc_max))
|
||||
vmem_alloc_max =
|
||||
atomic64_read(&vmem_alloc_used);
|
||||
vmem_alloc_used_add(size);
|
||||
if (unlikely(vmem_alloc_used_read() > vmem_alloc_max))
|
||||
vmem_alloc_max = vmem_alloc_used_read();
|
||||
|
||||
INIT_HLIST_NODE(&dptr->kd_hlist);
|
||||
INIT_LIST_HEAD(&dptr->kd_list);
|
||||
@@ -553,7 +556,7 @@ vmem_alloc_track(size_t size, int flags, const char *func, int line)
|
||||
|
||||
CDEBUG_LIMIT(D_INFO, "vmem_alloc(%llu, 0x%x) = %p "
|
||||
"(%lld/%llu)\n", (unsigned long long) size, flags,
|
||||
ptr, atomic64_read(&vmem_alloc_used),
|
||||
ptr, vmem_alloc_used_read(),
|
||||
vmem_alloc_max);
|
||||
}
|
||||
out:
|
||||
@@ -578,9 +581,9 @@ vmem_free_track(void *ptr, size_t size)
|
||||
"kd_func = %s, kd_line = %d\n", (unsigned long long) dptr->kd_size,
|
||||
(unsigned long long) size, dptr->kd_func, dptr->kd_line);
|
||||
|
||||
atomic64_sub(size, &vmem_alloc_used);
|
||||
vmem_alloc_used_sub(size);
|
||||
CDEBUG_LIMIT(D_INFO, "vmem_free(%p, %llu) (%lld/%llu)\n", ptr,
|
||||
(unsigned long long) size, atomic64_read(&vmem_alloc_used),
|
||||
(unsigned long long) size, vmem_alloc_used_read(),
|
||||
vmem_alloc_max);
|
||||
|
||||
kfree(dptr->kd_func);
|
||||
@@ -609,7 +612,7 @@ kmem_alloc_debug(size_t size, int flags, const char *func, int line,
|
||||
if (unlikely(size > (PAGE_SIZE * 2)) && kmem_warning_flag)
|
||||
CWARN("Large kmem_alloc(%llu, 0x%x) (%lld/%llu)\n",
|
||||
(unsigned long long) size, flags,
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
|
||||
/* Use the correct allocator */
|
||||
if (node_alloc) {
|
||||
@@ -624,15 +627,15 @@ kmem_alloc_debug(size_t size, int flags, const char *func, int line,
|
||||
if (ptr == NULL) {
|
||||
CWARN("kmem_alloc(%llu, 0x%x) failed (%lld/%llu)\n",
|
||||
(unsigned long long) size, flags,
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
} else {
|
||||
atomic64_add(size, &kmem_alloc_used);
|
||||
if (unlikely(atomic64_read(&kmem_alloc_used) > kmem_alloc_max))
|
||||
kmem_alloc_max = atomic64_read(&kmem_alloc_used);
|
||||
kmem_alloc_used_add(size);
|
||||
if (unlikely(kmem_alloc_used_read() > kmem_alloc_max))
|
||||
kmem_alloc_max = kmem_alloc_used_read();
|
||||
|
||||
CDEBUG_LIMIT(D_INFO, "kmem_alloc(%llu, 0x%x) = %p "
|
||||
"(%lld/%llu)\n", (unsigned long long) size, flags, ptr,
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
}
|
||||
RETURN(ptr);
|
||||
}
|
||||
@@ -646,10 +649,9 @@ kmem_free_debug(void *ptr, size_t size)
|
||||
ASSERTF(ptr || size > 0, "ptr: %p, size: %llu", ptr,
|
||||
(unsigned long long) size);
|
||||
|
||||
atomic64_sub(size, &kmem_alloc_used);
|
||||
|
||||
kmem_alloc_used_sub(size);
|
||||
CDEBUG_LIMIT(D_INFO, "kmem_free(%p, %llu) (%lld/%llu)\n", ptr,
|
||||
(unsigned long long) size, atomic64_read(&kmem_alloc_used),
|
||||
(unsigned long long) size, kmem_alloc_used_read(),
|
||||
kmem_alloc_max);
|
||||
|
||||
memset(ptr, 0x5a, size);
|
||||
@@ -672,19 +674,18 @@ vmem_alloc_debug(size_t size, int flags, const char *func, int line)
|
||||
if (ptr == NULL) {
|
||||
CWARN("vmem_alloc(%llu, 0x%x) failed (%lld/%llu)\n",
|
||||
(unsigned long long) size, flags,
|
||||
atomic64_read(&vmem_alloc_used), vmem_alloc_max);
|
||||
vmem_alloc_used_read(), vmem_alloc_max);
|
||||
} else {
|
||||
if (flags & __GFP_ZERO)
|
||||
memset(ptr, 0, size);
|
||||
|
||||
atomic64_add(size, &vmem_alloc_used);
|
||||
|
||||
if (unlikely(atomic64_read(&vmem_alloc_used) > vmem_alloc_max))
|
||||
vmem_alloc_max = atomic64_read(&vmem_alloc_used);
|
||||
vmem_alloc_used_add(size);
|
||||
if (unlikely(vmem_alloc_used_read() > vmem_alloc_max))
|
||||
vmem_alloc_max = vmem_alloc_used_read();
|
||||
|
||||
CDEBUG_LIMIT(D_INFO, "vmem_alloc(%llu, 0x%x) = %p "
|
||||
"(%lld/%llu)\n", (unsigned long long) size, flags, ptr,
|
||||
atomic64_read(&vmem_alloc_used), vmem_alloc_max);
|
||||
vmem_alloc_used_read(), vmem_alloc_max);
|
||||
}
|
||||
|
||||
RETURN(ptr);
|
||||
@@ -699,10 +700,9 @@ vmem_free_debug(void *ptr, size_t size)
|
||||
ASSERTF(ptr || size > 0, "ptr: %p, size: %llu", ptr,
|
||||
(unsigned long long) size);
|
||||
|
||||
atomic64_sub(size, &vmem_alloc_used);
|
||||
|
||||
vmem_alloc_used_sub(size);
|
||||
CDEBUG_LIMIT(D_INFO, "vmem_free(%p, %llu) (%lld/%llu)\n", ptr,
|
||||
(unsigned long long) size, atomic64_read(&vmem_alloc_used),
|
||||
(unsigned long long) size, vmem_alloc_used_read(),
|
||||
vmem_alloc_max);
|
||||
|
||||
memset(ptr, 0x5a, size);
|
||||
@@ -1969,8 +1969,8 @@ spl_kmem_init(void)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_KMEM
|
||||
atomic64_set(&kmem_alloc_used, 0);
|
||||
atomic64_set(&vmem_alloc_used, 0);
|
||||
kmem_alloc_used_set(0);
|
||||
vmem_alloc_used_set(0);
|
||||
|
||||
spl_kmem_init_tracking(&kmem_list, &kmem_lock, KMEM_TABLE_SIZE);
|
||||
spl_kmem_init_tracking(&vmem_list, &vmem_lock, VMEM_TABLE_SIZE);
|
||||
@@ -1986,14 +1986,14 @@ spl_kmem_fini(void)
|
||||
* allocation size and the first few bytes of what's located
|
||||
* at that address to aid in debugging. Performance is not
|
||||
* a serious concern here since it is module unload time. */
|
||||
if (atomic64_read(&kmem_alloc_used) != 0)
|
||||
if (kmem_alloc_used_read() != 0)
|
||||
CWARN("kmem leaked %ld/%ld bytes\n",
|
||||
atomic64_read(&kmem_alloc_used), kmem_alloc_max);
|
||||
kmem_alloc_used_read(), kmem_alloc_max);
|
||||
|
||||
|
||||
if (atomic64_read(&vmem_alloc_used) != 0)
|
||||
if (vmem_alloc_used_read() != 0)
|
||||
CWARN("vmem leaked %ld/%ld bytes\n",
|
||||
atomic64_read(&vmem_alloc_used), vmem_alloc_max);
|
||||
vmem_alloc_used_read(), vmem_alloc_max);
|
||||
|
||||
spl_kmem_fini_tracking(&kmem_list, &kmem_lock);
|
||||
spl_kmem_fini_tracking(&vmem_list, &vmem_lock);
|
||||
|
||||
+16
-4
@@ -409,8 +409,8 @@ proc_console_backoff(struct ctl_table *table, int write, struct file *filp,
|
||||
|
||||
#ifdef DEBUG_KMEM
|
||||
static int
|
||||
proc_doatomic64(struct ctl_table *table, int write, struct file *filp,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
proc_domemused(struct ctl_table *table, int write, struct file *filp,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long min = 0, max = ~0, val;
|
||||
@@ -425,7 +425,11 @@ proc_doatomic64(struct ctl_table *table, int write, struct file *filp,
|
||||
if (write) {
|
||||
*ppos += *lenp;
|
||||
} else {
|
||||
# ifdef HAVE_ATOMIC64_T
|
||||
val = atomic64_read((atomic64_t *)table->data);
|
||||
# else
|
||||
val = atomic_read((atomic_t *)table->data);
|
||||
# endif /* HAVE_ATOMIC64_T */
|
||||
rc = proc_doulongvec_minmax(&dummy, write, filp,
|
||||
buffer, lenp, ppos);
|
||||
}
|
||||
@@ -861,9 +865,13 @@ static struct ctl_table spl_kmem_table[] = {
|
||||
.ctl_name = CTL_KMEM_KMEMUSED,
|
||||
.procname = "kmem_used",
|
||||
.data = &kmem_alloc_used,
|
||||
# ifdef HAVE_ATOMIC64_T
|
||||
.maxlen = sizeof(atomic64_t),
|
||||
# else
|
||||
.maxlen = sizeof(atomic_t),
|
||||
# endif /* HAVE_ATOMIC64_T */
|
||||
.mode = 0444,
|
||||
.proc_handler = &proc_doatomic64,
|
||||
.proc_handler = &proc_domemused,
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_KMEM_KMEMMAX,
|
||||
@@ -879,9 +887,13 @@ static struct ctl_table spl_kmem_table[] = {
|
||||
.ctl_name = CTL_KMEM_VMEMUSED,
|
||||
.procname = "vmem_used",
|
||||
.data = &vmem_alloc_used,
|
||||
# ifdef HAVE_ATOMIC64_T
|
||||
.maxlen = sizeof(atomic64_t),
|
||||
# else
|
||||
.maxlen = sizeof(atomic_t),
|
||||
# endif /* HAVE_ATOMIC64_T */
|
||||
.mode = 0444,
|
||||
.proc_handler = &proc_doatomic64,
|
||||
.proc_handler = &proc_domemused,
|
||||
},
|
||||
{
|
||||
.ctl_name = CTL_KMEM_VMEMMAX,
|
||||
|
||||
Reference in New Issue
Block a user