diff options
Diffstat (limited to 'fs/ocfs2/super.c')
-rw-r--r-- | fs/ocfs2/super.c | 328 |
1 files changed, 326 insertions, 2 deletions
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 304b63ac78cf..43ed11345b59 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> |
@@ -51,6 +52,7 @@ | |||
51 | #include "ocfs1_fs_compat.h" | 52 | #include "ocfs1_fs_compat.h" |
52 | 53 | ||
53 | #include "alloc.h" | 54 | #include "alloc.h" |
55 | #include "blockcheck.h" | ||
54 | #include "dlmglue.h" | 56 | #include "dlmglue.h" |
55 | #include "export.h" | 57 | #include "export.h" |
56 | #include "extent_map.h" | 58 | #include "extent_map.h" |
@@ -65,10 +67,13 @@ | |||
65 | #include "uptodate.h" | 67 | #include "uptodate.h" |
66 | #include "ver.h" | 68 | #include "ver.h" |
67 | #include "xattr.h" | 69 | #include "xattr.h" |
70 | #include "quota.h" | ||
68 | 71 | ||
69 | #include "buffer_head_io.h" | 72 | #include "buffer_head_io.h" |
70 | 73 | ||
71 | static struct kmem_cache *ocfs2_inode_cachep = NULL; | 74 | static struct kmem_cache *ocfs2_inode_cachep = NULL; |
75 | struct kmem_cache *ocfs2_dquot_cachep; | ||
76 | struct kmem_cache *ocfs2_qf_chunk_cachep; | ||
72 | 77 | ||
73 | /* OCFS2 needs to schedule several differnt types of work which | 78 | /* OCFS2 needs to schedule several differnt types of work which |
74 | * require cluster locking, disk I/O, recovery waits, etc. Since these | 79 | * require cluster locking, disk I/O, recovery waits, etc. Since these |
@@ -124,6 +129,9 @@ static int ocfs2_get_sector(struct super_block *sb, | |||
124 | static void ocfs2_write_super(struct super_block *sb); | 129 | static void ocfs2_write_super(struct super_block *sb); |
125 | static struct inode *ocfs2_alloc_inode(struct super_block *sb); | 130 | static struct inode *ocfs2_alloc_inode(struct super_block *sb); |
126 | static void ocfs2_destroy_inode(struct inode *inode); | 131 | static void ocfs2_destroy_inode(struct inode *inode); |
132 | static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend); | ||
133 | static int ocfs2_enable_quotas(struct ocfs2_super *osb); | ||
134 | static void ocfs2_disable_quotas(struct ocfs2_super *osb); | ||
127 | 135 | ||
128 | static const struct super_operations ocfs2_sops = { | 136 | static const struct super_operations ocfs2_sops = { |
129 | .statfs = ocfs2_statfs, | 137 | .statfs = ocfs2_statfs, |
@@ -137,6 +145,8 @@ static const struct super_operations ocfs2_sops = { | |||
137 | .put_super = ocfs2_put_super, | 145 | .put_super = ocfs2_put_super, |
138 | .remount_fs = ocfs2_remount, | 146 | .remount_fs = ocfs2_remount, |
139 | .show_options = ocfs2_show_options, | 147 | .show_options = ocfs2_show_options, |
148 | .quota_read = ocfs2_quota_read, | ||
149 | .quota_write = ocfs2_quota_write, | ||
140 | }; | 150 | }; |
141 | 151 | ||
142 | enum { | 152 | enum { |
@@ -158,6 +168,10 @@ enum { | |||
158 | Opt_user_xattr, | 168 | Opt_user_xattr, |
159 | Opt_nouser_xattr, | 169 | Opt_nouser_xattr, |
160 | Opt_inode64, | 170 | Opt_inode64, |
171 | Opt_acl, | ||
172 | Opt_noacl, | ||
173 | Opt_usrquota, | ||
174 | Opt_grpquota, | ||
161 | Opt_err, | 175 | Opt_err, |
162 | }; | 176 | }; |
163 | 177 | ||
@@ -180,6 +194,10 @@ static const match_table_t tokens = { | |||
180 | {Opt_user_xattr, "user_xattr"}, | 194 | {Opt_user_xattr, "user_xattr"}, |
181 | {Opt_nouser_xattr, "nouser_xattr"}, | 195 | {Opt_nouser_xattr, "nouser_xattr"}, |
182 | {Opt_inode64, "inode64"}, | 196 | {Opt_inode64, "inode64"}, |
197 | {Opt_acl, "acl"}, | ||
198 | {Opt_noacl, "noacl"}, | ||
199 | {Opt_usrquota, "usrquota"}, | ||
200 | {Opt_grpquota, "grpquota"}, | ||
183 | {Opt_err, NULL} | 201 | {Opt_err, NULL} |
184 | }; | 202 | }; |
185 | 203 | ||
@@ -221,6 +239,19 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait) | |||
221 | return 0; | 239 | return 0; |
222 | } | 240 | } |
223 | 241 | ||
242 | static int ocfs2_need_system_inode(struct ocfs2_super *osb, int ino) | ||
243 | { | ||
244 | if (!OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA) | ||
245 | && (ino == USER_QUOTA_SYSTEM_INODE | ||
246 | || ino == LOCAL_USER_QUOTA_SYSTEM_INODE)) | ||
247 | return 0; | ||
248 | if (!OCFS2_HAS_RO_COMPAT_FEATURE(osb->sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA) | ||
249 | && (ino == GROUP_QUOTA_SYSTEM_INODE | ||
250 | || ino == LOCAL_GROUP_QUOTA_SYSTEM_INODE)) | ||
251 | return 0; | ||
252 | return 1; | ||
253 | } | ||
254 | |||
224 | static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) | 255 | static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) |
225 | { | 256 | { |
226 | struct inode *new = NULL; | 257 | struct inode *new = NULL; |
@@ -247,6 +278,8 @@ static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb) | |||
247 | 278 | ||
248 | for (i = OCFS2_FIRST_ONLINE_SYSTEM_INODE; | 279 | for (i = OCFS2_FIRST_ONLINE_SYSTEM_INODE; |
249 | i <= OCFS2_LAST_GLOBAL_SYSTEM_INODE; i++) { | 280 | i <= OCFS2_LAST_GLOBAL_SYSTEM_INODE; i++) { |
281 | if (!ocfs2_need_system_inode(osb, i)) | ||
282 | continue; | ||
250 | new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); | 283 | new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); |
251 | if (!new) { | 284 | if (!new) { |
252 | ocfs2_release_system_inodes(osb); | 285 | ocfs2_release_system_inodes(osb); |
@@ -277,6 +310,8 @@ static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb) | |||
277 | for (i = OCFS2_LAST_GLOBAL_SYSTEM_INODE + 1; | 310 | for (i = OCFS2_LAST_GLOBAL_SYSTEM_INODE + 1; |
278 | i < NUM_SYSTEM_INODES; | 311 | i < NUM_SYSTEM_INODES; |
279 | i++) { | 312 | i++) { |
313 | if (!ocfs2_need_system_inode(osb, i)) | ||
314 | continue; | ||
280 | new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); | 315 | new = ocfs2_get_system_file_inode(osb, i, osb->slot_num); |
281 | if (!new) { | 316 | if (!new) { |
282 | ocfs2_release_system_inodes(osb); | 317 | ocfs2_release_system_inodes(osb); |
@@ -426,6 +461,12 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) | |||
426 | 461 | ||
427 | /* We're going to/from readonly mode. */ | 462 | /* We're going to/from readonly mode. */ |
428 | if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { | 463 | if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { |
464 | /* Disable quota accounting before remounting RO */ | ||
465 | if (*flags & MS_RDONLY) { | ||
466 | ret = ocfs2_susp_quotas(osb, 0); | ||
467 | if (ret < 0) | ||
468 | goto out; | ||
469 | } | ||
429 | /* Lock here so the check of HARD_RO and the potential | 470 | /* Lock here so the check of HARD_RO and the potential |
430 | * setting of SOFT_RO is atomic. */ | 471 | * setting of SOFT_RO is atomic. */ |
431 | spin_lock(&osb->osb_lock); | 472 | spin_lock(&osb->osb_lock); |
@@ -461,11 +502,28 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) | |||
461 | } | 502 | } |
462 | unlock_osb: | 503 | unlock_osb: |
463 | spin_unlock(&osb->osb_lock); | 504 | spin_unlock(&osb->osb_lock); |
505 | /* Enable quota accounting after remounting RW */ | ||
506 | if (!ret && !(*flags & MS_RDONLY)) { | ||
507 | if (sb_any_quota_suspended(sb)) | ||
508 | ret = ocfs2_susp_quotas(osb, 1); | ||
509 | else | ||
510 | ret = ocfs2_enable_quotas(osb); | ||
511 | if (ret < 0) { | ||
512 | /* Return back changes... */ | ||
513 | spin_lock(&osb->osb_lock); | ||
514 | sb->s_flags |= MS_RDONLY; | ||
515 | osb->osb_flags |= OCFS2_OSB_SOFT_RO; | ||
516 | spin_unlock(&osb->osb_lock); | ||
517 | goto out; | ||
518 | } | ||
519 | } | ||
464 | } | 520 | } |
465 | 521 | ||
466 | if (!ret) { | 522 | if (!ret) { |
467 | /* Only save off the new mount options in case of a successful | 523 | /* Only save off the new mount options in case of a successful |
468 | * remount. */ | 524 | * remount. */ |
525 | if (!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)) | ||
526 | parsed_options.mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; | ||
469 | osb->s_mount_opt = parsed_options.mount_opt; | 527 | osb->s_mount_opt = parsed_options.mount_opt; |
470 | osb->s_atime_quantum = parsed_options.atime_quantum; | 528 | osb->s_atime_quantum = parsed_options.atime_quantum; |
471 | osb->preferred_slot = parsed_options.slot; | 529 | osb->preferred_slot = parsed_options.slot; |
@@ -619,6 +677,131 @@ static int ocfs2_verify_userspace_stack(struct ocfs2_super *osb, | |||
619 | return 0; | 677 | return 0; |
620 | } | 678 | } |
621 | 679 | ||
680 | static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend) | ||
681 | { | ||
682 | int type; | ||
683 | struct super_block *sb = osb->sb; | ||
684 | unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, | ||
685 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; | ||
686 | int status = 0; | ||
687 | |||
688 | for (type = 0; type < MAXQUOTAS; type++) { | ||
689 | if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) | ||
690 | continue; | ||
691 | if (unsuspend) | ||
692 | status = vfs_quota_enable( | ||
693 | sb_dqopt(sb)->files[type], | ||
694 | type, QFMT_OCFS2, | ||
695 | DQUOT_SUSPENDED); | ||
696 | else | ||
697 | status = vfs_quota_disable(sb, type, | ||
698 | DQUOT_SUSPENDED); | ||
699 | if (status < 0) | ||
700 | break; | ||
701 | } | ||
702 | if (status < 0) | ||
703 | mlog(ML_ERROR, "Failed to suspend/unsuspend quotas on " | ||
704 | "remount (error = %d).\n", status); | ||
705 | return status; | ||
706 | } | ||
707 | |||
708 | static int ocfs2_enable_quotas(struct ocfs2_super *osb) | ||
709 | { | ||
710 | struct inode *inode[MAXQUOTAS] = { NULL, NULL }; | ||
711 | struct super_block *sb = osb->sb; | ||
712 | unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, | ||
713 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; | ||
714 | unsigned int ino[MAXQUOTAS] = { LOCAL_USER_QUOTA_SYSTEM_INODE, | ||
715 | LOCAL_GROUP_QUOTA_SYSTEM_INODE }; | ||
716 | int status; | ||
717 | int type; | ||
718 | |||
719 | sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NEGATIVE_USAGE; | ||
720 | for (type = 0; type < MAXQUOTAS; type++) { | ||
721 | if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) | ||
722 | continue; | ||
723 | inode[type] = ocfs2_get_system_file_inode(osb, ino[type], | ||
724 | osb->slot_num); | ||
725 | if (!inode[type]) { | ||
726 | status = -ENOENT; | ||
727 | goto out_quota_off; | ||
728 | } | ||
729 | status = vfs_quota_enable(inode[type], type, QFMT_OCFS2, | ||
730 | DQUOT_USAGE_ENABLED); | ||
731 | if (status < 0) | ||
732 | goto out_quota_off; | ||
733 | } | ||
734 | |||
735 | for (type = 0; type < MAXQUOTAS; type++) | ||
736 | iput(inode[type]); | ||
737 | return 0; | ||
738 | out_quota_off: | ||
739 | ocfs2_disable_quotas(osb); | ||
740 | for (type = 0; type < MAXQUOTAS; type++) | ||
741 | iput(inode[type]); | ||
742 | mlog_errno(status); | ||
743 | return status; | ||
744 | } | ||
745 | |||
746 | static void ocfs2_disable_quotas(struct ocfs2_super *osb) | ||
747 | { | ||
748 | int type; | ||
749 | struct inode *inode; | ||
750 | struct super_block *sb = osb->sb; | ||
751 | |||
752 | /* We mostly ignore errors in this function because there's not much | ||
753 | * we can do when we see them */ | ||
754 | for (type = 0; type < MAXQUOTAS; type++) { | ||
755 | if (!sb_has_quota_loaded(sb, type)) | ||
756 | continue; | ||
757 | inode = igrab(sb->s_dquot.files[type]); | ||
758 | /* Turn off quotas. This will remove all dquot structures from | ||
759 | * memory and so they will be automatically synced to global | ||
760 | * quota files */ | ||
761 | vfs_quota_disable(sb, type, DQUOT_USAGE_ENABLED | | ||
762 | DQUOT_LIMITS_ENABLED); | ||
763 | if (!inode) | ||
764 | continue; | ||
765 | iput(inode); | ||
766 | } | ||
767 | } | ||
768 | |||
769 | /* Handle quota on quotactl */ | ||
770 | static int ocfs2_quota_on(struct super_block *sb, int type, int format_id, | ||
771 | char *path, int remount) | ||
772 | { | ||
773 | unsigned int feature[MAXQUOTAS] = { OCFS2_FEATURE_RO_COMPAT_USRQUOTA, | ||
774 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA}; | ||
775 | |||
776 | if (!OCFS2_HAS_RO_COMPAT_FEATURE(sb, feature[type])) | ||
777 | return -EINVAL; | ||
778 | |||
779 | if (remount) | ||
780 | return 0; /* Just ignore it has been handled in | ||
781 | * ocfs2_remount() */ | ||
782 | return vfs_quota_enable(sb_dqopt(sb)->files[type], type, | ||
783 | format_id, DQUOT_LIMITS_ENABLED); | ||
784 | } | ||
785 | |||
786 | /* Handle quota off quotactl */ | ||
787 | static int ocfs2_quota_off(struct super_block *sb, int type, int remount) | ||
788 | { | ||
789 | if (remount) | ||
790 | return 0; /* Ignore now and handle later in | ||
791 | * ocfs2_remount() */ | ||
792 | return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED); | ||
793 | } | ||
794 | |||
795 | static struct quotactl_ops ocfs2_quotactl_ops = { | ||
796 | .quota_on = ocfs2_quota_on, | ||
797 | .quota_off = ocfs2_quota_off, | ||
798 | .quota_sync = vfs_quota_sync, | ||
799 | .get_info = vfs_get_dqinfo, | ||
800 | .set_info = vfs_set_dqinfo, | ||
801 | .get_dqblk = vfs_get_dqblk, | ||
802 | .set_dqblk = vfs_set_dqblk, | ||
803 | }; | ||
804 | |||
622 | static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | 805 | static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) |
623 | { | 806 | { |
624 | struct dentry *root; | 807 | struct dentry *root; |
@@ -651,12 +834,32 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
651 | } | 834 | } |
652 | brelse(bh); | 835 | brelse(bh); |
653 | bh = NULL; | 836 | bh = NULL; |
837 | |||
838 | if (!(osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)) | ||
839 | parsed_options.mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; | ||
840 | |||
654 | osb->s_mount_opt = parsed_options.mount_opt; | 841 | osb->s_mount_opt = parsed_options.mount_opt; |
655 | osb->s_atime_quantum = parsed_options.atime_quantum; | 842 | osb->s_atime_quantum = parsed_options.atime_quantum; |
656 | osb->preferred_slot = parsed_options.slot; | 843 | osb->preferred_slot = parsed_options.slot; |
657 | osb->osb_commit_interval = parsed_options.commit_interval; | 844 | osb->osb_commit_interval = parsed_options.commit_interval; |
658 | osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); | 845 | osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt); |
659 | osb->local_alloc_bits = osb->local_alloc_default_bits; | 846 | osb->local_alloc_bits = osb->local_alloc_default_bits; |
847 | if (osb->s_mount_opt & OCFS2_MOUNT_USRQUOTA && | ||
848 | !OCFS2_HAS_RO_COMPAT_FEATURE(sb, | ||
849 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | ||
850 | status = -EINVAL; | ||
851 | mlog(ML_ERROR, "User quotas were requested, but this " | ||
852 | "filesystem does not have the feature enabled.\n"); | ||
853 | goto read_super_error; | ||
854 | } | ||
855 | if (osb->s_mount_opt & OCFS2_MOUNT_GRPQUOTA && | ||
856 | !OCFS2_HAS_RO_COMPAT_FEATURE(sb, | ||
857 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | ||
858 | status = -EINVAL; | ||
859 | mlog(ML_ERROR, "Group quotas were requested, but this " | ||
860 | "filesystem does not have the feature enabled.\n"); | ||
861 | goto read_super_error; | ||
862 | } | ||
660 | 863 | ||
661 | status = ocfs2_verify_userspace_stack(osb, &parsed_options); | 864 | status = ocfs2_verify_userspace_stack(osb, &parsed_options); |
662 | if (status) | 865 | if (status) |
@@ -664,6 +867,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
664 | 867 | ||
665 | sb->s_magic = OCFS2_SUPER_MAGIC; | 868 | sb->s_magic = OCFS2_SUPER_MAGIC; |
666 | 869 | ||
870 | sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | | ||
871 | ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); | ||
872 | |||
667 | /* Hard readonly mode only if: bdev_read_only, MS_RDONLY, | 873 | /* Hard readonly mode only if: bdev_read_only, MS_RDONLY, |
668 | * heartbeat=none */ | 874 | * heartbeat=none */ |
669 | if (bdev_read_only(sb->s_bdev)) { | 875 | if (bdev_read_only(sb->s_bdev)) { |
@@ -758,6 +964,28 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
758 | atomic_set(&osb->vol_state, VOLUME_MOUNTED); | 964 | atomic_set(&osb->vol_state, VOLUME_MOUNTED); |
759 | wake_up(&osb->osb_mount_event); | 965 | wake_up(&osb->osb_mount_event); |
760 | 966 | ||
967 | /* Now we can initialize quotas because we can afford to wait | ||
968 | * for cluster locks recovery now. That also means that truncation | ||
969 | * log recovery can happen but that waits for proper quota setup */ | ||
970 | if (!(sb->s_flags & MS_RDONLY)) { | ||
971 | status = ocfs2_enable_quotas(osb); | ||
972 | if (status < 0) { | ||
973 | /* We have to err-out specially here because | ||
974 | * s_root is already set */ | ||
975 | mlog_errno(status); | ||
976 | atomic_set(&osb->vol_state, VOLUME_DISABLED); | ||
977 | wake_up(&osb->osb_mount_event); | ||
978 | mlog_exit(status); | ||
979 | return status; | ||
980 | } | ||
981 | } | ||
982 | |||
983 | ocfs2_complete_quota_recovery(osb); | ||
984 | |||
985 | /* Now we wake up again for processes waiting for quotas */ | ||
986 | atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS); | ||
987 | wake_up(&osb->osb_mount_event); | ||
988 | |||
761 | mlog_exit(status); | 989 | mlog_exit(status); |
762 | return status; | 990 | return status; |
763 | 991 | ||
@@ -945,6 +1173,41 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
945 | case Opt_inode64: | 1173 | case Opt_inode64: |
946 | mopt->mount_opt |= OCFS2_MOUNT_INODE64; | 1174 | mopt->mount_opt |= OCFS2_MOUNT_INODE64; |
947 | break; | 1175 | break; |
1176 | case Opt_usrquota: | ||
1177 | /* We check only on remount, otherwise features | ||
1178 | * aren't yet initialized. */ | ||
1179 | if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb, | ||
1180 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | ||
1181 | mlog(ML_ERROR, "User quota requested but " | ||
1182 | "filesystem feature is not set\n"); | ||
1183 | status = 0; | ||
1184 | goto bail; | ||
1185 | } | ||
1186 | mopt->mount_opt |= OCFS2_MOUNT_USRQUOTA; | ||
1187 | break; | ||
1188 | case Opt_grpquota: | ||
1189 | if (is_remount && !OCFS2_HAS_RO_COMPAT_FEATURE(sb, | ||
1190 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | ||
1191 | mlog(ML_ERROR, "Group quota requested but " | ||
1192 | "filesystem feature is not set\n"); | ||
1193 | status = 0; | ||
1194 | goto bail; | ||
1195 | } | ||
1196 | mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA; | ||
1197 | break; | ||
1198 | #ifdef CONFIG_OCFS2_FS_POSIX_ACL | ||
1199 | case Opt_acl: | ||
1200 | mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL; | ||
1201 | break; | ||
1202 | case Opt_noacl: | ||
1203 | mopt->mount_opt &= ~OCFS2_MOUNT_POSIX_ACL; | ||
1204 | break; | ||
1205 | #else | ||
1206 | case Opt_acl: | ||
1207 | case Opt_noacl: | ||
1208 | printk(KERN_INFO "ocfs2 (no)acl options not supported\n"); | ||
1209 | break; | ||
1210 | #endif | ||
948 | default: | 1211 | default: |
949 | mlog(ML_ERROR, | 1212 | mlog(ML_ERROR, |
950 | "Unrecognized mount option \"%s\" " | 1213 | "Unrecognized mount option \"%s\" " |
@@ -1008,6 +1271,10 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1008 | if (osb->osb_cluster_stack[0]) | 1271 | if (osb->osb_cluster_stack[0]) |
1009 | seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, | 1272 | seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, |
1010 | osb->osb_cluster_stack); | 1273 | osb->osb_cluster_stack); |
1274 | if (opts & OCFS2_MOUNT_USRQUOTA) | ||
1275 | seq_printf(s, ",usrquota"); | ||
1276 | if (opts & OCFS2_MOUNT_GRPQUOTA) | ||
1277 | seq_printf(s, ",grpquota"); | ||
1011 | 1278 | ||
1012 | if (opts & OCFS2_MOUNT_NOUSERXATTR) | 1279 | if (opts & OCFS2_MOUNT_NOUSERXATTR) |
1013 | seq_printf(s, ",nouser_xattr"); | 1280 | seq_printf(s, ",nouser_xattr"); |
@@ -1017,6 +1284,13 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1017 | if (opts & OCFS2_MOUNT_INODE64) | 1284 | if (opts & OCFS2_MOUNT_INODE64) |
1018 | seq_printf(s, ",inode64"); | 1285 | seq_printf(s, ",inode64"); |
1019 | 1286 | ||
1287 | #ifdef CONFIG_OCFS2_FS_POSIX_ACL | ||
1288 | if (opts & OCFS2_MOUNT_POSIX_ACL) | ||
1289 | seq_printf(s, ",acl"); | ||
1290 | else | ||
1291 | seq_printf(s, ",noacl"); | ||
1292 | #endif | ||
1293 | |||
1020 | return 0; | 1294 | return 0; |
1021 | } | 1295 | } |
1022 | 1296 | ||
@@ -1052,10 +1326,16 @@ static int __init ocfs2_init(void) | |||
1052 | mlog(ML_ERROR, "Unable to create ocfs2 debugfs root.\n"); | 1326 | mlog(ML_ERROR, "Unable to create ocfs2 debugfs root.\n"); |
1053 | } | 1327 | } |
1054 | 1328 | ||
1329 | status = ocfs2_quota_setup(); | ||
1330 | if (status) | ||
1331 | goto leave; | ||
1332 | |||
1055 | ocfs2_set_locking_protocol(); | 1333 | ocfs2_set_locking_protocol(); |
1056 | 1334 | ||
1335 | status = register_quota_format(&ocfs2_quota_format); | ||
1057 | leave: | 1336 | leave: |
1058 | if (status < 0) { | 1337 | if (status < 0) { |
1338 | ocfs2_quota_shutdown(); | ||
1059 | ocfs2_free_mem_caches(); | 1339 | ocfs2_free_mem_caches(); |
1060 | exit_ocfs2_uptodate_cache(); | 1340 | exit_ocfs2_uptodate_cache(); |
1061 | } | 1341 | } |
@@ -1072,11 +1352,15 @@ static void __exit ocfs2_exit(void) | |||
1072 | { | 1352 | { |
1073 | mlog_entry_void(); | 1353 | mlog_entry_void(); |
1074 | 1354 | ||
1355 | ocfs2_quota_shutdown(); | ||
1356 | |||
1075 | if (ocfs2_wq) { | 1357 | if (ocfs2_wq) { |
1076 | flush_workqueue(ocfs2_wq); | 1358 | flush_workqueue(ocfs2_wq); |
1077 | destroy_workqueue(ocfs2_wq); | 1359 | destroy_workqueue(ocfs2_wq); |
1078 | } | 1360 | } |
1079 | 1361 | ||
1362 | unregister_quota_format(&ocfs2_quota_format); | ||
1363 | |||
1080 | debugfs_remove(ocfs2_debugfs_root); | 1364 | debugfs_remove(ocfs2_debugfs_root); |
1081 | 1365 | ||
1082 | ocfs2_free_mem_caches(); | 1366 | ocfs2_free_mem_caches(); |
@@ -1192,8 +1476,27 @@ static int ocfs2_initialize_mem_caches(void) | |||
1192 | (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | 1476 | (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| |
1193 | SLAB_MEM_SPREAD), | 1477 | SLAB_MEM_SPREAD), |
1194 | ocfs2_inode_init_once); | 1478 | ocfs2_inode_init_once); |
1195 | if (!ocfs2_inode_cachep) | 1479 | ocfs2_dquot_cachep = kmem_cache_create("ocfs2_dquot_cache", |
1480 | sizeof(struct ocfs2_dquot), | ||
1481 | 0, | ||
1482 | (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| | ||
1483 | SLAB_MEM_SPREAD), | ||
1484 | NULL); | ||
1485 | ocfs2_qf_chunk_cachep = kmem_cache_create("ocfs2_qf_chunk_cache", | ||
1486 | sizeof(struct ocfs2_quota_chunk), | ||
1487 | 0, | ||
1488 | (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD), | ||
1489 | NULL); | ||
1490 | if (!ocfs2_inode_cachep || !ocfs2_dquot_cachep || | ||
1491 | !ocfs2_qf_chunk_cachep) { | ||
1492 | if (ocfs2_inode_cachep) | ||
1493 | kmem_cache_destroy(ocfs2_inode_cachep); | ||
1494 | if (ocfs2_dquot_cachep) | ||
1495 | kmem_cache_destroy(ocfs2_dquot_cachep); | ||
1496 | if (ocfs2_qf_chunk_cachep) | ||
1497 | kmem_cache_destroy(ocfs2_qf_chunk_cachep); | ||
1196 | return -ENOMEM; | 1498 | return -ENOMEM; |
1499 | } | ||
1197 | 1500 | ||
1198 | return 0; | 1501 | return 0; |
1199 | } | 1502 | } |
@@ -1202,8 +1505,15 @@ static void ocfs2_free_mem_caches(void) | |||
1202 | { | 1505 | { |
1203 | if (ocfs2_inode_cachep) | 1506 | if (ocfs2_inode_cachep) |
1204 | kmem_cache_destroy(ocfs2_inode_cachep); | 1507 | kmem_cache_destroy(ocfs2_inode_cachep); |
1205 | |||
1206 | ocfs2_inode_cachep = NULL; | 1508 | ocfs2_inode_cachep = NULL; |
1509 | |||
1510 | if (ocfs2_dquot_cachep) | ||
1511 | kmem_cache_destroy(ocfs2_dquot_cachep); | ||
1512 | ocfs2_dquot_cachep = NULL; | ||
1513 | |||
1514 | if (ocfs2_qf_chunk_cachep) | ||
1515 | kmem_cache_destroy(ocfs2_qf_chunk_cachep); | ||
1516 | ocfs2_qf_chunk_cachep = NULL; | ||
1207 | } | 1517 | } |
1208 | 1518 | ||
1209 | static int ocfs2_get_sector(struct super_block *sb, | 1519 | static int ocfs2_get_sector(struct super_block *sb, |
@@ -1303,6 +1613,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err) | |||
1303 | osb = OCFS2_SB(sb); | 1613 | osb = OCFS2_SB(sb); |
1304 | BUG_ON(!osb); | 1614 | BUG_ON(!osb); |
1305 | 1615 | ||
1616 | ocfs2_disable_quotas(osb); | ||
1617 | |||
1306 | ocfs2_shutdown_local_alloc(osb); | 1618 | ocfs2_shutdown_local_alloc(osb); |
1307 | 1619 | ||
1308 | ocfs2_truncate_log_shutdown(osb); | 1620 | ocfs2_truncate_log_shutdown(osb); |
@@ -1413,6 +1725,8 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
1413 | sb->s_fs_info = osb; | 1725 | sb->s_fs_info = osb; |
1414 | sb->s_op = &ocfs2_sops; | 1726 | sb->s_op = &ocfs2_sops; |
1415 | sb->s_export_op = &ocfs2_export_ops; | 1727 | sb->s_export_op = &ocfs2_export_ops; |
1728 | sb->s_qcop = &ocfs2_quotactl_ops; | ||
1729 | sb->dq_op = &ocfs2_quota_operations; | ||
1416 | sb->s_xattr = ocfs2_xattr_handlers; | 1730 | sb->s_xattr = ocfs2_xattr_handlers; |
1417 | sb->s_time_gran = 1; | 1731 | sb->s_time_gran = 1; |
1418 | sb->s_flags |= MS_NOATIME; | 1732 | sb->s_flags |= MS_NOATIME; |
@@ -1676,6 +1990,15 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di, | |||
1676 | 1990 | ||
1677 | if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE, | 1991 | if (memcmp(di->i_signature, OCFS2_SUPER_BLOCK_SIGNATURE, |
1678 | strlen(OCFS2_SUPER_BLOCK_SIGNATURE)) == 0) { | 1992 | strlen(OCFS2_SUPER_BLOCK_SIGNATURE)) == 0) { |
1993 | /* We have to do a raw check of the feature here */ | ||
1994 | if (le32_to_cpu(di->id2.i_super.s_feature_incompat) & | ||
1995 | OCFS2_FEATURE_INCOMPAT_META_ECC) { | ||
1996 | status = ocfs2_block_check_validate(bh->b_data, | ||
1997 | bh->b_size, | ||
1998 | &di->i_check); | ||
1999 | if (status) | ||
2000 | goto out; | ||
2001 | } | ||
1679 | status = -EINVAL; | 2002 | status = -EINVAL; |
1680 | if ((1 << le32_to_cpu(di->id2.i_super.s_blocksize_bits)) != blksz) { | 2003 | if ((1 << le32_to_cpu(di->id2.i_super.s_blocksize_bits)) != blksz) { |
1681 | mlog(ML_ERROR, "found superblock with incorrect block " | 2004 | mlog(ML_ERROR, "found superblock with incorrect block " |
@@ -1717,6 +2040,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di, | |||
1717 | } | 2040 | } |
1718 | } | 2041 | } |
1719 | 2042 | ||
2043 | out: | ||
1720 | mlog_exit(status); | 2044 | mlog_exit(status); |
1721 | return status; | 2045 | return status; |
1722 | } | 2046 | } |