mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	xfs: split dquot buffer operations out
Parts of userspace want to be able to read and modify dquot buffers (e.g. xfs_db) so we need to split out the reading and writing of these buffers so it is easy to shared code with libxfs in userspace. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ben Myers <bpm@sgi.com>
This commit is contained in:
		
							parent
							
								
									5706278758
								
							
						
					
					
						commit
						9aede1d81b
					
				
					 8 changed files with 303 additions and 266 deletions
				
			
		|  | @ -72,6 +72,7 @@ xfs-y				+= xfs_alloc.o \ | ||||||
| 				   xfs_dir2_leaf.o \
 | 				   xfs_dir2_leaf.o \
 | ||||||
| 				   xfs_dir2_node.o \
 | 				   xfs_dir2_node.o \
 | ||||||
| 				   xfs_dir2_sf.o \
 | 				   xfs_dir2_sf.o \
 | ||||||
|  | 				   xfs_dquot_buf.o \
 | ||||||
| 				   xfs_ialloc.o \
 | 				   xfs_ialloc.o \
 | ||||||
| 				   xfs_ialloc_btree.o \
 | 				   xfs_ialloc_btree.o \
 | ||||||
| 				   xfs_icreate_item.o \
 | 				   xfs_icreate_item.o \
 | ||||||
|  |  | ||||||
|  | @ -293,118 +293,6 @@ xfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp) | ||||||
| 	dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; | 	dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| STATIC bool |  | ||||||
| xfs_dquot_buf_verify_crc( |  | ||||||
| 	struct xfs_mount	*mp, |  | ||||||
| 	struct xfs_buf		*bp) |  | ||||||
| { |  | ||||||
| 	struct xfs_dqblk	*d = (struct xfs_dqblk *)bp->b_addr; |  | ||||||
| 	int			ndquots; |  | ||||||
| 	int			i; |  | ||||||
| 
 |  | ||||||
| 	if (!xfs_sb_version_hascrc(&mp->m_sb)) |  | ||||||
| 		return true; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * 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_qm_calc_dquots_per_chunk(mp, |  | ||||||
| 					XFS_BB_TO_FSB(mp, bp->b_length)); |  | ||||||
| 
 |  | ||||||
| 	for (i = 0; i < ndquots; i++, d++) { |  | ||||||
| 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), |  | ||||||
| 				 XFS_DQUOT_CRC_OFF)) |  | ||||||
| 			return false; |  | ||||||
| 		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid)) |  | ||||||
| 			return false; |  | ||||||
| 	} |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| STATIC bool |  | ||||||
| xfs_dquot_buf_verify( |  | ||||||
| 	struct xfs_mount	*mp, |  | ||||||
| 	struct xfs_buf		*bp) |  | ||||||
| { |  | ||||||
| 	struct xfs_dqblk	*d = (struct xfs_dqblk *)bp->b_addr; |  | ||||||
| 	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_qm_calc_dquots_per_chunk(mp, 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; |  | ||||||
| 		int			error; |  | ||||||
| 
 |  | ||||||
| 		ddq = &d[i].dd_diskdq; |  | ||||||
| 
 |  | ||||||
| 		if (i == 0) |  | ||||||
| 			id = be32_to_cpu(ddq->d_id); |  | ||||||
| 
 |  | ||||||
| 		error = xfs_qm_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, |  | ||||||
| 				       "xfs_dquot_buf_verify"); |  | ||||||
| 		if (error) |  | ||||||
| 			return false; |  | ||||||
| 	} |  | ||||||
| 	return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void |  | ||||||
| xfs_dquot_buf_read_verify( |  | ||||||
| 	struct xfs_buf	*bp) |  | ||||||
| { |  | ||||||
| 	struct xfs_mount	*mp = bp->b_target->bt_mount; |  | ||||||
| 
 |  | ||||||
| 	if (!xfs_dquot_buf_verify_crc(mp, bp) || !xfs_dquot_buf_verify(mp, bp)) { |  | ||||||
| 		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); |  | ||||||
| 		xfs_buf_ioerror(bp, EFSCORRUPTED); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 |  | ||||||
|  * 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. |  | ||||||
|  */ |  | ||||||
| void |  | ||||||
| xfs_dquot_buf_write_verify( |  | ||||||
| 	struct xfs_buf	*bp) |  | ||||||
| { |  | ||||||
| 	struct xfs_mount	*mp = bp->b_target->bt_mount; |  | ||||||
| 
 |  | ||||||
| 	if (!xfs_dquot_buf_verify(mp, bp)) { |  | ||||||
| 		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); |  | ||||||
| 		xfs_buf_ioerror(bp, EFSCORRUPTED); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const struct xfs_buf_ops xfs_dquot_buf_ops = { |  | ||||||
| 	.verify_read = xfs_dquot_buf_read_verify, |  | ||||||
| 	.verify_write = xfs_dquot_buf_write_verify, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * Allocate a block and fill it with dquots. |  * Allocate a block and fill it with dquots. | ||||||
|  * This is called when the bmapi finds a hole. |  * This is called when the bmapi finds a hole. | ||||||
|  | @ -515,6 +403,7 @@ xfs_qm_dqalloc( | ||||||
| 
 | 
 | ||||||
| 	return (error); | 	return (error); | ||||||
| } | } | ||||||
|  | 
 | ||||||
| STATIC int | STATIC int | ||||||
| xfs_qm_dqrepair( | xfs_qm_dqrepair( | ||||||
| 	struct xfs_mount	*mp, | 	struct xfs_mount	*mp, | ||||||
|  | @ -548,7 +437,7 @@ xfs_qm_dqrepair( | ||||||
| 	/* Do the actual repair of dquots in this buffer */ | 	/* Do the actual repair of dquots in this buffer */ | ||||||
| 	for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) { | 	for (i = 0; i < mp->m_quotainfo->qi_dqperchunk; i++) { | ||||||
| 		ddq = &d[i].dd_diskdq; | 		ddq = &d[i].dd_diskdq; | ||||||
| 		error = xfs_qm_dqcheck(mp, ddq, firstid + i, | 		error = xfs_dqcheck(mp, ddq, firstid + i, | ||||||
| 				       dqp->dq_flags & XFS_DQ_ALLTYPES, | 				       dqp->dq_flags & XFS_DQ_ALLTYPES, | ||||||
| 				       XFS_QMOPT_DQREPAIR, "xfs_qm_dqrepair"); | 				       XFS_QMOPT_DQREPAIR, "xfs_qm_dqrepair"); | ||||||
| 		if (error) { | 		if (error) { | ||||||
|  | @ -1134,7 +1023,7 @@ xfs_qm_dqflush( | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * A simple sanity check in case we got a corrupted dquot.. | 	 * A simple sanity check in case we got a corrupted dquot.. | ||||||
| 	 */ | 	 */ | ||||||
| 	error = xfs_qm_dqcheck(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0, | 	error = xfs_dqcheck(mp, &dqp->q_core, be32_to_cpu(ddqp->d_id), 0, | ||||||
| 			   XFS_QMOPT_DOWARN, "dqflush (incore copy)"); | 			   XFS_QMOPT_DOWARN, "dqflush (incore copy)"); | ||||||
| 	if (error) { | 	if (error) { | ||||||
| 		xfs_buf_relse(bp); | 		xfs_buf_relse(bp); | ||||||
|  |  | ||||||
							
								
								
									
										288
									
								
								fs/xfs/xfs_dquot_buf.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								fs/xfs/xfs_dquot_buf.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,288 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2000-2006 Silicon Graphics, Inc. | ||||||
|  |  * Copyright (c) 2013 Red Hat, Inc. | ||||||
|  |  * All Rights Reserved. | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or | ||||||
|  |  * modify it under the terms of the GNU General Public License as | ||||||
|  |  * published by the Free Software Foundation. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it would be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program; if not, write the Free Software Foundation, | ||||||
|  |  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||||
|  |  */ | ||||||
|  | #include "xfs.h" | ||||||
|  | #include "xfs_fs.h" | ||||||
|  | #include "xfs_format.h" | ||||||
|  | #include "xfs_bit.h" | ||||||
|  | #include "xfs_log.h" | ||||||
|  | #include "xfs_trans.h" | ||||||
|  | #include "xfs_sb.h" | ||||||
|  | #include "xfs_ag.h" | ||||||
|  | #include "xfs_mount.h" | ||||||
|  | #include "xfs_bmap_btree.h" | ||||||
|  | #include "xfs_inode.h" | ||||||
|  | #include "xfs_quota.h" | ||||||
|  | #include "xfs_qm.h" | ||||||
|  | #include "xfs_error.h" | ||||||
|  | #include "xfs_cksum.h" | ||||||
|  | #include "xfs_trace.h" | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | xfs_calc_dquots_per_chunk( | ||||||
|  | 	struct xfs_mount	*mp, | ||||||
|  | 	unsigned int		nbblks)	/* basic block units */ | ||||||
|  | { | ||||||
|  | 	unsigned int	ndquots; | ||||||
|  | 
 | ||||||
|  | 	ASSERT(nbblks > 0); | ||||||
|  | 	ndquots = BBTOB(nbblks); | ||||||
|  | 	do_div(ndquots, sizeof(xfs_dqblk_t)); | ||||||
|  | 
 | ||||||
|  | 	return ndquots; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Do some primitive error checking on ondisk dquot data structures. | ||||||
|  |  */ | ||||||
|  | int | ||||||
|  | xfs_dqcheck( | ||||||
|  | 	struct xfs_mount *mp, | ||||||
|  | 	xfs_disk_dquot_t *ddq, | ||||||
|  | 	xfs_dqid_t	 id, | ||||||
|  | 	uint		 type,	  /* used only when IO_dorepair is true */ | ||||||
|  | 	uint		 flags, | ||||||
|  | 	char		 *str) | ||||||
|  | { | ||||||
|  | 	xfs_dqblk_t	 *d = (xfs_dqblk_t *)ddq; | ||||||
|  | 	int		errs = 0; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * 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)) { | ||||||
|  | 		if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 			xfs_alert(mp, | ||||||
|  | 			"%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", | ||||||
|  | 			str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); | ||||||
|  | 		errs++; | ||||||
|  | 	} | ||||||
|  | 	if (ddq->d_version != XFS_DQUOT_VERSION) { | ||||||
|  | 		if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 			xfs_alert(mp, | ||||||
|  | 			"%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", | ||||||
|  | 			str, id, ddq->d_version, XFS_DQUOT_VERSION); | ||||||
|  | 		errs++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ddq->d_flags != XFS_DQ_USER && | ||||||
|  | 	    ddq->d_flags != XFS_DQ_PROJ && | ||||||
|  | 	    ddq->d_flags != XFS_DQ_GROUP) { | ||||||
|  | 		if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 			xfs_alert(mp, | ||||||
|  | 			"%s : XFS dquot ID 0x%x, unknown flags 0x%x", | ||||||
|  | 			str, id, ddq->d_flags); | ||||||
|  | 		errs++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (id != -1 && id != be32_to_cpu(ddq->d_id)) { | ||||||
|  | 		if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 			xfs_alert(mp, | ||||||
|  | 			"%s : ondisk-dquot 0x%p, ID mismatch: " | ||||||
|  | 			"0x%x expected, found id 0x%x", | ||||||
|  | 			str, ddq, id, be32_to_cpu(ddq->d_id)); | ||||||
|  | 		errs++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!errs && ddq->d_id) { | ||||||
|  | 		if (ddq->d_blk_softlimit && | ||||||
|  | 		    be64_to_cpu(ddq->d_bcount) > | ||||||
|  | 				be64_to_cpu(ddq->d_blk_softlimit)) { | ||||||
|  | 			if (!ddq->d_btimer) { | ||||||
|  | 				if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 					xfs_alert(mp, | ||||||
|  | 			"%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", | ||||||
|  | 					str, (int)be32_to_cpu(ddq->d_id), ddq); | ||||||
|  | 				errs++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (ddq->d_ino_softlimit && | ||||||
|  | 		    be64_to_cpu(ddq->d_icount) > | ||||||
|  | 				be64_to_cpu(ddq->d_ino_softlimit)) { | ||||||
|  | 			if (!ddq->d_itimer) { | ||||||
|  | 				if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 					xfs_alert(mp, | ||||||
|  | 			"%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", | ||||||
|  | 					str, (int)be32_to_cpu(ddq->d_id), ddq); | ||||||
|  | 				errs++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (ddq->d_rtb_softlimit && | ||||||
|  | 		    be64_to_cpu(ddq->d_rtbcount) > | ||||||
|  | 				be64_to_cpu(ddq->d_rtb_softlimit)) { | ||||||
|  | 			if (!ddq->d_rtbtimer) { | ||||||
|  | 				if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 					xfs_alert(mp, | ||||||
|  | 			"%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", | ||||||
|  | 					str, (int)be32_to_cpu(ddq->d_id), ddq); | ||||||
|  | 				errs++; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) | ||||||
|  | 		return errs; | ||||||
|  | 
 | ||||||
|  | 	if (flags & XFS_QMOPT_DOWARN) | ||||||
|  | 		xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Typically, a repair is only requested by quotacheck. | ||||||
|  | 	 */ | ||||||
|  | 	ASSERT(id != -1); | ||||||
|  | 	ASSERT(flags & XFS_QMOPT_DQREPAIR); | ||||||
|  | 	memset(d, 0, sizeof(xfs_dqblk_t)); | ||||||
|  | 
 | ||||||
|  | 	d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); | ||||||
|  | 	d->dd_diskdq.d_version = XFS_DQUOT_VERSION; | ||||||
|  | 	d->dd_diskdq.d_flags = type; | ||||||
|  | 	d->dd_diskdq.d_id = cpu_to_be32(id); | ||||||
|  | 
 | ||||||
|  | 	if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||||||
|  | 		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid); | ||||||
|  | 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), | ||||||
|  | 				 XFS_DQUOT_CRC_OFF); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return errs; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | STATIC bool | ||||||
|  | xfs_dquot_buf_verify_crc( | ||||||
|  | 	struct xfs_mount	*mp, | ||||||
|  | 	struct xfs_buf		*bp) | ||||||
|  | { | ||||||
|  | 	struct xfs_dqblk	*d = (struct xfs_dqblk *)bp->b_addr; | ||||||
|  | 	int			ndquots; | ||||||
|  | 	int			i; | ||||||
|  | 
 | ||||||
|  | 	if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||||||
|  | 		return true; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * 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(mp, | ||||||
|  | 					XFS_BB_TO_FSB(mp, bp->b_length)); | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < ndquots; i++, d++) { | ||||||
|  | 		if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), | ||||||
|  | 				 XFS_DQUOT_CRC_OFF)) | ||||||
|  | 			return false; | ||||||
|  | 		if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_uuid)) | ||||||
|  | 			return false; | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | STATIC bool | ||||||
|  | xfs_dquot_buf_verify( | ||||||
|  | 	struct xfs_mount	*mp, | ||||||
|  | 	struct xfs_buf		*bp) | ||||||
|  | { | ||||||
|  | 	struct xfs_dqblk	*d = (struct xfs_dqblk *)bp->b_addr; | ||||||
|  | 	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(mp, 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; | ||||||
|  | 		int			error; | ||||||
|  | 
 | ||||||
|  | 		ddq = &d[i].dd_diskdq; | ||||||
|  | 
 | ||||||
|  | 		if (i == 0) | ||||||
|  | 			id = be32_to_cpu(ddq->d_id); | ||||||
|  | 
 | ||||||
|  | 		error = xfs_dqcheck(mp, ddq, id + i, 0, XFS_QMOPT_DOWARN, | ||||||
|  | 				       "xfs_dquot_buf_verify"); | ||||||
|  | 		if (error) | ||||||
|  | 			return false; | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void | ||||||
|  | xfs_dquot_buf_read_verify( | ||||||
|  | 	struct xfs_buf	*bp) | ||||||
|  | { | ||||||
|  | 	struct xfs_mount	*mp = bp->b_target->bt_mount; | ||||||
|  | 
 | ||||||
|  | 	if (!xfs_dquot_buf_verify_crc(mp, bp) || !xfs_dquot_buf_verify(mp, bp)) { | ||||||
|  | 		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||||||
|  | 		xfs_buf_ioerror(bp, EFSCORRUPTED); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * 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. | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | xfs_dquot_buf_write_verify( | ||||||
|  | 	struct xfs_buf	*bp) | ||||||
|  | { | ||||||
|  | 	struct xfs_mount	*mp = bp->b_target->bt_mount; | ||||||
|  | 
 | ||||||
|  | 	if (!xfs_dquot_buf_verify(mp, bp)) { | ||||||
|  | 		XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||||||
|  | 		xfs_buf_ioerror(bp, EFSCORRUPTED); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const struct xfs_buf_ops xfs_dquot_buf_ops = { | ||||||
|  | 	.verify_read = xfs_dquot_buf_read_verify, | ||||||
|  | 	.verify_write = xfs_dquot_buf_write_verify, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | @ -2363,7 +2363,7 @@ xlog_recover_do_reg_buffer( | ||||||
| 					item->ri_buf[i].i_len, __func__); | 					item->ri_buf[i].i_len, __func__); | ||||||
| 				goto next; | 				goto next; | ||||||
| 			} | 			} | ||||||
| 			error = xfs_qm_dqcheck(mp, item->ri_buf[i].i_addr, | 			error = xfs_dqcheck(mp, item->ri_buf[i].i_addr, | ||||||
| 					       -1, 0, XFS_QMOPT_DOWARN, | 					       -1, 0, XFS_QMOPT_DOWARN, | ||||||
| 					       "dquot_buf_recover"); | 					       "dquot_buf_recover"); | ||||||
| 			if (error) | 			if (error) | ||||||
|  | @ -2394,133 +2394,6 @@ xlog_recover_do_reg_buffer( | ||||||
| 		xlog_recover_validate_buf_type(mp, bp, buf_f); | 		xlog_recover_validate_buf_type(mp, bp, buf_f); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * Do some primitive error checking on ondisk dquot data structures. |  | ||||||
|  */ |  | ||||||
| int |  | ||||||
| xfs_qm_dqcheck( |  | ||||||
| 	struct xfs_mount *mp, |  | ||||||
| 	xfs_disk_dquot_t *ddq, |  | ||||||
| 	xfs_dqid_t	 id, |  | ||||||
| 	uint		 type,	  /* used only when IO_dorepair is true */ |  | ||||||
| 	uint		 flags, |  | ||||||
| 	char		 *str) |  | ||||||
| { |  | ||||||
| 	xfs_dqblk_t	 *d = (xfs_dqblk_t *)ddq; |  | ||||||
| 	int		errs = 0; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * 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)) { |  | ||||||
| 		if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 			xfs_alert(mp, |  | ||||||
| 			"%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", |  | ||||||
| 			str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); |  | ||||||
| 		errs++; |  | ||||||
| 	} |  | ||||||
| 	if (ddq->d_version != XFS_DQUOT_VERSION) { |  | ||||||
| 		if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 			xfs_alert(mp, |  | ||||||
| 			"%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", |  | ||||||
| 			str, id, ddq->d_version, XFS_DQUOT_VERSION); |  | ||||||
| 		errs++; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (ddq->d_flags != XFS_DQ_USER && |  | ||||||
| 	    ddq->d_flags != XFS_DQ_PROJ && |  | ||||||
| 	    ddq->d_flags != XFS_DQ_GROUP) { |  | ||||||
| 		if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 			xfs_alert(mp, |  | ||||||
| 			"%s : XFS dquot ID 0x%x, unknown flags 0x%x", |  | ||||||
| 			str, id, ddq->d_flags); |  | ||||||
| 		errs++; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (id != -1 && id != be32_to_cpu(ddq->d_id)) { |  | ||||||
| 		if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 			xfs_alert(mp, |  | ||||||
| 			"%s : ondisk-dquot 0x%p, ID mismatch: " |  | ||||||
| 			"0x%x expected, found id 0x%x", |  | ||||||
| 			str, ddq, id, be32_to_cpu(ddq->d_id)); |  | ||||||
| 		errs++; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!errs && ddq->d_id) { |  | ||||||
| 		if (ddq->d_blk_softlimit && |  | ||||||
| 		    be64_to_cpu(ddq->d_bcount) > |  | ||||||
| 				be64_to_cpu(ddq->d_blk_softlimit)) { |  | ||||||
| 			if (!ddq->d_btimer) { |  | ||||||
| 				if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 					xfs_alert(mp, |  | ||||||
| 			"%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", |  | ||||||
| 					str, (int)be32_to_cpu(ddq->d_id), ddq); |  | ||||||
| 				errs++; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if (ddq->d_ino_softlimit && |  | ||||||
| 		    be64_to_cpu(ddq->d_icount) > |  | ||||||
| 				be64_to_cpu(ddq->d_ino_softlimit)) { |  | ||||||
| 			if (!ddq->d_itimer) { |  | ||||||
| 				if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 					xfs_alert(mp, |  | ||||||
| 			"%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", |  | ||||||
| 					str, (int)be32_to_cpu(ddq->d_id), ddq); |  | ||||||
| 				errs++; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if (ddq->d_rtb_softlimit && |  | ||||||
| 		    be64_to_cpu(ddq->d_rtbcount) > |  | ||||||
| 				be64_to_cpu(ddq->d_rtb_softlimit)) { |  | ||||||
| 			if (!ddq->d_rtbtimer) { |  | ||||||
| 				if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 					xfs_alert(mp, |  | ||||||
| 			"%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", |  | ||||||
| 					str, (int)be32_to_cpu(ddq->d_id), ddq); |  | ||||||
| 				errs++; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) |  | ||||||
| 		return errs; |  | ||||||
| 
 |  | ||||||
| 	if (flags & XFS_QMOPT_DOWARN) |  | ||||||
| 		xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * Typically, a repair is only requested by quotacheck. |  | ||||||
| 	 */ |  | ||||||
| 	ASSERT(id != -1); |  | ||||||
| 	ASSERT(flags & XFS_QMOPT_DQREPAIR); |  | ||||||
| 	memset(d, 0, sizeof(xfs_dqblk_t)); |  | ||||||
| 
 |  | ||||||
| 	d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); |  | ||||||
| 	d->dd_diskdq.d_version = XFS_DQUOT_VERSION; |  | ||||||
| 	d->dd_diskdq.d_flags = type; |  | ||||||
| 	d->dd_diskdq.d_id = cpu_to_be32(id); |  | ||||||
| 
 |  | ||||||
| 	if (xfs_sb_version_hascrc(&mp->m_sb)) { |  | ||||||
| 		uuid_copy(&d->dd_uuid, &mp->m_sb.sb_uuid); |  | ||||||
| 		xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), |  | ||||||
| 				 XFS_DQUOT_CRC_OFF); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return errs; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /*
 | /*
 | ||||||
|  * Perform a dquot buffer recovery. |  * Perform a dquot buffer recovery. | ||||||
|  * Simple algorithm: if we have found a QUOTAOFF log item of the same type |  * Simple algorithm: if we have found a QUOTAOFF log item of the same type | ||||||
|  | @ -3126,7 +2999,7 @@ xlog_recover_dquot_pass2( | ||||||
| 	 */ | 	 */ | ||||||
| 	dq_f = item->ri_buf[0].i_addr; | 	dq_f = item->ri_buf[0].i_addr; | ||||||
| 	ASSERT(dq_f); | 	ASSERT(dq_f); | ||||||
| 	error = xfs_qm_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, | 	error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, | ||||||
| 			   "xlog_recover_dquot_pass2 (log copy)"); | 			   "xlog_recover_dquot_pass2 (log copy)"); | ||||||
| 	if (error) | 	if (error) | ||||||
| 		return XFS_ERROR(EIO); | 		return XFS_ERROR(EIO); | ||||||
|  | @ -3146,7 +3019,7 @@ xlog_recover_dquot_pass2( | ||||||
| 	 * was among a chunk of dquots created earlier, and we did some | 	 * was among a chunk of dquots created earlier, and we did some | ||||||
| 	 * minimal initialization then. | 	 * minimal initialization then. | ||||||
| 	 */ | 	 */ | ||||||
| 	error = xfs_qm_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, | 	error = xfs_dqcheck(mp, ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, | ||||||
| 			   "xlog_recover_dquot_pass2"); | 			   "xlog_recover_dquot_pass2"); | ||||||
| 	if (error) { | 	if (error) { | ||||||
| 		xfs_buf_relse(bp); | 		xfs_buf_relse(bp); | ||||||
|  |  | ||||||
|  | @ -665,20 +665,6 @@ xfs_qm_dqdetach( | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int |  | ||||||
| xfs_qm_calc_dquots_per_chunk( |  | ||||||
| 	struct xfs_mount	*mp, |  | ||||||
| 	unsigned int		nbblks)	/* basic block units */ |  | ||||||
| { |  | ||||||
| 	unsigned int	ndquots; |  | ||||||
| 
 |  | ||||||
| 	ASSERT(nbblks > 0); |  | ||||||
| 	ndquots = BBTOB(nbblks); |  | ||||||
| 	do_div(ndquots, sizeof(xfs_dqblk_t)); |  | ||||||
| 
 |  | ||||||
| 	return ndquots; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct xfs_qm_isolate { | struct xfs_qm_isolate { | ||||||
| 	struct list_head	buffers; | 	struct list_head	buffers; | ||||||
| 	struct list_head	dispose; | 	struct list_head	dispose; | ||||||
|  | @ -859,7 +845,7 @@ xfs_qm_init_quotainfo( | ||||||
| 
 | 
 | ||||||
| 	/* Precalc some constants */ | 	/* Precalc some constants */ | ||||||
| 	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); | 	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); | ||||||
| 	qinf->qi_dqperchunk = xfs_qm_calc_dquots_per_chunk(mp, | 	qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(mp, | ||||||
| 							qinf->qi_dqchunklen); | 							qinf->qi_dqchunklen); | ||||||
| 
 | 
 | ||||||
| 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); | 	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); | ||||||
|  | @ -1093,10 +1079,10 @@ xfs_qm_reset_dqcounts( | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Do a sanity check, and if needed, repair the dqblk. Don't | 		 * Do a sanity check, and if needed, repair the dqblk. Don't | ||||||
| 		 * output any warnings because it's perfectly possible to | 		 * output any warnings because it's perfectly possible to | ||||||
| 		 * find uninitialised dquot blks. See comment in xfs_qm_dqcheck. | 		 * find uninitialised dquot blks. See comment in xfs_dqcheck. | ||||||
| 		 */ | 		 */ | ||||||
| 		(void) xfs_qm_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR, | 		xfs_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR, | ||||||
| 				      "xfs_quotacheck"); | 			    "xfs_quotacheck"); | ||||||
| 		ddq->d_bcount = 0; | 		ddq->d_bcount = 0; | ||||||
| 		ddq->d_icount = 0; | 		ddq->d_icount = 0; | ||||||
| 		ddq->d_rtbcount = 0; | 		ddq->d_rtbcount = 0; | ||||||
|  |  | ||||||
|  | @ -103,8 +103,6 @@ xfs_dq_to_quota_inode(struct xfs_dquot *dqp) | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| extern int	xfs_qm_calc_dquots_per_chunk(struct xfs_mount *mp, |  | ||||||
| 					     unsigned int nbblks); |  | ||||||
| extern void	xfs_trans_mod_dquot(struct xfs_trans *, | extern void	xfs_trans_mod_dquot(struct xfs_trans *, | ||||||
| 					struct xfs_dquot *, uint, long); | 					struct xfs_dquot *, uint, long); | ||||||
| extern int	xfs_trans_reserve_quota_bydquots(struct xfs_trans *, | extern int	xfs_trans_reserve_quota_bydquots(struct xfs_trans *, | ||||||
|  |  | ||||||
|  | @ -150,8 +150,6 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp, | ||||||
| 	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \ | 	xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \ | ||||||
| 				f | XFS_QMOPT_RES_REGBLKS) | 				f | XFS_QMOPT_RES_REGBLKS) | ||||||
| 
 | 
 | ||||||
| extern int xfs_qm_dqcheck(struct xfs_mount *, xfs_disk_dquot_t *, |  | ||||||
| 				xfs_dqid_t, uint, uint, char *); |  | ||||||
| extern int xfs_mount_reset_sbqflags(struct xfs_mount *); | extern int xfs_mount_reset_sbqflags(struct xfs_mount *); | ||||||
| 
 | 
 | ||||||
| #endif	/* __XFS_QUOTA_H__ */ | #endif	/* __XFS_QUOTA_H__ */ | ||||||
|  |  | ||||||
|  | @ -154,4 +154,8 @@ typedef __uint16_t	xfs_qwarncnt_t; | ||||||
| 		(XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) | 		(XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) | ||||||
| #define XFS_QMOPT_RESBLK_MASK	(XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) | #define XFS_QMOPT_RESBLK_MASK	(XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) | ||||||
| 
 | 
 | ||||||
|  | extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq, | ||||||
|  | 		       xfs_dqid_t id, uint type, uint flags, char *str); | ||||||
|  | extern int xfs_calc_dquots_per_chunk(struct xfs_mount *mp, unsigned int nbblks); | ||||||
|  | 
 | ||||||
| #endif	/* __XFS_QUOTA_H__ */ | #endif	/* __XFS_QUOTA_H__ */ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Dave Chinner
						Dave Chinner