diff options
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_export.c | 11 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl.c | 7 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 15 | ||||
| -rw-r--r-- | fs/xfs/quota/xfs_qm.c | 18 | ||||
| -rw-r--r-- | fs/xfs/quota/xfs_qm_syscalls.c | 27 | ||||
| -rw-r--r-- | fs/xfs/xfs_dfrag.c | 5 | ||||
| -rw-r--r-- | fs/xfs/xfs_ialloc.c | 142 | ||||
| -rw-r--r-- | fs/xfs/xfs_iget.c | 10 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 5 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.h | 6 | ||||
| -rw-r--r-- | fs/xfs/xfs_itable.c | 285 | ||||
| -rw-r--r-- | fs/xfs/xfs_itable.h | 17 | ||||
| -rw-r--r-- | fs/xfs/xfs_log_recover.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_rtalloc.c | 4 | ||||
| -rw-r--r-- | fs/xfs/xfs_trans_inode.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 2 | 
17 files changed, 172 insertions, 388 deletions
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index 846b75aeb2a..e7839ee49e4 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -128,13 +128,12 @@ xfs_nfs_get_inode(  		return ERR_PTR(-ESTALE);  	/* -	 * The XFS_IGET_BULKSTAT means that an invalid inode number is just -	 * fine and not an indication of a corrupted filesystem.  Because -	 * clients can send any kind of invalid file handle, e.g. after -	 * a restore on the server we have to deal with this case gracefully. +	 * The XFS_IGET_UNTRUSTED means that an invalid inode number is just +	 * fine and not an indication of a corrupted filesystem as clients can +	 * send invalid file handles and we have to handle it gracefully..  	 */ -	error = xfs_iget(mp, NULL, ino, XFS_IGET_BULKSTAT, -			 XFS_ILOCK_SHARED, &ip, 0); +	error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, +			 XFS_ILOCK_SHARED, &ip);  	if (error) {  		/*  		 * EINVAL means the inode cluster doesn't exist anymore. diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 699b60cbab9..e59a8106283 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -679,10 +679,9 @@ xfs_ioc_bulkstat(  		error = xfs_bulkstat_single(mp, &inlast,  						bulkreq.ubuffer, &done);  	else	/* XFS_IOC_FSBULKSTAT */ -		error = xfs_bulkstat(mp, &inlast, &count, -			(bulkstat_one_pf)xfs_bulkstat_one, NULL, -			sizeof(xfs_bstat_t), bulkreq.ubuffer, -			BULKSTAT_FG_QUICK, &done); +		error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, +				     sizeof(xfs_bstat_t), bulkreq.ubuffer, +				     &done);  	if (error)  		return -error; diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 9287135e9bf..52ed49e6465 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -237,15 +237,12 @@ xfs_bulkstat_one_compat(  	xfs_ino_t	ino,		/* inode number to get data for */  	void		__user *buffer,	/* buffer to place output in */  	int		ubsize,		/* size of buffer */ -	void		*private_data,	/* my private data */ -	xfs_daddr_t	bno,		/* starting bno of inode cluster */  	int		*ubused,	/* bytes used by me */ -	void		*dibuff,	/* on-disk inode buffer */  	int		*stat)		/* BULKSTAT_RV_... */  {  	return xfs_bulkstat_one_int(mp, ino, buffer, ubsize, -				    xfs_bulkstat_one_fmt_compat, bno, -				    ubused, dibuff, stat); +				    xfs_bulkstat_one_fmt_compat, +				    ubused, stat);  }  /* copied from xfs_ioctl.c */ @@ -298,13 +295,11 @@ xfs_compat_ioc_bulkstat(  		int res;  		error = xfs_bulkstat_one_compat(mp, inlast, bulkreq.ubuffer, -				sizeof(compat_xfs_bstat_t), -				NULL, 0, NULL, NULL, &res); +				sizeof(compat_xfs_bstat_t), 0, &res);  	} else if (cmd == XFS_IOC_FSBULKSTAT_32) {  		error = xfs_bulkstat(mp, &inlast, &count, -			xfs_bulkstat_one_compat, NULL, -			sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, -			BULKSTAT_FG_QUICK, &done); +			xfs_bulkstat_one_compat, sizeof(compat_xfs_bstat_t), +			bulkreq.ubuffer, &done);  	} else  		error = XFS_ERROR(EINVAL);  	if (error) diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 2d8b7bc792c..8c117ff2e3a 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -1632,10 +1632,7 @@ xfs_qm_dqusage_adjust(  	xfs_ino_t	ino,		/* inode number to get data for */  	void		__user *buffer,	/* not used */  	int		ubsize,		/* not used */ -	void		*private_data,	/* not used */ -	xfs_daddr_t	bno,		/* starting block of inode cluster */  	int		*ubused,	/* not used */ -	void		*dip,		/* on-disk inode pointer (not used) */  	int		*res)		/* result code value */  {  	xfs_inode_t	*ip; @@ -1660,7 +1657,7 @@ xfs_qm_dqusage_adjust(  	 * the case in all other instances. It's OK that we do this because  	 * quotacheck is done only at mount time.  	 */ -	if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip, bno))) { +	if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip))) {  		*res = BULKSTAT_RV_NOTHING;  		return error;  	} @@ -1796,12 +1793,13 @@ xfs_qm_quotacheck(  		 * Iterate thru all the inodes in the file system,  		 * adjusting the corresponding dquot counters in core.  		 */ -		if ((error = xfs_bulkstat(mp, &lastino, &count, -				     xfs_qm_dqusage_adjust, NULL, -				     structsz, NULL, BULKSTAT_FG_IGET, &done))) +		error = xfs_bulkstat(mp, &lastino, &count, +				     xfs_qm_dqusage_adjust, +				     structsz, NULL, &done); +		if (error)  			break; -	} while (! done); +	} while (!done);  	/*  	 * We've made all the changes that we need to make incore. @@ -1889,14 +1887,14 @@ xfs_qm_init_quotainos(  		    mp->m_sb.sb_uquotino != NULLFSINO) {  			ASSERT(mp->m_sb.sb_uquotino > 0);  			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, -					     0, 0, &uip, 0))) +					     0, 0, &uip)))  				return XFS_ERROR(error);  		}  		if (XFS_IS_OQUOTA_ON(mp) &&  		    mp->m_sb.sb_gquotino != NULLFSINO) {  			ASSERT(mp->m_sb.sb_gquotino > 0);  			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, -					     0, 0, &gip, 0))) { +					     0, 0, &gip))) {  				if (uip)  					IRELE(uip);  				return XFS_ERROR(error); diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index 92b002f1805..b4487764e92 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -262,7 +262,7 @@ xfs_qm_scall_trunc_qfiles(  	}  	if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) { -		error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip, 0); +		error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip);  		if (!error) {  			error = xfs_truncate_file(mp, qip);  			IRELE(qip); @@ -271,7 +271,7 @@ xfs_qm_scall_trunc_qfiles(  	if ((flags & (XFS_DQ_GROUP|XFS_DQ_PROJ)) &&  	    mp->m_sb.sb_gquotino != NULLFSINO) { -		error2 = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0); +		error2 = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip);  		if (!error2) {  			error2 = xfs_truncate_file(mp, qip);  			IRELE(qip); @@ -417,12 +417,12 @@ xfs_qm_scall_getqstat(  	}  	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {  		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, -					0, 0, &uip, 0) == 0) +					0, 0, &uip) == 0)  			tempuqip = B_TRUE;  	}  	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {  		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, -					0, 0, &gip, 0) == 0) +					0, 0, &gip) == 0)  			tempgqip = B_TRUE;  	}  	if (uip) { @@ -1109,10 +1109,7 @@ xfs_qm_internalqcheck_adjust(  	xfs_ino_t	ino,		/* inode number to get data for */  	void		__user *buffer,	/* not used */  	int		ubsize,		/* not used */ -	void		*private_data,	/* not used */ -	xfs_daddr_t	bno,		/* starting block of inode cluster */  	int		*ubused,	/* not used */ -	void		*dip,		/* not used */  	int		*res)		/* bulkstat result code */  {  	xfs_inode_t		*ip; @@ -1134,7 +1131,7 @@ xfs_qm_internalqcheck_adjust(  	ipreleased = B_FALSE;   again:  	lock_flags = XFS_ILOCK_SHARED; -	if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) { +	if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip))) {  		*res = BULKSTAT_RV_NOTHING;  		return (error);  	} @@ -1205,15 +1202,15 @@ xfs_qm_internalqcheck(  		 * Iterate thru all the inodes in the file system,  		 * adjusting the corresponding dquot counters  		 */ -		if ((error = xfs_bulkstat(mp, &lastino, &count, -				 xfs_qm_internalqcheck_adjust, NULL, -				 0, NULL, BULKSTAT_FG_IGET, &done))) { +		error = xfs_bulkstat(mp, &lastino, &count, +				 xfs_qm_internalqcheck_adjust, +				 0, NULL, &done); +		if (error) { +			cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error);  			break;  		} -	} while (! done); -	if (error) { -		cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error); -	} +	} while (!done); +  	cmn_err(CE_DEBUG, "Checking results against system dquots");  	for (i = 0; i < qmtest_hashmask; i++) {  		xfs_dqtest_t	*d, *n; diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 5bba29a0781..7f159d2a429 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -69,7 +69,9 @@ xfs_swapext(  		goto out;  	} -	if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) { +	if (!(file->f_mode & FMODE_WRITE) || +	    !(file->f_mode & FMODE_READ) || +	    (file->f_flags & O_APPEND)) {  		error = XFS_ERROR(EBADF);  		goto out_put_file;  	} @@ -81,6 +83,7 @@ xfs_swapext(  	}  	if (!(tmp_file->f_mode & FMODE_WRITE) || +	    !(tmp_file->f_mode & FMODE_READ) ||  	    (tmp_file->f_flags & O_APPEND)) {  		error = XFS_ERROR(EBADF);  		goto out_put_tmp_file; diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 9d884c127bb..c7142a064c4 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -1203,6 +1203,63 @@ error0:  	return error;  } +STATIC int +xfs_imap_lookup( +	struct xfs_mount	*mp, +	struct xfs_trans	*tp, +	xfs_agnumber_t		agno, +	xfs_agino_t		agino, +	xfs_agblock_t		agbno, +	xfs_agblock_t		*chunk_agbno, +	xfs_agblock_t		*offset_agbno, +	int			flags) +{ +	struct xfs_inobt_rec_incore rec; +	struct xfs_btree_cur	*cur; +	struct xfs_buf		*agbp; +	xfs_agino_t		startino; +	int			error; +	int			i; + +	error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); +	if (error) { +		xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " +				"xfs_ialloc_read_agi() returned " +				"error %d, agno %d", +				error, agno); +		return error; +	} + +	/* +	 * derive and lookup the exact inode record for the given agino. If the +	 * record cannot be found, then it's an invalid inode number and we +	 * should abort. +	 */ +	cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); +	startino = agino & ~(XFS_IALLOC_INODES(mp) - 1); +	error = xfs_inobt_lookup(cur, startino, XFS_LOOKUP_EQ, &i); +	if (!error) { +		if (i) +			error = xfs_inobt_get_rec(cur, &rec, &i); +		if (!error && i == 0) +			error = EINVAL; +	} + +	xfs_trans_brelse(tp, agbp); +	xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); +	if (error) +		return error; + +	/* for untrusted inodes check it is allocated first */ +	if ((flags & XFS_IGET_UNTRUSTED) && +	    (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))) +		return EINVAL; + +	*chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino); +	*offset_agbno = agbno - *chunk_agbno; +	return 0; +} +  /*   * Return the location of the inode in imap, for mapping it into a buffer.   */ @@ -1235,8 +1292,11 @@ xfs_imap(  	if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks ||  	    ino != XFS_AGINO_TO_INO(mp, agno, agino)) {  #ifdef DEBUG -		/* no diagnostics for bulkstat, ino comes from userspace */ -		if (flags & XFS_IGET_BULKSTAT) +		/* +		 * Don't output diagnostic information for untrusted inodes +		 * as they can be invalid without implying corruption. +		 */ +		if (flags & XFS_IGET_UNTRUSTED)  			return XFS_ERROR(EINVAL);  		if (agno >= mp->m_sb.sb_agcount) {  			xfs_fs_cmn_err(CE_ALERT, mp, @@ -1263,6 +1323,23 @@ xfs_imap(  		return XFS_ERROR(EINVAL);  	} +	blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; + +	/* +	 * For bulkstat and handle lookups, we have an untrusted inode number +	 * that we have to verify is valid. We cannot do this just by reading +	 * the inode buffer as it may have been unlinked and removed leaving +	 * inodes in stale state on disk. Hence we have to do a btree lookup +	 * in all cases where an untrusted inode number is passed. +	 */ +	if (flags & XFS_IGET_UNTRUSTED) { +		error = xfs_imap_lookup(mp, tp, agno, agino, agbno, +					&chunk_agbno, &offset_agbno, flags); +		if (error) +			return error; +		goto out_map; +	} +  	/*  	 * If the inode cluster size is the same as the blocksize or  	 * smaller we get to the buffer by simple arithmetics. @@ -1277,24 +1354,6 @@ xfs_imap(  		return 0;  	} -	blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; - -	/* -	 * If we get a block number passed from bulkstat we can use it to -	 * find the buffer easily. -	 */ -	if (imap->im_blkno) { -		offset = XFS_INO_TO_OFFSET(mp, ino); -		ASSERT(offset < mp->m_sb.sb_inopblock); - -		cluster_agbno = xfs_daddr_to_agbno(mp, imap->im_blkno); -		offset += (agbno - cluster_agbno) * mp->m_sb.sb_inopblock; - -		imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster); -		imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog); -		return 0; -	} -  	/*  	 * If the inode chunks are aligned then use simple maths to  	 * find the location. Otherwise we have to do a btree @@ -1304,50 +1363,13 @@ xfs_imap(  		offset_agbno = agbno & mp->m_inoalign_mask;  		chunk_agbno = agbno - offset_agbno;  	} else { -		xfs_btree_cur_t	*cur;	/* inode btree cursor */ -		xfs_inobt_rec_incore_t chunk_rec; -		xfs_buf_t	*agbp;	/* agi buffer */ -		int		i;	/* temp state */ - -		error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); -		if (error) { -			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " -					"xfs_ialloc_read_agi() returned " -					"error %d, agno %d", -					error, agno); -			return error; -		} - -		cur = xfs_inobt_init_cursor(mp, tp, agbp, agno); -		error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); -		if (error) { -			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " -					"xfs_inobt_lookup() failed"); -			goto error0; -		} - -		error = xfs_inobt_get_rec(cur, &chunk_rec, &i); -		if (error) { -			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " -					"xfs_inobt_get_rec() failed"); -			goto error0; -		} -		if (i == 0) { -#ifdef DEBUG -			xfs_fs_cmn_err(CE_ALERT, mp, "xfs_imap: " -					"xfs_inobt_get_rec() failed"); -#endif /* DEBUG */ -			error = XFS_ERROR(EINVAL); -		} - error0: -		xfs_trans_brelse(tp, agbp); -		xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); +		error = xfs_imap_lookup(mp, tp, agno, agino, agbno, +					&chunk_agbno, &offset_agbno, flags);  		if (error)  			return error; -		chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_rec.ir_startino); -		offset_agbno = agbno - chunk_agbno;  	} +out_map:  	ASSERT(agbno >= chunk_agbno);  	cluster_agbno = chunk_agbno +  		((offset_agbno / blks_per_cluster) * blks_per_cluster); diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 75df75f43d4..8f8b91be2c9 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -259,7 +259,6 @@ xfs_iget_cache_miss(  	xfs_trans_t		*tp,  	xfs_ino_t		ino,  	struct xfs_inode	**ipp, -	xfs_daddr_t		bno,  	int			flags,  	int			lock_flags)  { @@ -272,7 +271,7 @@ xfs_iget_cache_miss(  	if (!ip)  		return ENOMEM; -	error = xfs_iread(mp, tp, ip, bno, flags); +	error = xfs_iread(mp, tp, ip, flags);  	if (error)  		goto out_destroy; @@ -358,8 +357,6 @@ out_destroy:   *        within the file system for the inode being requested.   * lock_flags -- flags indicating how to lock the inode.  See the comment   *		 for xfs_ilock() for a list of valid values. - * bno -- the block number starting the buffer containing the inode, - *	  if known (as by bulkstat), else 0.   */  int  xfs_iget( @@ -368,8 +365,7 @@ xfs_iget(  	xfs_ino_t	ino,  	uint		flags,  	uint		lock_flags, -	xfs_inode_t	**ipp, -	xfs_daddr_t	bno) +	xfs_inode_t	**ipp)  {  	xfs_inode_t	*ip;  	int		error; @@ -397,7 +393,7 @@ again:  		read_unlock(&pag->pag_ici_lock);  		XFS_STATS_INC(xs_ig_missed); -		error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip, bno, +		error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip,  							flags, lock_flags);  		if (error)  			goto out_error_or_again; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d53c39de7d0..b76a829d7e2 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -177,7 +177,7 @@ xfs_imap_to_bp(  		if (unlikely(XFS_TEST_ERROR(!di_ok, mp,  						XFS_ERRTAG_ITOBP_INOTOBP,  						XFS_RANDOM_ITOBP_INOTOBP))) { -			if (iget_flags & XFS_IGET_BULKSTAT) { +			if (iget_flags & XFS_IGET_UNTRUSTED) {  				xfs_trans_brelse(tp, bp);  				return XFS_ERROR(EINVAL);  			} @@ -787,7 +787,6 @@ xfs_iread(  	xfs_mount_t	*mp,  	xfs_trans_t	*tp,  	xfs_inode_t	*ip, -	xfs_daddr_t	bno,  	uint		iget_flags)  {  	xfs_buf_t	*bp; @@ -797,11 +796,9 @@ xfs_iread(  	/*  	 * Fill in the location information in the in-core inode.  	 */ -	ip->i_imap.im_blkno = bno;  	error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags);  	if (error)  		return error; -	ASSERT(bno == 0 || bno == ip->i_imap.im_blkno);  	/*  	 * Get pointers to the on-disk inode and the buffer containing it. diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 9965e40a461..78550df13cd 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -442,7 +442,7 @@ static inline void xfs_ifunlock(xfs_inode_t *ip)   * xfs_iget.c prototypes.   */  int		xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, -			 uint, uint, xfs_inode_t **, xfs_daddr_t); +			 uint, uint, xfs_inode_t **);  void		xfs_iput(xfs_inode_t *, uint);  void		xfs_iput_new(xfs_inode_t *, uint);  void		xfs_ilock(xfs_inode_t *, uint); @@ -500,7 +500,7 @@ do { \   * Flags for xfs_iget()   */  #define XFS_IGET_CREATE		0x1 -#define XFS_IGET_BULKSTAT	0x2 +#define XFS_IGET_UNTRUSTED	0x2  int		xfs_inotobp(struct xfs_mount *, struct xfs_trans *,  			    xfs_ino_t, struct xfs_dinode **, @@ -509,7 +509,7 @@ int		xfs_itobp(struct xfs_mount *, struct xfs_trans *,  			  struct xfs_inode *, struct xfs_dinode **,  			  struct xfs_buf **, uint);  int		xfs_iread(struct xfs_mount *, struct xfs_trans *, -			  struct xfs_inode *, xfs_daddr_t, uint); +			  struct xfs_inode *, uint);  void		xfs_dinode_to_disk(struct xfs_dinode *,  				   struct xfs_icdinode *);  void		xfs_idestroy_fork(struct xfs_inode *, int); diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index b1b801e4a28..2b86f861051 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -49,24 +49,40 @@ xfs_internal_inum(  		 (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));  } -STATIC int -xfs_bulkstat_one_iget( -	xfs_mount_t	*mp,		/* mount point for filesystem */ -	xfs_ino_t	ino,		/* inode number to get data for */ -	xfs_daddr_t	bno,		/* starting bno of inode cluster */ -	xfs_bstat_t	*buf,		/* return buffer */ -	int		*stat)		/* BULKSTAT_RV_... */ +/* + * Return stat information for one inode. + * Return 0 if ok, else errno. + */ +int +xfs_bulkstat_one_int( +	struct xfs_mount	*mp,		/* mount point for filesystem */ +	xfs_ino_t		ino,		/* inode to get data for */ +	void __user		*buffer,	/* buffer to place output in */ +	int			ubsize,		/* size of buffer */ +	bulkstat_one_fmt_pf	formatter,	/* formatter, copy to user */ +	int			*ubused,	/* bytes used by me */ +	int			*stat)		/* BULKSTAT_RV_... */  { -	xfs_icdinode_t	*dic;	/* dinode core info pointer */ -	xfs_inode_t	*ip;		/* incore inode pointer */ -	struct inode	*inode; -	int		error; +	struct xfs_icdinode	*dic;		/* dinode core info pointer */ +	struct xfs_inode	*ip;		/* incore inode pointer */ +	struct inode		*inode; +	struct xfs_bstat	*buf;		/* return buffer */ +	int			error = 0;	/* error value */ + +	*stat = BULKSTAT_RV_NOTHING; + +	if (!buffer || xfs_internal_inum(mp, ino)) +		return XFS_ERROR(EINVAL); + +	buf = kmem_alloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL); +	if (!buf) +		return XFS_ERROR(ENOMEM);  	error = xfs_iget(mp, NULL, ino, -			 XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno); +			 XFS_IGET_UNTRUSTED, XFS_ILOCK_SHARED, &ip);  	if (error) {  		*stat = BULKSTAT_RV_NOTHING; -		return error; +		goto out_free;  	}  	ASSERT(ip != NULL); @@ -127,77 +143,16 @@ xfs_bulkstat_one_iget(  		buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks;  		break;  	} -  	xfs_iput(ip, XFS_ILOCK_SHARED); -	return error; -} -STATIC void -xfs_bulkstat_one_dinode( -	xfs_mount_t	*mp,		/* mount point for filesystem */ -	xfs_ino_t	ino,		/* inode number to get data for */ -	xfs_dinode_t	*dic,		/* dinode inode pointer */ -	xfs_bstat_t	*buf)		/* return buffer */ -{ -	/* -	 * The inode format changed when we moved the link count and -	 * made it 32 bits long.  If this is an old format inode, -	 * convert it in memory to look like a new one.  If it gets -	 * flushed to disk we will convert back before flushing or -	 * logging it.  We zero out the new projid field and the old link -	 * count field.  We'll handle clearing the pad field (the remains -	 * of the old uuid field) when we actually convert the inode to -	 * the new format. We don't change the version number so that we -	 * can distinguish this from a real new format inode. -	 */ -	if (dic->di_version == 1) { -		buf->bs_nlink = be16_to_cpu(dic->di_onlink); -		buf->bs_projid = 0; -	} else { -		buf->bs_nlink = be32_to_cpu(dic->di_nlink); -		buf->bs_projid = be16_to_cpu(dic->di_projid); -	} +	error = formatter(buffer, ubsize, ubused, buf); -	buf->bs_ino = ino; -	buf->bs_mode = be16_to_cpu(dic->di_mode); -	buf->bs_uid = be32_to_cpu(dic->di_uid); -	buf->bs_gid = be32_to_cpu(dic->di_gid); -	buf->bs_size = be64_to_cpu(dic->di_size); -	buf->bs_atime.tv_sec = be32_to_cpu(dic->di_atime.t_sec); -	buf->bs_atime.tv_nsec = be32_to_cpu(dic->di_atime.t_nsec); -	buf->bs_mtime.tv_sec = be32_to_cpu(dic->di_mtime.t_sec); -	buf->bs_mtime.tv_nsec = be32_to_cpu(dic->di_mtime.t_nsec); -	buf->bs_ctime.tv_sec = be32_to_cpu(dic->di_ctime.t_sec); -	buf->bs_ctime.tv_nsec = be32_to_cpu(dic->di_ctime.t_nsec); -	buf->bs_xflags = xfs_dic2xflags(dic); -	buf->bs_extsize = be32_to_cpu(dic->di_extsize) << mp->m_sb.sb_blocklog; -	buf->bs_extents = be32_to_cpu(dic->di_nextents); -	buf->bs_gen = be32_to_cpu(dic->di_gen); -	memset(buf->bs_pad, 0, sizeof(buf->bs_pad)); -	buf->bs_dmevmask = be32_to_cpu(dic->di_dmevmask); -	buf->bs_dmstate = be16_to_cpu(dic->di_dmstate); -	buf->bs_aextents = be16_to_cpu(dic->di_anextents); -	buf->bs_forkoff = XFS_DFORK_BOFF(dic); +	if (!error) +		*stat = BULKSTAT_RV_DIDONE; -	switch (dic->di_format) { -	case XFS_DINODE_FMT_DEV: -		buf->bs_rdev = xfs_dinode_get_rdev(dic); -		buf->bs_blksize = BLKDEV_IOSIZE; -		buf->bs_blocks = 0; -		break; -	case XFS_DINODE_FMT_LOCAL: -	case XFS_DINODE_FMT_UUID: -		buf->bs_rdev = 0; -		buf->bs_blksize = mp->m_sb.sb_blocksize; -		buf->bs_blocks = 0; -		break; -	case XFS_DINODE_FMT_EXTENTS: -	case XFS_DINODE_FMT_BTREE: -		buf->bs_rdev = 0; -		buf->bs_blksize = mp->m_sb.sb_blocksize; -		buf->bs_blocks = be64_to_cpu(dic->di_nblocks); -		break; -	} + out_free: +	kmem_free(buf); +	return error;  }  /* Return 0 on success or positive error */ @@ -217,118 +172,17 @@ xfs_bulkstat_one_fmt(  	return 0;  } -/* - * Return stat information for one inode. - * Return 0 if ok, else errno. - */ -int		   	    		/* error status */ -xfs_bulkstat_one_int( -	xfs_mount_t	*mp,		/* mount point for filesystem */ -	xfs_ino_t	ino,		/* inode number to get data for */ -	void		__user *buffer,	/* buffer to place output in */ -	int		ubsize,		/* size of buffer */ -	bulkstat_one_fmt_pf formatter,	/* formatter, copy to user */ -	xfs_daddr_t	bno,		/* starting bno of inode cluster */ -	int		*ubused,	/* bytes used by me */ -	void		*dibuff,	/* on-disk inode buffer */ -	int		*stat)		/* BULKSTAT_RV_... */ -{ -	xfs_bstat_t	*buf;		/* return buffer */ -	int		error = 0;	/* error value */ -	xfs_dinode_t	*dip;		/* dinode inode pointer */ - -	dip = (xfs_dinode_t *)dibuff; -	*stat = BULKSTAT_RV_NOTHING; - -	if (!buffer || xfs_internal_inum(mp, ino)) -		return XFS_ERROR(EINVAL); - -	buf = kmem_alloc(sizeof(*buf), KM_SLEEP); - -	if (dip == NULL) { -		/* We're not being passed a pointer to a dinode.  This happens -		 * if BULKSTAT_FG_IGET is selected.  Do the iget. -		 */ -		error = xfs_bulkstat_one_iget(mp, ino, bno, buf, stat); -		if (error) -			goto out_free; -	} else { -		xfs_bulkstat_one_dinode(mp, ino, dip, buf); -	} - -	error = formatter(buffer, ubsize, ubused, buf); -	if (error) -		goto out_free; - -	*stat = BULKSTAT_RV_DIDONE; - - out_free: -	kmem_free(buf); -	return error; -} -  int  xfs_bulkstat_one(  	xfs_mount_t	*mp,		/* mount point for filesystem */  	xfs_ino_t	ino,		/* inode number to get data for */  	void		__user *buffer,	/* buffer to place output in */  	int		ubsize,		/* size of buffer */ -	void		*private_data,	/* my private data */ -	xfs_daddr_t	bno,		/* starting bno of inode cluster */  	int		*ubused,	/* bytes used by me */ -	void		*dibuff,	/* on-disk inode buffer */  	int		*stat)		/* BULKSTAT_RV_... */  {  	return xfs_bulkstat_one_int(mp, ino, buffer, ubsize, -				    xfs_bulkstat_one_fmt, bno, -				    ubused, dibuff, stat); -} - -/* - * Test to see whether we can use the ondisk inode directly, based - * on the given bulkstat flags, filling in dipp accordingly. - * Returns zero if the inode is dodgey. - */ -STATIC int -xfs_bulkstat_use_dinode( -	xfs_mount_t	*mp, -	int		flags, -	xfs_buf_t	*bp, -	int		clustidx, -	xfs_dinode_t	**dipp) -{ -	xfs_dinode_t	*dip; -	unsigned int	aformat; - -	*dipp = NULL; -	if (!bp || (flags & BULKSTAT_FG_IGET)) -		return 1; -	dip = (xfs_dinode_t *) -			xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog); -	/* -	 * Check the buffer containing the on-disk inode for di_mode == 0. -	 * This is to prevent xfs_bulkstat from picking up just reclaimed -	 * inodes that have their in-core state initialized but not flushed -	 * to disk yet. This is a temporary hack that would require a proper -	 * fix in the future. -	 */ -	if (be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC || -	    !XFS_DINODE_GOOD_VERSION(dip->di_version) || -	    !dip->di_mode) -		return 0; -	if (flags & BULKSTAT_FG_QUICK) { -		*dipp = dip; -		return 1; -	} -	/* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */ -	aformat = dip->di_aformat; -	if ((XFS_DFORK_Q(dip) == 0) || -	    (aformat == XFS_DINODE_FMT_LOCAL) || -	    (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_anextents)) { -		*dipp = dip; -		return 1; -	} -	return 1; +				    xfs_bulkstat_one_fmt, ubused, stat);  }  #define XFS_BULKSTAT_UBLEFT(ubleft)	((ubleft) >= statstruct_size) @@ -342,10 +196,8 @@ xfs_bulkstat(  	xfs_ino_t		*lastinop, /* last inode returned */  	int			*ubcountp, /* size of buffer/count returned */  	bulkstat_one_pf		formatter, /* func that'd fill a single buf */ -	void			*private_data,/* private data for formatter */  	size_t			statstruct_size, /* sizeof struct filling */  	char			__user *ubuffer, /* buffer with inode stats */ -	int			flags,	/* defined in xfs_itable.h */  	int			*done)	/* 1 if there are more stats to get */  {  	xfs_agblock_t		agbno=0;/* allocation group block number */ @@ -380,14 +232,12 @@ xfs_bulkstat(  	int			ubelem;	/* spaces used in user's buffer */  	int			ubused;	/* bytes used by formatter */  	xfs_buf_t		*bp;	/* ptr to on-disk inode cluster buf */ -	xfs_dinode_t		*dip;	/* ptr into bp for specific inode */  	/*  	 * Get the last inode value, see if there's nothing to do.  	 */  	ino = (xfs_ino_t)*lastinop;  	lastino = ino; -	dip = NULL;  	agno = XFS_INO_TO_AGNO(mp, ino);  	agino = XFS_INO_TO_AGINO(mp, ino);  	if (agno >= mp->m_sb.sb_agcount || @@ -612,37 +462,6 @@ xfs_bulkstat(  							irbp->ir_startino) +  						((chunkidx & nimask) >>  						 mp->m_sb.sb_inopblog); - -					if (flags & (BULKSTAT_FG_QUICK | -						     BULKSTAT_FG_INLINE)) { -						int offset; - -						ino = XFS_AGINO_TO_INO(mp, agno, -								       agino); -						bno = XFS_AGB_TO_DADDR(mp, agno, -								       agbno); - -						/* -						 * Get the inode cluster buffer -						 */ -						if (bp) -							xfs_buf_relse(bp); - -						error = xfs_inotobp(mp, NULL, ino, &dip, -								    &bp, &offset, -								    XFS_IGET_BULKSTAT); - -						if (!error) -							clustidx = offset / mp->m_sb.sb_inodesize; -						if (XFS_TEST_ERROR(error != 0, -								   mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK, -								   XFS_RANDOM_BULKSTAT_READ_CHUNK)) { -							bp = NULL; -							ubleft = 0; -							rval = error; -							break; -						} -					}  				}  				ino = XFS_AGINO_TO_INO(mp, agno, agino);  				bno = XFS_AGB_TO_DADDR(mp, agno, agbno); @@ -658,35 +477,13 @@ xfs_bulkstat(  				 * when the chunk is used up.  				 */  				irbp->ir_freecount++; -				if (!xfs_bulkstat_use_dinode(mp, flags, bp, -							     clustidx, &dip)) { -					lastino = ino; -					continue; -				} -				/* -				 * If we need to do an iget, cannot hold bp. -				 * Drop it, until starting the next cluster. -				 */ -				if ((flags & BULKSTAT_FG_INLINE) && !dip) { -					if (bp) -						xfs_buf_relse(bp); -					bp = NULL; -				}  				/*  				 * Get the inode and fill in a single buffer. -				 * BULKSTAT_FG_QUICK uses dip to fill it in. -				 * BULKSTAT_FG_IGET uses igets. -				 * BULKSTAT_FG_INLINE uses dip if we have an -				 * inline attr fork, else igets. -				 * See: xfs_bulkstat_one & xfs_dm_bulkstat_one. -				 * This is also used to count inodes/blks, etc -				 * in xfs_qm_quotacheck.  				 */  				ubused = statstruct_size; -				error = formatter(mp, ino, ubufp, -						ubleft, private_data, -						bno, &ubused, dip, &fmterror); +				error = formatter(mp, ino, ubufp, ubleft, +						  &ubused, &fmterror);  				if (fmterror == BULKSTAT_RV_NOTHING) {  					if (error && error != ENOENT &&  						error != EINVAL) { @@ -778,8 +575,7 @@ xfs_bulkstat_single(  	 */  	ino = (xfs_ino_t)*lastinop; -	error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), -				 NULL, 0, NULL, NULL, &res); +	error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), 0, &res);  	if (error) {  		/*  		 * Special case way failed, do it the "long" way @@ -788,8 +584,7 @@ xfs_bulkstat_single(  		(*lastinop)--;  		count = 1;  		if (xfs_bulkstat(mp, lastinop, &count, xfs_bulkstat_one, -				NULL, sizeof(xfs_bstat_t), buffer, -				BULKSTAT_FG_IGET, done)) +				sizeof(xfs_bstat_t), buffer, done))  			return error;  		if (count == 0 || (xfs_ino_t)*lastinop != ino)  			return error == EFSCORRUPTED ? diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index 20792bf4594..97295d91d17 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h @@ -27,10 +27,7 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount	*mp,  			       xfs_ino_t	ino,  			       void		__user *buffer,  			       int		ubsize, -			       void		*private_data, -			       xfs_daddr_t	bno,  			       int		*ubused, -			       void		*dip,  			       int		*stat);  /* @@ -41,13 +38,6 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount	*mp,  #define BULKSTAT_RV_GIVEUP	2  /* - * Values for bulkstat flag argument. - */ -#define BULKSTAT_FG_IGET	0x1	/* Go through the buffer cache */ -#define BULKSTAT_FG_QUICK	0x2	/* No iget, walk the dinode cluster */ -#define BULKSTAT_FG_INLINE	0x4	/* No iget if inline attrs */ - -/*   * Return stat information in bulk (by-inode) for the filesystem.   */  int					/* error status */ @@ -56,10 +46,8 @@ xfs_bulkstat(  	xfs_ino_t	*lastino,	/* last inode returned */  	int		*count,		/* size of buffer/count returned */  	bulkstat_one_pf formatter,	/* func that'd fill a single buf */ -	void		*private_data,	/* private data for formatter */  	size_t		statstruct_size,/* sizeof struct that we're filling */  	char		__user *ubuffer,/* buffer with inode stats */ -	int		flags,		/* flag to control access method */  	int		*done);		/* 1 if there are more stats to get */  int @@ -82,9 +70,7 @@ xfs_bulkstat_one_int(  	void			__user *buffer,  	int			ubsize,  	bulkstat_one_fmt_pf	formatter, -	xfs_daddr_t		bno,  	int			*ubused, -	void			*dibuff,  	int			*stat);  int @@ -93,10 +79,7 @@ xfs_bulkstat_one(  	xfs_ino_t		ino,  	void			__user *buffer,  	int			ubsize, -	void			*private_data, -	xfs_daddr_t		bno,  	int			*ubused, -	void			*dibuff,  	int			*stat);  typedef int (*inumbers_fmt_pf)( diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index ed0684cc50e..9ac5cfab27b 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3198,7 +3198,7 @@ xlog_recover_process_one_iunlink(  	int				error;  	ino = XFS_AGINO_TO_INO(mp, agno, agino); -	error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0); +	error = xfs_iget(mp, NULL, ino, 0, 0, &ip);  	if (error)  		goto fail; diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index d59f4e8bedc..69f62d8b281 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -1300,7 +1300,7 @@ xfs_mountfs(  	 * Get and sanity-check the root inode.  	 * Save the pointer to it in the mount structure.  	 */ -	error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0); +	error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip);  	if (error) {  		cmn_err(CE_WARN, "XFS: failed to read root inode");  		goto out_log_dealloc; diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 16445518506..a2d32ce335a 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -2277,12 +2277,12 @@ xfs_rtmount_inodes(  	sbp = &mp->m_sb;  	if (sbp->sb_rbmino == NULLFSINO)  		return 0; -	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0); +	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);  	if (error)  		return error;  	ASSERT(mp->m_rbmip != NULL);  	ASSERT(sbp->sb_rsumino != NULLFSINO); -	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0); +	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);  	if (error) {  		IRELE(mp->m_rbmip);  		return error; diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index 785ff101da0..2559dfec946 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c @@ -62,7 +62,7 @@ xfs_trans_iget(  {  	int			error; -	error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp, 0); +	error = xfs_iget(mp, tp, ino, flags, lock_flags, ipp);  	if (!error && tp)  		xfs_trans_ijoin(tp, *ipp, lock_flags);  	return error; diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index a06bd62504f..c1646838898 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -1269,7 +1269,7 @@ xfs_lookup(  	if (error)  		goto out; -	error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0); +	error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);  	if (error)  		goto out_free_name;  |