]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Jan Kara <jack@suse.cz> |
2 | References: fate#302681 | |
3 | Subject: [PATCH 05/28] quota: Allow to separately enable quota accounting and enforcing limits | |
4 | Patch-mainline: 2.6.29? | |
5 | ||
6 | Split DQUOT_USR_ENABLED (and DQUOT_GRP_ENABLED) into DQUOT_USR_USAGE_ENABLED | |
7 | and DQUOT_USR_LIMITS_ENABLED. This way we are able to separately enable / | |
8 | disable whether we should: | |
9 | 1) ignore quotas completely | |
10 | 2) just keep uptodate information about usage | |
11 | 3) actually enforce quota limits | |
12 | ||
13 | This is going to be useful when quota is treated as filesystem metadata - we | |
14 | then want to keep quota information uptodate all the time and just enable / | |
15 | disable limits enforcement. | |
16 | ||
17 | Signed-off-by: Jan Kara <jack@suse.cz> | |
18 | --- | |
19 | fs/dquot.c | 222 ++++++++++++++++++++++++++++----------------- | |
20 | fs/quota.c | 8 +- | |
21 | include/linux/quota.h | 30 ++++++- | |
22 | include/linux/quotaops.h | 86 ++++++++++++++---- | |
23 | 4 files changed, 234 insertions(+), 112 deletions(-) | |
24 | ||
25 | diff --git a/fs/dquot.c b/fs/dquot.c | |
26 | index aea7bf9..bdfae7d 100644 | |
27 | --- a/fs/dquot.c | |
28 | +++ b/fs/dquot.c | |
29 | @@ -489,7 +489,7 @@ int vfs_quota_sync(struct super_block *sb, int type) | |
30 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | |
31 | if (type != -1 && cnt != type) | |
32 | continue; | |
33 | - if (!sb_has_quota_enabled(sb, cnt)) | |
34 | + if (!sb_has_quota_active(sb, cnt)) | |
35 | continue; | |
36 | spin_lock(&dq_list_lock); | |
37 | dirty = &dqopt->info[cnt].dqi_dirty_list; | |
38 | @@ -514,8 +514,8 @@ int vfs_quota_sync(struct super_block *sb, int type) | |
39 | } | |
40 | ||
41 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) | |
42 | - if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) | |
43 | - && info_dirty(&dqopt->info[cnt])) | |
44 | + if ((cnt == type || type == -1) && sb_has_quota_active(sb, cnt) | |
45 | + && info_dirty(&dqopt->info[cnt])) | |
46 | sb->dq_op->write_info(sb, cnt); | |
47 | spin_lock(&dq_list_lock); | |
48 | dqstats.syncs++; | |
49 | @@ -594,7 +594,7 @@ we_slept: | |
50 | /* We have more than one user... nothing to do */ | |
51 | atomic_dec(&dquot->dq_count); | |
52 | /* Releasing dquot during quotaoff phase? */ | |
53 | - if (!sb_has_quota_enabled(dquot->dq_sb, dquot->dq_type) && | |
54 | + if (!sb_has_quota_active(dquot->dq_sb, dquot->dq_type) && | |
55 | atomic_read(&dquot->dq_count) == 1) | |
56 | wake_up(&dquot->dq_wait_unused); | |
57 | spin_unlock(&dq_list_lock); | |
58 | @@ -668,7 +668,7 @@ static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) | |
59 | unsigned int hashent = hashfn(sb, id, type); | |
60 | struct dquot *dquot, *empty = NODQUOT; | |
61 | ||
62 | - if (!sb_has_quota_enabled(sb, type)) | |
63 | + if (!sb_has_quota_active(sb, type)) | |
64 | return NODQUOT; | |
65 | we_slept: | |
66 | spin_lock(&dq_list_lock); | |
67 | @@ -1041,7 +1041,8 @@ static inline char ignore_hardlimit(struct dquot *dquot) | |
68 | static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) | |
69 | { | |
70 | *warntype = QUOTA_NL_NOWARN; | |
71 | - if (test_bit(DQ_FAKE_B, &dquot->dq_flags)) | |
72 | + if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || | |
73 | + test_bit(DQ_FAKE_B, &dquot->dq_flags)) | |
74 | return QUOTA_OK; | |
75 | ||
76 | if (dquot->dq_dqb.dqb_ihardlimit && | |
77 | @@ -1073,7 +1074,8 @@ static int check_idq(struct dquot *dquot, qsize_t inodes, char *warntype) | |
78 | static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype) | |
79 | { | |
80 | *warntype = QUOTA_NL_NOWARN; | |
81 | - if (test_bit(DQ_FAKE_B, &dquot->dq_flags)) | |
82 | + if (!sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type) || | |
83 | + test_bit(DQ_FAKE_B, &dquot->dq_flags)) | |
84 | return QUOTA_OK; | |
85 | ||
86 | if (dquot->dq_dqb.dqb_bhardlimit && | |
87 | @@ -1114,7 +1116,8 @@ static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *war | |
88 | static int info_idq_free(struct dquot *dquot, qsize_t inodes) | |
89 | { | |
90 | if (test_bit(DQ_FAKE_B, &dquot->dq_flags) || | |
91 | - dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit) | |
92 | + dquot->dq_dqb.dqb_curinodes <= dquot->dq_dqb.dqb_isoftlimit || | |
93 | + !sb_has_quota_limits_enabled(dquot->dq_sb, dquot->dq_type)) | |
94 | return QUOTA_NL_NOWARN; | |
95 | ||
96 | if (dquot->dq_dqb.dqb_curinodes - inodes <= dquot->dq_dqb.dqb_isoftlimit) | |
97 | @@ -1508,7 +1511,7 @@ warn_put_all: | |
98 | /* Wrapper for transferring ownership of an inode */ | |
99 | int vfs_dq_transfer(struct inode *inode, struct iattr *iattr) | |
100 | { | |
101 | - if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) { | |
102 | + if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) { | |
103 | vfs_dq_init(inode); | |
104 | if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) | |
105 | return 1; | |
106 | @@ -1549,53 +1552,22 @@ struct dquot_operations dquot_operations = { | |
107 | .write_info = dquot_commit_info | |
108 | }; | |
109 | ||
110 | -static inline void set_enable_flags(struct quota_info *dqopt, int type) | |
111 | -{ | |
112 | - switch (type) { | |
113 | - case USRQUOTA: | |
114 | - dqopt->flags |= DQUOT_USR_ENABLED; | |
115 | - dqopt->flags &= ~DQUOT_USR_SUSPENDED; | |
116 | - break; | |
117 | - case GRPQUOTA: | |
118 | - dqopt->flags |= DQUOT_GRP_ENABLED; | |
119 | - dqopt->flags &= ~DQUOT_GRP_SUSPENDED; | |
120 | - break; | |
121 | - } | |
122 | -} | |
123 | - | |
124 | -static inline void reset_enable_flags(struct quota_info *dqopt, int type, | |
125 | - int remount) | |
126 | -{ | |
127 | - switch (type) { | |
128 | - case USRQUOTA: | |
129 | - if (remount) | |
130 | - dqopt->flags |= DQUOT_USR_SUSPENDED; | |
131 | - else { | |
132 | - dqopt->flags &= ~DQUOT_USR_ENABLED; | |
133 | - dqopt->flags &= ~DQUOT_USR_SUSPENDED; | |
134 | - } | |
135 | - break; | |
136 | - case GRPQUOTA: | |
137 | - if (remount) | |
138 | - dqopt->flags |= DQUOT_GRP_SUSPENDED; | |
139 | - else { | |
140 | - dqopt->flags &= ~DQUOT_GRP_ENABLED; | |
141 | - dqopt->flags &= ~DQUOT_GRP_SUSPENDED; | |
142 | - } | |
143 | - break; | |
144 | - } | |
145 | -} | |
146 | - | |
147 | - | |
148 | /* | |
149 | * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) | |
150 | */ | |
151 | -int vfs_quota_off(struct super_block *sb, int type, int remount) | |
152 | +int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags) | |
153 | { | |
154 | int cnt, ret = 0; | |
155 | struct quota_info *dqopt = sb_dqopt(sb); | |
156 | struct inode *toputinode[MAXQUOTAS]; | |
157 | ||
158 | + /* Cannot turn off usage accounting without turning off limits, or | |
159 | + * suspend quotas and simultaneously turn quotas off. */ | |
160 | + if ((flags & DQUOT_USAGE_ENABLED && !(flags & DQUOT_LIMITS_ENABLED)) | |
161 | + || (flags & DQUOT_SUSPENDED && flags & (DQUOT_LIMITS_ENABLED | | |
162 | + DQUOT_USAGE_ENABLED))) | |
163 | + return -EINVAL; | |
164 | + | |
165 | /* We need to serialize quota_off() for device */ | |
166 | mutex_lock(&dqopt->dqonoff_mutex); | |
167 | ||
168 | @@ -1604,7 +1576,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) | |
169 | * sometimes we are called when fill_super() failed and calling | |
170 | * sync_fs() in such cases does no good. | |
171 | */ | |
172 | - if (!sb_any_quota_enabled(sb) && !sb_any_quota_suspended(sb)) { | |
173 | + if (!sb_any_quota_loaded(sb)) { | |
174 | mutex_unlock(&dqopt->dqonoff_mutex); | |
175 | return 0; | |
176 | } | |
177 | @@ -1612,17 +1584,28 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) | |
178 | toputinode[cnt] = NULL; | |
179 | if (type != -1 && cnt != type) | |
180 | continue; | |
181 | - /* If we keep inodes of quota files after remount and quotaoff | |
182 | - * is called, drop kept inodes. */ | |
183 | - if (!remount && sb_has_quota_suspended(sb, cnt)) { | |
184 | - iput(dqopt->files[cnt]); | |
185 | - dqopt->files[cnt] = NULL; | |
186 | - reset_enable_flags(dqopt, cnt, 0); | |
187 | + if (!sb_has_quota_loaded(sb, cnt)) | |
188 | continue; | |
189 | + | |
190 | + if (flags & DQUOT_SUSPENDED) { | |
191 | + dqopt->flags |= | |
192 | + dquot_state_flag(DQUOT_SUSPENDED, cnt); | |
193 | + } else { | |
194 | + dqopt->flags &= ~dquot_state_flag(flags, cnt); | |
195 | + /* Turning off suspended quotas? */ | |
196 | + if (!sb_has_quota_loaded(sb, cnt) && | |
197 | + sb_has_quota_suspended(sb, cnt)) { | |
198 | + dqopt->flags &= ~dquot_state_flag( | |
199 | + DQUOT_SUSPENDED, cnt); | |
200 | + iput(dqopt->files[cnt]); | |
201 | + dqopt->files[cnt] = NULL; | |
202 | + continue; | |
203 | + } | |
204 | } | |
205 | - if (!sb_has_quota_enabled(sb, cnt)) | |
206 | + | |
207 | + /* We still have to keep quota loaded? */ | |
208 | + if (sb_has_quota_loaded(sb, cnt) && !(flags & DQUOT_SUSPENDED)) | |
209 | continue; | |
210 | - reset_enable_flags(dqopt, cnt, remount); | |
211 | ||
212 | /* Note: these are blocking operations */ | |
213 | drop_dquot_ref(sb, cnt); | |
214 | @@ -1638,7 +1621,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) | |
215 | put_quota_format(dqopt->info[cnt].dqi_format); | |
216 | ||
217 | toputinode[cnt] = dqopt->files[cnt]; | |
218 | - if (!remount) | |
219 | + if (!sb_has_quota_loaded(sb, cnt)) | |
220 | dqopt->files[cnt] = NULL; | |
221 | dqopt->info[cnt].dqi_flags = 0; | |
222 | dqopt->info[cnt].dqi_igrace = 0; | |
223 | @@ -1661,7 +1644,7 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) | |
224 | mutex_lock(&dqopt->dqonoff_mutex); | |
225 | /* If quota was reenabled in the meantime, we have | |
226 | * nothing to do */ | |
227 | - if (!sb_has_quota_enabled(sb, cnt)) { | |
228 | + if (!sb_has_quota_loaded(sb, cnt)) { | |
229 | mutex_lock_nested(&toputinode[cnt]->i_mutex, I_MUTEX_QUOTA); | |
230 | toputinode[cnt]->i_flags &= ~(S_IMMUTABLE | | |
231 | S_NOATIME | S_NOQUOTA); | |
232 | @@ -1671,10 +1654,13 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) | |
233 | } | |
234 | mutex_unlock(&dqopt->dqonoff_mutex); | |
235 | /* On remount RO, we keep the inode pointer so that we | |
236 | - * can reenable quota on the subsequent remount RW. | |
237 | - * But we have better not keep inode pointer when there | |
238 | - * is pending delete on the quota file... */ | |
239 | - if (!remount) | |
240 | + * can reenable quota on the subsequent remount RW. We | |
241 | + * have to check 'flags' variable and not use sb_has_ | |
242 | + * function because another quotaon / quotaoff could | |
243 | + * change global state before we got here. We refuse | |
244 | + * to suspend quotas when there is pending delete on | |
245 | + * the quota file... */ | |
246 | + if (!(flags & DQUOT_SUSPENDED)) | |
247 | iput(toputinode[cnt]); | |
248 | else if (!toputinode[cnt]->i_nlink) | |
249 | ret = -EBUSY; | |
250 | @@ -1684,12 +1670,22 @@ int vfs_quota_off(struct super_block *sb, int type, int remount) | |
251 | return ret; | |
252 | } | |
253 | ||
254 | +int vfs_quota_off(struct super_block *sb, int type, int remount) | |
255 | +{ | |
256 | + return vfs_quota_disable(sb, type, remount ? DQUOT_SUSPENDED : | |
257 | + (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED)); | |
258 | +} | |
259 | + | |
260 | /* | |
261 | * Turn quotas on on a device | |
262 | */ | |
263 | ||
264 | -/* Helper function when we already have the inode */ | |
265 | -static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) | |
266 | +/* | |
267 | + * Helper function to turn quotas on when we already have the inode of | |
268 | + * quota file and no quota information is loaded. | |
269 | + */ | |
270 | +static int vfs_load_quota_inode(struct inode *inode, int type, int format_id, | |
271 | + unsigned int flags) | |
272 | { | |
273 | struct quota_format_type *fmt = find_quota_format(format_id); | |
274 | struct super_block *sb = inode->i_sb; | |
275 | @@ -1711,6 +1707,11 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) | |
276 | error = -EINVAL; | |
277 | goto out_fmt; | |
278 | } | |
279 | + /* Usage always has to be set... */ | |
280 | + if (!(flags & DQUOT_USAGE_ENABLED)) { | |
281 | + error = -EINVAL; | |
282 | + goto out_fmt; | |
283 | + } | |
284 | ||
285 | /* As we bypass the pagecache we must now flush the inode so that | |
286 | * we see all the changes from userspace... */ | |
287 | @@ -1719,8 +1720,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) | |
288 | invalidate_bdev(sb->s_bdev); | |
289 | mutex_lock(&inode->i_mutex); | |
290 | mutex_lock(&dqopt->dqonoff_mutex); | |
291 | - if (sb_has_quota_enabled(sb, type) || | |
292 | - sb_has_quota_suspended(sb, type)) { | |
293 | + if (sb_has_quota_loaded(sb, type)) { | |
294 | error = -EBUSY; | |
295 | goto out_lock; | |
296 | } | |
297 | @@ -1752,7 +1752,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id) | |
298 | } | |
299 | mutex_unlock(&dqopt->dqio_mutex); | |
300 | mutex_unlock(&inode->i_mutex); | |
301 | - set_enable_flags(dqopt, type); | |
302 | + dqopt->flags |= dquot_state_flag(flags, type); | |
303 | ||
304 | add_dquot_ref(sb, type); | |
305 | mutex_unlock(&dqopt->dqonoff_mutex); | |
306 | @@ -1785,20 +1785,23 @@ static int vfs_quota_on_remount(struct super_block *sb, int type) | |
307 | struct quota_info *dqopt = sb_dqopt(sb); | |
308 | struct inode *inode; | |
309 | int ret; | |
310 | + unsigned int flags; | |
311 | ||
312 | mutex_lock(&dqopt->dqonoff_mutex); | |
313 | if (!sb_has_quota_suspended(sb, type)) { | |
314 | mutex_unlock(&dqopt->dqonoff_mutex); | |
315 | return 0; | |
316 | } | |
317 | - BUG_ON(sb_has_quota_enabled(sb, type)); | |
318 | - | |
319 | inode = dqopt->files[type]; | |
320 | dqopt->files[type] = NULL; | |
321 | - reset_enable_flags(dqopt, type, 0); | |
322 | + flags = dqopt->flags & dquot_state_flag(DQUOT_USAGE_ENABLED | | |
323 | + DQUOT_LIMITS_ENABLED, type); | |
324 | + dqopt->flags &= ~dquot_state_flag(DQUOT_STATE_FLAGS, type); | |
325 | mutex_unlock(&dqopt->dqonoff_mutex); | |
326 | ||
327 | - ret = vfs_quota_on_inode(inode, type, dqopt->info[type].dqi_fmt_id); | |
328 | + flags = dquot_generic_flag(flags, type); | |
329 | + ret = vfs_load_quota_inode(inode, type, dqopt->info[type].dqi_fmt_id, | |
330 | + flags); | |
331 | iput(inode); | |
332 | ||
333 | return ret; | |
334 | @@ -1814,12 +1817,12 @@ int vfs_quota_on_path(struct super_block *sb, int type, int format_id, | |
335 | if (path->mnt->mnt_sb != sb) | |
336 | error = -EXDEV; | |
337 | else | |
338 | - error = vfs_quota_on_inode(path->dentry->d_inode, type, | |
339 | - format_id); | |
340 | + error = vfs_load_quota_inode(path->dentry->d_inode, type, | |
341 | + format_id, DQUOT_USAGE_ENABLED | | |
342 | + DQUOT_LIMITS_ENABLED); | |
343 | return error; | |
344 | } | |
345 | ||
346 | -/* Actual function called from quotactl() */ | |
347 | int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, | |
348 | int remount) | |
349 | { | |
350 | @@ -1838,6 +1841,50 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path, | |
351 | } | |
352 | ||
353 | /* | |
354 | + * More powerful function for turning on quotas allowing setting | |
355 | + * of individual quota flags | |
356 | + */ | |
357 | +int vfs_quota_enable(struct inode *inode, int type, int format_id, | |
358 | + unsigned int flags) | |
359 | +{ | |
360 | + int ret = 0; | |
361 | + struct super_block *sb = inode->i_sb; | |
362 | + struct quota_info *dqopt = sb_dqopt(sb); | |
363 | + | |
364 | + /* Just unsuspend quotas? */ | |
365 | + if (flags & DQUOT_SUSPENDED) | |
366 | + return vfs_quota_on_remount(sb, type); | |
367 | + if (!flags) | |
368 | + return 0; | |
369 | + /* Just updating flags needed? */ | |
370 | + if (sb_has_quota_loaded(sb, type)) { | |
371 | + mutex_lock(&dqopt->dqonoff_mutex); | |
372 | + /* Now do a reliable test... */ | |
373 | + if (!sb_has_quota_loaded(sb, type)) { | |
374 | + mutex_unlock(&dqopt->dqonoff_mutex); | |
375 | + goto load_quota; | |
376 | + } | |
377 | + if (flags & DQUOT_USAGE_ENABLED && | |
378 | + sb_has_quota_usage_enabled(sb, type)) { | |
379 | + ret = -EBUSY; | |
380 | + goto out_lock; | |
381 | + } | |
382 | + if (flags & DQUOT_LIMITS_ENABLED && | |
383 | + sb_has_quota_limits_enabled(sb, type)) { | |
384 | + ret = -EBUSY; | |
385 | + goto out_lock; | |
386 | + } | |
387 | + sb_dqopt(sb)->flags |= dquot_state_flag(flags, type); | |
388 | +out_lock: | |
389 | + mutex_unlock(&dqopt->dqonoff_mutex); | |
390 | + return ret; | |
391 | + } | |
392 | + | |
393 | +load_quota: | |
394 | + return vfs_load_quota_inode(inode, type, format_id, flags); | |
395 | +} | |
396 | + | |
397 | +/* | |
398 | * This function is used when filesystem needs to initialize quotas | |
399 | * during mount time. | |
400 | */ | |
401 | @@ -1858,7 +1905,8 @@ int vfs_quota_on_mount(struct super_block *sb, char *qf_name, | |
402 | ||
403 | error = security_quota_on(dentry); | |
404 | if (!error) | |
405 | - error = vfs_quota_on_inode(dentry->d_inode, type, format_id); | |
406 | + error = vfs_load_quota_inode(dentry->d_inode, type, format_id, | |
407 | + DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); | |
408 | ||
409 | out: | |
410 | dput(dentry); | |
411 | @@ -1995,12 +2043,14 @@ int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d | |
412 | int rc; | |
413 | ||
414 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); | |
415 | - if (!(dquot = dqget(sb, id, type))) { | |
416 | - mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | |
417 | - return -ESRCH; | |
418 | + dquot = dqget(sb, id, type); | |
419 | + if (!dquot) { | |
420 | + rc = -ESRCH; | |
421 | + goto out; | |
422 | } | |
423 | rc = do_set_dqblk(dquot, di); | |
424 | dqput(dquot); | |
425 | +out: | |
426 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | |
427 | return rc; | |
428 | } | |
429 | @@ -2011,7 +2061,7 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | |
430 | struct mem_dqinfo *mi; | |
431 | ||
432 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); | |
433 | - if (!sb_has_quota_enabled(sb, type)) { | |
434 | + if (!sb_has_quota_active(sb, type)) { | |
435 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | |
436 | return -ESRCH; | |
437 | } | |
438 | @@ -2030,11 +2080,12 @@ int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | |
439 | int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | |
440 | { | |
441 | struct mem_dqinfo *mi; | |
442 | + int err = 0; | |
443 | ||
444 | mutex_lock(&sb_dqopt(sb)->dqonoff_mutex); | |
445 | - if (!sb_has_quota_enabled(sb, type)) { | |
446 | - mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | |
447 | - return -ESRCH; | |
448 | + if (!sb_has_quota_active(sb, type)) { | |
449 | + err = -ESRCH; | |
450 | + goto out; | |
451 | } | |
452 | mi = sb_dqopt(sb)->info + type; | |
453 | spin_lock(&dq_data_lock); | |
454 | @@ -2048,8 +2099,9 @@ int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) | |
455 | mark_info_dirty(sb, type); | |
456 | /* Force write to disk */ | |
457 | sb->dq_op->write_info(sb, type); | |
458 | +out: | |
459 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | |
460 | - return 0; | |
461 | + return err; | |
462 | } | |
463 | ||
464 | struct quotactl_ops vfs_quotactl_ops = { | |
465 | @@ -2211,9 +2263,11 @@ EXPORT_SYMBOL(register_quota_format); | |
466 | EXPORT_SYMBOL(unregister_quota_format); | |
467 | EXPORT_SYMBOL(dqstats); | |
468 | EXPORT_SYMBOL(dq_data_lock); | |
469 | +EXPORT_SYMBOL(vfs_quota_enable); | |
470 | EXPORT_SYMBOL(vfs_quota_on); | |
471 | EXPORT_SYMBOL(vfs_quota_on_path); | |
472 | EXPORT_SYMBOL(vfs_quota_on_mount); | |
473 | +EXPORT_SYMBOL(vfs_quota_disable); | |
474 | EXPORT_SYMBOL(vfs_quota_off); | |
475 | EXPORT_SYMBOL(vfs_quota_sync); | |
476 | EXPORT_SYMBOL(vfs_get_dqinfo); | |
477 | diff --git a/fs/quota.c b/fs/quota.c | |
478 | index 7f4386e..a8026f1 100644 | |
479 | --- a/fs/quota.c | |
480 | +++ b/fs/quota.c | |
481 | @@ -73,7 +73,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid | |
482 | case Q_SETQUOTA: | |
483 | case Q_GETQUOTA: | |
484 | /* This is just informative test so we are satisfied without a lock */ | |
485 | - if (!sb_has_quota_enabled(sb, type)) | |
486 | + if (!sb_has_quota_active(sb, type)) | |
487 | return -ESRCH; | |
488 | } | |
489 | ||
490 | @@ -175,7 +175,7 @@ static void quota_sync_sb(struct super_block *sb, int type) | |
491 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | |
492 | if (type != -1 && cnt != type) | |
493 | continue; | |
494 | - if (!sb_has_quota_enabled(sb, cnt)) | |
495 | + if (!sb_has_quota_active(sb, cnt)) | |
496 | continue; | |
497 | mutex_lock_nested(&sb_dqopt(sb)->files[cnt]->i_mutex, I_MUTEX_QUOTA); | |
498 | truncate_inode_pages(&sb_dqopt(sb)->files[cnt]->i_data, 0); | |
499 | @@ -201,7 +201,7 @@ restart: | |
500 | for (cnt = 0; cnt < MAXQUOTAS; cnt++) { | |
501 | if (type != -1 && type != cnt) | |
502 | continue; | |
503 | - if (!sb_has_quota_enabled(sb, cnt)) | |
504 | + if (!sb_has_quota_active(sb, cnt)) | |
505 | continue; | |
506 | if (!info_dirty(&sb_dqopt(sb)->info[cnt]) && | |
507 | list_empty(&sb_dqopt(sb)->info[cnt].dqi_dirty_list)) | |
508 | @@ -245,7 +245,7 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void | |
509 | __u32 fmt; | |
510 | ||
511 | down_read(&sb_dqopt(sb)->dqptr_sem); | |
512 | - if (!sb_has_quota_enabled(sb, type)) { | |
513 | + if (!sb_has_quota_active(sb, type)) { | |
514 | up_read(&sb_dqopt(sb)->dqptr_sem); | |
515 | return -ESRCH; | |
516 | } | |
517 | diff --git a/include/linux/quota.h b/include/linux/quota.h | |
518 | index 5167786..0e4b550 100644 | |
519 | --- a/include/linux/quota.h | |
520 | +++ b/include/linux/quota.h | |
521 | @@ -320,12 +320,34 @@ struct quota_format_type { | |
522 | struct quota_format_type *qf_next; | |
523 | }; | |
524 | ||
525 | -#define DQUOT_USR_ENABLED 0x01 /* User diskquotas enabled */ | |
526 | -#define DQUOT_GRP_ENABLED 0x02 /* Group diskquotas enabled */ | |
527 | -#define DQUOT_USR_SUSPENDED 0x04 /* User diskquotas are off, but | |
528 | +/* Quota state flags - they actually come in two flavors - for users and groups */ | |
529 | +enum { | |
530 | + _DQUOT_USAGE_ENABLED = 0, /* Track disk usage for users */ | |
531 | + _DQUOT_LIMITS_ENABLED, /* Enforce quota limits for users */ | |
532 | + _DQUOT_SUSPENDED, /* User diskquotas are off, but | |
533 | * we have necessary info in | |
534 | * memory to turn them on */ | |
535 | -#define DQUOT_GRP_SUSPENDED 0x08 /* The same for group quotas */ | |
536 | + _DQUOT_STATE_FLAGS | |
537 | +}; | |
538 | +#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED) | |
539 | +#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED) | |
540 | +#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED) | |
541 | +#define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ | |
542 | + DQUOT_SUSPENDED) | |
543 | + | |
544 | +static inline unsigned int dquot_state_flag(unsigned int flags, int type) | |
545 | +{ | |
546 | + if (type == USRQUOTA) | |
547 | + return flags; | |
548 | + return flags << _DQUOT_STATE_FLAGS; | |
549 | +} | |
550 | + | |
551 | +static inline unsigned int dquot_generic_flag(unsigned int flags, int type) | |
552 | +{ | |
553 | + if (type == USRQUOTA) | |
554 | + return flags; | |
555 | + return flags >> _DQUOT_STATE_FLAGS; | |
556 | +} | |
557 | ||
558 | struct quota_info { | |
559 | unsigned int flags; /* Flags for diskquotas on this device */ | |
560 | diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h | |
561 | index 12363cc..f7dcc30 100644 | |
562 | --- a/include/linux/quotaops.h | |
563 | +++ b/include/linux/quotaops.h | |
564 | @@ -43,11 +43,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot); | |
565 | ||
566 | int vfs_quota_on(struct super_block *sb, int type, int format_id, | |
567 | char *path, int remount); | |
568 | +int vfs_quota_enable(struct inode *inode, int type, int format_id, | |
569 | + unsigned int flags); | |
570 | int vfs_quota_on_path(struct super_block *sb, int type, int format_id, | |
571 | struct path *path); | |
572 | int vfs_quota_on_mount(struct super_block *sb, char *qf_name, | |
573 | int format_id, int type); | |
574 | int vfs_quota_off(struct super_block *sb, int type, int remount); | |
575 | +int vfs_quota_disable(struct super_block *sb, int type, unsigned int flags); | |
576 | int vfs_quota_sync(struct super_block *sb, int type); | |
577 | int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); | |
578 | int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii); | |
579 | @@ -67,26 +70,22 @@ static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type) | |
580 | * Functions for checking status of quota | |
581 | */ | |
582 | ||
583 | -static inline int sb_has_quota_enabled(struct super_block *sb, int type) | |
584 | +static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type) | |
585 | { | |
586 | - if (type == USRQUOTA) | |
587 | - return (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) | |
588 | - && !(sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED); | |
589 | - return (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED) | |
590 | - && !(sb_dqopt(sb)->flags & DQUOT_GROUP_SUSPENDED); | |
591 | + return sb_dqopt(sb)->flags & | |
592 | + dquot_state_flag(DQUOT_USAGE_ENABLED, type); | |
593 | } | |
594 | ||
595 | -static inline int sb_any_quota_enabled(struct super_block *sb) | |
596 | +static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type) | |
597 | { | |
598 | - return sb_has_quota_enabled(sb, USRQUOTA) || | |
599 | - sb_has_quota_enabled(sb, GRPQUOTA); | |
600 | + return sb_dqopt(sb)->flags & | |
601 | + dquot_state_flag(DQUOT_LIMITS_ENABLED, type); | |
602 | } | |
603 | ||
604 | static inline int sb_has_quota_suspended(struct super_block *sb, int type) | |
605 | { | |
606 | - if (type == USRQUOTA) | |
607 | - return sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED; | |
608 | - return sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED; | |
609 | + return sb_dqopt(sb)->flags & | |
610 | + dquot_state_flag(DQUOT_SUSPENDED, type); | |
611 | } | |
612 | ||
613 | static inline int sb_any_quota_suspended(struct super_block *sb) | |
614 | @@ -95,6 +94,34 @@ static inline int sb_any_quota_suspended(struct super_block *sb) | |
615 | sb_has_quota_suspended(sb, GRPQUOTA); | |
616 | } | |
617 | ||
618 | +/* Does kernel know about any quota information for given sb + type? */ | |
619 | +static inline int sb_has_quota_loaded(struct super_block *sb, int type) | |
620 | +{ | |
621 | + /* Currently if anything is on, then quota usage is on as well */ | |
622 | + return sb_has_quota_usage_enabled(sb, type); | |
623 | +} | |
624 | + | |
625 | +static inline int sb_any_quota_loaded(struct super_block *sb) | |
626 | +{ | |
627 | + return sb_has_quota_loaded(sb, USRQUOTA) || | |
628 | + sb_has_quota_loaded(sb, GRPQUOTA); | |
629 | +} | |
630 | + | |
631 | +static inline int sb_has_quota_active(struct super_block *sb, int type) | |
632 | +{ | |
633 | + return sb_has_quota_loaded(sb, type) && | |
634 | + !sb_has_quota_suspended(sb, type); | |
635 | +} | |
636 | + | |
637 | +static inline int sb_any_quota_active(struct super_block *sb) | |
638 | +{ | |
639 | + return sb_has_quota_active(sb, USRQUOTA) || | |
640 | + sb_has_quota_active(sb, GRPQUOTA); | |
641 | +} | |
642 | + | |
643 | +/* For backward compatibility until we remove all users */ | |
644 | +#define sb_any_quota_enabled(sb) sb_any_quota_active(sb) | |
645 | + | |
646 | /* | |
647 | * Operations supported for diskquotas. | |
648 | */ | |
649 | @@ -109,7 +136,7 @@ extern struct quotactl_ops vfs_quotactl_ops; | |
650 | static inline void vfs_dq_init(struct inode *inode) | |
651 | { | |
652 | BUG_ON(!inode->i_sb); | |
653 | - if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) | |
654 | + if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) | |
655 | inode->i_sb->dq_op->initialize(inode, -1); | |
656 | } | |
657 | ||
658 | @@ -117,7 +144,7 @@ static inline void vfs_dq_init(struct inode *inode) | |
659 | * a transaction (deadlocks possible otherwise) */ | |
660 | static inline int vfs_dq_prealloc_space_nodirty(struct inode *inode, qsize_t nr) | |
661 | { | |
662 | - if (sb_any_quota_enabled(inode->i_sb)) { | |
663 | + if (sb_any_quota_active(inode->i_sb)) { | |
664 | /* Used space is updated in alloc_space() */ | |
665 | if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) | |
666 | return 1; | |
667 | @@ -137,7 +164,7 @@ static inline int vfs_dq_prealloc_space(struct inode *inode, qsize_t nr) | |
668 | ||
669 | static inline int vfs_dq_alloc_space_nodirty(struct inode *inode, qsize_t nr) | |
670 | { | |
671 | - if (sb_any_quota_enabled(inode->i_sb)) { | |
672 | + if (sb_any_quota_active(inode->i_sb)) { | |
673 | /* Used space is updated in alloc_space() */ | |
674 | if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) | |
675 | return 1; | |
676 | @@ -157,7 +184,7 @@ static inline int vfs_dq_alloc_space(struct inode *inode, qsize_t nr) | |
677 | ||
678 | static inline int vfs_dq_alloc_inode(struct inode *inode) | |
679 | { | |
680 | - if (sb_any_quota_enabled(inode->i_sb)) { | |
681 | + if (sb_any_quota_active(inode->i_sb)) { | |
682 | vfs_dq_init(inode); | |
683 | if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) | |
684 | return 1; | |
685 | @@ -167,7 +194,7 @@ static inline int vfs_dq_alloc_inode(struct inode *inode) | |
686 | ||
687 | static inline void vfs_dq_free_space_nodirty(struct inode *inode, qsize_t nr) | |
688 | { | |
689 | - if (sb_any_quota_enabled(inode->i_sb)) | |
690 | + if (sb_any_quota_active(inode->i_sb)) | |
691 | inode->i_sb->dq_op->free_space(inode, nr); | |
692 | else | |
693 | inode_sub_bytes(inode, nr); | |
694 | @@ -181,7 +208,7 @@ static inline void vfs_dq_free_space(struct inode *inode, qsize_t nr) | |
695 | ||
696 | static inline void vfs_dq_free_inode(struct inode *inode) | |
697 | { | |
698 | - if (sb_any_quota_enabled(inode->i_sb)) | |
699 | + if (sb_any_quota_active(inode->i_sb)) | |
700 | inode->i_sb->dq_op->free_inode(inode, 1); | |
701 | } | |
702 | ||
703 | @@ -202,12 +229,12 @@ static inline int vfs_dq_off(struct super_block *sb, int remount) | |
704 | ||
705 | #else | |
706 | ||
707 | -static inline int sb_has_quota_enabled(struct super_block *sb, int type) | |
708 | +static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type) | |
709 | { | |
710 | return 0; | |
711 | } | |
712 | ||
713 | -static inline int sb_any_quota_enabled(struct super_block *sb) | |
714 | +static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type) | |
715 | { | |
716 | return 0; | |
717 | } | |
718 | @@ -222,6 +249,25 @@ static inline int sb_any_quota_suspended(struct super_block *sb) | |
719 | return 0; | |
720 | } | |
721 | ||
722 | +/* Does kernel know about any quota information for given sb + type? */ | |
723 | +static inline int sb_has_quota_loaded(struct super_block *sb, int type) | |
724 | +{ | |
725 | + return 0; | |
726 | +} | |
727 | + | |
728 | +static inline int sb_any_quota_loaded(struct super_block *sb) | |
729 | +{ | |
730 | + return 0; | |
731 | +} | |
732 | + | |
733 | +static inline int sb_any_quota_active(struct super_block *sb) | |
734 | +{ | |
735 | + return 0; | |
736 | +} | |
737 | + | |
738 | +/* For backward compatibility until we remove all users */ | |
739 | +#define sb_any_quota_enabled(sb) sb_any_quota_active(sb) | |
740 | + | |
741 | /* | |
742 | * NO-OP when quota not configured. | |
743 | */ | |
744 | -- | |
745 | 1.5.2.4 | |
746 |