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

📄 file.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			    struct inode *inode, loff_t pos, size_t count,			    int writepage){	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_file *ff = file->private_data;	struct fuse_write_in *inarg = &req->misc.write.in;	struct fuse_write_out *outarg = &req->misc.write.out;	memset(inarg, 0, sizeof(struct fuse_write_in));	inarg->fh = ff->fh;	inarg->offset = pos;	inarg->size = count;	inarg->write_flags = writepage ? FUSE_WRITE_CACHE : 0;	inarg->flags = file->f_flags;	req->in.h.opcode = FUSE_WRITE;	req->in.h.nodeid = get_node_id(inode);	req->in.argpages = 1;	req->in.numargs = 2;	if (fc->minor < 9)		req->in.args[0].size = FUSE_COMPAT_WRITE_IN_SIZE;	else		req->in.args[0].size = sizeof(struct fuse_write_in);	req->in.args[0].value = inarg;	req->in.args[1].size = count;	req->out.numargs = 1;	req->out.args[0].size = sizeof(struct fuse_write_out);	req->out.args[0].value = outarg;}static size_t fuse_send_write(struct fuse_req *req, struct file *file,			      struct inode *inode, loff_t pos, size_t count,			      fl_owner_t owner){	struct fuse_conn *fc = get_fuse_conn(inode);	fuse_write_fill(req, file, inode, pos, count, 0);	if (owner != NULL) {		struct fuse_write_in *inarg = &req->misc.write.in;		inarg->write_flags |= FUSE_WRITE_LOCKOWNER;		inarg->lock_owner = fuse_lock_owner_id(fc, owner);	}	request_send(fc, req);	return req->misc.write.out.size;}static int fuse_write_begin(struct file *file, struct address_space *mapping,			loff_t pos, unsigned len, unsigned flags,			struct page **pagep, void **fsdata){	pgoff_t index = pos >> PAGE_CACHE_SHIFT;	*pagep = __grab_cache_page(mapping, index);	if (!*pagep)		return -ENOMEM;	return 0;}static int fuse_buffered_write(struct file *file, struct inode *inode,			       loff_t pos, unsigned count, struct page *page){	int err;	size_t nres;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_inode *fi = get_fuse_inode(inode);	unsigned offset = pos & (PAGE_CACHE_SIZE - 1);	struct fuse_req *req;	if (is_bad_inode(inode))		return -EIO;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	req->num_pages = 1;	req->pages[0] = page;	req->page_offset = offset;	nres = fuse_send_write(req, file, inode, pos, count, NULL);	err = req->out.h.error;	fuse_put_request(fc, req);	if (!err && !nres)		err = -EIO;	if (!err) {		pos += nres;		spin_lock(&fc->lock);		fi->attr_version = ++fc->attr_version;		if (pos > inode->i_size)			i_size_write(inode, pos);		spin_unlock(&fc->lock);		if (count == PAGE_CACHE_SIZE)			SetPageUptodate(page);	}	fuse_invalidate_attr(inode);	return err ? err : nres;}static int fuse_write_end(struct file *file, struct address_space *mapping,			loff_t pos, unsigned len, unsigned copied,			struct page *page, void *fsdata){	struct inode *inode = mapping->host;	int res = 0;	if (copied)		res = fuse_buffered_write(file, inode, pos, copied, page);	unlock_page(page);	page_cache_release(page);	return res;}static void fuse_release_user_pages(struct fuse_req *req, int write){	unsigned i;	for (i = 0; i < req->num_pages; i++) {		struct page *page = req->pages[i];		if (write)			set_page_dirty_lock(page);		put_page(page);	}}static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf,			       unsigned nbytes, int write){	unsigned long user_addr = (unsigned long) buf;	unsigned offset = user_addr & ~PAGE_MASK;	int npages;	/* This doesn't work with nfsd */	if (!current->mm)		return -EPERM;	nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);	npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;	npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ);	down_read(&current->mm->mmap_sem);	npages = get_user_pages(current, current->mm, user_addr, npages, write,				0, req->pages, NULL);	up_read(&current->mm->mmap_sem);	if (npages < 0)		return npages;	req->num_pages = npages;	req->page_offset = offset;	return 0;}static ssize_t fuse_direct_io(struct file *file, const char __user *buf,			      size_t count, loff_t *ppos, int write){	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	size_t nmax = write ? fc->max_write : fc->max_read;	loff_t pos = *ppos;	ssize_t res = 0;	struct fuse_req *req;	if (is_bad_inode(inode))		return -EIO;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	while (count) {		size_t nres;		size_t nbytes = min(count, nmax);		int err = fuse_get_user_pages(req, buf, nbytes, !write);		if (err) {			res = err;			break;		}		nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;		nbytes = min(count, nbytes);		if (write)			nres = fuse_send_write(req, file, inode, pos, nbytes,					       current->files);		else			nres = fuse_send_read(req, file, inode, pos, nbytes,					      current->files);		fuse_release_user_pages(req, !write);		if (req->out.h.error) {			if (!res)				res = req->out.h.error;			break;		} else if (nres > nbytes) {			res = -EIO;			break;		}		count -= nres;		res += nres;		pos += nres;		buf += nres;		if (nres != nbytes)			break;		if (count) {			fuse_put_request(fc, req);			req = fuse_get_req(fc);			if (IS_ERR(req))				break;		}	}	fuse_put_request(fc, req);	if (res > 0) {		if (write) {			spin_lock(&fc->lock);			if (pos > inode->i_size)				i_size_write(inode, pos);			spin_unlock(&fc->lock);		}		*ppos = pos;	}	fuse_invalidate_attr(inode);	return res;}static ssize_t fuse_direct_read(struct file *file, char __user *buf,				     size_t count, loff_t *ppos){	return fuse_direct_io(file, buf, count, ppos, 0);}static ssize_t fuse_direct_write(struct file *file, const char __user *buf,				 size_t count, loff_t *ppos){	struct inode *inode = file->f_path.dentry->d_inode;	ssize_t res;	/* Don't allow parallel writes to the same file */	mutex_lock(&inode->i_mutex);	res = generic_write_checks(file, ppos, &count, 0);	if (!res)		res = fuse_direct_io(file, buf, count, ppos, 1);	mutex_unlock(&inode->i_mutex);	return res;}static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma){	if ((vma->vm_flags & VM_SHARED)) {		if ((vma->vm_flags & VM_WRITE))			return -ENODEV;		else			vma->vm_flags &= ~VM_MAYWRITE;	}	return generic_file_mmap(file, vma);}static int fuse_set_page_dirty(struct page *page){	printk("fuse_set_page_dirty: should not happen\n");	dump_stack();	return 0;}static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,				  struct file_lock *fl){	switch (ffl->type) {	case F_UNLCK:		break;	case F_RDLCK:	case F_WRLCK:		if (ffl->start > OFFSET_MAX || ffl->end > OFFSET_MAX ||		    ffl->end < ffl->start)			return -EIO;		fl->fl_start = ffl->start;		fl->fl_end = ffl->end;		fl->fl_pid = ffl->pid;		break;	default:		return -EIO;	}	fl->fl_type = ffl->type;	return 0;}static void fuse_lk_fill(struct fuse_req *req, struct file *file,			 const struct file_lock *fl, int opcode, pid_t pid,			 int flock){	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_file *ff = file->private_data;	struct fuse_lk_in *arg = &req->misc.lk_in;	arg->fh = ff->fh;	arg->owner = fuse_lock_owner_id(fc, fl->fl_owner);	arg->lk.start = fl->fl_start;	arg->lk.end = fl->fl_end;	arg->lk.type = fl->fl_type;	arg->lk.pid = pid;	if (flock)		arg->lk_flags |= FUSE_LK_FLOCK;	req->in.h.opcode = opcode;	req->in.h.nodeid = get_node_id(inode);	req->in.numargs = 1;	req->in.args[0].size = sizeof(*arg);	req->in.args[0].value = arg;}static int fuse_getlk(struct file *file, struct file_lock *fl){	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_req *req;	struct fuse_lk_out outarg;	int err;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	fuse_lk_fill(req, file, fl, FUSE_GETLK, 0, 0);	req->out.numargs = 1;	req->out.args[0].size = sizeof(outarg);	req->out.args[0].value = &outarg;	request_send(fc, req);	err = req->out.h.error;	fuse_put_request(fc, req);	if (!err)		err = convert_fuse_file_lock(&outarg.lk, fl);	return err;}static int fuse_setlk(struct file *file, struct file_lock *fl, int flock){	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_req *req;	int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;	pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;	int err;	/* Unlock on close is handled by the flush method */	if (fl->fl_flags & FL_CLOSE)		return 0;	req = fuse_get_req(fc);	if (IS_ERR(req))		return PTR_ERR(req);	fuse_lk_fill(req, file, fl, opcode, pid, flock);	request_send(fc, req);	err = req->out.h.error;	/* locking is restartable */	if (err == -EINTR)		err = -ERESTARTSYS;	fuse_put_request(fc, req);	return err;}static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl){	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	int err;	if (cmd == F_GETLK) {		if (fc->no_lock) {			posix_test_lock(file, fl);			err = 0;		} else			err = fuse_getlk(file, fl);	} else {		if (fc->no_lock)			err = posix_lock_file_wait(file, fl);		else			err = fuse_setlk(file, fl, 0);	}	return err;}static int fuse_file_flock(struct file *file, int cmd, struct file_lock *fl){	struct inode *inode = file->f_path.dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	int err;	if (fc->no_lock) {		err = flock_lock_file_wait(file, fl);	} else {		/* emulate flock with POSIX locks */		fl->fl_owner = (fl_owner_t) file;		err = fuse_setlk(file, fl, 1);	}	return err;}static sector_t fuse_bmap(struct address_space *mapping, sector_t block){	struct inode *inode = mapping->host;	struct fuse_conn *fc = get_fuse_conn(inode);	struct fuse_req *req;	struct fuse_bmap_in inarg;	struct fuse_bmap_out outarg;	int err;	if (!inode->i_sb->s_bdev || fc->no_bmap)		return 0;	req = fuse_get_req(fc);	if (IS_ERR(req))		return 0;	memset(&inarg, 0, sizeof(inarg));	inarg.block = block;	inarg.blocksize = inode->i_sb->s_blocksize;	req->in.h.opcode = FUSE_BMAP;	req->in.h.nodeid = get_node_id(inode);	req->in.numargs = 1;	req->in.args[0].size = sizeof(inarg);	req->in.args[0].value = &inarg;	req->out.numargs = 1;	req->out.args[0].size = sizeof(outarg);	req->out.args[0].value = &outarg;	request_send(fc, req);	err = req->out.h.error;	fuse_put_request(fc, req);	if (err == -ENOSYS)		fc->no_bmap = 1;	return err ? 0 : outarg.block;}static const struct file_operations fuse_file_operations = {	.llseek		= generic_file_llseek,	.read		= do_sync_read,	.aio_read	= fuse_file_aio_read,	.write		= do_sync_write,	.aio_write	= generic_file_aio_write,	.mmap		= fuse_file_mmap,	.open		= fuse_open,	.flush		= fuse_flush,	.release	= fuse_release,	.fsync		= fuse_fsync,	.lock		= fuse_file_lock,	.flock		= fuse_file_flock,	.splice_read	= generic_file_splice_read,};static const struct file_operations fuse_direct_io_file_operations = {	.llseek		= generic_file_llseek,	.read		= fuse_direct_read,	.write		= fuse_direct_write,	.open		= fuse_open,	.flush		= fuse_flush,	.release	= fuse_release,	.fsync		= fuse_fsync,	.lock		= fuse_file_lock,	.flock		= fuse_file_flock,	/* no mmap and splice_read */};static const struct address_space_operations fuse_file_aops  = {	.readpage	= fuse_readpage,	.write_begin	= fuse_write_begin,	.write_end	= fuse_write_end,	.readpages	= fuse_readpages,	.set_page_dirty	= fuse_set_page_dirty,	.bmap		= fuse_bmap,};void fuse_init_file_inode(struct inode *inode){	inode->i_fop = &fuse_file_operations;	inode->i_data.a_ops = &fuse_file_aops;}

⌨️ 快捷键说明

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