0001
0002
0003
0004
0005
0006
0007 #include "xfs.h"
0008 #include "xfs_fs.h"
0009 #include "xfs_shared.h"
0010 #include "xfs_format.h"
0011 #include "xfs_log_format.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_inode.h"
0015 #include "xfs_quota.h"
0016 #include "xfs_trans.h"
0017 #include "xfs_qm.h"
0018 #include "xfs_error.h"
0019
0020 int
0021 xfs_calc_dquots_per_chunk(
0022 unsigned int nbblks)
0023 {
0024 ASSERT(nbblks > 0);
0025 return BBTOB(nbblks) / sizeof(struct xfs_dqblk);
0026 }
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 xfs_failaddr_t
0037 xfs_dquot_verify(
0038 struct xfs_mount *mp,
0039 struct xfs_disk_dquot *ddq,
0040 xfs_dqid_t id)
0041 {
0042 __u8 ddq_type;
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059 if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC))
0060 return __this_address;
0061 if (ddq->d_version != XFS_DQUOT_VERSION)
0062 return __this_address;
0063
0064 if (ddq->d_type & ~XFS_DQTYPE_ANY)
0065 return __this_address;
0066 ddq_type = ddq->d_type & XFS_DQTYPE_REC_MASK;
0067 if (ddq_type != XFS_DQTYPE_USER &&
0068 ddq_type != XFS_DQTYPE_PROJ &&
0069 ddq_type != XFS_DQTYPE_GROUP)
0070 return __this_address;
0071
0072 if ((ddq->d_type & XFS_DQTYPE_BIGTIME) &&
0073 !xfs_has_bigtime(mp))
0074 return __this_address;
0075
0076 if ((ddq->d_type & XFS_DQTYPE_BIGTIME) && !ddq->d_id)
0077 return __this_address;
0078
0079 if (id != -1 && id != be32_to_cpu(ddq->d_id))
0080 return __this_address;
0081
0082 if (!ddq->d_id)
0083 return NULL;
0084
0085 if (ddq->d_blk_softlimit &&
0086 be64_to_cpu(ddq->d_bcount) > be64_to_cpu(ddq->d_blk_softlimit) &&
0087 !ddq->d_btimer)
0088 return __this_address;
0089
0090 if (ddq->d_ino_softlimit &&
0091 be64_to_cpu(ddq->d_icount) > be64_to_cpu(ddq->d_ino_softlimit) &&
0092 !ddq->d_itimer)
0093 return __this_address;
0094
0095 if (ddq->d_rtb_softlimit &&
0096 be64_to_cpu(ddq->d_rtbcount) > be64_to_cpu(ddq->d_rtb_softlimit) &&
0097 !ddq->d_rtbtimer)
0098 return __this_address;
0099
0100 return NULL;
0101 }
0102
0103 xfs_failaddr_t
0104 xfs_dqblk_verify(
0105 struct xfs_mount *mp,
0106 struct xfs_dqblk *dqb,
0107 xfs_dqid_t id)
0108 {
0109 if (xfs_has_crc(mp) &&
0110 !uuid_equal(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid))
0111 return __this_address;
0112
0113 return xfs_dquot_verify(mp, &dqb->dd_diskdq, id);
0114 }
0115
0116
0117
0118
0119 void
0120 xfs_dqblk_repair(
0121 struct xfs_mount *mp,
0122 struct xfs_dqblk *dqb,
0123 xfs_dqid_t id,
0124 xfs_dqtype_t type)
0125 {
0126
0127
0128
0129 ASSERT(id != -1);
0130 memset(dqb, 0, sizeof(struct xfs_dqblk));
0131
0132 dqb->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
0133 dqb->dd_diskdq.d_version = XFS_DQUOT_VERSION;
0134 dqb->dd_diskdq.d_type = type;
0135 dqb->dd_diskdq.d_id = cpu_to_be32(id);
0136
0137 if (xfs_has_crc(mp)) {
0138 uuid_copy(&dqb->dd_uuid, &mp->m_sb.sb_meta_uuid);
0139 xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
0140 XFS_DQUOT_CRC_OFF);
0141 }
0142 }
0143
0144 STATIC bool
0145 xfs_dquot_buf_verify_crc(
0146 struct xfs_mount *mp,
0147 struct xfs_buf *bp,
0148 bool readahead)
0149 {
0150 struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr;
0151 int ndquots;
0152 int i;
0153
0154 if (!xfs_has_crc(mp))
0155 return true;
0156
0157
0158
0159
0160
0161
0162 if (mp->m_quotainfo)
0163 ndquots = mp->m_quotainfo->qi_dqperchunk;
0164 else
0165 ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
0166
0167 for (i = 0; i < ndquots; i++, d++) {
0168 if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk),
0169 XFS_DQUOT_CRC_OFF)) {
0170 if (!readahead)
0171 xfs_buf_verifier_error(bp, -EFSBADCRC, __func__,
0172 d, sizeof(*d), __this_address);
0173 return false;
0174 }
0175 }
0176 return true;
0177 }
0178
0179 STATIC xfs_failaddr_t
0180 xfs_dquot_buf_verify(
0181 struct xfs_mount *mp,
0182 struct xfs_buf *bp,
0183 bool readahead)
0184 {
0185 struct xfs_dqblk *dqb = bp->b_addr;
0186 xfs_failaddr_t fa;
0187 xfs_dqid_t id = 0;
0188 int ndquots;
0189 int i;
0190
0191
0192
0193
0194
0195
0196 if (mp->m_quotainfo)
0197 ndquots = mp->m_quotainfo->qi_dqperchunk;
0198 else
0199 ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
0200
0201
0202
0203
0204
0205
0206
0207
0208 for (i = 0; i < ndquots; i++) {
0209 struct xfs_disk_dquot *ddq;
0210
0211 ddq = &dqb[i].dd_diskdq;
0212
0213 if (i == 0)
0214 id = be32_to_cpu(ddq->d_id);
0215
0216 fa = xfs_dqblk_verify(mp, &dqb[i], id + i);
0217 if (fa) {
0218 if (!readahead)
0219 xfs_buf_verifier_error(bp, -EFSCORRUPTED,
0220 __func__, &dqb[i],
0221 sizeof(struct xfs_dqblk), fa);
0222 return fa;
0223 }
0224 }
0225
0226 return NULL;
0227 }
0228
0229 static xfs_failaddr_t
0230 xfs_dquot_buf_verify_struct(
0231 struct xfs_buf *bp)
0232 {
0233 struct xfs_mount *mp = bp->b_mount;
0234
0235 return xfs_dquot_buf_verify(mp, bp, false);
0236 }
0237
0238 static void
0239 xfs_dquot_buf_read_verify(
0240 struct xfs_buf *bp)
0241 {
0242 struct xfs_mount *mp = bp->b_mount;
0243
0244 if (!xfs_dquot_buf_verify_crc(mp, bp, false))
0245 return;
0246 xfs_dquot_buf_verify(mp, bp, false);
0247 }
0248
0249
0250
0251
0252
0253
0254
0255 static void
0256 xfs_dquot_buf_readahead_verify(
0257 struct xfs_buf *bp)
0258 {
0259 struct xfs_mount *mp = bp->b_mount;
0260
0261 if (!xfs_dquot_buf_verify_crc(mp, bp, true) ||
0262 xfs_dquot_buf_verify(mp, bp, true) != NULL) {
0263 xfs_buf_ioerror(bp, -EIO);
0264 bp->b_flags &= ~XBF_DONE;
0265 }
0266 }
0267
0268
0269
0270
0271
0272
0273 static void
0274 xfs_dquot_buf_write_verify(
0275 struct xfs_buf *bp)
0276 {
0277 struct xfs_mount *mp = bp->b_mount;
0278
0279 xfs_dquot_buf_verify(mp, bp, false);
0280 }
0281
0282 const struct xfs_buf_ops xfs_dquot_buf_ops = {
0283 .name = "xfs_dquot",
0284 .magic16 = { cpu_to_be16(XFS_DQUOT_MAGIC),
0285 cpu_to_be16(XFS_DQUOT_MAGIC) },
0286 .verify_read = xfs_dquot_buf_read_verify,
0287 .verify_write = xfs_dquot_buf_write_verify,
0288 .verify_struct = xfs_dquot_buf_verify_struct,
0289 };
0290
0291 const struct xfs_buf_ops xfs_dquot_buf_ra_ops = {
0292 .name = "xfs_dquot_ra",
0293 .magic16 = { cpu_to_be16(XFS_DQUOT_MAGIC),
0294 cpu_to_be16(XFS_DQUOT_MAGIC) },
0295 .verify_read = xfs_dquot_buf_readahead_verify,
0296 .verify_write = xfs_dquot_buf_write_verify,
0297 };
0298
0299
0300 time64_t
0301 xfs_dquot_from_disk_ts(
0302 struct xfs_disk_dquot *ddq,
0303 __be32 dtimer)
0304 {
0305 uint32_t t = be32_to_cpu(dtimer);
0306
0307 if (t != 0 && (ddq->d_type & XFS_DQTYPE_BIGTIME))
0308 return xfs_dq_bigtime_to_unix(t);
0309
0310 return t;
0311 }
0312
0313
0314 __be32
0315 xfs_dquot_to_disk_ts(
0316 struct xfs_dquot *dqp,
0317 time64_t timer)
0318 {
0319 uint32_t t = timer;
0320
0321 if (timer != 0 && (dqp->q_type & XFS_DQTYPE_BIGTIME))
0322 t = xfs_dq_unix_to_bigtime(timer);
0323
0324 return cpu_to_be32(t);
0325 }