summaryrefslogtreecommitdiff
path: root/pfinet/linux-src/include/linux/pagemap.h
blob: 1f5a62dd992622537448976bed85eece53065955 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#ifndef _LINUX_PAGEMAP_H
#define _LINUX_PAGEMAP_H

#include <asm/system.h>

/*
 * Page-mapping primitive inline functions
 *
 * Copyright 1995 Linus Torvalds
 */

#include <linux/mm.h>
#include <linux/fs.h>

static inline unsigned long page_address(struct page * page)
{
	return PAGE_OFFSET + PAGE_SIZE * (page - mem_map);
}

/*
 * The page cache can done in larger chunks than
 * one page, because it allows for more efficient
 * throughput (it can then be mapped into user
 * space in smaller chunks for same flexibility).
 *
 * Or rather, it _will_ be done in larger chunks.
 */
#define PAGE_CACHE_SHIFT	PAGE_SHIFT
#define PAGE_CACHE_SIZE		PAGE_SIZE
#define PAGE_CACHE_MASK		PAGE_MASK

#define page_cache_alloc()	__get_free_page(GFP_USER)
#define page_cache_free(x)	free_page(x)
#define page_cache_release(x)	__free_page(x)

/*
 * From a kernel address, get the "struct page *"
 */
#define page_cache_entry(x)	(mem_map + MAP_NR(x))

#define PAGE_HASH_BITS 12
#define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)

extern unsigned long page_cache_size; /* # of pages currently in the hash table */
extern struct page * page_hash_table[PAGE_HASH_SIZE];

/*
 * We use a power-of-two hash table to avoid a modulus,
 * and get a reasonable hash by knowing roughly how the
 * inode pointer and offsets are distributed (ie, we
 * roughly know which bits are "significant")
 */
static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
{
#define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
#define o (offset >> PAGE_SHIFT)
#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
	return s(i+o) & (PAGE_HASH_SIZE-1);
#undef i
#undef o
#undef s
}

#define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))

static inline struct page * __find_page(struct inode * inode, unsigned long offset, struct page *page)
{
	goto inside;
	for (;;) {
		page = page->next_hash;
inside:
		if (!page)
			goto not_found;
		if (page->inode != inode)
			continue;
		if (page->offset == offset)
			break;
	}
	/* Found the page. */
	atomic_inc(&page->count);
	set_bit(PG_referenced, &page->flags);
not_found:
	return page;
}

static inline struct page *find_page(struct inode * inode, unsigned long offset)
{
	return __find_page(inode, offset, *page_hash(inode, offset));
}

static inline void remove_page_from_hash_queue(struct page * page)
{
	if(page->pprev_hash) {
		if(page->next_hash)
			page->next_hash->pprev_hash = page->pprev_hash;
		*page->pprev_hash = page->next_hash;
		page->pprev_hash = NULL;
	}
	page_cache_size--;
}

static inline void __add_page_to_hash_queue(struct page * page, struct page **p)
{
	page_cache_size++;
	if((page->next_hash = *p) != NULL)
		(*p)->pprev_hash = &page->next_hash;
	*p = page;
	page->pprev_hash = p;
}

static inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long offset)
{
	__add_page_to_hash_queue(page, page_hash(inode,offset));
}

static inline void remove_page_from_inode_queue(struct page * page)
{
	struct inode * inode = page->inode;

	page->inode = NULL;
	inode->i_nrpages--;
	if (inode->i_pages == page)
		inode->i_pages = page->next;
	if (page->next)
		page->next->prev = page->prev;
	if (page->prev)
		page->prev->next = page->next;
	page->next = NULL;
	page->prev = NULL;
}

static inline void add_page_to_inode_queue(struct inode * inode, struct page * page)
{
	struct page **p = &inode->i_pages;

	inode->i_nrpages++;
	page->inode = inode;
	page->prev = NULL;
	if ((page->next = *p) != NULL)
		page->next->prev = page;
	*p = page;
}

extern void __wait_on_page(struct page *);
static inline void wait_on_page(struct page * page)
{
	if (PageLocked(page))
		__wait_on_page(page);
}

extern void update_vm_cache_conditional(struct inode *, unsigned long, const char *, int, unsigned long);
extern void update_vm_cache(struct inode *, unsigned long, const char *, int);

#endif