From 665383d3a1f4d1dc7f404301039432271ad85eaf Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Tue, 30 Nov 2021 12:13:03 +1100 Subject: [PATCH] LU-12056 ldiskfs: add trusted.projid virtual xattr Add trusted.projid virtual xattr in ldiskfs to export the current project id, intended for ldiskfs level MDT backup. When the project id is EXT4_DEF_PROJID/0, the virtual xattr is hidden from listxattr(2). It's also hidden on lustre client when parent has the project inherit flag and the same project ID, to stop mv from setting the virtual xattr on the dest with the project id from src, which could be different from dest. getxattr(2) on trusted.projid will report current project id, setxattr(2) will change curent project id and removexattr(2) will set project id back to EXT4_DEF_PROJID/0 Both get|setxattr(2) will work even when the virtual xattr is hidden. Invalidate client xattr cache for the inode when changing its project id, so the virtual xattr can get the new value for next getxattr(2) Add test cases to verify the virtual projid xattr and backup restore MDT using tar can now preserve the project id. Change mds_backup_restore in test framework, to use tar with --xattrs --xattrs-include='trusted.*'" options. Change-Id: I29b1aa922ef72d734cdc87125401fa08fb13d4af Signed-off-by: Li Dongyang Reviewed-on: https://review.whamcloud.com/45679 Reviewed-by: Andreas Dilger Reviewed-by: Yang Sheng Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- .../patches/base/ext4-projid-xattrs.patch | 167 +++++++++++++++ .../patches/rhel7.6/ext4-projid-xattrs.patch | 225 +++++++++++++++++++++ .../patches/ubuntu18/ext4-projid-xattrs.patch | 220 ++++++++++++++++++++ .../series/ldiskfs-3.10-rhel7.6.series | 1 + .../series/ldiskfs-3.10-rhel7.7.series | 1 + .../series/ldiskfs-3.10-rhel7.8.series | 1 + .../series/ldiskfs-3.10-rhel7.9.series | 1 + .../series/ldiskfs-4.12-sles15-22.series | 1 + .../series/ldiskfs-4.12-sles15.series | 1 + .../series/ldiskfs-4.12-sles15sp1-7.series | 1 + .../series/ldiskfs-4.12-sles15sp1.series | 1 + .../series/ldiskfs-4.15.0-20-ubuntu18.series | 1 + .../series/ldiskfs-4.15.0-24-ubuntu18.series | 1 + .../series/ldiskfs-4.18-rhel8.1.series | 1 + .../series/ldiskfs-4.18-rhel8.2.series | 1 + .../series/ldiskfs-4.18-rhel8.3.series | 1 + .../series/ldiskfs-4.18-rhel8.4.series | 1 + .../series/ldiskfs-4.18-rhel8.5.series | 1 + .../series/ldiskfs-4.18-rhel8.series | 1 + .../series/ldiskfs-5.0.0-13-ubuntu19.series | 1 + .../series/ldiskfs-5.4.0-42-ubuntu20.series | 1 + .../series/ldiskfs-5.4.0-66-ubuntu20.series | 1 + .../series/ldiskfs-5.4.0-80-ubuntu20.series | 1 + .../series/ldiskfs-5.4.0-90-ubuntu20.series | 1 + .../kernel_patches/series/ldiskfs-5.4.0-ml.series | 1 + .../series/ldiskfs-5.4.136-ml.series | 1 + .../kernel_patches/series/ldiskfs-5.4.21-ml.series | 1 + .../series/ldiskfs-5.8.0-53-ubuntu20.series | 1 + .../kernel_patches/series/ldiskfs-5.8.0-ml.series | 1 + .../kernel_patches/series/ldiskfs-5.9.0-ml.series | 1 + lustre/include/uapi/linux/lustre/lustre_idl.h | 1 + lustre/llite/xattr.c | 15 ++ lustre/llite/xattr_cache.c | 15 ++ lustre/mdt/mdt_reint.c | 5 + lustre/tests/conf-sanity.sh | 47 +++++ lustre/tests/sanity.sh | 63 ++++++ lustre/tests/test-framework.sh | 40 ++-- 37 files changed, 802 insertions(+), 23 deletions(-) create mode 100644 ldiskfs/kernel_patches/patches/base/ext4-projid-xattrs.patch create mode 100644 ldiskfs/kernel_patches/patches/rhel7.6/ext4-projid-xattrs.patch create mode 100644 ldiskfs/kernel_patches/patches/ubuntu18/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/patches/base/ext4-projid-xattrs.patch b/ldiskfs/kernel_patches/patches/base/ext4-projid-xattrs.patch new file mode 100644 index 0000000..95dbbf6 --- /dev/null +++ b/ldiskfs/kernel_patches/patches/base/ext4-projid-xattrs.patch @@ -0,0 +1,167 @@ +Index: linux-4.18.0-348.2.1.el8_5/fs/ext4/ext4.h +=================================================================== +--- linux-4.18.0-348.2.1.el8_5.orig/fs/ext4/ext4.h ++++ linux-4.18.0-348.2.1.el8_5/fs/ext4/ext4.h +@@ -2770,6 +2770,7 @@ extern int ext4_ind_remove_space(handle_ + /* ioctl.c */ + extern long ext4_ioctl(struct file *, unsigned int, unsigned long); + extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); ++extern int ext4_ioctl_setproject(struct inode *, __u32); + + /* migrate.c */ + extern int ext4_ext_migrate(struct inode *); +Index: linux-4.18.0-348.2.1.el8_5/fs/ext4/ioctl.c +=================================================================== +--- linux-4.18.0-348.2.1.el8_5.orig/fs/ext4/ioctl.c ++++ linux-4.18.0-348.2.1.el8_5/fs/ext4/ioctl.c +@@ -446,9 +446,8 @@ flags_out: + } + + #ifdef CONFIG_QUOTA +-static int ext4_ioctl_setproject(struct file *filp, __u32 projid) ++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; +@@ -532,7 +531,7 @@ out_stop: + 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; +@@ -1184,7 +1183,7 @@ resizefs_out: + err = ext4_ioctl_setflags(inode, flags); + if (err) + goto out; +- err = ext4_ioctl_setproject(filp, fa.fsx_projid); ++ err = ext4_ioctl_setproject(inode, fa.fsx_projid); + out: + inode_unlock(inode); + mnt_drop_write_file(filp); +Index: linux-4.18.0-348.2.1.el8_5/fs/ext4/xattr.c +=================================================================== +--- linux-4.18.0-348.2.1.el8_5.orig/fs/ext4/xattr.c ++++ linux-4.18.0-348.2.1.el8_5/fs/ext4/xattr.c +@@ -62,6 +62,8 @@ + #include "xattr.h" + #include "acl.h" + ++#define EXT4_XATTR_PROJID "projid" ++ + #ifdef EXT4_XATTR_DEBUG + # define ea_idebug(inode, fmt, ...) \ + printk(KERN_DEBUG "inode %s:%lu: " fmt "\n", \ +@@ -646,11 +648,30 @@ ext4_xattr_get(struct inode *inode, int + return -ERANGE; + + down_read(&EXT4_I(inode)->xattr_sem); ++ if (name_index == EXT4_XATTR_INDEX_TRUSTED && ++ strncmp(name, EXT4_XATTR_PROJID, strlen(name)) == 0 && ++ ext4_has_feature_project(inode->i_sb)) { ++ /* 10 chars to hold u32 in decimal, plus ending \0 */ ++ char value[11]; ++ __u32 projid = (__u32)from_kprojid(&init_user_ns, ++ EXT4_I(inode)->i_projid); ++ error = snprintf(value, sizeof(value), "%u", projid); ++ if (buffer) { ++ if (error > buffer_size) { ++ error = -ERANGE; ++ goto out; ++ } ++ memcpy(buffer, value, error); ++ } ++ goto out; ++ } ++ + error = ext4_xattr_ibody_get(inode, name_index, name, buffer, + buffer_size); + if (error == -ENODATA) + error = ext4_xattr_block_get(inode, name_index, name, buffer, + buffer_size); ++out: + up_read(&EXT4_I(inode)->xattr_sem); + return error; + } +@@ -772,7 +793,33 @@ ext4_listxattr(struct dentry *dentry, ch + ret = ext4_xattr_block_list(dentry, buffer, buffer_size); + if (ret < 0) + goto errout; ++ if (buffer) { ++ buffer += ret; ++ buffer_size -= ret; ++ } + ret += ret2; ++ if (ext4_has_feature_project(dentry->d_sb)) { ++ size_t prefix_len = strlen(XATTR_TRUSTED_PREFIX); ++ size_t name_len = strlen(EXT4_XATTR_PROJID); ++ size_t size = prefix_len + name_len + 1; ++ ++ if (__kprojid_val(EXT4_I(dentry->d_inode)->i_projid) == ++ EXT4_DEF_PROJID) ++ goto errout; ++ if (buffer) { ++ if (size > buffer_size) { ++ ret = -ERANGE; ++ goto errout; ++ } ++ strncpy(buffer, XATTR_TRUSTED_PREFIX, prefix_len); ++ buffer += prefix_len; ++ strncpy(buffer, EXT4_XATTR_PROJID, name_len); ++ buffer += name_len; ++ *buffer++ = 0; ++ buffer_size -= size; ++ } ++ ret += size; ++ } + errout: + up_read(&EXT4_I(d_inode(dentry))->xattr_sem); + return ret; +@@ -2464,6 +2511,43 @@ ext4_xattr_set(struct inode *inode, int + int error, retries = 0; + int credits; + ++ if (name_index == EXT4_XATTR_INDEX_TRUSTED && ++ strncmp(name, EXT4_XATTR_PROJID, strlen(name)) == 0 && ++ ext4_has_feature_project(inode->i_sb)) { ++ /* 10 chars to hold u32 in decimal, plus ending \0 */ ++ char buffer[11]; ++ __u32 projid; ++ ++ /* ++ * Project Quota ID state is only allowed to change from within ++ * the init namespace. ++ */ ++ if (current_user_ns() != &init_user_ns) ++ return -EINVAL; ++ ++ if (value && value_len) { ++ if (value_len >= sizeof(buffer)) ++ return -EINVAL; ++ memcpy(buffer, value, value_len); ++ buffer[value_len] = '\0'; ++ error = kstrtouint(buffer, 0, &projid); ++ if (error) ++ return error; ++ } else { ++ projid = EXT4_DEF_PROJID; ++ } ++ ++ /* ++ * Caller is allowed to change the project ID. If it is being ++ * changed, make sure that the new value is valid. ++ */ ++ if (!projid_valid(make_kprojid(&init_user_ns, projid))) ++ return -EINVAL; ++ ++ error = ext4_ioctl_setproject(inode, projid); ++ return error; ++ } ++ + error = dquot_initialize(inode); + if (error) + return error; diff --git a/ldiskfs/kernel_patches/patches/rhel7.6/ext4-projid-xattrs.patch b/ldiskfs/kernel_patches/patches/rhel7.6/ext4-projid-xattrs.patch new file mode 100644 index 0000000..19ea98d --- /dev/null +++ b/ldiskfs/kernel_patches/patches/rhel7.6/ext4-projid-xattrs.patch @@ -0,0 +1,225 @@ +Index: linux-3.10.0-1160.45.1.el7/fs/ext4/xattr.c +=================================================================== +--- linux-3.10.0-1160.45.1.el7.orig/fs/ext4/xattr.c ++++ linux-3.10.0-1160.45.1.el7/fs/ext4/xattr.c +@@ -61,6 +61,8 @@ + #include "xattr.h" + #include "acl.h" + ++#define EXT4_XATTR_PROJID "projid" ++ + #ifdef EXT4_XATTR_DEBUG + # define ea_idebug(inode, f...) do { \ + printk(KERN_DEBUG "inode %s:%lu: ", \ +@@ -531,11 +533,31 @@ ext4_xattr_get(struct inode *inode, int + return -ERANGE; + + down_read(&EXT4_I(inode)->xattr_sem); ++ if (name_index == EXT4_XATTR_INDEX_TRUSTED && ++ strncmp(name, EXT4_XATTR_PROJID, strlen(name)) == 0 && ++ EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, ++ EXT4_FEATURE_RO_COMPAT_PROJECT)) { ++ /* 10 chars to hold u32 in decimal, plus ending \0 */ ++ char value[11]; ++ __u32 projid = (__u32)from_kprojid(&init_user_ns, ++ EXT4_I(inode)->i_projid); ++ error = snprintf(value, sizeof(value), "%u", projid); ++ if (buffer) { ++ if (error > buffer_size) { ++ error = -ERANGE; ++ goto out; ++ } ++ memcpy(buffer, value, error); ++ } ++ goto out; ++ } ++ + error = ext4_xattr_ibody_get(inode, name_index, name, buffer, + buffer_size); + if (error == -ENODATA) + error = ext4_xattr_block_get(inode, name_index, name, buffer, + buffer_size); ++out: + up_read(&EXT4_I(inode)->xattr_sem); + return error; + } +@@ -657,7 +679,34 @@ ext4_xattr_list(struct dentry *dentry, c + ret = ext4_xattr_block_list(dentry, buffer, buffer_size); + if (ret < 0) + goto errout; ++ if (buffer) { ++ buffer += ret; ++ buffer_size -= ret; ++ } + ret += ret2; ++ if (EXT4_HAS_RO_COMPAT_FEATURE(dentry->d_sb, ++ EXT4_FEATURE_RO_COMPAT_PROJECT)) { ++ size_t prefix_len = strlen(XATTR_TRUSTED_PREFIX); ++ size_t name_len = strlen(EXT4_XATTR_PROJID); ++ size_t size = prefix_len + name_len + 1; ++ ++ if (__kprojid_val(EXT4_I(dentry->d_inode)->i_projid) == ++ EXT4_DEF_PROJID) ++ goto errout; ++ if (buffer) { ++ if (size > buffer_size) { ++ ret = -ERANGE; ++ goto errout; ++ } ++ strncpy(buffer, XATTR_TRUSTED_PREFIX, prefix_len); ++ buffer += prefix_len; ++ strncpy(buffer, EXT4_XATTR_PROJID, name_len); ++ buffer += name_len; ++ *buffer++ = 0; ++ buffer_size -= size; ++ } ++ ret += size; ++ } + errout: + up_read(&EXT4_I(dentry->d_inode)->xattr_sem); + return ret; +@@ -1552,6 +1601,44 @@ ext4_xattr_set(struct inode *inode, int + int error, retries = 0; + int credits = ext4_jbd2_credits_xattr(inode); + ++ if (name_index == EXT4_XATTR_INDEX_TRUSTED && ++ strncmp(name, EXT4_XATTR_PROJID, strlen(name)) == 0 && ++ EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, ++ EXT4_FEATURE_RO_COMPAT_PROJECT)) { ++ /* 10 chars to hold u32 in decimal, plus ending \0 */ ++ char buffer[11]; ++ __u32 projid; ++ ++ /* ++ * Project Quota ID state is only allowed to change from within ++ * the init namespace. ++ */ ++ if (current_user_ns() != &init_user_ns) ++ return -EINVAL; ++ ++ if (value && value_len) { ++ if (value_len >= sizeof(buffer)) ++ return -EINVAL; ++ memcpy(buffer, value, value_len); ++ buffer[value_len] = '\0'; ++ error = kstrtouint(buffer, 0, &projid); ++ if (error) ++ return error; ++ } else { ++ projid = EXT4_DEF_PROJID; ++ } ++ ++ /* ++ * Caller is allowed to change the project ID. If it is being ++ * changed, make sure that the new value is valid. ++ */ ++ if (!projid_valid(make_kprojid(&init_user_ns, projid))) ++ return -EINVAL; ++ ++ error = ext4_ioctl_setproject(inode, projid); ++ return error; ++ } ++ + if ((value_len >= EXT4_XATTR_MIN_LARGE_EA_SIZE(sb->s_blocksize)) && + EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EA_INODE)) { + int nrblocks = (value_len + sb->s_blocksize - 1) >> +Index: linux-3.10.0-1160.45.1.el7/fs/ext4/ioctl.c +=================================================================== +--- linux-3.10.0-1160.45.1.el7.orig/fs/ext4/ioctl.c ++++ linux-3.10.0-1160.45.1.el7/fs/ext4/ioctl.c +@@ -302,9 +302,8 @@ flags_out: + } + + #ifdef CONFIG_QUOTA +-static int ext4_ioctl_setproject(struct file *filp, __u32 projid) ++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; +@@ -332,25 +331,20 @@ static int ext4_ioctl_setproject(struct + if (projid_eq(kprojid, EXT4_I(inode)->i_projid)) + return 0; + +- err = mnt_want_write_file(filp); +- if (err) +- return err; +- + err = -EPERM; +- mutex_lock(&inode->i_mutex); + /* Is it quota file? Do not allow user to mess with it */ + if (IS_NOQUOTA(inode)) +- goto out_unlock; ++ goto out; + + err = ext4_get_inode_loc(inode, &iloc); + if (err) +- goto out_unlock; ++ goto out; + + raw_inode = ext4_raw_inode(&iloc); + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) { + err = -EOVERFLOW; + brelse(iloc.bh); +- goto out_unlock; ++ goto out; + } + brelse(iloc.bh); + +@@ -361,7 +355,7 @@ static int ext4_ioctl_setproject(struct + EXT4_QUOTA_DEL_BLOCKS(sb) + 3); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); +- goto out_unlock; ++ goto out; + } + + err = ext4_reserve_inode_write(handle, inode, &iloc); +@@ -384,16 +378,14 @@ out_dirty: + err = rc; + out_stop: + ext4_journal_stop(handle); +-out_unlock: +- mutex_unlock(&inode->i_mutex); +- mnt_drop_write_file(filp); ++out: + return err; + + + } + + #else +-static int ext4_ioctl_setproject(struct file *filp, __u32 projid) ++int ext4_ioctl_setproject(struct inode *inode, __u32 projid) + { + if (projid != EXT4_DEF_PROJID) + return -EOPNOTSUPP; +@@ -841,7 +833,14 @@ resizefs_out: + if (err) + return err; + +- err = ext4_ioctl_setproject(filp, fa.fsx_projid); ++ err = mnt_want_write_file(filp); ++ if (err) ++ return err; ++ ++ mutex_lock(&inode->i_mutex); ++ err = ext4_ioctl_setproject(inode, fa.fsx_projid); ++ mutex_unlock(&inode->i_mutex); ++ mnt_drop_write_file(filp); + if (err) + return err; + +Index: linux-3.10.0-1160.45.1.el7/fs/ext4/ext4.h +=================================================================== +--- linux-3.10.0-1160.45.1.el7.orig/fs/ext4/ext4.h ++++ linux-3.10.0-1160.45.1.el7/fs/ext4/ext4.h +@@ -2451,6 +2451,7 @@ extern int ext4_ind_remove_space(handle_ + /* ioctl.c */ + extern long ext4_ioctl(struct file *, unsigned int, unsigned long); + extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); ++extern int ext4_ioctl_setproject(struct inode *, __u32); + + /* migrate.c */ + extern int ext4_ext_migrate(struct inode *); diff --git a/ldiskfs/kernel_patches/patches/ubuntu18/ext4-projid-xattrs.patch b/ldiskfs/kernel_patches/patches/ubuntu18/ext4-projid-xattrs.patch new file mode 100644 index 0000000..6af91eb --- /dev/null +++ b/ldiskfs/kernel_patches/patches/ubuntu18/ext4-projid-xattrs.patch @@ -0,0 +1,220 @@ +Index: bionic/fs/ext4/ext4.h +=================================================================== +--- bionic.orig/fs/ext4/ext4.h ++++ bionic/fs/ext4/ext4.h +@@ -2669,6 +2669,7 @@ extern int ext4_ind_remove_space(handle_ + /* ioctl.c */ + extern long ext4_ioctl(struct file *, unsigned int, unsigned long); + extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); ++extern int ext4_ioctl_setproject(struct inode *, __u32); + + /* migrate.c */ + extern int ext4_ext_migrate(struct inode *); +Index: bionic/fs/ext4/ioctl.c +=================================================================== +--- bionic.orig/fs/ext4/ioctl.c ++++ bionic/fs/ext4/ioctl.c +@@ -315,9 +315,8 @@ flags_out: + } + + #ifdef CONFIG_QUOTA +-static int ext4_ioctl_setproject(struct file *filp, __u32 projid) ++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; +@@ -344,19 +343,14 @@ static int ext4_ioctl_setproject(struct + if (projid_eq(kprojid, EXT4_I(inode)->i_projid)) + return 0; + +- err = mnt_want_write_file(filp); +- if (err) +- return err; +- + err = -EPERM; +- inode_lock(inode); + /* Is it quota file? Do not allow user to mess with it */ + if (ext4_is_quota_file(inode)) +- goto out_unlock; ++ goto out; + + err = ext4_get_inode_loc(inode, &iloc); + if (err) +- goto out_unlock; ++ goto out; + + raw_inode = ext4_raw_inode(&iloc); + if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) { +@@ -364,7 +358,7 @@ static int ext4_ioctl_setproject(struct + EXT4_SB(sb)->s_want_extra_isize, + &iloc); + if (err) +- goto out_unlock; ++ goto out; + } else { + brelse(iloc.bh); + } +@@ -376,7 +370,7 @@ static int ext4_ioctl_setproject(struct + EXT4_QUOTA_DEL_BLOCKS(sb) + 3); + if (IS_ERR(handle)) { + err = PTR_ERR(handle); +- goto out_unlock; ++ goto out; + } + + err = ext4_reserve_inode_write(handle, inode, &iloc); +@@ -405,13 +399,11 @@ out_dirty: + err = rc; + out_stop: + ext4_journal_stop(handle); +-out_unlock: +- inode_unlock(inode); +- mnt_drop_write_file(filp); ++out: + 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; +@@ -1037,7 +1029,14 @@ resizefs_out: + if (err) + return err; + ++ err = mnt_want_write_file(filp); ++ if (err) ++ return err; ++ ++ inode_lock(inode); + err = ext4_ioctl_setproject(filp, fa.fsx_projid); ++ inode_unlock(inode); ++ mnt_drop_write_file(filp); + if (err) + return err; + +Index: bionic/fs/ext4/xattr.c +=================================================================== +--- bionic.orig/fs/ext4/xattr.c ++++ bionic/fs/ext4/xattr.c +@@ -61,6 +61,8 @@ + #include "xattr.h" + #include "acl.h" + ++#define EXT4_XATTR_PROJID "projid" ++ + #ifdef EXT4_XATTR_DEBUG + # define ea_idebug(inode, fmt, ...) \ + printk(KERN_DEBUG "inode %s:%lu: " fmt "\n", \ +@@ -644,11 +646,30 @@ ext4_xattr_get(struct inode *inode, int + return -ERANGE; + + down_read(&EXT4_I(inode)->xattr_sem); ++ if (name_index == EXT4_XATTR_INDEX_TRUSTED && ++ strncmp(name, EXT4_XATTR_PROJID, strlen(name)) == 0 && ++ ext4_has_feature_project(inode->i_sb)) { ++ /* 10 chars to hold u32 in decimal, plus ending \0 */ ++ char value[11]; ++ __u32 projid = (__u32)from_kprojid(&init_user_ns, ++ EXT4_I(inode)->i_projid); ++ error = snprintf(value, sizeof(value), "%u", projid); ++ if (buffer) { ++ if (error > buffer_size) { ++ error = -ERANGE; ++ goto out; ++ } ++ memcpy(buffer, value, error); ++ } ++ goto out; ++ } ++ + error = ext4_xattr_ibody_get(inode, name_index, name, buffer, + buffer_size); + if (error == -ENODATA) + error = ext4_xattr_block_get(inode, name_index, name, buffer, + buffer_size); ++out: + up_read(&EXT4_I(inode)->xattr_sem); + return error; + } +@@ -773,7 +794,33 @@ ext4_listxattr(struct dentry *dentry, ch + ret = ext4_xattr_block_list(dentry, buffer, buffer_size); + if (ret < 0) + goto errout; ++ if (buffer) { ++ buffer += ret; ++ buffer_size -= ret; ++ } + ret += ret2; ++ if (ext4_has_feature_project(dentry->d_sb)) { ++ size_t prefix_len = strlen(XATTR_TRUSTED_PREFIX); ++ size_t name_len = strlen(EXT4_XATTR_PROJID); ++ size_t size = prefix_len + name_len + 1; ++ ++ if (__kprojid_val(EXT4_I(dentry->d_inode)->i_projid) == ++ EXT4_DEF_PROJID) ++ goto errout; ++ if (buffer) { ++ if (size > buffer_size) { ++ ret = -ERANGE; ++ goto errout; ++ } ++ strncpy(buffer, XATTR_TRUSTED_PREFIX, prefix_len); ++ buffer += prefix_len; ++ strncpy(buffer, EXT4_XATTR_PROJID, name_len); ++ buffer += name_len; ++ *buffer++ = 0; ++ buffer_size -= size; ++ } ++ ret += size; ++ } + errout: + up_read(&EXT4_I(d_inode(dentry))->xattr_sem); + return ret; +@@ -2487,6 +2534,43 @@ ext4_xattr_set(struct inode *inode, int + int error, retries = 0; + int credits; + ++ if (name_index == EXT4_XATTR_INDEX_TRUSTED && ++ strncmp(name, EXT4_XATTR_PROJID, strlen(name)) == 0 && ++ ext4_has_feature_project(inode->i_sb)) { ++ /* 10 chars to hold u32 in decimal, plus ending \0 */ ++ char buffer[11]; ++ __u32 projid; ++ ++ /* ++ * Project Quota ID state is only allowed to change from within ++ * the init namespace. ++ */ ++ if (current_user_ns() != &init_user_ns) ++ return -EINVAL; ++ ++ if (value && value_len) { ++ if (value_len >= sizeof(buffer)) ++ return -EINVAL; ++ memcpy(buffer, value, value_len); ++ buffer[value_len] = '\0'; ++ error = kstrtouint(buffer, 0, &projid); ++ if (error) ++ return error; ++ } else { ++ projid = EXT4_DEF_PROJID; ++ } ++ ++ /* ++ * Caller is allowed to change the project ID. If it is being ++ * changed, make sure that the new value is valid. ++ */ ++ if (!projid_valid(make_kprojid(&init_user_ns, projid))) ++ return -EINVAL; ++ ++ error = ext4_ioctl_setproject(inode, projid); ++ return error; ++ } ++ + error = dquot_initialize(inode); + if (error) + return error; diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.6.series b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.6.series index d051d3b..e4cc884 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.6.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.6.series @@ -50,3 +50,4 @@ rhel7.6/ext4-introduce-aging-to-extent-status-tree.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.6/ext4-dquot-commit-speedup.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +rhel7.6/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.7.series b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.7.series index da4cf53..b883ee9 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.7.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.7.series @@ -50,3 +50,4 @@ rhel7.6/ext4-introduce-aging-to-extent-status-tree.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.6/ext4-dquot-commit-speedup.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +rhel7.6/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.8.series b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.8.series index 8178924..72d308f 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.8.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.8.series @@ -43,3 +43,4 @@ rhel7.7/ext4-mballoc-prefetch.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.6/ext4-dquot-commit-speedup.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +rhel7.6/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.9.series b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.9.series index dceb035..a50604c 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.9.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.9.series @@ -43,3 +43,4 @@ rhel7.7/ext4-mballoc-prefetch.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.6/ext4-dquot-commit-speedup.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +rhel7.6/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15-22.series b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15-22.series index a4c776c..e8a8420 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15-22.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15-22.series @@ -27,3 +27,4 @@ rhel7.6/ext4-export-orphan-add.patch suse15/ext4-export-mb-stream-allocator-variables.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15.series b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15.series index b7bb0f6..c731d36 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15.series @@ -27,3 +27,4 @@ rhel7.6/ext4-export-orphan-add.patch suse15/ext4-export-mb-stream-allocator-variables.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1-7.series b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1-7.series index a4c776c..e8a8420 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1-7.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1-7.series @@ -27,3 +27,4 @@ rhel7.6/ext4-export-orphan-add.patch suse15/ext4-export-mb-stream-allocator-variables.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1.series b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1.series index 2fc137d..a51161a 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1.series @@ -27,3 +27,4 @@ rhel7.6/ext4-export-orphan-add.patch suse15/ext4-export-mb-stream-allocator-variables.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel7.7/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-20-ubuntu18.series b/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-20-ubuntu18.series index 1c8f3c8..0d4b524 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-20-ubuntu18.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-20-ubuntu18.series @@ -25,3 +25,4 @@ ubuntu18/ext4-include-terminating-u32-in-size-of-xattr-entries-when-expanding-in rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +ubuntu18/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-24-ubuntu18.series b/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-24-ubuntu18.series index 325f762..6a19aa3 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-24-ubuntu18.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.15.0-24-ubuntu18.series @@ -26,3 +26,4 @@ suse15/ext4-export-mb-stream-allocator-variables.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +ubuntu18/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series index e18f0d9..d34d03d 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series @@ -27,3 +27,4 @@ rhel8.1/ext4-mballoc-prefetch.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series index 9c53636..02d29aa 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series @@ -27,3 +27,4 @@ rhel8.1/ext4-mballoc-prefetch.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series index b92964a..3a0ce31 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series @@ -27,3 +27,4 @@ rhel8.1/ext4-mballoc-prefetch.patch rhel8.3/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series index 7683149..9528ef5 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series @@ -27,3 +27,4 @@ rhel8.1/ext4-mballoc-prefetch.patch rhel8.3/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series index 7683149..9528ef5 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series @@ -27,3 +27,4 @@ rhel8.1/ext4-mballoc-prefetch.patch rhel8.3/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series index 9f91efd..f013041 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series @@ -29,3 +29,4 @@ rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch base/ext4-reset-exts-for-gcc10.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +ubuntu18/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.0.0-13-ubuntu19.series b/ldiskfs/kernel_patches/series/ldiskfs-5.0.0-13-ubuntu19.series index cfc1d66..b9b7674f 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.0.0-13-ubuntu19.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.0.0-13-ubuntu19.series @@ -26,3 +26,4 @@ rhel8/ext4-simple-blockalloc.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series index 25fb457..cd90a53 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series @@ -28,3 +28,4 @@ rhel8/ext4-simple-blockalloc.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series index e2c88e2..067d3fc 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series @@ -28,3 +28,4 @@ rhel8/ext4-simple-blockalloc.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series index a8eeb2f..556a59d 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series @@ -28,3 +28,4 @@ linux-5.4/ext4-simple-blockalloc.patch linux-5.4/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series index beeecbd..26f1a70f 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series @@ -28,3 +28,4 @@ linux-5.4/ext4-simple-blockalloc.patch linux-5.4/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series index 9eee135..4407f21 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series @@ -28,3 +28,4 @@ rhel8/ext4-simple-blockalloc.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series index 6dad60c..668b6b1 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series @@ -28,3 +28,4 @@ linux-5.4/ext4-simple-blockalloc.patch linux-5.4/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series index 25fb457..cd90a53 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series @@ -28,3 +28,4 @@ rhel8/ext4-simple-blockalloc.patch rhel8/ext4-xattr-disable-credits-check.patch base/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-53-ubuntu20.series b/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-53-ubuntu20.series index f4ef984..fae39d6 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-53-ubuntu20.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-53-ubuntu20.series @@ -28,3 +28,4 @@ ubuntu2004/ext4-simple-blockalloc.patch rhel8.3/ext4-xattr-disable-credits-check.patch linux-5.8/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-ml.series index c09e847..4d3c0f4 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.8.0-ml.series @@ -28,3 +28,4 @@ linux-5.8/ext4-simple-blockalloc.patch rhel8.3/ext4-xattr-disable-credits-check.patch linux-5.8/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/ldiskfs/kernel_patches/series/ldiskfs-5.9.0-ml.series b/ldiskfs/kernel_patches/series/ldiskfs-5.9.0-ml.series index df7742e..aa62e8d 100644 --- a/ldiskfs/kernel_patches/series/ldiskfs-5.9.0-ml.series +++ b/ldiskfs/kernel_patches/series/ldiskfs-5.9.0-ml.series @@ -27,3 +27,4 @@ linux-5.4/ext4-misc.patch linux-5.9/ext4-simple-blockalloc.patch linux-5.8/ext4-no-max-dir-size-limit-for-iam-objects.patch rhel8/ext4-ialloc-uid-gid-and-pass-owner-down.patch +base/ext4-projid-xattrs.patch diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index 06bcb8d..175cf1f 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1211,6 +1211,7 @@ struct lov_mds_md_v1 { /* LOV EA mds/wire data (little-endian) */ #define XATTR_NAME_HSM "trusted.hsm" #define XATTR_NAME_LFSCK_BITMAP "trusted.lfsck_bitmap" #define XATTR_NAME_DUMMY "trusted.dummy" +#define XATTR_NAME_PROJID "trusted.projid" #define LL_XATTR_NAME_ENCRYPTION_CONTEXT XATTR_SECURITY_PREFIX"c" diff --git a/lustre/llite/xattr.c b/lustre/llite/xattr.c index ca45354..6325c8a 100644 --- a/lustre/llite/xattr.c +++ b/lustre/llite/xattr.c @@ -623,6 +623,7 @@ static int ll_xattr_get(const struct xattr_handler *handler, ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size) { + struct inode *dir = d_inode(dentry->d_parent); struct inode *inode = dentry->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); ktime_t kstart = ktime_get(); @@ -666,6 +667,20 @@ ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size) hide_xattr = true; } + /* Hide virtual project id xattr from the list when + * parent has the inherit flag and the same project id, + * so project id won't be messed up by copying the xattrs + * when mv to a tree with different project id. + */ + if (get_xattr_type(xattr_name)->flags == XATTR_TRUSTED_T && + strcmp(xattr_name, XATTR_NAME_PROJID) == 0) { + if (ll_i2info(inode)->lli_projid == + ll_i2info(dir)->lli_projid && + test_bit(LLIF_PROJECT_INHERIT, + &ll_i2info(dir)->lli_flags)) + hide_xattr = true; + } + len = strnlen(xattr_name, rem - 1) + 1; rem -= len; if (!xattr_type_filter(sbi, hide_xattr ? NULL : diff --git a/lustre/llite/xattr_cache.c b/lustre/llite/xattr_cache.c index a42329d..ce3e3a7 100644 --- a/lustre/llite/xattr_cache.c +++ b/lustre/llite/xattr_cache.c @@ -610,6 +610,21 @@ int ll_xattr_cache_get(struct inode *inode, else rc = -ERANGE; } + /* Return the project id when the virtual project id xattr + * is explicitly asked. + */ + } else if (strcmp(name, XATTR_NAME_PROJID) == 0) { + /* 10 chars to hold u32 in decimal, plus ending \0 */ + char projid[11]; + + rc = snprintf(projid, sizeof(projid), + "%u", lli->lli_projid); + if (size != 0) { + if (rc <= size) + memcpy(buffer, projid, rc); + else + rc = -ERANGE; + } } } else if (valid & OBD_MD_FLXATTRLS) { rc = ll_xattr_cache_list(&lli->lli_xattrs, diff --git a/lustre/mdt/mdt_reint.c b/lustre/mdt/mdt_reint.c index 0e662cf..8b36314 100644 --- a/lustre/mdt/mdt_reint.c +++ b/lustre/mdt/mdt_reint.c @@ -717,6 +717,11 @@ static int mdt_attr_set(struct mdt_thread_info *info, struct mdt_object *mo, */ if (ma->ma_attr.la_valid & (LA_MODE|LA_UID|LA_GID)) lockpart |= MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM; + /* Clear xattr cache on clients, so the virtual project ID xattr + * can get the new project ID + */ + if (ma->ma_attr.la_valid & LA_PROJID) + lockpart |= MDS_INODELOCK_XATTR; rc = mdt_reint_striped_lock(info, mo, lh, lockpart, einfo, cos_incompat); diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index 5205d4b..d65c75d 100644 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -9324,6 +9324,53 @@ test_130() } run_test 130 "re-register an MDT after writeconf" +test_131() { + [ "$mds1_FSTYPE" == "ldiskfs" ] || skip "ldiskfs only test" + do_facet mds1 $DEBUGFS -R features $(mdsdevname 1) | + grep -q project || skip "skip project quota not supported" + + local projid + + setupall + test_mkdir -c $MDSCOUNT -p $DIR/$tdir + $LFS project -p 1000 $DIR/$tdir || error "set dir project id failed" + createmany -o $DIR/$tdir/f 512 + for ((i = 0; i < 512; ++i)); do + $LFS project -p $i $DIR/$tdir/f${i} || + error "set f${i} project id failed" + done + + test_mkdir -c $MDSCOUNT -p $DIR/$tdir.inherit + $LFS project -p 1001 -s $DIR/$tdir.inherit + createmany -o $DIR/$tdir.inherit/f 128 + (( $($LFS project $DIR/$tdir.inherit/f* | + awk '$1 == 1001 { print }' | wc -l) == 128 )) || + error "files did not inherit projid 1001" + + stopall + + for i in $(seq $MDSCOUNT); do + mds_backup_restore mds$i || + error "Backup/restore on mds$i failed" + done + + setupall + + projid=($($LFS project -d $DIR/$tdir)) + [ ${projid[0]} == "1000" ] || + error "projid expected 1000 not ${projid[0]}" + for ((i = 0; i < 512; ++i)); do + projid=($($LFS project $DIR/$tdir/f${i})) + [ ${projid[0]} == "$i" ] || + error "projid expected $i not ${projid[0]}" + done + + (( $($LFS project $DIR/$tdir.inherit/f* | + awk '$1 == 1001 { print }' | wc -l) == 128 )) || + error "restore did not copy projid 1001" +} +run_test 131 "MDT backup restore with project ID" + if ! combined_mgs_mds ; then stop mgs fi diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 60e0ef4..44fa276 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -27833,6 +27833,69 @@ test_903() { } run_test 903 "Test long page discard does not cause evictions" +test_904() { + [ "$mds1_FSTYPE" == "ldiskfs" ] || skip "ldiskfs only test" + do_facet mds1 $DEBUGFS -R features $(mdsdevname 1) | + grep -q project || skip "skip project quota not supported" + + local testfile="$DIR/$tdir/$tfile" + local xattr="trusted.projid" + local projid + + mkdir -p $DIR/$tdir + touch $testfile + #should be hidden when projid is 0 + $LFS project -p 0 $testfile || + error "set $testfile project id failed" + getfattr -m - $testfile | grep $xattr && + error "do not show trusted.projid with project ID 0" + + #still can getxattr explicitly + projid=$(getfattr -n $xattr $testfile | + sed -n 's/^trusted\.projid="\(.*\)"/\1/p') + [ $projid == "0" ] || + error "projid expected 0 not $projid" + + #set the projid via setxattr + setfattr -n $xattr -v "1000" $testfile || + error "setattr failed with $?" + projid=($($LFS project $testfile)) + [ ${projid[0]} == "1000" ] || + error "projid expected 1000 not $projid" + + #check the new projid via getxattr + $LFS project -p 1001 $testfile || + error "set $testfile project id failed" + projid=$(getfattr -n $xattr $testfile | + sed -n 's/^trusted\.projid="\(.*\)"/\1/p') + [ $projid == "1001" ] || + error "projid expected 1001 not $projid" + + #try to set invalid projid + setfattr -n $xattr -v "4294967295" $testfile && + error "set invalid projid should fail" + + #remove the xattr means setting projid to 0 + setfattr -x $xattr $testfile || + error "setfattr failed with $?" + projid=($($LFS project $testfile)) + [ ${projid[0]} == "0" ] || + error "projid expected 0 not $projid" + + #should be hidden when parent has inherit flag and same projid + $LFS project -srp 1002 $DIR/$tdir || + error "set $tdir project id failed" + getfattr -m - $testfile | grep $xattr && + error "do not show trusted.projid with inherit flag" + + #still can getxattr explicitly + projid=$(getfattr -n $xattr $testfile | + sed -n 's/^trusted\.projid="\(.*\)"/\1/p') + [ $projid == "1002" ] || + error "projid expected 1002 not $projid" +} +run_test 904 "virtual project ID xattr" + complete $SECONDS [ -f $EXT2_DEV ] && rm $EXT2_DEV || true check_and_cleanup_lustre diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh index 7f2457d..f621ec5 100755 --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -8698,7 +8698,6 @@ mds_backup_restore() { local devname=$(mdsdevname $(facet_number $facet)) local mntpt=$(facet_mntpt brpt) local rcmd="do_facet $facet" - local metaea=${TMP}/backup_restore.ea local metadata=${TMP}/backup_restore.tgz local opts=${MDS_MOUNT_FS_OPTS} local svc=${facet}_svc @@ -8712,41 +8711,36 @@ mds_backup_restore() { # step 1: build mount point ${rcmd} mkdir -p $mntpt # step 2: cleanup old backup - ${rcmd} rm -f $metaea $metadata + ${rcmd} rm -f $metadata # step 3: mount dev - ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 1 + ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 3 if [ ! -z $igif ]; then # step 3.5: rm .lustre - ${rcmd} rm -rf $mntpt/ROOT/.lustre || return 1 + ${rcmd} rm -rf $mntpt/ROOT/.lustre || return 3 fi - # step 4: backup metaea - echo "backup EA" - ${rcmd} "cd $mntpt && getfattr -R -d -m '.*' -P . > $metaea && cd -" || - return 2 - # step 5: backup metadata + # step 4: backup metadata echo "backup data" - ${rcmd} tar zcf $metadata -C $mntpt/ . > /dev/null 2>&1 || return 3 - # step 6: umount - ${rcmd} $UMOUNT $mntpt || return 4 - # step 8: reformat dev + ${rcmd} tar zcf $metadata --xattrs --xattrs-include="trusted.*" \ + --sparse -C $mntpt/ . > /dev/null 2>&1 || return 4 + # step 5: umount + ${rcmd} $UMOUNT $mntpt || return 5 + # step 6: reformat dev echo "reformat new device" format_mdt $(facet_number $facet) - # step 9: mount dev + # step 7: mount dev ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 7 - # step 10: restore metadata + # step 8: restore metadata echo "restore data" - ${rcmd} tar zxfp $metadata -C $mntpt > /dev/null 2>&1 || return 8 - # step 11: restore metaea - echo "restore EA" - ${rcmd} "cd $mntpt && setfattr --restore=$metaea && cd - " || return 9 - # step 12: remove recovery logs + ${rcmd} tar zxfp $metadata --xattrs --xattrs-include="trusted.*" \ + --sparse -C $mntpt > /dev/null 2>&1 || return 8 + # step 9: remove recovery logs echo "remove recovery logs" ${rcmd} rm -fv $mntpt/OBJECTS/* $mntpt/CATALOGS - # step 13: umount dev + # step 10: umount dev ${rcmd} $UMOUNT $mntpt || return 10 - # step 14: cleanup tmp backup + # step 11: cleanup tmp backup ${rcmd} rm -f $metaea $metadata - # step 15: reset device label - it's not virgin on + # step 12: reset device label - it's not virgin on ${rcmd} e2label $devname ${!svc} } -- 1.8.3.1