+static int v2_write_dqheader(struct file *f, int type)
+{
+ static const __u32 quota_magics[] = V2_INITQMAGICS;
+ static const __u32 quota_versions[] = V2_INITQVERSIONS;
+ struct v2_disk_dqheader dqhead;
+ loff_t offset = 0;
+
+ CLASSERT(ARRAY_SIZE(quota_magics) == ARRAY_SIZE(quota_versions));
+ LASSERT(0 <= type && type < ARRAY_SIZE(quota_magics));
+
+ dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
+ dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
+
+ return cfs_user_write(f, (char *)&dqhead, sizeof(dqhead), &offset);
+}
+
+/* write dqinfo struct in a new quota file */
+static int v2_write_dqinfo(struct file *f, int type, struct if_dqinfo *info)
+{
+ struct v2_disk_dqinfo dqinfo;
+ __u32 blocks = V2_DQTREEOFF + 1;
+ loff_t offset = V2_DQINFOOFF;
+
+ if (info) {
+ dqinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
+ dqinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+ dqinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK &
+ ~DQF_INFO_DIRTY);
+ } else {
+ dqinfo.dqi_bgrace = cpu_to_le32(MAX_DQ_TIME);
+ dqinfo.dqi_igrace = cpu_to_le32(MAX_IQ_TIME);
+ dqinfo.dqi_flags = 0;
+ }
+
+ dqinfo.dqi_blocks = cpu_to_le32(blocks);
+ dqinfo.dqi_free_blk = 0;
+ dqinfo.dqi_free_entry = 0;
+
+ return cfs_user_write(f, (char *)&dqinfo, sizeof(dqinfo), &offset);
+}
+
+static int create_new_quota_files(struct qchk_ctxt *qctxt,
+ struct obd_quotactl *oqc)
+{
+ int i, rc = 0;
+ ENTRY;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ struct if_dqinfo *info = qctxt->qckt_first_check[i]?
+ NULL : &qctxt->qckt_dqinfo[i];
+ struct file *file;
+
+ if (!Q_TYPESET(oqc, i))
+ continue;
+
+ file = filp_open(op_quotafile[i], O_RDWR | O_CREAT | O_TRUNC,
+ 0644);
+ if (IS_ERR(file)) {
+ rc = PTR_ERR(file);
+ CERROR("can't create %s file: rc = %d\n",
+ op_quotafile[i], rc);
+ GOTO(out, rc);
+ }
+
+ if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
+ CERROR("file %s is not regular", op_quotafile[i]);
+ filp_close(file, 0);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ rc = v2_write_dqheader(file, i);
+ if (rc) {
+ filp_close(file, 0);
+ GOTO(out, rc);
+ }
+
+ rc = v2_write_dqinfo(file, i, info);
+ filp_close(file, 0);
+ if (rc)
+ GOTO(out, rc);
+ }
+
+out:
+ RETURN(rc);
+}
+
+
+static int commit_chkquot(struct super_block *sb, struct qchk_ctxt *qctxt,
+ struct chk_dqblk *cdqb)
+{
+ struct obd_quotactl *oqc;
+ long now;
+ int rc;
+ ENTRY;
+
+ OBD_ALLOC_PTR(oqc);
+ if (!oqc)
+ RETURN(-ENOMEM);
+
+ now = cfs_time_current_sec();
+
+ if (cdqb->dqb_bsoftlimit &&
+ toqb(cdqb->dqb_curspace) >= cdqb->dqb_bsoftlimit &&
+ !cdqb->dqb_btime)
+ cdqb->dqb_btime =
+ now + qctxt->qckt_dqinfo[cdqb->dqb_type].dqi_bgrace;
+
+ if (cdqb->dqb_isoftlimit &&
+ cdqb->dqb_curinodes >= cdqb->dqb_isoftlimit &&
+ !cdqb->dqb_itime)
+ cdqb->dqb_itime =
+ now + qctxt->qckt_dqinfo[cdqb->dqb_type].dqi_igrace;
+
+ cdqb->dqb_valid = QIF_ALL;
+
+ oqc->qc_cmd = Q_SETQUOTA;
+ oqc->qc_type = cdqb->dqb_type;
+ oqc->qc_id = cdqb->dqb_id;
+ DQBLK_COPY(&oqc->qc_dqblk, cdqb);
+
+ rc = fsfilt_ext3_quotactl(sb, oqc);
+ OBD_FREE_PTR(oqc);
+ RETURN(rc);
+}
+
+static int prune_chkquots(struct super_block *sb,
+ struct qchk_ctxt *qctxt, int error)
+{
+ struct chk_dqblk *cdqb, *tmp;
+ int rc;
+
+ list_for_each_entry_safe(cdqb, tmp, &qctxt->qckt_list, dqb_list) {
+ if (!error) {
+ rc = commit_chkquot(sb, qctxt, cdqb);
+ if (rc)
+ error = rc;
+ }
+ hlist_del_init(&cdqb->dqb_hash);
+ list_del(&cdqb->dqb_list);
+ OBD_FREE_PTR(cdqb);
+ }
+
+ return error;
+}
+
+static int fsfilt_ext3_quotacheck(struct super_block *sb,
+ struct obd_quotactl *oqc)