1. 程式人生 > >從ramfs分析檔案系統的設計和實現

從ramfs分析檔案系統的設計和實現

作者:楊紅剛,蘭州大學

郵箱:[email protected] / [email protected]

--------------------------------------------------------------------

REF:
1. linux-3.6.9/fs/ramfs
2. Documentation/filesystems/ramfs-rootfs-initramfs.txt

目錄:

0. 檔案系統各個資料結構之間的聯絡圖

1. 分析了一個最簡單的Linux檔案系統ramfs的實現

   分析了最簡單的檔案系統ramfs的實現。

2. 最小檔案系統設計小結

    總結對ramfs的分析,得出最小檔案系統的設計實現關鍵。

3. 最小檔案系統例項

    該部分基本上覆制了ramfs的實現,通過該過程和修改相關的函式實現,可以研究

     每個函式的作用。加深對fs的理解。

-------------------------------------------------------------------------------------------------------------------

第零章 檔案系統各個資料結構之間的聯絡圖

在開始之前以ext4為例子先給出整個檔案系統的資料結構之間的關係圖。通過以後的

循序漸進的理解,最後就能理解整個圖的含義了。

高清圖下載


第一章 分析了一個最簡單的Linux檔案系統ramfs的實現

ramfs展示了怎樣設計一個虛擬檔案系統(virtual filesystem)。
它實現了一個符合POSIX規範的檔案系統的所有的邏輯。
該檔案系統沒有實現獨立的資料結構,僅僅利用了VFS中已經定義
結構。

ramfs將Linux磁碟緩衝匯出為一個可動態調整大小的基於RAM的檔案
系統。ramfs沒有後備儲存源。向ramfs中進行的檔案寫操作也會
分配目錄項和頁快取,但是資料並不寫回到任何其他儲存介質上。
這意味著涉及的記憶體頁不會被標記為“乾淨”狀態,這樣VM就不會
回收分配給ramfs的記憶體。

由於ramfs的實現完全基於已經存在的Linux緩衝機制,所以其程式碼
很少(不超過634行)。


首先,通過檢視Makefile檔案檢查ramfs依賴的模組。
obj-y += ramfs.o

file-mmu-y := file-nommu.o
file-mmu-$(CONFIG_MMU) := file-mmu.o
ramfs-objs += inode.o $(file-mmu-y)

可見ramfs-objs由inode.c,如果CONFIG_MMU配置為Y,那麼
還包括file-mmu.c,否則,包含file-nommu.c。
下面的討論假定CONFIG_MMU為Y。

--- include/linux/ramfs.h -----
該檔案中為ramfs模組對其他模組的介面。包括:

    函式
    ramfs_get_inode()
    ramfs_mount()
    init_rootfs()
    ramfs_fill_super()

    資料結構
    const struct file_operations ramfs_file_operations
    vm_operations_struct generic_file_vm_ops


------------------------------
---- fs/ramfs/file-mmu.c -----
------------------------------

該檔案中為ramfs_file_operations、ramfs_aops和ramfs_file_inode_operations
的具體初始化。

const struct address_space_operations ramfs_aops = {
    .readpage   = simple_readpage,
    .write_begin    = simple_write_begin,
    .write_end  = simple_write_end,
    .set_page_dirty = __set_page_dirty_no_writeback,
};
該結構中為ramfs的“地址空間”結構。"地址空間"結構,
將快取資料與其來源之間建立關聯。該結構用於ramfs向記憶體模組申請記憶體頁,並提供
從後備資料來源讀取資料並填充緩衝區以及將緩衝區中的資料寫入後備裝置等操作。


const struct file_operations ramfs_file_operations = {
    .read       = do_sync_read,
    .aio_read   = generic_file_aio_read,
    .write      = do_sync_write,
    .aio_write  = generic_file_aio_write,
    .mmap       = generic_file_mmap,
    .fsync      = noop_fsync,
    .splice_read    = generic_file_splice_read,
    .splice_write   = generic_file_splice_write,
    .llseek     = generic_file_llseek,
};
該結構為ramfs中檔案的通用檔案操作函式集合。

const struct inode_operations ramfs_file_inode_operations = {
    .setattr    = simple_setattr,
    .getattr    = simple_getattr,
};
尬結構包括ramfs的檔案節點操作函式集合。


-------------------------
---- fs/ramfs/inode.c ---
-------------------------

ramfs的模組初始化函式:
static int __init init_ramfs_fs(void);
呼叫核心函式register_filesystem()註冊ramfs。
關於ramfs的描述結構rootfs_fs_type的初始化如下:
static struct file_system_type ramfs_fs_type = {
    .name       = "ramfs",
    .mount      = ramfs_mount,
    .kill_sb    = ramfs_kill_sb,
};
"ramfs"為檔案系統的名字。
ramfs_mount為ramfs的掛載操作。
ramfs_kill_sb為不再需要ramfs檔案系統時執行相關清理工作。


------------------------------------------------------
作用:初始化ramfs的超級塊。
註釋:包括掛載引數,根inode和根目錄項等的初始化。
int ramfs_fill_super(struct super_block *sb, void *data, int silent);

 [1] 將檔案系統的掛載引數儲存到sb.s_options欄位。該值用於generic_show_options()
函式對檔案系統掛載引數的顯示操作。
 [2] 分配ramfs特有的ramfs_fs_info結構。其原型為:

struct ramfs_mount_opts {
    umode_t mode;
};

struct ramfs_fs_info {
    struct ramfs_mount_opts mount_opts;
};
 [3] 指向ramfs_fs_info結構的指標存放在ramfs的超級塊的私有欄位s_fs_info中。
 [4] 呼叫ramfs_parse_options()對掛載引數進行解析。將掛載引數“mode=XX”中的
   XX儲存在ramfs_mount_opts的mode欄位。預設值為0755。其他掛載引數都被忽略。
 [5] 初始化超級塊的s_maxbytes為MAX_LFS_FILESIZE。該欄位表示最大的檔案長度。
   初始化超級塊的s_blocksize欄位為PAGE_CACHE_SIZE。該欄位表示檔案系統塊的長度,
   單位為位元組。另一個欄位為s_blocksize_bits欄位,該欄位也表示檔案系統塊的長度,
   只是它為s_blocksize取以2為底的對數。
     初始化超級塊的s_magic欄位,該欄位為超級塊的魔數,用於檢查超級塊的損壞。
   初始化超級塊的s_op欄位為ramfs_ops。該結構包含了用於處理超級塊的相關操作。
 
static const struct super_operations ramfs_ops = {
    .statfs     = simple_statfs, //給出檔案系統的統計資訊,例如使用和未使用的資料塊的數目,或者檔案件名的最大長度。  
    .drop_inode = generic_delete_inode, //當inode的引用計數降為0時,將inode刪除。
    .show_options   = generic_show_options, //用以顯示檔案系統裝載的選項。
};

     初始化超級塊的s_time_gran欄位。它表示檔案系統支援的各種時間戳的最大可能的粒度。單位為ns。
 [6] 呼叫ramfs_get_inode()為ramfs超級塊在生成一個代表根節點inode。並將inode各個欄位進行初始化。最後,返回
   指向該根inode的指標。(具體操作詳見下文分析。)
 [7] 呼叫d_make_root()為根inode建立並初始化一個目錄項。

------------------------------------------------------
作用:查詢或者建立一個VFS超級塊super_block結構。執行ramfs_fill_supper()對ramfs的超級
   塊進行初始化。然後,對根目錄的目錄項引用計數增一。
struct dentry *ramfs_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *data);

-----------------------------------------------

static void ramfs_kill_sb(struct super_block *sb)

[1] 釋放ramfs私有的資料結構ramfs_fs_info。
[2] 呼叫kill_litter_super()執行對超級塊的清理操作。


------------------------------------------------------
struct inode *ramfs_get_inode(struct super_block *sb,
                const struct inode *dir, umode_t mode, dev_t dev)

[1] 呼叫new_inode()建立一個符合ramfs型別的inode結構。
[2] 初始化inode的編號。
  初始化inode的uid, gid, mode欄位。
  初始化inode的“地址空間”的操作集合為ramfs_aops,該操作集合和ramfs檔案內容讀寫相關。
    初始化inode的後備儲存裝置的有關資訊為ramfs_backing_dev_info。後備儲存裝置是與“地址空間”相關的外部裝置,是資料的來源和去向。

    為inode的flags欄位新增GFP_HIGHUSER標記。flags欄位標誌集主要用於儲存對映頁所來自的GFP記憶體區的有關資訊。該欄位也可以
  用來儲存非同步傳輸期間發生的錯誤資訊,在非同步傳輸期間錯誤無法直接傳遞給呼叫者。AS_EIO表示一般性I/O錯誤,AS_ENOSPC表示沒有足夠的空間
  來完成一個非同步寫操作。GFP_HIGHUSER表示儲存記憶體頁的實體記憶體優先從高階記憶體區域獲取。
    
    為inode的flags新增AS_UNEVICTABLE標誌。這樣ramfs涉及的記憶體頁就會放入unevictable_list中,這些記憶體頁不會再被回收。
    
    初始化inode的i_atime, i_mtime, i_ctime為當前時間。

[3] 根據mode的設定為inode設定四種不同操作集:
    - REG//普通檔案
        設定inode的i_op為ramfs_file_inode_operations操作集。
    設定inode的i_fop為ramfs_file_operations操作集。    
    - DIR//資料夾
        設定inode的i_op為ramfs_dir_inode_operations操作集。
    設定inode的i_fop為simple_dir_operations操作集。
    - LINK//連結    
        設定i_op為page_symlink_inode_operations操作集。
[4] 將初始化好的inode的指標返回。

--------- 地址空間操作 -------------------
const struct address_space_operations ramfs_aops = {
    .readpage   = simple_readpage,
    .write_begin    = simple_write_begin,
    .write_end  = simple_write_end,
    .set_page_dirty = __set_page_dirty_no_writeback,
};
simple_readpage: 用於從後備儲存器將一頁資料讀入頁框。對於ramfs沒有後備儲存器,只有RAM。

simple_write_begin:
  根據檔案的讀寫位置pos計算出檔案的頁偏移值。
    根據索引查詢或者分配一個page結構。
  將頁中資料初始化為“0”。

simple_write_end: 在對page執行寫入操作後,執行相關更新操作。

__set_page_dirty_no_writeback: 將某個頁標記為“髒”。但是並不執行寫回操作,
  因為ramfs不需要寫回到磁碟。這也是為什麼ramfs重寫掛載後,之前寫入的資料丟失的原因。


------------ 後備儲存器 -----------------
static struct backing_dev_info ramfs_backing_dev_info = {
    .name       = "ramfs",
    .ra_pages   = 0,    /* No readahead */
    .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK |
              BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
              BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
};
該結構描述了作為資料來源和去向的後備儲存裝置的相關描述資訊。

ra_pages: 設定了最大預讀數量。
BDI_CAP_NO_ACCT_AND_WRITEBACK 不需要寫回、不執行髒頁統計、不自動計算回寫頁統計。
BDI_CAP_MAP_DIRECT 可以直接對映。
BDI_CAP_MAP_COPY 拷貝可以被對映。
BDI_CAP_READ_MAP 可以對映讀取。
BDI_CAP_WRITE_MAP 可以對映寫。
BDI_CAP_EXEC_MAP 可以被對映執行程式碼。

----------- 檔案節點操作集 ------------

const struct inode_operations ramfs_file_inode_operations = {
    .setattr    = simple_setattr,
    .getattr    = simple_getattr,
};

simple_setattr: 一個簡單的屬性設定函式。僅僅針對記憶體檔案系統或者特殊的檔案系統。
  如果需要在檔案大小改變時也對磁碟上的元資料進行修改那麼需要檔案系統提供相關
  的修改方法。
simple_getattr: 獲取檔案的相關屬性資訊,如ino,mode,nlink, uid, gid 等等。

------------- 檔案操作集 ----------------

const struct file_operations ramfs_file_operations = {
    .read       = do_sync_read,
    .aio_read   = generic_file_aio_read,
    .write      = do_sync_write,
    .aio_write  = generic_file_aio_write,
    .mmap       = generic_file_mmap,
    .fsync      = noop_fsync,
    .splice_read    = generic_file_splice_read,
    .splice_write   = generic_file_splice_write,
    .llseek     = generic_file_llseek,
};

全部為VFS層提供的通用的檔案操作方法。

------------ 資料夾節點操作集 -------

static const struct inode_operations ramfs_dir_inode_operations = {
    .create     = ramfs_create,
    .lookup     = simple_lookup,
    .link       = simple_link,
    .unlink     = simple_unlink,
    .symlink    = ramfs_symlink,
    .mkdir      = ramfs_mkdir,
    .rmdir      = simple_rmdir,
    .mknod      = ramfs_mknod,
    .rename     = simple_rename,
};  

static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
        :在目錄@dir下,建立一個普通檔案,並在@dir下建立一個和檔案關聯的目錄項@dentry。

simple_lookup:通用的查詢操作。根據檔案系統物件的名字(字串)查詢對應的inode例項。???
   為目錄項設定d_delete欄位為simple_delete_dentry()。
   並將目錄項新增到目錄項的hash表上,方便快速查詢。
int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
   建立硬連結。建立從@dir下的@dentry目錄項到@old_dentry目錄項管理的inode的硬連結。
simple_unlink: 為ssimple_link()的逆操作。

static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
  在目錄@dir下新建並初始化一個連結inode,連結的路徑名為@symname。

static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
  在目錄@dir下,建立一個目錄項inode並和@dentry相關聯。
simple_rmdir: ramfs_mkdir的逆操作。

ramfs_mknod: 在@dir下分配和初始化一個裝置inode,並和@dentry相關聯。 


------------ simple_dir_operations ----------
const struct file_operations simple_dir_operations = {
    .open       = dcache_dir_open,
    .release    = dcache_dir_close,
    .llseek     = dcache_dir_lseek,
    .read       = generic_read_dir,
    .readdir    = dcache_readdir,
    .fsync      = noop_fsync,
};  

ramfs資料夾操作直接使用了simple_dir_operations。

第二章 最小檔案系統設計小結




********** 小結:最小檔案系統設計

1. 需要的操作

   - 檔案系統註冊
     使用register_filesystem()向核心註冊檔案系統。
   - 檔案系統解除安裝
     使用unregister_filesystem()來解除安裝檔案系統。

2. 需要提供的資料結構

   在使用register_filesystem()向核心註冊檔案系統時,需要提供一個[1] struct file_system_type的例項,
   該例項描述了檔案系統的基本資訊。主要包括@name,檔案系統的名字。@mount檔案系統的掛載相關的操作,
   掛載時需要提供初始化超級塊(super_block)的操作。@kill_sb提供了對超級塊的清理操作。
 
   在初始化檔案系統超級塊時需要指定超級塊相關的操作集合。這需要填充一個[2] struct super_operations結構。
   主要有@statfs,用於給出檔案系統的統計資訊,例如未使用的資料塊的數目、檔名的最大長度等。
   @drop_inode,用於當inode的引用計數降為0時,將inode刪除。
   @show_options,用於顯示檔案系統的裝載選項。

   在分配新的inode時,需要初始化inode的相關操作。這需要初始化一個[3] struct address_space_operations。
   該結構為“地址空間”的操作集。“地址空間”建立了記憶體中資料和其資料來源之間的關聯。當需要更多的物理
   記憶體時,負責向記憶體模組申請記憶體。並提供從後備資料來源讀取資料並填充記憶體緩衝區以及將更新後的資料
   寫回到後備裝置等操作。其中@readpage用於將一頁資料讀取頁框。通常初始化為核心的標準函式mpage_readpage。
   在ramfs中初始化為simple_readpage。@write_begin函式被通用的緩衝區寫函式呼叫,用來告知檔案系統
   準備好向檔案的特定偏移處寫若干個位元組的操作。檔案系統根據需要分配相關的記憶體空間等等。
   在成功地進行了@readpage和資料拷貝後,必須呼叫@write_end。
   @set_page_dirty被VM呼叫,來將一個頁標記為髒。應該設定頁的PageDirty標記和基樹的PAGECACHE_TAG_DIRTY的標記。

   [4] struct backing_dev_info包含了與“地址空間”相關的後備儲存器的有關資訊。後備儲存器是指與地址空間
   相關的外部裝置,用作地址空間中資料的來源,通常為塊裝置。@name是後備儲存裝置的名字。@ra_pages為最大預讀
   的數量,單位為PaGE_CACHE_SIZE。@capabilities中最重要的資訊是資料頁是否可以回寫。比如,BDI_CAP_NO_ACCT_AND_WRITEBACK
   表示不需要回寫、不執行髒頁統計、不自動計算回寫頁統計。

   [5] struct inode_operations 為資料夾節點相關的操作集。主要包括在指定目錄下建立/刪除普通檔案、裝置檔案、目錄檔案、
   連結檔案和查詢以及重新命名等相關操作。
   [6] struct file_operations 資料夾相關的操作集合。

   [7] struct inode_operations 為檔案節點相關的操作集。
   [8] struct file_operations 檔案相關的操作集。


第三章 最小檔案系統例項

*********** 最小檔案系統例項


wendyfs是為了方便讀者快速掌握Linux檔案系統的設計而從ramfs中抽取出來的一個基於RAM的檔案系統。具體實現
參見wendyfs.c。使用方法相見README。
在實現中註釋掉了wendyfs_dir_inode_operations中的.rename操作,這樣wendyfs中就無法使用重新命名操作。比如,
mv fileA fileB。這樣可以研究每一個方法的作用。

//wendyfs.c

/*
   * 本模組程式碼大部分拷貝自fs/ramfs/inode.c和fs/ramfs/file-mmu.c。
   * 主要實現了一個RAM檔案系統的基本功能(除了檔案重新命名 mv fileA fileB)
   * 本模組可以幫助我們學習Linux檔案系統。 
*/


#include <linux/fs.h> /* super_operations */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pagemap.h> /*mapping_set_unevictable() */
#include <linux/time.h> /* CURRENT_TIME */ 
#include <linux/backing-dev.h> 



//should be defined in the heaeder files
#define WENDYFS_MAGIC     0xa5a5a5a5


struct inode *wendyfs_get_inode(struct super_block *sb,
                const struct inode *dir, umode_t mode, dev_t dev);
int myset_page_dirty_no_writeback(struct page *page);


/* Wendyfs's address space operations */
const struct address_space_operations wendyfs_aops = {
		.readpage	= simple_readpage,
		.write_begin	= simple_write_begin,
		.write_end		= simple_write_end,
		.set_page_dirty	= myset_page_dirty_no_writeback,
};

static struct backing_dev_info wendyfs_backing_dev_info = { 
    .name       = "wendyfs",
    .ra_pages   = 0,    /* No readahead */
    .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK |
              BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
              BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
};


/*
 * For address_spaces which do not use buffers nor write back.
 */
int myset_page_dirty_no_writeback(struct page *page)
{
    if (!PageDirty(page))
        return !TestSetPageDirty(page);
    return 0;
}


/* File creation */
static int wendyfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
	int error = -ENOSPC;
	struct inode* inode = wendyfs_get_inode(dir->i_sb, dir, mode, dev);

	if (inode) {
		d_instantiate(dentry, inode);
		dget(dentry);   /* Extra count - pin the dentry in core */
		error = 0;
		dir->i_mtime = dir->i_ctime = CURRENT_TIME;
	}

	return error;
}

static int wendyfs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
{
	int retval = wendyfs_mknod(dir, dentry, mode | S_IFDIR, 0); // DIR inode
  	if (!retval)
			inc_nlink(dir);

	return retval;
}


static int wendyfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
{
    return wendyfs_mknod(dir, dentry, mode | S_IFREG, 0); 
}


static const struct inode_operations wendyfs_dir_inode_operations = {
	.create		= wendyfs_create,
	.lookup		= simple_lookup,
	.mkdir		= wendyfs_mkdir,
	.rmdir		= simple_rmdir,
	.link		= simple_link,
	.unlink		= simple_unlink,
//	.rename		= simple_rename, 
};


const struct inode_operations wendyfs_file_inode_operations = {
	.setattr	= simple_setattr,
	.getattr	= simple_getattr,
};


const struct file_operations wendyfs_file_operations = {
    .read       = do_sync_read,
    .aio_read   = generic_file_aio_read,
    .write      = do_sync_write,
    .aio_write  = generic_file_aio_write,
    .fsync      = noop_fsync,
    .llseek     = generic_file_llseek,
};

struct inode *wendyfs_get_inode(struct super_block *sb,
                const struct inode *dir, umode_t mode, dev_t dev) 
{
	/* Allocate one inode */
    struct inode * inode = new_inode(sb); 

	/* Init the inode */
    if (inode) {
		inode->i_ino = get_next_ino();

		/* Init uid,gid,mode for new inode according to posix standards */
	    inode_init_owner(inode, dir, mode);
		
		/* Set the address space operation set */
		inode->i_mapping->a_ops = &wendyfs_aops;
		
		/* Set the backing device info */
		inode->i_mapping->backing_dev_info = &wendyfs_backing_dev_info;
		
		/* The pages wendyfs covered will be placed on unevictable_list. So
		   these pages will not be reclaimed. */
		mapping_set_unevictable(inode->i_mapping);
		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
		
		/* Set inode and file operation sets */
		switch (mode & S_IFMT) {
		default: 
				init_special_inode(inode, mode, dev);
				break;
		case S_IFDIR:
				/* dir inode operation set */
				inode->i_op = &wendyfs_dir_inode_operations;
				/* dir operation set */
				inode->i_fop = &simple_dir_operations;
				inc_nlink(inode);
				break;
		case S_IFREG:
				/* regular file inode operation set */
				inode->i_op = &wendyfs_file_inode_operations;
				/* regular file operation set */
				inode->i_fop = &wendyfs_file_operations;
				break;
		}
	}

	return inode;
}

/* Super Block related operations */
static const struct super_operations wendyfs_ops = { 
    .statfs     = simple_statfs,
    .drop_inode = generic_delete_inode,
    .show_options   = generic_show_options,
};


int wendyfs_fill_super(struct super_block* sb, void* data, int silent)
{
	struct inode *inode;

	sb->s_maxbytes		= 4096;
	sb->s_blocksize		= 4096;
	sb->s_blocksize_bits	= 12;
	sb->s_magic			= WENDYFS_MAGIC;
	/* Set super block operations */
	sb->s_op			= &wendyfs_ops;
	sb->s_time_gran		= 1;

	/* Create and initialize the root inode */
	inode = wendyfs_get_inode(sb, NULL, S_IFDIR, 0);
	sb->s_root = d_make_root(inode);
	if (!sb->s_root)
			return -ENOMEM;

	return 0;
}



struct dentry* wendyfs_mount(struct file_system_type *fs_type,
				int flags, const char* dev_name, void* data)
{
	return mount_nodev(fs_type, flags, data, wendyfs_fill_super);
}

static void wendyfs_kill_sb(struct super_block* sb)
{
	kill_litter_super(sb);
}

static struct file_system_type	wendy_fs_type = {
		.name		= "wendyfs",
		.mount		= wendyfs_mount,
		.kill_sb	= wendyfs_kill_sb,
};


static int __init init_wendy_fs(void)
{
		return register_filesystem(&wendy_fs_type);
}

static void __exit exit_wendy_fs(void)
{
	unregister_filesystem(&wendy_fs_type);
}


module_init(init_wendy_fs)
module_exit(exit_wendy_fs)

MODULE_AUTHOR("Yang Honggang, <[email protected]>");
MODULE_LICENSE("GPL");

//README

Howto use:
0. Compile wendyfs module
   $make

1. Insert wendyfs module
	#insmod wendyfs.ko
2. Check the filesystem list
    #cat /proc/filesystems
    ...
	nodev	wendyfs
3. Mount the wendyfs 
    #mount -t wendyfs none /mnt
4. Create a dir in the mount point
    #cd /mnt
    #mkdir hello
5. Delete the hello dir
    #rm -rf hello
6. Create a file and rename it
   #echo "hello" > halo
   #cat halo
   #mv halo hello
   mv: cannot move `halo' to `hello': Operation not permitted
   ...


Makefile

obj-m := wendyfs.o
default:
	make -C /lib/modules/`uname -r`/build M=`pwd` modules	
clean:
	rm modules.order Module.symvers *.ko *.mod.* *.o .tmp_versions/ .*cmd -rf


相關推薦

ramfs分析檔案系統設計實現

作者:楊紅剛,蘭州大學 郵箱:[email protected] / [email protected] -------------------------------------------------------------------- REF:

動態規劃分析總結——怎樣設計實現動態規劃算法

基於 進一步 使用 sdn 能夠 疑惑 樓梯 -1 們的 進行算法設計的時候,時常有這種體會:假設已經知道一道題目能夠用動態規劃求解,那麽非常easy找到對應的動態規劃算法並實現;動態規劃算法的難度不在於實現,而在於分析和設計—— 首先你得知道這道題目須要用動態規劃來求

網路程式設計——(connectTCPconnectUDP的實現)2.利用TCP/UDP完成檔案傳輸的設計實現(下)

每個客戶與伺服器建立聯絡必須: 選擇協議(UDP或TCP) 查詢伺服器的機器名 查詢所期望的服務並將其對映到協議埠號 分配套接字並與之連線 將這部分工作進行封裝,置於某個過程當中,只需一次編碼。 我們想要實現以下抽象: socket = connectTCP(mac

[原始碼和文件分享]基於C#SQL SERVER的企業進銷存管理系統設計實現

摘要 進銷存管理是現代企業生產經營中的重要環節,是完成企業資源配置的重要管理工作,對企業生產經營效率的最大化發揮著重要作用。本文以我國中小企業的進銷存管理為研究物件,描述了企業進銷存管理系統從需求分析、系統設計、系統實現到系統測試的全週期。在本次設計確定了進銷存系統的基礎功能需求,深入剖析了企業

[原始碼和文件分享]基於VS2012SQL SERVER的餐廳點餐系統設計實現

一、需求分析 1. 面向物件 點典點菜系統是一款面向顧客和管理人員的全方面系統,其中管理人員又包括服務員、採購員和廚師。本組認真分析了不同物件的需求,為不同的物件都設計了獨特的系統功能。簡化了傳統點菜、燒菜和採購方式繁瑣的步驟,為顧客提供便捷操作的同時提高酒店管理的效率。 2. 市場背景

分散式檔案系統設計,該哪些方面考慮?

一、概述 分散式檔案系統是分散式領域的一個基礎應用,其中最著名的毫無疑問是 HDFS/GFS。如今該領域已經趨向於成熟,但瞭解它的設計要點和思想,對我們將來面臨類似場景 / 問題時,具有借鑑意義。並且,分散式檔案系統並非只有 HDFS/GFS 這一種形態,在它之外,還有其他形態各異、各有

【資料庫篇】——4.使用者登入註冊系統設計分析思路

1.功能需求分析  本系統的功能就兩個:使用者登入和註冊。a.使用者登入需要我們根據使用者的輸入的資訊到資料查詢使用者的賬號密碼是否能夠匹配的上。b.使用者註冊需要我們將使用者的資訊加入到資料庫中。2.架構設計:MVC的模式(模式一)  在這裡我們採用MVC的模式進行開發,這

DIY Android之一--原生Android系統主題支援的設計實現(來自本人cnblogs部落格)

口號:Android只是個Demo。 智慧手機何其多,Symbian、WP、Android...,問題是原生的Android系統不支援主題定製。 於是我等看著花哨的主題資源包在市場上氾濫,前提:你先下載一個執行這些主題資源的應用程式APK包先。 但是...... 原生Android系統是不願意還是不能夠支援

【高效能】Lustre分散式儲存檔案系統介紹故障分析

Lustre是應用廣泛的linux開源分散式儲存檔案系統,其容量可輕易擴容到PB級別,在HPC、雲上有相應的使用。 Lustre由元資料伺服器MDS、資料儲存伺服器OSS組成。MDS伺服器負責管理OSS伺服器上的資料,並處理來自客戶端的資料請求。每個OSS伺服器的本地儲存

Chromium多執行緒模型設計實現分析

       Chromium除了遠近聞名的多程序架構之外,它的多執行緒模型也相當引人注目的。Chromium的多程序架構是為了解決網頁的穩定性問題,而多執行緒模型則是為了解決網頁的卡頓問題。為了達到這個目的,Chromium的多執行緒模型是基於非同步通訊的。也就是說,一個執

資料訪問層的設計實現(分散式系統七)

(1)如何對外提供資料訪問層的功能 資料訪問層就是方便應用進行資料讀寫訪問的抽象層,在該層上解決各個應用通用的訪問資料庫的問題。 上圖顯示了三種方式,第一種是為使用者提供專有API,不過不推薦,通用

利用TCP完成檔案傳輸的設計實現

實驗課的內容,建立tcp 實現檔案的傳輸,需要注意的一個地方就是,客戶端和伺服器端不要放在一起,檔案可以放在客戶端,絕對路徑就可以。還有就是自己寫一個makefile  服務端: 建立socket 使用bind繫結套接字 使用listen監聽 使用accept接受連

設計實現回合制戰鬥系統

Main.cpp #include<iostream> #include<string> #include"MyRandom.h" #include "Master.h" #include "WarSystem.h" #include "Log.h" #include "stdlib

專案實踐: 銀行儲蓄系統設計實現

8.14 銀行儲蓄系統的設計和實現 一、問題描述: 模擬銀行櫃檯業務的要求,實現一個小型的“銀行儲蓄系統”軟體的開發,其中包括開戶、存款、取款、轉帳、改密、掛失、解掛、銷戶等功能。 在開發過程中,請按照問題求解過程的要求,體驗開發過程中需要做的工作。除了下面的系統基

WCF 設計實現服務協定(01)

equal del 時間 center tracking ng- size 實用 數據 作者:jiankunking 出處:http://blog.csdn.net/jiankunkingWCF 術語:? 消息 – 消息是一

分布式爬蟲系統設計實現與實戰:爬取京東、蘇寧易購全網手機商品數據+MySQL、HBase存儲

大數據 分布式 爬蟲 Java Redis [TOC] 1 概述 在不用爬蟲框架的情況,經過多方學習,嘗試實現了一個分布式爬蟲系統,並且可以將數據保存到不同地方,類似MySQL、HBase等。 基於面向接口的編碼思想來開發,因此這個系統具有一定的擴展性,有興趣的朋友直接看一下代碼,就能理

第八次團隊作業——系統設計任務分配

規範 模塊 討論 說明 編碼 sig pow 團隊項目 項目 團隊作業—系統設計和任務分配(換算成總分10) 一、團隊作業說明(一個團隊一份,發布在易知中團隊項目中) 一、建立團隊項目 的碼雲git代碼庫,並列出地址(5分) 二、討論制定團隊的編碼規範,討論之前和討論

團隊作業—系統設計任務分配

碼雲 ani 效果 大致 span IT 學習 blank 更多 團隊作業:http://www.yzhiliao.com/course/62/task/441/show 一、團隊作業碼雲:https://gitee.com/organizations/anynameok/

系統設計任務分配(個人)

日期 mage demo 系統時間 團隊 原生 閱讀 分享圖片 存儲 團隊作業:http://www.yzhiliao.com/course/62/task/441/show 一、碼雲地址 個人:https://gitee.com/Hesse/ 團隊: https://gi

碧瑤答疑網—系統設計任務分配

chat 硬件 英特爾 ace 操作 字母 單詞 代碼規範 e-r圖 一、團隊項目之碼雲Git代碼庫 團隊項目倉庫:https://gitee.com/emmm_m/leyaoproject 二、代碼規範及編碼原則 (1)代碼總體規範原則:通俗易懂,簡潔明了,正確率高,易