linux/fs/xfs/xfs_dquot_item.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
   4 * All Rights Reserved.
   5 */
   6#include "xfs.h"
   7#include "xfs_fs.h"
   8#include "xfs_shared.h"
   9#include "xfs_format.h"
  10#include "xfs_log_format.h"
  11#include "xfs_trans_resv.h"
  12#include "xfs_mount.h"
  13#include "xfs_inode.h"
  14#include "xfs_quota.h"
  15#include "xfs_trans.h"
  16#include "xfs_buf_item.h"
  17#include "xfs_trans_priv.h"
  18#include "xfs_qm.h"
  19#include "xfs_log.h"
  20
  21static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip)
  22{
  23        return container_of(lip, struct xfs_dq_logitem, qli_item);
  24}
  25
  26/*
  27 * returns the number of iovecs needed to log the given dquot item.
  28 */
  29STATIC void
  30xfs_qm_dquot_logitem_size(
  31        struct xfs_log_item     *lip,
  32        int                     *nvecs,
  33        int                     *nbytes)
  34{
  35        *nvecs += 2;
  36        *nbytes += sizeof(struct xfs_dq_logformat) +
  37                   sizeof(struct xfs_disk_dquot);
  38}
  39
  40/*
  41 * fills in the vector of log iovecs for the given dquot log item.
  42 */
  43STATIC void
  44xfs_qm_dquot_logitem_format(
  45        struct xfs_log_item     *lip,
  46        struct xfs_log_vec      *lv)
  47{
  48        struct xfs_disk_dquot   ddq;
  49        struct xfs_dq_logitem   *qlip = DQUOT_ITEM(lip);
  50        struct xfs_log_iovec    *vecp = NULL;
  51        struct xfs_dq_logformat *qlf;
  52
  53        qlf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_QFORMAT);
  54        qlf->qlf_type = XFS_LI_DQUOT;
  55        qlf->qlf_size = 2;
  56        qlf->qlf_id = qlip->qli_dquot->q_id;
  57        qlf->qlf_blkno = qlip->qli_dquot->q_blkno;
  58        qlf->qlf_len = 1;
  59        qlf->qlf_boffset = qlip->qli_dquot->q_bufoffset;
  60        xlog_finish_iovec(lv, vecp, sizeof(struct xfs_dq_logformat));
  61
  62        xfs_dquot_to_disk(&ddq, qlip->qli_dquot);
  63
  64        xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_DQUOT, &ddq,
  65                        sizeof(struct xfs_disk_dquot));
  66}
  67
  68/*
  69 * Increment the pin count of the given dquot.
  70 */
  71STATIC void
  72xfs_qm_dquot_logitem_pin(
  73        struct xfs_log_item     *lip)
  74{
  75        struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
  76
  77        ASSERT(XFS_DQ_IS_LOCKED(dqp));
  78        atomic_inc(&dqp->q_pincount);
  79}
  80
  81/*
  82 * Decrement the pin count of the given dquot, and wake up
  83 * anyone in xfs_dqwait_unpin() if the count goes to 0.  The
  84 * dquot must have been previously pinned with a call to
  85 * xfs_qm_dquot_logitem_pin().
  86 */
  87STATIC void
  88xfs_qm_dquot_logitem_unpin(
  89        struct xfs_log_item     *lip,
  90        int                     remove)
  91{
  92        struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
  93
  94        ASSERT(atomic_read(&dqp->q_pincount) > 0);
  95        if (atomic_dec_and_test(&dqp->q_pincount))
  96                wake_up(&dqp->q_pinwait);
  97}
  98
  99/*
 100 * This is called to wait for the given dquot to be unpinned.
 101 * Most of these pin/unpin routines are plagiarized from inode code.
 102 */
 103void
 104xfs_qm_dqunpin_wait(
 105        struct xfs_dquot        *dqp)
 106{
 107        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 108        if (atomic_read(&dqp->q_pincount) == 0)
 109                return;
 110
 111        /*
 112         * Give the log a push so we don't wait here too long.
 113         */
 114        xfs_log_force(dqp->q_mount, 0);
 115        wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
 116}
 117
 118STATIC uint
 119xfs_qm_dquot_logitem_push(
 120        struct xfs_log_item     *lip,
 121        struct list_head        *buffer_list)
 122                __releases(&lip->li_ailp->ail_lock)
 123                __acquires(&lip->li_ailp->ail_lock)
 124{
 125        struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 126        struct xfs_buf          *bp = lip->li_buf;
 127        uint                    rval = XFS_ITEM_SUCCESS;
 128        int                     error;
 129
 130        if (atomic_read(&dqp->q_pincount) > 0)
 131                return XFS_ITEM_PINNED;
 132
 133        if (!xfs_dqlock_nowait(dqp))
 134                return XFS_ITEM_LOCKED;
 135
 136        /*
 137         * Re-check the pincount now that we stabilized the value by
 138         * taking the quota lock.
 139         */
 140        if (atomic_read(&dqp->q_pincount) > 0) {
 141                rval = XFS_ITEM_PINNED;
 142                goto out_unlock;
 143        }
 144
 145        /*
 146         * Someone else is already flushing the dquot.  Nothing we can do
 147         * here but wait for the flush to finish and remove the item from
 148         * the AIL.
 149         */
 150        if (!xfs_dqflock_nowait(dqp)) {
 151                rval = XFS_ITEM_FLUSHING;
 152                goto out_unlock;
 153        }
 154
 155        spin_unlock(&lip->li_ailp->ail_lock);
 156
 157        error = xfs_qm_dqflush(dqp, &bp);
 158        if (!error) {
 159                if (!xfs_buf_delwri_queue(bp, buffer_list))
 160                        rval = XFS_ITEM_FLUSHING;
 161                xfs_buf_relse(bp);
 162        } else if (error == -EAGAIN)
 163                rval = XFS_ITEM_LOCKED;
 164
 165        spin_lock(&lip->li_ailp->ail_lock);
 166out_unlock:
 167        xfs_dqunlock(dqp);
 168        return rval;
 169}
 170
 171STATIC void
 172xfs_qm_dquot_logitem_release(
 173        struct xfs_log_item     *lip)
 174{
 175        struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
 176
 177        ASSERT(XFS_DQ_IS_LOCKED(dqp));
 178
 179        /*
 180         * dquots are never 'held' from getting unlocked at the end of
 181         * a transaction.  Their locking and unlocking is hidden inside the
 182         * transaction layer, within trans_commit. Hence, no LI_HOLD flag
 183         * for the logitem.
 184         */
 185        xfs_dqunlock(dqp);
 186}
 187
 188STATIC void
 189xfs_qm_dquot_logitem_committing(
 190        struct xfs_log_item     *lip,
 191        xfs_csn_t               seq)
 192{
 193        return xfs_qm_dquot_logitem_release(lip);
 194}
 195
 196static const struct xfs_item_ops xfs_dquot_item_ops = {
 197        .iop_size       = xfs_qm_dquot_logitem_size,
 198        .iop_format     = xfs_qm_dquot_logitem_format,
 199        .iop_pin        = xfs_qm_dquot_logitem_pin,
 200        .iop_unpin      = xfs_qm_dquot_logitem_unpin,
 201        .iop_release    = xfs_qm_dquot_logitem_release,
 202        .iop_committing = xfs_qm_dquot_logitem_committing,
 203        .iop_push       = xfs_qm_dquot_logitem_push,
 204};
 205
 206/*
 207 * Initialize the dquot log item for a newly allocated dquot.
 208 * The dquot isn't locked at this point, but it isn't on any of the lists
 209 * either, so we don't care.
 210 */
 211void
 212xfs_qm_dquot_logitem_init(
 213        struct xfs_dquot        *dqp)
 214{
 215        struct xfs_dq_logitem   *lp = &dqp->q_logitem;
 216
 217        xfs_log_item_init(dqp->q_mount, &lp->qli_item, XFS_LI_DQUOT,
 218                                        &xfs_dquot_item_ops);
 219        lp->qli_dquot = dqp;
 220}
 221