Whamcloud - gitweb
LU-12056 ldiskfs: add trusted.projid virtual xattr 79/45679/10
authorLi Dongyang <dongyangli@ddn.com>
Tue, 30 Nov 2021 01:13:03 +0000 (12:13 +1100)
committerOleg Drokin <green@whamcloud.com>
Thu, 6 Jan 2022 21:59:08 +0000 (21:59 +0000)
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 <dongyangli@ddn.com>
Reviewed-on: https://review.whamcloud.com/45679
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Yang Sheng <ys@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
37 files changed:
ldiskfs/kernel_patches/patches/base/ext4-projid-xattrs.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel7.6/ext4-projid-xattrs.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/ubuntu18/ext4-projid-xattrs.patch [new file with mode: 0644]
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.6.series
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.7.series
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.8.series
ldiskfs/kernel_patches/series/ldiskfs-3.10-rhel7.9.series
ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15-22.series
ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15.series
ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1-7.series
ldiskfs/kernel_patches/series/ldiskfs-4.12-sles15sp1.series
ldiskfs/kernel_patches/series/ldiskfs-4.15.0-20-ubuntu18.series
ldiskfs/kernel_patches/series/ldiskfs-4.15.0-24-ubuntu18.series
ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.1.series
ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.2.series
ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.3.series
ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.4.series
ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.5.series
ldiskfs/kernel_patches/series/ldiskfs-4.18-rhel8.series
ldiskfs/kernel_patches/series/ldiskfs-5.0.0-13-ubuntu19.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.0-42-ubuntu20.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.0-66-ubuntu20.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.0-80-ubuntu20.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.0-90-ubuntu20.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.0-ml.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.136-ml.series
ldiskfs/kernel_patches/series/ldiskfs-5.4.21-ml.series
ldiskfs/kernel_patches/series/ldiskfs-5.8.0-53-ubuntu20.series
ldiskfs/kernel_patches/series/ldiskfs-5.8.0-ml.series
ldiskfs/kernel_patches/series/ldiskfs-5.9.0-ml.series
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/llite/xattr.c
lustre/llite/xattr_cache.c
lustre/mdt/mdt_reint.c
lustre/tests/conf-sanity.sh
lustre/tests/sanity.sh
lustre/tests/test-framework.sh

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 (file)
index 0000000..95dbbf6
--- /dev/null
@@ -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 (file)
index 0000000..19ea98d
--- /dev/null
@@ -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 (file)
index 0000000..6af91eb
--- /dev/null
@@ -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;
index d051d3b..e4cc884 100644 (file)
@@ -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
 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
index da4cf53..b883ee9 100644 (file)
@@ -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
 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
index 8178924..72d308f 100644 (file)
@@ -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
 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
index dceb035..a50604c 100644 (file)
@@ -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
 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
index a4c776c..e8a8420 100644 (file)
@@ -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
 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
index b7bb0f6..c731d36 100644 (file)
@@ -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
 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
index a4c776c..e8a8420 100644 (file)
@@ -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
 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
index 2fc137d..a51161a 100644 (file)
@@ -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
 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
index 1c8f3c8..0d4b524 100644 (file)
@@ -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
 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
index 325f762..6a19aa3 100644 (file)
@@ -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
 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
index e18f0d9..d34d03d 100644 (file)
@@ -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
 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
index 9c53636..02d29aa 100644 (file)
@@ -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
 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
index b92964a..3a0ce31 100644 (file)
@@ -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
 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
index 7683149..9528ef5 100644 (file)
@@ -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
 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
index 7683149..9528ef5 100644 (file)
@@ -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
 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
index 9f91efd..f013041 100644 (file)
@@ -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
 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
index cfc1d66..b9b7674 100644 (file)
@@ -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
 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
index 25fb457..cd90a53 100644 (file)
@@ -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
 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
index e2c88e2..067d3fc 100644 (file)
@@ -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
 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
index a8eeb2f..556a59d 100644 (file)
@@ -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
 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
index beeecbd..26f1a70 100644 (file)
@@ -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
 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
index 9eee135..4407f21 100644 (file)
@@ -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
 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
index 6dad60c..668b6b1 100644 (file)
@@ -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
 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
index 25fb457..cd90a53 100644 (file)
@@ -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
 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
index f4ef984..fae39d6 100644 (file)
@@ -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
 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
index c09e847..4d3c0f4 100644 (file)
@@ -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
 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
index df7742e..aa62e8d 100644 (file)
@@ -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
 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
index 06bcb8d..175cf1f 100644 (file)
@@ -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_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"
 
 
 #define LL_XATTR_NAME_ENCRYPTION_CONTEXT XATTR_SECURITY_PREFIX"c"
 
index ca45354..6325c8a 100644 (file)
@@ -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)
 {
 
 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();
        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_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 :
                len = strnlen(xattr_name, rem - 1) + 1;
                rem -= len;
                if (!xattr_type_filter(sbi, hide_xattr ? NULL :
index a42329d..ce3e3a7 100644 (file)
@@ -610,6 +610,21 @@ int ll_xattr_cache_get(struct inode *inode,
                                else
                                        rc = -ERANGE;
                        }
                                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,
                }
        } else if (valid & OBD_MD_FLXATTRLS) {
                rc = ll_xattr_cache_list(&lli->lli_xattrs,
index 0e662cf..8b36314 100644 (file)
@@ -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;
         */
        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);
 
        rc = mdt_reint_striped_lock(info, mo, lh, lockpart, einfo,
                                    cos_incompat);
index 5205d4b..d65c75d 100644 (file)
@@ -9324,6 +9324,53 @@ test_130()
 }
 run_test 130 "re-register an MDT after writeconf"
 
 }
 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
 if ! combined_mgs_mds ; then
        stop mgs
 fi
index 60e0ef4..44fa276 100755 (executable)
@@ -27833,6 +27833,69 @@ test_903() {
 }
 run_test 903 "Test long page discard does not cause evictions"
 
 }
 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
 complete $SECONDS
 [ -f $EXT2_DEV ] && rm $EXT2_DEV || true
 check_and_cleanup_lustre
index 7f2457d..f621ec5 100755 (executable)
@@ -8698,7 +8698,6 @@ mds_backup_restore() {
        local devname=$(mdsdevname $(facet_number $facet))
        local mntpt=$(facet_mntpt brpt)
        local rcmd="do_facet $facet"
        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
        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
        # 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
        # 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
        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
        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"
        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)
        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
        ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 7
-       # step 10: restore metadata
+       # step 8: restore metadata
        echo "restore data"
        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
        echo "remove recovery logs"
        ${rcmd} rm -fv $mntpt/OBJECTS/* $mntpt/CATALOGS
-       # step 13: umount dev
+       # step 10: umount dev
        ${rcmd} $UMOUNT $mntpt || return 10
        ${rcmd} $UMOUNT $mntpt || return 10
-       # step 14: cleanup tmp backup
+       # step 11: cleanup tmp backup
        ${rcmd} rm -f $metaea $metadata
        ${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}
 }
 
        ${rcmd} e2label $devname ${!svc}
 }