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

📄 block_dev.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/fs/block_dev.c * *  Copyright (C) 1991, 1992  Linus Torvalds *  Copyright (C) 2001  Andrea Arcangeli <andrea@suse.de> SuSE */#include <linux/config.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/locks.h>#include <linux/fcntl.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/major.h>#include <linux/devfs_fs_kernel.h>#include <linux/smp_lock.h>#include <linux/iobuf.h>#include <linux/highmem.h>#include <linux/blkdev.h>#include <linux/module.h>#include <asm/uaccess.h>#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)static unsigned long max_block(kdev_t dev){	unsigned int retval = ~0U;	int major = MAJOR(dev);	if (blk_size[major]) {		int minor = MINOR(dev);		unsigned int blocks = blk_size[major][minor];		if (blocks) {			unsigned int size = block_size(dev);			unsigned int sizebits = blksize_bits(size);			blocks += (size-1) >> BLOCK_SIZE_BITS;			retval = blocks << (BLOCK_SIZE_BITS - sizebits);			if (sizebits > BLOCK_SIZE_BITS)				retval = blocks >> (sizebits - BLOCK_SIZE_BITS);		}	}	return retval;}static loff_t blkdev_size(kdev_t dev){	unsigned int blocks = ~0U;	int major = MAJOR(dev);	if (blk_size[major]) {		int minor = MINOR(dev);		blocks = blk_size[major][minor];	}	return (loff_t) blocks << BLOCK_SIZE_BITS;}/* Kill _all_ buffers, dirty or not.. */static void kill_bdev(struct block_device *bdev){	invalidate_bdev(bdev, 1);	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);}	int set_blocksize(kdev_t dev, int size){	int oldsize;	struct block_device *bdev;	/* Size must be a power of two, and between 512 and PAGE_SIZE */	if (size > PAGE_SIZE || size < 512 || (size & (size-1)))		return -EINVAL;	/* Size cannot be smaller than the size supported by the device */	if (size < get_hardsect_size(dev))		return -EINVAL;	/* No blocksize array? Implies hardcoded BLOCK_SIZE */	if (!blksize_size[MAJOR(dev)]) {		if (size == BLOCK_SIZE)			return 0;		return -EINVAL;	}	oldsize = blksize_size[MAJOR(dev)][MINOR(dev)];	if (oldsize == size)		return 0;	if (!oldsize && size == BLOCK_SIZE) {		blksize_size[MAJOR(dev)][MINOR(dev)] = size;		return 0;	}	/* Ok, we're actually changing the blocksize.. */	bdev = bdget(dev);	sync_buffers(dev, 2);	blksize_size[MAJOR(dev)][MINOR(dev)] = size;	bdev->bd_inode->i_blkbits = blksize_bits(size);	kill_bdev(bdev);	bdput(bdev);	return 0;}static int blkdev_get_block(struct inode * inode, long iblock, struct buffer_head * bh, int create){	if (iblock >= max_block(inode->i_rdev))		return -EIO;	bh->b_dev = inode->i_rdev;	bh->b_blocknr = iblock;	bh->b_state |= 1UL << BH_Mapped;	return 0;}static int blkdev_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize){	return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, blkdev_get_block);}static int blkdev_writepage(struct page * page){	return block_write_full_page(page, blkdev_get_block);}static int blkdev_readpage(struct file * file, struct page * page){	return block_read_full_page(page, blkdev_get_block);}static int blkdev_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to){	return block_prepare_write(page, from, to, blkdev_get_block);}static int blkdev_commit_write(struct file *file, struct page *page, unsigned from, unsigned to){	return block_commit_write(page, from, to);}/* * private llseek: * for a block special file file->f_dentry->d_inode->i_size is zero * so we compute the size by hand (just as in block_read/write above) */static loff_t block_llseek(struct file *file, loff_t offset, int origin){	/* ewww */	loff_t size = file->f_dentry->d_inode->i_bdev->bd_inode->i_size;	loff_t retval;	switch (origin) {		case 2:			offset += size;			break;		case 1:			offset += file->f_pos;	}	retval = -EINVAL;	if (offset >= 0 && offset <= size) {		if (offset != file->f_pos) {			file->f_pos = offset;			file->f_reada = 0;			file->f_version = ++event;		}		retval = offset;	}	return retval;}	static int __block_fsync(struct inode * inode){	int ret, err;	ret = filemap_fdatasync(inode->i_mapping);	err = sync_buffers(inode->i_rdev, 1);	if (err && !ret)		ret = err;	err = filemap_fdatawait(inode->i_mapping);	if (err && !ret)		ret = err;	return ret;}/* *	Filp may be NULL when we are called by an msync of a vma *	since the vma has no handle. */ static int block_fsync(struct file *filp, struct dentry *dentry, int datasync){	struct inode * inode = dentry->d_inode;	return __block_fsync(inode);}/* * pseudo-fs */static struct super_block *bd_read_super(struct super_block *sb, void *data, int silent){	static struct super_operations sops = {};	struct inode *root = new_inode(sb);	if (!root)		return NULL;	root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;	root->i_uid = root->i_gid = 0;	root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;	sb->s_maxbytes = ~0ULL;	sb->s_blocksize = 1024;	sb->s_blocksize_bits = 10;	sb->s_magic = 0x62646576;	sb->s_op = &sops;	sb->s_root = d_alloc(NULL, &(const struct qstr) { "bdev:", 5, 0 });	if (!sb->s_root) {		iput(root);		return NULL;	}	sb->s_root->d_sb = sb;	sb->s_root->d_parent = sb->s_root;	d_instantiate(sb->s_root, root);	return sb;}static DECLARE_FSTYPE(bd_type, "bdev", bd_read_super, FS_NOMOUNT);static struct vfsmount *bd_mnt;/* * bdev cache handling - shamelessly stolen from inode.c * We use smaller hashtable, though. */#define HASH_BITS	6#define HASH_SIZE	(1UL << HASH_BITS)#define HASH_MASK	(HASH_SIZE-1)static struct list_head bdev_hashtable[HASH_SIZE];static spinlock_t bdev_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;static kmem_cache_t * bdev_cachep;#define alloc_bdev() \	 ((struct block_device *) kmem_cache_alloc(bdev_cachep, SLAB_KERNEL))#define destroy_bdev(bdev) kmem_cache_free(bdev_cachep, (bdev))static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags){	struct block_device * bdev = (struct block_device *) foo;	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==	    SLAB_CTOR_CONSTRUCTOR)	{		memset(bdev, 0, sizeof(*bdev));		sema_init(&bdev->bd_sem, 1);		INIT_LIST_HEAD(&bdev->bd_inodes);	}}void __init bdev_cache_init(void){	int i, err;	struct list_head *head = bdev_hashtable;	i = HASH_SIZE;	do {		INIT_LIST_HEAD(head);		head++;		i--;	} while (i);	bdev_cachep = kmem_cache_create("bdev_cache",					 sizeof(struct block_device),					 0, SLAB_HWCACHE_ALIGN, init_once,					 NULL);	if (!bdev_cachep)		panic("Cannot create bdev_cache SLAB cache");	err = register_filesystem(&bd_type);	if (err)		panic("Cannot register bdev pseudo-fs");	bd_mnt = kern_mount(&bd_type);	err = PTR_ERR(bd_mnt);	if (IS_ERR(bd_mnt))		panic("Cannot create bdev pseudo-fs");}/* * Most likely _very_ bad one - but then it's hardly critical for small * /dev and can be fixed when somebody will need really large one. */static inline unsigned long hash(dev_t dev){	unsigned long tmp = dev;	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);	return tmp & HASH_MASK;}static struct block_device *bdfind(dev_t dev, struct list_head *head){	struct list_head *p;	struct block_device *bdev;	for (p=head->next; p!=head; p=p->next) {		bdev = list_entry(p, struct block_device, bd_hash);		if (bdev->bd_dev != dev)			continue;		atomic_inc(&bdev->bd_count);		return bdev;	}	return NULL;}struct block_device *bdget(dev_t dev){	struct list_head * head = bdev_hashtable + hash(dev);	struct block_device *bdev, *new_bdev;	spin_lock(&bdev_lock);	bdev = bdfind(dev, head);	spin_unlock(&bdev_lock);	if (bdev)		return bdev;	new_bdev = alloc_bdev();	if (new_bdev) {		struct inode *inode = new_inode(bd_mnt->mnt_sb);		if (inode) {			kdev_t kdev = to_kdev_t(dev);			atomic_set(&new_bdev->bd_count,1);			new_bdev->bd_dev = dev;			new_bdev->bd_op = NULL;			new_bdev->bd_inode = inode;			inode->i_rdev = kdev;			inode->i_dev = kdev;			inode->i_bdev = new_bdev;			inode->i_data.a_ops = &def_blk_aops;			inode->i_data.gfp_mask = GFP_USER;			inode->i_mode = S_IFBLK;			spin_lock(&bdev_lock);			bdev = bdfind(dev, head);			if (!bdev) {				list_add(&new_bdev->bd_hash, head);				spin_unlock(&bdev_lock);

⌨️ 快捷键说明

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