?? ramdisk.c
字號:
/* passed* linux/kernel/blk_drv/ramdisk.c** Written by Theodore Ts'o, 12/2/91*/
#include <set_seg.h>
/* 由Theodore Ts'o 編制,12/2/91*/// Theodore Ts'o (Ted Ts'o)是linux 社區中的著名人物。Linux 在世界范圍內的流行也有他很大的// 功勞,早在Linux 操作系統剛問世時,他就懷著極大的熱情為linux 的發展提供了maillist,并// 在北美洲地區最早設立了linux 的ftp 站點(tsx-11.mit.edu),而且至今仍然為廣大linux 用戶// 提供服務。他對linux 作出的最大貢獻之一是提出并實現了ext2 文件系統。該文件系統已成為// linux 世界中事實上的文件系統標準。最近他又推出了ext3 文件系統,大大提高了文件系統的// 穩定性和訪問效率。作為對他的推崇,第97 期(2002 年5 月)的linuxjournal 期刊將他作為// 了封面人物,并對他進行了采訪。目前,他為IBM linux 技術中心工作,并從事著有關LSB// (Linux Standard Base)等方面的工作。(他的主頁:http://thunk.org/tytso/)#include <string.h> // 字符串頭文件。主要定義了一些有關字符串操作的嵌入函數。#include <linux/config.h> // 內核配置頭文件。定義鍵盤語言和硬盤類型(HD_TYPE)可選項。#include <linux/sched.h> // 調度程序頭文件,定義了任務結構task_struct、初始任務0 的數據,// 還有一些有關描述符參數設置和獲取的嵌入式匯編函數宏語句。#include <linux/fs.h> // 文件系統頭文件。定義文件表結構(file,buffer_head,m_inode 等)。#include <linux/kernel.h> // 內核頭文件。含有一些內核常用函數的原形定義。#include <asm/system.h> // 系統頭文件。定義了設置或修改描述符/中斷門等的嵌入式匯編宏。#include <asm/segment.h> // 段操作頭文件。定義了有關段寄存器操作的嵌入式匯編函數。#include <asm/memory.h> // 內存拷貝頭文件。含有memcpy()嵌入式匯編宏函數。#define MAJOR_NR 1 // 內存主設備號是1。#include "blk.h"char *rd_start = 0; // 虛擬盤在內存中的起始位置。在52 行初始化函數rd_init()中// 確定。參見(init/main.c,124)(縮寫rd_代表ramdisk_)。int rd_length = 0; // 虛擬盤所占內存大?。ㄗ止潱?。// 執行虛擬盤(ramdisk)讀寫操作。程序結構與do_hd_request()類似(kernel/blk_drv/hd.c,294)。voiddo_rd_request (void){ int len; char *addr; INIT_REQUEST; // 檢測請求的合法性(參見kernel/blk_drv/blk.h,127)。// 下面語句取得ramdisk 的起始扇區對應的內存起始位置和內存長度。// 其中sector << 9 表示sector * 512,CURRENT 定義為(blk_dev[MAJOR_NR].current_request)。 addr = rd_start + (CURRENT->sector << 9); len = CURRENT->nr_sectors << 9;// 如果子設備號不為1 或者對應內存起始位置>虛擬盤末尾,則結束該請求,并跳轉到repeat 處// (定義在28 行的INIT_REQUEST 內開始處)。 if ((MINOR (CURRENT->dev) != 1) || (addr + len > rd_start + rd_length)) { end_request (0); goto repeat; }// 如果是寫命令(WRITE),則將請求項中緩沖區的內容復制到addr 處,長度為len 字節。 if (CURRENT->cmd == WRITE) { (void) memcpy (addr, CURRENT->buffer, len);// 如果是讀命令(READ),則將addr 開始的內容復制到請求項中緩沖區中,長度為len 字節。 } else if (CURRENT->cmd == READ) { (void) memcpy (CURRENT->buffer, addr, len);// 否則顯示命令不存在,死機。 } else panic ("unknown ramdisk-command");// 請求項成功后處理,置更新標志。并繼續處理本設備的下一請求項。 end_request (1); goto repeat;}/* 返回內存虛擬盤ramdisk 所需的內存量 */// 虛擬盤初始化函數。確定虛擬盤在內存中的起始地址,長度。并對整個虛擬盤區清零。longrd_init (long mem_start, int length){ int i; char *cp; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; // do_rd_request()。 rd_start = (char *) mem_start; rd_length = length; cp = rd_start; for (i = 0; i < length; i++) *cp++ = '\0'; return (length);}/** 如果根文件系統設備(root device)是ramdisk 的話,則嘗試加載它。root device 原先是指向* 軟盤的,我們將它改成指向ramdisk。*///// 加載根文件系統到ramdisk。voidrd_load (void){ struct buffer_head *bh; struct super_block s; int block = 256; /* Start at block 256 */ int i = 1; int nblocks; char *cp; /* Move pointer */ if (!rd_length) // 如果ramdisk 的長度為零,則退出。 return; printk ("Ram disk: %d bytes, starting at 0x%x\n", rd_length, (int) rd_start); // 顯示ramdisk 的大小以及內存起始位置。 if (MAJOR (ROOT_DEV) != 2) // 如果此時根文件設備不是軟盤,則退出。 return;// 讀軟盤塊256+1,256,256+2。breada()用于讀取指定的數據塊,并標出還需要讀的塊,然后返回// 含有數據塊的緩沖區指針。如果返回NULL,則表示數據塊不可讀(fs/buffer.c,322)。// 這里block+1 是指磁盤上的超級塊。 bh = breada (ROOT_DEV, block + 1, block, block + 2, -1); if (!bh) { printk ("Disk error while looking for ramdisk!\n"); return; }// 將s 指向緩沖區中的磁盤超級塊。(d_super_block 磁盤中超級塊結構)。 *((struct d_super_block *) &s) = *((struct d_super_block *) bh->b_data); brelse (bh); // [?? 為什么數據沒有復制就立刻釋放呢?] if (s.s_magic != SUPER_MAGIC) // 如果超級塊中魔數不對,則說明不是minix 文件系統。 return;/* 磁盤中沒有ramdisk 映像文件,退出執行通常的軟盤引導 */// 塊數 = 邏輯塊數(區段數) * 2^(每區段塊數的次方)。// 如果數據塊數大于內存中虛擬盤所能容納的塊數,則不能加載,顯示出錯信息并返回。否則顯示// 加載數據塊信息。 nblocks = s.s_nzones << s.s_log_zone_size; if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { printk ("Ram disk image too big! (%d blocks, %d avail)\n", nblocks, rd_length >> BLOCK_SIZE_BITS); return; } printk ("Loading %d bytes into ram disk... 0000k", nblocks << BLOCK_SIZE_BITS);// cp 指向虛擬盤起始處,然后將磁盤上的根文件系統映象文件復制到虛擬盤上。 cp = rd_start; while (nblocks) { if (nblocks > 2) // 如果需讀取的塊數多于3 快則采用超前預讀方式讀數據塊。 bh = breada (ROOT_DEV, block, block + 1, block + 2, -1); else // 否則就單塊讀取。 bh = bread (ROOT_DEV, block); if (!bh) { printk ("I/O error on block %d, aborting load\n", block); return; } (void) memcpy (cp, bh->b_data, BLOCK_SIZE); // 將緩沖區中的數據復制到cp 處。 brelse (bh); // 釋放緩沖區。 printk ("\010\010\010\010\010%4dk", i); // 打印加載塊計數值。 cp += BLOCK_SIZE; // 虛擬盤指針前移。 block++; nblocks--; i++; } printk ("\010\010\010\010\010done \n"); ROOT_DEV = 0x0101; // 修改ROOT_DEV 使其指向虛擬盤ramdisk。}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -