background if mount is successful. '-f' and '-d' options disable
backgrounding. This fixes the "Why does my FUSE daemon hang?"
newbie complaint.
+
+ * Cache ENOSYS (function not implemented) errors on *xattr, flush
+ and fsync
2004-05-18 Miklos Szeredi <mszeredi@inf.bme.hu>
* then set the callback pointer to NULL.
*
* - fsync() has a boolean 'datasync' parameter which if TRUE then do
- * an fdatasync() operation.
+ * an fdatasync() operation. Implementing this call is optional.
*/
struct fuse_operations {
int (*getattr) (const char *, struct stat *);
fc = kmalloc(sizeof(*fc), GFP_KERNEL);
if (fc != NULL) {
+ memset(fc, 0, sizeof(*fc));
fc->sb = NULL;
fc->file = NULL;
fc->flags = 0;
if (size > FUSE_XATTR_SIZE_MAX)
return -E2BIG;
+ if (fc->no_setxattr)
+ return -EOPNOTSUPP;
+
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
inarg.flags = flags;
in.args[2].size = size;
in.args[2].value = value;
request_send(fc, &in, &out);
+ if (out.h.error == -ENOSYS) {
+ fc->no_setxattr = 1;
+ return -EOPNOTSUPP;
+ }
return out.h.error;
}
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
+ if (fc->no_getxattr)
+ return -EOPNOTSUPP;
+
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
request_send(fc, &in, &out);
if (!out.h.error)
return size ? out.args[0].size : outarg.size;
- else
+ else {
+ if (out.h.error == -ENOSYS) {
+ fc->no_getxattr = 1;
+ return -EOPNOTSUPP;
+ }
return out.h.error;
+ }
}
static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
struct fuse_getxattr_in inarg;
struct fuse_getxattr_out outarg;
+ if (fc->no_listxattr)
+ return -EOPNOTSUPP;
+
memset(&inarg, 0, sizeof(inarg));
inarg.size = size;
request_send(fc, &in, &out);
if (!out.h.error)
return size ? out.args[0].size : outarg.size;
- else
+ else {
+ if (out.h.error == -ENOSYS) {
+ fc->no_listxattr = 1;
+ return -EOPNOTSUPP;
+ }
return out.h.error;
+ }
}
static int fuse_removexattr(struct dentry *entry, const char *name)
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
+ if (fc->no_removexattr)
+ return -EOPNOTSUPP;
+
in.h.opcode = FUSE_REMOVEXATTR;
in.h.ino = inode->i_ino;
in.numargs = 1;
in.args[0].size = strlen(name) + 1;
in.args[0].value = name;
request_send(fc, &in, &out);
+ if (out.h.error == -ENOSYS) {
+ fc->no_removexattr = 1;
+ return -EOPNOTSUPP;
+ }
return out.h.error;
}
struct fuse_in in = FUSE_IN_INIT;
struct fuse_out out = FUSE_OUT_INIT;
+ if (fc->no_flush)
+ return 0;
+
in.h.opcode = FUSE_FLUSH;
in.h.ino = inode->i_ino;
request_send(fc, &in, &out);
- if (out.h.error == -ENOSYS)
+ if (out.h.error == -ENOSYS) {
+ fc->no_flush = 1;
return 0;
+ }
else
return out.h.error;
}
struct fuse_out out = FUSE_OUT_INIT;
struct fuse_fsync_in inarg;
+ if (fc->no_fsync)
+ return 0;
+
memset(&inarg, 0, sizeof(inarg));
inarg.datasync = datasync;
in.args[0].size = sizeof(inarg);
in.args[0].value = &inarg;
request_send(fc, &in, &out);
+
+ if (out.h.error == -ENOSYS) {
+ fc->no_fsync = 1;
+ return 0;
+ }
return out.h.error;
/* FIXME: need to ensure, that all write requests issued
/** The next unique request id */
int reqctr;
+
+ /** Is fsync not implemented by fs? */
+ unsigned int no_fsync : 1;
+
+ /** Is flush not implemented by fs? */
+ unsigned int no_flush : 1;
+
+ /** Is setxattr not implemented by fs? */
+ unsigned int no_setxattr : 1;
+
+ /** Is getxattr not implemented by fs? */
+ unsigned int no_getxattr : 1;
+
+ /** Is listxattr not implemented by fs? */
+ unsigned int no_listxattr : 1;
+
+ /** Is removexattr not implemented by fs? */
+ unsigned int no_removexattr : 1;
};
/** One input argument of a request */
res = -ENOENT;
path = get_path(f, in->ino);
if(path != NULL) {
- /* fsync is not mandatory, so don't return ENOSYS */
- res = 0;
+ res = -ENOSYS;
if(f->op.fsync)
res = f->op.fsync(path, inarg->datasync);
free(path);
res = -ENOENT;
path = get_path(f, in->ino);
if (path != NULL) {
- res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
+ res = -ENOSYS;
if (f->op.setxattr)
res = f->op.setxattr(path, name, value, arg->size, arg->flags);
free(path);
res = -ENOENT;
path = get_path(f, in->ino);
if (path != NULL) {
- res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
+ res = -ENOSYS;
if (f->op.getxattr)
res = f->op.getxattr(path, name, value, size);
free(path);
res = -ENOENT;
path = get_path(f, in->ino);
if (path != NULL) {
- res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
+ res = -ENOSYS;
if (f->op.listxattr)
res = f->op.listxattr(path, list, size);
free(path);
res = -ENOENT;
path = get_path(f, in->ino);
if (path != NULL) {
- res = -EOPNOTSUPP; /* or is it ENOTSUPP ??? */
+ res = -ENOSYS;
if (f->op.removexattr)
res = f->op.removexattr(path, name);
free(path);