1 From: Jan Kara <jack@suse.cz>
2 References: fate#302681
3 Subject: [PATCH 26/28] ocfs2: Enable quota accounting on mount, disable on umount
4 Patch-mainline: 2.6.29?
6 Enable quota usage tracking on mount and disable it on umount. Also
7 add support for quota on and quota off quotactls and usrquota and
8 grpquota mount options.
10 Signed-off-by: Jan Kara <jack@suse.cz>
12 fs/ocfs2/journal.c | 20 ++++
14 fs/ocfs2/super.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++
15 3 files changed, 234 insertions(+), 3 deletions(-)
17 Index: 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
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
32 static int ocfs2_commit_thread(void *arg);
34 +static inline int ocfs2_wait_on_mount(struct ocfs2_super *osb)
36 + return __ocfs2_wait_on_mount(osb, 0);
39 +static inline int ocfs2_wait_on_quotas(struct ocfs2_super *osb)
41 + return __ocfs2_wait_on_mount(osb, 1);
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
50 mlog(0, "Complete recovery for slot %d\n", item->lri_slot);
52 + ocfs2_wait_on_quotas(osb);
54 la_dinode = item->lri_la_dinode;
56 mlog(0, "Clean up local alloc %llu\n",
57 @@ -1659,13 +1672,14 @@ static int ocfs2_recover_orphans(struct
61 -static int ocfs2_wait_on_mount(struct ocfs2_super *osb)
62 +static int __ocfs2_wait_on_mount(struct ocfs2_super *osb, int quota)
64 /* This check is good because ocfs2 will wait on our recovery
65 * thread before changing it to something other than MOUNTED
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);
73 /* If there's an error on mount, then we may never get to the
74 Index: 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
82 + VOLUME_MOUNTED_QUOTAS,
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 */
94 #define OCFS2_OSB_SOFT_RO 0x0001
95 Index: 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
100 #include <linux/debugfs.h>
101 #include <linux/mount.h>
102 #include <linux/seq_file.h>
103 +#include <linux/quotaops.h>
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);
115 static const struct super_operations ocfs2_sops = {
116 .statfs = ocfs2_statfs,
117 @@ -165,6 +169,8 @@ enum {
126 @@ -189,6 +195,8 @@ static match_table_t tokens = {
127 {Opt_inode64, "inode64"},
129 {Opt_noacl, "noacl"},
130 + {Opt_usrquota, "usrquota"},
131 + {Opt_grpquota, "grpquota"},
135 @@ -452,6 +460,12 @@ static int ocfs2_remount(struct super_bl
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);
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
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);
157 + ret = ocfs2_enable_quotas(osb);
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);
170 @@ -647,6 +676,131 @@ static int ocfs2_verify_userspace_stack(
174 +static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
177 + struct super_block *sb = osb->sb;
178 + unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
179 + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
182 + for (type = 0; type < MAXQUOTAS; type++) {
183 + if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
186 + status = vfs_quota_enable(
187 + sb_dqopt(sb)->files[type],
191 + status = vfs_quota_disable(sb, type,
197 + mlog(ML_ERROR, "Failed to suspend/unsuspend quotas on "
198 + "remount (error = %d).\n", status);
202 +static int ocfs2_enable_quotas(struct ocfs2_super *osb)
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 };
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]))
217 + inode[type] = ocfs2_get_system_file_inode(osb, ino[type],
219 + if (!inode[type]) {
221 + goto out_quota_off;
223 + status = vfs_quota_enable(inode[type], type, QFMT_OCFS2,
224 + DQUOT_USAGE_ENABLED);
226 + goto out_quota_off;
229 + for (type = 0; type < MAXQUOTAS; type++)
233 + ocfs2_disable_quotas(osb);
234 + for (type = 0; type < MAXQUOTAS; type++)
236 + mlog_errno(status);
240 +static void ocfs2_disable_quotas(struct ocfs2_super *osb)
243 + struct inode *inode;
244 + struct super_block *sb = osb->sb;
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))
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
255 + vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED |
256 + DQUOT_LIMITS_ENABLED);
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)
267 + unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
268 + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
270 + if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
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);
280 +/* Handle quota off quotactl */
281 +static int ocfs2_quota_off(struct super_block *sb, int type, int remount)
284 + return 0; /* Ignore now and handle later in
285 + * ocfs2_remount() */
286 + return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
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,
299 static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
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)) {
310 + mlog(ML_ERROR, "User quotas were requested, but this "
311 + "filesystem does not have the feature enabled.\n");
312 + goto read_super_error;
314 + if (osb->s_mount_opt & OCFS2_MOUNT_GRPQUOTA &&
315 + !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
316 + OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
318 + mlog(ML_ERROR, "Group quotas were requested, but this "
319 + "filesystem does not have the feature enabled.\n");
320 + goto read_super_error;
323 status = ocfs2_verify_userspace_stack(osb, &parsed_options);
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);
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);
335 + mlog_errno(status);
336 + goto read_super_error;
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);
346 @@ -993,6 +1177,28 @@ static int ocfs2_parse_options(struct su
347 printk(KERN_INFO "ocfs2 (no)acl options not supported\n");
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");
360 + mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
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");
370 + mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
374 "Unrecognized mount option \"%s\" "
375 @@ -1071,6 +1277,10 @@ static int ocfs2_show_options(struct seq
377 seq_printf(s, ",noacl");
379 + if (opts & OCFS2_MOUNT_USRQUOTA)
380 + seq_printf(s, ",usrquota");
381 + if (opts & OCFS2_MOUNT_GRPQUOTA)
382 + seq_printf(s, ",grpquota");
386 @@ -1396,6 +1606,8 @@ static void ocfs2_dismount_volume(struct
390 + ocfs2_disable_quotas(osb);
392 ocfs2_shutdown_local_alloc(osb);
394 ocfs2_truncate_log_shutdown(osb);
395 @@ -1506,6 +1718,8 @@ static int ocfs2_initialize_super(struct
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;
403 sb->s_flags |= MS_NOATIME;