Commit b61817e1166c5e19c08baf05196477cc345e1b1a

Authored by Joel Becker
Committed by Mark Fasheh
1 parent 74ae4e104d

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>

Showing 3 changed files with 134 additions and 3 deletions Side-by-side Diff

... ... @@ -248,6 +248,7 @@
248 248 struct ocfs2_alloc_stats alloc_stats;
249 249 char dev_str[20]; /* "major,minor" of the device */
250 250  
  251 + char osb_cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
251 252 struct ocfs2_cluster_connection *cconn;
252 253 struct ocfs2_lock_res osb_super_lockres;
253 254 struct ocfs2_lock_res osb_rename_lockres;
... ... @@ -366,6 +367,12 @@
366 367 spin_unlock(&osb->osb_lock);
367 368  
368 369 return ret;
  370 +}
  371 +
  372 +static inline int ocfs2_userspace_stack(struct ocfs2_super *osb)
  373 +{
  374 + return (osb->s_feature_incompat &
  375 + OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK);
369 376 }
370 377  
371 378 static inline int ocfs2_mount_local(struct ocfs2_super *osb)
... ... @@ -89,7 +89,8 @@
89 89 #define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
90 90 | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
91 91 | OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
92   - | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP)
  92 + | OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \
  93 + | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK)
93 94 #define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
94 95  
95 96 /*
... ... @@ -131,6 +132,17 @@
131 132  
132 133  
133 134 /*
  135 + * Support for alternate, userspace cluster stacks. If set, the superblock
  136 + * field s_cluster_info contains a tag for the alternate stack in use as
  137 + * well as the name of the cluster being joined.
  138 + * mount.ocfs2 must pass in a matching stack name.
  139 + *
  140 + * If not set, the classic stack will be used. This is compatbile with
  141 + * all older versions.
  142 + */
  143 +#define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK 0x0080
  144 +
  145 +/*
134 146 * backup superblock flag is used to indicate that this volume
135 147 * has backup superblocks.
136 148 */
... ... @@ -272,6 +284,10 @@
272 284 #define OCFS2_VOL_UUID_LEN 16
273 285 #define OCFS2_MAX_VOL_LABEL_LEN 64
274 286  
  287 +/* The alternate, userspace stack fields */
  288 +#define OCFS2_STACK_LABEL_LEN 4
  289 +#define OCFS2_CLUSTER_NAME_LEN 16
  290 +
275 291 /* Journal limits (in bytes) */
276 292 #define OCFS2_MIN_JOURNAL_SIZE (4 * 1024 * 1024)
277 293  
... ... @@ -513,6 +529,13 @@
513 529 */
514 530 };
515 531  
  532 +struct ocfs2_cluster_info {
  533 +/*00*/ __u8 ci_stack[OCFS2_STACK_LABEL_LEN];
  534 + __le32 ci_reserved;
  535 +/*08*/ __u8 ci_cluster[OCFS2_CLUSTER_NAME_LEN];
  536 +/*18*/
  537 +};
  538 +
516 539 /*
517 540 * On disk superblock for OCFS2
518 541 * Note that it is contained inside an ocfs2_dinode, so all offsets
... ... @@ -545,7 +568,20 @@
545 568 * group header */
546 569 /*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
547 570 /*90*/ __u8 s_uuid[OCFS2_VOL_UUID_LEN]; /* 128-bit uuid */
548   -/*A0*/
  571 +/*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Selected userspace
  572 + stack. Only valid
  573 + with INCOMPAT flag. */
  574 +/*B8*/ __le64 s_reserved2[17]; /* Fill out superblock */
  575 +/*140*/
  576 +
  577 + /*
  578 + * NOTE: As stated above, all offsets are relative to
  579 + * ocfs2_dinode.id2, which is at 0xC0 in the inode.
  580 + * 0xC0 + 0x140 = 0x200 or 512 bytes. A superblock must fit within
  581 + * our smallest blocksize, which is 512 bytes. To ensure this,
  582 + * we reserve the space in s_reserved2. Anything past s_reserved2
  583 + * will not be available on the smallest blocksize.
  584 + */
549 585 };
550 586  
551 587 /*
... ... @@ -87,6 +87,7 @@
87 87 unsigned int atime_quantum;
88 88 signed short slot;
89 89 unsigned int localalloc_opt;
  90 + char cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
90 91 };
91 92  
92 93 static int ocfs2_parse_options(struct super_block *sb, char *options,
... ... @@ -152,6 +153,7 @@
152 153 Opt_commit,
153 154 Opt_localalloc,
154 155 Opt_localflocks,
  156 + Opt_stack,
155 157 Opt_err,
156 158 };
157 159  
... ... @@ -170,6 +172,7 @@
170 172 {Opt_commit, "commit=%u"},
171 173 {Opt_localalloc, "localalloc=%d"},
172 174 {Opt_localflocks, "localflocks"},
  175 + {Opt_stack, "cluster_stack=%s"},
173 176 {Opt_err, NULL}
174 177 };
175 178  
176 179  
... ... @@ -549,8 +552,17 @@
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 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 566 mlog(ML_ERROR, "Heartbeat has to be started to mount "
555 567 "a read-write clustered device.\n");
556 568 return -EINVAL;
... ... @@ -560,6 +572,35 @@
560 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 604 static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
564 605 {
565 606 struct dentry *root;
... ... @@ -598,6 +639,10 @@
598 639 osb->osb_commit_interval = parsed_options.commit_interval;
599 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 646 sb->s_magic = OCFS2_SUPER_MAGIC;
602 647  
603 648 /* Hard readonly mode only if: bdev_read_only, MS_RDONLY,
... ... @@ -752,6 +797,7 @@
752 797 mopt->atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
753 798 mopt->slot = OCFS2_INVALID_SLOT;
754 799 mopt->localalloc_opt = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
  800 + mopt->cluster_stack[0] = '\0';
755 801  
756 802 if (!options) {
757 803 status = 1;
... ... @@ -853,6 +899,25 @@
853 899 if (!is_remount)
854 900 mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
855 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 921 default:
857 922 mlog(ML_ERROR,
858 923 "Unrecognized mount option \"%s\" "
... ... @@ -911,6 +976,10 @@
911 976 if (opts & OCFS2_MOUNT_LOCALFLOCKS)
912 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 983 return 0;
915 984 }
916 985  
... ... @@ -1401,6 +1470,25 @@
1401 1470 "unsupported optional features (%x).\n", i);
1402 1471 status = -EINVAL;
1403 1472 goto bail;
  1473 + }
  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';
1404 1492 }
1405 1493  
1406 1494 get_random_bytes(&osb->s_next_generation, sizeof(u32));