Commit f7fccaa7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fuse-update-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

 - Add support for idmapped fuse mounts (Alexander Mikhalitsyn)

 - Add optimization when checking for writeback (yangyun)

 - Add tracepoints (Josef Bacik)

 - Clean up writeback code (Joanne Koong)

 - Clean up request queuing (me)

 - Misc fixes

* tag 'fuse-update-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse: (32 commits)
  fuse: use exclusive lock when FUSE_I_CACHE_IO_MODE is set
  fuse: clear FR_PENDING if abort is detected when sending request
  fs/fuse: convert to use invalid_mnt_idmap
  fs/mnt_idmapping: introduce an invalid_mnt_idmap
  fs/fuse: introduce and use fuse_simple_idmap_request() helper
  fs/fuse: fix null-ptr-deref when checking SB_I_NOIDMAP flag
  fuse: allow O_PATH fd for FUSE_DEV_IOC_BACKING_OPEN
  virtio_fs: allow idmapped mounts
  fuse: allow idmapped mounts
  fuse: warn if fuse_access is called when idmapped mounts are allowed
  fuse: handle idmappings properly in ->write_iter()
  fuse: support idmapped ->rename op
  fuse: support idmapped ->set_acl
  fuse: drop idmap argument from __fuse_get_acl
  fuse: support idmapped ->setattr op
  fuse: support idmapped ->permission inode op
  fuse: support idmapped getattr inode op
  fuse: support idmap for mkdir/mknod/symlink/create/tmpfile
  fuse: support idmapped FUSE_EXT_GROUPS
  fuse: add an idmap argument to fuse_simple_request
  ...
parents 4165cee7 2f3d8ff4
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
# Makefile for the FUSE filesystem. # Makefile for the FUSE filesystem.
# #
# Needed for trace events
ccflags-y = -I$(src)
obj-$(CONFIG_FUSE_FS) += fuse.o obj-$(CONFIG_FUSE_FS) += fuse.o
obj-$(CONFIG_CUSE) += cuse.o obj-$(CONFIG_CUSE) += cuse.o
obj-$(CONFIG_VIRTIO_FS) += virtiofs.o obj-$(CONFIG_VIRTIO_FS) += virtiofs.o
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <linux/posix_acl_xattr.h> #include <linux/posix_acl_xattr.h>
static struct posix_acl *__fuse_get_acl(struct fuse_conn *fc, static struct posix_acl *__fuse_get_acl(struct fuse_conn *fc,
struct mnt_idmap *idmap,
struct inode *inode, int type, bool rcu) struct inode *inode, int type, bool rcu)
{ {
int size; int size;
...@@ -74,7 +73,7 @@ struct posix_acl *fuse_get_acl(struct mnt_idmap *idmap, ...@@ -74,7 +73,7 @@ struct posix_acl *fuse_get_acl(struct mnt_idmap *idmap,
if (fuse_no_acl(fc, inode)) if (fuse_no_acl(fc, inode))
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
return __fuse_get_acl(fc, idmap, inode, type, false); return __fuse_get_acl(fc, inode, type, false);
} }
struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu) struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu)
...@@ -90,8 +89,7 @@ struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu) ...@@ -90,8 +89,7 @@ struct posix_acl *fuse_get_inode_acl(struct inode *inode, int type, bool rcu)
*/ */
if (!fc->posix_acl) if (!fc->posix_acl)
return NULL; return NULL;
return __fuse_get_acl(fc, inode, type, rcu);
return __fuse_get_acl(fc, &nop_mnt_idmap, inode, type, rcu);
} }
int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
...@@ -146,8 +144,8 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, ...@@ -146,8 +144,8 @@ int fuse_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
* be stripped. * be stripped.
*/ */
if (fc->posix_acl && if (fc->posix_acl &&
!in_group_or_capable(&nop_mnt_idmap, inode, !in_group_or_capable(idmap, inode,
i_gid_into_vfsgid(&nop_mnt_idmap, inode))) i_gid_into_vfsgid(idmap, inode)))
extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID; extra_flags |= FUSE_SETXATTR_ACL_KILL_SGID;
ret = fuse_setxattr(inode, name, value, size, 0, extra_flags); ret = fuse_setxattr(inode, name, value, size, 0, extra_flags);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -449,22 +449,19 @@ struct fuse_iqueue; ...@@ -449,22 +449,19 @@ struct fuse_iqueue;
*/ */
struct fuse_iqueue_ops { struct fuse_iqueue_ops {
/** /**
* Signal that a forget has been queued * Send one forget
*/ */
void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq) void (*send_forget)(struct fuse_iqueue *fiq, struct fuse_forget_link *link);
__releases(fiq->lock);
/** /**
* Signal that an INTERRUPT request has been queued * Send interrupt for request
*/ */
void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq) void (*send_interrupt)(struct fuse_iqueue *fiq, struct fuse_req *req);
__releases(fiq->lock);
/** /**
* Signal that a request has been queued * Send one request
*/ */
void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq) void (*send_req)(struct fuse_iqueue *fiq, struct fuse_req *req);
__releases(fiq->lock);
/** /**
* Clean up when fuse_iqueue is destroyed * Clean up when fuse_iqueue is destroyed
...@@ -869,7 +866,7 @@ struct fuse_conn { ...@@ -869,7 +866,7 @@ struct fuse_conn {
/** Negotiated minor version */ /** Negotiated minor version */
unsigned minor; unsigned minor;
/** Entry on the fuse_mount_list */ /** Entry on the fuse_conn_list */
struct list_head entry; struct list_head entry;
/** Device ID from the root super block */ /** Device ID from the root super block */
...@@ -1053,10 +1050,6 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, ...@@ -1053,10 +1050,6 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
struct fuse_forget_link *fuse_alloc_forget(void); struct fuse_forget_link *fuse_alloc_forget(void);
struct fuse_forget_link *fuse_dequeue_forget(struct fuse_iqueue *fiq,
unsigned int max,
unsigned int *countp);
/* /*
* Initialize READ or READDIR request * Initialize READ or READDIR request
*/ */
...@@ -1154,7 +1147,22 @@ void __exit fuse_ctl_cleanup(void); ...@@ -1154,7 +1147,22 @@ void __exit fuse_ctl_cleanup(void);
/** /**
* Simple request sending that does request allocation and freeing * Simple request sending that does request allocation and freeing
*/ */
ssize_t fuse_simple_request(struct fuse_mount *fm, struct fuse_args *args); ssize_t __fuse_simple_request(struct mnt_idmap *idmap,
struct fuse_mount *fm,
struct fuse_args *args);
static inline ssize_t fuse_simple_request(struct fuse_mount *fm, struct fuse_args *args)
{
return __fuse_simple_request(&invalid_mnt_idmap, fm, args);
}
static inline ssize_t fuse_simple_idmap_request(struct mnt_idmap *idmap,
struct fuse_mount *fm,
struct fuse_args *args)
{
return __fuse_simple_request(idmap, fm, args);
}
int fuse_simple_background(struct fuse_mount *fm, struct fuse_args *args, int fuse_simple_background(struct fuse_mount *fm, struct fuse_args *args,
gfp_t gfp_flags); gfp_t gfp_flags);
...@@ -1330,8 +1338,8 @@ bool fuse_write_update_attr(struct inode *inode, loff_t pos, ssize_t written); ...@@ -1330,8 +1338,8 @@ bool fuse_write_update_attr(struct inode *inode, loff_t pos, ssize_t written);
int fuse_flush_times(struct inode *inode, struct fuse_file *ff); int fuse_flush_times(struct inode *inode, struct fuse_file *ff);
int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct file *file); struct iattr *attr, struct file *file);
void fuse_set_initialized(struct fuse_conn *fc); void fuse_set_initialized(struct fuse_conn *fc);
......
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM fuse
#if !defined(_TRACE_FUSE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_FUSE_H
#include <linux/tracepoint.h>
#define OPCODES \
EM( FUSE_LOOKUP, "FUSE_LOOKUP") \
EM( FUSE_FORGET, "FUSE_FORGET") \
EM( FUSE_GETATTR, "FUSE_GETATTR") \
EM( FUSE_SETATTR, "FUSE_SETATTR") \
EM( FUSE_READLINK, "FUSE_READLINK") \
EM( FUSE_SYMLINK, "FUSE_SYMLINK") \
EM( FUSE_MKNOD, "FUSE_MKNOD") \
EM( FUSE_MKDIR, "FUSE_MKDIR") \
EM( FUSE_UNLINK, "FUSE_UNLINK") \
EM( FUSE_RMDIR, "FUSE_RMDIR") \
EM( FUSE_RENAME, "FUSE_RENAME") \
EM( FUSE_LINK, "FUSE_LINK") \
EM( FUSE_OPEN, "FUSE_OPEN") \
EM( FUSE_READ, "FUSE_READ") \
EM( FUSE_WRITE, "FUSE_WRITE") \
EM( FUSE_STATFS, "FUSE_STATFS") \
EM( FUSE_RELEASE, "FUSE_RELEASE") \
EM( FUSE_FSYNC, "FUSE_FSYNC") \
EM( FUSE_SETXATTR, "FUSE_SETXATTR") \
EM( FUSE_GETXATTR, "FUSE_GETXATTR") \
EM( FUSE_LISTXATTR, "FUSE_LISTXATTR") \
EM( FUSE_REMOVEXATTR, "FUSE_REMOVEXATTR") \
EM( FUSE_FLUSH, "FUSE_FLUSH") \
EM( FUSE_INIT, "FUSE_INIT") \
EM( FUSE_OPENDIR, "FUSE_OPENDIR") \
EM( FUSE_READDIR, "FUSE_READDIR") \
EM( FUSE_RELEASEDIR, "FUSE_RELEASEDIR") \
EM( FUSE_FSYNCDIR, "FUSE_FSYNCDIR") \
EM( FUSE_GETLK, "FUSE_GETLK") \
EM( FUSE_SETLK, "FUSE_SETLK") \
EM( FUSE_SETLKW, "FUSE_SETLKW") \
EM( FUSE_ACCESS, "FUSE_ACCESS") \
EM( FUSE_CREATE, "FUSE_CREATE") \
EM( FUSE_INTERRUPT, "FUSE_INTERRUPT") \
EM( FUSE_BMAP, "FUSE_BMAP") \
EM( FUSE_DESTROY, "FUSE_DESTROY") \
EM( FUSE_IOCTL, "FUSE_IOCTL") \
EM( FUSE_POLL, "FUSE_POLL") \
EM( FUSE_NOTIFY_REPLY, "FUSE_NOTIFY_REPLY") \
EM( FUSE_BATCH_FORGET, "FUSE_BATCH_FORGET") \
EM( FUSE_FALLOCATE, "FUSE_FALLOCATE") \
EM( FUSE_READDIRPLUS, "FUSE_READDIRPLUS") \
EM( FUSE_RENAME2, "FUSE_RENAME2") \
EM( FUSE_LSEEK, "FUSE_LSEEK") \
EM( FUSE_COPY_FILE_RANGE, "FUSE_COPY_FILE_RANGE") \
EM( FUSE_SETUPMAPPING, "FUSE_SETUPMAPPING") \
EM( FUSE_REMOVEMAPPING, "FUSE_REMOVEMAPPING") \
EM( FUSE_SYNCFS, "FUSE_SYNCFS") \
EM( FUSE_TMPFILE, "FUSE_TMPFILE") \
EM( FUSE_STATX, "FUSE_STATX") \
EMe(CUSE_INIT, "CUSE_INIT")
/*
* This will turn the above table into TRACE_DEFINE_ENUM() for each of the
* entries.
*/
#undef EM
#undef EMe
#define EM(a, b) TRACE_DEFINE_ENUM(a);
#define EMe(a, b) TRACE_DEFINE_ENUM(a);
OPCODES
/* Now we redfine it with the table that __print_symbolic needs. */
#undef EM
#undef EMe
#define EM(a, b) {a, b},
#define EMe(a, b) {a, b}
TRACE_EVENT(fuse_request_send,
TP_PROTO(const struct fuse_req *req),
TP_ARGS(req),
TP_STRUCT__entry(
__field(dev_t, connection)
__field(uint64_t, unique)
__field(enum fuse_opcode, opcode)
__field(uint32_t, len)
),
TP_fast_assign(
__entry->connection = req->fm->fc->dev;
__entry->unique = req->in.h.unique;
__entry->opcode = req->in.h.opcode;
__entry->len = req->in.h.len;
),
TP_printk("connection %u req %llu opcode %u (%s) len %u ",
__entry->connection, __entry->unique, __entry->opcode,
__print_symbolic(__entry->opcode, OPCODES), __entry->len)
);
TRACE_EVENT(fuse_request_end,
TP_PROTO(const struct fuse_req *req),
TP_ARGS(req),
TP_STRUCT__entry(
__field(dev_t, connection)
__field(uint64_t, unique)
__field(uint32_t, len)
__field(int32_t, error)
),
TP_fast_assign(
__entry->connection = req->fm->fc->dev;
__entry->unique = req->in.h.unique;
__entry->len = req->out.h.len;
__entry->error = req->out.h.error;
),
TP_printk("connection %u req %llu len %u error %d", __entry->connection,
__entry->unique, __entry->len, __entry->error)
);
#endif /* _TRACE_FUSE_H */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE fuse_trace
#include <trace/define_trace.h>
...@@ -1348,6 +1348,12 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args, ...@@ -1348,6 +1348,12 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
} }
if (flags & FUSE_NO_EXPORT_SUPPORT) if (flags & FUSE_NO_EXPORT_SUPPORT)
fm->sb->s_export_op = &fuse_export_fid_operations; fm->sb->s_export_op = &fuse_export_fid_operations;
if (flags & FUSE_ALLOW_IDMAP) {
if (fc->default_permissions)
fm->sb->s_iflags &= ~SB_I_NOIDMAP;
else
ok = false;
}
} else { } else {
ra_pages = fc->max_read / PAGE_SIZE; ra_pages = fc->max_read / PAGE_SIZE;
fc->no_lock = 1; fc->no_lock = 1;
...@@ -1395,7 +1401,7 @@ void fuse_send_init(struct fuse_mount *fm) ...@@ -1395,7 +1401,7 @@ void fuse_send_init(struct fuse_mount *fm)
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT | FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP | FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP | FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND; FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_ALLOW_IDMAP;
#ifdef CONFIG_FUSE_DAX #ifdef CONFIG_FUSE_DAX
if (fm->fc->dax) if (fm->fc->dax)
flags |= FUSE_MAP_ALIGNMENT; flags |= FUSE_MAP_ALIGNMENT;
...@@ -1572,6 +1578,7 @@ static void fuse_sb_defaults(struct super_block *sb) ...@@ -1572,6 +1578,7 @@ static void fuse_sb_defaults(struct super_block *sb)
sb->s_time_gran = 1; sb->s_time_gran = 1;
sb->s_export_op = &fuse_export_operations; sb->s_export_op = &fuse_export_operations;
sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE; sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE;
sb->s_iflags |= SB_I_NOIDMAP;
if (sb->s_user_ns != &init_user_ns) if (sb->s_user_ns != &init_user_ns)
sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER; sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION); sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);
...@@ -1984,7 +1991,7 @@ static void fuse_kill_sb_anon(struct super_block *sb) ...@@ -1984,7 +1991,7 @@ static void fuse_kill_sb_anon(struct super_block *sb)
static struct file_system_type fuse_fs_type = { static struct file_system_type fuse_fs_type = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "fuse", .name = "fuse",
.fs_flags = FS_HAS_SUBTYPE | FS_USERNS_MOUNT, .fs_flags = FS_HAS_SUBTYPE | FS_USERNS_MOUNT | FS_ALLOW_IDMAP,
.init_fs_context = fuse_init_fs_context, .init_fs_context = fuse_init_fs_context,
.parameters = fuse_fs_parameters, .parameters = fuse_fs_parameters,
.kill_sb = fuse_kill_sb_anon, .kill_sb = fuse_kill_sb_anon,
...@@ -2005,7 +2012,7 @@ static struct file_system_type fuseblk_fs_type = { ...@@ -2005,7 +2012,7 @@ static struct file_system_type fuseblk_fs_type = {
.init_fs_context = fuse_init_fs_context, .init_fs_context = fuse_init_fs_context,
.parameters = fuse_fs_parameters, .parameters = fuse_fs_parameters,
.kill_sb = fuse_kill_sb_blk, .kill_sb = fuse_kill_sb_blk,
.fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE, .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE | FS_ALLOW_IDMAP,
}; };
MODULE_ALIAS_FS("fuseblk"); MODULE_ALIAS_FS("fuseblk");
......
...@@ -228,16 +228,13 @@ int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map) ...@@ -228,16 +228,13 @@ int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
if (map->flags || map->padding) if (map->flags || map->padding)
goto out; goto out;
file = fget(map->fd); file = fget_raw(map->fd);
res = -EBADF; res = -EBADF;
if (!file) if (!file)
goto out; goto out;
res = -EOPNOTSUPP;
if (!file->f_op->read_iter || !file->f_op->write_iter)
goto out_fput;
backing_sb = file_inode(file)->i_sb; backing_sb = file_inode(file)->i_sb;
pr_info("%s: %x:%pD %i\n", __func__, backing_sb->s_dev, file, backing_sb->s_stack_depth);
res = -ELOOP; res = -ELOOP;
if (backing_sb->s_stack_depth >= fc->max_stack_depth) if (backing_sb->s_stack_depth >= fc->max_stack_depth)
goto out_fput; goto out_fput;
......
...@@ -1091,22 +1091,13 @@ static struct virtio_driver virtio_fs_driver = { ...@@ -1091,22 +1091,13 @@ static struct virtio_driver virtio_fs_driver = {
#endif #endif
}; };
static void virtio_fs_wake_forget_and_unlock(struct fuse_iqueue *fiq) static void virtio_fs_send_forget(struct fuse_iqueue *fiq, struct fuse_forget_link *link)
__releases(fiq->lock)
{ {
struct fuse_forget_link *link;
struct virtio_fs_forget *forget; struct virtio_fs_forget *forget;
struct virtio_fs_forget_req *req; struct virtio_fs_forget_req *req;
struct virtio_fs *fs; struct virtio_fs *fs = fiq->priv;
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq = &fs->vqs[VQ_HIPRIO];
u64 unique; u64 unique = fuse_get_unique(fiq);
link = fuse_dequeue_forget(fiq, 1, NULL);
unique = fuse_get_unique(fiq);
fs = fiq->priv;
fsvq = &fs->vqs[VQ_HIPRIO];
spin_unlock(&fiq->lock);
/* Allocate a buffer for the request */ /* Allocate a buffer for the request */
forget = kmalloc(sizeof(*forget), GFP_NOFS | __GFP_NOFAIL); forget = kmalloc(sizeof(*forget), GFP_NOFS | __GFP_NOFAIL);
...@@ -1126,8 +1117,7 @@ __releases(fiq->lock) ...@@ -1126,8 +1117,7 @@ __releases(fiq->lock)
kfree(link); kfree(link);
} }
static void virtio_fs_wake_interrupt_and_unlock(struct fuse_iqueue *fiq) static void virtio_fs_send_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
__releases(fiq->lock)
{ {
/* /*
* TODO interrupts. * TODO interrupts.
...@@ -1136,7 +1126,6 @@ __releases(fiq->lock) ...@@ -1136,7 +1126,6 @@ __releases(fiq->lock)
* Exceptions are blocking lock operations; for example fcntl(F_SETLKW) * Exceptions are blocking lock operations; for example fcntl(F_SETLKW)
* with shared lock between host and guest. * with shared lock between host and guest.
*/ */
spin_unlock(&fiq->lock);
} }
/* Count number of scatter-gather elements required */ /* Count number of scatter-gather elements required */
...@@ -1341,21 +1330,17 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, ...@@ -1341,21 +1330,17 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
return ret; return ret;
} }
static void virtio_fs_wake_pending_and_unlock(struct fuse_iqueue *fiq) static void virtio_fs_send_req(struct fuse_iqueue *fiq, struct fuse_req *req)
__releases(fiq->lock)
{ {
unsigned int queue_id; unsigned int queue_id;
struct virtio_fs *fs; struct virtio_fs *fs;
struct fuse_req *req;
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq;
int ret; int ret;
WARN_ON(list_empty(&fiq->pending)); if (req->in.h.opcode != FUSE_NOTIFY_REPLY)
req = list_last_entry(&fiq->pending, struct fuse_req, list); req->in.h.unique = fuse_get_unique(fiq);
clear_bit(FR_PENDING, &req->flags); clear_bit(FR_PENDING, &req->flags);
list_del_init(&req->list);
WARN_ON(!list_empty(&fiq->pending));
spin_unlock(&fiq->lock);
fs = fiq->priv; fs = fiq->priv;
queue_id = VQ_REQUEST + fs->mq_map[raw_smp_processor_id()]; queue_id = VQ_REQUEST + fs->mq_map[raw_smp_processor_id()];
...@@ -1393,9 +1378,9 @@ __releases(fiq->lock) ...@@ -1393,9 +1378,9 @@ __releases(fiq->lock)
} }
static const struct fuse_iqueue_ops virtio_fs_fiq_ops = { static const struct fuse_iqueue_ops virtio_fs_fiq_ops = {
.wake_forget_and_unlock = virtio_fs_wake_forget_and_unlock, .send_forget = virtio_fs_send_forget,
.wake_interrupt_and_unlock = virtio_fs_wake_interrupt_and_unlock, .send_interrupt = virtio_fs_send_interrupt,
.wake_pending_and_unlock = virtio_fs_wake_pending_and_unlock, .send_req = virtio_fs_send_req,
.release = virtio_fs_fiq_release, .release = virtio_fs_fiq_release,
}; };
...@@ -1628,6 +1613,7 @@ static struct file_system_type virtio_fs_type = { ...@@ -1628,6 +1613,7 @@ static struct file_system_type virtio_fs_type = {
.name = "virtiofs", .name = "virtiofs",
.init_fs_context = virtio_fs_init_fs_context, .init_fs_context = virtio_fs_init_fs_context,
.kill_sb = virtio_kill_sb, .kill_sb = virtio_kill_sb,
.fs_flags = FS_ALLOW_IDMAP,
}; };
static int virtio_fs_uevent(const struct kobject *kobj, struct kobj_uevent_env *env) static int virtio_fs_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
......
...@@ -32,6 +32,15 @@ struct mnt_idmap nop_mnt_idmap = { ...@@ -32,6 +32,15 @@ struct mnt_idmap nop_mnt_idmap = {
}; };
EXPORT_SYMBOL_GPL(nop_mnt_idmap); EXPORT_SYMBOL_GPL(nop_mnt_idmap);
/*
* Carries the invalid idmapping of a full 0-4294967295 {g,u}id range.
* This means that all {g,u}ids are mapped to INVALID_VFS{G,U}ID.
*/
struct mnt_idmap invalid_mnt_idmap = {
.count = REFCOUNT_INIT(1),
};
EXPORT_SYMBOL_GPL(invalid_mnt_idmap);
/** /**
* initial_idmapping - check whether this is the initial mapping * initial_idmapping - check whether this is the initial mapping
* @ns: idmapping to check * @ns: idmapping to check
...@@ -75,6 +84,8 @@ vfsuid_t make_vfsuid(struct mnt_idmap *idmap, ...@@ -75,6 +84,8 @@ vfsuid_t make_vfsuid(struct mnt_idmap *idmap,
if (idmap == &nop_mnt_idmap) if (idmap == &nop_mnt_idmap)
return VFSUIDT_INIT(kuid); return VFSUIDT_INIT(kuid);
if (idmap == &invalid_mnt_idmap)
return INVALID_VFSUID;
if (initial_idmapping(fs_userns)) if (initial_idmapping(fs_userns))
uid = __kuid_val(kuid); uid = __kuid_val(kuid);
else else
...@@ -112,6 +123,8 @@ vfsgid_t make_vfsgid(struct mnt_idmap *idmap, ...@@ -112,6 +123,8 @@ vfsgid_t make_vfsgid(struct mnt_idmap *idmap,
if (idmap == &nop_mnt_idmap) if (idmap == &nop_mnt_idmap)
return VFSGIDT_INIT(kgid); return VFSGIDT_INIT(kgid);
if (idmap == &invalid_mnt_idmap)
return INVALID_VFSGID;
if (initial_idmapping(fs_userns)) if (initial_idmapping(fs_userns))
gid = __kgid_val(kgid); gid = __kgid_val(kgid);
else else
...@@ -140,6 +153,8 @@ kuid_t from_vfsuid(struct mnt_idmap *idmap, ...@@ -140,6 +153,8 @@ kuid_t from_vfsuid(struct mnt_idmap *idmap,
if (idmap == &nop_mnt_idmap) if (idmap == &nop_mnt_idmap)
return AS_KUIDT(vfsuid); return AS_KUIDT(vfsuid);
if (idmap == &invalid_mnt_idmap)
return INVALID_UID;
uid = map_id_up(&idmap->uid_map, __vfsuid_val(vfsuid)); uid = map_id_up(&idmap->uid_map, __vfsuid_val(vfsuid));
if (uid == (uid_t)-1) if (uid == (uid_t)-1)
return INVALID_UID; return INVALID_UID;
...@@ -167,6 +182,8 @@ kgid_t from_vfsgid(struct mnt_idmap *idmap, ...@@ -167,6 +182,8 @@ kgid_t from_vfsgid(struct mnt_idmap *idmap,
if (idmap == &nop_mnt_idmap) if (idmap == &nop_mnt_idmap)
return AS_KGIDT(vfsgid); return AS_KGIDT(vfsgid);
if (idmap == &invalid_mnt_idmap)
return INVALID_GID;
gid = map_id_up(&idmap->gid_map, __vfsgid_val(vfsgid)); gid = map_id_up(&idmap->gid_map, __vfsgid_val(vfsgid));
if (gid == (gid_t)-1) if (gid == (gid_t)-1)
return INVALID_GID; return INVALID_GID;
...@@ -296,7 +313,7 @@ struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns) ...@@ -296,7 +313,7 @@ struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns)
*/ */
struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap) struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap)
{ {
if (idmap != &nop_mnt_idmap) if (idmap != &nop_mnt_idmap && idmap != &invalid_mnt_idmap)
refcount_inc(&idmap->count); refcount_inc(&idmap->count);
return idmap; return idmap;
...@@ -312,7 +329,8 @@ EXPORT_SYMBOL_GPL(mnt_idmap_get); ...@@ -312,7 +329,8 @@ EXPORT_SYMBOL_GPL(mnt_idmap_get);
*/ */
void mnt_idmap_put(struct mnt_idmap *idmap) void mnt_idmap_put(struct mnt_idmap *idmap)
{ {
if (idmap != &nop_mnt_idmap && refcount_dec_and_test(&idmap->count)) if (idmap != &nop_mnt_idmap && idmap != &invalid_mnt_idmap &&
refcount_dec_and_test(&idmap->count))
free_mnt_idmap(idmap); free_mnt_idmap(idmap);
} }
EXPORT_SYMBOL_GPL(mnt_idmap_put); EXPORT_SYMBOL_GPL(mnt_idmap_put);
...@@ -4471,6 +4471,10 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt) ...@@ -4471,6 +4471,10 @@ static int can_idmap_mount(const struct mount_kattr *kattr, struct mount *mnt)
if (!(m->mnt_sb->s_type->fs_flags & FS_ALLOW_IDMAP)) if (!(m->mnt_sb->s_type->fs_flags & FS_ALLOW_IDMAP))
return -EINVAL; return -EINVAL;
/* The filesystem has turned off idmapped mounts. */
if (m->mnt_sb->s_iflags & SB_I_NOIDMAP)
return -EINVAL;
/* We're not controlling the superblock. */ /* We're not controlling the superblock. */
if (!ns_capable(fs_userns, CAP_SYS_ADMIN)) if (!ns_capable(fs_userns, CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
......
...@@ -1229,6 +1229,7 @@ extern int send_sigurg(struct file *file); ...@@ -1229,6 +1229,7 @@ extern int send_sigurg(struct file *file);
#define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */ #define SB_I_TS_EXPIRY_WARNED 0x00000400 /* warned about timestamp range expiry */
#define SB_I_RETIRED 0x00000800 /* superblock shouldn't be reused */ #define SB_I_RETIRED 0x00000800 /* superblock shouldn't be reused */
#define SB_I_NOUMASK 0x00001000 /* VFS does not apply umask */ #define SB_I_NOUMASK 0x00001000 /* VFS does not apply umask */
#define SB_I_NOIDMAP 0x00002000 /* No idmapped mounts on this superblock */
/* Possible states of 'frozen' field */ /* Possible states of 'frozen' field */
enum { enum {
......
...@@ -9,6 +9,7 @@ struct mnt_idmap; ...@@ -9,6 +9,7 @@ struct mnt_idmap;
struct user_namespace; struct user_namespace;
extern struct mnt_idmap nop_mnt_idmap; extern struct mnt_idmap nop_mnt_idmap;
extern struct mnt_idmap invalid_mnt_idmap;
extern struct user_namespace init_user_ns; extern struct user_namespace init_user_ns;
typedef struct { typedef struct {
......
...@@ -217,6 +217,9 @@ ...@@ -217,6 +217,9 @@
* - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag
* - add FUSE_NO_EXPORT_SUPPORT init flag * - add FUSE_NO_EXPORT_SUPPORT init flag
* - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag
*
* 7.41
* - add FUSE_ALLOW_IDMAP
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -252,7 +255,7 @@ ...@@ -252,7 +255,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 40 #define FUSE_KERNEL_MINOR_VERSION 41
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
...@@ -421,6 +424,7 @@ struct fuse_file_lock { ...@@ -421,6 +424,7 @@ struct fuse_file_lock {
* FUSE_NO_EXPORT_SUPPORT: explicitly disable export support * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support
* FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit
* of the request ID indicates resend requests * of the request ID indicates resend requests
* FUSE_ALLOW_IDMAP: allow creation of idmapped mounts
*/ */
#define FUSE_ASYNC_READ (1 << 0) #define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1) #define FUSE_POSIX_LOCKS (1 << 1)
...@@ -466,6 +470,7 @@ struct fuse_file_lock { ...@@ -466,6 +470,7 @@ struct fuse_file_lock {
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */ /* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP #define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
#define FUSE_ALLOW_IDMAP (1ULL << 40)
/** /**
* CUSE INIT request/reply flags * CUSE INIT request/reply flags
...@@ -984,6 +989,21 @@ struct fuse_fallocate_in { ...@@ -984,6 +989,21 @@ struct fuse_fallocate_in {
*/ */
#define FUSE_UNIQUE_RESEND (1ULL << 63) #define FUSE_UNIQUE_RESEND (1ULL << 63)
/**
* This value will be set by the kernel to
* (struct fuse_in_header).{uid,gid} fields in
* case when:
* - fuse daemon enabled FUSE_ALLOW_IDMAP
* - idmapping information is not available and uid/gid
* can not be mapped in accordance with an idmapping.
*
* Note: an idmapping information always available
* for inode creation operations like:
* FUSE_MKNOD, FUSE_SYMLINK, FUSE_MKDIR, FUSE_TMPFILE,
* FUSE_CREATE and FUSE_RENAME2 (with RENAME_WHITEOUT).
*/
#define FUSE_INVALID_UIDGID ((uint32_t)(-1))
struct fuse_in_header { struct fuse_in_header {
uint32_t len; uint32_t len;
uint32_t opcode; uint32_t opcode;
......
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