10
10
* Released under the terms of GNU General Public License Version 2.0
13
#ifdef CONFIG_ZRAM_DEBUG
17
#include <linux/module.h>
18
#include <linux/kernel.h>
13
19
#include <linux/bitops.h>
14
20
#include <linux/errno.h>
15
21
#include <linux/highmem.h>
49
* Given <page, offset> pair, provide a derefrencable pointer.
55
* Given <page, offset> pair, provide a dereferencable pointer.
50
56
* This is called from xv_malloc/xv_free path, so it
51
57
* needs to be fast.
200
206
nextblock->link.prev_page = page;
201
207
nextblock->link.prev_offset = offset;
202
208
put_ptr_atomic(nextblock, KM_USER1);
209
/* If there was a next page then the free bits are set. */
205
213
__set_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]);
210
* Remove block from head of freelist. Index 'slindex' identifies the freelist.
212
static void remove_block_head(struct xv_pool *pool,
213
struct block_header *block, u32 slindex)
215
struct block_header *tmpblock;
216
u32 flindex = slindex / BITS_PER_LONG;
218
pool->freelist[slindex].page = block->link.next_page;
219
pool->freelist[slindex].offset = block->link.next_offset;
220
block->link.prev_page = NULL;
221
block->link.prev_offset = 0;
223
if (!pool->freelist[slindex].page) {
224
__clear_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]);
225
if (!pool->slbitmap[flindex])
226
__clear_bit(flindex, &pool->flbitmap);
229
* DEBUG ONLY: We need not reinitialize freelist head previous
230
* pointer to 0 - we never depend on its value. But just for
231
* sanity, lets do it.
233
tmpblock = get_ptr_atomic(pool->freelist[slindex].page,
234
pool->freelist[slindex].offset, KM_USER1);
235
tmpblock->link.prev_page = NULL;
236
tmpblock->link.prev_offset = 0;
237
put_ptr_atomic(tmpblock, KM_USER1);
242
218
* Remove block from freelist. Index 'slindex' identifies the freelist.
244
220
static void remove_block(struct xv_pool *pool, struct page *page, u32 offset,
245
221
struct block_header *block, u32 slindex)
223
u32 flindex = slindex / BITS_PER_LONG;
248
224
struct block_header *tmpblock;
250
if (pool->freelist[slindex].page == page
251
&& pool->freelist[slindex].offset == offset) {
252
remove_block_head(pool, block, slindex);
256
flindex = slindex / BITS_PER_LONG;
258
226
if (block->link.prev_page) {
259
227
tmpblock = get_ptr_atomic(block->link.prev_page,
260
228
block->link.prev_offset, KM_USER1);
270
238
tmpblock->link.prev_offset = block->link.prev_offset;
271
239
put_ptr_atomic(tmpblock, KM_USER1);
242
/* Is this block is at the head of the freelist? */
243
if (pool->freelist[slindex].page == page
244
&& pool->freelist[slindex].offset == offset) {
246
pool->freelist[slindex].page = block->link.next_page;
247
pool->freelist[slindex].offset = block->link.next_offset;
249
if (pool->freelist[slindex].page) {
250
struct block_header *tmpblock;
251
tmpblock = get_ptr_atomic(pool->freelist[slindex].page,
252
pool->freelist[slindex].offset,
254
tmpblock->link.prev_page = NULL;
255
tmpblock->link.prev_offset = 0;
256
put_ptr_atomic(tmpblock, KM_USER1);
258
/* This freelist bucket is empty */
259
__clear_bit(slindex % BITS_PER_LONG,
260
&pool->slbitmap[flindex]);
261
if (!pool->slbitmap[flindex])
262
__clear_bit(flindex, &pool->flbitmap);
266
block->link.prev_page = NULL;
267
block->link.prev_offset = 0;
268
block->link.next_page = NULL;
269
block->link.next_offset = 0;
379
378
block = get_ptr_atomic(*page, *offset, KM_USER0);
381
remove_block_head(pool, block, index);
380
remove_block(pool, *page, *offset, block, index);
383
382
/* Split the block if required */
384
383
tmpoffset = *offset + size + XV_ALIGN;