xfs: I/O completion handlers must use NOFS allocations
When completing I/O requests we must not allow the memory allocator to recurse into the filesystem, as we might deadlock on waiting for the I/O completion otherwise. The only thing currently allocating normal GFP_KERNEL memory is the allocation of the transaction structure for the unwritten extent conversion. Add a memflags argument to _xfs_trans_alloc to allow controlling the allocator behaviour. Signed-off-by: Christoph Hellwig <hch@lst.de> Reported-by: Thomas Neumann <tneumann@users.sourceforge.net> Tested-by: Thomas Neumann <tneumann@users.sourceforge.net> Reviewed-by: Alex Elder <aelder@sgi.com> Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
		
							parent
							
								
									c56c9631cb
								
							
						
					
					
						commit
						80641dc66a
					
				| @ -611,7 +611,7 @@ xfs_fs_log_dummy( | ||||
| 	xfs_inode_t	*ip; | ||||
| 	int		error; | ||||
| 
 | ||||
| 	tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); | ||||
| 	tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1, KM_SLEEP); | ||||
| 	error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); | ||||
| 	if (error) { | ||||
| 		xfs_trans_cancel(tp, 0); | ||||
|  | ||||
| @ -860,8 +860,15 @@ xfs_iomap_write_unwritten( | ||||
| 		 * set up a transaction to convert the range of extents | ||||
| 		 * from unwritten to real. Do allocations in a loop until | ||||
| 		 * we have covered the range passed in. | ||||
| 		 * | ||||
| 		 * Note that we open code the transaction allocation here | ||||
| 		 * to pass KM_NOFS--we can't risk to recursing back into | ||||
| 		 * the filesystem here as we might be asked to write out | ||||
| 		 * the same inode that we complete here and might deadlock | ||||
| 		 * on the iolock. | ||||
| 		 */ | ||||
| 		tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE); | ||||
| 		xfs_wait_for_freeze(mp, SB_FREEZE_TRANS); | ||||
| 		tp = _xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE, KM_NOFS); | ||||
| 		tp->t_flags |= XFS_TRANS_RESERVE; | ||||
| 		error = xfs_trans_reserve(tp, resblks, | ||||
| 				XFS_WRITE_LOG_RES(mp), 0, | ||||
|  | ||||
| @ -1471,7 +1471,7 @@ xfs_log_sbcount( | ||||
| 	if (!xfs_sb_version_haslazysbcount(&mp->m_sb)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT); | ||||
| 	tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT, KM_SLEEP); | ||||
| 	error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, | ||||
| 					XFS_DEFAULT_LOG_COUNT); | ||||
| 	if (error) { | ||||
|  | ||||
| @ -236,19 +236,20 @@ xfs_trans_alloc( | ||||
| 	uint		type) | ||||
| { | ||||
| 	xfs_wait_for_freeze(mp, SB_FREEZE_TRANS); | ||||
| 	return _xfs_trans_alloc(mp, type); | ||||
| 	return _xfs_trans_alloc(mp, type, KM_SLEEP); | ||||
| } | ||||
| 
 | ||||
| xfs_trans_t * | ||||
| _xfs_trans_alloc( | ||||
| 	xfs_mount_t	*mp, | ||||
| 	uint		type) | ||||
| 	uint		type, | ||||
| 	uint		memflags) | ||||
| { | ||||
| 	xfs_trans_t	*tp; | ||||
| 
 | ||||
| 	atomic_inc(&mp->m_active_trans); | ||||
| 
 | ||||
| 	tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); | ||||
| 	tp = kmem_zone_zalloc(xfs_trans_zone, memflags); | ||||
| 	tp->t_magic = XFS_TRANS_MAGIC; | ||||
| 	tp->t_type = type; | ||||
| 	tp->t_mountp = mp; | ||||
|  | ||||
| @ -924,7 +924,7 @@ typedef struct xfs_trans { | ||||
|  * XFS transaction mechanism exported interfaces. | ||||
|  */ | ||||
| xfs_trans_t	*xfs_trans_alloc(struct xfs_mount *, uint); | ||||
| xfs_trans_t	*_xfs_trans_alloc(struct xfs_mount *, uint); | ||||
| xfs_trans_t	*_xfs_trans_alloc(struct xfs_mount *, uint, uint); | ||||
| xfs_trans_t	*xfs_trans_dup(xfs_trans_t *); | ||||
| int		xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, | ||||
| 				  uint, uint); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user