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

📄 file.c

📁 FUSE文件系统开发工具,将内核层面的文件系统开发过程平移到应用层面上来。
💻 C
📖 第 1 页 / 共 2 页
字号:
	inarg.offset = pos;	inarg.size = count;	req->in.h.opcode = FUSE_WRITE;	req->in.h.nodeid = get_node_id(inode);	req->in.argpages = 1;	req->in.numargs = 2;	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;	request_send(fc, req);	return outarg.size;}static int fuse_prepare_write(struct file *file, struct page *page,			      unsigned offset, unsigned to){	/* No op */	return 0;}static int fuse_commit_write(struct file *file, struct page *page,			     unsigned offset, unsigned to){	int err;	size_t nres;	unsigned count = to - offset;	struct inode *inode = page->mapping->host;	struct fuse_conn *fc = get_fuse_conn(inode);	loff_t pos = page_offset(page) + offset;	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);	err = req->out.h.error;	fuse_put_request(fc, req);	if (!err && nres != count)		err = -EIO;	if (!err) {		pos += count;		spin_lock(&fc->lock);		if (pos > inode->i_size)			i_size_write(inode, pos);		spin_unlock(&fc->lock);		if (offset == 0 && to == PAGE_CACHE_SIZE)			SetPageUptodate(page);	}	fuse_invalidate_attr(inode);	return err;}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 = max(npages, 1);	npages = min(npages, 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_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);		else			nres = fuse_send_read(req, file, inode, pos, nbytes);		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_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){	struct inode *inode = file->f_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;	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_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);	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){	struct inode *inode = file->f_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;#ifdef KERNEL_2_6_18_PLUS	/* Unlock on close is handled by the flush method */	if (fl->fl_flags & FL_CLOSE)		return 0;	req = fuse_get_req(fc);#else	/* If it's (possibly) unlock on close, don't fail the allocation */	if (fl->fl_type == F_UNLCK && fl->fl_start == 0 &&	    fl->fl_end == OFFSET_MAX)		req = fuse_get_req_nofail(fc, file);	else {		/* Hack: add dummy lock, otherwise unlock on close is		   optimized away */		struct file_lock **flp;		for (flp = &inode->i_flock;		     *flp && !((*flp)->fl_flags & FL_POSIX);		     flp = &(*flp)->fl_next);		if (!*flp) {			struct file_lock *dummy =				kmalloc(sizeof(struct file_lock), GFP_KERNEL);			if (!dummy)				return -ENOLCK;			locks_init_lock(dummy);			dummy->fl_flags |= FL_POSIX;			*flp = dummy;		}		req = fuse_get_req(fc);	}#endif	if (IS_ERR(req))		return PTR_ERR(req);	fuse_lk_fill(req, file, fl, opcode, pid);	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_dentry->d_inode;	struct fuse_conn *fc = get_fuse_conn(inode);	int err;	if (cmd == F_GETLK) {		if (fc->no_lock) {#ifdef KERNEL_2_6_22_PLUS			posix_test_lock(file, fl);#elif defined(KERNEL_2_6_17_PLUS)			if (!posix_test_lock(file, fl, fl))				fl->fl_type = F_UNLCK;#else			struct file_lock *cfl = posix_test_lock(file, fl);			if (!cfl)				fl->fl_type = F_UNLCK;			else				*fl = *cfl;#endif			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);	}	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 struct file_operations fuse_file_operations = {	.llseek		= generic_file_llseek,#ifndef KERNEL_2_6_19_PLUS	.read		= generic_file_read,	.write		= generic_file_write,#else	.read		= do_sync_read,	.aio_read	= generic_file_aio_read,	.write		= do_sync_write,	.aio_write	= generic_file_aio_write,#endif	.mmap		= fuse_file_mmap,	.open		= fuse_open,	.flush		= fuse_flush,	.release	= fuse_release,	.fsync		= fuse_fsync,	.lock		= fuse_file_lock,#ifdef KERNEL_2_6_23_PLUS	.splice_read	= generic_file_splice_read,#else	.sendfile	= generic_file_sendfile,#endif};static 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,	/* no mmap and sendfile */};static struct address_space_operations fuse_file_aops  = {	.readpage	= fuse_readpage,	.prepare_write	= fuse_prepare_write,	.commit_write	= fuse_commit_write,	.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 + -