]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Jan Kara <jack@suse.cz> |
2 | References: fate#302681 | |
3 | Subject: [PATCH 27/28] ocfs2: Implement quota syncing thread | |
4 | Patch-mainline: 2.6.29? | |
5 | ||
6 | This patch implements functions and timer setup which handles periodic | |
7 | syncing of locally cached quota information to global quota file. | |
8 | ||
9 | Signed-off-by: Jan Kara <jack@suse.cz> | |
10 | --- | |
11 | fs/ocfs2/quota.h | 3 ++ | |
12 | fs/ocfs2/quota_global.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++ | |
13 | fs/ocfs2/quota_local.c | 4 ++ | |
14 | mm/pdflush.c | 1 | |
15 | 4 files changed, 79 insertions(+) | |
16 | ||
17 | --- a/fs/ocfs2/quota.h | |
18 | +++ b/fs/ocfs2/quota.h | |
19 | @@ -14,6 +14,7 @@ | |
20 | #include <linux/quota.h> | |
21 | #include <linux/list.h> | |
22 | #include <linux/dqblk_qtree.h> | |
23 | +#include <linux/timer.h> | |
24 | ||
25 | #include "ocfs2.h" | |
26 | ||
27 | @@ -43,6 +44,7 @@ struct ocfs2_mem_dqinfo { | |
28 | unsigned int dqi_chunks; /* Number of chunks in local quota file */ | |
29 | unsigned int dqi_blocks; /* Number of blocks allocated for local quota file */ | |
30 | unsigned int dqi_syncms; /* How often should we sync with other nodes */ | |
31 | + unsigned int dqi_syncjiff; /* Precomputed dqi_syncms in jiffies */ | |
32 | struct list_head dqi_chunk; /* List of chunks */ | |
33 | struct inode *dqi_gqinode; /* Global quota file inode */ | |
34 | struct ocfs2_lock_res dqi_gqlock; /* Lock protecting quota information structure */ | |
35 | @@ -51,6 +53,7 @@ struct ocfs2_mem_dqinfo { | |
36 | struct buffer_head *dqi_lqi_bh; /* Buffer head with local quota file inode */ | |
37 | struct buffer_head *dqi_ibh; /* Buffer with information header */ | |
38 | struct qtree_mem_dqinfo dqi_gi; /* Info about global file */ | |
39 | + struct timer_list dqi_sync_timer; /* Timer for syncing dquots */ | |
40 | }; | |
41 | ||
42 | static inline struct ocfs2_dquot *OCFS2_DQUOT(struct dquot *dquot) | |
43 | --- a/fs/ocfs2/quota_global.c | |
44 | +++ b/fs/ocfs2/quota_global.c | |
45 | @@ -1,10 +1,14 @@ | |
46 | /* | |
47 | * Implementation of operations over global quota file | |
48 | */ | |
49 | +#include <linux/spinlock.h> | |
50 | #include <linux/fs.h> | |
51 | #include <linux/quota.h> | |
52 | #include <linux/quotaops.h> | |
53 | #include <linux/dqblk_qtree.h> | |
54 | +#include <linux/jiffies.h> | |
55 | +#include <linux/timer.h> | |
56 | +#include <linux/writeback.h> | |
57 | ||
58 | #define MLOG_MASK_PREFIX ML_QUOTA | |
59 | #include <cluster/masklog.h> | |
60 | @@ -19,6 +23,8 @@ | |
61 | #include "dlmglue.h" | |
62 | #include "quota.h" | |
63 | ||
64 | +static void qsync_timer_fn(unsigned long oinfo_ptr); | |
65 | + | |
66 | static void ocfs2_global_disk2memdqb(struct dquot *dquot, void *dp) | |
67 | { | |
68 | struct ocfs2_global_disk_dqblk *d = dp; | |
69 | @@ -269,6 +275,7 @@ int ocfs2_global_read_info(struct super_ | |
70 | info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); | |
71 | info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); | |
72 | oinfo->dqi_syncms = le32_to_cpu(dinfo.dqi_syncms); | |
73 | + oinfo->dqi_syncjiff = msecs_to_jiffies(oinfo->dqi_syncms); | |
74 | oinfo->dqi_gi.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); | |
75 | oinfo->dqi_gi.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); | |
76 | oinfo->dqi_gi.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); | |
77 | @@ -276,6 +283,10 @@ int ocfs2_global_read_info(struct super_ | |
78 | oinfo->dqi_gi.dqi_usable_bs = sb->s_blocksize - | |
79 | OCFS2_QBLK_RESERVED_SPACE; | |
80 | oinfo->dqi_gi.dqi_qtree_depth = qtree_depth(&oinfo->dqi_gi); | |
81 | + setup_timer(&oinfo->dqi_sync_timer, qsync_timer_fn, | |
82 | + (unsigned long)oinfo); | |
83 | + mod_timer(&oinfo->dqi_sync_timer, | |
84 | + round_jiffies(jiffies + oinfo->dqi_syncjiff)); | |
85 | out_err: | |
86 | mlog_exit(status); | |
87 | return status; | |
88 | @@ -463,6 +474,66 @@ out: | |
89 | } | |
90 | ||
91 | /* | |
92 | + * Functions for periodic syncing of dquots with global file | |
93 | + */ | |
94 | +static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type) | |
95 | +{ | |
96 | + handle_t *handle; | |
97 | + struct super_block *sb = dquot->dq_sb; | |
98 | + struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv; | |
99 | + struct ocfs2_super *osb = OCFS2_SB(sb); | |
100 | + int status = 0; | |
101 | + | |
102 | + mlog_entry("id=%u qtype=%u type=%lu device=%s\n", dquot->dq_id, | |
103 | + dquot->dq_type, type, sb->s_id); | |
104 | + if (type != dquot->dq_type) | |
105 | + goto out; | |
106 | + status = ocfs2_lock_global_qf(oinfo, 1); | |
107 | + if (status < 0) | |
108 | + goto out; | |
109 | + | |
110 | + handle = ocfs2_start_trans(osb, OCFS2_QSYNC_CREDITS); | |
111 | + if (IS_ERR(handle)) { | |
112 | + status = PTR_ERR(handle); | |
113 | + mlog_errno(status); | |
114 | + goto out_ilock; | |
115 | + } | |
116 | + mutex_lock(&sb_dqopt(sb)->dqio_mutex); | |
117 | + status = ocfs2_sync_dquot(dquot); | |
118 | + mutex_unlock(&sb_dqopt(sb)->dqio_mutex); | |
119 | + if (status < 0) | |
120 | + mlog_errno(status); | |
121 | + /* We have to write local structure as well... */ | |
122 | + dquot_mark_dquot_dirty(dquot); | |
123 | + status = dquot_commit(dquot); | |
124 | + if (status < 0) | |
125 | + mlog_errno(status); | |
126 | + ocfs2_commit_trans(osb, handle); | |
127 | +out_ilock: | |
128 | + ocfs2_unlock_global_qf(oinfo, 1); | |
129 | +out: | |
130 | + mlog_exit(status); | |
131 | + return status; | |
132 | +} | |
133 | + | |
134 | +static void ocfs2_do_qsync(unsigned long oinfo_ptr) | |
135 | +{ | |
136 | + struct ocfs2_mem_dqinfo *oinfo = (struct ocfs2_mem_dqinfo *)oinfo_ptr; | |
137 | + struct super_block *sb = oinfo->dqi_gqinode->i_sb; | |
138 | + | |
139 | + dquot_scan_active(sb, ocfs2_sync_dquot_helper, oinfo->dqi_type); | |
140 | +} | |
141 | + | |
142 | +static void qsync_timer_fn(unsigned long oinfo_ptr) | |
143 | +{ | |
144 | + struct ocfs2_mem_dqinfo *oinfo = (struct ocfs2_mem_dqinfo *)oinfo_ptr; | |
145 | + | |
146 | + pdflush_operation(ocfs2_do_qsync, oinfo_ptr); | |
147 | + mod_timer(&oinfo->dqi_sync_timer, | |
148 | + round_jiffies(jiffies + oinfo->dqi_syncjiff)); | |
149 | +} | |
150 | + | |
151 | +/* | |
152 | * Wrappers for generic quota functions | |
153 | */ | |
154 | ||
155 | --- a/fs/ocfs2/quota_local.c | |
156 | +++ b/fs/ocfs2/quota_local.c | |
157 | @@ -368,6 +368,10 @@ static int ocfs2_local_free_info(struct | |
158 | int mark_clean = 1, len; | |
159 | int status; | |
160 | ||
161 | + /* At this point we know there are no more dquots and thus | |
162 | + * even if there's some sync in the pdflush queue, it won't | |
163 | + * find any dquots and return without doing anything */ | |
164 | + del_timer_sync(&oinfo->dqi_sync_timer); | |
165 | iput(oinfo->dqi_gqinode); | |
166 | ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock); | |
167 | ocfs2_lock_res_free(&oinfo->dqi_gqlock); | |
168 | --- a/mm/pdflush.c | |
169 | +++ b/mm/pdflush.c | |
170 | @@ -225,6 +225,7 @@ int pdflush_operation(void (*fn)(unsigne | |
171 | ||
172 | return ret; | |
173 | } | |
174 | +EXPORT_SYMBOL(pdflush_operation); | |
175 | ||
176 | static void start_one_pdflush_thread(void) | |
177 | { |