Blame view

fs/xfs/xfs_qm_syscalls.c 24.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
4ce3121f6   Nathan Scott   [XFS] Update lice...
2
3
   * Copyright (c) 2000-2005 Silicon Graphics, Inc.
   * All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
4ce3121f6   Nathan Scott   [XFS] Update lice...
5
6
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   * published by the Free Software Foundation.
   *
4ce3121f6   Nathan Scott   [XFS] Update lice...
9
10
11
12
   * This program is distributed in the hope that it would be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
   *
4ce3121f6   Nathan Scott   [XFS] Update lice...
14
15
16
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write the Free Software Foundation,
   * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
   */
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
18
19
  
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  #include "xfs.h"
  #include "xfs_fs.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
22
  #include "xfs_bit.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
  #include "xfs_log.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
24
  #include "xfs_inum.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
  #include "xfs_trans.h"
  #include "xfs_sb.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
27
  #include "xfs_ag.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #include "xfs_alloc.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  #include "xfs_quota.h"
  #include "xfs_mount.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #include "xfs_bmap_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #include "xfs_inode.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
33
  #include "xfs_itable.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include "xfs_bmap.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include "xfs_rtalloc.h"
  #include "xfs_error.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  #include "xfs_attr.h"
  #include "xfs_buf_item.h"
  #include "xfs_utils.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #include "xfs_qm.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
41
  #include "xfs_trace.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  STATIC int	xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
  STATIC int	xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
  					uint);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  STATIC uint	xfs_qm_export_flags(uint);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
  STATIC uint	xfs_qm_export_qtype_flags(uint);
  STATIC void	xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *,
  					fs_disk_quota_t *);
  
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
58
59
   * Turn off quota accounting and/or enforcement for all udquots and/or
   * gdquots. Called only at unmount time.
   *
   * This assumes that there are no dquots of this file system cached
   * incore, and modifies the ondisk dquot directly. Therefore, for example,
   * it is an error to call this twice, without purging the cache.
   */
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
60
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  xfs_qm_scall_quotaoff(
  	xfs_mount_t		*mp,
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
63
  	uint			flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
65
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  	uint			dqtype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
  	int			error;
  	uint			inactivate_flags;
  	xfs_qoff_logitem_t	*qoffstart;
  	int			nculprits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  	/*
  	 * No file system can have quotas enabled on disk but not in core.
  	 * Note that quota utilities (like quotaoff) _expect_
  	 * errno == EEXIST here.
  	 */
  	if ((mp->m_qflags & flags) == 0)
  		return XFS_ERROR(EEXIST);
  	error = 0;
  
  	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
  
  	/*
  	 * We don't want to deal with two quotaoffs messing up each other,
  	 * so we're going to serialize it. quotaoff isn't exactly a performance
  	 * critical thing.
  	 * If quotaoff, then we must be dealing with the root filesystem.
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
88
89
  	ASSERT(q);
  	mutex_lock(&q->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
  
  	/*
  	 * If we're just turning off quota enforcement, change mp and go.
  	 */
  	if ((flags & XFS_ALL_QUOTA_ACCT) == 0) {
  		mp->m_qflags &= ~(flags);
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
96
  		spin_lock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  		mp->m_sb.sb_qflags = mp->m_qflags;
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
98
  		spin_unlock(&mp->m_sb_lock);
8a7b8a89a   Christoph Hellwig   xfs: access quota...
99
  		mutex_unlock(&q->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  
  		/* XXX what to do if error ? Revert back to old vals incore ? */
  		error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS);
  		return (error);
  	}
  
  	dqtype = 0;
  	inactivate_flags = 0;
  	/*
  	 * If accounting is off, we must turn enforcement off, clear the
  	 * quota 'CHKD' certificate to make it known that we have to
  	 * do a quotacheck the next time this quota is turned on.
  	 */
  	if (flags & XFS_UQUOTA_ACCT) {
  		dqtype |= XFS_QMOPT_UQUOTA;
  		flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD);
  		inactivate_flags |= XFS_UQUOTA_ACTIVE;
  	}
  	if (flags & XFS_GQUOTA_ACCT) {
  		dqtype |= XFS_QMOPT_GQUOTA;
c8ad20ffe   Nathan Scott   [XFS] Add support...
120
  		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  		inactivate_flags |= XFS_GQUOTA_ACTIVE;
c8ad20ffe   Nathan Scott   [XFS] Add support...
122
123
124
125
  	} else if (flags & XFS_PQUOTA_ACCT) {
  		dqtype |= XFS_QMOPT_PQUOTA;
  		flags |= (XFS_OQUOTA_CHKD | XFS_OQUOTA_ENFD);
  		inactivate_flags |= XFS_PQUOTA_ACTIVE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
131
  	}
  
  	/*
  	 * Nothing to do?  Don't complain. This happens when we're just
  	 * turning off quota enforcement.
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
132
133
  	if ((mp->m_qflags & flags) == 0)
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  
  	/*
  	 * Write the LI_QUOTAOFF log record, and do SB changes atomically,
cb6edc26c   David Chinner   [XFS] Catch error...
137
138
  	 * and synchronously. If we fail to write, we should abort the
  	 * operation as it cannot be recovered safely if we crash.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	 */
cb6edc26c   David Chinner   [XFS] Catch error...
140
141
  	error = xfs_qm_log_quotaoff(mp, &qoffstart, flags);
  	if (error)
8a7b8a89a   Christoph Hellwig   xfs: access quota...
142
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  
  	/*
  	 * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct
  	 * to take care of the race between dqget and quotaoff. We don't take
  	 * any special locks to reset these bits. All processes need to check
  	 * these bits *after* taking inode lock(s) to see if the particular
  	 * quota type is in the process of being turned off. If *ACTIVE, it is
  	 * guaranteed that all dquot structures and all quotainode ptrs will all
  	 * stay valid as long as that inode is kept locked.
  	 *
  	 * There is no turning back after this.
  	 */
  	mp->m_qflags &= ~inactivate_flags;
  
  	/*
  	 * Give back all the dquot reference(s) held by inodes.
  	 * Here we go thru every single incore inode in this file system, and
  	 * do a dqrele on the i_udquot/i_gdquot that it may have.
  	 * Essentially, as long as somebody has an inode locked, this guarantees
  	 * that quotas will not be turned off. This is handy because in a
  	 * transaction once we lock the inode(s) and check for quotaon, we can
  	 * depend on the quota inodes (and other things) being valid as long as
  	 * we keep the lock(s).
  	 */
  	xfs_qm_dqrele_all_inodes(mp, flags);
  
  	/*
  	 * Next we make the changes in the quota flag in the mount struct.
  	 * This isn't protected by a particular lock directly, because we
25985edce   Lucas De Marchi   Fix common misspe...
172
  	 * don't want to take a mrlock every time we depend on quotas being on.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
179
180
181
182
183
  	 */
  	mp->m_qflags &= ~(flags);
  
  	/*
  	 * Go through all the dquots of this file system and purge them,
  	 * according to what was turned off. We may not be able to get rid
  	 * of all dquots, because dquots can have temporary references that
  	 * are not attached to inodes. eg. xfs_setattr, xfs_create.
  	 * So, if we couldn't purge all the dquots from the filesystem,
  	 * we can't get rid of the incore data structures.
  	 */
8112e9dc6   Christoph Hellwig   xfs: removed unus...
184
  	while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
191
192
193
194
195
196
197
  		delay(10 * nculprits);
  
  	/*
  	 * Transactions that had started before ACTIVE state bit was cleared
  	 * could have logged many dquots, so they'd have higher LSNs than
  	 * the first QUOTAOFF log record does. If we happen to crash when
  	 * the tail of the log has gone past the QUOTAOFF record, but
  	 * before the last dquot modification, those dquots __will__
  	 * recover, and that's not good.
  	 *
  	 * So, we have QUOTAOFF start and end logitems; the start
  	 * logitem won't get overwritten until the end logitem appears...
  	 */
cb6edc26c   David Chinner   [XFS] Catch error...
198
199
200
201
  	error = xfs_qm_log_quotaoff_end(mp, qoffstart, flags);
  	if (error) {
  		/* We're screwed now. Shutdown is the only option. */
  		xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
8a7b8a89a   Christoph Hellwig   xfs: access quota...
202
  		goto out_unlock;
cb6edc26c   David Chinner   [XFS] Catch error...
203
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
  
  	/*
  	 * If quotas is completely disabled, close shop.
  	 */
c8ad20ffe   Nathan Scott   [XFS] Add support...
208
209
  	if (((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET1) ||
  	    ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_SET2)) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
210
  		mutex_unlock(&q->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
  		xfs_qm_destroy_quotainfo(mp);
  		return (0);
  	}
  
  	/*
8a7b8a89a   Christoph Hellwig   xfs: access quota...
216
  	 * Release our quotainode references if we don't need them anymore.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
218
219
220
  	if ((dqtype & XFS_QMOPT_UQUOTA) && q->qi_uquotaip) {
  		IRELE(q->qi_uquotaip);
  		q->qi_uquotaip = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
222
223
224
  	if ((dqtype & (XFS_QMOPT_GQUOTA|XFS_QMOPT_PQUOTA)) && q->qi_gquotaip) {
  		IRELE(q->qi_gquotaip);
  		q->qi_gquotaip = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226

8a7b8a89a   Christoph Hellwig   xfs: access quota...
227
228
229
  out_unlock:
  	mutex_unlock(&q->qi_quotaofflock);
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  }
5d18898b2   Christoph Hellwig   xfs: simplify xfs...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
  STATIC int
  xfs_qm_scall_trunc_qfile(
  	struct xfs_mount	*mp,
  	xfs_ino_t		ino)
  {
  	struct xfs_inode	*ip;
  	struct xfs_trans	*tp;
  	int			error;
  
  	if (ino == NULLFSINO)
  		return 0;
  
  	error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
  	if (error)
  		return error;
  
  	xfs_ilock(ip, XFS_IOLOCK_EXCL);
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
  	error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
  				  XFS_TRANS_PERM_LOG_RES,
  				  XFS_ITRUNCATE_LOG_COUNT);
  	if (error) {
  		xfs_trans_cancel(tp, 0);
  		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
  		goto out_put;
  	}
  
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
ddc3415ab   Christoph Hellwig   xfs: simplify xfs...
260
  	xfs_trans_ijoin(tp, ip, 0);
5d18898b2   Christoph Hellwig   xfs: simplify xfs...
261

8f04c47aa   Christoph Hellwig   xfs: split xfs_it...
262
  	error = xfs_itruncate_data(&tp, ip, 0);
5d18898b2   Christoph Hellwig   xfs: simplify xfs...
263
264
265
266
267
  	if (error) {
  		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
  				     XFS_TRANS_ABORT);
  		goto out_unlock;
  	}
dcd79a142   Dave Chinner   xfs: don't use vf...
268
  	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
5d18898b2   Christoph Hellwig   xfs: simplify xfs...
269
270
271
272
273
274
275
276
  	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
  
  out_unlock:
  	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
  out_put:
  	IRELE(ip);
  	return error;
  }
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
277
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
  xfs_qm_scall_trunc_qfiles(
  	xfs_mount_t	*mp,
  	uint		flags)
  {
88ab02085   David Chinner   [XFS] Propagate q...
282
  	int		error = 0, error2 = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283

621187099   Eric Sandeen   [XFS] remove shou...
284
  	if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) {
8221112b4   Dave Chinner   xfs: convert the ...
285
286
287
  		xfs_debug(mp, "%s: flags=%x m_qflags=%x
  ",
  			__func__, flags, mp->m_qflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  		return XFS_ERROR(EINVAL);
  	}
5d18898b2   Christoph Hellwig   xfs: simplify xfs...
290
291
292
293
  	if (flags & XFS_DQ_USER)
  		error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
  	if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
  		error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

88ab02085   David Chinner   [XFS] Propagate q...
295
  	return error ? error : error2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
  /*
   * Switch on (a given) quota enforcement for a filesystem.  This takes
   * effect immediately.
   * (Switching on quota accounting must be done at mount time.)
   */
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
302
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
  xfs_qm_scall_quotaon(
  	xfs_mount_t	*mp,
  	uint		flags)
  {
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	uint		qf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  	__int64_t	sbflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
  	flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD);
  	/*
  	 * Switching on quota accounting must be done at mount time.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
317
318
  	flags &= ~(XFS_ALL_QUOTA_ACCT);
  
  	sbflags = 0;
  
  	if (flags == 0) {
8221112b4   Dave Chinner   xfs: convert the ...
319
320
321
  		xfs_debug(mp, "%s: zero flags, m_qflags=%x
  ",
  			__func__, mp->m_qflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  		return XFS_ERROR(EINVAL);
  	}
  
  	/* No fs can turn on quotas with a delayed effect */
  	ASSERT((flags & XFS_ALL_QUOTA_ACCT) == 0);
  
  	/*
  	 * Can't enforce without accounting. We check the superblock
  	 * qflags here instead of m_qflags because rootfs can have
  	 * quota acct on ondisk without m_qflags' knowing.
  	 */
  	if (((flags & XFS_UQUOTA_ACCT) == 0 &&
  	    (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
  	    (flags & XFS_UQUOTA_ENFD))
  	    ||
c8ad20ffe   Nathan Scott   [XFS] Add support...
337
338
  	    ((flags & XFS_PQUOTA_ACCT) == 0 &&
  	    (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
424ea91ba   Donald Douwsma   [XFS] Fix quotaon...
339
  	    (flags & XFS_GQUOTA_ACCT) == 0 &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  	    (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
c8ad20ffe   Nathan Scott   [XFS] Add support...
341
  	    (flags & XFS_OQUOTA_ENFD))) {
8221112b4   Dave Chinner   xfs: convert the ...
342
343
344
345
  		xfs_debug(mp,
  			"%s: Can't enforce without acct, flags=%x sbflags=%x
  ",
  			__func__, flags, mp->m_sb.sb_qflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
348
  		return XFS_ERROR(EINVAL);
  	}
  	/*
25985edce   Lucas De Marchi   Fix common misspe...
349
  	 * If everything's up to-date incore, then don't waste time.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
357
  	 */
  	if ((mp->m_qflags & flags) == flags)
  		return XFS_ERROR(EEXIST);
  
  	/*
  	 * Change sb_qflags on disk but not incore mp->qflags
  	 * if this is the root filesystem.
  	 */
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
358
  	spin_lock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
360
  	qf = mp->m_sb.sb_qflags;
  	mp->m_sb.sb_qflags = qf | flags;
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
361
  	spin_unlock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  
  	/*
  	 * There's nothing to change if it's the same.
  	 */
  	if ((qf & flags) == flags && sbflags == 0)
  		return XFS_ERROR(EEXIST);
  	sbflags |= XFS_SB_QFLAGS;
  
  	if ((error = xfs_qm_write_sb_changes(mp, sbflags)))
  		return (error);
  	/*
  	 * If we aren't trying to switch on quota enforcement, we are done.
  	 */
  	if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
  	     (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
c8ad20ffe   Nathan Scott   [XFS] Add support...
377
378
379
380
  	     ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
  	     (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
  	     ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
  	     (mp->m_qflags & XFS_GQUOTA_ACCT)) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
386
387
388
389
  	    (flags & XFS_ALL_QUOTA_ENFD) == 0)
  		return (0);
  
  	if (! XFS_IS_QUOTA_RUNNING(mp))
  		return XFS_ERROR(ESRCH);
  
  	/*
  	 * Switch on quota enforcement in core.
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
390
  	mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
8a7b8a89a   Christoph Hellwig   xfs: access quota...
392
  	mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
  
  	return (0);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
  /*
   * Return quota status information, such as uquota-off, enforcements, etc.
   */
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
399
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
400
  xfs_qm_scall_getqstat(
8a7b8a89a   Christoph Hellwig   xfs: access quota...
401
402
  	struct xfs_mount	*mp,
  	struct fs_quota_stat	*out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
404
405
406
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
  	struct xfs_inode	*uip, *gip;
  	boolean_t		tempuqip, tempgqip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
412
  
  	uip = gip = NULL;
  	tempuqip = tempgqip = B_FALSE;
  	memset(out, 0, sizeof(fs_quota_stat_t));
  
  	out->qs_version = FS_QSTAT_VERSION;
621187099   Eric Sandeen   [XFS] remove shou...
413
  	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
419
420
421
422
423
  		out->qs_uquota.qfs_ino = NULLFSINO;
  		out->qs_gquota.qfs_ino = NULLFSINO;
  		return (0);
  	}
  	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
  							(XFS_ALL_QUOTA_ACCT|
  							 XFS_ALL_QUOTA_ENFD));
  	out->qs_pad = 0;
  	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
  	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
424
425
426
  	if (q) {
  		uip = q->qi_uquotaip;
  		gip = q->qi_gquotaip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
  	}
  	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
  		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
7b6259e7a   Dave Chinner   xfs: remove block...
430
  					0, 0, &uip) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
434
  			tempuqip = B_TRUE;
  	}
  	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
  		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
7b6259e7a   Dave Chinner   xfs: remove block...
435
  					0, 0, &gip) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
439
440
441
  			tempgqip = B_TRUE;
  	}
  	if (uip) {
  		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
  		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
  		if (tempuqip)
433550990   Christoph Hellwig   [XFS] remove most...
442
  			IRELE(uip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
446
447
  	}
  	if (gip) {
  		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
  		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
  		if (tempgqip)
433550990   Christoph Hellwig   [XFS] remove most...
448
  			IRELE(gip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
450
451
452
453
454
455
456
  	if (q) {
  		out->qs_incoredqs = q->qi_dquots;
  		out->qs_btimelimit = q->qi_btimelimit;
  		out->qs_itimelimit = q->qi_itimelimit;
  		out->qs_rtbtimelimit = q->qi_rtbtimelimit;
  		out->qs_bwarnlimit = q->qi_bwarnlimit;
  		out->qs_iwarnlimit = q->qi_iwarnlimit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
458
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  }
c472b4327   Christoph Hellwig   quota: unify ->se...
460
461
  #define XFS_DQ_MASK \
  	(FS_DQ_LIMIT_MASK | FS_DQ_TIMER_MASK | FS_DQ_WARNS_MASK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
  /*
   * Adjust quota limits, and start/stop timers accordingly.
   */
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
465
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
466
467
468
469
470
471
  xfs_qm_scall_setqlim(
  	xfs_mount_t		*mp,
  	xfs_dqid_t		id,
  	uint			type,
  	fs_disk_quota_t		*newlim)
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
472
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
  	xfs_disk_dquot_t	*ddq;
  	xfs_dquot_t		*dqp;
  	xfs_trans_t		*tp;
  	int			error;
  	xfs_qcnt_t		hard, soft;
c472b4327   Christoph Hellwig   quota: unify ->se...
478
479
480
481
  	if (newlim->d_fieldmask & ~XFS_DQ_MASK)
  		return EINVAL;
  	if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
488
489
490
491
492
493
494
495
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
  	if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128,
  				      0, 0, XFS_DEFAULT_LOG_COUNT))) {
  		xfs_trans_cancel(tp, 0);
  		return (error);
  	}
  
  	/*
  	 * We don't want to race with a quotaoff so take the quotaoff lock.
  	 * (We don't hold an inode lock, so there's nothing else to stop
  	 * a quotaoff from happening). (XXXThis doesn't currently happen
  	 * because we take the vfslock before calling xfs_qm_sysent).
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
496
  	mutex_lock(&q->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
499
500
501
502
503
  
  	/*
  	 * Get the dquot (locked), and join it to the transaction.
  	 * Allocate the dquot if this doesn't exist.
  	 */
  	if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) {
  		xfs_trans_cancel(tp, XFS_TRANS_ABORT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
  		ASSERT(error != ENOENT);
8a7b8a89a   Christoph Hellwig   xfs: access quota...
505
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
510
511
512
513
514
  	xfs_trans_dqjoin(tp, dqp);
  	ddq = &dqp->q_core;
  
  	/*
  	 * Make sure that hardlimits are >= soft limits before changing.
  	 */
  	hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
  		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
1149d96ae   Christoph Hellwig   [XFS] endianess a...
515
  			be64_to_cpu(ddq->d_blk_hardlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  	soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
  		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
1149d96ae   Christoph Hellwig   [XFS] endianess a...
518
  			be64_to_cpu(ddq->d_blk_softlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	if (hard == 0 || hard >= soft) {
1149d96ae   Christoph Hellwig   [XFS] endianess a...
520
521
  		ddq->d_blk_hardlimit = cpu_to_be64(hard);
  		ddq->d_blk_softlimit = cpu_to_be64(soft);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  		if (id == 0) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
523
524
  			q->qi_bhardlimit = hard;
  			q->qi_bsoftlimit = soft;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
  		}
  	} else {
8221112b4   Dave Chinner   xfs: convert the ...
527
528
  		xfs_debug(mp, "blkhard %Ld < blksoft %Ld
  ", hard, soft);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
  	}
  	hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
  		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
1149d96ae   Christoph Hellwig   [XFS] endianess a...
532
  			be64_to_cpu(ddq->d_rtb_hardlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  	soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
  		(xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
1149d96ae   Christoph Hellwig   [XFS] endianess a...
535
  			be64_to_cpu(ddq->d_rtb_softlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  	if (hard == 0 || hard >= soft) {
1149d96ae   Christoph Hellwig   [XFS] endianess a...
537
538
  		ddq->d_rtb_hardlimit = cpu_to_be64(hard);
  		ddq->d_rtb_softlimit = cpu_to_be64(soft);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  		if (id == 0) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
540
541
  			q->qi_rtbhardlimit = hard;
  			q->qi_rtbsoftlimit = soft;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  		}
  	} else {
8221112b4   Dave Chinner   xfs: convert the ...
544
545
  		xfs_debug(mp, "rtbhard %Ld < rtbsoft %Ld
  ", hard, soft);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
  	}
  
  	hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
  		(xfs_qcnt_t) newlim->d_ino_hardlimit :
1149d96ae   Christoph Hellwig   [XFS] endianess a...
550
  			be64_to_cpu(ddq->d_ino_hardlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
  	soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
  		(xfs_qcnt_t) newlim->d_ino_softlimit :
1149d96ae   Christoph Hellwig   [XFS] endianess a...
553
  			be64_to_cpu(ddq->d_ino_softlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  	if (hard == 0 || hard >= soft) {
1149d96ae   Christoph Hellwig   [XFS] endianess a...
555
556
  		ddq->d_ino_hardlimit = cpu_to_be64(hard);
  		ddq->d_ino_softlimit = cpu_to_be64(soft);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  		if (id == 0) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
558
559
  			q->qi_ihardlimit = hard;
  			q->qi_isoftlimit = soft;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
  		}
  	} else {
8221112b4   Dave Chinner   xfs: convert the ...
562
563
  		xfs_debug(mp, "ihard %Ld < isoft %Ld
  ", hard, soft);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  	}
754002b4f   Nathan Scott   [XFS] Merge a few...
565
566
567
568
  	/*
  	 * Update warnings counter(s) if requested
  	 */
  	if (newlim->d_fieldmask & FS_DQ_BWARNS)
1149d96ae   Christoph Hellwig   [XFS] endianess a...
569
  		ddq->d_bwarns = cpu_to_be16(newlim->d_bwarns);
754002b4f   Nathan Scott   [XFS] Merge a few...
570
  	if (newlim->d_fieldmask & FS_DQ_IWARNS)
1149d96ae   Christoph Hellwig   [XFS] endianess a...
571
  		ddq->d_iwarns = cpu_to_be16(newlim->d_iwarns);
754002b4f   Nathan Scott   [XFS] Merge a few...
572
  	if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
1149d96ae   Christoph Hellwig   [XFS] endianess a...
573
  		ddq->d_rtbwarns = cpu_to_be16(newlim->d_rtbwarns);
754002b4f   Nathan Scott   [XFS] Merge a few...
574

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
  	if (id == 0) {
  		/*
  		 * Timelimits for the super user set the relative time
  		 * the other users can be over quota for this file system.
  		 * If it is zero a default is used.  Ditto for the default
754002b4f   Nathan Scott   [XFS] Merge a few...
580
581
  		 * soft and hard limit values (already done, above), and
  		 * for warnings.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
  		 */
  		if (newlim->d_fieldmask & FS_DQ_BTIMER) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
584
  			q->qi_btimelimit = newlim->d_btimer;
1149d96ae   Christoph Hellwig   [XFS] endianess a...
585
  			ddq->d_btimer = cpu_to_be32(newlim->d_btimer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
  		}
  		if (newlim->d_fieldmask & FS_DQ_ITIMER) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
588
  			q->qi_itimelimit = newlim->d_itimer;
1149d96ae   Christoph Hellwig   [XFS] endianess a...
589
  			ddq->d_itimer = cpu_to_be32(newlim->d_itimer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
  		}
  		if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
592
  			q->qi_rtbtimelimit = newlim->d_rtbtimer;
1149d96ae   Christoph Hellwig   [XFS] endianess a...
593
  			ddq->d_rtbtimer = cpu_to_be32(newlim->d_rtbtimer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  		}
754002b4f   Nathan Scott   [XFS] Merge a few...
595
  		if (newlim->d_fieldmask & FS_DQ_BWARNS)
8a7b8a89a   Christoph Hellwig   xfs: access quota...
596
  			q->qi_bwarnlimit = newlim->d_bwarns;
754002b4f   Nathan Scott   [XFS] Merge a few...
597
  		if (newlim->d_fieldmask & FS_DQ_IWARNS)
8a7b8a89a   Christoph Hellwig   xfs: access quota...
598
  			q->qi_iwarnlimit = newlim->d_iwarns;
754002b4f   Nathan Scott   [XFS] Merge a few...
599
  		if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
8a7b8a89a   Christoph Hellwig   xfs: access quota...
600
  			q->qi_rtbwarnlimit = newlim->d_rtbwarns;
754002b4f   Nathan Scott   [XFS] Merge a few...
601
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
604
605
606
607
608
609
610
611
612
  		/*
  		 * If the user is now over quota, start the timelimit.
  		 * The user will not be 'warned'.
  		 * Note that we keep the timers ticking, whether enforcement
  		 * is on or off. We don't really want to bother with iterating
  		 * over all ondisk dquots and turning the timers on/off.
  		 */
  		xfs_qm_adjust_dqtimers(mp, ddq);
  	}
  	dqp->dq_flags |= XFS_DQ_DIRTY;
  	xfs_trans_log_dquot(tp, dqp);
e5720eec0   David Chinner   [XFS] Propagate e...
613
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
  	xfs_qm_dqrele(dqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

8a7b8a89a   Christoph Hellwig   xfs: access quota...
616
617
   out_unlock:
  	mutex_unlock(&q->qi_quotaofflock);
e5720eec0   David Chinner   [XFS] Propagate e...
618
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
  }
fcafb71b5   Christoph Hellwig   xfs: get rid of i...
620
  int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
  xfs_qm_scall_getquota(
  	xfs_mount_t	*mp,
  	xfs_dqid_t	id,
  	uint		type,
  	fs_disk_quota_t *out)
  {
  	xfs_dquot_t	*dqp;
  	int		error;
  
  	/*
  	 * Try to get the dquot. We don't want it allocated on disk, so
  	 * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't
  	 * exist, we'll get ENOENT back.
  	 */
  	if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) {
  		return (error);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
640
641
642
643
644
645
  	/*
  	 * If everything's NULL, this dquot doesn't quite exist as far as
  	 * our utility programs are concerned.
  	 */
  	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
  		xfs_qm_dqput(dqp);
  		return XFS_ERROR(ENOENT);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  	/*
  	 * Convert the disk dquot to the exportable format
  	 */
  	xfs_qm_export_dquot(mp, &dqp->q_core, out);
  	xfs_qm_dqput(dqp);
  	return (error ? XFS_ERROR(EFAULT) : 0);
  }
  
  
  STATIC int
  xfs_qm_log_quotaoff_end(
  	xfs_mount_t		*mp,
  	xfs_qoff_logitem_t	*startqoff,
  	uint			flags)
  {
c8ad20ffe   Nathan Scott   [XFS] Add support...
661
  	xfs_trans_t		*tp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  	int			error;
c8ad20ffe   Nathan Scott   [XFS] Add support...
663
  	xfs_qoff_logitem_t	*qoffi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
  
  	if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2,
  				      0, 0, XFS_DEFAULT_LOG_COUNT))) {
  		xfs_trans_cancel(tp, 0);
  		return (error);
  	}
  
  	qoffi = xfs_trans_get_qoff_item(tp, startqoff,
  					flags & XFS_ALL_QUOTA_ACCT);
  	xfs_trans_log_quotaoff_item(tp, qoffi);
  
  	/*
  	 * We have to make sure that the transaction is secure on disk before we
  	 * return and actually stop quota accounting. So, make it synchronous.
  	 * We don't care about quotoff's performance.
  	 */
  	xfs_trans_set_sync(tp);
1c72bf900   Eric Sandeen   [XFS] The last ar...
683
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
689
690
691
692
693
694
695
  	return (error);
  }
  
  
  STATIC int
  xfs_qm_log_quotaoff(
  	xfs_mount_t	       *mp,
  	xfs_qoff_logitem_t     **qoffstartp,
  	uint		       flags)
  {
  	xfs_trans_t	       *tp;
  	int			error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
  	xfs_qoff_logitem_t     *qoffi=NULL;
  	uint			oldsbqflag=0;
  
  	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
  	if ((error = xfs_trans_reserve(tp, 0,
  				      sizeof(xfs_qoff_logitem_t) * 2 +
  				      mp->m_sb.sb_sectsize + 128,
  				      0,
  				      0,
  				      XFS_DEFAULT_LOG_COUNT))) {
  		goto error0;
  	}
  
  	qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT);
  	xfs_trans_log_quotaoff_item(tp, qoffi);
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
711
  	spin_lock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  	oldsbqflag = mp->m_sb.sb_qflags;
  	mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL;
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
714
  	spin_unlock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
718
719
720
721
722
723
  
  	xfs_mod_sb(tp, XFS_SB_QFLAGS);
  
  	/*
  	 * We have to make sure that the transaction is secure on disk before we
  	 * return and actually stop quota accounting. So, make it synchronous.
  	 * We don't care about quotoff's performance.
  	 */
  	xfs_trans_set_sync(tp);
1c72bf900   Eric Sandeen   [XFS] The last ar...
724
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
729
730
731
732
  
  error0:
  	if (error) {
  		xfs_trans_cancel(tp, 0);
  		/*
  		 * No one else is modifying sb_qflags, so this is OK.
  		 * We still hold the quotaofflock.
  		 */
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
733
  		spin_lock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  		mp->m_sb.sb_qflags = oldsbqflag;
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
735
  		spin_unlock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
  	}
  	*qoffstartp = qoffi;
  	return (error);
  }
  
  
  /*
   * Translate an internal style on-disk-dquot to the exportable format.
   * The main differences are that the counters/limits are all in Basic
   * Blocks (BBs) instead of the internal FSBs, and all on-disk data has
   * to be converted to the native endianness.
   */
  STATIC void
  xfs_qm_export_dquot(
  	xfs_mount_t		*mp,
  	xfs_disk_dquot_t	*src,
  	struct fs_disk_quota	*dst)
  {
  	memset(dst, 0, sizeof(*dst));
  	dst->d_version = FS_DQUOT_VERSION;  /* different from src->d_version */
1149d96ae   Christoph Hellwig   [XFS] endianess a...
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  	dst->d_flags = xfs_qm_export_qtype_flags(src->d_flags);
  	dst->d_id = be32_to_cpu(src->d_id);
  	dst->d_blk_hardlimit =
  		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_hardlimit));
  	dst->d_blk_softlimit =
  		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_softlimit));
  	dst->d_ino_hardlimit = be64_to_cpu(src->d_ino_hardlimit);
  	dst->d_ino_softlimit = be64_to_cpu(src->d_ino_softlimit);
  	dst->d_bcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_bcount));
  	dst->d_icount = be64_to_cpu(src->d_icount);
  	dst->d_btimer = be32_to_cpu(src->d_btimer);
  	dst->d_itimer = be32_to_cpu(src->d_itimer);
  	dst->d_iwarns = be16_to_cpu(src->d_iwarns);
  	dst->d_bwarns = be16_to_cpu(src->d_bwarns);
  	dst->d_rtb_hardlimit =
  		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_hardlimit));
  	dst->d_rtb_softlimit =
  		XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_softlimit));
  	dst->d_rtbcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtbcount));
  	dst->d_rtbtimer = be32_to_cpu(src->d_rtbtimer);
  	dst->d_rtbwarns = be16_to_cpu(src->d_rtbwarns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
  
  	/*
  	 * Internally, we don't reset all the timers when quota enforcement
c41564b5a   Nathan Scott   [XFS] We really s...
780
  	 * gets turned off. No need to confuse the user level code,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
  	 * so return zeroes in that case.
  	 */
e6d29426b   Kouta Ooizumi   [XFS] Fix uquota ...
783
784
785
  	if ((!XFS_IS_UQUOTA_ENFORCED(mp) && src->d_flags == XFS_DQ_USER) ||
  	    (!XFS_IS_OQUOTA_ENFORCED(mp) &&
  			(src->d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
  		dst->d_btimer = 0;
  		dst->d_itimer = 0;
  		dst->d_rtbtimer = 0;
  	}
  
  #ifdef DEBUG
ade7ce31c   Christoph Hellwig   quota: Clean up t...
792
  	if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
e6d29426b   Kouta Ooizumi   [XFS] Fix uquota ...
793
  	     (XFS_IS_OQUOTA_ENFORCED(mp) &&
ade7ce31c   Christoph Hellwig   quota: Clean up t...
794
  			(dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
e6d29426b   Kouta Ooizumi   [XFS] Fix uquota ...
795
  	    dst->d_id != 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
802
803
804
805
806
807
808
  		if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
  		    (dst->d_blk_softlimit > 0)) {
  			ASSERT(dst->d_btimer != 0);
  		}
  		if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) &&
  		    (dst->d_ino_softlimit > 0)) {
  			ASSERT(dst->d_itimer != 0);
  		}
  	}
  #endif
  }
  
  STATIC uint
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
  xfs_qm_export_qtype_flags(
  	uint flags)
  {
  	/*
c8ad20ffe   Nathan Scott   [XFS] Add support...
813
  	 * Can't be more than one, or none.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  	 */
ade7ce31c   Christoph Hellwig   quota: Clean up t...
815
816
817
818
819
820
821
  	ASSERT((flags & (FS_PROJ_QUOTA | FS_USER_QUOTA)) !=
  		(FS_PROJ_QUOTA | FS_USER_QUOTA));
  	ASSERT((flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)) !=
  		(FS_PROJ_QUOTA | FS_GROUP_QUOTA));
  	ASSERT((flags & (FS_USER_QUOTA | FS_GROUP_QUOTA)) !=
  		(FS_USER_QUOTA | FS_GROUP_QUOTA));
  	ASSERT((flags & (FS_PROJ_QUOTA|FS_USER_QUOTA|FS_GROUP_QUOTA)) != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
  
  	return (flags & XFS_DQ_USER) ?
ade7ce31c   Christoph Hellwig   quota: Clean up t...
824
825
  		FS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
  			FS_PROJ_QUOTA : FS_GROUP_QUOTA;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
828
  }
  
  STATIC uint
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
833
834
835
  xfs_qm_export_flags(
  	uint flags)
  {
  	uint uflags;
  
  	uflags = 0;
  	if (flags & XFS_UQUOTA_ACCT)
ade7ce31c   Christoph Hellwig   quota: Clean up t...
836
  		uflags |= FS_QUOTA_UDQ_ACCT;
c8ad20ffe   Nathan Scott   [XFS] Add support...
837
  	if (flags & XFS_PQUOTA_ACCT)
ade7ce31c   Christoph Hellwig   quota: Clean up t...
838
  		uflags |= FS_QUOTA_PDQ_ACCT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
  	if (flags & XFS_GQUOTA_ACCT)
ade7ce31c   Christoph Hellwig   quota: Clean up t...
840
  		uflags |= FS_QUOTA_GDQ_ACCT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  	if (flags & XFS_UQUOTA_ENFD)
ade7ce31c   Christoph Hellwig   quota: Clean up t...
842
  		uflags |= FS_QUOTA_UDQ_ENFD;
c8ad20ffe   Nathan Scott   [XFS] Add support...
843
844
  	if (flags & (XFS_OQUOTA_ENFD)) {
  		uflags |= (flags & XFS_GQUOTA_ACCT) ?
ade7ce31c   Christoph Hellwig   quota: Clean up t...
845
  			FS_QUOTA_GDQ_ENFD : FS_QUOTA_PDQ_ENFD;
c8ad20ffe   Nathan Scott   [XFS] Add support...
846
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  	return (uflags);
  }
fe588ed32   Christoph Hellwig   xfs: use generic ...
849
850
851
852
853
  STATIC int
  xfs_dqrele_inode(
  	struct xfs_inode	*ip,
  	struct xfs_perag	*pag,
  	int			flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
  {
fe588ed32   Christoph Hellwig   xfs: use generic ...
855
  	/* skip quota inodes */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
856
857
  	if (ip == ip->i_mount->m_quotainfo->qi_uquotaip ||
  	    ip == ip->i_mount->m_quotainfo->qi_gquotaip) {
fe588ed32   Christoph Hellwig   xfs: use generic ...
858
859
  		ASSERT(ip->i_udquot == NULL);
  		ASSERT(ip->i_gdquot == NULL);
fe588ed32   Christoph Hellwig   xfs: use generic ...
860
861
  		return 0;
  	}
cb4f0d1d4   Dave Chinner   [XFS] fix uniniti...
862

fe588ed32   Christoph Hellwig   xfs: use generic ...
863
864
865
866
867
868
869
870
871
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
  	if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) {
  		xfs_qm_dqrele(ip->i_udquot);
  		ip->i_udquot = NULL;
  	}
  	if (flags & (XFS_PQUOTA_ACCT|XFS_GQUOTA_ACCT) && ip->i_gdquot) {
  		xfs_qm_dqrele(ip->i_gdquot);
  		ip->i_gdquot = NULL;
  	}
f2d676143   Christoph Hellwig   xfs: remove xfs_iput
872
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
fe588ed32   Christoph Hellwig   xfs: use generic ...
873
  	return 0;
5b4d89ae0   David Chinner   [XFS] Traverse in...
874
  }
fe588ed32   Christoph Hellwig   xfs: use generic ...
875

5b4d89ae0   David Chinner   [XFS] Traverse in...
876
877
  /*
   * Go thru all the inodes in the file system, releasing their dquots.
fe588ed32   Christoph Hellwig   xfs: use generic ...
878
   *
5b4d89ae0   David Chinner   [XFS] Traverse in...
879
   * Note that the mount structure gets modified to indicate that quotas are off
fe588ed32   Christoph Hellwig   xfs: use generic ...
880
   * AFTER this, in the case of quotaoff.
5b4d89ae0   David Chinner   [XFS] Traverse in...
881
882
883
884
885
886
   */
  void
  xfs_qm_dqrele_all_inodes(
  	struct xfs_mount *mp,
  	uint		 flags)
  {
5b4d89ae0   David Chinner   [XFS] Traverse in...
887
  	ASSERT(mp->m_quotainfo);
65d0f2053   Dave Chinner   xfs: split inode ...
888
  	xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
  }