Beispiel #1
0
/*
 * Update on-disk file size now that data has been written to disk.
 */
STATIC int
xfs_setfilesize(
	struct xfs_ioend	*ioend)
{
	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
	struct xfs_trans	*tp = ioend->io_append_trans;
	xfs_fsize_t		isize;

	/*
	 * The transaction may have been allocated in the I/O submission thread,
	 * thus we need to mark ourselves as beeing in a transaction manually.
	 * Similarly for freeze protection.
	 */
	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
	rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
			   0, 1, _THIS_IP_);

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
	if (!isize) {
		xfs_iunlock(ip, XFS_ILOCK_EXCL);
		xfs_trans_cancel(tp, 0);
		return 0;
	}

	trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);

	ip->i_d.di_size = isize;
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

	return xfs_trans_commit(tp, 0);
}
/*
 * Update on-disk file size now that data has been written to disk.
 */
STATIC int
xfs_setfilesize(
	struct xfs_ioend	*ioend)
{
	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
	struct xfs_trans	*tp = ioend->io_append_trans;
	xfs_fsize_t		isize;

	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
	if (!isize) {
		xfs_iunlock(ip, XFS_ILOCK_EXCL);
		xfs_trans_cancel(tp, 0);
		return 0;
	}

	trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);

	ip->i_d.di_size = isize;
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

	return xfs_trans_commit(tp, 0);
}
Beispiel #3
0
/*
 * Update on-disk file size now that data has been written to disk.
 */
STATIC int
xfs_setfilesize(
	struct xfs_ioend	*ioend)
{
	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
	struct xfs_trans	*tp = ioend->io_append_trans;
	xfs_fsize_t		isize;

	/*
	 * The transaction was allocated in the I/O submission thread,
	 * thus we need to mark ourselves as beeing in a transaction
	 * manually.
	 */
	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	isize = xfs_new_eof(ip, ioend->io_offset + ioend->io_size);
	if (!isize) {
		xfs_iunlock(ip, XFS_ILOCK_EXCL);
		xfs_trans_cancel(tp, 0);
		return 0;
	}

	trace_xfs_setfilesize(ip, ioend->io_offset, ioend->io_size);

	ip->i_d.di_size = isize;
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

	return xfs_trans_commit(tp, 0);
}
STATIC void
xfs_end_io(
	struct work_struct *work)
{
	xfs_ioend_t	*ioend = container_of(work, xfs_ioend_t, io_work);
	struct xfs_inode *ip = XFS_I(ioend->io_inode);
	int		error = 0;

	if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
		ioend->io_error = -EIO;
		goto done;
	}
	if (ioend->io_error)
		goto done;

	/*
	 * For unwritten extents we need to issue transactions to convert a
	 * range to normal written extens after the data I/O has finished.
	 */
	if (ioend->io_type == IO_UNWRITTEN) {
		/*
		 * For buffered I/O we never preallocate a transaction when
		 * doing the unwritten extent conversion, but for direct I/O
		 * we do not know if we are converting an unwritten extent
		 * or not at the point where we preallocate the transaction.
		 */
		if (ioend->io_append_trans) {
			ASSERT(ioend->io_isdirect);

			current_set_flags_nested(
				&ioend->io_append_trans->t_pflags, PF_FSTRANS);
			xfs_trans_cancel(ioend->io_append_trans, 0);
		}

		error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
						 ioend->io_size);
		if (error) {
			ioend->io_error = -error;
			goto done;
		}
	} else if (ioend->io_append_trans) {
		error = xfs_setfilesize(ioend);
		if (error)
			ioend->io_error = -error;
	} else {
		ASSERT(!xfs_ioend_is_append(ioend));
	}

done:
	xfs_destroy_ioend(ioend);
}
/*
 * Stack switching interfaces for allocation
 */
static void
xfs_bmapi_allocate_worker(
	struct work_struct	*work)
{
	struct xfs_bmalloca	*args = container_of(work,
						struct xfs_bmalloca, work);
	unsigned long		pflags;

	/* we are in a transaction context here */
	current_set_flags_nested(&pflags, PF_FSTRANS);

	args->result = __xfs_bmapi_allocate(args);
	complete(args->done);

	current_restore_flags_nested(&pflags, PF_FSTRANS);
}
Beispiel #6
0
STATIC int
xfs_setfilesize_ioend(
	struct xfs_ioend	*ioend)
{
	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
	struct xfs_trans	*tp = ioend->io_append_trans;

	/*
	 * The transaction may have been allocated in the I/O submission thread,
	 * thus we need to mark ourselves as being in a transaction manually.
	 * Similarly for freeze protection.
	 */
	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
	rwsem_acquire_read(&VFS_I(ip)->i_sb->s_writers.lock_map[SB_FREEZE_FS-1],
			   0, 1, _THIS_IP_);

	return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size);
}
Beispiel #7
0
STATIC int
xfs_setfilesize_ioend(
	struct xfs_ioend	*ioend)
{
	struct xfs_inode	*ip = XFS_I(ioend->io_inode);
	struct xfs_trans	*tp = ioend->io_append_trans;

	/*
	 * The transaction may have been allocated in the I/O submission thread,
	 * thus we need to mark ourselves as being in a transaction manually.
	 * Similarly for freeze protection.
	 */
	current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
	__sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS);

	/* we abort the update if there was an IO error */
	if (ioend->io_error) {
		xfs_trans_cancel(tp);
		return ioend->io_error;
	}

	return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size);
}
Beispiel #8
0
/*
 * This is called to reserve free disk blocks and log space for the
 * given transaction.  This must be done before allocating any resources
 * within the transaction.
 *
 * This will return ENOSPC if there are not enough blocks available.
 * It will sleep waiting for available log space.
 * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which
 * is used by long running transactions.  If any one of the reservations
 * fails then they will all be backed out.
 *
 * This does not do quota reservations. That typically is done by the
 * caller afterwards.
 */
int
xfs_trans_reserve(
    xfs_trans_t    *tp,
    uint        blocks,
    uint        logspace,
    uint        rtextents,
    uint        flags,
    uint        logcount)
{
    int        log_flags;
    int        error = 0;
    int        rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;

    /* Mark this thread as being in a transaction */
    current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);

    /*
     * Attempt to reserve the needed disk blocks by decrementing
     * the number needed from the number available.  This will
     * fail if the count would go below zero.
     */
    if (blocks > 0) {
        error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
                      -((int64_t)blocks), rsvd);
        if (error != 0) {
            current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
            return (XFS_ERROR(ENOSPC));
        }
        tp->t_blk_res += blocks;
    }

    /*
     * Reserve the log space needed for this transaction.
     */
    if (logspace > 0) {
        ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace));
        ASSERT((tp->t_log_count == 0) ||
            (tp->t_log_count == logcount));
        if (flags & XFS_TRANS_PERM_LOG_RES) {
            log_flags = XFS_LOG_PERM_RESERV;
            tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
        } else {
            ASSERT(tp->t_ticket == NULL);
            ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES));
            log_flags = 0;
        }

        error = xfs_log_reserve(tp->t_mountp, logspace, logcount,
                    &tp->t_ticket,
                    XFS_TRANSACTION, log_flags, tp->t_type);
        if (error) {
            goto undo_blocks;
        }
        tp->t_log_res = logspace;
        tp->t_log_count = logcount;
    }

    /*
     * Attempt to reserve the needed realtime extents by decrementing
     * the number needed from the number available.  This will
     * fail if the count would go below zero.
     */
    if (rtextents > 0) {
        error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS,
                      -((int64_t)rtextents), rsvd);
        if (error) {
            error = XFS_ERROR(ENOSPC);
            goto undo_log;
        }
        tp->t_rtx_res += rtextents;
    }

    return 0;

    /*
     * Error cases jump to one of these labels to undo any
     * reservations which have already been performed.
     */
undo_log:
    if (logspace > 0) {
        if (flags & XFS_TRANS_PERM_LOG_RES) {
            log_flags = XFS_LOG_REL_PERM_RESERV;
        } else {
            log_flags = 0;
        }
        xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, log_flags);
        tp->t_ticket = NULL;
        tp->t_log_res = 0;
        tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES;
    }

undo_blocks:
    if (blocks > 0) {
        (void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
                     (int64_t)blocks, rsvd);
        tp->t_blk_res = 0;
    }

    current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);

    return error;
}