⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linuxvfs.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * linux/fs/befs/linuxvfs.c * * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com * */#include <linux/module.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/stat.h>#include <linux/nls.h>#include <linux/buffer_head.h>#include <linux/vfs.h>#include <linux/parser.h>#include <linux/namei.h>#include "befs.h"#include "btree.h"#include "inode.h"#include "datastream.h"#include "super.h"#include "io.h"MODULE_DESCRIPTION("BeOS File System (BeFS) driver");MODULE_AUTHOR("Will Dyson");MODULE_LICENSE("GPL");/* The units the vfs expects inode->i_blocks to be in */#define VFS_BLOCK_SIZE 512static int befs_readdir(struct file *, void *, filldir_t);static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);static int befs_readpage(struct file *file, struct page *page);static sector_t befs_bmap(struct address_space *mapping, sector_t block);static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);static void befs_read_inode(struct inode *ino);static struct inode *befs_alloc_inode(struct super_block *sb);static void befs_destroy_inode(struct inode *inode);static int befs_init_inodecache(void);static void befs_destroy_inodecache(void);static void *befs_follow_link(struct dentry *, struct nameidata *);static void befs_put_link(struct dentry *, struct nameidata *, void *);static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,			char **out, int *out_len);static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,			char **out, int *out_len);static void befs_put_super(struct super_block *);static int befs_remount(struct super_block *, int *, char *);static int befs_statfs(struct dentry *, struct kstatfs *);static int parse_options(char *, befs_mount_options *);static const struct super_operations befs_sops = {	.read_inode	= befs_read_inode,	/* initialize & read inode */	.alloc_inode	= befs_alloc_inode,	/* allocate a new inode */	.destroy_inode	= befs_destroy_inode, /* deallocate an inode */	.put_super	= befs_put_super,	/* uninit super */	.statfs		= befs_statfs,	/* statfs */	.remount_fs	= befs_remount,};/* slab cache for befs_inode_info objects */static struct kmem_cache *befs_inode_cachep;static const struct file_operations befs_dir_operations = {	.read		= generic_read_dir,	.readdir	= befs_readdir,};static const struct inode_operations befs_dir_inode_operations = {	.lookup		= befs_lookup,};static const struct address_space_operations befs_aops = {	.readpage	= befs_readpage,	.sync_page	= block_sync_page,	.bmap		= befs_bmap,};static const struct inode_operations befs_symlink_inode_operations = {	.readlink	= generic_readlink,	.follow_link	= befs_follow_link,	.put_link	= befs_put_link,};/*  * Called by generic_file_read() to read a page of data *  * In turn, simply calls a generic block read function and * passes it the address of befs_get_block, for mapping file * positions to disk blocks. */static intbefs_readpage(struct file *file, struct page *page){	return block_read_full_page(page, befs_get_block);}static sector_tbefs_bmap(struct address_space *mapping, sector_t block){	return generic_block_bmap(mapping, block, befs_get_block);}/*  * Generic function to map a file position (block) to a  * disk offset (passed back in bh_result). * * Used by many higher level functions. * * Calls befs_fblock2brun() in datastream.c to do the real work. * * -WD 10-26-01 */static intbefs_get_block(struct inode *inode, sector_t block,	       struct buffer_head *bh_result, int create){	struct super_block *sb = inode->i_sb;	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;	befs_block_run run = BAD_IADDR;	int res = 0;	ulong disk_off;	befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld",		   inode->i_ino, block);	if (block < 0) {		befs_error(sb, "befs_get_block() was asked for a block "			   "number less than zero: block %ld in inode %lu",			   block, inode->i_ino);		return -EIO;	}	if (create) {		befs_error(sb, "befs_get_block() was asked to write to "			   "block %ld in inode %lu", block, inode->i_ino);		return -EPERM;	}	res = befs_fblock2brun(sb, ds, block, &run);	if (res != BEFS_OK) {		befs_error(sb,			   "<--- befs_get_block() for inode %lu, block "			   "%ld ERROR", inode->i_ino, block);		return -EFBIG;	}	disk_off = (ulong) iaddr2blockno(sb, &run);	map_bh(bh_result, inode->i_sb, disk_off);	befs_debug(sb, "<--- befs_get_block() for inode %lu, block %ld, "		   "disk address %lu", inode->i_ino, block, disk_off);	return 0;}static struct dentry *befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){	struct inode *inode = NULL;	struct super_block *sb = dir->i_sb;	befs_data_stream *ds = &BEFS_I(dir)->i_data.ds;	befs_off_t offset;	int ret;	int utfnamelen;	char *utfname;	const char *name = dentry->d_name.name;	befs_debug(sb, "---> befs_lookup() "		   "name %s inode %ld", dentry->d_name.name, dir->i_ino);	/* Convert to UTF-8 */	if (BEFS_SB(sb)->nls) {		ret =		    befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen);		if (ret < 0) {			befs_debug(sb, "<--- befs_lookup() ERROR");			return ERR_PTR(ret);		}		ret = befs_btree_find(sb, ds, utfname, &offset);		kfree(utfname);	} else {		ret = befs_btree_find(sb, ds, dentry->d_name.name, &offset);	}	if (ret == BEFS_BT_NOT_FOUND) {		befs_debug(sb, "<--- befs_lookup() %s not found",			   dentry->d_name.name);		return ERR_PTR(-ENOENT);	} else if (ret != BEFS_OK || offset == 0) {		befs_warning(sb, "<--- befs_lookup() Error");		return ERR_PTR(-ENODATA);	}	inode = iget(dir->i_sb, (ino_t) offset);	if (!inode)		return ERR_PTR(-EACCES);	d_add(dentry, inode);	befs_debug(sb, "<--- befs_lookup()");	return NULL;}static intbefs_readdir(struct file *filp, void *dirent, filldir_t filldir){	struct inode *inode = filp->f_path.dentry->d_inode;	struct super_block *sb = inode->i_sb;	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;	befs_off_t value;	int result;	size_t keysize;	unsigned char d_type;	char keybuf[BEFS_NAME_LEN + 1];	char *nlsname;	int nlsnamelen;	const char *dirname = filp->f_path.dentry->d_name.name;	befs_debug(sb, "---> befs_readdir() "		   "name %s, inode %ld, filp->f_pos %Ld",		   dirname, inode->i_ino, filp->f_pos);	result = befs_btree_read(sb, ds, filp->f_pos, BEFS_NAME_LEN + 1,				 keybuf, &keysize, &value);	if (result == BEFS_ERR) {		befs_debug(sb, "<--- befs_readdir() ERROR");		befs_error(sb, "IO error reading %s (inode %lu)",			   dirname, inode->i_ino);		return -EIO;	} else if (result == BEFS_BT_END) {		befs_debug(sb, "<--- befs_readdir() END");		return 0;	} else if (result == BEFS_BT_EMPTY) {		befs_debug(sb, "<--- befs_readdir() Empty directory");		return 0;	}	d_type = DT_UNKNOWN;	/* Convert to NLS */	if (BEFS_SB(sb)->nls) {		result =		    befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);		if (result < 0) {			befs_debug(sb, "<--- befs_readdir() ERROR");			return result;		}		result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos,				 (ino_t) value, d_type);		kfree(nlsname);	} else {		result = filldir(dirent, keybuf, keysize, filp->f_pos,				 (ino_t) value, d_type);	}	filp->f_pos++;	befs_debug(sb, "<--- befs_readdir() filp->f_pos %Ld", filp->f_pos);	return 0;}static struct inode *befs_alloc_inode(struct super_block *sb){        struct befs_inode_info *bi;        bi = (struct befs_inode_info *)kmem_cache_alloc(befs_inode_cachep,							GFP_KERNEL);        if (!bi)                return NULL;        return &bi->vfs_inode;}static voidbefs_destroy_inode(struct inode *inode){        kmem_cache_free(befs_inode_cachep, BEFS_I(inode));}static void init_once(struct kmem_cache *cachep, void *foo){        struct befs_inode_info *bi = (struct befs_inode_info *) foo;	inode_init_once(&bi->vfs_inode);}static voidbefs_read_inode(struct inode *inode){	struct buffer_head *bh = NULL;	befs_inode *raw_inode = NULL;	struct super_block *sb = inode->i_sb;	befs_sb_info *befs_sb = BEFS_SB(sb);	befs_inode_info *befs_ino = NULL;	befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino);	befs_ino = BEFS_I(inode);	/* convert from vfs's inode number to befs's inode number */	befs_ino->i_inode_num = blockno2iaddr(sb, inode->i_ino);	befs_debug(sb, "  real inode number [%u, %hu, %hu]",		   befs_ino->i_inode_num.allocation_group,		   befs_ino->i_inode_num.start, befs_ino->i_inode_num.len);	bh = befs_bread(sb, inode->i_ino);	if (!bh) {		befs_error(sb, "unable to read inode block - "			   "inode = %lu", inode->i_ino);		goto unacquire_none;	}	raw_inode = (befs_inode *) bh->b_data;	befs_dump_inode(sb, raw_inode);	if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) {		befs_error(sb, "Bad inode: %lu", inode->i_ino);		goto unacquire_bh;	}	inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode);	/*	 * set uid and gid.  But since current BeOS is single user OS, so	 * you can change by "uid" or "gid" options.	 */   	inode->i_uid = befs_sb->mount_opts.use_uid ?	    befs_sb->mount_opts.uid : (uid_t) fs32_to_cpu(sb, raw_inode->uid);	inode->i_gid = befs_sb->mount_opts.use_gid ?	    befs_sb->mount_opts.gid : (gid_t) fs32_to_cpu(sb, raw_inode->gid);	inode->i_nlink = 1;	/*	 * BEFS's time is 64 bits, but current VFS is 32 bits...	 * BEFS don't have access time. Nor inode change time. VFS	 * doesn't have creation time.	 * Also, the lower 16 bits of the last_modified_time and 	 * create_time are just a counter to help ensure uniqueness	 * for indexing purposes. (PFD, page 54)	 */	inode->i_mtime.tv_sec =	    fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16;	inode->i_mtime.tv_nsec = 0;   /* lower 16 bits are not a time */		inode->i_ctime = inode->i_mtime;	inode->i_atime = inode->i_mtime;	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);	befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent);	befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes);	befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags);	if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){		inode->i_size = 0;		inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;		strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,			BEFS_SYMLINK_LEN);	} else {		int num_blks;		befs_ino->i_data.ds =		    fsds_to_cpu(sb, raw_inode->data.datastream);		num_blks = befs_count_blocks(sb, &befs_ino->i_data.ds);		inode->i_blocks =		    num_blks * (befs_sb->block_size / VFS_BLOCK_SIZE);		inode->i_size = befs_ino->i_data.ds.size;	}	inode->i_mapping->a_ops = &befs_aops;	if (S_ISREG(inode->i_mode)) {		inode->i_fop = &generic_ro_fops;	} else if (S_ISDIR(inode->i_mode)) {		inode->i_op = &befs_dir_inode_operations;		inode->i_fop = &befs_dir_operations;	} else if (S_ISLNK(inode->i_mode)) {		inode->i_op = &befs_symlink_inode_operations;	} else {		befs_error(sb, "Inode %lu is not a regular file, "			   "directory or symlink. THAT IS WRONG! BeFS has no "			   "on disk special files", inode->i_ino);		goto unacquire_bh;	}	brelse(bh);	befs_debug(sb, "<--- befs_read_inode()");	return;      unacquire_bh:	brelse(bh);      unacquire_none:	make_bad_inode(inode);	befs_debug(sb, "<--- befs_read_inode() - Bad inode");	return;}/* Initialize the inode cache. Called at fs setup. * * Taken from NFS implementation by Al Viro. */static intbefs_init_inodecache(void){	befs_inode_cachep = kmem_cache_create("befs_inode_cache",					      sizeof (struct befs_inode_info),					      0, (SLAB_RECLAIM_ACCOUNT|						SLAB_MEM_SPREAD),					      init_once);	if (befs_inode_cachep == NULL) {		printk(KERN_ERR "befs_init_inodecache: "		       "Couldn't initalize inode slabcache\n");		return -ENOMEM;	}	return 0;}/* Called at fs teardown. *  * Taken from NFS implementation by Al Viro. */static voidbefs_destroy_inodecache(void){	kmem_cache_destroy(befs_inode_cachep);}/* * The inode of symbolic link is different to data stream. * The data stream become link name. Unless the LONG_SYMLINK * flag is set. */static void *befs_follow_link(struct dentry *dentry, struct nameidata *nd){	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);	char *link;	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {		struct super_block *sb = dentry->d_sb;		befs_data_stream *data = &befs_ino->i_data.ds;		befs_off_t len = data->size;		befs_debug(sb, "Follow long symlink");		link = kmalloc(len, GFP_NOFS);		if (!link) {			link = ERR_PTR(-ENOMEM);		} else if (befs_read_lsymlink(sb, data, link, len) != len) {			kfree(link);			befs_error(sb, "Failed to read entire long symlink");			link = ERR_PTR(-EIO);		}	} else {		link = befs_ino->i_data.symlink;	}	nd_set_link(nd, link);	return NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -