Digging into ext2

  • View
    19

  • Download
    2

Embed Size (px)

DESCRIPTION

Digging into ext2. Nezer J. Zaidenberg. Agenda. Linux kernel module programming (summary from TLDP) Abstract (Virtual) in C Initial code review and work on ext2 How to start working on ex 3 + more digging methods Some clues on ex3. References. - PowerPoint PPT Presentation

Text of Digging into ext2

  • Digging into ext2Nezer J. Zaidenberg

  • AgendaLinux kernel module programming (summary from TLDP)Abstract (Virtual) in CInitial code review and work on ext2How to start working on ex 3 + more digging methodsSome clues on ex3

  • ReferencesThe linux kernel - www.kernel.org (or local mirror)The linux documentation project Kernel module programming 2.6 www.tldp.org (http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html)Under KERNEL tree Documentation/Kbuildfs/*.cfs/ext2/*.cUNIX filesystemsUnderstanding The Linux KernelThe linuxkerenl (from tldp.org) has a fairly reqasonable description of ext2.h and file systems in general but is referring to version 2.0 of Linux (so The concepts are correct but but some files have different names!)

  • Hello world module (1/2) in kernel 2.6l#include/* Needed by all modules */#include /* Needed for KERN_INFO */#include /* Needed for the macros */static int __init hello_2_init(void){printk(KERN_INFO "Hello, world 2\n");return 0;}

  • Hello world module (2/2)static void __exit hello_2_exit(void){printk(KERN_INFO "Goodbye, world 2\n");}module_init(hello_2_init);module_exit(hello_2_exit);

  • Makefile for kernel moduleobj-m += hello-2.o

    all:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

    clean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

  • Makefile for multiple objectsobj-m += startstop.ostartstop-objs := start.ostop.o

    all:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

    clean:make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

  • Implementing abstract functions in Cclass base{virtual foo()virtual bar()Widget W;}class derived : public class base // Extends class base{foo()}

  • Calling base and derived functionsbase b;derived d;base * ptr=&b;(*ptr).foo();(*ptr).bar();ptr=&d;(*ptr).foo();(*ptr).bar();

  • How does the compiler knows which function to call?

  • The Virtual implementationWhen implementing virtual in memory, we keep for every object a Virtual tableThe virtual table holds function names and pointers to functionsWhen we use (*ptr)->foo() the function call goes to the Virtual table and looks for foo.When it finds foo it will call the right function.

  • What does it have to do with C?

  • Abstract functions in CThe fact that C have no virtual table built by the compiler for us does not mean we cannot built one ourselves. (If you think it through everything in C++/Java compiles to assembler (close to C) with no classes either)We just have to build the virtual table ourselvesFor every struct widget we can add structwidget_operations * which will hold pointers to functions that operate on widget. (and can be implemented as we want)Since the compiler in C lacks the class and inheritance mechanism we have to do lots of things ourselves such asDeliver the * this to the functionsInitialize the struct widget operations Call the function in a bit akward way (b.foo() -> (*(b->ops.foo)(&b))

  • The abstract interfacestructfile_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(*aio_read) (structkiocb *, char __user *, size_t, loff_t);ssize_t(*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t(*aio_write) (structkiocb *, const char __user *, size_t,Complete struct (and others) found under Kernel source tree include/linux/fs.h

  • Filling the abstract interface (GCC)structfile_operations fops = {read: device_read,write: device_write,open: device_open,release: device_release};

  • Filling the abstract interface (C99)structfile_operations fops = {.read = device_read,.write = device_write,.open = device_open,.release = device_release};

  • fs/ext2/super.c1426 static void __exit exit_ext2_fs(void)1427 {1428 unregister_filesystem(&ext2_fs_type);1429 destroy_inodecache();1430 exit_ext2_xattr();1431 }1432 1433 module_init(init_ext2_fs)1434 module_exit(exit_ext2_fs)

  • fs/ext2/super.c1407 static int __init init_ext2_fs(void)1408 {1409 int err = init_ext2_xattr();1410 if (err)1411 return err;1412 err = init_inodecache();1413 if (err)1414 goto out1;1415 err = register_filesystem(&ext2_fs_type);

  • fs/ext2/super.c1416 if (err)1417 goto out;1418 return 0;1419 out:1420 destroy_inodecache();1421 out1:1422 exit_ext2_xattr();1423 return err;1424 }

  • What have we just seenInit the moduleExitRegister/unregister the file systemIt would be perfectly reasonable if your module just call registerfs and unregisterfs in the init module and exit module (you dont REALLY need inode cache and xattr etc.)

  • Struct ex2_fs_type (fs/ext2/super.c)1399 static structfile_system_type ext2_fs_type = {1400 .owner = THIS_MODULE,1401 .name = "ext2",1402 .get_sb = ext2_get_sb,1403 .kill_sb = kill_block_super,1404 .fs_flags = FS_REQUIRES_DEV,1405 };

  • What have we just seenWe have 5 fields .owner = THIS_MODULE (so if this file system is mounted we cannot unmount this module).name = ext2 (the name that will be specified by t to mount).get_sb = what to do to get super block (call ext2 method).kill_sb = how to free the super block (call linux method)FS_REQUIRES_DEV This file system is based on device

  • ext2_get_sb (from fs/ext2/super.c)1288 static int ext2_get_sb(struct file_system_type *fs_type,1289 int flags, const char *dev_name, void *data, structvfsmount *mnt)1290 {1291 return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super, mnt);1292 }

  • What have we just seenWe call standard Linux kernel method to get super block for file system based on BLOCK device This function initialize the block deviceWe give this function as argument a function to fill the private file super block (read it from disk) called ext2_sb_fill

  • Continuing the dig fs/super.cYoull find get_sb_bdev at lines 751-813 (note its a different file) This function does a lot we dont really care about (initialize the block device) etc. But in lines 795-800 you shall find :795 error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);796 if (error) {797 up_write(&s->s_umount);798 deactivate_super(s);799 goto error;800 }Lets take it from there

  • Back to fs/ext2/super.c 738 static int ext2_fill_super(struct super_block *sb, void *data, int silent) 739 { 740 structbuffer_head* bh;756 sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 757 if (!sbi) 758 return -ENOMEM; 759 sb->s_fs_info = sbi;760 sbi->s_sb_block = sb_block;

  • fs/ext2/super.c 779 if (blocksize != BLOCK_SIZE) { 780 logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; 781 offset = (sb_block*BLOCK_SIZE) % blocksize; 782 } else { 783 logic_sb_block = sb_block; 784 } 785

  • fs/ext2/super.c786 if (!(bh = sb_bread(sb, logic_sb_block))) { 787 printk ("EXT2-fs: unable to read superblock\n"); 788 gotofailed_sbi; 789 } 790 /* 791 * Note: s_es must be initialized as soon as possible because 792 * some ext2 macro-instructions depend on its value 793 */ 794 es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); 795 sbi->s_es = es;

  • fs/ext2/super.c 798 if (sb->s_magic != EXT2_SUPER_MAGIC) 799 goto cantfind_ext2;1042 sb->s_op = &ext2_sops;1045 root = ext2_iget(sb, EXT2_ROOT_INO);

  • fs/ext2/super.c 299 static const structsuper_operations ext2_sops = { 300 .alloc_inode = ext2_alloc_inode, 301 .destroy_inode = ext2_destroy_inode, 302 .write_inode = ext2_write_inode, 303 .delete_inode = ext2_delete_inode, 304 .put_super = ext2_put_super,314 };

  • fs/ext2/super.c305 .write_super = ext2_write_super, 306 .statfs = ext2_statfs, 307 .remount_fs = ext2_remount, 308 .clear_inode = ext2_clear_inode, 309 .show_options = ext2_show_options, 310 #ifdef CONFIG_QUOTA 311 .quota_read = ext2_quota_read, 312 .quota_write = ext2_quota_write, 313 #endif

  • What have we just seenThe function find the exact block to read based on block device block size and super block block sizeThe function reads the super block via the bread API for block devices (the data is read into buffer header struct)The function stores private dataThe function checks magic number (you should also do)The function set super block opsThe function reads the root directory

  • Saving private dataLinux structsuper_block has a void * called s_fs_infoLinux structinode has a void * called i_privateThose pointers can be used to save private data (your file system structure)You can use those pointers data later

  • Include files and structsInclude/linux/fs.h has most struct definitions includingstructsuper_block (lines 1106-1176)structinode (lines 623-688)structblock_device (lines 550-580)Structbuffer_head is found at line 60 of buffer_head.hOperationssuper_operationsfs.h : 1358Inode_operationsfs.h: 1311File_ioerations: fs.h 1281Address_space_operationsfs.h : 486 (for mmap)

  • Lots of time we will go from our file system code to Linux code and