GNU Linux-libre 4.9.308-gnu1
[releases.git] / fs / quota / compat.c
1
2 #include <linux/syscalls.h>
3 #include <linux/compat.h>
4 #include <linux/quotaops.h>
5
6 /*
7  * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
8  * and is necessary due to alignment problems.
9  */
10 struct compat_if_dqblk {
11         compat_u64 dqb_bhardlimit;
12         compat_u64 dqb_bsoftlimit;
13         compat_u64 dqb_curspace;
14         compat_u64 dqb_ihardlimit;
15         compat_u64 dqb_isoftlimit;
16         compat_u64 dqb_curinodes;
17         compat_u64 dqb_btime;
18         compat_u64 dqb_itime;
19         compat_uint_t dqb_valid;
20 };
21
22 /* XFS structures */
23 struct compat_fs_qfilestat {
24         compat_u64 dqb_bhardlimit;
25         compat_u64 qfs_nblks;
26         compat_uint_t qfs_nextents;
27 };
28
29 struct compat_fs_quota_stat {
30         __s8            qs_version;
31         __u16           qs_flags;
32         __s8            qs_pad;
33         struct compat_fs_qfilestat      qs_uquota;
34         struct compat_fs_qfilestat      qs_gquota;
35         compat_uint_t   qs_incoredqs;
36         compat_int_t    qs_btimelimit;
37         compat_int_t    qs_itimelimit;
38         compat_int_t    qs_rtbtimelimit;
39         __u16           qs_bwarnlimit;
40         __u16           qs_iwarnlimit;
41 };
42
43 asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
44                                                 qid_t id, void __user *addr)
45 {
46         unsigned int cmds;
47         struct if_dqblk __user *dqblk;
48         struct compat_if_dqblk __user *compat_dqblk;
49         struct fs_quota_stat __user *fsqstat;
50         struct compat_fs_quota_stat __user *compat_fsqstat;
51         compat_uint_t data;
52         u16 xdata;
53         long ret;
54
55         cmds = cmd >> SUBCMDSHIFT;
56
57         switch (cmds) {
58         case Q_GETQUOTA:
59                 dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
60                 compat_dqblk = addr;
61                 ret = sys_quotactl(cmd, special, id, dqblk);
62                 if (ret)
63                         break;
64                 if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
65                         get_user(data, &dqblk->dqb_valid) ||
66                         put_user(data, &compat_dqblk->dqb_valid))
67                         ret = -EFAULT;
68                 break;
69         case Q_SETQUOTA:
70                 dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
71                 compat_dqblk = addr;
72                 ret = -EFAULT;
73                 if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
74                         get_user(data, &compat_dqblk->dqb_valid) ||
75                         put_user(data, &dqblk->dqb_valid))
76                         break;
77                 ret = sys_quotactl(cmd, special, id, dqblk);
78                 break;
79         case Q_XGETQSTAT:
80                 fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
81                 compat_fsqstat = addr;
82                 ret = sys_quotactl(cmd, special, id, fsqstat);
83                 if (ret)
84                         break;
85                 ret = -EFAULT;
86                 /* Copying qs_version, qs_flags, qs_pad */
87                 if (copy_in_user(compat_fsqstat, fsqstat,
88                         offsetof(struct compat_fs_quota_stat, qs_uquota)))
89                         break;
90                 /* Copying qs_uquota */
91                 if (copy_in_user(&compat_fsqstat->qs_uquota,
92                         &fsqstat->qs_uquota,
93                         sizeof(compat_fsqstat->qs_uquota)) ||
94                         get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
95                         put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
96                         break;
97                 /* Copying qs_gquota */
98                 if (copy_in_user(&compat_fsqstat->qs_gquota,
99                         &fsqstat->qs_gquota,
100                         sizeof(compat_fsqstat->qs_gquota)) ||
101                         get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
102                         put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
103                         break;
104                 /* Copying the rest */
105                 if (copy_in_user(&compat_fsqstat->qs_incoredqs,
106                         &fsqstat->qs_incoredqs,
107                         sizeof(struct compat_fs_quota_stat) -
108                         offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
109                         get_user(xdata, &fsqstat->qs_iwarnlimit) ||
110                         put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
111                         break;
112                 ret = 0;
113                 break;
114         default:
115                 ret = sys_quotactl(cmd, special, id, addr);
116         }
117         return ret;
118 }