diff options
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
| -rw-r--r-- | fs/xfs/xfs_vnodeops.c | 125 | 
1 files changed, 72 insertions, 53 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 52c41714ec5..de17aed578f 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -133,7 +133,7 @@ xfs_getattr(  	if (!(flags & ATTR_LAZY))  		xfs_ilock(ip, XFS_ILOCK_SHARED); -	vap->va_size = ip->i_d.di_size; +	vap->va_size = XFS_ISIZE(ip);  	if (vap->va_mask == XFS_AT_SIZE)  		goto all_done; @@ -496,7 +496,7 @@ xfs_setattr(  	if (mask & XFS_AT_SIZE) {  		/* Short circuit the truncate case for zero length files */  		if ((vap->va_size == 0) && -		   (ip->i_d.di_size == 0) && (ip->i_d.di_nextents == 0)) { +		   (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) {  			xfs_iunlock(ip, XFS_ILOCK_EXCL);  			lock_flags &= ~XFS_ILOCK_EXCL;  			if (mask & XFS_AT_CTIME) @@ -614,7 +614,7 @@ xfs_setattr(  	 */  	if (mask & XFS_AT_SIZE) {  		code = 0; -		if ((vap->va_size > ip->i_d.di_size) &&  +		if ((vap->va_size > ip->i_size) &&  		    (flags & ATTR_NOSIZETOK) == 0) {  			code = xfs_igrow_start(ip, vap->va_size, credp);  		} @@ -654,10 +654,10 @@ xfs_setattr(  	 * Truncate file.  Must have write permission and not be a directory.  	 */  	if (mask & XFS_AT_SIZE) { -		if (vap->va_size > ip->i_d.di_size) { +		if (vap->va_size > ip->i_size) {  			xfs_igrow_finish(tp, ip, vap->va_size,  			    !(flags & ATTR_DMI)); -		} else if ((vap->va_size <= ip->i_d.di_size) || +		} else if ((vap->va_size <= ip->i_size) ||  			   ((vap->va_size == 0) && ip->i_d.di_nextents)) {  			/*  			 * signal a sync transaction unless @@ -873,7 +873,7 @@ xfs_setattr(  		if (mp->m_flags & XFS_MOUNT_WSYNC)  			xfs_trans_set_sync(tp); -		code = xfs_trans_commit(tp, commit_flags, NULL); +		code = xfs_trans_commit(tp, commit_flags);  	}  	/* @@ -1176,7 +1176,7 @@ xfs_fsync(  		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);  		if (flag & FSYNC_WAIT)  			xfs_trans_set_sync(tp); -		error = _xfs_trans_commit(tp, 0, NULL, &log_flushed); +		error = _xfs_trans_commit(tp, 0, &log_flushed);  		xfs_iunlock(ip, XFS_ILOCK_EXCL);  	} @@ -1221,7 +1221,7 @@ xfs_inactive_free_eofblocks(  	 * Figure out if there are any blocks beyond the end  	 * of the file.  If not, then there is nothing to do.  	 */ -	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_d.di_size)); +	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));  	last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));  	map_len = last_fsb - end_fsb;  	if (map_len <= 0) @@ -1257,8 +1257,12 @@ xfs_inactive_free_eofblocks(  		 * do that within a transaction.  		 */  		xfs_ilock(ip, XFS_IOLOCK_EXCL); -		xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, -				    ip->i_d.di_size); +		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, +				    ip->i_size); +		if (error) { +			xfs_iunlock(ip, XFS_IOLOCK_EXCL); +			return error; +		}  		error = xfs_trans_reserve(tp, 0,  					  XFS_ITRUNCATE_LOG_RES(mp), @@ -1278,7 +1282,7 @@ xfs_inactive_free_eofblocks(  		xfs_trans_ihold(tp, ip);  		error = xfs_itruncate_finish(&tp, ip, -					     ip->i_d.di_size, +					     ip->i_size,  					     XFS_DATA_FORK,  					     0);  		/* @@ -1291,8 +1295,7 @@ xfs_inactive_free_eofblocks(  					  XFS_TRANS_ABORT));  		} else {  			error = xfs_trans_commit(tp, -						XFS_TRANS_RELEASE_LOG_RES, -						NULL); +						XFS_TRANS_RELEASE_LOG_RES);  		}  		xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);  	} @@ -1406,7 +1409,7 @@ xfs_inactive_symlink_rmt(  	 * we need to unlock the inode since the new transaction doesn't  	 * have the inode attached.  	 */ -	error = xfs_trans_commit(tp, 0, NULL); +	error = xfs_trans_commit(tp, 0);  	tp = ntp;  	if (error) {  		ASSERT(XFS_FORCED_SHUTDOWN(mp)); @@ -1503,7 +1506,7 @@ xfs_inactive_attrs(  	tp = *tpp;  	mp = ip->i_mount;  	ASSERT(ip->i_d.di_forkoff != 0); -	xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	xfs_iunlock(ip, XFS_ILOCK_EXCL);  	error = xfs_attr_inactive(ip); @@ -1565,7 +1568,7 @@ xfs_release(  	if (ip->i_d.di_nlink != 0) {  		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && -		     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 || +		     ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||  		       ip->i_delayed_blks > 0)) &&  		     (ip->i_df.if_flags & XFS_IFEXTENTS))  &&  		    (!(ip->i_d.di_flags & @@ -1626,8 +1629,8 @@ xfs_inactive(  	 * only one with a reference to the inode.  	 */  	truncate = ((ip->i_d.di_nlink == 0) && -            ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0) || -             (ip->i_delayed_blks > 0)) && +	    ((ip->i_d.di_size != 0) || (ip->i_size != 0) || +	     (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&  	    ((ip->i_d.di_mode & S_IFMT) == S_IFREG));  	mp = ip->i_mount; @@ -1645,7 +1648,7 @@ xfs_inactive(  	if (ip->i_d.di_nlink != 0) {  		if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && -                     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 || +                     ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||                         ip->i_delayed_blks > 0)) &&  		      (ip->i_df.if_flags & XFS_IFEXTENTS) &&  		     (!(ip->i_d.di_flags & @@ -1675,7 +1678,11 @@ xfs_inactive(  		 */  		xfs_ilock(ip, XFS_IOLOCK_EXCL); -		xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); +		error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); +		if (error) { +			xfs_iunlock(ip, XFS_IOLOCK_EXCL); +			return VN_INACTIVE_CACHE; +		}  		error = xfs_trans_reserve(tp, 0,  					  XFS_ITRUNCATE_LOG_RES(mp), @@ -1790,7 +1797,7 @@ xfs_inactive(  		 * nothing we can do except to try to keep going.  		 */  		(void) xfs_bmap_finish(&tp,  &free_list, &committed); -		(void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +		(void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	}  	/*  	 * Release the dquots held by inode, if any. @@ -1940,7 +1947,7 @@ xfs_create(  		goto error_return;  	} -	xfs_ilock(dp, XFS_ILOCK_EXCL); +	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);  	XFS_BMAP_INIT(&free_list, &first_block); @@ -2026,7 +2033,7 @@ xfs_create(  		goto abort_rele;  	} -	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	if (error) {  		IRELE(ip);  		tp = NULL; @@ -2121,7 +2128,6 @@ int xfs_rm_attempts;  STATIC int  xfs_lock_dir_and_entry(  	xfs_inode_t	*dp, -	bhv_vname_t	*dentry,  	xfs_inode_t	*ip)	/* inode of entry 'name' */  {  	int		attempts; @@ -2135,7 +2141,7 @@ xfs_lock_dir_and_entry(  	attempts = 0;  again: -	xfs_ilock(dp, XFS_ILOCK_EXCL); +	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);  	e_inum = ip->i_ino; @@ -2204,6 +2210,21 @@ int xfs_lock_delays;  #endif  /* + * Bump the subclass so xfs_lock_inodes() acquires each lock with + * a different value + */ +static inline int +xfs_lock_inumorder(int lock_mode, int subclass) +{ +	if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)) +		lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT; +	if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) +		lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT; + +	return lock_mode; +} + +/*   * The following routine will lock n inodes in exclusive mode.   * We assume the caller calls us with the inodes in i_ino order.   * @@ -2270,7 +2291,7 @@ again:  			 * that is in the AIL.  			 */  			ASSERT(i != 0); -			if (!xfs_ilock_nowait(ips[i], lock_mode)) { +			if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {  				attempts++;  				/* @@ -2305,7 +2326,7 @@ again:  				goto again;  			}  		} else { -			xfs_ilock(ips[i], lock_mode); +			xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));  		}  	} @@ -2440,7 +2461,7 @@ xfs_remove(  		return error;  	} -	error = xfs_lock_dir_and_entry(dp, dentry, ip); +	error = xfs_lock_dir_and_entry(dp, ip);  	if (error) {  		REMOVE_DEBUG_TRACE(__LINE__);  		xfs_trans_cancel(tp, cancel_flags); @@ -2511,7 +2532,7 @@ xfs_remove(  		goto error_rele;  	} -	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	if (error) {  		IRELE(ip);  		goto std_return; @@ -2719,7 +2740,7 @@ xfs_link(  		goto abort_return;  	} -	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	if (error)  		goto std_return; @@ -2839,7 +2860,7 @@ xfs_mkdir(  		goto error_return;  	} -	xfs_ilock(dp, XFS_ILOCK_EXCL); +	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);  	/*  	 * Check for directory link count overflow. @@ -2936,7 +2957,7 @@ xfs_mkdir(  		goto error2;  	} -	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	XFS_QM_DQRELE(mp, udqp);  	XFS_QM_DQRELE(mp, gdqp);  	if (error) { @@ -3096,7 +3117,7 @@ xfs_rmdir(  	 * that the directory entry for the child directory inode has  	 * not changed while we were obtaining a log reservation.  	 */ -	error = xfs_lock_dir_and_entry(dp, dentry, cdp); +	error = xfs_lock_dir_and_entry(dp, cdp);  	if (error) {  		xfs_trans_cancel(tp, cancel_flags);  		IRELE(cdp); @@ -3190,7 +3211,7 @@ xfs_rmdir(  		goto std_return;  	} -	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	if (error) {  		IRELE(cdp);  		goto std_return; @@ -3393,7 +3414,7 @@ xfs_symlink(  		goto error_return;  	} -	xfs_ilock(dp, XFS_ILOCK_EXCL); +	xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);  	/*  	 * Check whether the directory allows new symlinks or not. @@ -3535,7 +3556,7 @@ xfs_symlink(  	if (error) {  		goto error2;  	} -	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  	XFS_QM_DQRELE(mp, udqp);  	XFS_QM_DQRELE(mp, gdqp); @@ -3790,7 +3811,7 @@ xfs_set_dmattrs (  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);  	IHOLD(ip); -	error = xfs_trans_commit(tp, 0, NULL); +	error = xfs_trans_commit(tp, 0);  	return error;  } @@ -4049,14 +4070,14 @@ xfs_alloc_file_space(  	allocatesize_fsb = XFS_B_TO_FSB(mp, count);  	/*	Generate a DMAPI event if needed.	*/ -	if (alloc_type != 0 && offset < ip->i_d.di_size && +	if (alloc_type != 0 && offset < ip->i_size &&  			(attr_flags&ATTR_DMI) == 0  &&  			DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {  		xfs_off_t           end_dmi_offset;  		end_dmi_offset = offset+len; -		if (end_dmi_offset > ip->i_d.di_size) -			end_dmi_offset = ip->i_d.di_size; +		if (end_dmi_offset > ip->i_size) +			end_dmi_offset = ip->i_size;  		error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),  			offset, end_dmi_offset - offset,  			0, NULL); @@ -4148,7 +4169,7 @@ retry:  			goto error0;  		} -		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  		xfs_iunlock(ip, XFS_ILOCK_EXCL);  		if (error) {  			break; @@ -4283,7 +4304,6 @@ xfs_free_file_space(  	int			error;  	xfs_fsblock_t		firstfsb;  	xfs_bmap_free_t		free_list; -	xfs_off_t		ilen;  	xfs_bmbt_irec_t		imap;  	xfs_off_t		ioffset;  	xfs_extlen_t		mod=0; @@ -4312,11 +4332,11 @@ xfs_free_file_space(  	end_dmi_offset = offset + len;  	endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); -	if (offset < ip->i_d.di_size && +	if (offset < ip->i_size &&  	    (attr_flags & ATTR_DMI) == 0 &&  	    DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { -		if (end_dmi_offset > ip->i_d.di_size) -			end_dmi_offset = ip->i_d.di_size; +		if (end_dmi_offset > ip->i_size) +			end_dmi_offset = ip->i_size;  		error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp,  				offset, end_dmi_offset - offset,  				AT_DELAY_FLAG(attr_flags), NULL); @@ -4332,16 +4352,15 @@ xfs_free_file_space(  	}  	rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP); -	ilen = len + (offset & (rounding - 1));  	ioffset = offset & ~(rounding - 1); -	if (ilen & (rounding - 1)) -		ilen = (ilen + rounding) & ~(rounding - 1);  	if (VN_CACHED(vp) != 0) {  		xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1,  				ctooff(offtoct(ioffset)), -1); -		bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)), +		error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)),  				-1, FI_REMAPF_LOCKED); +		if (error) +			goto out_unlock_iolock;  	}  	/* @@ -4455,7 +4474,7 @@ xfs_free_file_space(  			goto error0;  		} -		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); +		error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);  		xfs_iunlock(ip, XFS_ILOCK_EXCL);  	} @@ -4533,7 +4552,7 @@ xfs_change_file_space(  		bf->l_start += offset;  		break;  	case 2: /*SEEK_END*/ -		bf->l_start += ip->i_d.di_size; +		bf->l_start += ip->i_size;  		break;  	default:  		return XFS_ERROR(EINVAL); @@ -4550,7 +4569,7 @@ xfs_change_file_space(  	bf->l_whence = 0;  	startoffset = bf->l_start; -	fsize = ip->i_d.di_size; +	fsize = ip->i_size;  	/*  	 * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve @@ -4649,7 +4668,7 @@ xfs_change_file_space(  	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);  	xfs_trans_set_sync(tp); -	error = xfs_trans_commit(tp, 0, NULL); +	error = xfs_trans_commit(tp, 0);  	xfs_iunlock(ip, XFS_ILOCK_EXCL);  | 
