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

📄 shmem.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return shmem_mknod(dir, dentry, mode | S_IFREG, 0);}/* * Link a file.. */static int shmem_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry){	struct inode *inode = old_dentry->d_inode;	if (S_ISDIR(inode->i_mode))		return -EPERM;	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;	inode->i_nlink++;	atomic_inc(&inode->i_count);	/* New dentry reference */	dget(dentry);		/* Extra pinning count for the created dentry */	d_instantiate(dentry, inode);	return 0;}static inline int shmem_positive(struct dentry *dentry){	return dentry->d_inode && !d_unhashed(dentry);}/* * Check that a directory is empty (this works * for regular files too, they'll just always be * considered empty..). * * Note that an empty directory can still have * children, they just all have to be negative.. */static int shmem_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 (shmem_positive(de)) {			spin_unlock(&dcache_lock);			return 0;		}		list = list->next;	}	spin_unlock(&dcache_lock);	return 1;}static int shmem_unlink(struct inode * dir, struct dentry *dentry){	struct inode *inode = dentry->d_inode;	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;	inode->i_nlink--;	dput(dentry);	/* Undo the count from "create" - this does all the work */	return 0;}static int shmem_rmdir(struct inode * dir, struct dentry *dentry){	if (!shmem_empty(dentry))		return -ENOTEMPTY;	dir->i_nlink--;	return shmem_unlink(dir, dentry);}/* * The VFS layer already does all the dentry stuff for rename, * we just have to decrement the usage count for the target if * it exists so that the VFS layer correctly free's it when it * gets overwritten. */static int shmem_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry){	int error = -ENOTEMPTY;	if (shmem_empty(new_dentry)) {		struct inode *inode = new_dentry->d_inode;		if (inode) {			inode->i_ctime = CURRENT_TIME;			inode->i_nlink--;			dput(new_dentry);		}		error = 0;		old_dentry->d_inode->i_ctime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;	}	return error;}static int shmem_symlink(struct inode * dir, struct dentry *dentry, const char * symname){	int error;	int len;	struct inode *inode;	struct page *page;	char *kaddr;	struct shmem_inode_info * info;	error = shmem_mknod(dir, dentry, S_IFLNK | S_IRWXUGO, 0);	if (error)		return error;	len = strlen(symname) + 1;	if (len > PAGE_CACHE_SIZE)		return -ENAMETOOLONG;			inode = dentry->d_inode;	info = SHMEM_I(inode);	inode->i_size = len-1;	if (len <= sizeof(struct shmem_inode_info)) {		/* do it inline */		memcpy(info, symname, len);		inode->i_op = &shmem_symlink_inline_operations;	} else {		spin_lock (&shmem_ilock);		list_add (&info->list, &shmem_inodes);		spin_unlock (&shmem_ilock);		down(&info->sem);		page = shmem_getpage_locked(info, inode, 0);		if (IS_ERR(page)) {			up(&info->sem);			return PTR_ERR(page);		}		kaddr = kmap(page);		memcpy(kaddr, symname, len);		kunmap(page);		SetPageDirty(page);		UnlockPage(page);		page_cache_release(page);		up(&info->sem);		inode->i_op = &shmem_symlink_inode_operations;	}	dir->i_ctime = dir->i_mtime = CURRENT_TIME;	return 0;}static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen){	return vfs_readlink(dentry,buffer,buflen, (const char *)SHMEM_I(dentry->d_inode));}static int shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd){	return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode));}static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen){	struct page * page;	int res = shmem_getpage(dentry->d_inode, 0, &page);	if (res)		return res;	res = vfs_readlink(dentry,buffer,buflen, kmap(page));	kunmap(page);	page_cache_release(page);	return res;}static int shmem_follow_link(struct dentry *dentry, struct nameidata *nd){	struct page * page;	int res = shmem_getpage(dentry->d_inode, 0, &page);	if (res)		return res;	res = vfs_follow_link(nd, kmap(page));	kunmap(page);	page_cache_release(page);	return res;}static struct inode_operations shmem_symlink_inline_operations = {	readlink:	shmem_readlink_inline,	follow_link:	shmem_follow_link_inline,};static struct inode_operations shmem_symlink_inode_operations = {	truncate:	shmem_truncate,	readlink:	shmem_readlink,	follow_link:	shmem_follow_link,};static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long * blocks, unsigned long *inodes){	char *this_char, *value, *rest;	this_char = NULL;	if ( options )		this_char = strtok(options,",");	for ( ; this_char; this_char = strtok(NULL,",")) {		if ((value = strchr(this_char,'=')) != NULL) {			*value++ = 0;		} else {			printk(KERN_ERR 			    "tmpfs: No value for mount option '%s'\n", 			    this_char);			return 1;		}		if (!strcmp(this_char,"size")) {			unsigned long long size;			size = memparse(value,&rest);			if (*rest)				goto bad_val;			*blocks = size >> PAGE_CACHE_SHIFT;		} else if (!strcmp(this_char,"nr_blocks")) {			*blocks = memparse(value,&rest);			if (*rest)				goto bad_val;		} else if (!strcmp(this_char,"nr_inodes")) {			*inodes = memparse(value,&rest);			if (*rest)				goto bad_val;		} else if (!strcmp(this_char,"mode")) {			if (!mode)				continue;			*mode = simple_strtoul(value,&rest,8);			if (*rest)				goto bad_val;		} else if (!strcmp(this_char,"uid")) {			if (!uid)				continue;			*uid = simple_strtoul(value,&rest,0);			if (*rest)				goto bad_val;		} else if (!strcmp(this_char,"gid")) {			if (!gid)				continue;			*gid = simple_strtoul(value,&rest,0);			if (*rest)				goto bad_val;		} else {			printk(KERN_ERR "tmpfs: Bad mount option %s\n",			       this_char);			return 1;		}	}	return 0;bad_val:	printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", 	       value, this_char);	return 1;}static int shmem_remount_fs (struct super_block *sb, int *flags, char *data){	struct shmem_sb_info *sbinfo = &sb->u.shmem_sb;	unsigned long max_blocks = sbinfo->max_blocks;	unsigned long max_inodes = sbinfo->max_inodes;	if (shmem_parse_options (data, NULL, NULL, NULL, &max_blocks, &max_inodes))		return -EINVAL;	return shmem_set_size(sbinfo, max_blocks, max_inodes);}int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync){	return 0;}#endifstatic struct super_block *shmem_read_super(struct super_block * sb, void * data, int silent){	struct inode * inode;	struct dentry * root;	unsigned long blocks, inodes;	int mode   = S_IRWXUGO | S_ISVTX;	uid_t uid = current->fsuid;	gid_t gid = current->fsgid;	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);	struct sysinfo si;	/*	 * Per default we only allow half of the physical ram per	 * tmpfs instance	 */	si_meminfo(&si);	blocks = inodes = si.totalram / 2;#ifdef CONFIG_TMPFS	if (shmem_parse_options (data, &mode, &uid, &gid, &blocks, &inodes))		return NULL;#endif	spin_lock_init (&sbinfo->stat_lock);	sbinfo->max_blocks = blocks;	sbinfo->free_blocks = blocks;	sbinfo->max_inodes = inodes;	sbinfo->free_inodes = inodes;	sb->s_maxbytes = (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT;	sb->s_blocksize = PAGE_CACHE_SIZE;	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;	sb->s_magic = TMPFS_MAGIC;	sb->s_op = &shmem_ops;	inode = shmem_get_inode(sb, S_IFDIR | mode, 0);	if (!inode)		return NULL;	inode->i_uid = uid;	inode->i_gid = gid;	root = d_alloc_root(inode);	if (!root) {		iput(inode);		return NULL;	}	sb->s_root = root;	return sb;}static struct address_space_operations shmem_aops = {	writepage:	shmem_writepage,};static struct file_operations shmem_file_operations = {	mmap:	shmem_mmap,#ifdef CONFIG_TMPFS	read:	shmem_file_read,	write:	shmem_file_write,	fsync:	shmem_sync_file,#endif};static struct inode_operations shmem_inode_operations = {	truncate:	shmem_truncate,};static struct file_operations shmem_dir_operations = {	read:		generic_read_dir,	readdir:	dcache_readdir,#ifdef CONFIG_TMPFS	fsync:		shmem_sync_file,#endif};static struct inode_operations shmem_dir_inode_operations = {#ifdef CONFIG_TMPFS	create:		shmem_create,	lookup:		shmem_lookup,	link:		shmem_link,	unlink:		shmem_unlink,	symlink:	shmem_symlink,	mkdir:		shmem_mkdir,	rmdir:		shmem_rmdir,	mknod:		shmem_mknod,	rename:		shmem_rename,#endif};static struct super_operations shmem_ops = {#ifdef CONFIG_TMPFS	statfs:		shmem_statfs,	remount_fs:	shmem_remount_fs,#endif	delete_inode:	shmem_delete_inode,	put_inode:	force_delete,	};static struct vm_operations_struct shmem_vm_ops = {	nopage:	shmem_nopage,};#ifdef CONFIG_TMPFS/* type "shm" will be tagged obsolete in 2.5 */static DECLARE_FSTYPE(shmem_fs_type, "shm", shmem_read_super, FS_LITTER);static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER);#elsestatic DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER|FS_NOMOUNT);#endifstatic struct vfsmount *shm_mnt;static int __init init_shmem_fs(void){	int error;	struct vfsmount * res;	if ((error = register_filesystem(&tmpfs_fs_type))) {		printk (KERN_ERR "Could not register tmpfs\n");		return error;	}#ifdef CONFIG_TMPFS	if ((error = register_filesystem(&shmem_fs_type))) {		printk (KERN_ERR "Could not register shm fs\n");		return error;	}	devfs_mk_dir (NULL, "shm", NULL);#endif	res = kern_mount(&tmpfs_fs_type);	if (IS_ERR (res)) {		printk (KERN_ERR "could not kern_mount tmpfs\n");		unregister_filesystem(&tmpfs_fs_type);		return PTR_ERR(res);	}	shm_mnt = res;	/* The internal instance should not do size checking */	if ((error = shmem_set_size(SHMEM_SB(res->mnt_sb), ULONG_MAX, ULONG_MAX)))		printk (KERN_ERR "could not set limits on internal tmpfs\n");	return 0;}static void __exit exit_shmem_fs(void){#ifdef CONFIG_TMPFS	unregister_filesystem(&shmem_fs_type);#endif	unregister_filesystem(&tmpfs_fs_type);	mntput(shm_mnt);}module_init(init_shmem_fs)module_exit(exit_shmem_fs)/* * shmem_file_setup - get an unlinked file living in shmem fs * * @name: name for dentry (to be seen in /proc/<pid>/maps * @size: size to be set for the file * */struct file *shmem_file_setup(char * name, loff_t size){	int error;	struct file *file;	struct inode * inode;	struct dentry *dentry, *root;	struct qstr this;	int vm_enough_memory(long pages);	if (size > (unsigned long long) SHMEM_MAX_BLOCKS << PAGE_CACHE_SHIFT)		return ERR_PTR(-EINVAL);	if (!vm_enough_memory((size) >> PAGE_CACHE_SHIFT))		return ERR_PTR(-ENOMEM);	this.name = name;	this.len = strlen(name);	this.hash = 0; /* will go */	root = shm_mnt->mnt_root;	dentry = d_alloc(root, &this);	if (!dentry)		return ERR_PTR(-ENOMEM);	error = -ENFILE;	file = get_empty_filp();	if (!file)		goto put_dentry;	error = -ENOSPC;	inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);	if (!inode) 		goto close_file;	d_instantiate(dentry, inode);	dentry->d_inode->i_size = size;	shmem_truncate(inode);	file->f_vfsmnt = mntget(shm_mnt);	file->f_dentry = dentry;	file->f_op = &shmem_file_operations;	file->f_mode = FMODE_WRITE | FMODE_READ;	inode->i_nlink = 0;	/* It is unlinked */	return(file);close_file:	put_filp(file);put_dentry:	dput (dentry);	return ERR_PTR(error);	}/* * shmem_zero_setup - setup a shared anonymous mapping * * @vma: the vma to be mmapped is prepared by do_mmap_pgoff */int shmem_zero_setup(struct vm_area_struct *vma){	struct file *file;	loff_t size = vma->vm_end - vma->vm_start;		file = shmem_file_setup("dev/zero", size);	if (IS_ERR(file))		return PTR_ERR(file);	if (vma->vm_file)		fput (vma->vm_file);	vma->vm_file = file;	vma->vm_ops = &shmem_vm_ops;	return 0;}EXPORT_SYMBOL(shmem_file_setup);

⌨️ 快捷键说明

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