aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/fuse/dir.c21
-rw-r--r--fs/fuse/file.c49
-rw-r--r--fs/fuse/fuse_i.h5
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 */
367static 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
1109static int fuse_dir_release(struct inode *inode, struct file *file) 1096static 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
1114static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync) 1103static 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
167void fuse_release_fill(struct fuse_file *ff, int flags, int opcode) 166static 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
181int fuse_release_common(struct inode *inode, struct file *file, int isdir) 189void 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
217static int fuse_open(struct inode *inode, struct file *file) 213static 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
222static int fuse_release(struct inode *inode, struct file *file) 218static 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
226void 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);
535void fuse_file_free(struct fuse_file *ff); 535void fuse_file_free(struct fuse_file *ff);
536void fuse_finish_open(struct inode *inode, struct file *file); 536void fuse_finish_open(struct inode *inode, struct file *file);
537 537
538/** Fill in ff->reserved_req with a RELEASE request */ 538void fuse_sync_release(struct fuse_file *ff, int flags);
539void 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 */
544int fuse_release_common(struct inode *inode, struct file *file, int isdir); 543void fuse_release_common(struct file *file, int opcode);
545 544
546/** 545/**
547 * Send FSYNC or FSYNCDIR request 546 * Send FSYNC or FSYNCDIR request