+2004-07-06 Miklos Szeredi <mszeredi@inf.bme.hu>
+
+ * Make RELEASE method synchronous. This fixes an abort in libfuse
+ if FORGET was received earlier than the last RELEASE (bug found
+ with the LTP test-suite)
+
2004-07-04 Miklos Szeredi <mszeredi@inf.bme.hu>
* Fix race between truncate and writepage (fsx-linux now runs
FUSE_STATFS = 17,
FUSE_RELEASE = 18, /* no reply */
FUSE_INVALIDATE = 19, /* user initiated */
- FUSE_FSYNC = 20
+ FUSE_FSYNC = 20,
+ FUSE_RELEASE2 = 21 /* reply needed after all */
};
/* Conservative buffer size for the client */
fc->file = NULL;
fc->flags = 0;
fc->uid = 0;
+ fc->oldrelease = 0;
init_waitqueue_head(&fc->waitq);
INIT_LIST_HEAD(&fc->pending);
INIT_LIST_HEAD(&fc->processing);
#endif
}
-static int fuse_release(struct inode *inode, struct file *file)
+static int fuse_release_old(struct inode *inode, struct file *file)
{
struct fuse_conn *fc = INO_FC(inode);
struct fuse_in *in = NULL;
struct fuse_open_in *inarg = NULL;
unsigned int s = sizeof(struct fuse_in) + sizeof(struct fuse_open_in);
- if(file->f_mode & FMODE_WRITE)
- fuse_sync_inode(inode);
-
in = kmalloc(s, GFP_NOFS);
if(!in)
return -ENOMEM;
return 0;
}
+static int fuse_release(struct inode *inode, struct file *file)
+{
+ struct fuse_conn *fc = INO_FC(inode);
+ struct fuse_in in = FUSE_IN_INIT;
+ struct fuse_out out = FUSE_OUT_INIT;
+ struct fuse_open_in inarg;
+
+ if(file->f_mode & FMODE_WRITE)
+ fuse_sync_inode(inode);
+
+ if (fc->oldrelease)
+ return fuse_release_old(inode, file);
+
+ memset(&inarg, 0, sizeof(inarg));
+ inarg.flags = file->f_flags & ~O_EXCL;
+
+ in.h.opcode = FUSE_RELEASE2;
+ in.h.ino = inode->i_ino;
+ in.numargs = 1;
+ in.args[0].size = sizeof(inarg);
+ in.args[0].value = &inarg;
+ request_send(fc, &in, &out);
+ if (out.h.error == -ENOSYS) {
+ fc->oldrelease = 1;
+ return fuse_release_old(inode, file);
+ }
+ return 0;
+}
+
static int fuse_fsync(struct file *file, struct dentry *de, int datasync)
{
struct inode *inode = de->d_inode;
/** The fuse mount flags for this mount */
unsigned int flags;
+ /** Is the new (synchronous) release not supported by
+ userspace? */
+ unsigned int oldrelease;
+
/** Readers of the connection are waiting on this */
wait_queue_head_t waitq;
case FUSE_STATFS: return "STATFS";
case FUSE_RELEASE: return "RELEASE";
case FUSE_FSYNC: return "FSYNC";
+ case FUSE_RELEASE2: return "RELEASE2";
default: return "???";
}
}
}
static void do_release(struct fuse *f, struct fuse_in_header *in,
- struct fuse_open_in *arg)
+ struct fuse_open_in *arg, int reply)
{
char *path;
f->op.release(path, arg->flags);
free(path);
}
+ if (reply)
+ send_reply(f, in, 0, NULL, 0);
}
static void do_read(struct fuse *f, struct fuse_in_header *in,
break;
case FUSE_RELEASE:
- do_release(f, in, (struct fuse_open_in *) inarg);
+ do_release(f, in, (struct fuse_open_in *) inarg, 0);
+ break;
+
+ case FUSE_RELEASE2:
+ do_release(f, in, (struct fuse_open_in *) inarg, 1);
break;
case FUSE_READ: