~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/quota/quota_v1.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         unsigned int memalloc;
164         int ret;
165 
166         down_read(&dqopt->dqio_sem);
167         memalloc = memalloc_nofs_save();
168         ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
169                                 sizeof(struct v1_disk_dqblk), v1_dqoff(0));
170         if (ret != sizeof(struct v1_disk_dqblk)) {
171                 if (ret >= 0)
172                         ret = -EIO;
173                 goto out;
174         }
175         ret = 0;
176         /* limits are stored as unsigned 32-bit data */
177         dqopt->info[type].dqi_max_spc_limit = 0xffffffffULL << QUOTABLOCK_BITS;
178         dqopt->info[type].dqi_max_ino_limit = 0xffffffff;
179         dqopt->info[type].dqi_igrace =
180                         dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
181         dqopt->info[type].dqi_bgrace =
182                         dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
183 out:
184         memalloc_nofs_restore(memalloc);
185         up_read(&dqopt->dqio_sem);
186         return ret;
187 }
188 
189 static int v1_write_file_info(struct super_block *sb, int type)
190 {
191         struct quota_info *dqopt = sb_dqopt(sb);
192         struct v1_disk_dqblk dqblk;
193         unsigned int memalloc;
194         int ret;
195 
196         down_write(&dqopt->dqio_sem);
197         memalloc = memalloc_nofs_save();
198         ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
199                                 sizeof(struct v1_disk_dqblk), v1_dqoff(0));
200         if (ret != sizeof(struct v1_disk_dqblk)) {
201                 if (ret >= 0)
202                         ret = -EIO;
203                 goto out;
204         }
205         spin_lock(&dq_data_lock);
206         dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY;
207         dqblk.dqb_itime = dqopt->info[type].dqi_igrace;
208         dqblk.dqb_btime = dqopt->info[type].dqi_bgrace;
209         spin_unlock(&dq_data_lock);
210         ret = sb->s_op->quota_write(sb, type, (char *)&dqblk,
211               sizeof(struct v1_disk_dqblk), v1_dqoff(0));
212         if (ret == sizeof(struct v1_disk_dqblk))
213                 ret = 0;
214         else if (ret >= 0)
215                 ret = -EIO;
216 out:
217         memalloc_nofs_restore(memalloc);
218         up_write(&dqopt->dqio_sem);
219         return ret;
220 }
221 
222 static const struct quota_format_ops v1_format_ops = {
223         .check_quota_file       = v1_check_quota_file,
224         .read_file_info         = v1_read_file_info,
225         .write_file_info        = v1_write_file_info,
226         .read_dqblk             = v1_read_dqblk,
227         .commit_dqblk           = v1_commit_dqblk,
228 };
229 
230 static struct quota_format_type v1_quota_format = {
231         .qf_fmt_id      = QFMT_VFS_OLD,
232         .qf_ops         = &v1_format_ops,
233         .qf_owner       = THIS_MODULE
234 };
235 
236 static int __init init_v1_quota_format(void)
237 {
238         return register_quota_format(&v1_quota_format);
239 }
240 
241 static void __exit exit_v1_quota_format(void)
242 {
243         unregister_quota_format(&v1_quota_format);
244 }
245 
246 module_init(init_v1_quota_format);
247 module_exit(exit_v1_quota_format);
248 
249 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php