fuse update for 5.17
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCYdw8xgAKCRDh3BK/laaZ PFy3AQCHSltzy6f234CcsFk3mtJn0im0tDbRoEYFD731JOR1YAD9HQKtJRn/sMCF r0PnZnOWJ35RWB3o8uEqptsgrZXJkQo= =HosR -----END PGP SIGNATURE----- Merge tag 'fuse-update-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse Pull fuse updates from Miklos Szeredi: - Fix a regression introduced in 5.15 - Extend the size of the FUSE_INIT request to accommodate for more flags. There's a slight possibility of a regression for obscure fuse servers; if this happens, then more complexity will need to be added to the protocol - Allow the DAX property to be controlled by the server on a per-inode basis in virtiofs - Allow sending security context to the server when creating a file or directory * tag 'fuse-update-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: Documentation/filesystem/dax: DAX on virtiofs fuse: mark inode DONT_CACHE when per inode DAX hint changes fuse: negotiate per inode DAX in FUSE_INIT fuse: enable per inode DAX fuse: support per inode DAX in fuse protocol fuse: make DAX mount option a tri-state fuse: add fuse_should_enable_dax() helper fuse: Pass correct lend value to filemap_write_and_wait_range() fuse: send security context of inode on file fuse: extend init flags
This commit is contained in:
Коммит
8975f89748
|
@ -23,8 +23,8 @@ on it as usual. The `DAX` code currently only supports files with a block
|
|||
size equal to your kernel's `PAGE_SIZE`, so you may need to specify a block
|
||||
size when creating the filesystem.
|
||||
|
||||
Currently 3 filesystems support `DAX`: ext2, ext4 and xfs. Enabling `DAX` on them
|
||||
is different.
|
||||
Currently 4 filesystems support `DAX`: ext2, ext4, xfs and virtiofs.
|
||||
Enabling `DAX` on them is different.
|
||||
|
||||
Enabling DAX on ext2
|
||||
--------------------
|
||||
|
@ -168,6 +168,22 @@ if the underlying media does not support dax and/or the filesystem is
|
|||
overridden with a mount option.
|
||||
|
||||
|
||||
Enabling DAX on virtiofs
|
||||
----------------------------
|
||||
The semantic of DAX on virtiofs is basically equal to that on ext4 and xfs,
|
||||
except that when '-o dax=inode' is specified, virtiofs client derives the hint
|
||||
whether DAX shall be enabled or not from virtiofs server through FUSE protocol,
|
||||
rather than the persistent `FS_XFLAG_DAX` flag. That is, whether DAX shall be
|
||||
enabled or not is completely determined by virtiofs server, while virtiofs
|
||||
server itself may deploy various algorithm making this decision, e.g. depending
|
||||
on the persistent `FS_XFLAG_DAX` flag on the host.
|
||||
|
||||
It is still supported to set or clear persistent `FS_XFLAG_DAX` flag inside
|
||||
guest, but it is not guaranteed that DAX will be enabled or disabled for
|
||||
corresponding file then. Users inside guest still need to call statx(2) and
|
||||
check the statx flag `STATX_ATTR_DAX` to see if DAX is enabled for this file.
|
||||
|
||||
|
||||
Implementation Tips for Block Driver Writers
|
||||
--------------------------------------------
|
||||
|
||||
|
|
|
@ -1279,11 +1279,14 @@ out_err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int fuse_dax_conn_alloc(struct fuse_conn *fc, struct dax_device *dax_dev)
|
||||
int fuse_dax_conn_alloc(struct fuse_conn *fc, enum fuse_dax_mode dax_mode,
|
||||
struct dax_device *dax_dev)
|
||||
{
|
||||
struct fuse_conn_dax *fcd;
|
||||
int err;
|
||||
|
||||
fc->dax_mode = dax_mode;
|
||||
|
||||
if (!dax_dev)
|
||||
return 0;
|
||||
|
||||
|
@ -1327,17 +1330,46 @@ static const struct address_space_operations fuse_dax_file_aops = {
|
|||
.invalidatepage = noop_invalidatepage,
|
||||
};
|
||||
|
||||
void fuse_dax_inode_init(struct inode *inode)
|
||||
static bool fuse_should_enable_dax(struct inode *inode, unsigned int flags)
|
||||
{
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
enum fuse_dax_mode dax_mode = fc->dax_mode;
|
||||
|
||||
if (dax_mode == FUSE_DAX_NEVER)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* fc->dax may be NULL in 'inode' mode when filesystem device doesn't
|
||||
* support DAX, in which case it will silently fallback to 'never' mode.
|
||||
*/
|
||||
if (!fc->dax)
|
||||
return false;
|
||||
|
||||
if (dax_mode == FUSE_DAX_ALWAYS)
|
||||
return true;
|
||||
|
||||
/* dax_mode is FUSE_DAX_INODE* */
|
||||
return fc->inode_dax && (flags & FUSE_ATTR_DAX);
|
||||
}
|
||||
|
||||
void fuse_dax_inode_init(struct inode *inode, unsigned int flags)
|
||||
{
|
||||
if (!fuse_should_enable_dax(inode, flags))
|
||||
return;
|
||||
|
||||
inode->i_flags |= S_DAX;
|
||||
inode->i_data.a_ops = &fuse_dax_file_aops;
|
||||
}
|
||||
|
||||
void fuse_dax_dontcache(struct inode *inode, unsigned int flags)
|
||||
{
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
|
||||
if (fuse_is_inode_dax_mode(fc->dax_mode) &&
|
||||
((bool) IS_DAX(inode) != (bool) (flags & FUSE_ATTR_DAX)))
|
||||
d_mark_dontcache(inode);
|
||||
}
|
||||
|
||||
bool fuse_dax_check_alignment(struct fuse_conn *fc, unsigned int map_alignment)
|
||||
{
|
||||
if (fc->dax && (map_alignment > FUSE_DAX_SHIFT)) {
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include <linux/xattr.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
static void fuse_advise_use_readdirplus(struct inode *dir)
|
||||
{
|
||||
|
@ -456,6 +459,62 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static int get_security_context(struct dentry *entry, umode_t mode,
|
||||
void **security_ctx, u32 *security_ctxlen)
|
||||
{
|
||||
struct fuse_secctx *fctx;
|
||||
struct fuse_secctx_header *header;
|
||||
void *ctx = NULL, *ptr;
|
||||
u32 ctxlen, total_len = sizeof(*header);
|
||||
int err, nr_ctx = 0;
|
||||
const char *name;
|
||||
size_t namelen;
|
||||
|
||||
err = security_dentry_init_security(entry, mode, &entry->d_name,
|
||||
&name, &ctx, &ctxlen);
|
||||
if (err) {
|
||||
if (err != -EOPNOTSUPP)
|
||||
goto out_err;
|
||||
/* No LSM is supporting this security hook. Ignore error */
|
||||
ctxlen = 0;
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
if (ctxlen) {
|
||||
nr_ctx = 1;
|
||||
namelen = strlen(name) + 1;
|
||||
err = -EIO;
|
||||
if (WARN_ON(namelen > XATTR_NAME_MAX + 1 || ctxlen > S32_MAX))
|
||||
goto out_err;
|
||||
total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen + ctxlen);
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
header = ptr = kzalloc(total_len, GFP_KERNEL);
|
||||
if (!ptr)
|
||||
goto out_err;
|
||||
|
||||
header->nr_secctx = nr_ctx;
|
||||
header->size = total_len;
|
||||
ptr += sizeof(*header);
|
||||
if (nr_ctx) {
|
||||
fctx = ptr;
|
||||
fctx->size = ctxlen;
|
||||
ptr += sizeof(*fctx);
|
||||
|
||||
strcpy(ptr, name);
|
||||
ptr += namelen;
|
||||
|
||||
memcpy(ptr, ctx, ctxlen);
|
||||
}
|
||||
*security_ctxlen = total_len;
|
||||
*security_ctx = header;
|
||||
err = 0;
|
||||
out_err:
|
||||
kfree(ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Atomic create+open operation
|
||||
*
|
||||
|
@ -476,6 +535,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
|||
struct fuse_entry_out outentry;
|
||||
struct fuse_inode *fi;
|
||||
struct fuse_file *ff;
|
||||
void *security_ctx = NULL;
|
||||
u32 security_ctxlen;
|
||||
|
||||
/* Userspace expects S_IFREG in create mode */
|
||||
BUG_ON((mode & S_IFMT) != S_IFREG);
|
||||
|
@ -517,7 +578,20 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
|||
args.out_args[0].value = &outentry;
|
||||
args.out_args[1].size = sizeof(outopen);
|
||||
args.out_args[1].value = &outopen;
|
||||
|
||||
if (fm->fc->init_security) {
|
||||
err = get_security_context(entry, mode, &security_ctx,
|
||||
&security_ctxlen);
|
||||
if (err)
|
||||
goto out_put_forget_req;
|
||||
|
||||
args.in_numargs = 3;
|
||||
args.in_args[2].size = security_ctxlen;
|
||||
args.in_args[2].value = security_ctx;
|
||||
}
|
||||
|
||||
err = fuse_simple_request(fm, &args);
|
||||
kfree(security_ctx);
|
||||
if (err)
|
||||
goto out_free_ff;
|
||||
|
||||
|
@ -620,6 +694,8 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
|
|||
struct dentry *d;
|
||||
int err;
|
||||
struct fuse_forget_link *forget;
|
||||
void *security_ctx = NULL;
|
||||
u32 security_ctxlen;
|
||||
|
||||
if (fuse_is_bad(dir))
|
||||
return -EIO;
|
||||
|
@ -633,7 +709,22 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
|
|||
args->out_numargs = 1;
|
||||
args->out_args[0].size = sizeof(outarg);
|
||||
args->out_args[0].value = &outarg;
|
||||
|
||||
if (fm->fc->init_security && args->opcode != FUSE_LINK) {
|
||||
err = get_security_context(entry, mode, &security_ctx,
|
||||
&security_ctxlen);
|
||||
if (err)
|
||||
goto out_put_forget_req;
|
||||
|
||||
BUG_ON(args->in_numargs != 2);
|
||||
|
||||
args->in_numargs = 3;
|
||||
args->in_args[2].size = security_ctxlen;
|
||||
args->in_args[2].value = security_ctx;
|
||||
}
|
||||
|
||||
err = fuse_simple_request(fm, args);
|
||||
kfree(security_ctx);
|
||||
if (err)
|
||||
goto out_put_forget_req;
|
||||
|
||||
|
|
|
@ -2910,7 +2910,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
|
||||
static int fuse_writeback_range(struct inode *inode, loff_t start, loff_t end)
|
||||
{
|
||||
int err = filemap_write_and_wait_range(inode->i_mapping, start, -1);
|
||||
int err = filemap_write_and_wait_range(inode->i_mapping, start, LLONG_MAX);
|
||||
|
||||
if (!err)
|
||||
fuse_sync_writes(inode);
|
||||
|
@ -3169,7 +3169,7 @@ static const struct address_space_operations fuse_file_aops = {
|
|||
.write_end = fuse_write_end,
|
||||
};
|
||||
|
||||
void fuse_init_file_inode(struct inode *inode)
|
||||
void fuse_init_file_inode(struct inode *inode, unsigned int flags)
|
||||
{
|
||||
struct fuse_inode *fi = get_fuse_inode(inode);
|
||||
|
||||
|
@ -3183,5 +3183,5 @@ void fuse_init_file_inode(struct inode *inode)
|
|||
fi->writepages = RB_ROOT;
|
||||
|
||||
if (IS_ENABLED(CONFIG_FUSE_DAX))
|
||||
fuse_dax_inode_init(inode);
|
||||
fuse_dax_inode_init(inode, flags);
|
||||
}
|
||||
|
|
|
@ -480,6 +480,18 @@ struct fuse_dev {
|
|||
struct list_head entry;
|
||||
};
|
||||
|
||||
enum fuse_dax_mode {
|
||||
FUSE_DAX_INODE_DEFAULT, /* default */
|
||||
FUSE_DAX_ALWAYS, /* "-o dax=always" */
|
||||
FUSE_DAX_NEVER, /* "-o dax=never" */
|
||||
FUSE_DAX_INODE_USER, /* "-o dax=inode" */
|
||||
};
|
||||
|
||||
static inline bool fuse_is_inode_dax_mode(enum fuse_dax_mode mode)
|
||||
{
|
||||
return mode == FUSE_DAX_INODE_DEFAULT || mode == FUSE_DAX_INODE_USER;
|
||||
}
|
||||
|
||||
struct fuse_fs_context {
|
||||
int fd;
|
||||
struct file *file;
|
||||
|
@ -497,7 +509,7 @@ struct fuse_fs_context {
|
|||
bool no_control:1;
|
||||
bool no_force_umount:1;
|
||||
bool legacy_opts_show:1;
|
||||
bool dax:1;
|
||||
enum fuse_dax_mode dax_mode;
|
||||
unsigned int max_read;
|
||||
unsigned int blksize;
|
||||
const char *subtype;
|
||||
|
@ -765,6 +777,12 @@ struct fuse_conn {
|
|||
/* Propagate syncfs() to server */
|
||||
unsigned int sync_fs:1;
|
||||
|
||||
/* Initialize security xattrs when creating a new inode */
|
||||
unsigned int init_security:1;
|
||||
|
||||
/* Does the filesystem support per inode DAX? */
|
||||
unsigned int inode_dax:1;
|
||||
|
||||
/** The number of requests waiting for completion */
|
||||
atomic_t num_waiting;
|
||||
|
||||
|
@ -802,6 +820,9 @@ struct fuse_conn {
|
|||
struct list_head devices;
|
||||
|
||||
#ifdef CONFIG_FUSE_DAX
|
||||
/* Dax mode */
|
||||
enum fuse_dax_mode dax_mode;
|
||||
|
||||
/* Dax specific conn data, non-NULL if DAX is enabled */
|
||||
struct fuse_conn_dax *dax;
|
||||
#endif
|
||||
|
@ -1007,7 +1028,7 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc,
|
|||
/**
|
||||
* Initialize file operations on a regular file
|
||||
*/
|
||||
void fuse_init_file_inode(struct inode *inode);
|
||||
void fuse_init_file_inode(struct inode *inode, unsigned int flags);
|
||||
|
||||
/**
|
||||
* Initialize inode operations on regular files and special files
|
||||
|
@ -1269,11 +1290,13 @@ ssize_t fuse_dax_read_iter(struct kiocb *iocb, struct iov_iter *to);
|
|||
ssize_t fuse_dax_write_iter(struct kiocb *iocb, struct iov_iter *from);
|
||||
int fuse_dax_mmap(struct file *file, struct vm_area_struct *vma);
|
||||
int fuse_dax_break_layouts(struct inode *inode, u64 dmap_start, u64 dmap_end);
|
||||
int fuse_dax_conn_alloc(struct fuse_conn *fc, struct dax_device *dax_dev);
|
||||
int fuse_dax_conn_alloc(struct fuse_conn *fc, enum fuse_dax_mode mode,
|
||||
struct dax_device *dax_dev);
|
||||
void fuse_dax_conn_free(struct fuse_conn *fc);
|
||||
bool fuse_dax_inode_alloc(struct super_block *sb, struct fuse_inode *fi);
|
||||
void fuse_dax_inode_init(struct inode *inode);
|
||||
void fuse_dax_inode_init(struct inode *inode, unsigned int flags);
|
||||
void fuse_dax_inode_cleanup(struct inode *inode);
|
||||
void fuse_dax_dontcache(struct inode *inode, unsigned int flags);
|
||||
bool fuse_dax_check_alignment(struct fuse_conn *fc, unsigned int map_alignment);
|
||||
void fuse_dax_cancel_work(struct fuse_conn *fc);
|
||||
|
||||
|
|
|
@ -301,6 +301,9 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
|
|||
if (inval)
|
||||
invalidate_inode_pages2(inode->i_mapping);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_FUSE_DAX))
|
||||
fuse_dax_dontcache(inode, attr->flags);
|
||||
}
|
||||
|
||||
static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
|
||||
|
@ -313,7 +316,7 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
|
|||
inode->i_ctime.tv_nsec = attr->ctimensec;
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
fuse_init_common(inode);
|
||||
fuse_init_file_inode(inode);
|
||||
fuse_init_file_inode(inode, attr->flags);
|
||||
} else if (S_ISDIR(inode->i_mode))
|
||||
fuse_init_dir(inode);
|
||||
else if (S_ISLNK(inode->i_mode))
|
||||
|
@ -767,8 +770,12 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
|
|||
seq_printf(m, ",blksize=%lu", sb->s_blocksize);
|
||||
}
|
||||
#ifdef CONFIG_FUSE_DAX
|
||||
if (fc->dax)
|
||||
seq_puts(m, ",dax");
|
||||
if (fc->dax_mode == FUSE_DAX_ALWAYS)
|
||||
seq_puts(m, ",dax=always");
|
||||
else if (fc->dax_mode == FUSE_DAX_NEVER)
|
||||
seq_puts(m, ",dax=never");
|
||||
else if (fc->dax_mode == FUSE_DAX_INODE_USER)
|
||||
seq_puts(m, ",dax=inode");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -1109,73 +1116,80 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
|
|||
process_init_limits(fc, arg);
|
||||
|
||||
if (arg->minor >= 6) {
|
||||
u64 flags = arg->flags | (u64) arg->flags2 << 32;
|
||||
|
||||
ra_pages = arg->max_readahead / PAGE_SIZE;
|
||||
if (arg->flags & FUSE_ASYNC_READ)
|
||||
if (flags & FUSE_ASYNC_READ)
|
||||
fc->async_read = 1;
|
||||
if (!(arg->flags & FUSE_POSIX_LOCKS))
|
||||
if (!(flags & FUSE_POSIX_LOCKS))
|
||||
fc->no_lock = 1;
|
||||
if (arg->minor >= 17) {
|
||||
if (!(arg->flags & FUSE_FLOCK_LOCKS))
|
||||
if (!(flags & FUSE_FLOCK_LOCKS))
|
||||
fc->no_flock = 1;
|
||||
} else {
|
||||
if (!(arg->flags & FUSE_POSIX_LOCKS))
|
||||
if (!(flags & FUSE_POSIX_LOCKS))
|
||||
fc->no_flock = 1;
|
||||
}
|
||||
if (arg->flags & FUSE_ATOMIC_O_TRUNC)
|
||||
if (flags & FUSE_ATOMIC_O_TRUNC)
|
||||
fc->atomic_o_trunc = 1;
|
||||
if (arg->minor >= 9) {
|
||||
/* LOOKUP has dependency on proto version */
|
||||
if (arg->flags & FUSE_EXPORT_SUPPORT)
|
||||
if (flags & FUSE_EXPORT_SUPPORT)
|
||||
fc->export_support = 1;
|
||||
}
|
||||
if (arg->flags & FUSE_BIG_WRITES)
|
||||
if (flags & FUSE_BIG_WRITES)
|
||||
fc->big_writes = 1;
|
||||
if (arg->flags & FUSE_DONT_MASK)
|
||||
if (flags & FUSE_DONT_MASK)
|
||||
fc->dont_mask = 1;
|
||||
if (arg->flags & FUSE_AUTO_INVAL_DATA)
|
||||
if (flags & FUSE_AUTO_INVAL_DATA)
|
||||
fc->auto_inval_data = 1;
|
||||
else if (arg->flags & FUSE_EXPLICIT_INVAL_DATA)
|
||||
else if (flags & FUSE_EXPLICIT_INVAL_DATA)
|
||||
fc->explicit_inval_data = 1;
|
||||
if (arg->flags & FUSE_DO_READDIRPLUS) {
|
||||
if (flags & FUSE_DO_READDIRPLUS) {
|
||||
fc->do_readdirplus = 1;
|
||||
if (arg->flags & FUSE_READDIRPLUS_AUTO)
|
||||
if (flags & FUSE_READDIRPLUS_AUTO)
|
||||
fc->readdirplus_auto = 1;
|
||||
}
|
||||
if (arg->flags & FUSE_ASYNC_DIO)
|
||||
if (flags & FUSE_ASYNC_DIO)
|
||||
fc->async_dio = 1;
|
||||
if (arg->flags & FUSE_WRITEBACK_CACHE)
|
||||
if (flags & FUSE_WRITEBACK_CACHE)
|
||||
fc->writeback_cache = 1;
|
||||
if (arg->flags & FUSE_PARALLEL_DIROPS)
|
||||
if (flags & FUSE_PARALLEL_DIROPS)
|
||||
fc->parallel_dirops = 1;
|
||||
if (arg->flags & FUSE_HANDLE_KILLPRIV)
|
||||
if (flags & FUSE_HANDLE_KILLPRIV)
|
||||
fc->handle_killpriv = 1;
|
||||
if (arg->time_gran && arg->time_gran <= 1000000000)
|
||||
fm->sb->s_time_gran = arg->time_gran;
|
||||
if ((arg->flags & FUSE_POSIX_ACL)) {
|
||||
if ((flags & FUSE_POSIX_ACL)) {
|
||||
fc->default_permissions = 1;
|
||||
fc->posix_acl = 1;
|
||||
fm->sb->s_xattr = fuse_acl_xattr_handlers;
|
||||
}
|
||||
if (arg->flags & FUSE_CACHE_SYMLINKS)
|
||||
if (flags & FUSE_CACHE_SYMLINKS)
|
||||
fc->cache_symlinks = 1;
|
||||
if (arg->flags & FUSE_ABORT_ERROR)
|
||||
if (flags & FUSE_ABORT_ERROR)
|
||||
fc->abort_err = 1;
|
||||
if (arg->flags & FUSE_MAX_PAGES) {
|
||||
if (flags & FUSE_MAX_PAGES) {
|
||||
fc->max_pages =
|
||||
min_t(unsigned int, fc->max_pages_limit,
|
||||
max_t(unsigned int, arg->max_pages, 1));
|
||||
}
|
||||
if (IS_ENABLED(CONFIG_FUSE_DAX) &&
|
||||
arg->flags & FUSE_MAP_ALIGNMENT &&
|
||||
!fuse_dax_check_alignment(fc, arg->map_alignment)) {
|
||||
ok = false;
|
||||
if (IS_ENABLED(CONFIG_FUSE_DAX)) {
|
||||
if (flags & FUSE_MAP_ALIGNMENT &&
|
||||
!fuse_dax_check_alignment(fc, arg->map_alignment)) {
|
||||
ok = false;
|
||||
}
|
||||
if (flags & FUSE_HAS_INODE_DAX)
|
||||
fc->inode_dax = 1;
|
||||
}
|
||||
if (arg->flags & FUSE_HANDLE_KILLPRIV_V2) {
|
||||
if (flags & FUSE_HANDLE_KILLPRIV_V2) {
|
||||
fc->handle_killpriv_v2 = 1;
|
||||
fm->sb->s_flags |= SB_NOSEC;
|
||||
}
|
||||
if (arg->flags & FUSE_SETXATTR_EXT)
|
||||
if (flags & FUSE_SETXATTR_EXT)
|
||||
fc->setxattr_ext = 1;
|
||||
if (flags & FUSE_SECURITY_CTX)
|
||||
fc->init_security = 1;
|
||||
} else {
|
||||
ra_pages = fc->max_read / PAGE_SIZE;
|
||||
fc->no_lock = 1;
|
||||
|
@ -1203,13 +1217,14 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
|
|||
void fuse_send_init(struct fuse_mount *fm)
|
||||
{
|
||||
struct fuse_init_args *ia;
|
||||
u64 flags;
|
||||
|
||||
ia = kzalloc(sizeof(*ia), GFP_KERNEL | __GFP_NOFAIL);
|
||||
|
||||
ia->in.major = FUSE_KERNEL_VERSION;
|
||||
ia->in.minor = FUSE_KERNEL_MINOR_VERSION;
|
||||
ia->in.max_readahead = fm->sb->s_bdi->ra_pages * PAGE_SIZE;
|
||||
ia->in.flags |=
|
||||
flags =
|
||||
FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
|
||||
FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
|
||||
FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
|
||||
|
@ -1219,13 +1234,19 @@ void fuse_send_init(struct fuse_mount *fm)
|
|||
FUSE_PARALLEL_DIROPS | FUSE_HANDLE_KILLPRIV | FUSE_POSIX_ACL |
|
||||
FUSE_ABORT_ERROR | FUSE_MAX_PAGES | FUSE_CACHE_SYMLINKS |
|
||||
FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA |
|
||||
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT;
|
||||
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
|
||||
FUSE_SECURITY_CTX;
|
||||
#ifdef CONFIG_FUSE_DAX
|
||||
if (fm->fc->dax)
|
||||
ia->in.flags |= FUSE_MAP_ALIGNMENT;
|
||||
flags |= FUSE_MAP_ALIGNMENT;
|
||||
if (fuse_is_inode_dax_mode(fm->fc->dax_mode))
|
||||
flags |= FUSE_HAS_INODE_DAX;
|
||||
#endif
|
||||
if (fm->fc->auto_submounts)
|
||||
ia->in.flags |= FUSE_SUBMOUNTS;
|
||||
flags |= FUSE_SUBMOUNTS;
|
||||
|
||||
ia->in.flags = flags;
|
||||
ia->in.flags2 = flags >> 32;
|
||||
|
||||
ia->args.opcode = FUSE_INIT;
|
||||
ia->args.in_numargs = 1;
|
||||
|
@ -1514,7 +1535,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
|
|||
sb->s_subtype = ctx->subtype;
|
||||
ctx->subtype = NULL;
|
||||
if (IS_ENABLED(CONFIG_FUSE_DAX)) {
|
||||
err = fuse_dax_conn_alloc(fc, ctx->dax_dev);
|
||||
err = fuse_dax_conn_alloc(fc, ctx->dax_mode, ctx->dax_dev);
|
||||
if (err)
|
||||
goto err;
|
||||
}
|
||||
|
|
|
@ -88,12 +88,21 @@ struct virtio_fs_req_work {
|
|||
static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
|
||||
struct fuse_req *req, bool in_flight);
|
||||
|
||||
static const struct constant_table dax_param_enums[] = {
|
||||
{"always", FUSE_DAX_ALWAYS },
|
||||
{"never", FUSE_DAX_NEVER },
|
||||
{"inode", FUSE_DAX_INODE_USER },
|
||||
{}
|
||||
};
|
||||
|
||||
enum {
|
||||
OPT_DAX,
|
||||
OPT_DAX_ENUM,
|
||||
};
|
||||
|
||||
static const struct fs_parameter_spec virtio_fs_parameters[] = {
|
||||
fsparam_flag("dax", OPT_DAX),
|
||||
fsparam_enum("dax", OPT_DAX_ENUM, dax_param_enums),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -110,7 +119,10 @@ static int virtio_fs_parse_param(struct fs_context *fsc,
|
|||
|
||||
switch (opt) {
|
||||
case OPT_DAX:
|
||||
ctx->dax = 1;
|
||||
ctx->dax_mode = FUSE_DAX_ALWAYS;
|
||||
break;
|
||||
case OPT_DAX_ENUM:
|
||||
ctx->dax_mode = result.uint_32;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -1326,8 +1338,8 @@ static int virtio_fs_fill_super(struct super_block *sb, struct fs_context *fsc)
|
|||
|
||||
/* virtiofs allocates and installs its own fuse devices */
|
||||
ctx->fudptr = NULL;
|
||||
if (ctx->dax) {
|
||||
if (!fs->dax_dev) {
|
||||
if (ctx->dax_mode != FUSE_DAX_NEVER) {
|
||||
if (ctx->dax_mode == FUSE_DAX_ALWAYS && !fs->dax_dev) {
|
||||
err = -EINVAL;
|
||||
pr_err("virtio-fs: dax can't be enabled as filesystem"
|
||||
" device does not support it.\n");
|
||||
|
|
|
@ -187,6 +187,13 @@
|
|||
*
|
||||
* 7.35
|
||||
* - add FOPEN_NOFLUSH
|
||||
*
|
||||
* 7.36
|
||||
* - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag
|
||||
* - add flags2 to fuse_init_in and fuse_init_out
|
||||
* - add FUSE_SECURITY_CTX init flag
|
||||
* - add security context to create, mkdir, symlink, and mknod requests
|
||||
* - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
|
@ -222,7 +229,7 @@
|
|||
#define FUSE_KERNEL_VERSION 7
|
||||
|
||||
/** Minor version number of this interface */
|
||||
#define FUSE_KERNEL_MINOR_VERSION 35
|
||||
#define FUSE_KERNEL_MINOR_VERSION 36
|
||||
|
||||
/** The node ID of the root inode */
|
||||
#define FUSE_ROOT_ID 1
|
||||
|
@ -341,6 +348,11 @@ struct fuse_file_lock {
|
|||
* write/truncate sgid is killed only if file has group
|
||||
* execute permission. (Same as Linux VFS behavior).
|
||||
* FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in
|
||||
* FUSE_INIT_EXT: extended fuse_init_in request
|
||||
* FUSE_INIT_RESERVED: reserved, do not use
|
||||
* FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and
|
||||
* mknod
|
||||
* FUSE_HAS_INODE_DAX: use per inode DAX
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
|
@ -372,6 +384,11 @@ struct fuse_file_lock {
|
|||
#define FUSE_SUBMOUNTS (1 << 27)
|
||||
#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28)
|
||||
#define FUSE_SETXATTR_EXT (1 << 29)
|
||||
#define FUSE_INIT_EXT (1 << 30)
|
||||
#define FUSE_INIT_RESERVED (1 << 31)
|
||||
/* bits 32..63 get shifted down 32 bits into the flags2 field */
|
||||
#define FUSE_SECURITY_CTX (1ULL << 32)
|
||||
#define FUSE_HAS_INODE_DAX (1ULL << 33)
|
||||
|
||||
/**
|
||||
* CUSE INIT request/reply flags
|
||||
|
@ -454,8 +471,10 @@ struct fuse_file_lock {
|
|||
* fuse_attr flags
|
||||
*
|
||||
* FUSE_ATTR_SUBMOUNT: Object is a submount root
|
||||
* FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode
|
||||
*/
|
||||
#define FUSE_ATTR_SUBMOUNT (1 << 0)
|
||||
#define FUSE_ATTR_DAX (1 << 1)
|
||||
|
||||
/**
|
||||
* Open flags
|
||||
|
@ -741,6 +760,8 @@ struct fuse_init_in {
|
|||
uint32_t minor;
|
||||
uint32_t max_readahead;
|
||||
uint32_t flags;
|
||||
uint32_t flags2;
|
||||
uint32_t unused[11];
|
||||
};
|
||||
|
||||
#define FUSE_COMPAT_INIT_OUT_SIZE 8
|
||||
|
@ -757,7 +778,8 @@ struct fuse_init_out {
|
|||
uint32_t time_gran;
|
||||
uint16_t max_pages;
|
||||
uint16_t map_alignment;
|
||||
uint32_t unused[8];
|
||||
uint32_t flags2;
|
||||
uint32_t unused[7];
|
||||
};
|
||||
|
||||
#define CUSE_INIT_INFO_MAX 4096
|
||||
|
@ -865,9 +887,12 @@ struct fuse_dirent {
|
|||
char name[];
|
||||
};
|
||||
|
||||
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
|
||||
#define FUSE_DIRENT_ALIGN(x) \
|
||||
/* Align variable length records to 64bit boundary */
|
||||
#define FUSE_REC_ALIGN(x) \
|
||||
(((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
|
||||
|
||||
#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
|
||||
#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x)
|
||||
#define FUSE_DIRENT_SIZE(d) \
|
||||
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
|
||||
|
||||
|
@ -984,4 +1009,26 @@ struct fuse_syncfs_in {
|
|||
uint64_t padding;
|
||||
};
|
||||
|
||||
/*
|
||||
* For each security context, send fuse_secctx with size of security context
|
||||
* fuse_secctx will be followed by security context name and this in turn
|
||||
* will be followed by actual context label.
|
||||
* fuse_secctx, name, context
|
||||
*/
|
||||
struct fuse_secctx {
|
||||
uint32_t size;
|
||||
uint32_t padding;
|
||||
};
|
||||
|
||||
/*
|
||||
* Contains the information about how many fuse_secctx structures are being
|
||||
* sent and what's the total size of all security contexts (including
|
||||
* size of fuse_secctx_header).
|
||||
*
|
||||
*/
|
||||
struct fuse_secctx_header {
|
||||
uint32_t size;
|
||||
uint32_t nr_secctx;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_FUSE_H */
|
||||
|
|
Загрузка…
Ссылка в новой задаче