From 63b8c1c99797322bb873803b0296ac302d5de4d2 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 3 Jun 2004 14:45:04 +0000 Subject: [PATCH] cache ENOSYS on some optional functions --- ChangeLog | 3 +++ include/fuse.h | 2 +- kernel/dev.c | 1 + kernel/dir.c | 34 ++++++++++++++++++++++++++++++++-- kernel/file.c | 15 ++++++++++++++- kernel/fuse_i.h | 18 ++++++++++++++++++ lib/fuse.c | 11 +++++------ 7 files changed, 74 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3d32987..da590de 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ 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 diff --git a/include/fuse.h b/include/fuse.h index e3e4333..d298cb3 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -103,7 +103,7 @@ typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type); * 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 *); diff --git a/kernel/dev.c b/kernel/dev.c index afc9f4c..af20de8 100644 --- a/kernel/dev.c +++ b/kernel/dev.c @@ -543,6 +543,7 @@ static struct fuse_conn *new_conn(void) fc = kmalloc(sizeof(*fc), GFP_KERNEL); if (fc != NULL) { + memset(fc, 0, sizeof(*fc)); fc->sb = NULL; fc->file = NULL; fc->flags = 0; diff --git a/kernel/dir.c b/kernel/dir.c index 110a472..e941e3e 100644 --- a/kernel/dir.c +++ b/kernel/dir.c @@ -783,6 +783,9 @@ static int fuse_setxattr(struct dentry *entry, const char *name, 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; @@ -797,6 +800,10 @@ static int fuse_setxattr(struct dentry *entry, const char *name, 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; } @@ -810,6 +817,9 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, struct fuse_getxattr_in inarg; struct fuse_getxattr_out outarg; + if (fc->no_getxattr) + return -EOPNOTSUPP; + memset(&inarg, 0, sizeof(inarg)); inarg.size = size; @@ -833,8 +843,13 @@ static ssize_t fuse_getxattr(struct dentry *entry, const char *name, 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) @@ -846,6 +861,9 @@ 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; @@ -867,8 +885,13 @@ static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t 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) @@ -878,12 +901,19 @@ 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; } diff --git a/kernel/file.c b/kernel/file.c index c9a44fd..2067bd7 100644 --- a/kernel/file.c +++ b/kernel/file.c @@ -99,11 +99,16 @@ static int fuse_flush(struct file *file) 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; } @@ -116,6 +121,9 @@ static int fuse_fsync(struct file *file, struct dentry *de, int datasync) 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; @@ -125,6 +133,11 @@ static int fuse_fsync(struct file *file, struct dentry *de, int 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 diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 1299139..d5943a9 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -96,6 +96,24 @@ struct fuse_conn { /** 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 */ diff --git a/lib/fuse.c b/lib/fuse.c index 255a24b..05d9713 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -980,8 +980,7 @@ static void do_fsync(struct fuse *f, struct fuse_in_header *in, 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); @@ -1000,7 +999,7 @@ static void do_setxattr(struct fuse *f, struct fuse_in_header *in, 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); @@ -1017,7 +1016,7 @@ static int common_getxattr(struct fuse *f, struct fuse_in_header *in, 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); @@ -1081,7 +1080,7 @@ static int common_listxattr(struct fuse *f, struct fuse_in_header *in, 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); @@ -1142,7 +1141,7 @@ static void do_removexattr(struct fuse *f, struct fuse_in_header *in, 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); -- 2.30.2