diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 21 | ||||
-rw-r--r-- | fs/fuse/file.c | 49 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 5 |
3 files changed, 36 insertions, 39 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index faa3b2f86740..b3089a083d30 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -362,19 +362,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
362 | } | 362 | } |
363 | 363 | ||
364 | /* | 364 | /* |
365 | * Synchronous release for the case when something goes wrong in CREATE_OPEN | ||
366 | */ | ||
367 | static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, | ||
368 | int flags) | ||
369 | { | ||
370 | fuse_release_fill(ff, flags, FUSE_RELEASE); | ||
371 | ff->reserved_req->force = 1; | ||
372 | fuse_request_send(fc, ff->reserved_req); | ||
373 | fuse_put_request(fc, ff->reserved_req); | ||
374 | kfree(ff); | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * Atomic create+open operation | 365 | * Atomic create+open operation |
379 | * | 366 | * |
380 | * If the filesystem doesn't support this, then fall back to separate | 367 | * If the filesystem doesn't support this, then fall back to separate |
@@ -452,7 +439,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
452 | &outentry.attr, entry_attr_timeout(&outentry), 0); | 439 | &outentry.attr, entry_attr_timeout(&outentry), 0); |
453 | if (!inode) { | 440 | if (!inode) { |
454 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 441 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
455 | fuse_sync_release(fc, ff, flags); | 442 | fuse_sync_release(ff, flags); |
456 | fuse_send_forget(fc, forget_req, outentry.nodeid, 1); | 443 | fuse_send_forget(fc, forget_req, outentry.nodeid, 1); |
457 | return -ENOMEM; | 444 | return -ENOMEM; |
458 | } | 445 | } |
@@ -462,7 +449,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
462 | fuse_invalidate_attr(dir); | 449 | fuse_invalidate_attr(dir); |
463 | file = lookup_instantiate_filp(nd, entry, generic_file_open); | 450 | file = lookup_instantiate_filp(nd, entry, generic_file_open); |
464 | if (IS_ERR(file)) { | 451 | if (IS_ERR(file)) { |
465 | fuse_sync_release(fc, ff, flags); | 452 | fuse_sync_release(ff, flags); |
466 | return PTR_ERR(file); | 453 | return PTR_ERR(file); |
467 | } | 454 | } |
468 | file->private_data = fuse_file_get(ff); | 455 | file->private_data = fuse_file_get(ff); |
@@ -1108,7 +1095,9 @@ static int fuse_dir_open(struct inode *inode, struct file *file) | |||
1108 | 1095 | ||
1109 | static int fuse_dir_release(struct inode *inode, struct file *file) | 1096 | static int fuse_dir_release(struct inode *inode, struct file *file) |
1110 | { | 1097 | { |
1111 | return fuse_release_common(inode, file, 1); | 1098 | fuse_release_common(file, FUSE_RELEASEDIR); |
1099 | |||
1100 | return 0; | ||
1112 | } | 1101 | } |
1113 | 1102 | ||
1114 | static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) | 1103 | static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 6bdaa55ae613..ab627b40c3ea 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -93,10 +93,9 @@ static void fuse_file_put(struct fuse_file *ff) | |||
93 | { | 93 | { |
94 | if (atomic_dec_and_test(&ff->count)) { | 94 | if (atomic_dec_and_test(&ff->count)) { |
95 | struct fuse_req *req = ff->reserved_req; | 95 | struct fuse_req *req = ff->reserved_req; |
96 | struct inode *inode = req->misc.release.path.dentry->d_inode; | 96 | |
97 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
98 | req->end = fuse_release_end; | 97 | req->end = fuse_release_end; |
99 | fuse_request_send_background(fc, req); | 98 | fuse_request_send_background(ff->fc, req); |
100 | kfree(ff); | 99 | kfree(ff); |
101 | } | 100 | } |
102 | } | 101 | } |
@@ -164,11 +163,20 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | |||
164 | return 0; | 163 | return 0; |
165 | } | 164 | } |
166 | 165 | ||
167 | void fuse_release_fill(struct fuse_file *ff, int flags, int opcode) | 166 | static void fuse_prepare_release(struct fuse_file *ff, int flags, int opcode) |
168 | { | 167 | { |
168 | struct fuse_conn *fc = ff->fc; | ||
169 | struct fuse_req *req = ff->reserved_req; | 169 | struct fuse_req *req = ff->reserved_req; |
170 | struct fuse_release_in *inarg = &req->misc.release.in; | 170 | struct fuse_release_in *inarg = &req->misc.release.in; |
171 | 171 | ||
172 | spin_lock(&fc->lock); | ||
173 | list_del(&ff->write_entry); | ||
174 | if (!RB_EMPTY_NODE(&ff->polled_node)) | ||
175 | rb_erase(&ff->polled_node, &fc->polled_files); | ||
176 | spin_unlock(&fc->lock); | ||
177 | |||
178 | wake_up_interruptible_sync(&ff->poll_wait); | ||
179 | |||
172 | inarg->fh = ff->fh; | 180 | inarg->fh = ff->fh; |
173 | inarg->flags = flags; | 181 | inarg->flags = flags; |
174 | req->in.h.opcode = opcode; | 182 | req->in.h.opcode = opcode; |
@@ -178,40 +186,28 @@ void fuse_release_fill(struct fuse_file *ff, int flags, int opcode) | |||
178 | req->in.args[0].value = inarg; | 186 | req->in.args[0].value = inarg; |
179 | } | 187 | } |
180 | 188 | ||
181 | int fuse_release_common(struct inode *inode, struct file *file, int isdir) | 189 | void fuse_release_common(struct file *file, int opcode) |
182 | { | 190 | { |
183 | struct fuse_conn *fc; | ||
184 | struct fuse_file *ff; | 191 | struct fuse_file *ff; |
185 | struct fuse_req *req; | 192 | struct fuse_req *req; |
186 | 193 | ||
187 | ff = file->private_data; | 194 | ff = file->private_data; |
188 | if (unlikely(!ff)) | 195 | if (unlikely(!ff)) |
189 | return 0; /* return value is ignored by VFS */ | 196 | return; |
190 | 197 | ||
191 | fc = get_fuse_conn(inode); | ||
192 | req = ff->reserved_req; | 198 | req = ff->reserved_req; |
193 | 199 | fuse_prepare_release(ff, file->f_flags, opcode); | |
194 | fuse_release_fill(ff, file->f_flags, | ||
195 | isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); | ||
196 | 200 | ||
197 | /* Hold vfsmount and dentry until release is finished */ | 201 | /* Hold vfsmount and dentry until release is finished */ |
198 | path_get(&file->f_path); | 202 | path_get(&file->f_path); |
199 | req->misc.release.path = file->f_path; | 203 | req->misc.release.path = file->f_path; |
200 | 204 | ||
201 | spin_lock(&fc->lock); | ||
202 | list_del(&ff->write_entry); | ||
203 | if (!RB_EMPTY_NODE(&ff->polled_node)) | ||
204 | rb_erase(&ff->polled_node, &fc->polled_files); | ||
205 | spin_unlock(&fc->lock); | ||
206 | |||
207 | wake_up_interruptible_sync(&ff->poll_wait); | ||
208 | /* | 205 | /* |
209 | * Normally this will send the RELEASE request, however if | 206 | * Normally this will send the RELEASE request, however if |
210 | * some asynchronous READ or WRITE requests are outstanding, | 207 | * some asynchronous READ or WRITE requests are outstanding, |
211 | * the sending will be delayed. | 208 | * the sending will be delayed. |
212 | */ | 209 | */ |
213 | fuse_file_put(ff); | 210 | fuse_file_put(ff); |
214 | return 0; | ||
215 | } | 211 | } |
216 | 212 | ||
217 | static int fuse_open(struct inode *inode, struct file *file) | 213 | static int fuse_open(struct inode *inode, struct file *file) |
@@ -221,7 +217,20 @@ static int fuse_open(struct inode *inode, struct file *file) | |||
221 | 217 | ||
222 | static int fuse_release(struct inode *inode, struct file *file) | 218 | static int fuse_release(struct inode *inode, struct file *file) |
223 | { | 219 | { |
224 | return fuse_release_common(inode, file, 0); | 220 | fuse_release_common(file, FUSE_RELEASE); |
221 | |||
222 | /* return value is ignored by VFS */ | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | void fuse_sync_release(struct fuse_file *ff, int flags) | ||
227 | { | ||
228 | WARN_ON(atomic_read(&ff->count) > 1); | ||
229 | fuse_prepare_release(ff, flags, FUSE_RELEASE); | ||
230 | ff->reserved_req->force = 1; | ||
231 | fuse_request_send(ff->fc, ff->reserved_req); | ||
232 | fuse_put_request(ff->fc, ff->reserved_req); | ||
233 | kfree(ff); | ||
225 | } | 234 | } |
226 | 235 | ||
227 | /* | 236 | /* |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 429e669d7859..ef2e1f3780b5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -535,13 +535,12 @@ struct fuse_file *fuse_file_get(struct fuse_file *ff); | |||
535 | void fuse_file_free(struct fuse_file *ff); | 535 | void fuse_file_free(struct fuse_file *ff); |
536 | void fuse_finish_open(struct inode *inode, struct file *file); | 536 | void fuse_finish_open(struct inode *inode, struct file *file); |
537 | 537 | ||
538 | /** Fill in ff->reserved_req with a RELEASE request */ | 538 | void fuse_sync_release(struct fuse_file *ff, int flags); |
539 | void fuse_release_fill(struct fuse_file *ff, int flags, int opcode); | ||
540 | 539 | ||
541 | /** | 540 | /** |
542 | * Send RELEASE or RELEASEDIR request | 541 | * Send RELEASE or RELEASEDIR request |
543 | */ | 542 | */ |
544 | int fuse_release_common(struct inode *inode, struct file *file, int isdir); | 543 | void fuse_release_common(struct file *file, int opcode); |
545 | 544 | ||
546 | /** | 545 | /** |
547 | * Send FSYNC or FSYNCDIR request | 546 | * Send FSYNC or FSYNCDIR request |