aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/quota_local.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_local.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_local.c')
-rw-r--r--fs/ocfs2/quota_local.c833
1 files changed, 833 insertions, 0 deletions
diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
new file mode 100644
index 000000000000..55c3f2f98dcd
--- /dev/null
+++ b/fs/ocfs2/quota_local.c
@@ -0,0 +1,833 @@
1/*
2 * Implementation of operations over local quota file
3 */
4
5#include <linux/fs.h>
6#include <linux/quota.h>
7#include <linux/quotaops.h>
8#include <linux/module.h>
9
10#define MLOG_MASK_PREFIX ML_QUOTA
11#include <cluster/masklog.h>
12
13#include "ocfs2_fs.h"
14#include "ocfs2.h"
15#include "inode.h"
16#include "alloc.h"
17#include "file.h"
18#include "buffer_head_io.h"
19#include "journal.h"
20#include "sysfile.h"
21#include "dlmglue.h"
22#include "quota.h"
23
24/* Number of local quota structures per block */
25static inline unsigned int ol_quota_entries_per_block(struct super_block *sb)
26{
27 return ((sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE) /
28 sizeof(struct ocfs2_local_disk_dqblk));
29}
30
31/* Number of blocks with entries in one chunk */
32static inline unsigned int ol_chunk_blocks(struct super_block *sb)
33{
34 return ((sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) -
35 OCFS2_QBLK_RESERVED_SPACE) << 3) /
36 ol_quota_entries_per_block(sb);
37}
38
39/* Number of entries in a chunk bitmap */
40static unsigned int ol_chunk_entries(struct super_block *sb)
41{
42 return ol_chunk_blocks(sb) * ol_quota_entries_per_block(sb);
43}
44
45/* Offset of the chunk in quota file */
46static unsigned int ol_quota_chunk_block(struct super_block *sb, int c)
47{
48 /* 1 block for local quota file info, 1 block per chunk for chunk info */
49 return 1 + (ol_chunk_blocks(sb) + 1) * c;
50}
51
52/* Offset of the dquot structure in the quota file */
53static loff_t ol_dqblk_off(struct super_block *sb, int c, int off)
54{
55 int epb = ol_quota_entries_per_block(sb);
56
57 return ((ol_quota_chunk_block(sb, c) + 1 + off / epb)
58 << sb->s_blocksize_bits) +
59 (off % epb) * sizeof(struct ocfs2_local_disk_dqblk);
60}
61
62/* Compute block number from given offset */
63static inline unsigned int ol_dqblk_file_block(struct super_block *sb, loff_t off)
64{
65 return off >> sb->s_blocksize_bits;
66}
67
68static inline unsigned int ol_dqblk_block_offset(struct super_block *sb, loff_t off)
69{
70 return off & ((1 << sb->s_blocksize_bits) - 1);
71}
72
73/* Compute offset in the chunk of a structure with the given offset */
74static int ol_dqblk_chunk_off(struct super_block *sb, int c, loff_t off)
75{
76 int epb = ol_quota_entries_per_block(sb);
77
78 return ((off >> sb->s_blocksize_bits) -
79 ol_quota_chunk_block(sb, c) - 1) * epb
80 + ((unsigned int)(off & ((1 << sb->s_blocksize_bits) - 1))) /
81 sizeof(struct ocfs2_local_disk_dqblk);
82}
83
84/* Write bufferhead into the fs */
85static int ocfs2_modify_bh(struct inode *inode, struct buffer_head *bh,
86 void (*modify)(struct buffer_head *, void *), void *private)
87{
88 struct super_block *sb = inode->i_sb;
89 handle_t *handle;
90 int status;
91
92 handle = ocfs2_start_trans(OCFS2_SB(sb), 1);
93 if (IS_ERR(handle)) {
94 status = PTR_ERR(handle);
95 mlog_errno(status);
96 return status;
97 }
98 status = ocfs2_journal_access(handle, inode, bh,
99 OCFS2_JOURNAL_ACCESS_WRITE);
100 if (status < 0) {
101 mlog_errno(status);
102 ocfs2_commit_trans(OCFS2_SB(sb), handle);
103 return status;
104 }
105 lock_buffer(bh);
106 modify(bh, private);
107 unlock_buffer(bh);
108 status = ocfs2_journal_dirty(handle, bh);
109 if (status < 0) {
110 mlog_errno(status);
111 ocfs2_commit_trans(OCFS2_SB(sb), handle);
112 return status;
113 }
114 status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
115 if (status < 0) {
116 mlog_errno(status);
117 return status;
118 }
119 return 0;
120}
121
122/* Check whether we understand format of quota files */
123static int ocfs2_local_check_quota_file(struct super_block *sb, int type)
124{
125 unsigned int lmagics[MAXQUOTAS] = OCFS2_LOCAL_QMAGICS;
126 unsigned int lversions[MAXQUOTAS] = OCFS2_LOCAL_QVERSIONS;
127 unsigned int gmagics[MAXQUOTAS] = OCFS2_GLOBAL_QMAGICS;
128 unsigned int gversions[MAXQUOTAS] = OCFS2_GLOBAL_QVERSIONS;
129 unsigned int ino[MAXQUOTAS] = { USER_QUOTA_SYSTEM_INODE,
130 GROUP_QUOTA_SYSTEM_INODE };
131 struct buffer_head *bh;
132 struct inode *linode = sb_dqopt(sb)->files[type];
133 struct inode *ginode = NULL;
134 struct ocfs2_disk_dqheader *dqhead;
135 int status, ret = 0;
136
137 /* First check whether we understand local quota file */
138 bh = ocfs2_read_quota_block(linode, 0, &status);
139 if (!bh) {
140 mlog_errno(status);
141 mlog(ML_ERROR, "failed to read quota file header (type=%d)\n",
142 type);
143 goto out_err;
144 }
145 dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data);
146 if (le32_to_cpu(dqhead->dqh_magic) != lmagics[type]) {
147 mlog(ML_ERROR, "quota file magic does not match (%u != %u),"
148 " type=%d\n", le32_to_cpu(dqhead->dqh_magic),
149 lmagics[type], type);
150 goto out_err;
151 }
152 if (le32_to_cpu(dqhead->dqh_version) != lversions[type]) {
153 mlog(ML_ERROR, "quota file version does not match (%u != %u),"
154 " type=%d\n", le32_to_cpu(dqhead->dqh_version),
155 lversions[type], type);
156 goto out_err;
157 }
158 brelse(bh);
159 bh = NULL;
160
161 /* Next check whether we understand global quota file */
162 ginode = ocfs2_get_system_file_inode(OCFS2_SB(sb), ino[type],
163 OCFS2_INVALID_SLOT);
164 if (!ginode) {
165 mlog(ML_ERROR, "cannot get global quota file inode "
166 "(type=%d)\n", type);
167 goto out_err;
168 }
169 /* Since the header is read only, we don't care about locking */
170 bh = ocfs2_read_quota_block(ginode, 0, &status);
171 if (!bh) {
172 mlog_errno(status);
173 mlog(ML_ERROR, "failed to read global quota file header "
174 "(type=%d)\n", type);
175 goto out_err;
176 }
177 dqhead = (struct ocfs2_disk_dqheader *)(bh->b_data);
178 if (le32_to_cpu(dqhead->dqh_magic) != gmagics[type]) {
179 mlog(ML_ERROR, "global quota file magic does not match "
180 "(%u != %u), type=%d\n",
181 le32_to_cpu(dqhead->dqh_magic), gmagics[type], type);
182 goto out_err;
183 }
184 if (le32_to_cpu(dqhead->dqh_version) != gversions[type]) {
185 mlog(ML_ERROR, "global quota file version does not match "
186 "(%u != %u), type=%d\n",
187 le32_to_cpu(dqhead->dqh_version), gversions[type],
188 type);
189 goto out_err;
190 }
191
192 ret = 1;
193out_err:
194 brelse(bh);
195 iput(ginode);
196 return ret;
197}
198
199/* Release given list of quota file chunks */
200static void ocfs2_release_local_quota_bitmaps(struct list_head *head)
201{
202 struct ocfs2_quota_chunk *pos, *next;
203
204 list_for_each_entry_safe(pos, next, head, qc_chunk) {
205 list_del(&pos->qc_chunk);
206 brelse(pos->qc_headerbh);
207 kmem_cache_free(ocfs2_qf_chunk_cachep, pos);
208 }
209}
210
211/* Load quota bitmaps into memory */
212static int ocfs2_load_local_quota_bitmaps(struct inode *inode,
213 struct ocfs2_local_disk_dqinfo *ldinfo,
214 struct list_head *head)
215{
216 struct ocfs2_quota_chunk *newchunk;
217 int i, status;
218
219 INIT_LIST_HEAD(head);
220 for (i = 0; i < le32_to_cpu(ldinfo->dqi_chunks); i++) {
221 newchunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS);
222 if (!newchunk) {
223 ocfs2_release_local_quota_bitmaps(head);
224 return -ENOMEM;
225 }
226 newchunk->qc_num = i;
227 newchunk->qc_headerbh = ocfs2_read_quota_block(inode,
228 ol_quota_chunk_block(inode->i_sb, i),
229 &status);
230 if (!newchunk->qc_headerbh) {
231 mlog_errno(status);
232 kmem_cache_free(ocfs2_qf_chunk_cachep, newchunk);
233 ocfs2_release_local_quota_bitmaps(head);
234 return status;
235 }
236 list_add_tail(&newchunk->qc_chunk, head);
237 }
238 return 0;
239}
240
241static void olq_update_info(struct buffer_head *bh, void *private)
242{
243 struct mem_dqinfo *info = private;
244 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
245 struct ocfs2_local_disk_dqinfo *ldinfo;
246
247 ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data +
248 OCFS2_LOCAL_INFO_OFF);
249 spin_lock(&dq_data_lock);
250 ldinfo->dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
251 ldinfo->dqi_chunks = cpu_to_le32(oinfo->dqi_chunks);
252 ldinfo->dqi_blocks = cpu_to_le32(oinfo->dqi_blocks);
253 spin_unlock(&dq_data_lock);
254}
255
256/* Read information header from quota file */
257static int ocfs2_local_read_info(struct super_block *sb, int type)
258{
259 struct ocfs2_local_disk_dqinfo *ldinfo;
260 struct mem_dqinfo *info = sb_dqinfo(sb, type);
261 struct ocfs2_mem_dqinfo *oinfo;
262 struct inode *lqinode = sb_dqopt(sb)->files[type];
263 int status;
264 struct buffer_head *bh = NULL;
265 int locked = 0;
266
267 info->dqi_maxblimit = 0x7fffffffffffffffLL;
268 info->dqi_maxilimit = 0x7fffffffffffffffLL;
269 oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
270 if (!oinfo) {
271 mlog(ML_ERROR, "failed to allocate memory for ocfs2 quota"
272 " info.");
273 goto out_err;
274 }
275 info->dqi_priv = oinfo;
276 oinfo->dqi_type = type;
277 INIT_LIST_HEAD(&oinfo->dqi_chunk);
278 oinfo->dqi_lqi_bh = NULL;
279 oinfo->dqi_ibh = NULL;
280
281 status = ocfs2_global_read_info(sb, type);
282 if (status < 0)
283 goto out_err;
284
285 status = ocfs2_inode_lock(lqinode, &oinfo->dqi_lqi_bh, 1);
286 if (status < 0) {
287 mlog_errno(status);
288 goto out_err;
289 }
290 locked = 1;
291
292 /* Now read local header */
293 bh = ocfs2_read_quota_block(lqinode, 0, &status);
294 if (!bh) {
295 mlog_errno(status);
296 mlog(ML_ERROR, "failed to read quota file info header "
297 "(type=%d)\n", type);
298 goto out_err;
299 }
300 ldinfo = (struct ocfs2_local_disk_dqinfo *)(bh->b_data +
301 OCFS2_LOCAL_INFO_OFF);
302 info->dqi_flags = le32_to_cpu(ldinfo->dqi_flags);
303 oinfo->dqi_chunks = le32_to_cpu(ldinfo->dqi_chunks);
304 oinfo->dqi_blocks = le32_to_cpu(ldinfo->dqi_blocks);
305 oinfo->dqi_ibh = bh;
306
307 /* We crashed when using local quota file? */
308 if (!(info->dqi_flags & OLQF_CLEAN))
309 goto out_err; /* So far we just bail out. Later we should resync here */
310
311 status = ocfs2_load_local_quota_bitmaps(sb_dqopt(sb)->files[type],
312 ldinfo,
313 &oinfo->dqi_chunk);
314 if (status < 0) {
315 mlog_errno(status);
316 goto out_err;
317 }
318
319 /* Now mark quota file as used */
320 info->dqi_flags &= ~OLQF_CLEAN;
321 status = ocfs2_modify_bh(lqinode, bh, olq_update_info, info);
322 if (status < 0) {
323 mlog_errno(status);
324 goto out_err;
325 }
326
327 return 0;
328out_err:
329 if (oinfo) {
330 iput(oinfo->dqi_gqinode);
331 ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock);
332 ocfs2_lock_res_free(&oinfo->dqi_gqlock);
333 brelse(oinfo->dqi_lqi_bh);
334 if (locked)
335 ocfs2_inode_unlock(lqinode, 1);
336 ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
337 kfree(oinfo);
338 }
339 brelse(bh);
340 return -1;
341}
342
343/* Write local info to quota file */
344static int ocfs2_local_write_info(struct super_block *sb, int type)
345{
346 struct mem_dqinfo *info = sb_dqinfo(sb, type);
347 struct buffer_head *bh = ((struct ocfs2_mem_dqinfo *)info->dqi_priv)
348 ->dqi_ibh;
349 int status;
350
351 status = ocfs2_modify_bh(sb_dqopt(sb)->files[type], bh, olq_update_info,
352 info);
353 if (status < 0) {
354 mlog_errno(status);
355 return -1;
356 }
357
358 return 0;
359}
360
361/* Release info from memory */
362static int ocfs2_local_free_info(struct super_block *sb, int type)
363{
364 struct mem_dqinfo *info = sb_dqinfo(sb, type);
365 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
366 struct ocfs2_quota_chunk *chunk;
367 struct ocfs2_local_disk_chunk *dchunk;
368 int mark_clean = 1, len;
369 int status;
370
371 iput(oinfo->dqi_gqinode);
372 ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock);
373 ocfs2_lock_res_free(&oinfo->dqi_gqlock);
374 list_for_each_entry(chunk, &oinfo->dqi_chunk, qc_chunk) {
375 dchunk = (struct ocfs2_local_disk_chunk *)
376 (chunk->qc_headerbh->b_data);
377 if (chunk->qc_num < oinfo->dqi_chunks - 1) {
378 len = ol_chunk_entries(sb);
379 } else {
380 len = (oinfo->dqi_blocks -
381 ol_quota_chunk_block(sb, chunk->qc_num) - 1)
382 * ol_quota_entries_per_block(sb);
383 }
384 /* Not all entries free? Bug! */
385 if (le32_to_cpu(dchunk->dqc_free) != len) {
386 mlog(ML_ERROR, "releasing quota file with used "
387 "entries (type=%d)\n", type);
388 mark_clean = 0;
389 }
390 }
391 ocfs2_release_local_quota_bitmaps(&oinfo->dqi_chunk);
392
393 if (!mark_clean)
394 goto out;
395
396 /* Mark local file as clean */
397 info->dqi_flags |= OLQF_CLEAN;
398 status = ocfs2_modify_bh(sb_dqopt(sb)->files[type],
399 oinfo->dqi_ibh,
400 olq_update_info,
401 info);
402 if (status < 0) {
403 mlog_errno(status);
404 goto out;
405 }
406
407out:
408 ocfs2_inode_unlock(sb_dqopt(sb)->files[type], 1);
409 brelse(oinfo->dqi_ibh);
410 brelse(oinfo->dqi_lqi_bh);
411 kfree(oinfo);
412 return 0;
413}
414
415static void olq_set_dquot(struct buffer_head *bh, void *private)
416{
417 struct ocfs2_dquot *od = private;
418 struct ocfs2_local_disk_dqblk *dqblk;
419 struct super_block *sb = od->dq_dquot.dq_sb;
420
421 dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
422 + ol_dqblk_block_offset(sb, od->dq_local_off));
423
424 dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
425 spin_lock(&dq_data_lock);
426 dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
427 od->dq_origspace);
428 dqblk->dqb_inodemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curinodes -
429 od->dq_originodes);
430 spin_unlock(&dq_data_lock);
431 mlog(0, "Writing local dquot %u space %lld inodes %lld\n",
432 od->dq_dquot.dq_id, dqblk->dqb_spacemod, dqblk->dqb_inodemod);
433}
434
435/* Write dquot to local quota file */
436static int ocfs2_local_write_dquot(struct dquot *dquot)
437{
438 struct super_block *sb = dquot->dq_sb;
439 struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
440 struct buffer_head *bh;
441 int status;
442
443 bh = ocfs2_read_quota_block(sb_dqopt(sb)->files[dquot->dq_type],
444 ol_dqblk_file_block(sb, od->dq_local_off),
445 &status);
446 if (!bh) {
447 mlog_errno(status);
448 goto out;
449 }
450 status = ocfs2_modify_bh(sb_dqopt(sb)->files[dquot->dq_type], bh,
451 olq_set_dquot, od);
452 if (status < 0) {
453 mlog_errno(status);
454 goto out;
455 }
456out:
457 brelse(bh);
458 return status;
459}
460
461/* Find free entry in local quota file */
462static struct ocfs2_quota_chunk *ocfs2_find_free_entry(struct super_block *sb,
463 int type,
464 int *offset)
465{
466 struct mem_dqinfo *info = sb_dqinfo(sb, type);
467 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
468 struct ocfs2_quota_chunk *chunk;
469 struct ocfs2_local_disk_chunk *dchunk;
470 int found = 0, len;
471
472 list_for_each_entry(chunk, &oinfo->dqi_chunk, qc_chunk) {
473 dchunk = (struct ocfs2_local_disk_chunk *)
474 chunk->qc_headerbh->b_data;
475 if (le32_to_cpu(dchunk->dqc_free) > 0) {
476 found = 1;
477 break;
478 }
479 }
480 if (!found)
481 return NULL;
482
483 if (chunk->qc_num < oinfo->dqi_chunks - 1) {
484 len = ol_chunk_entries(sb);
485 } else {
486 len = (oinfo->dqi_blocks -
487 ol_quota_chunk_block(sb, chunk->qc_num) - 1)
488 * ol_quota_entries_per_block(sb);
489 }
490
491 found = ocfs2_find_next_zero_bit(dchunk->dqc_bitmap, len, 0);
492 /* We failed? */
493 if (found == len) {
494 mlog(ML_ERROR, "Did not find empty entry in chunk %d with %u"
495 " entries free (type=%d)\n", chunk->qc_num,
496 le32_to_cpu(dchunk->dqc_free), type);
497 return ERR_PTR(-EIO);
498 }
499 *offset = found;
500 return chunk;
501}
502
503/* Add new chunk to the local quota file */
504static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
505 struct super_block *sb,
506 int type,
507 int *offset)
508{
509 struct mem_dqinfo *info = sb_dqinfo(sb, type);
510 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
511 struct inode *lqinode = sb_dqopt(sb)->files[type];
512 struct ocfs2_quota_chunk *chunk = NULL;
513 struct ocfs2_local_disk_chunk *dchunk;
514 int status;
515 handle_t *handle;
516 struct buffer_head *bh = NULL;
517 u64 p_blkno;
518
519 /* We are protected by dqio_sem so no locking needed */
520 status = ocfs2_extend_no_holes(lqinode,
521 lqinode->i_size + 2 * sb->s_blocksize,
522 lqinode->i_size);
523 if (status < 0) {
524 mlog_errno(status);
525 goto out;
526 }
527 status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh,
528 lqinode->i_size + 2 * sb->s_blocksize);
529 if (status < 0) {
530 mlog_errno(status);
531 goto out;
532 }
533
534 chunk = kmem_cache_alloc(ocfs2_qf_chunk_cachep, GFP_NOFS);
535 if (!chunk) {
536 status = -ENOMEM;
537 mlog_errno(status);
538 goto out;
539 }
540
541 down_read(&OCFS2_I(lqinode)->ip_alloc_sem);
542 status = ocfs2_extent_map_get_blocks(lqinode, oinfo->dqi_blocks,
543 &p_blkno, NULL, NULL);
544 up_read(&OCFS2_I(lqinode)->ip_alloc_sem);
545 if (status < 0) {
546 mlog_errno(status);
547 goto out;
548 }
549 bh = sb_getblk(sb, p_blkno);
550 if (!bh) {
551 status = -ENOMEM;
552 mlog_errno(status);
553 goto out;
554 }
555 dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
556
557 handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
558 if (IS_ERR(handle)) {
559 status = PTR_ERR(handle);
560 mlog_errno(status);
561 goto out;
562 }
563
564 status = ocfs2_journal_access(handle, lqinode, bh,
565 OCFS2_JOURNAL_ACCESS_WRITE);
566 if (status < 0) {
567 mlog_errno(status);
568 goto out_trans;
569 }
570 lock_buffer(bh);
571 dchunk->dqc_free = ol_quota_entries_per_block(sb);
572 memset(dchunk->dqc_bitmap, 0,
573 sb->s_blocksize - sizeof(struct ocfs2_local_disk_chunk) -
574 OCFS2_QBLK_RESERVED_SPACE);
575 set_buffer_uptodate(bh);
576 unlock_buffer(bh);
577 status = ocfs2_journal_dirty(handle, bh);
578 if (status < 0) {
579 mlog_errno(status);
580 goto out_trans;
581 }
582
583 oinfo->dqi_blocks += 2;
584 oinfo->dqi_chunks++;
585 status = ocfs2_local_write_info(sb, type);
586 if (status < 0) {
587 mlog_errno(status);
588 goto out_trans;
589 }
590 status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
591 if (status < 0) {
592 mlog_errno(status);
593 goto out;
594 }
595
596 list_add_tail(&chunk->qc_chunk, &oinfo->dqi_chunk);
597 chunk->qc_num = list_entry(chunk->qc_chunk.prev,
598 struct ocfs2_quota_chunk,
599 qc_chunk)->qc_num + 1;
600 chunk->qc_headerbh = bh;
601 *offset = 0;
602 return chunk;
603out_trans:
604 ocfs2_commit_trans(OCFS2_SB(sb), handle);
605out:
606 brelse(bh);
607 kmem_cache_free(ocfs2_qf_chunk_cachep, chunk);
608 return ERR_PTR(status);
609}
610
611/* Find free entry in local quota file */
612static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
613 struct super_block *sb,
614 int type,
615 int *offset)
616{
617 struct mem_dqinfo *info = sb_dqinfo(sb, type);
618 struct ocfs2_mem_dqinfo *oinfo = info->dqi_priv;
619 struct ocfs2_quota_chunk *chunk;
620 struct inode *lqinode = sb_dqopt(sb)->files[type];
621 struct ocfs2_local_disk_chunk *dchunk;
622 int epb = ol_quota_entries_per_block(sb);
623 unsigned int chunk_blocks;
624 int status;
625 handle_t *handle;
626
627 if (list_empty(&oinfo->dqi_chunk))
628 return ocfs2_local_quota_add_chunk(sb, type, offset);
629 /* Is the last chunk full? */
630 chunk = list_entry(oinfo->dqi_chunk.prev,
631 struct ocfs2_quota_chunk, qc_chunk);
632 chunk_blocks = oinfo->dqi_blocks -
633 ol_quota_chunk_block(sb, chunk->qc_num) - 1;
634 if (ol_chunk_blocks(sb) == chunk_blocks)
635 return ocfs2_local_quota_add_chunk(sb, type, offset);
636
637 /* We are protected by dqio_sem so no locking needed */
638 status = ocfs2_extend_no_holes(lqinode,
639 lqinode->i_size + sb->s_blocksize,
640 lqinode->i_size);
641 if (status < 0) {
642 mlog_errno(status);
643 goto out;
644 }
645 status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh,
646 lqinode->i_size + sb->s_blocksize);
647 if (status < 0) {
648 mlog_errno(status);
649 goto out;
650 }
651 handle = ocfs2_start_trans(OCFS2_SB(sb), 2);
652 if (IS_ERR(handle)) {
653 status = PTR_ERR(handle);
654 mlog_errno(status);
655 goto out;
656 }
657 status = ocfs2_journal_access(handle, lqinode, chunk->qc_headerbh,
658 OCFS2_JOURNAL_ACCESS_WRITE);
659 if (status < 0) {
660 mlog_errno(status);
661 goto out_trans;
662 }
663
664 dchunk = (struct ocfs2_local_disk_chunk *)chunk->qc_headerbh->b_data;
665 lock_buffer(chunk->qc_headerbh);
666 le32_add_cpu(&dchunk->dqc_free, ol_quota_entries_per_block(sb));
667 unlock_buffer(chunk->qc_headerbh);
668 status = ocfs2_journal_dirty(handle, chunk->qc_headerbh);
669 if (status < 0) {
670 mlog_errno(status);
671 goto out_trans;
672 }
673 oinfo->dqi_blocks++;
674 status = ocfs2_local_write_info(sb, type);
675 if (status < 0) {
676 mlog_errno(status);
677 goto out_trans;
678 }
679
680 status = ocfs2_commit_trans(OCFS2_SB(sb), handle);
681 if (status < 0) {
682 mlog_errno(status);
683 goto out;
684 }
685 *offset = chunk_blocks * epb;
686 return chunk;
687out_trans:
688 ocfs2_commit_trans(OCFS2_SB(sb), handle);
689out:
690 return ERR_PTR(status);
691}
692
693void olq_alloc_dquot(struct buffer_head *bh, void *private)
694{
695 int *offset = private;
696 struct ocfs2_local_disk_chunk *dchunk;
697
698 dchunk = (struct ocfs2_local_disk_chunk *)bh->b_data;
699 ocfs2_set_bit(*offset, dchunk->dqc_bitmap);
700 le32_add_cpu(&dchunk->dqc_free, -1);
701}
702
703/* Create dquot in the local file for given id */
704static int ocfs2_create_local_dquot(struct dquot *dquot)
705{
706 struct super_block *sb = dquot->dq_sb;
707 int type = dquot->dq_type;
708 struct inode *lqinode = sb_dqopt(sb)->files[type];
709 struct ocfs2_quota_chunk *chunk;
710 struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
711 int offset;
712 int status;
713
714 chunk = ocfs2_find_free_entry(sb, type, &offset);
715 if (!chunk) {
716 chunk = ocfs2_extend_local_quota_file(sb, type, &offset);
717 if (IS_ERR(chunk))
718 return PTR_ERR(chunk);
719 } else if (IS_ERR(chunk)) {
720 return PTR_ERR(chunk);
721 }
722 od->dq_local_off = ol_dqblk_off(sb, chunk->qc_num, offset);
723 od->dq_chunk = chunk;
724
725 /* Initialize dquot structure on disk */
726 status = ocfs2_local_write_dquot(dquot);
727 if (status < 0) {
728 mlog_errno(status);
729 goto out;
730 }
731
732 /* Mark structure as allocated */
733 status = ocfs2_modify_bh(lqinode, chunk->qc_headerbh, olq_alloc_dquot,
734 &offset);
735 if (status < 0) {
736 mlog_errno(status);
737 goto out;
738 }
739out:
740 return status;
741}
742
743/* Create entry in local file for dquot, load data from the global file */
744static int ocfs2_local_read_dquot(struct dquot *dquot)
745{
746 int status;
747
748 mlog_entry("id=%u, type=%d\n", dquot->dq_id, dquot->dq_type);
749
750 status = ocfs2_global_read_dquot(dquot);
751 if (status < 0) {
752 mlog_errno(status);
753 goto out_err;
754 }
755
756 /* Now create entry in the local quota file */
757 status = ocfs2_create_local_dquot(dquot);
758 if (status < 0) {
759 mlog_errno(status);
760 goto out_err;
761 }
762 mlog_exit(0);
763 return 0;
764out_err:
765 mlog_exit(status);
766 return status;
767}
768
769/* Release dquot structure from local quota file. ocfs2_release_dquot() has
770 * already started a transaction and obtained exclusive lock for global
771 * quota file. */
772static int ocfs2_local_release_dquot(struct dquot *dquot)
773{
774 int status;
775 int type = dquot->dq_type;
776 struct ocfs2_dquot *od = OCFS2_DQUOT(dquot);
777 struct super_block *sb = dquot->dq_sb;
778 struct ocfs2_local_disk_chunk *dchunk;
779 int offset;
780 handle_t *handle = journal_current_handle();
781
782 BUG_ON(!handle);
783 /* First write all local changes to global file */
784 status = ocfs2_global_release_dquot(dquot);
785 if (status < 0) {
786 mlog_errno(status);
787 goto out;
788 }
789
790 status = ocfs2_journal_access(handle, sb_dqopt(sb)->files[type],
791 od->dq_chunk->qc_headerbh, OCFS2_JOURNAL_ACCESS_WRITE);
792 if (status < 0) {
793 mlog_errno(status);
794 goto out;
795 }
796 offset = ol_dqblk_chunk_off(sb, od->dq_chunk->qc_num,
797 od->dq_local_off);
798 dchunk = (struct ocfs2_local_disk_chunk *)
799 (od->dq_chunk->qc_headerbh->b_data);
800 /* Mark structure as freed */
801 lock_buffer(od->dq_chunk->qc_headerbh);
802 ocfs2_clear_bit(offset, dchunk->dqc_bitmap);
803 le32_add_cpu(&dchunk->dqc_free, 1);
804 unlock_buffer(od->dq_chunk->qc_headerbh);
805 status = ocfs2_journal_dirty(handle, od->dq_chunk->qc_headerbh);
806 if (status < 0) {
807 mlog_errno(status);
808 goto out;
809 }
810 status = 0;
811out:
812 /* Clear the read bit so that next time someone uses this
813 * dquot he reads fresh info from disk and allocates local
814 * dquot structure */
815 clear_bit(DQ_READ_B, &dquot->dq_flags);
816 return status;
817}
818
819static struct quota_format_ops ocfs2_format_ops = {
820 .check_quota_file = ocfs2_local_check_quota_file,
821 .read_file_info = ocfs2_local_read_info,
822 .write_file_info = ocfs2_global_write_info,
823 .free_file_info = ocfs2_local_free_info,
824 .read_dqblk = ocfs2_local_read_dquot,
825 .commit_dqblk = ocfs2_local_write_dquot,
826 .release_dqblk = ocfs2_local_release_dquot,
827};
828
829struct quota_format_type ocfs2_quota_format = {
830 .qf_fmt_id = QFMT_OCFS2,
831 .qf_ops = &ocfs2_format_ops,
832 .qf_owner = THIS_MODULE
833};