Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
ea982d9f
Commit
ea982d9f
authored
Nov 11, 2013
by
Pekka Enberg
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'slab/struct-page' into slab/next
parents
d56791b3
7e007355
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
243 additions
and
365 deletions
+243
-365
include/linux/mm_types.h
include/linux/mm_types.h
+16
-8
include/linux/slab.h
include/linux/slab.h
+8
-1
include/linux/slab_def.h
include/linux/slab_def.h
+2
-2
mm/slab.c
mm/slab.c
+217
-354
No files found.
include/linux/mm_types.h
View file @
ea982d9f
...
...
@@ -42,6 +42,7 @@ struct page {
/* First double word block */
unsigned
long
flags
;
/* Atomic flags, some possibly
* updated asynchronously */
union
{
struct
address_space
*
mapping
;
/* If low bit clear, points to
* inode address_space, or NULL.
* If page mapped as anonymous
...
...
@@ -49,11 +50,14 @@ struct page {
* it points to anon_vma object:
* see PAGE_MAPPING_ANON below.
*/
void
*
s_mem
;
/* slab first object */
};
/* Second double word */
struct
{
union
{
pgoff_t
index
;
/* Our offset within mapping. */
void
*
freelist
;
/* sl
ub/slo
b first free object */
void
*
freelist
;
/* sl
[aou]
b first free object */
bool
pfmemalloc
;
/* If set by the page allocator,
* ALLOC_NO_WATERMARKS was set
* and the low watermark was not
...
...
@@ -109,6 +113,7 @@ struct page {
};
atomic_t
_count
;
/* Usage count, see below. */
};
unsigned
int
active
;
/* SLAB */
};
};
...
...
@@ -130,6 +135,9 @@ struct page {
struct
list_head
list
;
/* slobs list of pages */
struct
slab
*
slab_page
;
/* slab fields */
struct
rcu_head
rcu_head
;
/* Used by SLAB
* when destroying via RCU
*/
};
/* Remainder is not double word aligned */
...
...
include/linux/slab.h
View file @
ea982d9f
...
...
@@ -51,7 +51,14 @@
* }
* rcu_read_unlock();
*
* See also the comment on struct slab_rcu in mm/slab.c.
* This is useful if we need to approach a kernel structure obliquely,
* from its address obtained without the usual locking. We can lock
* the structure to stabilize it and check it's still at the given address,
* only if we can be sure that the memory has not been meanwhile reused
* for some other kind of object (which our subsystem's lock might corrupt).
*
* rcu_read_lock before reading the address, then rcu_read_unlock after
* taking the spinlock within the structure expected at that address.
*/
#define SLAB_DESTROY_BY_RCU 0x00080000UL
/* Defer freeing slabs to RCU */
#define SLAB_MEM_SPREAD 0x00100000UL
/* Spread some memory over cpuset */
...
...
include/linux/slab_def.h
View file @
ea982d9f
...
...
@@ -41,8 +41,8 @@ struct kmem_cache {
size_t
colour
;
/* cache colouring range */
unsigned
int
colour_off
;
/* colour offset */
struct
kmem_cache
*
slabp
_cache
;
unsigned
int
slab
_size
;
struct
kmem_cache
*
freelist
_cache
;
unsigned
int
freelist
_size
;
/* constructor func */
void
(
*
ctor
)(
void
*
obj
);
...
...
mm/slab.c
View file @
ea982d9f
...
...
@@ -163,72 +163,6 @@
*/
static
bool
pfmemalloc_active
__read_mostly
;
/*
* kmem_bufctl_t:
*
* Bufctl's are used for linking objs within a slab
* linked offsets.
*
* This implementation relies on "struct page" for locating the cache &
* slab an object belongs to.
* This allows the bufctl structure to be small (one int), but limits
* the number of objects a slab (not a cache) can contain when off-slab
* bufctls are used. The limit is the size of the largest general cache
* that does not use off-slab slabs.
* For 32bit archs with 4 kB pages, is this 56.
* This is not serious, as it is only for large objects, when it is unwise
* to have too many per slab.
* Note: This limit can be raised by introducing a general cache whose size
* is less than 512 (PAGE_SIZE<<3), but greater than 256.
*/
typedef
unsigned
int
kmem_bufctl_t
;
#define BUFCTL_END (((kmem_bufctl_t)(~0U))-0)
#define BUFCTL_FREE (((kmem_bufctl_t)(~0U))-1)
#define BUFCTL_ACTIVE (((kmem_bufctl_t)(~0U))-2)
#define SLAB_LIMIT (((kmem_bufctl_t)(~0U))-3)
/*
* struct slab_rcu
*
* slab_destroy on a SLAB_DESTROY_BY_RCU cache uses this structure to
* arrange for kmem_freepages to be called via RCU. This is useful if
* we need to approach a kernel structure obliquely, from its address
* obtained without the usual locking. We can lock the structure to
* stabilize it and check it's still at the given address, only if we
* can be sure that the memory has not been meanwhile reused for some
* other kind of object (which our subsystem's lock might corrupt).
*
* rcu_read_lock before reading the address, then rcu_read_unlock after
* taking the spinlock within the structure expected at that address.
*/
struct
slab_rcu
{
struct
rcu_head
head
;
struct
kmem_cache
*
cachep
;
void
*
addr
;
};
/*
* struct slab
*
* Manages the objs in a slab. Placed either at the beginning of mem allocated
* for a slab, or allocated from an general cache.
* Slabs are chained into three list: fully used, partial, fully free slabs.
*/
struct
slab
{
union
{
struct
{
struct
list_head
list
;
unsigned
long
colouroff
;
void
*
s_mem
;
/* including colour offset */
unsigned
int
inuse
;
/* num of objs active in slab */
kmem_bufctl_t
free
;
unsigned
short
nodeid
;
};
struct
slab_rcu
__slab_cover_slab_rcu
;
};
};
/*
* struct array_cache
*
...
...
@@ -456,18 +390,10 @@ static inline struct kmem_cache *virt_to_cache(const void *obj)
return
page
->
slab_cache
;
}
static
inline
struct
slab
*
virt_to_slab
(
const
void
*
obj
)
{
struct
page
*
page
=
virt_to_head_page
(
obj
);
VM_BUG_ON
(
!
PageSlab
(
page
));
return
page
->
slab_page
;
}
static
inline
void
*
index_to_obj
(
struct
kmem_cache
*
cache
,
struct
slab
*
slab
,
static
inline
void
*
index_to_obj
(
struct
kmem_cache
*
cache
,
struct
page
*
page
,
unsigned
int
idx
)
{
return
slab
->
s_mem
+
cache
->
size
*
idx
;
return
page
->
s_mem
+
cache
->
size
*
idx
;
}
/*
...
...
@@ -477,9 +403,9 @@ static inline void *index_to_obj(struct kmem_cache *cache, struct slab *slab,
* reciprocal_divide(offset, cache->reciprocal_buffer_size)
*/
static
inline
unsigned
int
obj_to_index
(
const
struct
kmem_cache
*
cache
,
const
struct
slab
*
slab
,
void
*
obj
)
const
struct
page
*
page
,
void
*
obj
)
{
u32
offset
=
(
obj
-
slab
->
s_mem
);
u32
offset
=
(
obj
-
page
->
s_mem
);
return
reciprocal_divide
(
offset
,
cache
->
reciprocal_buffer_size
);
}
...
...
@@ -641,7 +567,7 @@ static inline struct array_cache *cpu_cache_get(struct kmem_cache *cachep)
static
size_t
slab_mgmt_size
(
size_t
nr_objs
,
size_t
align
)
{
return
ALIGN
(
sizeof
(
struct
slab
)
+
nr_objs
*
sizeof
(
kmem_bufctl_
t
),
align
);
return
ALIGN
(
nr_objs
*
sizeof
(
unsigned
in
t
),
align
);
}
/*
...
...
@@ -660,8 +586,7 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
* on it. For the latter case, the memory allocated for a
* slab is used for:
*
* - The struct slab
* - One kmem_bufctl_t for each object
* - One unsigned int for each object
* - Padding to respect alignment of @align
* - @buffer_size bytes for each object
*
...
...
@@ -674,8 +599,6 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
mgmt_size
=
0
;
nr_objs
=
slab_size
/
buffer_size
;
if
(
nr_objs
>
SLAB_LIMIT
)
nr_objs
=
SLAB_LIMIT
;
}
else
{
/*
* Ignore padding for the initial guess. The padding
...
...
@@ -685,8 +608,7 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
* into the memory allocation when taking the padding
* into account.
*/
nr_objs
=
(
slab_size
-
sizeof
(
struct
slab
))
/
(
buffer_size
+
sizeof
(
kmem_bufctl_t
));
nr_objs
=
(
slab_size
)
/
(
buffer_size
+
sizeof
(
unsigned
int
));
/*
* This calculated number will be either the right
...
...
@@ -696,9 +618,6 @@ static void cache_estimate(unsigned long gfporder, size_t buffer_size,
>
slab_size
)
nr_objs
--
;
if
(
nr_objs
>
SLAB_LIMIT
)
nr_objs
=
SLAB_LIMIT
;
mgmt_size
=
slab_mgmt_size
(
nr_objs
,
align
);
}
*
num
=
nr_objs
;
...
...
@@ -829,10 +748,8 @@ static struct array_cache *alloc_arraycache(int node, int entries,
return
nc
;
}
static
inline
bool
is_slab_pfmemalloc
(
struct
slab
*
slabp
)
static
inline
bool
is_slab_pfmemalloc
(
struct
page
*
page
)
{
struct
page
*
page
=
virt_to_page
(
slabp
->
s_mem
);
return
PageSlabPfmemalloc
(
page
);
}
...
...
@@ -841,23 +758,23 @@ static void recheck_pfmemalloc_active(struct kmem_cache *cachep,
struct
array_cache
*
ac
)
{
struct
kmem_cache_node
*
n
=
cachep
->
node
[
numa_mem_id
()];
struct
slab
*
slabp
;
struct
page
*
page
;
unsigned
long
flags
;
if
(
!
pfmemalloc_active
)
return
;
spin_lock_irqsave
(
&
n
->
list_lock
,
flags
);
list_for_each_entry
(
slabp
,
&
n
->
slabs_full
,
list
)
if
(
is_slab_pfmemalloc
(
slabp
))
list_for_each_entry
(
page
,
&
n
->
slabs_full
,
lru
)
if
(
is_slab_pfmemalloc
(
page
))
goto
out
;
list_for_each_entry
(
slabp
,
&
n
->
slabs_partial
,
list
)
if
(
is_slab_pfmemalloc
(
slabp
))
list_for_each_entry
(
page
,
&
n
->
slabs_partial
,
lru
)
if
(
is_slab_pfmemalloc
(
page
))
goto
out
;
list_for_each_entry
(
slabp
,
&
n
->
slabs_free
,
list
)
if
(
is_slab_pfmemalloc
(
slabp
))
list_for_each_entry
(
page
,
&
n
->
slabs_free
,
lru
)
if
(
is_slab_pfmemalloc
(
page
))
goto
out
;
pfmemalloc_active
=
false
;
...
...
@@ -897,8 +814,8 @@ static void *__ac_get_obj(struct kmem_cache *cachep, struct array_cache *ac,
*/
n
=
cachep
->
node
[
numa_mem_id
()];
if
(
!
list_empty
(
&
n
->
slabs_free
)
&&
force_refill
)
{
struct
slab
*
slabp
=
virt_to_slab
(
objp
);
ClearPageSlabPfmemalloc
(
virt_to_head_page
(
slabp
->
s_mem
)
);
struct
page
*
page
=
virt_to_head_page
(
objp
);
ClearPageSlabPfmemalloc
(
page
);
clear_obj_pfmemalloc
(
&
objp
);
recheck_pfmemalloc_active
(
cachep
,
ac
);
return
objp
;
...
...
@@ -1099,8 +1016,7 @@ static void drain_alien_cache(struct kmem_cache *cachep,
static
inline
int
cache_free_alien
(
struct
kmem_cache
*
cachep
,
void
*
objp
)
{
struct
slab
*
slabp
=
virt_to_slab
(
objp
);
int
nodeid
=
slabp
->
nodeid
;
int
nodeid
=
page_to_nid
(
virt_to_page
(
objp
));
struct
kmem_cache_node
*
n
;
struct
array_cache
*
alien
=
NULL
;
int
node
;
...
...
@@ -1111,7 +1027,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
* Make sure we are not freeing a object from another node to the array
* cache on this cpu.
*/
if
(
likely
(
slabp
->
nodeid
==
node
))
if
(
likely
(
nodeid
==
node
))
return
0
;
n
=
cachep
->
node
[
node
];
...
...
@@ -1512,6 +1428,8 @@ void __init kmem_cache_init(void)
{
int
i
;
BUILD_BUG_ON
(
sizeof
(((
struct
page
*
)
NULL
)
->
lru
)
<
sizeof
(
struct
rcu_head
));
kmem_cache
=
&
kmem_cache_boot
;
setup_node_pointer
(
kmem_cache
);
...
...
@@ -1687,7 +1605,7 @@ static noinline void
slab_out_of_memory
(
struct
kmem_cache
*
cachep
,
gfp_t
gfpflags
,
int
nodeid
)
{
struct
kmem_cache_node
*
n
;
struct
slab
*
slabp
;
struct
page
*
page
;
unsigned
long
flags
;
int
node
;
...
...
@@ -1706,15 +1624,15 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
continue
;
spin_lock_irqsave
(
&
n
->
list_lock
,
flags
);
list_for_each_entry
(
slabp
,
&
n
->
slabs_full
,
list
)
{
list_for_each_entry
(
page
,
&
n
->
slabs_full
,
lru
)
{
active_objs
+=
cachep
->
num
;
active_slabs
++
;
}
list_for_each_entry
(
slabp
,
&
n
->
slabs_partial
,
list
)
{
active_objs
+=
slabp
->
inus
e
;
list_for_each_entry
(
page
,
&
n
->
slabs_partial
,
lru
)
{
active_objs
+=
page
->
activ
e
;
active_slabs
++
;
}
list_for_each_entry
(
slabp
,
&
n
->
slabs_free
,
list
)
list_for_each_entry
(
page
,
&
n
->
slabs_free
,
lru
)
num_slabs
++
;
free_objects
+=
n
->
free_objects
;
...
...
@@ -1736,19 +1654,11 @@ slab_out_of_memory(struct kmem_cache *cachep, gfp_t gfpflags, int nodeid)
* did not request dmaable memory, we might get it, but that
* would be relatively rare and ignorable.
*/
static
void
*
kmem_getpages
(
struct
kmem_cache
*
cachep
,
gfp_t
flags
,
int
nodeid
)
static
struct
page
*
kmem_getpages
(
struct
kmem_cache
*
cachep
,
gfp_t
flags
,
int
nodeid
)
{
struct
page
*
page
;
int
nr_pages
;
int
i
;
#ifndef CONFIG_MMU
/*
* Nommu uses slab's for process anonymous memory allocations, and thus
* requires __GFP_COMP to properly refcount higher order allocations
*/
flags
|=
__GFP_COMP
;
#endif
flags
|=
cachep
->
allocflags
;
if
(
cachep
->
flags
&
SLAB_RECLAIM_ACCOUNT
)
...
...
@@ -1772,12 +1682,9 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
else
add_zone_page_state
(
page_zone
(
page
),
NR_SLAB_UNRECLAIMABLE
,
nr_pages
);
for
(
i
=
0
;
i
<
nr_pages
;
i
++
)
{
__SetPageSlab
(
page
+
i
);
__SetPageSlab
(
page
);
if
(
page
->
pfmemalloc
)
SetPageSlabPfmemalloc
(
page
+
i
);
}
SetPageSlabPfmemalloc
(
page
);
memcg_bind_pages
(
cachep
,
cachep
->
gfporder
);
if
(
kmemcheck_enabled
&&
!
(
cachep
->
flags
&
SLAB_NOTRACK
))
{
...
...
@@ -1789,17 +1696,15 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
kmemcheck_mark_unallocated_pages
(
page
,
nr_pages
);
}
return
page
_address
(
page
)
;
return
page
;
}
/*
* Interface to system's page release.
*/
static
void
kmem_freepages
(
struct
kmem_cache
*
cachep
,
void
*
addr
)
static
void
kmem_freepages
(
struct
kmem_cache
*
cachep
,
struct
page
*
page
)
{
unsigned
long
i
=
(
1
<<
cachep
->
gfporder
);
struct
page
*
page
=
virt_to_page
(
addr
);
const
unsigned
long
nr_freed
=
i
;
const
unsigned
long
nr_freed
=
(
1
<<
cachep
->
gfporder
);
kmemcheck_free_shadow
(
page
,
cachep
->
gfporder
);
...
...
@@ -1809,27 +1714,28 @@ static void kmem_freepages(struct kmem_cache *cachep, void *addr)
else
sub_zone_page_state
(
page_zone
(
page
),
NR_SLAB_UNRECLAIMABLE
,
nr_freed
);
while
(
i
--
)
{
BUG_ON
(
!
PageSlab
(
page
));
__ClearPageSlabPfmemalloc
(
page
);
__ClearPageSlab
(
page
);
page
++
;
}
page_mapcount_reset
(
page
)
;
page
->
mapping
=
NULL
;
memcg_release_pages
(
cachep
,
cachep
->
gfporder
);
if
(
current
->
reclaim_state
)
current
->
reclaim_state
->
reclaimed_slab
+=
nr_freed
;
free_memcg_kmem_pages
((
unsigned
long
)
addr
,
cachep
->
gfporder
);
__free_memcg_kmem_pages
(
page
,
cachep
->
gfporder
);
}
static
void
kmem_rcu_free
(
struct
rcu_head
*
head
)
{
struct
slab_rcu
*
slab_rcu
=
(
struct
slab_rcu
*
)
head
;
struct
kmem_cache
*
cachep
=
slab_rcu
->
cachep
;
struct
kmem_cache
*
cachep
;
struct
page
*
page
;
kmem_freepages
(
cachep
,
slab_rcu
->
addr
);
if
(
OFF_SLAB
(
cachep
))
kmem_cache_free
(
cachep
->
slabp_cache
,
slab_rcu
);
page
=
container_of
(
head
,
struct
page
,
rcu_head
);
cachep
=
page
->
slab_cache
;
kmem_freepages
(
cachep
,
page
);
}
#if DEBUG
...
...
@@ -1978,19 +1884,19 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
/* Print some data about the neighboring objects, if they
* exist:
*/
struct
slab
*
slabp
=
virt_to_slab
(
objp
);
struct
page
*
page
=
virt_to_head_page
(
objp
);
unsigned
int
objnr
;
objnr
=
obj_to_index
(
cachep
,
slabp
,
objp
);
objnr
=
obj_to_index
(
cachep
,
page
,
objp
);
if
(
objnr
)
{
objp
=
index_to_obj
(
cachep
,
slabp
,
objnr
-
1
);
objp
=
index_to_obj
(
cachep
,
page
,
objnr
-
1
);
realobj
=
(
char
*
)
objp
+
obj_offset
(
cachep
);
printk
(
KERN_ERR
"Prev obj: start=%p, len=%d
\n
"
,
realobj
,
size
);
print_objinfo
(
cachep
,
objp
,
2
);
}
if
(
objnr
+
1
<
cachep
->
num
)
{
objp
=
index_to_obj
(
cachep
,
slabp
,
objnr
+
1
);
objp
=
index_to_obj
(
cachep
,
page
,
objnr
+
1
);
realobj
=
(
char
*
)
objp
+
obj_offset
(
cachep
);
printk
(
KERN_ERR
"Next obj: start=%p, len=%d
\n
"
,
realobj
,
size
);
...
...
@@ -2001,11 +1907,12 @@ static void check_poison_obj(struct kmem_cache *cachep, void *objp)
#endif
#if DEBUG
static
void
slab_destroy_debugcheck
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
)
static
void
slab_destroy_debugcheck
(
struct
kmem_cache
*
cachep
,
struct
page
*
page
)
{
int
i
;
for
(
i
=
0
;
i
<
cachep
->
num
;
i
++
)
{
void
*
objp
=
index_to_obj
(
cachep
,
slabp
,
i
);
void
*
objp
=
index_to_obj
(
cachep
,
page
,
i
);
if
(
cachep
->
flags
&
SLAB_POISON
)
{
#ifdef CONFIG_DEBUG_PAGEALLOC
...
...
@@ -2030,7 +1937,8 @@ static void slab_destroy_debugcheck(struct kmem_cache *cachep, struct slab *slab
}
}
#else
static
void
slab_destroy_debugcheck
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
)
static
void
slab_destroy_debugcheck
(
struct
kmem_cache
*
cachep
,
struct
page
*
page
)
{
}
#endif
...
...
@@ -2044,23 +1952,34 @@ static void slab_destroy_debugcheck(struct kmem_cache *cachep, struct slab *slab
* Before calling the slab must have been unlinked from the cache. The
* cache-lock is not held/needed.
*/
static
void
slab_destroy
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
)
static
void
slab_destroy
(
struct
kmem_cache
*
cachep
,
struct
page
*
page
)
{
void
*
addr
=
slabp
->
s_mem
-
slabp
->
colouroff
;
void
*
freelist
;
slab_destroy_debugcheck
(
cachep
,
slabp
);
freelist
=
page
->
freelist
;
slab_destroy_debugcheck
(
cachep
,
page
);
if
(
unlikely
(
cachep
->
flags
&
SLAB_DESTROY_BY_RCU
))
{
struct
slab_rcu
*
slab_rcu
;
struct
rcu_head
*
head
;
/*
* RCU free overloads the RCU head over the LRU.
* slab_page has been overloeaded over the LRU,
* however it is not used from now on so that
* we can use it safely.
*/
head
=
(
void
*
)
&
page
->
rcu_head
;
call_rcu
(
head
,
kmem_rcu_free
);
slab_rcu
=
(
struct
slab_rcu
*
)
slabp
;
slab_rcu
->
cachep
=
cachep
;
slab_rcu
->
addr
=
addr
;
call_rcu
(
&
slab_rcu
->
head
,
kmem_rcu_free
);
}
else
{
kmem_freepages
(
cachep
,
addr
);
if
(
OFF_SLAB
(
cachep
))
kmem_cache_free
(
cachep
->
slabp_cache
,
slabp
);
kmem_freepages
(
cachep
,
page
);
}
/*
* From now on, we don't use freelist
* although actual page can be freed in rcu context
*/
if
(
OFF_SLAB
(
cachep
))
kmem_cache_free
(
cachep
->
freelist_cache
,
freelist
);
}
/**
...
...
@@ -2097,8 +2016,8 @@ static size_t calculate_slab_order(struct kmem_cache *cachep,
* use off-slab slabs. Needed to avoid a possible
* looping condition in cache_grow().
*/
offslab_limit
=
size
-
sizeof
(
struct
slab
)
;
offslab_limit
/=
sizeof
(
kmem_bufctl_
t
);
offslab_limit
=
size
;
offslab_limit
/=
sizeof
(
unsigned
in
t
);
if
(
num
>
offslab_limit
)
break
;
...
...
@@ -2220,7 +2139,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep, gfp_t gfp)
int
__kmem_cache_create
(
struct
kmem_cache
*
cachep
,
unsigned
long
flags
)
{
size_t
left_over
,
slab
_size
,
ralign
;
size_t
left_over
,
freelist
_size
,
ralign
;
gfp_t
gfp
;
int
err
;
size_t
size
=
cachep
->
size
;
...
...
@@ -2339,22 +2258,21 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
if
(
!
cachep
->
num
)
return
-
E2BIG
;
slab_size
=
ALIGN
(
cachep
->
num
*
sizeof
(
kmem_bufctl_t
)
+
sizeof
(
struct
slab
),
cachep
->
align
);
freelist_size
=
ALIGN
(
cachep
->
num
*
sizeof
(
unsigned
int
),
cachep
->
align
);
/*
* If the slab has been placed off-slab, and we have enough space then
* move it on-slab. This is at the expense of any extra colouring.
*/
if
(
flags
&
CFLGS_OFF_SLAB
&&
left_over
>=
slab
_size
)
{
if
(
flags
&
CFLGS_OFF_SLAB
&&
left_over
>=
freelist
_size
)
{
flags
&=
~
CFLGS_OFF_SLAB
;
left_over
-=
slab
_size
;
left_over
-=
freelist
_size
;
}
if
(
flags
&
CFLGS_OFF_SLAB
)
{
/* really off slab. No need for manual alignment */
slab_size
=
cachep
->
num
*
sizeof
(
kmem_bufctl_t
)
+
sizeof
(
struct
slab
);
freelist_size
=
cachep
->
num
*
sizeof
(
unsigned
int
);
#ifdef CONFIG_PAGE_POISONING
/* If we're going to use the generic kernel_map_pages()
...
...
@@ -2371,16 +2289,16 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
if
(
cachep
->
colour_off
<
cachep
->
align
)
cachep
->
colour_off
=
cachep
->
align
;
cachep
->
colour
=
left_over
/
cachep
->
colour_off
;
cachep
->
slab_size
=
slab
_size
;
cachep
->
freelist_size
=
freelist
_size
;
cachep
->
flags
=
flags
;
cachep
->
allocflags
=
0
;
cachep
->
allocflags
=
__GFP_COMP
;
if
(
CONFIG_ZONE_DMA_FLAG
&&
(
flags
&
SLAB_CACHE_DMA
))
cachep
->
allocflags
|=
GFP_DMA
;
cachep
->
size
=
size
;
cachep
->
reciprocal_buffer_size
=
reciprocal_value
(
size
);
if
(
flags
&
CFLGS_OFF_SLAB
)
{
cachep
->
slabp_cache
=
kmalloc_slab
(
slab
_size
,
0u
);
cachep
->
freelist_cache
=
kmalloc_slab
(
freelist
_size
,
0u
);
/*
* This is a possibility for one of the malloc_sizes caches.
* But since we go off slab only for object size greater than
...
...
@@ -2388,7 +2306,7 @@ __kmem_cache_create (struct kmem_cache *cachep, unsigned long flags)
* this should not happen at all.
* But leave a BUG_ON for some lucky dude.
*/
BUG_ON
(
ZERO_OR_NULL_PTR
(
cachep
->
slabp
_cache
));
BUG_ON
(
ZERO_OR_NULL_PTR
(
cachep
->
freelist
_cache
));
}
err
=
setup_cpu_cache
(
cachep
,
gfp
);
...
...
@@ -2494,7 +2412,7 @@ static int drain_freelist(struct kmem_cache *cache,
{
struct
list_head
*
p
;
int
nr_freed
;
struct
slab
*
slabp
;
struct
page
*
page
;
nr_freed
=
0
;
while
(
nr_freed
<
tofree
&&
!
list_empty
(
&
n
->
slabs_free
))
{
...
...
@@ -2506,18 +2424,18 @@ static int drain_freelist(struct kmem_cache *cache,
goto
out
;
}
slabp
=
list_entry
(
p
,
struct
slab
,
list
);
page
=
list_entry
(
p
,
struct
page
,
lru
);
#if DEBUG
BUG_ON
(
slabp
->
inus
e
);
BUG_ON
(
page
->
activ
e
);
#endif
list_del
(
&
slabp
->
list
);
list_del
(
&
page
->
lru
);
/*
* Safe to drop the lock. The slab is no longer linked
* to the cache.
*/
n
->
free_objects
-=
cache
->
num
;
spin_unlock_irq
(
&
n
->
list_lock
);
slab_destroy
(
cache
,
slabp
);
slab_destroy
(
cache
,
page
);
nr_freed
++
;
}
out:
...
...
@@ -2600,52 +2518,42 @@ int __kmem_cache_shutdown(struct kmem_cache *cachep)
* descriptors in kmem_cache_create, we search through the malloc_sizes array.
* If we are creating a malloc_sizes cache here it would not be visible to
* kmem_find_general_cachep till the initialization is complete.
* Hence we cannot have
slabp
_cache same as the original cache.
* Hence we cannot have
freelist
_cache same as the original cache.
*/
static
struct
slab
*
alloc_slabmgmt
(
struct
kmem_cache
*
cachep
,
void
*
obj
p
,
int
colour_off
,
gfp_t
local_flags
,
int
nodeid
)
static
void
*
alloc_slabmgmt
(
struct
kmem_cache
*
cache
p
,
struct
page
*
page
,
int
colour_off
,
gfp_t
local_flags
,
int
nodeid
)
{
struct
slab
*
slabp
;
void
*
freelist
;
void
*
addr
=
page_address
(
page
);
if
(
OFF_SLAB
(
cachep
))
{
/* Slab management obj is off-slab. */
slabp
=
kmem_cache_alloc_node
(
cachep
->
slabp
_cache
,
freelist
=
kmem_cache_alloc_node
(
cachep
->
freelist
_cache
,
local_flags
,
nodeid
);
/*
* If the first object in the slab is leaked (it's allocated
* but no one has a reference to it), we want to make sure
* kmemleak does not treat the ->s_mem pointer as a reference
* to the object. Otherwise we will not report the leak.
*/
kmemleak_scan_area
(
&
slabp
->
list
,
sizeof
(
struct
list_head
),
local_flags
);
if
(
!
slabp
)
if
(
!
freelist
)
return
NULL
;
}
else
{
slabp
=
objp
+
colour_off
;
colour_off
+=
cachep
->
slab
_size
;
freelist
=
addr
+
colour_off
;
colour_off
+=
cachep
->
freelist
_size
;
}
slabp
->
inuse
=
0
;
slabp
->
colouroff
=
colour_off
;
slabp
->
s_mem
=
objp
+
colour_off
;
slabp
->
nodeid
=
nodeid
;
slabp
->
free
=
0
;
return
slabp
;
page
->
active
=
0
;
page
->
s_mem
=
addr
+
colour_off
;
return
freelist
;
}
static
inline
kmem_bufctl_t
*
slab_bufctl
(
struct
slab
*
slabp
)
static
inline
unsigned
int
*
slab_freelist
(
struct
page
*
page
)
{
return
(
kmem_bufctl_t
*
)
(
slabp
+
1
);
return
(
unsigned
int
*
)(
page
->
freelist
);
}
static
void
cache_init_objs
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
)
struct
page
*
page
)
{
int
i
;
for
(
i
=
0
;
i
<
cachep
->
num
;
i
++
)
{
void
*
objp
=
index_to_obj
(
cachep
,
slabp
,
i
);
void
*
objp
=
index_to_obj
(
cachep
,
page
,
i
);
#if DEBUG
/* need to poison the objs? */
if
(
cachep
->
flags
&
SLAB_POISON
)
...
...
@@ -2681,9 +2589,8 @@ static void cache_init_objs(struct kmem_cache *cachep,
if
(
cachep
->
ctor
)
cachep
->
ctor
(
objp
);
#endif
slab_
bufctl
(
slabp
)[
i
]
=
i
+
1
;
slab_
freelist
(
page
)[
i
]
=
i
;
}
slab_bufctl
(
slabp
)[
i
-
1
]
=
BUFCTL_END
;
}
static
void
kmem_flagcheck
(
struct
kmem_cache
*
cachep
,
gfp_t
flags
)
...
...
@@ -2696,41 +2603,41 @@ static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags)
}
}
static
void
*
slab_get_obj
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
,
static
void
*
slab_get_obj
(
struct
kmem_cache
*
cachep
,
struct
page
*
page
,
int
nodeid
)
{
void
*
objp
=
index_to_obj
(
cachep
,
slabp
,
slabp
->
free
);
kmem_bufctl_t
next
;
void
*
objp
;
slabp
->
inuse
++
;
next
=
slab_bufctl
(
slabp
)[
slabp
->
free
]
;
objp
=
index_to_obj
(
cachep
,
page
,
slab_freelist
(
page
)[
page
->
active
])
;
page
->
active
++
;
#if DEBUG
slab_bufctl
(
slabp
)[
slabp
->
free
]
=
BUFCTL_FREE
;
WARN_ON
(
slabp
->
nodeid
!=
nodeid
);
WARN_ON
(
page_to_nid
(
virt_to_page
(
objp
))
!=
nodeid
);
#endif
slabp
->
free
=
next
;
return
objp
;
}
static
void
slab_put_obj
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
,
static
void
slab_put_obj
(
struct
kmem_cache
*
cachep
,
struct
page
*
page
,
void
*
objp
,
int
nodeid
)
{
unsigned
int
objnr
=
obj_to_index
(
cachep
,
slabp
,
objp
);
unsigned
int
objnr
=
obj_to_index
(
cachep
,
page
,
objp
);
#if DEBUG
unsigned
int
i
;
/* Verify that the slab belongs to the intended node */
WARN_ON
(
slabp
->
nodeid
!=
nodeid
);
WARN_ON
(
page_to_nid
(
virt_to_page
(
objp
))
!=
nodeid
);
if
(
slab_bufctl
(
slabp
)[
objnr
]
+
1
<=
SLAB_LIMIT
+
1
)
{
/* Verify double free bug */
for
(
i
=
page
->
active
;
i
<
cachep
->
num
;
i
++
)
{
if
(
slab_freelist
(
page
)[
i
]
==
objnr
)
{
printk
(
KERN_ERR
"slab: double free detected in cache "
"'%s', objp %p
\n
"
,
cachep
->
name
,
objp
);
BUG
();
}
}
#endif
slab_bufctl
(
slabp
)[
objnr
]
=
slabp
->
free
;
slabp
->
free
=
objnr
;
slabp
->
inuse
--
;
page
->
active
--
;
slab_freelist
(
page
)[
page
->
active
]
=
objnr
;
}
/*
...
...
@@ -2738,23 +2645,11 @@ static void slab_put_obj(struct kmem_cache *cachep, struct slab *slabp,
* for the slab allocator to be able to lookup the cache and slab of a
* virtual address for kfree, ksize, and slab debugging.
*/
static
void
slab_map_pages
(
struct
kmem_cache
*
cache
,
struct
slab
*
slab
,
void
*
addr
)
static
void
slab_map_pages
(
struct
kmem_cache
*
cache
,
struct
page
*
page
,
void
*
freelist
)
{
int
nr_pages
;
struct
page
*
page
;
page
=
virt_to_page
(
addr
);
nr_pages
=
1
;
if
(
likely
(
!
PageCompound
(
page
)))
nr_pages
<<=
cache
->
gfporder
;
do
{
page
->
slab_cache
=
cache
;
page
->
slab_page
=
slab
;
page
++
;
}
while
(
--
nr_pages
);
page
->
freelist
=
freelist
;
}
/*
...
...
@@ -2762,9 +2657,9 @@ static void slab_map_pages(struct kmem_cache *cache, struct slab *slab,
* kmem_cache_alloc() when there are no active objs left in a cache.
*/
static
int
cache_grow
(
struct
kmem_cache
*
cachep
,
gfp_t
flags
,
int
nodeid
,
void
*
objp
)
gfp_t
flags
,
int
nodeid
,
struct
page
*
page
)
{
struct
slab
*
slabp
;
void
*
freelist
;
size_t
offset
;
gfp_t
local_flags
;
struct
kmem_cache_node
*
n
;
...
...
@@ -2805,20 +2700,20 @@ static int cache_grow(struct kmem_cache *cachep,
* Get mem for the objs. Attempt to allocate a physical page from
* 'nodeid'.
*/
if
(
!
objp
)
objp
=
kmem_getpages
(
cachep
,
local_flags
,
nodeid
);
if
(
!
objp
)
if
(
!
page
)
page
=
kmem_getpages
(
cachep
,
local_flags
,
nodeid
);
if
(
!
page
)
goto
failed
;
/* Get slab management. */
slabp
=
alloc_slabmgmt
(
cachep
,
objp
,
offset
,
freelist
=
alloc_slabmgmt
(
cachep
,
page
,
offset
,
local_flags
&
~
GFP_CONSTRAINT_MASK
,
nodeid
);
if
(
!
slabp
)
if
(
!
freelist
)
goto
opps1
;
slab_map_pages
(
cachep
,
slabp
,
objp
);
slab_map_pages
(
cachep
,
page
,
freelist
);
cache_init_objs
(
cachep
,
slabp
);
cache_init_objs
(
cachep
,
page
);
if
(
local_flags
&
__GFP_WAIT
)
local_irq_disable
();
...
...
@@ -2826,13 +2721,13 @@ static int cache_grow(struct kmem_cache *cachep,
spin_lock
(
&
n
->
list_lock
);
/* Make slab active. */
list_add_tail
(
&
slabp
->
list
,
&
(
n
->
slabs_free
));
list_add_tail
(
&
page
->
lru
,
&
(
n
->
slabs_free
));
STATS_INC_GROWN
(
cachep
);
n
->
free_objects
+=
cachep
->
num
;
spin_unlock
(
&
n
->
list_lock
);
return
1
;
opps1:
kmem_freepages
(
cachep
,
objp
);
kmem_freepages
(
cachep
,
page
);
failed:
if
(
local_flags
&
__GFP_WAIT
)
local_irq_disable
();
...
...
@@ -2880,9 +2775,8 @@ static inline void verify_redzone_free(struct kmem_cache *cache, void *obj)
static
void
*
cache_free_debugcheck
(
struct
kmem_cache
*
cachep
,
void
*
objp
,
unsigned
long
caller
)
{
struct
page
*
page
;
unsigned
int
objnr
;
struct
slab
*
slabp
;
struct
page
*
page
;
BUG_ON
(
virt_to_cache
(
objp
)
!=
cachep
);
...
...
@@ -2890,8 +2784,6 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
kfree_debugcheck
(
objp
);
page
=
virt_to_head_page
(
objp
);
slabp
=
page
->
slab_page
;
if
(
cachep
->
flags
&
SLAB_RED_ZONE
)
{
verify_redzone_free
(
cachep
,
objp
);
*
dbg_redzone1
(
cachep
,
objp
)
=
RED_INACTIVE
;
...
...
@@ -2900,14 +2792,11 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
if
(
cachep
->
flags
&
SLAB_STORE_USER
)
*
dbg_userword
(
cachep
,
objp
)
=
(
void
*
)
caller
;
objnr
=
obj_to_index
(
cachep
,
slabp
,
objp
);
objnr
=
obj_to_index
(
cachep
,
page
,
objp
);
BUG_ON
(
objnr
>=
cachep
->
num
);
BUG_ON
(
objp
!=
index_to_obj
(
cachep
,
slabp
,
objnr
));
BUG_ON
(
objp
!=
index_to_obj
(
cachep
,
page
,
objnr
));
#ifdef CONFIG_DEBUG_SLAB_LEAK
slab_bufctl
(
slabp
)[
objnr
]
=
BUFCTL_FREE
;
#endif
if
(
cachep
->
flags
&
SLAB_POISON
)
{
#ifdef CONFIG_DEBUG_PAGEALLOC
if
((
cachep
->
size
%
PAGE_SIZE
)
==
0
&&
OFF_SLAB
(
cachep
))
{
...
...
@@ -2924,33 +2813,9 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
return
objp
;
}
static
void
check_slabp
(
struct
kmem_cache
*
cachep
,
struct
slab
*
slabp
)
{
kmem_bufctl_t
i
;
int
entries
=
0
;
/* Check slab's freelist to see if this obj is there. */
for
(
i
=
slabp
->
free
;
i
!=
BUFCTL_END
;
i
=
slab_bufctl
(
slabp
)[
i
])
{
entries
++
;
if
(
entries
>
cachep
->
num
||
i
>=
cachep
->
num
)
goto
bad
;
}
if
(
entries
!=
cachep
->
num
-
slabp
->
inuse
)
{
bad:
printk
(
KERN_ERR
"slab: Internal list corruption detected in "
"cache '%s'(%d), slabp %p(%d). Tainted(%s). Hexdump:
\n
"
,
cachep
->
name
,
cachep
->
num
,
slabp
,
slabp
->
inuse
,
print_tainted
());
print_hex_dump
(
KERN_ERR
,
""
,
DUMP_PREFIX_OFFSET
,
16
,
1
,
slabp
,
sizeof
(
*
slabp
)
+
cachep
->
num
*
sizeof
(
kmem_bufctl_t
),
1
);
BUG
();
}
}
#else
#define kfree_debugcheck(x) do { } while(0)
#define cache_free_debugcheck(x,objp,z) (objp)
#define check_slabp(x,y) do { } while(0)
#endif
static
void
*
cache_alloc_refill
(
struct
kmem_cache
*
cachep
,
gfp_t
flags
,
...
...
@@ -2989,7 +2854,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
while
(
batchcount
>
0
)
{
struct
list_head
*
entry
;
struct
slab
*
slabp
;
struct
page
*
page
;
/* Get slab alloc is to come from. */
entry
=
n
->
slabs_partial
.
next
;
if
(
entry
==
&
n
->
slabs_partial
)
{
...
...
@@ -2999,8 +2864,7 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
goto
must_grow
;
}
slabp
=
list_entry
(
entry
,
struct
slab
,
list
);
check_slabp
(
cachep
,
slabp
);
page
=
list_entry
(
entry
,
struct
page
,
lru
);
check_spinlock_acquired
(
cachep
);
/*
...
...
@@ -3008,24 +2872,23 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags,
* there must be at least one object available for
* allocation.
*/
BUG_ON
(
slabp
->
inus
e
>=
cachep
->
num
);
BUG_ON
(
page
->
activ
e
>=
cachep
->
num
);
while
(
slabp
->
inus
e
<
cachep
->
num
&&
batchcount
--
)
{
while
(
page
->
activ
e
<
cachep
->
num
&&
batchcount
--
)
{
STATS_INC_ALLOCED
(
cachep
);
STATS_INC_ACTIVE
(
cachep
);
STATS_SET_HIGH
(
cachep
);
ac_put_obj
(
cachep
,
ac
,
slab_get_obj
(
cachep
,
slabp
,
ac_put_obj
(
cachep
,
ac
,
slab_get_obj
(
cachep
,
page
,
node
));
}
check_slabp
(
cachep
,
slabp
);
/* move slabp to correct slabp list: */
list_del
(
&
slabp
->
list
);
if
(
slabp
->
free
==
BUFCTL_END
)
list_add
(
&
slabp
->
list
,
&
n
->
slabs_full
);
list_del
(
&
page
->
lru
);
if
(
page
->
active
==
cachep
->
num
)
list_add
(
&
page
->
list
,
&
n
->
slabs_full
);
else
list_add
(
&
slabp
->
list
,
&
n
->
slabs_partial
);
list_add
(
&
page
->
list
,
&
n
->
slabs_partial
);
}
must_grow:
...
...
@@ -3097,16 +2960,6 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
*
dbg_redzone1
(
cachep
,
objp
)
=
RED_ACTIVE
;
*
dbg_redzone2
(
cachep
,
objp
)
=
RED_ACTIVE
;
}
#ifdef CONFIG_DEBUG_SLAB_LEAK
{
struct
slab
*
slabp
;
unsigned
objnr
;
slabp
=
virt_to_head_page
(
objp
)
->
slab_page
;
objnr
=
(
unsigned
)(
objp
-
slabp
->
s_mem
)
/
cachep
->
size
;
slab_bufctl
(
slabp
)[
objnr
]
=
BUFCTL_ACTIVE
;
}
#endif
objp
+=
obj_offset
(
cachep
);
if
(
cachep
->
ctor
&&
cachep
->
flags
&
SLAB_POISON
)
cachep
->
ctor
(
objp
);
...
...
@@ -3248,18 +3101,20 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
* We may trigger various forms of reclaim on the allowed
* set and go into memory reserves if necessary.
*/
struct
page
*
page
;
if
(
local_flags
&
__GFP_WAIT
)
local_irq_enable
();
kmem_flagcheck
(
cache
,
flags
);
obj
=
kmem_getpages
(
cache
,
local_flags
,
numa_mem_id
());
page
=
kmem_getpages
(
cache
,
local_flags
,
numa_mem_id
());
if
(
local_flags
&
__GFP_WAIT
)
local_irq_disable
();
if
(
obj
)
{
if
(
page
)
{
/*
* Insert into the appropriate per node queues
*/
nid
=
page_to_nid
(
virt_to_page
(
obj
)
);
if
(
cache_grow
(
cache
,
flags
,
nid
,
obj
))
{
nid
=
page_to_nid
(
page
);
if
(
cache_grow
(
cache
,
flags
,
nid
,
page
))
{
obj
=
____cache_alloc_node
(
cache
,
flags
|
GFP_THISNODE
,
nid
);
if
(
!
obj
)
...
...
@@ -3288,7 +3143,7 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
int
nodeid
)
{
struct
list_head
*
entry
;
struct
slab
*
slabp
;
struct
page
*
page
;
struct
kmem_cache_node
*
n
;
void
*
obj
;
int
x
;
...
...
@@ -3308,26 +3163,24 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
goto
must_grow
;
}
slabp
=
list_entry
(
entry
,
struct
slab
,
list
);
page
=
list_entry
(
entry
,
struct
page
,
lru
);
check_spinlock_acquired_node
(
cachep
,
nodeid
);
check_slabp
(
cachep
,
slabp
);
STATS_INC_NODEALLOCS
(
cachep
);
STATS_INC_ACTIVE
(
cachep
);
STATS_SET_HIGH
(
cachep
);
BUG_ON
(
slabp
->
inus
e
==
cachep
->
num
);
BUG_ON
(
page
->
activ
e
==
cachep
->
num
);
obj
=
slab_get_obj
(
cachep
,
slabp
,
nodeid
);
check_slabp
(
cachep
,
slabp
);
obj
=
slab_get_obj
(
cachep
,
page
,
nodeid
);
n
->
free_objects
--
;
/* move slabp to correct slabp list: */
list_del
(
&
slabp
->
list
);
list_del
(
&
page
->
lru
);
if
(
slabp
->
free
==
BUFCTL_END
)
list_add
(
&
slabp
->
list
,
&
n
->
slabs_full
);
if
(
page
->
active
==
cachep
->
num
)
list_add
(
&
page
->
lru
,
&
n
->
slabs_full
);
else
list_add
(
&
slabp
->
list
,
&
n
->
slabs_partial
);
list_add
(
&
page
->
lru
,
&
n
->
slabs_partial
);
spin_unlock
(
&
n
->
list_lock
);
goto
done
;
...
...
@@ -3477,23 +3330,21 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
for
(
i
=
0
;
i
<
nr_objects
;
i
++
)
{
void
*
objp
;
struct
slab
*
slabp
;
struct
page
*
page
;
clear_obj_pfmemalloc
(
&
objpp
[
i
]);
objp
=
objpp
[
i
];
slabp
=
virt_to_slab
(
objp
);
page
=
virt_to_head_page
(
objp
);
n
=
cachep
->
node
[
node
];
list_del
(
&
slabp
->
list
);
list_del
(
&
page
->
lru
);
check_spinlock_acquired_node
(
cachep
,
node
);
check_slabp
(
cachep
,
slabp
);
slab_put_obj
(
cachep
,
slabp
,
objp
,
node
);
slab_put_obj
(
cachep
,
page
,
objp
,
node
);
STATS_DEC_ACTIVE
(
cachep
);
n
->
free_objects
++
;
check_slabp
(
cachep
,
slabp
);
/* fixup slab chains */
if
(
slabp
->
inus
e
==
0
)
{
if
(
page
->
activ
e
==
0
)
{
if
(
n
->
free_objects
>
n
->
free_limit
)
{
n
->
free_objects
-=
cachep
->
num
;
/* No need to drop any previously held
...
...
@@ -3502,16 +3353,16 @@ static void free_block(struct kmem_cache *cachep, void **objpp, int nr_objects,
* a different cache, refer to comments before
* alloc_slabmgmt.
*/
slab_destroy
(
cachep
,
slabp
);
slab_destroy
(
cachep
,
page
);
}
else
{
list_add
(
&
slabp
->
list
,
&
n
->
slabs_free
);
list_add
(
&
page
->
lru
,
&
n
->
slabs_free
);
}
}
else
{
/* Unconditionally move a slab to the end of the
* partial list on free - maximum time for the
* other objects to be freed, too.
*/
list_add_tail
(
&
slabp
->
list
,
&
n
->
slabs_partial
);
list_add_tail
(
&
page
->
lru
,
&
n
->
slabs_partial
);
}
}
}
...
...
@@ -3551,10 +3402,10 @@ static void cache_flusharray(struct kmem_cache *cachep, struct array_cache *ac)
p
=
n
->
slabs_free
.
next
;
while
(
p
!=
&
(
n
->
slabs_free
))
{
struct
slab
*
slabp
;
struct
page
*
page
;
slabp
=
list_entry
(
p
,
struct
slab
,
list
);
BUG_ON
(
slabp
->
inus
e
);
page
=
list_entry
(
p
,
struct
page
,
lru
);
BUG_ON
(
page
->
activ
e
);
i
++
;
p
=
p
->
next
;
...
...
@@ -4158,7 +4009,7 @@ static void cache_reap(struct work_struct *w)
#ifdef CONFIG_SLABINFO
void
get_slabinfo
(
struct
kmem_cache
*
cachep
,
struct
slabinfo
*
sinfo
)
{
struct
slab
*
slabp
;
struct
page
*
page
;
unsigned
long
active_objs
;
unsigned
long
num_objs
;
unsigned
long
active_slabs
=
0
;
...
...
@@ -4178,23 +4029,23 @@ void get_slabinfo(struct kmem_cache *cachep, struct slabinfo *sinfo)
check_irq_on
();
spin_lock_irq
(
&
n
->
list_lock
);
list_for_each_entry
(
slabp
,
&
n
->
slabs_full
,
list
)
{
if
(
slabp
->
inus
e
!=
cachep
->
num
&&
!
error
)
list_for_each_entry
(
page
,
&
n
->
slabs_full
,
lru
)
{
if
(
page
->
activ
e
!=
cachep
->
num
&&
!
error
)
error
=
"slabs_full accounting error"
;
active_objs
+=
cachep
->
num
;
active_slabs
++
;
}
list_for_each_entry
(
slabp
,
&
n
->
slabs_partial
,
list
)
{
if
(
slabp
->
inus
e
==
cachep
->
num
&&
!
error
)
error
=
"slabs_partial
inuse
accounting error"
;
if
(
!
slabp
->
inus
e
&&
!
error
)
error
=
"slabs_partial
/inuse
accounting error"
;
active_objs
+=
slabp
->
inus
e
;
list_for_each_entry
(
page
,
&
n
->
slabs_partial
,
lru
)
{
if
(
page
->
activ
e
==
cachep
->
num
&&
!
error
)
error
=
"slabs_partial accounting error"
;
if
(
!
page
->
activ
e
&&
!
error
)
error
=
"slabs_partial accounting error"
;
active_objs
+=
page
->
activ
e
;
active_slabs
++
;
}
list_for_each_entry
(
slabp
,
&
n
->
slabs_free
,
list
)
{
if
(
slabp
->
inus
e
&&
!
error
)
error
=
"slabs_free
/inuse
accounting error"
;
list_for_each_entry
(
page
,
&
n
->
slabs_free
,
lru
)
{
if
(
page
->
activ
e
&&
!
error
)
error
=
"slabs_free accounting error"
;
num_slabs
++
;
}
free_objects
+=
n
->
free_objects
;
...
...
@@ -4346,15 +4197,27 @@ static inline int add_caller(unsigned long *n, unsigned long v)
return
1
;
}
static
void
handle_slab
(
unsigned
long
*
n
,
struct
kmem_cache
*
c
,
struct
slab
*
s
)
static
void
handle_slab
(
unsigned
long
*
n
,
struct
kmem_cache
*
c
,
struct
page
*
page
)
{
void
*
p
;
int
i
;
int
i
,
j
;
if
(
n
[
0
]
==
n
[
1
])
return
;
for
(
i
=
0
,
p
=
s
->
s_mem
;
i
<
c
->
num
;
i
++
,
p
+=
c
->
size
)
{
if
(
slab_bufctl
(
s
)[
i
]
!=
BUFCTL_ACTIVE
)
for
(
i
=
0
,
p
=
page
->
s_mem
;
i
<
c
->
num
;
i
++
,
p
+=
c
->
size
)
{
bool
active
=
true
;
for
(
j
=
page
->
active
;
j
<
c
->
num
;
j
++
)
{
/* Skip freed item */
if
(
slab_freelist
(
page
)[
j
]
==
i
)
{
active
=
false
;
break
;
}
}
if
(
!
active
)
continue
;
if
(
!
add_caller
(
n
,
(
unsigned
long
)
*
dbg_userword
(
c
,
p
)))
return
;
}
...
...
@@ -4379,7 +4242,7 @@ static void show_symbol(struct seq_file *m, unsigned long address)
static
int
leaks_show
(
struct
seq_file
*
m
,
void
*
p
)
{
struct
kmem_cache
*
cachep
=
list_entry
(
p
,
struct
kmem_cache
,
list
);
struct
slab
*
slabp
;
struct
page
*
page
;
struct
kmem_cache_node
*
n
;
const
char
*
name
;
unsigned
long
*
x
=
m
->
private
;
...
...
@@ -4403,10 +4266,10 @@ static int leaks_show(struct seq_file *m, void *p)
check_irq_on
();
spin_lock_irq
(
&
n
->
list_lock
);
list_for_each_entry
(
slabp
,
&
n
->
slabs_full
,
list
)
handle_slab
(
x
,
cachep
,
slabp
);
list_for_each_entry
(
slabp
,
&
n
->
slabs_partial
,
list
)
handle_slab
(
x
,
cachep
,
slabp
);
list_for_each_entry
(
page
,
&
n
->
slabs_full
,
lru
)
handle_slab
(
x
,
cachep
,
page
);
list_for_each_entry
(
page
,
&
n
->
slabs_partial
,
lru
)
handle_slab
(
x
,
cachep
,
page
);
spin_unlock_irq
(
&
n
->
list_lock
);
}
name
=
cachep
->
name
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment