// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2006 Silicon Graphics, Inc. * Copyright (c) 2013 Red Hat, Inc. * All Rights Reserved.
*/ #include"xfs.h" #include"xfs_fs.h" #include"xfs_shared.h" #include"xfs_format.h" #include"xfs_log_format.h" #include"xfs_trans_resv.h" #include"xfs_mount.h" #include"xfs_inode.h" #include"xfs_quota.h" #include"xfs_trans.h" #include"xfs_qm.h" #include"xfs_error.h" #include"xfs_health.h" #include"xfs_metadir.h" #include"xfs_metafile.h"
int
xfs_calc_dquots_per_chunk( unsignedint nbblks) /* basic block units */
{
ASSERT(nbblks > 0); return BBTOB(nbblks) / sizeof(struct xfs_dqblk);
}
/* * Do some primitive error checking on ondisk dquot data structures. * * The xfs_dqblk structure /contains/ the xfs_disk_dquot structure; * we verify them separately because at some points we have only the * smaller xfs_disk_dquot structure available.
*/
xfs_failaddr_t
xfs_dquot_verify( struct xfs_mount *mp, struct xfs_disk_dquot *ddq,
xfs_dqid_t id) /* used only during quotacheck */
{
__u8 ddq_type;
/* * We can encounter an uninitialized dquot buffer for 2 reasons: * 1. If we crash while deleting the quotainode(s), and those blks got * used for user data. This is because we take the path of regular * file deletion; however, the size field of quotainodes is never * updated, so all the tricks that we play in itruncate_finish * don't quite matter. * * 2. We don't play the quota buffers when there's a quotaoff logitem. * But the allocation will be replayed so we'll end up with an * uninitialized quota block. * * This is all fine; things are still consistent, and we haven't lost * any quota information. Just don't complain about bad dquot blks.
*/ if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) return __this_address; if (ddq->d_version != XFS_DQUOT_VERSION) return __this_address;
/* * if we are in log recovery, the quota subsystem has not been * initialised so we have no quotainfo structure. In that case, we need * to manually calculate the number of dquots in the buffer.
*/ if (mp->m_quotainfo)
ndquots = mp->m_quotainfo->qi_dqperchunk; else
ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
for (i = 0; i < ndquots; i++, d++) { if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
XFS_DQUOT_CRC_OFF)) { if (!readahead)
xfs_buf_verifier_error(bp, -EFSBADCRC, __func__,
d, sizeof(*d), __this_address); returnfalse;
}
} returntrue;
}
STATIC xfs_failaddr_t
xfs_dquot_buf_verify( struct xfs_mount *mp, struct xfs_buf *bp, bool readahead)
{ struct xfs_dqblk *dqb = bp->b_addr;
xfs_failaddr_t fa;
xfs_dqid_t id = 0; int ndquots; int i;
/* * if we are in log recovery, the quota subsystem has not been * initialised so we have no quotainfo structure. In that case, we need * to manually calculate the number of dquots in the buffer.
*/ if (mp->m_quotainfo)
ndquots = mp->m_quotainfo->qi_dqperchunk; else
ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
/* * On the first read of the buffer, verify that each dquot is valid. * We don't know what the id of the dquot is supposed to be, just that * they should be increasing monotonically within the buffer. If the * first id is corrupt, then it will fail on the second dquot in the * buffer so corruptions could point to the wrong dquot in this case.
*/ for (i = 0; i < ndquots; i++) { struct xfs_disk_dquot *ddq;
ddq = &dqb[i].dd_diskdq;
if (i == 0)
id = be32_to_cpu(ddq->d_id);
fa = xfs_dqblk_verify(mp, &dqb[i], id + i); if (fa) { if (!readahead)
xfs_buf_verifier_error(bp, -EFSCORRUPTED,
__func__, &dqb[i], sizeof(struct xfs_dqblk), fa); return fa;
}
}
if (!xfs_dquot_buf_verify_crc(mp, bp, false)) return;
xfs_dquot_buf_verify(mp, bp, false);
}
/* * readahead errors are silent and simply leave the buffer as !done so a real * read will then be run with the xfs_dquot_buf_ops verifier. See * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than * reporting the failure.
*/ staticvoid
xfs_dquot_buf_readahead_verify( struct xfs_buf *bp)
{ struct xfs_mount *mp = bp->b_mount;
/* * we don't calculate the CRC here as that is done when the dquot is flushed to * the buffer after the update is done. This ensures that the dquot in the * buffer always has an up-to-date CRC value.
*/ staticvoid
xfs_dquot_buf_write_verify( struct xfs_buf *bp)
{ struct xfs_mount *mp = bp->b_mount;
/* Convert an on-disk timer value into an incore timer value. */
time64_t
xfs_dquot_from_disk_ts( struct xfs_disk_dquot *ddq,
__be32 dtimer)
{
uint32_t t = be32_to_cpu(dtimer);
if (t != 0 && (ddq->d_type & XFS_DQTYPE_BIGTIME)) return xfs_dq_bigtime_to_unix(t);
return t;
}
/* Convert an incore timer value into an on-disk timer value. */
__be32
xfs_dquot_to_disk_ts( struct xfs_dquot *dqp,
time64_t timer)
{
uint32_t t = timer;
if (timer != 0 && (dqp->q_type & XFS_DQTYPE_BIGTIME))
t = xfs_dq_unix_to_bigtime(timer);
return cpu_to_be32(t);
}
inlineunsignedint
xfs_dqinode_sick_mask(xfs_dqtype_t type)
{ switch (type) { case XFS_DQTYPE_USER: return XFS_SICK_FS_UQUOTA; case XFS_DQTYPE_GROUP: return XFS_SICK_FS_GQUOTA; case XFS_DQTYPE_PROJ: return XFS_SICK_FS_PQUOTA;
}
ASSERT(0); return 0;
}
/* * Load the inode for a given type of quota, assuming that the sb fields have * been sorted out. This is not true when switching quota types on a V4 * filesystem, so do not use this function for that. If metadir is enabled, * @dp must be the /quota metadir. * * Returns -ENOENT if the quota inode field is NULLFSINO; 0 and an inode on * success; or a negative errno.
*/ int
xfs_dqinode_load( struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dqtype_t type, struct xfs_inode **ipp)
{ struct xfs_mount *mp = tp->t_mountp; struct xfs_inode *ip; enum xfs_metafile_type metafile_type = xfs_dqinode_metafile_type(type); int error;
if (!xfs_has_metadir(mp)) {
xfs_ino_t ino;
switch (type) { case XFS_DQTYPE_USER:
ino = mp->m_sb.sb_uquotino; break; case XFS_DQTYPE_GROUP:
ino = mp->m_sb.sb_gquotino; break; case XFS_DQTYPE_PROJ:
ino = mp->m_sb.sb_pquotino; break; default:
ASSERT(0); return -EFSCORRUPTED;
}
/* Should have set 0 to NULLFSINO when loading superblock */ if (ino == NULLFSINO) return -ENOENT;
/* Create the parent directory for all quota inodes and load it. */ int
xfs_dqinode_mkdir_parent( struct xfs_mount *mp, struct xfs_inode **dpp)
{ if (!mp->m_metadirip) {
xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED;
}
/* * Load the parent directory of all quota inodes. Pass the inode to the caller * because quota functions (e.g. QUOTARM) can be called on the quota files even * if quotas are not enabled.
*/ int
xfs_dqinode_load_parent( struct xfs_trans *tp, struct xfs_inode **dpp)
{ struct xfs_mount *mp = tp->t_mountp;
if (!mp->m_metadirip) {
xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR); return -EFSCORRUPTED;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.