From: Miklos Szeredi Date: Tue, 13 Apr 2004 10:49:14 +0000 (+0000) Subject: text mount options X-Git-Tag: fuse_1_9~69 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=7f6bc8968ff6ca488991b0c5b1b9c4846dc1ccda;p=qemu-gpiodev%2Flibfuse.git text mount options --- diff --git a/include/linux/fuse.h b/include/linux/fuse.h index bee2930..63cf167 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -23,42 +23,6 @@ /** The file containing the version in the form MAJOR.MINOR */ #define FUSE_VERSION_FILE "/proc/fs/fuse/version" -/** Data passed to mount */ -struct fuse_mount_data { - /** The control file descriptor */ - int fd; - - /** The file type of the root inode */ - unsigned int rootmode; - - /** The user ID of the user initiating this mount */ - unsigned int uid; - - /** FUSE specific mount flags */ - unsigned int flags; -}; - -/* FUSE mount flags: */ - -/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem -module will check permissions based on the file mode. Otherwise no -permission checking is done in the kernel */ -#define FUSE_DEFAULT_PERMISSIONS (1 << 0) - -/** If the FUSE_ALLOW_OTHER flag is given, then not only the user - doing the mount will be allowed to access the filesystem */ -#define FUSE_ALLOW_OTHER (1 << 1) - -/** If the FUSE_KERNEL_CACHE flag is given, then files will be cached - until the INVALIDATE operation is invoked */ -#define FUSE_KERNEL_CACHE (1 << 2) - -/** Allow FUSE to combine reads into 64k chunks. This is useful if - the filesystem is better at handling large chunks. NOTE: in - current implementation the raw throughput is worse for large reads - than for small. */ -#define FUSE_LARGE_READ (1 << 3) - struct fuse_attr { unsigned int mode; unsigned int nlink; diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index 6f064fe..1299139 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -43,6 +43,25 @@ #define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT) +/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem +module will check permissions based on the file mode. Otherwise no +permission checking is done in the kernel */ +#define FUSE_DEFAULT_PERMISSIONS (1 << 0) + +/** If the FUSE_ALLOW_OTHER flag is given, then not only the user + doing the mount will be allowed to access the filesystem */ +#define FUSE_ALLOW_OTHER (1 << 1) + +/** If the FUSE_KERNEL_CACHE flag is given, then files will be cached + until the INVALIDATE operation is invoked */ +#define FUSE_KERNEL_CACHE (1 << 2) + +/** Allow FUSE to combine reads into 64k chunks. This is useful if + the filesystem is better at handling large chunks. NOTE: in + current implementation the raw throughput is worse for large reads + than for small. */ +#define FUSE_LARGE_READ (1 << 3) + /** * A Fuse connection. * diff --git a/kernel/inode.c b/kernel/inode.c index 17c0f60..a719ad9 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -12,7 +12,10 @@ #include #include #include +#include #include +#include +#include #ifdef KERNEL_2_6 #include #endif @@ -26,9 +29,13 @@ #ifndef FS_SAFE #define FS_SAFE 0 #endif -#ifndef FS_BINARY_MOUNTDATA -#define FS_BINARY_MOUNTDATA 0 -#endif + +struct fuse_mount_data { + int fd; + unsigned int rootmode; + unsigned int uid; + unsigned int flags; +}; static void fuse_read_inode(struct inode *inode) { @@ -111,24 +118,113 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) return out.h.error; } -static struct fuse_conn *get_conn(struct fuse_mount_data *d) +enum { opt_fd, opt_rootmode, opt_uid, opt_default_permissions, + opt_allow_other, opt_kernel_cache, opt_large_read, opt_err }; + +static match_table_t tokens = { + {opt_fd, "fd=%u"}, + {opt_rootmode, "rootmode=%o"}, + {opt_uid, "uid=%u"}, + {opt_default_permissions, "default_permissions"}, + {opt_allow_other, "allow_other"}, + {opt_kernel_cache, "kernel_cache"}, + {opt_large_read, "large_read"}, + {opt_err, NULL} +}; + +static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) +{ + char *p; + memset(d, 0, sizeof(struct fuse_mount_data)); + d->fd = -1; + + if (opt == NULL) + return 0; + + if (opt[PAGE_SIZE - 1] != '\0') + return 0; + + while ((p = strsep(&opt, ",")) != NULL) { + int token; + int value; + substring_t args[MAX_OPT_ARGS]; + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case opt_fd: + if (match_int(&args[0], &value)) + return 0; + d->fd = value; + break; + + case opt_rootmode: + if (match_octal(&args[0], &value)) + return 0; + d->rootmode = value; + break; + + case opt_uid: + if (match_int(&args[0], &value)) + return 0; + d->uid = value; + break; + + case opt_default_permissions: + d->flags |= FUSE_DEFAULT_PERMISSIONS; + break; + + case opt_allow_other: + d->flags |= FUSE_ALLOW_OTHER; + break; + + case opt_kernel_cache: + d->flags |= FUSE_KERNEL_CACHE; + break; + + case opt_large_read: + d->flags |= FUSE_LARGE_READ; + break; + default: + return 0; + } + } + if (d->fd == -1) + return 0; + + return 1; +} + +static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) +{ + struct fuse_conn *fc = SB_FC(mnt->mnt_sb); + + seq_printf(m, ",uid=%u", fc->uid); + if (fc->flags & FUSE_DEFAULT_PERMISSIONS) + seq_puts(m, ",default_permissions"); + if (fc->flags & FUSE_ALLOW_OTHER) + seq_puts(m, ",allow_other"); + if (fc->flags & FUSE_KERNEL_CACHE) + seq_puts(m, ",kernel_cache"); + if (fc->flags & FUSE_LARGE_READ) + seq_puts(m, ",large_read"); + return 0; +} + +static struct fuse_conn *get_conn(int fd) { struct fuse_conn *fc = NULL; struct file *file; struct inode *ino; - if (d == NULL) { - printk("fuse_read_super: Bad mount data\n"); - return NULL; - } - - file = fget(d->fd); + file = fget(fd); ino = NULL; if (file) ino = file->f_dentry->d_inode; if (!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) { - printk("fuse_read_super: Bad file: %i\n", d->fd); + printk("FUSE: bad communication file descriptor: %i\n", fd); goto out; } @@ -186,18 +282,20 @@ static struct super_operations fuse_super_operations = { .clear_inode = fuse_clear_inode, .put_super = fuse_put_super, .statfs = fuse_statfs, + .show_options = fuse_show_options, }; static int fuse_read_super(struct super_block *sb, void *data, int silent) { struct fuse_conn *fc; struct inode *root; - struct fuse_mount_data *d = data; + struct fuse_mount_data d; - if (!capable(CAP_SYS_ADMIN)) { - if (d->flags & FUSE_ALLOW_OTHER) - return -EPERM; - } + if (!parse_fuse_opt((char *) data, &d)) + return -EINVAL; + + if ((d.flags & FUSE_ALLOW_OTHER) && !capable(CAP_SYS_ADMIN)) + return -EPERM; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -208,9 +306,10 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &fuse_export_operations; #endif - fc = get_conn(d); + fc = get_conn(d.fd); if (fc == NULL) return -EINVAL; + spin_lock(&fuse_lock); if (fc->sb != NULL) { printk("fuse_read_super: connection already mounted\n"); @@ -218,15 +317,15 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent) return -EINVAL; } fc->sb = sb; - fc->flags = d->flags; - fc->uid = d->uid; + fc->flags = d.flags; + fc->uid = d.uid; spin_unlock(&fuse_lock); /* fc is needed in fuse_init_file_inode which could be called from get_root_inode */ SB_FC(sb) = fc; - root = get_root_inode(sb, d->rootmode); + root = get_root_inode(sb, d.rootmode); if (root == NULL) { printk("fuse_read_super: failed to get root inode\n"); return -EINVAL; @@ -252,7 +351,7 @@ static struct file_system_type fuse_fs_type = { .name = "fuse", .get_sb = fuse_get_sb, .kill_sb = kill_anon_super, - .fs_flags = FS_SAFE | FS_BINARY_MOUNTDATA, + .fs_flags = FS_SAFE, }; #else static struct super_block *fuse_read_super_compat(struct super_block *sb, diff --git a/util/fusermount.c b/util/fusermount.c index 42e9d47..bd52e4a 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -41,6 +41,13 @@ const char *progname; +struct fuse_opts { + int kernel_cache; + int default_permissions; + int allow_other; + int large_read; +}; + static const char *get_user_name() { struct passwd *pw = getpwuid(getuid()); @@ -289,11 +296,12 @@ static void restore_privs() } static int do_mount(const char *dev, const char *mnt, const char *type, - mode_t rootmode, int fd, int fuseflags) + mode_t rootmode, int fd, struct fuse_opts *opts) { int res; - struct fuse_mount_data data; int flags = MS_NOSUID | MS_NODEV; + char optbuf[1024]; + char *s = optbuf; if(getuid() != 0) { res = drop_privs(); @@ -301,12 +309,17 @@ static int do_mount(const char *dev, const char *mnt, const char *type, return -1; } - data.fd = fd; - data.rootmode = rootmode; - data.uid = getuid(); - data.flags = fuseflags; - - res = mount(dev, mnt, type, flags, &data); + s += sprintf(s, "fd=%i,rootmode=%o,uid=%i", fd, rootmode, getuid()); + if (opts->kernel_cache) + s += sprintf(s, ",kernel_cache"); + if (opts->default_permissions) + s += sprintf(s, ",default_permissions"); + if (opts->allow_other) + s += sprintf(s, ",allow_other"); + if (opts->large_read) + s += sprintf(s, ",large_read"); + + res = mount(dev, mnt, type, flags, optbuf); if(res == -1) fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno)); @@ -354,7 +367,8 @@ static int check_perm(const char *mnt, struct stat *stbuf) return 0; } -static int mount_fuse(const char *mnt, int flags, const char *fsname) +static int mount_fuse(const char *mnt, struct fuse_opts *opts, + const char *fsname) { int res; int fd; @@ -390,7 +404,7 @@ static int mount_fuse(const char *mnt, int flags, const char *fsname) if(fsname == NULL) fsname = dev; - res = do_mount(fsname, mnt, type, stbuf.st_mode & S_IFMT, fd, flags); + res = do_mount(fsname, mnt, type, stbuf.st_mode & S_IFMT, fd, opts); if(res == -1) return -1; @@ -499,10 +513,12 @@ int main(int argc, char *argv[]) int lazy = 0; char *commfd; const char *fsname = NULL; - int flags = 0; int quiet = 0; + struct fuse_opts opts; int cfd; + + memset(&opts, 0, sizeof(struct fuse_opts)); progname = argv[0]; for(a = 1; a < argc; a++) { @@ -511,7 +527,7 @@ int main(int argc, char *argv[]) switch(argv[a][1]) { case 'c': - flags |= FUSE_KERNEL_CACHE; + opts.kernel_cache = 1; break; case 'h': @@ -527,7 +543,7 @@ int main(int argc, char *argv[]) break; case 'p': - flags |= FUSE_DEFAULT_PERMISSIONS; + opts.default_permissions = 1; break; case 'x': @@ -536,7 +552,7 @@ int main(int argc, char *argv[]) progname, argv[a]); exit(1); } - flags |= FUSE_ALLOW_OTHER; + opts.allow_other = 1; break; case 'n': @@ -549,7 +565,7 @@ int main(int argc, char *argv[]) break; case 'l': - flags |= FUSE_LARGE_READ; + opts.large_read = 1; break; case 'q': @@ -604,7 +620,7 @@ int main(int argc, char *argv[]) exit(1); } - fd = mount_fuse(mnt, flags, fsname); + fd = mount_fuse(mnt, &opts, fsname); if(fd == -1) exit(1);