Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  vfsv0 quota IO operations on file
0004  */
0005 
0006 #include <linux/errno.h>
0007 #include <linux/fs.h>
0008 #include <linux/mount.h>
0009 #include <linux/dqblk_v2.h>
0010 #include <linux/kernel.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/slab.h>
0014 #include <linux/quotaops.h>
0015 
0016 #include <asm/byteorder.h>
0017 
0018 #include "quota_tree.h"
0019 #include "quotaio_v2.h"
0020 
0021 MODULE_AUTHOR("Jan Kara");
0022 MODULE_DESCRIPTION("Quota format v2 support");
0023 MODULE_LICENSE("GPL");
0024 
0025 static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
0026 static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
0027 static int v2r0_is_id(void *dp, struct dquot *dquot);
0028 static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
0029 static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
0030 static int v2r1_is_id(void *dp, struct dquot *dquot);
0031 
0032 static const struct qtree_fmt_operations v2r0_qtree_ops = {
0033     .mem2disk_dqblk = v2r0_mem2diskdqb,
0034     .disk2mem_dqblk = v2r0_disk2memdqb,
0035     .is_id = v2r0_is_id,
0036 };
0037 
0038 static const struct qtree_fmt_operations v2r1_qtree_ops = {
0039     .mem2disk_dqblk = v2r1_mem2diskdqb,
0040     .disk2mem_dqblk = v2r1_disk2memdqb,
0041     .is_id = v2r1_is_id,
0042 };
0043 
0044 #define QUOTABLOCK_BITS 10
0045 #define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
0046 
0047 static inline qsize_t v2_stoqb(qsize_t space)
0048 {
0049     return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
0050 }
0051 
0052 static inline qsize_t v2_qbtos(qsize_t blocks)
0053 {
0054     return blocks << QUOTABLOCK_BITS;
0055 }
0056 
0057 static int v2_read_header(struct super_block *sb, int type,
0058               struct v2_disk_dqheader *dqhead)
0059 {
0060     ssize_t size;
0061 
0062     size = sb->s_op->quota_read(sb, type, (char *)dqhead,
0063                     sizeof(struct v2_disk_dqheader), 0);
0064     if (size != sizeof(struct v2_disk_dqheader)) {
0065         quota_error(sb, "Failed header read: expected=%zd got=%zd",
0066                 sizeof(struct v2_disk_dqheader), size);
0067         if (size < 0)
0068             return size;
0069         return -EIO;
0070     }
0071     return 0;
0072 }
0073 
0074 /* Check whether given file is really vfsv0 quotafile */
0075 static int v2_check_quota_file(struct super_block *sb, int type)
0076 {
0077     struct v2_disk_dqheader dqhead;
0078     static const uint quota_magics[] = V2_INITQMAGICS;
0079     static const uint quota_versions[] = V2_INITQVERSIONS;
0080 
0081     if (v2_read_header(sb, type, &dqhead))
0082         return 0;
0083     if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
0084         le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
0085         return 0;
0086     return 1;
0087 }
0088 
0089 /* Read information header from quota file */
0090 static int v2_read_file_info(struct super_block *sb, int type)
0091 {
0092     struct v2_disk_dqinfo dinfo;
0093     struct v2_disk_dqheader dqhead;
0094     struct quota_info *dqopt = sb_dqopt(sb);
0095     struct mem_dqinfo *info = &dqopt->info[type];
0096     struct qtree_mem_dqinfo *qinfo;
0097     ssize_t size;
0098     unsigned int version;
0099     int ret;
0100 
0101     down_read(&dqopt->dqio_sem);
0102     ret = v2_read_header(sb, type, &dqhead);
0103     if (ret < 0)
0104         goto out;
0105     version = le32_to_cpu(dqhead.dqh_version);
0106     if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) ||
0107         (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) {
0108         ret = -EINVAL;
0109         goto out;
0110     }
0111 
0112     size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
0113            sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
0114     if (size != sizeof(struct v2_disk_dqinfo)) {
0115         quota_error(sb, "Can't read info structure");
0116         if (size < 0)
0117             ret = size;
0118         else
0119             ret = -EIO;
0120         goto out;
0121     }
0122     info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS);
0123     if (!info->dqi_priv) {
0124         ret = -ENOMEM;
0125         goto out;
0126     }
0127     qinfo = info->dqi_priv;
0128     if (version == 0) {
0129         /* limits are stored as unsigned 32-bit data */
0130         info->dqi_max_spc_limit = 0xffffffffLL << QUOTABLOCK_BITS;
0131         info->dqi_max_ino_limit = 0xffffffff;
0132     } else {
0133         /*
0134          * Used space is stored as unsigned 64-bit value in bytes but
0135          * quota core supports only signed 64-bit values so use that
0136          * as a limit
0137          */
0138         info->dqi_max_spc_limit = 0x7fffffffffffffffLL; /* 2^63-1 */
0139         info->dqi_max_ino_limit = 0x7fffffffffffffffLL;
0140     }
0141     info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
0142     info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
0143     /* No flags currently supported */
0144     info->dqi_flags = 0;
0145     qinfo->dqi_sb = sb;
0146     qinfo->dqi_type = type;
0147     qinfo->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
0148     qinfo->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
0149     qinfo->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
0150     qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
0151     qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
0152     qinfo->dqi_qtree_depth = qtree_depth(qinfo);
0153     if (version == 0) {
0154         qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
0155         qinfo->dqi_ops = &v2r0_qtree_ops;
0156     } else {
0157         qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
0158         qinfo->dqi_ops = &v2r1_qtree_ops;
0159     }
0160     ret = -EUCLEAN;
0161     /* Some sanity checks of the read headers... */
0162     if ((loff_t)qinfo->dqi_blocks << qinfo->dqi_blocksize_bits >
0163         i_size_read(sb_dqopt(sb)->files[type])) {
0164         quota_error(sb, "Number of blocks too big for quota file size (%llu > %llu).",
0165             (loff_t)qinfo->dqi_blocks << qinfo->dqi_blocksize_bits,
0166             i_size_read(sb_dqopt(sb)->files[type]));
0167         goto out_free;
0168     }
0169     if (qinfo->dqi_free_blk >= qinfo->dqi_blocks) {
0170         quota_error(sb, "Free block number too big (%u >= %u).",
0171                 qinfo->dqi_free_blk, qinfo->dqi_blocks);
0172         goto out_free;
0173     }
0174     if (qinfo->dqi_free_entry >= qinfo->dqi_blocks) {
0175         quota_error(sb, "Block with free entry too big (%u >= %u).",
0176                 qinfo->dqi_free_entry, qinfo->dqi_blocks);
0177         goto out_free;
0178     }
0179     ret = 0;
0180 out_free:
0181     if (ret) {
0182         kfree(info->dqi_priv);
0183         info->dqi_priv = NULL;
0184     }
0185 out:
0186     up_read(&dqopt->dqio_sem);
0187     return ret;
0188 }
0189 
0190 /* Write information header to quota file */
0191 static int v2_write_file_info(struct super_block *sb, int type)
0192 {
0193     struct v2_disk_dqinfo dinfo;
0194     struct quota_info *dqopt = sb_dqopt(sb);
0195     struct mem_dqinfo *info = &dqopt->info[type];
0196     struct qtree_mem_dqinfo *qinfo = info->dqi_priv;
0197     ssize_t size;
0198 
0199     down_write(&dqopt->dqio_sem);
0200     spin_lock(&dq_data_lock);
0201     info->dqi_flags &= ~DQF_INFO_DIRTY;
0202     dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
0203     dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
0204     /* No flags currently supported */
0205     dinfo.dqi_flags = cpu_to_le32(0);
0206     spin_unlock(&dq_data_lock);
0207     dinfo.dqi_blocks = cpu_to_le32(qinfo->dqi_blocks);
0208     dinfo.dqi_free_blk = cpu_to_le32(qinfo->dqi_free_blk);
0209     dinfo.dqi_free_entry = cpu_to_le32(qinfo->dqi_free_entry);
0210     size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
0211            sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
0212     up_write(&dqopt->dqio_sem);
0213     if (size != sizeof(struct v2_disk_dqinfo)) {
0214         quota_error(sb, "Can't write info structure");
0215         return -1;
0216     }
0217     return 0;
0218 }
0219 
0220 static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
0221 {
0222     struct v2r0_disk_dqblk *d = dp, empty;
0223     struct mem_dqblk *m = &dquot->dq_dqb;
0224 
0225     m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
0226     m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
0227     m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
0228     m->dqb_itime = le64_to_cpu(d->dqb_itime);
0229     m->dqb_bhardlimit = v2_qbtos(le32_to_cpu(d->dqb_bhardlimit));
0230     m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
0231     m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
0232     m->dqb_btime = le64_to_cpu(d->dqb_btime);
0233     /* We need to escape back all-zero structure */
0234     memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
0235     empty.dqb_itime = cpu_to_le64(1);
0236     if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
0237         m->dqb_itime = 0;
0238 }
0239 
0240 static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
0241 {
0242     struct v2r0_disk_dqblk *d = dp;
0243     struct mem_dqblk *m = &dquot->dq_dqb;
0244     struct qtree_mem_dqinfo *info =
0245             sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
0246 
0247     d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
0248     d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
0249     d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
0250     d->dqb_itime = cpu_to_le64(m->dqb_itime);
0251     d->dqb_bhardlimit = cpu_to_le32(v2_stoqb(m->dqb_bhardlimit));
0252     d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
0253     d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
0254     d->dqb_btime = cpu_to_le64(m->dqb_btime);
0255     d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
0256     if (qtree_entry_unused(info, dp))
0257         d->dqb_itime = cpu_to_le64(1);
0258 }
0259 
0260 static int v2r0_is_id(void *dp, struct dquot *dquot)
0261 {
0262     struct v2r0_disk_dqblk *d = dp;
0263     struct qtree_mem_dqinfo *info =
0264             sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
0265 
0266     if (qtree_entry_unused(info, dp))
0267         return 0;
0268     return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
0269                 le32_to_cpu(d->dqb_id)),
0270               dquot->dq_id);
0271 }
0272 
0273 static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
0274 {
0275     struct v2r1_disk_dqblk *d = dp, empty;
0276     struct mem_dqblk *m = &dquot->dq_dqb;
0277 
0278     m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
0279     m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
0280     m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
0281     m->dqb_itime = le64_to_cpu(d->dqb_itime);
0282     m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
0283     m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
0284     m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
0285     m->dqb_btime = le64_to_cpu(d->dqb_btime);
0286     /* We need to escape back all-zero structure */
0287     memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
0288     empty.dqb_itime = cpu_to_le64(1);
0289     if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
0290         m->dqb_itime = 0;
0291 }
0292 
0293 static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
0294 {
0295     struct v2r1_disk_dqblk *d = dp;
0296     struct mem_dqblk *m = &dquot->dq_dqb;
0297     struct qtree_mem_dqinfo *info =
0298             sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
0299 
0300     d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
0301     d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
0302     d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
0303     d->dqb_itime = cpu_to_le64(m->dqb_itime);
0304     d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
0305     d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
0306     d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
0307     d->dqb_btime = cpu_to_le64(m->dqb_btime);
0308     d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
0309     d->dqb_pad = 0;
0310     if (qtree_entry_unused(info, dp))
0311         d->dqb_itime = cpu_to_le64(1);
0312 }
0313 
0314 static int v2r1_is_id(void *dp, struct dquot *dquot)
0315 {
0316     struct v2r1_disk_dqblk *d = dp;
0317     struct qtree_mem_dqinfo *info =
0318             sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
0319 
0320     if (qtree_entry_unused(info, dp))
0321         return 0;
0322     return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
0323                 le32_to_cpu(d->dqb_id)),
0324               dquot->dq_id);
0325 }
0326 
0327 static int v2_read_dquot(struct dquot *dquot)
0328 {
0329     struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
0330     int ret;
0331 
0332     down_read(&dqopt->dqio_sem);
0333     ret = qtree_read_dquot(
0334             sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
0335             dquot);
0336     up_read(&dqopt->dqio_sem);
0337     return ret;
0338 }
0339 
0340 static int v2_write_dquot(struct dquot *dquot)
0341 {
0342     struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
0343     int ret;
0344     bool alloc = false;
0345 
0346     /*
0347      * If space for dquot is already allocated, we don't need any
0348      * protection as we'll only overwrite the place of dquot. We are
0349      * still protected by concurrent writes of the same dquot by
0350      * dquot->dq_lock.
0351      */
0352     if (!dquot->dq_off) {
0353         alloc = true;
0354         down_write(&dqopt->dqio_sem);
0355     } else {
0356         down_read(&dqopt->dqio_sem);
0357     }
0358     ret = qtree_write_dquot(
0359             sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
0360             dquot);
0361     if (alloc)
0362         up_write(&dqopt->dqio_sem);
0363     else
0364         up_read(&dqopt->dqio_sem);
0365     return ret;
0366 }
0367 
0368 static int v2_release_dquot(struct dquot *dquot)
0369 {
0370     struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
0371     int ret;
0372 
0373     down_write(&dqopt->dqio_sem);
0374     ret = qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
0375     up_write(&dqopt->dqio_sem);
0376 
0377     return ret;
0378 }
0379 
0380 static int v2_free_file_info(struct super_block *sb, int type)
0381 {
0382     kfree(sb_dqinfo(sb, type)->dqi_priv);
0383     return 0;
0384 }
0385 
0386 static int v2_get_next_id(struct super_block *sb, struct kqid *qid)
0387 {
0388     struct quota_info *dqopt = sb_dqopt(sb);
0389     int ret;
0390 
0391     down_read(&dqopt->dqio_sem);
0392     ret = qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid);
0393     up_read(&dqopt->dqio_sem);
0394     return ret;
0395 }
0396 
0397 static const struct quota_format_ops v2_format_ops = {
0398     .check_quota_file   = v2_check_quota_file,
0399     .read_file_info     = v2_read_file_info,
0400     .write_file_info    = v2_write_file_info,
0401     .free_file_info     = v2_free_file_info,
0402     .read_dqblk     = v2_read_dquot,
0403     .commit_dqblk       = v2_write_dquot,
0404     .release_dqblk      = v2_release_dquot,
0405     .get_next_id        = v2_get_next_id,
0406 };
0407 
0408 static struct quota_format_type v2r0_quota_format = {
0409     .qf_fmt_id  = QFMT_VFS_V0,
0410     .qf_ops     = &v2_format_ops,
0411     .qf_owner   = THIS_MODULE
0412 };
0413 
0414 static struct quota_format_type v2r1_quota_format = {
0415     .qf_fmt_id  = QFMT_VFS_V1,
0416     .qf_ops     = &v2_format_ops,
0417     .qf_owner   = THIS_MODULE
0418 };
0419 
0420 static int __init init_v2_quota_format(void)
0421 {
0422     int ret;
0423 
0424     ret = register_quota_format(&v2r0_quota_format);
0425     if (ret)
0426         return ret;
0427     return register_quota_format(&v2r1_quota_format);
0428 }
0429 
0430 static void __exit exit_v2_quota_format(void)
0431 {
0432     unregister_quota_format(&v2r0_quota_format);
0433     unregister_quota_format(&v2r1_quota_format);
0434 }
0435 
0436 module_init(init_v2_quota_format);
0437 module_exit(exit_v2_quota_format);