無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

擬似ファイルシステムを作ってみる(1)


仮想ファイルシステムサンプル

ネタ元のファイルシステムに読み込み、書き込みの処理を追加しました。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <asm/uaccess.h> /* for copy_to_user */

// ファイル名
static char *dir_entries[] = { "a", "b", "c", "d", "e", };
// ファイルの中身
static char dir_msg[5][20];
 
static struct inode *my_vfs_get_inode(struct super_block *sb, unsigned int ino);
static unsigned long my_vfs_internal_lookup(const char *name, size_t name_sz)
{
	int i;
	for (i = 0; i < sizeof(dir_entries) / sizeof(*dir_entries); i++) {
		if (0 == strncmp(dir_entries[i], name, name_sz))
			return i + 100;
	}
	return 0;
}

static int my_vfs_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
{
	unsigned int i = file->f_pos;
	while (i < 2 + sizeof(dir_entries) / sizeof(*dir_entries)) {
		if (i == 0) {
			/* "." の処理 */
			if (filldir(dirent, ".", sizeof(".") - 1, i, 1, DT_DIR))
				break;
		} else if (i == 1) {
			/* ".." の処理 */
			if (filldir(dirent, "..", sizeof("..") - 1, i,
					parent_ino(file->f_path.dentry), DT_DIR))
				break;
		} else {
			/* それ以外 */
			if (filldir(dirent, dir_entries[i - 2], strlen(dir_entries[i - 2]),
					i, (unsigned long)dir_entries[i - 2], DT_REG))
				break;
		}
		++i;
	}
	file->f_pos = i;
	return 0;
}

// 本関数が無いとumountでセグメントエラー
static int my_vfs_dir_dentry_delete(struct dentry *dentry)
{
	return 1;
}
static struct dentry_operations my_vfs_dir_dentry_operations = {
	.d_delete = my_vfs_dir_dentry_delete
};

static struct dentry *my_vfs_dir_lookup(struct inode *inode, struct dentry *entry, struct nameidata *nd)
{
	(void)nd; /* unused */
	if (entry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);
	{
		unsigned long file_inode_n;
		struct inode *file_inode;
		file_inode_n = my_vfs_internal_lookup(entry->d_name.name,
					entry->d_name.len);
		if (!file_inode_n)
			return ERR_PTR(-ENOENT);
		file_inode = my_vfs_get_inode(inode->i_sb, file_inode_n);
		if (!file_inode)
			return ERR_PTR(-EINVAL);
		entry->d_op = &my_vfs_dir_dentry_operations;
		d_add(entry, file_inode);
	}
	return NULL;
}

static const struct file_operations my_vfs_dir_ops = {
	.readdir = my_vfs_dir_readdir,
};
static const struct inode_operations my_vfs_dir_inode_ops = {
	.lookup	 = my_vfs_dir_lookup,
};

// 通常countはページサイズ? 4096
static ssize_t my_vfs_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	ssize_t nbytes;
	int msglen;
	int i;

	for (i = 0; i < 5; i++) {
		if (!strcmp(file->f_path.dentry->d_name.name, dir_entries[i])) {
			msglen = strlen(dir_msg[i]);
			if (*ppos >= msglen)
				return 0;
			nbytes = ((loff_t)(msglen) < *ppos + count ? msglen: 
			*ppos + count) - *ppos;
			if (copy_to_user(buf, dir_msg[i] + *ppos, nbytes))
				return -EFAULT;
				*ppos += nbytes;
			break;	
		}
	}
	return nbytes;
}

static ssize_t my_vfs_file_write(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	ssize_t nbytes = 0;
	int msglen;
	int i;

	for (i = 0; i < 5; i++) {
		if (!strcmp(file->f_path.dentry->d_name.name, dir_entries[i])) {
			if (copy_from_user(dir_msg[i], buf, count))
				return -EFAULT;
			dir_msg[i][count] = 0;
				*ppos += count;
			break;	
		}
	}
	return count;
}


// これが無いとviで書き込みできなかった。
static int my_vfs_file_fsync(struct file *file, struct dentry *dentry, int datasync)
{
	return 0;
}

static const struct file_operations my_vfs_file_ops = {
	.read	 = my_vfs_file_read,
	.write	 = my_vfs_file_write,
	.fsync	 = my_vfs_file_fsync
};

static const struct inode_operations my_vfs_file_inode_ops = {
};

static struct inode *my_vfs_get_root(struct super_block *sb)
{
	return my_vfs_get_inode(sb, 1);
}

static const struct super_operations my_vfs_ops = {
	.statfs		 = simple_statfs,
};
static int my_vfs_fill_super(struct super_block *sb, void *data, int silent)
{
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_blocksize = PAGE_CACHE_SIZE;
	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
	sb->s_magic = 0x484f4745; /* 'HOGE' */
	sb->s_op = &my_vfs_ops;
//	sb->s_flags |= MS_RDONLY;
	{
		struct inode *inode = my_vfs_get_root(sb);
		struct dentry *root = 0;
		if (!inode)
			return -ENOMEM;
		root = d_alloc_root(inode);
		if (!root) {
			iput(inode);
			return -ENOMEM;
		}
		sb->s_root = root;
	}
	return 0;
}

static struct inode *my_vfs_get_inode(struct super_block *sb, unsigned int ino)
{
	struct inode *retval;
	retval = iget_locked(sb, ino);
	if (!retval)
		return 0;
	retval->i_uid = 0;
	retval->i_gid = 0;
	retval->i_mode = 0666;
	if (ino == 1) {
		retval->i_fop = &my_vfs_dir_ops;
		retval->i_op = &my_vfs_dir_inode_ops;
		retval->i_mode |= 0111 | S_IFDIR;
	} else {
		retval->i_fop = &my_vfs_file_ops;
		retval->i_op = &my_vfs_file_inode_ops;
		retval->i_mode |= S_IFREG;
		retval->i_size = 10;	// ファイルサイズは適当 ls -l で10で表示される
	}
	unlock_new_inode(retval);
	return retval;
}

static int my_vfs_get_sb(struct file_system_type *self,
		int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
	return get_sb_nodev(self, flags, data, my_vfs_fill_super, mnt);
}

static struct file_system_type my_vfs_type = {
	.name		= "my_vfs",
	.get_sb		= my_vfs_get_sb,
	.kill_sb	= kill_litter_super,
	.owner		= THIS_MODULE
};

static int __init my_vfs_module_init(void)
{
// 初期ファイルデータ a->1000,b->1001,c->10002....
	int i;
	for (i = 0; i < 5; i++) {	
		sprintf(dir_msg[i], "%d", i + 1000);
	}
	register_filesystem(&my_vfs_type);
	return 0;
}
 
static void __exit my_vfs_module_exit(void)
{
	unregister_filesystem(&my_vfs_type);
}
module_init(my_vfs_module_init)
module_exit(my_vfs_module_exit)


最終更新 2010/01/09 23:55:17 - north
(2010/01/09 23:48:12 作成)