* Re: [PATCH V2 08/13] md: set MD_CHANGE_PENDING in a spinlocked region
From: Guoqing Jiang @ 2016-04-26 3:19 UTC (permalink / raw)
To: Shaohua Li; +Cc: neilb, linux-raid
In-Reply-To: <20160425173201.GA11993@kernel.org>
On 04/26/2016 01:32 AM, Shaohua Li wrote:
> On Thu, Apr 21, 2016 at 02:58:15PM +0800, Guoqing Jiang wrote:
>> Some code waits for a metadata update by:
>>
>> 1. flagging that it is needed (MD_CHANGE_DEVS or MD_CHANGE_CLEAN)
>> 2. setting MD_CHANGE_PENDING and waking the management thread
>> 3. waiting for MD_CHANGE_PENDING to be cleared
>>
>> If the first two are done without locking, the code in md_update_sb()
>> which checks if it needs to repeat might test if an update is needed
>> before step 1, then clear MD_CHANGE_PENDING after step 2, resulting
>> in the wait returning early.
>>
>> So make sure all places that set MD_CHANGE_PENDING are protected by
>> mddev->lock.
>>
>> Reviewed-by: NeilBrown <neilb@suse.com>
>> Signed-off-by: Guoqing Jiang <gqjiang@suse.com>
>> ---
>> Changes:
>> 1. s/write_lock/lock which is reported by auto build
>>
>> drivers/md/md.c | 22 +++++++++++++++++-----
>> drivers/md/raid1.c | 2 ++
>> drivers/md/raid10.c | 6 +++++-
>> drivers/md/raid5-cache.c | 2 ++
>> drivers/md/raid5.c | 2 ++
>> 5 files changed, 28 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/md/md.c b/drivers/md/md.c
>> index bf2b74d..e74657e 100644
>> --- a/drivers/md/md.c
>> +++ b/drivers/md/md.c
>> @@ -2293,12 +2293,18 @@ repeat:
>> if (mddev_is_clustered(mddev)) {
>> if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
>> force_change = 1;
>> + if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags))
>> + nospares = 1;
>> ret = md_cluster_ops->metadata_update_start(mddev);
>> /* Has someone else has updated the sb */
>> if (!does_sb_need_changing(mddev)) {
>> if (ret == 0)
>> md_cluster_ops->metadata_update_cancel(mddev);
>> - clear_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_lock(&mddev->lock);
>> + if (!test_bit(MD_CHANGE_DEVS, &mddev->flags) &&
>> + !test_bit(MD_CHANGE_CLEAN, &mddev->flags))
>> + clear_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_unlock(&mddev->lock);
>> return;
>> }
>> }
>> @@ -2434,7 +2440,8 @@ repeat:
>>
>> spin_lock(&mddev->lock);
>> if (mddev->in_sync != sync_req ||
>> - test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
>> + test_bit(MD_CHANGE_DEVS, &mddev->flags) ||
>> + test_bit(MD_CHANGE_CLEAN, &mddev->flags)) {
>> /* have to write it out again */
>> spin_unlock(&mddev->lock);
>> goto repeat;
>> @@ -8145,18 +8152,20 @@ void md_do_sync(struct md_thread *thread)
>> }
>> }
>> skip:
>> - set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> -
>> if (mddev_is_clustered(mddev) &&
>> ret == 0) {
>> /* set CHANGE_PENDING here since maybe another
>> * update is needed, so other nodes are informed */
>> + spin_lock(&mddev->lock);
>> + set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_unlock(&mddev->lock);
>> md_wakeup_thread(mddev->thread);
>> wait_event(mddev->sb_wait,
>> !test_bit(MD_CHANGE_PENDING, &mddev->flags));
>> md_cluster_ops->resync_finish(mddev);
>> - }
>> + } else
>> + set_bit(MD_CHANGE_DEVS, &mddev->flags);
>>
>> spin_lock(&mddev->lock);
>> if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
>> @@ -8548,6 +8557,7 @@ EXPORT_SYMBOL(md_finish_reshape);
>> int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
>> int is_new)
>> {
>> + struct mddev *mddev = rdev->mddev;
>> int rv;
>> if (is_new)
>> s += rdev->new_data_offset;
>> @@ -8557,8 +8567,10 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
>> if (rv == 0) {
>> /* Make sure they get written out promptly */
>> sysfs_notify_dirent_safe(rdev->sysfs_state);
>> + spin_lock(&mddev->lock);
>> set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &rdev->mddev->flags);
>> + spin_unlock(&mddev->lock);
>> md_wakeup_thread(rdev->mddev->thread);
>> return 1;
>> } else
>> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
>> index a7f2b9c..985fa07 100644
>> --- a/drivers/md/raid1.c
>> +++ b/drivers/md/raid1.c
>> @@ -1474,8 +1474,10 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev)
>> * if recovery is running, make sure it aborts.
>> */
>> set_bit(MD_RECOVERY_INTR, &mddev->recovery);
>> + spin_lock(&mddev->lock);
>> set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_unlock(&mddev->lock);
>> printk(KERN_ALERT
>> "md/raid1:%s: Disk failure on %s, disabling device.\n"
>> "md/raid1:%s: Operation continuing on %d devices.\n",
>> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
>> index e3fd725..98a4cf1 100644
>> --- a/drivers/md/raid10.c
>> +++ b/drivers/md/raid10.c
>> @@ -1102,8 +1102,10 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
>> bio->bi_iter.bi_sector < conf->reshape_progress))) {
>> /* Need to update reshape_position in metadata */
>> mddev->reshape_position = conf->reshape_progress;
>> + spin_lock(&mddev->lock);
>> set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_unlock(&mddev->lock);
>> md_wakeup_thread(mddev->thread);
>> wait_event(mddev->sb_wait,
>> !test_bit(MD_CHANGE_PENDING, &mddev->flags));
>> @@ -1585,15 +1587,17 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)
>> }
>> if (test_and_clear_bit(In_sync, &rdev->flags))
>> mddev->degraded++;
>> + spin_unlock_irqrestore(&conf->device_lock, flags);
>> /*
>> * If recovery is running, make sure it aborts.
>> */
>> set_bit(MD_RECOVERY_INTR, &mddev->recovery);
>> set_bit(Blocked, &rdev->flags);
>> set_bit(Faulty, &rdev->flags);
>> + spin_lock(&mddev->lock);
>> set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &mddev->flags);
>> - spin_unlock_irqrestore(&conf->device_lock, flags);
>> + spin_unlock(&mddev->lock);
>> printk(KERN_ALERT
>> "md/raid10:%s: Disk failure on %s, disabling device.\n"
>> "md/raid10:%s: Operation continuing on %d devices.\n",
>> diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
>> index 9531f5f..2ba9366 100644
>> --- a/drivers/md/raid5-cache.c
>> +++ b/drivers/md/raid5-cache.c
>> @@ -712,8 +712,10 @@ static void r5l_write_super_and_discard_space(struct r5l_log *log,
>> * in_teardown check workaround this issue.
>> */
>> if (!log->in_teardown) {
>> + spin_lock(&mddev->lock);
>> set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_unlock(&mddev->lock);
>> md_wakeup_thread(mddev->thread);
>> wait_event(mddev->sb_wait,
>> !test_bit(MD_CHANGE_PENDING, &mddev->flags) ||
>> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
>> index 8ab8b65..d4a1e37 100644
>> --- a/drivers/md/raid5.c
>> +++ b/drivers/md/raid5.c
>> @@ -2514,8 +2514,10 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev)
>>
>> set_bit(Blocked, &rdev->flags);
>> set_bit(Faulty, &rdev->flags);
>> + spin_lock(&mddev->lock);
>> set_bit(MD_CHANGE_DEVS, &mddev->flags);
>> set_bit(MD_CHANGE_PENDING, &mddev->flags);
>> + spin_unlock(&mddev->lock);
>> printk(KERN_ALERT
>> "md/raid:%s: Disk failure on %s, disabling device.\n"
>> "md/raid:%s: Operation continuing on %d devices.\n",
> The .error_handler is called by md_error, called by .bio_endio, which is called
> in softirq. So the lock should be hold with irq disabled.
Thanks, I will change them to spin_lock_irqsave/restore.
Thanks,
Guoqing
^ permalink raw reply
* Re: [PATCH] MD: make bio mergeable
From: Jens Axboe @ 2016-04-26 1:15 UTC (permalink / raw)
To: Shaohua Li, linux-block, linux-kernel, linux-raid
Cc: qkrwngud825, Kernel-team, v4.3+, Ming Lei, Jens Axboe, Neil Brown
In-Reply-To: <571EBD56.7010204@kernel.dk>
On 04/25/2016 06:59 PM, Jens Axboe wrote:
> On 04/25/2016 05:52 PM, Shaohua Li wrote:
>> blk_queue_split marks bio unmergeable, which makes sense for normal bio.
>> But if dispatching the bio to underlayer disk, the blk_queue_split
>> checks are invalid, hence it's possible the bio becomes mergeable.
>>
>> In the reported bug, this bug causes trim against raid0 performance slash
>> https://bugzilla.kernel.org/show_bug.cgi?id=117051
>
> Good catch! Will apply for this series, thanks Shaohua.
Actually, let's let that go through the md tree instead. But you can add
my Reviewed-by, and it'd be nice to get this into 4.6.
--
Jens Axboe
^ permalink raw reply
* Re: [PATCH] MD: make bio mergeable
From: Jens Axboe @ 2016-04-26 0:59 UTC (permalink / raw)
To: Shaohua Li, linux-block, linux-kernel, linux-raid
Cc: qkrwngud825, Kernel-team, v4.3+, Ming Lei, Jens Axboe, Neil Brown
In-Reply-To: <384a0e0c7d6f2700aadbcbdef003cece88fa7dd7.1461626533.git.shli@fb.com>
On 04/25/2016 05:52 PM, Shaohua Li wrote:
> blk_queue_split marks bio unmergeable, which makes sense for normal bio.
> But if dispatching the bio to underlayer disk, the blk_queue_split
> checks are invalid, hence it's possible the bio becomes mergeable.
>
> In the reported bug, this bug causes trim against raid0 performance slash
> https://bugzilla.kernel.org/show_bug.cgi?id=117051
Good catch! Will apply for this series, thanks Shaohua.
--
Jens Axboe
^ permalink raw reply
* [PATCH] MD: make bio mergeable
From: Shaohua Li @ 2016-04-25 23:52 UTC (permalink / raw)
To: linux-block, linux-kernel, linux-raid
Cc: qkrwngud825, Kernel-team, v4.3+, Ming Lei, Jens Axboe, Neil Brown
blk_queue_split marks bio unmergeable, which makes sense for normal bio.
But if dispatching the bio to underlayer disk, the blk_queue_split
checks are invalid, hence it's possible the bio becomes mergeable.
In the reported bug, this bug causes trim against raid0 performance slash
https://bugzilla.kernel.org/show_bug.cgi?id=117051
Reported-by: Park Ju Hyung <qkrwngud825@gmail.com>
Fixes: 6ac45aeb6bca(block: avoid to merge splitted bio)
Cc: stable@vger.kernel.org (v4.3+)
Cc: Ming Lei <ming.lei@canonical.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Neil Brown <neilb@suse.de>
Signed-off-by: Shaohua Li <shli@fb.com>
---
drivers/md/md.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 194580f..14d3b37 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -284,6 +284,8 @@ static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
* go away inside make_request
*/
sectors = bio_sectors(bio);
+ /* bio could be mergeable after passing to underlayer */
+ bio->bi_rw &= ~REQ_NOMERGE;
mddev->pers->make_request(mddev, bio);
cpu = part_stat_lock();
--
2.8.0.rc2
^ permalink raw reply related
* Re: [PATCH v3 14/21] fs: Allow superblock owner to change ownership of inodes with unmappable ids
From: Seth Forshee @ 2016-04-25 20:54 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: Eric W. Biederman, Alexander Viro, Greg Kroah-Hartman,
Serge Hallyn, Richard Weinberger, Austin S Hemmelgarn,
Miklos Szeredi, Pavel Tikhomirov, linux-kernel, linux-bcache,
dm-devel, linux-raid, linux-mtd, linux-fsdevel, fuse-devel,
linux-security-module, selinux, cgroups
In-Reply-To: <20160425203047.GA29927@mail.hallyn.com>
On Mon, Apr 25, 2016 at 03:30:47PM -0500, Serge E. Hallyn wrote:
> Quoting Seth Forshee (seth.forshee@canonical.com):
> > In a userns mount some on-disk inodes may have ids which do not
> > map into s_user_ns, in which case the in-kernel inodes are owned
> > by invalid users. The superblock owner should be able to change
> > attributes of these inodes but cannot. However it is unsafe to
> > grant the superblock owner privileged access to all inodes in the
> > superblock since proc, sysfs, etc. use DAC to protect files which
> > may not belong to s_user_ns. The problem is restricted to only
> > inodes where the owner or group is an invalid user.
> >
> > We can work around this by allowing users with CAP_CHOWN in
> > s_user_ns to change an invalid owner or group id, so long as the
> > other id is either invalid or mappable in s_user_ns. After
> > changing ownership the user will be privileged towards the inode
> > and thus able to change other attributes.
> >
> > As an precaution, checks for invalid ids are added to the proc
> > and kernfs setattr interfaces. These filesystems are not expected
> > to have inodes with invalid ids, but if it does happen any
> > setattr operations will return -EPERM.
> >
> > Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
>
> Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
>
> bug a request below,
>
> > ---
> > fs/attr.c | 47 +++++++++++++++++++++++++++++++++++++++--------
> > fs/kernfs/inode.c | 2 ++
> > fs/proc/base.c | 2 ++
> > fs/proc/generic.c | 3 +++
> > fs/proc/proc_sysctl.c | 2 ++
> > 5 files changed, 48 insertions(+), 8 deletions(-)
> >
> > diff --git a/fs/attr.c b/fs/attr.c
> > index 3cfaaac4a18e..a8b0931654a5 100644
> > --- a/fs/attr.c
> > +++ b/fs/attr.c
> > @@ -16,6 +16,43 @@
> > #include <linux/evm.h>
> > #include <linux/ima.h>
> >
> > +static bool chown_ok(const struct inode *inode, kuid_t uid)
> > +{
> > + struct user_namespace *user_ns;
> > +
> > + if (uid_eq(current_fsuid(), inode->i_uid) && uid_eq(uid, inode->i_uid))
> > + return true;
> > + if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
> > + return true;
> > +
> > + user_ns = inode->i_sb->s_user_ns;
> > + if (!uid_valid(inode->i_uid) &&
> > + (!gid_valid(inode->i_gid) || kgid_has_mapping(user_ns, inode->i_gid)) &&
>
> This confused me to no end :) Perhaps a "is_unmapped_valid_gid()" helper
> would make it clearer what this is meant to do? Or else maybe a comment
> above chown_ok(), explaining that
>
> 1. for a blockdev, the uid is converted at inode read so that it is
> either mapped or invalid
> 2. for sysfs / etc, uid can be valid but not mapped into the userns
Even with a helper a comment is probably helpful to explain why. I'll do
that first, then see if a helper would make things any clearer.
Honestly, I had to think about the helper name you proposed for a minute
before it made sense even though I already understood the code ;-)
^ permalink raw reply
* Re: [PATCH v3 14/21] fs: Allow superblock owner to change ownership of inodes with unmappable ids
From: Serge E. Hallyn @ 2016-04-25 20:30 UTC (permalink / raw)
To: Seth Forshee
Cc: Eric W. Biederman, Alexander Viro, Greg Kroah-Hartman,
Serge Hallyn, Richard Weinberger, Austin S Hemmelgarn,
Miklos Szeredi, Pavel Tikhomirov, linux-kernel, linux-bcache,
dm-devel, linux-raid, linux-mtd, linux-fsdevel, fuse-devel,
linux-security-module, selinux, cgroups
In-Reply-To: <1461339521-123191-15-git-send-email-seth.forshee@canonical.com>
Quoting Seth Forshee (seth.forshee@canonical.com):
> In a userns mount some on-disk inodes may have ids which do not
> map into s_user_ns, in which case the in-kernel inodes are owned
> by invalid users. The superblock owner should be able to change
> attributes of these inodes but cannot. However it is unsafe to
> grant the superblock owner privileged access to all inodes in the
> superblock since proc, sysfs, etc. use DAC to protect files which
> may not belong to s_user_ns. The problem is restricted to only
> inodes where the owner or group is an invalid user.
>
> We can work around this by allowing users with CAP_CHOWN in
> s_user_ns to change an invalid owner or group id, so long as the
> other id is either invalid or mappable in s_user_ns. After
> changing ownership the user will be privileged towards the inode
> and thus able to change other attributes.
>
> As an precaution, checks for invalid ids are added to the proc
> and kernfs setattr interfaces. These filesystems are not expected
> to have inodes with invalid ids, but if it does happen any
> setattr operations will return -EPERM.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
bug a request below,
> ---
> fs/attr.c | 47 +++++++++++++++++++++++++++++++++++++++--------
> fs/kernfs/inode.c | 2 ++
> fs/proc/base.c | 2 ++
> fs/proc/generic.c | 3 +++
> fs/proc/proc_sysctl.c | 2 ++
> 5 files changed, 48 insertions(+), 8 deletions(-)
>
> diff --git a/fs/attr.c b/fs/attr.c
> index 3cfaaac4a18e..a8b0931654a5 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -16,6 +16,43 @@
> #include <linux/evm.h>
> #include <linux/ima.h>
>
> +static bool chown_ok(const struct inode *inode, kuid_t uid)
> +{
> + struct user_namespace *user_ns;
> +
> + if (uid_eq(current_fsuid(), inode->i_uid) && uid_eq(uid, inode->i_uid))
> + return true;
> + if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
> + return true;
> +
> + user_ns = inode->i_sb->s_user_ns;
> + if (!uid_valid(inode->i_uid) &&
> + (!gid_valid(inode->i_gid) || kgid_has_mapping(user_ns, inode->i_gid)) &&
This confused me to no end :) Perhaps a "is_unmapped_valid_gid()" helper
would make it clearer what this is meant to do? Or else maybe a comment
above chown_ok(), explaining that
1. for a blockdev, the uid is converted at inode read so that it is
either mapped or invalid
2. for sysfs / etc, uid can be valid but not mapped into the userns
> + ns_capable(user_ns, CAP_CHOWN))
> + return true;
> +
> + return false;
> +}
> +
> +static bool chgrp_ok(const struct inode *inode, kgid_t gid)
> +{
> + struct user_namespace *user_ns;
> +
> + if (uid_eq(current_fsuid(), inode->i_uid) &&
> + (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
> + return true;
> + if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
> + return true;
> +
> + user_ns = inode->i_sb->s_user_ns;
> + if (!gid_valid(inode->i_gid) &&
> + (!uid_valid(inode->i_uid) || kuid_has_mapping(user_ns, inode->i_uid)) &&
> + ns_capable(user_ns, CAP_CHOWN))
> + return true;
> +
> + return false;
> +}
> +
> /**
> * inode_change_ok - check if attribute changes to an inode are allowed
> * @inode: inode to check
> @@ -58,17 +95,11 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
> return 0;
>
> /* Make sure a caller can chown. */
> - if ((ia_valid & ATTR_UID) &&
> - (!uid_eq(current_fsuid(), inode->i_uid) ||
> - !uid_eq(attr->ia_uid, inode->i_uid)) &&
> - !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
> + if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
> return -EPERM;
>
> /* Make sure caller can chgrp. */
> - if ((ia_valid & ATTR_GID) &&
> - (!uid_eq(current_fsuid(), inode->i_uid) ||
> - (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
> - !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
> + if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
> return -EPERM;
>
> /* Make sure a caller can chmod. */
> diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
> index 16405ae88d2d..2e97a337ee5f 100644
> --- a/fs/kernfs/inode.c
> +++ b/fs/kernfs/inode.c
> @@ -117,6 +117,8 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
>
> if (!kn)
> return -EINVAL;
> + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
> + return -EPERM;
>
> mutex_lock(&kernfs_mutex);
> error = inode_change_ok(inode, iattr);
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index b1755b23893e..648d623e2158 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -711,6 +711,8 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
>
> if (attr->ia_valid & ATTR_MODE)
> return -EPERM;
> + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
> + return -EPERM;
>
> error = inode_change_ok(inode, attr);
> if (error)
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index ff3ffc76a937..1461570c552c 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -105,6 +105,9 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
> struct proc_dir_entry *de = PDE(inode);
> int error;
>
> + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
> + return -EPERM;
> +
> error = inode_change_ok(inode, iattr);
> if (error)
> return error;
> diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
> index fe5b6e6c4671..f5d575157194 100644
> --- a/fs/proc/proc_sysctl.c
> +++ b/fs/proc/proc_sysctl.c
> @@ -752,6 +752,8 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
>
> if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
> return -EPERM;
> + if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
> + return -EPERM;
>
> error = inode_change_ok(inode, attr);
> if (error)
> --
> 1.9.1
^ permalink raw reply
* Re: [PATCH v3 03/21] fs: Allow sysfs and cgroupfs to share super blocks between user namespaces
From: Serge E. Hallyn @ 2016-04-25 19:01 UTC (permalink / raw)
To: Seth Forshee
Cc: Eric W. Biederman, Alexander Viro, Greg Kroah-Hartman,
Jeff Layton, J. Bruce Fields, Tejun Heo, Li Zefan,
Johannes Weiner, Serge Hallyn, Richard Weinberger,
Austin S Hemmelgarn, Miklos Szeredi, Pavel Tikhomirov,
linux-kernel, linux-bcache, dm-devel, linux-raid, linux-mtd,
linux-fsdevel, fuse-devel, linux-security-module, selinux,
cgroups
In-Reply-To: <1461339521-123191-4-git-send-email-seth.forshee@canonical.com>
Quoting Seth Forshee (seth.forshee@canonical.com):
> Both of these filesystems already have use cases for mounting the
> same super block from multiple user namespaces. For sysfs this
> happens when using criu for snapshotting a container, where sysfs
> is mounted in the containers network ns but the hosts user ns.
> The cgroup filesystem shares the same super block for all mounts
> of the same hierarchy regardless of the namespace.
>
> As a result, the restriction on mounting a super block from a
> single user namespace creates regressions for existing uses of
> these filesystems. For these specific filesystems this
> restriction isn't really necessary since the backing store is
> objects in kernel memory and thus the ids assigned from inodes
> is not subject to translation relative to s_user_ns.
>
> Add a new filesystem flag, FS_USERNS_SHARE_SB, which when set
> causes sget_userns() to skip the check of s_user_ns. Set this
> flag for the sysfs and cgroup filesystems to fix the
> regressions.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
thanks.
> ---
> fs/super.c | 3 ++-
> fs/sysfs/mount.c | 3 ++-
> include/linux/fs.h | 1 +
> kernel/cgroup.c | 4 ++--
> 4 files changed, 7 insertions(+), 4 deletions(-)
>
> diff --git a/fs/super.c b/fs/super.c
> index 092a7828442e..ead156b44bf8 100644
> --- a/fs/super.c
> +++ b/fs/super.c
> @@ -472,7 +472,8 @@ retry:
> hlist_for_each_entry(old, &type->fs_supers, s_instances) {
> if (!test(old, data))
> continue;
> - if (user_ns != old->s_user_ns) {
> + if (!(type->fs_flags & FS_USERNS_SHARE_SB) &&
> + user_ns != old->s_user_ns) {
> spin_unlock(&sb_lock);
> if (s) {
> up_write(&s->s_umount);
> diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
> index f3db82071cfb..9555accd4322 100644
> --- a/fs/sysfs/mount.c
> +++ b/fs/sysfs/mount.c
> @@ -59,7 +59,8 @@ static struct file_system_type sysfs_fs_type = {
> .name = "sysfs",
> .mount = sysfs_mount,
> .kill_sb = sysfs_kill_sb,
> - .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
> + .fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT |
> + FS_USERNS_SHARE_SB,
> };
>
> int __init sysfs_init(void)
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index be0f8023e28c..66a639ec1bc4 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1988,6 +1988,7 @@ struct file_system_type {
> #define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */
> #define FS_USERNS_DEV_MOUNT 16 /* A userns mount does not imply MNT_NODEV */
> #define FS_USERNS_VISIBLE 32 /* FS must already be visible */
> +#define FS_USERNS_SHARE_SB 64 /* Allow sharing sb between userns-es */
> #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */
> struct dentry *(*mount) (struct file_system_type *, int,
> const char *, void *);
> diff --git a/kernel/cgroup.c b/kernel/cgroup.c
> index 671dc05c0b0f..9c9aa27e531a 100644
> --- a/kernel/cgroup.c
> +++ b/kernel/cgroup.c
> @@ -2247,14 +2247,14 @@ static struct file_system_type cgroup_fs_type = {
> .name = "cgroup",
> .mount = cgroup_mount,
> .kill_sb = cgroup_kill_sb,
> - .fs_flags = FS_USERNS_MOUNT,
> + .fs_flags = FS_USERNS_MOUNT | FS_USERNS_SHARE_SB,
> };
>
> static struct file_system_type cgroup2_fs_type = {
> .name = "cgroup2",
> .mount = cgroup_mount,
> .kill_sb = cgroup_kill_sb,
> - .fs_flags = FS_USERNS_MOUNT,
> + .fs_flags = FS_USERNS_MOUNT | FS_USERNS_SHARE_SB,
> };
>
> static char *cgroup_path_ns_locked(struct cgroup *cgrp, char *buf, size_t buflen,
> --
> 1.9.1
^ permalink raw reply
* Re: [PATCH 09/13] md-cluster: always setup in-memory bitmap
From: Shaohua Li @ 2016-04-25 17:45 UTC (permalink / raw)
To: Guoqing Jiang; +Cc: neilb, linux-raid
In-Reply-To: <1461218294-4960-10-git-send-email-gqjiang@suse.com>
On Thu, Apr 21, 2016 at 01:58:10PM +0800, Guoqing Jiang wrote:
> The in-memory bitmap for raid is allocated on demand,
> then for cluster scenario, it is possible that slave
> node which received RESYNCING message doesn't have the
> in-memory bitmap when master node is perform resyncing,
> so we can't make bitmap is match up well among each
> nodes.
>
> So for cluster scenario, we need always preserve the
> bitmap, and ensure the page will not be freed. And a
> no_hijack flag is introduced to both bitmap_checkpage
> and bitmap_get_counter, which makes cluster raid returns
> fail once allocate failed.
>
> And the next patch is relied on this change since it
> keeps sync bitmap among each nodes during resyncing
> stage.
>
> Reviewed-by: NeilBrown <neilb@suse.com>
> Signed-off-by: Guoqing Jiang <gqjiang@suse.com>
> ---
> drivers/md/bitmap.c | 59 +++++++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 46 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
> index 7df6b4f..00cf1c1 100644
> --- a/drivers/md/bitmap.c
> +++ b/drivers/md/bitmap.c
> @@ -46,7 +46,7 @@ static inline char *bmname(struct bitmap *bitmap)
> * allocated while we're using it
> */
> static int bitmap_checkpage(struct bitmap_counts *bitmap,
> - unsigned long page, int create)
> + unsigned long page, int create, int no_hijack)
> __releases(bitmap->lock)
> __acquires(bitmap->lock)
> {
> @@ -90,6 +90,9 @@ __acquires(bitmap->lock)
>
> if (mappage == NULL) {
> pr_debug("md/bitmap: map page allocation failed, hijacking\n");
> + /* We don't support hijack for cluster raid */
> + if (no_hijack)
> + return -ENOMEM;
> /* failed - set the hijacked flag so that we can use the
> * pointer as a counter */
> if (!bitmap->bp[page].map)
> @@ -1177,7 +1180,7 @@ static void bitmap_set_pending(struct bitmap_counts *bitmap, sector_t offset)
>
> static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
> sector_t offset, sector_t *blocks,
> - int create);
> + int create, int no_hijack);
>
> /*
> * bitmap daemon -- periodically wakes up to clean bits and flush pages
> @@ -1257,7 +1260,7 @@ void bitmap_daemon_work(struct mddev *mddev)
> }
> bmc = bitmap_get_counter(counts,
> block,
> - &blocks, 0);
> + &blocks, 0, 0);
>
> if (!bmc) {
> j |= PAGE_COUNTER_MASK;
> @@ -1307,7 +1310,7 @@ void bitmap_daemon_work(struct mddev *mddev)
>
> static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
> sector_t offset, sector_t *blocks,
> - int create)
> + int create, int no_hijack)
> __releases(bitmap->lock)
> __acquires(bitmap->lock)
> {
> @@ -1321,7 +1324,7 @@ __acquires(bitmap->lock)
> sector_t csize;
> int err;
>
> - err = bitmap_checkpage(bitmap, page, create);
> + err = bitmap_checkpage(bitmap, page, create, 0);
>
> if (bitmap->bp[page].hijacked ||
> bitmap->bp[page].map == NULL)
bitmap_get_counter doesn't use the new no_hijack parameter. And you always pass
0 to this function. so looks this change isn't required.
^ permalink raw reply
* Re: [PATCH V2 08/13] md: set MD_CHANGE_PENDING in a spinlocked region
From: Shaohua Li @ 2016-04-25 17:32 UTC (permalink / raw)
To: Guoqing Jiang; +Cc: neilb, linux-raid
In-Reply-To: <1461221895-20688-1-git-send-email-gqjiang@suse.com>
On Thu, Apr 21, 2016 at 02:58:15PM +0800, Guoqing Jiang wrote:
> Some code waits for a metadata update by:
>
> 1. flagging that it is needed (MD_CHANGE_DEVS or MD_CHANGE_CLEAN)
> 2. setting MD_CHANGE_PENDING and waking the management thread
> 3. waiting for MD_CHANGE_PENDING to be cleared
>
> If the first two are done without locking, the code in md_update_sb()
> which checks if it needs to repeat might test if an update is needed
> before step 1, then clear MD_CHANGE_PENDING after step 2, resulting
> in the wait returning early.
>
> So make sure all places that set MD_CHANGE_PENDING are protected by
> mddev->lock.
>
> Reviewed-by: NeilBrown <neilb@suse.com>
> Signed-off-by: Guoqing Jiang <gqjiang@suse.com>
> ---
> Changes:
> 1. s/write_lock/lock which is reported by auto build
>
> drivers/md/md.c | 22 +++++++++++++++++-----
> drivers/md/raid1.c | 2 ++
> drivers/md/raid10.c | 6 +++++-
> drivers/md/raid5-cache.c | 2 ++
> drivers/md/raid5.c | 2 ++
> 5 files changed, 28 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index bf2b74d..e74657e 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -2293,12 +2293,18 @@ repeat:
> if (mddev_is_clustered(mddev)) {
> if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
> force_change = 1;
> + if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags))
> + nospares = 1;
> ret = md_cluster_ops->metadata_update_start(mddev);
> /* Has someone else has updated the sb */
> if (!does_sb_need_changing(mddev)) {
> if (ret == 0)
> md_cluster_ops->metadata_update_cancel(mddev);
> - clear_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_lock(&mddev->lock);
> + if (!test_bit(MD_CHANGE_DEVS, &mddev->flags) &&
> + !test_bit(MD_CHANGE_CLEAN, &mddev->flags))
> + clear_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_unlock(&mddev->lock);
> return;
> }
> }
> @@ -2434,7 +2440,8 @@ repeat:
>
> spin_lock(&mddev->lock);
> if (mddev->in_sync != sync_req ||
> - test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
> + test_bit(MD_CHANGE_DEVS, &mddev->flags) ||
> + test_bit(MD_CHANGE_CLEAN, &mddev->flags)) {
> /* have to write it out again */
> spin_unlock(&mddev->lock);
> goto repeat;
> @@ -8145,18 +8152,20 @@ void md_do_sync(struct md_thread *thread)
> }
> }
> skip:
> - set_bit(MD_CHANGE_DEVS, &mddev->flags);
> -
> if (mddev_is_clustered(mddev) &&
> ret == 0) {
> /* set CHANGE_PENDING here since maybe another
> * update is needed, so other nodes are informed */
> + spin_lock(&mddev->lock);
> + set_bit(MD_CHANGE_DEVS, &mddev->flags);
> set_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_unlock(&mddev->lock);
> md_wakeup_thread(mddev->thread);
> wait_event(mddev->sb_wait,
> !test_bit(MD_CHANGE_PENDING, &mddev->flags));
> md_cluster_ops->resync_finish(mddev);
> - }
> + } else
> + set_bit(MD_CHANGE_DEVS, &mddev->flags);
>
> spin_lock(&mddev->lock);
> if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
> @@ -8548,6 +8557,7 @@ EXPORT_SYMBOL(md_finish_reshape);
> int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
> int is_new)
> {
> + struct mddev *mddev = rdev->mddev;
> int rv;
> if (is_new)
> s += rdev->new_data_offset;
> @@ -8557,8 +8567,10 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
> if (rv == 0) {
> /* Make sure they get written out promptly */
> sysfs_notify_dirent_safe(rdev->sysfs_state);
> + spin_lock(&mddev->lock);
> set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags);
> set_bit(MD_CHANGE_PENDING, &rdev->mddev->flags);
> + spin_unlock(&mddev->lock);
> md_wakeup_thread(rdev->mddev->thread);
> return 1;
> } else
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index a7f2b9c..985fa07 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -1474,8 +1474,10 @@ static void raid1_error(struct mddev *mddev, struct md_rdev *rdev)
> * if recovery is running, make sure it aborts.
> */
> set_bit(MD_RECOVERY_INTR, &mddev->recovery);
> + spin_lock(&mddev->lock);
> set_bit(MD_CHANGE_DEVS, &mddev->flags);
> set_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_unlock(&mddev->lock);
> printk(KERN_ALERT
> "md/raid1:%s: Disk failure on %s, disabling device.\n"
> "md/raid1:%s: Operation continuing on %d devices.\n",
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index e3fd725..98a4cf1 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -1102,8 +1102,10 @@ static void __make_request(struct mddev *mddev, struct bio *bio)
> bio->bi_iter.bi_sector < conf->reshape_progress))) {
> /* Need to update reshape_position in metadata */
> mddev->reshape_position = conf->reshape_progress;
> + spin_lock(&mddev->lock);
> set_bit(MD_CHANGE_DEVS, &mddev->flags);
> set_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_unlock(&mddev->lock);
> md_wakeup_thread(mddev->thread);
> wait_event(mddev->sb_wait,
> !test_bit(MD_CHANGE_PENDING, &mddev->flags));
> @@ -1585,15 +1587,17 @@ static void raid10_error(struct mddev *mddev, struct md_rdev *rdev)
> }
> if (test_and_clear_bit(In_sync, &rdev->flags))
> mddev->degraded++;
> + spin_unlock_irqrestore(&conf->device_lock, flags);
> /*
> * If recovery is running, make sure it aborts.
> */
> set_bit(MD_RECOVERY_INTR, &mddev->recovery);
> set_bit(Blocked, &rdev->flags);
> set_bit(Faulty, &rdev->flags);
> + spin_lock(&mddev->lock);
> set_bit(MD_CHANGE_DEVS, &mddev->flags);
> set_bit(MD_CHANGE_PENDING, &mddev->flags);
> - spin_unlock_irqrestore(&conf->device_lock, flags);
> + spin_unlock(&mddev->lock);
> printk(KERN_ALERT
> "md/raid10:%s: Disk failure on %s, disabling device.\n"
> "md/raid10:%s: Operation continuing on %d devices.\n",
> diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
> index 9531f5f..2ba9366 100644
> --- a/drivers/md/raid5-cache.c
> +++ b/drivers/md/raid5-cache.c
> @@ -712,8 +712,10 @@ static void r5l_write_super_and_discard_space(struct r5l_log *log,
> * in_teardown check workaround this issue.
> */
> if (!log->in_teardown) {
> + spin_lock(&mddev->lock);
> set_bit(MD_CHANGE_DEVS, &mddev->flags);
> set_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_unlock(&mddev->lock);
> md_wakeup_thread(mddev->thread);
> wait_event(mddev->sb_wait,
> !test_bit(MD_CHANGE_PENDING, &mddev->flags) ||
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index 8ab8b65..d4a1e37 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -2514,8 +2514,10 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev)
>
> set_bit(Blocked, &rdev->flags);
> set_bit(Faulty, &rdev->flags);
> + spin_lock(&mddev->lock);
> set_bit(MD_CHANGE_DEVS, &mddev->flags);
> set_bit(MD_CHANGE_PENDING, &mddev->flags);
> + spin_unlock(&mddev->lock);
> printk(KERN_ALERT
> "md/raid:%s: Disk failure on %s, disabling device.\n"
> "md/raid:%s: Operation continuing on %d devices.\n",
The .error_handler is called by md_error, called by .bio_endio, which is called
in softirq. So the lock should be hold with irq disabled.
Thanks,
Shaohua
^ permalink raw reply
* Re: [PATCH] md/raid0: remove empty line printk from dump_zones
From: Shaohua Li @ 2016-04-25 15:42 UTC (permalink / raw)
To: Michał Pecio; +Cc: Neil Brown, linux-raid
In-Reply-To: <20160424181145.41aae9dd@sauron>
On Sun, Apr 24, 2016 at 06:11:45PM +0200, Michał Pecio wrote:
>
> Remove the final printk. All preceding output is already properly
> newline-terminated and the printk isn't even KERN_CONT to begin with,
> so it only adds one empty line to the log.
>
> Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
> ---
> drivers/md/raid0.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
> index f8e5db0..3e51f4d 100644
> --- a/drivers/md/raid0.c
> +++ b/drivers/md/raid0.c
> @@ -70,7 +70,6 @@ static void dump_zones(struct mddev *mddev)
> (unsigned long long)zone_size>>1);
> zone_start = conf->strip_zone[j].zone_end;
> }
> - printk(KERN_INFO "\n");
> }
applied, thanks!
--
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] md/raid0: remove empty line printk from dump_zones
From: Michał Pecio @ 2016-04-24 16:11 UTC (permalink / raw)
To: Neil Brown; +Cc: linux-raid
Remove the final printk. All preceding output is already properly
newline-terminated and the printk isn't even KERN_CONT to begin with,
so it only adds one empty line to the log.
Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
---
drivers/md/raid0.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index f8e5db0..3e51f4d 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -70,7 +70,6 @@ static void dump_zones(struct mddev *mddev)
(unsigned long long)zone_size>>1);
zone_start = conf->strip_zone[j].zone_end;
}
- printk(KERN_INFO "\n");
}
static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
^ permalink raw reply related
* Re: [dm-devel] [PATCH 23/42] md/raid: set bi_op to REQ_OP
From: Shaun Tancheff @ 2016-04-23 23:26 UTC (permalink / raw)
To: mchristi
Cc: linux-bcache, linux-block, xfs, ocfs2-devel, linux-scsi,
konrad.wilk, LKML, philipp.reisner, linux-f2fs-devel, linux-raid,
dm-devel, target-devel, linux-mtd, osd-dev, linux-fsdevel,
lars.ellenberg, linux-ext4, linux-btrfs, drbd-dev
In-Reply-To: <1460716802-2294-24-git-send-email-mchristi@redhat.com>
[-- Attachment #1.1: Type: text/plain, Size: 37466 bytes --]
On Fri, Apr 15, 2016 at 5:39 AM, <mchristi@redhat.com> wrote:
> From: Mike Christie <mchristi@redhat.com>
>
> This patch has md use bio->bi_op for REQ_OPs and rq_flag_bits
> to bio->bi_rw.
>
> Signed-off-by: Mike Christie <mchristi@redhat.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Reviewed-by: Hannes Reinecke <hare@suse.com>
> ---
> drivers/md/bitmap.c | 2 +-
> drivers/md/dm-raid.c | 5 +++--
> drivers/md/md.c | 11 +++++++----
> drivers/md/md.h | 3 ++-
> drivers/md/raid1.c | 34 ++++++++++++++++----------------
> drivers/md/raid10.c | 50
> ++++++++++++++++++++++++++----------------------
> drivers/md/raid5-cache.c | 25 +++++++++++++++---------
> drivers/md/raid5.c | 48
> ++++++++++++++++++++++++++--------------------
> 8 files changed, 101 insertions(+), 77 deletions(-)
>
>
Sorry I though this would thread propertly:
https://lkml.kernel.org/r/1461452709-6702-1-git-send-email-shaun@tancheff.com
In raid0.c, raid10.c and raid5.c
A couple of checks for REQ_PREFLUSH flag should also check for
bi_op matching REQ_OP_FLUSH.
In raid1.c [r1_sync_page_io()] and raid10.c [r10_sync_page_io()]
Wrappers for sync_page_io() are passed READ/WRITE but need to
be passed REQ_OP_READ and REQ_OP_WRITE.
Anyway my raid testing was getting weird hangs and corruption
without the patch.
Thanks!
> diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
> index 8b2e16f..9e8019e 100644
> --- a/drivers/md/bitmap.c
> +++ b/drivers/md/bitmap.c
> @@ -159,7 +159,7 @@ static int read_sb_page(struct mddev *mddev, loff_t
> offset,
>
> if (sync_page_io(rdev, target,
> roundup(size,
> bdev_logical_block_size(rdev->bdev)),
> - page, READ, true)) {
> + page, REQ_OP_READ, 0, true)) {
> page->index = index;
> return 0;
> }
> diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
> index a090121..43a749c 100644
> --- a/drivers/md/dm-raid.c
> +++ b/drivers/md/dm-raid.c
> @@ -792,7 +792,7 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
> if (rdev->sb_loaded)
> return 0;
>
> - if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
> + if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, 0,
> 1)) {
> DMERR("Failed to read superblock of device at position %d",
> rdev->raid_disk);
> md_error(rdev->mddev, rdev);
> @@ -1646,7 +1646,8 @@ static void attempt_restore_of_faulty_devices(struct
> raid_set *rs)
> for (i = 0; i < rs->md.raid_disks; i++) {
> r = &rs->dev[i].rdev;
> if (test_bit(Faulty, &r->flags) && r->sb_page &&
> - sync_page_io(r, 0, r->sb_size, r->sb_page, READ, 1)) {
> + sync_page_io(r, 0, r->sb_size, r->sb_page,
> REQ_OP_READ, 0,
> + 1)) {
> DMINFO("Faulty %s device #%d has readable super
> block."
> " Attempting to revive it.",
> rs->raid_type->name, i);
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index ec3c98d..9c40368 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -392,6 +392,7 @@ static void submit_flushes(struct work_struct *ws)
> bi->bi_end_io = md_end_flush;
> bi->bi_private = rdev;
> bi->bi_bdev = rdev->bdev;
> + bi->bi_op = REQ_OP_WRITE;
> bi->bi_rw = WRITE_FLUSH;
> atomic_inc(&mddev->flush_pending);
> submit_bio(bi);
> @@ -741,6 +742,7 @@ void md_super_write(struct mddev *mddev, struct
> md_rdev *rdev,
> bio_add_page(bio, page, size, 0);
> bio->bi_private = rdev;
> bio->bi_end_io = super_written;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_rw = WRITE_FLUSH_FUA;
>
> atomic_inc(&mddev->pending_writes);
> @@ -754,14 +756,15 @@ void md_super_wait(struct mddev *mddev)
> }
>
> int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
> - struct page *page, int rw, bool metadata_op)
> + struct page *page, int op, int op_flags, bool metadata_op)
> {
> struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev);
> int ret;
>
> bio->bi_bdev = (metadata_op && rdev->meta_bdev) ?
> rdev->meta_bdev : rdev->bdev;
> - bio->bi_rw = rw;
> + bio->bi_op = op;
> + bio->bi_rw = op_flags;
> if (metadata_op)
> bio->bi_iter.bi_sector = sector + rdev->sb_start;
> else if (rdev->mddev->reshape_position != MaxSector &&
> @@ -787,7 +790,7 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
> if (rdev->sb_loaded)
> return 0;
>
> - if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, true))
> + if (!sync_page_io(rdev, 0, size, rdev->sb_page, REQ_OP_READ, 0,
> true))
> goto fail;
> rdev->sb_loaded = 1;
> return 0;
> @@ -1473,7 +1476,7 @@ static int super_1_load(struct md_rdev *rdev, struct
> md_rdev *refdev, int minor_
> return -EINVAL;
> bb_sector = (long long)offset;
> if (!sync_page_io(rdev, bb_sector, sectors << 9,
> - rdev->bb_page, READ, true))
> + rdev->bb_page, REQ_OP_READ, 0, true))
> return -EIO;
> bbp = (u64 *)page_address(rdev->bb_page);
> rdev->badblocks.shift = sb->bblog_shift;
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index b5c4be7..2e0918f 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -618,7 +618,8 @@ extern void md_super_write(struct mddev *mddev, struct
> md_rdev *rdev,
> sector_t sector, int size, struct page *page);
> extern void md_super_wait(struct mddev *mddev);
> extern int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
> - struct page *page, int rw, bool metadata_op);
> + struct page *page, int op, int op_flags,
> + bool metadata_op);
> extern void md_do_sync(struct md_thread *thread);
> extern void md_new_event(struct mddev *mddev);
> extern int md_allow_write(struct mddev *mddev);
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 424df7e..c7abd2d 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -759,7 +759,7 @@ static void flush_pending_writes(struct r1conf *conf)
> while (bio) { /* submit pending writes */
> struct bio *next = bio->bi_next;
> bio->bi_next = NULL;
> - if (unlikely((bio->bi_rw & REQ_DISCARD) &&
> + if (unlikely((bio->bi_op == REQ_OP_DISCARD) &&
>
> !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
> /* Just ignore it */
> bio_endio(bio);
> @@ -1033,7 +1033,7 @@ static void raid1_unplug(struct blk_plug_cb *cb,
> bool from_schedule)
> while (bio) { /* submit pending writes */
> struct bio *next = bio->bi_next;
> bio->bi_next = NULL;
> - if (unlikely((bio->bi_rw & REQ_DISCARD) &&
> + if (unlikely((bio->bi_op == REQ_OP_DISCARD) &&
> !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
> /* Just ignore it */
> bio_endio(bio);
> @@ -1053,12 +1053,11 @@ static void raid1_make_request(struct mddev
> *mddev, struct bio * bio)
> int i, disks;
> struct bitmap *bitmap;
> unsigned long flags;
> + const int op = bio->bi_op;
> const int rw = bio_data_dir(bio);
> const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
> const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH |
> REQ_FUA));
> - const unsigned long do_discard = (bio->bi_rw
> - & (REQ_DISCARD | REQ_SECURE));
> - const unsigned long do_same = (bio->bi_rw & REQ_WRITE_SAME);
> + const unsigned long do_sec = (bio->bi_rw & REQ_SECURE);
> struct md_rdev *blocked_rdev;
> struct blk_plug_cb *cb;
> struct raid1_plug_cb *plug = NULL;
> @@ -1166,7 +1165,8 @@ read_again:
> mirror->rdev->data_offset;
> read_bio->bi_bdev = mirror->rdev->bdev;
> read_bio->bi_end_io = raid1_end_read_request;
> - read_bio->bi_rw = READ | do_sync;
> + read_bio->bi_op = op;
> + read_bio->bi_rw = do_sync;
> read_bio->bi_private = r1_bio;
>
> if (max_sectors < r1_bio->sectors) {
> @@ -1376,8 +1376,9 @@ read_again:
> conf->mirrors[i].rdev->data_offset);
> mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
> mbio->bi_end_io = raid1_end_write_request;
> + mbio->bi_op = op;
> mbio->bi_rw =
> - WRITE | do_flush_fua | do_sync | do_discard |
> do_same;
> + do_flush_fua | do_sync | do_sec;
> mbio->bi_private = r1_bio;
>
> atomic_inc(&r1_bio->remaining);
> @@ -1771,7 +1772,7 @@ static void end_sync_write(struct bio *bio)
> static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
> int sectors, struct page *page, int rw)
> {
> - if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
> + if (sync_page_io(rdev, sector, sectors << 9, page, rw, 0, false))
> /* success */
> return 1;
> if (rw == WRITE) {
> @@ -1825,7 +1826,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
> rdev = conf->mirrors[d].rdev;
> if (sync_page_io(rdev, sect, s<<9,
>
> bio->bi_io_vec[idx].bv_page,
> - READ, false)) {
> + REQ_OP_READ, 0, false)) {
> success = 1;
> break;
> }
> @@ -2030,7 +2031,7 @@ static void sync_request_write(struct mddev *mddev,
> struct r1bio *r1_bio)
> !test_bit(MD_RECOVERY_SYNC, &mddev->recovery))))
> continue;
>
> - wbio->bi_rw = WRITE;
> + wbio->bi_op = REQ_OP_WRITE;
> wbio->bi_end_io = end_sync_write;
> atomic_inc(&r1_bio->remaining);
> md_sync_acct(conf->mirrors[i].rdev->bdev,
> bio_sectors(wbio));
> @@ -2090,7 +2091,7 @@ static void fix_read_error(struct r1conf *conf, int
> read_disk,
> is_badblock(rdev, sect, s,
> &first_bad, &bad_sectors) == 0 &&
> sync_page_io(rdev, sect, s<<9,
> - conf->tmppage, READ, false))
> + conf->tmppage, REQ_OP_READ, 0,
> false))
> success = 1;
> else {
> d++;
> @@ -2201,7 +2202,7 @@ static int narrow_write_error(struct r1bio *r1_bio,
> int i)
> wbio = bio_clone_mddev(r1_bio->master_bio,
> GFP_NOIO, mddev);
> }
>
> - wbio->bi_rw = WRITE;
> + wbio->bi_op = REQ_OP_WRITE;
> wbio->bi_iter.bi_sector = r1_bio->sector;
> wbio->bi_iter.bi_size = r1_bio->sectors << 9;
>
> @@ -2344,7 +2345,8 @@ read_more:
> bio->bi_iter.bi_sector = r1_bio->sector +
> rdev->data_offset;
> bio->bi_bdev = rdev->bdev;
> bio->bi_end_io = raid1_end_read_request;
> - bio->bi_rw = READ | do_sync;
> + bio->bi_op = REQ_OP_READ;
> + bio->bi_rw = do_sync;
> bio->bi_private = r1_bio;
> if (max_sectors < r1_bio->sectors) {
> /* Drat - have to split this up more */
> @@ -2572,7 +2574,7 @@ static sector_t raid1_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> if (i < conf->raid_disks)
> still_degraded = 1;
> } else if (!test_bit(In_sync, &rdev->flags)) {
> - bio->bi_rw = WRITE;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_end_io = end_sync_write;
> write_targets ++;
> } else {
> @@ -2599,7 +2601,7 @@ static sector_t raid1_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> if (disk < 0)
> disk = i;
> }
> - bio->bi_rw = READ;
> + bio->bi_op = REQ_OP_READ;
> bio->bi_end_io = end_sync_read;
> read_targets++;
> } else if (!test_bit(WriteErrorSeen, &rdev->flags)
> &&
> @@ -2611,7 +2613,7 @@ static sector_t raid1_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> * if we are doing resync or repair.
> Otherwise, leave
> * this device alone for this sync request.
> */
> - bio->bi_rw = WRITE;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_end_io = end_sync_write;
> write_targets++;
> }
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 4736be8..63cd985 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -865,7 +865,7 @@ static void flush_pending_writes(struct r10conf *conf)
> while (bio) { /* submit pending writes */
> struct bio *next = bio->bi_next;
> bio->bi_next = NULL;
> - if (unlikely((bio->bi_rw & REQ_DISCARD) &&
> + if (unlikely((bio->bi_op == REQ_OP_DISCARD) &&
>
> !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
> /* Just ignore it */
> bio_endio(bio);
> @@ -1041,7 +1041,7 @@ static void raid10_unplug(struct blk_plug_cb *cb,
> bool from_schedule)
> while (bio) { /* submit pending writes */
> struct bio *next = bio->bi_next;
> bio->bi_next = NULL;
> - if (unlikely((bio->bi_rw & REQ_DISCARD) &&
> + if (unlikely((bio->bi_op == REQ_OP_DISCARD) &&
> !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
> /* Just ignore it */
> bio_endio(bio);
> @@ -1058,12 +1058,11 @@ static void __make_request(struct mddev *mddev,
> struct bio *bio)
> struct r10bio *r10_bio;
> struct bio *read_bio;
> int i;
> + const int op = bio->bi_op;
> const int rw = bio_data_dir(bio);
> const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
> const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
> - const unsigned long do_discard = (bio->bi_rw
> - & (REQ_DISCARD | REQ_SECURE));
> - const unsigned long do_same = (bio->bi_rw & REQ_WRITE_SAME);
> + const unsigned long do_sec = (bio->bi_rw & REQ_SECURE);
> unsigned long flags;
> struct md_rdev *blocked_rdev;
> struct blk_plug_cb *cb;
> @@ -1156,7 +1155,8 @@ read_again:
> choose_data_offset(r10_bio, rdev);
> read_bio->bi_bdev = rdev->bdev;
> read_bio->bi_end_io = raid10_end_read_request;
> - read_bio->bi_rw = READ | do_sync;
> + read_bio->bi_op = op;
> + read_bio->bi_rw = do_sync;
> read_bio->bi_private = r10_bio;
>
> if (max_sectors < r10_bio->sectors) {
> @@ -1363,8 +1363,9 @@ retry_write:
> rdev));
> mbio->bi_bdev = rdev->bdev;
> mbio->bi_end_io = raid10_end_write_request;
> + mbio->bi_op = op;
> mbio->bi_rw =
> - WRITE | do_sync | do_fua | do_discard |
> do_same;
> + do_sync | do_fua | do_sec;
> mbio->bi_private = r10_bio;
>
> atomic_inc(&r10_bio->remaining);
> @@ -1406,8 +1407,9 @@ retry_write:
> r10_bio, rdev));
> mbio->bi_bdev = rdev->bdev;
> mbio->bi_end_io = raid10_end_write_request;
> + mbio->bi_op = op;
> mbio->bi_rw =
> - WRITE | do_sync | do_fua | do_discard |
> do_same;
> + do_sync | do_fua | do_sec;
> mbio->bi_private = r10_bio;
>
> atomic_inc(&r10_bio->remaining);
> @@ -1992,7 +1994,7 @@ static void sync_request_write(struct mddev *mddev,
> struct r10bio *r10_bio)
>
> tbio->bi_vcnt = vcnt;
> tbio->bi_iter.bi_size = fbio->bi_iter.bi_size;
> - tbio->bi_rw = WRITE;
> + tbio->bi_op = REQ_OP_WRITE;
> tbio->bi_private = r10_bio;
> tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
> tbio->bi_end_io = end_sync_write;
> @@ -2078,7 +2080,7 @@ static void fix_recovery_read_error(struct r10bio
> *r10_bio)
> addr,
> s << 9,
> bio->bi_io_vec[idx].bv_page,
> - READ, false);
> + REQ_OP_READ, 0, false);
> if (ok) {
> rdev = conf->mirrors[dw].rdev;
> addr = r10_bio->devs[1].addr + sect;
> @@ -2086,7 +2088,7 @@ static void fix_recovery_read_error(struct r10bio
> *r10_bio)
> addr,
> s << 9,
> bio->bi_io_vec[idx].bv_page,
> - WRITE, false);
> + REQ_OP_WRITE, 0, false);
> if (!ok) {
> set_bit(WriteErrorSeen, &rdev->flags);
> if (!test_and_set_bit(WantReplacement,
> @@ -2213,7 +2215,7 @@ static int r10_sync_page_io(struct md_rdev *rdev,
> sector_t sector,
> if (is_badblock(rdev, sector, sectors, &first_bad, &bad_sectors)
> && (rw == READ || test_bit(WriteErrorSeen, &rdev->flags)))
> return -1;
> - if (sync_page_io(rdev, sector, sectors << 9, page, rw, false))
> + if (sync_page_io(rdev, sector, sectors << 9, page, rw, 0, false))
> /* success */
> return 1;
> if (rw == WRITE) {
> @@ -2299,7 +2301,8 @@ static void fix_read_error(struct r10conf *conf,
> struct mddev *mddev, struct r10
>
> r10_bio->devs[sl].addr +
> sect,
> s<<9,
> - conf->tmppage,
> READ, false);
> + conf->tmppage,
> + REQ_OP_READ, 0,
> false);
> rdev_dec_pending(rdev, mddev);
> rcu_read_lock();
> if (success)
> @@ -2474,7 +2477,7 @@ static int narrow_write_error(struct r10bio
> *r10_bio, int i)
> choose_data_offset(r10_bio, rdev) +
> (sector - r10_bio->sector));
> wbio->bi_bdev = rdev->bdev;
> - wbio->bi_rw = WRITE;
> + wbio->bi_op = REQ_OP_WRITE;
>
> if (submit_bio_wait(wbio) < 0)
> /* Failure! */
> @@ -2550,7 +2553,8 @@ read_more:
> bio->bi_iter.bi_sector = r10_bio->devs[slot].addr
> + choose_data_offset(r10_bio, rdev);
> bio->bi_bdev = rdev->bdev;
> - bio->bi_rw = READ | do_sync;
> + bio->bi_op = REQ_OP_READ;
> + bio->bi_rw = do_sync;
> bio->bi_private = r10_bio;
> bio->bi_end_io = raid10_end_read_request;
> if (max_sectors < r10_bio->sectors) {
> @@ -3040,7 +3044,7 @@ static sector_t raid10_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> biolist = bio;
> bio->bi_private = r10_bio;
> bio->bi_end_io = end_sync_read;
> - bio->bi_rw = READ;
> + bio->bi_op = REQ_OP_READ;
> from_addr = r10_bio->devs[j].addr;
> bio->bi_iter.bi_sector = from_addr +
> rdev->data_offset;
> @@ -3066,7 +3070,7 @@ static sector_t raid10_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> biolist = bio;
> bio->bi_private = r10_bio;
> bio->bi_end_io = end_sync_write;
> - bio->bi_rw = WRITE;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_iter.bi_sector = to_addr
> + rdev->data_offset;
> bio->bi_bdev = rdev->bdev;
> @@ -3095,7 +3099,7 @@ static sector_t raid10_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> biolist = bio;
> bio->bi_private = r10_bio;
> bio->bi_end_io = end_sync_write;
> - bio->bi_rw = WRITE;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_iter.bi_sector = to_addr +
> rdev->data_offset;
> bio->bi_bdev = rdev->bdev;
> @@ -3215,7 +3219,7 @@ static sector_t raid10_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> biolist = bio;
> bio->bi_private = r10_bio;
> bio->bi_end_io = end_sync_read;
> - bio->bi_rw = READ;
> + bio->bi_op = REQ_OP_READ;
> bio->bi_iter.bi_sector = sector +
> conf->mirrors[d].rdev->data_offset;
> bio->bi_bdev = conf->mirrors[d].rdev->bdev;
> @@ -3237,7 +3241,7 @@ static sector_t raid10_sync_request(struct mddev
> *mddev, sector_t sector_nr,
> biolist = bio;
> bio->bi_private = r10_bio;
> bio->bi_end_io = end_sync_write;
> - bio->bi_rw = WRITE;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_iter.bi_sector = sector +
> conf->mirrors[d].replacement->data_offset;
> bio->bi_bdev = conf->mirrors[d].replacement->bdev;
> @@ -4320,7 +4324,7 @@ read_more:
> + rdev->data_offset);
> read_bio->bi_private = r10_bio;
> read_bio->bi_end_io = end_sync_read;
> - read_bio->bi_rw = READ;
> + read_bio->bi_op = REQ_OP_READ;
> read_bio->bi_flags &= (~0UL << BIO_RESET_BITS);
> read_bio->bi_error = 0;
> read_bio->bi_vcnt = 0;
> @@ -4354,7 +4358,7 @@ read_more:
> rdev2->new_data_offset;
> b->bi_private = r10_bio;
> b->bi_end_io = end_reshape_write;
> - b->bi_rw = WRITE;
> + b->bi_op = REQ_OP_WRITE;
> b->bi_next = blist;
> blist = b;
> }
> @@ -4522,7 +4526,7 @@ static int handle_reshape_read_error(struct mddev
> *mddev,
> addr,
> s << 9,
> bvec[idx].bv_page,
> - READ, false);
> + REQ_OP_READ, 0, false);
> if (success)
> break;
> failed:
> diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c
> index 90c2618..56b20c3 100644
> --- a/drivers/md/raid5-cache.c
> +++ b/drivers/md/raid5-cache.c
> @@ -261,7 +261,7 @@ static struct bio *r5l_bio_alloc(struct r5l_log *log)
> {
> struct bio *bio = bio_alloc_bioset(GFP_NOIO, BIO_MAX_PAGES,
> log->bs);
>
> - bio->bi_rw = WRITE;
> + bio->bi_op = REQ_OP_WRITE;
> bio->bi_bdev = log->rdev->bdev;
> bio->bi_iter.bi_sector = log->rdev->data_offset + log->log_start;
>
> @@ -686,6 +686,7 @@ void r5l_flush_stripe_to_raid(struct r5l_log *log)
> bio_reset(&log->flush_bio);
> log->flush_bio.bi_bdev = log->rdev->bdev;
> log->flush_bio.bi_end_io = r5l_log_flush_endio;
> + log->flush_bio.bi_op = REQ_OP_WRITE;
> log->flush_bio.bi_rw = WRITE_FLUSH;
> submit_bio(&log->flush_bio);
> }
> @@ -882,7 +883,8 @@ static int r5l_read_meta_block(struct r5l_log *log,
> struct r5l_meta_block *mb;
> u32 crc, stored_crc;
>
> - if (!sync_page_io(log->rdev, ctx->pos, PAGE_SIZE, page, READ,
> false))
> + if (!sync_page_io(log->rdev, ctx->pos, PAGE_SIZE, page,
> REQ_OP_READ, 0,
> + false))
> return -EIO;
>
> mb = page_address(page);
> @@ -927,7 +929,8 @@ static int r5l_recovery_flush_one_stripe(struct
> r5l_log *log,
> &disk_index, sh);
>
> sync_page_io(log->rdev, *log_offset, PAGE_SIZE,
> - sh->dev[disk_index].page, READ,
> false);
> + sh->dev[disk_index].page,
> REQ_OP_READ, 0,
> + false);
> sh->dev[disk_index].log_checksum =
> le32_to_cpu(payload->checksum[0]);
> set_bit(R5_Wantwrite, &sh->dev[disk_index].flags);
> @@ -935,7 +938,8 @@ static int r5l_recovery_flush_one_stripe(struct
> r5l_log *log,
> } else {
> disk_index = sh->pd_idx;
> sync_page_io(log->rdev, *log_offset, PAGE_SIZE,
> - sh->dev[disk_index].page, READ,
> false);
> + sh->dev[disk_index].page,
> REQ_OP_READ, 0,
> + false);
> sh->dev[disk_index].log_checksum =
> le32_to_cpu(payload->checksum[0]);
> set_bit(R5_Wantwrite, &sh->dev[disk_index].flags);
> @@ -945,7 +949,7 @@ static int r5l_recovery_flush_one_stripe(struct
> r5l_log *log,
> sync_page_io(log->rdev,
> r5l_ring_add(log,
> *log_offset, BLOCK_SECTORS),
> PAGE_SIZE,
> sh->dev[disk_index].page,
> - READ, false);
> + REQ_OP_READ, 0, false);
> sh->dev[disk_index].log_checksum =
> le32_to_cpu(payload->checksum[1]);
> set_bit(R5_Wantwrite,
> @@ -987,11 +991,13 @@ static int r5l_recovery_flush_one_stripe(struct
> r5l_log *log,
> rdev = rcu_dereference(conf->disks[disk_index].rdev);
> if (rdev)
> sync_page_io(rdev, stripe_sect, PAGE_SIZE,
> - sh->dev[disk_index].page, WRITE,
> false);
> + sh->dev[disk_index].page,
> REQ_OP_WRITE, 0,
> + false);
> rrdev =
> rcu_dereference(conf->disks[disk_index].replacement);
> if (rrdev)
> sync_page_io(rrdev, stripe_sect, PAGE_SIZE,
> - sh->dev[disk_index].page, WRITE,
> false);
> + sh->dev[disk_index].page,
> REQ_OP_WRITE, 0,
> + false);
> }
> raid5_release_stripe(sh);
> return 0;
> @@ -1063,7 +1069,8 @@ static int r5l_log_write_empty_meta_block(struct
> r5l_log *log, sector_t pos,
> crc = crc32c_le(log->uuid_checksum, mb, PAGE_SIZE);
> mb->checksum = cpu_to_le32(crc);
>
> - if (!sync_page_io(log->rdev, pos, PAGE_SIZE, page, WRITE_FUA,
> false)) {
> + if (!sync_page_io(log->rdev, pos, PAGE_SIZE, page, REQ_OP_WRITE,
> + WRITE_FUA, false)) {
> __free_page(page);
> return -EIO;
> }
> @@ -1138,7 +1145,7 @@ static int r5l_load_log(struct r5l_log *log)
> if (!page)
> return -ENOMEM;
>
> - if (!sync_page_io(rdev, cp, PAGE_SIZE, page, READ, false)) {
> + if (!sync_page_io(rdev, cp, PAGE_SIZE, page, REQ_OP_READ, 0,
> false)) {
> ret = -EIO;
> goto ioerr;
> }
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index 8ab8b65..c36b817 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -806,7 +806,8 @@ static void stripe_add_to_batch_list(struct r5conf
> *conf, struct stripe_head *sh
> dd_idx = 0;
> while (dd_idx == sh->pd_idx || dd_idx == sh->qd_idx)
> dd_idx++;
> - if (head->dev[dd_idx].towrite->bi_rw !=
> sh->dev[dd_idx].towrite->bi_rw)
> + if (head->dev[dd_idx].towrite->bi_rw !=
> sh->dev[dd_idx].towrite->bi_rw ||
> + head->dev[dd_idx].towrite->bi_op !=
> sh->dev[dd_idx].towrite->bi_op)
> goto unlock_out;
>
> if (head->batch_head) {
> @@ -891,29 +892,32 @@ static void ops_run_io(struct stripe_head *sh,
> struct stripe_head_state *s)
> if (r5l_write_stripe(conf->log, sh) == 0)
> return;
> for (i = disks; i--; ) {
> - int rw;
> + int op;
> + int op_flags = 0;
> int replace_only = 0;
> struct bio *bi, *rbi;
> struct md_rdev *rdev, *rrdev = NULL;
>
> sh = head_sh;
> if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) {
> - if (test_and_clear_bit(R5_WantFUA,
> &sh->dev[i].flags))
> - rw = WRITE_FUA;
> - else
> - rw = WRITE;
> + if (test_and_clear_bit(R5_WantFUA,
> &sh->dev[i].flags)) {
> + op = REQ_OP_WRITE;
> + op_flags = WRITE_FUA;
> + } else {
> + op = REQ_OP_WRITE;
> + }
> if (test_bit(R5_Discard, &sh->dev[i].flags))
> - rw |= REQ_DISCARD;
> + op = REQ_OP_DISCARD;
> } else if (test_and_clear_bit(R5_Wantread,
> &sh->dev[i].flags))
> - rw = READ;
> + op = REQ_OP_READ;
> else if (test_and_clear_bit(R5_WantReplace,
> &sh->dev[i].flags)) {
> - rw = WRITE;
> + op = REQ_OP_WRITE;
> replace_only = 1;
> } else
> continue;
> if (test_and_clear_bit(R5_SyncIO, &sh->dev[i].flags))
> - rw |= REQ_SYNC;
> + op_flags |= REQ_SYNC;
>
> again:
> bi = &sh->dev[i].req;
> @@ -927,7 +931,7 @@ again:
> rdev = rrdev;
> rrdev = NULL;
> }
> - if (rw & WRITE) {
> + if (op_is_write(op)) {
> if (replace_only)
> rdev = NULL;
> if (rdev == rrdev)
> @@ -953,7 +957,7 @@ again:
> * need to check for writes. We never accept write errors
> * on the replacement, so we don't to check rrdev.
> */
> - while ((rw & WRITE) && rdev &&
> + while (op_is_write(op) && rdev &&
> test_bit(WriteErrorSeen, &rdev->flags)) {
> sector_t first_bad;
> int bad_sectors;
> @@ -995,8 +999,9 @@ again:
>
> bio_reset(bi);
> bi->bi_bdev = rdev->bdev;
> - bi->bi_rw = rw;
> - bi->bi_end_io = (rw & WRITE)
> + bi->bi_op = op;
> + bi->bi_rw = op_flags;
> + bi->bi_end_io = op_is_write(op)
> ? raid5_end_write_request
> : raid5_end_read_request;
> bi->bi_private = sh;
> @@ -1027,7 +1032,7 @@ again:
> * If this is discard request, set bi_vcnt 0. We
> don't
> * want to confuse SCSI because SCSI will replace
> payload
> */
> - if (rw & REQ_DISCARD)
> + if (op == REQ_OP_DISCARD)
> bi->bi_vcnt = 0;
> if (rrdev)
> set_bit(R5_DOUBLE_LOCKED,
> &sh->dev[i].flags);
> @@ -1047,8 +1052,9 @@ again:
>
> bio_reset(rbi);
> rbi->bi_bdev = rrdev->bdev;
> - rbi->bi_rw = rw;
> - BUG_ON(!(rw & WRITE));
> + rbi->bi_op = op;
> + rbi->bi_rw = op_flags;
> + BUG_ON(!op_is_write(op));
> rbi->bi_end_io = raid5_end_write_request;
> rbi->bi_private = sh;
>
> @@ -1076,7 +1082,7 @@ again:
> * If this is discard request, set bi_vcnt 0. We
> don't
> * want to confuse SCSI because SCSI will replace
> payload
> */
> - if (rw & REQ_DISCARD)
> + if (op == REQ_OP_DISCARD)
> rbi->bi_vcnt = 0;
> if (conf->mddev->gendisk)
>
> trace_block_bio_remap(bdev_get_queue(rbi->bi_bdev),
> @@ -1085,7 +1091,7 @@ again:
> generic_make_request(rbi);
> }
> if (!rdev && !rrdev) {
> - if (rw & WRITE)
> + if (op_is_write(op))
> set_bit(STRIPE_DEGRADED, &sh->state);
> pr_debug("skip op %ld on disc %d for sector
> %llu\n",
> bi->bi_rw, i, (unsigned long
> long)sh->sector);
> @@ -1623,7 +1629,7 @@ again:
> set_bit(R5_WantFUA, &dev->flags);
> if (wbi->bi_rw & REQ_SYNC)
> set_bit(R5_SyncIO, &dev->flags);
> - if (wbi->bi_rw & REQ_DISCARD)
> + if (wbi->bi_op == REQ_OP_DISCARD)
> set_bit(R5_Discard, &dev->flags);
> else {
> tx = async_copy_data(1, wbi,
> &dev->page,
> @@ -5178,7 +5184,7 @@ static void raid5_make_request(struct mddev *mddev,
> struct bio * bi)
> return;
> }
>
> - if (unlikely(bi->bi_rw & REQ_DISCARD)) {
> + if (unlikely(bi->bi_op == REQ_OP_DISCARD)) {
> make_discard_request(mddev, bi);
> return;
> }
> --
> 2.7.2
>
> --
> dm-devel mailing list
> dm-devel@redhat.com
> https://www.redhat.com/mailman/listinfo/dm-devel
>
--
Shaun Tancheff
[-- Attachment #1.2: Type: text/html, Size: 48914 bytes --]
[-- Attachment #2: Type: text/plain, Size: 121 bytes --]
_______________________________________________
xfs mailing list
xfs@oss.sgi.com
http://oss.sgi.com/mailman/listinfo/xfs
^ permalink raw reply
* [PATCH] RAID Cleanup for bio-split
From: Shaun Tancheff @ 2016-04-23 23:05 UTC (permalink / raw)
To: mchristi, linux-f2fs-devel, linux-ext4, konrad.wilk, drbd-dev,
philipp.reisner, lars.ellenberg, linux-raid, dm-devel,
linux-fsdevel, linux-bcache, linux-block, linux-kernel,
linux-scsi, linux-mtd, target-devel, linux-btrfs, osd-dev, xfs,
ocfs2-devel
Cc: Shaun Tancheff, Shaun Tancheff
In-Reply-To: <1460747777-8479-24-git-send-email-mchristi@redhat.com>
It looks like some minor changes slipped through on the RAID.
A couple of checks for REQ_PREFLUSH flag should also check for
bi_op matching REQ_OP_FLUSH.
Wrappers for sync_page_io() are passed READ/WRITE but need to
be passed REQ_OP_READ and REQ_OP_WRITE.
Signed-off-by: Shaun Tancheff <shaun.tancheff@seagate.com>
---
drivers/md/raid0.c | 3 ++-
drivers/md/raid1.c | 13 +++++++------
drivers/md/raid10.c | 21 ++++++++++-----------
drivers/md/raid5.c | 3 ++-
4 files changed, 21 insertions(+), 19 deletions(-)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index f95463d..46e9ba8 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -458,7 +458,8 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
struct md_rdev *tmp_dev;
struct bio *split;
- if (unlikely(bio->bi_rw & REQ_PREFLUSH)) {
+ if (unlikely(bio->bi_rw & REQ_PREFLUSH) ||
+ unlikely(bio->bi_op == REQ_OP_FLUSH)) {
md_flush_request(mddev, bio);
return;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 2a2c177..f7c0577 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1771,12 +1771,12 @@ static void end_sync_write(struct bio *bio)
}
static int r1_sync_page_io(struct md_rdev *rdev, sector_t sector,
- int sectors, struct page *page, int rw)
+ int sectors, struct page *page, int op)
{
- if (sync_page_io(rdev, sector, sectors << 9, page, rw, 0, false))
+ if (sync_page_io(rdev, sector, sectors << 9, page, op, 0, false))
/* success */
return 1;
- if (rw == WRITE) {
+ if (op == REQ_OP_WRITE) {
set_bit(WriteErrorSeen, &rdev->flags);
if (!test_and_set_bit(WantReplacement,
&rdev->flags))
@@ -1883,7 +1883,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
rdev = conf->mirrors[d].rdev;
if (r1_sync_page_io(rdev, sect, s,
bio->bi_io_vec[idx].bv_page,
- WRITE) == 0) {
+ REQ_OP_WRITE) == 0) {
r1_bio->bios[d]->bi_end_io = NULL;
rdev_dec_pending(rdev, mddev);
}
@@ -2118,7 +2118,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
if (rdev &&
!test_bit(Faulty, &rdev->flags))
r1_sync_page_io(rdev, sect, s,
- conf->tmppage, WRITE);
+ conf->tmppage, REQ_OP_WRITE);
}
d = start;
while (d != read_disk) {
@@ -2130,7 +2130,7 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
if (rdev &&
!test_bit(Faulty, &rdev->flags)) {
if (r1_sync_page_io(rdev, sect, s,
- conf->tmppage, READ)) {
+ conf->tmppage, REQ_OP_READ)) {
atomic_add(s, &rdev->corrected_errors);
printk(KERN_INFO
"md/raid1:%s: read error corrected "
@@ -2204,6 +2204,7 @@ static int narrow_write_error(struct r1bio *r1_bio, int i)
}
wbio->bi_op = REQ_OP_WRITE;
+ wbio->bi_rw = 0;
wbio->bi_iter.bi_sector = r1_bio->sector;
wbio->bi_iter.bi_size = r1_bio->sectors << 9;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index c5dc4e4..44e87c2 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1364,8 +1364,7 @@ retry_write:
mbio->bi_bdev = rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_op = op;
- mbio->bi_rw =
- do_sync | do_fua | do_sec;
+ mbio->bi_rw = do_sync | do_fua | do_sec;
mbio->bi_private = r10_bio;
atomic_inc(&r10_bio->remaining);
@@ -1408,8 +1407,7 @@ retry_write:
mbio->bi_bdev = rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_op = op;
- mbio->bi_rw =
- do_sync | do_fua | do_sec;
+ mbio->bi_rw = do_sync | do_fua | do_sec;
mbio->bi_private = r10_bio;
atomic_inc(&r10_bio->remaining);
@@ -1452,7 +1450,8 @@ static void raid10_make_request(struct mddev *mddev, struct bio *bio)
struct bio *split;
- if (unlikely(bio->bi_rw & REQ_PREFLUSH)) {
+ if (unlikely(bio->bi_rw & REQ_PREFLUSH) ||
+ unlikely(bio->bi_op == REQ_OP_FLUSH)) {
md_flush_request(mddev, bio);
return;
}
@@ -2207,18 +2206,18 @@ static void check_decay_read_errors(struct mddev *mddev, struct md_rdev *rdev)
}
static int r10_sync_page_io(struct md_rdev *rdev, sector_t sector,
- int sectors, struct page *page, int rw)
+ int sectors, struct page *page, int op)
{
sector_t first_bad;
int bad_sectors;
if (is_badblock(rdev, sector, sectors, &first_bad, &bad_sectors)
- && (rw == READ || test_bit(WriteErrorSeen, &rdev->flags)))
+ && (op == REQ_OP_READ || test_bit(WriteErrorSeen, &rdev->flags)))
return -1;
- if (sync_page_io(rdev, sector, sectors << 9, page, rw, 0, false))
+ if (sync_page_io(rdev, sector, sectors << 9, page, op, 0, false))
/* success */
return 1;
- if (rw == WRITE) {
+ if (op == REQ_OP_WRITE) {
set_bit(WriteErrorSeen, &rdev->flags);
if (!test_and_set_bit(WantReplacement, &rdev->flags))
set_bit(MD_RECOVERY_NEEDED,
@@ -2354,7 +2353,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
if (r10_sync_page_io(rdev,
r10_bio->devs[sl].addr +
sect,
- s, conf->tmppage, WRITE)
+ s, conf->tmppage, REQ_OP_WRITE)
== 0) {
/* Well, this device is dead */
printk(KERN_NOTICE
@@ -2394,7 +2393,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
r10_bio->devs[sl].addr +
sect,
s, conf->tmppage,
- READ)) {
+ REQ_OP_READ)) {
case 0:
/* Well, this device is dead */
printk(KERN_NOTICE
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 8504862..3e5a9db 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5161,7 +5161,8 @@ static void raid5_make_request(struct mddev *mddev, struct bio * bi)
DEFINE_WAIT(w);
bool do_prepare;
- if (unlikely(bi->bi_rw & REQ_PREFLUSH)) {
+ if (unlikely(bi->bi_rw & REQ_PREFLUSH) ||
+ unlikely(bi->bi_op == REQ_OP_FLUSH)) {
int ret = r5l_handle_flush_request(conf->log, bi);
if (ret == 0)
--
2.8.1
^ permalink raw reply related
* HELLO DEAR
From: Melissa Robert @ 2016-04-22 17:46 UTC (permalink / raw)
Hello Dear,
how are you doing hope fine, I am (Melissa Robert) by name. i will like
to
know more about you believing that friendship is a free gift of nature.
Please get back to me as soon as possible through this my private Email.
(mr4785395@gmail.com)
thank you.
^ permalink raw reply
* [PATCH v3 21/21] fuse: Allow user namespace mounts
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Miklos Szeredi
Cc: Alexander Viro, Serge Hallyn, Richard Weinberger,
Austin S Hemmelgarn, Miklos Szeredi, Pavel Tikhomirov,
linux-kernel, linux-bcache, dm-devel, linux-raid, linux-mtd,
linux-fsdevel, fuse-devel, linux-security-module, selinux,
cgroups, Seth Forshee
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee@canonical.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
---
fs/fuse/inode.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 0a771145d853..254f1944ee98 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1199,7 +1199,7 @@ static void fuse_kill_sb_anon(struct super_block *sb)
static struct file_system_type fuse_fs_type = {
.owner = THIS_MODULE,
.name = "fuse",
- .fs_flags = FS_HAS_SUBTYPE,
+ .fs_flags = FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
.mount = fuse_mount,
.kill_sb = fuse_kill_sb_anon,
};
@@ -1231,7 +1231,7 @@ static struct file_system_type fuseblk_fs_type = {
.name = "fuseblk",
.mount = fuse_mount_blk,
.kill_sb = fuse_kill_sb_blk,
- .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE,
+ .fs_flags = FS_REQUIRES_DEV | FS_HAS_SUBTYPE | FS_USERNS_MOUNT,
};
MODULE_ALIAS_FS("fuseblk");
--
1.9.1
^ permalink raw reply related
* [PATCH v3 20/21] fuse: Restrict allow_other to the superblock's namespace or a descendant
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Miklos Szeredi
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alexander Viro,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Unprivileged users are normally restricted from mounting with the
allow_other option by system policy, but this could be bypassed
for a mount done with user namespace root permissions. In such
cases allow_other should not allow users outside the userns
to access the mount as doing so would give the unprivileged user
the ability to manipulate processes it would otherwise be unable
to manipulate. Restrict allow_other to apply to users in the same
userns used at mount or a descendant of that namespace.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Miklos Szeredi <mszeredi-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/fuse/dir.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index ecba75bf6640..1a6c5af49608 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1015,7 +1015,7 @@ int fuse_allow_current_process(struct fuse_conn *fc)
const struct cred *cred;
if (fc->flags & FUSE_ALLOW_OTHER)
- return 1;
+ return current_in_userns(fc->user_ns);
cred = current_cred();
if (uid_eq(cred->euid, fc->user_id) &&
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 19/21] fuse: Support fuse filesystems outside of init_user_ns
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Miklos Szeredi
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alexander Viro,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
In order to support mounts from namespaces other than
init_user_ns, fuse must translate uids and gids to/from the
userns of the process servicing requests on /dev/fuse. This
patch does that, with a couple of restrictions on the namespace:
- The userns for the fuse connection is fixed to the namespace
from which /dev/fuse is opened.
- The namespace must be the same as s_user_ns.
These restrictions simplify the implementation by avoiding the
need to pass around userns references and by allowing fuse to
rely on the checks in inode_change_ok for ownership changes.
Either restriction could be relaxed in the future if needed.
For cuse the namespace used for the connection is also simply
current_user_ns() at the time /dev/cuse is opened.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
fs/fuse/cuse.c | 3 ++-
fs/fuse/dev.c | 13 ++++++++-----
fs/fuse/dir.c | 14 +++++++-------
fs/fuse/fuse_i.h | 6 +++++-
fs/fuse/inode.c | 33 +++++++++++++++++++++------------
5 files changed, 43 insertions(+), 26 deletions(-)
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index c5b6b7165489..98ebd0f4fd4c 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -48,6 +48,7 @@
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/uio.h>
+#include <linux/user_namespace.h>
#include "fuse_i.h"
@@ -498,7 +499,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
if (!cc)
return -ENOMEM;
- fuse_conn_init(&cc->fc);
+ fuse_conn_init(&cc->fc, current_user_ns());
fud = fuse_dev_alloc(&cc->fc);
if (!fud) {
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 4e91b2ac25a7..8fa1ce934df3 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -127,8 +127,8 @@ static void __fuse_put_request(struct fuse_req *req)
static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
{
- req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
- req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
+ req->in.h.uid = from_kuid(fc->user_ns, current_fsuid());
+ req->in.h.gid = from_kgid(fc->user_ns, current_fsgid());
req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
}
@@ -186,7 +186,8 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
__set_bit(FR_WAITING, &req->flags);
if (for_background)
__set_bit(FR_BACKGROUND, &req->flags);
- if (req->in.h.pid == 0) {
+ if (req->in.h.pid == 0 || req->in.h.uid == (uid_t)-1 ||
+ req->in.h.gid == (gid_t)-1) {
fuse_put_request(fc, req);
return ERR_PTR(-EOVERFLOW);
}
@@ -1248,7 +1249,8 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
struct fuse_in *in;
unsigned reqsize;
- if (task_active_pid_ns(current) != fc->pid_ns)
+ if (task_active_pid_ns(current) != fc->pid_ns ||
+ current_user_ns() != fc->user_ns)
return -EIO;
restart:
@@ -1880,7 +1882,8 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
struct fuse_req *req;
struct fuse_out_header oh;
- if (task_active_pid_ns(current) != fc->pid_ns)
+ if (task_active_pid_ns(current) != fc->pid_ns ||
+ current_user_ns() != fc->user_ns)
return -EIO;
if (nbytes < sizeof(struct fuse_out_header))
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 4b855b65d457..ecba75bf6640 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -841,8 +841,8 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
stat->ino = attr->ino;
stat->mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
stat->nlink = attr->nlink;
- stat->uid = make_kuid(&init_user_ns, attr->uid);
- stat->gid = make_kgid(&init_user_ns, attr->gid);
+ stat->uid = make_kuid(fc->user_ns, attr->uid);
+ stat->gid = make_kgid(fc->user_ns, attr->gid);
stat->rdev = inode->i_rdev;
stat->atime.tv_sec = attr->atime;
stat->atime.tv_nsec = attr->atimensec;
@@ -1459,17 +1459,17 @@ static bool update_mtime(unsigned ivalid, bool trust_local_mtime)
return true;
}
-static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg,
- bool trust_local_cmtime)
+static void iattr_to_fattr(struct fuse_conn *fc, struct iattr *iattr,
+ struct fuse_setattr_in *arg, bool trust_local_cmtime)
{
unsigned ivalid = iattr->ia_valid;
if (ivalid & ATTR_MODE)
arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
if (ivalid & ATTR_UID)
- arg->valid |= FATTR_UID, arg->uid = from_kuid(&init_user_ns, iattr->ia_uid);
+ arg->valid |= FATTR_UID, arg->uid = from_kuid(fc->user_ns, iattr->ia_uid);
if (ivalid & ATTR_GID)
- arg->valid |= FATTR_GID, arg->gid = from_kgid(&init_user_ns, iattr->ia_gid);
+ arg->valid |= FATTR_GID, arg->gid = from_kgid(fc->user_ns, iattr->ia_gid);
if (ivalid & ATTR_SIZE)
arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
if (ivalid & ATTR_ATIME) {
@@ -1629,7 +1629,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
memset(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg));
- iattr_to_fattr(attr, &inarg, trust_local_cmtime);
+ iattr_to_fattr(fc, attr, &inarg, trust_local_cmtime);
if (file) {
struct fuse_file *ff = file->private_data;
inarg.valid |= FATTR_FH;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 9145445a759a..9f4c3c82edd6 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -24,6 +24,7 @@
#include <linux/workqueue.h>
#include <linux/kref.h>
#include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
/** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32
@@ -469,6 +470,9 @@ struct fuse_conn {
/** The pid namespace for this mount */
struct pid_namespace *pid_ns;
+ /** The user namespace for this mount */
+ struct user_namespace *user_ns;
+
/** The fuse mount flags for this mount */
unsigned flags;
@@ -867,7 +871,7 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
/**
* Initialize fuse_conn
*/
-void fuse_conn_init(struct fuse_conn *fc);
+void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns);
/**
* Release reference to fuse_conn
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index eade0bfa4488..0a771145d853 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -167,8 +167,8 @@ void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
inode->i_ino = fuse_squash_ino(attr->ino);
inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
set_nlink(inode, attr->nlink);
- inode->i_uid = make_kuid(&init_user_ns, attr->uid);
- inode->i_gid = make_kgid(&init_user_ns, attr->gid);
+ inode->i_uid = make_kuid(fc->user_ns, attr->uid);
+ inode->i_gid = make_kgid(fc->user_ns, attr->gid);
inode->i_blocks = attr->blocks;
inode->i_atime.tv_sec = attr->atime;
inode->i_atime.tv_nsec = attr->atimensec;
@@ -467,7 +467,8 @@ static int fuse_match_uint(substring_t *s, unsigned int *res)
return err;
}
-static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
+static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev,
+ struct user_namespace *user_ns)
{
char *p;
memset(d, 0, sizeof(struct fuse_mount_data));
@@ -503,7 +504,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
case OPT_USER_ID:
if (fuse_match_uint(&args[0], &uv))
return 0;
- d->user_id = make_kuid(current_user_ns(), uv);
+ d->user_id = make_kuid(user_ns, uv);
if (!uid_valid(d->user_id))
return 0;
d->user_id_present = 1;
@@ -512,7 +513,7 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev)
case OPT_GROUP_ID:
if (fuse_match_uint(&args[0], &uv))
return 0;
- d->group_id = make_kgid(current_user_ns(), uv);
+ d->group_id = make_kgid(user_ns, uv);
if (!gid_valid(d->group_id))
return 0;
d->group_id_present = 1;
@@ -555,8 +556,10 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
struct super_block *sb = root->d_sb;
struct fuse_conn *fc = get_fuse_conn_super(sb);
- seq_printf(m, ",user_id=%u", from_kuid_munged(&init_user_ns, fc->user_id));
- seq_printf(m, ",group_id=%u", from_kgid_munged(&init_user_ns, fc->group_id));
+ seq_printf(m, ",user_id=%u",
+ from_kuid_munged(fc->user_ns, fc->user_id));
+ seq_printf(m, ",group_id=%u",
+ from_kgid_munged(fc->user_ns, fc->group_id));
if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
seq_puts(m, ",default_permissions");
if (fc->flags & FUSE_ALLOW_OTHER)
@@ -587,7 +590,7 @@ static void fuse_pqueue_init(struct fuse_pqueue *fpq)
fpq->connected = 1;
}
-void fuse_conn_init(struct fuse_conn *fc)
+void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns)
{
memset(fc, 0, sizeof(*fc));
spin_lock_init(&fc->lock);
@@ -611,6 +614,7 @@ void fuse_conn_init(struct fuse_conn *fc)
fc->attr_version = 1;
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
+ fc->user_ns = get_user_ns(user_ns);
}
EXPORT_SYMBOL_GPL(fuse_conn_init);
@@ -620,6 +624,7 @@ void fuse_conn_put(struct fuse_conn *fc)
if (fc->destroy_req)
fuse_request_free(fc->destroy_req);
put_pid_ns(fc->pid_ns);
+ put_user_ns(fc->user_ns);
fc->release(fc);
}
}
@@ -1046,7 +1051,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
sb->s_flags &= ~(MS_NOSEC | MS_I_VERSION);
- if (!parse_fuse_opt(data, &d, is_bdev))
+ if (!parse_fuse_opt(data, &d, is_bdev, sb->s_user_ns))
goto err;
if (is_bdev) {
@@ -1070,8 +1075,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (!file)
goto err;
- if ((file->f_op != &fuse_dev_operations) ||
- (file->f_cred->user_ns != &init_user_ns))
+ /*
+ * Require mount to happen from the same user namespace which
+ * opened /dev/fuse to prevent potential attacks.
+ */
+ if (file->f_op != &fuse_dev_operations ||
+ file->f_cred->user_ns != sb->s_user_ns)
goto err_fput;
fc = kmalloc(sizeof(*fc), GFP_KERNEL);
@@ -1079,7 +1088,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
if (!fc)
goto err_fput;
- fuse_conn_init(fc);
+ fuse_conn_init(fc, sb->s_user_ns);
fc->release = fuse_free_conn;
fud = fuse_dev_alloc(fc);
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 18/21] fuse: Add support for pid namespaces
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Miklos Szeredi
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alexander Viro,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
When the userspace process servicing fuse requests is running in
a pid namespace then pids passed via the fuse fd are not being
translated into that process' namespace. Translation is necessary
for the pid to be useful to that process.
Since no use case currently exists for changing namespaces all
translations can be done relative to the pid namespace in use
when fuse_conn_init() is called. For fuse this translates to
mount time, and for cuse this is when /dev/cuse is opened. IO for
this connection from another namespace will return errors.
Requests from processes whose pid cannot be translated into the
target namespace are not permitted, except for requests
allocated via fuse_get_req_nofail_nopages. For no-fail requests
in.h.pid will be 0 if the pid translation fails.
File locking changes based on previous work done by Eric
Biederman.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Miklos Szeredi <mszeredi-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
fs/fuse/dev.c | 19 +++++++++++++++----
fs/fuse/file.c | 22 +++++++++++++++++-----
fs/fuse/fuse_i.h | 4 ++++
fs/fuse/inode.c | 3 +++
4 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index cbece1221417..4e91b2ac25a7 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -19,6 +19,7 @@
#include <linux/pipe_fs_i.h>
#include <linux/swap.h>
#include <linux/splice.h>
+#include <linux/sched.h>
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");
@@ -124,11 +125,11 @@ static void __fuse_put_request(struct fuse_req *req)
atomic_dec(&req->count);
}
-static void fuse_req_init_context(struct fuse_req *req)
+static void fuse_req_init_context(struct fuse_conn *fc, struct fuse_req *req)
{
req->in.h.uid = from_kuid_munged(&init_user_ns, current_fsuid());
req->in.h.gid = from_kgid_munged(&init_user_ns, current_fsgid());
- req->in.h.pid = current->pid;
+ req->in.h.pid = pid_nr_ns(task_pid(current), fc->pid_ns);
}
void fuse_set_initialized(struct fuse_conn *fc)
@@ -181,10 +182,14 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
goto out;
}
- fuse_req_init_context(req);
+ fuse_req_init_context(fc, req);
__set_bit(FR_WAITING, &req->flags);
if (for_background)
__set_bit(FR_BACKGROUND, &req->flags);
+ if (req->in.h.pid == 0) {
+ fuse_put_request(fc, req);
+ return ERR_PTR(-EOVERFLOW);
+ }
return req;
@@ -274,7 +279,7 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
if (!req)
req = get_reserved_req(fc, file);
- fuse_req_init_context(req);
+ fuse_req_init_context(fc, req);
__set_bit(FR_WAITING, &req->flags);
__clear_bit(FR_BACKGROUND, &req->flags);
return req;
@@ -1243,6 +1248,9 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file,
struct fuse_in *in;
unsigned reqsize;
+ if (task_active_pid_ns(current) != fc->pid_ns)
+ return -EIO;
+
restart:
spin_lock(&fiq->waitq.lock);
err = -EAGAIN;
@@ -1872,6 +1880,9 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
struct fuse_req *req;
struct fuse_out_header oh;
+ if (task_active_pid_ns(current) != fc->pid_ns)
+ return -EIO;
+
if (nbytes < sizeof(struct fuse_out_header))
return -EINVAL;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 719924d6c706..b5c616c5ec98 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2067,7 +2067,8 @@ static int fuse_direct_mmap(struct file *file, struct vm_area_struct *vma)
return generic_file_mmap(file, vma);
}
-static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
+static int convert_fuse_file_lock(struct fuse_conn *fc,
+ const struct fuse_file_lock *ffl,
struct file_lock *fl)
{
switch (ffl->type) {
@@ -2082,7 +2083,14 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl,
fl->fl_start = ffl->start;
fl->fl_end = ffl->end;
- fl->fl_pid = ffl->pid;
+
+ /*
+ * Convert pid into the caller's pid namespace. If the pid
+ * does not map into the namespace fl_pid will get set to 0.
+ */
+ rcu_read_lock();
+ fl->fl_pid = pid_vnr(find_pid_ns(ffl->pid, fc->pid_ns));
+ rcu_read_unlock();
break;
default:
@@ -2131,7 +2139,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl)
args.out.args[0].value = &outarg;
err = fuse_simple_request(fc, &args);
if (!err)
- err = convert_fuse_file_lock(&outarg.lk, fl);
+ err = convert_fuse_file_lock(fc, &outarg.lk, fl);
return err;
}
@@ -2143,7 +2151,8 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
FUSE_ARGS(args);
struct fuse_lk_in inarg;
int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK;
- pid_t pid = fl->fl_type != F_UNLCK ? current->tgid : 0;
+ struct pid *pid = fl->fl_type != F_UNLCK ? task_tgid(current) : NULL;
+ pid_t pid_nr = pid_nr_ns(pid, fc->pid_ns);
int err;
if (fl->fl_lmops && fl->fl_lmops->lm_grant) {
@@ -2155,7 +2164,10 @@ static int fuse_setlk(struct file *file, struct file_lock *fl, int flock)
if (fl->fl_flags & FL_CLOSE)
return 0;
- fuse_lk_fill(&args, file, fl, opcode, pid, flock, &inarg);
+ if (pid && pid_nr == 0)
+ return -EOVERFLOW;
+
+ fuse_lk_fill(&args, file, fl, opcode, pid_nr, flock, &inarg);
err = fuse_simple_request(fc, &args);
/* locking is restartable */
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index eddbe02c4028..9145445a759a 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -23,6 +23,7 @@
#include <linux/poll.h>
#include <linux/workqueue.h>
#include <linux/kref.h>
+#include <linux/pid_namespace.h>
/** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32
@@ -465,6 +466,9 @@ struct fuse_conn {
/** The group id for this mount */
kgid_t group_id;
+ /** The pid namespace for this mount */
+ struct pid_namespace *pid_ns;
+
/** The fuse mount flags for this mount */
unsigned flags;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 1ce67668a8e1..eade0bfa4488 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -20,6 +20,7 @@
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/exportfs.h>
+#include <linux/pid_namespace.h>
MODULE_AUTHOR("Miklos Szeredi <miklos-sUDqSbJrdHQHWmgEVkV9KA@public.gmane.org>");
MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -609,6 +610,7 @@ void fuse_conn_init(struct fuse_conn *fc)
fc->connected = 1;
fc->attr_version = 1;
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
+ fc->pid_ns = get_pid_ns(task_active_pid_ns(current));
}
EXPORT_SYMBOL_GPL(fuse_conn_init);
@@ -617,6 +619,7 @@ void fuse_conn_put(struct fuse_conn *fc)
if (atomic_dec_and_test(&fc->count)) {
if (fc->destroy_req)
fuse_request_free(fc->destroy_req);
+ put_pid_ns(fc->pid_ns);
fc->release(fc);
}
}
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 17/21] capabilities: Allow privileged user in s_user_ns to set security.* xattrs
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Serge Hallyn, James Morris, Serge E. Hallyn
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Miklos Szeredi, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alexander Viro,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
A privileged user in s_user_ns will generally have the ability to
manipulate the backing store and insert security.* xattrs into
the filesystem directly. Therefore the kernel must be prepared to
handle these xattrs from unprivileged mounts, and it makes little
sense for commoncap to prevent writing these xattrs to the
filesystem. The capability and LSM code have already been updated
to appropriately handle xattrs from unprivileged mounts, so it
is safe to loosen this restriction on setting xattrs.
The exception to this logic is that writing xattrs to a mounted
filesystem may also cause the LSM inode_post_setxattr or
inode_setsecurity callbacks to be invoked. SELinux will deny the
xattr update by virtue of applying mountpoint labeling to
unprivileged userns mounts, and Smack will deny the writes for
any user without global CAP_MAC_ADMIN, so loosening the
capability check in commoncap is safe in this respect as well.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
security/commoncap.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/security/commoncap.c b/security/commoncap.c
index e657227d221e..12477afaa8ed 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -664,15 +664,17 @@ int cap_bprm_secureexec(struct linux_binprm *bprm)
int cap_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
+ struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
+
if (!strcmp(name, XATTR_NAME_CAPS)) {
- if (!capable(CAP_SETFCAP))
+ if (!ns_capable(user_ns, CAP_SETFCAP))
return -EPERM;
return 0;
}
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
- !capable(CAP_SYS_ADMIN))
+ !ns_capable(user_ns, CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
@@ -690,15 +692,17 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
*/
int cap_inode_removexattr(struct dentry *dentry, const char *name)
{
+ struct user_namespace *user_ns = dentry->d_sb->s_user_ns;
+
if (!strcmp(name, XATTR_NAME_CAPS)) {
- if (!capable(CAP_SETFCAP))
+ if (!ns_capable(user_ns, CAP_SETFCAP))
return -EPERM;
return 0;
}
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
- !capable(CAP_SYS_ADMIN))
+ !ns_capable(user_ns, CAP_SYS_ADMIN))
return -EPERM;
return 0;
}
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 16/21] fs: Allow superblock owner to access do_remount_sb()
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Alexander Viro
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Superblock level remounts are currently restricted to global
CAP_SYS_ADMIN, as is the path for changing the root mount to
read only on umount. Loosen both of these permission checks to
also allow CAP_SYS_ADMIN in any namespace which is privileged
towards the userns which originally mounted the filesystem.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
fs/namespace.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 0ad8e4a4f50b..575e3f8b34fd 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1510,7 +1510,7 @@ static int do_umount(struct mount *mnt, int flags)
* Special case for "unmounting" root ...
* we just try to remount it readonly.
*/
- if (!capable(CAP_SYS_ADMIN))
+ if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
return -EPERM;
down_write(&sb->s_umount);
if (!(sb->s_flags & MS_RDONLY))
@@ -2207,7 +2207,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
down_write(&sb->s_umount);
if (flags & MS_BIND)
err = change_mount_flags(path->mnt, flags);
- else if (!capable(CAP_SYS_ADMIN))
+ else if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN))
err = -EPERM;
else
err = do_remount_sb(sb, flags, data, 0);
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 15/21] fs: Don't remove suid for CAP_FSETID in s_user_ns
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Alexander Viro
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Expand the check in should_remove_suid() to keep privileges for
CAP_FSETID in s_user_ns rather than init_user_ns.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
fs/inode.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/fs/inode.c b/fs/inode.c
index 69b8b526c194..cd52170f9117 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1690,7 +1690,8 @@ int should_remove_suid(struct dentry *dentry)
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
kill |= ATTR_KILL_SGID;
- if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode)))
+ if (unlikely(kill && !ns_capable(dentry->d_sb->s_user_ns, CAP_FSETID) &&
+ S_ISREG(mode)))
return kill;
return 0;
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 14/21] fs: Allow superblock owner to change ownership of inodes with unmappable ids
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Alexander Viro, Greg Kroah-Hartman
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
In a userns mount some on-disk inodes may have ids which do not
map into s_user_ns, in which case the in-kernel inodes are owned
by invalid users. The superblock owner should be able to change
attributes of these inodes but cannot. However it is unsafe to
grant the superblock owner privileged access to all inodes in the
superblock since proc, sysfs, etc. use DAC to protect files which
may not belong to s_user_ns. The problem is restricted to only
inodes where the owner or group is an invalid user.
We can work around this by allowing users with CAP_CHOWN in
s_user_ns to change an invalid owner or group id, so long as the
other id is either invalid or mappable in s_user_ns. After
changing ownership the user will be privileged towards the inode
and thus able to change other attributes.
As an precaution, checks for invalid ids are added to the proc
and kernfs setattr interfaces. These filesystems are not expected
to have inodes with invalid ids, but if it does happen any
setattr operations will return -EPERM.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
fs/attr.c | 47 +++++++++++++++++++++++++++++++++++++++--------
fs/kernfs/inode.c | 2 ++
fs/proc/base.c | 2 ++
fs/proc/generic.c | 3 +++
fs/proc/proc_sysctl.c | 2 ++
5 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/fs/attr.c b/fs/attr.c
index 3cfaaac4a18e..a8b0931654a5 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -16,6 +16,43 @@
#include <linux/evm.h>
#include <linux/ima.h>
+static bool chown_ok(const struct inode *inode, kuid_t uid)
+{
+ struct user_namespace *user_ns;
+
+ if (uid_eq(current_fsuid(), inode->i_uid) && uid_eq(uid, inode->i_uid))
+ return true;
+ if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+ return true;
+
+ user_ns = inode->i_sb->s_user_ns;
+ if (!uid_valid(inode->i_uid) &&
+ (!gid_valid(inode->i_gid) || kgid_has_mapping(user_ns, inode->i_gid)) &&
+ ns_capable(user_ns, CAP_CHOWN))
+ return true;
+
+ return false;
+}
+
+static bool chgrp_ok(const struct inode *inode, kgid_t gid)
+{
+ struct user_namespace *user_ns;
+
+ if (uid_eq(current_fsuid(), inode->i_uid) &&
+ (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
+ return true;
+ if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+ return true;
+
+ user_ns = inode->i_sb->s_user_ns;
+ if (!gid_valid(inode->i_gid) &&
+ (!uid_valid(inode->i_uid) || kuid_has_mapping(user_ns, inode->i_uid)) &&
+ ns_capable(user_ns, CAP_CHOWN))
+ return true;
+
+ return false;
+}
+
/**
* inode_change_ok - check if attribute changes to an inode are allowed
* @inode: inode to check
@@ -58,17 +95,11 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return 0;
/* Make sure a caller can chown. */
- if ((ia_valid & ATTR_UID) &&
- (!uid_eq(current_fsuid(), inode->i_uid) ||
- !uid_eq(attr->ia_uid, inode->i_uid)) &&
- !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+ if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
return -EPERM;
/* Make sure caller can chgrp. */
- if ((ia_valid & ATTR_GID) &&
- (!uid_eq(current_fsuid(), inode->i_uid) ||
- (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
- !capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+ if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
return -EPERM;
/* Make sure a caller can chmod. */
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 16405ae88d2d..2e97a337ee5f 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -117,6 +117,8 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
if (!kn)
return -EINVAL;
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EPERM;
mutex_lock(&kernfs_mutex);
error = inode_change_ok(inode, iattr);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index b1755b23893e..648d623e2158 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -711,6 +711,8 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & ATTR_MODE)
return -EPERM;
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EPERM;
error = inode_change_ok(inode, attr);
if (error)
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index ff3ffc76a937..1461570c552c 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -105,6 +105,9 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
struct proc_dir_entry *de = PDE(inode);
int error;
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EPERM;
+
error = inode_change_ok(inode, iattr);
if (error)
return error;
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index fe5b6e6c4671..f5d575157194 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -752,6 +752,8 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
return -EPERM;
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EPERM;
error = inode_change_ok(inode, attr);
if (error)
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 13/21] fs: Update posix_acl support to handle user namespace mounts
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Alexander Viro
Cc: Serge Hallyn, Richard Weinberger, Austin S Hemmelgarn,
Miklos Szeredi, Pavel Tikhomirov, linux-kernel, linux-bcache,
dm-devel, linux-raid, linux-mtd, linux-fsdevel, fuse-devel,
linux-security-module, selinux, cgroups, Seth Forshee
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee@canonical.com>
ids in on-disk ACLs should be converted to s_user_ns instead of
init_user_ns as is done now. This introduces the possibility for
id mappings to fail, and when this happens syscalls will return
EOVERFLOW.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
Acked-by: Serge Hallyn <serge.hallyn@canonical.com>
---
fs/posix_acl.c | 67 ++++++++++++++++++++++++++---------------
fs/xattr.c | 19 +++++++++---
include/linux/posix_acl_xattr.h | 17 ++++++++---
3 files changed, 70 insertions(+), 33 deletions(-)
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 711dd5170376..dac2842dd4cb 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -595,59 +595,77 @@ EXPORT_SYMBOL_GPL(posix_acl_create);
/*
* Fix up the uids and gids in posix acl extended attributes in place.
*/
-static void posix_acl_fix_xattr_userns(
+static int posix_acl_fix_xattr_userns(
struct user_namespace *to, struct user_namespace *from,
void *value, size_t size)
{
posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
int count;
- kuid_t uid;
- kgid_t gid;
+ kuid_t kuid;
+ uid_t uid;
+ kgid_t kgid;
+ gid_t gid;
if (!value)
- return;
+ return 0;
if (size < sizeof(posix_acl_xattr_header))
- return;
+ return 0;
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
- return;
+ return 0;
count = posix_acl_xattr_count(size);
if (count < 0)
- return;
+ return 0;
if (count == 0)
- return;
+ return 0;
for (end = entry + count; entry != end; entry++) {
switch(le16_to_cpu(entry->e_tag)) {
case ACL_USER:
- uid = make_kuid(from, le32_to_cpu(entry->e_id));
- entry->e_id = cpu_to_le32(from_kuid(to, uid));
+ kuid = make_kuid(from, le32_to_cpu(entry->e_id));
+ if (!uid_valid(kuid))
+ return -EOVERFLOW;
+ uid = from_kuid(to, kuid);
+ if (uid == (uid_t)-1)
+ return -EOVERFLOW;
+ entry->e_id = cpu_to_le32(uid);
break;
case ACL_GROUP:
- gid = make_kgid(from, le32_to_cpu(entry->e_id));
- entry->e_id = cpu_to_le32(from_kgid(to, gid));
+ kgid = make_kgid(from, le32_to_cpu(entry->e_id));
+ if (!gid_valid(kgid))
+ return -EOVERFLOW;
+ gid = from_kgid(to, kgid);
+ if (gid == (gid_t)-1)
+ return -EOVERFLOW;
+ entry->e_id = cpu_to_le32(gid);
break;
default:
break;
}
}
+
+ return 0;
}
-void posix_acl_fix_xattr_from_user(void *value, size_t size)
+int
+posix_acl_fix_xattr_from_user(struct user_namespace *target_ns, void *value,
+ size_t size)
{
- struct user_namespace *user_ns = current_user_ns();
- if (user_ns == &init_user_ns)
- return;
- posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
+ struct user_namespace *source_ns = current_user_ns();
+ if (source_ns == target_ns)
+ return 0;
+ return posix_acl_fix_xattr_userns(target_ns, source_ns, value, size);
}
-void posix_acl_fix_xattr_to_user(void *value, size_t size)
+int
+posix_acl_fix_xattr_to_user(struct user_namespace *source_ns, void *value,
+ size_t size)
{
- struct user_namespace *user_ns = current_user_ns();
- if (user_ns == &init_user_ns)
- return;
- posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
+ struct user_namespace *target_ns = current_user_ns();
+ if (target_ns == source_ns)
+ return 0;
+ return posix_acl_fix_xattr_userns(target_ns, source_ns, value, size);
}
/*
@@ -780,7 +798,7 @@ posix_acl_xattr_get(const struct xattr_handler *handler,
if (acl == NULL)
return -ENODATA;
- error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+ error = posix_acl_to_xattr(dentry->d_sb->s_user_ns, acl, value, size);
posix_acl_release(acl);
return error;
@@ -806,7 +824,8 @@ posix_acl_xattr_set(const struct xattr_handler *handler,
return -EPERM;
if (value) {
- acl = posix_acl_from_xattr(&init_user_ns, value, size);
+ acl = posix_acl_from_xattr(dentry->d_sb->s_user_ns, value,
+ size);
if (IS_ERR(acl))
return PTR_ERR(acl);
diff --git a/fs/xattr.c b/fs/xattr.c
index 4861322e28e8..c541121945cd 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -330,8 +330,12 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
goto out;
}
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
- (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
- posix_acl_fix_xattr_from_user(kvalue, size);
+ (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) {
+ error = posix_acl_fix_xattr_from_user(d->d_sb->s_user_ns,
+ kvalue, size);
+ if (error)
+ goto out;
+ }
}
error = vfs_setxattr(d, kname, kvalue, size, flags);
@@ -427,9 +431,14 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
error = vfs_getxattr(d, kname, kvalue, size);
if (error > 0) {
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
- (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
- posix_acl_fix_xattr_to_user(kvalue, size);
- if (size && copy_to_user(value, kvalue, error))
+ (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) {
+ int ret;
+ ret = posix_acl_fix_xattr_to_user(d->d_sb->s_user_ns,
+ kvalue, size);
+ if (ret)
+ error = ret;
+ }
+ if (error > 0 && size && copy_to_user(value, kvalue, error))
error = -EFAULT;
} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
/* The file system tried to returned a value bigger
diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h
index e5e8ec40278d..5dec6b10951a 100644
--- a/include/linux/posix_acl_xattr.h
+++ b/include/linux/posix_acl_xattr.h
@@ -49,14 +49,23 @@ posix_acl_xattr_count(size_t size)
}
#ifdef CONFIG_FS_POSIX_ACL
-void posix_acl_fix_xattr_from_user(void *value, size_t size);
-void posix_acl_fix_xattr_to_user(void *value, size_t size);
+int posix_acl_fix_xattr_from_user(struct user_namespace *target_ns,
+ void *value, size_t size);
+int posix_acl_fix_xattr_to_user(struct user_namespace *source_ns, void *value,
+ size_t size);
#else
-static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
+static inline int
+posix_acl_fix_xattr_from_user(struct user_namespace *target_ns, void *value,
+ size_t size)
{
+ return 0;
}
-static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
+
+static inline int
+posix_acl_fix_xattr_to_user(struct user_namespace *source_ns, void *value,
+ size_t size)
{
+ return 0;
}
#endif
--
1.9.1
^ permalink raw reply related
* [PATCH v3 12/21] fs: Refuse uid/gid changes which don't map into s_user_ns
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman, Alexander Viro
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Add checks to inode_change_ok to verify that uid and gid changes
will map into the superblock's user namespace. If they do not
fail with -EOVERFLOW. This cannot be overriden with ATTR_FORCE.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
fs/attr.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/fs/attr.c b/fs/attr.c
index 25b24d0f6c88..3cfaaac4a18e 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -42,6 +42,17 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
return error;
}
+ /*
+ * Verify that uid/gid changes are valid in the target namespace
+ * of the superblock. This cannot be overriden using ATTR_FORCE.
+ */
+ if (ia_valid & ATTR_UID &&
+ from_kuid(inode->i_sb->s_user_ns, attr->ia_uid) == (uid_t)-1)
+ return -EOVERFLOW;
+ if (ia_valid & ATTR_GID &&
+ from_kgid(inode->i_sb->s_user_ns, attr->ia_gid) == (gid_t)-1)
+ return -EOVERFLOW;
+
/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
return 0;
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
* [PATCH v3 11/21] cred: Reject inodes with invalid ids in set_create_file_as()
From: Seth Forshee @ 2016-04-22 15:38 UTC (permalink / raw)
To: Eric W. Biederman
Cc: linux-bcache-u79uwXL29TY76Z2rM5mHXA, Serge Hallyn, Seth Forshee,
dm-devel-H+wXaHxf7aLQT0dZR+AlfA, Miklos Szeredi,
linux-security-module-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-raid-u79uwXL29TY76Z2rM5mHXA,
fuse-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Austin S Hemmelgarn,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alexander Viro,
selinux-+05T5uksL2qpZYMLLGbcSA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Pavel Tikhomirov
In-Reply-To: <1461339521-123191-1-git-send-email-seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Using INVALID_[UG]ID for the LSM file creation context doesn't
make sense, so return an error if the inode passed to
set_create_file_as() has an invalid id.
Signed-off-by: Seth Forshee <seth.forshee-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
---
kernel/cred.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/kernel/cred.c b/kernel/cred.c
index 0c0cd8a62285..5f264fb5737d 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -689,6 +689,8 @@ EXPORT_SYMBOL(set_security_override_from_ctx);
*/
int set_create_files_as(struct cred *new, struct inode *inode)
{
+ if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid))
+ return -EINVAL;
new->fsuid = inode->i_uid;
new->fsgid = inode->i_gid;
return security_kernel_create_files_as(new, inode);
--
1.9.1
------------------------------------------------------------------------------
Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
https://ad.doubleclick.net/ddm/clk/302982198;130105516;z
--
fuse-devel mailing list
To unsubscribe or subscribe, visit https://lists.sourceforge.net/lists/listinfo/fuse-devel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox