fs/ext4
fs/ext4/Kconfig
fs/ext4/Makefile
fs/ext4/code.c
(Aus fs/ext4/Kconfig)
config
leitet eine Konfigurationsoption ein, dahinter der Bezeichner der Optiontristate
bezeichnet den Typ der Option (tristate
, bool
, int
, string
, …)select
wählt zusätzliche Optionen, wenn diese Option aktiviert wirdhelp
ist selbst erklärenddepends
→ Beschreibt Abhängigkeiten zu anderen OptionenCONFIG_
zur Verfügungobj-y += foo.o
: Übersetze Datei foo.c
immerobj-m += foo.o
: Übersetze Datei foo.c
, wenn die Modulunterstützung aktiv istobj-$(CONFIG_FOO) += foo.o
foo.c
, wenn Konfigurationsoption CONFIG_FOO
entweder y oder m ist(Aus fs/Makefile)
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux ext4-filesystem routines.
#
obj-$(CONFIG_EXT4_FS) += ext4.o
ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \
extents_status.o file.o fsmap.o fsync.o hash.o ialloc.o \
indirect.o inline.o inode.o ioctl.o mballoc.o migrate.o \
mmp.o move_extent.o namei.o page-io.o readpage.o resize.o \
super.o symlink.o sysfs.o xattr.o xattr_hurd.o xattr_trusted.o \
xattr_user.o fast_commit.o orphan.o
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
# [....]
obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o
# [....]
(Aus fs/ext4/Makefile)
ext4.o
besteht aus mehreren Quellcodedateienext4-y :=
(gdb) bt
#0 universe_read (file=0xffff88800453b700,
buf=0x7f9b78c4a000 <error: Cannot access memory at address 0x7f9b78c4a000>,
count=42, ppos=0xffffc90000507ef0) at drivers/sst/sst_chrdev.c:25
#1 0xffffffff812a5579 in vfs_read (file=file@entry=0xffff88800453b700,
buf=buf@entry=0x7f9b78c4a000 <error: Cannot access memory at address 0x7f9b78c4a000>,
count=count@entry=131072, pos=pos@entry=0xffffc90000507ef0) at fs/read_write.c:468
#2 0xffffffff812a60e3 in ksys_read (fd=<optimized out>,
buf=0x7f9b78c4a000 <error: Cannot access memory at address 0x7f9b78c4a000>,
count=131072) at fs/read_write.c:613
#3 0xffffffff812a6179 in __do_sys_read (count=<optimized out>, buf=<optimized out>,
fd=<optimized out>) at fs/read_write.c:623
#4 __se_sys_read (count=<optimized out>, buf=<optimized out>, fd=<optimized out>)
at fs/read_write.c:621
#5 __x64_sys_read (regs=<optimized out>) at fs/read_write.c:621
#6 0xffffffff81b1b055 in do_syscall_x64 (nr=<optimized out>, regs=0xffffc90000507f58)
at arch/x86/entry/common.c:50
#7 do_syscall_64 (regs=0xffffc90000507f58, nr=<optimized out>)
at arch/x86/entry/common.c:80
#8 0xffffffff81c0006a in entry_SYSCALL_64 () at arch/x86/entry/entry_64.S:120
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret;
if (!(file->f_mode & FMODE_READ))
return -EBADF;
if (!(file->f_mode & FMODE_CAN_READ))
return -EINVAL;
if (unlikely(!access_ok(buf, count)))
return -EFAULT;
// [...]
if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);
else if (file->f_op->read_iter)
ret = new_sync_read(file, buf, count, pos);
else
ret = -EINVAL;
if (ret > 0) {
fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
return ret;
}
(Aus fs/read_write.c:468)
UNIX
-Paradigma
struct file_operations
:struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
// [...]
} __randomize_layout;
(Aus include/linux/fs.h:2109)
struct file
struct file {
// [...]
struct path f_path;
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;
// [...]
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
loff_t f_pos;
// [...]
/* needed for tty driver, and maybe others */
void *private_data;
// [...]
} __randomize_layout
__attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
(Aus include/linux/fs.h:940)
printf()
(Formatstring, Argumente, …)printk()
, Semantik ist aber gleich!pr_err
, pr_info
, pr_debug
, …printk_ratelimited()
🤔vmalloc
/vfree
kmalloc
/kfree
kmalloc
-Flags
GFP_KERNEL
: „Allocate normal kernel ram. May sleep.”GFP_NOWAIT
: „Allocation will not sleep.”GFP_ATOMIC
: „Allocation will not sleep. May use emergency pools.”clone()
, wie beim Systemaufruf fork()
Thread erstellen:
struct *task_struct kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[],...)
Erstellten Thread aufwecken:
int wake_up_process(struct task_struct *tsk)
Warten bis der Thread sich beendet:
int kthread_stop(struct task_struct *tsk)
Soll der Thread anhalten?
bool kthread_should_stop(void)
Weitere Funktionen und „Dokumentation” finden sich in include/linux/kthread.h
#include <linux/kthread.h>
char *text = "Hello from the other side!";
struct task_struct *faden;
static int work_fn(void *arg) {
char *text = (char*)arg;
while (!kthread_should_stop()) {
printk("Working: %s\n", text);
ssleep(1);
}
return 0;
}
static init __init module_init(void) {
faden = kthread_create(work_fn, (void*)text, "ein-name");
if (IS_ERR(faden)) {
pr_err("Error\n");
}
return 0;
wake_up_process(faden);
return 0;
}
// kthread_stop(faden);
(Siehe Kapitel 10 in „Linux Kernel Development” [2])
spin_lock
/spin_unlock
_bh
, _irq
, _irqsave
down
/up
(Besser: down_interruptible
)mutex_lock
/mutex_unlock
drivers/sst/sst_common.c
in Zeile 146 bzw. 171)BoundedBuffer
aus unserem Treiber. Fragt gerne nach.)get_random_uX()
– siehe include/linux/random.hstrcpy()
, strcmp()
, … (Dokumentation)kstrtol()
(Dokumentation) oder sscanf()
(Dokumentation)→ Im Zweifel eine Ausgabe und einen Fehlercode zurückgegeben