inode(s) and file, so that FORGET and RELEASE are not sent until
userspace finishes the request.
+ * remove /{sys,proc}/fs/fuse/version, and instead add an INIT
+ request with the same information, which is more flexible,
+ simpler, works on embedded systems.
+
2004-12-16 Miklos Szeredi <miklos@szeredi.hu>
* KERNEL ABI: update interface to make it independent of type
for f in dev.c dir.c file.c inode.c util.c fuse_i.h; do
- unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -DHAVE_FS_SUBSYS -D__user -DMODULE_LICENSE $f > $destdir/fs/fuse/$f
+ unifdef -DKERNEL_2_6 -DKERNEL_2_6_6_PLUS -DKERNEL_2_6_10_PLUS -DHAVE_KERNEL_XATTR -DFS_SAFE -DMAX_LFS_FILESIZE -DFUSE_MAINLINE -DBUG_ON -D__user -DMODULE_LICENSE $f > $destdir/fs/fuse/$f
done
cp fuse_kernel.h $destdir/include/linux/fuse.h
CFLAGS="$old_cflags"
fi
-AC_MSG_CHECKING([whether fs_subsys is declared])
-if grep -q fs_subsys $kernelsrc/include/linux/fs.h; then
- AC_DEFINE(HAVE_FS_SUBSYS, 1, [Kernel defines fs_subsys])
- AC_MSG_RESULT([yes])
-else
- AC_MSG_RESULT([no])
-fi
-
AC_MSG_CHECKING([if kernel has extended attribute support])
if test -f $kernelsrc/include/linux/xattr.h; then
AC_DEFINE(HAVE_KERNEL_XATTR, 1, [Kernel has xattr support])
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/uio.h>
-#ifdef KERNEL_2_6
-#include <linux/kobject.h>
-#else
-#include <linux/proc_fs.h>
-#endif
#include <linux/miscdevice.h>
#include <linux/pagemap.h>
#include <linux/file.h>
{
if (down_interruptible(&fc->outstanding_sem))
return NULL;
- return do_get_request(fc);
+ return do_get_request(fc);
}
struct fuse_req *fuse_get_request_nonint(struct fuse_conn *fc)
fput(req->file);
}
wake_up(&req->waitq);
+ if (req->in.h.opcode == FUSE_INIT) {
+ int i;
+ /* up() one less than FUSE_MAX_OUTSTANDING, because
+ fuse_putback_request() will also do an up() */
+ for (i = 1; i < FUSE_MAX_OUTSTANDING; i++)
+ up(&fc->outstanding_sem);
+ }
if (putback)
fuse_putback_request(fc, req);
}
request_send_nowait(fc, req);
}
+void fuse_send_init(struct fuse_conn *fc)
+{
+ /* This is called from fuse_read_super() so there's guaranteed
+ to be a request available */
+ struct fuse_req *req = do_get_request(fc);
+ struct fuse_init_in_out *arg = &req->misc.init_in_out;
+ arg->major = FUSE_KERNEL_VERSION;
+ arg->minor = FUSE_KERNEL_MINOR_VERSION;
+ req->in.h.opcode = FUSE_INIT;
+ req->in.numargs = 1;
+ req->in.args[0].size = sizeof(*arg);
+ req->in.args[0].value = arg;
+ req->out.numargs = 1;
+ req->out.args[0].size = sizeof(*arg);
+ req->out.args[0].value = arg;
+ request_send_background(fc, req);
+}
+
static inline int lock_request(struct fuse_req *req)
{
int err = 0;
.release = fuse_dev_release,
};
-#ifdef KERNEL_2_6
-#ifndef HAVE_FS_SUBSYS
-static decl_subsys(fs, NULL, NULL);
-#endif
-static decl_subsys(fuse, NULL, NULL);
-
-static ssize_t version_show(struct subsystem *subsys, char *buf)
-{
- return sprintf(buf, "%i.%i\n", FUSE_KERNEL_VERSION,
- FUSE_KERNEL_MINOR_VERSION);
-}
-static struct subsys_attribute fuse_attr_version = __ATTR_RO(version);
-
-static int __init fuse_version_init(void)
-{
- int err;
-
-#ifndef HAVE_FS_SUBSYS
- subsystem_register(&fs_subsys);
-#endif
- kset_set_kset_s(&fuse_subsys, fs_subsys);
- err = subsystem_register(&fuse_subsys);
- if (err)
- return err;
- err = subsys_create_file(&fuse_subsys, &fuse_attr_version);
- if (err) {
- subsystem_unregister(&fuse_subsys);
-#ifndef HAVE_FS_SUBSYS
- subsystem_unregister(&fs_subsys);
-#endif
- return err;
- }
- return 0;
-}
-
-static void fuse_version_clean(void)
-{
- subsys_remove_file(&fuse_subsys, &fuse_attr_version);
- subsystem_unregister(&fuse_subsys);
-#ifndef HAVE_FS_SUBSYS
- subsystem_unregister(&fs_subsys);
-#endif
-}
-#else
-static struct proc_dir_entry *proc_fs_fuse;
-
-static int read_version(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- char *s = page;
- s += sprintf(s, "%i.%i\n", FUSE_KERNEL_VERSION,
- FUSE_KERNEL_MINOR_VERSION);
- return s - page;
-}
-
-static int fuse_version_init(void)
-{
- proc_fs_fuse = proc_mkdir("fuse", proc_root_fs);
- if (proc_fs_fuse) {
- struct proc_dir_entry *de;
-
- de = create_proc_entry("version", S_IFREG | 0444, proc_fs_fuse);
- if (de) {
- de->owner = THIS_MODULE;
- de->read_proc = read_version;
- }
- }
- return 0;
-}
-
-static void fuse_version_clean(void)
-{
- if (proc_fs_fuse) {
- remove_proc_entry("version", proc_fs_fuse);
- remove_proc_entry("fuse", proc_root_fs);
- }
-}
-#endif
-
static struct miscdevice fuse_miscdevice = {
.minor = FUSE_MINOR,
.name = "fuse",
int __init fuse_dev_init(void)
{
- int err;
- err = fuse_version_init();
- if (err)
- goto out;
-
- err = -ENOMEM;
+ int err = -ENOMEM;
fuse_req_cachep = kmem_cache_create("fuser_request",
sizeof(struct fuse_req),
0, 0, NULL, NULL);
if (!fuse_req_cachep)
- goto out_version_clean;
+ goto out;
err = misc_register(&fuse_miscdevice);
if (err)
out_cache_clean:
kmem_cache_destroy(fuse_req_cachep);
- out_version_clean:
- fuse_version_clean();
out:
return err;
}
{
misc_deregister(&fuse_miscdevice);
kmem_cache_destroy(fuse_req_cachep);
- fuse_version_clean();
}
union {
struct fuse_forget_in forget_in;
struct fuse_release_in release_in;
+ struct fuse_init_in_out init_in_out;
} misc;
/** page vector */
* Invalidate inode attributes
*/
void fuse_invalidate_attr(struct inode *inode);
+
+/**
+ * Send the INIT message
+ */
+void fuse_send_init(struct fuse_conn *fc);
FUSE_WRITE = 16,
FUSE_STATFS = 17,
FUSE_RELEASE = 18,
- /*FUSE_INVALIDATE = 19,*/
FUSE_FSYNC = 20,
FUSE_SETXATTR = 21,
FUSE_GETXATTR = 22,
FUSE_LISTXATTR = 23,
FUSE_REMOVEXATTR = 24,
FUSE_FLUSH = 25,
+ FUSE_INIT = 26
};
/* Conservative buffer size for the client */
__u32 size;
};
+struct fuse_init_in_out {
+ __u32 major;
+ __u32 minor;
+};
+
struct fuse_in_header {
__u32 len;
__u32 opcode;
INIT_LIST_HEAD(&fc->pending);
INIT_LIST_HEAD(&fc->processing);
INIT_LIST_HEAD(&fc->unused_list);
- sema_init(&fc->outstanding_sem, FUSE_MAX_OUTSTANDING);
+ sema_init(&fc->outstanding_sem, 0);
for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) {
struct fuse_req *req = fuse_request_alloc();
if (!req) {
free_conn(fc);
return NULL;
}
- req->preallocated = 1;
list_add(&req->list, &fc->unused_list);
}
#ifdef KERNEL_2_6
iput(root);
goto err;
}
-
+ fuse_send_init(fc);
return 0;
err:
case FUSE_GETXATTR: return "GETXATTR";
case FUSE_LISTXATTR: return "LISTXATTR";
case FUSE_REMOVEXATTR: return "REMOVEXATTR";
+ case FUSE_INIT: return "INIT";
default: return "???";
}
}
send_reply(f, in, res, NULL, 0);
}
+static void do_init(struct fuse *f, struct fuse_in_header *in,
+ struct fuse_init_in_out *arg)
+{
+ struct fuse_init_in_out outarg;
+ if (f->flags & FUSE_DEBUG) {
+ printf(" INIT: %u.%u\n", arg->major, arg->minor);
+ fflush(stdout);
+ }
+ f->got_init = 1;
+ memset(&outarg, 0, sizeof(outarg));
+ outarg.major = FUSE_KERNEL_VERSION;
+ outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+ send_reply(f, in, 0, &outarg, sizeof(outarg));
+}
static void free_cmd(struct fuse_cmd *cmd)
{
fflush(stdout);
}
+ if (!f->got_init && in->opcode != FUSE_INIT) {
+ /* Old kernel version probably */
+ send_reply(f, in, -EPROTO, NULL, 0);
+ goto out;
+ }
+
ctx->fuse = f;
ctx->uid = in->uid;
ctx->gid = in->gid;
do_removexattr(f, in, (char *) inarg);
break;
+ case FUSE_INIT:
+ do_init(f, in, (struct fuse_init_in_out *) inarg);
+ break;
+
default:
send_reply(f, in, -ENOSYS, NULL, 0);
}
+ out:
free_cmd(cmd);
}
fuse_getcontext = func;
}
-static int check_version(struct fuse *f)
-{
- int res;
- const char *version_file = FUSE_VERSION_FILE_NEW;
- FILE *vf = fopen(version_file, "r");
- if (vf == NULL) {
- version_file = FUSE_VERSION_FILE_OLD;
- vf = fopen(version_file, "r");
- if (vf == NULL) {
- struct stat tmp;
- if (stat(FUSE_DEV_OLD, &tmp) != -1) {
- fprintf(stderr, "fuse: kernel interface too old, need >= %i.%i\n",
- FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
- return -1;
- } else {
- fprintf(stderr, "fuse: warning: version of kernel interface unknown\n");
- return 0;
- }
- }
- }
- res = fscanf(vf, "%i.%i", &f->majorver, &f->minorver);
- fclose(vf);
- if (res != 2) {
- fprintf(stderr, "fuse: error reading %s\n", version_file);
- return -1;
- }
- if (f->majorver != FUSE_KERNEL_VERSION) {
- fprintf(stderr, "fuse: bad kernel interface major version: needs %i\n",
- FUSE_KERNEL_VERSION);
- return -1;
- }
- if (f->minorver < FUSE_KERNEL_MINOR_VERSION_NEED) {
- fprintf(stderr, "fuse: kernel interface too old: need >= %i.%i\n",
- FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
- return -1;
- }
-
- return 0;
-}
-
-
int fuse_is_lib_option(const char *opt)
{
if (strcmp(opt, "debug") == 0 ||
goto out;
}
- if (check_version(f) == -1)
- goto out_free;
-
if (parse_lib_opts(f, opts) == -1)
goto out_free;
int numworker;
int numavail;
volatile int exited;
- int majorver;
- int minorver;
+ int got_init;
};
struct fuse *fuse_new_common(int fd, const char *opts,
#define FUSE_DEV_OLD "/proc/fs/fuse/dev"
#define FUSE_DEV_NEW "/dev/fuse"
#define FUSE_VERSION_FILE_OLD "/proc/fs/fuse/version"
-#define FUSE_VERSION_FILE_NEW "/sys/fs/fuse/version"
#define FUSE_MAJOR 10
#define FUSE_MINOR 229
int majorver;
int minorver;
const char *version_file;
- int isold = 0;
FILE *vf;
- if (strcmp(dev, FUSE_DEV_OLD) == 0)
- isold = 1;
+ if (strcmp(dev, FUSE_DEV_OLD) != 0)
+ return 0;
- version_file = FUSE_VERSION_FILE_NEW;
+ version_file = FUSE_VERSION_FILE_OLD;
vf = fopen(version_file, "r");
if (vf == NULL) {
- version_file = FUSE_VERSION_FILE_OLD;
- vf = fopen(version_file, "r");
- if (vf == NULL) {
- if (isold) {
- fprintf(stderr, "%s: kernel interface too old\n", progname);
- return -1;
- } else
- return 0;
- }
+ fprintf(stderr, "%s: kernel interface too old\n", progname);
+ return -1;
}
res = fscanf(vf, "%i.%i", &majorver, &minorver);
fclose(vf);
fprintf(stderr, "%s: error reading %s\n", progname, version_file);
return -1;
}
- if (majorver < 3) {
+ if (majorver < 3) {
fprintf(stderr, "%s: kernel interface too old\n", progname);
return -1;
}