1 #include <linux/errno.h>
3 #include <linux/quota.h>
4 #include <linux/dqblk_v1.h>
5 #include <linux/quotaio_v1.h>
6 #include <linux/kernel.h>
7 #include <linux/init.h>
8 #include <linux/module.h>
10 #include <asm/uaccess.h>
11 #include <asm/byteorder.h>
13 static void v1_disk2mem_dqblk(struct mem_dqblk
*m
, struct v1_disk_dqblk
*d
)
15 m
->dqb_ihardlimit
= d
->dqb_ihardlimit
;
16 m
->dqb_isoftlimit
= d
->dqb_isoftlimit
;
17 m
->dqb_curinodes
= d
->dqb_curinodes
;
18 m
->dqb_bhardlimit
= d
->dqb_bhardlimit
;
19 m
->dqb_bsoftlimit
= d
->dqb_bsoftlimit
;
20 m
->dqb_curspace
= ((qsize_t
)d
->dqb_curblocks
) << QUOTABLOCK_BITS
;
21 m
->dqb_itime
= d
->dqb_itime
;
22 m
->dqb_btime
= d
->dqb_btime
;
25 static void v1_mem2disk_dqblk(struct v1_disk_dqblk
*d
, struct mem_dqblk
*m
)
27 d
->dqb_ihardlimit
= m
->dqb_ihardlimit
;
28 d
->dqb_isoftlimit
= m
->dqb_isoftlimit
;
29 d
->dqb_curinodes
= m
->dqb_curinodes
;
30 d
->dqb_bhardlimit
= m
->dqb_bhardlimit
;
31 d
->dqb_bsoftlimit
= m
->dqb_bsoftlimit
;
32 d
->dqb_curblocks
= toqb(m
->dqb_curspace
);
33 d
->dqb_itime
= m
->dqb_itime
;
34 d
->dqb_btime
= m
->dqb_btime
;
37 static int v1_read_dqblk(struct dquot
*dquot
)
39 int type
= dquot
->dq_type
;
43 struct v1_disk_dqblk dqblk
;
45 filp
= sb_dqopt(dquot
->dq_sb
)->files
[type
];
46 if (filp
== (struct file
*)NULL
)
49 memset(&dqblk
, 0, sizeof(dqblk
)); /* Initialize buffer in case file is too short */
50 /* Now we are sure filp is valid */
51 offset
= v1_dqoff(dquot
->dq_id
);
54 filp
->f_op
->read(filp
, (char *)&dqblk
, sizeof(struct v1_disk_dqblk
), &offset
);
57 v1_disk2mem_dqblk(&dquot
->dq_dqb
, &dqblk
);
58 if (dquot
->dq_dqb
.dqb_bhardlimit
== 0 && dquot
->dq_dqb
.dqb_bsoftlimit
== 0 &&
59 dquot
->dq_dqb
.dqb_ihardlimit
== 0 && dquot
->dq_dqb
.dqb_isoftlimit
== 0)
60 dquot
->dq_flags
|= DQ_FAKE
;
65 static int v1_commit_dqblk(struct dquot
*dquot
)
67 short type
= dquot
->dq_type
;
72 struct v1_disk_dqblk dqblk
;
74 filp
= sb_dqopt(dquot
->dq_sb
)->files
[type
];
75 offset
= v1_dqoff(dquot
->dq_id
);
80 * Note: clear the DQ_MOD flag unconditionally,
81 * so we don't loop forever on failure.
83 v1_mem2disk_dqblk(&dqblk
, &dquot
->dq_dqb
);
84 dquot
->dq_flags
&= ~DQ_MOD
;
85 if (dquot
->dq_id
== 0) {
86 dqblk
.dqb_btime
= sb_dqopt(dquot
->dq_sb
)->info
[type
].dqi_bgrace
;
87 dqblk
.dqb_itime
= sb_dqopt(dquot
->dq_sb
)->info
[type
].dqi_igrace
;
91 ret
= filp
->f_op
->write(filp
, (char *)&dqblk
,
92 sizeof(struct v1_disk_dqblk
), &offset
);
93 if (ret
!= sizeof(struct v1_disk_dqblk
)) {
94 printk(KERN_WARNING
"VFS: dquota write failed on dev %s\n",
95 kdevname(dquot
->dq_dev
));
108 /* Magics of new quota format */
109 #define V2_INITQMAGICS {\
110 0xd9c01f11, /* USRQUOTA */\
111 0xd9c01927 /* GRPQUOTA */\
114 /* Header of new quota format */
115 struct v2_disk_dqheader
{
116 __u32 dqh_magic
; /* Magic number identifying file */
117 __u32 dqh_version
; /* File version */
120 static int v1_check_quota_file(struct super_block
*sb
, int type
)
122 struct file
*f
= sb_dqopt(sb
)->files
[type
];
123 struct inode
*inode
= f
->f_dentry
->d_inode
;
126 struct v2_disk_dqheader dqhead
;
130 static const uint quota_magics
[] = V2_INITQMAGICS
;
134 blocks
= inode
->i_size
>> BLOCK_SIZE_BITS
;
135 off
= inode
->i_size
& (BLOCK_SIZE
- 1);
136 if ((blocks
% sizeof(struct v1_disk_dqblk
) * BLOCK_SIZE
+ off
) % sizeof(struct v1_disk_dqblk
))
138 /* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */
141 size
= f
->f_op
->read(f
, (char *)&dqhead
, sizeof(struct v2_disk_dqheader
), &offset
);
143 if (size
!= sizeof(struct v2_disk_dqheader
))
144 return 1; /* Probably not new format */
145 if (le32_to_cpu(dqhead
.dqh_magic
) != quota_magics
[type
])
146 return 1; /* Definitely not new format */
147 printk(KERN_INFO
"VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", kdevname(sb
->s_dev
));
148 return 0; /* Seems like a new format file -> refuse it */
151 static int v1_read_file_info(struct super_block
*sb
, int type
)
153 struct quota_info
*dqopt
= sb_dqopt(sb
);
156 struct file
*filp
= dqopt
->files
[type
];
157 struct v1_disk_dqblk dqblk
;
160 down(&dqopt
->dqio_sem
);
161 offset
= v1_dqoff(0);
164 if ((ret
= filp
->f_op
->read(filp
, (char *)&dqblk
, sizeof(struct v1_disk_dqblk
), &offset
)) != sizeof(struct v1_disk_dqblk
)) {
170 dqopt
->info
[type
].dqi_igrace
= dqblk
.dqb_itime
? dqblk
.dqb_itime
: MAX_IQ_TIME
;
171 dqopt
->info
[type
].dqi_bgrace
= dqblk
.dqb_btime
? dqblk
.dqb_btime
: MAX_DQ_TIME
;
173 up(&dqopt
->dqio_sem
);
178 static int v1_write_file_info(struct super_block
*sb
, int type
)
180 struct quota_info
*dqopt
= sb_dqopt(sb
);
182 struct file
*filp
= dqopt
->files
[type
];
183 struct v1_disk_dqblk dqblk
;
187 down(&dqopt
->dqio_sem
);
188 dqopt
->info
[type
].dqi_flags
&= ~DQF_INFO_DIRTY
;
189 offset
= v1_dqoff(0);
192 if ((ret
= filp
->f_op
->read(filp
, (char *)&dqblk
, sizeof(struct v1_disk_dqblk
), &offset
)) != sizeof(struct v1_disk_dqblk
)) {
197 dqblk
.dqb_itime
= dqopt
->info
[type
].dqi_igrace
;
198 dqblk
.dqb_btime
= dqopt
->info
[type
].dqi_bgrace
;
199 offset
= v1_dqoff(0);
200 ret
= filp
->f_op
->write(filp
, (char *)&dqblk
, sizeof(struct v1_disk_dqblk
), &offset
);
201 if (ret
== sizeof(struct v1_disk_dqblk
))
206 up(&dqopt
->dqio_sem
);
211 static struct quota_format_ops v1_format_ops
= {
212 check_quota_file
: v1_check_quota_file
,
213 read_file_info
: v1_read_file_info
,
214 write_file_info
: v1_write_file_info
,
215 free_file_info
: NULL
,
216 read_dqblk
: v1_read_dqblk
,
217 commit_dqblk
: v1_commit_dqblk
,
220 static struct quota_format_type v1_quota_format
= {
221 qf_fmt_id
: QFMT_VFS_OLD
,
222 qf_ops
: &v1_format_ops
,
223 qf_owner
: THIS_MODULE
226 static int __init
init_v1_quota_format(void)
228 return register_quota_format(&v1_quota_format
);
231 static void __exit
exit_v1_quota_format(void)
233 unregister_quota_format(&v1_quota_format
);
238 module_init(init_v1_quota_format
);
239 module_exit(exit_v1_quota_format
);