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:
		 Andrew Gallagher
					Andrew Gallagher
				
			
				
					committed by
					
						 Miklos Szeredi
						Miklos Szeredi
					
				
			
			
				
	
			
			
			 Miklos Szeredi
						Miklos Szeredi
					
				
			
						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)) { | 	if (atomic_dec_and_test(&ff->count)) { | ||||||
| 		struct fuse_req *req = ff->reserved_req; | 		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; | 			req->background = 0; | ||||||
| 			fuse_request_send(ff->fc, req); | 			fuse_request_send(ff->fc, req); | ||||||
| 			path_put(&req->misc.release.path); | 			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, | int fuse_do_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | ||||||
| 		 bool isdir) | 		 bool isdir) | ||||||
| { | { | ||||||
| 	struct fuse_open_out outarg; |  | ||||||
| 	struct fuse_file *ff; | 	struct fuse_file *ff; | ||||||
| 	int err; |  | ||||||
| 	int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; | 	int opcode = isdir ? FUSE_OPENDIR : FUSE_OPEN; | ||||||
|  |  | ||||||
| 	ff = fuse_file_alloc(fc); | 	ff = fuse_file_alloc(fc); | ||||||
| 	if (!ff) | 	if (!ff) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
|  |  | ||||||
| 	err = fuse_send_open(fc, nodeid, file, opcode, &outarg); | 	ff->fh = 0; | ||||||
| 	if (err) { | 	ff->open_flags = FOPEN_KEEP_CACHE; /* Default for no-open */ | ||||||
| 		fuse_file_free(ff); | 	if (!fc->no_open || isdir) { | ||||||
| 		return err; | 		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) | 	if (isdir) | ||||||
| 		outarg.open_flags &= ~FOPEN_DIRECT_IO; | 		ff->open_flags &= ~FOPEN_DIRECT_IO; | ||||||
|  |  | ||||||
| 	ff->fh = outarg.fh; |  | ||||||
| 	ff->nodeid = nodeid; | 	ff->nodeid = nodeid; | ||||||
| 	ff->open_flags = outarg.open_flags; |  | ||||||
| 	file->private_data = fuse_file_get(ff); | 	file->private_data = fuse_file_get(ff); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
|   | |||||||
| @@ -485,6 +485,9 @@ struct fuse_conn { | |||||||
| 	 * and hence races in setting them will not cause malfunction | 	 * 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? */ | 	/** Is fsync not implemented by fs? */ | ||||||
| 	unsigned no_fsync:1; | 	unsigned no_fsync:1; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user