You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
638 lines
20 KiB
638 lines
20 KiB
6 years ago
|
commit 2432ce9b3235f34d00ef6c28ef6b624a32b85530
|
||
|
Author: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
|
||
|
Date: Wed Mar 29 11:54:17 2017 +0200
|
||
|
|
||
|
imsm: PPL support
|
||
|
|
||
|
Enable creating and assembling IMSM raid5 arrays with PPL. Update the
|
||
|
IMSM metadata format to include new fields used for PPL.
|
||
|
|
||
|
Add structures for PPL metadata. They are used also by super1 and shared
|
||
|
with the kernel, so put them in md_p.h.
|
||
|
|
||
|
Write the initial empty PPL header when creating an array. When
|
||
|
assembling an array with PPL, validate the PPL header and in case it is
|
||
|
not correct allow to overwrite it if --force was provided.
|
||
|
|
||
|
Write the PPL location and size for a device to the new rdev sysfs
|
||
|
attributes 'ppl_sector' and 'ppl_size'. Enable PPL in the kernel by
|
||
|
writing to 'consistency_policy' before the array is activated.
|
||
|
|
||
|
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
|
||
|
Signed-off-by: Jes Sorensen <Jes.Sorensen@gmail.com>
|
||
|
|
||
|
diff --git a/Assemble.c b/Assemble.c
|
||
|
index 3da0903..8e55b49 100644
|
||
|
--- a/Assemble.c
|
||
|
+++ b/Assemble.c
|
||
|
@@ -1942,6 +1942,55 @@ int assemble_container_content(struct supertype *st, int mdfd,
|
||
|
map_update(NULL, fd2devnm(mdfd), content->text_version,
|
||
|
content->uuid, chosen_name);
|
||
|
|
||
|
+ if (content->consistency_policy == CONSISTENCY_POLICY_PPL &&
|
||
|
+ st->ss->validate_ppl) {
|
||
|
+ content->array.state |= 1;
|
||
|
+ err = 0;
|
||
|
+
|
||
|
+ for (dev = content->devs; dev; dev = dev->next) {
|
||
|
+ int dfd;
|
||
|
+ char *devpath;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ ret = st->ss->validate_ppl(st, content, dev);
|
||
|
+ if (ret == 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (ret < 0) {
|
||
|
+ err = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!c->force) {
|
||
|
+ pr_err("%s contains invalid PPL - consider --force or --update-subarray with --update=no-ppl\n",
|
||
|
+ chosen_name);
|
||
|
+ content->array.state &= ~1;
|
||
|
+ avail[dev->disk.raid_disk] = 0;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* have --force - overwrite the invalid ppl */
|
||
|
+ devpath = map_dev(dev->disk.major, dev->disk.minor, 0);
|
||
|
+ dfd = dev_open(devpath, O_RDWR);
|
||
|
+ if (dfd < 0) {
|
||
|
+ pr_err("Failed to open %s\n", devpath);
|
||
|
+ err = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ err = st->ss->write_init_ppl(st, content, dfd);
|
||
|
+ close(dfd);
|
||
|
+
|
||
|
+ if (err)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (err) {
|
||
|
+ free(avail);
|
||
|
+ return err;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
if (enough(content->array.level, content->array.raid_disks,
|
||
|
content->array.layout, content->array.state & 1, avail) == 0) {
|
||
|
if (c->export && result)
|
||
|
diff --git a/Makefile b/Makefile
|
||
|
index d1a6ac4..5ff6cc0 100644
|
||
|
--- a/Makefile
|
||
|
+++ b/Makefile
|
||
|
@@ -151,7 +151,7 @@ MON_OBJS = mdmon.o monitor.o managemon.o util.o maps.o mdstat.o sysfs.o \
|
||
|
Kill.o sg_io.o dlink.o ReadMe.o super-intel.o \
|
||
|
super-mbr.o super-gpt.o \
|
||
|
super-ddf.o sha1.o crc32.o msg.o bitmap.o xmalloc.o \
|
||
|
- platform-intel.o probe_roms.o
|
||
|
+ platform-intel.o probe_roms.o crc32c.o
|
||
|
|
||
|
MON_SRCS = $(patsubst %.o,%.c,$(MON_OBJS))
|
||
|
|
||
|
@@ -161,7 +161,8 @@ STATICOBJS = pwgr.o
|
||
|
ASSEMBLE_SRCS := mdassemble.c Assemble.c Manage.c config.c policy.c dlink.c util.c \
|
||
|
maps.c lib.c xmalloc.c \
|
||
|
super0.c super1.c super-ddf.c super-intel.c sha1.c crc32.c sg_io.c mdstat.c \
|
||
|
- platform-intel.c probe_roms.c sysfs.c super-mbr.c super-gpt.c mapfile.c
|
||
|
+ platform-intel.c probe_roms.c sysfs.c super-mbr.c super-gpt.c mapfile.c \
|
||
|
+ crc32c.c
|
||
|
ASSEMBLE_AUTO_SRCS := mdopen.c
|
||
|
ASSEMBLE_FLAGS:= $(CFLAGS) -DMDASSEMBLE
|
||
|
ifdef MDASSEMBLE_AUTO
|
||
|
diff --git a/md_p.h b/md_p.h
|
||
|
index dc9fec1..358a28c 100644
|
||
|
--- a/md_p.h
|
||
|
+++ b/md_p.h
|
||
|
@@ -267,4 +267,29 @@ struct r5l_meta_block {
|
||
|
#define R5LOG_VERSION 0x1
|
||
|
#define R5LOG_MAGIC 0x6433c509
|
||
|
|
||
|
+struct ppl_header_entry {
|
||
|
+ __u64 data_sector; /* raid sector of the new data */
|
||
|
+ __u32 pp_size; /* length of partial parity */
|
||
|
+ __u32 data_size; /* length of data */
|
||
|
+ __u32 parity_disk; /* member disk containing parity */
|
||
|
+ __u32 checksum; /* checksum of this entry's partial parity */
|
||
|
+} __attribute__ ((__packed__));
|
||
|
+
|
||
|
+#define PPL_HEADER_SIZE 4096
|
||
|
+#define PPL_HDR_RESERVED 512
|
||
|
+#define PPL_HDR_ENTRY_SPACE \
|
||
|
+ (PPL_HEADER_SIZE - PPL_HDR_RESERVED - 4 * sizeof(__u32) - sizeof(__u64))
|
||
|
+#define PPL_HDR_MAX_ENTRIES \
|
||
|
+ (PPL_HDR_ENTRY_SPACE / sizeof(struct ppl_header_entry))
|
||
|
+
|
||
|
+struct ppl_header {
|
||
|
+ __u8 reserved[PPL_HDR_RESERVED];/* reserved space, fill with 0xff */
|
||
|
+ __u32 signature; /* signature (family number of volume) */
|
||
|
+ __u32 padding; /* zero pad */
|
||
|
+ __u64 generation; /* generation number of the header */
|
||
|
+ __u32 entries_count; /* number of entries in entry array */
|
||
|
+ __u32 checksum; /* checksum of the header */
|
||
|
+ struct ppl_header_entry entries[PPL_HDR_MAX_ENTRIES];
|
||
|
+} __attribute__ ((__packed__));
|
||
|
+
|
||
|
#endif
|
||
|
diff --git a/mdadm.h b/mdadm.h
|
||
|
index b52d4d3..d222cc3 100644
|
||
|
--- a/mdadm.h
|
||
|
+++ b/mdadm.h
|
||
|
@@ -300,6 +300,8 @@ struct mdinfo {
|
||
|
#define MaxSector (~0ULL) /* resync/recovery complete position */
|
||
|
};
|
||
|
long bitmap_offset; /* 0 == none, 1 == a file */
|
||
|
+ unsigned int ppl_size;
|
||
|
+ unsigned long long ppl_sector;
|
||
|
unsigned long safe_mode_delay; /* ms delay to mark clean */
|
||
|
int new_level, delta_disks, new_layout, new_chunk;
|
||
|
int errors;
|
||
|
@@ -1074,6 +1076,10 @@ extern struct superswitch {
|
||
|
/* write initial empty PPL on device */
|
||
|
int (*write_init_ppl)(struct supertype *st, struct mdinfo *info, int fd);
|
||
|
|
||
|
+ /* validate ppl before assemble */
|
||
|
+ int (*validate_ppl)(struct supertype *st, struct mdinfo *info,
|
||
|
+ struct mdinfo *disk);
|
||
|
+
|
||
|
/* records new bad block in metadata */
|
||
|
int (*record_bad_block)(struct active_array *a, int n,
|
||
|
unsigned long long sector, int length);
|
||
|
diff --git a/super-intel.c b/super-intel.c
|
||
|
index 2d92c8e..87fec8b 100644
|
||
|
--- a/super-intel.c
|
||
|
+++ b/super-intel.c
|
||
|
@@ -102,6 +102,7 @@ struct imsm_disk {
|
||
|
#define SPARE_DISK __cpu_to_le32(0x01) /* Spare */
|
||
|
#define CONFIGURED_DISK __cpu_to_le32(0x02) /* Member of some RaidDev */
|
||
|
#define FAILED_DISK __cpu_to_le32(0x04) /* Permanent failure */
|
||
|
+#define JOURNAL_DISK __cpu_to_le32(0x2000000) /* Device marked as Journaling Drive */
|
||
|
__u32 status; /* 0xF0 - 0xF3 */
|
||
|
__u32 owner_cfg_num; /* which config 0,1,2... owns this disk */
|
||
|
__u32 total_blocks_hi; /* 0xF4 - 0xF5 total blocks hi */
|
||
|
@@ -155,6 +156,9 @@ struct imsm_vol {
|
||
|
#define MIGR_STATE_CHANGE 4
|
||
|
#define MIGR_REPAIR 5
|
||
|
__u8 migr_type; /* Initializing, Rebuilding, ... */
|
||
|
+#define RAIDVOL_CLEAN 0
|
||
|
+#define RAIDVOL_DIRTY 1
|
||
|
+#define RAIDVOL_DSRECORD_VALID 2
|
||
|
__u8 dirty;
|
||
|
__u8 fs_state; /* fast-sync state for CnG (0xff == disabled) */
|
||
|
__u16 verify_errors; /* number of mismatches */
|
||
|
@@ -190,7 +194,24 @@ struct imsm_dev {
|
||
|
__u16 cache_policy;
|
||
|
__u8 cng_state;
|
||
|
__u8 cng_sub_state;
|
||
|
-#define IMSM_DEV_FILLERS 10
|
||
|
+ __u16 my_vol_raid_dev_num; /* Used in Unique volume Id for this RaidDev */
|
||
|
+
|
||
|
+ /* NVM_EN */
|
||
|
+ __u8 nv_cache_mode;
|
||
|
+ __u8 nv_cache_flags;
|
||
|
+
|
||
|
+ /* Unique Volume Id of the NvCache Volume associated with this volume */
|
||
|
+ __u32 nvc_vol_orig_family_num;
|
||
|
+ __u16 nvc_vol_raid_dev_num;
|
||
|
+
|
||
|
+#define RWH_OFF 0
|
||
|
+#define RWH_DISTRIBUTED 1
|
||
|
+#define RWH_JOURNALING_DRIVE 2
|
||
|
+ __u8 rwh_policy; /* Raid Write Hole Policy */
|
||
|
+ __u8 jd_serial[MAX_RAID_SERIAL_LEN]; /* Journal Drive serial number */
|
||
|
+ __u8 filler1;
|
||
|
+
|
||
|
+#define IMSM_DEV_FILLERS 3
|
||
|
__u32 filler[IMSM_DEV_FILLERS];
|
||
|
struct imsm_vol vol;
|
||
|
} __attribute__ ((packed));
|
||
|
@@ -257,6 +278,9 @@ static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed"
|
||
|
#define UNIT_SRC_IN_CP_AREA 1 /* Source data for curr_migr_unit has
|
||
|
* already been migrated and must
|
||
|
* be recovered from checkpoint area */
|
||
|
+
|
||
|
+#define PPL_ENTRY_SPACE (128 * 1024) /* Size of the PPL, without the header */
|
||
|
+
|
||
|
struct migr_record {
|
||
|
__u32 rec_status; /* Status used to determine how to restart
|
||
|
* migration in case it aborts
|
||
|
@@ -1288,6 +1312,11 @@ static int is_failed(struct imsm_disk *disk)
|
||
|
return (disk->status & FAILED_DISK) == FAILED_DISK;
|
||
|
}
|
||
|
|
||
|
+static int is_journal(struct imsm_disk *disk)
|
||
|
+{
|
||
|
+ return (disk->status & JOURNAL_DISK) == JOURNAL_DISK;
|
||
|
+}
|
||
|
+
|
||
|
/* try to determine how much space is reserved for metadata from
|
||
|
* the last get_extents() entry on the smallest active disk,
|
||
|
* otherwise fallback to the default
|
||
|
@@ -1477,7 +1506,17 @@ static void print_imsm_dev(struct intel_super *super,
|
||
|
blocks_per_migr_unit(super, dev));
|
||
|
}
|
||
|
printf("\n");
|
||
|
- printf(" Dirty State : %s\n", dev->vol.dirty ? "dirty" : "clean");
|
||
|
+ printf(" Dirty State : %s\n", (dev->vol.dirty & RAIDVOL_DIRTY) ?
|
||
|
+ "dirty" : "clean");
|
||
|
+ printf(" RWH Policy : ");
|
||
|
+ if (dev->rwh_policy == RWH_OFF)
|
||
|
+ printf("off\n");
|
||
|
+ else if (dev->rwh_policy == RWH_DISTRIBUTED)
|
||
|
+ printf("PPL distributed\n");
|
||
|
+ else if (dev->rwh_policy == RWH_JOURNALING_DRIVE)
|
||
|
+ printf("PPL journaling drive\n");
|
||
|
+ else
|
||
|
+ printf("<unknown:%d>\n", dev->rwh_policy);
|
||
|
}
|
||
|
|
||
|
static void print_imsm_disk(struct imsm_disk *disk,
|
||
|
@@ -1496,9 +1535,10 @@ static void print_imsm_disk(struct imsm_disk *disk,
|
||
|
printf(" Disk%02d Serial : %s\n", index, str);
|
||
|
else
|
||
|
printf(" Disk Serial : %s\n", str);
|
||
|
- printf(" State :%s%s%s\n", is_spare(disk) ? " spare" : "",
|
||
|
- is_configured(disk) ? " active" : "",
|
||
|
- is_failed(disk) ? " failed" : "");
|
||
|
+ printf(" State :%s%s%s%s\n", is_spare(disk) ? " spare" : "",
|
||
|
+ is_configured(disk) ? " active" : "",
|
||
|
+ is_failed(disk) ? " failed" : "",
|
||
|
+ is_journal(disk) ? " journal" : "");
|
||
|
printf(" Id : %08x\n", __le32_to_cpu(disk->scsi_id));
|
||
|
sz = total_blocks(disk) - reserved;
|
||
|
printf(" Usable Size : %llu%s\n",
|
||
|
@@ -3114,6 +3154,15 @@ static unsigned long long imsm_component_size_aligment_check(int level,
|
||
|
return component_size;
|
||
|
}
|
||
|
|
||
|
+static unsigned long long get_ppl_sector(struct intel_super *super, int dev_idx)
|
||
|
+{
|
||
|
+ struct imsm_dev *dev = get_imsm_dev(super, dev_idx);
|
||
|
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
|
||
|
+
|
||
|
+ return pba_of_lba0(map) +
|
||
|
+ (num_data_stripes(map) * map->blocks_per_strip);
|
||
|
+}
|
||
|
+
|
||
|
static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
|
||
|
{
|
||
|
struct intel_super *super = st->sb;
|
||
|
@@ -3140,7 +3189,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
|
||
|
info->array.utime = 0;
|
||
|
info->array.chunk_size =
|
||
|
__le16_to_cpu(map_to_analyse->blocks_per_strip) << 9;
|
||
|
- info->array.state = !dev->vol.dirty;
|
||
|
+ info->array.state = !(dev->vol.dirty & RAIDVOL_DIRTY);
|
||
|
info->custom_array_size = __le32_to_cpu(dev->size_high);
|
||
|
info->custom_array_size <<= 32;
|
||
|
info->custom_array_size |= __le32_to_cpu(dev->size_low);
|
||
|
@@ -3221,10 +3270,20 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
|
||
|
memset(info->uuid, 0, sizeof(info->uuid));
|
||
|
info->recovery_start = MaxSector;
|
||
|
|
||
|
+ if (info->array.level == 5 && dev->rwh_policy == RWH_DISTRIBUTED) {
|
||
|
+ info->consistency_policy = CONSISTENCY_POLICY_PPL;
|
||
|
+ info->ppl_sector = get_ppl_sector(super, super->current_vol);
|
||
|
+ info->ppl_size = (PPL_HEADER_SIZE + PPL_ENTRY_SPACE) >> 9;
|
||
|
+ } else if (info->array.level <= 0) {
|
||
|
+ info->consistency_policy = CONSISTENCY_POLICY_NONE;
|
||
|
+ } else {
|
||
|
+ info->consistency_policy = CONSISTENCY_POLICY_RESYNC;
|
||
|
+ }
|
||
|
+
|
||
|
info->reshape_progress = 0;
|
||
|
info->resync_start = MaxSector;
|
||
|
if ((map_to_analyse->map_state == IMSM_T_STATE_UNINITIALIZED ||
|
||
|
- dev->vol.dirty) &&
|
||
|
+ !(info->array.state & 1)) &&
|
||
|
imsm_reshape_blocks_arrays_changes(super) == 0) {
|
||
|
info->resync_start = 0;
|
||
|
}
|
||
|
@@ -3451,7 +3510,8 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
|
||
|
* found the 'most fresh' version of the metadata
|
||
|
*/
|
||
|
info->disk.state |= is_failed(disk) ? (1 << MD_DISK_FAULTY) : 0;
|
||
|
- info->disk.state |= is_spare(disk) ? 0 : (1 << MD_DISK_SYNC);
|
||
|
+ info->disk.state |= (is_spare(disk) || is_journal(disk)) ?
|
||
|
+ 0 : (1 << MD_DISK_SYNC);
|
||
|
}
|
||
|
|
||
|
/* only call uuid_from_super_imsm when this disk is part of a populated container,
|
||
|
@@ -3906,7 +3966,7 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd)
|
||
|
*/
|
||
|
if (is_failed(&dl->disk))
|
||
|
dl->index = -2;
|
||
|
- else if (is_spare(&dl->disk))
|
||
|
+ else if (is_spare(&dl->disk) || is_journal(&dl->disk))
|
||
|
dl->index = -1;
|
||
|
}
|
||
|
|
||
|
@@ -5303,6 +5363,20 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
|
||
|
}
|
||
|
mpb->num_raid_devs++;
|
||
|
|
||
|
+ if (s->consistency_policy == UnSet ||
|
||
|
+ s->consistency_policy == CONSISTENCY_POLICY_RESYNC ||
|
||
|
+ s->consistency_policy == CONSISTENCY_POLICY_NONE) {
|
||
|
+ dev->rwh_policy = RWH_OFF;
|
||
|
+ } else if (s->consistency_policy == CONSISTENCY_POLICY_PPL) {
|
||
|
+ dev->rwh_policy = RWH_DISTRIBUTED;
|
||
|
+ } else {
|
||
|
+ free(dev);
|
||
|
+ free(dv);
|
||
|
+ pr_err("imsm does not support consistency policy %s\n",
|
||
|
+ map_num(consistency_policies, s->consistency_policy));
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
dv->dev = dev;
|
||
|
dv->index = super->current_vol;
|
||
|
dv->next = super->devlist;
|
||
|
@@ -5927,11 +6001,146 @@ static int mgmt_disk(struct supertype *st)
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
+#endif
|
||
|
+
|
||
|
+__u32 crc32c_le(__u32 crc, unsigned char const *p, size_t len);
|
||
|
+
|
||
|
+static int write_init_ppl_imsm(struct supertype *st, struct mdinfo *info, int fd)
|
||
|
+{
|
||
|
+ struct intel_super *super = st->sb;
|
||
|
+ void *buf;
|
||
|
+ struct ppl_header *ppl_hdr;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ ret = posix_memalign(&buf, 4096, PPL_HEADER_SIZE);
|
||
|
+ if (ret) {
|
||
|
+ pr_err("Failed to allocate PPL header buffer\n");
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(buf, 0, PPL_HEADER_SIZE);
|
||
|
+ ppl_hdr = buf;
|
||
|
+ memset(ppl_hdr->reserved, 0xff, PPL_HDR_RESERVED);
|
||
|
+ ppl_hdr->signature = __cpu_to_le32(super->anchor->orig_family_num);
|
||
|
+ ppl_hdr->checksum = __cpu_to_le32(~crc32c_le(~0, buf, PPL_HEADER_SIZE));
|
||
|
+
|
||
|
+ if (lseek64(fd, info->ppl_sector * 512, SEEK_SET) < 0) {
|
||
|
+ ret = errno;
|
||
|
+ perror("Failed to seek to PPL header location");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!ret && write(fd, buf, PPL_HEADER_SIZE) != PPL_HEADER_SIZE) {
|
||
|
+ ret = errno;
|
||
|
+ perror("Write PPL header failed");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!ret)
|
||
|
+ fsync(fd);
|
||
|
+
|
||
|
+ free(buf);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static int validate_ppl_imsm(struct supertype *st, struct mdinfo *info,
|
||
|
+ struct mdinfo *disk)
|
||
|
+{
|
||
|
+ struct intel_super *super = st->sb;
|
||
|
+ struct dl *d;
|
||
|
+ void *buf;
|
||
|
+ int ret = 0;
|
||
|
+ struct ppl_header *ppl_hdr;
|
||
|
+ __u32 crc;
|
||
|
+ struct imsm_dev *dev;
|
||
|
+ struct imsm_map *map;
|
||
|
+ __u32 idx;
|
||
|
+
|
||
|
+ if (disk->disk.raid_disk < 0)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (posix_memalign(&buf, 4096, PPL_HEADER_SIZE)) {
|
||
|
+ pr_err("Failed to allocate PPL header buffer\n");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ dev = get_imsm_dev(super, info->container_member);
|
||
|
+ map = get_imsm_map(dev, MAP_X);
|
||
|
+ idx = get_imsm_disk_idx(dev, disk->disk.raid_disk, MAP_X);
|
||
|
+ d = get_imsm_dl_disk(super, idx);
|
||
|
+
|
||
|
+ if (!d || d->index < 0 || is_failed(&d->disk))
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ if (lseek64(d->fd, info->ppl_sector * 512, SEEK_SET) < 0) {
|
||
|
+ perror("Failed to seek to PPL header location");
|
||
|
+ ret = -1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (read(d->fd, buf, PPL_HEADER_SIZE) != PPL_HEADER_SIZE) {
|
||
|
+ perror("Read PPL header failed");
|
||
|
+ ret = -1;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ppl_hdr = buf;
|
||
|
+
|
||
|
+ crc = __le32_to_cpu(ppl_hdr->checksum);
|
||
|
+ ppl_hdr->checksum = 0;
|
||
|
+
|
||
|
+ if (crc != ~crc32c_le(~0, buf, PPL_HEADER_SIZE)) {
|
||
|
+ dprintf("Wrong PPL header checksum on %s\n",
|
||
|
+ d->devname);
|
||
|
+ ret = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!ret && (__le32_to_cpu(ppl_hdr->signature) !=
|
||
|
+ super->anchor->orig_family_num)) {
|
||
|
+ dprintf("Wrong PPL header signature on %s\n",
|
||
|
+ d->devname);
|
||
|
+ ret = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ free(buf);
|
||
|
+
|
||
|
+ if (ret == 1 && map->map_state == IMSM_T_STATE_UNINITIALIZED)
|
||
|
+ return st->ss->write_init_ppl(st, info, d->fd);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+#ifndef MDASSEMBLE
|
||
|
+
|
||
|
+static int write_init_ppl_imsm_all(struct supertype *st, struct mdinfo *info)
|
||
|
+{
|
||
|
+ struct intel_super *super = st->sb;
|
||
|
+ struct dl *d;
|
||
|
+ int ret = 0;
|
||
|
+
|
||
|
+ if (info->consistency_policy != CONSISTENCY_POLICY_PPL ||
|
||
|
+ info->array.level != 5)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ for (d = super->disks; d ; d = d->next) {
|
||
|
+ if (d->index < 0 || is_failed(&d->disk))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ ret = st->ss->write_init_ppl(st, info, d->fd);
|
||
|
+ if (ret)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
|
||
|
static int write_init_super_imsm(struct supertype *st)
|
||
|
{
|
||
|
struct intel_super *super = st->sb;
|
||
|
int current_vol = super->current_vol;
|
||
|
+ int rv = 0;
|
||
|
+ struct mdinfo info;
|
||
|
+
|
||
|
+ getinfo_super_imsm(st, &info, NULL);
|
||
|
|
||
|
/* we are done with current_vol reset it to point st at the container */
|
||
|
super->current_vol = -1;
|
||
|
@@ -5939,24 +6148,29 @@ static int write_init_super_imsm(struct supertype *st)
|
||
|
if (st->update_tail) {
|
||
|
/* queue the recently created array / added disk
|
||
|
* as a metadata update */
|
||
|
- int rv;
|
||
|
|
||
|
/* determine if we are creating a volume or adding a disk */
|
||
|
if (current_vol < 0) {
|
||
|
/* in the mgmt (add/remove) disk case we are running
|
||
|
* in mdmon context, so don't close fd's
|
||
|
*/
|
||
|
- return mgmt_disk(st);
|
||
|
- } else
|
||
|
- rv = create_array(st, current_vol);
|
||
|
-
|
||
|
- return rv;
|
||
|
+ rv = mgmt_disk(st);
|
||
|
+ } else {
|
||
|
+ rv = write_init_ppl_imsm_all(st, &info);
|
||
|
+ if (!rv)
|
||
|
+ rv = create_array(st, current_vol);
|
||
|
+ }
|
||
|
} else {
|
||
|
struct dl *d;
|
||
|
for (d = super->disks; d; d = d->next)
|
||
|
Kill(d->devname, NULL, 0, -1, 1);
|
||
|
- return write_super_imsm(st, 1);
|
||
|
+ if (current_vol >= 0)
|
||
|
+ rv = write_init_ppl_imsm_all(st, &info);
|
||
|
+ if (!rv)
|
||
|
+ rv = write_super_imsm(st, 1);
|
||
|
}
|
||
|
+
|
||
|
+ return rv;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
@@ -7375,7 +7589,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
|
||
|
*
|
||
|
* FIXME handle dirty degraded
|
||
|
*/
|
||
|
- if ((skip || recovery_start == 0) && !dev->vol.dirty)
|
||
|
+ if ((skip || recovery_start == 0) &&
|
||
|
+ !(dev->vol.dirty & RAIDVOL_DIRTY))
|
||
|
this->resync_start = MaxSector;
|
||
|
if (skip)
|
||
|
continue;
|
||
|
@@ -7410,9 +7625,12 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
|
||
|
info_d->component_size =
|
||
|
num_data_stripes(map) *
|
||
|
map->blocks_per_strip;
|
||
|
+ info_d->ppl_sector = this->ppl_sector;
|
||
|
+ info_d->ppl_size = this->ppl_size;
|
||
|
} else {
|
||
|
info_d->component_size = blocks_per_member(map);
|
||
|
}
|
||
|
+ info_d->consistency_policy = this->consistency_policy;
|
||
|
|
||
|
info_d->bb.supported = 1;
|
||
|
get_volume_badblocks(super->bbm_log, ord_to_idx(ord),
|
||
|
@@ -7928,12 +8146,16 @@ mark_checkpoint:
|
||
|
|
||
|
skip_mark_checkpoint:
|
||
|
/* mark dirty / clean */
|
||
|
- if (dev->vol.dirty != !consistent) {
|
||
|
+ if (((dev->vol.dirty & RAIDVOL_DIRTY) && consistent) ||
|
||
|
+ (!(dev->vol.dirty & RAIDVOL_DIRTY) && !consistent)) {
|
||
|
dprintf("imsm: mark '%s'\n", consistent ? "clean" : "dirty");
|
||
|
- if (consistent)
|
||
|
- dev->vol.dirty = 0;
|
||
|
- else
|
||
|
- dev->vol.dirty = 1;
|
||
|
+ if (consistent) {
|
||
|
+ dev->vol.dirty = RAIDVOL_CLEAN;
|
||
|
+ } else {
|
||
|
+ dev->vol.dirty = RAIDVOL_DIRTY;
|
||
|
+ if (dev->rwh_policy == RWH_DISTRIBUTED)
|
||
|
+ dev->vol.dirty |= RAIDVOL_DSRECORD_VALID;
|
||
|
+ }
|
||
|
super->updates_pending++;
|
||
|
}
|
||
|
|
||
|
@@ -8445,6 +8667,11 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
|
||
|
di->component_size = a->info.component_size;
|
||
|
di->container_member = inst;
|
||
|
di->bb.supported = 1;
|
||
|
+ if (dev->rwh_policy == RWH_DISTRIBUTED) {
|
||
|
+ di->consistency_policy = CONSISTENCY_POLICY_PPL;
|
||
|
+ di->ppl_sector = get_ppl_sector(super, inst);
|
||
|
+ di->ppl_size = (PPL_HEADER_SIZE + PPL_ENTRY_SPACE) >> 9;
|
||
|
+ }
|
||
|
super->random = random32();
|
||
|
di->next = rv;
|
||
|
rv = di;
|
||
|
@@ -11600,6 +11827,9 @@ struct superswitch super_imsm = {
|
||
|
.container_content = container_content_imsm,
|
||
|
.validate_container = validate_container_imsm,
|
||
|
|
||
|
+ .write_init_ppl = write_init_ppl_imsm,
|
||
|
+ .validate_ppl = validate_ppl_imsm,
|
||
|
+
|
||
|
.external = 1,
|
||
|
.name = "imsm",
|
||
|
|
||
|
diff --git a/sysfs.c b/sysfs.c
|
||
|
index 53589a7..2a91ba0 100644
|
||
|
--- a/sysfs.c
|
||
|
+++ b/sysfs.c
|
||
|
@@ -689,6 +689,16 @@ int sysfs_set_array(struct mdinfo *info, int vers)
|
||
|
* once the reshape completes.
|
||
|
*/
|
||
|
}
|
||
|
+
|
||
|
+ if (info->consistency_policy == CONSISTENCY_POLICY_PPL) {
|
||
|
+ if (sysfs_set_str(info, NULL, "consistency_policy",
|
||
|
+ map_num(consistency_policies,
|
||
|
+ info->consistency_policy))) {
|
||
|
+ pr_err("This kernel does not support PPL\n");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
@@ -720,6 +730,10 @@ int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd, int resume)
|
||
|
rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
|
||
|
rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
|
||
|
if (sra->array.level != LEVEL_CONTAINER) {
|
||
|
+ if (sd->consistency_policy == CONSISTENCY_POLICY_PPL) {
|
||
|
+ rv |= sysfs_set_num(sra, sd, "ppl_sector", sd->ppl_sector);
|
||
|
+ rv |= sysfs_set_num(sra, sd, "ppl_size", sd->ppl_size);
|
||
|
+ }
|
||
|
if (sd->recovery_start == MaxSector)
|
||
|
/* This can correctly fail if array isn't started,
|
||
|
* yet, so just ignore status for now.
|