/*
* Implementation of operations over global quota file
*/
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/quota.h>
#include <linux/quotaops.h>
#include <linux/dqblk_qtree.h>
#include <linux/jiffies.h>
#include <linux/writeback.h>
#include <linux/workqueue.h>
#define MLOG_MASK_PREFIX ML_QUOTA
#include <cluster/masklog.h>
#include "ocfs2_fs.h"
#include "ocfs2.h"
#include "alloc.h"
#include "inode.h"
#include "journal.h"
#include "file.h"
#include "sysfile.h"
#include "dlmglue.h"
#include "uptodate.h"
#include "quota.h"
static struct workqueue_struct *ocfs2_quota_wq = NULL;
static void qsync_work_fn(struct work_struct *work);
static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
{
struct ocfs2_global_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
/* Update from disk only entries not set by the admin */
if (!test_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags)) {
m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
}
if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
if (!test_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags)) {
m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit);
m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit);
}
if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags))
m->dqb_btime = le64_to_cpu(d->dqb_btime);
if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags))
m->dqb_itime = le64_to_cpu(d->dqb_itime);
OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count);
}
static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
{
struct ocfs2_global_disk_dqblk *d = dp;
struct mem_dqblk *m = &dquot->dq_dqb;
d->dqb_id = cpu_to_le32(dquot->dq_id);
d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
d->dqb_btime = cpu_to_le64(m->dqb_btime);
d->dqb_itime = cpu_to_le64(m->dqb_itime);
}
static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
{
struct ocfs2_global_disk_dqblk *d = dp;
struct ocfs2_mem_dqinfo *oinfo =
sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
if (qtree_entry_unused(&oinfo->dqi_gi, dp))
return 0;
return le32_to_cpu(d->dqb_id) == dquot->dq_id;
}
struct qtree_fmt_operations ocfs2_global_ops = {
.mem2disk_dqblk = ocfs2_global_mem2diskdqb,
.disk2mem_dqblk = ocfs2_global_disk2memdqb,
.is_id = ocfs2_global_is_id,
};
struct buffer_head *ocfs2_read_quota_block(struct inode *inode,
int block, int *err)
{
struct buffer_head *tmp = NULL;
*err = ocfs2_read_virt_blocks(inode, block, 1, &tmp, 0, NULL);
if (*err)
mlog_errno(*err);
return tmp;
}
static struct buffer_head *ocfs2_get_quota_block(struct inode *inode,
int block, int *err)
{
u64 pblock, pcount;
struct buffer_head *bh;
down_read(&OCFS2_I(inode)->ip_alloc_sem);
*err = ocfs2_extent_map_get_blocks(inode, block