162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2003 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_format.h" 962306a36Sopenharmony_ci#include "xfs_log_format.h" 1062306a36Sopenharmony_ci#include "xfs_shared.h" 1162306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1262306a36Sopenharmony_ci#include "xfs_bit.h" 1362306a36Sopenharmony_ci#include "xfs_mount.h" 1462306a36Sopenharmony_ci#include "xfs_defer.h" 1562306a36Sopenharmony_ci#include "xfs_inode.h" 1662306a36Sopenharmony_ci#include "xfs_bmap.h" 1762306a36Sopenharmony_ci#include "xfs_quota.h" 1862306a36Sopenharmony_ci#include "xfs_trans.h" 1962306a36Sopenharmony_ci#include "xfs_buf_item.h" 2062306a36Sopenharmony_ci#include "xfs_trans_space.h" 2162306a36Sopenharmony_ci#include "xfs_trans_priv.h" 2262306a36Sopenharmony_ci#include "xfs_qm.h" 2362306a36Sopenharmony_ci#include "xfs_trace.h" 2462306a36Sopenharmony_ci#include "xfs_log.h" 2562306a36Sopenharmony_ci#include "xfs_bmap_btree.h" 2662306a36Sopenharmony_ci#include "xfs_error.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Lock order: 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * ip->i_lock 3262306a36Sopenharmony_ci * qi->qi_tree_lock 3362306a36Sopenharmony_ci * dquot->q_qlock (xfs_dqlock() and friends) 3462306a36Sopenharmony_ci * dquot->q_flush (xfs_dqflock() and friends) 3562306a36Sopenharmony_ci * qi->qi_lru_lock 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * If two dquots need to be locked the order is user before group/project, 3862306a36Sopenharmony_ci * otherwise by the lowest id first, see xfs_dqlock2. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistruct kmem_cache *xfs_dqtrx_cache; 4262306a36Sopenharmony_cistatic struct kmem_cache *xfs_dquot_cache; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic struct lock_class_key xfs_dquot_group_class; 4562306a36Sopenharmony_cistatic struct lock_class_key xfs_dquot_project_class; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * This is called to free all the memory associated with a dquot 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_civoid 5162306a36Sopenharmony_cixfs_qm_dqdestroy( 5262306a36Sopenharmony_ci struct xfs_dquot *dqp) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci ASSERT(list_empty(&dqp->q_lru)); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci kmem_free(dqp->q_logitem.qli_item.li_lv_shadow); 5762306a36Sopenharmony_ci mutex_destroy(&dqp->q_qlock); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot); 6062306a36Sopenharmony_ci kmem_cache_free(xfs_dquot_cache, dqp); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * If default limits are in force, push them into the dquot now. 6562306a36Sopenharmony_ci * We overwrite the dquot limits only if they are zero and this 6662306a36Sopenharmony_ci * is not the root dquot. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_civoid 6962306a36Sopenharmony_cixfs_qm_adjust_dqlimits( 7062306a36Sopenharmony_ci struct xfs_dquot *dq) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct xfs_mount *mp = dq->q_mount; 7362306a36Sopenharmony_ci struct xfs_quotainfo *q = mp->m_quotainfo; 7462306a36Sopenharmony_ci struct xfs_def_quota *defq; 7562306a36Sopenharmony_ci int prealloc = 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci ASSERT(dq->q_id); 7862306a36Sopenharmony_ci defq = xfs_get_defquota(q, xfs_dquot_type(dq)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (!dq->q_blk.softlimit) { 8162306a36Sopenharmony_ci dq->q_blk.softlimit = defq->blk.soft; 8262306a36Sopenharmony_ci prealloc = 1; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci if (!dq->q_blk.hardlimit) { 8562306a36Sopenharmony_ci dq->q_blk.hardlimit = defq->blk.hard; 8662306a36Sopenharmony_ci prealloc = 1; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci if (!dq->q_ino.softlimit) 8962306a36Sopenharmony_ci dq->q_ino.softlimit = defq->ino.soft; 9062306a36Sopenharmony_ci if (!dq->q_ino.hardlimit) 9162306a36Sopenharmony_ci dq->q_ino.hardlimit = defq->ino.hard; 9262306a36Sopenharmony_ci if (!dq->q_rtb.softlimit) 9362306a36Sopenharmony_ci dq->q_rtb.softlimit = defq->rtb.soft; 9462306a36Sopenharmony_ci if (!dq->q_rtb.hardlimit) 9562306a36Sopenharmony_ci dq->q_rtb.hardlimit = defq->rtb.hard; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (prealloc) 9862306a36Sopenharmony_ci xfs_dquot_set_prealloc_limits(dq); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci/* Set the expiration time of a quota's grace period. */ 10262306a36Sopenharmony_citime64_t 10362306a36Sopenharmony_cixfs_dquot_set_timeout( 10462306a36Sopenharmony_ci struct xfs_mount *mp, 10562306a36Sopenharmony_ci time64_t timeout) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct xfs_quotainfo *qi = mp->m_quotainfo; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci return clamp_t(time64_t, timeout, qi->qi_expiry_min, 11062306a36Sopenharmony_ci qi->qi_expiry_max); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* Set the length of the default grace period. */ 11462306a36Sopenharmony_citime64_t 11562306a36Sopenharmony_cixfs_dquot_set_grace_period( 11662306a36Sopenharmony_ci time64_t grace) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci return clamp_t(time64_t, grace, XFS_DQ_GRACE_MIN, XFS_DQ_GRACE_MAX); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Determine if this quota counter is over either limit and set the quota 12362306a36Sopenharmony_ci * timers as appropriate. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic inline void 12662306a36Sopenharmony_cixfs_qm_adjust_res_timer( 12762306a36Sopenharmony_ci struct xfs_mount *mp, 12862306a36Sopenharmony_ci struct xfs_dquot_res *res, 12962306a36Sopenharmony_ci struct xfs_quota_limits *qlim) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci ASSERT(res->hardlimit == 0 || res->softlimit <= res->hardlimit); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if ((res->softlimit && res->count > res->softlimit) || 13462306a36Sopenharmony_ci (res->hardlimit && res->count > res->hardlimit)) { 13562306a36Sopenharmony_ci if (res->timer == 0) 13662306a36Sopenharmony_ci res->timer = xfs_dquot_set_timeout(mp, 13762306a36Sopenharmony_ci ktime_get_real_seconds() + qlim->time); 13862306a36Sopenharmony_ci } else { 13962306a36Sopenharmony_ci res->timer = 0; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Check the limits and timers of a dquot and start or reset timers 14562306a36Sopenharmony_ci * if necessary. 14662306a36Sopenharmony_ci * This gets called even when quota enforcement is OFF, which makes our 14762306a36Sopenharmony_ci * life a little less complicated. (We just don't reject any quota 14862306a36Sopenharmony_ci * reservations in that case, when enforcement is off). 14962306a36Sopenharmony_ci * We also return 0 as the values of the timers in Q_GETQUOTA calls, when 15062306a36Sopenharmony_ci * enforcement's off. 15162306a36Sopenharmony_ci * In contrast, warnings are a little different in that they don't 15262306a36Sopenharmony_ci * 'automatically' get started when limits get exceeded. They do 15362306a36Sopenharmony_ci * get reset to zero, however, when we find the count to be under 15462306a36Sopenharmony_ci * the soft limit (they are only ever set non-zero via userspace). 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_civoid 15762306a36Sopenharmony_cixfs_qm_adjust_dqtimers( 15862306a36Sopenharmony_ci struct xfs_dquot *dq) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct xfs_mount *mp = dq->q_mount; 16162306a36Sopenharmony_ci struct xfs_quotainfo *qi = mp->m_quotainfo; 16262306a36Sopenharmony_ci struct xfs_def_quota *defq; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ASSERT(dq->q_id); 16562306a36Sopenharmony_ci defq = xfs_get_defquota(qi, xfs_dquot_type(dq)); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_blk, &defq->blk); 16862306a36Sopenharmony_ci xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_ino, &defq->ino); 16962306a36Sopenharmony_ci xfs_qm_adjust_res_timer(dq->q_mount, &dq->q_rtb, &defq->rtb); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * initialize a buffer full of dquots and log the whole thing 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ciSTATIC void 17662306a36Sopenharmony_cixfs_qm_init_dquot_blk( 17762306a36Sopenharmony_ci struct xfs_trans *tp, 17862306a36Sopenharmony_ci struct xfs_mount *mp, 17962306a36Sopenharmony_ci xfs_dqid_t id, 18062306a36Sopenharmony_ci xfs_dqtype_t type, 18162306a36Sopenharmony_ci struct xfs_buf *bp) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct xfs_quotainfo *q = mp->m_quotainfo; 18462306a36Sopenharmony_ci struct xfs_dqblk *d; 18562306a36Sopenharmony_ci xfs_dqid_t curid; 18662306a36Sopenharmony_ci unsigned int qflag; 18762306a36Sopenharmony_ci unsigned int blftype; 18862306a36Sopenharmony_ci int i; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ASSERT(tp); 19162306a36Sopenharmony_ci ASSERT(xfs_buf_islocked(bp)); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci switch (type) { 19462306a36Sopenharmony_ci case XFS_DQTYPE_USER: 19562306a36Sopenharmony_ci qflag = XFS_UQUOTA_CHKD; 19662306a36Sopenharmony_ci blftype = XFS_BLF_UDQUOT_BUF; 19762306a36Sopenharmony_ci break; 19862306a36Sopenharmony_ci case XFS_DQTYPE_PROJ: 19962306a36Sopenharmony_ci qflag = XFS_PQUOTA_CHKD; 20062306a36Sopenharmony_ci blftype = XFS_BLF_PDQUOT_BUF; 20162306a36Sopenharmony_ci break; 20262306a36Sopenharmony_ci case XFS_DQTYPE_GROUP: 20362306a36Sopenharmony_ci qflag = XFS_GQUOTA_CHKD; 20462306a36Sopenharmony_ci blftype = XFS_BLF_GDQUOT_BUF; 20562306a36Sopenharmony_ci break; 20662306a36Sopenharmony_ci default: 20762306a36Sopenharmony_ci ASSERT(0); 20862306a36Sopenharmony_ci return; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci d = bp->b_addr; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * ID of the first dquot in the block - id's are zero based. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci curid = id - (id % q->qi_dqperchunk); 21762306a36Sopenharmony_ci memset(d, 0, BBTOB(q->qi_dqchunklen)); 21862306a36Sopenharmony_ci for (i = 0; i < q->qi_dqperchunk; i++, d++, curid++) { 21962306a36Sopenharmony_ci d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); 22062306a36Sopenharmony_ci d->dd_diskdq.d_version = XFS_DQUOT_VERSION; 22162306a36Sopenharmony_ci d->dd_diskdq.d_id = cpu_to_be32(curid); 22262306a36Sopenharmony_ci d->dd_diskdq.d_type = type; 22362306a36Sopenharmony_ci if (curid > 0 && xfs_has_bigtime(mp)) 22462306a36Sopenharmony_ci d->dd_diskdq.d_type |= XFS_DQTYPE_BIGTIME; 22562306a36Sopenharmony_ci if (xfs_has_crc(mp)) { 22662306a36Sopenharmony_ci uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid); 22762306a36Sopenharmony_ci xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), 22862306a36Sopenharmony_ci XFS_DQUOT_CRC_OFF); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci xfs_trans_dquot_buf(tp, bp, blftype); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * quotacheck uses delayed writes to update all the dquots on disk in an 23662306a36Sopenharmony_ci * efficient manner instead of logging the individual dquot changes as 23762306a36Sopenharmony_ci * they are made. However if we log the buffer allocated here and crash 23862306a36Sopenharmony_ci * after quotacheck while the logged initialisation is still in the 23962306a36Sopenharmony_ci * active region of the log, log recovery can replay the dquot buffer 24062306a36Sopenharmony_ci * initialisation over the top of the checked dquots and corrupt quota 24162306a36Sopenharmony_ci * accounting. 24262306a36Sopenharmony_ci * 24362306a36Sopenharmony_ci * To avoid this problem, quotacheck cannot log the initialised buffer. 24462306a36Sopenharmony_ci * We must still dirty the buffer and write it back before the 24562306a36Sopenharmony_ci * allocation transaction clears the log. Therefore, mark the buffer as 24662306a36Sopenharmony_ci * ordered instead of logging it directly. This is safe for quotacheck 24762306a36Sopenharmony_ci * because it detects and repairs allocated but initialized dquot blocks 24862306a36Sopenharmony_ci * in the quota inodes. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci if (!(mp->m_qflags & qflag)) 25162306a36Sopenharmony_ci xfs_trans_ordered_buf(tp, bp); 25262306a36Sopenharmony_ci else 25362306a36Sopenharmony_ci xfs_trans_log_buf(tp, bp, 0, BBTOB(q->qi_dqchunklen) - 1); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 25762306a36Sopenharmony_ci * Initialize the dynamic speculative preallocation thresholds. The lo/hi 25862306a36Sopenharmony_ci * watermarks correspond to the soft and hard limits by default. If a soft limit 25962306a36Sopenharmony_ci * is not specified, we use 95% of the hard limit. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_civoid 26262306a36Sopenharmony_cixfs_dquot_set_prealloc_limits(struct xfs_dquot *dqp) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci uint64_t space; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci dqp->q_prealloc_hi_wmark = dqp->q_blk.hardlimit; 26762306a36Sopenharmony_ci dqp->q_prealloc_lo_wmark = dqp->q_blk.softlimit; 26862306a36Sopenharmony_ci if (!dqp->q_prealloc_lo_wmark) { 26962306a36Sopenharmony_ci dqp->q_prealloc_lo_wmark = dqp->q_prealloc_hi_wmark; 27062306a36Sopenharmony_ci do_div(dqp->q_prealloc_lo_wmark, 100); 27162306a36Sopenharmony_ci dqp->q_prealloc_lo_wmark *= 95; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci space = dqp->q_prealloc_hi_wmark; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci do_div(space, 100); 27762306a36Sopenharmony_ci dqp->q_low_space[XFS_QLOWSP_1_PCNT] = space; 27862306a36Sopenharmony_ci dqp->q_low_space[XFS_QLOWSP_3_PCNT] = space * 3; 27962306a36Sopenharmony_ci dqp->q_low_space[XFS_QLOWSP_5_PCNT] = space * 5; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* 28362306a36Sopenharmony_ci * Ensure that the given in-core dquot has a buffer on disk backing it, and 28462306a36Sopenharmony_ci * return the buffer locked and held. This is called when the bmapi finds a 28562306a36Sopenharmony_ci * hole. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_ciSTATIC int 28862306a36Sopenharmony_cixfs_dquot_disk_alloc( 28962306a36Sopenharmony_ci struct xfs_dquot *dqp, 29062306a36Sopenharmony_ci struct xfs_buf **bpp) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct xfs_bmbt_irec map; 29362306a36Sopenharmony_ci struct xfs_trans *tp; 29462306a36Sopenharmony_ci struct xfs_mount *mp = dqp->q_mount; 29562306a36Sopenharmony_ci struct xfs_buf *bp; 29662306a36Sopenharmony_ci xfs_dqtype_t qtype = xfs_dquot_type(dqp); 29762306a36Sopenharmony_ci struct xfs_inode *quotip = xfs_quota_inode(mp, qtype); 29862306a36Sopenharmony_ci int nmaps = 1; 29962306a36Sopenharmony_ci int error; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci trace_xfs_dqalloc(dqp); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_dqalloc, 30462306a36Sopenharmony_ci XFS_QM_DQALLOC_SPACE_RES(mp), 0, 0, &tp); 30562306a36Sopenharmony_ci if (error) 30662306a36Sopenharmony_ci return error; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci xfs_ilock(quotip, XFS_ILOCK_EXCL); 30962306a36Sopenharmony_ci xfs_trans_ijoin(tp, quotip, 0); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (!xfs_this_quota_on(dqp->q_mount, qtype)) { 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * Return if this type of quotas is turned off while we didn't 31462306a36Sopenharmony_ci * have an inode lock 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci error = -ESRCH; 31762306a36Sopenharmony_ci goto err_cancel; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci error = xfs_iext_count_may_overflow(quotip, XFS_DATA_FORK, 32162306a36Sopenharmony_ci XFS_IEXT_ADD_NOSPLIT_CNT); 32262306a36Sopenharmony_ci if (error == -EFBIG) 32362306a36Sopenharmony_ci error = xfs_iext_count_upgrade(tp, quotip, 32462306a36Sopenharmony_ci XFS_IEXT_ADD_NOSPLIT_CNT); 32562306a36Sopenharmony_ci if (error) 32662306a36Sopenharmony_ci goto err_cancel; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Create the block mapping. */ 32962306a36Sopenharmony_ci error = xfs_bmapi_write(tp, quotip, dqp->q_fileoffset, 33062306a36Sopenharmony_ci XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA, 0, &map, 33162306a36Sopenharmony_ci &nmaps); 33262306a36Sopenharmony_ci if (error) 33362306a36Sopenharmony_ci goto err_cancel; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); 33662306a36Sopenharmony_ci ASSERT(nmaps == 1); 33762306a36Sopenharmony_ci ASSERT((map.br_startblock != DELAYSTARTBLOCK) && 33862306a36Sopenharmony_ci (map.br_startblock != HOLESTARTBLOCK)); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* 34162306a36Sopenharmony_ci * Keep track of the blkno to save a lookup later 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* now we can just get the buffer (there's nothing to read yet) */ 34662306a36Sopenharmony_ci error = xfs_trans_get_buf(tp, mp->m_ddev_targp, dqp->q_blkno, 34762306a36Sopenharmony_ci mp->m_quotainfo->qi_dqchunklen, 0, &bp); 34862306a36Sopenharmony_ci if (error) 34962306a36Sopenharmony_ci goto err_cancel; 35062306a36Sopenharmony_ci bp->b_ops = &xfs_dquot_buf_ops; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Make a chunk of dquots out of this buffer and log 35462306a36Sopenharmony_ci * the entire thing. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci xfs_qm_init_dquot_blk(tp, mp, dqp->q_id, qtype, bp); 35762306a36Sopenharmony_ci xfs_buf_set_ref(bp, XFS_DQUOT_REF); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * Hold the buffer and join it to the dfops so that we'll still own 36162306a36Sopenharmony_ci * the buffer when we return to the caller. The buffer disposal on 36262306a36Sopenharmony_ci * error must be paid attention to very carefully, as it has been 36362306a36Sopenharmony_ci * broken since commit efa092f3d4c6 "[XFS] Fixes a bug in the quota 36462306a36Sopenharmony_ci * code when allocating a new dquot record" in 2005, and the later 36562306a36Sopenharmony_ci * conversion to xfs_defer_ops in commit 310a75a3c6c747 failed to keep 36662306a36Sopenharmony_ci * the buffer locked across the _defer_finish call. We can now do 36762306a36Sopenharmony_ci * this correctly with xfs_defer_bjoin. 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * Above, we allocated a disk block for the dquot information and used 37062306a36Sopenharmony_ci * get_buf to initialize the dquot. If the _defer_finish fails, the old 37162306a36Sopenharmony_ci * transaction is gone but the new buffer is not joined or held to any 37262306a36Sopenharmony_ci * transaction, so we must _buf_relse it. 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * If everything succeeds, the caller of this function is returned a 37562306a36Sopenharmony_ci * buffer that is locked and held to the transaction. The caller 37662306a36Sopenharmony_ci * is responsible for unlocking any buffer passed back, either 37762306a36Sopenharmony_ci * manually or by committing the transaction. On error, the buffer is 37862306a36Sopenharmony_ci * released and not passed back. 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * Keep the quota inode ILOCKed until after the transaction commit to 38162306a36Sopenharmony_ci * maintain the atomicity of bmap/rmap updates. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci xfs_trans_bhold(tp, bp); 38462306a36Sopenharmony_ci error = xfs_trans_commit(tp); 38562306a36Sopenharmony_ci xfs_iunlock(quotip, XFS_ILOCK_EXCL); 38662306a36Sopenharmony_ci if (error) { 38762306a36Sopenharmony_ci xfs_buf_relse(bp); 38862306a36Sopenharmony_ci return error; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci *bpp = bp; 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cierr_cancel: 39562306a36Sopenharmony_ci xfs_trans_cancel(tp); 39662306a36Sopenharmony_ci xfs_iunlock(quotip, XFS_ILOCK_EXCL); 39762306a36Sopenharmony_ci return error; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* 40162306a36Sopenharmony_ci * Read in the in-core dquot's on-disk metadata and return the buffer. 40262306a36Sopenharmony_ci * Returns ENOENT to signal a hole. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ciSTATIC int 40562306a36Sopenharmony_cixfs_dquot_disk_read( 40662306a36Sopenharmony_ci struct xfs_mount *mp, 40762306a36Sopenharmony_ci struct xfs_dquot *dqp, 40862306a36Sopenharmony_ci struct xfs_buf **bpp) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct xfs_bmbt_irec map; 41162306a36Sopenharmony_ci struct xfs_buf *bp; 41262306a36Sopenharmony_ci xfs_dqtype_t qtype = xfs_dquot_type(dqp); 41362306a36Sopenharmony_ci struct xfs_inode *quotip = xfs_quota_inode(mp, qtype); 41462306a36Sopenharmony_ci uint lock_mode; 41562306a36Sopenharmony_ci int nmaps = 1; 41662306a36Sopenharmony_ci int error; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci lock_mode = xfs_ilock_data_map_shared(quotip); 41962306a36Sopenharmony_ci if (!xfs_this_quota_on(mp, qtype)) { 42062306a36Sopenharmony_ci /* 42162306a36Sopenharmony_ci * Return if this type of quotas is turned off while we 42262306a36Sopenharmony_ci * didn't have the quota inode lock. 42362306a36Sopenharmony_ci */ 42462306a36Sopenharmony_ci xfs_iunlock(quotip, lock_mode); 42562306a36Sopenharmony_ci return -ESRCH; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* 42962306a36Sopenharmony_ci * Find the block map; no allocations yet 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci error = xfs_bmapi_read(quotip, dqp->q_fileoffset, 43262306a36Sopenharmony_ci XFS_DQUOT_CLUSTER_SIZE_FSB, &map, &nmaps, 0); 43362306a36Sopenharmony_ci xfs_iunlock(quotip, lock_mode); 43462306a36Sopenharmony_ci if (error) 43562306a36Sopenharmony_ci return error; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ASSERT(nmaps == 1); 43862306a36Sopenharmony_ci ASSERT(map.br_blockcount >= 1); 43962306a36Sopenharmony_ci ASSERT(map.br_startblock != DELAYSTARTBLOCK); 44062306a36Sopenharmony_ci if (map.br_startblock == HOLESTARTBLOCK) 44162306a36Sopenharmony_ci return -ENOENT; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci trace_xfs_dqtobp_read(dqp); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* 44662306a36Sopenharmony_ci * store the blkno etc so that we don't have to do the 44762306a36Sopenharmony_ci * mapping all the time 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, 45262306a36Sopenharmony_ci mp->m_quotainfo->qi_dqchunklen, 0, &bp, 45362306a36Sopenharmony_ci &xfs_dquot_buf_ops); 45462306a36Sopenharmony_ci if (error) { 45562306a36Sopenharmony_ci ASSERT(bp == NULL); 45662306a36Sopenharmony_ci return error; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ASSERT(xfs_buf_islocked(bp)); 46062306a36Sopenharmony_ci xfs_buf_set_ref(bp, XFS_DQUOT_REF); 46162306a36Sopenharmony_ci *bpp = bp; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/* Allocate and initialize everything we need for an incore dquot. */ 46762306a36Sopenharmony_ciSTATIC struct xfs_dquot * 46862306a36Sopenharmony_cixfs_dquot_alloc( 46962306a36Sopenharmony_ci struct xfs_mount *mp, 47062306a36Sopenharmony_ci xfs_dqid_t id, 47162306a36Sopenharmony_ci xfs_dqtype_t type) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct xfs_dquot *dqp; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci dqp = kmem_cache_zalloc(xfs_dquot_cache, GFP_KERNEL | __GFP_NOFAIL); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci dqp->q_type = type; 47862306a36Sopenharmony_ci dqp->q_id = id; 47962306a36Sopenharmony_ci dqp->q_mount = mp; 48062306a36Sopenharmony_ci INIT_LIST_HEAD(&dqp->q_lru); 48162306a36Sopenharmony_ci mutex_init(&dqp->q_qlock); 48262306a36Sopenharmony_ci init_waitqueue_head(&dqp->q_pinwait); 48362306a36Sopenharmony_ci dqp->q_fileoffset = (xfs_fileoff_t)id / mp->m_quotainfo->qi_dqperchunk; 48462306a36Sopenharmony_ci /* 48562306a36Sopenharmony_ci * Offset of dquot in the (fixed sized) dquot chunk. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci dqp->q_bufoffset = (id % mp->m_quotainfo->qi_dqperchunk) * 48862306a36Sopenharmony_ci sizeof(struct xfs_dqblk); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* 49162306a36Sopenharmony_ci * Because we want to use a counting completion, complete 49262306a36Sopenharmony_ci * the flush completion once to allow a single access to 49362306a36Sopenharmony_ci * the flush completion without blocking. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci init_completion(&dqp->q_flush); 49662306a36Sopenharmony_ci complete(&dqp->q_flush); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* 49962306a36Sopenharmony_ci * Make sure group quotas have a different lock class than user 50062306a36Sopenharmony_ci * quotas. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci switch (type) { 50362306a36Sopenharmony_ci case XFS_DQTYPE_USER: 50462306a36Sopenharmony_ci /* uses the default lock class */ 50562306a36Sopenharmony_ci break; 50662306a36Sopenharmony_ci case XFS_DQTYPE_GROUP: 50762306a36Sopenharmony_ci lockdep_set_class(&dqp->q_qlock, &xfs_dquot_group_class); 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci case XFS_DQTYPE_PROJ: 51062306a36Sopenharmony_ci lockdep_set_class(&dqp->q_qlock, &xfs_dquot_project_class); 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci default: 51362306a36Sopenharmony_ci ASSERT(0); 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci xfs_qm_dquot_logitem_init(dqp); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_qm_dquot); 52062306a36Sopenharmony_ci return dqp; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* Check the ondisk dquot's id and type match what the incore dquot expects. */ 52462306a36Sopenharmony_cistatic bool 52562306a36Sopenharmony_cixfs_dquot_check_type( 52662306a36Sopenharmony_ci struct xfs_dquot *dqp, 52762306a36Sopenharmony_ci struct xfs_disk_dquot *ddqp) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci uint8_t ddqp_type; 53062306a36Sopenharmony_ci uint8_t dqp_type; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ddqp_type = ddqp->d_type & XFS_DQTYPE_REC_MASK; 53362306a36Sopenharmony_ci dqp_type = xfs_dquot_type(dqp); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (be32_to_cpu(ddqp->d_id) != dqp->q_id) 53662306a36Sopenharmony_ci return false; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* 53962306a36Sopenharmony_ci * V5 filesystems always expect an exact type match. V4 filesystems 54062306a36Sopenharmony_ci * expect an exact match for user dquots and for non-root group and 54162306a36Sopenharmony_ci * project dquots. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci if (xfs_has_crc(dqp->q_mount) || 54462306a36Sopenharmony_ci dqp_type == XFS_DQTYPE_USER || dqp->q_id != 0) 54562306a36Sopenharmony_ci return ddqp_type == dqp_type; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* 54862306a36Sopenharmony_ci * V4 filesystems support either group or project quotas, but not both 54962306a36Sopenharmony_ci * at the same time. The non-user quota file can be switched between 55062306a36Sopenharmony_ci * group and project quota uses depending on the mount options, which 55162306a36Sopenharmony_ci * means that we can encounter the other type when we try to load quota 55262306a36Sopenharmony_ci * defaults. Quotacheck will soon reset the entire quota file 55362306a36Sopenharmony_ci * (including the root dquot) anyway, but don't log scary corruption 55462306a36Sopenharmony_ci * reports to dmesg. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ci return ddqp_type == XFS_DQTYPE_GROUP || ddqp_type == XFS_DQTYPE_PROJ; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/* Copy the in-core quota fields in from the on-disk buffer. */ 56062306a36Sopenharmony_ciSTATIC int 56162306a36Sopenharmony_cixfs_dquot_from_disk( 56262306a36Sopenharmony_ci struct xfs_dquot *dqp, 56362306a36Sopenharmony_ci struct xfs_buf *bp) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct xfs_dqblk *dqb = xfs_buf_offset(bp, dqp->q_bufoffset); 56662306a36Sopenharmony_ci struct xfs_disk_dquot *ddqp = &dqb->dd_diskdq; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci * Ensure that we got the type and ID we were looking for. 57062306a36Sopenharmony_ci * Everything else was checked by the dquot buffer verifier. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci if (!xfs_dquot_check_type(dqp, ddqp)) { 57362306a36Sopenharmony_ci xfs_alert_tag(bp->b_mount, XFS_PTAG_VERIFIER_ERROR, 57462306a36Sopenharmony_ci "Metadata corruption detected at %pS, quota %u", 57562306a36Sopenharmony_ci __this_address, dqp->q_id); 57662306a36Sopenharmony_ci xfs_alert(bp->b_mount, "Unmount and run xfs_repair"); 57762306a36Sopenharmony_ci return -EFSCORRUPTED; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* copy everything from disk dquot to the incore dquot */ 58162306a36Sopenharmony_ci dqp->q_type = ddqp->d_type; 58262306a36Sopenharmony_ci dqp->q_blk.hardlimit = be64_to_cpu(ddqp->d_blk_hardlimit); 58362306a36Sopenharmony_ci dqp->q_blk.softlimit = be64_to_cpu(ddqp->d_blk_softlimit); 58462306a36Sopenharmony_ci dqp->q_ino.hardlimit = be64_to_cpu(ddqp->d_ino_hardlimit); 58562306a36Sopenharmony_ci dqp->q_ino.softlimit = be64_to_cpu(ddqp->d_ino_softlimit); 58662306a36Sopenharmony_ci dqp->q_rtb.hardlimit = be64_to_cpu(ddqp->d_rtb_hardlimit); 58762306a36Sopenharmony_ci dqp->q_rtb.softlimit = be64_to_cpu(ddqp->d_rtb_softlimit); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci dqp->q_blk.count = be64_to_cpu(ddqp->d_bcount); 59062306a36Sopenharmony_ci dqp->q_ino.count = be64_to_cpu(ddqp->d_icount); 59162306a36Sopenharmony_ci dqp->q_rtb.count = be64_to_cpu(ddqp->d_rtbcount); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci dqp->q_blk.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_btimer); 59462306a36Sopenharmony_ci dqp->q_ino.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_itimer); 59562306a36Sopenharmony_ci dqp->q_rtb.timer = xfs_dquot_from_disk_ts(ddqp, ddqp->d_rtbtimer); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* 59862306a36Sopenharmony_ci * Reservation counters are defined as reservation plus current usage 59962306a36Sopenharmony_ci * to avoid having to add every time. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci dqp->q_blk.reserved = dqp->q_blk.count; 60262306a36Sopenharmony_ci dqp->q_ino.reserved = dqp->q_ino.count; 60362306a36Sopenharmony_ci dqp->q_rtb.reserved = dqp->q_rtb.count; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* initialize the dquot speculative prealloc thresholds */ 60662306a36Sopenharmony_ci xfs_dquot_set_prealloc_limits(dqp); 60762306a36Sopenharmony_ci return 0; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci/* Copy the in-core quota fields into the on-disk buffer. */ 61162306a36Sopenharmony_civoid 61262306a36Sopenharmony_cixfs_dquot_to_disk( 61362306a36Sopenharmony_ci struct xfs_disk_dquot *ddqp, 61462306a36Sopenharmony_ci struct xfs_dquot *dqp) 61562306a36Sopenharmony_ci{ 61662306a36Sopenharmony_ci ddqp->d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); 61762306a36Sopenharmony_ci ddqp->d_version = XFS_DQUOT_VERSION; 61862306a36Sopenharmony_ci ddqp->d_type = dqp->q_type; 61962306a36Sopenharmony_ci ddqp->d_id = cpu_to_be32(dqp->q_id); 62062306a36Sopenharmony_ci ddqp->d_pad0 = 0; 62162306a36Sopenharmony_ci ddqp->d_pad = 0; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci ddqp->d_blk_hardlimit = cpu_to_be64(dqp->q_blk.hardlimit); 62462306a36Sopenharmony_ci ddqp->d_blk_softlimit = cpu_to_be64(dqp->q_blk.softlimit); 62562306a36Sopenharmony_ci ddqp->d_ino_hardlimit = cpu_to_be64(dqp->q_ino.hardlimit); 62662306a36Sopenharmony_ci ddqp->d_ino_softlimit = cpu_to_be64(dqp->q_ino.softlimit); 62762306a36Sopenharmony_ci ddqp->d_rtb_hardlimit = cpu_to_be64(dqp->q_rtb.hardlimit); 62862306a36Sopenharmony_ci ddqp->d_rtb_softlimit = cpu_to_be64(dqp->q_rtb.softlimit); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ddqp->d_bcount = cpu_to_be64(dqp->q_blk.count); 63162306a36Sopenharmony_ci ddqp->d_icount = cpu_to_be64(dqp->q_ino.count); 63262306a36Sopenharmony_ci ddqp->d_rtbcount = cpu_to_be64(dqp->q_rtb.count); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci ddqp->d_bwarns = 0; 63562306a36Sopenharmony_ci ddqp->d_iwarns = 0; 63662306a36Sopenharmony_ci ddqp->d_rtbwarns = 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci ddqp->d_btimer = xfs_dquot_to_disk_ts(dqp, dqp->q_blk.timer); 63962306a36Sopenharmony_ci ddqp->d_itimer = xfs_dquot_to_disk_ts(dqp, dqp->q_ino.timer); 64062306a36Sopenharmony_ci ddqp->d_rtbtimer = xfs_dquot_to_disk_ts(dqp, dqp->q_rtb.timer); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* 64462306a36Sopenharmony_ci * Read in the ondisk dquot using dqtobp() then copy it to an incore version, 64562306a36Sopenharmony_ci * and release the buffer immediately. If @can_alloc is true, fill any 64662306a36Sopenharmony_ci * holes in the on-disk metadata. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_cistatic int 64962306a36Sopenharmony_cixfs_qm_dqread( 65062306a36Sopenharmony_ci struct xfs_mount *mp, 65162306a36Sopenharmony_ci xfs_dqid_t id, 65262306a36Sopenharmony_ci xfs_dqtype_t type, 65362306a36Sopenharmony_ci bool can_alloc, 65462306a36Sopenharmony_ci struct xfs_dquot **dqpp) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci struct xfs_dquot *dqp; 65762306a36Sopenharmony_ci struct xfs_buf *bp; 65862306a36Sopenharmony_ci int error; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci dqp = xfs_dquot_alloc(mp, id, type); 66162306a36Sopenharmony_ci trace_xfs_dqread(dqp); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* Try to read the buffer, allocating if necessary. */ 66462306a36Sopenharmony_ci error = xfs_dquot_disk_read(mp, dqp, &bp); 66562306a36Sopenharmony_ci if (error == -ENOENT && can_alloc) 66662306a36Sopenharmony_ci error = xfs_dquot_disk_alloc(dqp, &bp); 66762306a36Sopenharmony_ci if (error) 66862306a36Sopenharmony_ci goto err; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * At this point we should have a clean locked buffer. Copy the data 67262306a36Sopenharmony_ci * to the incore dquot and release the buffer since the incore dquot 67362306a36Sopenharmony_ci * has its own locking protocol so we needn't tie up the buffer any 67462306a36Sopenharmony_ci * further. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci ASSERT(xfs_buf_islocked(bp)); 67762306a36Sopenharmony_ci error = xfs_dquot_from_disk(dqp, bp); 67862306a36Sopenharmony_ci xfs_buf_relse(bp); 67962306a36Sopenharmony_ci if (error) 68062306a36Sopenharmony_ci goto err; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci *dqpp = dqp; 68362306a36Sopenharmony_ci return error; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_cierr: 68662306a36Sopenharmony_ci trace_xfs_dqread_fail(dqp); 68762306a36Sopenharmony_ci xfs_qm_dqdestroy(dqp); 68862306a36Sopenharmony_ci *dqpp = NULL; 68962306a36Sopenharmony_ci return error; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci/* 69362306a36Sopenharmony_ci * Advance to the next id in the current chunk, or if at the 69462306a36Sopenharmony_ci * end of the chunk, skip ahead to first id in next allocated chunk 69562306a36Sopenharmony_ci * using the SEEK_DATA interface. 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_cistatic int 69862306a36Sopenharmony_cixfs_dq_get_next_id( 69962306a36Sopenharmony_ci struct xfs_mount *mp, 70062306a36Sopenharmony_ci xfs_dqtype_t type, 70162306a36Sopenharmony_ci xfs_dqid_t *id) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct xfs_inode *quotip = xfs_quota_inode(mp, type); 70462306a36Sopenharmony_ci xfs_dqid_t next_id = *id + 1; /* simple advance */ 70562306a36Sopenharmony_ci uint lock_flags; 70662306a36Sopenharmony_ci struct xfs_bmbt_irec got; 70762306a36Sopenharmony_ci struct xfs_iext_cursor cur; 70862306a36Sopenharmony_ci xfs_fsblock_t start; 70962306a36Sopenharmony_ci int error = 0; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* If we'd wrap past the max ID, stop */ 71262306a36Sopenharmony_ci if (next_id < *id) 71362306a36Sopenharmony_ci return -ENOENT; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* If new ID is within the current chunk, advancing it sufficed */ 71662306a36Sopenharmony_ci if (next_id % mp->m_quotainfo->qi_dqperchunk) { 71762306a36Sopenharmony_ci *id = next_id; 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Nope, next_id is now past the current chunk, so find the next one */ 72262306a36Sopenharmony_ci start = (xfs_fsblock_t)next_id / mp->m_quotainfo->qi_dqperchunk; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci lock_flags = xfs_ilock_data_map_shared(quotip); 72562306a36Sopenharmony_ci error = xfs_iread_extents(NULL, quotip, XFS_DATA_FORK); 72662306a36Sopenharmony_ci if (error) 72762306a36Sopenharmony_ci return error; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci if (xfs_iext_lookup_extent(quotip, "ip->i_df, start, &cur, &got)) { 73062306a36Sopenharmony_ci /* contiguous chunk, bump startoff for the id calculation */ 73162306a36Sopenharmony_ci if (got.br_startoff < start) 73262306a36Sopenharmony_ci got.br_startoff = start; 73362306a36Sopenharmony_ci *id = got.br_startoff * mp->m_quotainfo->qi_dqperchunk; 73462306a36Sopenharmony_ci } else { 73562306a36Sopenharmony_ci error = -ENOENT; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci xfs_iunlock(quotip, lock_flags); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return error; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci/* 74462306a36Sopenharmony_ci * Look up the dquot in the in-core cache. If found, the dquot is returned 74562306a36Sopenharmony_ci * locked and ready to go. 74662306a36Sopenharmony_ci */ 74762306a36Sopenharmony_cistatic struct xfs_dquot * 74862306a36Sopenharmony_cixfs_qm_dqget_cache_lookup( 74962306a36Sopenharmony_ci struct xfs_mount *mp, 75062306a36Sopenharmony_ci struct xfs_quotainfo *qi, 75162306a36Sopenharmony_ci struct radix_tree_root *tree, 75262306a36Sopenharmony_ci xfs_dqid_t id) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct xfs_dquot *dqp; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cirestart: 75762306a36Sopenharmony_ci mutex_lock(&qi->qi_tree_lock); 75862306a36Sopenharmony_ci dqp = radix_tree_lookup(tree, id); 75962306a36Sopenharmony_ci if (!dqp) { 76062306a36Sopenharmony_ci mutex_unlock(&qi->qi_tree_lock); 76162306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_qm_dqcachemisses); 76262306a36Sopenharmony_ci return NULL; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci xfs_dqlock(dqp); 76662306a36Sopenharmony_ci if (dqp->q_flags & XFS_DQFLAG_FREEING) { 76762306a36Sopenharmony_ci xfs_dqunlock(dqp); 76862306a36Sopenharmony_ci mutex_unlock(&qi->qi_tree_lock); 76962306a36Sopenharmony_ci trace_xfs_dqget_freeing(dqp); 77062306a36Sopenharmony_ci delay(1); 77162306a36Sopenharmony_ci goto restart; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci dqp->q_nrefs++; 77562306a36Sopenharmony_ci mutex_unlock(&qi->qi_tree_lock); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci trace_xfs_dqget_hit(dqp); 77862306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_qm_dqcachehits); 77962306a36Sopenharmony_ci return dqp; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci/* 78362306a36Sopenharmony_ci * Try to insert a new dquot into the in-core cache. If an error occurs the 78462306a36Sopenharmony_ci * caller should throw away the dquot and start over. Otherwise, the dquot 78562306a36Sopenharmony_ci * is returned locked (and held by the cache) as if there had been a cache 78662306a36Sopenharmony_ci * hit. 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_cistatic int 78962306a36Sopenharmony_cixfs_qm_dqget_cache_insert( 79062306a36Sopenharmony_ci struct xfs_mount *mp, 79162306a36Sopenharmony_ci struct xfs_quotainfo *qi, 79262306a36Sopenharmony_ci struct radix_tree_root *tree, 79362306a36Sopenharmony_ci xfs_dqid_t id, 79462306a36Sopenharmony_ci struct xfs_dquot *dqp) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci int error; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci mutex_lock(&qi->qi_tree_lock); 79962306a36Sopenharmony_ci error = radix_tree_insert(tree, id, dqp); 80062306a36Sopenharmony_ci if (unlikely(error)) { 80162306a36Sopenharmony_ci /* Duplicate found! Caller must try again. */ 80262306a36Sopenharmony_ci mutex_unlock(&qi->qi_tree_lock); 80362306a36Sopenharmony_ci trace_xfs_dqget_dup(dqp); 80462306a36Sopenharmony_ci return error; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* Return a locked dquot to the caller, with a reference taken. */ 80862306a36Sopenharmony_ci xfs_dqlock(dqp); 80962306a36Sopenharmony_ci dqp->q_nrefs = 1; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci qi->qi_dquots++; 81262306a36Sopenharmony_ci mutex_unlock(&qi->qi_tree_lock); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci return 0; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/* Check our input parameters. */ 81862306a36Sopenharmony_cistatic int 81962306a36Sopenharmony_cixfs_qm_dqget_checks( 82062306a36Sopenharmony_ci struct xfs_mount *mp, 82162306a36Sopenharmony_ci xfs_dqtype_t type) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci switch (type) { 82462306a36Sopenharmony_ci case XFS_DQTYPE_USER: 82562306a36Sopenharmony_ci if (!XFS_IS_UQUOTA_ON(mp)) 82662306a36Sopenharmony_ci return -ESRCH; 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci case XFS_DQTYPE_GROUP: 82962306a36Sopenharmony_ci if (!XFS_IS_GQUOTA_ON(mp)) 83062306a36Sopenharmony_ci return -ESRCH; 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci case XFS_DQTYPE_PROJ: 83362306a36Sopenharmony_ci if (!XFS_IS_PQUOTA_ON(mp)) 83462306a36Sopenharmony_ci return -ESRCH; 83562306a36Sopenharmony_ci return 0; 83662306a36Sopenharmony_ci default: 83762306a36Sopenharmony_ci WARN_ON_ONCE(0); 83862306a36Sopenharmony_ci return -EINVAL; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/* 84362306a36Sopenharmony_ci * Given the file system, id, and type (UDQUOT/GDQUOT/PDQUOT), return a 84462306a36Sopenharmony_ci * locked dquot, doing an allocation (if requested) as needed. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_ciint 84762306a36Sopenharmony_cixfs_qm_dqget( 84862306a36Sopenharmony_ci struct xfs_mount *mp, 84962306a36Sopenharmony_ci xfs_dqid_t id, 85062306a36Sopenharmony_ci xfs_dqtype_t type, 85162306a36Sopenharmony_ci bool can_alloc, 85262306a36Sopenharmony_ci struct xfs_dquot **O_dqpp) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci struct xfs_quotainfo *qi = mp->m_quotainfo; 85562306a36Sopenharmony_ci struct radix_tree_root *tree = xfs_dquot_tree(qi, type); 85662306a36Sopenharmony_ci struct xfs_dquot *dqp; 85762306a36Sopenharmony_ci int error; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci error = xfs_qm_dqget_checks(mp, type); 86062306a36Sopenharmony_ci if (error) 86162306a36Sopenharmony_ci return error; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cirestart: 86462306a36Sopenharmony_ci dqp = xfs_qm_dqget_cache_lookup(mp, qi, tree, id); 86562306a36Sopenharmony_ci if (dqp) { 86662306a36Sopenharmony_ci *O_dqpp = dqp; 86762306a36Sopenharmony_ci return 0; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci error = xfs_qm_dqread(mp, id, type, can_alloc, &dqp); 87162306a36Sopenharmony_ci if (error) 87262306a36Sopenharmony_ci return error; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci error = xfs_qm_dqget_cache_insert(mp, qi, tree, id, dqp); 87562306a36Sopenharmony_ci if (error) { 87662306a36Sopenharmony_ci /* 87762306a36Sopenharmony_ci * Duplicate found. Just throw away the new dquot and start 87862306a36Sopenharmony_ci * over. 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_ci xfs_qm_dqdestroy(dqp); 88162306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_qm_dquot_dups); 88262306a36Sopenharmony_ci goto restart; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci trace_xfs_dqget_miss(dqp); 88662306a36Sopenharmony_ci *O_dqpp = dqp; 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci/* 89162306a36Sopenharmony_ci * Given a dquot id and type, read and initialize a dquot from the on-disk 89262306a36Sopenharmony_ci * metadata. This function is only for use during quota initialization so 89362306a36Sopenharmony_ci * it ignores the dquot cache assuming that the dquot shrinker isn't set up. 89462306a36Sopenharmony_ci * The caller is responsible for _qm_dqdestroy'ing the returned dquot. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ciint 89762306a36Sopenharmony_cixfs_qm_dqget_uncached( 89862306a36Sopenharmony_ci struct xfs_mount *mp, 89962306a36Sopenharmony_ci xfs_dqid_t id, 90062306a36Sopenharmony_ci xfs_dqtype_t type, 90162306a36Sopenharmony_ci struct xfs_dquot **dqpp) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci int error; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci error = xfs_qm_dqget_checks(mp, type); 90662306a36Sopenharmony_ci if (error) 90762306a36Sopenharmony_ci return error; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci return xfs_qm_dqread(mp, id, type, 0, dqpp); 91062306a36Sopenharmony_ci} 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci/* Return the quota id for a given inode and type. */ 91362306a36Sopenharmony_cixfs_dqid_t 91462306a36Sopenharmony_cixfs_qm_id_for_quotatype( 91562306a36Sopenharmony_ci struct xfs_inode *ip, 91662306a36Sopenharmony_ci xfs_dqtype_t type) 91762306a36Sopenharmony_ci{ 91862306a36Sopenharmony_ci switch (type) { 91962306a36Sopenharmony_ci case XFS_DQTYPE_USER: 92062306a36Sopenharmony_ci return i_uid_read(VFS_I(ip)); 92162306a36Sopenharmony_ci case XFS_DQTYPE_GROUP: 92262306a36Sopenharmony_ci return i_gid_read(VFS_I(ip)); 92362306a36Sopenharmony_ci case XFS_DQTYPE_PROJ: 92462306a36Sopenharmony_ci return ip->i_projid; 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci ASSERT(0); 92762306a36Sopenharmony_ci return 0; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci/* 93162306a36Sopenharmony_ci * Return the dquot for a given inode and type. If @can_alloc is true, then 93262306a36Sopenharmony_ci * allocate blocks if needed. The inode's ILOCK must be held and it must not 93362306a36Sopenharmony_ci * have already had an inode attached. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_ciint 93662306a36Sopenharmony_cixfs_qm_dqget_inode( 93762306a36Sopenharmony_ci struct xfs_inode *ip, 93862306a36Sopenharmony_ci xfs_dqtype_t type, 93962306a36Sopenharmony_ci bool can_alloc, 94062306a36Sopenharmony_ci struct xfs_dquot **O_dqpp) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct xfs_mount *mp = ip->i_mount; 94362306a36Sopenharmony_ci struct xfs_quotainfo *qi = mp->m_quotainfo; 94462306a36Sopenharmony_ci struct radix_tree_root *tree = xfs_dquot_tree(qi, type); 94562306a36Sopenharmony_ci struct xfs_dquot *dqp; 94662306a36Sopenharmony_ci xfs_dqid_t id; 94762306a36Sopenharmony_ci int error; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci error = xfs_qm_dqget_checks(mp, type); 95062306a36Sopenharmony_ci if (error) 95162306a36Sopenharmony_ci return error; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); 95462306a36Sopenharmony_ci ASSERT(xfs_inode_dquot(ip, type) == NULL); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci id = xfs_qm_id_for_quotatype(ip, type); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_cirestart: 95962306a36Sopenharmony_ci dqp = xfs_qm_dqget_cache_lookup(mp, qi, tree, id); 96062306a36Sopenharmony_ci if (dqp) { 96162306a36Sopenharmony_ci *O_dqpp = dqp; 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci } 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * Dquot cache miss. We don't want to keep the inode lock across 96762306a36Sopenharmony_ci * a (potential) disk read. Also we don't want to deal with the lock 96862306a36Sopenharmony_ci * ordering between quotainode and this inode. OTOH, dropping the inode 96962306a36Sopenharmony_ci * lock here means dealing with a chown that can happen before 97062306a36Sopenharmony_ci * we re-acquire the lock. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci xfs_iunlock(ip, XFS_ILOCK_EXCL); 97362306a36Sopenharmony_ci error = xfs_qm_dqread(mp, id, type, can_alloc, &dqp); 97462306a36Sopenharmony_ci xfs_ilock(ip, XFS_ILOCK_EXCL); 97562306a36Sopenharmony_ci if (error) 97662306a36Sopenharmony_ci return error; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* 97962306a36Sopenharmony_ci * A dquot could be attached to this inode by now, since we had 98062306a36Sopenharmony_ci * dropped the ilock. 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci if (xfs_this_quota_on(mp, type)) { 98362306a36Sopenharmony_ci struct xfs_dquot *dqp1; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci dqp1 = xfs_inode_dquot(ip, type); 98662306a36Sopenharmony_ci if (dqp1) { 98762306a36Sopenharmony_ci xfs_qm_dqdestroy(dqp); 98862306a36Sopenharmony_ci dqp = dqp1; 98962306a36Sopenharmony_ci xfs_dqlock(dqp); 99062306a36Sopenharmony_ci goto dqret; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci } else { 99362306a36Sopenharmony_ci /* inode stays locked on return */ 99462306a36Sopenharmony_ci xfs_qm_dqdestroy(dqp); 99562306a36Sopenharmony_ci return -ESRCH; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci error = xfs_qm_dqget_cache_insert(mp, qi, tree, id, dqp); 99962306a36Sopenharmony_ci if (error) { 100062306a36Sopenharmony_ci /* 100162306a36Sopenharmony_ci * Duplicate found. Just throw away the new dquot and start 100262306a36Sopenharmony_ci * over. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci xfs_qm_dqdestroy(dqp); 100562306a36Sopenharmony_ci XFS_STATS_INC(mp, xs_qm_dquot_dups); 100662306a36Sopenharmony_ci goto restart; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cidqret: 101062306a36Sopenharmony_ci ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); 101162306a36Sopenharmony_ci trace_xfs_dqget_miss(dqp); 101262306a36Sopenharmony_ci *O_dqpp = dqp; 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci/* 101762306a36Sopenharmony_ci * Starting at @id and progressing upwards, look for an initialized incore 101862306a36Sopenharmony_ci * dquot, lock it, and return it. 101962306a36Sopenharmony_ci */ 102062306a36Sopenharmony_ciint 102162306a36Sopenharmony_cixfs_qm_dqget_next( 102262306a36Sopenharmony_ci struct xfs_mount *mp, 102362306a36Sopenharmony_ci xfs_dqid_t id, 102462306a36Sopenharmony_ci xfs_dqtype_t type, 102562306a36Sopenharmony_ci struct xfs_dquot **dqpp) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci struct xfs_dquot *dqp; 102862306a36Sopenharmony_ci int error = 0; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci *dqpp = NULL; 103162306a36Sopenharmony_ci for (; !error; error = xfs_dq_get_next_id(mp, type, &id)) { 103262306a36Sopenharmony_ci error = xfs_qm_dqget(mp, id, type, false, &dqp); 103362306a36Sopenharmony_ci if (error == -ENOENT) 103462306a36Sopenharmony_ci continue; 103562306a36Sopenharmony_ci else if (error != 0) 103662306a36Sopenharmony_ci break; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (!XFS_IS_DQUOT_UNINITIALIZED(dqp)) { 103962306a36Sopenharmony_ci *dqpp = dqp; 104062306a36Sopenharmony_ci return 0; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci xfs_qm_dqput(dqp); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci return error; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci/* 105062306a36Sopenharmony_ci * Release a reference to the dquot (decrement ref-count) and unlock it. 105162306a36Sopenharmony_ci * 105262306a36Sopenharmony_ci * If there is a group quota attached to this dquot, carefully release that 105362306a36Sopenharmony_ci * too without tripping over deadlocks'n'stuff. 105462306a36Sopenharmony_ci */ 105562306a36Sopenharmony_civoid 105662306a36Sopenharmony_cixfs_qm_dqput( 105762306a36Sopenharmony_ci struct xfs_dquot *dqp) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci ASSERT(dqp->q_nrefs > 0); 106062306a36Sopenharmony_ci ASSERT(XFS_DQ_IS_LOCKED(dqp)); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci trace_xfs_dqput(dqp); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (--dqp->q_nrefs == 0) { 106562306a36Sopenharmony_ci struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo; 106662306a36Sopenharmony_ci trace_xfs_dqput_free(dqp); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci if (list_lru_add(&qi->qi_lru, &dqp->q_lru)) 106962306a36Sopenharmony_ci XFS_STATS_INC(dqp->q_mount, xs_qm_dquot_unused); 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci xfs_dqunlock(dqp); 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci/* 107562306a36Sopenharmony_ci * Release a dquot. Flush it if dirty, then dqput() it. 107662306a36Sopenharmony_ci * dquot must not be locked. 107762306a36Sopenharmony_ci */ 107862306a36Sopenharmony_civoid 107962306a36Sopenharmony_cixfs_qm_dqrele( 108062306a36Sopenharmony_ci struct xfs_dquot *dqp) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci if (!dqp) 108362306a36Sopenharmony_ci return; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci trace_xfs_dqrele(dqp); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci xfs_dqlock(dqp); 108862306a36Sopenharmony_ci /* 108962306a36Sopenharmony_ci * We don't care to flush it if the dquot is dirty here. 109062306a36Sopenharmony_ci * That will create stutters that we want to avoid. 109162306a36Sopenharmony_ci * Instead we do a delayed write when we try to reclaim 109262306a36Sopenharmony_ci * a dirty dquot. Also xfs_sync will take part of the burden... 109362306a36Sopenharmony_ci */ 109462306a36Sopenharmony_ci xfs_qm_dqput(dqp); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci/* 109862306a36Sopenharmony_ci * This is the dquot flushing I/O completion routine. It is called 109962306a36Sopenharmony_ci * from interrupt level when the buffer containing the dquot is 110062306a36Sopenharmony_ci * flushed to disk. It is responsible for removing the dquot logitem 110162306a36Sopenharmony_ci * from the AIL if it has not been re-logged, and unlocking the dquot's 110262306a36Sopenharmony_ci * flush lock. This behavior is very similar to that of inodes.. 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_cistatic void 110562306a36Sopenharmony_cixfs_qm_dqflush_done( 110662306a36Sopenharmony_ci struct xfs_log_item *lip) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct xfs_dq_logitem *qip = (struct xfs_dq_logitem *)lip; 110962306a36Sopenharmony_ci struct xfs_dquot *dqp = qip->qli_dquot; 111062306a36Sopenharmony_ci struct xfs_ail *ailp = lip->li_ailp; 111162306a36Sopenharmony_ci xfs_lsn_t tail_lsn; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* 111462306a36Sopenharmony_ci * We only want to pull the item from the AIL if its 111562306a36Sopenharmony_ci * location in the log has not changed since we started the flush. 111662306a36Sopenharmony_ci * Thus, we only bother if the dquot's lsn has 111762306a36Sopenharmony_ci * not changed. First we check the lsn outside the lock 111862306a36Sopenharmony_ci * since it's cheaper, and then we recheck while 111962306a36Sopenharmony_ci * holding the lock before removing the dquot from the AIL. 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci if (test_bit(XFS_LI_IN_AIL, &lip->li_flags) && 112262306a36Sopenharmony_ci ((lip->li_lsn == qip->qli_flush_lsn) || 112362306a36Sopenharmony_ci test_bit(XFS_LI_FAILED, &lip->li_flags))) { 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci spin_lock(&ailp->ail_lock); 112662306a36Sopenharmony_ci xfs_clear_li_failed(lip); 112762306a36Sopenharmony_ci if (lip->li_lsn == qip->qli_flush_lsn) { 112862306a36Sopenharmony_ci /* xfs_ail_update_finish() drops the AIL lock */ 112962306a36Sopenharmony_ci tail_lsn = xfs_ail_delete_one(ailp, lip); 113062306a36Sopenharmony_ci xfs_ail_update_finish(ailp, tail_lsn); 113162306a36Sopenharmony_ci } else { 113262306a36Sopenharmony_ci spin_unlock(&ailp->ail_lock); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci /* 113762306a36Sopenharmony_ci * Release the dq's flush lock since we're done with it. 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_ci xfs_dqfunlock(dqp); 114062306a36Sopenharmony_ci} 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_civoid 114362306a36Sopenharmony_cixfs_buf_dquot_iodone( 114462306a36Sopenharmony_ci struct xfs_buf *bp) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci struct xfs_log_item *lip, *n; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci list_for_each_entry_safe(lip, n, &bp->b_li_list, li_bio_list) { 114962306a36Sopenharmony_ci list_del_init(&lip->li_bio_list); 115062306a36Sopenharmony_ci xfs_qm_dqflush_done(lip); 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_civoid 115562306a36Sopenharmony_cixfs_buf_dquot_io_fail( 115662306a36Sopenharmony_ci struct xfs_buf *bp) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct xfs_log_item *lip; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci spin_lock(&bp->b_mount->m_ail->ail_lock); 116162306a36Sopenharmony_ci list_for_each_entry(lip, &bp->b_li_list, li_bio_list) 116262306a36Sopenharmony_ci xfs_set_li_failed(lip, bp); 116362306a36Sopenharmony_ci spin_unlock(&bp->b_mount->m_ail->ail_lock); 116462306a36Sopenharmony_ci} 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci/* Check incore dquot for errors before we flush. */ 116762306a36Sopenharmony_cistatic xfs_failaddr_t 116862306a36Sopenharmony_cixfs_qm_dqflush_check( 116962306a36Sopenharmony_ci struct xfs_dquot *dqp) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci xfs_dqtype_t type = xfs_dquot_type(dqp); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (type != XFS_DQTYPE_USER && 117462306a36Sopenharmony_ci type != XFS_DQTYPE_GROUP && 117562306a36Sopenharmony_ci type != XFS_DQTYPE_PROJ) 117662306a36Sopenharmony_ci return __this_address; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (dqp->q_id == 0) 117962306a36Sopenharmony_ci return NULL; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (dqp->q_blk.softlimit && dqp->q_blk.count > dqp->q_blk.softlimit && 118262306a36Sopenharmony_ci !dqp->q_blk.timer) 118362306a36Sopenharmony_ci return __this_address; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (dqp->q_ino.softlimit && dqp->q_ino.count > dqp->q_ino.softlimit && 118662306a36Sopenharmony_ci !dqp->q_ino.timer) 118762306a36Sopenharmony_ci return __this_address; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (dqp->q_rtb.softlimit && dqp->q_rtb.count > dqp->q_rtb.softlimit && 119062306a36Sopenharmony_ci !dqp->q_rtb.timer) 119162306a36Sopenharmony_ci return __this_address; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* bigtime flag should never be set on root dquots */ 119462306a36Sopenharmony_ci if (dqp->q_type & XFS_DQTYPE_BIGTIME) { 119562306a36Sopenharmony_ci if (!xfs_has_bigtime(dqp->q_mount)) 119662306a36Sopenharmony_ci return __this_address; 119762306a36Sopenharmony_ci if (dqp->q_id == 0) 119862306a36Sopenharmony_ci return __this_address; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci return NULL; 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci/* 120562306a36Sopenharmony_ci * Write a modified dquot to disk. 120662306a36Sopenharmony_ci * The dquot must be locked and the flush lock too taken by caller. 120762306a36Sopenharmony_ci * The flush lock will not be unlocked until the dquot reaches the disk, 120862306a36Sopenharmony_ci * but the dquot is free to be unlocked and modified by the caller 120962306a36Sopenharmony_ci * in the interim. Dquot is still locked on return. This behavior is 121062306a36Sopenharmony_ci * identical to that of inodes. 121162306a36Sopenharmony_ci */ 121262306a36Sopenharmony_ciint 121362306a36Sopenharmony_cixfs_qm_dqflush( 121462306a36Sopenharmony_ci struct xfs_dquot *dqp, 121562306a36Sopenharmony_ci struct xfs_buf **bpp) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci struct xfs_mount *mp = dqp->q_mount; 121862306a36Sopenharmony_ci struct xfs_log_item *lip = &dqp->q_logitem.qli_item; 121962306a36Sopenharmony_ci struct xfs_buf *bp; 122062306a36Sopenharmony_ci struct xfs_dqblk *dqblk; 122162306a36Sopenharmony_ci xfs_failaddr_t fa; 122262306a36Sopenharmony_ci int error; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci ASSERT(XFS_DQ_IS_LOCKED(dqp)); 122562306a36Sopenharmony_ci ASSERT(!completion_done(&dqp->q_flush)); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci trace_xfs_dqflush(dqp); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci *bpp = NULL; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci xfs_qm_dqunpin_wait(dqp); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* 123462306a36Sopenharmony_ci * Get the buffer containing the on-disk dquot 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno, 123762306a36Sopenharmony_ci mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK, 123862306a36Sopenharmony_ci &bp, &xfs_dquot_buf_ops); 123962306a36Sopenharmony_ci if (error == -EAGAIN) 124062306a36Sopenharmony_ci goto out_unlock; 124162306a36Sopenharmony_ci if (error) 124262306a36Sopenharmony_ci goto out_abort; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci fa = xfs_qm_dqflush_check(dqp); 124562306a36Sopenharmony_ci if (fa) { 124662306a36Sopenharmony_ci xfs_alert(mp, "corrupt dquot ID 0x%x in memory at %pS", 124762306a36Sopenharmony_ci dqp->q_id, fa); 124862306a36Sopenharmony_ci xfs_buf_relse(bp); 124962306a36Sopenharmony_ci error = -EFSCORRUPTED; 125062306a36Sopenharmony_ci goto out_abort; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci /* Flush the incore dquot to the ondisk buffer. */ 125462306a36Sopenharmony_ci dqblk = xfs_buf_offset(bp, dqp->q_bufoffset); 125562306a36Sopenharmony_ci xfs_dquot_to_disk(&dqblk->dd_diskdq, dqp); 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* 125862306a36Sopenharmony_ci * Clear the dirty field and remember the flush lsn for later use. 125962306a36Sopenharmony_ci */ 126062306a36Sopenharmony_ci dqp->q_flags &= ~XFS_DQFLAG_DIRTY; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci xfs_trans_ail_copy_lsn(mp->m_ail, &dqp->q_logitem.qli_flush_lsn, 126362306a36Sopenharmony_ci &dqp->q_logitem.qli_item.li_lsn); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* 126662306a36Sopenharmony_ci * copy the lsn into the on-disk dquot now while we have the in memory 126762306a36Sopenharmony_ci * dquot here. This can't be done later in the write verifier as we 126862306a36Sopenharmony_ci * can't get access to the log item at that point in time. 126962306a36Sopenharmony_ci * 127062306a36Sopenharmony_ci * We also calculate the CRC here so that the on-disk dquot in the 127162306a36Sopenharmony_ci * buffer always has a valid CRC. This ensures there is no possibility 127262306a36Sopenharmony_ci * of a dquot without an up-to-date CRC getting to disk. 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_ci if (xfs_has_crc(mp)) { 127562306a36Sopenharmony_ci dqblk->dd_lsn = cpu_to_be64(dqp->q_logitem.qli_item.li_lsn); 127662306a36Sopenharmony_ci xfs_update_cksum((char *)dqblk, sizeof(struct xfs_dqblk), 127762306a36Sopenharmony_ci XFS_DQUOT_CRC_OFF); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* 128162306a36Sopenharmony_ci * Attach the dquot to the buffer so that we can remove this dquot from 128262306a36Sopenharmony_ci * the AIL and release the flush lock once the dquot is synced to disk. 128362306a36Sopenharmony_ci */ 128462306a36Sopenharmony_ci bp->b_flags |= _XBF_DQUOTS; 128562306a36Sopenharmony_ci list_add_tail(&dqp->q_logitem.qli_item.li_bio_list, &bp->b_li_list); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci /* 128862306a36Sopenharmony_ci * If the buffer is pinned then push on the log so we won't 128962306a36Sopenharmony_ci * get stuck waiting in the write for too long. 129062306a36Sopenharmony_ci */ 129162306a36Sopenharmony_ci if (xfs_buf_ispinned(bp)) { 129262306a36Sopenharmony_ci trace_xfs_dqflush_force(dqp); 129362306a36Sopenharmony_ci xfs_log_force(mp, 0); 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci trace_xfs_dqflush_done(dqp); 129762306a36Sopenharmony_ci *bpp = bp; 129862306a36Sopenharmony_ci return 0; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ciout_abort: 130162306a36Sopenharmony_ci dqp->q_flags &= ~XFS_DQFLAG_DIRTY; 130262306a36Sopenharmony_ci xfs_trans_ail_delete(lip, 0); 130362306a36Sopenharmony_ci xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 130462306a36Sopenharmony_ciout_unlock: 130562306a36Sopenharmony_ci xfs_dqfunlock(dqp); 130662306a36Sopenharmony_ci return error; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci/* 131062306a36Sopenharmony_ci * Lock two xfs_dquot structures. 131162306a36Sopenharmony_ci * 131262306a36Sopenharmony_ci * To avoid deadlocks we always lock the quota structure with 131362306a36Sopenharmony_ci * the lowerd id first. 131462306a36Sopenharmony_ci */ 131562306a36Sopenharmony_civoid 131662306a36Sopenharmony_cixfs_dqlock2( 131762306a36Sopenharmony_ci struct xfs_dquot *d1, 131862306a36Sopenharmony_ci struct xfs_dquot *d2) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci if (d1 && d2) { 132162306a36Sopenharmony_ci ASSERT(d1 != d2); 132262306a36Sopenharmony_ci if (d1->q_id > d2->q_id) { 132362306a36Sopenharmony_ci mutex_lock(&d2->q_qlock); 132462306a36Sopenharmony_ci mutex_lock_nested(&d1->q_qlock, XFS_QLOCK_NESTED); 132562306a36Sopenharmony_ci } else { 132662306a36Sopenharmony_ci mutex_lock(&d1->q_qlock); 132762306a36Sopenharmony_ci mutex_lock_nested(&d2->q_qlock, XFS_QLOCK_NESTED); 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci } else if (d1) { 133062306a36Sopenharmony_ci mutex_lock(&d1->q_qlock); 133162306a36Sopenharmony_ci } else if (d2) { 133262306a36Sopenharmony_ci mutex_lock(&d2->q_qlock); 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ciint __init 133762306a36Sopenharmony_cixfs_qm_init(void) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci xfs_dquot_cache = kmem_cache_create("xfs_dquot", 134062306a36Sopenharmony_ci sizeof(struct xfs_dquot), 134162306a36Sopenharmony_ci 0, 0, NULL); 134262306a36Sopenharmony_ci if (!xfs_dquot_cache) 134362306a36Sopenharmony_ci goto out; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci xfs_dqtrx_cache = kmem_cache_create("xfs_dqtrx", 134662306a36Sopenharmony_ci sizeof(struct xfs_dquot_acct), 134762306a36Sopenharmony_ci 0, 0, NULL); 134862306a36Sopenharmony_ci if (!xfs_dqtrx_cache) 134962306a36Sopenharmony_ci goto out_free_dquot_cache; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return 0; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ciout_free_dquot_cache: 135462306a36Sopenharmony_ci kmem_cache_destroy(xfs_dquot_cache); 135562306a36Sopenharmony_ciout: 135662306a36Sopenharmony_ci return -ENOMEM; 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_civoid 136062306a36Sopenharmony_cixfs_qm_exit(void) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci kmem_cache_destroy(xfs_dqtrx_cache); 136362306a36Sopenharmony_ci kmem_cache_destroy(xfs_dquot_cache); 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci/* 136762306a36Sopenharmony_ci * Iterate every dquot of a particular type. The caller must ensure that the 136862306a36Sopenharmony_ci * particular quota type is active. iter_fn can return negative error codes, 136962306a36Sopenharmony_ci * or -ECANCELED to indicate that it wants to stop iterating. 137062306a36Sopenharmony_ci */ 137162306a36Sopenharmony_ciint 137262306a36Sopenharmony_cixfs_qm_dqiterate( 137362306a36Sopenharmony_ci struct xfs_mount *mp, 137462306a36Sopenharmony_ci xfs_dqtype_t type, 137562306a36Sopenharmony_ci xfs_qm_dqiterate_fn iter_fn, 137662306a36Sopenharmony_ci void *priv) 137762306a36Sopenharmony_ci{ 137862306a36Sopenharmony_ci struct xfs_dquot *dq; 137962306a36Sopenharmony_ci xfs_dqid_t id = 0; 138062306a36Sopenharmony_ci int error; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci do { 138362306a36Sopenharmony_ci error = xfs_qm_dqget_next(mp, id, type, &dq); 138462306a36Sopenharmony_ci if (error == -ENOENT) 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci if (error) 138762306a36Sopenharmony_ci return error; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci error = iter_fn(dq, type, priv); 139062306a36Sopenharmony_ci id = dq->q_id + 1; 139162306a36Sopenharmony_ci xfs_qm_dqput(dq); 139262306a36Sopenharmony_ci } while (error == 0 && id != 0); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci return error; 139562306a36Sopenharmony_ci} 1396