fuse update for 5.2
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCXNpuRwAKCRDh3BK/laaZ PMq/AP9kLvB97JU2GbzIJq6wOjDV8whPE/a2Knx0fajvW3AEOAD+NQwdZLmVNql7 DkkY8lZ7fVut3TMj8jHhpIbv4P1R1AE= =qX6f -----END PGP SIGNATURE----- Merge tag 'fuse-update-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse Pull fuse update from Miklos Szeredi: "Add more caching controls for userspace filesystems to use, as well as bug fixes and cleanups" * tag 'fuse-update-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: fuse: clean up fuse_alloc_inode fuse: Add ioctl flag for x32 compat ioctl fuse: Convert fusectl to use the new mount API fuse: fix changelog entry for protocol 7.9 fuse: fix changelog entry for protocol 7.12 fuse: document fuse_fsync_in.fsync_flags fuse: Add FOPEN_STREAM to use stream_open() fuse: require /dev/fuse reads to have enough buffer capacity fuse: retrieve: cap requested size to negotiated max_write fuse: allow filesystems to have precise control over data cache fuse: convert printk -> pr_* fuse: honor RLIMIT_FSIZE in fuse_file_fallocate fuse: fix writepages on 32bit
This commit is contained in:
commit
4856118f49
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs_context.h>
|
||||
|
||||
#define FUSE_CTL_SUPER_MAGIC 0x65735543
|
||||
|
||||
|
@ -317,7 +318,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc)
|
|||
drop_nlink(d_inode(fuse_control_sb->s_root));
|
||||
}
|
||||
|
||||
static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
|
||||
static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx)
|
||||
{
|
||||
static const struct tree_descr empty_descr = {""};
|
||||
struct fuse_conn *fc;
|
||||
|
@ -343,10 +344,19 @@ static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *fuse_ctl_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *raw_data)
|
||||
static int fuse_ctl_get_tree(struct fs_context *fc)
|
||||
{
|
||||
return mount_single(fs_type, flags, raw_data, fuse_ctl_fill_super);
|
||||
return vfs_get_super(fc, vfs_get_single_super, fuse_ctl_fill_super);
|
||||
}
|
||||
|
||||
static const struct fs_context_operations fuse_ctl_context_ops = {
|
||||
.get_tree = fuse_ctl_get_tree,
|
||||
};
|
||||
|
||||
static int fuse_ctl_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
fc->ops = &fuse_ctl_context_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fuse_ctl_kill_sb(struct super_block *sb)
|
||||
|
@ -365,7 +375,7 @@ static void fuse_ctl_kill_sb(struct super_block *sb)
|
|||
static struct file_system_type fuse_ctl_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "fusectl",
|
||||
.mount = fuse_ctl_mount,
|
||||
.init_fs_context = fuse_ctl_init_fs_context,
|
||||
.kill_sb = fuse_ctl_kill_sb,
|
||||
};
|
||||
MODULE_ALIAS_FS("fusectl");
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
* closed.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "CUSE: " fmt
|
||||
|
||||
#include <linux/fuse.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -225,7 +227,7 @@ static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
|
|||
return 0;
|
||||
|
||||
if (end[-1] != '\0') {
|
||||
printk(KERN_ERR "CUSE: info not properly terminated\n");
|
||||
pr_err("info not properly terminated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -242,7 +244,7 @@ static int cuse_parse_one(char **pp, char *end, char **keyp, char **valp)
|
|||
key = strstrip(key);
|
||||
|
||||
if (!strlen(key)) {
|
||||
printk(KERN_ERR "CUSE: zero length info key specified\n");
|
||||
pr_err("zero length info key specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -282,12 +284,11 @@ static int cuse_parse_devinfo(char *p, size_t len, struct cuse_devinfo *devinfo)
|
|||
if (strcmp(key, "DEVNAME") == 0)
|
||||
devinfo->name = val;
|
||||
else
|
||||
printk(KERN_WARNING "CUSE: unknown device info \"%s\"\n",
|
||||
key);
|
||||
pr_warn("unknown device info \"%s\"\n", key);
|
||||
}
|
||||
|
||||
if (!devinfo->name || !strlen(devinfo->name)) {
|
||||
printk(KERN_ERR "CUSE: DEVNAME unspecified\n");
|
||||
pr_err("DEVNAME unspecified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -341,7 +342,7 @@ static void cuse_process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
|
|||
else
|
||||
rc = register_chrdev_region(devt, 1, devinfo.name);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "CUSE: failed to register chrdev region\n");
|
||||
pr_err("failed to register chrdev region\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -906,8 +906,8 @@ static int fuse_check_page(struct page *page)
|
|||
1 << PG_lru |
|
||||
1 << PG_active |
|
||||
1 << PG_reclaim))) {
|
||||
printk(KERN_WARNING "fuse: trying to steal weird page\n");
|
||||
printk(KERN_WARNING " page=%p index=%li flags=%08lx, count=%i, mapcount=%i, mapping=%p\n", page, page->index, page->flags, page_count(page), page_mapcount(page), page->mapping);
|
||||
pr_warn("trying to steal weird page\n");
|
||||
pr_warn(" page=%p index=%li flags=%08lx, count=%i, mapcount=%i, mapping=%p\n", page, page->index, page->flags, page_count(page), page_mapcount(page), page->mapping);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1317,6 +1317,16 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
|
|||
unsigned reqsize;
|
||||
unsigned int hash;
|
||||
|
||||
/*
|
||||
* Require sane minimum read buffer - that has capacity for fixed part
|
||||
* of any request header + negotated max_write room for data. If the
|
||||
* requirement is not satisfied return EINVAL to the filesystem server
|
||||
* to indicate that it is not following FUSE server/client contract.
|
||||
* Don't dequeue / abort any request.
|
||||
*/
|
||||
if (nbytes < max_t(size_t, FUSE_MIN_READ_BUFFER, 4096 + fc->max_write))
|
||||
return -EINVAL;
|
||||
|
||||
restart:
|
||||
spin_lock(&fiq->waitq.lock);
|
||||
err = -EAGAIN;
|
||||
|
@ -1749,7 +1759,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
|
|||
offset = outarg->offset & ~PAGE_MASK;
|
||||
file_size = i_size_read(inode);
|
||||
|
||||
num = outarg->size;
|
||||
num = min(outarg->size, fc->max_write);
|
||||
if (outarg->offset > file_size)
|
||||
num = 0;
|
||||
else if (outarg->offset + num > file_size)
|
||||
|
|
|
@ -178,7 +178,9 @@ void fuse_finish_open(struct inode *inode, struct file *file)
|
|||
|
||||
if (!(ff->open_flags & FOPEN_KEEP_CACHE))
|
||||
invalidate_inode_pages2(inode->i_mapping);
|
||||
if (ff->open_flags & FOPEN_NONSEEKABLE)
|
||||
if (ff->open_flags & FOPEN_STREAM)
|
||||
stream_open(inode, file);
|
||||
else if (ff->open_flags & FOPEN_NONSEEKABLE)
|
||||
nonseekable_open(inode, file);
|
||||
if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) {
|
||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||
|
@ -462,7 +464,7 @@ int fuse_fsync_common(struct file *file, loff_t start, loff_t end,
|
|||
|
||||
memset(&inarg, 0, sizeof(inarg));
|
||||
inarg.fh = ff->fh;
|
||||
inarg.fsync_flags = datasync ? 1 : 0;
|
||||
inarg.fsync_flags = datasync ? FUSE_FSYNC_FDATASYNC : 0;
|
||||
args.in.h.opcode = opcode;
|
||||
args.in.h.nodeid = get_node_id(inode);
|
||||
args.in.numargs = 1;
|
||||
|
@ -1586,7 +1588,7 @@ __acquires(fi->lock)
|
|||
{
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||
size_t crop = i_size_read(inode);
|
||||
loff_t crop = i_size_read(inode);
|
||||
struct fuse_req *req;
|
||||
|
||||
while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) {
|
||||
|
@ -2576,8 +2578,13 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg,
|
|||
#if BITS_PER_LONG == 32
|
||||
inarg.flags |= FUSE_IOCTL_32BIT;
|
||||
#else
|
||||
if (flags & FUSE_IOCTL_COMPAT)
|
||||
if (flags & FUSE_IOCTL_COMPAT) {
|
||||
inarg.flags |= FUSE_IOCTL_32BIT;
|
||||
#ifdef CONFIG_X86_X32
|
||||
if (in_x32_syscall())
|
||||
inarg.flags |= FUSE_IOCTL_COMPAT_X32;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* assume all the iovs returned by client always fits in a page */
|
||||
|
@ -3044,6 +3051,13 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
|
|||
}
|
||||
}
|
||||
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
||||
offset + length > i_size_read(inode)) {
|
||||
err = inode_newsize_ok(inode, offset + length);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!(mode & FALLOC_FL_KEEP_SIZE))
|
||||
set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#ifndef _FS_FUSE_I_H
|
||||
#define _FS_FUSE_I_H
|
||||
|
||||
#ifndef pr_fmt
|
||||
# define pr_fmt(fmt) "fuse: " fmt
|
||||
#endif
|
||||
|
||||
#include <linux/fuse.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mount.h>
|
||||
|
@ -690,6 +694,9 @@ struct fuse_conn {
|
|||
/** Use enhanced/automatic page cache invalidation. */
|
||||
unsigned auto_inval_data:1;
|
||||
|
||||
/** Filesystem is fully reponsible for page cache invalidation. */
|
||||
unsigned explicit_inval_data:1;
|
||||
|
||||
/** Does the filesystem support readdirplus? */
|
||||
unsigned do_readdirplus:1;
|
||||
|
||||
|
|
|
@ -81,14 +81,12 @@ struct fuse_forget_link *fuse_alloc_forget(void)
|
|||
|
||||
static struct inode *fuse_alloc_inode(struct super_block *sb)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct fuse_inode *fi;
|
||||
|
||||
inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL);
|
||||
if (!inode)
|
||||
fi = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL);
|
||||
if (!fi)
|
||||
return NULL;
|
||||
|
||||
fi = get_fuse_inode(inode);
|
||||
fi->i_time = 0;
|
||||
fi->inval_mask = 0;
|
||||
fi->nodeid = 0;
|
||||
|
@ -100,11 +98,11 @@ static struct inode *fuse_alloc_inode(struct super_block *sb)
|
|||
spin_lock_init(&fi->lock);
|
||||
fi->forget = fuse_alloc_forget();
|
||||
if (!fi->forget) {
|
||||
kmem_cache_free(fuse_inode_cachep, inode);
|
||||
kmem_cache_free(fuse_inode_cachep, fi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return inode;
|
||||
return &fi->inode;
|
||||
}
|
||||
|
||||
static void fuse_free_inode(struct inode *inode)
|
||||
|
@ -233,7 +231,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
|
|||
|
||||
if (oldsize != attr->size) {
|
||||
truncate_pagecache(inode, attr->size);
|
||||
inval = true;
|
||||
if (!fc->explicit_inval_data)
|
||||
inval = true;
|
||||
} else if (fc->auto_inval_data) {
|
||||
struct timespec64 new_mtime = {
|
||||
.tv_sec = attr->mtime,
|
||||
|
@ -908,6 +907,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
|
|||
fc->dont_mask = 1;
|
||||
if (arg->flags & FUSE_AUTO_INVAL_DATA)
|
||||
fc->auto_inval_data = 1;
|
||||
else if (arg->flags & FUSE_EXPLICIT_INVAL_DATA)
|
||||
fc->explicit_inval_data = 1;
|
||||
if (arg->flags & FUSE_DO_READDIRPLUS) {
|
||||
fc->do_readdirplus = 1;
|
||||
if (arg->flags & FUSE_READDIRPLUS_AUTO)
|
||||
|
@ -969,7 +970,7 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
|
|||
FUSE_WRITEBACK_CACHE | FUSE_NO_OPEN_SUPPORT |
|
||||
FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
|
||||
FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS |
|
||||
FUSE_NO_OPENDIR_SUPPORT;
|
||||
FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA;
|
||||
req->in.h.opcode = FUSE_INIT;
|
||||
req->in.numargs = 1;
|
||||
req->in.args[0].size = sizeof(*arg);
|
||||
|
@ -1393,8 +1394,8 @@ static int __init fuse_init(void)
|
|||
{
|
||||
int res;
|
||||
|
||||
printk(KERN_INFO "fuse init (API version %i.%i)\n",
|
||||
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
|
||||
pr_info("init (API version %i.%i)\n",
|
||||
FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
|
||||
|
||||
INIT_LIST_HEAD(&fuse_conn_list);
|
||||
res = fuse_fs_init();
|
||||
|
@ -1430,7 +1431,7 @@ static int __init fuse_init(void)
|
|||
|
||||
static void __exit fuse_exit(void)
|
||||
{
|
||||
printk(KERN_DEBUG "fuse exit\n");
|
||||
pr_debug("exit\n");
|
||||
|
||||
fuse_ctl_cleanup();
|
||||
fuse_sysfs_cleanup();
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
* - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
|
||||
* - add blksize field to fuse_attr
|
||||
* - add file flags field to fuse_read_in and fuse_write_in
|
||||
* - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in
|
||||
*
|
||||
* 7.10
|
||||
* - add nonseekable open flag
|
||||
|
@ -54,7 +55,7 @@
|
|||
* - add POLL message and NOTIFY_POLL notification
|
||||
*
|
||||
* 7.12
|
||||
* - add umask flag to input argument of open, mknod and mkdir
|
||||
* - add umask flag to input argument of create, mknod and mkdir
|
||||
* - add notification messages for invalidation of inodes and
|
||||
* directory entries
|
||||
*
|
||||
|
@ -125,6 +126,10 @@
|
|||
*
|
||||
* 7.29
|
||||
* - add FUSE_NO_OPENDIR_SUPPORT flag
|
||||
*
|
||||
* 7.30
|
||||
* - add FUSE_EXPLICIT_INVAL_DATA
|
||||
* - add FUSE_IOCTL_COMPAT_X32
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
|
@ -160,7 +165,7 @@
|
|||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 29
|
||||
#define FUSE_KERNEL_MINOR_VERSION 30
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
|
@ -229,11 +234,13 @@ struct fuse_file_lock {
|
|||
* FOPEN_KEEP_CACHE: don't invalidate the data cache on open
|
||||
* FOPEN_NONSEEKABLE: the file is not seekable
|
||||
* FOPEN_CACHE_DIR: allow caching this directory
|
||||
* FOPEN_STREAM: the file is stream-like (no file position at all)
|
||||
*/
|
||||
#define FOPEN_DIRECT_IO (1 << 0)
|
||||
#define FOPEN_KEEP_CACHE (1 << 1)
|
||||
#define FOPEN_NONSEEKABLE (1 << 2)
|
||||
#define FOPEN_CACHE_DIR (1 << 3)
|
||||
#define FOPEN_STREAM (1 << 4)
|
||||
|
||||
/**
|
||||
* INIT request/reply flags
|
||||
|
@ -263,6 +270,7 @@ struct fuse_file_lock {
|
|||
* FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages
|
||||
* FUSE_CACHE_SYMLINKS: cache READLINK responses
|
||||
* FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir
|
||||
* FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
|
@ -289,6 +297,7 @@ struct fuse_file_lock {
|
|||
#define FUSE_MAX_PAGES (1 << 22)
|
||||
#define FUSE_CACHE_SYMLINKS (1 << 23)
|
||||
#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
|
||||
#define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
|
||||
|
||||
/**
|
||||
* CUSE INIT request/reply flags
|
||||
|
@ -335,6 +344,7 @@ struct fuse_file_lock {
|
|||
* FUSE_IOCTL_RETRY: retry with new iovecs
|
||||
* FUSE_IOCTL_32BIT: 32bit ioctl
|
||||
* FUSE_IOCTL_DIR: is a directory
|
||||
* FUSE_IOCTL_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t)
|
||||
*
|
||||
* FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs
|
||||
*/
|
||||
|
@ -343,6 +353,7 @@ struct fuse_file_lock {
|
|||
#define FUSE_IOCTL_RETRY (1 << 2)
|
||||
#define FUSE_IOCTL_32BIT (1 << 3)
|
||||
#define FUSE_IOCTL_DIR (1 << 4)
|
||||
#define FUSE_IOCTL_COMPAT_X32 (1 << 5)
|
||||
|
||||
#define FUSE_IOCTL_MAX_IOV 256
|
||||
|
||||
|
@ -353,6 +364,13 @@ struct fuse_file_lock {
|
|||
*/
|
||||
#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
|
||||
|
||||
/**
|
||||
* Fsync flags
|
||||
*
|
||||
* FUSE_FSYNC_FDATASYNC: Sync data only, not metadata
|
||||
*/
|
||||
#define FUSE_FSYNC_FDATASYNC (1 << 0)
|
||||
|
||||
enum fuse_opcode {
|
||||
FUSE_LOOKUP = 1,
|
||||
FUSE_FORGET = 2, /* no reply */
|
||||
|
|
Loading…
Reference in a new issue