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

📄 shmem.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* The shmem_alloc_entry() call may have blocked, and	 * shmem_writepage may have been moving a page between the page	 * cache and swap cache.  We need to recheck the page cache	 * under the protection of the info->lock spinlock. */	page = find_get_page(mapping, idx);	if (page) {		if (TryLockPage(page))			goto wait_retry;		spin_unlock (&info->lock);		return page;	}		shmem_recalc_inode(inode);	if (entry->val) {		unsigned long flags;		/* Look it up and read it in.. */		page = find_get_page(&swapper_space, entry->val);		if (!page) {			swp_entry_t swap = *entry;			spin_unlock (&info->lock);			swapin_readahead(*entry);			page = read_swap_cache_async(*entry);			if (!page) {				if (entry->val != swap.val)					goto repeat;				return ERR_PTR(-ENOMEM);			}			wait_on_page(page);			if (!Page_Uptodate(page) && entry->val == swap.val) {				page_cache_release(page);				return ERR_PTR(-EIO);			}						/* Too bad we can't trust this page, because we			 * dropped the info->lock spinlock */			page_cache_release(page);			goto repeat;		}		/* We have to this with page locked to prevent races */		if (TryLockPage(page)) 			goto wait_retry;		swap_free(*entry);		*entry = (swp_entry_t) {0};		delete_from_swap_cache(page);		flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced) | (1 << PG_arch_1));		page->flags = flags | (1 << PG_dirty);		add_to_page_cache_locked(page, mapping, idx);		info->swapped--;		spin_unlock (&info->lock);	} else {		sbinfo = SHMEM_SB(inode->i_sb);		spin_unlock (&info->lock);		spin_lock (&sbinfo->stat_lock);		if (sbinfo->free_blocks == 0)			goto no_space;		sbinfo->free_blocks--;		spin_unlock (&sbinfo->stat_lock);		/* Ok, get a new page.  We don't have to worry about the		 * info->lock spinlock here: we cannot race against		 * shm_writepage because we have already verified that		 * there is no page present either in memory or in the		 * swap cache, so we are guaranteed to be populating a		 * new shm entry.  The inode semaphore we already hold		 * is enough to make this atomic. */		page = page_cache_alloc(mapping);		if (!page)			return ERR_PTR(-ENOMEM);		clear_highpage(page);		inode->i_blocks += BLOCKS_PER_PAGE;		add_to_page_cache (page, mapping, idx);	}	/* We have the page */	SetPageUptodate(page);	return page;no_space:	spin_unlock (&sbinfo->stat_lock);	return ERR_PTR(-ENOSPC);wait_retry:	spin_unlock (&info->lock);	wait_on_page(page);	page_cache_release(page);	goto repeat;}static int shmem_getpage(struct inode * inode, unsigned long idx, struct page **ptr){	struct shmem_inode_info *info = SHMEM_I(inode);	int error;	down (&info->sem);	*ptr = ERR_PTR(-EFAULT);	if (inode->i_size <= (loff_t) idx * PAGE_CACHE_SIZE)		goto failed;	*ptr = shmem_getpage_locked(info, inode, idx);	if (IS_ERR (*ptr))		goto failed;	UnlockPage(*ptr);	up (&info->sem);	return 0;failed:	up (&info->sem);	error = PTR_ERR(*ptr);	*ptr = NOPAGE_SIGBUS;	if (error == -ENOMEM)		*ptr = NOPAGE_OOM;	return error;}struct page * shmem_nopage(struct vm_area_struct * vma, unsigned long address, int unused){	struct page * page;	unsigned int idx;	struct inode * inode = vma->vm_file->f_dentry->d_inode;	idx = (address - vma->vm_start) >> PAGE_CACHE_SHIFT;	idx += vma->vm_pgoff;	if (shmem_getpage(inode, idx, &page))		return page;	flush_page_to_ram(page);	return(page);}void shmem_lock(struct file * file, int lock){	struct inode * inode = file->f_dentry->d_inode;	struct shmem_inode_info * info = SHMEM_I(inode);	down(&info->sem);	info->locked = lock;	up(&info->sem);}static int shmem_mmap(struct file * file, struct vm_area_struct * vma){	struct vm_operations_struct * ops;	struct inode *inode = file->f_dentry->d_inode;	ops = &shmem_vm_ops;	if (!inode->i_sb || !S_ISREG(inode->i_mode))		return -EACCES;	UPDATE_ATIME(inode);	vma->vm_ops = ops;	return 0;}struct inode *shmem_get_inode(struct super_block *sb, int mode, int dev){	struct inode * inode;	struct shmem_inode_info *info;	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);	spin_lock (&sbinfo->stat_lock);	if (!sbinfo->free_inodes) {		spin_unlock (&sbinfo->stat_lock);		return NULL;	}	sbinfo->free_inodes--;	spin_unlock (&sbinfo->stat_lock);	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 = NODEV;		inode->i_mapping->a_ops = &shmem_aops;		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;		info = SHMEM_I(inode);		info->inode = inode;		spin_lock_init (&info->lock);		sema_init (&info->sem, 1);		switch (mode & S_IFMT) {		default:			init_special_inode(inode, mode, dev);			break;		case S_IFREG:			inode->i_op = &shmem_inode_operations;			inode->i_fop = &shmem_file_operations;			spin_lock (&shmem_ilock);			list_add (&SHMEM_I(inode)->list, &shmem_inodes);			spin_unlock (&shmem_ilock);			break;		case S_IFDIR:			inode->i_nlink++;			inode->i_op = &shmem_dir_inode_operations;			inode->i_fop = &shmem_dir_operations;			break;		case S_IFLNK:			break;		}	}	return inode;}static int shmem_set_size(struct shmem_sb_info *info,			  unsigned long max_blocks, unsigned long max_inodes){	int error;	unsigned long blocks, inodes;	spin_lock(&info->stat_lock);	blocks = info->max_blocks - info->free_blocks;	inodes = info->max_inodes - info->free_inodes;	error = -EINVAL;	if (max_blocks < blocks)		goto out;	if (max_inodes < inodes)		goto out;	error = 0;	info->max_blocks  = max_blocks;	info->free_blocks = max_blocks - blocks;	info->max_inodes  = max_inodes;	info->free_inodes = max_inodes - inodes;out:	spin_unlock(&info->stat_lock);	return error;}#ifdef CONFIG_TMPFSstatic struct inode_operations shmem_symlink_inode_operations;static struct inode_operations shmem_symlink_inline_operations;static ssize_tshmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos){	struct inode	*inode = file->f_dentry->d_inode; 	struct shmem_inode_info *info;	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;	loff_t		pos;	struct page	*page;	unsigned long	written;	long		status;	int		err;	if ((ssize_t) count < 0)		return -EINVAL;	if (!access_ok(VERIFY_READ, buf, count))		return -EFAULT;	down(&inode->i_sem);	pos = *ppos;	err = -EINVAL;	if (pos < 0)		goto out;	err = file->f_error;	if (err) {		file->f_error = 0;		goto out;	}	written = 0;	if (file->f_flags & O_APPEND)		pos = inode->i_size;	/*	 * Check whether we've reached the file size limit.	 */	err = -EFBIG;	if (limit != RLIM_INFINITY) {		if (pos >= limit) {			send_sig(SIGXFSZ, current, 0);			goto out;		}		if (count > limit - pos) {			send_sig(SIGXFSZ, current, 0);			count = limit - pos;		}	}	status	= 0;	if (count) {		remove_suid(inode);		inode->i_ctime = inode->i_mtime = CURRENT_TIME;	}	while (count) {		unsigned long bytes, index, offset;		char *kaddr;		/*		 * Try to find the page in the cache. If it isn't there,		 * allocate a free page.		 */		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */		index = pos >> PAGE_CACHE_SHIFT;		bytes = PAGE_CACHE_SIZE - offset;		if (bytes > count) {			bytes = count;		}		/*		 * Bring in the user page that we will copy from _first_.		 * Otherwise there's a nasty deadlock on copying from the		 * same page as we're writing to, without it being marked		 * up-to-date.		 */		{ volatile unsigned char dummy;			__get_user(dummy, buf);			__get_user(dummy, buf+bytes-1);		}		info = SHMEM_I(inode);		down (&info->sem);		page = shmem_getpage_locked(info, inode, index);		up (&info->sem);		status = PTR_ERR(page);		if (IS_ERR(page))			break;		/* We have exclusive IO access to the page.. */		if (!PageLocked(page)) {			PAGE_BUG(page);		}		kaddr = kmap(page);		status = copy_from_user(kaddr+offset, buf, bytes);		kunmap(page);		if (status)			goto fail_write;		flush_dcache_page(page);		if (bytes > 0) {			SetPageDirty(page);			written += bytes;			count -= bytes;			pos += bytes;			buf += bytes;			if (pos > inode->i_size) 				inode->i_size = pos;		}unlock:		/* Mark it unlocked again and drop the page.. */		UnlockPage(page);		page_cache_release(page);		if (status < 0)			break;	}	*ppos = pos;	err = written ? written : status;out:	up(&inode->i_sem);	return err;fail_write:	status = -EFAULT;	ClearPageUptodate(page);	kunmap(page);	goto unlock;}static void do_shmem_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc){	struct inode *inode = filp->f_dentry->d_inode;	struct address_space *mapping = inode->i_mapping;	unsigned long index, offset;	int nr = 1;	index = *ppos >> PAGE_CACHE_SHIFT;	offset = *ppos & ~PAGE_CACHE_MASK;	while (nr && desc->count) {		struct page *page;		unsigned long end_index, nr;		end_index = inode->i_size >> PAGE_CACHE_SHIFT;		if (index > end_index)			break;		nr = PAGE_CACHE_SIZE;		if (index == end_index) {			nr = inode->i_size & ~PAGE_CACHE_MASK;			if (nr <= offset)				break;		}		nr = nr - offset;		if ((desc->error = shmem_getpage(inode, index, &page)))			break;		if (mapping->i_mmap_shared != NULL)			flush_dcache_page(page);		/*		 * Ok, we have the page, and it's up-to-date, so		 * now we can copy it to user space...		 *		 * The actor routine returns how many bytes were actually used..		 * NOTE! This may not be the same as how much of a user buffer		 * we filled up (we may be padding etc), so we can only update		 * "pos" here (the actor routine has to update the user buffer		 * pointers and the remaining count).		 */		nr = file_read_actor(desc, page, offset, nr);		offset += nr;		index += offset >> PAGE_CACHE_SHIFT;		offset &= ~PAGE_CACHE_MASK;			page_cache_release(page);	}	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;	UPDATE_ATIME(inode);}static ssize_t shmem_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos){	ssize_t retval;	retval = -EFAULT;	if (access_ok(VERIFY_WRITE, buf, count)) {		retval = 0;		if (count) {			read_descriptor_t desc;			desc.written = 0;			desc.count = count;			desc.buf = buf;			desc.error = 0;			do_shmem_file_read(filp, ppos, &desc);			retval = desc.written;			if (!retval)				retval = desc.error;		}	}	return retval;}static int shmem_statfs(struct super_block *sb, struct statfs *buf){	struct shmem_sb_info *sbinfo = SHMEM_SB(sb);	buf->f_type = TMPFS_MAGIC;	buf->f_bsize = PAGE_CACHE_SIZE;	spin_lock (&sbinfo->stat_lock);	buf->f_blocks = sbinfo->max_blocks;	buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;	buf->f_files = sbinfo->max_inodes;	buf->f_ffree = sbinfo->free_inodes;	spin_unlock (&sbinfo->stat_lock);	buf->f_namelen = 255;	return 0;}/* * Lookup the data. This is trivial - if the dentry didn't already * exist, we know it is negative. */static struct dentry * shmem_lookup(struct inode *dir, struct dentry *dentry){	d_add(dentry, NULL);	return NULL;}/* * File creation. Allocate an inode, and we're done.. */static int shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev){	struct inode * inode = shmem_get_inode(dir->i_sb, mode, dev);	int error = -ENOSPC;	dir->i_ctime = dir->i_mtime = CURRENT_TIME;	if (inode) {		d_instantiate(dentry, inode);		dget(dentry); /* Extra count - pin the dentry in core */		error = 0;	}	return error;}static int shmem_mkdir(struct inode * dir, struct dentry * dentry, int mode){	int error;	if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))		return error;	dir->i_nlink++;	return 0;}static int shmem_create(struct inode *dir, struct dentry *dentry, int mode){

⌨️ 快捷键说明

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