Skip to content

Commit 4db5c2e

Browse files
author
Miklos Szeredi
committed
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>
1 parent aba405e commit 4db5c2e

4 files changed

Lines changed: 50 additions & 174 deletions

File tree

fs/ext4/ext4.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -472,15 +472,6 @@ struct flex_groups {
472472
EXT4_VERITY_FL | \
473473
EXT4_INLINE_DATA_FL)
474474

475-
/* Flags we can manipulate with through FS_IOC_FSSETXATTR */
476-
#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
477-
EXT4_IMMUTABLE_FL | \
478-
EXT4_APPEND_FL | \
479-
EXT4_NODUMP_FL | \
480-
EXT4_NOATIME_FL | \
481-
EXT4_PROJINHERIT_FL | \
482-
EXT4_DAX_FL)
483-
484475
/* Flags that should be inherited by new inodes from their parent. */
485476
#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
486477
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,
29282919
/* ioctl.c */
29292920
extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
29302921
extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
2922+
int ext4_fileattr_set(struct user_namespace *mnt_userns,
2923+
struct dentry *dentry, struct fileattr *fa);
2924+
int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa);
29312925
extern void ext4_reset_inode_seed(struct inode *inode);
29322926

29332927
/* migrate.c */

fs/ext4/file.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,5 +919,7 @@ const struct inode_operations ext4_file_inode_operations = {
919919
.get_acl = ext4_get_acl,
920920
.set_acl = ext4_set_acl,
921921
.fiemap = ext4_fiemap,
922+
.fileattr_get = ext4_fileattr_get,
923+
.fileattr_set = ext4_fileattr_set,
922924
};
923925

fs/ext4/ioctl.c

Lines changed: 43 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/uaccess.h>
2121
#include <linux/delay.h>
2222
#include <linux/iversion.h>
23+
#include <linux/fileattr.h>
2324
#include "ext4_jbd2.h"
2425
#include "ext4.h"
2526
#include <linux/fsmap.h>
@@ -344,11 +345,6 @@ static int ext4_ioctl_setflags(struct inode *inode,
344345
goto flags_out;
345346

346347
oldflags = ei->i_flags;
347-
348-
err = vfs_ioc_setflags_prepare(inode, oldflags, flags);
349-
if (err)
350-
goto flags_out;
351-
352348
/*
353349
* The JOURNAL_DATA flag can only be changed by
354350
* the relevant capability.
@@ -459,9 +455,8 @@ static int ext4_ioctl_setflags(struct inode *inode,
459455
}
460456

461457
#ifdef CONFIG_QUOTA
462-
static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
458+
static int ext4_ioctl_setproject(struct inode *inode, __u32 projid)
463459
{
464-
struct inode *inode = file_inode(filp);
465460
struct super_block *sb = inode->i_sb;
466461
struct ext4_inode_info *ei = EXT4_I(inode);
467462
int err, rc;
@@ -545,64 +540,14 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
545540
return err;
546541
}
547542
#else
548-
static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
543+
static int ext4_ioctl_setproject(struct inode *inode, __u32 projid)
549544
{
550545
if (projid != EXT4_DEF_PROJID)
551546
return -EOPNOTSUPP;
552547
return 0;
553548
}
554549
#endif
555550

556-
/* Transfer internal flags to xflags */
557-
static inline __u32 ext4_iflags_to_xflags(unsigned long iflags)
558-
{
559-
__u32 xflags = 0;
560-
561-
if (iflags & EXT4_SYNC_FL)
562-
xflags |= FS_XFLAG_SYNC;
563-
if (iflags & EXT4_IMMUTABLE_FL)
564-
xflags |= FS_XFLAG_IMMUTABLE;
565-
if (iflags & EXT4_APPEND_FL)
566-
xflags |= FS_XFLAG_APPEND;
567-
if (iflags & EXT4_NODUMP_FL)
568-
xflags |= FS_XFLAG_NODUMP;
569-
if (iflags & EXT4_NOATIME_FL)
570-
xflags |= FS_XFLAG_NOATIME;
571-
if (iflags & EXT4_PROJINHERIT_FL)
572-
xflags |= FS_XFLAG_PROJINHERIT;
573-
if (iflags & EXT4_DAX_FL)
574-
xflags |= FS_XFLAG_DAX;
575-
return xflags;
576-
}
577-
578-
#define EXT4_SUPPORTED_FS_XFLAGS (FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | \
579-
FS_XFLAG_APPEND | FS_XFLAG_NODUMP | \
580-
FS_XFLAG_NOATIME | FS_XFLAG_PROJINHERIT | \
581-
FS_XFLAG_DAX)
582-
583-
/* Transfer xflags flags to internal */
584-
static inline unsigned long ext4_xflags_to_iflags(__u32 xflags)
585-
{
586-
unsigned long iflags = 0;
587-
588-
if (xflags & FS_XFLAG_SYNC)
589-
iflags |= EXT4_SYNC_FL;
590-
if (xflags & FS_XFLAG_IMMUTABLE)
591-
iflags |= EXT4_IMMUTABLE_FL;
592-
if (xflags & FS_XFLAG_APPEND)
593-
iflags |= EXT4_APPEND_FL;
594-
if (xflags & FS_XFLAG_NODUMP)
595-
iflags |= EXT4_NODUMP_FL;
596-
if (xflags & FS_XFLAG_NOATIME)
597-
iflags |= EXT4_NOATIME_FL;
598-
if (xflags & FS_XFLAG_PROJINHERIT)
599-
iflags |= EXT4_PROJINHERIT_FL;
600-
if (xflags & FS_XFLAG_DAX)
601-
iflags |= EXT4_DAX_FL;
602-
603-
return iflags;
604-
}
605-
606551
static int ext4_shutdown(struct super_block *sb, unsigned long arg)
607552
{
608553
struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -770,15 +715,52 @@ static long ext4_ioctl_group_add(struct file *file,
770715
return err;
771716
}
772717

773-
static void ext4_fill_fsxattr(struct inode *inode, struct fsxattr *fa)
718+
int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa)
774719
{
720+
struct inode *inode = d_inode(dentry);
775721
struct ext4_inode_info *ei = EXT4_I(inode);
722+
u32 flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
776723

777-
simple_fill_fsxattr(fa, ext4_iflags_to_xflags(ei->i_flags &
778-
EXT4_FL_USER_VISIBLE));
724+
if (S_ISREG(inode->i_mode))
725+
flags &= ~FS_PROJINHERIT_FL;
779726

727+
fileattr_fill_flags(fa, flags);
780728
if (ext4_has_feature_project(inode->i_sb))
781729
fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
730+
731+
return 0;
732+
}
733+
734+
int ext4_fileattr_set(struct user_namespace *mnt_userns,
735+
struct dentry *dentry, struct fileattr *fa)
736+
{
737+
struct inode *inode = d_inode(dentry);
738+
u32 flags = fa->flags;
739+
int err = -EOPNOTSUPP;
740+
741+
ext4_fc_start_update(inode);
742+
if (flags & ~EXT4_FL_USER_VISIBLE)
743+
goto out;
744+
745+
/*
746+
* chattr(1) grabs flags via GETFLAGS, modifies the result and
747+
* passes that to SETFLAGS. So we cannot easily make SETFLAGS
748+
* more restrictive than just silently masking off visible but
749+
* not settable flags as we always did.
750+
*/
751+
flags &= EXT4_FL_USER_MODIFIABLE;
752+
if (ext4_mask_flags(inode->i_mode, flags) != flags)
753+
goto out;
754+
err = ext4_ioctl_check_immutable(inode, fa->fsx_projid, flags);
755+
if (err)
756+
goto out;
757+
err = ext4_ioctl_setflags(inode, flags);
758+
if (err)
759+
goto out;
760+
err = ext4_ioctl_setproject(inode, fa->fsx_projid);
761+
out:
762+
ext4_fc_stop_update(inode);
763+
return err;
782764
}
783765

784766
/* 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)
816798
{
817799
struct inode *inode = file_inode(filp);
818800
struct super_block *sb = inode->i_sb;
819-
struct ext4_inode_info *ei = EXT4_I(inode);
820801
struct user_namespace *mnt_userns = file_mnt_user_ns(filp);
821-
unsigned int flags;
822802

823803
ext4_debug("cmd = %u, arg = %lu\n", cmd, arg);
824804

825805
switch (cmd) {
826806
case FS_IOC_GETFSMAP:
827807
return ext4_ioc_getfsmap(sb, (void __user *)arg);
828-
case FS_IOC_GETFLAGS:
829-
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
830-
if (S_ISREG(inode->i_mode))
831-
flags &= ~EXT4_PROJINHERIT_FL;
832-
return put_user(flags, (int __user *) arg);
833-
case FS_IOC_SETFLAGS: {
834-
int err;
835-
836-
if (!inode_owner_or_capable(mnt_userns, inode))
837-
return -EACCES;
838-
839-
if (get_user(flags, (int __user *) arg))
840-
return -EFAULT;
841-
842-
if (flags & ~EXT4_FL_USER_VISIBLE)
843-
return -EOPNOTSUPP;
844-
/*
845-
* chattr(1) grabs flags via GETFLAGS, modifies the result and
846-
* passes that to SETFLAGS. So we cannot easily make SETFLAGS
847-
* more restrictive than just silently masking off visible but
848-
* not settable flags as we always did.
849-
*/
850-
flags &= EXT4_FL_USER_MODIFIABLE;
851-
if (ext4_mask_flags(inode->i_mode, flags) != flags)
852-
return -EOPNOTSUPP;
853-
854-
err = mnt_want_write_file(filp);
855-
if (err)
856-
return err;
857-
858-
inode_lock(inode);
859-
err = ext4_ioctl_check_immutable(inode,
860-
from_kprojid(&init_user_ns, ei->i_projid),
861-
flags);
862-
if (!err)
863-
err = ext4_ioctl_setflags(inode, flags);
864-
inode_unlock(inode);
865-
mnt_drop_write_file(filp);
866-
return err;
867-
}
868808
case EXT4_IOC_GETVERSION:
869809
case EXT4_IOC_GETVERSION_OLD:
870810
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)
12461186
case EXT4_IOC_GET_ES_CACHE:
12471187
return ext4_ioctl_get_es_cache(filp, arg);
12481188

1249-
case FS_IOC_FSGETXATTR:
1250-
{
1251-
struct fsxattr fa;
1252-
1253-
ext4_fill_fsxattr(inode, &fa);
1254-
1255-
if (copy_to_user((struct fsxattr __user *)arg,
1256-
&fa, sizeof(fa)))
1257-
return -EFAULT;
1258-
return 0;
1259-
}
1260-
case FS_IOC_FSSETXATTR:
1261-
{
1262-
struct fsxattr fa, old_fa;
1263-
int err;
1264-
1265-
if (copy_from_user(&fa, (struct fsxattr __user *)arg,
1266-
sizeof(fa)))
1267-
return -EFAULT;
1268-
1269-
/* Make sure caller has proper permission */
1270-
if (!inode_owner_or_capable(mnt_userns, inode))
1271-
return -EACCES;
1272-
1273-
if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS)
1274-
return -EOPNOTSUPP;
1275-
1276-
flags = ext4_xflags_to_iflags(fa.fsx_xflags);
1277-
if (ext4_mask_flags(inode->i_mode, flags) != flags)
1278-
return -EOPNOTSUPP;
1279-
1280-
err = mnt_want_write_file(filp);
1281-
if (err)
1282-
return err;
1283-
1284-
inode_lock(inode);
1285-
ext4_fill_fsxattr(inode, &old_fa);
1286-
err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa);
1287-
if (err)
1288-
goto out;
1289-
flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) |
1290-
(flags & EXT4_FL_XFLAG_VISIBLE);
1291-
err = ext4_ioctl_check_immutable(inode, fa.fsx_projid, flags);
1292-
if (err)
1293-
goto out;
1294-
err = ext4_ioctl_setflags(inode, flags);
1295-
if (err)
1296-
goto out;
1297-
err = ext4_ioctl_setproject(filp, fa.fsx_projid);
1298-
out:
1299-
inode_unlock(inode);
1300-
mnt_drop_write_file(filp);
1301-
return err;
1302-
}
13031189
case EXT4_IOC_SHUTDOWN:
13041190
return ext4_shutdown(sb, arg);
13051191

@@ -1340,12 +1226,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
13401226
{
13411227
/* These are just misnamed, they actually get/put from/to user an int */
13421228
switch (cmd) {
1343-
case FS_IOC32_GETFLAGS:
1344-
cmd = FS_IOC_GETFLAGS;
1345-
break;
1346-
case FS_IOC32_SETFLAGS:
1347-
cmd = FS_IOC_SETFLAGS;
1348-
break;
13491229
case EXT4_IOC32_GETVERSION:
13501230
cmd = EXT4_IOC_GETVERSION;
13511231
break;
@@ -1405,8 +1285,6 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
14051285
case EXT4_IOC_CLEAR_ES_CACHE:
14061286
case EXT4_IOC_GETSTATE:
14071287
case EXT4_IOC_GET_ES_CACHE:
1408-
case FS_IOC_FSGETXATTR:
1409-
case FS_IOC_FSSETXATTR:
14101288
break;
14111289
default:
14121290
return -ENOIOCTLCMD;

fs/ext4/namei.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4172,6 +4172,8 @@ const struct inode_operations ext4_dir_inode_operations = {
41724172
.get_acl = ext4_get_acl,
41734173
.set_acl = ext4_set_acl,
41744174
.fiemap = ext4_fiemap,
4175+
.fileattr_get = ext4_fileattr_get,
4176+
.fileattr_set = ext4_fileattr_set,
41754177
};
41764178

41774179
const struct inode_operations ext4_special_inode_operations = {

0 commit comments

Comments
 (0)