]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.suse/ocfs2-Enable-quota-accounting-on-mount-disable-on.patch
Imported linux-2.6.27.39 suse/xen patches.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.suse / ocfs2-Enable-quota-accounting-on-mount-disable-on.patch
CommitLineData
2cb7cef9
BS
1From: Jan Kara <jack@suse.cz>
2References: fate#302681
3Subject: [PATCH 26/28] ocfs2: Enable quota accounting on mount, disable on umount
4Patch-mainline: 2.6.29?
5
6Enable quota usage tracking on mount and disable it on umount. Also
7add support for quota on and quota off quotactls and usrquota and
8grpquota mount options.
9
10Signed-off-by: Jan Kara <jack@suse.cz>
11---
12 fs/ocfs2/journal.c | 20 ++++
13 fs/ocfs2/ocfs2.h | 3
14 fs/ocfs2/super.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++
15 3 files changed, 234 insertions(+), 3 deletions(-)
16
17Index: linux-2.6.27-ocfs2/fs/ocfs2/journal.c
18===================================================================
19--- linux-2.6.27-ocfs2.orig/fs/ocfs2/journal.c
20+++ linux-2.6.27-ocfs2/fs/ocfs2/journal.c
21@@ -55,7 +55,7 @@ static int ocfs2_recover_node(struct ocf
22 int node_num);
23 static int __ocfs2_recovery_thread(void *arg);
24 static int ocfs2_commit_cache(struct ocfs2_super *osb);
25-static int ocfs2_wait_on_mount(struct ocfs2_super *osb);
26+static int __ocfs2_wait_on_mount(struct ocfs2_super *osb, int quota);
27 static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
28 int dirty, int replayed);
29 static int ocfs2_trylock_journal(struct ocfs2_super *osb,
30@@ -64,6 +64,17 @@ static int ocfs2_recover_orphans(struct
31 int slot);
32 static int ocfs2_commit_thread(void *arg);
33
34+static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb)
35+{
36+ return __ocfs2_wait_on_mount(osb, 0);
37+}
38+
39+static inline int ocfs2_wait_on_quotas(struct ocfs2_super *osb)
40+{
41+ return __ocfs2_wait_on_mount(osb, 1);
42+}
43+
44+
45
46 /*
47 * The recovery_list is a simple linked list of node numbers to recover.
48@@ -913,6 +924,8 @@ void ocfs2_complete_recovery(struct work
49
50 mlog(0, "Complete recovery for slot %d\n", item->lri_slot);
51
52+ ocfs2_wait_on_quotas(osb);
53+
54 la_dinode = item->lri_la_dinode;
55 if (la_dinode) {
56 mlog(0, "Clean up local alloc %llu\n",
57@@ -1659,13 +1672,14 @@ static int ocfs2_recover_orphans(struct
58 return ret;
59 }
60
61-static int ocfs2_wait_on_mount(struct ocfs2_super *osb)
62+static int __ocfs2_wait_on_mount(struct ocfs2_super *osb, int quota)
63 {
64 /* This check is good because ocfs2 will wait on our recovery
65 * thread before changing it to something other than MOUNTED
66 * or DISABLED. */
67 wait_event(osb->osb_mount_event,
68- atomic_read(&osb->vol_state) == VOLUME_MOUNTED ||
69+ (!quota && atomic_read(&osb->vol_state) == VOLUME_MOUNTED) ||
70+ atomic_read(&osb->vol_state) == VOLUME_MOUNTED_QUOTAS ||
71 atomic_read(&osb->vol_state) == VOLUME_DISABLED);
72
73 /* If there's an error on mount, then we may never get to the
74Index: linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h
75===================================================================
76--- linux-2.6.27-ocfs2.orig/fs/ocfs2/ocfs2.h
77+++ linux-2.6.27-ocfs2/fs/ocfs2/ocfs2.h
78@@ -161,6 +161,7 @@ enum ocfs2_vol_state
79 {
80 VOLUME_INIT = 0,
81 VOLUME_MOUNTED,
82+ VOLUME_MOUNTED_QUOTAS,
83 VOLUME_DISMOUNTED,
84 VOLUME_DISABLED
85 };
86@@ -196,6 +197,8 @@ enum ocfs2_mount_options
87 OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */
88 OCFS2_MOUNT_INODE64 = 1 << 7, /* Allow inode numbers > 2^32 */
89 OCFS2_MOUNT_POSIX_ACL = 1 << 8, /* POSIX access control lists */
90+ OCFS2_MOUNT_USRQUOTA = 1 << 9, /* We support user quotas */
91+ OCFS2_MOUNT_GRPQUOTA = 1 << 10, /* We support group quotas */
92 };
93
94 #define OCFS2_OSB_SOFT_RO 0x0001
95Index: linux-2.6.27-ocfs2/fs/ocfs2/super.c
96===================================================================
97--- linux-2.6.27-ocfs2.orig/fs/ocfs2/super.c
98+++ linux-2.6.27-ocfs2/fs/ocfs2/super.c
99@@ -41,6 +41,7 @@
100 #include <linux/debugfs.h>
101 #include <linux/mount.h>
102 #include <linux/seq_file.h>
103+#include <linux/quotaops.h>
104
105 #define MLOG_MASK_PREFIX ML_SUPER
106 #include <cluster/masklog.h>
107@@ -127,6 +128,9 @@ static int ocfs2_get_sector(struct super
108 static void ocfs2_write_super(struct super_block *sb);
109 static struct inode *ocfs2_alloc_inode(struct super_block *sb);
110 static void ocfs2_destroy_inode(struct inode *inode);
111+static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend);
112+static int ocfs2_enable_quotas(struct ocfs2_super *osb);
113+static void ocfs2_disable_quotas(struct ocfs2_super *osb);
114
115 static const struct super_operations ocfs2_sops = {
116 .statfs = ocfs2_statfs,
117@@ -165,6 +169,8 @@ enum {
118 Opt_inode64,
119 Opt_acl,
120 Opt_noacl,
121+ Opt_usrquota,
122+ Opt_grpquota,
123 Opt_err,
124 };
125
126@@ -189,6 +195,8 @@ static match_table_t tokens = {
127 {Opt_inode64, "inode64"},
128 {Opt_acl, "acl"},
129 {Opt_noacl, "noacl"},
130+ {Opt_usrquota, "usrquota"},
131+ {Opt_grpquota, "grpquota"},
132 {Opt_err, NULL}
133 };
134
135@@ -452,6 +460,12 @@ static int ocfs2_remount(struct super_bl
136
137 /* We're going to/from readonly mode. */
138 if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
139+ /* Disable quota accounting before remounting RO */
140+ if (*flags & MS_RDONLY) {
141+ ret = ocfs2_susp_quotas(osb, 0);
142+ if (ret < 0)
143+ goto out;
144+ }
145 /* Lock here so the check of HARD_RO and the potential
146 * setting of SOFT_RO is atomic. */
147 spin_lock(&osb->osb_lock);
148@@ -487,6 +501,21 @@ static int ocfs2_remount(struct super_bl
149 }
150 unlock_osb:
151 spin_unlock(&osb->osb_lock);
152+ /* Enable quota accounting after remounting RW */
153+ if (!ret && !(*flags & MS_RDONLY)) {
154+ if (sb_any_quota_suspended(sb))
155+ ret = ocfs2_susp_quotas(osb, 1);
156+ else
157+ ret = ocfs2_enable_quotas(osb);
158+ if (ret < 0) {
159+ /* Return back changes... */
160+ spin_lock(&osb->osb_lock);
161+ sb->s_flags |= MS_RDONLY;
162+ osb->osb_flags |= OCFS2_OSB_SOFT_RO;
163+ spin_unlock(&osb->osb_lock);
164+ goto out;
165+ }
166+ }
167 }
168
169 if (!ret) {
170@@ -647,6 +676,131 @@ static int ocfs2_verify_userspace_stack(
171 return 0;
172 }
173
174+static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
175+{
176+ int type;
177+ struct super_block *sb = osb->sb;
178+ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
179+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
180+ int status = 0;
181+
182+ for (type = 0; type < MAXQUOTAS; type++) {
183+ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
184+ continue;
185+ if (unsuspend)
186+ status = vfs_quota_enable(
187+ sb_dqopt(sb)->files[type],
188+ type, QFMT_OCFS2,
189+ DQUOT_SUSPENDED);
190+ else
191+ status = vfs_quota_disable(sb, type,
192+ DQUOT_SUSPENDED);
193+ if (status < 0)
194+ break;
195+ }
196+ if (status < 0)
197+ mlog(ML_ERROR, "Failed to suspend/unsuspend quotas on "
198+ "remount (error = %d).\n", status);
199+ return status;
200+}
201+
202+static int ocfs2_enable_quotas(struct ocfs2_super *osb)
203+{
204+ struct inode *inode[MAXQUOTAS] = { NULL, NULL };
205+ struct super_block *sb = osb->sb;
206+ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
207+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
208+ unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
209+ LOCAL_GROUP_QUOTA_SYSTEM_INODE };
210+ int status;
211+ int type;
212+
213+ sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NEGATIVE_USAGE;
214+ for (type = 0; type < MAXQUOTAS; type++) {
215+ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
216+ continue;
217+ inode[type] = ocfs2_get_system_file_inode(osb, ino[type],
218+ osb->slot_num);
219+ if (!inode[type]) {
220+ status = -ENOENT;
221+ goto out_quota_off;
222+ }
223+ status = vfs_quota_enable(inode[type], type, QFMT_OCFS2,
224+ DQUOT_USAGE_ENABLED);
225+ if (status < 0)
226+ goto out_quota_off;
227+ }
228+
229+ for (type = 0; type < MAXQUOTAS; type++)
230+ iput(inode[type]);
231+ return 0;
232+out_quota_off:
233+ ocfs2_disable_quotas(osb);
234+ for (type = 0; type < MAXQUOTAS; type++)
235+ iput(inode[type]);
236+ mlog_errno(status);
237+ return status;
238+}
239+
240+static void ocfs2_disable_quotas(struct ocfs2_super *osb)
241+{
242+ int type;
243+ struct inode *inode;
244+ struct super_block *sb = osb->sb;
245+
246+ /* We mostly ignore errors in this function because there's not much
247+ * we can do when we see them */
248+ for (type = 0; type < MAXQUOTAS; type++) {
249+ if (!sb_has_quota_loaded(sb, type))
250+ continue;
251+ inode = igrab(sb->s_dquot.files[type]);
252+ /* Turn off quotas. This will remove all dquot structures from
253+ * memory and so they will be automatically synced to global
254+ * quota files */
255+ vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED |
256+ DQUOT_LIMITS_ENABLED);
257+ if (!inode)
258+ continue;
259+ iput(inode);
260+ }
261+}
262+
263+/* Handle quota on quotactl */
264+static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
265+ char *path, int remount)
266+{
267+ unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
268+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
269+
270+ if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
271+ return -EINVAL;
272+
273+ if (remount)
274+ return 0; /* Just ignore it has been handled in
275+ * ocfs2_remount() */
276+ return vfs_quota_enable(sb_dqopt(sb)->files[type], type,
277+ format_id, DQUOT_LIMITS_ENABLED);
278+}
279+
280+/* Handle quota off quotactl */
281+static int ocfs2_quota_off(struct super_block *sb, int type, int remount)
282+{
283+ if (remount)
284+ return 0; /* Ignore now and handle later in
285+ * ocfs2_remount() */
286+ return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
287+}
288+
289+static struct quotactl_ops ocfs2_quotactl_ops = {
290+ .quota_on = ocfs2_quota_on,
291+ .quota_off = ocfs2_quota_off,
292+ .quota_sync = vfs_quota_sync,
293+ .get_info = vfs_get_dqinfo,
294+ .set_info = vfs_set_dqinfo,
295+ .get_dqblk = vfs_get_dqblk,
296+ .set_dqblk = vfs_set_dqblk,
297+};
298+
299 static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
300 {
301 struct dentry *root;
302@@ -689,6 +843,22 @@ static int ocfs2_fill_super(struct super
303 osb->osb_commit_interval = parsed_options.commit_interval;
304 osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt);
305 osb->local_alloc_bits = osb->local_alloc_default_bits;
306+ if (osb->s_mount_opt & OCFS2_MOUNT_USRQUOTA &&
307+ !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
308+ OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
309+ status = -EINVAL;
310+ mlog(ML_ERROR, "User quotas were requested, but this "
311+ "filesystem does not have the feature enabled.\n");
312+ goto read_super_error;
313+ }
314+ if (osb->s_mount_opt & OCFS2_MOUNT_GRPQUOTA &&
315+ !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
316+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
317+ status = -EINVAL;
318+ mlog(ML_ERROR, "Group quotas were requested, but this "
319+ "filesystem does not have the feature enabled.\n");
320+ goto read_super_error;
321+ }
322
323 status = ocfs2_verify_userspace_stack(osb, &parsed_options);
324 if (status)
325@@ -793,6 +963,20 @@ static int ocfs2_fill_super(struct super
326 atomic_set(&osb->vol_state, VOLUME_MOUNTED);
327 wake_up(&osb->osb_mount_event);
328
329+ /* Now we can initialize quotas because we can afford to wait
330+ * for cluster locks recovery now. That also means that truncation
331+ * log recovery can happen but that waits for proper quota setup */
332+ if (!(sb->s_flags & MS_RDONLY)) {
333+ status = ocfs2_enable_quotas(osb);
334+ if (status < 0) {
335+ mlog_errno(status);
336+ goto read_super_error;
337+ }
338+ }
339+ /* Now we wake up again for processes waiting for quotas */
340+ atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS);
341+ wake_up(&osb->osb_mount_event);
342+
343 mlog_exit(status);
344 return status;
345
346@@ -993,6 +1177,28 @@ static int ocfs2_parse_options(struct su
347 printk(KERN_INFO "ocfs2 (no)acl options not supported\n");
348 break;
349 #endif
350+ case Opt_usrquota:
351+ /* We check only on remount, otherwise features
352+ * aren't yet initialized. */
353+ if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
354+ OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
355+ mlog(ML_ERROR, "User quota requested but "
356+ "filesystem feature is not set\n");
357+ status = 0;
358+ goto bail;
359+ }
360+ mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
361+ break;
362+ case Opt_grpquota:
363+ if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
364+ OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
365+ mlog(ML_ERROR, "Group quota requested but "
366+ "filesystem feature is not set\n");
367+ status = 0;
368+ goto bail;
369+ }
370+ mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
371+ break;
372 default:
373 mlog(ML_ERROR,
374 "Unrecognized mount option \"%s\" "
375@@ -1071,6 +1277,10 @@ static int ocfs2_show_options(struct seq
376 else
377 seq_printf(s, ",noacl");
378 #endif
379+ if (opts & OCFS2_MOUNT_USRQUOTA)
380+ seq_printf(s, ",usrquota");
381+ if (opts & OCFS2_MOUNT_GRPQUOTA)
382+ seq_printf(s, ",grpquota");
383
384 return 0;
385 }
386@@ -1396,6 +1606,8 @@ static void ocfs2_dismount_volume(struct
387 osb = OCFS2_SB(sb);
388 BUG_ON(!osb);
389
390+ ocfs2_disable_quotas(osb);
391+
392 ocfs2_shutdown_local_alloc(osb);
393
394 ocfs2_truncate_log_shutdown(osb);
395@@ -1506,6 +1718,8 @@ static int ocfs2_initialize_super(struct
396 sb->s_fs_info = osb;
397 sb->s_op = &ocfs2_sops;
398 sb->s_export_op = &ocfs2_export_ops;
399+ sb->s_qcop = &ocfs2_quotactl_ops;
400+ sb->dq_op = &ocfs2_quota_operations;
401 sb->s_xattr = ocfs2_xattr_handlers;
402 sb->s_time_gran = 1;
403 sb->s_flags |= MS_NOATIME;