@@ -164,6 +164,13 @@ static unsigned int btrfs_inode_flags_to_fsflags(struct btrfs_inode *binode)
return iflags;
}
+static inline unsigned int btrfs_supported_fsflags(void)
+{
+ return FS_SYNC_FL | FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL |
+ FS_NOATIME_FL | FS_DIRSYNC_FL | FS_NOCOW_FL | FS_VERITY_FL |
+ FS_NOCOMP_FL | FS_COMPR_FL;
+}
+
/*
* Update inode->i_flags based on the btrfs internal flags.
*/
@@ -250,7 +257,7 @@ int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
struct btrfs_inode *binode = BTRFS_I(d_inode(dentry));
- fileattr_fill_flags(fa, btrfs_inode_flags_to_fsflags(binode));
+ fileattr_fill_flags(fa, btrfs_inode_flags_to_fsflags(binode), btrfs_supported_fsflags());
return 0;
}
@@ -142,12 +142,13 @@ efivarfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
unsigned int i_flags;
unsigned int flags = 0;
+ unsigned int mask = FS_IMMUTABLE_FL;
i_flags = d_inode(dentry)->i_flags;
if (i_flags & S_IMMUTABLE)
flags |= FS_IMMUTABLE_FL;
- fileattr_fill_flags(fa, flags);
+ fileattr_fill_flags(fa, flags, mask);
return 0;
}
@@ -22,7 +22,7 @@ int ext2_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
struct ext2_inode_info *ei = EXT2_I(d_inode(dentry));
- fileattr_fill_flags(fa, ei->i_flags & EXT2_FL_USER_VISIBLE);
+ fileattr_fill_flags(fa, ei->i_flags & EXT2_FL_USER_VISIBLE, EXT2_FL_USER_VISIBLE);
return 0;
}
@@ -989,7 +989,7 @@ int ext4_fileattr_get(struct dentry *dentry, struct fileattr *fa)
if (S_ISREG(inode->i_mode))
flags &= ~FS_PROJINHERIT_FL;
- fileattr_fill_flags(fa, flags);
+ fileattr_fill_flags(fa, flags, EXT4_FL_USER_VISIBLE);
if (ext4_has_feature_project(inode->i_sb))
fa->fsx_projid = from_kprojid(&init_user_ns, ei->i_projid);
@@ -3297,7 +3297,7 @@ int f2fs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
if (is_inode_flag_set(inode, FI_PIN_FILE))
fsflags |= FS_NOCOW_FL;
- fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL);
+ fileattr_fill_flags(fa, fsflags & F2FS_GETTABLE_FS_FL, F2FS_GETTABLE_FS_FL);
if (f2fs_sb_has_project_quota(F2FS_I_SB(inode)))
fa->fsx_projid = from_kprojid(&init_user_ns, fi->i_projid);
@@ -520,14 +520,20 @@ int fuse_fileattr_get(struct dentry *dentry, struct fileattr *fa)
if (err)
goto cleanup;
- fileattr_fill_flags(fa, flags);
+ fileattr_fill_flags(fa, flags, ~0);
} else {
err = fuse_priv_ioctl(inode, ff, FS_IOC_FSGETXATTR,
&xfa, sizeof(xfa));
if (err)
goto cleanup;
- fileattr_fill_xflags(fa, xfa.fsx_xflags);
+ if (!(xfa.fsx_xflags & FS_XFLAG_HASEXTFIELDS)) {
+ xfa.fsx_xflags_mask = 0;
+ xfa.fsx_xflags2 = 0;
+ xfa.fsx_xflags2_mask = 0;
+ }
+
+ fileattr_fill_xflags(fa, xfa.fsx_xflags, xfa.fsx_xflags_mask, xfa.fsx_xflags2, xfa.fsx_xflags2_mask);
fa->fsx_extsize = xfa.fsx_extsize;
fa->fsx_nextents = xfa.fsx_nextents;
fa->fsx_projid = xfa.fsx_projid;
@@ -564,6 +570,9 @@ int fuse_fileattr_set(struct mnt_idmap *idmap,
xfa.fsx_nextents = fa->fsx_nextents;
xfa.fsx_projid = fa->fsx_projid;
xfa.fsx_cowextsize = fa->fsx_cowextsize;
+ xfa.fsx_xflags2 = fa->fsx_xflags2;
+ xfa.fsx_xflags2_mask = fa->fsx_xflags2_mask;
+ xfa.fsx_xflags_mask = fa->fsx_xflags_mask;
err = fuse_priv_ioctl(inode, ff, FS_IOC_FSSETXATTR,
&xfa, sizeof(xfa));
@@ -139,6 +139,16 @@ static struct {
{FS_JOURNAL_DATA_FL, GFS2_DIF_JDATA | GFS2_DIF_INHERIT_JDATA},
};
+static inline u32 gfs2_supported_fsflags(void)
+{
+ int i;
+ u32 fsflags = 0;
+
+ for (i = 0; i < ARRAY_SIZE(fsflag_gfs2flag); i++)
+ fsflags |= fsflag_gfs2flag[i].fsflag;
+ return fsflags;
+}
+
static inline u32 gfs2_gfsflags_to_fsflags(struct inode *inode, u32 gfsflags)
{
int i;
@@ -162,6 +172,7 @@ int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa)
struct gfs2_holder gh;
int error;
u32 fsflags;
+ u32 fsmask;
if (d_is_special(dentry))
return -ENOTTY;
@@ -172,8 +183,9 @@ int gfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa)
goto out_uninit;
fsflags = gfs2_gfsflags_to_fsflags(inode, ip->i_diskflags);
+ fsmask = gfs2_supported_fsflags();
- fileattr_fill_flags(fa, fsflags);
+ fileattr_fill_flags(fa, fsflags, fsmask);
gfs2_glock_dq(&gh);
out_uninit:
@@ -659,6 +659,7 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa)
struct inode *inode = d_inode(dentry);
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
unsigned int flags = 0;
+ unsigned int mask = FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL;
if (inode->i_flags & S_IMMUTABLE)
flags |= FS_IMMUTABLE_FL;
@@ -667,7 +668,7 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa)
if (hip->userflags & HFSPLUS_FLG_NODUMP)
flags |= FS_NODUMP_FL;
- fileattr_fill_flags(fa, flags);
+ fileattr_fill_flags(fa, flags, mask);
return 0;
}
@@ -458,14 +458,19 @@ static int ioctl_file_dedupe_range(struct file *file,
* @fa: fileattr pointer
* @xflags: FS_XFLAG_* flags
*
- * Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All
- * other fields are zeroed.
+ * Set ->fsx_xflags, ->fsx_xflags2, ->fsx->xflags_mask, ->fsx_xflags2_mask,
+ * ->fsx_valid and ->flags (translated xflags). All other fields are zeroed.
*/
-void fileattr_fill_xflags(struct fileattr *fa, u32 xflags)
+void fileattr_fill_xflags(struct fileattr *fa, u32 xflags, u32 xflags_mask, u16 xflags2, u16 xflags2_mask)
{
memset(fa, 0, sizeof(*fa));
fa->fsx_valid = true;
fa->fsx_xflags = xflags;
+ fa->fsx_xflags2 = xflags2;
+ fa->fsx_xflags_mask = xflags_mask;
+ fa->fsx_xflags2_mask = xflags2_mask;
+ if (fa->fsx_xflags2 != 0 || fa->fsx_xflags_mask != 0 || fa->fsx_xflags2_mask != 0)
+ fa->fsx_xflags |= FS_XFLAG_HASEXTFIELDS;
if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)
fa->flags |= FS_IMMUTABLE_FL;
if (fa->fsx_xflags & FS_XFLAG_APPEND)
@@ -491,15 +496,20 @@ EXPORT_SYMBOL(fileattr_fill_xflags);
* fileattr_fill_flags - initialize fileattr with flags
* @fa: fileattr pointer
* @flags: FS_*_FL flags
+ * @mask: FS_*_FL flags mask
*
- * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags).
+ * Set ->flags, ->flags_valid and ->fsx_xflags (translated flags),
+ * fa->fsx_xflags_mask (translated flags mask).
* All other fields are zeroed.
*/
-void fileattr_fill_flags(struct fileattr *fa, u32 flags)
+void fileattr_fill_flags(struct fileattr *fa, u32 flags, u32 mask)
{
memset(fa, 0, sizeof(*fa));
fa->flags_valid = true;
fa->flags = flags;
+
+ fa->fsx_xflags |= FS_XFLAG_HASEXTFIELDS;
+
if (fa->flags & FS_COMPR_FL)
fa->fsx_xflags |= FS_XFLAG_COMPRESSED;
if (fa->flags & FS_SYNC_FL)
@@ -518,6 +528,25 @@ void fileattr_fill_flags(struct fileattr *fa, u32 flags)
fa->fsx_xflags |= FS_XFLAG_DAX;
if (fa->flags & FS_PROJINHERIT_FL)
fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
+
+ if (mask & FS_COMPR_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_COMPRESSED;
+ if (mask & FS_SYNC_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_SYNC;
+ if (mask & FS_IMMUTABLE_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_IMMUTABLE;
+ if (mask & FS_APPEND_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_APPEND;
+ if (mask & FS_NODUMP_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_NODUMP;
+ if (mask & FS_NOATIME_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_NOATIME;
+ if (mask & FS_ENCRYPT_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_ENCRYPTED;
+ if (mask & FS_DAX_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_DAX;
+ if (mask & FS_PROJINHERIT_FL)
+ fa->fsx_xflags_mask |= FS_XFLAG_PROJINHERIT;
}
EXPORT_SYMBOL(fileattr_fill_flags);
@@ -558,6 +587,11 @@ int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa)
xfa.fsx_nextents = fa->fsx_nextents;
xfa.fsx_projid = fa->fsx_projid;
xfa.fsx_cowextsize = fa->fsx_cowextsize;
+ if (xfa.fsx_xflags & FS_XFLAG_HASEXTFIELDS) {
+ xfa.fsx_xflags2 = fa->fsx_xflags2;
+ xfa.fsx_xflags2_mask = fa->fsx_xflags2_mask;
+ xfa.fsx_xflags_mask = fa->fsx_xflags_mask;
+ }
if (copy_to_user(ufa, &xfa, sizeof(xfa)))
return -EFAULT;
@@ -574,7 +608,13 @@ static int copy_fsxattr_from_user(struct fileattr *fa,
if (copy_from_user(&xfa, ufa, sizeof(xfa)))
return -EFAULT;
- fileattr_fill_xflags(fa, xfa.fsx_xflags);
+ if (!(xfa.fsx_xflags & FS_XFLAG_HASEXTFIELDS)) {
+ xfa.fsx_xflags_mask = 0;
+ xfa.fsx_xflags2 = 0;
+ xfa.fsx_xflags2_mask = 0;
+ }
+
+ fileattr_fill_xflags(fa, xfa.fsx_xflags, xfa.fsx_xflags_mask, xfa.fsx_xflags2, xfa.fsx_xflags2_mask);
fa->fsx_extsize = xfa.fsx_extsize;
fa->fsx_nextents = xfa.fsx_nextents;
fa->fsx_projid = xfa.fsx_projid;
@@ -692,11 +732,22 @@ int vfs_fileattr_set(struct mnt_idmap *idmap, struct dentry *dentry,
/* initialize missing bits from old_ma */
if (fa->flags_valid) {
fa->fsx_xflags |= old_ma.fsx_xflags & ~FS_XFLAG_COMMON;
+ fa->fsx_xflags_mask = fa->fsx_xflags ^ old_ma.fsx_xflags;
fa->fsx_extsize = old_ma.fsx_extsize;
fa->fsx_nextents = old_ma.fsx_nextents;
fa->fsx_projid = old_ma.fsx_projid;
fa->fsx_cowextsize = old_ma.fsx_cowextsize;
+ fa->fsx_xflags2 = 0;
+ fa->fsx_xflags2_mask = 0;
} else {
+ if (fa->fsx_xflags & FS_XFLAG_HASEXTFIELDS) {
+ fa->fsx_xflags = (fa->fsx_xflags & fa->fsx_xflags_mask) | (old_ma.fsx_xflags & ~fa->fsx_xflags_mask);
+ fa->fsx_xflags2 = (fa->fsx_xflags2 & fa->fsx_xflags2_mask) | (old_ma.fsx_xflags2 & ~fa->fsx_xflags2_mask);
+ } else {
+ fa->fsx_xflags_mask = fa->fsx_xflags ^ old_ma.fsx_xflags;
+ fa->fsx_xflags2 = old_ma.fsx_xflags2;
+ fa->fsx_xflags2_mask = 0;
+ }
fa->flags |= old_ma.flags & ~FS_COMMON_FL;
}
err = fileattr_set_prepare(inode, &old_ma, fa);
@@ -732,7 +783,7 @@ static int ioctl_setflags(struct file *file, unsigned int __user *argp)
if (!err) {
err = mnt_want_write_file(file);
if (!err) {
- fileattr_fill_flags(&fa, flags);
+ fileattr_fill_flags(&fa, flags, FS_COMMON_FL);
err = vfs_fileattr_set(idmap, dentry, &fa);
mnt_drop_write_file(file);
}
@@ -39,6 +39,18 @@ static struct {
{0, 0},
};
+static long jfs_supported_ext2_flags(void)
+{
+ int index=0;
+ long mapped=0;
+
+ while (jfs_map[index].jfs_flag) {
+ mapped |= jfs_map[index].ext2_flag;
+ index++;
+ }
+ return mapped;
+}
+
static long jfs_map_ext2(unsigned long flags, int from)
{
int index=0;
@@ -65,7 +77,7 @@ int jfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
if (d_is_special(dentry))
return -ENOTTY;
- fileattr_fill_flags(fa, jfs_map_ext2(flags, 0));
+ fileattr_fill_flags(fa, jfs_map_ext2(flags, 0), jfs_supported_ext2_flags());
return 0;
}
@@ -122,7 +122,7 @@ int nilfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
struct inode *inode = d_inode(dentry);
- fileattr_fill_flags(fa, NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE);
+ fileattr_fill_flags(fa, NILFS_I(inode)->i_flags & FS_FL_USER_VISIBLE, FS_FL_USER_VISIBLE);
return 0;
}
@@ -57,6 +57,7 @@ int ntfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
struct inode *inode = d_inode(dentry);
struct ntfs_inode *ni = ntfs_i(inode);
u32 flags = 0;
+ u32 mask = FS_IMMUTABLE_FL | FS_APPEND_FL | FS_COMPR_FL | FS_ENCRYPT_FL;
if (inode->i_flags & S_IMMUTABLE)
flags |= FS_IMMUTABLE_FL;
@@ -70,7 +71,7 @@ int ntfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
if (is_encrypted(ni))
flags |= FS_ENCRYPT_FL;
- fileattr_fill_flags(fa, flags);
+ fileattr_fill_flags(fa, flags, mask);
return 0;
}
@@ -77,7 +77,7 @@ int ocfs2_fileattr_get(struct dentry *dentry, struct fileattr *fa)
flags = OCFS2_I(inode)->ip_attr;
ocfs2_inode_unlock(inode, 0);
- fileattr_fill_flags(fa, flags & OCFS2_FL_VISIBLE);
+ fileattr_fill_flags(fa, flags & OCFS2_FL_VISIBLE, OCFS2_FL_VISIBLE);
return status;
}
@@ -923,7 +923,7 @@ static int orangefs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
gossip_debug(GOSSIP_FILE_DEBUG, "%s: flags=%u\n", __func__, (u32) val);
- fileattr_fill_flags(fa, val);
+ fileattr_fill_flags(fa, val, FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NOATIME_FL);
return 0;
}
@@ -134,12 +134,13 @@ int ubifs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
struct inode *inode = d_inode(dentry);
int flags = ubifs2ioctl(ubifs_inode(inode)->flags);
+ int mask = ubifs2ioctl(~0);
if (d_is_special(dentry))
return -ENOTTY;
dbg_gen("get flags: %#x, i_flags %#x", flags, inode->i_flags);
- fileattr_fill_flags(fa, flags);
+ fileattr_fill_flags(fa, flags, mask);
return 0;
}
@@ -448,8 +448,11 @@ xfs_fill_fsxattr(
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork);
+ struct xfs_inode ip_all_xflags = { .i_diflags = XFS_DIFLAG_ANY,
+ .i_diflags2 = XFS_DIFLAG2_ANY,
+ .i_forkoff = 1 };
- fileattr_fill_xflags(fa, xfs_ip2xflags(ip));
+ fileattr_fill_xflags(fa, xfs_ip2xflags(ip), xfs_ip2xflags(&ip_all_xflags), 0, 0);
if (ip->i_diflags & XFS_DIFLAG_EXTSIZE) {
fa->fsx_extsize = XFS_FSB_TO_B(mp, ip->i_extsize);
@@ -28,6 +28,9 @@ struct fileattr {
u32 fsx_nextents; /* nextents field value (get) */
u32 fsx_projid; /* project identifier (get/set) */
u32 fsx_cowextsize; /* CoW extsize field value (get/set)*/
+ u16 fsx_xflags2; /* xflags2 field value (get/set)*/
+ u16 fsx_xflags2_mask;/*mask for xflags2 (get/set)*/
+ u32 fsx_xflags_mask;/* mask for xflags (get/set)*/
/* selectors: */
bool flags_valid:1;
bool fsx_valid:1;
@@ -35,8 +38,8 @@ struct fileattr {
int copy_fsxattr_to_user(const struct fileattr *fa, struct fsxattr __user *ufa);
-void fileattr_fill_xflags(struct fileattr *fa, u32 xflags);
-void fileattr_fill_flags(struct fileattr *fa, u32 flags);
+void fileattr_fill_xflags(struct fileattr *fa, u32 xflags, u32 xflags_mask, u16 xflags2, u16 xflags2_mask);
+void fileattr_fill_flags(struct fileattr *fa, u32 flags, u32 mask);
/**
* fileattr_has_fsx - check for extended flags/attributes
@@ -49,7 +52,9 @@ static inline bool fileattr_has_fsx(const struct fileattr *fa)
{
return fa->fsx_valid &&
((fa->fsx_xflags & ~FS_XFLAG_COMMON) || fa->fsx_extsize != 0 ||
- fa->fsx_projid != 0 || fa->fsx_cowextsize != 0);
+ fa->fsx_projid != 0 || fa->fsx_cowextsize != 0 ||
+ fa->fsx_xflags2 != 0 || fa->fsx_xflags2_mask != 0 ||
+ (fa->fsx_xflags_mask & ~FS_XFLAG_COMMON));
}
int vfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
@@ -4178,7 +4178,7 @@ static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa)
{
struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
- fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE);
+ fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE, SHMEM_FL_USER_VISIBLE);
return 0;
}
This change adds support for new struct fileattr fields fsx_xflags_mask, fsx_xflags2 and fsx_xflags2_mask into FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR ioctls. All filesystem will start reporting values in new *_mask fields. This change does not contain support for any new flag yet. This will be in some followup changes. Signed-off-by: Pali Rohár <pali@kernel.org> --- fs/btrfs/ioctl.c | 9 +++++- fs/efivarfs/inode.c | 3 +- fs/ext2/ioctl.c | 2 +- fs/ext4/ioctl.c | 2 +- fs/f2fs/file.c | 2 +- fs/fuse/ioctl.c | 13 ++++++-- fs/gfs2/file.c | 14 ++++++++- fs/hfsplus/inode.c | 3 +- fs/ioctl.c | 65 +++++++++++++++++++++++++++++++++++----- fs/jfs/ioctl.c | 14 ++++++++- fs/nilfs2/ioctl.c | 2 +- fs/ntfs3/file.c | 3 +- fs/ocfs2/ioctl.c | 2 +- fs/orangefs/inode.c | 2 +- fs/ubifs/ioctl.c | 3 +- fs/xfs/xfs_ioctl.c | 5 +++- include/linux/fileattr.h | 11 +++++-- mm/shmem.c | 2 +- 18 files changed, 130 insertions(+), 27 deletions(-)