08
19

Linux file system for dummies-只花你45分鐘

小弟其實一直很想跟大家介紹這篇文章"Linux File Systems in 45 minutes”,原文出處是在2006的Linux symposium的open conference,由NFS和Samba的作者Steve French執筆,而其主要的內容是把linux VFS和file system之間的函式呼叫和使用到的資料結構做一個簡單的介紹

Linux file system簡單的架構圖如下

attachments/200908/4390102026.jpg 

假設有一個/mnt的目錄,而在其下有兩個檔案和一個hardlink,從上圖的左上方看到super_block透過register_filesystem而跟kernel的file system type list產生連繫,super_block內記載了root inode的訊息,而root inode也把它的next指標指向dentry object

每個dentry object都是double linked list item,藉由此dentry list,可以走遍所有的目錄和其下的檔案,從上圖出可看到file的f_dentry指標皆連至dentry的hash list,在實做file system的過程中,dentry的manipulation是不需要programmer擔心的,programmer只要專心在inode的操縱和file operation的call back撰寫

我照著此篇文章的範本,改寫成在2.6.26的kernel可以動的程式,分段解釋如下

宣告file system的type並註冊get_sb和kill_sb的function,這兩個function會在mount及unmount時被呼叫

  1. static struct file_system_type myfs_type = { 
  2. .owner = THIS_MODULE,
  3. .name = "myfs",
  4. .get_sb = myfs_get_sb,
  5. .kill_sb = kill_litter_super,
  6. /* .fs_flags */ 
  7. };
  8.  
  9.  
  10. static int __init init_myfs_fs(void) 
  11. { 
  12. return register_filesystem(&myfs_type);
  13. } 
  14.  
  15. static void __exit exit_myfs_fs(void) 
  16. { 
  17. unregister_filesystem(&myfs_type);
  18. }

設定super block的相關參數,並創造第一個root inode

  1. static int myfs_fill_super(struct super_block * sb, void * data, int silent) 
  2. { 
  3. struct inode * inode;
  4. struct dentry * root;
  5.  
  6. printk("mount option %s\n",(char *)data);
  7. sb->s_maxbytes = MAX_LFS_FILESIZE;
  8. sb->s_blocksize = PAGE_CACHE_SIZE;
  9. sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
  10. sb->s_magic = MYFS_MAGIC;
  11. sb->s_op = &myfs_ops;
  12. sb->s_time_gran = 1;
  13. inode = myfs_get_inode(sb, S_IFDIR | 0755, 0);;
  14. if (!inode) 
  15. return -ENOMEM;
  16.  
  17. root = d_alloc_root(inode);
  18. if (!root) { 
  19. iput(inode);
  20. return -ENOMEM;
  21. } 
  22. sb->s_root = root;
  23.  
  24. return 0;
  25. }

這是程式裡面最重要的一個function,它會根據mode的不同而賦予inode不同的operation

  1. struct inode *myfs_get_inode(struct super_block *sb, int mode, dev_t dev) 
  2. { 
  3. struct inode * inode = new_inode(sb);
  4.  
  5. if (inode) { 
  6. inode->i_mode = mode;
  7. inode->i_uid = current->fsuid;
  8. inode->i_gid = current->fsgid;
  9. inode->i_blocks = 0;
  10. //add file operation
  11. inode->i_mapping->a_ops = &myfs_aops;
  12. inode->i_mapping->backing_dev_info = &myfs_backing_dev_info;
  13.  
  14. inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  15. switch (mode & S_IFMT) { 
  16. default:
  17. init_special_inode(inode, mode, dev);
  18. break;
  19. case S_IFREG:
  20. inode->i_op = &simple_dir_inode_operations;
  21. inode->i_fop = &myfs_file_operations;
  22. break;
  23. case S_IFDIR:
  24. inode->i_op = &myfs_dir_inode_operations;
  25. inode->i_fop = &simple_dir_operations;
  26.  
  27. /* directory inodes start off with i_nlink == 2 (for "." entry) */ 
  28. inc_nlink(inode);
  29. break;
  30. //case S_IFLNK:
  31. //inode->i_op = &page_symlink_inode_operations;
  32. break;
  33. } 
  34. } 
  35. return inode;
  36. }

在目錄的operation callback中,有三個要自己實作,分別是mknod,mkdir和create,內容大致如下

  1. static int myfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) 
  2. { 
  3. struct inode * inode = myfs_get_inode(dir->i_sb, mode, dev);
  4. int error = -ENOSPC;
  5.  
  6. if (inode) { 
  7. if (dir->i_mode & S_ISGID) { 
  8. inode->i_gid = dir->i_gid;
  9. if (S_ISDIR(mode)) 
  10. inode->i_mode |= S_ISGID;
  11. } 
  12. d_instantiate(dentry, inode);
  13. dget(dentry); /* Extra count - pin the dentry in core */ 
  14. error = 0;
  15. dir->i_mtime = dir->i_ctime = CURRENT_TIME;
  16. } 
  17. return error;
  18. } 
  19.  
  20.  
  21. static int myfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) 
  22. { 
  23.  
  24. int retval = myfs_mknod(dir, dentry, mode | S_IFDIR, 0);
  25. if (!retval) 
  26. inc_nlink(dir);
  27. return retval;
  28. } 
  29.  
  30. static int myfs_create(struct inode *dir, struct dentry *dentry, int mode,struct nameidata *nd) 
  31. { 
  32. return myfs_mknod(dir, dentry, mode | S_IFREG, 0);
  33. } 
  34.  
  35. struct inode_operations myfs_dir_inode_operations = { 
  36. .create = myfs_create,
  37. .lookup = simple_lookup,
  38. .unlink = simple_unlink,
  39. .mkdir = myfs_mkdir,
  40. .rmdir = simple_rmdir,
  41. .mknod = myfs_mknod,
  42. .rename = simple_rename,
  43. };

而file的operation就不用多說了,直接拉現成的API即可

  1. struct address_space_operations myfs_aops = { 
  2. .readpage = simple_readpage,
  3. .write_begin = simple_write_begin,
  4. .write_end = simple_write_end,
  5. };
  6.  
  7. struct file_operations myfs_file_operations = { 
  8. .read = do_sync_read,
  9. .aio_read = generic_file_aio_read,
  10. .write = do_sync_write,
  11. .aio_write = generic_file_aio_write,
  12. .mmap = generic_file_mmap,
  13. .fsync = simple_sync_file,
  14. .llseek = generic_file_llseek,
  15. .splice_read = generic_file_splice_read,
  16. };

程式編好後,丟到板子上並執行,步驟如下
1.insmod myfs.ko
2.mount –t myfs any /myfs
3.stat /myfs;cat /proc/mounts
4.Go into myfs directory and do some basic read/write
5.umount myfs and remove module
執行畫面如下

attachments/200908/5478913517.jpg

完整的範例程式碼請在這裡下載

標籤: linux
評論: 0 | 引用: 0 | 閱讀: 16666
發表評論
暱 稱: 密 碼:
網 址: E - mail:
驗證碼: 驗證碼圖片 選 項:
頭 像:
內 容: