diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2019-09-10 09:04:10 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2019-09-10 10:29:50 -0400 |
commit | 4cb548666e4c13699904a063f6909b169d3f900c (patch) | |
tree | 8a49d640133a82335f1cd3901834b5303a47574b /fs/fuse | |
parent | b50ef7c52ad7c954b743cd1cb181e9bf03537bab (diff) |
fuse: convert release to simple api
Since we cannot reserve the request structure up-front, make sure that the
request allocation doesn't fail using __GFP_NOFAIL.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/file.c | 75 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 8 |
2 files changed, 42 insertions, 41 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 399b89b29bb4..56ed45ef3058 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -53,6 +53,12 @@ static int fuse_send_open(struct fuse_conn *fc, u64 nodeid, struct file *file, | |||
53 | return fuse_simple_request(fc, &args); | 53 | return fuse_simple_request(fc, &args); |
54 | } | 54 | } |
55 | 55 | ||
56 | struct fuse_release_args { | ||
57 | struct fuse_args args; | ||
58 | struct fuse_release_in inarg; | ||
59 | struct inode *inode; | ||
60 | }; | ||
61 | |||
56 | struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) | 62 | struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) |
57 | { | 63 | { |
58 | struct fuse_file *ff; | 64 | struct fuse_file *ff; |
@@ -62,8 +68,8 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) | |||
62 | return NULL; | 68 | return NULL; |
63 | 69 | ||
64 | ff->fc = fc; | 70 | ff->fc = fc; |
65 | ff->reserved_req = fuse_request_alloc(0); | 71 | ff->release_args = kzalloc(sizeof(*ff->release_args), GFP_KERNEL); |
66 | if (unlikely(!ff->reserved_req)) { | 72 | if (!ff->release_args) { |
67 | kfree(ff); | 73 | kfree(ff); |
68 | return NULL; | 74 | return NULL; |
69 | } | 75 | } |
@@ -81,7 +87,7 @@ struct fuse_file *fuse_file_alloc(struct fuse_conn *fc) | |||
81 | 87 | ||
82 | void fuse_file_free(struct fuse_file *ff) | 88 | void fuse_file_free(struct fuse_file *ff) |
83 | { | 89 | { |
84 | fuse_request_free(ff->reserved_req); | 90 | kfree(ff->release_args); |
85 | mutex_destroy(&ff->readdir.lock); | 91 | mutex_destroy(&ff->readdir.lock); |
86 | kfree(ff); | 92 | kfree(ff); |
87 | } | 93 | } |
@@ -92,34 +98,31 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff) | |||
92 | return ff; | 98 | return ff; |
93 | } | 99 | } |
94 | 100 | ||
95 | static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) | 101 | static void fuse_release_end(struct fuse_conn *fc, struct fuse_args *args, |
102 | int error) | ||
96 | { | 103 | { |
97 | iput(req->misc.release.inode); | 104 | struct fuse_release_args *ra = container_of(args, typeof(*ra), args); |
105 | |||
106 | iput(ra->inode); | ||
107 | kfree(ra); | ||
98 | } | 108 | } |
99 | 109 | ||
100 | static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) | 110 | static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) |
101 | { | 111 | { |
102 | if (refcount_dec_and_test(&ff->count)) { | 112 | if (refcount_dec_and_test(&ff->count)) { |
103 | struct fuse_req *req = ff->reserved_req; | 113 | struct fuse_args *args = &ff->release_args->args; |
104 | 114 | ||
105 | if (isdir ? ff->fc->no_opendir : ff->fc->no_open) { | 115 | if (isdir ? ff->fc->no_opendir : ff->fc->no_open) { |
106 | /* | 116 | /* Do nothing when client does not implement 'open' */ |
107 | * Drop the release request when client does not | 117 | fuse_release_end(ff->fc, args, 0); |
108 | * implement 'open' | ||
109 | */ | ||
110 | __clear_bit(FR_BACKGROUND, &req->flags); | ||
111 | iput(req->misc.release.inode); | ||
112 | fuse_put_request(ff->fc, req); | ||
113 | } else if (sync) { | 118 | } else if (sync) { |
114 | __set_bit(FR_FORCE, &req->flags); | 119 | fuse_simple_request(ff->fc, args); |
115 | __clear_bit(FR_BACKGROUND, &req->flags); | 120 | fuse_release_end(ff->fc, args, 0); |
116 | fuse_request_send(ff->fc, req); | ||
117 | iput(req->misc.release.inode); | ||
118 | fuse_put_request(ff->fc, req); | ||
119 | } else { | 121 | } else { |
120 | req->end = fuse_release_end; | 122 | args->end = fuse_release_end; |
121 | __set_bit(FR_BACKGROUND, &req->flags); | 123 | if (fuse_simple_background(ff->fc, args, |
122 | fuse_request_send_background(ff->fc, req); | 124 | GFP_KERNEL | __GFP_NOFAIL)) |
125 | fuse_release_end(ff->fc, args, -ENOTCONN); | ||
123 | } | 126 | } |
124 | kfree(ff); | 127 | kfree(ff); |
125 | } | 128 | } |
@@ -239,8 +242,7 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff, | |||
239 | int flags, int opcode) | 242 | int flags, int opcode) |
240 | { | 243 | { |
241 | struct fuse_conn *fc = ff->fc; | 244 | struct fuse_conn *fc = ff->fc; |
242 | struct fuse_req *req = ff->reserved_req; | 245 | struct fuse_release_args *ra = ff->release_args; |
243 | struct fuse_release_in *inarg = &req->misc.release.in; | ||
244 | 246 | ||
245 | /* Inode is NULL on error path of fuse_create_open() */ | 247 | /* Inode is NULL on error path of fuse_create_open() */ |
246 | if (likely(fi)) { | 248 | if (likely(fi)) { |
@@ -255,32 +257,33 @@ static void fuse_prepare_release(struct fuse_inode *fi, struct fuse_file *ff, | |||
255 | 257 | ||
256 | wake_up_interruptible_all(&ff->poll_wait); | 258 | wake_up_interruptible_all(&ff->poll_wait); |
257 | 259 | ||
258 | inarg->fh = ff->fh; | 260 | ra->inarg.fh = ff->fh; |
259 | inarg->flags = flags; | 261 | ra->inarg.flags = flags; |
260 | req->in.h.opcode = opcode; | 262 | ra->args.in_numargs = 1; |
261 | req->in.h.nodeid = ff->nodeid; | 263 | ra->args.in_args[0].size = sizeof(struct fuse_release_in); |
262 | req->in.numargs = 1; | 264 | ra->args.in_args[0].value = &ra->inarg; |
263 | req->in.args[0].size = sizeof(struct fuse_release_in); | 265 | ra->args.opcode = opcode; |
264 | req->in.args[0].value = inarg; | 266 | ra->args.nodeid = ff->nodeid; |
267 | ra->args.force = true; | ||
268 | ra->args.nocreds = true; | ||
265 | } | 269 | } |
266 | 270 | ||
267 | void fuse_release_common(struct file *file, bool isdir) | 271 | void fuse_release_common(struct file *file, bool isdir) |
268 | { | 272 | { |
269 | struct fuse_inode *fi = get_fuse_inode(file_inode(file)); | 273 | struct fuse_inode *fi = get_fuse_inode(file_inode(file)); |
270 | struct fuse_file *ff = file->private_data; | 274 | struct fuse_file *ff = file->private_data; |
271 | struct fuse_req *req = ff->reserved_req; | 275 | struct fuse_release_args *ra = ff->release_args; |
272 | int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; | 276 | int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; |
273 | 277 | ||
274 | fuse_prepare_release(fi, ff, file->f_flags, opcode); | 278 | fuse_prepare_release(fi, ff, file->f_flags, opcode); |
275 | 279 | ||
276 | if (ff->flock) { | 280 | if (ff->flock) { |
277 | struct fuse_release_in *inarg = &req->misc.release.in; | 281 | ra->inarg.release_flags |= FUSE_RELEASE_FLOCK_UNLOCK; |
278 | inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK; | 282 | ra->inarg.lock_owner = fuse_lock_owner_id(ff->fc, |
279 | inarg->lock_owner = fuse_lock_owner_id(ff->fc, | 283 | (fl_owner_t) file); |
280 | (fl_owner_t) file); | ||
281 | } | 284 | } |
282 | /* Hold inode until release is finished */ | 285 | /* Hold inode until release is finished */ |
283 | req->misc.release.inode = igrab(file_inode(file)); | 286 | ra->inode = igrab(file_inode(file)); |
284 | 287 | ||
285 | /* | 288 | /* |
286 | * Normally this will send the RELEASE request, however if | 289 | * Normally this will send the RELEASE request, however if |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index a9d707bf2e69..a055a45361ef 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -164,17 +164,15 @@ enum { | |||
164 | }; | 164 | }; |
165 | 165 | ||
166 | struct fuse_conn; | 166 | struct fuse_conn; |
167 | struct fuse_release_args; | ||
167 | 168 | ||
168 | /** FUSE specific file data */ | 169 | /** FUSE specific file data */ |
169 | struct fuse_file { | 170 | struct fuse_file { |
170 | /** Fuse connection for this file */ | 171 | /** Fuse connection for this file */ |
171 | struct fuse_conn *fc; | 172 | struct fuse_conn *fc; |
172 | 173 | ||
173 | /* | 174 | /* Argument space reserved for release */ |
174 | * Request reserved for flush and release. | 175 | struct fuse_release_args *release_args; |
175 | * Modified under relative fuse_inode::lock. | ||
176 | */ | ||
177 | struct fuse_req *reserved_req; | ||
178 | 176 | ||
179 | /** Kernel file handle guaranteed to be unique */ | 177 | /** Kernel file handle guaranteed to be unique */ |
180 | u64 kh; | 178 | u64 kh; |