aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/quota_global.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-08-25 13:56:50 -0400
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:40:23 -0500
commit9e33d69f553aaf11377307e8d6f82deb3385e351 (patch)
treeded5f48f6cf82db976f30d5f0f4d44b941f60f44 /fs/ocfs2/quota_global.c
parentbbbd0eb34bf801dee01e345785959a75258f6567 (diff)
ocfs2: Implementation of local and global quota file handling
For each quota type each node has local quota file. In this file it stores changes users have made to disk usage via this node. Once in a while this information is synced to global file (and thus with other nodes) so that limits enforcement at least aproximately works. Global quota files contain all the information about usage and limits. It's mostly handled by the generic VFS code (which implements a trie of structures inside a quota file). We only have to provide functions to convert structures from on-disk format to in-memory one. We also have to provide wrappers for various quota functions starting transactions and acquiring necessary cluster locks before the actual IO is really started. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/quota_global.c')
-rw-r--r--fs/ocfs2/quota_global.c919
1 files changed, 919 insertions, 0 deletions
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
new file mode 100644
index 000000000000..af8340c45367
--- /dev/null
+++ b/fs/ocfs2/quota_global.c
@@ -0,0 +1,919 @@
1/*
2 * Implementation of operations over global quota file
3 */
4#include <linux/fs.h>
5#include <linux/quota.h>
6#include <linux/quotaops.h>
7#include <linux/dqblk_qtree.h>
8
9#define MLOG_MASK_PREFIX ML_QUOTA
10#include <cluster/masklog.h>
11
12#include "ocfs2_fs.h"
13#include "ocfs2.h"
14#include "alloc.h"
15#include "inode.h"
16#include "journal.h"
17#include "file.h"
18#include "sysfile.h"
19#include "dlmglue.h"
20#include "uptodate.h"
21#include "quota.h"
22
23static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp)
24{
25 struct ocfs2_global_disk_dqblk *d = dp;
26 struct mem_dqblk *m = &dquot->dq_dqb;
27
28 /* Update from disk only entries not set by the admin */
29 if (!test_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags)) {
30 m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
31 m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
32 }
33 if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
34 m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
35 if (!test_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags)) {
36 m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit);
37 m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit);
38 }
39 if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
40 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
41 if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags))
42 m->dqb_btime = le64_to_cpu(d->dqb_btime);
43 if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags))
44 m->dqb_itime = le64_to_cpu(d->dqb_itime);
45 OCFS2_DQUOT(dquot)->dq_use_count = le32_to_cpu(d->dqb_use_count);
46}
47
48static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
49{
50 struct ocfs2_global_disk_dqblk *d = dp;
51 struct mem_dqblk *m = &dquot->dq_dqb;
52
53 d->dqb_id = cpu_to_le32(dquot->dq_id);
54 d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
55 d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
56 d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
57 d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
58 d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit);
59 d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit);
60 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
61 d->dqb_btime = cpu_to_le64(m->dqb_btime);
62 d->dqb_itime = cpu_to_le64(m->dqb_itime);
63}
64
65static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
66{
67 struct ocfs2_global_disk_dqblk *d = dp;
68 struct ocfs2_mem_dqinfo *oinfo =
69 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
70
71 if (qtree_entry_unused(&oinfo->dqi_gi, dp))
72 return 0;
73 return le32_to_cpu(d->dqb_id) == dquot->dq_id;
74}
75
76struct qtree_fmt_operations ocfs2_global_ops = {
77 .mem2disk_dqblk = ocfs2_global_mem2diskdqb,
78 .disk2mem_dqblk = ocfs2_global_disk2memdqb,
79 .is_id = ocfs2_global_is_id,
80};
81
82
83struct buffer_head *ocfs2_read_quota_block(struct inode *inode,
84 int block, int *err)
85{
86 struct buffer_head *tmp = NULL;
87
88 *err = ocfs2_read_virt_blocks(inode, block, 1, &tmp, 0, NULL);
89 if (*err)
90 mlog_errno(*err);
91
92 return tmp;
93}
94
95static struct buffer_head *ocfs2_get_quota_block(struct inode *inode,
96 int block, int *err)
97{
98 u64 pblock, pcount;
99 struct buffer_head *bh;
100
101 down_read(&OCFS2_I(inode)->ip_alloc_sem);
102 *err = ocfs2_extent_map_get_blocks(inode, block, &pblock, &pcount,
103 NULL);
104 up_read(&OCFS2_I(inode)->ip_alloc_sem);
105 if (*err) {
106 mlog_errno(*err);
107 return NULL;
108 }
109 bh = sb_getblk(inode->i_sb, pblock);
110 if (!bh) {
111 *err = -EIO;
112 mlog_errno(*err);
113 }
114 return bh;
115}
116
117/* Read data from global quotafile - avoid pagecache and such because we cannot
118 * afford acquiring the locks... We use quota cluster lock to serialize
119 * operations. Caller is responsible for acquiring it. */
120ssize_t ocfs2_quota_read(struct super_block *sb, int type, char *data,
121 size_t len, loff_t off)
122{
123 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
124 struct inode *gqinode = oinfo->dqi_gqinode;
125 loff_t i_size = i_size_read(gqinode);
126 int offset = off & (sb->s_blocksize - 1);
127 sector_t blk = off >> sb->s_blocksize_bits;
128 int err = 0;
129 struct buffer_head *bh;
130 size_t toread, tocopy;
131
132 if (off > i_size)
133 return 0;
134 if (off + len > i_size)
135 len = i_size - off;
136 toread = len;
137 while (toread > 0) {
138 tocopy = min((size_t)(sb->s_blocksize - offset), toread);
139 bh = ocfs2_read_quota_block(gqinode, blk, &err);
140 if (!bh) {
141 mlog_errno(err);
142 return err;
143 }
144 memcpy(data, bh->b_data + offset, tocopy);
145 brelse(bh);
146 offset = 0;
147 toread -= tocopy;
148 data += tocopy;
149 blk++;
150 }
151 return len;
152}
153
154/* Write to quotafile (we know the transaction is already started and has
155 * enough credits) */
156ssize_t ocfs2_quota_write(struct super_block *sb, int type,
157 const char *data, size_t len, loff_t off)
158{
159 struct mem_dqinfo *info = sb_dqinfo(sb, type);
160 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
161 struct inode *gqinode = oinfo->dqi_gqinode;
162 int offset = off & (sb->s_blocksize - 1);
163 sector_t blk = off >> sb->s_blocksize_bits;
164 int err = 0, new = 0;
165 struct buffer_head *bh;
166 handle_t *handle = journal_current_handle();
167
168 if (!handle) {
169 mlog(ML_ERROR, "Quota write (off=%llu, len=%llu) cancelled "
170 "because transaction was not started.\n",
171 (unsigned long long)off, (unsigned long long)len);
172 return -EIO;
173 }
174 if (len > sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset) {
175 WARN_ON(1);
176 len = sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset;
177 }
178
179 mutex_lock_nested(&gqinode->i_mutex, I_MUTEX_QUOTA);
180 if (gqinode->i_size < off + len) {
181 down_write(&OCFS2_I(gqinode)->ip_alloc_sem);
182 err = ocfs2_extend_no_holes(gqinode, off + len, off);
183 up_write(&OCFS2_I(gqinode)->ip_alloc_sem);
184 if (err < 0)
185 goto out;
186 err = ocfs2_simple_size_update(gqinode,
187 oinfo->dqi_gqi_bh,
188 off + len);
189 if (err < 0)
190 goto out;
191 new = 1;
192 }
193 /* Not rewriting whole block? */
194 if ((offset || len < sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) &&
195 !new) {
196 bh = ocfs2_read_quota_block(gqinode, blk, &err);
197 if (!bh) {
198 mlog_errno(err);
199 return err;
200 }
201 err = ocfs2_journal_access(handle, gqinode, bh,
202 OCFS2_JOURNAL_ACCESS_WRITE);
203 } else {
204 bh = ocfs2_get_quota_block(gqinode, blk, &err);
205 if (!bh) {
206 mlog_errno(err);
207 return err;
208 }
209 err = ocfs2_journal_access(handle, gqinode, bh,
210 OCFS2_JOURNAL_ACCESS_CREATE);
211 }
212 if (err < 0) {
213 brelse(bh);
214 goto out;
215 }
216 lock_buffer(bh);
217 if (new)
218 memset(bh->b_data, 0, sb->s_blocksize);
219 memcpy(bh->b_data + offset, data, len);
220 flush_dcache_page(bh->b_page);
221 unlock_buffer(bh);
222 ocfs2_set_buffer_uptodate(gqinode, bh);
223 err = ocfs2_journal_dirty(handle, bh);
224 brelse(bh);
225 if (err < 0)
226 goto out;
227out:
228 if (err) {
229 mutex_unlock(&gqinode->i_mutex);
230 mlog_errno(err);
231 return err;
232 }
233 gqinode->i_version++;
234 ocfs2_mark_inode_dirty(handle, gqinode, oinfo->dqi_gqi_bh);
235 mutex_unlock(&gqinode->i_mutex);
236 return len;
237}
238
239int ocfs2_lock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
240{
241 int status;
242 struct buffer_head *bh = NULL;
243
244 status = ocfs2_inode_lock(oinfo->dqi_gqinode, &bh, ex);
245 if (status < 0)
246 return status;
247 spin_lock(&dq_data_lock);
248 if (!oinfo->dqi_gqi_count++)
249 oinfo->dqi_gqi_bh = bh;
250 else
251 WARN_ON(bh != oinfo->dqi_gqi_bh);
252 spin_unlock(&dq_data_lock);
253 return 0;
254}
255
256void ocfs2_unlock_global_qf(struct ocfs2_mem_dqinfo *oinfo, int ex)
257{
258 ocfs2_inode_unlock(oinfo->dqi_gqinode, ex);
259 brelse(oinfo->dqi_gqi_bh);
260 spin_lock(&dq_data_lock);
261 if (!--oinfo->dqi_gqi_count)
262 oinfo->dqi_gqi_bh = NULL;
263 spin_unlock(&dq_data_lock);
264}
265
266/* Read information header from global quota file */
267int ocfs2_global_read_info(struct super_block *sb, int type)
268{
269 struct inode *gqinode = NULL;
270 unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
271 GROUP_QUOTA_SYSTEM_INODE };
272 struct ocfs2_global_disk_dqinfo dinfo;
273 struct mem_dqinfo *info = sb_dqinfo(sb, type);
274 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
275 int status;
276
277 mlog_entry_void();
278
279 /* Read global header */
280 gqinode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type],
281 OCFS2_INVALID_SLOT);
282 if (!gqinode) {
283 mlog(ML_ERROR, "failed to get global quota inode (type=%d)\n",
284 type);
285 status = -EINVAL;
286 goto out_err;
287 }
288 oinfo->dqi_gi.dqi_sb = sb;
289 oinfo->dqi_gi.dqi_type = type;
290 ocfs2_qinfo_lock_res_init(&oinfo->dqi_gqlock, oinfo);
291 oinfo->dqi_gi.dqi_entry_size = sizeof(struct ocfs2_global_disk_dqblk);
292 oinfo->dqi_gi.dqi_ops = &ocfs2_global_ops;
293 oinfo->dqi_gqi_bh = NULL;
294 oinfo->dqi_gqi_count = 0;
295 oinfo->dqi_gqinode = gqinode;
296 status = ocfs2_lock_global_qf(oinfo, 0);
297 if (status < 0) {
298 mlog_errno(status);
299 goto out_err;
300 }
301 status = sb->s_op->quota_read(sb, type, (char *)&dinfo,
302 sizeof(struct ocfs2_global_disk_dqinfo),
303 OCFS2_GLOBAL_INFO_OFF);
304 ocfs2_unlock_global_qf(oinfo, 0);
305 if (status != sizeof(struct ocfs2_global_disk_dqinfo)) {
306 mlog(ML_ERROR, "Cannot read global quota info (%d).\n",
307 status);
308 if (status >= 0)
309 status = -EIO;
310 mlog_errno(status);
311 goto out_err;
312 }
313 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
314 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
315 oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms);
316 oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
317 oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
318 oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
319 oinfo->dqi_gi.dqi_blocksize_bits = sb->s_blocksize_bits;
320 oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize -
321 OCFS2_QBLK_RESERVED_SPACE;
322 oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi);
323out_err:
324 mlog_exit(status);
325 return status;
326}
327
328/* Write information to global quota file. Expects exlusive lock on quota
329 * file inode and quota info */
330static int __ocfs2_global_write_info(struct super_block *sb, int type)
331{
332 struct mem_dqinfo *info = sb_dqinfo(sb, type);
333 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
334 struct ocfs2_global_disk_dqinfo dinfo;
335 ssize_t size;
336
337 spin_lock(&dq_data_lock);
338 info->dqi_flags &= ~DQF_INFO_DIRTY;
339 dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
340 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
341 spin_unlock(&dq_data_lock);
342 dinfo.dqi_syncms = cpu_to_le32(oinfo->dqi_syncms);
343 dinfo.dqi_blocks = cpu_to_le32(oinfo->dqi_gi.dqi_blocks);
344 dinfo.dqi_free_blk = cpu_to_le32(oinfo->dqi_gi.dqi_free_blk);
345 dinfo.dqi_free_entry = cpu_to_le32(oinfo->dqi_gi.dqi_free_entry);
346 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
347 sizeof(struct ocfs2_global_disk_dqinfo),
348 OCFS2_GLOBAL_INFO_OFF);
349 if (size != sizeof(struct ocfs2_global_disk_dqinfo)) {
350 mlog(ML_ERROR, "Cannot write global quota info structure\n");
351 if (size >= 0)
352 size = -EIO;
353 return size;
354 }
355 return 0;
356}
357
358int ocfs2_global_write_info(struct super_block *sb, int type)
359{
360 int err;
361 struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
362
363 err = ocfs2_qinfo_lock(info, 1);
364 if (err < 0)
365 return err;
366 err = __ocfs2_global_write_info(sb, type);
367 ocfs2_qinfo_unlock(info, 1);
368 return err;
369}
370
371/* Read in information from global quota file and acquire a reference to it.
372 * dquot_acquire() has already started the transaction and locked quota file */
373int ocfs2_global_read_dquot(struct dquot *dquot)
374{
375 int err, err2, ex = 0;
376 struct ocfs2_mem_dqinfo *info =
377 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
378
379 err = ocfs2_qinfo_lock(info, 0);
380 if (err < 0)
381 goto out;
382 err = qtree_read_dquot(&info->dqi_gi, dquot);
383 if (err < 0)
384 goto out_qlock;
385 OCFS2_DQUOT(dquot)->dq_use_count++;
386 OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
387 OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
388 if (!dquot->dq_off) { /* No real quota entry? */
389 /* Upgrade to exclusive lock for allocation */
390 err = ocfs2_qinfo_lock(info, 1);
391 if (err < 0)
392 goto out_qlock;
393 ex = 1;
394 }
395 err = qtree_write_dquot(&info->dqi_gi, dquot);
396 if (ex && info_dirty(sb_dqinfo(dquot->dq_sb, dquot->dq_type))) {
397 err2 = __ocfs2_global_write_info(dquot->dq_sb, dquot->dq_type);
398 if (!err)
399 err = err2;
400 }
401out_qlock:
402 if (ex)
403 ocfs2_qinfo_unlock(info, 1);
404 ocfs2_qinfo_unlock(info, 0);
405out:
406 if (err < 0)
407 mlog_errno(err);
408 return err;
409}
410
411/* Sync local information about quota modifications with global quota file.
412 * Caller must have started the transaction and obtained exclusive lock for
413 * global quota file inode */
414int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
415{
416 int err, err2;
417 struct super_block *sb = dquot->dq_sb;
418 int type = dquot->dq_type;
419 struct ocfs2_mem_dqinfo *info = sb_dqinfo(sb, type)->dqi_priv;
420 struct ocfs2_global_disk_dqblk dqblk;
421 s64 spacechange, inodechange;
422 time_t olditime, oldbtime;
423
424 err = sb->s_op->quota_read(sb, type, (char *)&dqblk,
425 sizeof(struct ocfs2_global_disk_dqblk),
426 dquot->dq_off);
427 if (err != sizeof(struct ocfs2_global_disk_dqblk)) {
428 if (err >= 0) {
429 mlog(ML_ERROR, "Short read from global quota file "
430 "(%u read)\n", err);
431 err = -EIO;
432 }
433 goto out;
434 }
435
436 /* Update space and inode usage. Get also other information from
437 * global quota file so that we don't overwrite any changes there.
438 * We are */
439 spin_lock(&dq_data_lock);
440 spacechange = dquot->dq_dqb.dqb_curspace -
441 OCFS2_DQUOT(dquot)->dq_origspace;
442 inodechange = dquot->dq_dqb.dqb_curinodes -
443 OCFS2_DQUOT(dquot)->dq_originodes;
444 olditime = dquot->dq_dqb.dqb_itime;
445 oldbtime = dquot->dq_dqb.dqb_btime;
446 ocfs2_global_disk2memdqb(dquot, &dqblk);
447 mlog(0, "Syncing global dquot %d space %lld+%lld, inodes %lld+%lld\n",
448 dquot->dq_id, dquot->dq_dqb.dqb_curspace, spacechange,
449 dquot->dq_dqb.dqb_curinodes, inodechange);
450 if (!test_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags))
451 dquot->dq_dqb.dqb_curspace += spacechange;
452 if (!test_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags))
453 dquot->dq_dqb.dqb_curinodes += inodechange;
454 /* Set properly space grace time... */
455 if (dquot->dq_dqb.dqb_bsoftlimit &&
456 dquot->dq_dqb.dqb_curspace > dquot->dq_dqb.dqb_bsoftlimit) {
457 if (!test_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags) &&
458 oldbtime > 0) {
459 if (dquot->dq_dqb.dqb_btime > 0)
460 dquot->dq_dqb.dqb_btime =
461 min(dquot->dq_dqb.dqb_btime, oldbtime);
462 else
463 dquot->dq_dqb.dqb_btime = oldbtime;
464 }
465 } else {
466 dquot->dq_dqb.dqb_btime = 0;
467 clear_bit(DQ_BLKS_B, &dquot->dq_flags);
468 }
469 /* Set properly inode grace time... */
470 if (dquot->dq_dqb.dqb_isoftlimit &&
471 dquot->dq_dqb.dqb_curinodes > dquot->dq_dqb.dqb_isoftlimit) {
472 if (!test_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags) &&
473 olditime > 0) {
474 if (dquot->dq_dqb.dqb_itime > 0)
475 dquot->dq_dqb.dqb_itime =
476 min(dquot->dq_dqb.dqb_itime, olditime);
477 else
478 dquot->dq_dqb.dqb_itime = olditime;
479 }
480 } else {
481 dquot->dq_dqb.dqb_itime = 0;
482 clear_bit(DQ_INODES_B, &dquot->dq_flags);
483 }
484 /* All information is properly updated, clear the flags */
485 __clear_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
486 __clear_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
487 __clear_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
488 __clear_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
489 __clear_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
490 __clear_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
491 OCFS2_DQUOT(dquot)->dq_origspace = dquot->dq_dqb.dqb_curspace;
492 OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
493 spin_unlock(&dq_data_lock);
494 err = ocfs2_qinfo_lock(info, freeing);
495 if (err < 0) {
496 mlog(ML_ERROR, "Failed to lock quota info, loosing quota write"
497 " (type=%d, id=%u)\n", dquot->dq_type,
498 (unsigned)dquot->dq_id);
499 goto out;
500 }
501 if (freeing)
502 OCFS2_DQUOT(dquot)->dq_use_count--;
503 err = qtree_write_dquot(&info->dqi_gi, dquot);
504 if (err < 0)
505 goto out_qlock;
506 if (freeing && !OCFS2_DQUOT(dquot)->dq_use_count) {
507 err = qtree_release_dquot(&info->dqi_gi, dquot);
508 if (info_dirty(sb_dqinfo(sb, type))) {
509 err2 = __ocfs2_global_write_info(sb, type);
510 if (!err)
511 err = err2;
512 }
513 }
514out_qlock:
515 ocfs2_qinfo_unlock(info, freeing);
516out:
517 if (err < 0)
518 mlog_errno(err);
519 return err;
520}
521
522/*
523 * Wrappers for generic quota functions
524 */
525
526static int ocfs2_write_dquot(struct dquot *dquot)
527{
528 handle_t *handle;
529 struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
530 int status = 0;
531
532 mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
533
534 handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
535 if (IS_ERR(handle)) {
536 status = PTR_ERR(handle);
537 mlog_errno(status);
538 goto out;
539 }
540 status = dquot_commit(dquot);
541 ocfs2_commit_trans(osb, handle);
542out:
543 mlog_exit(status);
544 return status;
545}
546
547int ocfs2_calc_qdel_credits(struct super_block *sb, int type)
548{
549 struct ocfs2_mem_dqinfo *oinfo;
550 int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
551 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
552
553 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
554 return 0;
555
556 oinfo = sb_dqinfo(sb, type)->dqi_priv;
557 /* We modify tree, leaf block, global info, local chunk header,
558 * global and local inode */
559 return oinfo->dqi_gi.dqi_qtree_depth + 2 + 1 +
560 2 * OCFS2_INODE_UPDATE_CREDITS;
561}
562
563static int ocfs2_release_dquot(struct dquot *dquot)
564{
565 handle_t *handle;
566 struct ocfs2_mem_dqinfo *oinfo =
567 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
568 struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
569 int status = 0;
570
571 mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
572
573 status = ocfs2_lock_global_qf(oinfo, 1);
574 if (status < 0)
575 goto out;
576 handle = ocfs2_start_trans(osb,
577 ocfs2_calc_qdel_credits(dquot->dq_sb, dquot->dq_type));
578 if (IS_ERR(handle)) {
579 status = PTR_ERR(handle);
580 mlog_errno(status);
581 goto out_ilock;
582 }
583 status = dquot_release(dquot);
584 ocfs2_commit_trans(osb, handle);
585out_ilock:
586 ocfs2_unlock_global_qf(oinfo, 1);
587out:
588 mlog_exit(status);
589 return status;
590}
591
592int ocfs2_calc_qinit_credits(struct super_block *sb, int type)
593{
594 struct ocfs2_mem_dqinfo *oinfo;
595 int features[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
596 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA };
597 struct ocfs2_dinode *lfe, *gfe;
598
599 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, features[type]))
600 return 0;
601
602 oinfo = sb_dqinfo(sb, type)->dqi_priv;
603 gfe = (struct ocfs2_dinode *)oinfo->dqi_gqi_bh->b_data;
604 lfe = (struct ocfs2_dinode *)oinfo->dqi_lqi_bh->b_data;
605 /* We can extend local file + global file. In local file we
606 * can modify info, chunk header block and dquot block. In
607 * global file we can modify info, tree and leaf block */
608 return ocfs2_calc_extend_credits(sb, &lfe->id2.i_list, 0) +
609 ocfs2_calc_extend_credits(sb, &gfe->id2.i_list, 0) +
610 3 + oinfo->dqi_gi.dqi_qtree_depth + 2;
611}
612
613static int ocfs2_acquire_dquot(struct dquot *dquot)
614{
615 handle_t *handle;
616 struct ocfs2_mem_dqinfo *oinfo =
617 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
618 struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
619 int status = 0;
620
621 mlog_entry("id=%u, type=%d", dquot->dq_id, dquot->dq_type);
622 /* We need an exclusive lock, because we're going to update use count
623 * and instantiate possibly new dquot structure */
624 status = ocfs2_lock_global_qf(oinfo, 1);
625 if (status < 0)
626 goto out;
627 handle = ocfs2_start_trans(osb,
628 ocfs2_calc_qinit_credits(dquot->dq_sb, dquot->dq_type));
629 if (IS_ERR(handle)) {
630 status = PTR_ERR(handle);
631 mlog_errno(status);
632 goto out_ilock;
633 }
634 status = dquot_acquire(dquot);
635 ocfs2_commit_trans(osb, handle);
636out_ilock:
637 ocfs2_unlock_global_qf(oinfo, 1);
638out:
639 mlog_exit(status);
640 return status;
641}
642
643static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
644{
645 unsigned long mask = (1 << (DQ_LASTSET_B + QIF_ILIMITS_B)) |
646 (1 << (DQ_LASTSET_B + QIF_BLIMITS_B)) |
647 (1 << (DQ_LASTSET_B + QIF_INODES_B)) |
648 (1 << (DQ_LASTSET_B + QIF_SPACE_B)) |
649 (1 << (DQ_LASTSET_B + QIF_BTIME_B)) |
650 (1 << (DQ_LASTSET_B + QIF_ITIME_B));
651 int sync = 0;
652 int status;
653 struct super_block *sb = dquot->dq_sb;
654 int type = dquot->dq_type;
655 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
656 handle_t *handle;
657 struct ocfs2_super *osb = OCFS2_SB(sb);
658
659 mlog_entry("id=%u, type=%d", dquot->dq_id, type);
660 dquot_mark_dquot_dirty(dquot);
661
662 /* In case user set some limits, sync dquot immediately to global
663 * quota file so that information propagates quicker */
664 spin_lock(&dq_data_lock);
665 if (dquot->dq_flags & mask)
666 sync = 1;
667 spin_unlock(&dq_data_lock);
668 if (!sync) {
669 status = ocfs2_write_dquot(dquot);
670 goto out;
671 }
672 status = ocfs2_lock_global_qf(oinfo, 1);
673 if (status < 0)
674 goto out;
675 handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS);
676 if (IS_ERR(handle)) {
677 status = PTR_ERR(handle);
678 mlog_errno(status);
679 goto out_ilock;
680 }
681 status = ocfs2_sync_dquot(dquot);
682 if (status < 0) {
683 mlog_errno(status);
684 goto out_trans;
685 }
686 /* Now write updated local dquot structure */
687 status = dquot_commit(dquot);
688out_trans:
689 ocfs2_commit_trans(osb, handle);
690out_ilock:
691 ocfs2_unlock_global_qf(oinfo, 1);
692out:
693 mlog_exit(status);
694 return status;
695}
696
697/* This should happen only after set_dqinfo(). */
698static int ocfs2_write_info(struct super_block *sb, int type)
699{
700 handle_t *handle;
701 int status = 0;
702 struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
703
704 mlog_entry_void();
705
706 status = ocfs2_lock_global_qf(oinfo, 1);
707 if (status < 0)
708 goto out;
709 handle = ocfs2_start_trans(OCFS2_SB(sb), OCFS2_QINFO_WRITE_CREDITS);
710 if (IS_ERR(handle)) {
711 status = PTR_ERR(handle);
712 mlog_errno(status);
713 goto out_ilock;
714 }
715 status = dquot_commit_info(sb, type);
716 ocfs2_commit_trans(OCFS2_SB(sb), handle);
717out_ilock:
718 ocfs2_unlock_global_qf(oinfo, 1);
719out:
720 mlog_exit(status);
721 return status;
722}
723
724/* This is difficult. We have to lock quota inode and start transaction
725 * in this function but we don't want to take the penalty of exlusive
726 * quota file lock when we are just going to use cached structures. So
727 * we just take read lock check whether we have dquot cached and if so,
728 * we don't have to take the write lock... */
729static int ocfs2_dquot_initialize(struct inode *inode, int type)
730{
731 handle_t *handle = NULL;
732 int status = 0;
733 struct super_block *sb = inode->i_sb;
734 struct ocfs2_mem_dqinfo *oinfo;
735 int exclusive = 0;
736 int cnt;
737 qid_t id;
738
739 mlog_entry_void();
740
741 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
742 if (type != -1 && cnt != type)
743 continue;
744 if (!sb_has_quota_active(sb, cnt))
745 continue;
746 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
747 status = ocfs2_lock_global_qf(oinfo, 0);
748 if (status < 0)
749 goto out;
750 /* This is just a performance optimization not a reliable test.
751 * Since we hold an inode lock, noone can actually release
752 * the structure until we are finished with initialization. */
753 if (inode->i_dquot[cnt] != NODQUOT) {
754 ocfs2_unlock_global_qf(oinfo, 0);
755 continue;
756 }
757 /* When we have inode lock, we know that no dquot_release() can
758 * run and thus we can safely check whether we need to
759 * read+modify global file to get quota information or whether
760 * our node already has it. */
761 if (cnt == USRQUOTA)
762 id = inode->i_uid;
763 else if (cnt == GRPQUOTA)
764 id = inode->i_gid;
765 else
766 BUG();
767 /* Obtain exclusion from quota off... */
768 down_write(&sb_dqopt(sb)->dqptr_sem);
769 exclusive = !dquot_is_cached(sb, id, cnt);
770 up_write(&sb_dqopt(sb)->dqptr_sem);
771 if (exclusive) {
772 status = ocfs2_lock_global_qf(oinfo, 1);
773 if (status < 0) {
774 exclusive = 0;
775 mlog_errno(status);
776 goto out_ilock;
777 }
778 handle = ocfs2_start_trans(OCFS2_SB(sb),
779 ocfs2_calc_qinit_credits(sb, cnt));
780 if (IS_ERR(handle)) {
781 status = PTR_ERR(handle);
782 mlog_errno(status);
783 goto out_ilock;
784 }
785 }
786 dquot_initialize(inode, cnt);
787 if (exclusive) {
788 ocfs2_commit_trans(OCFS2_SB(sb), handle);
789 ocfs2_unlock_global_qf(oinfo, 1);
790 }
791 ocfs2_unlock_global_qf(oinfo, 0);
792 }
793 mlog_exit(0);
794 return 0;
795out_ilock:
796 if (exclusive)
797 ocfs2_unlock_global_qf(oinfo, 1);
798 ocfs2_unlock_global_qf(oinfo, 0);
799out:
800 mlog_exit(status);
801 return status;
802}
803
804static int ocfs2_dquot_drop_slow(struct inode *inode)
805{
806 int status;
807 int cnt;
808 int got_lock[MAXQUOTAS] = {0, 0};
809 handle_t *handle;
810 struct super_block *sb = inode->i_sb;
811 struct ocfs2_mem_dqinfo *oinfo;
812
813 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
814 if (!sb_has_quota_active(sb, cnt))
815 continue;
816 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
817 status = ocfs2_lock_global_qf(oinfo, 1);
818 if (status < 0)
819 goto out;
820 got_lock[cnt] = 1;
821 }
822 handle = ocfs2_start_trans(OCFS2_SB(sb),
823 ocfs2_calc_qinit_credits(sb, USRQUOTA) +
824 ocfs2_calc_qinit_credits(sb, GRPQUOTA));
825 if (IS_ERR(handle)) {
826 status = PTR_ERR(handle);
827 mlog_errno(status);
828 goto out;
829 }
830 dquot_drop(inode);
831 ocfs2_commit_trans(OCFS2_SB(sb), handle);
832out:
833 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
834 if (got_lock[cnt]) {
835 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
836 ocfs2_unlock_global_qf(oinfo, 1);
837 }
838 return status;
839}
840
841/* See the comment before ocfs2_dquot_initialize. */
842static int ocfs2_dquot_drop(struct inode *inode)
843{
844 int status = 0;
845 struct super_block *sb = inode->i_sb;
846 struct ocfs2_mem_dqinfo *oinfo;
847 int exclusive = 0;
848 int cnt;
849 int got_lock[MAXQUOTAS] = {0, 0};
850
851 mlog_entry_void();
852 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
853 if (!sb_has_quota_active(sb, cnt))
854 continue;
855 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
856 status = ocfs2_lock_global_qf(oinfo, 0);
857 if (status < 0)
858 goto out;
859 got_lock[cnt] = 1;
860 }
861 /* Lock against anyone releasing references so that when when we check
862 * we know we are not going to be last ones to release dquot */
863 down_write(&sb_dqopt(sb)->dqptr_sem);
864 /* Urgh, this is a terrible hack :( */
865 for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
866 if (inode->i_dquot[cnt] != NODQUOT &&
867 atomic_read(&inode->i_dquot[cnt]->dq_count) > 1) {
868 exclusive = 1;
869 break;
870 }
871 }
872 if (!exclusive)
873 dquot_drop_locked(inode);
874 up_write(&sb_dqopt(sb)->dqptr_sem);
875out:
876 for (cnt = 0; cnt < MAXQUOTAS; cnt++)
877 if (got_lock[cnt]) {
878 oinfo = sb_dqinfo(sb, cnt)->dqi_priv;
879 ocfs2_unlock_global_qf(oinfo, 0);
880 }
881 /* In case we bailed out because we had to do expensive locking
882 * do it now... */
883 if (exclusive)
884 status = ocfs2_dquot_drop_slow(inode);
885 mlog_exit(status);
886 return status;
887}
888
889static struct dquot *ocfs2_alloc_dquot(struct super_block *sb, int type)
890{
891 struct ocfs2_dquot *dquot =
892 kmem_cache_zalloc(ocfs2_dquot_cachep, GFP_NOFS);
893
894 if (!dquot)
895 return NULL;
896 return &dquot->dq_dquot;
897}
898
899static void ocfs2_destroy_dquot(struct dquot *dquot)
900{
901 kmem_cache_free(ocfs2_dquot_cachep, dquot);
902}
903
904struct dquot_operations ocfs2_quota_operations = {
905 .initialize = ocfs2_dquot_initialize,
906 .drop = ocfs2_dquot_drop,
907 .alloc_space = dquot_alloc_space,
908 .alloc_inode = dquot_alloc_inode,
909 .free_space = dquot_free_space,
910 .free_inode = dquot_free_inode,
911 .transfer = dquot_transfer,
912 .write_dquot = ocfs2_write_dquot,
913 .acquire_dquot = ocfs2_acquire_dquot,
914 .release_dquot = ocfs2_release_dquot,
915 .mark_dirty = ocfs2_mark_dquot_dirty,
916 .write_info = ocfs2_write_info,
917 .alloc_dquot = ocfs2_alloc_dquot,
918 .destroy_dquot = ocfs2_destroy_dquot,
919};