1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/syscalls.h>
4 #include <linux/compat.h>
5 #include <linux/quotaops.h>
8 * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
9 * and is necessary due to alignment problems.
11 struct compat_if_dqblk
{
12 compat_u64 dqb_bhardlimit
;
13 compat_u64 dqb_bsoftlimit
;
14 compat_u64 dqb_curspace
;
15 compat_u64 dqb_ihardlimit
;
16 compat_u64 dqb_isoftlimit
;
17 compat_u64 dqb_curinodes
;
20 compat_uint_t dqb_valid
;
24 struct compat_fs_qfilestat
{
25 compat_u64 dqb_bhardlimit
;
27 compat_uint_t qfs_nextents
;
30 struct compat_fs_quota_stat
{
34 struct compat_fs_qfilestat qs_uquota
;
35 struct compat_fs_qfilestat qs_gquota
;
36 compat_uint_t qs_incoredqs
;
37 compat_int_t qs_btimelimit
;
38 compat_int_t qs_itimelimit
;
39 compat_int_t qs_rtbtimelimit
;
44 COMPAT_SYSCALL_DEFINE4(quotactl32
, unsigned int, cmd
,
45 const char __user
*, special
, qid_t
, id
,
49 struct if_dqblk __user
*dqblk
;
50 struct compat_if_dqblk __user
*compat_dqblk
;
51 struct fs_quota_stat __user
*fsqstat
;
52 struct compat_fs_quota_stat __user
*compat_fsqstat
;
57 cmds
= cmd
>> SUBCMDSHIFT
;
61 dqblk
= compat_alloc_user_space(sizeof(struct if_dqblk
));
63 ret
= kernel_quotactl(cmd
, special
, id
, dqblk
);
66 if (copy_in_user(compat_dqblk
, dqblk
, sizeof(*compat_dqblk
)) ||
67 get_user(data
, &dqblk
->dqb_valid
) ||
68 put_user(data
, &compat_dqblk
->dqb_valid
))
72 dqblk
= compat_alloc_user_space(sizeof(struct if_dqblk
));
75 if (copy_in_user(dqblk
, compat_dqblk
, sizeof(*compat_dqblk
)) ||
76 get_user(data
, &compat_dqblk
->dqb_valid
) ||
77 put_user(data
, &dqblk
->dqb_valid
))
79 ret
= kernel_quotactl(cmd
, special
, id
, dqblk
);
82 fsqstat
= compat_alloc_user_space(sizeof(struct fs_quota_stat
));
83 compat_fsqstat
= addr
;
84 ret
= kernel_quotactl(cmd
, special
, id
, fsqstat
);
88 /* Copying qs_version, qs_flags, qs_pad */
89 if (copy_in_user(compat_fsqstat
, fsqstat
,
90 offsetof(struct compat_fs_quota_stat
, qs_uquota
)))
92 /* Copying qs_uquota */
93 if (copy_in_user(&compat_fsqstat
->qs_uquota
,
95 sizeof(compat_fsqstat
->qs_uquota
)) ||
96 get_user(data
, &fsqstat
->qs_uquota
.qfs_nextents
) ||
97 put_user(data
, &compat_fsqstat
->qs_uquota
.qfs_nextents
))
99 /* Copying qs_gquota */
100 if (copy_in_user(&compat_fsqstat
->qs_gquota
,
102 sizeof(compat_fsqstat
->qs_gquota
)) ||
103 get_user(data
, &fsqstat
->qs_gquota
.qfs_nextents
) ||
104 put_user(data
, &compat_fsqstat
->qs_gquota
.qfs_nextents
))
106 /* Copying the rest */
107 if (copy_in_user(&compat_fsqstat
->qs_incoredqs
,
108 &fsqstat
->qs_incoredqs
,
109 sizeof(struct compat_fs_quota_stat
) -
110 offsetof(struct compat_fs_quota_stat
, qs_incoredqs
)) ||
111 get_user(xdata
, &fsqstat
->qs_iwarnlimit
) ||
112 put_user(xdata
, &compat_fsqstat
->qs_iwarnlimit
))
117 ret
= kernel_quotactl(cmd
, special
, id
, addr
);