162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2006 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_log_format.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_quota.h" 1362306a36Sopenharmony_ci#include "xfs_mount.h" 1462306a36Sopenharmony_ci#include "xfs_inode.h" 1562306a36Sopenharmony_ci#include "xfs_trans.h" 1662306a36Sopenharmony_ci#include "xfs_qm.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciSTATIC void 2062306a36Sopenharmony_cixfs_fill_statvfs_from_dquot( 2162306a36Sopenharmony_ci struct kstatfs *statp, 2262306a36Sopenharmony_ci struct xfs_dquot *dqp) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci uint64_t limit; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci limit = dqp->q_blk.softlimit ? 2762306a36Sopenharmony_ci dqp->q_blk.softlimit : 2862306a36Sopenharmony_ci dqp->q_blk.hardlimit; 2962306a36Sopenharmony_ci if (limit && statp->f_blocks > limit) { 3062306a36Sopenharmony_ci statp->f_blocks = limit; 3162306a36Sopenharmony_ci statp->f_bfree = statp->f_bavail = 3262306a36Sopenharmony_ci (statp->f_blocks > dqp->q_blk.reserved) ? 3362306a36Sopenharmony_ci (statp->f_blocks - dqp->q_blk.reserved) : 0; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci limit = dqp->q_ino.softlimit ? 3762306a36Sopenharmony_ci dqp->q_ino.softlimit : 3862306a36Sopenharmony_ci dqp->q_ino.hardlimit; 3962306a36Sopenharmony_ci if (limit && statp->f_files > limit) { 4062306a36Sopenharmony_ci statp->f_files = limit; 4162306a36Sopenharmony_ci statp->f_ffree = 4262306a36Sopenharmony_ci (statp->f_files > dqp->q_ino.reserved) ? 4362306a36Sopenharmony_ci (statp->f_files - dqp->q_ino.reserved) : 0; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * Directory tree accounting is implemented using project quotas, where 5062306a36Sopenharmony_ci * the project identifier is inherited from parent directories. 5162306a36Sopenharmony_ci * A statvfs (df, etc.) of a directory that is using project quota should 5262306a36Sopenharmony_ci * return a statvfs of the project, not the entire filesystem. 5362306a36Sopenharmony_ci * This makes such trees appear as if they are filesystems in themselves. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_civoid 5662306a36Sopenharmony_cixfs_qm_statvfs( 5762306a36Sopenharmony_ci struct xfs_inode *ip, 5862306a36Sopenharmony_ci struct kstatfs *statp) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 6162306a36Sopenharmony_ci struct xfs_dquot *dqp; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (!xfs_qm_dqget(mp, ip->i_projid, XFS_DQTYPE_PROJ, false, &dqp)) { 6462306a36Sopenharmony_ci xfs_fill_statvfs_from_dquot(statp, dqp); 6562306a36Sopenharmony_ci xfs_qm_dqput(dqp); 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciint 7062306a36Sopenharmony_cixfs_qm_newmount( 7162306a36Sopenharmony_ci xfs_mount_t *mp, 7262306a36Sopenharmony_ci uint *needquotamount, 7362306a36Sopenharmony_ci uint *quotaflags) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci uint quotaondisk; 7662306a36Sopenharmony_ci uint uquotaondisk = 0, gquotaondisk = 0, pquotaondisk = 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci quotaondisk = xfs_has_quota(mp) && 7962306a36Sopenharmony_ci (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (quotaondisk) { 8262306a36Sopenharmony_ci uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT; 8362306a36Sopenharmony_ci pquotaondisk = mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT; 8462306a36Sopenharmony_ci gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * If the device itself is read-only, we can't allow 8962306a36Sopenharmony_ci * the user to change the state of quota on the mount - 9062306a36Sopenharmony_ci * this would generate a transaction on the ro device, 9162306a36Sopenharmony_ci * which would lead to an I/O error and shutdown 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) || 9562306a36Sopenharmony_ci (!uquotaondisk && XFS_IS_UQUOTA_ON(mp)) || 9662306a36Sopenharmony_ci (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) || 9762306a36Sopenharmony_ci (!gquotaondisk && XFS_IS_GQUOTA_ON(mp)) || 9862306a36Sopenharmony_ci (pquotaondisk && !XFS_IS_PQUOTA_ON(mp)) || 9962306a36Sopenharmony_ci (!pquotaondisk && XFS_IS_PQUOTA_ON(mp))) && 10062306a36Sopenharmony_ci xfs_dev_is_read_only(mp, "changing quota state")) { 10162306a36Sopenharmony_ci xfs_warn(mp, "please mount with%s%s%s%s.", 10262306a36Sopenharmony_ci (!quotaondisk ? "out quota" : ""), 10362306a36Sopenharmony_ci (uquotaondisk ? " usrquota" : ""), 10462306a36Sopenharmony_ci (gquotaondisk ? " grpquota" : ""), 10562306a36Sopenharmony_ci (pquotaondisk ? " prjquota" : "")); 10662306a36Sopenharmony_ci return -EPERM; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (XFS_IS_QUOTA_ON(mp) || quotaondisk) { 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * Call mount_quotas at this point only if we won't have to do 11262306a36Sopenharmony_ci * a quotacheck. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci if (quotaondisk && !XFS_QM_NEED_QUOTACHECK(mp)) { 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * If an error occurred, qm_mount_quotas code 11762306a36Sopenharmony_ci * has already disabled quotas. So, just finish 11862306a36Sopenharmony_ci * mounting, and get on with the boring life 11962306a36Sopenharmony_ci * without disk quotas. 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci xfs_qm_mount_quotas(mp); 12262306a36Sopenharmony_ci } else { 12362306a36Sopenharmony_ci /* 12462306a36Sopenharmony_ci * Clear the quota flags, but remember them. This 12562306a36Sopenharmony_ci * is so that the quota code doesn't get invoked 12662306a36Sopenharmony_ci * before we're ready. This can happen when an 12762306a36Sopenharmony_ci * inode goes inactive and wants to free blocks, 12862306a36Sopenharmony_ci * or via xfs_log_mount_finish. 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci *needquotamount = true; 13162306a36Sopenharmony_ci *quotaflags = mp->m_qflags; 13262306a36Sopenharmony_ci mp->m_qflags = 0; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 138