]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - super-intel.c
Introduce pr_err for printing error messages.
[thirdparty/mdadm.git] / super-intel.c
index dad4c4d33bb0914453eb9a3d5e8012a15986fef1..2ecb9589c196ff8d0abf6c0415c41d70e35855a4 100644 (file)
@@ -295,7 +295,7 @@ struct md_list {
        struct md_list *next;
 };
 
-#define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
+#define pr_vrb(fmt, arg...) (void) (verbose && pr_err(fmt, ##arg))
 
 static __u8 migr_type(struct imsm_dev *dev)
 {
@@ -405,6 +405,7 @@ struct extent {
 enum imsm_reshape_type {
        CH_TAKEOVER,
        CH_MIGRATION,
+       CH_ARRAY_SIZE,
 };
 
 /* definition of messages passed to imsm_process_update */
@@ -418,6 +419,7 @@ enum imsm_update_type {
        update_reshape_migration,
        update_takeover,
        update_general_migration_checkpoint,
+       update_size_change,
 };
 
 struct imsm_update_activate_spare {
@@ -470,6 +472,12 @@ struct imsm_update_reshape_migration {
        int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
 };
 
+struct imsm_update_size_change {
+       enum imsm_update_type type;
+       int subdev;
+       long long new_size;
+};
+
 struct imsm_update_general_migration_checkpoint {
        enum imsm_update_type type;
        __u32 curr_migr_unit;
@@ -910,6 +918,7 @@ static unsigned long long blocks_per_member(struct imsm_map *map)
        return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi);
 }
 
+#ifndef MDASSEMBLE
 static unsigned long long num_data_stripes(struct imsm_map *map)
 {
        if (map == NULL)
@@ -921,6 +930,7 @@ static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
 {
        split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
 }
+#endif
 
 static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
 {
@@ -1331,7 +1341,7 @@ static int imsm_check_attributes(__u32 attributes)
 
        not_supported &= attributes;
        if (not_supported) {
-               fprintf(stderr, Name "(IMSM): Unsupported attributes : %x\n",
+               pr_err("(IMSM): Unsupported attributes : %x\n",
                        (unsigned)__le32_to_cpu(not_supported));
                if (not_supported & MPB_ATTRIB_CHECKSUM_VERIFY) {
                        dprintf("\t\tMPB_ATTRIB_CHECKSUM_VERIFY \n");
@@ -1563,7 +1573,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 
        if (port_count > (int)sizeof(port_mask) * 8) {
                if (verbose)
-                       fprintf(stderr, Name ": port_count %d out of range\n", port_count);
+                       pr_err("port_count %d out of range\n", port_count);
                return 2;
        }
 
@@ -1596,14 +1606,14 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                /* retrieve the scsi device type */
                if (asprintf(&device, "/sys/dev/block/%d:%d/device/xxxxxxx", major, minor) < 0) {
                        if (verbose)
-                               fprintf(stderr, Name ": failed to allocate 'device'\n");
+                               pr_err("failed to allocate 'device'\n");
                        err = 2;
                        break;
                }
                sprintf(device, "/sys/dev/block/%d:%d/device/type", major, minor);
                if (load_sys(device, buf) != 0) {
                        if (verbose)
-                               fprintf(stderr, Name ": failed to read device type for %s\n",
+                               pr_err("failed to read device type for %s\n",
                                        path);
                        err = 2;
                        free(device);
@@ -1656,7 +1666,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                c = strchr(&path[hba_len], '/');
                if (!c) {
                        if (verbose)
-                               fprintf(stderr, Name ": %s - invalid path name\n", path + hba_len);
+                               pr_err("%s - invalid path name\n", path + hba_len);
                        err = 2;
                        break;
                }
@@ -1666,7 +1676,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
                else {
                        if (verbose) {
                                *c = '/'; /* repair the full string */
-                               fprintf(stderr, Name ": failed to determine port number for %s\n",
+                               pr_err("failed to determine port number for %s\n",
                                        path);
                        }
                        err = 2;
@@ -1715,7 +1725,7 @@ static int ahci_enumerate_ports(const char *hba_path, int port_count, int host_b
 static void print_found_intel_controllers(struct sys_dev *elem)
 {
        for (; elem; elem = elem->next) {
-               fprintf(stderr, Name ": found Intel(R) ");
+               pr_err("found Intel(R) ");
                if (elem->type == SYS_DEV_SATA)
                        fprintf(stderr, "SATA ");
                else if (elem->type == SYS_DEV_SAS)
@@ -1783,12 +1793,13 @@ static void print_imsm_capability(const struct imsm_orom *orom)
               imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "",
               imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "",
               imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : "");
-       printf("      Max Disks : %d\n", orom->tds);
-       printf("    Max Volumes : %d\n", orom->vpa);
        printf("    2TB volumes :%s supported\n",
               (orom->attr & IMSM_OROM_ATTR_2TB)?"":" not");
        printf("      2TB disks :%s supported\n",
               (orom->attr & IMSM_OROM_ATTR_2TB_DISK)?"":" not");
+       printf("      Max Disks : %d\n", orom->tds);
+       printf("    Max Volumes : %d per array, %d per controller\n",
+              orom->vpa, orom->vphba);
        return;
 }
 
@@ -1831,7 +1842,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
        list = find_intel_devices();
        if (!list) {
                if (verbose)
-                       fprintf(stderr, Name ": no active Intel(R) RAID "
+                       pr_err("no active Intel(R) RAID "
                                "controller found.\n");
                free_sys_dev(&list);
                return 2;
@@ -1841,7 +1852,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
        for (hba = list; hba; hba = hba->next) {
                orom = find_imsm_capability(hba->type);
                if (!orom)
-                       fprintf(stderr, Name ": imsm capabilities not found for controller: %s (type %s)\n",
+                       pr_err("imsm capabilities not found for controller: %s (type %s)\n",
                                hba->path, get_sys_dev_type(hba->type));
                else
                        print_imsm_capability(orom);
@@ -1855,7 +1866,7 @@ static int detail_platform_imsm(int verbose, int enumerate_only)
                        host_base = ahci_get_port_count(hba->path, &port_count);
                        if (ahci_enumerate_ports(hba->path, port_count, host_base, verbose)) {
                                if (verbose)
-                                       fprintf(stderr, Name ": failed to enumerate "
+                                       pr_err("failed to enumerate "
                                                "ports on SATA controller at %s.", hba->pci_id);
                                result |= 2;
                        }
@@ -2031,9 +2042,11 @@ static __u8 imsm_num_data_members(struct imsm_dev *dev, int second_map)
 
        switch (get_imsm_raid_level(map)) {
        case 0:
+               return map->num_members;
+               break;
        case 1:
        case 10:
-               return map->num_members;
+               return map->num_members/2;
        case 5:
                return map->num_members - 1;
        default:
@@ -2170,16 +2183,14 @@ static int read_imsm_migr_rec(int fd, struct intel_super *super)
 
        get_dev_size(fd, NULL, &dsize);
        if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
-               fprintf(stderr,
-                       Name ": Cannot seek to anchor block: %s\n",
-                       strerror(errno));
+               pr_err("Cannot seek to anchor block: %s\n",
+                      strerror(errno));
                goto out;
        }
        if (read(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
                                                            MIGR_REC_BUF_SIZE) {
-               fprintf(stderr,
-                       Name ": Cannot read migr record block: %s\n",
-                       strerror(errno));
+               pr_err("Cannot read migr record block: %s\n",
+                      strerror(errno));
                goto out;
        }
        ret_val = 0;
@@ -2376,16 +2387,14 @@ static int write_imsm_migr_rec(struct supertype *st)
                        continue;
                get_dev_size(fd, NULL, &dsize);
                if (lseek64(fd, dsize - MIGR_REC_POSITION, SEEK_SET) < 0) {
-                       fprintf(stderr,
-                               Name ": Cannot seek to anchor block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot seek to anchor block: %s\n",
+                              strerror(errno));
                        goto out;
                }
                if (write(fd, super->migr_rec_buf, MIGR_REC_BUF_SIZE) !=
                                                            MIGR_REC_BUF_SIZE) {
-                       fprintf(stderr,
-                               Name ": Cannot write migr record block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot write migr record block: %s\n",
+                              strerror(errno));
                        goto out;
                }
                close(fd);
@@ -2443,6 +2452,32 @@ int imsm_reshape_blocks_arrays_changes(struct intel_super *super)
        }
        return rv;
 }
+static unsigned long long imsm_component_size_aligment_check(int level,
+                                             int chunk_size,
+                                             unsigned long long component_size)
+{
+       unsigned int component_size_alligment;
+
+       /* check component size aligment
+       */
+       component_size_alligment = component_size % (chunk_size/512);
+
+       dprintf("imsm_component_size_aligment_check(Level: %i, "
+               "chunk_size = %i, component_size = %llu), "
+               "component_size_alligment = %u\n",
+               level, chunk_size, component_size,
+               component_size_alligment);
+
+       if (component_size_alligment && (level != 1) && (level != UnSet)) {
+               dprintf("imsm: reported component size alligned from %llu ",
+                       component_size);
+               component_size -= component_size_alligment;
+               dprintf("to %llu (%i).\n",
+                       component_size, component_size_alligment);
+       }
+
+       return component_size;
+}
 
 static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
 {
@@ -2454,7 +2489,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        struct imsm_map *map_to_analyse = map;
        struct dl *dl;
        char *devname;
-       unsigned int component_size_alligment;
        int map_disks = info->array.raid_disks;
 
        memset(info, 0, sizeof(*info));
@@ -2537,19 +2571,10 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
        info->data_offset         = pba_of_lba0(map_to_analyse);
        info->component_size      = blocks_per_member(map_to_analyse);
 
-       /* check component size aligment
-        */
-       component_size_alligment =
-               info->component_size % (info->array.chunk_size/512);
-
-       if (component_size_alligment &&
-           (info->array.level != 1) && (info->array.level != UnSet)) {
-               dprintf("imsm: reported component size alligned from %llu ",
-                       info->component_size);
-               info->component_size -= component_size_alligment;
-               dprintf("to %llu (%i).\n",
-                       info->component_size, component_size_alligment);
-       }
+       info->component_size = imsm_component_size_aligment_check(
+                                                       info->array.level,
+                                                       info->array.chunk_size,
+                                                       info->component_size);
 
        memset(info->uuid, 0, sizeof(info->uuid));
        info->recovery_start = MaxSector;
@@ -2822,7 +2847,7 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
        dl = super->disks;
        mddev = malloc(sizeof(*mddev));
        if (!mddev) {
-               fprintf(stderr, Name ": Failed to allocate memory.\n");
+               pr_err("Failed to allocate memory.\n");
                return NULL;
        }
        memset(mddev, 0, sizeof(*mddev));
@@ -2831,7 +2856,7 @@ struct mdinfo *getinfo_super_disks_imsm(struct supertype *st)
                disk = &dl->disk;
                tmp = malloc(sizeof(*tmp));
                if (!tmp) {
-                       fprintf(stderr, Name ": Failed to allocate memory.\n");
+                       pr_err("Failed to allocate memory.\n");
                        if (mddev)
                                sysfs_free(mddev);
                        return NULL;
@@ -3120,18 +3145,16 @@ static int imsm_read_serial(int fd, char *devname,
 
        if (rv != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to retrieve serial for %s\n",
-                               devname);
+                       pr_err("Failed to retrieve serial for %s\n",
+                              devname);
                return rv;
        }
 
        rsp_len = scsi_serial[3];
        if (!rsp_len) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to retrieve serial for %s\n",
-                               devname);
+                       pr_err("Failed to retrieve serial for %s\n",
+                              devname);
                return 2;
        }
        rsp_buf = (char *) &scsi_serial[4];
@@ -3223,9 +3246,8 @@ load_imsm_disk(int fd, struct intel_super *super, char *devname, int keep_fd)
        dl = calloc(1, sizeof(*dl));
        if (!dl) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": failed to allocate disk buffer for %s\n",
-                               devname);
+                       pr_err("failed to allocate disk buffer for %s\n",
+                              devname);
                return 2;
        }
 
@@ -3476,40 +3498,35 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        get_dev_size(fd, NULL, &dsize);
        if (dsize < 1024) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": %s: device to small for imsm\n",
-                               devname);
+                       pr_err("%s: device to small for imsm\n",
+                              devname);
                return 1;
        }
 
        if (lseek64(fd, dsize - (512 * 2), SEEK_SET) < 0) {
                if (devname)
-                       fprintf(stderr, Name
-                               ": Cannot seek to anchor block on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot seek to anchor block on %s: %s\n",
+                              devname, strerror(errno));
                return 1;
        }
 
        if (posix_memalign((void**)&anchor, 512, 512) != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to allocate imsm anchor buffer"
-                               " on %s\n", devname);
+                       pr_err("Failed to allocate imsm anchor buffer"
+                              " on %s\n", devname);
                return 1;
        }
        if (read(fd, anchor, 512) != 512) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Cannot read anchor block on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot read anchor block on %s: %s\n",
+                              devname, strerror(errno));
                free(anchor);
                return 1;
        }
 
        if (strncmp((char *) anchor->sig, MPB_SIGNATURE, MPB_SIG_LEN) != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": no IMSM anchor on %s\n", devname);
+                       pr_err("no IMSM anchor on %s\n", devname);
                free(anchor);
                return 2;
        }
@@ -3522,9 +3539,8 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        super->len = ROUND_UP(anchor->mpb_size, 512);
        if (posix_memalign(&super->buf, 512, super->len) != 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": unable to allocate %zu byte mpb buffer\n",
-                               super->len);
+                       pr_err("unable to allocate %zu byte mpb buffer\n",
+                              super->len);
                free(anchor);
                return 2;
        }
@@ -3534,8 +3550,7 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        free(anchor);
 
        if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
-               fprintf(stderr, Name
-                       ": %s could not allocate migr_rec buffer\n", __func__);
+               pr_err("%s could not allocate migr_rec buffer\n", __func__);
                free(super->buf);
                return 2;
        }
@@ -3545,11 +3560,10 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
                check_sum = __gen_imsm_checksum(super->anchor);
                if (check_sum != __le32_to_cpu(super->anchor->check_sum)) {
                        if (devname)
-                               fprintf(stderr,
-                                       Name ": IMSM checksum %x != %x on %s\n",
-                                       check_sum,
-                                       __le32_to_cpu(super->anchor->check_sum),
-                                       devname);
+                               pr_err("IMSM checksum %x != %x on %s\n",
+                                      check_sum,
+                                      __le32_to_cpu(super->anchor->check_sum),
+                                      devname);
                        return 2;
                }
 
@@ -3559,27 +3573,24 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
        /* read the extended mpb */
        if (lseek64(fd, dsize - (512 * (2 + sectors)), SEEK_SET) < 0) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Cannot seek to extended mpb on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot seek to extended mpb on %s: %s\n",
+                              devname, strerror(errno));
                return 1;
        }
 
        if ((unsigned)read(fd, super->buf + 512, super->len - 512) != super->len - 512) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Cannot read extended mpb on %s: %s\n",
-                               devname, strerror(errno));
+                       pr_err("Cannot read extended mpb on %s: %s\n",
+                              devname, strerror(errno));
                return 2;
        }
 
        check_sum = __gen_imsm_checksum(super->anchor);
        if (check_sum != __le32_to_cpu(super->anchor->check_sum)) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": IMSM checksum %x != %x on %s\n",
-                               check_sum, __le32_to_cpu(super->anchor->check_sum),
-                               devname);
+                       pr_err("IMSM checksum %x != %x on %s\n",
+                              check_sum, __le32_to_cpu(super->anchor->check_sum),
+                              devname);
                return 3;
        }
 
@@ -3744,9 +3755,8 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
        hba_name = find_disk_attached_hba(fd, NULL);
        if (!hba_name) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": %s is not attached to Intel(R) RAID controller.\n",
-                               devname);
+                       pr_err("%s is not attached to Intel(R) RAID controller.\n",
+                              devname);
                return 1;
        }
        rv = attach_hba_to_super(super, hba_name);
@@ -3754,7 +3764,7 @@ static int find_intel_hba_capability(int fd, struct intel_super *super, char *de
                if (devname) {
                        struct intel_hba *hba = super->hba;
 
-                       fprintf(stderr, Name ": %s is attached to Intel(R) %s RAID "
+                       pr_err("%s is attached to Intel(R) %s RAID "
                                "controller (%s),\n"
                                "    but the container is assigned to Intel(R) "
                                "%s RAID controller (",
@@ -4079,6 +4089,8 @@ imsm_thunderdome(struct intel_super **super_list, int len)
                if (s == champion)
                        continue;
 
+               mpb->attributes |= s->anchor->attributes & MPB_ATTRIB_2TB_DISK;
+
                for (i = 0; i < mpb->num_disks; i++) {
                        struct imsm_disk *disk;
 
@@ -4188,7 +4200,7 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
 
        /* Check migration compatibility */
        if ((err == 0) && (check_mpb_migr_compatibility(super) != 0)) {
-               fprintf(stderr, Name ": Unsupported migration detected");
+               pr_err("Unsupported migration detected");
                if (devname)
                        fprintf(stderr, " on %s\n", devname);
                else
@@ -4241,7 +4253,7 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
                        int lmax = 0;
                        int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
                        if (fd < 0) {
-                               fprintf(stderr, Name ": cannot open device %s: %s\n",
+                               pr_err("cannot open device %s: %s\n",
                                        tmpdev->devname, strerror(errno));
                                err = 8;
                                goto error;
@@ -4322,7 +4334,7 @@ static int get_super_block(struct intel_super **super_list, int devnum, char *de
        } else {
                if (s)
                        free(s);
-               if (dfd)
+               if (dfd >= 0)
                        close(dfd);
        }
        if ((dfd >= 0) && (!keep_fd))
@@ -4383,9 +4395,8 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 
        super = alloc_super();
        if (!super) {
-               fprintf(stderr,
-                       Name ": malloc of %zu failed.\n",
-                       sizeof(*super));
+               pr_err("malloc of %zu failed.\n",
+                      sizeof(*super));
                return 1;
        }
        /* Load hba and capabilities if they exist.
@@ -4396,8 +4407,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        /* no orom/efi or non-intel hba of the disk */
        if ((rv != 0) && (st->ignore_hw_compat == 0)) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": No OROM/EFI properties for %s\n", devname);
+                       pr_err("No OROM/EFI properties for %s\n", devname);
                free_imsm(super);
                return 2;
        }
@@ -4405,9 +4415,8 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 
        if (rv) {
                if (devname)
-                       fprintf(stderr,
-                               Name ": Failed to load all information "
-                               "sections on %s\n", devname);
+                       pr_err("Failed to load all information "
+                              "sections on %s\n", devname);
                free_imsm(super);
                return rv;
        }
@@ -4423,8 +4432,7 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
        if (load_imsm_migr_rec(super, NULL) == 0) {
                /* Check for unsupported migration features */
                if (check_mpb_migr_compatibility(super) != 0) {
-                       fprintf(stderr,
-                               Name ": Unsupported migration detected");
+                       pr_err("Unsupported migration detected");
                        if (devname)
                                fprintf(stderr, " on %s\n", devname);
                        else
@@ -4518,7 +4526,7 @@ static int check_name(struct intel_super *super, char *name, int quiet)
        }
 
        if (reason && !quiet)
-               fprintf(stderr, Name ": imsm volume name %s\n", reason);
+               pr_err("imsm volume name %s\n", reason);
 
        return !reason;
 }
@@ -4543,7 +4551,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        unsigned long long num_data_stripes;
 
        if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
-               fprintf(stderr, Name": This imsm-container already has the "
+               pr_err("This imsm-container already has the "
                        "maximum of %d volumes\n", super->orom->vpa);
                return 0;
        }
@@ -4556,14 +4564,13 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                size_t size_round = ROUND_UP(size_new, 512);
 
                if (posix_memalign(&mpb_new, 512, size_round) != 0) {
-                       fprintf(stderr, Name": could not allocate new mpb\n");
+                       pr_err("could not allocate new mpb\n");
                        return 0;
                }
                if (posix_memalign(&super->migr_rec_buf, 512,
                                   MIGR_REC_BUF_SIZE) != 0) {
-                       fprintf(stderr, Name
-                               ": %s could not allocate migr_rec buffer\n",
-                               __func__);
+                       pr_err("%s could not allocate migr_rec buffer\n",
+                              __func__);
                        free(super->buf);
                        free(super);
                        free(mpb_new);
@@ -4607,7 +4614,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                for (d = super->missing; d; d = d->next)
                        missing++;
                if (info->failed_disks > missing) {
-                       fprintf(stderr, Name": unable to add 'missing' disk to container\n");
+                       pr_err("unable to add 'missing' disk to container\n");
                        return 0;
                }
        }
@@ -4616,13 +4623,13 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
                return 0;
        dv = malloc(sizeof(*dv));
        if (!dv) {
-               fprintf(stderr, Name ": failed to allocate device list entry\n");
+               pr_err("failed to allocate device list entry\n");
                return 0;
        }
        dev = calloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
        if (!dev) {
                free(dv);
-               fprintf(stderr, Name": could not allocate raid device\n");
+               pr_err("could not allocate raid device\n");
                return 0;
        }
 
@@ -4656,7 +4663,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
        if (info->level == 1 && info->raid_disks > 2) {
                free(dev);
                free(dv);
-               fprintf(stderr, Name": imsm does not support more than 2 disks"
+               pr_err("imsm does not support more than 2 disks"
                                "in a raid1 volume\n");
                return 0;
        }
@@ -4723,13 +4730,11 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
                super = NULL;
        }
        if (!super) {
-               fprintf(stderr, Name
-                       ": %s could not allocate superblock\n", __func__);
+               pr_err("%s could not allocate superblock\n", __func__);
                return 0;
        }
        if (posix_memalign(&super->migr_rec_buf, 512, MIGR_REC_BUF_SIZE) != 0) {
-               fprintf(stderr, Name
-                       ": %s could not allocate migr_rec buffer\n", __func__);
+               pr_err("%s could not allocate migr_rec buffer\n", __func__);
                free(super->buf);
                free(super);
                return 0;
@@ -4770,7 +4775,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        map = get_imsm_map(dev, MAP_0);
 
        if (! (dk->state & (1<<MD_DISK_SYNC))) {
-               fprintf(stderr, Name ": %s: Cannot add spare devices to IMSM volume\n",
+               pr_err("%s: Cannot add spare devices to IMSM volume\n",
                        devname);
                return 1;
        }
@@ -4790,7 +4795,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        }
 
        if (!dl) {
-               fprintf(stderr, Name ": %s is not a member of the same container\n", devname);
+               pr_err("%s is not a member of the same container\n", devname);
                return 1;
        }
 
@@ -4803,7 +4808,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
        slot = get_imsm_disk_slot(map, dl->index);
        if (slot >= 0 &&
            (get_imsm_ord_tbl_ent(dev, slot, MAP_X) & IMSM_ORD_REBUILD) == 0) {
-               fprintf(stderr, Name ": %s has been included in this array twice\n",
+               pr_err("%s has been included in this array twice\n",
                        devname);
                return 1;
        }
@@ -4859,7 +4864,7 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
 
                _disk = __get_imsm_disk(mpb, dl->index);
                if (!_dev || !_disk) {
-                       fprintf(stderr, Name ": BUG mpb setup error\n");
+                       pr_err("BUG mpb setup error\n");
                        return 1;
                }
                *_dev = *dev;
@@ -4934,8 +4939,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        fstat(fd, &stb);
        dd = malloc(sizeof(*dd));
        if (!dd) {
-               fprintf(stderr,
-                       Name ": malloc failed %s:%d.\n", __func__, __LINE__);
+               pr_err("malloc failed %s:%d.\n", __func__, __LINE__);
                return 1;
        }
        memset(dd, 0, sizeof(*dd));
@@ -4947,8 +4951,7 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        dd->action = DISK_ADD;
        rv = imsm_read_serial(fd, devname, dd->serial);
        if (rv) {
-               fprintf(stderr,
-                       Name ": failed to retrieve scsi serial, aborting\n");
+               pr_err("failed to retrieve scsi serial, aborting\n");
                free(dd);
                abort();
        }
@@ -4990,15 +4993,13 @@ static int remove_from_super_imsm(struct supertype *st, mdu_disk_info_t *dk)
         * is prepared.
         */
        if (!st->update_tail) {
-               fprintf(stderr,
-                       Name ": %s shall be used in mdmon context only"
-                       "(line %d).\n", __func__, __LINE__);
+               pr_err("%s shall be used in mdmon context only"
+                      "(line %d).\n", __func__, __LINE__);
                return 1;
        }
        dd = malloc(sizeof(*dd));
        if (!dd) {
-               fprintf(stderr,
-                       Name ": malloc failed %s:%d.\n", __func__, __LINE__);
+               pr_err("malloc failed %s:%d.\n", __func__, __LINE__);
                return 1;
        }
        memset(dd, 0, sizeof(*dd));
@@ -5299,7 +5300,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
        fd = open(dev, O_RDONLY|O_EXCL, 0);
        if (fd < 0) {
                if (verbose)
-                       fprintf(stderr, Name ": imsm: Cannot open %s: %s\n",
+                       pr_err("imsm: Cannot open %s: %s\n",
                                dev, strerror(errno));
                return 0;
        }
@@ -5313,9 +5314,8 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
         */
        super = alloc_super();
        if (!super) {
-               fprintf(stderr,
-                       Name ": malloc of %zu failed.\n",
-                       sizeof(*super));
+               pr_err("malloc of %zu failed.\n",
+                      sizeof(*super));
                close(fd);
                return 0;
        }
@@ -5337,7 +5337,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
        if (super->orom) {
                if (raiddisks > super->orom->tds) {
                        if (verbose)
-                               fprintf(stderr, Name ": %d exceeds maximum number of"
+                               pr_err("%d exceeds maximum number of"
                                        " platform supported disks: %d\n",
                                        raiddisks, super->orom->tds);
                        free_imsm(super);
@@ -5346,7 +5346,7 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
                if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 &&
                    (ldsize >> 9) >> 32 > 0) {
                        if (verbose)
-                               fprintf(stderr, Name ": %s exceeds maximum platform supported size\n", dev);
+                               pr_err("%s exceeds maximum platform supported size\n", dev);
                        free_imsm(super);
                        return 0;
                }
@@ -5536,7 +5536,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
                                if (*devlist && (found < dpa)) {
                                  dv = calloc(1, sizeof(*dv));
                                        if (dv == NULL)
-                                               fprintf(stderr, Name ": calloc failed\n");
+                                               pr_err("calloc failed\n");
                                        else {
                                                dv->devname = malloc(strlen(memb->dev) + strlen("/dev/") + 1);
                                                if (dv->devname != NULL) {
@@ -5569,12 +5569,12 @@ get_loop_devices(void)
        for(i = 0; i < 12; i++) {
                dv = calloc(1, sizeof(*dv));
                if (dv == NULL) {
-                       fprintf(stderr, Name ": calloc failed\n");
+                       pr_err("calloc failed\n");
                        break;
                }
                dv->devname = malloc(40);
                if (dv->devname == NULL) {
-                       fprintf(stderr, Name ": malloc failed\n");
+                       pr_err("malloc failed\n");
                        free(dv);
                        break;
                }
@@ -5625,7 +5625,7 @@ get_devices(const char *hba_path)
                        fd2devname(fd, buf);
                        close(fd);
                } else {
-                       fprintf(stderr, Name ": cannot open device: %s\n",
+                       pr_err("cannot open device: %s\n",
                                ent->d_name);
                        continue;
                }
@@ -5633,13 +5633,13 @@ get_devices(const char *hba_path)
 
                dv = calloc(1, sizeof(*dv));
                if (dv == NULL) {
-                       fprintf(stderr, Name ": malloc failed\n");
+                       pr_err("malloc failed\n");
                        err = 1;
                        break;
                }
                dv->devname = strdup(buf);
                if (dv->devname == NULL) {
-                       fprintf(stderr, Name ": malloc failed\n");
+                       pr_err("malloc failed\n");
                        err = 1;
                        free(dv);
                        break;
@@ -5655,6 +5655,7 @@ get_devices(const char *hba_path)
                        free(dv);
                }
        }
+       closedir(dir);
        return devlist;
 }
 
@@ -5940,7 +5941,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        mpb = super->anchor;
 
        if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, size, verbose)) {
-               fprintf(stderr, Name ": RAID gemetry validation failed. "
+               pr_err("RAID gemetry validation failed. "
                        "Cannot proceed with the action(s).\n");
                return 0;
        }
@@ -5982,7 +5983,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                }
                if (dcnt < raiddisks) {
                        if (verbose)
-                               fprintf(stderr, Name ": imsm: Not enough "
+                               pr_err("imsm: Not enough "
                                        "devices with space for this array "
                                        "(%d < %d)\n",
                                        dcnt, raiddisks);
@@ -6003,7 +6004,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        }
        if (!dl) {
                if (verbose)
-                       fprintf(stderr, Name ": %s is not in the "
+                       pr_err("%s is not in the "
                                "same imsm set\n", dev);
                return 0;
        } else if (super->orom && dl->index < 0 && mpb->num_raid_devs) {
@@ -6012,14 +6013,14 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                 * understand this configuration (all member disks must be
                 * members of each array in the container).
                 */
-               fprintf(stderr, Name ": %s is a spare and a volume"
+               pr_err("%s is a spare and a volume"
                        " is already defined for this container\n", dev);
-               fprintf(stderr, Name ": The option-rom requires all member"
+               pr_err("The option-rom requires all member"
                        " disks to be a member of all volumes\n");
                return 0;
        } else if (super->orom && mpb->num_raid_devs > 0 &&
                   mpb->num_disks != raiddisks) {
-               fprintf(stderr, Name ": The option-rom requires all member"
+               pr_err("The option-rom requires all member"
                        " disks to be a member of all volumes\n");
                return 0;
        }
@@ -6042,13 +6043,13 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                dl->extent_cnt = i;
        } else {
                if (verbose)
-                       fprintf(stderr, Name ": unable to determine free space for: %s\n",
+                       pr_err("unable to determine free space for: %s\n",
                                dev);
                return 0;
        }
        if (maxsize < size) {
                if (verbose)
-                       fprintf(stderr, Name ": %s not enough space (%llu < %llu)\n",
+                       pr_err("%s not enough space (%llu < %llu)\n",
                                dev, maxsize, size);
                return 0;
        }
@@ -6063,7 +6064,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
 
        if (!check_env("IMSM_NO_PLATFORM") &&
            mpb->num_raid_devs > 0 && size && size != maxsize) {
-               fprintf(stderr, Name ": attempting to create a second "
+               pr_err("attempting to create a second "
                        "volume with size less then remaining space. "
                        "Aborting...\n");
                return 0;
@@ -6072,10 +6073,10 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        if (maxsize < size || maxsize == 0) {
                if (verbose) {
                        if (maxsize == 0)
-                               fprintf(stderr, Name ": no free space"
+                               pr_err("no free space"
                                                " left on device. Aborting...\n");
                        else
-                               fprintf(stderr, Name ": not enough space"
+                               pr_err("not enough space"
                                                " to create volume of given size"
                                                " (%llu < %llu). Aborting...\n",
                                                maxsize, size);
@@ -6089,7 +6090,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
                int count = count_volumes(super->hba->path,
                                      super->orom->dpa, verbose);
                if (super->orom->vphba <= count) {
-                       pr_vrb(": platform does not support more then %d raid volumes.\n",
+                       pr_vrb(": platform does not support more than %d raid volumes.\n",
                               super->orom->vphba);
                        return 0;
                }
@@ -6097,7 +6098,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        return 1;
 }
 
-static int reserve_space(struct supertype *st, int raiddisks,
+static int imsm_get_free_size(struct supertype *st, int raiddisks,
                         unsigned long long size, int chunk,
                         unsigned long long *freesize)
 {
@@ -6149,7 +6150,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
            (super->orom && used && used != raiddisks) ||
            maxsize < minsize ||
            maxsize == 0) {
-               fprintf(stderr, Name ": not enough devices with space to create array.\n");
+               pr_err("not enough devices with space to create array.\n");
                return 0; /* No enough free spaces large enough */
        }
 
@@ -6163,7 +6164,7 @@ static int reserve_space(struct supertype *st, int raiddisks,
        }
        if (!check_env("IMSM_NO_PLATFORM") &&
            mpb->num_raid_devs > 0 && size && size != maxsize) {
-               fprintf(stderr, Name ": attempting to create a second "
+               pr_err("attempting to create a second "
                        "volume with size less then remaining space. "
                        "Aborting...\n");
                return 0;
@@ -6175,9 +6176,32 @@ static int reserve_space(struct supertype *st, int raiddisks,
 
        *freesize = size;
 
+       dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
+
        return 1;
 }
 
+static int reserve_space(struct supertype *st, int raiddisks,
+                        unsigned long long size, int chunk,
+                        unsigned long long *freesize)
+{
+       struct intel_super *super = st->sb;
+       struct dl *dl;
+       int cnt;
+       int rv = 0;
+
+       rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
+       if (rv) {
+               cnt = 0;
+               for (dl = super->disks; dl; dl = dl->next)
+                       if (dl->e)
+                               dl->raiddisk = cnt++;
+               rv = 1;
+       }
+
+       return rv;
+}
+
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                  int raiddisks, int *chunk, unsigned long long size,
                                  char *dev, unsigned long long *freesize,
@@ -6223,7 +6247,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                                      super->orom->dpa, verbose);
                                if (super->orom->vphba <= count) {
                                        pr_vrb(": platform does not support more"
-                                              "then %d raid volumes.\n",
+                                              " than %d raid volumes.\n",
                                               super->orom->vphba);
                                        return 0;
                                }
@@ -6245,15 +6269,14 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        fd = open(dev, O_RDONLY|O_EXCL, 0);
        if (fd >= 0) {
                if (verbose)
-                       fprintf(stderr,
-                               Name ": Cannot create this array on device %s\n",
-                               dev);
+                       pr_err("Cannot create this array on device %s\n",
+                              dev);
                close(fd);
                return 0;
        }
        if (errno != EBUSY || (fd = open(dev, O_RDONLY, 0)) < 0) {
                if (verbose)
-                       fprintf(stderr, Name ": Cannot open %s: %s\n",
+                       pr_err("Cannot open %s: %s\n",
                                dev, strerror(errno));
                return 0;
        }
@@ -6262,7 +6285,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        close(fd);
        if (cfd < 0) {
                if (verbose)
-                       fprintf(stderr, Name ": Cannot use %s: It is busy\n",
+                       pr_err("Cannot use %s: It is busy\n",
                                dev);
                return 0;
        }
@@ -6290,7 +6313,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
        }
 
        if (verbose)
-               fprintf(stderr, Name ": failed container membership check\n");
+               pr_err("failed container membership check\n");
 
        close(cfd);
        return 0;
@@ -6338,9 +6361,8 @@ static int kill_subarray_imsm(struct supertype *st)
                        continue;
                sprintf(subarray, "%u", i);
                if (is_subarray_active(subarray, st->devname)) {
-                       fprintf(stderr,
-                               Name ": deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
-                               current_vol, i);
+                       pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
+                              current_vol, i);
 
                        return 2;
                }
@@ -6397,8 +6419,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
                int vol;
 
                if (is_subarray_active(subarray, st->devname)) {
-                       fprintf(stderr,
-                               Name ": Unable to update name of active subarray\n");
+                       pr_err("Unable to update name of active subarray\n");
                        return 2;
                }
 
@@ -6547,14 +6568,14 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
        /* do not assemble arrays when not all attributes are supported */
        if (imsm_check_attributes(mpb->attributes) == 0) {
                sb_errors = 1;
-               fprintf(stderr, Name ": Unsupported attributes in IMSM metadata."
+               pr_err("Unsupported attributes in IMSM metadata."
                        "Arrays activation is blocked.\n");
        }
 
        /* check for bad blocks */
        if (imsm_bbm_log_size(super->anchor)) {
-               fprintf(stderr, Name ": BBM log found in IMSM metadata."
-                       "Arrays activation is blocked.\n");
+               pr_err("BBM log found in IMSM metadata."
+                      "Arrays activation is blocked.\n");
                sb_errors = 1;
        }
 
@@ -6589,7 +6610,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                 */
                if (dev->vol.migr_state &&
                    (migr_type(dev) == MIGR_STATE_CHANGE)) {
-                       fprintf(stderr, Name ": cannot assemble volume '%.16s':"
+                       pr_err("cannot assemble volume '%.16s':"
                                " unsupported migration in progress\n",
                                dev->volume);
                        continue;
@@ -6600,7 +6621,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 
                this = malloc(sizeof(*this));
                if (!this) {
-                       fprintf(stderr, Name ": failed to allocate %zu bytes\n",
+                       pr_err("failed to allocate %zu bytes\n",
                                sizeof(*this));
                        break;
                }
@@ -6617,7 +6638,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                                                 map->num_members, /* raid disks */
                                                 &chunk, join_u32(dev->size_low, dev->size_high),
                                                 1 /* verbose */)) {
-                       fprintf(stderr, Name ": IMSM RAID geometry validation"
+                       pr_err("IMSM RAID geometry validation"
                                " failed.  Array %s activation is blocked.\n",
                                dev->volume);
                        this->array.state |=
@@ -6669,8 +6690,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
 
                        info_d = calloc(1, sizeof(*info_d));
                        if (!info_d) {
-                               fprintf(stderr, Name ": failed to allocate disk"
-                                       " for volume %.16s\n", dev->volume);
+                               pr_err("failed to allocate disk"
+                                      " for volume %.16s\n", dev->volume);
                                info_d = this->devs;
                                while (info_d) {
                                        struct mdinfo *d = info_d->next;
@@ -6970,7 +6991,8 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
        super->updates_pending++;
 }
 
-static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
+                                             long long new_size)
 {
        int used_disks = imsm_num_data_members(dev, MAP_0);
        unsigned long long array_blocks;
@@ -6989,8 +7011,17 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
 
        /* set array size in metadata
         */
-       map = get_imsm_map(dev, MAP_0);
-       array_blocks = blocks_per_member(map) * used_disks;
+       if (new_size <= 0) {
+               /* OLCE size change is caused by added disks
+                */
+               map = get_imsm_map(dev, MAP_0);
+               array_blocks = blocks_per_member(map) * used_disks;
+       } else {
+               /* Online Volume Size Change
+                * Using  available free space
+                */
+               array_blocks = new_size;
+       }
 
        /* round array size down to closest MB
         */
@@ -7047,7 +7078,7 @@ static void imsm_progress_container_reshape(struct intel_super *super)
                memcpy(map2, map, copy_map_size);
                map2->num_members = prev_num_members;
 
-               imsm_set_array_size(dev);
+               imsm_set_array_size(dev, -1);
                super->clean_migration_record_by_mdmon = 1;
                super->updates_pending++;
        }
@@ -7211,6 +7242,8 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
        struct imsm_dev *dev = get_imsm_dev(super, inst);
        struct imsm_map *map = get_imsm_map(dev, MAP_0);
        struct imsm_disk *disk;
+       struct mdinfo *mdi;
+       int recovery_not_finished = 0;
        int failed;
        __u32 ord;
        __u8 map_state;
@@ -7251,6 +7284,21 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
                dprintf("normal: ");
                if (is_rebuilding(dev)) {
                        dprintf("while rebuilding");
+                       /* check if recovery is really finished */
+                       for (mdi = a->info.devs; mdi ; mdi = mdi->next)
+                               if (mdi->recovery_start != MaxSector) {
+                                       recovery_not_finished = 1;
+                                       break;
+                               }
+                       if (recovery_not_finished) {
+                               dprintf("\nimsm: Rebuild has not finished yet, "
+                                               "state not changed");
+                               if (a->last_checkpoint < mdi->recovery_start) {
+                                       a->last_checkpoint = mdi->recovery_start;
+                                       super->updates_pending++;
+                               }
+                               break;
+                       }
                        end_migration(dev, super, map_state);
                        map = get_imsm_map(dev, MAP_0);
                        map->failed_disk_num = ~0;
@@ -7937,7 +7985,7 @@ skip_disk_add:
                        *tofree = *space_list;
                        /* calculate new size
                         */
-                       imsm_set_array_size(new_dev);
+                       imsm_set_array_size(new_dev, -1);
 
                        ret_val = 1;
                }
@@ -7952,6 +8000,44 @@ error_disk_add:
        return ret_val;
 }
 
+static int apply_size_change_update(struct imsm_update_size_change *u,
+               struct intel_super *super)
+{
+       struct intel_dev *id;
+       int ret_val = 0;
+
+       dprintf("apply_size_change_update()\n");
+       if ((u->subdev < 0) ||
+           (u->subdev > 1)) {
+               dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
+               return ret_val;
+       }
+
+       for (id = super->devlist ; id; id = id->next) {
+               if (id->index == (unsigned)u->subdev) {
+                       struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
+                       struct imsm_map *map = get_imsm_map(dev, MAP_0);
+                       int used_disks = imsm_num_data_members(dev, MAP_0);
+                       unsigned long long blocks_per_member;
+
+                       /* calculate new size
+                        */
+                       blocks_per_member = u->new_size / used_disks;
+                       dprintf("imsm: apply_size_change_update(size: %llu, "
+                               "blocks per member: %llu)\n",
+                               u->new_size, blocks_per_member);
+                       set_blocks_per_member(map, blocks_per_member);
+                       imsm_set_array_size(dev, u->new_size);
+
+                       ret_val = 1;
+                       break;
+               }
+       }
+
+       return ret_val;
+}
+
+
 static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
                                       struct intel_super *super,
                                       struct active_array *active_array)
@@ -8151,7 +8237,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
                        newmap = get_imsm_map(newdev, MAP_1);
                        memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
 
-                       imsm_set_array_size(newdev);
+                       imsm_set_array_size(newdev, -1);
                }
 
                sp = (void **)id->dev;
@@ -8359,6 +8445,12 @@ static void imsm_process_update(struct supertype *st,
                        super->updates_pending++;
                break;
        }
+       case update_size_change: {
+               struct imsm_update_size_change *u = (void *)update->buf;
+               if (apply_size_change_update(u, super))
+                       super->updates_pending++;
+               break;
+       }
        case update_activate_spare: {
                struct imsm_update_activate_spare *u = (void *) update->buf; 
                if (apply_update_activate_spare(u, super, st->arrays))
@@ -8753,6 +8845,9 @@ static void imsm_prepare_update(struct supertype *st,
                dprintf("New anchor length is %llu\n", (unsigned long long)len);
                break;
        }
+       case update_size_change: {
+               break;
+       }
        case update_create_array: {
                struct imsm_update_create_array *u = (void *) update->buf;
                struct intel_dev *dv;
@@ -9147,7 +9242,7 @@ int save_backup_imsm(struct supertype *st,
                            start,
                            length,
                            buf) != 0) {
-               fprintf(stderr, Name ": Error restoring stripes\n");
+               pr_err("Error restoring stripes\n");
                goto abort;
        }
 
@@ -9283,8 +9378,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                goto abort;
 
        if (open_backup_targets(info, new_disks, targets, super, id->dev)) {
-               fprintf(stderr,
-                       Name ": Cannot open some devices belonging to array.\n");
+               pr_err("Cannot open some devices belonging to array.\n");
                goto abort;
        }
 
@@ -9294,30 +9388,26 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                        continue;
                }
                if (lseek64(targets[i], read_offset, SEEK_SET) < 0) {
-                       fprintf(stderr,
-                               Name ": Cannot seek to block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot seek to block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
                if ((unsigned)read(targets[i], buf, unit_len) != unit_len) {
-                       fprintf(stderr,
-                               Name ": Cannot read copy area block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot read copy area block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
                if (lseek64(targets[i], write_offset, SEEK_SET) < 0) {
-                       fprintf(stderr,
-                               Name ": Cannot seek to block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot seek to block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
                if ((unsigned)write(targets[i], buf, unit_len) != unit_len) {
-                       fprintf(stderr,
-                               Name ": Cannot restore block: %s\n",
-                               strerror(errno));
+                       pr_err("Cannot restore block: %s\n",
+                              strerror(errno));
                        skipped_disks++;
                        continue;
                }
@@ -9327,9 +9417,8 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
                                                         new_disks,
                                                         super,
                                                         id->dev)) {
-               fprintf(stderr,
-                       Name ": Cannot restore data from backup."
-                       " Too many failed disks\n");
+               pr_err("Cannot restore data from backup."
+                      " Too many failed disks\n");
                goto abort;
        }
 
@@ -9402,7 +9491,8 @@ static int imsm_find_array_minor_by_subdev(int subdev, int container, int *minor
 
 static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                                                struct geo_params *geo,
-                                               int *old_raid_disks)
+                                               int *old_raid_disks,
+                                               int direction)
 {
        /* currently we only support increasing the number of devices
         * for a container.  This increases the number of device for each
@@ -9426,6 +9516,12 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
                return ret_val;
        }
 
+       if (direction == ROLLBACK_METADATA_CHANGES) {
+               dprintf("imsm: Metadata changes rollback is not supported for "
+                       "container operation.\n");
+               return ret_val;
+       }
+
        info = container_content_imsm(st, NULL);
        for (member = info; member; member = member->next) {
                int result;
@@ -9567,7 +9663,7 @@ static int imsm_create_metadata_update_for_reshape(
 
        if (spares == NULL
            || delta_disks > spares->array.spare_disks) {
-               fprintf(stderr, Name ": imsm: ERROR: Cannot get spare devices "
+               pr_err("imsm: ERROR: Cannot get spare devices "
                        "for %s.\n", geo->dev_name);
                i = -1;
                goto abort;
@@ -9610,6 +9706,43 @@ abort:
        return 0;
 }
 
+
+/******************************************************************************
+ * function: imsm_create_metadata_update_for_size_change()
+ *           Creates update for IMSM array for array size change.
+ *
+ ******************************************************************************/
+static int imsm_create_metadata_update_for_size_change(
+                               struct supertype *st,
+                               struct geo_params *geo,
+                               struct imsm_update_size_change **updatep)
+{
+       struct intel_super *super = st->sb;
+       int update_memory_size = 0;
+       struct imsm_update_size_change *u = NULL;
+
+       dprintf("imsm_create_metadata_update_for_size_change(enter)"
+               " New size = %llu\n", geo->size);
+
+       /* size of all update data without anchor */
+       update_memory_size = sizeof(struct imsm_update_size_change);
+
+       u = calloc(1, update_memory_size);
+       if (u == NULL) {
+               dprintf("error: cannot get memory for "
+                       "imsm_create_metadata_update_for_size_change\n");
+               return 0;
+       }
+       u->type = update_size_change;
+       u->subdev = super->current_vol;
+       u->new_size = geo->size;
+
+       dprintf("imsm: reshape update preparation : OK\n");
+       *updatep = u;
+
+       return update_memory_size;
+}
+
 /******************************************************************************
  * function: imsm_create_metadata_update_for_migration()
  *           Creates update for IMSM array.
@@ -9709,11 +9842,13 @@ static void imsm_update_metadata_locally(struct supertype *st,
 * Function:    imsm_analyze_change
 * Description: Function analyze change for single volume
 *              and validate if transition is supported
-* Parameters:  Geometry parameters, supertype structure
+* Parameters:  Geometry parameters, supertype structure,
+*              metadata change direction (apply/rollback)
 * Returns:     Operation type code on success, -1 if fail
 ****************************************************************************/
 enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
-                                          struct geo_params *geo)
+                                          struct geo_params *geo,
+                                          int direction)
 {
        struct mdinfo info;
        int change = -1;
@@ -9723,6 +9858,13 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
        int devNumChange = 0;
        /* imsm compatible layout value for array geometry verification */
        int imsm_layout = -1;
+       int data_disks;
+       struct imsm_dev *dev;
+       struct intel_super *super;
+       long long current_size;
+       unsigned long long free_size;
+       long long max_size;
+       int rv;
 
        getinfo_super_imsm_volume(st, &info, NULL);
        if ((geo->level != info.array.level) &&
@@ -9733,10 +9875,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        if (geo->level == 5) {
                                change = CH_MIGRATION;
                                if (geo->layout != ALGORITHM_LEFT_ASYMMETRIC) {
-                                       fprintf(stderr,
-                                       Name " Error. Requested Layout "
-                                       "not supported (left-asymmetric layout "
-                                       "is supported only)!\n");
+                                       pr_err("Error. Requested Layout "
+                                              "not supported (left-asymmetric layout "
+                                              "is supported only)!\n");
                                        change = -1;
                                        goto analyse_change_exit;
                                }
@@ -9761,10 +9902,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        break;
                }
                if (change == -1) {
-                       fprintf(stderr,
-                               Name " Error. Level Migration from %d to %d "
-                               "not supported!\n",
-                               info.array.level, geo->level);
+                       pr_err("Error. Level Migration from %d to %d "
+                              "not supported!\n",
+                              info.array.level, geo->level);
                        goto analyse_change_exit;
                }
        } else
@@ -9784,10 +9924,9 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                        geo->layout = 0;
                        geo->level = 5;
                } else {
-                       fprintf(stderr,
-                               Name " Error. Layout Migration from %d to %d "
-                               "not supported!\n",
-                               info.array.layout, geo->layout);
+                       pr_err("Error. Layout Migration from %d to %d "
+                              "not supported!\n",
+                              info.array.layout, geo->layout);
                        change = -1;
                        goto analyse_change_exit;
                }
@@ -9804,6 +9943,95 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                geo->chunksize = info.array.chunk_size;
 
        chunk = geo->chunksize / 1024;
+
+       super = st->sb;
+       dev = get_imsm_dev(super, super->current_vol);
+       data_disks = imsm_num_data_members(dev , MAP_0);
+       /* compute current size per disk member
+        */
+       current_size = info.custom_array_size / data_disks;
+
+       if (geo->size > 0) {
+               /* align component size
+                */
+               geo->size = imsm_component_size_aligment_check(
+                                   get_imsm_raid_level(dev->vol.map),
+                                   chunk * 1024,
+                                   geo->size * 2);
+       }
+
+       if ((current_size != geo->size) && (geo->size >= 0)) {
+               if (change != -1) {
+                       pr_err("Error. Size change should be the only "
+                               "one at a time.\n");
+                       change = -1;
+                       goto analyse_change_exit;
+               }
+               if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
+                       pr_err("Error. The last volume in container "
+                              "can be expanded only (%i/%i).\n",
+                              super->current_vol, st->devnum);
+                       goto analyse_change_exit;
+               }
+               /* check the maximum available size
+                */
+               rv =  imsm_get_free_size(st, dev->vol.map->num_members,
+                                        0, chunk, &free_size);
+               if (rv == 0)
+                       /* Cannot find maximum available space
+                        */
+                       max_size = 0;
+               else {
+                       max_size = free_size + current_size;
+                       /* align component size
+                        */
+                       max_size = imsm_component_size_aligment_check(
+                                       get_imsm_raid_level(dev->vol.map),
+                                       chunk * 1024,
+                                       max_size);
+               }
+               if (geo->size == 0) {
+                       /* requested size change to the maximum available size
+                        */
+                       if (max_size == 0) {
+                               pr_err("Error. Cannot find "
+                                       "maximum available space.\n");
+                               change = -1;
+                               goto analyse_change_exit;
+                       } else
+                               geo->size = max_size;
+               }
+
+               if ((direction == ROLLBACK_METADATA_CHANGES)) {
+                       /* accept size for rollback only
+                       */
+               } else {
+                       /* round size due to metadata compatibility
+                       */
+                       geo->size = (geo->size >> SECT_PER_MB_SHIFT)
+                                   << SECT_PER_MB_SHIFT;
+                       dprintf("Prepare update for size change to %llu\n",
+                               geo->size );
+                       if (current_size >= geo->size) {
+                               pr_err("Error. Size expansion is "
+                                      "supported only (current size is %llu, "
+                                      "requested size /rounded/ is %llu).\n",
+                                      current_size, geo->size);
+                               goto analyse_change_exit;
+                       }
+                       if (max_size && geo->size > max_size) {
+                               pr_err("Error. Requested size is larger "
+                                      "than maximum available size (maximum "
+                                      "available size is %llu, "
+                                      "requested size /rounded/ is %llu).\n",
+                                      max_size, geo->size);
+                               goto analyse_change_exit;
+                       }
+               }
+               geo->size *= data_disks;
+               geo->raid_disks = dev->vol.map->num_members;
+               change = CH_ARRAY_SIZE;
+       }
        if (!validate_geometry_imsm(st,
                                    geo->level,
                                    imsm_layout,
@@ -9818,17 +10046,21 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
                struct imsm_super *mpb = super->anchor;
 
                if (mpb->num_raid_devs > 1) {
-                       fprintf(stderr,
-                               Name " Error. Cannot perform operation on %s"
-                               "- for this operation it MUST be single "
-                               "array in container\n",
-                               geo->dev_name);
+                       pr_err("Error. Cannot perform operation on %s"
+                              "- for this operation it MUST be single "
+                              "array in container\n",
+                              geo->dev_name);
                        change = -1;
                }
        }
 
 analyse_change_exit:
-
+       if ((direction == ROLLBACK_METADATA_CHANGES) &&
+            ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) {
+               dprintf("imsm: Metadata changes rollback is not supported for "
+                       "migration and takeover operations.\n");
+               change = -1;
+       }
        return change;
 }
 
@@ -9868,7 +10100,7 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
 static int imsm_reshape_super(struct supertype *st, long long size, int level,
                              int layout, int chunksize, int raid_disks,
                              int delta_disks, char *backup, char *dev,
-                             int verbose)
+                             int direction, int verbose)
 {
        int ret_val = 1;
        struct geo_params geo;
@@ -9899,7 +10131,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                int old_raid_disks = 0;
 
                if (imsm_reshape_is_allowed_on_container(
-                           st, &geo, &old_raid_disks)) {
+                           st, &geo, &old_raid_disks, direction)) {
                        struct imsm_update_reshape *u = NULL;
                        int len;
 
@@ -9921,7 +10153,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                                free(u);
 
                } else {
-                       fprintf(stderr, Name ": (imsm) Operation "
+                       pr_err("(imsm) Operation "
                                "is not allowed on this container\n");
                }
        } else {
@@ -9943,12 +10175,12 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                        dev = dev->next;
                }
                if (dev == NULL) {
-                       fprintf(stderr, Name " Cannot find %s (%i) subarray\n",
+                       pr_err("Cannot find %s (%i) subarray\n",
                                geo.dev_name, geo.dev_id);
                        goto exit_imsm_reshape_super;
                }
                super->current_vol = dev->index;
-               change = imsm_analyze_change(st, &geo);
+               change = imsm_analyze_change(st, &geo, direction);
                switch (change) {
                case CH_TAKEOVER:
                        ret_val = imsm_takeover(st, &geo);
@@ -9973,6 +10205,26 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
                                free(u);
                }
                break;
+               case CH_ARRAY_SIZE: {
+                       struct imsm_update_size_change *u = NULL;
+                       int len =
+                               imsm_create_metadata_update_for_size_change(
+                                       st, &geo, &u);
+                       if (len < 1) {
+                               dprintf("imsm: "
+                                       "Cannot prepare update\n");
+                               break;
+                       }
+                       ret_val = 0;
+                       /* update metadata locally */
+                       imsm_update_metadata_locally(st, u, len);
+                       /* and possibly remotely */
+                       if (st->update_tail)
+                               append_metadata_update(st, u, len);
+                       else
+                               free(u);
+               }
+               break;
                default:
                        ret_val = 1;
                }
@@ -10070,8 +10322,10 @@ int check_degradation_change(struct mdinfo *info,
                             int degraded)
 {
        unsigned long long new_degraded;
-       sysfs_get_ll(info, NULL, "degraded", &new_degraded);
-       if (new_degraded != (unsigned long long)degraded) {
+       int rv;
+
+       rv = sysfs_get_ll(info, NULL, "degraded", &new_degraded);
+       if ((rv == -1) || (new_degraded != (unsigned long long)degraded)) {
                /* check each device to ensure it is still working */
                struct mdinfo *sd;
                new_degraded = 0;
@@ -10161,7 +10415,7 @@ static int imsm_manage_reshape(
        }
        /* Only one volume can migrate at the same time */
        if (migr_vol_qan != 1) {
-               fprintf(stderr, Name " : %s", migr_vol_qan ?
+               pr_err(": %s", migr_vol_qan ?
                        "Number of migrating volumes greater than 1\n" :
                        "There is no volume during migrationg\n");
                goto abort;