Blame view

fs/quota/quota.c 26.5 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
  /*
   * Quota code necessary even when VFS quota support is not compiled
   * into the kernel.  The interesting stuff is over in dquot.c, here
   * we have symbols for initial quotactl(2) handling, the sysctl(2)
   * variables, etc - things needed even when quota support disabled.
   */
  
  #include <linux/fs.h>
  #include <linux/namei.h>
  #include <linux/slab.h>
  #include <asm/current.h>
f3da93105   Jeff Liu   quota: fix checkp...
13
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/security.h>
  #include <linux/syscalls.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
17
  #include <linux/capability.h>
be586bab8   Adrian Bunk   [PATCH] quota: sm...
18
  #include <linux/quotaops.h>
b716395e2   Vasily Tarasov   diskquota: 32bit ...
19
  #include <linux/types.h>
8c4e4acd6   Christoph Hellwig   quota: clean up Q...
20
  #include <linux/writeback.h>
7b6924d94   Jeremy Cline   fs/quota: Fix spe...
21
  #include <linux/nospec.h>
80bdad3d7   Christoph Hellwig   quota: simplify t...
22
  #include "compat.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

c988afb5f   Christoph Hellwig   quota: simplify p...
24
25
  static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
  				     qid_t id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  {
c988afb5f   Christoph Hellwig   quota: simplify p...
27
28
29
30
31
32
  	switch (cmd) {
  	/* these commands do not require any special privilegues */
  	case Q_GETFMT:
  	case Q_SYNC:
  	case Q_GETINFO:
  	case Q_XGETQSTAT:
af30cb446   Chandra Seetharaman   quota: Add a new ...
33
  	case Q_XGETQSTATV:
c988afb5f   Christoph Hellwig   quota: simplify p...
34
35
36
37
38
  	case Q_XQUOTASYNC:
  		break;
  	/* allow to query information for dquots we "own" */
  	case Q_GETQUOTA:
  	case Q_XGETQUOTA:
74a8a1037   Eric W. Biederman   userns: Convert q...
39
40
  		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
  		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
c988afb5f   Christoph Hellwig   quota: simplify p...
41
  			break;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
42
  		fallthrough;
c988afb5f   Christoph Hellwig   quota: simplify p...
43
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
  		if (!capable(CAP_SYS_ADMIN))
  			return -EPERM;
  	}
c988afb5f   Christoph Hellwig   quota: simplify p...
47
  	return security_quotactl(cmd, type, id, sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  }
01a05b337   Al Viro   new helper: itera...
49
50
  static void quota_sync_one(struct super_block *sb, void *arg)
  {
2c5f648aa   Jan Kara   quota: Allow each...
51
52
53
54
55
  	int type = *(int *)arg;
  
  	if (sb->s_qcop && sb->s_qcop->quota_sync &&
  	    (sb->s_quota_types & (1 << type)))
  		sb->s_qcop->quota_sync(sb, type);
01a05b337   Al Viro   new helper: itera...
56
  }
6ae09575b   Christoph Hellwig   quota: special ca...
57
  static int quota_sync_all(int type)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  {
6ae09575b   Christoph Hellwig   quota: special ca...
59
  	int ret;
6ae09575b   Christoph Hellwig   quota: special ca...
60
  	ret = security_quotactl(Q_SYNC, type, 0, NULL);
01a05b337   Al Viro   new helper: itera...
61
62
63
  	if (!ret)
  		iterate_supers(quota_sync_one, &type);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  }
d3b863248   Jan Kara   quota: Wire up ->...
65
66
67
68
69
70
71
72
73
74
75
76
  unsigned int qtype_enforce_flag(int type)
  {
  	switch (type) {
  	case USRQUOTA:
  		return FS_QUOTA_UDQ_ENFD;
  	case GRPQUOTA:
  		return FS_QUOTA_GDQ_ENFD;
  	case PRJQUOTA:
  		return FS_QUOTA_PDQ_ENFD;
  	}
  	return 0;
  }
3218a3ec8   Eric Sandeen   quota: remove unu...
77
  static int quota_quotaon(struct super_block *sb, int type, qid_t id,
8c54ca9c6   Al Viro   quota: constify s...
78
  		         const struct path *path)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  {
aaa3daed1   Jan Kara   quota: Remove quo...
80
  	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_enable)
f00c9e44a   Jan Kara   quota: Fix deadlo...
81
  		return -ENOSYS;
d3b863248   Jan Kara   quota: Wire up ->...
82
83
  	if (sb->s_qcop->quota_enable)
  		return sb->s_qcop->quota_enable(sb, qtype_enforce_flag(type));
f00c9e44a   Jan Kara   quota: Fix deadlo...
84
85
86
  	if (IS_ERR(path))
  		return PTR_ERR(path);
  	return sb->s_qcop->quota_on(sb, type, id, path);
c411e5f66   Christoph Hellwig   quota: split do_q...
87
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88

d3b863248   Jan Kara   quota: Wire up ->...
89
90
91
92
93
94
95
96
  static int quota_quotaoff(struct super_block *sb, int type)
  {
  	if (!sb->s_qcop->quota_off && !sb->s_qcop->quota_disable)
  		return -ENOSYS;
  	if (sb->s_qcop->quota_disable)
  		return sb->s_qcop->quota_disable(sb, qtype_enforce_flag(type));
  	return sb->s_qcop->quota_off(sb, type);
  }
c411e5f66   Christoph Hellwig   quota: split do_q...
97
98
99
  static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
  {
  	__u32 fmt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

9d1ccbe70   Jan Kara   quota: Use s_umou...
101
  	if (!sb_has_quota_active(sb, type))
c411e5f66   Christoph Hellwig   quota: split do_q...
102
  		return -ESRCH;
c411e5f66   Christoph Hellwig   quota: split do_q...
103
  	fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
c411e5f66   Christoph Hellwig   quota: split do_q...
104
105
106
107
  	if (copy_to_user(addr, &fmt, sizeof(fmt)))
  		return -EFAULT;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108

c411e5f66   Christoph Hellwig   quota: split do_q...
109
110
  static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
  {
0a240339a   Jan Kara   quota: Make VFS q...
111
112
113
  	struct qc_state state;
  	struct qc_type_state *tstate;
  	struct if_dqinfo uinfo;
c411e5f66   Christoph Hellwig   quota: split do_q...
114
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115

0a240339a   Jan Kara   quota: Make VFS q...
116
  	if (!sb->s_qcop->get_state)
f450d4fee   Christoph Hellwig   quota: clean up c...
117
  		return -ENOSYS;
0a240339a   Jan Kara   quota: Make VFS q...
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  	ret = sb->s_qcop->get_state(sb, &state);
  	if (ret)
  		return ret;
  	tstate = state.s_state + type;
  	if (!(tstate->flags & QCI_ACCT_ENABLED))
  		return -ESRCH;
  	memset(&uinfo, 0, sizeof(uinfo));
  	uinfo.dqi_bgrace = tstate->spc_timelimit;
  	uinfo.dqi_igrace = tstate->ino_timelimit;
  	if (tstate->flags & QCI_SYSFILE)
  		uinfo.dqi_flags |= DQF_SYS_FILE;
  	if (tstate->flags & QCI_ROOT_SQUASH)
  		uinfo.dqi_flags |= DQF_ROOT_SQUASH;
  	uinfo.dqi_valid = IIF_ALL;
72d4d0e48   Dan Carpenter   quota: remove an ...
132
  	if (copy_to_user(addr, &uinfo, sizeof(uinfo)))
c411e5f66   Christoph Hellwig   quota: split do_q...
133
  		return -EFAULT;
72d4d0e48   Dan Carpenter   quota: remove an ...
134
  	return 0;
c411e5f66   Christoph Hellwig   quota: split do_q...
135
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136

c411e5f66   Christoph Hellwig   quota: split do_q...
137
138
139
  static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
  {
  	struct if_dqinfo info;
5eacb2ac0   Jan Kara   quota: Make ->set...
140
  	struct qc_info qinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

c411e5f66   Christoph Hellwig   quota: split do_q...
142
143
  	if (copy_from_user(&info, addr, sizeof(info)))
  		return -EFAULT;
f450d4fee   Christoph Hellwig   quota: clean up c...
144
145
  	if (!sb->s_qcop->set_info)
  		return -ENOSYS;
5eacb2ac0   Jan Kara   quota: Make ->set...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  	if (info.dqi_valid & ~(IIF_FLAGS | IIF_BGRACE | IIF_IGRACE))
  		return -EINVAL;
  	memset(&qinfo, 0, sizeof(qinfo));
  	if (info.dqi_valid & IIF_FLAGS) {
  		if (info.dqi_flags & ~DQF_SETINFO_MASK)
  			return -EINVAL;
  		if (info.dqi_flags & DQF_ROOT_SQUASH)
  			qinfo.i_flags |= QCI_ROOT_SQUASH;
  		qinfo.i_fieldmask |= QC_FLAGS;
  	}
  	if (info.dqi_valid & IIF_BGRACE) {
  		qinfo.i_spc_timelimit = info.dqi_bgrace;
  		qinfo.i_fieldmask |= QC_SPC_TIMER;
  	}
  	if (info.dqi_valid & IIF_IGRACE) {
  		qinfo.i_ino_timelimit = info.dqi_igrace;
  		qinfo.i_fieldmask |= QC_INO_TIMER;
  	}
  	return sb->s_qcop->set_info(sb, type, &qinfo);
c411e5f66   Christoph Hellwig   quota: split do_q...
165
  }
14bf61ffe   Jan Kara   quota: Switch ->g...
166
167
168
169
170
171
172
173
174
175
176
  static inline qsize_t qbtos(qsize_t blocks)
  {
  	return blocks << QIF_DQBLKSIZE_BITS;
  }
  
  static inline qsize_t stoqb(qsize_t space)
  {
  	return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
  }
  
  static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src)
b9b2dd36c   Christoph Hellwig   quota: unify ->ge...
177
  {
18da65e7d   Dan Carpenter   quota: info leak ...
178
  	memset(dst, 0, sizeof(*dst));
14bf61ffe   Jan Kara   quota: Switch ->g...
179
180
181
  	dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
  	dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
  	dst->dqb_curspace = src->d_space;
b9b2dd36c   Christoph Hellwig   quota: unify ->ge...
182
183
  	dst->dqb_ihardlimit = src->d_ino_hardlimit;
  	dst->dqb_isoftlimit = src->d_ino_softlimit;
14bf61ffe   Jan Kara   quota: Switch ->g...
184
185
186
  	dst->dqb_curinodes = src->d_ino_count;
  	dst->dqb_btime = src->d_spc_timer;
  	dst->dqb_itime = src->d_ino_timer;
b9b2dd36c   Christoph Hellwig   quota: unify ->ge...
187
188
  	dst->dqb_valid = QIF_ALL;
  }
c411e5f66   Christoph Hellwig   quota: split do_q...
189
190
191
  static int quota_getquota(struct super_block *sb, int type, qid_t id,
  			  void __user *addr)
  {
74a8a1037   Eric W. Biederman   userns: Convert q...
192
  	struct kqid qid;
14bf61ffe   Jan Kara   quota: Switch ->g...
193
  	struct qc_dqblk fdq;
c411e5f66   Christoph Hellwig   quota: split do_q...
194
195
  	struct if_dqblk idq;
  	int ret;
f450d4fee   Christoph Hellwig   quota: clean up c...
196
197
  	if (!sb->s_qcop->get_dqblk)
  		return -ENOSYS;
74a8a1037   Eric W. Biederman   userns: Convert q...
198
  	qid = make_kqid(current_user_ns(), type, id);
d49d37624   Eric W. Biederman   quota: Ensure qid...
199
  	if (!qid_has_mapping(sb->s_user_ns, qid))
74a8a1037   Eric W. Biederman   userns: Convert q...
200
201
  		return -EINVAL;
  	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
c411e5f66   Christoph Hellwig   quota: split do_q...
202
203
  	if (ret)
  		return ret;
b9b2dd36c   Christoph Hellwig   quota: unify ->ge...
204
  	copy_to_if_dqblk(&idq, &fdq);
80bdad3d7   Christoph Hellwig   quota: simplify t...
205
206
207
208
209
210
211
212
213
214
215
216
  
  	if (compat_need_64bit_alignment_fixup()) {
  		struct compat_if_dqblk __user *compat_dqblk = addr;
  
  		if (copy_to_user(compat_dqblk, &idq, sizeof(*compat_dqblk)))
  			return -EFAULT;
  		if (put_user(idq.dqb_valid, &compat_dqblk->dqb_valid))
  			return -EFAULT;
  	} else {
  		if (copy_to_user(addr, &idq, sizeof(idq)))
  			return -EFAULT;
  	}
c411e5f66   Christoph Hellwig   quota: split do_q...
217
218
  	return 0;
  }
926132c02   Eric Sandeen   quota: add new qu...
219
220
  /*
   * Return quota for next active quota >= this id, if any exists,
ba58148b6   Eric Sandeen   quota: Fixup comm...
221
   * otherwise return -ENOENT via ->get_nextdqblk
926132c02   Eric Sandeen   quota: add new qu...
222
223
224
225
226
227
228
229
230
231
232
233
   */
  static int quota_getnextquota(struct super_block *sb, int type, qid_t id,
  			  void __user *addr)
  {
  	struct kqid qid;
  	struct qc_dqblk fdq;
  	struct if_nextdqblk idq;
  	int ret;
  
  	if (!sb->s_qcop->get_nextdqblk)
  		return -ENOSYS;
  	qid = make_kqid(current_user_ns(), type, id);
d49d37624   Eric W. Biederman   quota: Ensure qid...
234
  	if (!qid_has_mapping(sb->s_user_ns, qid))
926132c02   Eric Sandeen   quota: add new qu...
235
236
237
238
239
240
241
242
243
244
245
  		return -EINVAL;
  	ret = sb->s_qcop->get_nextdqblk(sb, &qid, &fdq);
  	if (ret)
  		return ret;
  	/* struct if_nextdqblk is a superset of struct if_dqblk */
  	copy_to_if_dqblk((struct if_dqblk *)&idq, &fdq);
  	idq.dqb_id = from_kqid(current_user_ns(), qid);
  	if (copy_to_user(addr, &idq, sizeof(idq)))
  		return -EFAULT;
  	return 0;
  }
14bf61ffe   Jan Kara   quota: Switch ->g...
246
  static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
c472b4327   Christoph Hellwig   quota: unify ->se...
247
  {
14bf61ffe   Jan Kara   quota: Switch ->g...
248
249
250
  	dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
  	dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
  	dst->d_space = src->dqb_curspace;
c472b4327   Christoph Hellwig   quota: unify ->se...
251
252
  	dst->d_ino_hardlimit = src->dqb_ihardlimit;
  	dst->d_ino_softlimit = src->dqb_isoftlimit;
14bf61ffe   Jan Kara   quota: Switch ->g...
253
254
255
  	dst->d_ino_count = src->dqb_curinodes;
  	dst->d_spc_timer = src->dqb_btime;
  	dst->d_ino_timer = src->dqb_itime;
c472b4327   Christoph Hellwig   quota: unify ->se...
256
257
258
  
  	dst->d_fieldmask = 0;
  	if (src->dqb_valid & QIF_BLIMITS)
14bf61ffe   Jan Kara   quota: Switch ->g...
259
  		dst->d_fieldmask |= QC_SPC_SOFT | QC_SPC_HARD;
c472b4327   Christoph Hellwig   quota: unify ->se...
260
  	if (src->dqb_valid & QIF_SPACE)
14bf61ffe   Jan Kara   quota: Switch ->g...
261
  		dst->d_fieldmask |= QC_SPACE;
c472b4327   Christoph Hellwig   quota: unify ->se...
262
  	if (src->dqb_valid & QIF_ILIMITS)
14bf61ffe   Jan Kara   quota: Switch ->g...
263
  		dst->d_fieldmask |= QC_INO_SOFT | QC_INO_HARD;
c472b4327   Christoph Hellwig   quota: unify ->se...
264
  	if (src->dqb_valid & QIF_INODES)
14bf61ffe   Jan Kara   quota: Switch ->g...
265
  		dst->d_fieldmask |= QC_INO_COUNT;
c472b4327   Christoph Hellwig   quota: unify ->se...
266
  	if (src->dqb_valid & QIF_BTIME)
14bf61ffe   Jan Kara   quota: Switch ->g...
267
  		dst->d_fieldmask |= QC_SPC_TIMER;
c472b4327   Christoph Hellwig   quota: unify ->se...
268
  	if (src->dqb_valid & QIF_ITIME)
14bf61ffe   Jan Kara   quota: Switch ->g...
269
  		dst->d_fieldmask |= QC_INO_TIMER;
c472b4327   Christoph Hellwig   quota: unify ->se...
270
  }
c411e5f66   Christoph Hellwig   quota: split do_q...
271
272
273
  static int quota_setquota(struct super_block *sb, int type, qid_t id,
  			  void __user *addr)
  {
14bf61ffe   Jan Kara   quota: Switch ->g...
274
  	struct qc_dqblk fdq;
c411e5f66   Christoph Hellwig   quota: split do_q...
275
  	struct if_dqblk idq;
74a8a1037   Eric W. Biederman   userns: Convert q...
276
  	struct kqid qid;
c411e5f66   Christoph Hellwig   quota: split do_q...
277

80bdad3d7   Christoph Hellwig   quota: simplify t...
278
279
280
281
282
283
284
285
286
287
  	if (compat_need_64bit_alignment_fixup()) {
  		struct compat_if_dqblk __user *compat_dqblk = addr;
  
  		if (copy_from_user(&idq, compat_dqblk, sizeof(*compat_dqblk)) ||
  		    get_user(idq.dqb_valid, &compat_dqblk->dqb_valid))
  			return -EFAULT;
  	} else {
  		if (copy_from_user(&idq, addr, sizeof(idq)))
  			return -EFAULT;
  	}
f450d4fee   Christoph Hellwig   quota: clean up c...
288
289
  	if (!sb->s_qcop->set_dqblk)
  		return -ENOSYS;
74a8a1037   Eric W. Biederman   userns: Convert q...
290
  	qid = make_kqid(current_user_ns(), type, id);
d49d37624   Eric W. Biederman   quota: Ensure qid...
291
  	if (!qid_has_mapping(sb->s_user_ns, qid))
74a8a1037   Eric W. Biederman   userns: Convert q...
292
  		return -EINVAL;
c472b4327   Christoph Hellwig   quota: unify ->se...
293
  	copy_from_if_dqblk(&fdq, &idq);
74a8a1037   Eric W. Biederman   userns: Convert q...
294
  	return sb->s_qcop->set_dqblk(sb, qid, &fdq);
c411e5f66   Christoph Hellwig   quota: split do_q...
295
  }
38e478c44   Jan Kara   quota: Split ->se...
296
  static int quota_enable(struct super_block *sb, void __user *addr)
c411e5f66   Christoph Hellwig   quota: split do_q...
297
298
299
300
301
  {
  	__u32 flags;
  
  	if (copy_from_user(&flags, addr, sizeof(flags)))
  		return -EFAULT;
38e478c44   Jan Kara   quota: Split ->se...
302
  	if (!sb->s_qcop->quota_enable)
f450d4fee   Christoph Hellwig   quota: clean up c...
303
  		return -ENOSYS;
38e478c44   Jan Kara   quota: Split ->se...
304
305
306
307
308
309
310
311
312
313
314
315
  	return sb->s_qcop->quota_enable(sb, flags);
  }
  
  static int quota_disable(struct super_block *sb, void __user *addr)
  {
  	__u32 flags;
  
  	if (copy_from_user(&flags, addr, sizeof(flags)))
  		return -EFAULT;
  	if (!sb->s_qcop->quota_disable)
  		return -ENOSYS;
  	return sb->s_qcop->quota_disable(sb, flags);
c411e5f66   Christoph Hellwig   quota: split do_q...
316
  }
bc230e4a2   Jan Kara   quota: Wire up Q_...
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  static int quota_state_to_flags(struct qc_state *state)
  {
  	int flags = 0;
  
  	if (state->s_state[USRQUOTA].flags & QCI_ACCT_ENABLED)
  		flags |= FS_QUOTA_UDQ_ACCT;
  	if (state->s_state[USRQUOTA].flags & QCI_LIMITS_ENFORCED)
  		flags |= FS_QUOTA_UDQ_ENFD;
  	if (state->s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)
  		flags |= FS_QUOTA_GDQ_ACCT;
  	if (state->s_state[GRPQUOTA].flags & QCI_LIMITS_ENFORCED)
  		flags |= FS_QUOTA_GDQ_ENFD;
  	if (state->s_state[PRJQUOTA].flags & QCI_ACCT_ENABLED)
  		flags |= FS_QUOTA_PDQ_ACCT;
  	if (state->s_state[PRJQUOTA].flags & QCI_LIMITS_ENFORCED)
  		flags |= FS_QUOTA_PDQ_ENFD;
  	return flags;
  }
555b2c3da   Eric Sandeen   quota: honor quot...
335
336
  static int quota_getstate(struct super_block *sb, int type,
  			  struct fs_quota_stat *fqs)
bc230e4a2   Jan Kara   quota: Wire up Q_...
337
  {
bc230e4a2   Jan Kara   quota: Wire up Q_...
338
339
  	struct qc_state state;
  	int ret;
3cd0126dc   Eric Sandeen   quota: fill in Q_...
340
  	memset(&state, 0, sizeof (struct qc_state));
bc230e4a2   Jan Kara   quota: Wire up Q_...
341
342
343
344
345
346
347
348
349
350
351
  	ret = sb->s_qcop->get_state(sb, &state);
  	if (ret < 0)
  		return ret;
  
  	memset(fqs, 0, sizeof(*fqs));
  	fqs->qs_version = FS_QSTAT_VERSION;
  	fqs->qs_flags = quota_state_to_flags(&state);
  	/* No quota enabled? */
  	if (!fqs->qs_flags)
  		return -ENOSYS;
  	fqs->qs_incoredqs = state.s_incoredqs;
555b2c3da   Eric Sandeen   quota: honor quot...
352

bc230e4a2   Jan Kara   quota: Wire up Q_...
353
354
355
356
357
  	fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
  	fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
  	fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
  	fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
  	fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
3cd0126dc   Eric Sandeen   quota: fill in Q_...
358
359
360
  
  	/* Inodes may be allocated even if inactive; copy out if present */
  	if (state.s_state[USRQUOTA].ino) {
bc230e4a2   Jan Kara   quota: Wire up Q_...
361
362
363
364
  		fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
  		fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
  		fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
  	}
3cd0126dc   Eric Sandeen   quota: fill in Q_...
365
  	if (state.s_state[GRPQUOTA].ino) {
bc230e4a2   Jan Kara   quota: Wire up Q_...
366
367
368
369
  		fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
  		fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
  		fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
  	}
3cd0126dc   Eric Sandeen   quota: fill in Q_...
370
  	if (state.s_state[PRJQUOTA].ino) {
bc230e4a2   Jan Kara   quota: Wire up Q_...
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  		/*
  		 * Q_XGETQSTAT doesn't have room for both group and project
  		 * quotas.  So, allow the project quota values to be copied out
  		 * only if there is no group quota information available.
  		 */
  		if (!(state.s_state[GRPQUOTA].flags & QCI_ACCT_ENABLED)) {
  			fqs->qs_gquota.qfs_ino = state.s_state[PRJQUOTA].ino;
  			fqs->qs_gquota.qfs_nblks =
  					state.s_state[PRJQUOTA].blocks;
  			fqs->qs_gquota.qfs_nextents =
  					state.s_state[PRJQUOTA].nextents;
  		}
  	}
  	return 0;
  }
80bdad3d7   Christoph Hellwig   quota: simplify t...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
  static int compat_copy_fs_qfilestat(struct compat_fs_qfilestat __user *to,
  		struct fs_qfilestat *from)
  {
  	if (copy_to_user(to, from, sizeof(*to)) ||
  	    put_user(from->qfs_nextents, &to->qfs_nextents))
  		return -EFAULT;
  	return 0;
  }
  
  static int compat_copy_fs_quota_stat(struct compat_fs_quota_stat __user *to,
  		struct fs_quota_stat *from)
  {
  	if (put_user(from->qs_version, &to->qs_version) ||
  	    put_user(from->qs_flags, &to->qs_flags) ||
  	    put_user(from->qs_pad, &to->qs_pad) ||
  	    compat_copy_fs_qfilestat(&to->qs_uquota, &from->qs_uquota) ||
  	    compat_copy_fs_qfilestat(&to->qs_gquota, &from->qs_gquota) ||
  	    put_user(from->qs_incoredqs, &to->qs_incoredqs) ||
  	    put_user(from->qs_btimelimit, &to->qs_btimelimit) ||
  	    put_user(from->qs_itimelimit, &to->qs_itimelimit) ||
  	    put_user(from->qs_rtbtimelimit, &to->qs_rtbtimelimit) ||
  	    put_user(from->qs_bwarnlimit, &to->qs_bwarnlimit) ||
  	    put_user(from->qs_iwarnlimit, &to->qs_iwarnlimit))
  		return -EFAULT;
  	return 0;
  }
555b2c3da   Eric Sandeen   quota: honor quot...
412
  static int quota_getxstate(struct super_block *sb, int type, void __user *addr)
c411e5f66   Christoph Hellwig   quota: split do_q...
413
414
415
  {
  	struct fs_quota_stat fqs;
  	int ret;
f450d4fee   Christoph Hellwig   quota: clean up c...
416

59b6ba699   Jan Kara   quota: Remove ->g...
417
  	if (!sb->s_qcop->get_state)
f450d4fee   Christoph Hellwig   quota: clean up c...
418
  		return -ENOSYS;
555b2c3da   Eric Sandeen   quota: honor quot...
419
  	ret = quota_getstate(sb, type, &fqs);
80bdad3d7   Christoph Hellwig   quota: simplify t...
420
421
422
423
424
425
  	if (ret)
  		return ret;
  
  	if (compat_need_64bit_alignment_fixup())
  		return compat_copy_fs_quota_stat(addr, &fqs);
  	if (copy_to_user(addr, &fqs, sizeof(fqs)))
c411e5f66   Christoph Hellwig   quota: split do_q...
426
  		return -EFAULT;
80bdad3d7   Christoph Hellwig   quota: simplify t...
427
  	return 0;
c411e5f66   Christoph Hellwig   quota: split do_q...
428
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

555b2c3da   Eric Sandeen   quota: honor quot...
430
431
  static int quota_getstatev(struct super_block *sb, int type,
  			   struct fs_quota_statv *fqs)
bc230e4a2   Jan Kara   quota: Wire up Q_...
432
  {
bc230e4a2   Jan Kara   quota: Wire up Q_...
433
434
  	struct qc_state state;
  	int ret;
3cd0126dc   Eric Sandeen   quota: fill in Q_...
435
  	memset(&state, 0, sizeof (struct qc_state));
bc230e4a2   Jan Kara   quota: Wire up Q_...
436
437
438
439
440
441
442
443
444
445
446
  	ret = sb->s_qcop->get_state(sb, &state);
  	if (ret < 0)
  		return ret;
  
  	memset(fqs, 0, sizeof(*fqs));
  	fqs->qs_version = FS_QSTAT_VERSION;
  	fqs->qs_flags = quota_state_to_flags(&state);
  	/* No quota enabled? */
  	if (!fqs->qs_flags)
  		return -ENOSYS;
  	fqs->qs_incoredqs = state.s_incoredqs;
555b2c3da   Eric Sandeen   quota: honor quot...
447

bc230e4a2   Jan Kara   quota: Wire up Q_...
448
449
450
451
452
  	fqs->qs_btimelimit = state.s_state[type].spc_timelimit;
  	fqs->qs_itimelimit = state.s_state[type].ino_timelimit;
  	fqs->qs_rtbtimelimit = state.s_state[type].rt_spc_timelimit;
  	fqs->qs_bwarnlimit = state.s_state[type].spc_warnlimit;
  	fqs->qs_iwarnlimit = state.s_state[type].ino_warnlimit;
3cd0126dc   Eric Sandeen   quota: fill in Q_...
453
454
455
  
  	/* Inodes may be allocated even if inactive; copy out if present */
  	if (state.s_state[USRQUOTA].ino) {
bc230e4a2   Jan Kara   quota: Wire up Q_...
456
457
458
459
  		fqs->qs_uquota.qfs_ino = state.s_state[USRQUOTA].ino;
  		fqs->qs_uquota.qfs_nblks = state.s_state[USRQUOTA].blocks;
  		fqs->qs_uquota.qfs_nextents = state.s_state[USRQUOTA].nextents;
  	}
3cd0126dc   Eric Sandeen   quota: fill in Q_...
460
  	if (state.s_state[GRPQUOTA].ino) {
bc230e4a2   Jan Kara   quota: Wire up Q_...
461
462
463
464
  		fqs->qs_gquota.qfs_ino = state.s_state[GRPQUOTA].ino;
  		fqs->qs_gquota.qfs_nblks = state.s_state[GRPQUOTA].blocks;
  		fqs->qs_gquota.qfs_nextents = state.s_state[GRPQUOTA].nextents;
  	}
3cd0126dc   Eric Sandeen   quota: fill in Q_...
465
  	if (state.s_state[PRJQUOTA].ino) {
bc230e4a2   Jan Kara   quota: Wire up Q_...
466
467
468
469
470
471
  		fqs->qs_pquota.qfs_ino = state.s_state[PRJQUOTA].ino;
  		fqs->qs_pquota.qfs_nblks = state.s_state[PRJQUOTA].blocks;
  		fqs->qs_pquota.qfs_nextents = state.s_state[PRJQUOTA].nextents;
  	}
  	return 0;
  }
555b2c3da   Eric Sandeen   quota: honor quot...
472
  static int quota_getxstatev(struct super_block *sb, int type, void __user *addr)
af30cb446   Chandra Seetharaman   quota: Add a new ...
473
474
475
  {
  	struct fs_quota_statv fqs;
  	int ret;
59b6ba699   Jan Kara   quota: Remove ->g...
476
  	if (!sb->s_qcop->get_state)
af30cb446   Chandra Seetharaman   quota: Add a new ...
477
478
479
480
481
482
483
484
485
486
487
488
489
  		return -ENOSYS;
  
  	memset(&fqs, 0, sizeof(fqs));
  	if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
  		return -EFAULT;
  
  	/* If this kernel doesn't support user specified version, fail */
  	switch (fqs.qs_version) {
  	case FS_QSTATV_VERSION1:
  		break;
  	default:
  		return -EINVAL;
  	}
555b2c3da   Eric Sandeen   quota: honor quot...
490
  	ret = quota_getstatev(sb, type, &fqs);
af30cb446   Chandra Seetharaman   quota: Add a new ...
491
492
493
494
  	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
  		return -EFAULT;
  	return ret;
  }
14bf61ffe   Jan Kara   quota: Switch ->g...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  /*
   * XFS defines BBTOB and BTOBB macros inside fs/xfs/ and we cannot move them
   * out of there as xfsprogs rely on definitions being in that header file. So
   * just define same functions here for quota purposes.
   */
  #define XFS_BB_SHIFT 9
  
  static inline u64 quota_bbtob(u64 blocks)
  {
  	return blocks << XFS_BB_SHIFT;
  }
  
  static inline u64 quota_btobb(u64 bytes)
  {
  	return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
  }
ad47ff330   Darrick J. Wong   quota: widen time...
511
512
513
514
515
516
517
  static inline s64 copy_from_xfs_dqblk_ts(const struct fs_disk_quota *d,
  		__s32 timer, __s8 timer_hi)
  {
  	if (d->d_fieldmask & FS_DQ_BIGTIME)
  		return (u32)timer | (s64)timer_hi << 32;
  	return timer;
  }
14bf61ffe   Jan Kara   quota: Switch ->g...
518
519
520
521
522
523
524
525
  static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
  {
  	dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
  	dst->d_spc_softlimit = quota_bbtob(src->d_blk_softlimit);
  	dst->d_ino_hardlimit = src->d_ino_hardlimit;
  	dst->d_ino_softlimit = src->d_ino_softlimit;
  	dst->d_space = quota_bbtob(src->d_bcount);
  	dst->d_ino_count = src->d_icount;
ad47ff330   Darrick J. Wong   quota: widen time...
526
527
528
529
  	dst->d_ino_timer = copy_from_xfs_dqblk_ts(src, src->d_itimer,
  						  src->d_itimer_hi);
  	dst->d_spc_timer = copy_from_xfs_dqblk_ts(src, src->d_btimer,
  						  src->d_btimer_hi);
14bf61ffe   Jan Kara   quota: Switch ->g...
530
531
532
533
534
  	dst->d_ino_warns = src->d_iwarns;
  	dst->d_spc_warns = src->d_bwarns;
  	dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
  	dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
  	dst->d_rt_space = quota_bbtob(src->d_rtbcount);
ad47ff330   Darrick J. Wong   quota: widen time...
535
536
  	dst->d_rt_spc_timer = copy_from_xfs_dqblk_ts(src, src->d_rtbtimer,
  						     src->d_rtbtimer_hi);
14bf61ffe   Jan Kara   quota: Switch ->g...
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  	dst->d_rt_spc_warns = src->d_rtbwarns;
  	dst->d_fieldmask = 0;
  	if (src->d_fieldmask & FS_DQ_ISOFT)
  		dst->d_fieldmask |= QC_INO_SOFT;
  	if (src->d_fieldmask & FS_DQ_IHARD)
  		dst->d_fieldmask |= QC_INO_HARD;
  	if (src->d_fieldmask & FS_DQ_BSOFT)
  		dst->d_fieldmask |= QC_SPC_SOFT;
  	if (src->d_fieldmask & FS_DQ_BHARD)
  		dst->d_fieldmask |= QC_SPC_HARD;
  	if (src->d_fieldmask & FS_DQ_RTBSOFT)
  		dst->d_fieldmask |= QC_RT_SPC_SOFT;
  	if (src->d_fieldmask & FS_DQ_RTBHARD)
  		dst->d_fieldmask |= QC_RT_SPC_HARD;
  	if (src->d_fieldmask & FS_DQ_BTIMER)
  		dst->d_fieldmask |= QC_SPC_TIMER;
  	if (src->d_fieldmask & FS_DQ_ITIMER)
  		dst->d_fieldmask |= QC_INO_TIMER;
  	if (src->d_fieldmask & FS_DQ_RTBTIMER)
  		dst->d_fieldmask |= QC_RT_SPC_TIMER;
  	if (src->d_fieldmask & FS_DQ_BWARNS)
  		dst->d_fieldmask |= QC_SPC_WARNS;
  	if (src->d_fieldmask & FS_DQ_IWARNS)
  		dst->d_fieldmask |= QC_INO_WARNS;
  	if (src->d_fieldmask & FS_DQ_RTBWARNS)
  		dst->d_fieldmask |= QC_RT_SPC_WARNS;
  	if (src->d_fieldmask & FS_DQ_BCOUNT)
  		dst->d_fieldmask |= QC_SPACE;
  	if (src->d_fieldmask & FS_DQ_ICOUNT)
  		dst->d_fieldmask |= QC_INO_COUNT;
  	if (src->d_fieldmask & FS_DQ_RTBCOUNT)
  		dst->d_fieldmask |= QC_RT_SPACE;
  }
c39fb53b4   Jan Kara   quota: Hook up Q_...
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  static void copy_qcinfo_from_xfs_dqblk(struct qc_info *dst,
  				       struct fs_disk_quota *src)
  {
  	memset(dst, 0, sizeof(*dst));
  	dst->i_spc_timelimit = src->d_btimer;
  	dst->i_ino_timelimit = src->d_itimer;
  	dst->i_rt_spc_timelimit = src->d_rtbtimer;
  	dst->i_ino_warnlimit = src->d_iwarns;
  	dst->i_spc_warnlimit = src->d_bwarns;
  	dst->i_rt_spc_warnlimit = src->d_rtbwarns;
  	if (src->d_fieldmask & FS_DQ_BWARNS)
  		dst->i_fieldmask |= QC_SPC_WARNS;
  	if (src->d_fieldmask & FS_DQ_IWARNS)
  		dst->i_fieldmask |= QC_INO_WARNS;
  	if (src->d_fieldmask & FS_DQ_RTBWARNS)
  		dst->i_fieldmask |= QC_RT_SPC_WARNS;
  	if (src->d_fieldmask & FS_DQ_BTIMER)
  		dst->i_fieldmask |= QC_SPC_TIMER;
  	if (src->d_fieldmask & FS_DQ_ITIMER)
  		dst->i_fieldmask |= QC_INO_TIMER;
  	if (src->d_fieldmask & FS_DQ_RTBTIMER)
  		dst->i_fieldmask |= QC_RT_SPC_TIMER;
  }
c411e5f66   Christoph Hellwig   quota: split do_q...
593
594
595
596
  static int quota_setxquota(struct super_block *sb, int type, qid_t id,
  			   void __user *addr)
  {
  	struct fs_disk_quota fdq;
14bf61ffe   Jan Kara   quota: Switch ->g...
597
  	struct qc_dqblk qdq;
74a8a1037   Eric W. Biederman   userns: Convert q...
598
  	struct kqid qid;
c411e5f66   Christoph Hellwig   quota: split do_q...
599
600
601
  
  	if (copy_from_user(&fdq, addr, sizeof(fdq)))
  		return -EFAULT;
c472b4327   Christoph Hellwig   quota: unify ->se...
602
  	if (!sb->s_qcop->set_dqblk)
f450d4fee   Christoph Hellwig   quota: clean up c...
603
  		return -ENOSYS;
74a8a1037   Eric W. Biederman   userns: Convert q...
604
  	qid = make_kqid(current_user_ns(), type, id);
d49d37624   Eric W. Biederman   quota: Ensure qid...
605
  	if (!qid_has_mapping(sb->s_user_ns, qid))
74a8a1037   Eric W. Biederman   userns: Convert q...
606
  		return -EINVAL;
c39fb53b4   Jan Kara   quota: Hook up Q_...
607
  	/* Are we actually setting timer / warning limits for all users? */
cfd4c70a1   Eric W. Biederman   quota: Handle quo...
608
  	if (from_kqid(sb->s_user_ns, qid) == 0 &&
c39fb53b4   Jan Kara   quota: Hook up Q_...
609
610
611
612
613
614
615
616
617
618
619
620
621
  	    fdq.d_fieldmask & (FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK)) {
  		struct qc_info qinfo;
  		int ret;
  
  		if (!sb->s_qcop->set_info)
  			return -EINVAL;
  		copy_qcinfo_from_xfs_dqblk(&qinfo, &fdq);
  		ret = sb->s_qcop->set_info(sb, type, &qinfo);
  		if (ret)
  			return ret;
  		/* These are already done */
  		fdq.d_fieldmask &= ~(FS_DQ_WARNS_MASK | FS_DQ_TIMER_MASK);
  	}
14bf61ffe   Jan Kara   quota: Switch ->g...
622
623
624
  	copy_from_xfs_dqblk(&qdq, &fdq);
  	return sb->s_qcop->set_dqblk(sb, qid, &qdq);
  }
ad47ff330   Darrick J. Wong   quota: widen time...
625
626
627
628
629
630
631
632
633
634
635
636
  static inline void copy_to_xfs_dqblk_ts(const struct fs_disk_quota *d,
  		__s32 *timer_lo, __s8 *timer_hi, s64 timer)
  {
  	*timer_lo = timer;
  	if (d->d_fieldmask & FS_DQ_BIGTIME)
  		*timer_hi = timer >> 32;
  }
  
  static inline bool want_bigtime(s64 timer)
  {
  	return timer > S32_MAX || timer < S32_MIN;
  }
14bf61ffe   Jan Kara   quota: Switch ->g...
637
638
639
640
  static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
  			      int type, qid_t id)
  {
  	memset(dst, 0, sizeof(*dst));
ad47ff330   Darrick J. Wong   quota: widen time...
641
642
643
  	if (want_bigtime(src->d_ino_timer) || want_bigtime(src->d_spc_timer) ||
  	    want_bigtime(src->d_rt_spc_timer))
  		dst->d_fieldmask |= FS_DQ_BIGTIME;
14bf61ffe   Jan Kara   quota: Switch ->g...
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  	dst->d_version = FS_DQUOT_VERSION;
  	dst->d_id = id;
  	if (type == USRQUOTA)
  		dst->d_flags = FS_USER_QUOTA;
  	else if (type == PRJQUOTA)
  		dst->d_flags = FS_PROJ_QUOTA;
  	else
  		dst->d_flags = FS_GROUP_QUOTA;
  	dst->d_blk_hardlimit = quota_btobb(src->d_spc_hardlimit);
  	dst->d_blk_softlimit = quota_btobb(src->d_spc_softlimit);
  	dst->d_ino_hardlimit = src->d_ino_hardlimit;
  	dst->d_ino_softlimit = src->d_ino_softlimit;
  	dst->d_bcount = quota_btobb(src->d_space);
  	dst->d_icount = src->d_ino_count;
ad47ff330   Darrick J. Wong   quota: widen time...
658
659
660
661
  	copy_to_xfs_dqblk_ts(dst, &dst->d_itimer, &dst->d_itimer_hi,
  			     src->d_ino_timer);
  	copy_to_xfs_dqblk_ts(dst, &dst->d_btimer, &dst->d_btimer_hi,
  			     src->d_spc_timer);
14bf61ffe   Jan Kara   quota: Switch ->g...
662
663
664
665
666
  	dst->d_iwarns = src->d_ino_warns;
  	dst->d_bwarns = src->d_spc_warns;
  	dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
  	dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
  	dst->d_rtbcount = quota_btobb(src->d_rt_space);
ad47ff330   Darrick J. Wong   quota: widen time...
667
668
  	copy_to_xfs_dqblk_ts(dst, &dst->d_rtbtimer, &dst->d_rtbtimer_hi,
  			     src->d_rt_spc_timer);
14bf61ffe   Jan Kara   quota: Switch ->g...
669
  	dst->d_rtbwarns = src->d_rt_spc_warns;
c411e5f66   Christoph Hellwig   quota: split do_q...
670
671
672
673
674
675
  }
  
  static int quota_getxquota(struct super_block *sb, int type, qid_t id,
  			   void __user *addr)
  {
  	struct fs_disk_quota fdq;
14bf61ffe   Jan Kara   quota: Switch ->g...
676
  	struct qc_dqblk qdq;
74a8a1037   Eric W. Biederman   userns: Convert q...
677
  	struct kqid qid;
c411e5f66   Christoph Hellwig   quota: split do_q...
678
  	int ret;
b9b2dd36c   Christoph Hellwig   quota: unify ->ge...
679
  	if (!sb->s_qcop->get_dqblk)
f450d4fee   Christoph Hellwig   quota: clean up c...
680
  		return -ENOSYS;
74a8a1037   Eric W. Biederman   userns: Convert q...
681
  	qid = make_kqid(current_user_ns(), type, id);
d49d37624   Eric W. Biederman   quota: Ensure qid...
682
  	if (!qid_has_mapping(sb->s_user_ns, qid))
74a8a1037   Eric W. Biederman   userns: Convert q...
683
  		return -EINVAL;
14bf61ffe   Jan Kara   quota: Switch ->g...
684
685
686
687
688
  	ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
  	if (ret)
  		return ret;
  	copy_to_xfs_dqblk(&fdq, &qdq, type, id);
  	if (copy_to_user(addr, &fdq, sizeof(fdq)))
c411e5f66   Christoph Hellwig   quota: split do_q...
689
690
691
  		return -EFAULT;
  	return ret;
  }
8b3752496   Eric Sandeen   quota: add new qu...
692
693
  /*
   * Return quota for next active quota >= this id, if any exists,
ba58148b6   Eric Sandeen   quota: Fixup comm...
694
   * otherwise return -ENOENT via ->get_nextdqblk.
8b3752496   Eric Sandeen   quota: add new qu...
695
696
697
698
699
700
701
702
703
704
705
706
707
   */
  static int quota_getnextxquota(struct super_block *sb, int type, qid_t id,
  			    void __user *addr)
  {
  	struct fs_disk_quota fdq;
  	struct qc_dqblk qdq;
  	struct kqid qid;
  	qid_t id_out;
  	int ret;
  
  	if (!sb->s_qcop->get_nextdqblk)
  		return -ENOSYS;
  	qid = make_kqid(current_user_ns(), type, id);
d49d37624   Eric W. Biederman   quota: Ensure qid...
708
  	if (!qid_has_mapping(sb->s_user_ns, qid))
8b3752496   Eric Sandeen   quota: add new qu...
709
710
711
712
713
714
715
716
717
718
  		return -EINVAL;
  	ret = sb->s_qcop->get_nextdqblk(sb, &qid, &qdq);
  	if (ret)
  		return ret;
  	id_out = from_kqid(current_user_ns(), qid);
  	copy_to_xfs_dqblk(&fdq, &qdq, type, id_out);
  	if (copy_to_user(addr, &fdq, sizeof(fdq)))
  		return -EFAULT;
  	return ret;
  }
9da93f9b7   Eric Sandeen   xfs: fix Q_XQUOTA...
719
720
721
722
723
724
725
726
727
728
  static int quota_rmxquota(struct super_block *sb, void __user *addr)
  {
  	__u32 flags;
  
  	if (copy_from_user(&flags, addr, sizeof(flags)))
  		return -EFAULT;
  	if (!sb->s_qcop->rm_xquota)
  		return -ENOSYS;
  	return sb->s_qcop->rm_xquota(sb, flags);
  }
c411e5f66   Christoph Hellwig   quota: split do_q...
729
730
  /* Copy parameters and call proper function */
  static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
8c54ca9c6   Al Viro   quota: constify s...
731
  		       void __user *addr, const struct path *path)
c411e5f66   Christoph Hellwig   quota: split do_q...
732
  {
c988afb5f   Christoph Hellwig   quota: simplify p...
733
  	int ret;
7b6924d94   Jeremy Cline   fs/quota: Fix spe...
734
  	type = array_index_nospec(type, MAXQUOTAS);
2c5f648aa   Jan Kara   quota: Allow each...
735
736
737
738
  	/*
  	 * Quota not supported on this fs? Check this before s_quota_types
  	 * since they needn't be set if quota is not supported at all.
  	 */
c988afb5f   Christoph Hellwig   quota: simplify p...
739
740
  	if (!sb->s_qcop)
  		return -ENOSYS;
2c5f648aa   Jan Kara   quota: Allow each...
741
742
  	if (!(sb->s_quota_types & (1 << type)))
  		return -EINVAL;
c988afb5f   Christoph Hellwig   quota: simplify p...
743
744
745
746
  
  	ret = check_quotactl_permission(sb, type, cmd, id);
  	if (ret < 0)
  		return ret;
c411e5f66   Christoph Hellwig   quota: split do_q...
747
748
  	switch (cmd) {
  	case Q_QUOTAON:
3218a3ec8   Eric Sandeen   quota: remove unu...
749
  		return quota_quotaon(sb, type, id, path);
c411e5f66   Christoph Hellwig   quota: split do_q...
750
  	case Q_QUOTAOFF:
d3b863248   Jan Kara   quota: Wire up ->...
751
  		return quota_quotaoff(sb, type);
c411e5f66   Christoph Hellwig   quota: split do_q...
752
753
754
755
756
757
758
759
  	case Q_GETFMT:
  		return quota_getfmt(sb, type, addr);
  	case Q_GETINFO:
  		return quota_getinfo(sb, type, addr);
  	case Q_SETINFO:
  		return quota_setinfo(sb, type, addr);
  	case Q_GETQUOTA:
  		return quota_getquota(sb, type, id, addr);
926132c02   Eric Sandeen   quota: add new qu...
760
761
  	case Q_GETNEXTQUOTA:
  		return quota_getnextquota(sb, type, id, addr);
c411e5f66   Christoph Hellwig   quota: split do_q...
762
763
764
  	case Q_SETQUOTA:
  		return quota_setquota(sb, type, id, addr);
  	case Q_SYNC:
6ae09575b   Christoph Hellwig   quota: special ca...
765
766
  		if (!sb->s_qcop->quota_sync)
  			return -ENOSYS;
ceed17236   Jan Kara   quota: Split dquo...
767
  		return sb->s_qcop->quota_sync(sb, type);
c411e5f66   Christoph Hellwig   quota: split do_q...
768
  	case Q_XQUOTAON:
38e478c44   Jan Kara   quota: Split ->se...
769
  		return quota_enable(sb, addr);
c411e5f66   Christoph Hellwig   quota: split do_q...
770
  	case Q_XQUOTAOFF:
38e478c44   Jan Kara   quota: Split ->se...
771
  		return quota_disable(sb, addr);
9da93f9b7   Eric Sandeen   xfs: fix Q_XQUOTA...
772
773
  	case Q_XQUOTARM:
  		return quota_rmxquota(sb, addr);
c411e5f66   Christoph Hellwig   quota: split do_q...
774
  	case Q_XGETQSTAT:
555b2c3da   Eric Sandeen   quota: honor quot...
775
  		return quota_getxstate(sb, type, addr);
af30cb446   Chandra Seetharaman   quota: Add a new ...
776
  	case Q_XGETQSTATV:
555b2c3da   Eric Sandeen   quota: honor quot...
777
  		return quota_getxstatev(sb, type, addr);
c411e5f66   Christoph Hellwig   quota: split do_q...
778
779
780
781
  	case Q_XSETQLIM:
  		return quota_setxquota(sb, type, id, addr);
  	case Q_XGETQUOTA:
  		return quota_getxquota(sb, type, id, addr);
8b3752496   Eric Sandeen   quota: add new qu...
782
783
  	case Q_XGETNEXTQUOTA:
  		return quota_getnextxquota(sb, type, id, addr);
c411e5f66   Christoph Hellwig   quota: split do_q...
784
  	case Q_XQUOTASYNC:
bc98a42c1   David Howells   VFS: Convert sb->...
785
  		if (sb_rdonly(sb))
8c4e4acd6   Christoph Hellwig   quota: clean up Q...
786
  			return -EROFS;
4b217ed9e   Christoph Hellwig   quota: make Q_XQU...
787
  		/* XFS quotas are fully coherent now, making this call a noop */
8c4e4acd6   Christoph Hellwig   quota: clean up Q...
788
  		return 0;
c411e5f66   Christoph Hellwig   quota: split do_q...
789
  	default:
f450d4fee   Christoph Hellwig   quota: clean up c...
790
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  }
56df12785   Lee Jones   quota: Use the pr...
793
  #ifdef CONFIG_BLOCK
dcdbed853   Jan Kara   quota: Fix deadlo...
794
795
796
  /* Return 1 if 'cmd' will block on frozen filesystem */
  static int quotactl_cmd_write(int cmd)
  {
ccf370e43   Jan Kara   quota: Forbid Q_G...
797
798
799
800
801
  	/*
  	 * We cannot allow Q_GETQUOTA and Q_GETNEXTQUOTA without write access
  	 * as dquot_acquire() may allocate space for new structure and OCFS2
  	 * needs to increment on-disk use count.
  	 */
dcdbed853   Jan Kara   quota: Fix deadlo...
802
803
804
805
806
  	switch (cmd) {
  	case Q_GETFMT:
  	case Q_GETINFO:
  	case Q_SYNC:
  	case Q_XGETQSTAT:
af30cb446   Chandra Seetharaman   quota: Add a new ...
807
  	case Q_XGETQSTATV:
dcdbed853   Jan Kara   quota: Fix deadlo...
808
  	case Q_XGETQUOTA:
8b3752496   Eric Sandeen   quota: add new qu...
809
  	case Q_XGETNEXTQUOTA:
dcdbed853   Jan Kara   quota: Fix deadlo...
810
811
812
813
814
  	case Q_XQUOTASYNC:
  		return 0;
  	}
  	return 1;
  }
56df12785   Lee Jones   quota: Use the pr...
815
  #endif /* CONFIG_BLOCK */
7d6cd73d3   Jan Kara   quota: Hold s_umo...
816
817
818
  /* Return true if quotactl command is manipulating quota on/off state */
  static bool quotactl_cmd_onoff(int cmd)
  {
41c4f85cd   Javier Barrio   quota: Lock s_umo...
819
820
  	return (cmd == Q_QUOTAON) || (cmd == Q_QUOTAOFF) ||
  		 (cmd == Q_XQUOTAON) || (cmd == Q_XQUOTAOFF);
7d6cd73d3   Jan Kara   quota: Hold s_umo...
821
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  /*
9361401eb   David Howells   [PATCH] BLOCK: Ma...
823
824
825
   * look up a superblock on which quota ops will be performed
   * - use the name of a block device to find the superblock thereon
   */
dcdbed853   Jan Kara   quota: Fix deadlo...
826
  static struct super_block *quotactl_block(const char __user *special, int cmd)
9361401eb   David Howells   [PATCH] BLOCK: Ma...
827
828
829
830
  {
  #ifdef CONFIG_BLOCK
  	struct block_device *bdev;
  	struct super_block *sb;
91a27b2a7   Jeff Layton   vfs: define struc...
831
  	struct filename *tmp = getname(special);
9361401eb   David Howells   [PATCH] BLOCK: Ma...
832
833
  
  	if (IS_ERR(tmp))
e231c2ee6   David Howells   Convert ERR_PTR(P...
834
  		return ERR_CAST(tmp);
91a27b2a7   Jeff Layton   vfs: define struc...
835
  	bdev = lookup_bdev(tmp->name);
9361401eb   David Howells   [PATCH] BLOCK: Ma...
836
837
  	putname(tmp);
  	if (IS_ERR(bdev))
e231c2ee6   David Howells   Convert ERR_PTR(P...
838
  		return ERR_CAST(bdev);
7d6cd73d3   Jan Kara   quota: Hold s_umo...
839
840
841
  	if (quotactl_cmd_onoff(cmd))
  		sb = get_super_exclusive_thawed(bdev);
  	else if (quotactl_cmd_write(cmd))
dcdbed853   Jan Kara   quota: Fix deadlo...
842
843
844
  		sb = get_super_thawed(bdev);
  	else
  		sb = get_super(bdev);
9361401eb   David Howells   [PATCH] BLOCK: Ma...
845
846
847
848
849
850
851
852
853
854
855
  	bdput(bdev);
  	if (!sb)
  		return ERR_PTR(-ENODEV);
  
  	return sb;
  #else
  	return ERR_PTR(-ENODEV);
  #endif
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
858
859
860
   * This is the system call interface. This communicates with
   * the user-level programs. Currently this only supports diskquota
   * calls. Maybe we need to add the process quotas etc. in the future,
   * but we probably should use rlimits for that.
   */
80bdad3d7   Christoph Hellwig   quota: simplify t...
861
862
  SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
  		qid_t, id, void __user *, addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
865
  {
  	uint cmds, type;
  	struct super_block *sb = NULL;
f00c9e44a   Jan Kara   quota: Fix deadlo...
866
  	struct path path, *pathp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
869
870
  	int ret;
  
  	cmds = cmd >> SUBCMDSHIFT;
  	type = cmd & SUBCMDMASK;
a6810312b   Chengguang Xu   quota: check quot...
871
872
  	if (type >= MAXQUOTAS)
  		return -EINVAL;
6ae09575b   Christoph Hellwig   quota: special ca...
873
874
875
876
877
878
879
880
881
  	/*
  	 * As a special case Q_SYNC can be called without a specific device.
  	 * It will iterate all superblocks that have quota enabled and call
  	 * the sync action on each of them.
  	 */
  	if (!special) {
  		if (cmds == Q_SYNC)
  			return quota_sync_all(type);
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
  	}
f00c9e44a   Jan Kara   quota: Fix deadlo...
883
884
885
886
887
888
  	/*
  	 * Path for quotaon has to be resolved before grabbing superblock
  	 * because that gets s_umount sem which is also possibly needed by path
  	 * resolution (think about autofs) and thus deadlocks could arise.
  	 */
  	if (cmds == Q_QUOTAON) {
815d405ce   Trond Myklebust   VFS: Fix the rema...
889
  		ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
f00c9e44a   Jan Kara   quota: Fix deadlo...
890
891
892
893
894
  		if (ret)
  			pathp = ERR_PTR(ret);
  		else
  			pathp = &path;
  	}
dcdbed853   Jan Kara   quota: Fix deadlo...
895
  	sb = quotactl_block(special, cmds);
0aaa61886   Jan Kara   quota: Drop path ...
896
897
898
899
  	if (IS_ERR(sb)) {
  		ret = PTR_ERR(sb);
  		goto out;
  	}
6ae09575b   Christoph Hellwig   quota: special ca...
900

f00c9e44a   Jan Kara   quota: Fix deadlo...
901
  	ret = do_quotactl(sb, type, cmds, id, addr, pathp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902

7d6cd73d3   Jan Kara   quota: Hold s_umo...
903
904
905
906
  	if (!quotactl_cmd_onoff(cmds))
  		drop_super(sb);
  	else
  		drop_super_exclusive(sb);
0aaa61886   Jan Kara   quota: Drop path ...
907
  out:
f00c9e44a   Jan Kara   quota: Fix deadlo...
908
909
  	if (pathp && !IS_ERR(pathp))
  		path_put(pathp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
  	return ret;
  }