linux/fs/quota/quota_v2.c
<<
>>
Prefs
   1/*
   2 *      vfsv0 quota IO operations on file
   3 */
   4
   5#include <linux/errno.h>
   6#include <linux/fs.h>
   7#include <linux/mount.h>
   8#include <linux/dqblk_v2.h>
   9#include <linux/kernel.h>
  10#include <linux/init.h>
  11#include <linux/module.h>
  12#include <linux/slab.h>
  13#include <linux/quotaops.h>
  14
  15#include <asm/byteorder.h>
  16
  17#include "quota_tree.h"
  18#include "quotaio_v2.h"
  19
  20MODULE_AUTHOR("Jan Kara");
  21MODULE_DESCRIPTION("Quota format v2 support");
  22MODULE_LICENSE("GPL");
  23
  24#define __QUOTA_V2_PARANOIA
  25
  26static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
  27static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
  28static int v2r0_is_id(void *dp, struct dquot *dquot);
  29static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
  30static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
  31static int v2r1_is_id(void *dp, struct dquot *dquot);
  32
  33static const struct qtree_fmt_operations v2r0_qtree_ops = {
  34        .mem2disk_dqblk = v2r0_mem2diskdqb,
  35        .disk2mem_dqblk = v2r0_disk2memdqb,
  36        .is_id = v2r0_is_id,
  37};
  38
  39static const struct qtree_fmt_operations v2r1_qtree_ops = {
  40        .mem2disk_dqblk = v2r1_mem2diskdqb,
  41        .disk2mem_dqblk = v2r1_disk2memdqb,
  42        .is_id = v2r1_is_id,
  43};
  44
  45#define QUOTABLOCK_BITS 10
  46#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
  47
  48static inline qsize_t v2_stoqb(qsize_t space)
  49{
  50        return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
  51}
  52
  53static inline qsize_t v2_qbtos(qsize_t blocks)
  54{
  55        return blocks << QUOTABLOCK_BITS;
  56}
  57
  58static int v2_read_header(struct super_block *sb, int type,
  59                          struct v2_disk_dqheader *dqhead)
  60{
  61        ssize_t size;
  62
  63        size = sb->s_op->quota_read(sb, type, (char *)dqhead,
  64                                    sizeof(struct v2_disk_dqheader), 0);
  65        if (size != sizeof(struct v2_disk_dqheader)) {
  66                quota_error(sb, "Failed header read: expected=%zd got=%zd",
  67                            sizeof(struct v2_disk_dqheader), size);
  68                if (size < 0)
  69                        return size;
  70                return -EIO;
  71        }
  72        return 0;
  73}
  74
  75/* Check whether given file is really vfsv0 quotafile */
  76static int v2_check_quota_file(struct super_block *sb, int type)
  77{
  78        struct v2_disk_dqheader dqhead;
  79        static const uint quota_magics[] = V2_INITQMAGICS;
  80        static const uint quota_versions[] = V2_INITQVERSIONS;
  81 
  82        if (v2_read_header(sb, type, &dqhead))
  83                return 0;
  84        if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
  85            le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
  86                return 0;
  87        return 1;
  88}
  89
  90/* Read information header from quota file */
  91static int v2_read_file_info(struct super_block *sb, int type)
  92{
  93        struct v2_disk_dqinfo dinfo;
  94        struct v2_disk_dqheader dqhead;
  95        struct quota_info *dqopt = sb_dqopt(sb);
  96        struct mem_dqinfo *info = &dqopt->info[type];
  97        struct qtree_mem_dqinfo *qinfo;
  98        ssize_t size;
  99        unsigned int version;
 100        int ret;
 101
 102        down_read(&dqopt->dqio_sem);
 103        ret = v2_read_header(sb, type, &dqhead);
 104        if (ret < 0)
 105                goto out;
 106        version = le32_to_cpu(dqhead.dqh_version);
 107        if ((info->dqi_fmt_id == QFMT_VFS_V0 && version != 0) ||
 108            (info->dqi_fmt_id == QFMT_VFS_V1 && version != 1)) {
 109                ret = -EINVAL;
 110                goto out;
 111        }
 112
 113        size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
 114               sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
 115        if (size != sizeof(struct v2_disk_dqinfo)) {
 116                quota_error(sb, "Can't read info structure");
 117                if (size < 0)
 118                        ret = size;
 119                else
 120                        ret = -EIO;
 121                goto out;
 122        }
 123        info->dqi_priv = kmalloc(sizeof(struct qtree_mem_dqinfo), GFP_NOFS);
 124        if (!info->dqi_priv) {
 125                ret = -ENOMEM;
 126                goto out;
 127        }
 128        qinfo = info->dqi_priv;
 129        if (version == 0) {
 130                /* limits are stored as unsigned 32-bit data */
 131                info->dqi_max_spc_limit = 0xffffffffLL << QUOTABLOCK_BITS;
 132                info->dqi_max_ino_limit = 0xffffffff;
 133        } else {
 134                /*
 135                 * Used space is stored as unsigned 64-bit value in bytes but
 136                 * quota core supports only signed 64-bit values so use that
 137                 * as a limit
 138                 */
 139                info->dqi_max_spc_limit = 0x7fffffffffffffffLL; /* 2^63-1 */
 140                info->dqi_max_ino_limit = 0x7fffffffffffffffLL;
 141        }
 142        info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
 143        info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
 144        /* No flags currently supported */
 145        info->dqi_flags = 0;
 146        qinfo->dqi_sb = sb;
 147        qinfo->dqi_type = type;
 148        qinfo->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
 149        qinfo->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
 150        qinfo->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
 151        qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
 152        qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
 153        qinfo->dqi_qtree_depth = qtree_depth(qinfo);
 154        if (version == 0) {
 155                qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
 156                qinfo->dqi_ops = &v2r0_qtree_ops;
 157        } else {
 158                qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
 159                qinfo->dqi_ops = &v2r1_qtree_ops;
 160        }
 161        ret = 0;
 162out:
 163        up_read(&dqopt->dqio_sem);
 164        return ret;
 165}
 166
 167/* Write information header to quota file */
 168static int v2_write_file_info(struct super_block *sb, int type)
 169{
 170        struct v2_disk_dqinfo dinfo;
 171        struct quota_info *dqopt = sb_dqopt(sb);
 172        struct mem_dqinfo *info = &dqopt->info[type];
 173        struct qtree_mem_dqinfo *qinfo = info->dqi_priv;
 174        ssize_t size;
 175
 176        down_write(&dqopt->dqio_sem);
 177        spin_lock(&dq_data_lock);
 178        info->dqi_flags &= ~DQF_INFO_DIRTY;
 179        dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
 180        dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
 181        /* No flags currently supported */
 182        dinfo.dqi_flags = cpu_to_le32(0);
 183        spin_unlock(&dq_data_lock);
 184        dinfo.dqi_blocks = cpu_to_le32(qinfo->dqi_blocks);
 185        dinfo.dqi_free_blk = cpu_to_le32(qinfo->dqi_free_blk);
 186        dinfo.dqi_free_entry = cpu_to_le32(qinfo->dqi_free_entry);
 187        size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
 188               sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
 189        up_write(&dqopt->dqio_sem);
 190        if (size != sizeof(struct v2_disk_dqinfo)) {
 191                quota_error(sb, "Can't write info structure");
 192                return -1;
 193        }
 194        return 0;
 195}
 196
 197static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
 198{
 199        struct v2r0_disk_dqblk *d = dp, empty;
 200        struct mem_dqblk *m = &dquot->dq_dqb;
 201
 202        m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
 203        m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
 204        m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
 205        m->dqb_itime = le64_to_cpu(d->dqb_itime);
 206        m->dqb_bhardlimit = v2_qbtos(le32_to_cpu(d->dqb_bhardlimit));
 207        m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
 208        m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
 209        m->dqb_btime = le64_to_cpu(d->dqb_btime);
 210        /* We need to escape back all-zero structure */
 211        memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
 212        empty.dqb_itime = cpu_to_le64(1);
 213        if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
 214                m->dqb_itime = 0;
 215}
 216
 217static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
 218{
 219        struct v2r0_disk_dqblk *d = dp;
 220        struct mem_dqblk *m = &dquot->dq_dqb;
 221        struct qtree_mem_dqinfo *info =
 222                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 223
 224        d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
 225        d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
 226        d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
 227        d->dqb_itime = cpu_to_le64(m->dqb_itime);
 228        d->dqb_bhardlimit = cpu_to_le32(v2_stoqb(m->dqb_bhardlimit));
 229        d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
 230        d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 231        d->dqb_btime = cpu_to_le64(m->dqb_btime);
 232        d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
 233        if (qtree_entry_unused(info, dp))
 234                d->dqb_itime = cpu_to_le64(1);
 235}
 236
 237static int v2r0_is_id(void *dp, struct dquot *dquot)
 238{
 239        struct v2r0_disk_dqblk *d = dp;
 240        struct qtree_mem_dqinfo *info =
 241                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 242
 243        if (qtree_entry_unused(info, dp))
 244                return 0;
 245        return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
 246                                le32_to_cpu(d->dqb_id)),
 247                      dquot->dq_id);
 248}
 249
 250static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
 251{
 252        struct v2r1_disk_dqblk *d = dp, empty;
 253        struct mem_dqblk *m = &dquot->dq_dqb;
 254
 255        m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
 256        m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
 257        m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
 258        m->dqb_itime = le64_to_cpu(d->dqb_itime);
 259        m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
 260        m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
 261        m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
 262        m->dqb_btime = le64_to_cpu(d->dqb_btime);
 263        /* We need to escape back all-zero structure */
 264        memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
 265        empty.dqb_itime = cpu_to_le64(1);
 266        if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
 267                m->dqb_itime = 0;
 268}
 269
 270static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
 271{
 272        struct v2r1_disk_dqblk *d = dp;
 273        struct mem_dqblk *m = &dquot->dq_dqb;
 274        struct qtree_mem_dqinfo *info =
 275                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 276
 277        d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
 278        d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
 279        d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
 280        d->dqb_itime = cpu_to_le64(m->dqb_itime);
 281        d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
 282        d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
 283        d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
 284        d->dqb_btime = cpu_to_le64(m->dqb_btime);
 285        d->dqb_id = cpu_to_le32(from_kqid(&init_user_ns, dquot->dq_id));
 286        if (qtree_entry_unused(info, dp))
 287                d->dqb_itime = cpu_to_le64(1);
 288}
 289
 290static int v2r1_is_id(void *dp, struct dquot *dquot)
 291{
 292        struct v2r1_disk_dqblk *d = dp;
 293        struct qtree_mem_dqinfo *info =
 294                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv;
 295
 296        if (qtree_entry_unused(info, dp))
 297                return 0;
 298        return qid_eq(make_kqid(&init_user_ns, dquot->dq_id.type,
 299                                le32_to_cpu(d->dqb_id)),
 300                      dquot->dq_id);
 301}
 302
 303static int v2_read_dquot(struct dquot *dquot)
 304{
 305        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 306        int ret;
 307
 308        down_read(&dqopt->dqio_sem);
 309        ret = qtree_read_dquot(
 310                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
 311                        dquot);
 312        up_read(&dqopt->dqio_sem);
 313        return ret;
 314}
 315
 316static int v2_write_dquot(struct dquot *dquot)
 317{
 318        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 319        int ret;
 320        bool alloc = false;
 321
 322        /*
 323         * If space for dquot is already allocated, we don't need any
 324         * protection as we'll only overwrite the place of dquot. We are
 325         * still protected by concurrent writes of the same dquot by
 326         * dquot->dq_lock.
 327         */
 328        if (!dquot->dq_off) {
 329                alloc = true;
 330                down_write(&dqopt->dqio_sem);
 331        } else {
 332                down_read(&dqopt->dqio_sem);
 333        }
 334        ret = qtree_write_dquot(
 335                        sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
 336                        dquot);
 337        if (alloc)
 338                up_write(&dqopt->dqio_sem);
 339        else
 340                up_read(&dqopt->dqio_sem);
 341        return ret;
 342}
 343
 344static int v2_release_dquot(struct dquot *dquot)
 345{
 346        struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 347        int ret;
 348
 349        down_write(&dqopt->dqio_sem);
 350        ret = qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
 351        up_write(&dqopt->dqio_sem);
 352
 353        return ret;
 354}
 355
 356static int v2_free_file_info(struct super_block *sb, int type)
 357{
 358        kfree(sb_dqinfo(sb, type)->dqi_priv);
 359        return 0;
 360}
 361
 362static int v2_get_next_id(struct super_block *sb, struct kqid *qid)
 363{
 364        struct quota_info *dqopt = sb_dqopt(sb);
 365        int ret;
 366
 367        down_read(&dqopt->dqio_sem);
 368        ret = qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid);
 369        up_read(&dqopt->dqio_sem);
 370        return ret;
 371}
 372
 373static const struct quota_format_ops v2_format_ops = {
 374        .check_quota_file       = v2_check_quota_file,
 375        .read_file_info         = v2_read_file_info,
 376        .write_file_info        = v2_write_file_info,
 377        .free_file_info         = v2_free_file_info,
 378        .read_dqblk             = v2_read_dquot,
 379        .commit_dqblk           = v2_write_dquot,
 380        .release_dqblk          = v2_release_dquot,
 381        .get_next_id            = v2_get_next_id,
 382};
 383
 384static struct quota_format_type v2r0_quota_format = {
 385        .qf_fmt_id      = QFMT_VFS_V0,
 386        .qf_ops         = &v2_format_ops,
 387        .qf_owner       = THIS_MODULE
 388};
 389
 390static struct quota_format_type v2r1_quota_format = {
 391        .qf_fmt_id      = QFMT_VFS_V1,
 392        .qf_ops         = &v2_format_ops,
 393        .qf_owner       = THIS_MODULE
 394};
 395
 396static int __init init_v2_quota_format(void)
 397{
 398        int ret;
 399
 400        ret = register_quota_format(&v2r0_quota_format);
 401        if (ret)
 402                return ret;
 403        return register_quota_format(&v2r1_quota_format);
 404}
 405
 406static void __exit exit_v2_quota_format(void)
 407{
 408        unregister_quota_format(&v2r0_quota_format);
 409        unregister_quota_format(&v2r1_quota_format);
 410}
 411
 412module_init(init_v2_quota_format);
 413module_exit(exit_v2_quota_format);
 414