Blame view

fs/xfs/xfs_qm.c 58.1 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
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include "xfs.h"
  #include "xfs_fs.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
20
  #include "xfs_bit.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #include "xfs_log.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
22
  #include "xfs_inum.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
  #include "xfs_trans.h"
  #include "xfs_sb.h"
  #include "xfs_ag.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #include "xfs_alloc.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
  #include "xfs_quota.h"
  #include "xfs_mount.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  #include "xfs_bmap_btree.h"
  #include "xfs_ialloc_btree.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
  #include "xfs_dinode.h"
  #include "xfs_inode.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
33
34
  #include "xfs_ialloc.h"
  #include "xfs_itable.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include "xfs_rtalloc.h"
  #include "xfs_error.h"
a844f4510   Nathan Scott   [XFS] Remove xfs_...
37
  #include "xfs_bmap.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
  #include "xfs_attr.h"
  #include "xfs_buf_item.h"
  #include "xfs_trans_space.h"
  #include "xfs_utils.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #include "xfs_qm.h"
0b1b213fc   Christoph Hellwig   xfs: event tracin...
43
  #include "xfs_trace.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
  
  /*
   * The global quota manager. There is only one of these for the entire
   * system, _not_ one per file system. XQM keeps track of the overall
   * quota functionality, including maintaining the freelist and hash
   * tables of dquots.
   */
a0b0b8a5b   Christoph Hellwig   xfs: kill mutex_t...
51
  struct mutex	xfs_Gqm_lock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  struct xfs_qm	*xfs_Gqm;
6b3f6b5b8   Nathan Scott   [XFS] Rework the ...
53
  uint		ndquot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
  
  kmem_zone_t	*qm_dqzone;
  kmem_zone_t	*qm_dqtrxzone;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
  
  STATIC void	xfs_qm_list_init(xfs_dqlist_t *, char *, int);
  STATIC void	xfs_qm_list_destroy(xfs_dqlist_t *);
  
  STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
ba0f32d46   Christoph Hellwig   [XFS] mark variou...
62
  STATIC int	xfs_qm_init_quotainfo(xfs_mount_t *);
1495f230f   Ying Han   vmscan: change sh...
63
  STATIC int	xfs_qm_shake(struct shrinker *, struct shrink_control *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64

8e1f936b7   Rusty Russell   mm: clean up and ...
65
66
67
68
  static struct shrinker xfs_qm_shaker = {
  	.shrink = xfs_qm_shake,
  	.seeks = DEFAULT_SEEKS,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
  /*
   * Initialize the XQM structure.
   * Note that there is not one quota manager per file system.
   */
  STATIC struct xfs_qm *
  xfs_Gqm_init(void)
  {
6b3f6b5b8   Nathan Scott   [XFS] Rework the ...
76
77
  	xfs_dqhash_t	*udqhash, *gdqhash;
  	xfs_qm_t	*xqm;
215101c36   Nathan Scott   [XFS] Fix kmem_za...
78
79
  	size_t		hsize;
  	uint		i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
  
  	/*
  	 * Initialize the dquot hash tables.
  	 */
77e4635ae   Nathan Scott   [XFS] Add a greed...
84
  	udqhash = kmem_zalloc_greedy(&hsize,
5995cb7d8   Eric Sandeen   [XFS] fix nasty q...
85
  				     XFS_QM_HASHSIZE_LOW * sizeof(xfs_dqhash_t),
bdfb04301   Christoph Hellwig   xfs: replace KM_L...
86
87
88
89
90
  				     XFS_QM_HASHSIZE_HIGH * sizeof(xfs_dqhash_t));
  	if (!udqhash)
  		goto out;
  
  	gdqhash = kmem_zalloc_large(hsize);
d67b1b032   Julia Lawall   fs/xfs: Correct N...
91
  	if (!gdqhash)
bdfb04301   Christoph Hellwig   xfs: replace KM_L...
92
  		goto out_free_udqhash;
77e4635ae   Nathan Scott   [XFS] Add a greed...
93
  	hsize /= sizeof(xfs_dqhash_t);
6b3f6b5b8   Nathan Scott   [XFS] Rework the ...
94
  	ndquot = hsize << 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

6b3f6b5b8   Nathan Scott   [XFS] Rework the ...
96
97
98
99
  	xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
  	xqm->qm_dqhashmask = hsize - 1;
  	xqm->qm_usr_dqhtable = udqhash;
  	xqm->qm_grp_dqhtable = gdqhash;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
103
104
105
106
107
108
109
110
  	ASSERT(xqm->qm_usr_dqhtable != NULL);
  	ASSERT(xqm->qm_grp_dqhtable != NULL);
  
  	for (i = 0; i < hsize; i++) {
  		xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i);
  		xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i);
  	}
  
  	/*
  	 * Freelist of all dquots of all file systems
  	 */
3a8406f6d   Dave Chinner   xfs: convert the ...
111
112
113
  	INIT_LIST_HEAD(&xqm->qm_dqfrlist);
  	xqm->qm_dqfrlist_cnt = 0;
  	mutex_init(&xqm->qm_dqfrlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
116
117
118
119
120
121
122
123
  
  	/*
  	 * dquot zone. we register our own low-memory callback.
  	 */
  	if (!qm_dqzone) {
  		xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t),
  						"xfs_dquots");
  		qm_dqzone = xqm->qm_dqzone;
  	} else
  		xqm->qm_dqzone = qm_dqzone;
8e1f936b7   Rusty Russell   mm: clean up and ...
124
  	register_shrinker(&xfs_qm_shaker);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  
  	/*
  	 * The t_dqinfo portion of transactions.
  	 */
  	if (!qm_dqtrxzone) {
  		xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t),
  						   "xfs_dqtrx");
  		qm_dqtrxzone = xqm->qm_dqtrxzone;
  	} else
  		xqm->qm_dqtrxzone = qm_dqtrxzone;
  
  	atomic_set(&xqm->qm_totaldquots, 0);
  	xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO;
  	xqm->qm_nrefs = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	return xqm;
bdfb04301   Christoph Hellwig   xfs: replace KM_L...
140
141
142
143
144
  
   out_free_udqhash:
  	kmem_free_large(udqhash);
   out:
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
  }
  
  /*
   * Destroy the global quota manager when its reference count goes to zero.
   */
ba0f32d46   Christoph Hellwig   [XFS] mark variou...
150
  STATIC void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
  xfs_qm_destroy(
  	struct xfs_qm	*xqm)
  {
3a8406f6d   Dave Chinner   xfs: convert the ...
154
  	struct xfs_dquot *dqp, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
  	int		hsize, i;
  
  	ASSERT(xqm != NULL);
  	ASSERT(xqm->qm_nrefs == 0);
8e1f936b7   Rusty Russell   mm: clean up and ...
159
  	unregister_shrinker(&xfs_qm_shaker);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
  	hsize = xqm->qm_dqhashmask + 1;
  	for (i = 0; i < hsize; i++) {
  		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
  		xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i]));
  	}
bdfb04301   Christoph Hellwig   xfs: replace KM_L...
165
166
  	kmem_free_large(xqm->qm_usr_dqhtable);
  	kmem_free_large(xqm->qm_grp_dqhtable);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
  	xqm->qm_usr_dqhtable = NULL;
  	xqm->qm_grp_dqhtable = NULL;
  	xqm->qm_dqhashmask = 0;
3a8406f6d   Dave Chinner   xfs: convert the ...
170
171
172
173
174
  
  	/* frlist cleanup */
  	mutex_lock(&xqm->qm_dqfrlist_lock);
  	list_for_each_entry_safe(dqp, n, &xqm->qm_dqfrlist, q_freelist) {
  		xfs_dqlock(dqp);
3a8406f6d   Dave Chinner   xfs: convert the ...
175
176
177
178
179
180
181
  		list_del_init(&dqp->q_freelist);
  		xfs_Gqm->qm_dqfrlist_cnt--;
  		xfs_dqunlock(dqp);
  		xfs_qm_dqdestroy(dqp);
  	}
  	mutex_unlock(&xqm->qm_dqfrlist_lock);
  	mutex_destroy(&xqm->qm_dqfrlist_lock);
f0e2d93c2   Denys Vlasenko   [XFS] Remove unus...
182
  	kmem_free(xqm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
  }
  
  /*
   * Called at mount time to let XQM know that another file system is
   * starting quotas. This isn't crucial information as the individual mount
   * structures are pretty independent, but it helps the XQM keep a
   * global view of what's going on.
   */
  /* ARGSUSED */
  STATIC int
  xfs_qm_hold_quotafs_ref(
  	struct xfs_mount *mp)
  {
  	/*
  	 * Need to lock the xfs_Gqm structure for things like this. For example,
  	 * the structure could disappear between the entry to this routine and
  	 * a HOLD operation if not locked.
  	 */
e24945822   Christoph Hellwig   xfs: remove XFS_Q...
201
  	mutex_lock(&xfs_Gqm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

bdfb04301   Christoph Hellwig   xfs: replace KM_L...
203
  	if (!xfs_Gqm) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  		xfs_Gqm = xfs_Gqm_init();
38e712ab3   Julia Lawall   fs/xfs/quota: Add...
205
206
  		if (!xfs_Gqm) {
  			mutex_unlock(&xfs_Gqm_lock);
bdfb04301   Christoph Hellwig   xfs: replace KM_L...
207
  			return ENOMEM;
38e712ab3   Julia Lawall   fs/xfs/quota: Add...
208
  		}
bdfb04301   Christoph Hellwig   xfs: replace KM_L...
209
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
214
  	/*
  	 * We can keep a list of all filesystems with quotas mounted for
  	 * debugging and statistical purposes, but ...
  	 * Just take a reference and get out.
  	 */
e24945822   Christoph Hellwig   xfs: remove XFS_Q...
215
216
  	xfs_Gqm->qm_nrefs++;
  	mutex_unlock(&xfs_Gqm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
223
224
225
226
227
228
229
230
  
  	return 0;
  }
  
  
  /*
   * Release the reference that a filesystem took at mount time,
   * so that we know when we need to destroy the entire quota manager.
   */
  /* ARGSUSED */
  STATIC void
  xfs_qm_rele_quotafs_ref(
  	struct xfs_mount *mp)
  {
3a8406f6d   Dave Chinner   xfs: convert the ...
231
  	xfs_dquot_t	*dqp, *n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
  
  	ASSERT(xfs_Gqm);
  	ASSERT(xfs_Gqm->qm_nrefs > 0);
  
  	/*
  	 * Go thru the freelist and destroy all inactive dquots.
  	 */
3a8406f6d   Dave Chinner   xfs: convert the ...
239
  	mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240

3a8406f6d   Dave Chinner   xfs: convert the ...
241
  	list_for_each_entry_safe(dqp, n, &xfs_Gqm->qm_dqfrlist, q_freelist) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  		xfs_dqlock(dqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
  			ASSERT(dqp->q_mount == NULL);
  			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
e6a81f13a   Dave Chinner   xfs: convert the ...
246
  			ASSERT(list_empty(&dqp->q_hashlist));
3a25404b3   Dave Chinner   xfs: convert the ...
247
  			ASSERT(list_empty(&dqp->q_mplist));
3a8406f6d   Dave Chinner   xfs: convert the ...
248
249
  			list_del_init(&dqp->q_freelist);
  			xfs_Gqm->qm_dqfrlist_cnt--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
  			xfs_dqunlock(dqp);
  			xfs_qm_dqdestroy(dqp);
  		} else {
  			xfs_dqunlock(dqp);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  	}
3a8406f6d   Dave Chinner   xfs: convert the ...
256
  	mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
258
259
260
261
  
  	/*
  	 * Destroy the entire XQM. If somebody mounts with quotaon, this'll
  	 * be restarted.
  	 */
e24945822   Christoph Hellwig   xfs: remove XFS_Q...
262
263
  	mutex_lock(&xfs_Gqm_lock);
  	if (--xfs_Gqm->qm_nrefs == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
265
266
  		xfs_qm_destroy(xfs_Gqm);
  		xfs_Gqm = NULL;
  	}
e24945822   Christoph Hellwig   xfs: remove XFS_Q...
267
  	mutex_unlock(&xfs_Gqm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
   * Just destroy the quotainfo structure.
   */
  void
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
274
275
  xfs_qm_unmount(
  	struct xfs_mount	*mp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
277
  	if (mp->m_quotainfo) {
8112e9dc6   Christoph Hellwig   xfs: removed unus...
278
  		xfs_qm_dqpurge_all(mp, XFS_QMOPT_QUOTALL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  		xfs_qm_destroy_quotainfo(mp);
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
280
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
286
287
288
  }
  
  
  /*
   * This is called from xfs_mountfs to start quotas and initialize all
   * necessary data structures like quotainfo.  This is also responsible for
   * running a quotacheck as necessary.  We are guaranteed that the superblock
   * is consistently read in at this point.
53aa7915d   David Chinner   [XFS] Clean up qu...
289
290
291
   *
   * If we fail here, the mount will continue with quota turned off. We don't
   * need to inidicate success or failure at all.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
   */
53aa7915d   David Chinner   [XFS] Clean up qu...
293
  void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  xfs_qm_mount_quotas(
4249023a5   Christoph Hellwig   [XFS] cleanup xfs...
295
  	xfs_mount_t	*mp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  	int		error = 0;
  	uint		sbf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
  	/*
  	 * If quotas on realtime volumes is not supported, we disable
  	 * quotas immediately.
  	 */
  	if (mp->m_sb.sb_rextents) {
0b932cccb   Dave Chinner   xfs: Convert rema...
304
  		xfs_notice(mp, "Cannot turn on quotas for realtime filesystem");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
  		mp->m_qflags = 0;
  		goto write_changes;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
155ffd075   Nathan Scott   [XFS] Remove extr...
309

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
313
  	/*
  	 * Allocate the quotainfo structure inside the mount struct, and
  	 * create quotainode(s), and change/rev superblock if necessary.
  	 */
53aa7915d   David Chinner   [XFS] Clean up qu...
314
315
  	error = xfs_qm_init_quotainfo(mp);
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
324
325
  		/*
  		 * We must turn off quotas.
  		 */
  		ASSERT(mp->m_quotainfo == NULL);
  		mp->m_qflags = 0;
  		goto write_changes;
  	}
  	/*
  	 * If any of the quotas are not consistent, do a quotacheck.
  	 */
4249023a5   Christoph Hellwig   [XFS] cleanup xfs...
326
  	if (XFS_QM_NEED_QUOTACHECK(mp)) {
53aa7915d   David Chinner   [XFS] Clean up qu...
327
328
329
330
  		error = xfs_qm_quotacheck(mp);
  		if (error) {
  			/* Quotacheck failed and disabled quotas. */
  			return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  	}
646d5bdab   Donald Douwsma   [XFS] Invalidate ...
333
334
335
336
337
  	/* 
  	 * If one type of quotas is off, then it will lose its
  	 * quotachecked status, since we won't be doing accounting for
  	 * that type anymore.
  	 */
53aa7915d   David Chinner   [XFS] Clean up qu...
338
  	if (!XFS_IS_UQUOTA_ON(mp))
646d5bdab   Donald Douwsma   [XFS] Invalidate ...
339
  		mp->m_qflags &= ~XFS_UQUOTA_CHKD;
53aa7915d   David Chinner   [XFS] Clean up qu...
340
  	if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp)))
646d5bdab   Donald Douwsma   [XFS] Invalidate ...
341
  		mp->m_qflags &= ~XFS_OQUOTA_CHKD;
155ffd075   Nathan Scott   [XFS] Remove extr...
342

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
   write_changes:
  	/*
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
345
  	 * We actually don't have to acquire the m_sb_lock at all.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
  	 * This can only be called from mount, and that's single threaded. XXX
  	 */
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
348
  	spin_lock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  	sbf = mp->m_sb.sb_qflags;
  	mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL;
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
351
  	spin_unlock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
354
355
356
357
358
359
360
361
  
  	if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) {
  		if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) {
  			/*
  			 * We could only have been turning quotas off.
  			 * We aren't in very good shape actually because
  			 * the incore structures are convinced that quotas are
  			 * off, but the on disk superblock doesn't know that !
  			 */
  			ASSERT(!(XFS_IS_QUOTA_RUNNING(mp)));
534877869   Dave Chinner   xfs: convert xfs_...
362
363
  			xfs_alert(mp, "%s: Superblock update failed!",
  				__func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
  		}
  	}
  
  	if (error) {
534877869   Dave Chinner   xfs: convert xfs_...
368
  		xfs_warn(mp, "Failed to initialize disk quotas.");
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
369
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
  }
  
  /*
   * Called from the vfsops layer.
   */
e57481dc2   Christoph Hellwig   no explicit xfs_i...
376
  void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
  xfs_qm_unmount_quotas(
  	xfs_mount_t	*mp)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
388
389
390
391
  	/*
  	 * Release the dquots that root inode, et al might be holding,
  	 * before we flush quotas and blow away the quotainfo structure.
  	 */
  	ASSERT(mp->m_rootip);
  	xfs_qm_dqdetach(mp->m_rootip);
  	if (mp->m_rbmip)
  		xfs_qm_dqdetach(mp->m_rbmip);
  	if (mp->m_rsumip)
  		xfs_qm_dqdetach(mp->m_rsumip);
  
  	/*
e57481dc2   Christoph Hellwig   no explicit xfs_i...
392
  	 * Release the quota inodes.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
  	if (mp->m_quotainfo) {
e57481dc2   Christoph Hellwig   no explicit xfs_i...
395
396
397
  		if (mp->m_quotainfo->qi_uquotaip) {
  			IRELE(mp->m_quotainfo->qi_uquotaip);
  			mp->m_quotainfo->qi_uquotaip = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  		}
e57481dc2   Christoph Hellwig   no explicit xfs_i...
399
400
401
  		if (mp->m_quotainfo->qi_gquotaip) {
  			IRELE(mp->m_quotainfo->qi_gquotaip);
  			mp->m_quotainfo->qi_gquotaip = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
403
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
407
408
409
  }
  
  /*
   * Flush all dquots of the given file system to disk. The dquots are
   * _not_ purged from memory here, just their data written to disk.
   */
ba0f32d46   Christoph Hellwig   [XFS] mark variou...
410
  STATIC int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  xfs_qm_dqflush_all(
8a7b8a89a   Christoph Hellwig   xfs: access quota...
412
413
  	struct xfs_mount	*mp,
  	int			sync_mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
415
416
417
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
  	int			recl;
  	struct xfs_dquot	*dqp;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
418
  	int			error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419

8a7b8a89a   Christoph Hellwig   xfs: access quota...
420
  	if (!q)
014c2544e   Jesper Juhl   return statement ...
421
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
  again:
8a7b8a89a   Christoph Hellwig   xfs: access quota...
423
424
  	mutex_lock(&q->qi_dqlist_lock);
  	list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
429
  		xfs_dqlock(dqp);
  		if (! XFS_DQ_IS_DIRTY(dqp)) {
  			xfs_dqunlock(dqp);
  			continue;
  		}
0b1b213fc   Christoph Hellwig   xfs: event tracin...
430

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
  		/* XXX a sentinel would be better */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
432
  		recl = q->qi_dqreclaims;
e1f49cf20   David Chinner   [XFS] replace dqu...
433
  		if (!xfs_dqflock_nowait(dqp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
440
441
442
443
444
445
446
  			/*
  			 * If we can't grab the flush lock then check
  			 * to see if the dquot has been flushed delayed
  			 * write.  If so, grab its buffer and send it
  			 * out immediately.  We'll be able to acquire
  			 * the flush lock when the I/O completes.
  			 */
  			xfs_qm_dqflock_pushbuf_wait(dqp);
  		}
  		/*
  		 * Let go of the mplist lock. We don't want to hold it
  		 * across a disk write.
  		 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
447
  		mutex_unlock(&q->qi_dqlist_lock);
20026d920   Dave Chinner   xfs: kill the unu...
448
  		error = xfs_qm_dqflush(dqp, sync_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
  		xfs_dqunlock(dqp);
  		if (error)
014c2544e   Jesper Juhl   return statement ...
451
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452

8a7b8a89a   Christoph Hellwig   xfs: access quota...
453
454
455
  		mutex_lock(&q->qi_dqlist_lock);
  		if (recl != q->qi_dqreclaims) {
  			mutex_unlock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
458
459
  			/* XXX restart limit */
  			goto again;
  		}
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
460
  	mutex_unlock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  	/* return ! busy */
014c2544e   Jesper Juhl   return statement ...
462
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
467
468
469
  }
  /*
   * Release the group dquot pointers the user dquots may be
   * carrying around as a hint. mplist is locked on entry and exit.
   */
  STATIC void
  xfs_qm_detach_gdquots(
8a7b8a89a   Christoph Hellwig   xfs: access quota...
470
  	struct xfs_mount	*mp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
472
473
474
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
  	struct xfs_dquot	*dqp, *gdqp;
  	int			nrecl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
  
   again:
8a7b8a89a   Christoph Hellwig   xfs: access quota...
477
478
  	ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
  	list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
485
486
487
488
489
490
  		xfs_dqlock(dqp);
  		if ((gdqp = dqp->q_gdquot)) {
  			xfs_dqlock(gdqp);
  			dqp->q_gdquot = NULL;
  		}
  		xfs_dqunlock(dqp);
  
  		if (gdqp) {
  			/*
  			 * Can't hold the mplist lock across a dqput.
  			 * XXXmust convert to marker based iterations here.
  			 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
491
492
  			nrecl = q->qi_dqreclaims;
  			mutex_unlock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
  			xfs_qm_dqput(gdqp);
8a7b8a89a   Christoph Hellwig   xfs: access quota...
494
495
  			mutex_lock(&q->qi_dqlist_lock);
  			if (nrecl != q->qi_dqreclaims)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
  				goto again;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
499
500
501
502
503
504
505
506
507
508
  	}
  }
  
  /*
   * Go through all the incore dquots of this file system and take them
   * off the mplist and hashlist, if the dquot type matches the dqtype
   * parameter. This is used when turning off quota accounting for
   * users and/or groups, as well as when the filesystem is unmounting.
   */
  STATIC int
  xfs_qm_dqpurge_int(
8a7b8a89a   Christoph Hellwig   xfs: access quota...
509
510
  	struct xfs_mount	*mp,
  	uint			flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
512
513
514
515
516
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
  	struct xfs_dquot	*dqp, *n;
  	uint			dqtype;
  	int			nrecl;
  	int			nmisses;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517

8a7b8a89a   Christoph Hellwig   xfs: access quota...
518
  	if (!q)
014c2544e   Jesper Juhl   return statement ...
519
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  
  	dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0;
c8ad20ffe   Nathan Scott   [XFS] Add support...
522
  	dqtype |= (flags & XFS_QMOPT_PQUOTA) ? XFS_DQ_PROJ : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  	dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
524
  	mutex_lock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
528
529
530
531
532
533
534
535
  
  	/*
  	 * In the first pass through all incore dquots of this filesystem,
  	 * we release the group dquot pointers the user dquots may be
  	 * carrying around as a hint. We need to do this irrespective of
  	 * what's being turned off.
  	 */
  	xfs_qm_detach_gdquots(mp);
  
        again:
  	nmisses = 0;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
536
  	ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
  	/*
  	 * Try to get rid of all of the unwanted dquots. The idea is to
  	 * get them off mplist and hashlist, but leave them on freelist.
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
541
  	list_for_each_entry_safe(dqp, n, &q->qi_dqlist, q_mplist) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
  		/*
  		 * It's OK to look at the type without taking dqlock here.
  		 * We're holding the mplist lock here, and that's needed for
  		 * a dqreclaim.
  		 */
3a25404b3   Dave Chinner   xfs: convert the ...
547
  		if ((dqp->dq_flags & dqtype) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

c9a192dcf   Christoph Hellwig   xfs: sanitize qh_...
550
  		if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
551
552
  			nrecl = q->qi_dqreclaims;
  			mutex_unlock(&q->qi_dqlist_lock);
c9a192dcf   Christoph Hellwig   xfs: sanitize qh_...
553
  			mutex_lock(&dqp->q_hash->qh_lock);
8a7b8a89a   Christoph Hellwig   xfs: access quota...
554
  			mutex_lock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
557
558
559
560
561
  
  			/*
  			 * XXXTheoretically, we can get into a very long
  			 * ping pong game here.
  			 * No one can be adding dquots to the mplist at
  			 * this point, but somebody might be taking things off.
  			 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
562
  			if (nrecl != q->qi_dqreclaims) {
c9a192dcf   Christoph Hellwig   xfs: sanitize qh_...
563
  				mutex_unlock(&dqp->q_hash->qh_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
568
569
570
571
  				goto again;
  			}
  		}
  
  		/*
  		 * Take the dquot off the mplist and hashlist. It may remain on
  		 * freelist in INACTIVE state.
  		 */
4f0e8a981   Denys Vlasenko   [XFS] Remove unus...
572
  		nmisses += xfs_qm_dqpurge(dqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
574
  	mutex_unlock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  	return nmisses;
  }
  
  int
  xfs_qm_dqpurge_all(
  	xfs_mount_t	*mp,
  	uint		flags)
  {
  	int		ndquots;
  
  	/*
  	 * Purge the dquot cache.
  	 * None of the dquots should really be busy at this point.
  	 */
  	if (mp->m_quotainfo) {
  		while ((ndquots = xfs_qm_dqpurge_int(mp, flags))) {
  			delay(ndquots * 10);
  		}
  	}
  	return 0;
  }
  
  STATIC int
  xfs_qm_dqattach_one(
  	xfs_inode_t	*ip,
  	xfs_dqid_t	id,
  	uint		type,
  	uint		doalloc,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
605
606
607
  	xfs_dquot_t	*udqhint, /* hint */
  	xfs_dquot_t	**IO_idqpp)
  {
  	xfs_dquot_t	*dqp;
  	int		error;
579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
608
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  	error = 0;
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
610

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
615
  	/*
  	 * See if we already have it in the inode itself. IO_idqpp is
  	 * &i_udquot or &i_gdquot. This made the code look weird, but
  	 * made the logic a lot simpler.
  	 */
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
616
617
  	dqp = *IO_idqpp;
  	if (dqp) {
0b1b213fc   Christoph Hellwig   xfs: event tracin...
618
  		trace_xfs_dqattach_found(dqp);
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
619
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
  	}
  
  	/*
  	 * udqhint is the i_udquot field in inode, and is non-NULL only
c8ad20ffe   Nathan Scott   [XFS] Add support...
624
  	 * when the type arg is group/project. Its purpose is to save a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
  	 * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
  	 * the user dquot.
  	 */
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
628
629
  	if (udqhint) {
  		ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  		xfs_dqlock(udqhint);
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
631
632
633
634
635
636
637
638
639
640
641
642
643
  		/*
  		 * No need to take dqlock to look at the id.
  		 *
  		 * The ID can't change until it gets reclaimed, and it won't
  		 * be reclaimed as long as we have a ref from inode and we
  		 * hold the ilock.
  		 */
  		dqp = udqhint->q_gdquot;
  		if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
  			xfs_dqlock(dqp);
  			XFS_DQHOLD(dqp);
  			ASSERT(*IO_idqpp == NULL);
  			*IO_idqpp = dqp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  			xfs_dqunlock(dqp);
  			xfs_dqunlock(udqhint);
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
646
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  		}
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
648
649
650
651
652
653
654
  
  		/*
  		 * We can't hold a dquot lock when we call the dqget code.
  		 * We'll deadlock in no time, because of (not conforming to)
  		 * lock ordering - the inodelock comes before any dquot lock,
  		 * and we may drop and reacquire the ilock in xfs_qm_dqget().
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  		xfs_dqunlock(udqhint);
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
656
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
658
659
660
661
662
663
  	/*
  	 * Find the dquot from somewhere. This bumps the
  	 * reference count of dquot and returns it locked.
  	 * This can return ENOENT if dquot didn't exist on
  	 * disk and we didn't ask it to allocate;
  	 * ESRCH if quotas got turned off suddenly.
  	 */
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
664
665
666
  	error = xfs_qm_dqget(ip->i_mount, ip, id, type, XFS_QMOPT_DOWARN, &dqp);
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667

0b1b213fc   Christoph Hellwig   xfs: event tracin...
668
  	trace_xfs_dqattach_get(dqp);
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
669

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
  	/*
  	 * dqget may have dropped and re-acquired the ilock, but it guarantees
  	 * that the dquot returned is the one that should go in the inode.
  	 */
  	*IO_idqpp = dqp;
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
675
676
  	xfs_dqunlock(dqp);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
680
681
682
683
  }
  
  
  /*
   * Given a udquot and gdquot, attach a ptr to the group dquot in the
   * udquot as a hint for future lookups. The idea sounds simple, but the
   * execution isn't, because the udquot might have a group dquot attached
c41564b5a   Nathan Scott   [XFS] We really s...
684
   * already and getting rid of that gets us into lock ordering constraints.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
   * The process is complicated more by the fact that the dquots may or may not
   * be locked on entry.
   */
  STATIC void
  xfs_qm_dqattach_grouphint(
  	xfs_dquot_t	*udq,
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
691
  	xfs_dquot_t	*gdq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  {
  	xfs_dquot_t	*tmp;
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
694
  	xfs_dqlock(udq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
697
  
  	if ((tmp = udq->q_gdquot)) {
  		if (tmp == gdq) {
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
698
  			xfs_dqunlock(udq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
701
702
703
704
705
706
707
  			return;
  		}
  
  		udq->q_gdquot = NULL;
  		/*
  		 * We can't keep any dqlocks when calling dqrele,
  		 * because the freelist lock comes before dqlocks.
  		 */
  		xfs_dqunlock(udq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
716
717
718
719
  		/*
  		 * we took a hard reference once upon a time in dqget,
  		 * so give it back when the udquot no longer points at it
  		 * dqput() does the unlocking of the dquot.
  		 */
  		xfs_qm_dqrele(tmp);
  
  		xfs_dqlock(udq);
  		xfs_dqlock(gdq);
  
  	} else {
  		ASSERT(XFS_DQ_IS_LOCKED(udq));
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
720
  		xfs_dqlock(gdq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
726
727
728
729
730
731
732
  	}
  
  	ASSERT(XFS_DQ_IS_LOCKED(udq));
  	ASSERT(XFS_DQ_IS_LOCKED(gdq));
  	/*
  	 * Somebody could have attached a gdquot here,
  	 * when we dropped the uqlock. If so, just do nothing.
  	 */
  	if (udq->q_gdquot == NULL) {
  		XFS_DQHOLD(gdq);
  		udq->q_gdquot = gdq;
  	}
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
733
734
735
  
  	xfs_dqunlock(gdq);
  	xfs_dqunlock(udq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
739
  }
  
  
  /*
c8ad20ffe   Nathan Scott   [XFS] Add support...
740
741
   * Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON
   * into account.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
   * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
746
   * Inode may get unlocked and relocked in here, and the caller must deal with
   * the consequences.
   */
  int
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
747
  xfs_qm_dqattach_locked(
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
751
752
753
  	xfs_inode_t	*ip,
  	uint		flags)
  {
  	xfs_mount_t	*mp = ip->i_mount;
  	uint		nquotas = 0;
  	int		error = 0;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
754
755
756
757
758
  	if (!XFS_IS_QUOTA_RUNNING(mp) ||
  	    !XFS_IS_QUOTA_ON(mp) ||
  	    !XFS_NOT_DQATTACHED(mp, ip) ||
  	    ip->i_ino == mp->m_sb.sb_uquotino ||
  	    ip->i_ino == mp->m_sb.sb_gquotino)
014c2544e   Jesper Juhl   return statement ...
759
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
761
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
765
  
  	if (XFS_IS_UQUOTA_ON(mp)) {
  		error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
  						flags & XFS_QMOPT_DQALLOC,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
767
768
769
770
  						NULL, &ip->i_udquot);
  		if (error)
  			goto done;
  		nquotas++;
  	}
579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
771
772
  
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
c8ad20ffe   Nathan Scott   [XFS] Add support...
773
774
775
776
  	if (XFS_IS_OQUOTA_ON(mp)) {
  		error = XFS_IS_GQUOTA_ON(mp) ?
  			xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
  						flags & XFS_QMOPT_DQALLOC,
c8ad20ffe   Nathan Scott   [XFS] Add support...
777
  						ip->i_udquot, &ip->i_gdquot) :
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
778
  			xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
  						flags & XFS_QMOPT_DQALLOC,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
  						ip->i_udquot, &ip->i_gdquot);
  		/*
  		 * Don't worry about the udquot that we may have
  		 * attached above. It'll get detached, if not already.
  		 */
  		if (error)
  			goto done;
  		nquotas++;
  	}
  
  	/*
  	 * Attach this group quota to the user quota as a hint.
  	 * This WON'T, in general, result in a thrash.
  	 */
  	if (nquotas == 2) {
579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
795
  		ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  		ASSERT(ip->i_udquot);
  		ASSERT(ip->i_gdquot);
  
  		/*
  		 * We may or may not have the i_udquot locked at this point,
  		 * but this check is OK since we don't depend on the i_gdquot to
  		 * be accurate 100% all the time. It is just a hint, and this
  		 * will succeed in general.
  		 */
  		if (ip->i_udquot->q_gdquot == ip->i_gdquot)
  			goto done;
  		/*
  		 * Attach i_gdquot to the gdquot hint inside the i_udquot.
  		 */
8e9b6e7fa   Christoph Hellwig   xfs: remove the u...
810
  		xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  	}
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
812
   done:
ea15ab3cd   Christoph Hellwig   xfs: remove the d...
813
814
  #ifdef DEBUG
  	if (!error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
  		if (XFS_IS_UQUOTA_ON(mp))
  			ASSERT(ip->i_udquot);
c8ad20ffe   Nathan Scott   [XFS] Add support...
817
  		if (XFS_IS_OQUOTA_ON(mp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
  			ASSERT(ip->i_gdquot);
  	}
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
820
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
  #endif
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
822
823
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
825
826
827
828
829
830
831
832
833
834
  int
  xfs_qm_dqattach(
  	struct xfs_inode	*ip,
  	uint			flags)
  {
  	int			error;
  
  	xfs_ilock(ip, XFS_ILOCK_EXCL);
  	error = xfs_qm_dqattach_locked(ip, flags);
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835

014c2544e   Jesper Juhl   return statement ...
836
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
842
843
844
845
846
847
848
849
  }
  
  /*
   * Release dquots (and their references) if any.
   * The inode should be locked EXCL except when this's called by
   * xfs_ireclaim.
   */
  void
  xfs_qm_dqdetach(
  	xfs_inode_t	*ip)
  {
  	if (!(ip->i_udquot || ip->i_gdquot))
  		return;
0b1b213fc   Christoph Hellwig   xfs: event tracin...
850
  	trace_xfs_dquot_dqdetach(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
  	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino);
  	ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
854
855
856
857
858
859
860
861
  	if (ip->i_udquot) {
  		xfs_qm_dqrele(ip->i_udquot);
  		ip->i_udquot = NULL;
  	}
  	if (ip->i_gdquot) {
  		xfs_qm_dqrele(ip->i_gdquot);
  		ip->i_gdquot = NULL;
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
  int
  xfs_qm_sync(
8a7b8a89a   Christoph Hellwig   xfs: access quota...
864
865
  	struct xfs_mount	*mp,
  	int			flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
867
868
869
870
  	struct xfs_quotainfo	*q = mp->m_quotainfo;
  	int			recl, restarts;
  	struct xfs_dquot	*dqp;
  	int			error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
872
  	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
d757762bf   Donald Douwsma   [XFS] Fix dbflush...
873
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
  	restarts = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
  
    again:
8a7b8a89a   Christoph Hellwig   xfs: access quota...
877
  	mutex_lock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
883
  	/*
  	 * dqpurge_all() also takes the mplist lock and iterate thru all dquots
  	 * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared
  	 * when we have the mplist lock, we know that dquots will be consistent
  	 * as long as we have it locked.
  	 */
3a25404b3   Dave Chinner   xfs: convert the ...
884
  	if (!XFS_IS_QUOTA_ON(mp)) {
8a7b8a89a   Christoph Hellwig   xfs: access quota...
885
  		mutex_unlock(&q->qi_dqlist_lock);
014c2544e   Jesper Juhl   return statement ...
886
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
888
889
  	ASSERT(mutex_is_locked(&q->qi_dqlist_lock));
  	list_for_each_entry(dqp, &q->qi_dqlist, q_mplist) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
893
894
  		/*
  		 * If this is vfs_sync calling, then skip the dquots that
  		 * don't 'seem' to be dirty. ie. don't acquire dqlock.
  		 * This is very similar to what xfs_sync does with inodes.
  		 */
8b5403a6d   Christoph Hellwig   xfs: remove SYNC_...
895
896
  		if (flags & SYNC_TRYLOCK) {
  			if (!XFS_DQ_IS_DIRTY(dqp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
  				continue;
8b5403a6d   Christoph Hellwig   xfs: remove SYNC_...
898
  			if (!xfs_qm_dqlock_nowait(dqp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  				continue;
  		} else {
  			xfs_dqlock(dqp);
  		}
  
  		/*
  		 * Now, find out for sure if this dquot is dirty or not.
  		 */
  		if (! XFS_DQ_IS_DIRTY(dqp)) {
  			xfs_dqunlock(dqp);
  			continue;
  		}
  
  		/* XXX a sentinel would be better */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
913
  		recl = q->qi_dqreclaims;
e1f49cf20   David Chinner   [XFS] replace dqu...
914
  		if (!xfs_dqflock_nowait(dqp)) {
8b5403a6d   Christoph Hellwig   xfs: remove SYNC_...
915
  			if (flags & SYNC_TRYLOCK) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
917
918
919
920
  				xfs_dqunlock(dqp);
  				continue;
  			}
  			/*
  			 * If we can't grab the flush lock then if the caller
c41564b5a   Nathan Scott   [XFS] We really s...
921
  			 * really wanted us to give this our best shot, so
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
923
  			 * see if we can give a push to the buffer before we wait
  			 * on the flush lock. At this point, we know that
c41564b5a   Nathan Scott   [XFS] We really s...
924
  			 * even though the dquot is being flushed,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
929
930
931
932
  			 * it has (new) dirty data.
  			 */
  			xfs_qm_dqflock_pushbuf_wait(dqp);
  		}
  		/*
  		 * Let go of the mplist lock. We don't want to hold it
  		 * across a disk write
  		 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
933
  		mutex_unlock(&q->qi_dqlist_lock);
20026d920   Dave Chinner   xfs: kill the unu...
934
  		error = xfs_qm_dqflush(dqp, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
936
  		xfs_dqunlock(dqp);
  		if (error && XFS_FORCED_SHUTDOWN(mp))
014c2544e   Jesper Juhl   return statement ...
937
  			return 0;	/* Need to prevent umount failure */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  		else if (error)
014c2544e   Jesper Juhl   return statement ...
939
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940

8a7b8a89a   Christoph Hellwig   xfs: access quota...
941
942
  		mutex_lock(&q->qi_dqlist_lock);
  		if (recl != q->qi_dqreclaims) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
  			if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS)
  				break;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
945
  			mutex_unlock(&q->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
948
  			goto again;
  		}
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
949
  	mutex_unlock(&q->qi_dqlist_lock);
014c2544e   Jesper Juhl   return statement ...
950
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
  }
a4edd1da2   Christoph Hellwig   xfs: add a separa...
952
953
954
955
956
957
958
  /*
   * The hash chains and the mplist use the same xfs_dqhash structure as
   * their list head, but we can take the mplist qh_lock and one of the
   * hash qh_locks at the same time without any problem as they aren't
   * related.
   */
  static struct lock_class_key xfs_quota_mplist_class;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
962
963
  
  /*
   * This initializes all the quota information that's kept in the
   * mount structure
   */
ba0f32d46   Christoph Hellwig   [XFS] mark variou...
964
  STATIC int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
965
966
967
968
969
970
971
972
973
974
975
976
977
  xfs_qm_init_quotainfo(
  	xfs_mount_t	*mp)
  {
  	xfs_quotainfo_t *qinf;
  	int		error;
  	xfs_dquot_t	*dqp;
  
  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
  
  	/*
  	 * Tell XQM that we exist as soon as possible.
  	 */
  	if ((error = xfs_qm_hold_quotafs_ref(mp))) {
014c2544e   Jesper Juhl   return statement ...
978
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
980
981
982
983
984
985
986
987
  	}
  
  	qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
  
  	/*
  	 * See if quotainodes are setup, and if not, allocate them,
  	 * and change the superblock accordingly.
  	 */
  	if ((error = xfs_qm_init_quotainos(mp))) {
f0e2d93c2   Denys Vlasenko   [XFS] Remove unus...
988
  		kmem_free(qinf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  		mp->m_quotainfo = NULL;
014c2544e   Jesper Juhl   return statement ...
990
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
  	}
3a25404b3   Dave Chinner   xfs: convert the ...
992
993
994
  	INIT_LIST_HEAD(&qinf->qi_dqlist);
  	mutex_init(&qinf->qi_dqlist_lock);
  	lockdep_set_class(&qinf->qi_dqlist_lock, &xfs_quota_mplist_class);
a4edd1da2   Christoph Hellwig   xfs: add a separa...
995

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
998
  	qinf->qi_dqreclaims = 0;
  
  	/* mutex used to serialize quotaoffs */
794ee1bae   Jes Sorensen   [PATCH] mutex sub...
999
  	mutex_init(&qinf->qi_quotaofflock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  
  	/* Precalc some constants */
  	qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
  	ASSERT(qinf->qi_dqchunklen);
  	qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen);
  	do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t));
  
  	mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);
  
  	/*
  	 * We try to get the limits from the superuser's limits fields.
  	 * This is quite hacky, but it is standard quota practice.
  	 * We look at the USR dquot with id == 0 first, but if user quotas
  	 * are not enabled we goto the GRP dquot with id == 0.
  	 * We don't really care to keep separate default limits for user
  	 * and group quotas, at least not at this point.
  	 */
  	error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0,
c8ad20ffe   Nathan Scott   [XFS] Add support...
1018
1019
1020
  			     XFS_IS_UQUOTA_RUNNING(mp) ? XFS_DQ_USER : 
  			     (XFS_IS_GQUOTA_RUNNING(mp) ? XFS_DQ_GROUP :
  				XFS_DQ_PROJ),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
  			     XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN,
  			     &dqp);
  	if (! error) {
  		xfs_disk_dquot_t	*ddqp = &dqp->q_core;
  
  		/*
  		 * The warnings and timers set the grace period given to
  		 * a user or group before he or she can not perform any
  		 * more writing. If it is zero, a default is used.
  		 */
1149d96ae   Christoph Hellwig   [XFS] endianess a...
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
  		qinf->qi_btimelimit = ddqp->d_btimer ?
  			be32_to_cpu(ddqp->d_btimer) : XFS_QM_BTIMELIMIT;
  		qinf->qi_itimelimit = ddqp->d_itimer ?
  			be32_to_cpu(ddqp->d_itimer) : XFS_QM_ITIMELIMIT;
  		qinf->qi_rtbtimelimit = ddqp->d_rtbtimer ?
  			be32_to_cpu(ddqp->d_rtbtimer) : XFS_QM_RTBTIMELIMIT;
  		qinf->qi_bwarnlimit = ddqp->d_bwarns ?
  			be16_to_cpu(ddqp->d_bwarns) : XFS_QM_BWARNLIMIT;
  		qinf->qi_iwarnlimit = ddqp->d_iwarns ?
  			be16_to_cpu(ddqp->d_iwarns) : XFS_QM_IWARNLIMIT;
  		qinf->qi_rtbwarnlimit = ddqp->d_rtbwarns ?
  			be16_to_cpu(ddqp->d_rtbwarns) : XFS_QM_RTBWARNLIMIT;
  		qinf->qi_bhardlimit = be64_to_cpu(ddqp->d_blk_hardlimit);
  		qinf->qi_bsoftlimit = be64_to_cpu(ddqp->d_blk_softlimit);
  		qinf->qi_ihardlimit = be64_to_cpu(ddqp->d_ino_hardlimit);
  		qinf->qi_isoftlimit = be64_to_cpu(ddqp->d_ino_softlimit);
  		qinf->qi_rtbhardlimit = be64_to_cpu(ddqp->d_rtb_hardlimit);
  		qinf->qi_rtbsoftlimit = be64_to_cpu(ddqp->d_rtb_softlimit);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
   
  		/*
  		 * We sent the XFS_QMOPT_DQSUSER flag to dqget because
  		 * we don't want this dquot cached. We haven't done a
  		 * quotacheck yet, and quotacheck doesn't like incore dquots.
  		 */
  		xfs_qm_dqdestroy(dqp);
  	} else {
  		qinf->qi_btimelimit = XFS_QM_BTIMELIMIT;
  		qinf->qi_itimelimit = XFS_QM_ITIMELIMIT;
  		qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT;
  		qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT;
  		qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT;
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
1062
  		qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
  	}
014c2544e   Jesper Juhl   return statement ...
1064
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
  }
  
  
  /*
   * Gets called when unmounting a filesystem or when all quotas get
   * turned off.
   * This purges the quota inodes, destroys locks and frees itself.
   */
  void
  xfs_qm_destroy_quotainfo(
  	xfs_mount_t	*mp)
  {
  	xfs_quotainfo_t *qi;
  
  	qi = mp->m_quotainfo;
  	ASSERT(qi != NULL);
  	ASSERT(xfs_Gqm != NULL);
  
  	/*
  	 * Release the reference that XQM kept, so that we know
  	 * when the XQM structure should be freed. We cannot assume
  	 * that xfs_Gqm is non-null after this point.
  	 */
  	xfs_qm_rele_quotafs_ref(mp);
3a25404b3   Dave Chinner   xfs: convert the ...
1089
1090
  	ASSERT(list_empty(&qi->qi_dqlist));
  	mutex_destroy(&qi->qi_dqlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091
1092
  
  	if (qi->qi_uquotaip) {
26cc00218   Christoph Hellwig   [XFS] s/XFS_PURGE...
1093
  		IRELE(qi->qi_uquotaip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1094
1095
1096
  		qi->qi_uquotaip = NULL; /* paranoia */
  	}
  	if (qi->qi_gquotaip) {
26cc00218   Christoph Hellwig   [XFS] s/XFS_PURGE...
1097
  		IRELE(qi->qi_gquotaip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
  		qi->qi_gquotaip = NULL;
  	}
  	mutex_destroy(&qi->qi_quotaofflock);
f0e2d93c2   Denys Vlasenko   [XFS] Remove unus...
1101
  	kmem_free(qi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
  	mp->m_quotainfo = NULL;
  }
  
  
  
  /* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */
  
  /* ARGSUSED */
  STATIC void
  xfs_qm_list_init(
  	xfs_dqlist_t	*list,
  	char		*str,
  	int		n)
  {
794ee1bae   Jes Sorensen   [PATCH] mutex sub...
1116
  	mutex_init(&list->qh_lock);
e6a81f13a   Dave Chinner   xfs: convert the ...
1117
  	INIT_LIST_HEAD(&list->qh_list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
  	list->qh_version = 0;
  	list->qh_nelems = 0;
  }
  
  STATIC void
  xfs_qm_list_destroy(
  	xfs_dqlist_t	*list)
  {
  	mutex_destroy(&(list->qh_lock));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
  /*
   * Create an inode and return with a reference already taken, but unlocked
   * This is how we create quota inodes
   */
  STATIC int
  xfs_qm_qino_alloc(
  	xfs_mount_t	*mp,
  	xfs_inode_t	**ip,
  	__int64_t	sbfields,
  	uint		flags)
  {
  	xfs_trans_t	*tp;
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1141
  	int		committed;
061f7209b   Nathan Scott   [XFS] Do not inhe...
1142
  	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
1145
1146
1147
1148
  	if ((error = xfs_trans_reserve(tp,
  				      XFS_QM_QINOCREATE_SPACE_RES(mp),
  				      XFS_CREATE_LOG_RES(mp), 0,
  				      XFS_TRANS_PERM_LOG_RES,
  				      XFS_CREATE_LOG_COUNT))) {
  		xfs_trans_cancel(tp, 0);
014c2544e   Jesper Juhl   return statement ...
1149
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151

6c77b0ea1   Christoph Hellwig   xfs: remove xfs_c...
1152
1153
  	error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, &committed);
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
  		xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
  				 XFS_TRANS_ABORT);
014c2544e   Jesper Juhl   return statement ...
1156
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
  	}
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
1161
1162
1163
  	 * Make the changes in the superblock, and log those too.
  	 * sbfields arg may contain fields other than *QUOTINO;
  	 * VERSIONNUM for example.
  	 */
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
1164
  	spin_lock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
  	if (flags & XFS_QMOPT_SBVERSION) {
621187099   Eric Sandeen   [XFS] remove shou...
1166
  		ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
1168
1169
1170
  		ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
  				   XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
  		       (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
  			XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
621187099   Eric Sandeen   [XFS] remove shou...
1171
  		xfs_sb_version_addquota(&mp->m_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
1176
  		mp->m_sb.sb_uquotino = NULLFSINO;
  		mp->m_sb.sb_gquotino = NULLFSINO;
  
  		/* qflags will get updated _after_ quotacheck */
  		mp->m_sb.sb_qflags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1177
1178
1179
1180
1181
  	}
  	if (flags & XFS_QMOPT_UQUOTA)
  		mp->m_sb.sb_uquotino = (*ip)->i_ino;
  	else
  		mp->m_sb.sb_gquotino = (*ip)->i_ino;
3685c2a1d   Eric Sandeen   [XFS] Unwrap XFS_...
1182
  	spin_unlock(&mp->m_sb_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1183
  	xfs_mod_sb(tp, sbfields);
1c72bf900   Eric Sandeen   [XFS] The last ar...
1184
  	if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) {
534877869   Dave Chinner   xfs: convert xfs_...
1185
  		xfs_alert(mp, "%s failed (error %d)!", __func__, error);
014c2544e   Jesper Juhl   return statement ...
1186
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1187
  	}
014c2544e   Jesper Juhl   return statement ...
1188
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
  }
5b1397385   David Chinner   [XFS] xfs_qm_rese...
1190
  STATIC void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
1192
1193
1194
1195
1196
1197
1198
  xfs_qm_reset_dqcounts(
  	xfs_mount_t	*mp,
  	xfs_buf_t	*bp,
  	xfs_dqid_t	id,
  	uint		type)
  {
  	xfs_disk_dquot_t	*ddq;
  	int			j;
0b1b213fc   Christoph Hellwig   xfs: event tracin...
1199
  	trace_xfs_reset_dqcounts(bp, _RET_IP_);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200
1201
1202
1203
1204
1205
1206
  	/*
  	 * Reset all counters and timers. They'll be
  	 * started afresh by xfs_qm_quotacheck.
  	 */
  #ifdef DEBUG
  	j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
  	do_div(j, sizeof(xfs_dqblk_t));
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1207
  	ASSERT(mp->m_quotainfo->qi_dqperchunk == j);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  #endif
629260444   Chandra Seetharaman   xfs: Remove the m...
1209
  	ddq = bp->b_addr;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1210
  	for (j = 0; j < mp->m_quotainfo->qi_dqperchunk; j++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
1212
1213
  		/*
  		 * Do a sanity check, and if needed, repair the dqblk. Don't
  		 * output any warnings because it's perfectly possible to
c41564b5a   Nathan Scott   [XFS] We really s...
1214
  		 * find uninitialised dquot blks. See comment in xfs_qm_dqcheck.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
  		 */
a0fa2b679   Dave Chinner   xfs: Convert xlog...
1216
  		(void) xfs_qm_dqcheck(mp, ddq, id+j, type, XFS_QMOPT_DQREPAIR,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
  				      "xfs_quotacheck");
1149d96ae   Christoph Hellwig   [XFS] endianess a...
1218
1219
1220
1221
1222
1223
1224
1225
1226
  		ddq->d_bcount = 0;
  		ddq->d_icount = 0;
  		ddq->d_rtbcount = 0;
  		ddq->d_btimer = 0;
  		ddq->d_itimer = 0;
  		ddq->d_rtbtimer = 0;
  		ddq->d_bwarns = 0;
  		ddq->d_iwarns = 0;
  		ddq->d_rtbwarns = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
1228
  		ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
  }
  
  STATIC int
  xfs_qm_dqiter_bufs(
  	xfs_mount_t	*mp,
  	xfs_dqid_t	firstid,
  	xfs_fsblock_t	bno,
  	xfs_filblks_t	blkcnt,
  	uint		flags)
  {
  	xfs_buf_t	*bp;
  	int		error;
c8ad20ffe   Nathan Scott   [XFS] Add support...
1241
  	int		type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1242
1243
  
  	ASSERT(blkcnt > 0);
c8ad20ffe   Nathan Scott   [XFS] Add support...
1244
1245
  	type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER :
  		(flags & XFS_QMOPT_PQUOTA ? XFS_DQ_PROJ : XFS_DQ_GROUP);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
  	error = 0;
  
  	/*
  	 * Blkcnt arg can be a very big number, and might even be
  	 * larger than the log itself. So, we have to break it up into
  	 * manageable-sized transactions.
  	 * Note that we don't start a permanent transaction here; we might
  	 * not be able to get a log reservation for the whole thing up front,
  	 * and we don't really care to either, because we just discard
  	 * everything if we were to crash in the middle of this loop.
  	 */
  	while (blkcnt--) {
  		error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
  			      XFS_FSB_TO_DADDR(mp, bno),
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1260
  			      mp->m_quotainfo->qi_dqchunklen, 0, &bp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261
1262
  		if (error)
  			break;
5b1397385   David Chinner   [XFS] xfs_qm_rese...
1263
  		xfs_qm_reset_dqcounts(mp, bp, firstid, type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
1265
1266
1267
1268
  		xfs_bdwrite(mp, bp);
  		/*
  		 * goto the next block.
  		 */
  		bno++;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1269
  		firstid += mp->m_quotainfo->qi_dqperchunk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1270
  	}
014c2544e   Jesper Juhl   return statement ...
1271
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
1274
  }
  
  /*
c8ad20ffe   Nathan Scott   [XFS] Add support...
1275
   * Iterate over all allocated USR/GRP/PRJ dquots in the system, calling a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
   * caller supplied function for every chunk of dquots that we find.
   */
  STATIC int
  xfs_qm_dqiterate(
  	xfs_mount_t	*mp,
  	xfs_inode_t	*qip,
  	uint		flags)
  {
  	xfs_bmbt_irec_t		*map;
  	int			i, nmaps;	/* number of map entries */
  	int			error;		/* return value */
  	xfs_fileoff_t		lblkno;
  	xfs_filblks_t		maxlblkcnt;
  	xfs_dqid_t		firstid;
  	xfs_fsblock_t		rablkno;
  	xfs_filblks_t		rablkcnt;
  
  	error = 0;
  	/*
c41564b5a   Nathan Scott   [XFS] We really s...
1295
  	 * This looks racy, but we can't keep an inode lock across a
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296
1297
1298
1299
  	 * trans_reserve. But, this gets called during quotacheck, and that
  	 * happens only at mount time which is single threaded.
  	 */
  	if (qip->i_d.di_nblocks == 0)
014c2544e   Jesper Juhl   return statement ...
1300
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
  
  	map = kmem_alloc(XFS_DQITER_MAP_SIZE * sizeof(*map), KM_SLEEP);
  
  	lblkno = 0;
  	maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
  	do {
  		nmaps = XFS_DQITER_MAP_SIZE;
  		/*
  		 * We aren't changing the inode itself. Just changing
  		 * some of its data. No new blocks are added here, and
  		 * the inode is never added to the transaction.
  		 */
  		xfs_ilock(qip, XFS_ILOCK_SHARED);
  		error = xfs_bmapi(NULL, qip, lblkno,
  				  maxlblkcnt - lblkno,
  				  XFS_BMAPI_METADATA,
  				  NULL,
b4e9181e7   Christoph Hellwig   xfs: remove unuse...
1318
  				  0, map, &nmaps, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
  		xfs_iunlock(qip, XFS_ILOCK_SHARED);
  		if (error)
  			break;
  
  		ASSERT(nmaps <= XFS_DQITER_MAP_SIZE);
  		for (i = 0; i < nmaps; i++) {
  			ASSERT(map[i].br_startblock != DELAYSTARTBLOCK);
  			ASSERT(map[i].br_blockcount);
  
  
  			lblkno += map[i].br_blockcount;
  
  			if (map[i].br_startblock == HOLESTARTBLOCK)
  				continue;
  
  			firstid = (xfs_dqid_t) map[i].br_startoff *
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1335
  				mp->m_quotainfo->qi_dqperchunk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
1337
1338
1339
1340
1341
1342
1343
  			/*
  			 * Do a read-ahead on the next extent.
  			 */
  			if ((i+1 < nmaps) &&
  			    (map[i+1].br_startblock != HOLESTARTBLOCK)) {
  				rablkcnt =  map[i+1].br_blockcount;
  				rablkno = map[i+1].br_startblock;
  				while (rablkcnt--) {
1a1a3e97b   Christoph Hellwig   xfs: remove xfs_b...
1344
  					xfs_buf_readahead(mp->m_ddev_targp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1345
  					       XFS_FSB_TO_DADDR(mp, rablkno),
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1346
  					       mp->m_quotainfo->qi_dqchunklen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
  					rablkno++;
  				}
  			}
  			/*
  			 * Iterate thru all the blks in the extent and
  			 * reset the counters of all the dquots inside them.
  			 */
  			if ((error = xfs_qm_dqiter_bufs(mp,
  						       firstid,
  						       map[i].br_startblock,
  						       map[i].br_blockcount,
  						       flags))) {
  				break;
  			}
  		}
  
  		if (error)
  			break;
  	} while (nmaps > 0);
f0e2d93c2   Denys Vlasenko   [XFS] Remove unus...
1366
  	kmem_free(map);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367

014c2544e   Jesper Juhl   return statement ...
1368
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1369
1370
1371
1372
  }
  
  /*
   * Called by dqusage_adjust in doing a quotacheck.
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1373
1374
1375
1376
1377
   *
   * Given the inode, and a dquot id this updates both the incore dqout as well
   * as the buffer copy. This is so that once the quotacheck is done, we can
   * just log all the buffers, as opposed to logging numerous updates to
   * individual dquots.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1378
   */
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1379
  STATIC int
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
  xfs_qm_quotacheck_dqadjust(
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1381
1382
1383
  	struct xfs_inode	*ip,
  	xfs_dqid_t		id,
  	uint			type,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
1385
1386
  	xfs_qcnt_t		nblks,
  	xfs_qcnt_t		rtblks)
  {
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  	struct xfs_mount	*mp = ip->i_mount;
  	struct xfs_dquot	*dqp;
  	int			error;
  
  	error = xfs_qm_dqget(mp, ip, id, type,
  			     XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, &dqp);
  	if (error) {
  		/*
  		 * Shouldn't be able to turn off quotas here.
  		 */
  		ASSERT(error != ESRCH);
  		ASSERT(error != ENOENT);
  		return error;
  	}
0b1b213fc   Christoph Hellwig   xfs: event tracin...
1401
1402
  
  	trace_xfs_dqadjust(dqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403
1404
1405
1406
  	/*
  	 * Adjust the inode count and the block count to reflect this inode's
  	 * resource usage.
  	 */
413d57c99   Marcin Slusarz   xfs: convert beX_...
1407
  	be64_add_cpu(&dqp->q_core.d_icount, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1408
1409
  	dqp->q_res_icount++;
  	if (nblks) {
413d57c99   Marcin Slusarz   xfs: convert beX_...
1410
  		be64_add_cpu(&dqp->q_core.d_bcount, nblks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411
1412
1413
  		dqp->q_res_bcount += nblks;
  	}
  	if (rtblks) {
413d57c99   Marcin Slusarz   xfs: convert beX_...
1414
  		be64_add_cpu(&dqp->q_core.d_rtbcount, rtblks);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1415
1416
1417
1418
1419
  		dqp->q_res_rtbcount += rtblks;
  	}
  
  	/*
  	 * Set default limits, adjust timers (since we changed usages)
191f8488f   Christoph Hellwig   xfs: remove a few...
1420
1421
  	 *
  	 * There are no timers for the default values set in the root dquot.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1422
  	 */
191f8488f   Christoph Hellwig   xfs: remove a few...
1423
  	if (dqp->q_core.d_id) {
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1424
1425
  		xfs_qm_adjust_dqlimits(mp, &dqp->q_core);
  		xfs_qm_adjust_dqtimers(mp, &dqp->q_core);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
1428
  	}
  
  	dqp->dq_flags |= XFS_DQ_DIRTY;
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1429
1430
  	xfs_qm_dqput(dqp);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
1432
1433
1434
1435
1436
1437
1438
  }
  
  STATIC int
  xfs_qm_get_rtblks(
  	xfs_inode_t	*ip,
  	xfs_qcnt_t	*O_rtblks)
  {
  	xfs_filblks_t	rtblks;			/* total rt blks */
4eea22f01   Mandy Kirkconnell   [XFS] 929045 5673...
1439
  	xfs_extnum_t	idx;			/* extent record index */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1440
1441
  	xfs_ifork_t	*ifp;			/* inode fork pointer */
  	xfs_extnum_t	nextents;		/* number of extent entries */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
1443
1444
1445
1446
1447
  	int		error;
  
  	ASSERT(XFS_IS_REALTIME_INODE(ip));
  	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
  	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
  		if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK)))
014c2544e   Jesper Juhl   return statement ...
1448
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1449
1450
  	}
  	rtblks = 0;
4eea22f01   Mandy Kirkconnell   [XFS] 929045 5673...
1451
  	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
a6f64d4ae   Christoph Hellwig   [XFS] split ondis...
1452
1453
  	for (idx = 0; idx < nextents; idx++)
  		rtblks += xfs_bmbt_get_blockcount(xfs_iext_get_ext(ifp, idx));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
  	*O_rtblks = (xfs_qcnt_t)rtblks;
014c2544e   Jesper Juhl   return statement ...
1455
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
  }
  
  /*
   * callback routine supplied to bulkstat(). Given an inumber, find its
   * dquots and update them to account for resources taken by that inode.
   */
  /* ARGSUSED */
  STATIC int
  xfs_qm_dqusage_adjust(
  	xfs_mount_t	*mp,		/* mount point for filesystem */
  	xfs_ino_t	ino,		/* inode number to get data for */
  	void		__user *buffer,	/* not used */
  	int		ubsize,		/* not used */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
  	int		*ubused,	/* not used */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1470
1471
1472
  	int		*res)		/* result code value */
  {
  	xfs_inode_t	*ip;
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1473
  	xfs_qcnt_t	nblks, rtblks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
  	int		error;
  
  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
  
  	/*
  	 * rootino must have its resources accounted for, not so with the quota
  	 * inodes.
  	 */
  	if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) {
  		*res = BULKSTAT_RV_NOTHING;
  		return XFS_ERROR(EINVAL);
  	}
  
  	/*
  	 * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget
  	 * interface expects the inode to be exclusively locked because that's
  	 * the case in all other instances. It's OK that we do this because
  	 * quotacheck is done only at mount time.
  	 */
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1493
1494
  	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip);
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
  		*res = BULKSTAT_RV_NOTHING;
014c2544e   Jesper Juhl   return statement ...
1496
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
  	}
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1498
  	ASSERT(ip->i_delayed_blks == 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1499

52fda1142   Christoph Hellwig   xfs: simplify xfs...
1500
  	if (XFS_IS_REALTIME_INODE(ip)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
1503
  		/*
  		 * Walk thru the extent list and count the realtime blocks.
  		 */
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1504
1505
1506
  		error = xfs_qm_get_rtblks(ip, &rtblks);
  		if (error)
  			goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1508

52fda1142   Christoph Hellwig   xfs: simplify xfs...
1509
  	nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
  
  	/*
  	 * Add the (disk blocks and inode) resources occupied by this
  	 * inode to its dquots. We do this adjustment in the incore dquot,
  	 * and also copy the changes to its buffer.
  	 * We don't care about putting these changes in a transaction
  	 * envelope because if we crash in the middle of a 'quotacheck'
  	 * we have to start from the beginning anyway.
  	 * Once we're done, we'll log all the dquot bufs.
  	 *
c41564b5a   Nathan Scott   [XFS] We really s...
1520
  	 * The *QUOTA_ON checks below may look pretty racy, but quotachecks
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1521
1522
1523
  	 * and quotaoffs don't race. (Quotachecks happen at mount time only).
  	 */
  	if (XFS_IS_UQUOTA_ON(mp)) {
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1524
1525
1526
1527
  		error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_uid,
  						   XFS_DQ_USER, nblks, rtblks);
  		if (error)
  			goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
  	}
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1529
1530
1531
1532
1533
1534
  
  	if (XFS_IS_GQUOTA_ON(mp)) {
  		error = xfs_qm_quotacheck_dqadjust(ip, ip->i_d.di_gid,
  						   XFS_DQ_GROUP, nblks, rtblks);
  		if (error)
  			goto error0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536

52fda1142   Christoph Hellwig   xfs: simplify xfs...
1537
  	if (XFS_IS_PQUOTA_ON(mp)) {
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
1538
  		error = xfs_qm_quotacheck_dqadjust(ip, xfs_get_projid(ip),
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1539
1540
1541
1542
1543
1544
1545
  						   XFS_DQ_PROJ, nblks, rtblks);
  		if (error)
  			goto error0;
  	}
  
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
  	IRELE(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1546
  	*res = BULKSTAT_RV_DIDONE;
014c2544e   Jesper Juhl   return statement ...
1547
  	return 0;
52fda1142   Christoph Hellwig   xfs: simplify xfs...
1548
1549
1550
1551
1552
1553
  
  error0:
  	xfs_iunlock(ip, XFS_ILOCK_EXCL);
  	IRELE(ip);
  	*res = BULKSTAT_RV_GIVEUP;
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
  }
  
  /*
   * Walk thru all the filesystem inodes and construct a consistent view
   * of the disk quota world. If the quotacheck fails, disable quotas.
   */
  int
  xfs_qm_quotacheck(
  	xfs_mount_t	*mp)
  {
  	int		done, count, error;
  	xfs_ino_t	lastino;
  	size_t		structsz;
  	xfs_inode_t	*uip, *gip;
  	uint		flags;
  
  	count = INT_MAX;
  	structsz = 1;
  	lastino = 0;
  	flags = 0;
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1574
  	ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1575
1576
1577
1578
1579
1580
  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
  
  	/*
  	 * There should be no cached dquots. The (simplistic) quotacheck
  	 * algorithm doesn't like that.
  	 */
3a25404b3   Dave Chinner   xfs: convert the ...
1581
  	ASSERT(list_empty(&mp->m_quotainfo->qi_dqlist));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1582

0b932cccb   Dave Chinner   xfs: Convert rema...
1583
  	xfs_notice(mp, "Quotacheck needed: Please wait.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1584
1585
  
  	/*
c8ad20ffe   Nathan Scott   [XFS] Add support...
1586
  	 * First we go thru all the dquots on disk, USR and GRP/PRJ, and reset
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1587
1588
1589
  	 * their counters to zero. We need a clean slate.
  	 * We don't log our changes till later.
  	 */
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1590
1591
1592
1593
  	uip = mp->m_quotainfo->qi_uquotaip;
  	if (uip) {
  		error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA);
  		if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594
1595
1596
  			goto error_return;
  		flags |= XFS_UQUOTA_CHKD;
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1597
1598
1599
1600
1601
  	gip = mp->m_quotainfo->qi_gquotaip;
  	if (gip) {
  		error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ?
  					XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
  		if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602
  			goto error_return;
c8ad20ffe   Nathan Scott   [XFS] Add support...
1603
  		flags |= XFS_OQUOTA_CHKD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
1605
1606
1607
1608
1609
1610
  	}
  
  	do {
  		/*
  		 * Iterate thru all the inodes in the file system,
  		 * adjusting the corresponding dquot counters in core.
  		 */
7dce11dba   Christoph Hellwig   xfs: always use i...
1611
1612
1613
1614
  		error = xfs_bulkstat(mp, &lastino, &count,
  				     xfs_qm_dqusage_adjust,
  				     structsz, NULL, &done);
  		if (error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615
  			break;
7dce11dba   Christoph Hellwig   xfs: always use i...
1616
  	} while (!done);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
1618
  
  	/*
4b8879df8   David Chinner   [XFS] Propagate x...
1619
1620
1621
1622
1623
  	 * We've made all the changes that we need to make incore.
  	 * Flush them down to disk buffers if everything was updated
  	 * successfully.
  	 */
  	if (!error)
20026d920   Dave Chinner   xfs: kill the unu...
1624
  		error = xfs_qm_dqflush_all(mp, 0);
4b8879df8   David Chinner   [XFS] Propagate x...
1625
1626
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1627
1628
1629
1630
1631
1632
1633
  	 * We can get this error if we couldn't do a dquot allocation inside
  	 * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
  	 * dirty dquots that might be cached, we just want to get rid of them
  	 * and turn quotaoff. The dquots won't be attached to any of the inodes
  	 * at this point (because we intentionally didn't in dqget_noattach).
  	 */
  	if (error) {
8112e9dc6   Christoph Hellwig   xfs: removed unus...
1634
  		xfs_qm_dqpurge_all(mp, XFS_QMOPT_QUOTALL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
1636
  		goto error_return;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
  
  	/*
  	 * We didn't log anything, because if we crashed, we'll have to
  	 * start the quotacheck from scratch anyway. However, we must make
  	 * sure that our dquot changes are secure before we put the
  	 * quotacheck'd stamp on the superblock. So, here we do a synchronous
  	 * flush.
  	 */
  	XFS_bflush(mp->m_ddev_targp);
  
  	/*
  	 * If one type of quotas is off, then it will lose its
  	 * quotachecked status, since we won't be doing accounting for
  	 * that type anymore.
  	 */
c8ad20ffe   Nathan Scott   [XFS] Add support...
1652
  	mp->m_qflags &= ~(XFS_OQUOTA_CHKD | XFS_UQUOTA_CHKD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1653
  	mp->m_qflags |= flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1654
1655
   error_return:
  	if (error) {
0b932cccb   Dave Chinner   xfs: Convert rema...
1656
1657
1658
  		xfs_warn(mp,
  	"Quotacheck: Unsuccessful (Error %d): Disabling quotas.",
  			error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1659
1660
1661
1662
1663
1664
  		/*
  		 * We must turn off quotas.
  		 */
  		ASSERT(mp->m_quotainfo != NULL);
  		ASSERT(xfs_Gqm != NULL);
  		xfs_qm_destroy_quotainfo(mp);
31d5577b3   David Chinner   [XFS] Catch error...
1665
  		if (xfs_mount_reset_sbqflags(mp)) {
0b932cccb   Dave Chinner   xfs: Convert rema...
1666
1667
  			xfs_warn(mp,
  				"Quotacheck: Failed to reset quota flags.");
31d5577b3   David Chinner   [XFS] Catch error...
1668
  		}
0b932cccb   Dave Chinner   xfs: Convert rema...
1669
1670
  	} else
  		xfs_notice(mp, "Quotacheck: Done.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
  	return (error);
  }
  
  /*
   * This is called after the superblock has been read in and we're ready to
   * iget the quota inodes.
   */
  STATIC int
  xfs_qm_init_quotainos(
  	xfs_mount_t	*mp)
  {
  	xfs_inode_t	*uip, *gip;
  	int		error;
  	__int64_t	sbflags;
  	uint		flags;
  
  	ASSERT(mp->m_quotainfo);
  	uip = gip = NULL;
  	sbflags = 0;
  	flags = 0;
  
  	/*
  	 * Get the uquota and gquota inodes
  	 */
621187099   Eric Sandeen   [XFS] remove shou...
1695
  	if (xfs_sb_version_hasquota(&mp->m_sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1696
1697
1698
1699
  		if (XFS_IS_UQUOTA_ON(mp) &&
  		    mp->m_sb.sb_uquotino != NULLFSINO) {
  			ASSERT(mp->m_sb.sb_uquotino > 0);
  			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
7b6259e7a   Dave Chinner   xfs: remove block...
1700
  					     0, 0, &uip)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
1702
  				return XFS_ERROR(error);
  		}
c8ad20ffe   Nathan Scott   [XFS] Add support...
1703
  		if (XFS_IS_OQUOTA_ON(mp) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1704
1705
1706
  		    mp->m_sb.sb_gquotino != NULLFSINO) {
  			ASSERT(mp->m_sb.sb_gquotino > 0);
  			if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
7b6259e7a   Dave Chinner   xfs: remove block...
1707
  					     0, 0, &gip))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1708
  				if (uip)
433550990   Christoph Hellwig   [XFS] remove most...
1709
  					IRELE(uip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
  				return XFS_ERROR(error);
  			}
  		}
  	} else {
  		flags |= XFS_QMOPT_SBVERSION;
  		sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
  			    XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
  	}
  
  	/*
  	 * Create the two inodes, if they don't exist already. The changes
  	 * made above will get added to a transaction and logged in one of
  	 * the qino_alloc calls below.  If the device is readonly,
  	 * temporarily switch to read-write to do this.
  	 */
  	if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) {
  		if ((error = xfs_qm_qino_alloc(mp, &uip,
  					      sbflags | XFS_SB_UQUOTINO,
  					      flags | XFS_QMOPT_UQUOTA)))
  			return XFS_ERROR(error);
  
  		flags &= ~XFS_QMOPT_SBVERSION;
  	}
c8ad20ffe   Nathan Scott   [XFS] Add support...
1733
1734
1735
1736
1737
1738
  	if (XFS_IS_OQUOTA_ON(mp) && gip == NULL) {
  		flags |= (XFS_IS_GQUOTA_ON(mp) ?
  				XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
  		error = xfs_qm_qino_alloc(mp, &gip,
  					  sbflags | XFS_SB_GQUOTINO, flags);
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1739
  			if (uip)
433550990   Christoph Hellwig   [XFS] remove most...
1740
  				IRELE(uip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1741
1742
1743
1744
  
  			return XFS_ERROR(error);
  		}
  	}
8a7b8a89a   Christoph Hellwig   xfs: access quota...
1745
1746
  	mp->m_quotainfo->qi_uquotaip = uip;
  	mp->m_quotainfo->qi_gquotaip = gip;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1747

014c2544e   Jesper Juhl   return statement ...
1748
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
  }
368e13617   Dave Chinner   xfs: remove dupli...
1750

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1751
  /*
368e13617   Dave Chinner   xfs: remove dupli...
1752
1753
   * Just pop the least recently used dquot off the freelist and
   * recycle it. The returned dquot is locked.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1754
   */
368e13617   Dave Chinner   xfs: remove dupli...
1755
1756
  STATIC xfs_dquot_t *
  xfs_qm_dqreclaim_one(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1757
  {
368e13617   Dave Chinner   xfs: remove dupli...
1758
1759
  	xfs_dquot_t	*dqpout;
  	xfs_dquot_t	*dqp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1760
  	int		restarts;
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1761
  	int		startagain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1763
  	restarts = 0;
368e13617   Dave Chinner   xfs: remove dupli...
1764
  	dqpout = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765

368e13617   Dave Chinner   xfs: remove dupli...
1766
  	/* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1767
1768
  again:
  	startagain = 0;
3a8406f6d   Dave Chinner   xfs: convert the ...
1769
  	mutex_lock(&xfs_Gqm->qm_dqfrlist_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770

3a8406f6d   Dave Chinner   xfs: convert the ...
1771
  	list_for_each_entry(dqp, &xfs_Gqm->qm_dqfrlist, q_freelist) {
3a25404b3   Dave Chinner   xfs: convert the ...
1772
  		struct xfs_mount *mp = dqp->q_mount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1773
1774
1775
1776
  		xfs_dqlock(dqp);
  
  		/*
  		 * We are racing with dqlookup here. Naturally we don't
368e13617   Dave Chinner   xfs: remove dupli...
1777
1778
1779
  		 * want to reclaim a dquot that lookup wants. We release the
  		 * freelist lock and start over, so that lookup will grab
  		 * both the dquot and the freelistlock.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1780
1781
  		 */
  		if (dqp->dq_flags & XFS_DQ_WANT) {
368e13617   Dave Chinner   xfs: remove dupli...
1782
1783
1784
  			ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
  
  			trace_xfs_dqreclaim_want(dqp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1785
  			XQM_STATS_INC(xqmstats.xs_qm_dqwants);
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1786
1787
1788
  			restarts++;
  			startagain = 1;
  			goto dqunlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
1790
1791
1792
1793
1794
1795
1796
  		}
  
  		/*
  		 * If the dquot is inactive, we are assured that it is
  		 * not on the mplist or the hashlist, and that makes our
  		 * life easier.
  		 */
  		if (dqp->dq_flags & XFS_DQ_INACTIVE) {
3a25404b3   Dave Chinner   xfs: convert the ...
1797
  			ASSERT(mp == NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1798
  			ASSERT(! XFS_DQ_IS_DIRTY(dqp));
e6a81f13a   Dave Chinner   xfs: convert the ...
1799
  			ASSERT(list_empty(&dqp->q_hashlist));
3a25404b3   Dave Chinner   xfs: convert the ...
1800
  			ASSERT(list_empty(&dqp->q_mplist));
3a8406f6d   Dave Chinner   xfs: convert the ...
1801
1802
  			list_del_init(&dqp->q_freelist);
  			xfs_Gqm->qm_dqfrlist_cnt--;
368e13617   Dave Chinner   xfs: remove dupli...
1803
  			dqpout = dqp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
  			XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1805
  			goto dqunlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1806
  		}
368e13617   Dave Chinner   xfs: remove dupli...
1807
  		ASSERT(dqp->q_hash);
3a25404b3   Dave Chinner   xfs: convert the ...
1808
  		ASSERT(!list_empty(&dqp->q_mplist));
368e13617   Dave Chinner   xfs: remove dupli...
1809

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  		/*
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1811
1812
  		 * Try to grab the flush lock. If this dquot is in the process
  		 * of getting flushed to disk, we don't want to reclaim it.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1813
  		 */
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1814
1815
  		if (!xfs_dqflock_nowait(dqp))
  			goto dqunlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1816
1817
1818
1819
1820
1821
1822
1823
  
  		/*
  		 * We have the flush lock so we know that this is not in the
  		 * process of being flushed. So, if this is dirty, flush it
  		 * DELWRI so that we don't get a freelist infested with
  		 * dirty dquots.
  		 */
  		if (XFS_DQ_IS_DIRTY(dqp)) {
3c56836f9   David Chinner   [XFS] Check for d...
1824
  			int	error;
0b1b213fc   Christoph Hellwig   xfs: event tracin...
1825

368e13617   Dave Chinner   xfs: remove dupli...
1826
  			trace_xfs_dqreclaim_dirty(dqp);
0b1b213fc   Christoph Hellwig   xfs: event tracin...
1827

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1828
1829
  			/*
  			 * We flush it delayed write, so don't bother
368e13617   Dave Chinner   xfs: remove dupli...
1830
  			 * releasing the freelist lock.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1831
  			 */
20026d920   Dave Chinner   xfs: kill the unu...
1832
  			error = xfs_qm_dqflush(dqp, 0);
3c56836f9   David Chinner   [XFS] Check for d...
1833
  			if (error) {
534877869   Dave Chinner   xfs: convert xfs_...
1834
1835
  				xfs_warn(mp, "%s: dquot %p flush failed",
  					__func__, dqp);
3c56836f9   David Chinner   [XFS] Check for d...
1836
  			}
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1837
  			goto dqunlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1838
  		}
368e13617   Dave Chinner   xfs: remove dupli...
1839

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
1842
1843
1844
1845
1846
  		/*
  		 * We're trying to get the hashlock out of order. This races
  		 * with dqlookup; so, we giveup and goto the next dquot if
  		 * we couldn't get the hashlock. This way, we won't starve
  		 * a dqlookup process that holds the hashlock that is
  		 * waiting for the freelist lock.
  		 */
c9a192dcf   Christoph Hellwig   xfs: sanitize qh_...
1847
  		if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
368e13617   Dave Chinner   xfs: remove dupli...
1848
1849
  			restarts++;
  			goto dqfunlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1850
  		}
368e13617   Dave Chinner   xfs: remove dupli...
1851

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
1853
1854
1855
1856
  		/*
  		 * This races with dquot allocation code as well as dqflush_all
  		 * and reclaim code. So, if we failed to grab the mplist lock,
  		 * giveup everything and start over.
  		 */
3a25404b3   Dave Chinner   xfs: convert the ...
1857
  		if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
368e13617   Dave Chinner   xfs: remove dupli...
1858
  			restarts++;
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1859
1860
  			startagain = 1;
  			goto qhunlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1861
  		}
0b1b213fc   Christoph Hellwig   xfs: event tracin...
1862

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1863
  		ASSERT(dqp->q_nrefs == 0);
3a25404b3   Dave Chinner   xfs: convert the ...
1864
1865
1866
  		list_del_init(&dqp->q_mplist);
  		mp->m_quotainfo->qi_dquots--;
  		mp->m_quotainfo->qi_dqreclaims++;
e6a81f13a   Dave Chinner   xfs: convert the ...
1867
1868
  		list_del_init(&dqp->q_hashlist);
  		dqp->q_hash->qh_version++;
3a8406f6d   Dave Chinner   xfs: convert the ...
1869
1870
  		list_del_init(&dqp->q_freelist);
  		xfs_Gqm->qm_dqfrlist_cnt--;
368e13617   Dave Chinner   xfs: remove dupli...
1871
1872
  		dqpout = dqp;
  		mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1873
  qhunlock:
368e13617   Dave Chinner   xfs: remove dupli...
1874
1875
1876
  		mutex_unlock(&dqp->q_hash->qh_lock);
  dqfunlock:
  		xfs_dqfunlock(dqp);
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1877
  dqunlock:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1878
  		xfs_dqunlock(dqp);
368e13617   Dave Chinner   xfs: remove dupli...
1879
1880
1881
  		if (dqpout)
  			break;
  		if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
0fbca4d1c   Dave Chinner   xfs: fix dquot sh...
1882
1883
1884
1885
1886
  			break;
  		if (startagain) {
  			mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
  			goto again;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1887
  	}
3a8406f6d   Dave Chinner   xfs: convert the ...
1888
  	mutex_unlock(&xfs_Gqm->qm_dqfrlist_lock);
368e13617   Dave Chinner   xfs: remove dupli...
1889
  	return dqpout;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1890
  }
368e13617   Dave Chinner   xfs: remove dupli...
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
  /*
   * Traverse the freelist of dquots and attempt to reclaim a maximum of
   * 'howmany' dquots. This operation races with dqlookup(), and attempts to
   * favor the lookup function ...
   */
  STATIC int
  xfs_qm_shake_freelist(
  	int	howmany)
  {
  	int		nreclaimed = 0;
  	xfs_dquot_t	*dqp;
  
  	if (howmany <= 0)
  		return 0;
  
  	while (nreclaimed < howmany) {
  		dqp = xfs_qm_dqreclaim_one();
  		if (!dqp)
  			return nreclaimed;
  		xfs_qm_dqdestroy(dqp);
  		nreclaimed++;
  	}
  	return nreclaimed;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1915
1916
1917
1918
1919
1920
  
  /*
   * The kmem_shake interface is invoked when memory is running low.
   */
  /* ARGSUSED */
  STATIC int
7f8275d0d   Dave Chinner   mm: add context a...
1921
1922
  xfs_qm_shake(
  	struct shrinker	*shrink,
1495f230f   Ying Han   vmscan: change sh...
1923
  	struct shrink_control *sc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
1925
  {
  	int	ndqused, nfree, n;
1495f230f   Ying Han   vmscan: change sh...
1926
  	gfp_t gfp_mask = sc->gfp_mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1927
1928
  
  	if (!kmem_shake_allow(gfp_mask))
014c2544e   Jesper Juhl   return statement ...
1929
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1930
  	if (!xfs_Gqm)
014c2544e   Jesper Juhl   return statement ...
1931
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1932

3a8406f6d   Dave Chinner   xfs: convert the ...
1933
  	nfree = xfs_Gqm->qm_dqfrlist_cnt; /* free dquots */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1934
1935
1936
1937
1938
1939
  	/* incore dquots in all f/s's */
  	ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree;
  
  	ASSERT(ndqused >= 0);
  
  	if (nfree <= ndqused && nfree < ndquot)
014c2544e   Jesper Juhl   return statement ...
1940
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1941
1942
1943
1944
1945
1946
  
  	ndqused *= xfs_Gqm->qm_dqfree_ratio;	/* target # of free dquots */
  	n = nfree - ndqused - ndquot;		/* # over target */
  
  	return xfs_qm_shake_freelist(MAX(nfree, n));
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
  /*------------------------------------------------------------------*/
  
  /*
   * Return a new incore dquot. Depending on the number of
   * dquots in the system, we either allocate a new one on the kernel heap,
   * or reclaim a free one.
   * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed
   * to reclaim an existing one from the freelist.
   */
  boolean_t
  xfs_qm_dqalloc_incore(
  	xfs_dquot_t **O_dqpp)
  {
  	xfs_dquot_t	*dqp;
  
  	/*
  	 * Check against high water mark to see if we want to pop
  	 * a nincompoop dquot off the freelist.
  	 */
  	if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) {
  		/*
  		 * Try to recycle a dquot from the freelist.
  		 */
  		if ((dqp = xfs_qm_dqreclaim_one())) {
  			XQM_STATS_INC(xqmstats.xs_qm_dqreclaims);
  			/*
  			 * Just zero the core here. The rest will get
  			 * reinitialized by caller. XXX we shouldn't even
  			 * do this zero ...
  			 */
  			memset(&dqp->q_core, 0, sizeof(dqp->q_core));
  			*O_dqpp = dqp;
014c2544e   Jesper Juhl   return statement ...
1979
  			return B_FALSE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
  		}
  		XQM_STATS_INC(xqmstats.xs_qm_dqreclaim_misses);
  	}
  
  	/*
  	 * Allocate a brand new dquot on the kernel heap and return it
  	 * to the caller to initialize.
  	 */
  	ASSERT(xfs_Gqm->qm_dqzone != NULL);
  	*O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP);
  	atomic_inc(&xfs_Gqm->qm_totaldquots);
014c2544e   Jesper Juhl   return statement ...
1991
  	return B_TRUE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
  }
  
  
  /*
   * Start a transaction and write the incore superblock changes to
   * disk. flags parameter indicates which fields have changed.
   */
  int
  xfs_qm_write_sb_changes(
  	xfs_mount_t	*mp,
  	__int64_t	flags)
  {
  	xfs_trans_t	*tp;
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2006
2007
2008
2009
2010
2011
  	tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
  	if ((error = xfs_trans_reserve(tp, 0,
  				      mp->m_sb.sb_sectsize + 128, 0,
  				      0,
  				      XFS_DEFAULT_LOG_COUNT))) {
  		xfs_trans_cancel(tp, 0);
014c2544e   Jesper Juhl   return statement ...
2012
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2013
2014
2015
  	}
  
  	xfs_mod_sb(tp, flags);
e5720eec0   David Chinner   [XFS] Propagate e...
2016
  	error = xfs_trans_commit(tp, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2017

e5720eec0   David Chinner   [XFS] Propagate e...
2018
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
2020
2021
2022
2023
2024
2025
  }
  
  
  /* --------------- utility functions for vnodeops ---------------- */
  
  
  /*
6c77b0ea1   Christoph Hellwig   xfs: remove xfs_c...
2026
   * Given an inode, a uid, gid and prid make sure that we have
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
   * allocated relevant dquot(s) on disk, and that we won't exceed inode
   * quotas by creating this file.
   * This also attaches dquot(s) to the given inode after locking it,
   * and returns the dquots corresponding to the uid and/or gid.
   *
   * in	: inode (unlocked)
   * out	: udquot, gdquot with references taken and unlocked
   */
  int
  xfs_qm_vop_dqalloc(
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2037
2038
2039
2040
2041
2042
2043
  	struct xfs_inode	*ip,
  	uid_t			uid,
  	gid_t			gid,
  	prid_t			prid,
  	uint			flags,
  	struct xfs_dquot	**O_udqpp,
  	struct xfs_dquot	**O_gdqpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
  {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2045
2046
2047
2048
  	struct xfs_mount	*mp = ip->i_mount;
  	struct xfs_dquot	*uq, *gq;
  	int			error;
  	uint			lockflags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2050
  	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2051
2052
2053
2054
  		return 0;
  
  	lockflags = XFS_ILOCK_EXCL;
  	xfs_ilock(ip, lockflags);
bd186aa90   Christoph Hellwig   [XFS] kill the vf...
2055
  	if ((flags & XFS_QMOPT_INHERIT) && XFS_INHERIT_GID(ip))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2056
2057
2058
2059
2060
2061
2062
  		gid = ip->i_d.di_gid;
  
  	/*
  	 * Attach the dquot(s) to this inode, doing a dquot allocation
  	 * if necessary. The dquot(s) will not be locked.
  	 */
  	if (XFS_NOT_DQATTACHED(mp, ip)) {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2063
2064
  		error = xfs_qm_dqattach_locked(ip, XFS_QMOPT_DQALLOC);
  		if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2065
  			xfs_iunlock(ip, lockflags);
014c2544e   Jesper Juhl   return statement ...
2066
  			return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2067
2068
2069
2070
  		}
  	}
  
  	uq = gq = NULL;
c8ad20ffe   Nathan Scott   [XFS] Add support...
2071
  	if ((flags & XFS_QMOPT_UQUOTA) && XFS_IS_UQUOTA_ON(mp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
  		if (ip->i_d.di_uid != uid) {
  			/*
  			 * What we need is the dquot that has this uid, and
  			 * if we send the inode to dqget, the uid of the inode
  			 * takes priority over what's sent in the uid argument.
  			 * We must unlock inode here before calling dqget if
  			 * we're not sending the inode, because otherwise
  			 * we'll deadlock by doing trans_reserve while
  			 * holding ilock.
  			 */
  			xfs_iunlock(ip, lockflags);
  			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
  						 XFS_DQ_USER,
  						 XFS_QMOPT_DQALLOC |
  						 XFS_QMOPT_DOWARN,
  						 &uq))) {
  				ASSERT(error != ENOENT);
014c2544e   Jesper Juhl   return statement ...
2089
  				return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
  			}
  			/*
  			 * Get the ilock in the right order.
  			 */
  			xfs_dqunlock(uq);
  			lockflags = XFS_ILOCK_SHARED;
  			xfs_ilock(ip, lockflags);
  		} else {
  			/*
  			 * Take an extra reference, because we'll return
  			 * this to caller
  			 */
  			ASSERT(ip->i_udquot);
  			uq = ip->i_udquot;
  			xfs_dqlock(uq);
  			XFS_DQHOLD(uq);
  			xfs_dqunlock(uq);
  		}
  	}
c8ad20ffe   Nathan Scott   [XFS] Add support...
2109
  	if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
  		if (ip->i_d.di_gid != gid) {
  			xfs_iunlock(ip, lockflags);
  			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
  						 XFS_DQ_GROUP,
  						 XFS_QMOPT_DQALLOC |
  						 XFS_QMOPT_DOWARN,
  						 &gq))) {
  				if (uq)
  					xfs_qm_dqrele(uq);
  				ASSERT(error != ENOENT);
014c2544e   Jesper Juhl   return statement ...
2120
  				return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
  			}
  			xfs_dqunlock(gq);
  			lockflags = XFS_ILOCK_SHARED;
  			xfs_ilock(ip, lockflags);
  		} else {
  			ASSERT(ip->i_gdquot);
  			gq = ip->i_gdquot;
  			xfs_dqlock(gq);
  			XFS_DQHOLD(gq);
  			xfs_dqunlock(gq);
  		}
c8ad20ffe   Nathan Scott   [XFS] Add support...
2132
  	} else if ((flags & XFS_QMOPT_PQUOTA) && XFS_IS_PQUOTA_ON(mp)) {
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
2133
  		if (xfs_get_projid(ip) != prid) {
c8ad20ffe   Nathan Scott   [XFS] Add support...
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
  			xfs_iunlock(ip, lockflags);
  			if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)prid,
  						 XFS_DQ_PROJ,
  						 XFS_QMOPT_DQALLOC |
  						 XFS_QMOPT_DOWARN,
  						 &gq))) {
  				if (uq)
  					xfs_qm_dqrele(uq);
  				ASSERT(error != ENOENT);
  				return (error);
  			}
  			xfs_dqunlock(gq);
  			lockflags = XFS_ILOCK_SHARED;
  			xfs_ilock(ip, lockflags);
  		} else {
  			ASSERT(ip->i_gdquot);
  			gq = ip->i_gdquot;
  			xfs_dqlock(gq);
  			XFS_DQHOLD(gq);
  			xfs_dqunlock(gq);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2155
2156
  	}
  	if (uq)
0b1b213fc   Christoph Hellwig   xfs: event tracin...
2157
  		trace_xfs_dquot_dqalloc(ip);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
  
  	xfs_iunlock(ip, lockflags);
  	if (O_udqpp)
  		*O_udqpp = uq;
  	else if (uq)
  		xfs_qm_dqrele(uq);
  	if (O_gdqpp)
  		*O_gdqpp = gq;
  	else if (gq)
  		xfs_qm_dqrele(gq);
014c2544e   Jesper Juhl   return statement ...
2168
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
  }
  
  /*
   * Actually transfer ownership, and do dquot modifications.
   * These were already reserved.
   */
  xfs_dquot_t *
  xfs_qm_vop_chown(
  	xfs_trans_t	*tp,
  	xfs_inode_t	*ip,
  	xfs_dquot_t	**IO_olddq,
  	xfs_dquot_t	*newdq)
  {
  	xfs_dquot_t	*prevdq;
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
2183
2184
  	uint		bfield = XFS_IS_REALTIME_INODE(ip) ?
  				 XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2185

579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
2186
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2187
2188
2189
2190
2191
2192
  	ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
  
  	/* old dquot */
  	prevdq = *IO_olddq;
  	ASSERT(prevdq);
  	ASSERT(prevdq != newdq);
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
2193
2194
  	xfs_trans_mod_dquot(tp, prevdq, bfield, -(ip->i_d.di_nblocks));
  	xfs_trans_mod_dquot(tp, prevdq, XFS_TRANS_DQ_ICOUNT, -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2195
2196
  
  	/* the sparkling new dquot */
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
2197
2198
  	xfs_trans_mod_dquot(tp, newdq, bfield, ip->i_d.di_nblocks);
  	xfs_trans_mod_dquot(tp, newdq, XFS_TRANS_DQ_ICOUNT, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
  
  	/*
  	 * Take an extra reference, because the inode
  	 * is going to keep this dquot pointer even
  	 * after the trans_commit.
  	 */
  	xfs_dqlock(newdq);
  	XFS_DQHOLD(newdq);
  	xfs_dqunlock(newdq);
  	*IO_olddq = newdq;
014c2544e   Jesper Juhl   return statement ...
2209
  	return prevdq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2210
2211
2212
  }
  
  /*
c8ad20ffe   Nathan Scott   [XFS] Add support...
2213
   * Quota reservations for setattr(AT_UID|AT_GID|AT_PROJID).
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2214
2215
2216
2217
2218
2219
2220
2221
2222
   */
  int
  xfs_qm_vop_chown_reserve(
  	xfs_trans_t	*tp,
  	xfs_inode_t	*ip,
  	xfs_dquot_t	*udqp,
  	xfs_dquot_t	*gdqp,
  	uint		flags)
  {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2223
  	xfs_mount_t	*mp = ip->i_mount;
9a2a7de26   Nathan Scott   [XFS] Make projec...
2224
  	uint		delblks, blkflags, prjflags = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2225
  	xfs_dquot_t	*unresudq, *unresgdq, *delblksudq, *delblksgdq;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2226
  	int		error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2227

579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
2228
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2229
2230
2231
2232
  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
  
  	delblks = ip->i_delayed_blks;
  	delblksudq = delblksgdq = unresudq = unresgdq = NULL;
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
2233
2234
  	blkflags = XFS_IS_REALTIME_INODE(ip) ?
  			XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2235
2236
  
  	if (XFS_IS_UQUOTA_ON(mp) && udqp &&
1149d96ae   Christoph Hellwig   [XFS] endianess a...
2237
  	    ip->i_d.di_uid != (uid_t)be32_to_cpu(udqp->q_core.d_id)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
  		delblksudq = udqp;
  		/*
  		 * If there are delayed allocation blocks, then we have to
  		 * unreserve those from the old dquot, and add them to the
  		 * new dquot.
  		 */
  		if (delblks) {
  			ASSERT(ip->i_udquot);
  			unresudq = ip->i_udquot;
  		}
  	}
c8ad20ffe   Nathan Scott   [XFS] Add support...
2249
  	if (XFS_IS_OQUOTA_ON(ip->i_mount) && gdqp) {
9a2a7de26   Nathan Scott   [XFS] Make projec...
2250
  		if (XFS_IS_PQUOTA_ON(ip->i_mount) &&
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
2251
  		     xfs_get_projid(ip) != be32_to_cpu(gdqp->q_core.d_id))
9a2a7de26   Nathan Scott   [XFS] Make projec...
2252
2253
2254
2255
2256
  			prjflags = XFS_QMOPT_ENOSPC;
  
  		if (prjflags ||
  		    (XFS_IS_GQUOTA_ON(ip->i_mount) &&
  		     ip->i_d.di_gid != be32_to_cpu(gdqp->q_core.d_id))) {
c8ad20ffe   Nathan Scott   [XFS] Add support...
2257
2258
2259
2260
2261
  			delblksgdq = gdqp;
  			if (delblks) {
  				ASSERT(ip->i_gdquot);
  				unresgdq = ip->i_gdquot;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2262
2263
2264
2265
2266
  		}
  	}
  
  	if ((error = xfs_trans_reserve_quota_bydquots(tp, ip->i_mount,
  				delblksudq, delblksgdq, ip->i_d.di_nblocks, 1,
9a2a7de26   Nathan Scott   [XFS] Make projec...
2267
  				flags | blkflags | prjflags)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
  		return (error);
  
  	/*
  	 * Do the delayed blks reservations/unreservations now. Since, these
  	 * are done without the help of a transaction, if a reservation fails
  	 * its previous reservations won't be automatically undone by trans
  	 * code. So, we have to do it manually here.
  	 */
  	if (delblks) {
  		/*
  		 * Do the reservations first. Unreservation can't fail.
  		 */
  		ASSERT(delblksudq || delblksgdq);
  		ASSERT(unresudq || unresgdq);
  		if ((error = xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
  				delblksudq, delblksgdq, (xfs_qcnt_t)delblks, 0,
9a2a7de26   Nathan Scott   [XFS] Make projec...
2284
  				flags | blkflags | prjflags)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
2286
2287
  			return (error);
  		xfs_trans_reserve_quota_bydquots(NULL, ip->i_mount,
  				unresudq, unresgdq, -((xfs_qcnt_t)delblks), 0,
06d10dd9c   Nathan Scott   [XFS] Merge fixes...
2288
  				blkflags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2289
2290
2291
2292
2293
2294
2295
  	}
  
  	return (0);
  }
  
  int
  xfs_qm_vop_rename_dqattach(
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2296
  	struct xfs_inode	**i_tab)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2297
  {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2298
2299
  	struct xfs_mount	*mp = i_tab[0]->i_mount;
  	int			i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2300

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2301
  	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
014c2544e   Jesper Juhl   return statement ...
2302
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2303

7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2304
2305
2306
  	for (i = 0; (i < 4 && i_tab[i]); i++) {
  		struct xfs_inode	*ip = i_tab[i];
  		int			error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
2308
2309
  		/*
  		 * Watch out for duplicate entries in the table.
  		 */
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2310
2311
  		if (i == 0 || ip != i_tab[i-1]) {
  			if (XFS_NOT_DQATTACHED(mp, ip)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2312
2313
  				error = xfs_qm_dqattach(ip, 0);
  				if (error)
014c2544e   Jesper Juhl   return statement ...
2314
  					return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315
2316
2317
  			}
  		}
  	}
014c2544e   Jesper Juhl   return statement ...
2318
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2319
2320
2321
  }
  
  void
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2322
2323
2324
2325
2326
  xfs_qm_vop_create_dqattach(
  	struct xfs_trans	*tp,
  	struct xfs_inode	*ip,
  	struct xfs_dquot	*udqp,
  	struct xfs_dquot	*gdqp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2327
  {
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2328
2329
2330
  	struct xfs_mount	*mp = tp->t_mountp;
  
  	if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2331
  		return;
579aa9caf   Christoph Hellwig   [XFS] shrink mrlo...
2332
  	ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2333
  	ASSERT(XFS_IS_QUOTA_RUNNING(mp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2334
2335
2336
2337
2338
2339
2340
  
  	if (udqp) {
  		xfs_dqlock(udqp);
  		XFS_DQHOLD(udqp);
  		xfs_dqunlock(udqp);
  		ASSERT(ip->i_udquot == NULL);
  		ip->i_udquot = udqp;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2341
  		ASSERT(XFS_IS_UQUOTA_ON(mp));
1149d96ae   Christoph Hellwig   [XFS] endianess a...
2342
  		ASSERT(ip->i_d.di_uid == be32_to_cpu(udqp->q_core.d_id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2343
2344
2345
2346
2347
2348
2349
2350
  		xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1);
  	}
  	if (gdqp) {
  		xfs_dqlock(gdqp);
  		XFS_DQHOLD(gdqp);
  		xfs_dqunlock(gdqp);
  		ASSERT(ip->i_gdquot == NULL);
  		ip->i_gdquot = gdqp;
7d095257e   Christoph Hellwig   xfs: kill xfs_qmops
2351
2352
  		ASSERT(XFS_IS_OQUOTA_ON(mp));
  		ASSERT((XFS_IS_GQUOTA_ON(mp) ?
6743099ce   Arkadiusz Mi?kiewicz   xfs: Extend proje...
2353
  			ip->i_d.di_gid : xfs_get_projid(ip)) ==
ee2a4f7ca   Nathan Scott   [XFS] Fix an inte...
2354
  				be32_to_cpu(gdqp->q_core.d_id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2355
2356
2357
  		xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1);
  	}
  }