diff options
Diffstat (limited to 'fs/ocfs2/quota_global.c')
-rw-r--r-- | fs/ocfs2/quota_global.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index af8340c45367..adf53508bdb8 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c | |||
@@ -1,10 +1,14 @@ | |||
1 | /* | 1 | /* |
2 | * Implementation of operations over global quota file | 2 | * Implementation of operations over global quota file |
3 | */ | 3 | */ |
4 | #include <linux/spinlock.h> | ||
4 | #include <linux/fs.h> | 5 | #include <linux/fs.h> |
5 | #include <linux/quota.h> | 6 | #include <linux/quota.h> |
6 | #include <linux/quotaops.h> | 7 | #include <linux/quotaops.h> |
7 | #include <linux/dqblk_qtree.h> | 8 | #include <linux/dqblk_qtree.h> |
9 | #include <linux/jiffies.h> | ||
10 | #include <linux/writeback.h> | ||
11 | #include <linux/workqueue.h> | ||
8 | 12 | ||
9 | #define MLOG_MASK_PREFIX ML_QUOTA | 13 | #define MLOG_MASK_PREFIX ML_QUOTA |
10 | #include <cluster/masklog.h> | 14 | #include <cluster/masklog.h> |
@@ -20,6 +24,10 @@ | |||
20 | #include "uptodate.h" | 24 | #include "uptodate.h" |
21 | #include "quota.h" | 25 | #include "quota.h" |
22 | 26 | ||
27 | static struct workqueue_struct *ocfs2_quota_wq = NULL; | ||
28 | |||
29 | static void qsync_work_fn(struct work_struct *work); | ||
30 | |||
23 | static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp) | 31 | static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp) |
24 | { | 32 | { |
25 | struct ocfs2_global_disk_dqblk *d = dp; | 33 | struct ocfs2_global_disk_dqblk *d = dp; |
@@ -313,6 +321,7 @@ int ocfs2_global_read_info(struct super_block *sb, int type) | |||
313 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); | 321 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); |
314 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); | 322 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); |
315 | oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); | 323 | oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); |
324 | oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms); | ||
316 | oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); | 325 | 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); | 326 | 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); | 327 | oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); |
@@ -320,6 +329,10 @@ int ocfs2_global_read_info(struct super_block *sb, int type) | |||
320 | oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize - | 329 | oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize - |
321 | OCFS2_QBLK_RESERVED_SPACE; | 330 | OCFS2_QBLK_RESERVED_SPACE; |
322 | oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi); | 331 | oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi); |
332 | INIT_DELAYED_WORK(&oinfo->dqi_sync_work, qsync_work_fn); | ||
333 | queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work, | ||
334 | oinfo->dqi_syncjiff); | ||
335 | |||
323 | out_err: | 336 | out_err: |
324 | mlog_exit(status); | 337 | mlog_exit(status); |
325 | return status; | 338 | return status; |
@@ -520,6 +533,61 @@ out: | |||
520 | } | 533 | } |
521 | 534 | ||
522 | /* | 535 | /* |
536 | * Functions for periodic syncing of dquots with global file | ||
537 | */ | ||
538 | static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type) | ||
539 | { | ||
540 | handle_t *handle; | ||
541 | struct super_block *sb = dquot->dq_sb; | ||
542 | struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; | ||
543 | struct ocfs2_super *osb = OCFS2_SB(sb); | ||
544 | int status = 0; | ||
545 | |||
546 | mlog_entry("id=%u qtype=%u type=%lu device=%s\n", dquot->dq_id, | ||
547 | dquot->dq_type, type, sb->s_id); | ||
548 | if (type != dquot->dq_type) | ||
549 | goto out; | ||
550 | status = ocfs2_lock_global_qf(oinfo, 1); | ||
551 | if (status < 0) | ||
552 | goto out; | ||
553 | |||
554 | handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS); | ||
555 | if (IS_ERR(handle)) { | ||
556 | status = PTR_ERR(handle); | ||
557 | mlog_errno(status); | ||
558 | goto out_ilock; | ||
559 | } | ||
560 | mutex_lock(&sb_dqopt(sb)->dqio_mutex); | ||
561 | status = ocfs2_sync_dquot(dquot); | ||
562 | mutex_unlock(&sb_dqopt(sb)->dqio_mutex); | ||
563 | if (status < 0) | ||
564 | mlog_errno(status); | ||
565 | /* We have to write local structure as well... */ | ||
566 | dquot_mark_dquot_dirty(dquot); | ||
567 | status = dquot_commit(dquot); | ||
568 | if (status < 0) | ||
569 | mlog_errno(status); | ||
570 | ocfs2_commit_trans(osb, handle); | ||
571 | out_ilock: | ||
572 | ocfs2_unlock_global_qf(oinfo, 1); | ||
573 | out: | ||
574 | mlog_exit(status); | ||
575 | return status; | ||
576 | } | ||
577 | |||
578 | static void qsync_work_fn(struct work_struct *work) | ||
579 | { | ||
580 | struct ocfs2_mem_dqinfo *oinfo = container_of(work, | ||
581 | struct ocfs2_mem_dqinfo, | ||
582 | dqi_sync_work.work); | ||
583 | struct super_block *sb = oinfo->dqi_gqinode->i_sb; | ||
584 | |||
585 | dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type); | ||
586 | queue_delayed_work(ocfs2_quota_wq, &oinfo->dqi_sync_work, | ||
587 | oinfo->dqi_syncjiff); | ||
588 | } | ||
589 | |||
590 | /* | ||
523 | * Wrappers for generic quota functions | 591 | * Wrappers for generic quota functions |
524 | */ | 592 | */ |
525 | 593 | ||
@@ -917,3 +985,20 @@ struct dquot_operations ocfs2_quota_operations = { | |||
917 | .alloc_dquot = ocfs2_alloc_dquot, | 985 | .alloc_dquot = ocfs2_alloc_dquot, |
918 | .destroy_dquot = ocfs2_destroy_dquot, | 986 | .destroy_dquot = ocfs2_destroy_dquot, |
919 | }; | 987 | }; |
988 | |||
989 | int ocfs2_quota_setup(void) | ||
990 | { | ||
991 | ocfs2_quota_wq = create_workqueue("o2quot"); | ||
992 | if (!ocfs2_quota_wq) | ||
993 | return -ENOMEM; | ||
994 | return 0; | ||
995 | } | ||
996 | |||
997 | void ocfs2_quota_shutdown(void) | ||
998 | { | ||
999 | if (ocfs2_quota_wq) { | ||
1000 | flush_workqueue(ocfs2_quota_wq); | ||
1001 | destroy_workqueue(ocfs2_quota_wq); | ||
1002 | ocfs2_quota_wq = NULL; | ||
1003 | } | ||
1004 | } | ||