From patchwork Mon May 7 23:43:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Sandeen X-Patchwork-Id: 10384963 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 6CF1060353 for ; Mon, 7 May 2018 23:43:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1EA0A28B88 for ; Mon, 7 May 2018 23:43:24 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1336F28BA0; Mon, 7 May 2018 23:43:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 04C1228B88 for ; Mon, 7 May 2018 23:43:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753055AbeEGXnU (ORCPT ); Mon, 7 May 2018 19:43:20 -0400 Received: from sandeen.net ([63.231.237.45]:36996 "EHLO sandeen.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753512AbeEGXnS (ORCPT ); Mon, 7 May 2018 19:43:18 -0400 Received: from [10.0.0.4] (liberator [10.0.0.4]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by sandeen.net (Postfix) with ESMTPSA id 2787515D69; Mon, 7 May 2018 18:41:55 -0500 (CDT) Subject: [PATCH V2] xfs_repair: check and repair quota metadata To: Eric Sandeen , linux-xfs References: <9e494d70-53bd-db81-c118-73ef7eaad667@redhat.com> From: Eric Sandeen Openpgp: preference=signencrypt Autocrypt: addr=sandeen@sandeen.net; prefer-encrypt=mutual; keydata= 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 pA== Message-ID: <92d87853-cbaa-7c5f-2b8f-4c6d23e4ed3c@sandeen.net> Date: Mon, 7 May 2018 18:43:17 -0500 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <9e494d70-53bd-db81-c118-73ef7eaad667@redhat.com> Content-Language: en-US Sender: linux-xfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-xfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Today, quota inodes are not checked at all in xfs_repair. (This is a little odd, because xfs_check used to do it in process_quota()). The kernel has quota inode validation and repair routines, but it is out of the ordinary for the kernel to be doing metadata repair. And now that we have metadata verifiers, this also yields a surprisingly noisy mount if quota inodes are corrupted, even immediately after an xfs_repair. So this patch allows xfs_repair to fix the quota inode metadata. Quotacheck is still left for the kernel. After a few more releases, I'll propose removing the repair calls from quotacheck. Signed-off-by: Eric Sandeen Reviewed-by: Darrick J. Wong --- V2: don't renumber all the XR_INO_* defines This will need a bit of adjustment when my other quota patches land in 4.18, but that should be no big deal. -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index ab195f5f..e5eb3de1 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -196,8 +196,6 @@ enum ce { CE_DEBUG, CE_CONT, CE_NOTE, CE_WARN, CE_ALERT, CE_PANIC }; # define barrier() __memory_barrier() #endif -#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 - /* miscellaneous kernel routines not in user space */ #define down_read(a) ((void) 0) #define up_read(a) ((void) 0) diff --git a/libxfs/xfs_quota_defs.h b/libxfs/xfs_quota_defs.h index bb1b13a9..067475e2 100644 --- a/libxfs/xfs_quota_defs.h +++ b/libxfs/xfs_quota_defs.h @@ -30,6 +30,8 @@ typedef uint64_t xfs_qcnt_t; typedef uint16_t xfs_qwarncnt_t; +#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 + /* * flags for q_flags field in the dquot. */ diff --git a/repair/dinode.c b/repair/dinode.c index 9af4f058..a4887f8c 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -1277,6 +1277,118 @@ null_check(char *name, int length) return(0); } +/* + * This does /not/ do quotacheck, it validates the basic quota + * inode metadata, checksums, etc. + */ +#define uuid_equal(s,d) (platform_uuid_compare((s),(d)) == 0) +static int +process_quota_inode( + struct xfs_mount *mp, + xfs_ino_t lino, + struct xfs_dinode *dino, + uint ino_type, + struct blkmap *blkmap) +{ + xfs_fsblock_t fsbno; + struct xfs_buf *bp; + xfs_filblks_t dqchunklen; + uint dqperchunk; + int quota_type; + char *quota_string; + xfs_dqid_t dqid; + xfs_fileoff_t qbno; + int i; + int t = 0; + + switch (ino_type) { + case XR_INO_UQUOTA: + quota_type = XFS_DQ_USER; + quota_string = _("User quota"); + break; + case XR_INO_GQUOTA: + quota_type = XFS_DQ_GROUP; + quota_string = _("Group quota"); + break; + case XR_INO_PQUOTA: + quota_type = XFS_DQ_PROJ; + quota_string = _("Project quota"); + break; + default: + ASSERT(0); + } + + dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); + dqperchunk = xfs_calc_dquots_per_chunk(dqchunklen); + dqid = 0; + qbno = NULLFILEOFF; + + while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) { + xfs_dqblk_t *dqb; + int writebuf = 0; + + fsbno = blkmap_get(blkmap, qbno); + dqid = (xfs_dqid_t)qbno * dqperchunk; + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + dqchunklen, 0, &xfs_dquot_buf_ops); + if (!bp) { + do_warn( +_("cannot read inode %" PRIu64 ", file block %" PRIu64 ", disk block %" PRIu64 "\n"), + lino, qbno, fsbno); + return 1; + } + + dqb = bp->b_addr; + for (i = 0; i < dqperchunk; i++, dqid++, dqb++) { + xfs_failaddr_t fa; + int bad_dqb = 0; + + /* We only print the first problem we find */ + if (xfs_sb_version_hascrc(&mp->m_sb)) { + if (!xfs_verify_cksum((char *)dqb, sizeof(*dqb), + XFS_DQUOT_CRC_OFF)) { + do_warn(_("%s: bad CRC for id %u. "), + quota_string, dqid); + bad_dqb = 1; + goto bad; + } + + if (!uuid_equal(&dqb->dd_uuid, + &mp->m_sb.sb_meta_uuid)) { + do_warn(_("%s: bad UUID for id %u. "), + quota_string, dqid); + bad_dqb = 1; + goto bad; + } + } + fa = xfs_dquot_verify(mp, &dqb->dd_diskdq, dqid, quota_type, 0); + if (fa) { + do_warn(_("%s: Corrupt quota for id %u. "), + quota_string, dqid); + bad_dqb = 1; + } + +bad: + if (bad_dqb) { + if (no_modify) + do_warn(_("Would correct.\n")); + else { + do_warn(_("Corrected.\n")); + xfs_dquot_repair(mp, &dqb->dd_diskdq, dqid, quota_type); + writebuf = 1; + } + } + } + + if (writebuf && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + } + return 0; +} + static int process_symlink_remote( struct xfs_mount *mp, @@ -1479,6 +1591,13 @@ _("size of socket inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, _("size of fifo inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, (int64_t)be64_to_cpu(dino->di_size)); break; + case XR_INO_UQUOTA: + case XR_INO_GQUOTA: + case XR_INO_PQUOTA: + do_warn( +_("size of quota inode %" PRIu64 " != 0 (%" PRId64 " bytes)\n"), lino, + (int64_t)be64_to_cpu(dino->di_size)); + break; default: do_warn(_("Internal error - process_misc_ino_types, " "illegal type %d\n"), type); @@ -1599,7 +1718,7 @@ process_check_sb_inodes( int *dirty) { if (lino == mp->m_sb.sb_rootino) { - if (*type != XR_INO_DIR) { + if (*type != XR_INO_DIR) { do_warn(_("root inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); *type = XR_INO_DIR; @@ -1613,7 +1732,7 @@ process_check_sb_inodes( return 0; } if (lino == mp->m_sb.sb_uquotino) { - if (*type != XR_INO_DATA) { + if (*type != XR_INO_UQUOTA) { do_warn(_("user quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); mp->m_sb.sb_uquotino = NULLFSINO; @@ -1622,7 +1741,7 @@ process_check_sb_inodes( return 0; } if (lino == mp->m_sb.sb_gquotino) { - if (*type != XR_INO_DATA) { + if (*type != XR_INO_GQUOTA) { do_warn(_("group quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); mp->m_sb.sb_gquotino = NULLFSINO; @@ -1631,7 +1750,7 @@ process_check_sb_inodes( return 0; } if (lino == mp->m_sb.sb_pquotino) { - if (*type != XR_INO_DATA) { + if (*type != XR_INO_PQUOTA) { do_warn(_("project quota inode %" PRIu64 " has bad type 0x%x\n"), lino, dinode_fmt(dinoc)); mp->m_sb.sb_pquotino = NULLFSINO; @@ -1738,6 +1857,14 @@ _("directory inode %" PRIu64 " has bad size %" PRId64 "\n"), return 1; break; + case XR_INO_UQUOTA: + case XR_INO_GQUOTA: + case XR_INO_PQUOTA: + /* Quota inodes have same restrictions as above types */ + if (process_misc_ino_types(mp, dino, lino, type)) + return 1; + break; + case XR_INO_RTDATA: /* * if we have no realtime blocks, any inode claiming @@ -2620,6 +2747,12 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), type = XR_INO_RTBITMAP; else if (lino == mp->m_sb.sb_rsumino) type = XR_INO_RTSUM; + else if (lino == mp->m_sb.sb_uquotino) + type = XR_INO_UQUOTA; + else if (lino == mp->m_sb.sb_gquotino) + type = XR_INO_GQUOTA; + else if (lino == mp->m_sb.sb_pquotino) + type = XR_INO_PQUOTA; else type = XR_INO_DATA; break; @@ -2784,6 +2917,15 @@ _("Cannot have CoW extent size of zero on cowextsize inode %" PRIu64 ", "), goto clear_bad_out; } break; + case XR_INO_UQUOTA: + case XR_INO_GQUOTA: + case XR_INO_PQUOTA: + if (process_quota_inode(mp, lino, dino, type, dblkmap) != 0) { + do_warn( + _("problem with quota inode %" PRIu64 "\n"), lino); + goto clear_bad_out; + } + break; default: break; } diff --git a/repair/incore.h b/repair/incore.h index fd66084f..e6b71272 100644 --- a/repair/incore.h +++ b/repair/incore.h @@ -229,6 +229,9 @@ int count_bcnt_extents(xfs_agnumber_t); #define XR_INO_SOCK 9 /* socket */ #define XR_INO_FIFO 10 /* fifo */ #define XR_INO_MOUNTPOINT 11 /* mountpoint */ +#define XR_INO_UQUOTA 12 /* user quota inode */ +#define XR_INO_GQUOTA 13 /* group quota inode */ +#define XR_INO_PQUOTA 14 /* project quota inode */ /* inode allocation tree */