+ devsize -= choose_bm_space(devsize);
+
+ switch(st->minor_version) {
+ case -1: /* no specified. Now time to set default */
+ st->minor_version = 0;
+ /* FALL THROUGH */
+ case 0:
+ /* at end */
+ return ((devsize - 8*2 ) & ~(4*2-1));
+ case 1:
+ /* at start, 4K for superblock and possible bitmap */
+ return devsize - 4*2;
+ case 2:
+ /* 4k from start, 4K for superblock and possible bitmap */
+ return devsize - (4+4)*2;
+ }
+ return 0;
+}
+
+static int
+add_internal_bitmap1(struct supertype *st,
+ int *chunkp, int delay, int write_behind,
+ unsigned long long size,
+ int may_change, int major)
+{
+ /*
+ * If not may_change, then this is a 'Grow', and the bitmap
+ * must fit after the superblock.
+ * If may_change, then this is create, and we can put the bitmap
+ * before the superblock if we like, or may move the start.
+ * If !may_change, the bitmap MUST live at offset of 1K, until
+ * we get a sysfs interface.
+ *
+ * size is in sectors, chunk is in bytes !!!
+ */
+
+ unsigned long long bits;
+ unsigned long long max_bits;
+ unsigned long long min_chunk;
+ long offset;
+ int chunk = *chunkp;
+ int room = 0;
+ struct mdp_superblock_1 *sb = st->sb;
+ bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb) + 1024);
+
+ switch(st->minor_version) {
+ case 0:
+ /* either 3K after the superblock, or some amount of space
+ * before.
+ */
+ if (may_change) {
+ /* We are creating array, so we *know* how much room has
+ * been left.
+ */
+ offset = 0;
+ room = choose_bm_space(__le64_to_cpu(sb->size));
+ if (room == 4*2) {
+ /* make it 3K after the superblock */
+ room = 3*2;
+ offset = 2;
+ }
+ } else {
+ room = __le64_to_cpu(sb->super_offset)
+ - __le64_to_cpu(sb->data_offset)
+ - __le64_to_cpu(sb->data_size);
+ /* remove '1 ||' when we can set offset via sysfs */
+ if (1 || (room < 3*2 &&
+ __le32_to_cpu(sb->max_dev) <= 384)) {
+ room = 3*2;
+ offset = 1*2;
+ } else {
+ offset = 0; /* means movable offset */
+ }
+ }
+ break;
+ case 1:
+ case 2: /* between superblock and data */
+ if (may_change) {
+ offset = 4*2;
+ room = choose_bm_space(__le64_to_cpu(sb->size));
+ } else {
+ room = __le64_to_cpu(sb->data_offset)
+ - __le64_to_cpu(sb->super_offset);
+ if (1 || __le32_to_cpu(sb->max_dev) <= 384) {
+ room -= 2;
+ offset = 2;
+ } else {
+ room -= 4*2;
+ offset = 4*2;
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ if (chunk == UnSet && room > 128*2)
+ /* Limit to 128K of bitmap when chunk size not requested */
+ room = 128*2;
+
+ max_bits = (room * 512 - sizeof(bitmap_super_t)) * 8;
+
+ min_chunk = 4096; /* sub-page chunks don't work yet.. */
+ bits = (size*512)/min_chunk +1;
+ while (bits > max_bits) {
+ min_chunk *= 2;
+ bits = (bits+1)/2;
+ }
+ if (chunk == UnSet)
+ chunk = min_chunk;
+ else if (chunk < min_chunk)
+ return 0; /* chunk size too small */
+ if (chunk == 0) /* rounding problem */
+ return 0;
+
+ if (offset == 0) {
+ bits = (size*512) / chunk + 1;
+ room = ((bits+7)/8 + sizeof(bitmap_super_t) +511)/512;
+ offset = -room;
+ }
+
+ sb->bitmap_offset = __cpu_to_le32(offset);
+
+ sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map) | 1);
+ memset(bms, 0, sizeof(*bms));
+ bms->magic = __cpu_to_le32(BITMAP_MAGIC);
+ bms->version = __cpu_to_le32(major);
+ uuid_from_super1(st, (int*)bms->uuid);
+ bms->chunksize = __cpu_to_le32(chunk);
+ bms->daemon_sleep = __cpu_to_le32(delay);
+ bms->sync_size = __cpu_to_le64(size);
+ bms->write_behind = __cpu_to_le32(write_behind);
+
+ *chunkp = chunk;
+ return 1;
+}
+
+
+static void locate_bitmap1(struct supertype *st, int fd)
+{
+ unsigned long long offset;
+ struct mdp_superblock_1 *sb;
+ int mustfree = 0;
+
+ if (!st->sb) {
+ if (st->ss->load_super(st, fd, NULL))
+ return; /* no error I hope... */
+ mustfree = 1;
+ }
+ sb = st->sb;
+
+ offset = __le64_to_cpu(sb->super_offset);
+ offset += (int32_t) __le32_to_cpu(sb->bitmap_offset);
+ if (mustfree)
+ free(sb);
+ lseek64(fd, offset<<9, 0);
+}
+
+static int write_bitmap1(struct supertype *st, int fd)
+{
+ struct mdp_superblock_1 *sb = st->sb;
+ bitmap_super_t *bms = (bitmap_super_t*)(((char*)sb)+1024);
+ int rv = 0;
+
+ int towrite, n;
+ char buf[4096];
+
+ locate_bitmap1(st, fd);
+
+ if (write(fd, ((char*)sb)+1024, sizeof(bitmap_super_t)) !=
+ sizeof(bitmap_super_t))
+ return -2;
+ towrite = __le64_to_cpu(bms->sync_size) / (__le32_to_cpu(bms->chunksize)>>9);
+ towrite = (towrite+7) >> 3; /* bits to bytes */
+ memset(buf, 0xff, sizeof(buf));
+ while (towrite > 0) {
+ n = towrite;
+ if (n > sizeof(buf))
+ n = sizeof(buf);
+ n = write(fd, buf, n);
+ if (n > 0)
+ towrite -= n;
+ else
+ break;
+ }
+ fsync(fd);
+ if (towrite)
+ rv = -2;
+
+ return rv;
+}
+
+static void free_super1(struct supertype *st)
+{
+ if (st->sb)
+ free(st->sb);
+ st->sb = NULL;
+}
+
+static int validate_geometry1(struct supertype *st, int level,
+ int layout, int raiddisks,
+ int chunk, unsigned long long size,
+ char *subdev, unsigned long long *freesize)
+{
+ unsigned long long ldsize;
+ int fd;
+
+ if (level == LEVEL_CONTAINER)
+ return 0;
+ if (!subdev)
+ return 1;
+
+ fd = open(subdev, O_RDONLY|O_EXCL, 0);
+ if (fd < 0) {
+ fprintf(stderr, Name ": Cannot open %s: %s\n",
+ subdev, strerror(errno));
+ return 0;
+ }
+ if (!get_dev_size(fd, subdev, &ldsize)) {
+ close(fd);
+ return 0;
+ }
+ close(fd);
+
+ *freesize = avail_size1(st, ldsize >> 9);
+ return 1;