ext4: convert to fileattr
Use the fileattr API to let the VFS handle locking, permission checking and conversion. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Cc: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
aba405e33e
commit
4db5c2e623
|
@ -472,15 +472,6 @@ struct flex_groups {
|
|||
EXT4_VERITY_FL | \
|
||||
EXT4_INLINE_DATA_FL)
|
||||
|
||||
/* Flags we can manipulate with through FS_IOC_FSSETXATTR */
|
||||
#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
|
||||
EXT4_IMMUTABLE_FL | \
|
||||
EXT4_APPEND_FL | \
|
||||
EXT4_NODUMP_FL | \
|
||||
EXT4_NOATIME_FL | \
|
||||
EXT4_PROJINHERIT_FL | \
|
||||
EXT4_DAX_FL)
|
||||
|
||||
/* Flags that should be inherited by new inodes from their parent. */
|
||||
#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
|
||||
EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
|
||||
|
@ -2928,6 +2919,9 @@ extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
|
|||
/* ioctl.c */
|
||||
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
|
||||
extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
|
||||
int ext4_fileattr_set(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct fileattr *fa);
|
||||
int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa);
|
||||
extern void ext4_reset_inode_seed(struct inode *inode);
|
||||
|
||||
/* migrate.c */
|
||||
|
|
|
@ -919,5 +919,7 @@ const struct inode_operations ext4_file_inode_operations = {
|
|||
.get_acl = ext4_get_acl,
|
||||
.set_acl = ext4_set_acl,
|
||||
.fiemap = ext4_fiemap,
|
||||
.fileattr_get = ext4_fileattr_get,
|
||||
.fileattr_set = ext4_fileattr_set,
|
||||
};
|
||||
|
||||
|
|
208
fs/ext4/ioctl.c
208
fs/ext4/ioctl.c
|
@ -20,6 +20,7 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fileattr.h>
|
||||
#include "ext4_jbd2.h"
|
||||
#include "ext4.h"
|
||||
#include <linux/fsmap.h>
|
||||
|
@ -344,11 +345,6 @@ static int ext4_ioctl_setflags(struct inode *inode,
|
|||
goto flags_out;
|
||||
|
||||
oldflags = ei->i_flags;
|
||||
|
||||
err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
|
||||
if (err)
|
||||
goto flags_out;
|
||||
|
||||
/*
|
||||
* The JOURNAL_DATA flag can only be changed by
|
||||
* the relevant capability.
|
||||
|
@ -459,9 +455,8 @@ static int ext4_ioctl_setflags(struct inode *inode,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
|
||||
static int ext4_ioctl_setproject(struct inode *inode, __u32 projid)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
int err, rc;
|
||||
|
@ -545,7 +540,7 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
|
|||
return err;
|
||||
}
|
||||
#else
|
||||
static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
|
||||
static int ext4_ioctl_setproject(struct inode *inode, __u32 projid)
|
||||
{
|
||||
if (projid != EXT4_DEF_PROJID)
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -553,56 +548,6 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Transfer internal flags to xflags */
|
||||
static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
|
||||
{
|
||||
__u32 xflags = 0;
|
||||
|
||||
if (iflags & EXT4_SYNC_FL)
|
||||
xflags |= FS_XFLAG_SYNC;
|
||||
if (iflags & EXT4_IMMUTABLE_FL)
|
||||
xflags |= FS_XFLAG_IMMUTABLE;
|
||||
if (iflags & EXT4_APPEND_FL)
|
||||
xflags |= FS_XFLAG_APPEND;
|
||||
if (iflags & EXT4_NODUMP_FL)
|
||||
xflags |= FS_XFLAG_NODUMP;
|
||||
if (iflags & EXT4_NOATIME_FL)
|
||||
xflags |= FS_XFLAG_NOATIME;
|
||||
if (iflags & EXT4_PROJINHERIT_FL)
|
||||
xflags |= FS_XFLAG_PROJINHERIT;
|
||||
if (iflags & EXT4_DAX_FL)
|
||||
xflags |= FS_XFLAG_DAX;
|
||||
return xflags;
|
||||
}
|
||||
|
||||
#define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
|
||||
FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
|
||||
FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT | \
|
||||
FS_XFLAG_DAX)
|
||||
|
||||
/* Transfer xflags flags to internal */
|
||||
static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
|
||||
{
|
||||
unsigned long iflags = 0;
|
||||
|
||||
if (xflags & FS_XFLAG_SYNC)
|
||||
iflags |= EXT4_SYNC_FL;
|
||||
if (xflags & FS_XFLAG_IMMUTABLE)
|
||||
iflags |= EXT4_IMMUTABLE_FL;
|
||||
if (xflags & FS_XFLAG_APPEND)
|
||||
iflags |= EXT4_APPEND_FL;
|
||||
if (xflags & FS_XFLAG_NODUMP)
|
||||
iflags |= EXT4_NODUMP_FL;
|
||||
if (xflags & FS_XFLAG_NOATIME)
|
||||
iflags |= EXT4_NOATIME_FL;
|
||||
if (xflags & FS_XFLAG_PROJINHERIT)
|
||||
iflags |= EXT4_PROJINHERIT_FL;
|
||||
if (xflags & FS_XFLAG_DAX)
|
||||
iflags |= EXT4_DAX_FL;
|
||||
|
||||
return iflags;
|
||||
}
|
||||
|
||||
static int ext4_shutdown(struct super_block *sb, unsigned long arg)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
@ -770,15 +715,52 @@ static long ext4_ioctl_group_add(struct file *file,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa)
|
||||
int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
u32 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
|
||||
|
||||
simple_fill_fsxattr(fa, ext4_iflags_to_xflags(ei->i_flags &
|
||||
EXT4_FL_USER_VISIBLE));
|
||||
if (S_ISREG(inode->i_mode))
|
||||
flags &= ~FS_PROJINHERIT_FL;
|
||||
|
||||
fileattr_fill_flags(fa, flags);
|
||||
if (ext4_has_feature_project(inode->i_sb))
|
||||
fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext4_fileattr_set(struct user_namespace *mnt_userns,
|
||||
struct dentry *dentry, struct fileattr *fa)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
u32 flags = fa->flags;
|
||||
int err = -EOPNOTSUPP;
|
||||
|
||||
ext4_fc_start_update(inode);
|
||||
if (flags & ~EXT4_FL_USER_VISIBLE)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* chattr(1) grabs flags via GETFLAGS, modifies the result and
|
||||
* passes that to SETFLAGS. So we cannot easily make SETFLAGS
|
||||
* more restrictive than just silently masking off visible but
|
||||
* not settable flags as we always did.
|
||||
*/
|
||||
flags &= EXT4_FL_USER_MODIFIABLE;
|
||||
if (ext4_mask_flags(inode->i_mode, flags) != flags)
|
||||
goto out;
|
||||
err = ext4_ioctl_check_immutable(inode, fa->fsx_projid, flags);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext4_ioctl_setflags(inode, flags);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext4_ioctl_setproject(inode, fa->fsx_projid);
|
||||
out:
|
||||
ext4_fc_stop_update(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* So that the fiemap access checks can't overflow on 32 bit machines. */
|
||||
|
@ -816,55 +798,13 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct ext4_inode_info *ei = EXT4_I(inode);
|
||||
struct user_namespace *mnt_userns = file_mnt_user_ns(filp);
|
||||
unsigned int flags;
|
||||
|
||||
ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
|
||||
|
||||
switch (cmd) {
|
||||
case FS_IOC_GETFSMAP:
|
||||
return ext4_ioc_getfsmap(sb, (void __user *)arg);
|
||||
case FS_IOC_GETFLAGS:
|
||||
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
|
||||
if (S_ISREG(inode->i_mode))
|
||||
flags &= ~EXT4_PROJINHERIT_FL;
|
||||
return put_user(flags, (int __user *) arg);
|
||||
case FS_IOC_SETFLAGS: {
|
||||
int err;
|
||||
|
||||
if (!inode_owner_or_capable(mnt_userns, inode))
|
||||
return -EACCES;
|
||||
|
||||
if (get_user(flags, (int __user *) arg))
|
||||
return -EFAULT;
|
||||
|
||||
if (flags & ~EXT4_FL_USER_VISIBLE)
|
||||
return -EOPNOTSUPP;
|
||||
/*
|
||||
* chattr(1) grabs flags via GETFLAGS, modifies the result and
|
||||
* passes that to SETFLAGS. So we cannot easily make SETFLAGS
|
||||
* more restrictive than just silently masking off visible but
|
||||
* not settable flags as we always did.
|
||||
*/
|
||||
flags &= EXT4_FL_USER_MODIFIABLE;
|
||||
if (ext4_mask_flags(inode->i_mode, flags) != flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = mnt_want_write_file(filp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode_lock(inode);
|
||||
err = ext4_ioctl_check_immutable(inode,
|
||||
from_kprojid(&init_user_ns, ei->i_projid),
|
||||
flags);
|
||||
if (!err)
|
||||
err = ext4_ioctl_setflags(inode, flags);
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
return err;
|
||||
}
|
||||
case EXT4_IOC_GETVERSION:
|
||||
case EXT4_IOC_GETVERSION_OLD:
|
||||
return put_user(inode->i_generation, (int __user *) arg);
|
||||
|
@ -1246,60 +1186,6 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
case EXT4_IOC_GET_ES_CACHE:
|
||||
return ext4_ioctl_get_es_cache(filp, arg);
|
||||
|
||||
case FS_IOC_FSGETXATTR:
|
||||
{
|
||||
struct fsxattr fa;
|
||||
|
||||
ext4_fill_fsxattr(inode, &fa);
|
||||
|
||||
if (copy_to_user((struct fsxattr __user *)arg,
|
||||
&fa, sizeof(fa)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
case FS_IOC_FSSETXATTR:
|
||||
{
|
||||
struct fsxattr fa, old_fa;
|
||||
int err;
|
||||
|
||||
if (copy_from_user(&fa, (struct fsxattr __user *)arg,
|
||||
sizeof(fa)))
|
||||
return -EFAULT;
|
||||
|
||||
/* Make sure caller has proper permission */
|
||||
if (!inode_owner_or_capable(mnt_userns, inode))
|
||||
return -EACCES;
|
||||
|
||||
if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
flags = ext4_xflags_to_iflags(fa.fsx_xflags);
|
||||
if (ext4_mask_flags(inode->i_mode, flags) != flags)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
err = mnt_want_write_file(filp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode_lock(inode);
|
||||
ext4_fill_fsxattr(inode, &old_fa);
|
||||
err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa);
|
||||
if (err)
|
||||
goto out;
|
||||
flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
|
||||
(flags & EXT4_FL_XFLAG_VISIBLE);
|
||||
err = ext4_ioctl_check_immutable(inode, fa.fsx_projid, flags);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext4_ioctl_setflags(inode, flags);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext4_ioctl_setproject(filp, fa.fsx_projid);
|
||||
out:
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
return err;
|
||||
}
|
||||
case EXT4_IOC_SHUTDOWN:
|
||||
return ext4_shutdown(sb, arg);
|
||||
|
||||
|
@ -1340,12 +1226,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
{
|
||||
/* These are just misnamed, they actually get/put from/to user an int */
|
||||
switch (cmd) {
|
||||
case FS_IOC32_GETFLAGS:
|
||||
cmd = FS_IOC_GETFLAGS;
|
||||
break;
|
||||
case FS_IOC32_SETFLAGS:
|
||||
cmd = FS_IOC_SETFLAGS;
|
||||
break;
|
||||
case EXT4_IOC32_GETVERSION:
|
||||
cmd = EXT4_IOC_GETVERSION;
|
||||
break;
|
||||
|
@ -1405,8 +1285,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
case EXT4_IOC_CLEAR_ES_CACHE:
|
||||
case EXT4_IOC_GETSTATE:
|
||||
case EXT4_IOC_GET_ES_CACHE:
|
||||
case FS_IOC_FSGETXATTR:
|
||||
case FS_IOC_FSSETXATTR:
|
||||
break;
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
|
|
|
@ -4172,6 +4172,8 @@ const struct inode_operations ext4_dir_inode_operations = {
|
|||
.get_acl = ext4_get_acl,
|
||||
.set_acl = ext4_set_acl,
|
||||
.fiemap = ext4_fiemap,
|
||||
.fileattr_get = ext4_fileattr_get,
|
||||
.fileattr_set = ext4_fileattr_set,
|
||||
};
|
||||
|
||||
const struct inode_operations ext4_special_inode_operations = {
|
||||
|
|
Loading…
Reference in New Issue