diff options
author | Joel Becker <joel.becker@oracle.com> | 2008-02-01 18:08:23 -0500 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-04-18 11:56:05 -0400 |
commit | b61817e1166c5e19c08baf05196477cc345e1b1a (patch) | |
tree | 8da1c387086313aecdbb8f96fd0ab33417860620 /fs/ocfs2/super.c | |
parent | 74ae4e104dfc57017783fc07d5f2f9129062207f (diff) |
ocfs2: Add the USERSPACE_STACK incompat bit.
The filesystem gains the USERSPACE_STACK incomat bit and the
s_cluster_info field on the superblock. When a userspace stack is in
use, the name of the stack is stored on-disk for mount-time
verification.
The "cluster_stack" option is added to mount(2) processing. The mount
process needs to pass the matching stack name. If the passed name and
the on-disk name do not match, the mount is failed.
When using the classic o2cb stack, the incompat bit is *not* set and no
mount option is used other than the usual heartbeat=local. Thus, the
filesystem is compatible with older tools.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/ocfs2/super.c')
-rw-r--r-- | fs/ocfs2/super.c | 90 |
1 files changed, 89 insertions, 1 deletions
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index e27a0d47ea2b..96ebe36d5d77 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -87,6 +87,7 @@ struct mount_options | |||
87 | unsigned int atime_quantum; | 87 | unsigned int atime_quantum; |
88 | signed short slot; | 88 | signed short slot; |
89 | unsigned int localalloc_opt; | 89 | unsigned int localalloc_opt; |
90 | char cluster_stack[OCFS2_STACK_LABEL_LEN + 1]; | ||
90 | }; | 91 | }; |
91 | 92 | ||
92 | static int ocfs2_parse_options(struct super_block *sb, char *options, | 93 | static int ocfs2_parse_options(struct super_block *sb, char *options, |
@@ -152,6 +153,7 @@ enum { | |||
152 | Opt_commit, | 153 | Opt_commit, |
153 | Opt_localalloc, | 154 | Opt_localalloc, |
154 | Opt_localflocks, | 155 | Opt_localflocks, |
156 | Opt_stack, | ||
155 | Opt_err, | 157 | Opt_err, |
156 | }; | 158 | }; |
157 | 159 | ||
@@ -170,6 +172,7 @@ static match_table_t tokens = { | |||
170 | {Opt_commit, "commit=%u"}, | 172 | {Opt_commit, "commit=%u"}, |
171 | {Opt_localalloc, "localalloc=%d"}, | 173 | {Opt_localalloc, "localalloc=%d"}, |
172 | {Opt_localflocks, "localflocks"}, | 174 | {Opt_localflocks, "localflocks"}, |
175 | {Opt_stack, "cluster_stack=%s"}, | ||
173 | {Opt_err, NULL} | 176 | {Opt_err, NULL} |
174 | }; | 177 | }; |
175 | 178 | ||
@@ -549,8 +552,17 @@ static int ocfs2_verify_heartbeat(struct ocfs2_super *osb) | |||
549 | } | 552 | } |
550 | } | 553 | } |
551 | 554 | ||
555 | if (ocfs2_userspace_stack(osb)) { | ||
556 | if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) { | ||
557 | mlog(ML_ERROR, "Userspace stack expected, but " | ||
558 | "o2cb heartbeat arguments passed to mount\n"); | ||
559 | return -EINVAL; | ||
560 | } | ||
561 | } | ||
562 | |||
552 | if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) { | 563 | if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) { |
553 | if (!ocfs2_mount_local(osb) && !ocfs2_is_hard_readonly(osb)) { | 564 | if (!ocfs2_mount_local(osb) && !ocfs2_is_hard_readonly(osb) && |
565 | !ocfs2_userspace_stack(osb)) { | ||
554 | mlog(ML_ERROR, "Heartbeat has to be started to mount " | 566 | mlog(ML_ERROR, "Heartbeat has to be started to mount " |
555 | "a read-write clustered device.\n"); | 567 | "a read-write clustered device.\n"); |
556 | return -EINVAL; | 568 | return -EINVAL; |
@@ -560,6 +572,35 @@ static int ocfs2_verify_heartbeat(struct ocfs2_super *osb) | |||
560 | return 0; | 572 | return 0; |
561 | } | 573 | } |
562 | 574 | ||
575 | /* | ||
576 | * If we're using a userspace stack, mount should have passed | ||
577 | * a name that matches the disk. If not, mount should not | ||
578 | * have passed a stack. | ||
579 | */ | ||
580 | static int ocfs2_verify_userspace_stack(struct ocfs2_super *osb, | ||
581 | struct mount_options *mopt) | ||
582 | { | ||
583 | if (!ocfs2_userspace_stack(osb) && mopt->cluster_stack[0]) { | ||
584 | mlog(ML_ERROR, | ||
585 | "cluster stack passed to mount, but this filesystem " | ||
586 | "does not support it\n"); | ||
587 | return -EINVAL; | ||
588 | } | ||
589 | |||
590 | if (ocfs2_userspace_stack(osb) && | ||
591 | strncmp(osb->osb_cluster_stack, mopt->cluster_stack, | ||
592 | OCFS2_STACK_LABEL_LEN)) { | ||
593 | mlog(ML_ERROR, | ||
594 | "cluster stack passed to mount (\"%s\") does not " | ||
595 | "match the filesystem (\"%s\")\n", | ||
596 | mopt->cluster_stack, | ||
597 | osb->osb_cluster_stack); | ||
598 | return -EINVAL; | ||
599 | } | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
563 | static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | 604 | static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) |
564 | { | 605 | { |
565 | struct dentry *root; | 606 | struct dentry *root; |
@@ -598,6 +639,10 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) | |||
598 | osb->osb_commit_interval = parsed_options.commit_interval; | 639 | osb->osb_commit_interval = parsed_options.commit_interval; |
599 | osb->local_alloc_size = parsed_options.localalloc_opt; | 640 | osb->local_alloc_size = parsed_options.localalloc_opt; |
600 | 641 | ||
642 | status = ocfs2_verify_userspace_stack(osb, &parsed_options); | ||
643 | if (status) | ||
644 | goto read_super_error; | ||
645 | |||
601 | sb->s_magic = OCFS2_SUPER_MAGIC; | 646 | sb->s_magic = OCFS2_SUPER_MAGIC; |
602 | 647 | ||
603 | /* Hard readonly mode only if: bdev_read_only, MS_RDONLY, | 648 | /* Hard readonly mode only if: bdev_read_only, MS_RDONLY, |
@@ -752,6 +797,7 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
752 | mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; | 797 | mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; |
753 | mopt->slot = OCFS2_INVALID_SLOT; | 798 | mopt->slot = OCFS2_INVALID_SLOT; |
754 | mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; | 799 | mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE; |
800 | mopt->cluster_stack[0] = '\0'; | ||
755 | 801 | ||
756 | if (!options) { | 802 | if (!options) { |
757 | status = 1; | 803 | status = 1; |
@@ -853,6 +899,25 @@ static int ocfs2_parse_options(struct super_block *sb, | |||
853 | if (!is_remount) | 899 | if (!is_remount) |
854 | mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS; | 900 | mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS; |
855 | break; | 901 | break; |
902 | case Opt_stack: | ||
903 | /* Check both that the option we were passed | ||
904 | * is of the right length and that it is a proper | ||
905 | * string of the right length. | ||
906 | */ | ||
907 | if (((args[0].to - args[0].from) != | ||
908 | OCFS2_STACK_LABEL_LEN) || | ||
909 | (strnlen(args[0].from, | ||
910 | OCFS2_STACK_LABEL_LEN) != | ||
911 | OCFS2_STACK_LABEL_LEN)) { | ||
912 | mlog(ML_ERROR, | ||
913 | "Invalid cluster_stack option\n"); | ||
914 | status = 0; | ||
915 | goto bail; | ||
916 | } | ||
917 | memcpy(mopt->cluster_stack, args[0].from, | ||
918 | OCFS2_STACK_LABEL_LEN); | ||
919 | mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0'; | ||
920 | break; | ||
856 | default: | 921 | default: |
857 | mlog(ML_ERROR, | 922 | mlog(ML_ERROR, |
858 | "Unrecognized mount option \"%s\" " | 923 | "Unrecognized mount option \"%s\" " |
@@ -911,6 +976,10 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
911 | if (opts & OCFS2_MOUNT_LOCALFLOCKS) | 976 | if (opts & OCFS2_MOUNT_LOCALFLOCKS) |
912 | seq_printf(s, ",localflocks,"); | 977 | seq_printf(s, ",localflocks,"); |
913 | 978 | ||
979 | if (osb->osb_cluster_stack[0]) | ||
980 | seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, | ||
981 | osb->osb_cluster_stack); | ||
982 | |||
914 | return 0; | 983 | return 0; |
915 | } | 984 | } |
916 | 985 | ||
@@ -1403,6 +1472,25 @@ static int ocfs2_initialize_super(struct super_block *sb, | |||
1403 | goto bail; | 1472 | goto bail; |
1404 | } | 1473 | } |
1405 | 1474 | ||
1475 | if (ocfs2_userspace_stack(osb)) { | ||
1476 | memcpy(osb->osb_cluster_stack, | ||
1477 | OCFS2_RAW_SB(di)->s_cluster_info.ci_stack, | ||
1478 | OCFS2_STACK_LABEL_LEN); | ||
1479 | osb->osb_cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0'; | ||
1480 | if (strlen(osb->osb_cluster_stack) != OCFS2_STACK_LABEL_LEN) { | ||
1481 | mlog(ML_ERROR, | ||
1482 | "couldn't mount because of an invalid " | ||
1483 | "cluster stack label (%s) \n", | ||
1484 | osb->osb_cluster_stack); | ||
1485 | status = -EINVAL; | ||
1486 | goto bail; | ||
1487 | } | ||
1488 | } else { | ||
1489 | /* The empty string is identical with classic tools that | ||
1490 | * don't know about s_cluster_info. */ | ||
1491 | osb->osb_cluster_stack[0] = '\0'; | ||
1492 | } | ||
1493 | |||
1406 | get_random_bytes(&osb->s_next_generation, sizeof(u32)); | 1494 | get_random_bytes(&osb->s_next_generation, sizeof(u32)); |
1407 | 1495 | ||
1408 | /* FIXME | 1496 | /* FIXME |