]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - util.c
open_dev_excl: allow device to be read-only.
[thirdparty/mdadm.git] / util.c
diff --git a/util.c b/util.c
index b806a97c73d7363575d0c7d06a88a9347bdb7bdd..e0671eb6cbbe28944dd495564f2fa244151edc92 100644 (file)
--- a/util.c
+++ b/util.c
@@ -160,6 +160,7 @@ int get_linux_version()
        return (a*1000000)+(b*1000)+c;
 }
 
+#ifndef MDASSEMBLE
 int mdadm_version(char *version)
 {
        int a, b, c;
@@ -185,7 +186,6 @@ int mdadm_version(char *version)
        return (a*1000000)+(b*1000)+c;
 }
 
-#ifndef MDASSEMBLE
 long long parse_size(char *size)
 {
        /* parse 'size' which should be a number optionally
@@ -295,6 +295,19 @@ int test_partition(int fd)
        return 1;
 }
 
+int test_partition_from_id(dev_t id)
+{
+       char buf[20];
+       int fd, rv;
+
+       sprintf(buf, "%d:%d", major(id), minor(id));
+       fd = dev_open(buf, O_RDONLY);
+       if (fd < 0)
+               return -1;
+       rv = test_partition(fd);
+       close(fd);
+       return rv;
+}
 
 int enough(int level, int raid_disks, int layout, int clean,
           char *avail, int avail_disks)
@@ -985,24 +998,34 @@ int dev_open(char *dev, int flags)
        return fd;
 }
 
-int open_dev(int devnum)
+int open_dev_flags(int devnum, int flags)
 {
        char buf[20];
 
        sprintf(buf, "%d:%d", dev2major(devnum), dev2minor(devnum));
-       return dev_open(buf, O_RDWR);
+       return dev_open(buf, flags);
+}
+
+int open_dev(int devnum)
+{
+       return open_dev_flags(devnum, O_RDONLY);
 }
 
 int open_dev_excl(int devnum)
 {
        char buf[20];
        int i;
+       int flags = O_RDWR;
 
        sprintf(buf, "%d:%d", dev2major(devnum), dev2minor(devnum));
        for (i=0 ; i<25 ; i++) {
-               int fd = dev_open(buf, O_RDWR|O_EXCL);
+               int fd = dev_open(buf, flags|O_EXCL);
                if (fd >= 0)
                        return fd;
+               if (errno == EACCES && flags == O_RDWR) {
+                       flags = O_RDONLY;
+                       continue;
+               }
                if (errno != EBUSY)
                        return fd;
                usleep(200000);
@@ -1178,6 +1201,7 @@ struct supertype *guess_super_type(int fd, enum guess_types guess_type)
                if (guess_type == guess_partitions && ss->add_to_super != NULL)
                        continue;
                memset(st, 0, sizeof(*st));
+               st->ignore_hw_compat = 1;
                rv = ss->load_super(st, fd, NULL);
                if (rv == 0) {
                        struct mdinfo info;
@@ -1193,9 +1217,11 @@ struct supertype *guess_super_type(int fd, enum guess_types guess_type)
        if (bestsuper != -1) {
                int rv;
                memset(st, 0, sizeof(*st));
+               st->ignore_hw_compat = 1;
                rv = superlist[bestsuper]->load_super(st, fd, NULL);
                if (rv == 0) {
                        superlist[bestsuper]->free_super(st);
+                       st->ignore_hw_compat = 0;
                        return st;
                }
        }
@@ -1357,7 +1383,8 @@ static int get_last_partition_end(int fd, unsigned long long *endofpart)
        return retval;
 }
 
-int check_partitions(int fd, char *dname, unsigned long long freesize)
+int check_partitions(int fd, char *dname, unsigned long long freesize,
+                       unsigned long long size)
 {
        /*
         * Check where the last partition ends
@@ -1380,6 +1407,12 @@ int check_partitions(int fd, char *dname, unsigned long long freesize)
                                Name ": metadata will over-write last partition on %s.\n",
                                dname);
                        return 1;
+               } else if (size && endofpart > size) {
+                       /* partitions will be truncated in new device */
+                       fprintf(stderr,
+                               Name ": array size is too small to cover all partitions on %s.\n",
+                               dname);
+                       return 1;
                }
        }
        return 0;
@@ -1477,8 +1510,7 @@ int is_subarray_active(char *subarray, char *container)
 
        for (ent = mdstat; ent; ent = ent->next)
                if (is_container_member(ent, container))
-                       if (!subarray ||
-                           strcmp(to_subarray(ent, container), subarray) == 0)
+                       if (strcmp(to_subarray(ent, container), subarray) == 0)
                                break;
 
        free_mdstat(mdstat);
@@ -1486,11 +1518,6 @@ int is_subarray_active(char *subarray, char *container)
        return ent != NULL;
 }
 
-int is_container_active(char *container)
-{
-       return is_subarray_active(NULL, container);
-}
-
 /* open_subarray - opens a subarray in a container
  * @dev: container device name
  * @st: empty supertype
@@ -1949,7 +1976,7 @@ struct mdinfo *container_choose_spares(struct supertype *st,
                                if (spare_group)
                                        pol_add(&pol, pol_domain,
                                                spare_group, NULL);
-                               if (!domain_test(domlist, pol, metadata))
+                               if (domain_test(domlist, pol, metadata) != 1)
                                        found = 0;
                                dev_policy_free(pol);
                        }