aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/super.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-08-21 14:13:17 -0400
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:40:24 -0500
commit19ece546a418997226bd91552fbc41abcb05cea6 (patch)
treef10ba25a07d020551833f53720bbba475788f957 /fs/ocfs2/super.c
parent2205363dce7447b8e85f1ead14387664c1a98753 (diff)
ocfs2: Enable quota accounting on mount, disable on umount
Enable quota usage tracking on mount and disable it on umount. Also add support for quota on and quota off quotactls and usrquota and grpquota mount options. Add quota features among supported ones. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/super.c')
-rw-r--r--fs/ocfs2/super.c222
1 files changed, 222 insertions, 0 deletions
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 60f1d29421ad..2eb657c3e7a8 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -41,6 +41,7 @@
41#include <linux/debugfs.h> 41#include <linux/debugfs.h>
42#include <linux/mount.h> 42#include <linux/mount.h>
43#include <linux/seq_file.h> 43#include <linux/seq_file.h>
44#include <linux/quotaops.h>
44 45
45#define MLOG_MASK_PREFIX ML_SUPER 46#define MLOG_MASK_PREFIX ML_SUPER
46#include <cluster/masklog.h> 47#include <cluster/masklog.h>
@@ -127,6 +128,9 @@ static int ocfs2_get_sector(struct super_block *sb,
127static void ocfs2_write_super(struct super_block *sb); 128static void ocfs2_write_super(struct super_block *sb);
128static struct inode *ocfs2_alloc_inode(struct super_block *sb); 129static struct inode *ocfs2_alloc_inode(struct super_block *sb);
129static void ocfs2_destroy_inode(struct inode *inode); 130static void ocfs2_destroy_inode(struct inode *inode);
131static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend);
132static int ocfs2_enable_quotas(struct ocfs2_super *osb);
133static void ocfs2_disable_quotas(struct ocfs2_super *osb);
130 134
131static const struct super_operations ocfs2_sops = { 135static const struct super_operations ocfs2_sops = {
132 .statfs = ocfs2_statfs, 136 .statfs = ocfs2_statfs,
@@ -165,6 +169,8 @@ enum {
165 Opt_inode64, 169 Opt_inode64,
166 Opt_acl, 170 Opt_acl,
167 Opt_noacl, 171 Opt_noacl,
172 Opt_usrquota,
173 Opt_grpquota,
168 Opt_err, 174 Opt_err,
169}; 175};
170 176
@@ -189,6 +195,8 @@ static const match_table_t tokens = {
189 {Opt_inode64, "inode64"}, 195 {Opt_inode64, "inode64"},
190 {Opt_acl, "acl"}, 196 {Opt_acl, "acl"},
191 {Opt_noacl, "noacl"}, 197 {Opt_noacl, "noacl"},
198 {Opt_usrquota, "usrquota"},
199 {Opt_grpquota, "grpquota"},
192 {Opt_err, NULL} 200 {Opt_err, NULL}
193}; 201};
194 202
@@ -452,6 +460,12 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
452 460
453 /* We're going to/from readonly mode. */ 461 /* We're going to/from readonly mode. */
454 if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { 462 if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
463 /* Disable quota accounting before remounting RO */
464 if (*flags & MS_RDONLY) {
465 ret = ocfs2_susp_quotas(osb, 0);
466 if (ret < 0)
467 goto out;
468 }
455 /* Lock here so the check of HARD_RO and the potential 469 /* Lock here so the check of HARD_RO and the potential
456 * setting of SOFT_RO is atomic. */ 470 * setting of SOFT_RO is atomic. */
457 spin_lock(&osb->osb_lock); 471 spin_lock(&osb->osb_lock);
@@ -487,6 +501,21 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
487 } 501 }
488unlock_osb: 502unlock_osb:
489 spin_unlock(&osb->osb_lock); 503 spin_unlock(&osb->osb_lock);
504 /* Enable quota accounting after remounting RW */
505 if (!ret && !(*flags & MS_RDONLY)) {
506 if (sb_any_quota_suspended(sb))
507 ret = ocfs2_susp_quotas(osb, 1);
508 else
509 ret = ocfs2_enable_quotas(osb);
510 if (ret < 0) {
511 /* Return back changes... */
512 spin_lock(&osb->osb_lock);
513 sb->s_flags |= MS_RDONLY;
514 osb->osb_flags |= OCFS2_OSB_SOFT_RO;
515 spin_unlock(&osb->osb_lock);
516 goto out;
517 }
518 }
490 } 519 }
491 520
492 if (!ret) { 521 if (!ret) {
@@ -647,6 +676,131 @@ static int ocfs2_verify_userspace_stack(struct ocfs2_super *osb,
647 return 0; 676 return 0;
648} 677}
649 678
679static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend)
680{
681 int type;
682 struct super_block *sb = osb->sb;
683 unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
684 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
685 int status = 0;
686
687 for (type = 0; type < MAXQUOTAS; type++) {
688 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
689 continue;
690 if (unsuspend)
691 status = vfs_quota_enable(
692 sb_dqopt(sb)->files[type],
693 type, QFMT_OCFS2,
694 DQUOT_SUSPENDED);
695 else
696 status = vfs_quota_disable(sb, type,
697 DQUOT_SUSPENDED);
698 if (status < 0)
699 break;
700 }
701 if (status < 0)
702 mlog(ML_ERROR, "Failed to suspend/unsuspend quotas on "
703 "remount (error = %d).\n", status);
704 return status;
705}
706
707static int ocfs2_enable_quotas(struct ocfs2_super *osb)
708{
709 struct inode *inode[MAXQUOTAS] = { NULL, NULL };
710 struct super_block *sb = osb->sb;
711 unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
712 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
713 unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE,
714 LOCAL_GROUP_QUOTA_SYSTEM_INODE };
715 int status;
716 int type;
717
718 sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NEGATIVE_USAGE;
719 for (type = 0; type < MAXQUOTAS; type++) {
720 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
721 continue;
722 inode[type] = ocfs2_get_system_file_inode(osb, ino[type],
723 osb->slot_num);
724 if (!inode[type]) {
725 status = -ENOENT;
726 goto out_quota_off;
727 }
728 status = vfs_quota_enable(inode[type], type, QFMT_OCFS2,
729 DQUOT_USAGE_ENABLED);
730 if (status < 0)
731 goto out_quota_off;
732 }
733
734 for (type = 0; type < MAXQUOTAS; type++)
735 iput(inode[type]);
736 return 0;
737out_quota_off:
738 ocfs2_disable_quotas(osb);
739 for (type = 0; type < MAXQUOTAS; type++)
740 iput(inode[type]);
741 mlog_errno(status);
742 return status;
743}
744
745static void ocfs2_disable_quotas(struct ocfs2_super *osb)
746{
747 int type;
748 struct inode *inode;
749 struct super_block *sb = osb->sb;
750
751 /* We mostly ignore errors in this function because there's not much
752 * we can do when we see them */
753 for (type = 0; type < MAXQUOTAS; type++) {
754 if (!sb_has_quota_loaded(sb, type))
755 continue;
756 inode = igrab(sb->s_dquot.files[type]);
757 /* Turn off quotas. This will remove all dquot structures from
758 * memory and so they will be automatically synced to global
759 * quota files */
760 vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED |
761 DQUOT_LIMITS_ENABLED);
762 if (!inode)
763 continue;
764 iput(inode);
765 }
766}
767
768/* Handle quota on quotactl */
769static int ocfs2_quota_on(struct super_block *sb, int type, int format_id,
770 char *path, int remount)
771{
772 unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA,
773 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA};
774
775 if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type]))
776 return -EINVAL;
777
778 if (remount)
779 return 0; /* Just ignore it has been handled in
780 * ocfs2_remount() */
781 return vfs_quota_enable(sb_dqopt(sb)->files[type], type,
782 format_id, DQUOT_LIMITS_ENABLED);
783}
784
785/* Handle quota off quotactl */
786static int ocfs2_quota_off(struct super_block *sb, int type, int remount)
787{
788 if (remount)
789 return 0; /* Ignore now and handle later in
790 * ocfs2_remount() */
791 return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
792}
793
794static struct quotactl_ops ocfs2_quotactl_ops = {
795 .quota_on = ocfs2_quota_on,
796 .quota_off = ocfs2_quota_off,
797 .quota_sync = vfs_quota_sync,
798 .get_info = vfs_get_dqinfo,
799 .set_info = vfs_set_dqinfo,
800 .get_dqblk = vfs_get_dqblk,
801 .set_dqblk = vfs_set_dqblk,
802};
803
650static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) 804static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
651{ 805{
652 struct dentry *root; 806 struct dentry *root;
@@ -689,6 +843,22 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
689 osb->osb_commit_interval = parsed_options.commit_interval; 843 osb->osb_commit_interval = parsed_options.commit_interval;
690 osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); 844 osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt);
691 osb->local_alloc_bits = osb->local_alloc_default_bits; 845 osb->local_alloc_bits = osb->local_alloc_default_bits;
846 if (osb->s_mount_opt & OCFS2_MOUNT_USRQUOTA &&
847 !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
848 OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
849 status = -EINVAL;
850 mlog(ML_ERROR, "User quotas were requested, but this "
851 "filesystem does not have the feature enabled.\n");
852 goto read_super_error;
853 }
854 if (osb->s_mount_opt & OCFS2_MOUNT_GRPQUOTA &&
855 !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
856 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
857 status = -EINVAL;
858 mlog(ML_ERROR, "Group quotas were requested, but this "
859 "filesystem does not have the feature enabled.\n");
860 goto read_super_error;
861 }
692 862
693 status = ocfs2_verify_userspace_stack(osb, &parsed_options); 863 status = ocfs2_verify_userspace_stack(osb, &parsed_options);
694 if (status) 864 if (status)
@@ -793,6 +963,28 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
793 atomic_set(&osb->vol_state, VOLUME_MOUNTED); 963 atomic_set(&osb->vol_state, VOLUME_MOUNTED);
794 wake_up(&osb->osb_mount_event); 964 wake_up(&osb->osb_mount_event);
795 965
966 /* Now we can initialize quotas because we can afford to wait
967 * for cluster locks recovery now. That also means that truncation
968 * log recovery can happen but that waits for proper quota setup */
969 if (!(sb->s_flags & MS_RDONLY)) {
970 status = ocfs2_enable_quotas(osb);
971 if (status < 0) {
972 /* We have to err-out specially here because
973 * s_root is already set */
974 mlog_errno(status);
975 atomic_set(&osb->vol_state, VOLUME_DISABLED);
976 wake_up(&osb->osb_mount_event);
977 mlog_exit(status);
978 return status;
979 }
980 }
981
982 ocfs2_complete_quota_recovery(osb);
983
984 /* Now we wake up again for processes waiting for quotas */
985 atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS);
986 wake_up(&osb->osb_mount_event);
987
796 mlog_exit(status); 988 mlog_exit(status);
797 return status; 989 return status;
798 990
@@ -980,6 +1172,28 @@ static int ocfs2_parse_options(struct super_block *sb,
980 case Opt_inode64: 1172 case Opt_inode64:
981 mopt->mount_opt |= OCFS2_MOUNT_INODE64; 1173 mopt->mount_opt |= OCFS2_MOUNT_INODE64;
982 break; 1174 break;
1175 case Opt_usrquota:
1176 /* We check only on remount, otherwise features
1177 * aren't yet initialized. */
1178 if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
1179 OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
1180 mlog(ML_ERROR, "User quota requested but "
1181 "filesystem feature is not set\n");
1182 status = 0;
1183 goto bail;
1184 }
1185 mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA;
1186 break;
1187 case Opt_grpquota:
1188 if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb,
1189 OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
1190 mlog(ML_ERROR, "Group quota requested but "
1191 "filesystem feature is not set\n");
1192 status = 0;
1193 goto bail;
1194 }
1195 mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
1196 break;
983#ifdef CONFIG_OCFS2_FS_POSIX_ACL 1197#ifdef CONFIG_OCFS2_FS_POSIX_ACL
984 case Opt_acl: 1198 case Opt_acl:
985 mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL; 1199 mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
@@ -1056,6 +1270,10 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
1056 if (osb->osb_cluster_stack[0]) 1270 if (osb->osb_cluster_stack[0])
1057 seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, 1271 seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN,
1058 osb->osb_cluster_stack); 1272 osb->osb_cluster_stack);
1273 if (opts & OCFS2_MOUNT_USRQUOTA)
1274 seq_printf(s, ",usrquota");
1275 if (opts & OCFS2_MOUNT_GRPQUOTA)
1276 seq_printf(s, ",grpquota");
1059 1277
1060 if (opts & OCFS2_MOUNT_NOUSERXATTR) 1278 if (opts & OCFS2_MOUNT_NOUSERXATTR)
1061 seq_printf(s, ",nouser_xattr"); 1279 seq_printf(s, ",nouser_xattr");
@@ -1394,6 +1612,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
1394 osb = OCFS2_SB(sb); 1612 osb = OCFS2_SB(sb);
1395 BUG_ON(!osb); 1613 BUG_ON(!osb);
1396 1614
1615 ocfs2_disable_quotas(osb);
1616
1397 ocfs2_shutdown_local_alloc(osb); 1617 ocfs2_shutdown_local_alloc(osb);
1398 1618
1399 ocfs2_truncate_log_shutdown(osb); 1619 ocfs2_truncate_log_shutdown(osb);
@@ -1504,6 +1724,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
1504 sb->s_fs_info = osb; 1724 sb->s_fs_info = osb;
1505 sb->s_op = &ocfs2_sops; 1725 sb->s_op = &ocfs2_sops;
1506 sb->s_export_op = &ocfs2_export_ops; 1726 sb->s_export_op = &ocfs2_export_ops;
1727 sb->s_qcop = &ocfs2_quotactl_ops;
1728 sb->dq_op = &ocfs2_quota_operations;
1507 sb->s_xattr = ocfs2_xattr_handlers; 1729 sb->s_xattr = ocfs2_xattr_handlers;
1508 sb->s_time_gran = 1; 1730 sb->s_time_gran = 1;
1509 sb->s_flags |= MS_NOATIME; 1731 sb->s_flags |= MS_NOATIME;