分享

RAMFS

 昵称16791680 2014-05-05

RamFS 与 TempFS

Ramfs顾名思义是内存文件系统,它工作于虚拟文件系统(VFS)层。不能格式化,可以创建多个,在创建时可以指定其最大能使用的内存大小。如果你的Linux已经将Ramfs编译进内核,你就可以很容易地使用Ramfs了。创建一个目录,加载Ramfs到该目录即可。
        # mkdir -p /RAM1
        # mount -t ramfs none /RAM1
    缺省情况下,Ramfs被限制最多可使用内存大小的一半。可以通过maxsize
(以kbyte为单位)选项来改变。
        # mkdir -p /RAM1
        # mount -t ramfs none /RAM1 -o maxsize=10000
    以上即创建了一个限定了最大使用内存大小为10M的ramdisk。
   
   
Tmpfs是一个虚拟内存文件系统,它不同于传统的用块设备形式来实现的ramdisk,也不同于针对物理内存的Ramfs。Tmpfs可以使用物理内
存,也可以使用交换分区。在Linux内核中,虚拟内存资源由物理内存(RAM)和交换分区组成,这些资源是由内核中的虚拟内存子系统来负责分配和管理。
Tmpfs就是和虚拟内存子系统来"打交道"的,它向虚拟内存子系统请求页来存储文件,它同Linux的其它请求页的部分一样,不知道分配给自己的页是在
内存中还是在交换分区中。Tmpfs同Ramfs一样,其大小也不是固定的,而是随着所需要的空间而动态的增减。使用tmpfs,首先你编译内核时得选择
"虚拟内存文件系统支持(Virtual memory filesystem support)" ,然后就可以加载tmpfs文件系统了。
        # mkdir -p /mnt/tmpfs
        # mount tmpfs /mnt/tmpfs -t tmpfs
    为了防止tmpfs使用过多的内存资源而造成系统的性能下降或死机,可以在加载时指定tmpfs文件系统大小的最大限制。
        # mount tmpfs /mnt/tmpfs -t tmpfs -o size=32m
    以上创建的tmpfs文件系统就规定了其最大的大小为32M。不管是使用ramfs还是tmpfs,必须明白的是,一旦系统重启,它们中的内容将会丢失。所以那些东西可以放在内存文件系统中得根据系统的具体情况而定。

RAMFS文件系统

RAMFS是一个非常巧妙的,利用VFS自身结构而形成的内存文件系统.
RAMFS没有自已的文件存储结构,它的文件存储于page cache中,
目录结构由dentry链表本身描述,文件则由VFS的inode结构本身描述.
从RAMFS可看出,VFS本质上可看成一种内存文件系统,
它统一了文件在内核中的表示方式并对磁盘文件系统进行缓冲.

代码摘录分析如下:


; fs/ramfs/inode.c
static struct address_space_operations ramfs_aops = { 文件的低级页操作接口
readpage: ramfs_readpage, 读文件页块
writepage: ramfs_writepage, 写文件脏页入块设备
prepare_write: ramfs_prepare_write, 准备从用户写文件页块
commit_write: ramfs_commit_write 从用户写文件页块完成
};
static int ramfs_readpage(struct file *file, struct page * page)
{
; 将文件页块读入page所描述的页面

if (!Page_Uptodate(page)) {
; 当lseek()在文件中造成空洞时,会运行到这里
memset(kmap(page), 0, PAGE_CACHE_SIZE); 页面清零
kunmap(page);
flush_dcache_page(page);
SetPageUptodate(page); 标记为最新
}
现在的问题是什么情况下系统调用该函数并且Page_Uptodate(page)为TRUE.
UnlockPage(page);
return 0;
}
static int ramfs_writepage(struct page *page)
{
; 将page cache中脏页写入块设备.
;对于RAMFS,这里将它重新标记为DIRTY,防止它们被系统丢弃
SetPageDirty(page);
UnlockPage(page);
return 0;
}
static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset,
unsigned to)
{
; 系统将用户数据拷贝到page之前调用此函数,
;offset是文件指针在页内的起始位置,to是在页内的终止位置
;表示系统将要在page从offset到to的位置上拷贝用户数据.

void *addr = kmap(page); 取页面描述结构(page)所描述页面的地址
if (!Page_Uptodate(page)) {
; 对于RAMFS,当lseek()在文件中产生空洞时,运行到这里.
memset(addr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
SetPageUptodate(page);
}
SetPageDirty(page);
return 0;
}

static int ramfs_commit_write(struct file *file, struct page *page, unsigned offset,
unsigned to)
{
; 系统将用户数据拷贝到page之后调用此函数

struct inode *inode = page->mapping->host; //
取page所代表的文件,mapping结构是inode的一部分,
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
// page->index表示该page在文件中的页块号,to是该页的终止偏移量
kunmap(page);
if (pos > inode->i_size) // inode->i_size为文件的尺寸
inode->i_size = pos; 如果文件的写入的终止位置大于文件原来的尺寸,则更新i_size的值
return 0;
}

static struct file_operations ramfs_file_operations = {
read: generic_file_read, 数据文件的通用高级读函数
write: generic_file_write, 数据文件的通用高级写函数
mmap: generic_file_mmap,数据文件的通用高级内存映射函数
fsync: ramfs_sync_file,
};
static int ramfs_sync_file(struct file * file, struct dentry *dentry, int datasync)
{
return 0;
}
static struct file_operations ramfs_dir_operations = {
read: generic_read_dir, 返回-EISDIR错误的函数
readdir: dcache_readdir, 目录文件的高级读目录函数
fsync: ramfs_sync_file,
};
static struct inode_operations ramfs_dir_inode_operations = {
create: ramfs_create,
lookup: ramfs_lookup,
link: ramfs_link,
unlink: ramfs_unlink,
symlink: ramfs_symlink,
mkdir: ramfs_mkdir,
rmdir: ramfs_rmdir,
mknod: ramfs_mknod,
rename: ramfs_rename,
};
static int ramfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
; 在目录dir内创建一个以dentry为目录项的普通文件
return ramfs_mknod(dir, dentry, mode | S_IFREG, 0);
}
static struct dentry * ramfs_lookup(struct inode *dir, struct dentry *dentry)
{
;
对于ramfs,所有的目录项都已经在dentry链表中,只有企图寻找VFS中不存在的项时,才会运行到这?br>?br> d_add(dentry, NULL);
; 将dentry加入目录链表,置空的inode,表示No such file or
directories,就是说生成一个"虚"的目录项,
;之所以这样,为了加速create过程
return NULL;
}
static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry *
dentry)
{
struct inode *inode = old_dentry->d_inode;

; 在目录dir内创建一个以dentry所表示目录项的链接,指向old_entry目录项所表示的文件

if (S_ISDIR(inode->i_mode))
return -EPERM;

inode->i_nlink++; 文件的连接数,为0表示文件已删除
atomic_inc(&inode->i_count); /* New dentry reference */
dget(dentry); /* Extra pinning count for the created dentry */
d_instantiate(dentry, inode); 使目录项dentry指向文件inode
return 0;
}
static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
{
int retval = -ENOTEMPTY;

; 在目录dir内删除dentry所表示的目录项

if (ramfs_empty(dentry)) { 只能删除空目录
struct inode *inode = dentry->d_inode;

inode->i_nlink--;
dput(dentry); /* Undo the count from "create" - this does all the work */
retval = 0;
}
return retval;
}
static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char *
symname)
{
int error;
; 在目录dir中创建名称为symname的符号链接文件目录项
; 符号链接的名称作为符号链接文件的数据体存放在page cache中

error = ramfs_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);
if (!error) {
int l = strlen(symname)+1;
struct inode *inode = dentry->d_inode;
error = block_symlink(inode, symname, l);
}
return error;
}
static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
; 在目录dir内创建一个以dentry为目录项的目录
return ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
}
static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct
inode * new_dir,struct dentry *new_dentry)
{
int error = -ENOTEMPTY;
; 将目录old_dir内的目录项改名为new_dir目录中的new_dentry所描述的目录项

if (ramfs_empty(new_dentry)) {
struct inode *inode = new_dentry->d_inode;
if (inode) {
inode->i_nlink--;
dput(new_dentry);
}
error = 0;
}
return error;
}
; 在VFS中创建一个节点,用来描述文件,目录或符号链接
static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
{
struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev);
int error = -ENOSPC;
if (inode) {
d_instantiate(dentry, inode); 将目录项dentry与文件描述inode相关联
dget(dentry); /* Extra count - pin the dentry in core */
error = 0;
}
return error;
}

static struct super_operations ramfs_ops = {
statfs: ramfs_statfs,
put_inode: force_delete,
};
static int ramfs_statfs(struct super_block *sb, struct statfs *buf)
{
; 取文件系统结构参数
buf->f_type = RAMFS_MAGIC;
buf->f_bsize = PAGE_CACHE_SIZE;
buf->f_namelen = 255;
return 0;
}

; 获取一个属于ramfs的自由的inode.
struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
{
struct inode * inode = new_inode(sb);

if (inode) {
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_rdev = to_kdev_t(dev);
inode->i_mapping->a_ops = &ramfs_aops;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev); 与设备文件相联的inode函数
break;
case S_IFREG: 普通文件的inode函数
inode->i_fop = &ramfs_file_operations;
break;
case S_IFDIR: 目录文件的inode函数
inode->i_op = &ramfs_dir_inode_operations;
inode->i_fop = &ramfs_dir_operations;
break;
case S_IFLNK: 符号链接的inode函数
inode->i_op = &page_symlink_inode_operations;
break;
}
}
return inode;
}
static int ramfs_empty(struct dentry *dentry) 判断目录是否为空
{
struct list_head *list;

spin_lock(&dcache_lock);
list = dentry->d_subdirs.next; 取子目录链

while (list != &dentry->d_subdirs) {
struct dentry *de = list_entry(list, struct dentry, d_child);

if (ramfs_positive(de)) {
spin_unlock(&dcache_lock);
return 0; 如果dentry目录中存在一个实在的子目录项,则说明该目录非空.
}
list = list->next;
}
spin_unlock(&dcache_lock);
return 1;
}
static inline int ramfs_positive(struct dentry *dentry)
{
; 判断dentry是否实在,即dentry指向某个文件并且被dentry的散列表索引
return dentry->d_inode && !d_unhashed(dentry);
}
; fs/devices.c
void init_special_inode(struct inode *inode, umode_t mode, int rdev)
{
inode->i_mode = mode;
if (S_ISCHR(mode)) { 如果为字符设备文件,提供字符设备的inode函数
inode->i_fop = &def_chr_fops;
inode->i_rdev = to_kdev_t(rdev);
} else if (S_ISBLK(mode)) { 如果为块设备文件,提供块设备的inode函数
inode->i_fop = &def_blk_fops;
inode->i_rdev = to_kdev_t(rdev);
inode->i_bdev = bdget(rdev); 指向块设备描述结构
} else if (S_ISFIFO(mode)) 如果为FIFO文件,提供FIFO的inode函数
inode->i_fop = &def_fifo_fops;
else if (S_ISSOCK(mode)) 如果为SOCK文件,提供SOCK的inode函数
inode->i_fop = &bad_sock_fops;
else
printk(KERN_DEBUG "init_special_inode: bogus imode (%o) ", mode);
}
; fs/buffer.c
int block_symlink(struct inode *inode, const char *symname, int len)
{
struct address_space *mapping = inode->i_mapping;
struct page *page = grab_cache_page(mapping, 0);
int err = -ENOMEM;
char *kaddr;
; 符号链接中的符号名存放在page cache中.

if (!page)
goto fail;
err = mapping->a_ops->prepare_write(NULL, page, 0, len-1);
if (err)
goto fail_map;
kaddr = page_address(page);
memcpy(kaddr, symname, len-1);
mapping->a_ops->commit_write(NULL, page, 0, len-1);
/*
* Notice that we are _not_ going to block here - end of page is
* unmapped, so this will only try to map the rest of page, see
* that it is unmapped (typically even will not look into inode -
* ->i_size will be enough for everything) and zero it out.
* OTOH it's obviously correct and should make the page up-to-date.
*/
err = mapping->a_ops->readpage(NULL, page);
wait_on_page(page);
page_cache_release(page); 释放grab状态
if (err < 0)
goto fail;
mark_inode_dirty(inode);
return 0;
fail_map:
UnlockPage(page);
page_cache_release(page);
fail:
return err;
}
实际例子:
在XOS NPM6上,
/ # mount -t ramfs none /tmp
/ # cd /tmp/
/tmp # ls
/tmp # dd if=/dev/zero of=a bs=1M count=230
分配了230MB的内存,不过都存在cached上了,cached会增大230MB,内存减小230MB。
/ # rm -f /tmp/a
/ # umount /tmp
这里/dev/zero 是当你读它时,产生 0x00 输出的设备。
dd if=/dev/zero of=initrd.img bs=512 count=8192 产生出来一个4兆文件,内容全都是零。
bs = 单元大小
count = 单元的数量
eg : dd if=/dev/hda of=/boot.bin bs=512 count=1
就是拷贝hda的前512个字节(一般都是主引导纪录)

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多