diff options
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_buf.c | 2 | ||||
| -rw-r--r-- | fs/xfs/linux-2.6/xfs_ioctl32.c | 2 | ||||
| -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 | 113 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 10 | ||||
| -rw-r--r-- | fs/xfs/xfs_log.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 4 | 
14 files changed, 112 insertions, 77 deletions
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 0c93c7ef3d1..965df1227d6 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -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_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c index 0882d166239..eafcc7c1870 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl32.c +++ b/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -619,7 +619,7 @@ xfs_file_compat_ioctl(  	case XFS_IOC_GETVERSION_32:  		cmd = _NATIVE_IOC(cmd, long);  		return xfs_file_ioctl(filp, cmd, p); -	case XFS_IOC_SWAPEXT: { +	case XFS_IOC_SWAPEXT_32: {  		struct xfs_swapext	  sxp;  		struct compat_xfs_swapext __user *sxu = arg; 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 34ec86923f7..ecbf8b4d2e2 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -191,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); @@ -274,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;  } 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_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",  | 
