Introduction
The kmem subsystem in RHEL7 has changed to include cache aliases, which can be confusing. This article covers a bit of the internals of the slab aliases and which should give some pointers to faster crash analysis as well as some areas for further study.
Kernel code walk-through on 3.10.0-862\*el7
As an example, we start with the 'filp_cachep'. It's fairly easy to see the alias if you know which slab you're looking for.
For example, you can do this and know what the alias is.
crash> p filp_cachep
filp_cachep = $86 = (struct kmem_cache *) 0xffff9ce73fc03700
crash> p filp_cachep->name
$87 = 0xffffffffb3876ec6 "kmalloc-256"
However, what if you just have high slab cache usage in one slab? How do you know what is allocating the memory? If you have a kmem_cache name, how do you list all of the aliases to that kmem_cache in a RHEL7 vmcore?
Let's see if we can find the actual kmem_cache and look at the items in the cache. At the high level it would seem 'filp' would show up in "kmem -s" output but unfortunately it does not. In case of a crash bug, list out the slab_caches as well, but it is not listed in there.
crash> kmem -s | grep filp
crash>
slab_caches = $15 = {
next = 0xffff9ce73b987d68,
prev = 0xffff9ce73fc02068
}
crash> list -H 0xffff9ce73b987d68 -s kmem_cache.name -o kmem_cache.list | grep filp
crash>
Now RHEL7 has slab aliases which are recorded in sysfs at /sys/kernel/slab. So look to see if 'filp' is an alias and let's do it "the hard way"
Here's how this works. When kmem_cache_create() is called, we call kmem_cache_create_memcg() with NULL as the 'memcg' parameter. This means we'll call __kmem_cache_alias on line 242 and assuming the alias function comes back with a non-NULL kmem_cache *, we will skip over the allocation. So the next question is how does __kmem_cache_alias work?
mm/slab_common.c
182 /*
183 * kmem_cache_create - Create a cache.
184 * @name: A string which is used in /proc/slabinfo to identify this cache.
185 * @size: The size of objects to be created in this cache.
186 * @align: The required alignment for the objects.
187 * @flags: SLAB flags
188 * @ctor: A constructor for the objects.
189 *
190 * Returns a ptr to the cache on success, NULL on failure.
191 * Cannot be called within a interrupt, but can be interrupted.
192 * The @ctor is run when new pages are allocated by the cache.
193 *
194 * The flags are
195 *
196 * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
197 * to catch references to uninitialised memory.
198 *
199 * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check
200 * for buffer overruns.
201 *
202 * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
203 * cacheline. This can be beneficial if you're counting cycles as closely
204 * as davem.
205 */
206
207 struct kmem_cache *
208 kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size,
209 size_t align, unsigned long flags, void (*ctor)(void *),
210 struct kmem_cache *parent_cache)
211 {
212 struct kmem_cache *s = NULL;
213 int err = 0;
214
215 get_online_cpus();
216 mutex_lock(&slab_mutex);
217
218 if (!kmem_cache_sanity_check(memcg, name, size) == 0)
219 goto out_locked;
220
221 if (memcg) {
222 /*
223 * Since per-memcg caches are created asynchronously on first
224 * allocation (see memcg_kmem_get_cache()), several threads can
225 * try to create the same cache, but only one of them may
226 * succeed. Therefore if we get here and see the cache has
227 * already been created, we silently return NULL.
228 */
229 if (cache_from_memcg(parent_cache, memcg_cache_id(memcg)))
230 goto out_locked;
231 }
232
233 /*
234 * Some allocators will constraint the set of valid flags to a subset
235 * of all flags. We expect them to define CACHE_CREATE_MASK in this
236 * case, and we'll just provide them with a sanitized version of the
237 * passed flags.
238 */
239 flags &= CACHE_CREATE_MASK;
240
241 if (!memcg) {
242 s = __kmem_cache_alias(name, size, align, flags, ctor);
243 if (s)
244 goto out_locked;
245 }
246
247 s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
248 if (s) {
249 s->object_size = s->size = size;
250 s->align = calculate_alignment(flags, align, size);
251 s->ctor = ctor;
252
253 err = memcg_alloc_cache_params(memcg, s, parent_cache);
254 if (err) {
255 kmem_cache_free(kmem_cache, s);
256 goto out_locked;
257 }
258
259 s->name = kstrdup(name, GFP_KERNEL);
260 if (!s->name) {
261 memcg_free_cache_params(s);
262 kmem_cache_free(kmem_cache, s);
263 err = -ENOMEM;
264 goto out_locked;
265 }
266
267 err = __kmem_cache_create(s, flags);
268 if (!err) {
269 s->refcount = 1;
270 list_add(&s->list, &slab_caches);
271 memcg_register_cache(s);
272 } else {
273 memcg_free_cache_params(s);
274 kfree(s->name);
275 kmem_cache_free(kmem_cache, s);
276 }
277 } else
278 err = -ENOMEM;
279
280 out_locked:
281 mutex_unlock(&slab_mutex);
282 put_online_cpus();
283
284 if (err) {
285
286 if (flags & SLAB_PANIC)
287 panic("kmem_cache_create: Failed to create slab '%s'. Error %d\n",
288 name, err);
289 else {
290 printk(KERN_WARNING "kmem_cache_create(%s) failed with error %d",
291 name, err);
292 dump_stack();
293 }
294
295 return NULL;
296 }
297
298 return s;
299 }
300
301 struct kmem_cache *
302 kmem_cache_create(const char *name, size_t size, size_t align,
303 unsigned long flags, void (*ctor)(void *))
304 {
305 return kmem_cache_create_memcg(NULL, name, size, align, flags, ctor, NULL);
306 }
307 EXPORT_SYMBOL(kmem_cache_create);
Now __kmem_cache_alias calls find_mergeable, which does a few checks and then eventually runs through 'slab_caches' list of kmem_cache structures allocated. Assuming it passes additional checks, the function will return that kmem_cache pointer. Otherwise, it eventually goes through the full list, finds nothing, and returns NULL. But we're thinking we found something which is why 'filp' did not show up the list of slab_caches. So we think find_mergeable() returned non-NULL, which implies __kmem_cache_alias passes the 'if (s)' check on line 3960. Then we call into sysfs_slab_alias with the kmem_cache we found and our 'name' that we're wanting to alias to this existing kmem_cache.
mm/slub.c
3913 static struct kmem_cache *find_mergeable(size_t size, size_t align,
3914 unsigned long flags, const char *name, void (*ctor)(void *))
3915 {
3916 struct kmem_cache *s;
3917
3918 if (slub_nomerge || (flags & SLUB_NEVER_MERGE))
3919 return NULL;
3920
3921 if (ctor)
3922 return NULL;
3923
3924 size = ALIGN(size, sizeof(void *));
3925 align = calculate_alignment(flags, align, size);
3926 size = ALIGN(size, align);
3927 flags = kmem_cache_flags(size, flags, name, NULL);
3928
3929 list_for_each_entry(s, &slab_caches, list) {
3930 if (slab_unmergeable(s))
3931 continue;
3932
3933 if (size > s->size)
3934 continue;
3935
3936 if ((flags & SLUB_MERGE_SAME) != (s->flags & SLUB_MERGE_SAME))
3937 continue;
3938 /*
3939 * Check if alignment is compatible.
3940 * Courtesy of Adrian Drzewiecki
3941 */
3942 if ((s->size & ~(align - 1)) != s->size)
3943 continue;
3944
3945 if (s->size - size >= sizeof(void *))
3946 continue;
3947
3948 return s;
3949 }
3950 return NULL;
3951 }
...
3953 struct kmem_cache *
3954 __kmem_cache_alias(const char *name, size_t size, size_t align,
3955 unsigned long flags, void (*ctor)(void *))
3956 {
3957 struct kmem_cache *s;
3958
3959 s = find_mergeable(size, align, flags, name, ctor);
3960 if (s) {
3961 s->refcount++;
3962 /*
3963 * Adjust the object sizes so that we clear
3964 * the complete object on kzalloc.
3965 */
3966 s->object_size = max(s->object_size, (int)size);
3967 s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
3968
3969 if (sysfs_slab_alias(s, name)) {
3970 s->refcount--;
3971 s = NULL;
3972 }
3973 }
3974
3975 return s;
3976 }
Ok, so sysfs_slab_alias will call sysfs_create_link with the slab_kset->kobj and our kmem_cache's kobj, as well as the 'name' we passed in for the alias.
5452 static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
5453 {
5454 struct saved_alias *al;
5455
5456 if (slab_state == FULL) {
5457 /*
5458 * If we have a leftover link then remove it.
5459 */
5460 sysfs_remove_link(&slab_kset->kobj, name);
5461 return sysfs_create_link(&slab_kset->kobj, &s->kobj, name);
5462 }
5463
5464 al = kmalloc(sizeof(struct saved_alias), GFP_KERNEL);
5465 if (!al)
5466 return -ENOMEM;
5467
5468 al->s = s;
5469 al->name = name;
5470 al->next = alias_list;
5471 alias_list = al;
5472 return 0;
5473 }
Now we move over into sysfs's symlink code. At this point it appears we probably can walk slab_kset->kobj and obtain the list of all aliases, but we don't know how to do that yet, so let's look at the code further.
fs/sysfs/symlink.c
21 static int sysfs_do_create_link_sd(struct kernfs_node *parent,
22 struct kobject *target_kobj,
23 const char *name, int warn)
24 {
25 struct kernfs_node *kn, *target = NULL;
26
27 BUG_ON(!name || !parent);
28
29 /*
30 * We don't own @target_kobj and it may be removed at any time.
31 * Synchronize using sysfs_symlink_target_lock. See
32 * sysfs_remove_dir() for details.
33 */
34 spin_lock(&sysfs_symlink_target_lock);
35 if (target_kobj->sd) {
36 target = target_kobj->sd;
37 kernfs_get(target);
38 }
39 spin_unlock(&sysfs_symlink_target_lock);
40
41 if (!target)
42 return -ENOENT;
43
44 kn = kernfs_create_link(parent, name, target);
45 kernfs_put(target);
46
47 if (!IS_ERR(kn))
48 return 0;
49
50 if (warn && PTR_ERR(kn) == -EEXIST)
51 sysfs_warn_dup(parent, name);
52 return PTR_ERR(kn);
53 }
54
55 /**
56 * sysfs_create_link_sd - create symlink to a given object.
57 * @kn: directory we're creating the link in.
58 * @target: object we're pointing to.
59 * @name: name of the symlink.
60 */
61 int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target,
62 const char *name)
63 {
64 return sysfs_do_create_link_sd(kn, target, name, 1);
65 }
66
67 static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
68 const char *name, int warn)
69 {
70 struct kernfs_node *parent = NULL;
71
72 if (!kobj)
73 parent = sysfs_root_kn;
74 else
75 parent = kobj->sd;
76
77 if (!parent)
78 return -EFAULT;
79
80 return sysfs_do_create_link_sd(parent, target, name, warn);
81 }
82
83 /**
84 * sysfs_create_link - create symlink between two objects.
85 * @kobj: object whose directory we're creating the link in.
86 * @target: object we're pointing to.
87 * @name: name of the symlink.
88 */
89 int sysfs_create_link(struct kobject *kobj, struct kobject *target,
90 const char *name)
91 {
92 return sysfs_do_create_link(kobj, target, name, 1);
93 }
94 EXPORT_SYMBOL_GPL(sysfs_create_link);
Now inside kernfs_create_link(), we see that the key point is we allocate a new 'kernfs_node' on line 32. Then on line 38 we set kn->synlink.target_kn = target. So this is how we know the aliases.
17 /**
18 * kernfs_create_link - create a symlink
19 * @parent: directory to create the symlink in
20 * @name: name of the symlink
21 * @target: target node for the symlink to point to
22 *
23 * Returns the created node on success, ERR_PTR() value on error.
24 */
25 struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
26 const char *name,
27 struct kernfs_node *target)
28 {
29 struct kernfs_node *kn;
30 int error;
31
32 kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, KERNFS_LINK);
33 if (!kn)
34 return ERR_PTR(-ENOMEM);
35
36 if (kernfs_ns_enabled(parent))
37 kn->ns = target->ns;
38 kn->symlink.target_kn = target;
39 kernfs_get(target); /* ref owned by symlink */
40
41 error = kernfs_add_one(kn);
42 if (!error)
43 return kn;
44
45 kernfs_put(kn);
46 return ERR_PTR(error);
47 }
...
500 static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
501 const char *name, umode_t mode,
502 unsigned flags)
503 {
504 char *dup_name = NULL;
505 struct kernfs_node *kn;
506 int ret;
507
508 if (!(flags & KERNFS_STATIC_NAME)) {
509 name = dup_name = kstrdup(name, GFP_KERNEL);
510 if (!name)
511 return NULL;
512 }
513
514 kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL);
515 if (!kn)
516 goto err_out1;
517
518 ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL);
519 if (ret < 0)
520 goto err_out2;
521 kn->ino = ret;
522
523 atomic_set(&kn->count, 1);
524 atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
525 RB_CLEAR_NODE(&kn->rb);
526
527 kn->name = name;
528 kn->mode = mode;
529 kn->flags = flags;
530
531 return kn;
532
533 err_out2:
534 kmem_cache_free(kernfs_node_cache, kn);
535 err_out1:
536 kfree(dup_name);
537 return NULL;
538 }
539
540 struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
541 const char *name, umode_t mode,
542 unsigned flags)
543 {
544 struct kernfs_node *kn;
545
546 kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags);
547 if (kn) {
548 kernfs_get(parent);
549 kn->parent = parent;
550 }
551 return kn;
552 }
...
fs/kernfs/kernfs-internal.h
31 /**
32 * kernfs_root - find out the kernfs_root a kernfs_node belongs to
33 * @kn: kernfs_node of interest
34 *
35 * Return the kernfs_root @kn belongs to.
36 */
37 static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn)
38 {
39 /* if parent exists, it's always a dir; otherwise, @sd is a dir */
40 if (kn->parent)
41 kn = kn->parent;
42 return kn->dir.root;
43 }
Example 1: Finding the target kmem_cache for "kmalloc-256" and the list of aliases to the target
1) Find the kmem_cache structure for the specific slab cache you're interested in, which can be done easily with the 'kmem -s' command of crash.
crash> kmem -s kmalloc-256
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffff9ce73fc03700 kmalloc-256 256 58268801 58289024 1821532 8k
crash> p (struct kmem_cache *)0xffff9ce73fc03700
$1 = (struct kmem_cache *) 0xffff9ce73fc03700
2) Now using the kmem_cache pointer, move through the kobject to the kernfs_node, then the parent of the kernfs_node. From there, go the directory and print out the 'rb_root' for the rbtree that lists the children for the kernfs_node that represents the parent. This in essence is how we will list the directory contents of '/sys/kernel/slab'
crash> p &$1->kobj.sd->parent.dir.children
$2 = (struct rb_root *) 0xffff9cf1cef3ab10
3) Using the rb_root pointer, list out the rbtree and grep out the name of the specific slab cache you were interested in. List the pointer that is printed in the tree, since that represents the kernfs_node of this child, as well as the 'name' and in the 'synmlink' structure the 'target_kn' which is the target of the symlink. The target of the symlink is the actual kmem_alloc slab that has been allocated and this one is aliased to. If the target_kn is 0, then there is no alias.
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -A 2 -B 1 "kmalloc-256"
ffff9cedce86fd20
name = 0xffff9cf5def7c510 "dma-kmalloc-256",
symlink = {
target_kn = 0xffff9ce9cfbc2e10
--
ffff9cf1cef4a708
name = 0xffff9cf5def7c780 "kmalloc-256",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
4) Now print the name of the 'target_kn' to see what the target of the alias is.
crash> kernfs_node.name 0xffff9ce9cfbc67f8
name = 0xffff9cf5def7c770 ":t-0000256"
5) Now that we know the target of the alias, list all the other kernfs_nodes that also have this same target_kn. These will be all the aliases to the same slab, ":t-0000256"
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -B 3 "target_kn = 0xffff9ce9cfbc67f8"
name = 0xffff9cf5def7cc50 "sgpool-8",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
ffff9cf1cef4f528
name = 0xffff9cf1cef06250 "filp",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9cf1cef4f168
name = 0xffff9ce9cfb466c0 "skbuff_head_cache",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9ce9cfbcbbb8
name = 0xffff9cf1cef06240 "bio-1",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9ce9cfbcbc30
name = 0xffff9cf1cef06248 "bio-0",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
ffff9cf1cef4f348
name = 0xffff9cf5def7ca50 "pool_workqueue",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9cf1ce665d98
name = 0xffff9cf1cf714178 "bio-2",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9ce9cfbcb708
name = 0xffff9cf5def7c9b0 "ip_dst_cache",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9ce9cfbcbe10
name = 0xffff9cf5def7ca20 "biovec-16",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9cf1cef7e1e0
name = 0xffff9cf5cdc9e200 "request_sock_TCPv6",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9cf1cef4a708
name = 0xffff9cf5def7c780 "kmalloc-256",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9cf5c8ebc4b0
name = 0xffff9cf5c97eb520 "nf_conntrack_expect",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9cf1ceb6ae88
name = 0xffff9cf1dfeeea40 "rpc_tasks",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
--
ffff9ce9cfbcb870
name = 0xffff9ce9cfb463a0 "request_sock_TCP",
symlink = {
target_kn = 0xffff9ce9cfbc67f8
Example 2: Finding the target kmem_cache for "kmalloc-192" and the list of aliases to the target
1) Find the kmem_cache structure and list out the rb_root
crash> kmem -s kmalloc-192
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffff9ce73fc03800 kmalloc-192 192 116270567 116306442 2769201 8k
crash> p &((struct kmem_cache *)0xffff9ce73fc03800)->kobj.sd->parent.dir.children
$88 = (struct rb_root *) 0xffff9cf1cef3ab10
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -A 2 -B 1 "kmalloc-192"
ffff9ce9cfbc3a50
name = 0xffff9cf5def7c630 "dma-kmalloc-192",
symlink = {
target_kn = 0xffff9cf1cef46b40
--
ffff9ce9cfbc7690
name = 0xffff9cf5def7c7b0 "kmalloc-192",
symlink = {
target_kn = 0xffff9cf1cef4a780
crash>
2) List out the aliases
Raw
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -B 3 "target_kn = 0xffff9cf1cef4a780"
ffff9ce9cfbcb528
name = 0xffff9cf5def7c970 "inet_peer_cache",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9cf1cef4f690
name = 0xffff9cf1cef06258 "key_jar",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9cf1cef55168
name = 0xffff9cf1cef06278 "kiocb",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9cf1cef4f000
name = 0xffff9ce9cfb46660 "dmaengine-unmap-16",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9ce9cfbcbe88
name = 0xffff9ce9cfb46620 "bio_integrity_payload",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9ce9cfbc7690
name = 0xffff9cf5def7c7b0 "kmalloc-192",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9cf1cef4f7f8
name = 0xffff9cf5def7cac0 "cred_jar",
symlink = {
target_kn = 0xffff9cf1cef4a780
--
ffff9cf1cef4f1e0
name = 0xffff9cf5def7ca40 "file_lock_cache",
symlink = {
target_kn = 0xffff9cf1cef4a780
3) Dump out the name and 'symlink.target_kn' field of the kernfs_node for the allocated kmem_cache. Note that the 'target_kn' field is NULL and the name is "dt-0000192".
crash> kernfs_node.name 0xffff9cf1cef46b40
name = 0xffff9cf5def7c620 ":dt-0000192"
crash> kernfs_node.name,symlink 0xffff9cf1cef46b40 | grep target_kn
target_kn = 0x0
Example 3: Finding the target kmem_cache for "kmalloc-32" and "kmalloc-16" and all the aliases
Below all steps are combined. Interestingly, there is only two aliases here - "kmalloc-32" and "dma-kmalloc-32" is aliased to ":dt-0000032".
crash> kmem -s kmalloc-32
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffff9ce73fc03c00 kmalloc-32 32 58259317 58278144 455298 4k
crash> p &((struct kmem_cache *)0xffff9ce73fc03c00)->kobj.sd->parent.dir.children
$89 = (struct rb_root *) 0xffff9cf1cef3ab10
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -A 2 -B 1 "kmalloc-32"
ffff9ce9cfbc94b0
name = 0xffff9cf5def7c870 "kmalloc-32",
symlink = {
target_kn = 0xffff9cf1cef4c5a0
--
ffff9cf5def76bb8
name = 0xffff9cf5def7c5a0 "dma-kmalloc-32",
symlink = {
target_kn = 0xffff9cedce870ca8
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -B 3 "target_kn = 0xffff9cedce870ca8"
ffff9cf5def76bb8
name = 0xffff9cf5def7c5a0 "dma-kmalloc-32",
symlink = {
target_kn = 0xffff9cedce870ca8
crash> kernfs_node.name,symlink 0xffff9cedce870ca8 | grep target_kn
target_kn = 0x0
crash> kernfs_node.name,symlink 0xffff9cedce870ca8
name = 0xffff9cf5def7c590 ":dt-0000032"
symlink = {
target_kn = 0x0
}
Similarly, "kmalloc-16" and "dma-kmalloc-16" are the only two aliases to ":dt-0000016"
crash> kmem -s kmalloc-16
CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE
ffff9ce73fc03d00 kmalloc-16 16 58194387 58206464 227369 4k
crash> p &((struct kmem_cache *)0xffff9ce73fc03d00)->kobj.sd->parent.dir.children
$90 = (struct rb_root *) 0xffff9cf1cef3ab10
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -A 2 -B 1 "kmalloc-16"
ffff9cf1cef4d438
name = 0xffff9cf5def7c8a0 "kmalloc-16",
symlink = {
target_kn = 0xffff9ce9cfbc9528
--
ffff9cedce871b40
name = 0xffff9cf5def7c5d0 "dma-kmalloc-16",
symlink = {
target_kn = 0xffff9cf5def76c30
crash> tree -t rbtree 0xffff9cf1cef3ab10 -s kernfs_node -o kernfs_node.rb | egrep '(^ffff|name|symlink|target_kn)' | grep -B 3 "target_kn = 0xffff9cf5def76c30"
ffff9cedce871b40
name = 0xffff9cf5def7c5d0 "dma-kmalloc-16",
symlink = {
target_kn = 0xffff9cf5def76c30
crash> kernfs_node.name,symlink 0xffff9cf5def76c30
name = 0xffff9cf5def7c5c0 ":dt-0000016"
symlink = {
target_kn = 0x0
}