Commit 8975f897 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 1fb38c93 073c3ab6
......@@ -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 @@ static int fuse_dax_mem_range_init(struct fuse_conn_dax *fcd)
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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment