mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	xfs: Convert to new freezing code
Generic code now blocks all writers from standard write paths. So we add blocking of all writers coming from ioctl (we get a protection of ioctl against racing remount read-only as a bonus) and convert xfs_file_aio_write() to a non-racy freeze protection. We also keep freeze protection on transaction start to block internal filesystem writes such as removal of preallocated blocks. CC: Ben Myers <bpm@sgi.com> CC: Alex Elder <elder@kernel.org> CC: xfs@oss.sgi.com Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
		
							parent
							
								
									8e8ad8a57c
								
							
						
					
					
						commit
						d9457dc056
					
				
					 10 changed files with 109 additions and 16 deletions
				
			
		|  | @ -123,6 +123,12 @@ xfs_setfilesize_trans_alloc( | |||
| 
 | ||||
| 	ioend->io_append_trans = tp; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We will pass freeze protection with a transaction.  So tell lockdep | ||||
| 	 * we released it. | ||||
| 	 */ | ||||
| 	rwsem_release(&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], | ||||
| 		      1, _THIS_IP_); | ||||
| 	/*
 | ||||
| 	 * We hand off the transaction to the completion thread now, so | ||||
| 	 * clear the flag here. | ||||
|  | @ -199,6 +205,15 @@ xfs_end_io( | |||
| 	struct xfs_inode *ip = XFS_I(ioend->io_inode); | ||||
| 	int		error = 0; | ||||
| 
 | ||||
| 	if (ioend->io_append_trans) { | ||||
| 		/*
 | ||||
| 		 * We've got freeze protection passed with the transaction. | ||||
| 		 * Tell lockdep about it. | ||||
| 		 */ | ||||
| 		rwsem_acquire_read( | ||||
| 			&ioend->io_inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], | ||||
| 			0, 1, _THIS_IP_); | ||||
| 	} | ||||
| 	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { | ||||
| 		ioend->io_error = -EIO; | ||||
| 		goto done; | ||||
|  | @ -1410,6 +1425,9 @@ out_trans_cancel: | |||
| 	if (ioend->io_append_trans) { | ||||
| 		current_set_flags_nested(&ioend->io_append_trans->t_pflags, | ||||
| 					 PF_FSTRANS); | ||||
| 		rwsem_acquire_read( | ||||
| 			&inode->i_sb->s_writers.lock_map[SB_FREEZE_FS-1], | ||||
| 			0, 1, _THIS_IP_); | ||||
| 		xfs_trans_cancel(ioend->io_append_trans, 0); | ||||
| 	} | ||||
| out_destroy_ioend: | ||||
|  |  | |||
|  | @ -781,10 +781,12 @@ xfs_file_aio_write( | |||
| 	if (ocount == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	xfs_wait_for_freeze(ip->i_mount, SB_FREEZE_WRITE); | ||||
| 	sb_start_write(inode->i_sb); | ||||
| 
 | ||||
| 	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) | ||||
| 		return -EIO; | ||||
| 	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { | ||||
| 		ret = -EIO; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (unlikely(file->f_flags & O_DIRECT)) | ||||
| 		ret = xfs_file_dio_aio_write(iocb, iovp, nr_segs, pos, ocount); | ||||
|  | @ -803,6 +805,8 @@ xfs_file_aio_write( | |||
| 			ret = err; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	sb_end_write(inode->i_sb); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -364,9 +364,15 @@ xfs_fssetdm_by_handle( | |||
| 	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) | ||||
| 		return -XFS_ERROR(EFAULT); | ||||
| 
 | ||||
| 	error = mnt_want_write_file(parfilp); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 
 | ||||
| 	dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq); | ||||
| 	if (IS_ERR(dentry)) | ||||
| 	if (IS_ERR(dentry)) { | ||||
| 		mnt_drop_write_file(parfilp); | ||||
| 		return PTR_ERR(dentry); | ||||
| 	} | ||||
| 
 | ||||
| 	if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode)) { | ||||
| 		error = -XFS_ERROR(EPERM); | ||||
|  | @ -382,6 +388,7 @@ xfs_fssetdm_by_handle( | |||
| 				 fsd.fsd_dmstate); | ||||
| 
 | ||||
|  out: | ||||
| 	mnt_drop_write_file(parfilp); | ||||
| 	dput(dentry); | ||||
| 	return error; | ||||
| } | ||||
|  | @ -634,7 +641,11 @@ xfs_ioc_space( | |||
| 	if (ioflags & IO_INVIS) | ||||
| 		attr_flags |= XFS_ATTR_DMI; | ||||
| 
 | ||||
| 	error = mnt_want_write_file(filp); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 	error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags); | ||||
| 	mnt_drop_write_file(filp); | ||||
| 	return -error; | ||||
| } | ||||
| 
 | ||||
|  | @ -1163,6 +1174,7 @@ xfs_ioc_fssetxattr( | |||
| { | ||||
| 	struct fsxattr		fa; | ||||
| 	unsigned int		mask; | ||||
| 	int error; | ||||
| 
 | ||||
| 	if (copy_from_user(&fa, arg, sizeof(fa))) | ||||
| 		return -EFAULT; | ||||
|  | @ -1171,7 +1183,12 @@ xfs_ioc_fssetxattr( | |||
| 	if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) | ||||
| 		mask |= FSX_NONBLOCK; | ||||
| 
 | ||||
| 	return -xfs_ioctl_setattr(ip, &fa, mask); | ||||
| 	error = mnt_want_write_file(filp); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 	error = xfs_ioctl_setattr(ip, &fa, mask); | ||||
| 	mnt_drop_write_file(filp); | ||||
| 	return -error; | ||||
| } | ||||
| 
 | ||||
| STATIC int | ||||
|  | @ -1196,6 +1213,7 @@ xfs_ioc_setxflags( | |||
| 	struct fsxattr		fa; | ||||
| 	unsigned int		flags; | ||||
| 	unsigned int		mask; | ||||
| 	int error; | ||||
| 
 | ||||
| 	if (copy_from_user(&flags, arg, sizeof(flags))) | ||||
| 		return -EFAULT; | ||||
|  | @ -1210,7 +1228,12 @@ xfs_ioc_setxflags( | |||
| 		mask |= FSX_NONBLOCK; | ||||
| 	fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); | ||||
| 
 | ||||
| 	return -xfs_ioctl_setattr(ip, &fa, mask); | ||||
| 	error = mnt_want_write_file(filp); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 	error = xfs_ioctl_setattr(ip, &fa, mask); | ||||
| 	mnt_drop_write_file(filp); | ||||
| 	return -error; | ||||
| } | ||||
| 
 | ||||
| STATIC int | ||||
|  | @ -1385,8 +1408,13 @@ xfs_file_ioctl( | |||
| 		if (copy_from_user(&dmi, arg, sizeof(dmi))) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 
 | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 
 | ||||
| 		error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask, | ||||
| 				dmi.fsd_dmstate); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1434,7 +1462,11 @@ xfs_file_ioctl( | |||
| 
 | ||||
| 		if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t))) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_swapext(&sxp); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1463,9 +1495,14 @@ xfs_file_ioctl( | |||
| 		if (copy_from_user(&inout, arg, sizeof(inout))) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 
 | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 
 | ||||
| 		/* input parameter is passed in resblks field of structure */ | ||||
| 		in = inout.resblks; | ||||
| 		error = xfs_reserve_blocks(mp, &in, &inout); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		if (error) | ||||
| 			return -error; | ||||
| 
 | ||||
|  | @ -1496,7 +1533,11 @@ xfs_file_ioctl( | |||
| 		if (copy_from_user(&in, arg, sizeof(in))) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 
 | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_growfs_data(mp, &in); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1506,7 +1547,11 @@ xfs_file_ioctl( | |||
| 		if (copy_from_user(&in, arg, sizeof(in))) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 
 | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_growfs_log(mp, &in); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1516,7 +1561,11 @@ xfs_file_ioctl( | |||
| 		if (copy_from_user(&in, arg, sizeof(in))) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 
 | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_growfs_rt(mp, &in); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -600,7 +600,11 @@ xfs_file_compat_ioctl( | |||
| 
 | ||||
| 		if (xfs_compat_growfs_data_copyin(&in, arg)) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_growfs_data(mp, &in); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 	case XFS_IOC_FSGROWFSRT_32: { | ||||
|  | @ -608,7 +612,11 @@ xfs_file_compat_ioctl( | |||
| 
 | ||||
| 		if (xfs_compat_growfs_rt_copyin(&in, arg)) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_growfs_rt(mp, &in); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| #endif | ||||
|  | @ -627,7 +635,11 @@ xfs_file_compat_ioctl( | |||
| 				   offsetof(struct xfs_swapext, sx_stat)) || | ||||
| 		    xfs_ioctl32_bstat_copyin(&sxp.sx_stat, &sxu->sx_stat)) | ||||
| 			return -XFS_ERROR(EFAULT); | ||||
| 		error = mnt_want_write_file(filp); | ||||
| 		if (error) | ||||
| 			return error; | ||||
| 		error = xfs_swapext(&sxp); | ||||
| 		mnt_drop_write_file(filp); | ||||
| 		return -error; | ||||
| 	} | ||||
| 	case XFS_IOC_FSBULKSTAT_32: | ||||
|  |  | |||
|  | @ -680,9 +680,9 @@ xfs_iomap_write_unwritten( | |||
| 		 * the same inode that we complete here and might deadlock | ||||
| 		 * on the iolock. | ||||
| 		 */ | ||||
| 		xfs_wait_for_freeze(mp, SB_FREEZE_TRANS); | ||||
| 		sb_start_intwrite(mp->m_super); | ||||
| 		tp = _xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE, KM_NOFS); | ||||
| 		tp->t_flags |= XFS_TRANS_RESERVE; | ||||
| 		tp->t_flags |= XFS_TRANS_RESERVE | XFS_TRANS_FREEZE_PROT; | ||||
| 		error = xfs_trans_reserve(tp, resblks, | ||||
| 				XFS_WRITE_LOG_RES(mp), 0, | ||||
| 				XFS_TRANS_PERM_LOG_RES, | ||||
|  |  | |||
|  | @ -1544,7 +1544,7 @@ xfs_unmountfs( | |||
| int | ||||
| xfs_fs_writable(xfs_mount_t *mp) | ||||
| { | ||||
| 	return !(xfs_test_for_freeze(mp) || XFS_FORCED_SHUTDOWN(mp) || | ||||
| 	return !(mp->m_super->s_writers.frozen || XFS_FORCED_SHUTDOWN(mp) || | ||||
| 		(mp->m_flags & XFS_MOUNT_RDONLY)); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -314,9 +314,6 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, | |||
| #define SHUTDOWN_REMOTE_REQ	0x0010	/* shutdown came from remote cell */ | ||||
| #define SHUTDOWN_DEVICE_REQ	0x0020	/* failed all paths to the device */ | ||||
| 
 | ||||
| #define xfs_test_for_freeze(mp)		((mp)->m_super->s_frozen) | ||||
| #define xfs_wait_for_freeze(mp,l)	vfs_check_frozen((mp)->m_super, (l)) | ||||
| 
 | ||||
| /*
 | ||||
|  * Flags for xfs_mountfs | ||||
|  */ | ||||
|  |  | |||
|  | @ -394,7 +394,7 @@ xfs_sync_worker( | |||
| 	if (!(mp->m_super->s_flags & MS_ACTIVE) && | ||||
| 	    !(mp->m_flags & XFS_MOUNT_RDONLY)) { | ||||
| 		/* dgc: errors ignored here */ | ||||
| 		if (mp->m_super->s_frozen == SB_UNFROZEN && | ||||
| 		if (mp->m_super->s_writers.frozen == SB_UNFROZEN && | ||||
| 		    xfs_log_need_covered(mp)) | ||||
| 			error = xfs_fs_log_dummy(mp); | ||||
| 		else | ||||
|  |  | |||
|  | @ -576,8 +576,12 @@ xfs_trans_alloc( | |||
| 	xfs_mount_t	*mp, | ||||
| 	uint		type) | ||||
| { | ||||
| 	xfs_wait_for_freeze(mp, SB_FREEZE_TRANS); | ||||
| 	return _xfs_trans_alloc(mp, type, KM_SLEEP); | ||||
| 	xfs_trans_t     *tp; | ||||
| 
 | ||||
| 	sb_start_intwrite(mp->m_super); | ||||
| 	tp = _xfs_trans_alloc(mp, type, KM_SLEEP); | ||||
| 	tp->t_flags |= XFS_TRANS_FREEZE_PROT; | ||||
| 	return tp; | ||||
| } | ||||
| 
 | ||||
| xfs_trans_t * | ||||
|  | @ -588,6 +592,7 @@ _xfs_trans_alloc( | |||
| { | ||||
| 	xfs_trans_t	*tp; | ||||
| 
 | ||||
| 	WARN_ON(mp->m_super->s_writers.frozen == SB_FREEZE_COMPLETE); | ||||
| 	atomic_inc(&mp->m_active_trans); | ||||
| 
 | ||||
| 	tp = kmem_zone_zalloc(xfs_trans_zone, memflags); | ||||
|  | @ -611,6 +616,8 @@ xfs_trans_free( | |||
| 	xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false); | ||||
| 
 | ||||
| 	atomic_dec(&tp->t_mountp->m_active_trans); | ||||
| 	if (tp->t_flags & XFS_TRANS_FREEZE_PROT) | ||||
| 		sb_end_intwrite(tp->t_mountp->m_super); | ||||
| 	xfs_trans_free_dqinfo(tp); | ||||
| 	kmem_zone_free(xfs_trans_zone, tp); | ||||
| } | ||||
|  | @ -643,7 +650,11 @@ xfs_trans_dup( | |||
| 	ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); | ||||
| 	ASSERT(tp->t_ticket != NULL); | ||||
| 
 | ||||
| 	ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE); | ||||
| 	ntp->t_flags = XFS_TRANS_PERM_LOG_RES | | ||||
| 		       (tp->t_flags & XFS_TRANS_RESERVE) | | ||||
| 		       (tp->t_flags & XFS_TRANS_FREEZE_PROT); | ||||
| 	/* We gave our writer reference to the new transaction */ | ||||
| 	tp->t_flags &= ~XFS_TRANS_FREEZE_PROT; | ||||
| 	ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket); | ||||
| 	ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; | ||||
| 	tp->t_blk_res = tp->t_blk_res_used; | ||||
|  |  | |||
|  | @ -179,6 +179,8 @@ struct xfs_log_item_desc { | |||
| #define	XFS_TRANS_SYNC		0x08	/* make commit synchronous */ | ||||
| #define XFS_TRANS_DQ_DIRTY	0x10	/* at least one dquot in trx dirty */ | ||||
| #define XFS_TRANS_RESERVE	0x20    /* OK to use reserved data blocks */ | ||||
| #define XFS_TRANS_FREEZE_PROT	0x40	/* Transaction has elevated writer | ||||
| 					   count in superblock */ | ||||
| 
 | ||||
| /*
 | ||||
|  * Values for call flags parameter. | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Jan Kara
						Jan Kara