mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
Inherit the project ID for every object type
zfs_mknode() only assigned a project ID to regular files and directories, so a symlink, device node, FIFO or socket created inside a directory with ZFS_PROJINHERIT set was left at ZFS_DEFAULT_PROJID. The cross-project checks in zfs_rename() and zfs_link() compare the object's project ID against the directory's, so such an object is treated as foreign to the very directory holding it, and cannot be renamed or linked there at all -- "ln -sfn", which creates the new symlink under a temporary name and renames it into place, fails with EXDEV. ext4 and XFS store a project ID on every inode type and so do not have this problem. Do the same, and quota-check new symlinks and rename whiteouts against the inherited ID rather than the default one, so their space is accounted to the project that owns them. This changes accounting for newly created objects: symlinks, device nodes and FIFOs now consume the project's quota where they previously consumed none, so on a dataset already at its project quota, creating one begins to fail with EDQUOT where it used to succeed. The space involved is small, but the change in behavior is visible. The ZFS_PROJINHERIT flag itself keeps propagating to regular files and directories only, leaving lsattr(1) output unchanged. Note that this only covers newly created objects; symlinks already on disk keep the default project ID. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Matt Turner <[email protected]> Closes #18932
This commit is contained in:
1 parent
df3ff37fc8
commit
e90badec11
4 files changed
+49
-43
No files matched your search
@@ -1107,8 +1107,7 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
|
||||
cr, vsecp, &acl_ids)) != 0)
|
||||
goto out;
|
||||
|
||||
if (S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode))
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, projid)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
error = SET_ERROR(EDQUOT);
|
||||
@@ -3651,7 +3650,7 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, ZFS_DEFAULT_PROJID)) {
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, zfs_inherit_projid(dzp))) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
zfs_exit(zfsvfs, FTAG);
|
||||
return (SET_ERROR(EDQUOT));
|
||||
|
||||
@@ -672,22 +672,28 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
|
||||
if (flag & IS_XATTR)
|
||||
pflags |= ZFS_XATTR;
|
||||
|
||||
if (vap->va_type == VREG || vap->va_type == VDIR) {
|
||||
/*
|
||||
* With ZFS_PROJID flag, we can easily know whether there is
|
||||
* project ID stored on disk or not. See zpl_get_file_info().
|
||||
*/
|
||||
if (obj_type != DMU_OT_ZNODE &&
|
||||
dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
pflags |= ZFS_PROJID;
|
||||
/*
|
||||
* With ZFS_PROJID flag, we can easily know whether there is
|
||||
* project ID stored on disk or not. See zpl_get_file_info().
|
||||
*/
|
||||
if (obj_type != DMU_OT_ZNODE &&
|
||||
dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
pflags |= ZFS_PROJID;
|
||||
|
||||
/*
|
||||
* Inherit project ID from parent if required.
|
||||
*/
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if (dzp_pflags & ZFS_PROJINHERIT)
|
||||
pflags |= ZFS_PROJINHERIT;
|
||||
}
|
||||
/*
|
||||
* Inherit project ID from parent if required. Every object type
|
||||
* takes part, as ext4 and XFS do: an object that carried no project
|
||||
* ID of its own would be treated as belonging to a different project
|
||||
* than the directory holding it, so zfs_rename() and zfs_link()
|
||||
* would refuse it with EXDEV even within its own project.
|
||||
*
|
||||
* The ZFS_PROJINHERIT flag itself keeps passing to regular files and
|
||||
* directories only, as before, so that lsattr(1) output is unchanged.
|
||||
*/
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if ((vap->va_type == VREG || vap->va_type == VDIR) &&
|
||||
(dzp_pflags & ZFS_PROJINHERIT))
|
||||
pflags |= ZFS_PROJINHERIT;
|
||||
|
||||
/*
|
||||
* No execs denied will be determined when zfs_mode_compute() is called.
|
||||
|
||||
@@ -725,8 +725,7 @@ top:
|
||||
goto out;
|
||||
have_acl = B_TRUE;
|
||||
|
||||
if (S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode))
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, projid)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
error = SET_ERROR(EDQUOT);
|
||||
@@ -925,8 +924,7 @@ top:
|
||||
goto out;
|
||||
have_acl = B_TRUE;
|
||||
|
||||
if (S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode))
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, projid)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
error = SET_ERROR(EDQUOT);
|
||||
@@ -3068,11 +3066,8 @@ top:
|
||||
|
||||
/* Set up inode creation for RENAME_WHITEOUT. */
|
||||
if (rflags & RENAME_WHITEOUT) {
|
||||
/*
|
||||
* Whiteout files are not regular files or directories, so to
|
||||
* match zfs_create() we do not inherit the project id.
|
||||
*/
|
||||
uint64_t wo_projid = ZFS_DEFAULT_PROJID;
|
||||
/* Match zfs_create(): the whiteout joins its directory. */
|
||||
uint64_t wo_projid = zfs_inherit_projid(sdzp);
|
||||
|
||||
error = zfs_zaccess_idmap(sdzp, ACE_ADD_FILE, 0, B_FALSE,
|
||||
cr, idmap);
|
||||
@@ -3409,7 +3404,7 @@ top:
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, ZFS_DEFAULT_PROJID)) {
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, zfs_inherit_projid(dzp))) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
zfs_dirent_unlock(dl);
|
||||
zfs_exit(zfsvfs, FTAG);
|
||||
|
||||
@@ -782,22 +782,28 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
|
||||
if (flag & IS_XATTR)
|
||||
pflags |= ZFS_XATTR;
|
||||
|
||||
if (S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode)) {
|
||||
/*
|
||||
* With ZFS_PROJID flag, we can easily know whether there is
|
||||
* project ID stored on disk or not. See zpl_get_file_info().
|
||||
*/
|
||||
if (obj_type != DMU_OT_ZNODE &&
|
||||
dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
pflags |= ZFS_PROJID;
|
||||
/*
|
||||
* With ZFS_PROJID flag, we can easily know whether there is
|
||||
* project ID stored on disk or not. See zpl_get_file_info().
|
||||
*/
|
||||
if (obj_type != DMU_OT_ZNODE &&
|
||||
dmu_objset_projectquota_enabled(zfsvfs->z_os))
|
||||
pflags |= ZFS_PROJID;
|
||||
|
||||
/*
|
||||
* Inherit project ID from parent if required.
|
||||
*/
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if (dzp->z_pflags & ZFS_PROJINHERIT)
|
||||
pflags |= ZFS_PROJINHERIT;
|
||||
}
|
||||
/*
|
||||
* Inherit project ID from parent if required. Every object type
|
||||
* takes part, as ext4 and XFS do: an object that carried no project
|
||||
* ID of its own would be treated as belonging to a different project
|
||||
* than the directory holding it, so zfs_rename() and zfs_link()
|
||||
* would refuse it with EXDEV even within its own project.
|
||||
*
|
||||
* The ZFS_PROJINHERIT flag itself keeps passing to regular files and
|
||||
* directories only, as before, so that lsattr(1) output is unchanged.
|
||||
*/
|
||||
projid = zfs_inherit_projid(dzp);
|
||||
if ((S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode)) &&
|
||||
(dzp->z_pflags & ZFS_PROJINHERIT))
|
||||
pflags |= ZFS_PROJINHERIT;
|
||||
|
||||
/*
|
||||
* No execs denied will be determined when zfs_mode_compute() is called.
|
||||
|
||||
Reference in new issue
Block a user