root/fs/quota/quota_v1.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. v1_stoqb
  2. v1_qbtos
  3. v1_disk2mem_dqblk
  4. v1_mem2disk_dqblk
  5. v1_read_dqblk
  6. v1_commit_dqblk
  7. v1_check_quota_file
  8. v1_read_file_info
  9. v1_write_file_info
  10. init_v1_quota_format
  11. exit_v1_quota_format

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #include <linux/errno.h>
   3 #include <linux/fs.h>
   4 #include <linux/quota.h>
   5 #include <linux/quotaops.h>
   6 #include <linux/dqblk_v1.h>
   7 #include <linux/kernel.h>
   8 #include <linux/init.h>
   9 #include <linux/module.h>
  10 
  11 #include <asm/byteorder.h>
  12 
  13 #include "quotaio_v1.h"
  14 
  15 MODULE_AUTHOR("Jan Kara");
  16 MODULE_DESCRIPTION("Old quota format support");
  17 MODULE_LICENSE("GPL");
  18 
  19 #define QUOTABLOCK_BITS 10
  20 #define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
  21 
  22 static inline qsize_t v1_stoqb(qsize_t space)
  23 {
  24         return (space + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS;
  25 }
  26 
  27 static inline qsize_t v1_qbtos(qsize_t blocks)
  28 {
  29         return blocks << QUOTABLOCK_BITS;
  30 }
  31 
  32 static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d)
  33 {
  34         m->dqb_ihardlimit = d->dqb_ihardlimit;
  35         m->dqb_isoftlimit = d->dqb_isoftlimit;
  36         m->dqb_curinodes = d->dqb_curinodes;
  37         m->dqb_bhardlimit = v1_qbtos(d->dqb_bhardlimit);
  38         m->dqb_bsoftlimit = v1_qbtos(d->dqb_bsoftlimit);
  39         m->dqb_curspace = v1_qbtos(d->dqb_curblocks);
  40         m->dqb_itime = d->dqb_itime;
  41         m->dqb_btime = d->dqb_btime;
  42 }
  43 
  44 static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
  45 {
  46         d->dqb_ihardlimit = m->dqb_ihardlimit;
  47         d->dqb_isoftlimit = m->dqb_isoftlimit;
  48         d->dqb_curinodes = m->dqb_curinodes;
  49         d->dqb_bhardlimit = v1_stoqb(m->dqb_bhardlimit);
  50         d->dqb_bsoftlimit = v1_stoqb(m->dqb_bsoftlimit);
  51         d->dqb_curblocks = v1_stoqb(m->dqb_curspace);
  52         d->dqb_itime = m->dqb_itime;
  53         d->dqb_btime = m->dqb_btime;
  54 }
  55 
  56 static int v1_read_dqblk(struct dquot *dquot)
  57 {
  58         int type = dquot->dq_id.type;
  59         struct v1_disk_dqblk dqblk;
  60         struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
  61 
  62         if (!dqopt->files[type])
  63                 return -EINVAL;
  64 
  65         /* Set structure to 0s in case read fails/is after end of file */
  66         memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
  67         dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
  68                         sizeof(struct v1_disk_dqblk),
  69                         v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
  70 
  71         v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
  72         if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
  73             dquot->dq_dqb.dqb_bsoftlimit == 0 &&
  74             dquot->dq_dqb.dqb_ihardlimit == 0 &&
  75             dquot->dq_dqb.dqb_isoftlimit == 0)
  76                 set_bit(DQ_FAKE_B, &dquot->dq_flags);
  77         dqstats_inc(DQST_READS);
  78 
  79         return 0;
  80 }
  81 
  82 static int v1_commit_dqblk(struct dquot *dquot)
  83 {
  84         short type = dquot->dq_id.type;
  85         ssize_t ret;
  86         struct v1_disk_dqblk dqblk;
  87 
  88         v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
  89         if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
  90             ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
  91                 dqblk.dqb_btime =
  92                         sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
  93                 dqblk.dqb_itime =
  94                         sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
  95         }
  96         ret = 0;
  97         if (sb_dqopt(dquot->dq_sb)->files[type])
  98                 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
  99                         (char *)&dqblk, sizeof(struct v1_disk_dqblk),
 100                         v1_dqoff(from_kqid(&init_user_ns, dquot->dq_id)));
 101         if (ret != sizeof(struct v1_disk_dqblk)) {
 102                 quota_error(dquot->dq_sb, "dquota write failed");
 103                 if (ret >= 0)
 104                         ret = -EIO;
 105                 goto out;
 106         }
 107         ret = 0;
 108 
 109 out:
 110         dqstats_inc(DQST_WRITES);
 111 
 112         return ret;
 113 }
 114 
 115 /* Magics of new quota format */
 116 #define V2_INITQMAGICS {\
 117         0xd9c01f11,     /* USRQUOTA */\
 118         0xd9c01927      /* GRPQUOTA */\
 119 }
 120 
 121 /* Header of new quota format */
 122 struct v2_disk_dqheader {
 123         __le32 dqh_magic;        /* Magic number identifying file */
 124         __le32 dqh_version;      /* File version */
 125 };
 126 
 127 static int v1_check_quota_file(struct super_block *sb, int type)
 128 {
 129         struct inode *inode = sb_dqopt(sb)->files[type];
 130         ulong blocks;
 131         size_t off;
 132         struct v2_disk_dqheader dqhead;
 133         ssize_t size;
 134         loff_t isize;
 135         static const uint quota_magics[] = V2_INITQMAGICS;
 136 
 137         isize = i_size_read(inode);
 138         if (!isize)
 139                 return 0;
 140         blocks = isize >> BLOCK_SIZE_BITS;
 141         off = isize & (BLOCK_SIZE - 1);
 142         if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) %
 143             sizeof(struct v1_disk_dqblk))
 144                 return 0;
 145         /* Doublecheck whether we didn't get file with new format - with old
 146          * quotactl() this could happen */
 147         size = sb->s_op->quota_read(sb, type, (char *)&dqhead,
 148                                     sizeof(struct v2_disk_dqheader), 0);
 149         if (size != sizeof(struct v2_disk_dqheader))
 150                 return 1;       /* Probably not new format */
 151         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type])
 152                 return 1;       /* Definitely not new format */
 153         printk(KERN_INFO
 154                "VFS: %s: Refusing to turn on old quota format on given file."
 155                " It probably contains newer quota format.\n", sb->s_id);
 156         return 0;               /* Seems like a new format file -> refuse it */
 157 }
 158 
 159 static int v1_read_file_info(struct super_block *sb, int type)
 160 {
 161         struct quota_info *dqopt = sb_dqopt(sb);
 162         struct v1_disk_dqblk dqblk;
 163         int ret;
 164 
 165         down_read(&dqopt->dqio_sem);
 166         ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
 167                                 sizeof(struct v1_disk_dqblk), v1_dqoff(0));
 168         if (ret != sizeof(struct v1_disk_dqblk)) {
 169                 if (ret >= 0)
 170                         ret = -EIO;
 171                 goto out;
 172         }
 173         ret = 0;
 174         /* limits are stored as unsigned 32-bit data */
 175         dqopt->info[type].dqi_max_spc_limit = 0xffffffffULL << QUOTABLOCK_BITS;
 176         dqopt->info[type].dqi_max_ino_limit = 0xffffffff;
 177         dqopt->info[type].dqi_igrace =
 178                         dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
 179         dqopt->info[type].dqi_bgrace =
 180                         dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
 181 out:
 182         up_read(&dqopt->dqio_sem);
 183         return ret;
 184 }
 185 
 186 static int v1_write_file_info(struct super_block *sb, int type)
 187 {
 188         struct quota_info *dqopt = sb_dqopt(sb);
 189         struct v1_disk_dqblk dqblk;
 190         int ret;
 191 
 192         down_write(&dqopt->dqio_sem);
 193         ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
 194                                 sizeof(struct v1_disk_dqblk), v1_dqoff(0));
 195         if (ret != sizeof(struct v1_disk_dqblk)) {
 196                 if (ret >= 0)
 197                         ret = -EIO;
 198                 goto out;
 199         }
 200         spin_lock(&dq_data_lock);
 201         dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY;
 202         dqblk.dqb_itime = dqopt->info[type].dqi_igrace;
 203         dqblk.dqb_btime = dqopt->info[type].dqi_bgrace;
 204         spin_unlock(&dq_data_lock);
 205         ret = sb->s_op->quota_write(sb, type, (char *)&dqblk,
 206               sizeof(struct v1_disk_dqblk), v1_dqoff(0));
 207         if (ret == sizeof(struct v1_disk_dqblk))
 208                 ret = 0;
 209         else if (ret > 0)
 210                 ret = -EIO;
 211 out:
 212         up_write(&dqopt->dqio_sem);
 213         return ret;
 214 }
 215 
 216 static const struct quota_format_ops v1_format_ops = {
 217         .check_quota_file       = v1_check_quota_file,
 218         .read_file_info         = v1_read_file_info,
 219         .write_file_info        = v1_write_file_info,
 220         .free_file_info         = NULL,
 221         .read_dqblk             = v1_read_dqblk,
 222         .commit_dqblk           = v1_commit_dqblk,
 223 };
 224 
 225 static struct quota_format_type v1_quota_format = {
 226         .qf_fmt_id      = QFMT_VFS_OLD,
 227         .qf_ops         = &v1_format_ops,
 228         .qf_owner       = THIS_MODULE
 229 };
 230 
 231 static int __init init_v1_quota_format(void)
 232 {
 233         return register_quota_format(&v1_quota_format);
 234 }
 235 
 236 static void __exit exit_v1_quota_format(void)
 237 {
 238         unregister_quota_format(&v1_quota_format);
 239 }
 240 
 241 module_init(init_v1_quota_format);
 242 module_exit(exit_v1_quota_format);
 243 

/* [<][>][^][v][top][bottom][index][help] */