1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/errno.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>
11 #include <asm/byteorder.h>
13 #include "quotaio_v1.h"
15 MODULE_AUTHOR("Jan Kara");
16 MODULE_DESCRIPTION("Old quota format support");
17 MODULE_LICENSE("GPL");
19 #define QUOTABLOCK_BITS 10
20 #define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
22 static inline qsize_t
v1_stoqb(qsize_t space
)
24 return (space
+ QUOTABLOCK_SIZE
- 1) >> QUOTABLOCK_BITS
;
27 static inline qsize_t
v1_qbtos(qsize_t blocks
)
29 return blocks
<< QUOTABLOCK_BITS
;
32 static void v1_disk2mem_dqblk(struct mem_dqblk
*m
, struct v1_disk_dqblk
*d
)
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
;
44 static void v1_mem2disk_dqblk(struct v1_disk_dqblk
*d
, struct mem_dqblk
*m
)
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
;
56 static int v1_read_dqblk(struct dquot
*dquot
)
58 int type
= dquot
->dq_id
.type
;
59 struct v1_disk_dqblk dqblk
;
60 struct quota_info
*dqopt
= sb_dqopt(dquot
->dq_sb
);
62 if (!dqopt
->files
[type
])
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
)));
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
);
82 static int v1_commit_dqblk(struct dquot
*dquot
)
84 short type
= dquot
->dq_id
.type
;
86 struct v1_disk_dqblk dqblk
;
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
))) {
92 sb_dqopt(dquot
->dq_sb
)->info
[type
].dqi_bgrace
;
94 sb_dqopt(dquot
->dq_sb
)->info
[type
].dqi_igrace
;
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");
110 dqstats_inc(DQST_WRITES
);
115 /* Magics of new quota format */
116 #define V2_INITQMAGICS {\
117 0xd9c01f11, /* USRQUOTA */\
118 0xd9c01927 /* GRPQUOTA */\
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 */
127 static int v1_check_quota_file(struct super_block
*sb
, int type
)
129 struct inode
*inode
= sb_dqopt(sb
)->files
[type
];
132 struct v2_disk_dqheader dqhead
;
135 static const uint quota_magics
[] = V2_INITQMAGICS
;
137 isize
= i_size_read(inode
);
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
))
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 */
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 */
159 static int v1_read_file_info(struct super_block
*sb
, int type
)
161 struct quota_info
*dqopt
= sb_dqopt(sb
);
162 struct v1_disk_dqblk dqblk
;
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
)) {
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
;
182 up_read(&dqopt
->dqio_sem
);
186 static int v1_write_file_info(struct super_block
*sb
, int type
)
188 struct quota_info
*dqopt
= sb_dqopt(sb
);
189 struct v1_disk_dqblk dqblk
;
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
)) {
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
))
212 up_write(&dqopt
->dqio_sem
);
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 .read_dqblk
= v1_read_dqblk
,
221 .commit_dqblk
= v1_commit_dqblk
,
224 static struct quota_format_type v1_quota_format
= {
225 .qf_fmt_id
= QFMT_VFS_OLD
,
226 .qf_ops
= &v1_format_ops
,
227 .qf_owner
= THIS_MODULE
230 static int __init
init_v1_quota_format(void)
232 return register_quota_format(&v1_quota_format
);
235 static void __exit
exit_v1_quota_format(void)
237 unregister_quota_format(&v1_quota_format
);
240 module_init(init_v1_quota_format
);
241 module_exit(exit_v1_quota_format
);