Пример #1
0
STATIC int
xfs_setfilesize_trans_alloc(
	struct xfs_ioend	*ioend)
{
	struct xfs_mount	*mp = XFS_I(ioend->io_inode)->i_mount;
	struct xfs_trans	*tp;
	int			error;

	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);

	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		return error;
	}

	ioend->io_append_trans = tp;

	/*
	 * We hand off the transaction to the completion thread now, so
	 * clear the flag here.
	 */
	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
	return 0;
}
Пример #2
0
STATIC int
xfs_setfilesize_trans_alloc(
	struct xfs_ioend	*ioend)
{
	struct xfs_mount	*mp = XFS_I(ioend->io_inode)->i_mount;
	struct xfs_trans	*tp;
	int			error;

	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);

	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		return error;
	}

	ioend->io_append_trans = tp;

	/*
	 * We may 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.
	 */
	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
	return 0;
}
Пример #3
0
STATIC int
xfs_setfilesize_trans_alloc(
	struct xfs_ioend	*ioend)
{
	struct xfs_mount	*mp = XFS_I(ioend->io_inode)->i_mount;
	struct xfs_trans	*tp;
	int			error;

	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp);
	if (error)
		return error;

	ioend->io_append_trans = tp;

	/*
	 * We may pass freeze protection with a transaction.  So tell lockdep
	 * we released it.
	 */
	__sb_writers_release(ioend->io_inode->i_sb, SB_FREEZE_FS);
	/*
	 * We hand off the transaction to the completion thread now, so
	 * clear the flag here.
	 */
	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
	return 0;
}
Пример #4
0
/*
 * 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);
}
STATIC int
xfs_setfilesize_trans_alloc(
	struct xfs_ioend	*ioend)
{
	struct xfs_mount	*mp = XFS_I(ioend->io_inode)->i_mount;
	struct xfs_trans	*tp;
	int			error;

	tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);

	error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		return error;
	}

	ioend->io_append_trans = tp;

	current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
	return 0;
}
Пример #6
0
 /*ARGSUSED*/
int
_xfs_trans_commit(
    xfs_trans_t    *tp,
    uint        flags,
    int        *log_flushed)
{
    xfs_log_iovec_t        *log_vector;
    int            nvec;
    xfs_mount_t        *mp;
    xfs_lsn_t        commit_lsn;
    /* REFERENCED */
    int            error;
    int            log_flags;
    int            sync;
#define    XFS_TRANS_LOGVEC_COUNT    16
    xfs_log_iovec_t        log_vector_fast[XFS_TRANS_LOGVEC_COUNT];
    void            *commit_iclog;
    int            shutdown;

    commit_lsn = -1;

    /*
     * Determine whether this commit is releasing a permanent
     * log reservation or not.
     */
    if (flags & XFS_TRANS_RELEASE_LOG_RES) {
        ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
        log_flags = XFS_LOG_REL_PERM_RESERV;
    } else {
        log_flags = 0;
    }
    mp = tp->t_mountp;

    /*
     * If there is nothing to be logged by the transaction,
     * then unlock all of the items associated with the
     * transaction and free the transaction structure.
     * Also make sure to return any reserved blocks to
     * the free pool.
     */
shut_us_down:
    shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0;
    if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) {
        xfs_trans_unreserve_and_mod_sb(tp);
        /*
         * It is indeed possible for the transaction to be
         * not dirty but the dqinfo portion to be. All that
         * means is that we have some (non-persistent) quota
         * reservations that need to be unreserved.
         */
        XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);
        if (tp->t_ticket) {
            commit_lsn = xfs_log_done(mp, tp->t_ticket,
                            NULL, log_flags);
            if (commit_lsn == -1 && !shutdown)
                shutdown = XFS_ERROR(EIO);
        }
        current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
        xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
        xfs_trans_free_busy(tp);
        xfs_trans_free(tp);
        XFS_STATS_INC(xs_trans_empty);
        return (shutdown);
    }
    ASSERT(tp->t_ticket != NULL);

    /*
     * If we need to update the superblock, then do it now.
     */
    if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
        xfs_trans_apply_sb_deltas(tp);
    }
    XFS_TRANS_APPLY_DQUOT_DELTAS(mp, tp);

    /*
     * Ask each log item how many log_vector entries it will
     * need so we can figure out how many to allocate.
     * Try to avoid the kmem_alloc() call in the common case
     * by using a vector from the stack when it fits.
     */
    nvec = xfs_trans_count_vecs(tp);
    if (nvec == 0) {
        xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
        goto shut_us_down;
    } else if (nvec <= XFS_TRANS_LOGVEC_COUNT) {
        log_vector = log_vector_fast;
    } else {
        log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec *
                           sizeof(xfs_log_iovec_t),
                           KM_SLEEP);
    }

    /*
     * Fill in the log_vector and pin the logged items, and
     * then write the transaction to the log.
     */
    xfs_trans_fill_vecs(tp, log_vector);

    error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, &(tp->t_lsn));

    /*
     * The transaction is committed incore here, and can go out to disk
     * at any time after this call.  However, all the items associated
     * with the transaction are still locked and pinned in memory.
     */
    commit_lsn = xfs_log_done(mp, tp->t_ticket, &commit_iclog, log_flags);

    tp->t_commit_lsn = commit_lsn;
    if (nvec > XFS_TRANS_LOGVEC_COUNT) {
        kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
    }

    /*
     * If we got a log write error. Unpin the logitems that we
     * had pinned, clean up, free trans structure, and return error.
     */
    if (error || commit_lsn == -1) {
        current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);
        xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
        return XFS_ERROR(EIO);
    }

    /*
     * Once the transaction has committed, unused
     * reservations need to be released and changes to
     * the superblock need to be reflected in the in-core
     * version.  Do that now.
     */
    xfs_trans_unreserve_and_mod_sb(tp);

    sync = tp->t_flags & XFS_TRANS_SYNC;

    /*
     * Tell the LM to call the transaction completion routine
     * when the log write with LSN commit_lsn completes (e.g.
     * when the transaction commit really hits the on-disk log).
     * After this call we cannot reference tp, because the call
     * can happen at any time and the call will free the transaction
     * structure pointed to by tp.  The only case where we call
     * the completion routine (xfs_trans_committed) directly is
     * if the log is turned off on a debug kernel or we're
     * running in simulation mode (the log is explicitly turned
     * off).
     */
    tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed;
    tp->t_logcb.cb_arg = tp;

    /*
     * We need to pass the iclog buffer which was used for the
     * transaction commit record into this function, and attach
     * the callback to it. The callback must be attached before
     * the items are unlocked to avoid racing with other threads
     * waiting for an item to unlock.
     */
    shutdown = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));

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

    /*
     * Once all the items of the transaction have been copied
     * to the in core log and the callback is attached, the
     * items can be unlocked.
     *
     * This will free descriptors pointing to items which were
     * not logged since there is nothing more to do with them.
     * For items which were logged, we will keep pointers to them
     * so they can be unpinned after the transaction commits to disk.
     * This will also stamp each modified meta-data item with
     * the commit lsn of this transaction for dependency tracking
     * purposes.
     */
    xfs_trans_unlock_items(tp, commit_lsn);

    /*
     * If we detected a log error earlier, finish committing
     * the transaction now (unpin log items, etc).
     *
     * Order is critical here, to avoid using the transaction
     * pointer after its been freed (by xfs_trans_committed
     * either here now, or as a callback).  We cannot do this
     * step inside xfs_log_notify as was done earlier because
     * of this issue.
     */
    if (shutdown)
        xfs_trans_committed(tp, XFS_LI_ABORTED);

    /*
     * Now that the xfs_trans_committed callback has been attached,
     * and the items are released we can finally allow the iclog to
     * go to disk.
     */
    error = xfs_log_release_iclog(mp, commit_iclog);

    /*
     * If the transaction needs to be synchronous, then force the
     * log out now and wait for it.
     */
    if (sync) {
        if (!error) {
            error = _xfs_log_force(mp, commit_lsn,
                      XFS_LOG_FORCE | XFS_LOG_SYNC,
                      log_flushed);
        }
        XFS_STATS_INC(xs_trans_sync);
    } else {
        XFS_STATS_INC(xs_trans_async);
    }

    return (error);
}
Пример #7
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;
}
Пример #8
0
/*
 * Unlock all of the transaction's items and free the transaction.
 * The transaction must not have modified any of its items, because
 * there is no way to restore them to their previous state.
 *
 * If the transaction has made a log reservation, make sure to release
 * it as well.
 */
void
xfs_trans_cancel(
    xfs_trans_t        *tp,
    int            flags)
{
    int            log_flags;
#ifdef DEBUG
    xfs_log_item_chunk_t    *licp;
    xfs_log_item_desc_t    *lidp;
    xfs_log_item_t        *lip;
    int            i;
#endif
    xfs_mount_t        *mp = tp->t_mountp;

    /*
     * See if the caller is being too lazy to figure out if
     * the transaction really needs an abort.
     */
    if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY))
        flags &= ~XFS_TRANS_ABORT;
    /*
     * See if the caller is relying on us to shut down the
     * filesystem.  This happens in paths where we detect
     * corruption and decide to give up.
     */
    if ((tp->t_flags & XFS_TRANS_DIRTY) && !XFS_FORCED_SHUTDOWN(mp)) {
        XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp);
        xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
    }
#ifdef DEBUG
    if (!(flags & XFS_TRANS_ABORT)) {
        licp = &(tp->t_items);
        while (licp != NULL) {
            lidp = licp->lic_descs;
            for (i = 0; i < licp->lic_unused; i++, lidp++) {
                if (XFS_LIC_ISFREE(licp, i)) {
                    continue;
                }

                lip = lidp->lid_item;
                if (!XFS_FORCED_SHUTDOWN(mp))
                    ASSERT(!(lip->li_type == XFS_LI_EFD));
            }
            licp = licp->lic_next;
        }
    }
#endif
    xfs_trans_unreserve_and_mod_sb(tp);
    XFS_TRANS_UNRESERVE_AND_MOD_DQUOTS(mp, tp);

    if (tp->t_ticket) {
        if (flags & XFS_TRANS_RELEASE_LOG_RES) {
            ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
            log_flags = XFS_LOG_REL_PERM_RESERV;
        } else {
            log_flags = 0;
        }
        xfs_log_done(mp, tp->t_ticket, NULL, log_flags);
    }

    /* mark this thread as no longer being in a transaction */
    current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS);

    xfs_trans_free_items(tp, flags);
    xfs_trans_free_busy(tp);
    xfs_trans_free(tp);
}