diff options
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/linux-2.6/kmem.c | 4 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_aops.c | 8 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 4 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 1 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.c | 4 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.c | 13 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_sync.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_attr.c | 8 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_btree.c | 4 | ||||
| -rw-r--r-- | fs/xfs/xfs_da_btree.c | 6 | ||||
| -rw-r--r-- | fs/xfs/xfs_dir2.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_fsops.c | 20 | ||||
| -rw-r--r-- | fs/xfs/xfs_iget.c | 253 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 10 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.h | 17 | ||||
| -rw-r--r-- | fs/xfs/xfs_log.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 4 | 
18 files changed, 196 insertions, 167 deletions
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c index 1cd3b55ee3d..2d3f90afe5f 100644 --- a/fs/xfs/linux-2.6/kmem.c +++ b/fs/xfs/linux-2.6/kmem.c @@ -53,7 +53,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags)  			printk(KERN_ERR "XFS: possible memory allocation "  					"deadlock in %s (mode:0x%x)\n",  					__func__, lflags); -		congestion_wait(WRITE, HZ/50); +		congestion_wait(BLK_RW_ASYNC, HZ/50);  	} while (1);  } @@ -130,7 +130,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)  			printk(KERN_ERR "XFS: possible memory allocation "  					"deadlock in %s (mode:0x%x)\n",  					__func__, lflags); -		congestion_wait(WRITE, HZ/50); +		congestion_wait(BLK_RW_ASYNC, HZ/50);  	} while (1);  } diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 7ec89fc05b2..aecf2519db7 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -1268,6 +1268,14 @@ xfs_vm_writepage(  	if (!page_has_buffers(page))  		create_empty_buffers(page, 1 << inode->i_blkbits, 0); + +	/* +	 *  VM calculation for nr_to_write seems off.  Bump it way +	 *  up, this gets simple streaming writes zippy again. +	 *  To be reviewed again after Jens' writeback changes. +	 */ +	wbc->nr_to_write *= 4; +  	/*  	 * Convert delayed allocate, unwritten or unmapped space  	 * to real space and flush out to disk. diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 1418b916fc2..965df1227d6 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -412,7 +412,7 @@ _xfs_buf_lookup_pages(  			XFS_STATS_INC(xb_page_retries);  			xfsbufd_wakeup(0, gfp_mask); -			congestion_wait(WRITE, HZ/50); +			congestion_wait(BLK_RW_ASYNC, HZ/50);  			goto retry;  		} @@ -770,7 +770,7 @@ xfs_buf_associate_memory(  	bp->b_pages = NULL;  	bp->b_addr = mem; -	rval = _xfs_buf_get_pages(bp, page_count, 0); +	rval = _xfs_buf_get_pages(bp, page_count, XBF_DONT_BLOCK);  	if (rval)  		return rval; diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index f4e25544157..0542fd50764 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -41,7 +41,6 @@  #include "xfs_ioctl.h"  #include <linux/dcache.h> -#include <linux/smp_lock.h>  static struct vm_operations_struct xfs_file_vm_ops; diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 58973bb4603..8070b34cc28 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -680,8 +680,8 @@ xfs_vn_fiemap(  	else  		bm.bmv_length = BTOBB(length); -	/* our formatter will tell xfs_getbmap when to stop. */ -	bm.bmv_count = MAXEXTNUM; +	/* We add one because in getbmap world count includes the header */ +	bm.bmv_count = fieinfo->fi_extents_max + 1;  	bm.bmv_iflags = BMV_IF_PREALLOC;  	if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR)  		bm.bmv_iflags |= BMV_IF_ATTRFORK; diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index b619d6b8ca4..98ef624d9ba 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -708,6 +708,16 @@ xfs_reclaim_inode(  	return 0;  } +void +__xfs_inode_set_reclaim_tag( +	struct xfs_perag	*pag, +	struct xfs_inode	*ip) +{ +	radix_tree_tag_set(&pag->pag_ici_root, +			   XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), +			   XFS_ICI_RECLAIM_TAG); +} +  /*   * We set the inode flag atomically with the radix tree tag.   * Once we get tag lookups on the radix tree, this inode flag @@ -722,8 +732,7 @@ xfs_inode_set_reclaim_tag(  	read_lock(&pag->pag_ici_lock);  	spin_lock(&ip->i_flags_lock); -	radix_tree_tag_set(&pag->pag_ici_root, -			XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG); +	__xfs_inode_set_reclaim_tag(pag, ip);  	__xfs_iflags_set(ip, XFS_IRECLAIMABLE);  	spin_unlock(&ip->i_flags_lock);  	read_unlock(&pag->pag_ici_lock); diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index 2a10301c99c..59120602588 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h @@ -48,6 +48,7 @@ int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode);  int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);  void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); +void __xfs_inode_set_reclaim_tag(struct xfs_perag *pag, struct xfs_inode *ip);  void xfs_inode_clear_reclaim_tag(struct xfs_inode *ip);  void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, struct xfs_perag *pag,  				struct xfs_inode *ip); diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index db15feb906f..4ece1906bd4 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -2010,7 +2010,9 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)  			dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);  			blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);  			error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, -					     blkcnt, XFS_BUF_LOCK, &bp); +					     blkcnt, +					     XFS_BUF_LOCK | XBF_DONT_BLOCK, +					     &bp);  			if (error)  				return(error); @@ -2141,8 +2143,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)  		dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),  		blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); -		bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, -							blkcnt, XFS_BUF_LOCK); +		bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, blkcnt, +				       XFS_BUF_LOCK | XBF_DONT_BLOCK);  		ASSERT(bp);  		ASSERT(!XFS_BUF_GETERROR(bp)); diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 7928b9983c1..8ee5b5a76a2 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -6009,7 +6009,7 @@ xfs_getbmap(  	 */  	error = ENOMEM;  	subnex = 16; -	map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL); +	map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS);  	if (!map)  		goto out_unlock_ilock; diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index e9df9957482..26717388acf 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c @@ -120,8 +120,8 @@ xfs_btree_check_sblock(  			XFS_RANDOM_BTREE_CHECK_SBLOCK))) {  		if (bp)  			xfs_buftrace("SBTREE ERROR", bp); -		XFS_ERROR_REPORT("xfs_btree_check_sblock", XFS_ERRLEVEL_LOW, -				 cur->bc_mp); +		XFS_CORRUPTION_ERROR("xfs_btree_check_sblock", +			XFS_ERRLEVEL_LOW, cur->bc_mp, block);  		return XFS_ERROR(EFSCORRUPTED);  	}  	return 0; diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 9ff6e57a507..2847bbc1c53 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -2201,7 +2201,7 @@ kmem_zone_t *xfs_dabuf_zone;		/* dabuf zone */  xfs_da_state_t *  xfs_da_state_alloc(void)  { -	return kmem_zone_zalloc(xfs_da_state_zone, KM_SLEEP); +	return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS);  }  /* @@ -2261,9 +2261,9 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra)  	int		off;  	if (nbuf == 1) -		dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_SLEEP); +		dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_NOFS);  	else -		dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_SLEEP); +		dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_NOFS);  	dabuf->dirty = 0;  #ifdef XFS_DABUF_DEBUG  	dabuf->ra = ra; diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c index c657bec6d95..bb1d58eb398 100644 --- a/fs/xfs/xfs_dir2.c +++ b/fs/xfs/xfs_dir2.c @@ -256,7 +256,7 @@ xfs_dir_cilookup_result(  					!(args->op_flags & XFS_DA_OP_CILOOKUP))  		return EEXIST; -	args->value = kmem_alloc(len, KM_MAYFAIL); +	args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL);  	if (!args->value)  		return ENOMEM; diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index cbd451bb484..2d0b3e1da9e 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -167,17 +167,25 @@ xfs_growfs_data_private(  	new = nb - mp->m_sb.sb_dblocks;  	oagcount = mp->m_sb.sb_agcount;  	if (nagcount > oagcount) { +		void *new_perag, *old_perag; +  		xfs_filestream_flush(mp); + +		new_perag = kmem_zalloc(sizeof(xfs_perag_t) * nagcount, +					KM_MAYFAIL); +		if (!new_perag) +			return XFS_ERROR(ENOMEM); +  		down_write(&mp->m_peraglock); -		mp->m_perag = kmem_realloc(mp->m_perag, -			sizeof(xfs_perag_t) * nagcount, -			sizeof(xfs_perag_t) * oagcount, -			KM_SLEEP); -		memset(&mp->m_perag[oagcount], 0, -			(nagcount - oagcount) * sizeof(xfs_perag_t)); +		memcpy(new_perag, mp->m_perag, sizeof(xfs_perag_t) * oagcount); +		old_perag = mp->m_perag; +		mp->m_perag = new_perag; +  		mp->m_flags |= XFS_MOUNT_32BITINODES;  		nagimax = xfs_initialize_perag(mp, nagcount);  		up_write(&mp->m_peraglock); + +		kmem_free(old_perag);  	}  	tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);  	tp->t_flags |= XFS_TRANS_RESERVE; diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 5fcec6f020a..ecbf8b4d2e2 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -64,6 +64,10 @@ xfs_inode_alloc(  	ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP);  	if (!ip)  		return NULL; +	if (inode_init_always(mp->m_super, VFS_I(ip))) { +		kmem_zone_free(xfs_inode_zone, ip); +		return NULL; +	}  	ASSERT(atomic_read(&ip->i_iocount) == 0);  	ASSERT(atomic_read(&ip->i_pincount) == 0); @@ -105,17 +109,6 @@ xfs_inode_alloc(  #ifdef XFS_DIR2_TRACE  	ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);  #endif -	/* -	* Now initialise the VFS inode. We do this after the xfs_inode -	* initialisation as internal failures will result in ->destroy_inode -	* being called and that will pass down through the reclaim path and -	* free the XFS inode. This path requires the XFS inode to already be -	* initialised. Hence if this call fails, the xfs_inode has already -	* been freed and we should not reference it at all in the error -	* handling. -	*/ -	if (!inode_init_always(mp->m_super, VFS_I(ip))) -		return NULL;  	/* prevent anyone from using this yet */  	VFS_I(ip)->i_state = I_NEW|I_LOCK; @@ -123,6 +116,71 @@ xfs_inode_alloc(  	return ip;  } +STATIC void +xfs_inode_free( +	struct xfs_inode	*ip) +{ +	switch (ip->i_d.di_mode & S_IFMT) { +	case S_IFREG: +	case S_IFDIR: +	case S_IFLNK: +		xfs_idestroy_fork(ip, XFS_DATA_FORK); +		break; +	} + +	if (ip->i_afp) +		xfs_idestroy_fork(ip, XFS_ATTR_FORK); + +#ifdef XFS_INODE_TRACE +	ktrace_free(ip->i_trace); +#endif +#ifdef XFS_BMAP_TRACE +	ktrace_free(ip->i_xtrace); +#endif +#ifdef XFS_BTREE_TRACE +	ktrace_free(ip->i_btrace); +#endif +#ifdef XFS_RW_TRACE +	ktrace_free(ip->i_rwtrace); +#endif +#ifdef XFS_ILOCK_TRACE +	ktrace_free(ip->i_lock_trace); +#endif +#ifdef XFS_DIR2_TRACE +	ktrace_free(ip->i_dir_trace); +#endif + +	if (ip->i_itemp) { +		/* +		 * Only if we are shutting down the fs will we see an +		 * inode still in the AIL. If it is there, we should remove +		 * it to prevent a use-after-free from occurring. +		 */ +		xfs_log_item_t	*lip = &ip->i_itemp->ili_item; +		struct xfs_ail	*ailp = lip->li_ailp; + +		ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || +				       XFS_FORCED_SHUTDOWN(ip->i_mount)); +		if (lip->li_flags & XFS_LI_IN_AIL) { +			spin_lock(&ailp->xa_lock); +			if (lip->li_flags & XFS_LI_IN_AIL) +				xfs_trans_ail_delete(ailp, lip); +			else +				spin_unlock(&ailp->xa_lock); +		} +		xfs_inode_item_destroy(ip); +		ip->i_itemp = NULL; +	} + +	/* asserts to verify all state is correct here */ +	ASSERT(atomic_read(&ip->i_iocount) == 0); +	ASSERT(atomic_read(&ip->i_pincount) == 0); +	ASSERT(!spin_is_locked(&ip->i_flags_lock)); +	ASSERT(completion_done(&ip->i_flush)); + +	kmem_zone_free(xfs_inode_zone, ip); +} +  /*   * Check the validity of the inode we just found it the cache   */ @@ -133,80 +191,82 @@ xfs_iget_cache_hit(  	int			flags,  	int			lock_flags) __releases(pag->pag_ici_lock)  { +	struct inode		*inode = VFS_I(ip);  	struct xfs_mount	*mp = ip->i_mount; -	int			error = EAGAIN; +	int			error; + +	spin_lock(&ip->i_flags_lock);  	/* -	 * If INEW is set this inode is being set up -	 * If IRECLAIM is set this inode is being torn down -	 * Pause and try again. +	 * If we are racing with another cache hit that is currently +	 * instantiating this inode or currently recycling it out of +	 * reclaimabe state, wait for the initialisation to complete +	 * before continuing. +	 * +	 * XXX(hch): eventually we should do something equivalent to +	 *	     wait_on_inode to wait for these flags to be cleared +	 *	     instead of polling for it.  	 */ -	if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) { +	if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) {  		XFS_STATS_INC(xs_ig_frecycle); +		error = EAGAIN;  		goto out_error;  	} -	/* If IRECLAIMABLE is set, we've torn down the vfs inode part */ -	if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) { - -		/* -		 * If lookup is racing with unlink, then we should return an -		 * error immediately so we don't remove it from the reclaim -		 * list and potentially leak the inode. -		 */ -		if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) { -			error = ENOENT; -			goto out_error; -		} +	/* +	 * If lookup is racing with unlink return an error immediately. +	 */ +	if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) { +		error = ENOENT; +		goto out_error; +	} +	/* +	 * If IRECLAIMABLE is set, we've torn down the VFS inode already. +	 * Need to carefully get it back into useable state. +	 */ +	if (ip->i_flags & XFS_IRECLAIMABLE) {  		xfs_itrace_exit_tag(ip, "xfs_iget.alloc");  		/* -		 * We need to re-initialise the VFS inode as it has been -		 * 'freed' by the VFS. Do this here so we can deal with -		 * errors cleanly, then tag it so it can be set up correctly -		 * later. +		 * We need to set XFS_INEW atomically with clearing the +		 * reclaimable tag so that we do have an indicator of the +		 * inode still being initialized.  		 */ -		if (!inode_init_always(mp->m_super, VFS_I(ip))) { -			error = ENOMEM; -			goto out_error; -		} +		ip->i_flags |= XFS_INEW; +		ip->i_flags &= ~XFS_IRECLAIMABLE; +		__xfs_inode_clear_reclaim_tag(mp, pag, ip); -		/* -		 * We must set the XFS_INEW flag before clearing the -		 * XFS_IRECLAIMABLE flag so that if a racing lookup does -		 * not find the XFS_IRECLAIMABLE above but has the igrab() -		 * below succeed we can safely check XFS_INEW to detect -		 * that this inode is still being initialised. -		 */ -		xfs_iflags_set(ip, XFS_INEW); -		xfs_iflags_clear(ip, XFS_IRECLAIMABLE); +		spin_unlock(&ip->i_flags_lock); +		read_unlock(&pag->pag_ici_lock); -		/* clear the radix tree reclaim flag as well. */ -		__xfs_inode_clear_reclaim_tag(mp, pag, ip); -	} else if (!igrab(VFS_I(ip))) { +		error = -inode_init_always(mp->m_super, inode); +		if (error) { +			/* +			 * Re-initializing the inode failed, and we are in deep +			 * trouble.  Try to re-add it to the reclaim list. +			 */ +			read_lock(&pag->pag_ici_lock); +			spin_lock(&ip->i_flags_lock); + +			ip->i_flags &= ~XFS_INEW; +			ip->i_flags |= XFS_IRECLAIMABLE; +			__xfs_inode_set_reclaim_tag(pag, ip); +			goto out_error; +		} +		inode->i_state = I_LOCK|I_NEW; +	} else {  		/* If the VFS inode is being torn down, pause and try again. */ -		XFS_STATS_INC(xs_ig_frecycle); -		goto out_error; -	} else if (xfs_iflags_test(ip, XFS_INEW)) { -		/* -		 * We are racing with another cache hit that is -		 * currently recycling this inode out of the XFS_IRECLAIMABLE -		 * state. Wait for the initialisation to complete before -		 * continuing. -		 */ -		wait_on_inode(VFS_I(ip)); -	} +		if (!igrab(inode)) { +			error = EAGAIN; +			goto out_error; +		} -	if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) { -		error = ENOENT; -		iput(VFS_I(ip)); -		goto out_error; +		/* We've got a live one. */ +		spin_unlock(&ip->i_flags_lock); +		read_unlock(&pag->pag_ici_lock);  	} -	/* We've got a live one. */ -	read_unlock(&pag->pag_ici_lock); -  	if (lock_flags != 0)  		xfs_ilock(ip, lock_flags); @@ -216,6 +276,7 @@ xfs_iget_cache_hit(  	return 0;  out_error: +	spin_unlock(&ip->i_flags_lock);  	read_unlock(&pag->pag_ici_lock);  	return error;  } @@ -299,7 +360,8 @@ out_preload_end:  	if (lock_flags)  		xfs_iunlock(ip, lock_flags);  out_destroy: -	xfs_destroy_inode(ip); +	__destroy_inode(VFS_I(ip)); +	xfs_inode_free(ip);  	return error;  } @@ -504,62 +566,7 @@ xfs_ireclaim(  	xfs_qm_dqdetach(ip);  	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); -	switch (ip->i_d.di_mode & S_IFMT) { -	case S_IFREG: -	case S_IFDIR: -	case S_IFLNK: -		xfs_idestroy_fork(ip, XFS_DATA_FORK); -		break; -	} - -	if (ip->i_afp) -		xfs_idestroy_fork(ip, XFS_ATTR_FORK); - -#ifdef XFS_INODE_TRACE -	ktrace_free(ip->i_trace); -#endif -#ifdef XFS_BMAP_TRACE -	ktrace_free(ip->i_xtrace); -#endif -#ifdef XFS_BTREE_TRACE -	ktrace_free(ip->i_btrace); -#endif -#ifdef XFS_RW_TRACE -	ktrace_free(ip->i_rwtrace); -#endif -#ifdef XFS_ILOCK_TRACE -	ktrace_free(ip->i_lock_trace); -#endif -#ifdef XFS_DIR2_TRACE -	ktrace_free(ip->i_dir_trace); -#endif -	if (ip->i_itemp) { -		/* -		 * Only if we are shutting down the fs will we see an -		 * inode still in the AIL. If it is there, we should remove -		 * it to prevent a use-after-free from occurring. -		 */ -		xfs_log_item_t	*lip = &ip->i_itemp->ili_item; -		struct xfs_ail	*ailp = lip->li_ailp; - -		ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || -				       XFS_FORCED_SHUTDOWN(ip->i_mount)); -		if (lip->li_flags & XFS_LI_IN_AIL) { -			spin_lock(&ailp->xa_lock); -			if (lip->li_flags & XFS_LI_IN_AIL) -				xfs_trans_ail_delete(ailp, lip); -			else -				spin_unlock(&ailp->xa_lock); -		} -		xfs_inode_item_destroy(ip); -		ip->i_itemp = NULL; -	} -	/* asserts to verify all state is correct here */ -	ASSERT(atomic_read(&ip->i_iocount) == 0); -	ASSERT(atomic_read(&ip->i_pincount) == 0); -	ASSERT(!spin_is_locked(&ip->i_flags_lock)); -	ASSERT(completion_done(&ip->i_flush)); -	kmem_zone_free(xfs_inode_zone, ip); +	xfs_inode_free(ip);  }  /* diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 1f22d65fed0..da428b3fe0f 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -343,6 +343,16 @@ xfs_iformat(  		return XFS_ERROR(EFSCORRUPTED);  	} +	if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && +		     !ip->i_mount->m_rtdev_targp)) { +		xfs_fs_repair_cmn_err(CE_WARN, ip->i_mount, +			"corrupt dinode %Lu, has realtime flag set.", +			ip->i_ino); +		XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", +				     XFS_ERRLEVEL_LOW, ip->i_mount, dip); +		return XFS_ERROR(EFSCORRUPTED); +	} +  	switch (ip->i_d.di_mode & S_IFMT) {  	case S_IFIFO:  	case S_IFCHR: diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 1804f866a71..65f24a3cc99 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -310,23 +310,6 @@ static inline struct inode *VFS_I(struct xfs_inode *ip)  }  /* - * Get rid of a partially initialized inode. - * - * We have to go through destroy_inode to make sure allocations - * from init_inode_always like the security data are undone. - * - * We mark the inode bad so that it takes the short cut in - * the reclaim path instead of going through the flush path - * which doesn't make sense for an inode that has never seen the - * light of day. - */ -static inline void xfs_destroy_inode(struct xfs_inode *ip) -{ -	make_bad_inode(VFS_I(ip)); -	return destroy_inode(VFS_I(ip)); -} - -/*   * i_flags helper functions   */  static inline void diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 3750f04ede0..9dbdff3ea48 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -3180,7 +3180,7 @@ try_again:  STATIC void  xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog)  { -	ASSERT(spin_is_locked(&log->l_icloglock)); +	assert_spin_locked(&log->l_icloglock);  	if (iclog->ic_state == XLOG_STATE_ACTIVE) {  		xlog_state_switch_iclogs(log, iclog, 0); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index c4eca5ed5da..492d75bae2b 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -538,7 +538,9 @@ xfs_readlink_bmap(  		d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);  		byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); -		bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0); +		bp = xfs_buf_read_flags(mp->m_ddev_targp, d, BTOBB(byte_cnt), +					XBF_LOCK | XBF_MAPPED | +					XBF_DONT_BLOCK);  		error = XFS_BUF_GETERROR(bp);  		if (error) {  			xfs_ioerror_alert("xfs_readlink",  |