xref: /openbmc/linux/fs/ocfs2/quota_global.c (revision dad7d975)
19e33d69fSJan Kara /*
29e33d69fSJan Kara  *  Implementation of operations over global quota file
39e33d69fSJan Kara  */
4171bf93cSMark Fasheh #include <linux/spinlock.h>
59e33d69fSJan Kara #include <linux/fs.h>
69e33d69fSJan Kara #include <linux/quota.h>
79e33d69fSJan Kara #include <linux/quotaops.h>
89e33d69fSJan Kara #include <linux/dqblk_qtree.h>
9171bf93cSMark Fasheh #include <linux/jiffies.h>
10171bf93cSMark Fasheh #include <linux/writeback.h>
11171bf93cSMark Fasheh #include <linux/workqueue.h>
129e33d69fSJan Kara 
139e33d69fSJan Kara #define MLOG_MASK_PREFIX ML_QUOTA
149e33d69fSJan Kara #include <cluster/masklog.h>
159e33d69fSJan Kara 
169e33d69fSJan Kara #include "ocfs2_fs.h"
179e33d69fSJan Kara #include "ocfs2.h"
189e33d69fSJan Kara #include "alloc.h"
19d6b32bbbSJoel Becker #include "blockcheck.h"
209e33d69fSJan Kara #include "inode.h"
219e33d69fSJan Kara #include "journal.h"
229e33d69fSJan Kara #include "file.h"
239e33d69fSJan Kara #include "sysfile.h"
249e33d69fSJan Kara #include "dlmglue.h"
259e33d69fSJan Kara #include "uptodate.h"
269e33d69fSJan Kara #include "quota.h"
279e33d69fSJan Kara 
28171bf93cSMark Fasheh static struct workqueue_struct *ocfs2_quota_wq = NULL;
29171bf93cSMark Fasheh 
30171bf93cSMark Fasheh static void qsync_work_fn(struct work_struct *work);
31171bf93cSMark Fasheh 
329e33d69fSJan Kara static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
339e33d69fSJan Kara {
349e33d69fSJan Kara 	struct ocfs2_global_disk_dqblk *d = dp;
359e33d69fSJan Kara 	struct mem_dqblk *m = &dquot->dq_dqb;
369e33d69fSJan Kara 
379e33d69fSJan Kara 	/* Update from disk only entries not set by the admin */
389e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags)) {
399e33d69fSJan Kara 		m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
409e33d69fSJan Kara 		m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
419e33d69fSJan Kara 	}
429e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
439e33d69fSJan Kara 		m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
449e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags)) {
459e33d69fSJan Kara 		m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit);
469e33d69fSJan Kara 		m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit);
479e33d69fSJan Kara 	}
489e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
499e33d69fSJan Kara 		m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
509e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags))
519e33d69fSJan Kara 		m->dqb_btime = le64_to_cpu(d->dqb_btime);
529e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags))
539e33d69fSJan Kara 		m->dqb_itime = le64_to_cpu(d->dqb_itime);
549e33d69fSJan Kara 	OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count);
559e33d69fSJan Kara }
569e33d69fSJan Kara 
579e33d69fSJan Kara static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
589e33d69fSJan Kara {
599e33d69fSJan Kara 	struct ocfs2_global_disk_dqblk *d = dp;
609e33d69fSJan Kara 	struct mem_dqblk *m = &dquot->dq_dqb;
619e33d69fSJan Kara 
629e33d69fSJan Kara 	d->dqb_id = cpu_to_le32(dquot->dq_id);
639e33d69fSJan Kara 	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
649e33d69fSJan Kara 	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
659e33d69fSJan Kara 	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
669e33d69fSJan Kara 	d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
679e33d69fSJan Kara 	d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
689e33d69fSJan Kara 	d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
699e33d69fSJan Kara 	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
709e33d69fSJan Kara 	d->dqb_btime = cpu_to_le64(m->dqb_btime);
719e33d69fSJan Kara 	d->dqb_itime = cpu_to_le64(m->dqb_itime);
729e33d69fSJan Kara }
739e33d69fSJan Kara 
749e33d69fSJan Kara static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
759e33d69fSJan Kara {
769e33d69fSJan Kara 	struct ocfs2_global_disk_dqblk *d = dp;
779e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo =
789e33d69fSJan Kara 			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
799e33d69fSJan Kara 
809e33d69fSJan Kara 	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
819e33d69fSJan Kara 		return 0;
829e33d69fSJan Kara 	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
839e33d69fSJan Kara }
849e33d69fSJan Kara 
859e33d69fSJan Kara struct qtree_fmt_operations ocfs2_global_ops = {
869e33d69fSJan Kara 	.mem2disk_dqblk = ocfs2_global_mem2diskdqb,
879e33d69fSJan Kara 	.disk2mem_dqblk = ocfs2_global_disk2memdqb,
889e33d69fSJan Kara 	.is_id = ocfs2_global_is_id,
899e33d69fSJan Kara };
909e33d69fSJan Kara 
91684ef278SJoel Becker static int ocfs2_validate_quota_block(struct super_block *sb,
92684ef278SJoel Becker 				      struct buffer_head *bh)
93684ef278SJoel Becker {
94d6b32bbbSJoel Becker 	struct ocfs2_disk_dqtrailer *dqt =
95d6b32bbbSJoel Becker 		ocfs2_block_dqtrailer(sb->s_blocksize, bh->b_data);
96684ef278SJoel Becker 
97684ef278SJoel Becker 	mlog(0, "Validating quota block %llu\n",
98684ef278SJoel Becker 	     (unsigned long long)bh->b_blocknr);
99684ef278SJoel Becker 
100d6b32bbbSJoel Becker 	BUG_ON(!buffer_uptodate(bh));
101d6b32bbbSJoel Becker 
102d6b32bbbSJoel Becker 	/*
103d6b32bbbSJoel Becker 	 * If the ecc fails, we return the error but otherwise
104d6b32bbbSJoel Becker 	 * leave the filesystem running.  We know any error is
105d6b32bbbSJoel Becker 	 * local to this block.
106d6b32bbbSJoel Becker 	 */
107d6b32bbbSJoel Becker 	return ocfs2_validate_meta_ecc(sb, bh->b_data, &dqt->dq_check);
108684ef278SJoel Becker }
109684ef278SJoel Becker 
11085eb8b73SJoel Becker int ocfs2_read_quota_block(struct inode *inode, u64 v_block,
11185eb8b73SJoel Becker 			   struct buffer_head **bh)
1129e33d69fSJan Kara {
11385eb8b73SJoel Becker 	int rc = 0;
11485eb8b73SJoel Becker 	struct buffer_head *tmp = *bh;
1159e33d69fSJan Kara 
116684ef278SJoel Becker 	rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, 0,
117684ef278SJoel Becker 				    ocfs2_validate_quota_block);
11885eb8b73SJoel Becker 	if (rc)
11985eb8b73SJoel Becker 		mlog_errno(rc);
1209e33d69fSJan Kara 
12185eb8b73SJoel Becker 	/* If ocfs2_read_virt_blocks() got us a new bh, pass it up. */
12285eb8b73SJoel Becker 	if (!rc && !*bh)
12385eb8b73SJoel Becker 		*bh = tmp;
12485eb8b73SJoel Becker 
12585eb8b73SJoel Becker 	return rc;
1269e33d69fSJan Kara }
1279e33d69fSJan Kara 
12853a36046SJan Kara static int ocfs2_get_quota_block(struct inode *inode, int block,
12953a36046SJan Kara 				 struct buffer_head **bh)
1309e33d69fSJan Kara {
1319e33d69fSJan Kara 	u64 pblock, pcount;
13253a36046SJan Kara 	int err;
1339e33d69fSJan Kara 
1349e33d69fSJan Kara 	down_read(&OCFS2_I(inode)->ip_alloc_sem);
13553a36046SJan Kara 	err = ocfs2_extent_map_get_blocks(inode, block, &pblock, &pcount, NULL);
1369e33d69fSJan Kara 	up_read(&OCFS2_I(inode)->ip_alloc_sem);
13753a36046SJan Kara 	if (err) {
13853a36046SJan Kara 		mlog_errno(err);
13953a36046SJan Kara 		return err;
1409e33d69fSJan Kara 	}
14153a36046SJan Kara 	*bh = sb_getblk(inode->i_sb, pblock);
14253a36046SJan Kara 	if (!*bh) {
14353a36046SJan Kara 		err = -EIO;
14453a36046SJan Kara 		mlog_errno(err);
1459e33d69fSJan Kara 	}
14653a36046SJan Kara 	return err;;
1479e33d69fSJan Kara }
1489e33d69fSJan Kara 
1499e33d69fSJan Kara /* Read data from global quotafile - avoid pagecache and such because we cannot
1509e33d69fSJan Kara  * afford acquiring the locks... We use quota cluster lock to serialize
1519e33d69fSJan Kara  * operations. Caller is responsible for acquiring it. */
1529e33d69fSJan Kara ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data,
1539e33d69fSJan Kara 			 size_t len, loff_t off)
1549e33d69fSJan Kara {
1559e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
1569e33d69fSJan Kara 	struct inode *gqinode = oinfo->dqi_gqinode;
1579e33d69fSJan Kara 	loff_t i_size = i_size_read(gqinode);
1589e33d69fSJan Kara 	int offset = off & (sb->s_blocksize - 1);
1599e33d69fSJan Kara 	sector_t blk = off >> sb->s_blocksize_bits;
1609e33d69fSJan Kara 	int err = 0;
1619e33d69fSJan Kara 	struct buffer_head *bh;
1629e33d69fSJan Kara 	size_t toread, tocopy;
1639e33d69fSJan Kara 
1649e33d69fSJan Kara 	if (off > i_size)
1659e33d69fSJan Kara 		return 0;
1669e33d69fSJan Kara 	if (off + len > i_size)
1679e33d69fSJan Kara 		len = i_size - off;
1689e33d69fSJan Kara 	toread = len;
1699e33d69fSJan Kara 	while (toread > 0) {
170dad7d975SMark Fasheh 		tocopy = min_t(size_t, (sb->s_blocksize - offset), toread);
17185eb8b73SJoel Becker 		bh = NULL;
17285eb8b73SJoel Becker 		err = ocfs2_read_quota_block(gqinode, blk, &bh);
17385eb8b73SJoel Becker 		if (err) {
1749e33d69fSJan Kara 			mlog_errno(err);
1759e33d69fSJan Kara 			return err;
1769e33d69fSJan Kara 		}
1779e33d69fSJan Kara 		memcpy(data, bh->b_data + offset, tocopy);
1789e33d69fSJan Kara 		brelse(bh);
1799e33d69fSJan Kara 		offset = 0;
1809e33d69fSJan Kara 		toread -= tocopy;
1819e33d69fSJan Kara 		data += tocopy;
1829e33d69fSJan Kara 		blk++;
1839e33d69fSJan Kara 	}
1849e33d69fSJan Kara 	return len;
1859e33d69fSJan Kara }
1869e33d69fSJan Kara 
1879e33d69fSJan Kara /* Write to quotafile (we know the transaction is already started and has
1889e33d69fSJan Kara  * enough credits) */
1899e33d69fSJan Kara ssize_t ocfs2_quota_write(struct super_block *sb, int type,
1909e33d69fSJan Kara 			  const char *data, size_t len, loff_t off)
1919e33d69fSJan Kara {
1929e33d69fSJan Kara 	struct mem_dqinfo *info = sb_dqinfo(sb, type);
1939e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
1949e33d69fSJan Kara 	struct inode *gqinode = oinfo->dqi_gqinode;
1959e33d69fSJan Kara 	int offset = off & (sb->s_blocksize - 1);
1969e33d69fSJan Kara 	sector_t blk = off >> sb->s_blocksize_bits;
197af09e51bSJan Kara 	int err = 0, new = 0, ja_type;
19885eb8b73SJoel Becker 	struct buffer_head *bh = NULL;
1999e33d69fSJan Kara 	handle_t *handle = journal_current_handle();
2009e33d69fSJan Kara 
2019e33d69fSJan Kara 	if (!handle) {
2029e33d69fSJan Kara 		mlog(ML_ERROR, "Quota write (off=%llu, len=%llu) cancelled "
2039e33d69fSJan Kara 		     "because transaction was not started.\n",
2049e33d69fSJan Kara 		     (unsigned long long)off, (unsigned long long)len);
2059e33d69fSJan Kara 		return -EIO;
2069e33d69fSJan Kara 	}
2079e33d69fSJan Kara 	if (len > sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset) {
2089e33d69fSJan Kara 		WARN_ON(1);
2099e33d69fSJan Kara 		len = sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset;
2109e33d69fSJan Kara 	}
2119e33d69fSJan Kara 
2129e33d69fSJan Kara 	mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA);
2139e33d69fSJan Kara 	if (gqinode->i_size < off + len) {
2149e33d69fSJan Kara 		down_write(&OCFS2_I(gqinode)->ip_alloc_sem);
2159e33d69fSJan Kara 		err = ocfs2_extend_no_holes(gqinode, off + len, off);
2169e33d69fSJan Kara 		up_write(&OCFS2_I(gqinode)->ip_alloc_sem);
2179e33d69fSJan Kara 		if (err < 0)
2189e33d69fSJan Kara 			goto out;
2199e33d69fSJan Kara 		err = ocfs2_simple_size_update(gqinode,
2209e33d69fSJan Kara 					       oinfo->dqi_gqi_bh,
2219e33d69fSJan Kara 					       off + len);
2229e33d69fSJan Kara 		if (err < 0)
2239e33d69fSJan Kara 			goto out;
2249e33d69fSJan Kara 		new = 1;
2259e33d69fSJan Kara 	}
2269e33d69fSJan Kara 	/* Not rewriting whole block? */
2279e33d69fSJan Kara 	if ((offset || len < sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) &&
2289e33d69fSJan Kara 	    !new) {
22985eb8b73SJoel Becker 		err = ocfs2_read_quota_block(gqinode, blk, &bh);
230af09e51bSJan Kara 		ja_type = OCFS2_JOURNAL_ACCESS_WRITE;
231af09e51bSJan Kara 	} else {
23253a36046SJan Kara 		err = ocfs2_get_quota_block(gqinode, blk, &bh);
233af09e51bSJan Kara 		ja_type = OCFS2_JOURNAL_ACCESS_CREATE;
234af09e51bSJan Kara 	}
23585eb8b73SJoel Becker 	if (err) {
2369e33d69fSJan Kara 		mlog_errno(err);
2379e33d69fSJan Kara 		return err;
2389e33d69fSJan Kara 	}
2399e33d69fSJan Kara 	lock_buffer(bh);
2409e33d69fSJan Kara 	if (new)
2419e33d69fSJan Kara 		memset(bh->b_data, 0, sb->s_blocksize);
2429e33d69fSJan Kara 	memcpy(bh->b_data + offset, data, len);
2439e33d69fSJan Kara 	flush_dcache_page(bh->b_page);
244af09e51bSJan Kara 	set_buffer_uptodate(bh);
2459e33d69fSJan Kara 	unlock_buffer(bh);
2469e33d69fSJan Kara 	ocfs2_set_buffer_uptodate(gqinode, bh);
24713723d00SJoel Becker 	err = ocfs2_journal_access_dq(handle, gqinode, bh, ja_type);
248af09e51bSJan Kara 	if (err < 0) {
249af09e51bSJan Kara 		brelse(bh);
250af09e51bSJan Kara 		goto out;
251af09e51bSJan Kara 	}
2529e33d69fSJan Kara 	err = ocfs2_journal_dirty(handle, bh);
2539e33d69fSJan Kara 	brelse(bh);
2549e33d69fSJan Kara 	if (err < 0)
2559e33d69fSJan Kara 		goto out;
2569e33d69fSJan Kara out:
2579e33d69fSJan Kara 	if (err) {
2589e33d69fSJan Kara 		mutex_unlock(&gqinode->i_mutex);
2599e33d69fSJan Kara 		mlog_errno(err);
2609e33d69fSJan Kara 		return err;
2619e33d69fSJan Kara 	}
2629e33d69fSJan Kara 	gqinode->i_version++;
2639e33d69fSJan Kara 	ocfs2_mark_inode_dirty(handle, gqinode, oinfo->dqi_gqi_bh);
2649e33d69fSJan Kara 	mutex_unlock(&gqinode->i_mutex);
2659e33d69fSJan Kara 	return len;
2669e33d69fSJan Kara }
2679e33d69fSJan Kara 
2689e33d69fSJan Kara int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
2699e33d69fSJan Kara {
2709e33d69fSJan Kara 	int status;
2719e33d69fSJan Kara 	struct buffer_head *bh = NULL;
2729e33d69fSJan Kara 
2739e33d69fSJan Kara 	status = ocfs2_inode_lock(oinfo->dqi_gqinode, &bh, ex);
2749e33d69fSJan Kara 	if (status < 0)
2759e33d69fSJan Kara 		return status;
2769e33d69fSJan Kara 	spin_lock(&dq_data_lock);
2779e33d69fSJan Kara 	if (!oinfo->dqi_gqi_count++)
2789e33d69fSJan Kara 		oinfo->dqi_gqi_bh = bh;
2799e33d69fSJan Kara 	else
2809e33d69fSJan Kara 		WARN_ON(bh != oinfo->dqi_gqi_bh);
2819e33d69fSJan Kara 	spin_unlock(&dq_data_lock);
2829e33d69fSJan Kara 	return 0;
2839e33d69fSJan Kara }
2849e33d69fSJan Kara 
2859e33d69fSJan Kara void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
2869e33d69fSJan Kara {
2879e33d69fSJan Kara 	ocfs2_inode_unlock(oinfo->dqi_gqinode, ex);
2889e33d69fSJan Kara 	brelse(oinfo->dqi_gqi_bh);
2899e33d69fSJan Kara 	spin_lock(&dq_data_lock);
2909e33d69fSJan Kara 	if (!--oinfo->dqi_gqi_count)
2919e33d69fSJan Kara 		oinfo->dqi_gqi_bh = NULL;
2929e33d69fSJan Kara 	spin_unlock(&dq_data_lock);
2939e33d69fSJan Kara }
2949e33d69fSJan Kara 
2959e33d69fSJan Kara /* Read information header from global quota file */
2969e33d69fSJan Kara int ocfs2_global_read_info(struct super_block *sb, int type)
2979e33d69fSJan Kara {
2989e33d69fSJan Kara 	struct inode *gqinode = NULL;
2999e33d69fSJan Kara 	unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
3009e33d69fSJan Kara 					GROUP_QUOTA_SYSTEM_INODE };
3019e33d69fSJan Kara 	struct ocfs2_global_disk_dqinfo dinfo;
3029e33d69fSJan Kara 	struct mem_dqinfo *info = sb_dqinfo(sb, type);
3039e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
3049e33d69fSJan Kara 	int status;
3059e33d69fSJan Kara 
3069e33d69fSJan Kara 	mlog_entry_void();
3079e33d69fSJan Kara 
3089e33d69fSJan Kara 	/* Read global header */
3099e33d69fSJan Kara 	gqinode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type],
3109e33d69fSJan Kara 			OCFS2_INVALID_SLOT);
3119e33d69fSJan Kara 	if (!gqinode) {
3129e33d69fSJan Kara 		mlog(ML_ERROR, "failed to get global quota inode (type=%d)\n",
3139e33d69fSJan Kara 			type);
3149e33d69fSJan Kara 		status = -EINVAL;
3159e33d69fSJan Kara 		goto out_err;
3169e33d69fSJan Kara 	}
3179e33d69fSJan Kara 	oinfo->dqi_gi.dqi_sb = sb;
3189e33d69fSJan Kara 	oinfo->dqi_gi.dqi_type = type;
3199e33d69fSJan Kara 	ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo);
3209e33d69fSJan Kara 	oinfo->dqi_gi.dqi_entry_size = sizeof(struct ocfs2_global_disk_dqblk);
3219e33d69fSJan Kara 	oinfo->dqi_gi.dqi_ops = &ocfs2_global_ops;
3229e33d69fSJan Kara 	oinfo->dqi_gqi_bh = NULL;
3239e33d69fSJan Kara 	oinfo->dqi_gqi_count = 0;
3249e33d69fSJan Kara 	oinfo->dqi_gqinode = gqinode;
3259e33d69fSJan Kara 	status = ocfs2_lock_global_qf(oinfo, 0);
3269e33d69fSJan Kara 	if (status < 0) {
3279e33d69fSJan Kara 		mlog_errno(status);
3289e33d69fSJan Kara 		goto out_err;
3299e33d69fSJan Kara 	}
3309e33d69fSJan Kara 	status = sb->s_op->quota_read(sb, type, (char *)&dinfo,
3319e33d69fSJan Kara 				      sizeof(struct ocfs2_global_disk_dqinfo),
3329e33d69fSJan Kara 				      OCFS2_GLOBAL_INFO_OFF);
3339e33d69fSJan Kara 	ocfs2_unlock_global_qf(oinfo, 0);
3349e33d69fSJan Kara 	if (status != sizeof(struct ocfs2_global_disk_dqinfo)) {
3359e33d69fSJan Kara 		mlog(ML_ERROR, "Cannot read global quota info (%d).\n",
3369e33d69fSJan Kara 		     status);
3379e33d69fSJan Kara 		if (status >= 0)
3389e33d69fSJan Kara 			status = -EIO;
3399e33d69fSJan Kara 		mlog_errno(status);
3409e33d69fSJan Kara 		goto out_err;
3419e33d69fSJan Kara 	}
3429e33d69fSJan Kara 	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
3439e33d69fSJan Kara 	info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
3449e33d69fSJan Kara 	oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms);
345171bf93cSMark Fasheh 	oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms);
3469e33d69fSJan Kara 	oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
3479e33d69fSJan Kara 	oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
3489e33d69fSJan Kara 	oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
3499e33d69fSJan Kara 	oinfo->dqi_gi.dqi_blocksize_bits = sb->s_blocksize_bits;
3509e33d69fSJan Kara 	oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize -
3519e33d69fSJan Kara 						OCFS2_QBLK_RESERVED_SPACE;
3529e33d69fSJan Kara 	oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi);
353171bf93cSMark Fasheh 	INIT_DELAYED_WORK(&oinfo->dqi_sync_work, qsync_work_fn);
354171bf93cSMark Fasheh 	queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work,
355171bf93cSMark Fasheh 			   oinfo->dqi_syncjiff);
356171bf93cSMark Fasheh 
3579e33d69fSJan Kara out_err:
3589e33d69fSJan Kara 	mlog_exit(status);
3599e33d69fSJan Kara 	return status;
3609e33d69fSJan Kara }
3619e33d69fSJan Kara 
3629e33d69fSJan Kara /* Write information to global quota file. Expects exlusive lock on quota
3639e33d69fSJan Kara  * file inode and quota info */
3649e33d69fSJan Kara static int __ocfs2_global_write_info(struct super_block *sb, int type)
3659e33d69fSJan Kara {
3669e33d69fSJan Kara 	struct mem_dqinfo *info = sb_dqinfo(sb, type);
3679e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
3689e33d69fSJan Kara 	struct ocfs2_global_disk_dqinfo dinfo;
3699e33d69fSJan Kara 	ssize_t size;
3709e33d69fSJan Kara 
3719e33d69fSJan Kara 	spin_lock(&dq_data_lock);
3729e33d69fSJan Kara 	info->dqi_flags &= ~DQF_INFO_DIRTY;
3739e33d69fSJan Kara 	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
3749e33d69fSJan Kara 	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
3759e33d69fSJan Kara 	spin_unlock(&dq_data_lock);
3769e33d69fSJan Kara 	dinfo.dqi_syncms = cpu_to_le32(oinfo->dqi_syncms);
3779e33d69fSJan Kara 	dinfo.dqi_blocks = cpu_to_le32(oinfo->dqi_gi.dqi_blocks);
3789e33d69fSJan Kara 	dinfo.dqi_free_blk = cpu_to_le32(oinfo->dqi_gi.dqi_free_blk);
3799e33d69fSJan Kara 	dinfo.dqi_free_entry = cpu_to_le32(oinfo->dqi_gi.dqi_free_entry);
3809e33d69fSJan Kara 	size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
3819e33d69fSJan Kara 				     sizeof(struct ocfs2_global_disk_dqinfo),
3829e33d69fSJan Kara 				     OCFS2_GLOBAL_INFO_OFF);
3839e33d69fSJan Kara 	if (size != sizeof(struct ocfs2_global_disk_dqinfo)) {
3849e33d69fSJan Kara 		mlog(ML_ERROR, "Cannot write global quota info structure\n");
3859e33d69fSJan Kara 		if (size >= 0)
3869e33d69fSJan Kara 			size = -EIO;
3879e33d69fSJan Kara 		return size;
3889e33d69fSJan Kara 	}
3899e33d69fSJan Kara 	return 0;
3909e33d69fSJan Kara }
3919e33d69fSJan Kara 
3929e33d69fSJan Kara int ocfs2_global_write_info(struct super_block *sb, int type)
3939e33d69fSJan Kara {
3949e33d69fSJan Kara 	int err;
3959e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
3969e33d69fSJan Kara 
3979e33d69fSJan Kara 	err = ocfs2_qinfo_lock(info, 1);
3989e33d69fSJan Kara 	if (err < 0)
3999e33d69fSJan Kara 		return err;
4009e33d69fSJan Kara 	err = __ocfs2_global_write_info(sb, type);
4019e33d69fSJan Kara 	ocfs2_qinfo_unlock(info, 1);
4029e33d69fSJan Kara 	return err;
4039e33d69fSJan Kara }
4049e33d69fSJan Kara 
4059e33d69fSJan Kara /* Read in information from global quota file and acquire a reference to it.
4069e33d69fSJan Kara  * dquot_acquire() has already started the transaction and locked quota file */
4079e33d69fSJan Kara int ocfs2_global_read_dquot(struct dquot *dquot)
4089e33d69fSJan Kara {
4099e33d69fSJan Kara 	int err, err2, ex = 0;
4109e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *info =
4119e33d69fSJan Kara 			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
4129e33d69fSJan Kara 
4139e33d69fSJan Kara 	err = ocfs2_qinfo_lock(info, 0);
4149e33d69fSJan Kara 	if (err < 0)
4159e33d69fSJan Kara 		goto out;
4169e33d69fSJan Kara 	err = qtree_read_dquot(&info->dqi_gi, dquot);
4179e33d69fSJan Kara 	if (err < 0)
4189e33d69fSJan Kara 		goto out_qlock;
4199e33d69fSJan Kara 	OCFS2_DQUOT(dquot)->dq_use_count++;
4209e33d69fSJan Kara 	OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
4219e33d69fSJan Kara 	OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
4229e33d69fSJan Kara 	if (!dquot->dq_off) {	/* No real quota entry? */
4239e33d69fSJan Kara 		/* Upgrade to exclusive lock for allocation */
4249e33d69fSJan Kara 		err = ocfs2_qinfo_lock(info, 1);
4259e33d69fSJan Kara 		if (err < 0)
4269e33d69fSJan Kara 			goto out_qlock;
4279e33d69fSJan Kara 		ex = 1;
4289e33d69fSJan Kara 	}
4299e33d69fSJan Kara 	err = qtree_write_dquot(&info->dqi_gi, dquot);
4309e33d69fSJan Kara 	if (ex && info_dirty(sb_dqinfo(dquot->dq_sb, dquot->dq_type))) {
4319e33d69fSJan Kara 		err2 = __ocfs2_global_write_info(dquot->dq_sb, dquot->dq_type);
4329e33d69fSJan Kara 		if (!err)
4339e33d69fSJan Kara 			err = err2;
4349e33d69fSJan Kara 	}
4359e33d69fSJan Kara out_qlock:
4369e33d69fSJan Kara 	if (ex)
4379e33d69fSJan Kara 		ocfs2_qinfo_unlock(info, 1);
4389e33d69fSJan Kara 	ocfs2_qinfo_unlock(info, 0);
4399e33d69fSJan Kara out:
4409e33d69fSJan Kara 	if (err < 0)
4419e33d69fSJan Kara 		mlog_errno(err);
4429e33d69fSJan Kara 	return err;
4439e33d69fSJan Kara }
4449e33d69fSJan Kara 
4459e33d69fSJan Kara /* Sync local information about quota modifications with global quota file.
4469e33d69fSJan Kara  * Caller must have started the transaction and obtained exclusive lock for
4479e33d69fSJan Kara  * global quota file inode */
4489e33d69fSJan Kara int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
4499e33d69fSJan Kara {
4509e33d69fSJan Kara 	int err, err2;
4519e33d69fSJan Kara 	struct super_block *sb = dquot->dq_sb;
4529e33d69fSJan Kara 	int type = dquot->dq_type;
4539e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
4549e33d69fSJan Kara 	struct ocfs2_global_disk_dqblk dqblk;
4559e33d69fSJan Kara 	s64 spacechange, inodechange;
4569e33d69fSJan Kara 	time_t olditime, oldbtime;
4579e33d69fSJan Kara 
4589e33d69fSJan Kara 	err = sb->s_op->quota_read(sb, type, (char *)&dqblk,
4599e33d69fSJan Kara 				   sizeof(struct ocfs2_global_disk_dqblk),
4609e33d69fSJan Kara 				   dquot->dq_off);
4619e33d69fSJan Kara 	if (err != sizeof(struct ocfs2_global_disk_dqblk)) {
4629e33d69fSJan Kara 		if (err >= 0) {
4639e33d69fSJan Kara 			mlog(ML_ERROR, "Short read from global quota file "
4649e33d69fSJan Kara 				       "(%u read)\n", err);
4659e33d69fSJan Kara 			err = -EIO;
4669e33d69fSJan Kara 		}
4679e33d69fSJan Kara 		goto out;
4689e33d69fSJan Kara 	}
4699e33d69fSJan Kara 
4709e33d69fSJan Kara 	/* Update space and inode usage. Get also other information from
4719e33d69fSJan Kara 	 * global quota file so that we don't overwrite any changes there.
4729e33d69fSJan Kara 	 * We are */
4739e33d69fSJan Kara 	spin_lock(&dq_data_lock);
4749e33d69fSJan Kara 	spacechange = dquot->dq_dqb.dqb_curspace -
4759e33d69fSJan Kara 					OCFS2_DQUOT(dquot)->dq_origspace;
4769e33d69fSJan Kara 	inodechange = dquot->dq_dqb.dqb_curinodes -
4779e33d69fSJan Kara 					OCFS2_DQUOT(dquot)->dq_originodes;
4789e33d69fSJan Kara 	olditime = dquot->dq_dqb.dqb_itime;
4799e33d69fSJan Kara 	oldbtime = dquot->dq_dqb.dqb_btime;
4809e33d69fSJan Kara 	ocfs2_global_disk2memdqb(dquot, &dqblk);
4819a2f3866SJan Kara 	mlog(0, "Syncing global dquot %u space %lld+%lld, inodes %lld+%lld\n",
4829a2f3866SJan Kara 	     dquot->dq_id, dquot->dq_dqb.dqb_curspace, (long long)spacechange,
4839a2f3866SJan Kara 	     dquot->dq_dqb.dqb_curinodes, (long long)inodechange);
4849e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
4859e33d69fSJan Kara 		dquot->dq_dqb.dqb_curspace += spacechange;
4869e33d69fSJan Kara 	if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
4879e33d69fSJan Kara 		dquot->dq_dqb.dqb_curinodes += inodechange;
4889e33d69fSJan Kara 	/* Set properly space grace time... */
4899e33d69fSJan Kara 	if (dquot->dq_dqb.dqb_bsoftlimit &&
4909e33d69fSJan Kara 	    dquot->dq_dqb.dqb_curspace > dquot->dq_dqb.dqb_bsoftlimit) {
4919e33d69fSJan Kara 		if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) &&
4929e33d69fSJan Kara 		    oldbtime > 0) {
4939e33d69fSJan Kara 			if (dquot->dq_dqb.dqb_btime > 0)
4949e33d69fSJan Kara 				dquot->dq_dqb.dqb_btime =
4959e33d69fSJan Kara 					min(dquot->dq_dqb.dqb_btime, oldbtime);
4969e33d69fSJan Kara 			else
4979e33d69fSJan Kara 				dquot->dq_dqb.dqb_btime = oldbtime;
4989e33d69fSJan Kara 		}
4999e33d69fSJan Kara 	} else {
5009e33d69fSJan Kara 		dquot->dq_dqb.dqb_btime = 0;
5019e33d69fSJan Kara 		clear_bit(DQ_BLKS_B, &dquot->dq_flags);
5029e33d69fSJan Kara 	}
5039e33d69fSJan Kara 	/* Set properly inode grace time... */
5049e33d69fSJan Kara 	if (dquot->dq_dqb.dqb_isoftlimit &&
5059e33d69fSJan Kara 	    dquot->dq_dqb.dqb_curinodes > dquot->dq_dqb.dqb_isoftlimit) {
5069e33d69fSJan Kara 		if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) &&
5079e33d69fSJan Kara 		    olditime > 0) {
5089e33d69fSJan Kara 			if (dquot->dq_dqb.dqb_itime > 0)
5099e33d69fSJan Kara 				dquot->dq_dqb.dqb_itime =
5109e33d69fSJan Kara 					min(dquot->dq_dqb.dqb_itime, olditime);
5119e33d69fSJan Kara 			else
5129e33d69fSJan Kara 				dquot->dq_dqb.dqb_itime = olditime;
5139e33d69fSJan Kara 		}
5149e33d69fSJan Kara 	} else {
5159e33d69fSJan Kara 		dquot->dq_dqb.dqb_itime = 0;
5169e33d69fSJan Kara 		clear_bit(DQ_INODES_B, &dquot->dq_flags);
5179e33d69fSJan Kara 	}
5189e33d69fSJan Kara 	/* All information is properly updated, clear the flags */
5199e33d69fSJan Kara 	__clear_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
5209e33d69fSJan Kara 	__clear_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
5219e33d69fSJan Kara 	__clear_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
5229e33d69fSJan Kara 	__clear_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
5239e33d69fSJan Kara 	__clear_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
5249e33d69fSJan Kara 	__clear_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
5259e33d69fSJan Kara 	OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
5269e33d69fSJan Kara 	OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
5279e33d69fSJan Kara 	spin_unlock(&dq_data_lock);
5289e33d69fSJan Kara 	err = ocfs2_qinfo_lock(info, freeing);
5299e33d69fSJan Kara 	if (err < 0) {
5309e33d69fSJan Kara 		mlog(ML_ERROR, "Failed to lock quota info, loosing quota write"
5319e33d69fSJan Kara 			       " (type=%d, id=%u)\n", dquot->dq_type,
5329e33d69fSJan Kara 			       (unsigned)dquot->dq_id);
5339e33d69fSJan Kara 		goto out;
5349e33d69fSJan Kara 	}
5359e33d69fSJan Kara 	if (freeing)
5369e33d69fSJan Kara 		OCFS2_DQUOT(dquot)->dq_use_count--;
5379e33d69fSJan Kara 	err = qtree_write_dquot(&info->dqi_gi, dquot);
5389e33d69fSJan Kara 	if (err < 0)
5399e33d69fSJan Kara 		goto out_qlock;
5409e33d69fSJan Kara 	if (freeing && !OCFS2_DQUOT(dquot)->dq_use_count) {
5419e33d69fSJan Kara 		err = qtree_release_dquot(&info->dqi_gi, dquot);
5429e33d69fSJan Kara 		if (info_dirty(sb_dqinfo(sb, type))) {
5439e33d69fSJan Kara 			err2 = __ocfs2_global_write_info(sb, type);
5449e33d69fSJan Kara 			if (!err)
5459e33d69fSJan Kara 				err = err2;
5469e33d69fSJan Kara 		}
5479e33d69fSJan Kara 	}
5489e33d69fSJan Kara out_qlock:
5499e33d69fSJan Kara 	ocfs2_qinfo_unlock(info, freeing);
5509e33d69fSJan Kara out:
5519e33d69fSJan Kara 	if (err < 0)
5529e33d69fSJan Kara 		mlog_errno(err);
5539e33d69fSJan Kara 	return err;
5549e33d69fSJan Kara }
5559e33d69fSJan Kara 
5569e33d69fSJan Kara /*
557171bf93cSMark Fasheh  *  Functions for periodic syncing of dquots with global file
558171bf93cSMark Fasheh  */
559171bf93cSMark Fasheh static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
560171bf93cSMark Fasheh {
561171bf93cSMark Fasheh 	handle_t *handle;
562171bf93cSMark Fasheh 	struct super_block *sb = dquot->dq_sb;
563171bf93cSMark Fasheh 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
564171bf93cSMark Fasheh 	struct ocfs2_super *osb = OCFS2_SB(sb);
565171bf93cSMark Fasheh 	int status = 0;
566171bf93cSMark Fasheh 
567171bf93cSMark Fasheh 	mlog_entry("id=%u qtype=%u type=%lu device=%s\n", dquot->dq_id,
568171bf93cSMark Fasheh 		   dquot->dq_type, type, sb->s_id);
569171bf93cSMark Fasheh 	if (type != dquot->dq_type)
570171bf93cSMark Fasheh 		goto out;
571171bf93cSMark Fasheh 	status = ocfs2_lock_global_qf(oinfo, 1);
572171bf93cSMark Fasheh 	if (status < 0)
573171bf93cSMark Fasheh 		goto out;
574171bf93cSMark Fasheh 
575171bf93cSMark Fasheh 	handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS);
576171bf93cSMark Fasheh 	if (IS_ERR(handle)) {
577171bf93cSMark Fasheh 		status = PTR_ERR(handle);
578171bf93cSMark Fasheh 		mlog_errno(status);
579171bf93cSMark Fasheh 		goto out_ilock;
580171bf93cSMark Fasheh 	}
581171bf93cSMark Fasheh 	mutex_lock(&sb_dqopt(sb)->dqio_mutex);
582171bf93cSMark Fasheh 	status = ocfs2_sync_dquot(dquot);
583171bf93cSMark Fasheh 	mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
584171bf93cSMark Fasheh 	if (status < 0)
585171bf93cSMark Fasheh 		mlog_errno(status);
586171bf93cSMark Fasheh 	/* We have to write local structure as well... */
587171bf93cSMark Fasheh 	dquot_mark_dquot_dirty(dquot);
588171bf93cSMark Fasheh 	status = dquot_commit(dquot);
589171bf93cSMark Fasheh 	if (status < 0)
590171bf93cSMark Fasheh 		mlog_errno(status);
591171bf93cSMark Fasheh 	ocfs2_commit_trans(osb, handle);
592171bf93cSMark Fasheh out_ilock:
593171bf93cSMark Fasheh 	ocfs2_unlock_global_qf(oinfo, 1);
594171bf93cSMark Fasheh out:
595171bf93cSMark Fasheh 	mlog_exit(status);
596171bf93cSMark Fasheh 	return status;
597171bf93cSMark Fasheh }
598171bf93cSMark Fasheh 
599171bf93cSMark Fasheh static void qsync_work_fn(struct work_struct *work)
600171bf93cSMark Fasheh {
601171bf93cSMark Fasheh 	struct ocfs2_mem_dqinfo *oinfo = container_of(work,
602171bf93cSMark Fasheh 						      struct ocfs2_mem_dqinfo,
603171bf93cSMark Fasheh 						      dqi_sync_work.work);
604171bf93cSMark Fasheh 	struct super_block *sb = oinfo->dqi_gqinode->i_sb;
605171bf93cSMark Fasheh 
606171bf93cSMark Fasheh 	dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type);
607171bf93cSMark Fasheh 	queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work,
608171bf93cSMark Fasheh 			   oinfo->dqi_syncjiff);
609171bf93cSMark Fasheh }
610171bf93cSMark Fasheh 
611171bf93cSMark Fasheh /*
6129e33d69fSJan Kara  *  Wrappers for generic quota functions
6139e33d69fSJan Kara  */
6149e33d69fSJan Kara 
6159e33d69fSJan Kara static int ocfs2_write_dquot(struct dquot *dquot)
6169e33d69fSJan Kara {
6179e33d69fSJan Kara 	handle_t *handle;
6189e33d69fSJan Kara 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
6199e33d69fSJan Kara 	int status = 0;
6209e33d69fSJan Kara 
6219e33d69fSJan Kara 	mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
6229e33d69fSJan Kara 
6239e33d69fSJan Kara 	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
6249e33d69fSJan Kara 	if (IS_ERR(handle)) {
6259e33d69fSJan Kara 		status = PTR_ERR(handle);
6269e33d69fSJan Kara 		mlog_errno(status);
6279e33d69fSJan Kara 		goto out;
6289e33d69fSJan Kara 	}
6299e33d69fSJan Kara 	status = dquot_commit(dquot);
6309e33d69fSJan Kara 	ocfs2_commit_trans(osb, handle);
6319e33d69fSJan Kara out:
6329e33d69fSJan Kara 	mlog_exit(status);
6339e33d69fSJan Kara 	return status;
6349e33d69fSJan Kara }
6359e33d69fSJan Kara 
6369e33d69fSJan Kara int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
6379e33d69fSJan Kara {
6389e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo;
6399e33d69fSJan Kara 	int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
6409e33d69fSJan Kara 				    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
6419e33d69fSJan Kara 
6429e33d69fSJan Kara 	if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
6439e33d69fSJan Kara 		return 0;
6449e33d69fSJan Kara 
6459e33d69fSJan Kara 	oinfo = sb_dqinfo(sb, type)->dqi_priv;
6469e33d69fSJan Kara 	/* We modify tree, leaf block, global info, local chunk header,
6479e33d69fSJan Kara 	 * global and local inode */
6489e33d69fSJan Kara 	return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 +
6499e33d69fSJan Kara 	       2 * OCFS2_INODE_UPDATE_CREDITS;
6509e33d69fSJan Kara }
6519e33d69fSJan Kara 
6529e33d69fSJan Kara static int ocfs2_release_dquot(struct dquot *dquot)
6539e33d69fSJan Kara {
6549e33d69fSJan Kara 	handle_t *handle;
6559e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo =
6569e33d69fSJan Kara 			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
6579e33d69fSJan Kara 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
6589e33d69fSJan Kara 	int status = 0;
6599e33d69fSJan Kara 
6609e33d69fSJan Kara 	mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
6619e33d69fSJan Kara 
6629e33d69fSJan Kara 	status = ocfs2_lock_global_qf(oinfo, 1);
6639e33d69fSJan Kara 	if (status < 0)
6649e33d69fSJan Kara 		goto out;
6659e33d69fSJan Kara 	handle = ocfs2_start_trans(osb,
6669e33d69fSJan Kara 		ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
6679e33d69fSJan Kara 	if (IS_ERR(handle)) {
6689e33d69fSJan Kara 		status = PTR_ERR(handle);
6699e33d69fSJan Kara 		mlog_errno(status);
6709e33d69fSJan Kara 		goto out_ilock;
6719e33d69fSJan Kara 	}
6729e33d69fSJan Kara 	status = dquot_release(dquot);
6739e33d69fSJan Kara 	ocfs2_commit_trans(osb, handle);
6749e33d69fSJan Kara out_ilock:
6759e33d69fSJan Kara 	ocfs2_unlock_global_qf(oinfo, 1);
6769e33d69fSJan Kara out:
6779e33d69fSJan Kara 	mlog_exit(status);
6789e33d69fSJan Kara 	return status;
6799e33d69fSJan Kara }
6809e33d69fSJan Kara 
6819e33d69fSJan Kara int ocfs2_calc_qinit_credits(struct super_block *sb, int type)
6829e33d69fSJan Kara {
6839e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo;
6849e33d69fSJan Kara 	int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
6859e33d69fSJan Kara 				    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
6869e33d69fSJan Kara 	struct ocfs2_dinode *lfe, *gfe;
6879e33d69fSJan Kara 
6889e33d69fSJan Kara 	if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
6899e33d69fSJan Kara 		return 0;
6909e33d69fSJan Kara 
6919e33d69fSJan Kara 	oinfo = sb_dqinfo(sb, type)->dqi_priv;
6929e33d69fSJan Kara 	gfe = (struct ocfs2_dinode *)oinfo->dqi_gqi_bh->b_data;
6939e33d69fSJan Kara 	lfe = (struct ocfs2_dinode *)oinfo->dqi_lqi_bh->b_data;
6949e33d69fSJan Kara 	/* We can extend local file + global file. In local file we
6959e33d69fSJan Kara 	 * can modify info, chunk header block and dquot block. In
6969e33d69fSJan Kara 	 * global file we can modify info, tree and leaf block */
6979e33d69fSJan Kara 	return ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) +
6989e33d69fSJan Kara 	       ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) +
6999e33d69fSJan Kara 	       3 + oinfo->dqi_gi.dqi_qtree_depth + 2;
7009e33d69fSJan Kara }
7019e33d69fSJan Kara 
7029e33d69fSJan Kara static int ocfs2_acquire_dquot(struct dquot *dquot)
7039e33d69fSJan Kara {
7049e33d69fSJan Kara 	handle_t *handle;
7059e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo =
7069e33d69fSJan Kara 			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
7079e33d69fSJan Kara 	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
7089e33d69fSJan Kara 	int status = 0;
7099e33d69fSJan Kara 
7109e33d69fSJan Kara 	mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
7119e33d69fSJan Kara 	/* We need an exclusive lock, because we're going to update use count
7129e33d69fSJan Kara 	 * and instantiate possibly new dquot structure */
7139e33d69fSJan Kara 	status = ocfs2_lock_global_qf(oinfo, 1);
7149e33d69fSJan Kara 	if (status < 0)
7159e33d69fSJan Kara 		goto out;
7169e33d69fSJan Kara 	handle = ocfs2_start_trans(osb,
7179e33d69fSJan Kara 		ocfs2_calc_qinit_credits(dquot->dq_sb, dquot->dq_type));
7189e33d69fSJan Kara 	if (IS_ERR(handle)) {
7199e33d69fSJan Kara 		status = PTR_ERR(handle);
7209e33d69fSJan Kara 		mlog_errno(status);
7219e33d69fSJan Kara 		goto out_ilock;
7229e33d69fSJan Kara 	}
7239e33d69fSJan Kara 	status = dquot_acquire(dquot);
7249e33d69fSJan Kara 	ocfs2_commit_trans(osb, handle);
7259e33d69fSJan Kara out_ilock:
7269e33d69fSJan Kara 	ocfs2_unlock_global_qf(oinfo, 1);
7279e33d69fSJan Kara out:
7289e33d69fSJan Kara 	mlog_exit(status);
7299e33d69fSJan Kara 	return status;
7309e33d69fSJan Kara }
7319e33d69fSJan Kara 
7329e33d69fSJan Kara static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
7339e33d69fSJan Kara {
7349e33d69fSJan Kara 	unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) |
7359e33d69fSJan Kara 			     (1 << (DQ_LASTSET_B + QIF_BLIMITS_B)) |
7369e33d69fSJan Kara 			     (1 << (DQ_LASTSET_B + QIF_INODES_B)) |
7379e33d69fSJan Kara 			     (1 << (DQ_LASTSET_B + QIF_SPACE_B)) |
7389e33d69fSJan Kara 			     (1 << (DQ_LASTSET_B + QIF_BTIME_B)) |
7399e33d69fSJan Kara 			     (1 << (DQ_LASTSET_B + QIF_ITIME_B));
7409e33d69fSJan Kara 	int sync = 0;
7419e33d69fSJan Kara 	int status;
7429e33d69fSJan Kara 	struct super_block *sb = dquot->dq_sb;
7439e33d69fSJan Kara 	int type = dquot->dq_type;
7449e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
7459e33d69fSJan Kara 	handle_t *handle;
7469e33d69fSJan Kara 	struct ocfs2_super *osb = OCFS2_SB(sb);
7479e33d69fSJan Kara 
7489e33d69fSJan Kara 	mlog_entry("id=%u, type=%d", dquot->dq_id, type);
7499e33d69fSJan Kara 	dquot_mark_dquot_dirty(dquot);
7509e33d69fSJan Kara 
7519e33d69fSJan Kara 	/* In case user set some limits, sync dquot immediately to global
7529e33d69fSJan Kara 	 * quota file so that information propagates quicker */
7539e33d69fSJan Kara 	spin_lock(&dq_data_lock);
7549e33d69fSJan Kara 	if (dquot->dq_flags & mask)
7559e33d69fSJan Kara 		sync = 1;
7569e33d69fSJan Kara 	spin_unlock(&dq_data_lock);
7579e33d69fSJan Kara 	if (!sync) {
7589e33d69fSJan Kara 		status = ocfs2_write_dquot(dquot);
7599e33d69fSJan Kara 		goto out;
7609e33d69fSJan Kara 	}
7619e33d69fSJan Kara 	status = ocfs2_lock_global_qf(oinfo, 1);
7629e33d69fSJan Kara 	if (status < 0)
7639e33d69fSJan Kara 		goto out;
7649e33d69fSJan Kara 	handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS);
7659e33d69fSJan Kara 	if (IS_ERR(handle)) {
7669e33d69fSJan Kara 		status = PTR_ERR(handle);
7679e33d69fSJan Kara 		mlog_errno(status);
7689e33d69fSJan Kara 		goto out_ilock;
7699e33d69fSJan Kara 	}
7709e33d69fSJan Kara 	status = ocfs2_sync_dquot(dquot);
7719e33d69fSJan Kara 	if (status < 0) {
7729e33d69fSJan Kara 		mlog_errno(status);
7739e33d69fSJan Kara 		goto out_trans;
7749e33d69fSJan Kara 	}
7759e33d69fSJan Kara 	/* Now write updated local dquot structure */
7769e33d69fSJan Kara 	status = dquot_commit(dquot);
7779e33d69fSJan Kara out_trans:
7789e33d69fSJan Kara 	ocfs2_commit_trans(osb, handle);
7799e33d69fSJan Kara out_ilock:
7809e33d69fSJan Kara 	ocfs2_unlock_global_qf(oinfo, 1);
7819e33d69fSJan Kara out:
7829e33d69fSJan Kara 	mlog_exit(status);
7839e33d69fSJan Kara 	return status;
7849e33d69fSJan Kara }
7859e33d69fSJan Kara 
7869e33d69fSJan Kara /* This should happen only after set_dqinfo(). */
7879e33d69fSJan Kara static int ocfs2_write_info(struct super_block *sb, int type)
7889e33d69fSJan Kara {
7899e33d69fSJan Kara 	handle_t *handle;
7909e33d69fSJan Kara 	int status = 0;
7919e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
7929e33d69fSJan Kara 
7939e33d69fSJan Kara 	mlog_entry_void();
7949e33d69fSJan Kara 
7959e33d69fSJan Kara 	status = ocfs2_lock_global_qf(oinfo, 1);
7969e33d69fSJan Kara 	if (status < 0)
7979e33d69fSJan Kara 		goto out;
7989e33d69fSJan Kara 	handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QINFO_WRITE_CREDITS);
7999e33d69fSJan Kara 	if (IS_ERR(handle)) {
8009e33d69fSJan Kara 		status = PTR_ERR(handle);
8019e33d69fSJan Kara 		mlog_errno(status);
8029e33d69fSJan Kara 		goto out_ilock;
8039e33d69fSJan Kara 	}
8049e33d69fSJan Kara 	status = dquot_commit_info(sb, type);
8059e33d69fSJan Kara 	ocfs2_commit_trans(OCFS2_SB(sb), handle);
8069e33d69fSJan Kara out_ilock:
8079e33d69fSJan Kara 	ocfs2_unlock_global_qf(oinfo, 1);
8089e33d69fSJan Kara out:
8099e33d69fSJan Kara 	mlog_exit(status);
8109e33d69fSJan Kara 	return status;
8119e33d69fSJan Kara }
8129e33d69fSJan Kara 
8139e33d69fSJan Kara /* This is difficult. We have to lock quota inode and start transaction
8149e33d69fSJan Kara  * in this function but we don't want to take the penalty of exlusive
8159e33d69fSJan Kara  * quota file lock when we are just going to use cached structures. So
8169e33d69fSJan Kara  * we just take read lock check whether we have dquot cached and if so,
8179e33d69fSJan Kara  * we don't have to take the write lock... */
8189e33d69fSJan Kara static int ocfs2_dquot_initialize(struct inode *inode, int type)
8199e33d69fSJan Kara {
8209e33d69fSJan Kara 	handle_t *handle = NULL;
8219e33d69fSJan Kara 	int status = 0;
8229e33d69fSJan Kara 	struct super_block *sb = inode->i_sb;
8239e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo;
8249e33d69fSJan Kara 	int exclusive = 0;
8259e33d69fSJan Kara 	int cnt;
8269e33d69fSJan Kara 	qid_t id;
8279e33d69fSJan Kara 
8289e33d69fSJan Kara 	mlog_entry_void();
8299e33d69fSJan Kara 
8309e33d69fSJan Kara 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
8319e33d69fSJan Kara 		if (type != -1 && cnt != type)
8329e33d69fSJan Kara 			continue;
8339e33d69fSJan Kara 		if (!sb_has_quota_active(sb, cnt))
8349e33d69fSJan Kara 			continue;
8359e33d69fSJan Kara 		oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
8369e33d69fSJan Kara 		status = ocfs2_lock_global_qf(oinfo, 0);
8379e33d69fSJan Kara 		if (status < 0)
8389e33d69fSJan Kara 			goto out;
8399e33d69fSJan Kara 		/* This is just a performance optimization not a reliable test.
8409e33d69fSJan Kara 		 * Since we hold an inode lock, noone can actually release
8419e33d69fSJan Kara 		 * the structure until we are finished with initialization. */
8429e33d69fSJan Kara 		if (inode->i_dquot[cnt] != NODQUOT) {
8439e33d69fSJan Kara 			ocfs2_unlock_global_qf(oinfo, 0);
8449e33d69fSJan Kara 			continue;
8459e33d69fSJan Kara 		}
8469e33d69fSJan Kara 		/* When we have inode lock, we know that no dquot_release() can
8479e33d69fSJan Kara 		 * run and thus we can safely check whether we need to
8489e33d69fSJan Kara 		 * read+modify global file to get quota information or whether
8499e33d69fSJan Kara 		 * our node already has it. */
8509e33d69fSJan Kara 		if (cnt == USRQUOTA)
8519e33d69fSJan Kara 			id = inode->i_uid;
8529e33d69fSJan Kara 		else if (cnt == GRPQUOTA)
8539e33d69fSJan Kara 			id = inode->i_gid;
8549e33d69fSJan Kara 		else
8559e33d69fSJan Kara 			BUG();
8569e33d69fSJan Kara 		/* Obtain exclusion from quota off... */
8579e33d69fSJan Kara 		down_write(&sb_dqopt(sb)->dqptr_sem);
8589e33d69fSJan Kara 		exclusive = !dquot_is_cached(sb, id, cnt);
8599e33d69fSJan Kara 		up_write(&sb_dqopt(sb)->dqptr_sem);
8609e33d69fSJan Kara 		if (exclusive) {
8619e33d69fSJan Kara 			status = ocfs2_lock_global_qf(oinfo, 1);
8629e33d69fSJan Kara 			if (status < 0) {
8639e33d69fSJan Kara 				exclusive = 0;
8649e33d69fSJan Kara 				mlog_errno(status);
8659e33d69fSJan Kara 				goto out_ilock;
8669e33d69fSJan Kara 			}
8679e33d69fSJan Kara 			handle = ocfs2_start_trans(OCFS2_SB(sb),
8689e33d69fSJan Kara 					ocfs2_calc_qinit_credits(sb, cnt));
8699e33d69fSJan Kara 			if (IS_ERR(handle)) {
8709e33d69fSJan Kara 				status = PTR_ERR(handle);
8719e33d69fSJan Kara 				mlog_errno(status);
8729e33d69fSJan Kara 				goto out_ilock;
8739e33d69fSJan Kara 			}
8749e33d69fSJan Kara 		}
8759e33d69fSJan Kara 		dquot_initialize(inode, cnt);
8769e33d69fSJan Kara 		if (exclusive) {
8779e33d69fSJan Kara 			ocfs2_commit_trans(OCFS2_SB(sb), handle);
8789e33d69fSJan Kara 			ocfs2_unlock_global_qf(oinfo, 1);
8799e33d69fSJan Kara 		}
8809e33d69fSJan Kara 		ocfs2_unlock_global_qf(oinfo, 0);
8819e33d69fSJan Kara 	}
8829e33d69fSJan Kara 	mlog_exit(0);
8839e33d69fSJan Kara 	return 0;
8849e33d69fSJan Kara out_ilock:
8859e33d69fSJan Kara 	if (exclusive)
8869e33d69fSJan Kara 		ocfs2_unlock_global_qf(oinfo, 1);
8879e33d69fSJan Kara 	ocfs2_unlock_global_qf(oinfo, 0);
8889e33d69fSJan Kara out:
8899e33d69fSJan Kara 	mlog_exit(status);
8909e33d69fSJan Kara 	return status;
8919e33d69fSJan Kara }
8929e33d69fSJan Kara 
8939e33d69fSJan Kara static int ocfs2_dquot_drop_slow(struct inode *inode)
8949e33d69fSJan Kara {
89557a09a7bSJan Kara 	int status = 0;
8969e33d69fSJan Kara 	int cnt;
8979e33d69fSJan Kara 	int got_lock[MAXQUOTAS] = {0, 0};
8989e33d69fSJan Kara 	handle_t *handle;
8999e33d69fSJan Kara 	struct super_block *sb = inode->i_sb;
9009e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo;
9019e33d69fSJan Kara 
9029e33d69fSJan Kara 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
9039e33d69fSJan Kara 		if (!sb_has_quota_active(sb, cnt))
9049e33d69fSJan Kara 			continue;
9059e33d69fSJan Kara 		oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
9069e33d69fSJan Kara 		status = ocfs2_lock_global_qf(oinfo, 1);
9079e33d69fSJan Kara 		if (status < 0)
9089e33d69fSJan Kara 			goto out;
9099e33d69fSJan Kara 		got_lock[cnt] = 1;
9109e33d69fSJan Kara 	}
9119e33d69fSJan Kara 	handle = ocfs2_start_trans(OCFS2_SB(sb),
9129e33d69fSJan Kara 			ocfs2_calc_qinit_credits(sb, USRQUOTA) +
9139e33d69fSJan Kara 			ocfs2_calc_qinit_credits(sb, GRPQUOTA));
9149e33d69fSJan Kara 	if (IS_ERR(handle)) {
9159e33d69fSJan Kara 		status = PTR_ERR(handle);
9169e33d69fSJan Kara 		mlog_errno(status);
9179e33d69fSJan Kara 		goto out;
9189e33d69fSJan Kara 	}
9199e33d69fSJan Kara 	dquot_drop(inode);
9209e33d69fSJan Kara 	ocfs2_commit_trans(OCFS2_SB(sb), handle);
9219e33d69fSJan Kara out:
9229e33d69fSJan Kara 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
9239e33d69fSJan Kara 		if (got_lock[cnt]) {
9249e33d69fSJan Kara 			oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
9259e33d69fSJan Kara 			ocfs2_unlock_global_qf(oinfo, 1);
9269e33d69fSJan Kara 		}
9279e33d69fSJan Kara 	return status;
9289e33d69fSJan Kara }
9299e33d69fSJan Kara 
9309e33d69fSJan Kara /* See the comment before ocfs2_dquot_initialize. */
9319e33d69fSJan Kara static int ocfs2_dquot_drop(struct inode *inode)
9329e33d69fSJan Kara {
9339e33d69fSJan Kara 	int status = 0;
9349e33d69fSJan Kara 	struct super_block *sb = inode->i_sb;
9359e33d69fSJan Kara 	struct ocfs2_mem_dqinfo *oinfo;
9369e33d69fSJan Kara 	int exclusive = 0;
9379e33d69fSJan Kara 	int cnt;
9389e33d69fSJan Kara 	int got_lock[MAXQUOTAS] = {0, 0};
9399e33d69fSJan Kara 
9409e33d69fSJan Kara 	mlog_entry_void();
9419e33d69fSJan Kara 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
9429e33d69fSJan Kara 		if (!sb_has_quota_active(sb, cnt))
9439e33d69fSJan Kara 			continue;
9449e33d69fSJan Kara 		oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
9459e33d69fSJan Kara 		status = ocfs2_lock_global_qf(oinfo, 0);
9469e33d69fSJan Kara 		if (status < 0)
9479e33d69fSJan Kara 			goto out;
9489e33d69fSJan Kara 		got_lock[cnt] = 1;
9499e33d69fSJan Kara 	}
9509e33d69fSJan Kara 	/* Lock against anyone releasing references so that when when we check
9519e33d69fSJan Kara 	 * we know we are not going to be last ones to release dquot */
9529e33d69fSJan Kara 	down_write(&sb_dqopt(sb)->dqptr_sem);
9539e33d69fSJan Kara 	/* Urgh, this is a terrible hack :( */
9549e33d69fSJan Kara 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
9559e33d69fSJan Kara 		if (inode->i_dquot[cnt] != NODQUOT &&
9569e33d69fSJan Kara 		    atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) {
9579e33d69fSJan Kara 			exclusive = 1;
9589e33d69fSJan Kara 			break;
9599e33d69fSJan Kara 		}
9609e33d69fSJan Kara 	}
9619e33d69fSJan Kara 	if (!exclusive)
9629e33d69fSJan Kara 		dquot_drop_locked(inode);
9639e33d69fSJan Kara 	up_write(&sb_dqopt(sb)->dqptr_sem);
9649e33d69fSJan Kara out:
9659e33d69fSJan Kara 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
9669e33d69fSJan Kara 		if (got_lock[cnt]) {
9679e33d69fSJan Kara 			oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
9689e33d69fSJan Kara 			ocfs2_unlock_global_qf(oinfo, 0);
9699e33d69fSJan Kara 		}
9709e33d69fSJan Kara 	/* In case we bailed out because we had to do expensive locking
9719e33d69fSJan Kara 	 * do it now... */
9729e33d69fSJan Kara 	if (exclusive)
9739e33d69fSJan Kara 		status = ocfs2_dquot_drop_slow(inode);
9749e33d69fSJan Kara 	mlog_exit(status);
9759e33d69fSJan Kara 	return status;
9769e33d69fSJan Kara }
9779e33d69fSJan Kara 
9789e33d69fSJan Kara static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type)
9799e33d69fSJan Kara {
9809e33d69fSJan Kara 	struct ocfs2_dquot *dquot =
9819e33d69fSJan Kara 				kmem_cache_zalloc(ocfs2_dquot_cachep, GFP_NOFS);
9829e33d69fSJan Kara 
9839e33d69fSJan Kara 	if (!dquot)
9849e33d69fSJan Kara 		return NULL;
9859e33d69fSJan Kara 	return &dquot->dq_dquot;
9869e33d69fSJan Kara }
9879e33d69fSJan Kara 
9889e33d69fSJan Kara static void ocfs2_destroy_dquot(struct dquot *dquot)
9899e33d69fSJan Kara {
9909e33d69fSJan Kara 	kmem_cache_free(ocfs2_dquot_cachep, dquot);
9919e33d69fSJan Kara }
9929e33d69fSJan Kara 
9939e33d69fSJan Kara struct dquot_operations ocfs2_quota_operations = {
9949e33d69fSJan Kara 	.initialize	= ocfs2_dquot_initialize,
9959e33d69fSJan Kara 	.drop		= ocfs2_dquot_drop,
9969e33d69fSJan Kara 	.alloc_space	= dquot_alloc_space,
9979e33d69fSJan Kara 	.alloc_inode	= dquot_alloc_inode,
9989e33d69fSJan Kara 	.free_space	= dquot_free_space,
9999e33d69fSJan Kara 	.free_inode	= dquot_free_inode,
10009e33d69fSJan Kara 	.transfer	= dquot_transfer,
10019e33d69fSJan Kara 	.write_dquot	= ocfs2_write_dquot,
10029e33d69fSJan Kara 	.acquire_dquot	= ocfs2_acquire_dquot,
10039e33d69fSJan Kara 	.release_dquot	= ocfs2_release_dquot,
10049e33d69fSJan Kara 	.mark_dirty	= ocfs2_mark_dquot_dirty,
10059e33d69fSJan Kara 	.write_info	= ocfs2_write_info,
10069e33d69fSJan Kara 	.alloc_dquot	= ocfs2_alloc_dquot,
10079e33d69fSJan Kara 	.destroy_dquot	= ocfs2_destroy_dquot,
10089e33d69fSJan Kara };
1009171bf93cSMark Fasheh 
1010171bf93cSMark Fasheh int ocfs2_quota_setup(void)
1011171bf93cSMark Fasheh {
1012171bf93cSMark Fasheh 	ocfs2_quota_wq = create_workqueue("o2quot");
1013171bf93cSMark Fasheh 	if (!ocfs2_quota_wq)
1014171bf93cSMark Fasheh 		return -ENOMEM;
1015171bf93cSMark Fasheh 	return 0;
1016171bf93cSMark Fasheh }
1017171bf93cSMark Fasheh 
1018171bf93cSMark Fasheh void ocfs2_quota_shutdown(void)
1019171bf93cSMark Fasheh {
1020171bf93cSMark Fasheh 	if (ocfs2_quota_wq) {
1021171bf93cSMark Fasheh 		flush_workqueue(ocfs2_quota_wq);
1022171bf93cSMark Fasheh 		destroy_workqueue(ocfs2_quota_wq);
1023171bf93cSMark Fasheh 		ocfs2_quota_wq = NULL;
1024171bf93cSMark Fasheh 	}
1025171bf93cSMark Fasheh }
1026