mirror of
https://github.com/schoebel/mars
synced 2024-12-22 14:42:58 +00:00
259 lines
7.4 KiB
C
259 lines
7.4 KiB
C
/*
|
|
* MARS Long Distance Replication Software
|
|
*
|
|
* This file is part of MARS project: http://schoebel.github.io/mars/
|
|
*
|
|
* Copyright (C) 2010-2014 Thomas Schoebel-Theuer
|
|
* Copyright (C) 2011-2014 1&1 Internet AG
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#ifndef BRICK_MEM_H
|
|
#define BRICK_MEM_H
|
|
|
|
/* TRANSITIONAL compatibility to BOTH the old prepatch
|
|
* and the new wrapper around vfs_*(). Both will be replaced
|
|
* for kernel upstream.
|
|
*/
|
|
#include "compat.h"
|
|
|
|
#include <linux/mm_types.h>
|
|
|
|
#ifndef CONFIG_MARS_MODULE
|
|
// when unsure, include faked config file
|
|
#include "mars_config.h"
|
|
#endif
|
|
|
|
#define BRICK_DEBUG_MEM 4096
|
|
|
|
#ifndef CONFIG_MARS_DEBUG_MEM
|
|
#undef BRICK_DEBUG_MEM
|
|
#endif
|
|
#ifdef CONFIG_MARS_DEBUG_ORDER0
|
|
#define BRICK_DEBUG_ORDER0
|
|
#endif
|
|
|
|
#if defined(__GFP_NORETRY) && \
|
|
defined(__GFP_KSWAPD_RECLAIM) && \
|
|
defined(__GFP_RECLAIM)
|
|
#if !defined(__GFP_COLD) /* see upstream 453f85d43fa9 after v4.14 */
|
|
#define GFP_BRICK \
|
|
((GFP_NOIO & \
|
|
~__GFP_KSWAPD_RECLAIM & \
|
|
~__GFP_RECLAIM & \
|
|
~0x0u) | \
|
|
__GFP_NORETRY | \
|
|
0x0u)
|
|
#else
|
|
#define GFP_BRICK GFP_NOIO /* otherwise people may get alarmed by massses of stacktraces */
|
|
#endif
|
|
#else
|
|
/* very old kernels */
|
|
#warning Using outdated GFP_NOIO because your kernel does not reliably support OOM mitigation via __GFP_NORETRY and co
|
|
#define GFP_BRICK GFP_NOIO
|
|
#endif
|
|
|
|
extern long long brick_global_memavail;
|
|
extern long long brick_global_memlimit;
|
|
extern atomic64_t brick_global_block_used;
|
|
|
|
void msleep_backoff(int *ms);
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// compiler tweaking
|
|
|
|
/* Some functions are known to return non-null pointer values,
|
|
* at least under some Kconfig conditions.
|
|
*
|
|
* In code like...
|
|
*
|
|
* void *ptr = myfunction();
|
|
* if (unlikely(!ptr)) {
|
|
* printk("ERROR: this should not happen\n");
|
|
* goto fail;
|
|
* }
|
|
*
|
|
* ... the dead code elimination of gcc will not remove the if clause
|
|
* because the function might return a NULL value, even if a human
|
|
* would know that myfunction() does not return a NULL value.
|
|
*
|
|
* Unfortunately, the __attribute__((nonnull)) can only be applied
|
|
* to input parameters, but not to the return value.
|
|
*
|
|
* More unfortunately, a small inline wrapper does not help,
|
|
* because it seems that together with the elimination of the wrapper,
|
|
* its nonnull attribute seems to be eliminated alltogether.
|
|
* I don't know whether this is a bug or a feature (or just a weakness).
|
|
*
|
|
* Following is a small hack which solves the problem at least for gcc 4.7.
|
|
*
|
|
* In order to be useful, the -fdelete-null-pointer-checks must be set.
|
|
* Since MARS is superuser-only anyway, enabling this for MARS should not
|
|
* be a security risk
|
|
* (c.f. upstream kernel commit a3ca86aea507904148870946d599e07a340b39bf)
|
|
*/
|
|
extern inline
|
|
void *__mark_ptr_nonnull(void *_ptr)
|
|
{
|
|
char *ptr = _ptr;
|
|
// fool gcc to believe that the pointer were dereferenced...
|
|
asm("" : : "X" (*ptr));
|
|
return ptr;
|
|
}
|
|
|
|
/* All the brick memory allocations need to succeed.
|
|
* In case of low memory, they will retry (forever),
|
|
* but only after some pause.
|
|
*
|
|
* This allows OOM to catch in, and to (hopefully)
|
|
* improve the situation.
|
|
*/
|
|
#define brick_mark_nonnull __mark_ptr_nonnull
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// small memory allocation (use this only for len < PAGE_SIZE)
|
|
|
|
#define brick_mem_alloc(_len_) \
|
|
({ \
|
|
void *_res_ = _brick_mem_alloc(_len_, __LINE__); \
|
|
brick_mark_nonnull(_res_); \
|
|
})
|
|
|
|
#define brick_zmem_alloc(_len_) \
|
|
({ \
|
|
void *_res_ = _brick_mem_alloc(_len_, __LINE__); \
|
|
_res_ = brick_mark_nonnull(_res_); \
|
|
if (_res_) { \
|
|
memset(_res_, 0, _len_); \
|
|
} \
|
|
_res_; \
|
|
})
|
|
|
|
#define brick_mem_free(_data_) \
|
|
do { \
|
|
if (_data_) { \
|
|
_brick_mem_free(_data_, __LINE__); \
|
|
SET_PTR_NULL(_data_); \
|
|
} \
|
|
} while(0)
|
|
|
|
|
|
// don't use the following directly
|
|
extern void *_brick_mem_alloc(int len, int line) __attribute__((malloc)) __attribute__((alloc_size(1)));
|
|
extern void _brick_mem_free(void *data, int line);
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// string memory allocation
|
|
|
|
#define BRICK_STRING_LEN 1024 /* default value when len == 0 */
|
|
|
|
#define brick_string_alloc(_len_) \
|
|
({ \
|
|
char *_res_ = _brick_string_alloc((_len_), __LINE__); \
|
|
(char*)brick_mark_nonnull(_res_); \
|
|
})
|
|
|
|
#define brick_strndup(_orig_,_len_) \
|
|
({ \
|
|
char *_res_ = _brick_string_alloc((_len_) + 1, __LINE__); \
|
|
_res_ = brick_mark_nonnull(_res_); \
|
|
if (_res_) { \
|
|
strncpy(_res_, (_orig_), (_len_)); \
|
|
/* always null-terminate for safety */ \
|
|
_res_[_len_] = '\0'; \
|
|
} \
|
|
(char*)brick_mark_nonnull(_res_); \
|
|
})
|
|
|
|
#define brick_strdup(_orig_) \
|
|
({ \
|
|
int _len_ = strlen(_orig_); \
|
|
char *_res_ = _brick_string_alloc((_len_) + 1, __LINE__); \
|
|
_res_ = brick_mark_nonnull(_res_); \
|
|
if (_res_) { \
|
|
strncpy(_res_, (_orig_), (_len_) + 1); \
|
|
} \
|
|
(char*)brick_mark_nonnull(_res_); \
|
|
})
|
|
|
|
#define brick_string_free(_data_) \
|
|
do { \
|
|
if (_data_) { \
|
|
_brick_string_free(_data_, __LINE__); \
|
|
SET_PTR_NULL(_data_); \
|
|
} \
|
|
} while(0)
|
|
|
|
// don't use the following directly
|
|
extern char *_brick_string_alloc(int len, int line) __attribute__((malloc));
|
|
extern void _brick_string_free(const char *data, int line);
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// block memory allocation (for aligned multiples of 512 resp PAGE_SIZE)
|
|
|
|
#define brick_block_alloc(_pos_,_len_) \
|
|
({ \
|
|
void *_res_ = _brick_block_alloc((_pos_), (_len_), __LINE__); \
|
|
brick_mark_nonnull(_res_); \
|
|
})
|
|
|
|
#define brick_block_free(_data_,_len_)\
|
|
do { \
|
|
if (_data_) { \
|
|
_brick_block_free((_data_), (_len_), __LINE__); \
|
|
SET_PTR_NULL(_data_); \
|
|
} \
|
|
} while(0)
|
|
|
|
extern struct page *brick_iomap(void *data, int *offset, int *len);
|
|
|
|
// don't use the following directly
|
|
extern void *_brick_block_alloc(loff_t pos, int len, int line) __attribute__((malloc)) __attribute__((alloc_size(2)));
|
|
extern void _brick_block_free(void *data, int len, int cline);
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// reservations / preallocation
|
|
|
|
#define BRICK_MAX_ORDER 11
|
|
|
|
#ifdef CONFIG_MARS_MEM_PREALLOC
|
|
extern int brick_allow_freelist;
|
|
|
|
extern int brick_pre_reserve[BRICK_MAX_ORDER+1];
|
|
extern int brick_mem_freelist_max[BRICK_MAX_ORDER+1];
|
|
extern int brick_mem_alloc_count[BRICK_MAX_ORDER+1];
|
|
extern int brick_mem_alloc_max[BRICK_MAX_ORDER+1];
|
|
|
|
extern int brick_mem_reserve(void);
|
|
|
|
#endif
|
|
|
|
extern void brick_mem_statistics(bool final);
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// init
|
|
|
|
extern int init_brick_mem(void);
|
|
extern void exit_brick_mem(void);
|
|
|
|
#endif
|