3

I'm trying to compile kernel version 4.4 in Ubuntu 16.04 LTS. I added or modified some code to store the block number of the write block in the block I / O layer into the custom buffer.

I modified the codes [linux-kernel-location]/block/blk-core.c (original):

...
#include <custom/custom-buffer.h>
...
blk_qt_t submit_bio(int rw, struct bio *bio)
{
    ...
    if(rw & WRITE)
    {
        unsigned long cntUnit = bio->bi_bdev->bd_super->s_blocks / bdev_logical_block_size(bio->bi_bdev);
        unsigned long blk_no = bio->bi_iter.bi_sector / cntUnit;

        count_vm_events(PGPGOUT, count);

        custom_buf_write_blk_no(blk_no);
    }
    ...
}
...

[linux-kernel-location]/block/Makefile (original):

...
obj-y += custom/

[linux-kernel-location]/block/Kconfig (original):

...
source "block/custom/Kconfig"

and created directories [linux-kernel-location]/include/custom, [linux-kernel-location]/block/custom. Then, I created files [linux-kernel-location]/include/custom/custom-buffer.h:

#ifndef _CUSTOM_BUFFER_H_
#define _CUSTOM_BUFFER_H_

extern int custom_buf_write_blk_no(unsigned long blk_no);

#endif

[linux-kernel-location]/block/custom/Makefile:

obj-y += custom-buffer.o

[linux-kernel-location]/block/custom/Kconfig:

config CUSTOM_BUFFER
    tristate
    depends on BLOCK
    default y

[linux-kernel-location]/block/custom/custom-buffer.c(include definition of custom_buf_write_blk_no(unsigned long blk_no) with EXPORT_SYMBOL macro).

I typed make command in shell at linux kernel location, and the following results were obtained:

...
LD    init/built-in.o
block/built-in.o: In function `submit_bio':
[linux-kernel-location]/block/blk-core.c:2117: undefined reference to `custom_buf_write_blk_no'
block/built-in.o:(___ksymtab+custom_buf_write_blk_no+0x0): undefined reference to `custom_buf_write_blk_no'
Makefile:927: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1

My guess is I need to fix the Makefile, how do I fix it?

Edit: I also know that this is happening because linker can not find the symbol in the linking process. But I don't know how to fix it in the Makefile that the Kbuild system applies to.

Solved by self: custom-buffer.c has a wrong letter. I fixed it correctly so it was compiled well.

It's too hard to find typos...

monadef
  • 55
  • 1
  • 9
  • Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Ken White Oct 14 '17 at 21:51
  • @KenWhite I also know that this is happening because linker can not find the symbol. But I don't know how to fix Makefile in Kbuild system. – monadef Oct 14 '17 at 22:04
  • As a side note, SystemTap will allow to capture block numbers without kernel recompilation. – myaut Oct 14 '17 at 22:17
  • @myaut This is to understand the behavior pattern when writing in nilfs2. I need the target block number in the write process and the time value at the time of the request to write to that block. – monadef Oct 14 '17 at 22:23
  • @monadef Have you checked kernel `make` output if your custom-buffer.c is compiled to custom-buffer.o? – Jakub Piskorz Oct 15 '17 at 00:45
  • @JakubPiskorz Yep. In steps `CC block/custom/custom-buffer.o`, `LD block/custom/built-in.o` and `LD block/built-in.o`, nothing happens. But In the next step of `LD init/built-in.o`, an error appeared. – monadef Oct 15 '17 at 01:02
  • @monadef There must be something unusual in your setup, I just cloned 4.4 kernel source `git clone --depth 1 --single-branch --branch v4.4 git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git`, added exactly the same files you're describing. With dummy implementation: `int custom_buf_write_blk_no(unsigned long blk_no) { printk(KERN_INFO "WIP NUMBER %lu\n", blk_no); return 0; } EXPORT_SYMBOL(custom_buf_write_blk_no);`. And it compiles. – Jakub Piskorz Oct 15 '17 at 02:59
  • @JakubPiskorz I found a typo in my source file... It is very difficult to find typos... – monadef Oct 15 '17 at 09:27

1 Answers1

3

Yes, it is hard to find typos. But compiler tries to show us place where the typo been made.

I've tried to reproduce your issue to write an answer that may help others visiting this question.

First, what would have happened if you made a typo in your filename? Lets say custom/custom-buffe.c

Kernel build system will complain:

CHK     include/generated/compile.h
make[2]: *** No rule to make target 'block/custom/custom-buffer.o', needed by 'block/custom/built-in.o'.  Stop.
scripts/Makefile.build:403: recipe for target 'block/custom' failed
make[1]: *** [block/custom] Error 2
Makefile:943: recipe for target 'block' failed
make: *** [block] Error 2

So, it is clear that build rule is looking for file to create custom-buffer.o, but it is missing. By default, it should have custom-buffer.c. From documentation:

The most simple kbuild makefile contains one line:

Example: obj-y += foo.o

This tells kbuild that there is one object in that directory, named foo.o. foo.o will be built from foo.c or foo.S.

It was not your case. So then I've made a typo in function definition (buff vs buf):

int custom_buff_write_blk_no(unsigned long blk_no) {
  printk(KERN_INFO "WIP NUMBER %lu\n", blk_no);
  return 0;
}
EXPORT_SYMBOL(custom_buff_write_blk_no);

And now, after building I have info from compiler:

LD      init/built-in.o
block/built-in.o: In function `submit_bio':
(.text+0x8bb0): undefined reference to `custom_buf_write_blk_no'
Makefile:929: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1

We can trace what exactly this LD step is doing by issuing make V=1:

+ ld -m elf_x86_64 --build-id -o .tmp_vmlinux1 -T ./arch/x86/kernel/vmlinux.lds arch/x86/kernel/head_64.o arch/x86/kernel/head64.o arch/x86/kernel/head.o init/built-in.o --start-gr
oup usr/built-in.o arch/x86/built-in.o kernel/built-in.o certs/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o lib/lib.
a arch/x86/lib/lib.a lib/built-in.o arch/x86/lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch/x86/pci/built-in.o arch/x86/power/built-in.o arch/x86/video
/built-in.o arch/x86/ras/built-in.o net/built-in.o virt/built-in.o --end-group
block/built-in.o: In function `submit_bio':
(.text+0x8bb0): undefined reference to `custom_buf_write_blk_no'

First, we think that everything is correct, and our custom_buf_write_blk_no symbol should be in file block/custom/build-in.o. Here we don't see this file. But, Kbuild system merges all objects recursively to one build-in.o:

Kbuild compiles all the $(obj-y) files. It then calls "$(LD) -r" to merge these files into one built-in.o file. built-in.o is later linked into vmlinux by the parent Makefile.

So it should be in block/build-in.o. To make sure we can trace it by investigating make V=1 output:

...
ld -m elf_x86_64   -r -o block/custom/built-in.o block/custom/custom-buffer.o
...
ld -m elf_x86_64   -r -o block/built-in.o block/bio.o block/elevator.o block/blk-core.o block/blk-tag.o block/blk-sysfs.o block/blk-flush.o block/blk-settings.o block/blk-ioc.o 
block/blk-map.o block/blk-exec.o block/blk-merge.o block/blk-softirq.o block/blk-timeout.o block/blk-iopoll.o block/blk-lib.o block/blk-mq.o block/blk-mq-tag.o block/blk-mq-sysfs.o
block/blk-mq-cpu.o block/blk-mq-cpumap.o block/ioctl.o block/genhd.o block/scsi_ioctl.o block/partition-generic.o block/ioprio.o block/partitions/built-in.o block/bounce.o block/b
sg.o block/noop-iosched.o block/deadline-iosched.o block/cfq-iosched.o block/compat_ioctl.o block/custom/built-in.o 

Indeed, there is our custom-buffer.o. So why we have undefined reference? Well, we can investigate symbols that are in block/build-in.o, by using objdump -t block/built-in.o | grep custom:

0000000000000000 l    d  ___ksymtab+custom_buff_write_blk_no    0000000000000000 ___ksymtab+custom_buff_write_blk_no
0000000000000000 l    df *ABS*  0000000000000000 custom-buffer.c
000000000000132e l     O __ksymtab_strings      0000000000000019 __kstrtab_custom_buff_write_blk_no
0000000000000000         *UND*  0000000000000000 custom_buf_write_blk_no
0000000000000000 g     O ___ksymtab+custom_buff_write_blk_no    0000000000000010 __ksymtab_custom_buff_write_blk_no
0000000000025ed0 g     F .text  0000000000000017 custom_buff_write_blk_no

Now we see symbol custom_buff_write_blk_no and compiler complains that he is looking for custom_buf_write_blk_no.

Jakub Piskorz
  • 1,023
  • 12
  • 21
  • I had to step this way! I did not think I would use `objdump`... You've reproduced it perfectly! You are the first to write me an answer so easily understandable! – monadef Oct 16 '17 at 14:14