diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 56 |
1 files changed, 30 insertions, 26 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8d7546e832e8..72a74cde6de8 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | FUSE: Filesystem in Userspace | 2 | FUSE: Filesystem in Userspace |
3 | Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu> | 3 | Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> |
4 | 4 | ||
5 | This program can be distributed under the terms of the GNU GPL. | 5 | This program can be distributed under the terms of the GNU GPL. |
6 | See the file COPYING. | 6 | See the file COPYING. |
@@ -79,7 +79,6 @@ static void fuse_lookup_init(struct fuse_req *req, struct inode *dir, | |||
79 | { | 79 | { |
80 | req->in.h.opcode = FUSE_LOOKUP; | 80 | req->in.h.opcode = FUSE_LOOKUP; |
81 | req->in.h.nodeid = get_node_id(dir); | 81 | req->in.h.nodeid = get_node_id(dir); |
82 | req->inode = dir; | ||
83 | req->in.numargs = 1; | 82 | req->in.numargs = 1; |
84 | req->in.args[0].size = entry->d_name.len + 1; | 83 | req->in.args[0].size = entry->d_name.len + 1; |
85 | req->in.args[0].value = entry->d_name.name; | 84 | req->in.args[0].value = entry->d_name.name; |
@@ -225,6 +224,20 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
225 | } | 224 | } |
226 | 225 | ||
227 | /* | 226 | /* |
227 | * Synchronous release for the case when something goes wrong in CREATE_OPEN | ||
228 | */ | ||
229 | static void fuse_sync_release(struct fuse_conn *fc, struct fuse_file *ff, | ||
230 | u64 nodeid, int flags) | ||
231 | { | ||
232 | struct fuse_req *req; | ||
233 | |||
234 | req = fuse_release_fill(ff, nodeid, flags, FUSE_RELEASE); | ||
235 | req->force = 1; | ||
236 | request_send(fc, req); | ||
237 | fuse_put_request(fc, req); | ||
238 | } | ||
239 | |||
240 | /* | ||
228 | * Atomic create+open operation | 241 | * Atomic create+open operation |
229 | * | 242 | * |
230 | * If the filesystem doesn't support this, then fall back to separate | 243 | * If the filesystem doesn't support this, then fall back to separate |
@@ -237,6 +250,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
237 | struct inode *inode; | 250 | struct inode *inode; |
238 | struct fuse_conn *fc = get_fuse_conn(dir); | 251 | struct fuse_conn *fc = get_fuse_conn(dir); |
239 | struct fuse_req *req; | 252 | struct fuse_req *req; |
253 | struct fuse_req *forget_req; | ||
240 | struct fuse_open_in inarg; | 254 | struct fuse_open_in inarg; |
241 | struct fuse_open_out outopen; | 255 | struct fuse_open_out outopen; |
242 | struct fuse_entry_out outentry; | 256 | struct fuse_entry_out outentry; |
@@ -247,9 +261,14 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
247 | if (fc->no_create) | 261 | if (fc->no_create) |
248 | return -ENOSYS; | 262 | return -ENOSYS; |
249 | 263 | ||
264 | forget_req = fuse_get_req(fc); | ||
265 | if (IS_ERR(forget_req)) | ||
266 | return PTR_ERR(forget_req); | ||
267 | |||
250 | req = fuse_get_req(fc); | 268 | req = fuse_get_req(fc); |
269 | err = PTR_ERR(req); | ||
251 | if (IS_ERR(req)) | 270 | if (IS_ERR(req)) |
252 | return PTR_ERR(req); | 271 | goto out_put_forget_req; |
253 | 272 | ||
254 | err = -ENOMEM; | 273 | err = -ENOMEM; |
255 | ff = fuse_file_alloc(); | 274 | ff = fuse_file_alloc(); |
@@ -262,7 +281,6 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
262 | inarg.mode = mode; | 281 | inarg.mode = mode; |
263 | req->in.h.opcode = FUSE_CREATE; | 282 | req->in.h.opcode = FUSE_CREATE; |
264 | req->in.h.nodeid = get_node_id(dir); | 283 | req->in.h.nodeid = get_node_id(dir); |
265 | req->inode = dir; | ||
266 | req->in.numargs = 2; | 284 | req->in.numargs = 2; |
267 | req->in.args[0].size = sizeof(inarg); | 285 | req->in.args[0].size = sizeof(inarg); |
268 | req->in.args[0].value = &inarg; | 286 | req->in.args[0].value = &inarg; |
@@ -285,25 +303,23 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
285 | if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) | 303 | if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid)) |
286 | goto out_free_ff; | 304 | goto out_free_ff; |
287 | 305 | ||
306 | fuse_put_request(fc, req); | ||
288 | inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, | 307 | inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, |
289 | &outentry.attr); | 308 | &outentry.attr); |
290 | err = -ENOMEM; | ||
291 | if (!inode) { | 309 | if (!inode) { |
292 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 310 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
293 | ff->fh = outopen.fh; | 311 | ff->fh = outopen.fh; |
294 | /* Special release, with inode = NULL, this will | 312 | fuse_sync_release(fc, ff, outentry.nodeid, flags); |
295 | trigger a 'forget' request when the release is | 313 | fuse_send_forget(fc, forget_req, outentry.nodeid, 1); |
296 | complete */ | 314 | return -ENOMEM; |
297 | fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0); | ||
298 | goto out_put_request; | ||
299 | } | 315 | } |
300 | fuse_put_request(fc, req); | 316 | fuse_put_request(fc, forget_req); |
301 | d_instantiate(entry, inode); | 317 | d_instantiate(entry, inode); |
302 | fuse_change_timeout(entry, &outentry); | 318 | fuse_change_timeout(entry, &outentry); |
303 | file = lookup_instantiate_filp(nd, entry, generic_file_open); | 319 | file = lookup_instantiate_filp(nd, entry, generic_file_open); |
304 | if (IS_ERR(file)) { | 320 | if (IS_ERR(file)) { |
305 | ff->fh = outopen.fh; | 321 | ff->fh = outopen.fh; |
306 | fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0); | 322 | fuse_sync_release(fc, ff, outentry.nodeid, flags); |
307 | return PTR_ERR(file); | 323 | return PTR_ERR(file); |
308 | } | 324 | } |
309 | fuse_finish_open(inode, file, ff, &outopen); | 325 | fuse_finish_open(inode, file, ff, &outopen); |
@@ -313,6 +329,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
313 | fuse_file_free(ff); | 329 | fuse_file_free(ff); |
314 | out_put_request: | 330 | out_put_request: |
315 | fuse_put_request(fc, req); | 331 | fuse_put_request(fc, req); |
332 | out_put_forget_req: | ||
333 | fuse_put_request(fc, forget_req); | ||
316 | return err; | 334 | return err; |
317 | } | 335 | } |
318 | 336 | ||
@@ -328,7 +346,6 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
328 | int err; | 346 | int err; |
329 | 347 | ||
330 | req->in.h.nodeid = get_node_id(dir); | 348 | req->in.h.nodeid = get_node_id(dir); |
331 | req->inode = dir; | ||
332 | req->out.numargs = 1; | 349 | req->out.numargs = 1; |
333 | req->out.args[0].size = sizeof(outarg); | 350 | req->out.args[0].size = sizeof(outarg); |
334 | req->out.args[0].value = &outarg; | 351 | req->out.args[0].value = &outarg; |
@@ -448,7 +465,6 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry) | |||
448 | 465 | ||
449 | req->in.h.opcode = FUSE_UNLINK; | 466 | req->in.h.opcode = FUSE_UNLINK; |
450 | req->in.h.nodeid = get_node_id(dir); | 467 | req->in.h.nodeid = get_node_id(dir); |
451 | req->inode = dir; | ||
452 | req->in.numargs = 1; | 468 | req->in.numargs = 1; |
453 | req->in.args[0].size = entry->d_name.len + 1; | 469 | req->in.args[0].size = entry->d_name.len + 1; |
454 | req->in.args[0].value = entry->d_name.name; | 470 | req->in.args[0].value = entry->d_name.name; |
@@ -480,7 +496,6 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry) | |||
480 | 496 | ||
481 | req->in.h.opcode = FUSE_RMDIR; | 497 | req->in.h.opcode = FUSE_RMDIR; |
482 | req->in.h.nodeid = get_node_id(dir); | 498 | req->in.h.nodeid = get_node_id(dir); |
483 | req->inode = dir; | ||
484 | req->in.numargs = 1; | 499 | req->in.numargs = 1; |
485 | req->in.args[0].size = entry->d_name.len + 1; | 500 | req->in.args[0].size = entry->d_name.len + 1; |
486 | req->in.args[0].value = entry->d_name.name; | 501 | req->in.args[0].value = entry->d_name.name; |
@@ -510,8 +525,6 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent, | |||
510 | inarg.newdir = get_node_id(newdir); | 525 | inarg.newdir = get_node_id(newdir); |
511 | req->in.h.opcode = FUSE_RENAME; | 526 | req->in.h.opcode = FUSE_RENAME; |
512 | req->in.h.nodeid = get_node_id(olddir); | 527 | req->in.h.nodeid = get_node_id(olddir); |
513 | req->inode = olddir; | ||
514 | req->inode2 = newdir; | ||
515 | req->in.numargs = 3; | 528 | req->in.numargs = 3; |
516 | req->in.args[0].size = sizeof(inarg); | 529 | req->in.args[0].size = sizeof(inarg); |
517 | req->in.args[0].value = &inarg; | 530 | req->in.args[0].value = &inarg; |
@@ -558,7 +571,6 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, | |||
558 | memset(&inarg, 0, sizeof(inarg)); | 571 | memset(&inarg, 0, sizeof(inarg)); |
559 | inarg.oldnodeid = get_node_id(inode); | 572 | inarg.oldnodeid = get_node_id(inode); |
560 | req->in.h.opcode = FUSE_LINK; | 573 | req->in.h.opcode = FUSE_LINK; |
561 | req->inode2 = inode; | ||
562 | req->in.numargs = 2; | 574 | req->in.numargs = 2; |
563 | req->in.args[0].size = sizeof(inarg); | 575 | req->in.args[0].size = sizeof(inarg); |
564 | req->in.args[0].value = &inarg; | 576 | req->in.args[0].value = &inarg; |
@@ -587,7 +599,6 @@ int fuse_do_getattr(struct inode *inode) | |||
587 | 599 | ||
588 | req->in.h.opcode = FUSE_GETATTR; | 600 | req->in.h.opcode = FUSE_GETATTR; |
589 | req->in.h.nodeid = get_node_id(inode); | 601 | req->in.h.nodeid = get_node_id(inode); |
590 | req->inode = inode; | ||
591 | req->out.numargs = 1; | 602 | req->out.numargs = 1; |
592 | req->out.args[0].size = sizeof(arg); | 603 | req->out.args[0].size = sizeof(arg); |
593 | req->out.args[0].value = &arg; | 604 | req->out.args[0].value = &arg; |
@@ -679,7 +690,6 @@ static int fuse_access(struct inode *inode, int mask) | |||
679 | inarg.mask = mask; | 690 | inarg.mask = mask; |
680 | req->in.h.opcode = FUSE_ACCESS; | 691 | req->in.h.opcode = FUSE_ACCESS; |
681 | req->in.h.nodeid = get_node_id(inode); | 692 | req->in.h.nodeid = get_node_id(inode); |
682 | req->inode = inode; | ||
683 | req->in.numargs = 1; | 693 | req->in.numargs = 1; |
684 | req->in.args[0].size = sizeof(inarg); | 694 | req->in.args[0].size = sizeof(inarg); |
685 | req->in.args[0].value = &inarg; | 695 | req->in.args[0].value = &inarg; |
@@ -820,7 +830,6 @@ static char *read_link(struct dentry *dentry) | |||
820 | } | 830 | } |
821 | req->in.h.opcode = FUSE_READLINK; | 831 | req->in.h.opcode = FUSE_READLINK; |
822 | req->in.h.nodeid = get_node_id(inode); | 832 | req->in.h.nodeid = get_node_id(inode); |
823 | req->inode = inode; | ||
824 | req->out.argvar = 1; | 833 | req->out.argvar = 1; |
825 | req->out.numargs = 1; | 834 | req->out.numargs = 1; |
826 | req->out.args[0].size = PAGE_SIZE - 1; | 835 | req->out.args[0].size = PAGE_SIZE - 1; |
@@ -939,7 +948,6 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
939 | iattr_to_fattr(attr, &inarg); | 948 | iattr_to_fattr(attr, &inarg); |
940 | req->in.h.opcode = FUSE_SETATTR; | 949 | req->in.h.opcode = FUSE_SETATTR; |
941 | req->in.h.nodeid = get_node_id(inode); | 950 | req->in.h.nodeid = get_node_id(inode); |
942 | req->inode = inode; | ||
943 | req->in.numargs = 1; | 951 | req->in.numargs = 1; |
944 | req->in.args[0].size = sizeof(inarg); | 952 | req->in.args[0].size = sizeof(inarg); |
945 | req->in.args[0].value = &inarg; | 953 | req->in.args[0].value = &inarg; |
@@ -1002,7 +1010,6 @@ static int fuse_setxattr(struct dentry *entry, const char *name, | |||
1002 | inarg.flags = flags; | 1010 | inarg.flags = flags; |
1003 | req->in.h.opcode = FUSE_SETXATTR; | 1011 | req->in.h.opcode = FUSE_SETXATTR; |
1004 | req->in.h.nodeid = get_node_id(inode); | 1012 | req->in.h.nodeid = get_node_id(inode); |
1005 | req->inode = inode; | ||
1006 | req->in.numargs = 3; | 1013 | req->in.numargs = 3; |
1007 | req->in.args[0].size = sizeof(inarg); | 1014 | req->in.args[0].size = sizeof(inarg); |
1008 | req->in.args[0].value = &inarg; | 1015 | req->in.args[0].value = &inarg; |
@@ -1041,7 +1048,6 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, | |||
1041 | inarg.size = size; | 1048 | inarg.size = size; |
1042 | req->in.h.opcode = FUSE_GETXATTR; | 1049 | req->in.h.opcode = FUSE_GETXATTR; |
1043 | req->in.h.nodeid = get_node_id(inode); | 1050 | req->in.h.nodeid = get_node_id(inode); |
1044 | req->inode = inode; | ||
1045 | req->in.numargs = 2; | 1051 | req->in.numargs = 2; |
1046 | req->in.args[0].size = sizeof(inarg); | 1052 | req->in.args[0].size = sizeof(inarg); |
1047 | req->in.args[0].value = &inarg; | 1053 | req->in.args[0].value = &inarg; |
@@ -1091,7 +1097,6 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) | |||
1091 | inarg.size = size; | 1097 | inarg.size = size; |
1092 | req->in.h.opcode = FUSE_LISTXATTR; | 1098 | req->in.h.opcode = FUSE_LISTXATTR; |
1093 | req->in.h.nodeid = get_node_id(inode); | 1099 | req->in.h.nodeid = get_node_id(inode); |
1094 | req->inode = inode; | ||
1095 | req->in.numargs = 1; | 1100 | req->in.numargs = 1; |
1096 | req->in.args[0].size = sizeof(inarg); | 1101 | req->in.args[0].size = sizeof(inarg); |
1097 | req->in.args[0].value = &inarg; | 1102 | req->in.args[0].value = &inarg; |
@@ -1135,7 +1140,6 @@ static int fuse_removexattr(struct dentry *entry, const char *name) | |||
1135 | 1140 | ||
1136 | req->in.h.opcode = FUSE_REMOVEXATTR; | 1141 | req->in.h.opcode = FUSE_REMOVEXATTR; |
1137 | req->in.h.nodeid = get_node_id(inode); | 1142 | req->in.h.nodeid = get_node_id(inode); |
1138 | req->inode = inode; | ||
1139 | req->in.numargs = 1; | 1143 | req->in.numargs = 1; |
1140 | req->in.args[0].size = strlen(name) + 1; | 1144 | req->in.args[0].size = strlen(name) + 1; |
1141 | req->in.args[0].value = name; | 1145 | req->in.args[0].value = name; |