* [RFC PATCH 0/3] tmpfs: Add tmpfs project quota support @ 2023-09-25 13:00 cem 2023-09-25 13:00 ` [PATCH 1/3] tmpfs: add project ID support cem ` (2 more replies) 0 siblings, 3 replies; 10+ messages in thread From: cem @ 2023-09-25 13:00 UTC (permalink / raw) To: linux-fsdevel; +Cc: hughd, brauner, jack From: Carlos Maiolino <cem@kernel.org> Hi, this is my first implementation attempt of project quotas on tmpfs, this is not complete yet, it should still have statfs implementation and default block/inode limits mount options for prjquota, other than that this series already make prjquotas functional for tmpfs. I'm sending this on early stage so maybe Jan, Hugh and Christian could comment on it as they were in the loop during quota implementation for tmpfs. So maybe you guys could take a look on it and give me your PoV? Thanks Carlos Maiolino (3): tmpfs: add project ID support tmpfs: Add project quota mount option tmpfs: Add project quota interface support for get/set attr include/linux/shmem_fs.h | 13 ++++++---- mm/shmem.c | 52 ++++++++++++++++++++++++++++++++++++---- mm/shmem_quota.c | 10 ++++++++ 3 files changed, 66 insertions(+), 9 deletions(-) Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> -- 2.39.2 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/3] tmpfs: add project ID support 2023-09-25 13:00 [RFC PATCH 0/3] tmpfs: Add tmpfs project quota support cem @ 2023-09-25 13:00 ` cem 2023-10-03 11:23 ` Jan Kara 2023-09-25 13:00 ` [PATCH 2/3] tmpfs: Add project quota mount option cem 2023-09-25 13:00 ` [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr cem 2 siblings, 1 reply; 10+ messages in thread From: cem @ 2023-09-25 13:00 UTC (permalink / raw) To: linux-fsdevel; +Cc: hughd, brauner, jack From: Carlos Maiolino <cem@kernel.org> Lay down infrastructure to support project quotas. Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> --- include/linux/shmem_fs.h | 11 ++++++++--- mm/shmem.c | 6 ++++++ mm/shmem_quota.c | 10 ++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index 6b0c626620f5..e82a64f97917 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -15,7 +15,10 @@ #ifdef CONFIG_TMPFS_QUOTA #define SHMEM_MAXQUOTAS 2 -#endif + +/* Default project ID */ +#define SHMEM_DEF_PROJID 0 +#endif /* CONFIG_TMPFS_QUOTA */ struct shmem_inode_info { spinlock_t lock; @@ -33,14 +36,16 @@ struct shmem_inode_info { unsigned int fsflags; /* flags for FS_IOC_[SG]ETFLAGS */ #ifdef CONFIG_TMPFS_QUOTA struct dquot *i_dquot[MAXQUOTAS]; + kprojid_t i_projid; #endif struct offset_ctx dir_offsets; /* stable entry offsets */ struct inode vfs_inode; }; -#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE +#define SHMEM_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL) #define SHMEM_FL_USER_MODIFIABLE \ - (FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL) + (FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | \ + FS_NOATIME_FL | FS_PROJINHERIT_FL) #define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL) struct shmem_quota_limits { diff --git a/mm/shmem.c b/mm/shmem.c index 67d93dd37a5e..6ccf60bd1690 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2539,6 +2539,12 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap, if (IS_ERR(inode)) return inode; + if (dir && sb_has_quota_active(sb, PRJQUOTA)) + SHMEM_I(inode)->i_projid = SHMEM_I(dir)->i_projid; + else + SHMEM_I(inode)->i_projid = make_kprojid(&init_user_ns, + SHMEM_DEF_PROJID); + err = dquot_initialize(inode); if (err) goto errout; diff --git a/mm/shmem_quota.c b/mm/shmem_quota.c index 062d1c1097ae..71224caa3e85 100644 --- a/mm/shmem_quota.c +++ b/mm/shmem_quota.c @@ -325,6 +325,15 @@ static int shmem_dquot_write_info(struct super_block *sb, int type) return 0; } +static int shmem_get_projid(struct inode *inode, kprojid_t *projid) +{ + if (!sb_has_quota_active(inode->i_sb, PRJQUOTA)) + return -EOPNOTSUPP; + + *projid = SHMEM_I(inode)->i_projid; + return 0; +} + static const struct quota_format_ops shmem_format_ops = { .check_quota_file = shmem_check_quota_file, .read_file_info = shmem_read_file_info, @@ -346,5 +355,6 @@ const struct dquot_operations shmem_quota_operations = { .write_info = shmem_dquot_write_info, .mark_dirty = shmem_mark_dquot_dirty, .get_next_id = shmem_get_next_id, + .get_projid = shmem_get_projid, }; #endif /* CONFIG_TMPFS_QUOTA */ -- 2.39.2 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/3] tmpfs: add project ID support 2023-09-25 13:00 ` [PATCH 1/3] tmpfs: add project ID support cem @ 2023-10-03 11:23 ` Jan Kara 0 siblings, 0 replies; 10+ messages in thread From: Jan Kara @ 2023-10-03 11:23 UTC (permalink / raw) To: cem; +Cc: linux-fsdevel, hughd, brauner, jack On Mon 25-09-23 15:00:26, cem@kernel.org wrote: > From: Carlos Maiolino <cem@kernel.org> > > Lay down infrastructure to support project quotas. > > Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> > --- > include/linux/shmem_fs.h | 11 ++++++++--- > mm/shmem.c | 6 ++++++ > mm/shmem_quota.c | 10 ++++++++++ > 3 files changed, 24 insertions(+), 3 deletions(-) > > diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h > index 6b0c626620f5..e82a64f97917 100644 > --- a/include/linux/shmem_fs.h > +++ b/include/linux/shmem_fs.h > @@ -15,7 +15,10 @@ > > #ifdef CONFIG_TMPFS_QUOTA > #define SHMEM_MAXQUOTAS 2 > -#endif > + > +/* Default project ID */ > +#define SHMEM_DEF_PROJID 0 > +#endif /* CONFIG_TMPFS_QUOTA */ > > struct shmem_inode_info { > spinlock_t lock; > @@ -33,14 +36,16 @@ struct shmem_inode_info { > unsigned int fsflags; /* flags for FS_IOC_[SG]ETFLAGS */ > #ifdef CONFIG_TMPFS_QUOTA > struct dquot *i_dquot[MAXQUOTAS]; > + kprojid_t i_projid; > #endif I'm not sure it is great to bind project ID support with CONFIG_TMPFS_QUOTA and in particular with sb_has_quota_active(sb, PRJQUOTA). It seems as a bit unnatural restriction that could confuse administrators. > struct offset_ctx dir_offsets; /* stable entry offsets */ > struct inode vfs_inode; > }; > > -#define SHMEM_FL_USER_VISIBLE FS_FL_USER_VISIBLE > +#define SHMEM_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL) > #define SHMEM_FL_USER_MODIFIABLE \ > - (FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | FS_NOATIME_FL) > + (FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | \ > + FS_NOATIME_FL | FS_PROJINHERIT_FL) > #define SHMEM_FL_INHERITED (FS_NODUMP_FL | FS_NOATIME_FL) > > struct shmem_quota_limits { > diff --git a/mm/shmem.c b/mm/shmem.c > index 67d93dd37a5e..6ccf60bd1690 100644 > --- a/mm/shmem.c > +++ b/mm/shmem.c > @@ -2539,6 +2539,12 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap, > if (IS_ERR(inode)) > return inode; > > + if (dir && sb_has_quota_active(sb, PRJQUOTA)) > + SHMEM_I(inode)->i_projid = SHMEM_I(dir)->i_projid; > + else > + SHMEM_I(inode)->i_projid = make_kprojid(&init_user_ns, > + SHMEM_DEF_PROJID); > + > err = dquot_initialize(inode); > if (err) > goto errout; > diff --git a/mm/shmem_quota.c b/mm/shmem_quota.c > index 062d1c1097ae..71224caa3e85 100644 > --- a/mm/shmem_quota.c > +++ b/mm/shmem_quota.c > @@ -325,6 +325,15 @@ static int shmem_dquot_write_info(struct super_block *sb, int type) > return 0; > } > > +static int shmem_get_projid(struct inode *inode, kprojid_t *projid) > +{ > + if (!sb_has_quota_active(inode->i_sb, PRJQUOTA)) > + return -EOPNOTSUPP; This is not needed as quota code ever calls ->get_projid only when project quotas are enabled... Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/3] tmpfs: Add project quota mount option 2023-09-25 13:00 [RFC PATCH 0/3] tmpfs: Add tmpfs project quota support cem 2023-09-25 13:00 ` [PATCH 1/3] tmpfs: add project ID support cem @ 2023-09-25 13:00 ` cem 2023-09-25 13:00 ` [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr cem 2 siblings, 0 replies; 10+ messages in thread From: cem @ 2023-09-25 13:00 UTC (permalink / raw) To: linux-fsdevel; +Cc: hughd, brauner, jack From: Carlos Maiolino <cem@kernel.org> Enable tmpfs filesystems to be mounted using project quotas. Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> --- include/linux/shmem_fs.h | 2 +- mm/shmem.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index e82a64f97917..c897cb6a70a2 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h @@ -14,7 +14,7 @@ /* inode in-kernel data */ #ifdef CONFIG_TMPFS_QUOTA -#define SHMEM_MAXQUOTAS 2 +#define SHMEM_MAXQUOTAS 3 /* Default project ID */ #define SHMEM_DEF_PROJID 0 diff --git a/mm/shmem.c b/mm/shmem.c index 6ccf60bd1690..4d2b713bff06 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3865,6 +3865,7 @@ enum shmem_param { Opt_quota, Opt_usrquota, Opt_grpquota, + Opt_prjquota, Opt_usrquota_block_hardlimit, Opt_usrquota_inode_hardlimit, Opt_grpquota_block_hardlimit, @@ -3895,6 +3896,7 @@ const struct fs_parameter_spec shmem_fs_parameters[] = { fsparam_flag ("quota", Opt_quota), fsparam_flag ("usrquota", Opt_usrquota), fsparam_flag ("grpquota", Opt_grpquota), + fsparam_flag ("prjquota", Opt_prjquota), fsparam_string("usrquota_block_hardlimit", Opt_usrquota_block_hardlimit), fsparam_string("usrquota_inode_hardlimit", Opt_usrquota_inode_hardlimit), fsparam_string("grpquota_block_hardlimit", Opt_grpquota_block_hardlimit), @@ -4029,6 +4031,12 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param) ctx->seen |= SHMEM_SEEN_QUOTA; ctx->quota_types |= QTYPE_MASK_GRP; break; + case Opt_prjquota: + if (fc->user_ns != &init_user_ns) + return invalfc(fc, "Quotas in unprivileged tmpfs mounts are unsupported"); + ctx->seen |= SHMEM_SEEN_QUOTA; + ctx->quota_types |= QTYPE_MASK_PRJ; + break; case Opt_usrquota_block_hardlimit: size = memparse(param->string, &rest); if (*rest || !size) @@ -4363,7 +4371,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc) if (ctx->seen & SHMEM_SEEN_QUOTA) { sb->dq_op = &shmem_quota_operations; sb->s_qcop = &dquot_quotactl_sysfile_ops; - sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; + sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | + QTYPE_MASK_PRJ; /* Copy the default limits from ctx into sbinfo */ memcpy(&sbinfo->qlimits, &ctx->qlimits, -- 2.39.2 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr 2023-09-25 13:00 [RFC PATCH 0/3] tmpfs: Add tmpfs project quota support cem 2023-09-25 13:00 ` [PATCH 1/3] tmpfs: add project ID support cem 2023-09-25 13:00 ` [PATCH 2/3] tmpfs: Add project quota mount option cem @ 2023-09-25 13:00 ` cem 2023-09-26 20:28 ` Andreas Dilger ` (2 more replies) 2 siblings, 3 replies; 10+ messages in thread From: cem @ 2023-09-25 13:00 UTC (permalink / raw) To: linux-fsdevel; +Cc: hughd, brauner, jack From: Carlos Maiolino <cem@kernel.org> Not project quota support is in place, enable users to use it. Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> --- mm/shmem.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 4d2b713bff06..744a39251a31 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3571,6 +3571,23 @@ static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa) fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE); + fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); + return 0; +} + +static int shmem_set_project(struct inode *inode, __u32 projid) +{ + int err = -EOPNOTSUPP; + kprojid_t kprojid = make_kprojid(&init_user_ns, (projid_t)projid); + + if (projid_eq(kprojid, SHMEM_I(inode)->i_projid)) + return 0; + + err = dquot_initialize(inode); + if (err) + return err; + + SHMEM_I(inode)->i_projid = kprojid; return 0; } @@ -3579,19 +3596,29 @@ static int shmem_fileattr_set(struct mnt_idmap *idmap, { struct inode *inode = d_inode(dentry); struct shmem_inode_info *info = SHMEM_I(inode); + int err = -EOPNOTSUPP; + + if (fa->fsx_valid && + ((fa->fsx_xflags & ~FS_XFLAG_COMMON) || + fa->fsx_extsize != 0 || fa->fsx_cowextsize != 0)) + goto out; - if (fileattr_has_fsx(fa)) - return -EOPNOTSUPP; if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE) - return -EOPNOTSUPP; + goto out; info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) | (fa->flags & SHMEM_FL_USER_MODIFIABLE); shmem_set_inode_flags(inode, info->fsflags); + err = shmem_set_project(inode, fa->fsx_projid); + if (err) + goto out; + inode_set_ctime_current(inode); inode_inc_iversion(inode); - return 0; + +out: + return err; } /* -- 2.39.2 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr 2023-09-25 13:00 ` [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr cem @ 2023-09-26 20:28 ` Andreas Dilger 2023-09-27 1:09 ` Dave Chinner 2023-09-27 12:48 ` Carlos Maiolino 2023-09-26 21:35 ` kernel test robot 2023-10-02 8:41 ` kernel test robot 2 siblings, 2 replies; 10+ messages in thread From: Andreas Dilger @ 2023-09-26 20:28 UTC (permalink / raw) To: cem; +Cc: linux-fsdevel, Hugh Dickins, Christian Brauner, Jan Kara, Dave Chinner [-- Attachment #1: Type: text/plain, Size: 5690 bytes --] I've added Dave to the CC list, since he has a deep understanding of the projid code since it originated from XFS. On Sep 25, 2023, at 7:00 AM, cem@kernel.org wrote: > > From: Carlos Maiolino <cem@kernel.org> > > Not project quota support is in place, enable users to use it. There is a peculiar behavior of project quotas, that rename across directories with different project IDs and PROJINHERIT set should cause the project ID to be updated (similar to BSD setgid). For renaming regular files and other non-directories, it is OK to change the projid and update the quota for the old and new IDs to avoid copying all of the data needlessly. For directories this (unfortunately) means that the kernel should return -EXDEV if the project IDs don't match, and then "mv" will create a new target directory and resume moving the files (which are thankfully still done with a rename() call if possible). The reason for this is that just renaming the directory does not atomically update the projid on all of the (possibly millions of) sub-files/sub-dirs, which is required for PROJINHERIT directories. Another option for tmpfs to maintain this PROJINHERIT behavior would be to rename the directory and then spawn a background kernel thread to change the projids on the whole tree. Since tmpfs is an in-memory filesystem there will be a "limited" number of files and subdirs to update, and you don't need to worry about error handling if the system crashes before the projid updates are done. While not 100% atomic, it is not *less* atomic than having "mv" recursively copy the whole directory tree to the target name when the projid on the source and target don't match. It is also a *lot* less overhead than doing a million mkdir() + rename() calls. There would be a risk that the target directory projid could go over quota, but the alternative (that "mv" is half-way between moving the directory tree from the source to the destination before it fails, or fills up the filesystem because it can't hold another full copy of the tree being renamed) is not better. > > Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> > --- > mm/shmem.c | 35 +++++++++++++++++++++++++++++++---- > 1 file changed, 31 insertions(+), 4 deletions(-) > > diff --git a/mm/shmem.c b/mm/shmem.c > index 4d2b713bff06..744a39251a31 100644 > --- a/mm/shmem.c > +++ b/mm/shmem.c > @@ -3571,6 +3571,23 @@ static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa) > > fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE); > > + fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); > + return 0; > +} > + > +static int shmem_set_project(struct inode *inode, __u32 projid) > +{ > + int err = -EOPNOTSUPP; > + kprojid_t kprojid = make_kprojid(&init_user_ns, (projid_t)projid); > + > + if (projid_eq(kprojid, SHMEM_I(inode)->i_projid)) > + return 0; > + > + err = dquot_initialize(inode); > + if (err) > + return err; > + > + SHMEM_I(inode)->i_projid = kprojid; > return 0; > } (defect) this also needs to __dquot_transfer() the quota away from the previous projid, or the accounting will be broken. I think one hole in project quotas is the fact that any user can set the projid of their files to any project they want. Changing the projid/PROJINHERIT is restricted outside of the init namespace by fileattr_set_prepare(), which is good in itself, but I think it makes sense for root/CAP_SYS_RESOURCE to be needed to change projid/PROJINHERIT even in the init namespace. Otherwise project quota is only an estimate of space usage in a directory, if users are not actively subverting it. > @@ -3579,19 +3596,29 @@ static int shmem_fileattr_set(struct mnt_idmap *idmap, > { > struct inode *inode = d_inode(dentry); > struct shmem_inode_info *info = SHMEM_I(inode); > + int err = -EOPNOTSUPP; > + > + if (fa->fsx_valid && > + ((fa->fsx_xflags & ~FS_XFLAG_COMMON) || > + fa->fsx_extsize != 0 || fa->fsx_cowextsize != 0)) > + goto out; > > - if (fileattr_has_fsx(fa)) > - return -EOPNOTSUPP; > if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE) > - return -EOPNOTSUPP; > + goto out; > > info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) | > (fa->flags & SHMEM_FL_USER_MODIFIABLE); > > shmem_set_inode_flags(inode, info->fsflags); > + err = shmem_set_project(inode, fa->fsx_projid); > + if (err) > + goto out; > + > inode_set_ctime_current(inode); > inode_inc_iversion(inode); > - return 0; > + > +out: > + return err; > } There were also some patches to add projid support to statx() that didn't quite get merged: https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449184-7942-3-git-send-email-wshilong1991@gmail.com/ https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449184-7942-2-git-send-email-wshilong1991@gmail.com/ https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-6-git-send-email-wshilong1991@gmail.com/ https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-7-git-send-email-wshilong1991@gmail.com/ https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-8-git-send-email-wshilong1991@gmail.com/ https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-9-git-send-email-wshilong1991@gmail.com/ They were part of a larger series to allow setting projid directly with the fchownat(2), but that got bogged down in how the interface should work, and whether i_projid should be moved to struct inode, but I think the statx() functionality was uncontroversial and could land as-is. Cheers, Andreas [-- Attachment #2: Message signed with OpenPGP --] [-- Type: application/pgp-signature, Size: 873 bytes --] ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr 2023-09-26 20:28 ` Andreas Dilger @ 2023-09-27 1:09 ` Dave Chinner 2023-09-27 12:48 ` Carlos Maiolino 1 sibling, 0 replies; 10+ messages in thread From: Dave Chinner @ 2023-09-27 1:09 UTC (permalink / raw) To: Andreas Dilger Cc: cem, linux-fsdevel, Hugh Dickins, Christian Brauner, Jan Kara On Tue, Sep 26, 2023 at 02:28:06PM -0600, Andreas Dilger wrote: > I've added Dave to the CC list, since he has a deep understanding > of the projid code since it originated from XFS. > > On Sep 25, 2023, at 7:00 AM, cem@kernel.org wrote: > > > > From: Carlos Maiolino <cem@kernel.org> > > > > Not project quota support is in place, enable users to use it. > > There is a peculiar behavior of project quotas, that rename across > directories with different project IDs and PROJINHERIT set should > cause the project ID to be updated (similar to BSD setgid). > > For renaming regular files and other non-directories, it is OK to > change the projid and update the quota for the old and new IDs > to avoid copying all of the data needlessly. For directories this > (unfortunately) means that the kernel should return -EXDEV if the > project IDs don't match, and then "mv" will create a new target > directory and resume moving the files (which are thankfully still > done with a rename() call if possible). > > The reason for this is that just renaming the directory does not > atomically update the projid on all of the (possibly millions of) > sub-files/sub-dirs, which is required for PROJINHERIT directories. Yup, PROJINHERIT implies that project quotas are being used to implement directory tree quotas, hence everything in the destination directory should have the same projid as the parent. This code in xfs_rename() implements that restriction: /* * If we are using project inheritance, we only allow renames * into our tree when the project IDs are the same; else the * tree quota mechanism would be circumvented. */ if (unlikely((target_dp->i_diflags & XFS_DIFLAG_PROJINHERIT) && target_dp->i_projid != src_ip->i_projid)) { error = -EXDEV; goto out_trans_cancel; } > Another option for tmpfs to maintain this PROJINHERIT behavior would > be to rename the directory and then spawn a background kernel thread > to change the projids on the whole tree. Since tmpfs is an in-memory > filesystem there will be a "limited" number of files and subdirs > to update, and you don't need to worry about error handling if the > system crashes before the projid updates are done. Except that can get EDQUOT half way through and now there's nothing to report the ENOSPC error to, nor any way that the application can interrupt and/or recover the situation. I think that's a non-starter. And, quite frankly, it's also massive feature creep as well as premature optimisation. We don't need tmpfs project quotas to be "smart" like this; we just need the initial support patch set to -do the right thing-. -Dave. -- Dave Chinner david@fromorbit.com ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr 2023-09-26 20:28 ` Andreas Dilger 2023-09-27 1:09 ` Dave Chinner @ 2023-09-27 12:48 ` Carlos Maiolino 1 sibling, 0 replies; 10+ messages in thread From: Carlos Maiolino @ 2023-09-27 12:48 UTC (permalink / raw) To: Andreas Dilger Cc: linux-fsdevel, Hugh Dickins, Christian Brauner, Jan Kara, Dave Chinner On Tue, Sep 26, 2023 at 02:28:06PM -0600, Andreas Dilger wrote: > I've added Dave to the CC list, since he has a deep understanding > of the projid code since it originated from XFS. > > On Sep 25, 2023, at 7:00 AM, cem@kernel.org wrote: > > > > From: Carlos Maiolino <cem@kernel.org> > > > > Not project quota support is in place, enable users to use it. > > There is a peculiar behavior of project quotas, that rename across > directories with different project IDs and PROJINHERIT set should > cause the project ID to be updated (similar to BSD setgid). > > For renaming regular files and other non-directories, it is OK to > change the projid and update the quota for the old and new IDs > to avoid copying all of the data needlessly. For directories this > (unfortunately) means that the kernel should return -EXDEV if the > project IDs don't match, and then "mv" will create a new target > directory and resume moving the files (which are thankfully still > done with a rename() call if possible). Right! I meant to include it on the TODO list of things, but I totally forgot to do so, thanks for reminding me! > > The reason for this is that just renaming the directory does not > atomically update the projid on all of the (possibly millions of) > sub-files/sub-dirs, which is required for PROJINHERIT directories. > > > Another option for tmpfs to maintain this PROJINHERIT behavior would > be to rename the directory and then spawn a background kernel thread > to change the projids on the whole tree. Since tmpfs is an in-memory > filesystem there will be a "limited" number of files and subdirs > to update, and you don't need to worry about error handling if the > system crashes before the projid updates are done. > > While not 100% atomic, it is not *less* atomic than having "mv" > recursively copy the whole directory tree to the target name when > the projid on the source and target don't match. It is also a > *lot* less overhead than doing a million mkdir() + rename() calls. > > There would be a risk that the target directory projid could go over > quota, but the alternative (that "mv" is half-way between moving the > directory tree from the source to the destination before it fails, > or fills up the filesystem because it can't hold another full copy > of the tree being renamed) is not better. I will look into these while I work on a non-rfc version of this series. Thanks Andreas. Carlos > > > > > Signed-off-by: Carlos Maiolino <cmaiolino@redhat.com> > > --- > > mm/shmem.c | 35 +++++++++++++++++++++++++++++++---- > > 1 file changed, 31 insertions(+), 4 deletions(-) > > > > diff --git a/mm/shmem.c b/mm/shmem.c > > index 4d2b713bff06..744a39251a31 100644 > > --- a/mm/shmem.c > > +++ b/mm/shmem.c > > @@ -3571,6 +3571,23 @@ static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa) > > > > fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE); > > > > + fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); > > + return 0; > > +} > > + > > +static int shmem_set_project(struct inode *inode, __u32 projid) > > +{ > > + int err = -EOPNOTSUPP; > > + kprojid_t kprojid = make_kprojid(&init_user_ns, (projid_t)projid); > > + > > + if (projid_eq(kprojid, SHMEM_I(inode)->i_projid)) > > + return 0; > > + > > + err = dquot_initialize(inode); > > + if (err) > > + return err; > > + > > + SHMEM_I(inode)->i_projid = kprojid; > > return 0; > > } > > (defect) this also needs to __dquot_transfer() the quota away from the > previous projid, or the accounting will be broken. > > > I think one hole in project quotas is the fact that any user can set > the projid of their files to any project they want. Changing the projid/PROJINHERIT is restricted outside of the init namespace by > fileattr_set_prepare(), which is good in itself, but I think it makes > sense for root/CAP_SYS_RESOURCE to be needed to change projid/PROJINHERIT > even in the init namespace. Otherwise project quota is only an estimate > of space usage in a directory, if users are not actively subverting it. > > > @@ -3579,19 +3596,29 @@ static int shmem_fileattr_set(struct mnt_idmap *idmap, > > { > > struct inode *inode = d_inode(dentry); > > struct shmem_inode_info *info = SHMEM_I(inode); > > + int err = -EOPNOTSUPP; > > + > > + if (fa->fsx_valid && > > + ((fa->fsx_xflags & ~FS_XFLAG_COMMON) || > > + fa->fsx_extsize != 0 || fa->fsx_cowextsize != 0)) > > + goto out; > > > > - if (fileattr_has_fsx(fa)) > > - return -EOPNOTSUPP; > > if (fa->flags & ~SHMEM_FL_USER_MODIFIABLE) > > - return -EOPNOTSUPP; > > + goto out; > > > > info->fsflags = (info->fsflags & ~SHMEM_FL_USER_MODIFIABLE) | > > (fa->flags & SHMEM_FL_USER_MODIFIABLE); > > > > shmem_set_inode_flags(inode, info->fsflags); > > + err = shmem_set_project(inode, fa->fsx_projid); > > + if (err) > > + goto out; > > + > > inode_set_ctime_current(inode); > > inode_inc_iversion(inode); > > - return 0; > > + > > +out: > > + return err; > > } > > > > There were also some patches to add projid support to statx() that didn't > quite get merged: > > https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449184-7942-3-git-send-email-wshilong1991@gmail.com/ > https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449184-7942-2-git-send-email-wshilong1991@gmail.com/ > https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-6-git-send-email-wshilong1991@gmail.com/ > https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-7-git-send-email-wshilong1991@gmail.com/ > https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-8-git-send-email-wshilong1991@gmail.com/ > https://patchwork.ozlabs.org/project/linux-ext4/patch/1551449141-7884-9-git-send-email-wshilong1991@gmail.com/ > > They were part of a larger series to allow setting projid directly with > the fchownat(2), but that got bogged down in how the interface should > work, and whether i_projid should be moved to struct inode, but I think > the statx() functionality was uncontroversial and could land as-is. > > Cheers, Andreas > > > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr 2023-09-25 13:00 ` [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr cem 2023-09-26 20:28 ` Andreas Dilger @ 2023-09-26 21:35 ` kernel test robot 2023-10-02 8:41 ` kernel test robot 2 siblings, 0 replies; 10+ messages in thread From: kernel test robot @ 2023-09-26 21:35 UTC (permalink / raw) To: cem, linux-fsdevel; +Cc: oe-kbuild-all, hughd, brauner, jack Hi, kernel test robot noticed the following build errors: [auto build test ERROR on akpm-mm/mm-everything] [also build test ERROR on linus/master v6.6-rc3 next-20230926] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/cem-kernel-org/tmpfs-add-project-ID-support/20230925-210238 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20230925130028.1244740-4-cem%40kernel.org patch subject: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr config: arc-randconfig-001-20230926 (https://download.01.org/0day-ci/archive/20230927/202309270552.A4zwjPrB-lkp@intel.com/config) compiler: arceb-elf-gcc (GCC) 13.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230927/202309270552.A4zwjPrB-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202309270552.A4zwjPrB-lkp@intel.com/ All errors (new ones prefixed by >>): mm/shmem.c: In function 'shmem_fileattr_get': >> mm/shmem.c:3574:63: error: 'struct shmem_inode_info' has no member named 'i_projid' 3574 | fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); | ^~ mm/shmem.c: In function 'shmem_set_project': mm/shmem.c:3583:46: error: 'struct shmem_inode_info' has no member named 'i_projid' 3583 | if (projid_eq(kprojid, SHMEM_I(inode)->i_projid)) | ^~ mm/shmem.c:3590:23: error: 'struct shmem_inode_info' has no member named 'i_projid' 3590 | SHMEM_I(inode)->i_projid = kprojid; | ^~ vim +3574 mm/shmem.c 3567 3568 static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa) 3569 { 3570 struct shmem_inode_info *info = SHMEM_I(d_inode(dentry)); 3571 3572 fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE); 3573 > 3574 fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); 3575 return 0; 3576 } 3577 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr 2023-09-25 13:00 ` [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr cem 2023-09-26 20:28 ` Andreas Dilger 2023-09-26 21:35 ` kernel test robot @ 2023-10-02 8:41 ` kernel test robot 2 siblings, 0 replies; 10+ messages in thread From: kernel test robot @ 2023-10-02 8:41 UTC (permalink / raw) To: cem, linux-fsdevel; +Cc: llvm, oe-kbuild-all, hughd, brauner, jack Hi, kernel test robot noticed the following build errors: [auto build test ERROR on akpm-mm/mm-everything] [also build test ERROR on linus/master v6.6-rc4 next-20230929] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/cem-kernel-org/tmpfs-add-project-ID-support/20230925-210238 base: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything patch link: https://lore.kernel.org/r/20230925130028.1244740-4-cem%40kernel.org patch subject: [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr config: arm-sp7021_defconfig (https://download.01.org/0day-ci/archive/20231002/202310021602.dvZVjyMh-lkp@intel.com/config) compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231002/202310021602.dvZVjyMh-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202310021602.dvZVjyMh-lkp@intel.com/ All errors (new ones prefixed by >>): >> mm/shmem.c:3574:58: error: no member named 'i_projid' in 'struct shmem_inode_info' 3574 | fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); | ~~~~ ^ mm/shmem.c:3583:41: error: no member named 'i_projid' in 'struct shmem_inode_info' 3583 | if (projid_eq(kprojid, SHMEM_I(inode)->i_projid)) | ~~~~~~~~~~~~~~ ^ mm/shmem.c:3590:18: error: no member named 'i_projid' in 'struct shmem_inode_info' 3590 | SHMEM_I(inode)->i_projid = kprojid; | ~~~~~~~~~~~~~~ ^ 3 errors generated. vim +3574 mm/shmem.c 3567 3568 static int shmem_fileattr_get(struct dentry *dentry, struct fileattr *fa) 3569 { 3570 struct shmem_inode_info *info = SHMEM_I(d_inode(dentry)); 3571 3572 fileattr_fill_flags(fa, info->fsflags & SHMEM_FL_USER_VISIBLE); 3573 > 3574 fa->fsx_projid = (u32)from_kprojid(&init_user_ns, info->i_projid); 3575 return 0; 3576 } 3577 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-10-03 11:23 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-09-25 13:00 [RFC PATCH 0/3] tmpfs: Add tmpfs project quota support cem 2023-09-25 13:00 ` [PATCH 1/3] tmpfs: add project ID support cem 2023-10-03 11:23 ` Jan Kara 2023-09-25 13:00 ` [PATCH 2/3] tmpfs: Add project quota mount option cem 2023-09-25 13:00 ` [PATCH 3/3] tmpfs: Add project quota interface support for get/set attr cem 2023-09-26 20:28 ` Andreas Dilger 2023-09-27 1:09 ` Dave Chinner 2023-09-27 12:48 ` Carlos Maiolino 2023-09-26 21:35 ` kernel test robot 2023-10-02 8:41 ` kernel test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).