fuse: support clients that don't implement 'open'
open/release operations require userspace transitions to keep track of the open count and to perform any FS-specific setup. However, for some purely read-only FSs which don't need to perform any setup at open/release time, we can avoid the performance overhead of calling into userspace for open/release calls. This patch adds the necessary support to the fuse kernel modules to prevent open/release operations from hitting in userspace. When the client returns ENOSYS, we avoid sending the subsequent release to userspace, and also remember this so that future opens also don't trigger a userspace operation. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
This commit is contained in:
		
							parent
							
								
									451418fc92
								
							
						
					
					
						commit
						7678ac5061
					
				| @ -127,7 +127,15 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) | ||||
| 	if (atomic_dec_and_test(&ff->count)) { | ||||
| 		struct fuse_req *req = ff->reserved_req; | ||||
| 
 | ||||
| 		if (sync) { | ||||
| 		if (ff->fc->no_open) { | ||||
| 			/*
 | ||||
| 			 * Drop the release request when client does not | ||||
| 			 * implement 'open' | ||||
| 			 */ | ||||
| 			req->background = 0; | ||||
| 			path_put(&req->misc.release.path); | ||||
| 			fuse_put_request(ff->fc, req); | ||||
| 		} else if (sync) { | ||||
| 			req->background = 0; | ||||
| 			fuse_request_send(ff->fc, req); | ||||
| 			path_put(&req->misc.release.path); | ||||
| @ -144,27 +152,36 @@ static void fuse_file_put(struct fuse_file *ff, bool sync) | ||||
| int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | ||||
| 		 bool isdir) | ||||
| { | ||||
| 	struct fuse_open_out outarg; | ||||
| 	struct fuse_file *ff; | ||||
| 	int err; | ||||
| 	int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; | ||||
| 
 | ||||
| 	ff = fuse_file_alloc(fc); | ||||
| 	if (!ff) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	err = fuse_send_open(fc, nodeid, file, opcode, &outarg); | ||||
| 	if (err) { | ||||
| 		fuse_file_free(ff); | ||||
| 		return err; | ||||
| 	ff->fh = 0; | ||||
| 	ff->open_flags = FOPEN_KEEP_CACHE; /* Default for no-open */ | ||||
| 	if (!fc->no_open || isdir) { | ||||
| 		struct fuse_open_out outarg; | ||||
| 		int err; | ||||
| 
 | ||||
| 		err = fuse_send_open(fc, nodeid, file, opcode, &outarg); | ||||
| 		if (!err) { | ||||
| 			ff->fh = outarg.fh; | ||||
| 			ff->open_flags = outarg.open_flags; | ||||
| 
 | ||||
| 		} else if (err != -ENOSYS || isdir) { | ||||
| 			fuse_file_free(ff); | ||||
| 			return err; | ||||
| 		} else { | ||||
| 			fc->no_open = 1; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (isdir) | ||||
| 		outarg.open_flags &= ~FOPEN_DIRECT_IO; | ||||
| 		ff->open_flags &= ~FOPEN_DIRECT_IO; | ||||
| 
 | ||||
| 	ff->fh = outarg.fh; | ||||
| 	ff->nodeid = nodeid; | ||||
| 	ff->open_flags = outarg.open_flags; | ||||
| 	file->private_data = fuse_file_get(ff); | ||||
| 
 | ||||
| 	return 0; | ||||
|  | ||||
| @ -485,6 +485,9 @@ struct fuse_conn { | ||||
| 	 * and hence races in setting them will not cause malfunction | ||||
| 	 */ | ||||
| 
 | ||||
| 	/** Is open/release not implemented by fs? */ | ||||
| 	unsigned no_open:1; | ||||
| 
 | ||||
| 	/** Is fsync not implemented by fs? */ | ||||
| 	unsigned no_fsync:1; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user