Use remapping to error target instead of calling udevsettle for temporary crypt device.
authorMilan Broz <gmazyland@gmail.com>
Tue, 16 Sep 2008 15:35:50 +0000 (15:35 +0000)
committerMilan Broz <gmazyland@gmail.com>
Tue, 16 Sep 2008 15:35:50 +0000 (15:35 +0000)
git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@32 36d66b0a-2a48-0410-832c-cd162a569da5

lib/internal.h
lib/libdevmapper.c
lib/setup.c
luks/keyencryption.c

index 53011f7..670b349 100644 (file)
@@ -40,7 +40,7 @@ struct setup_backend {
                                  const char *key);
        int             (*status)(int details, struct crypt_options *options,
                                  char **key);
-       int             (*remove)(struct crypt_options *options);
+       int             (*remove)(int force, struct crypt_options *options);
 
        const char *    (*dir)(void);
 };
index 07f0a6a..6c3daea 100644 (file)
 #define DEVICE_DIR     "/dev"
 
 #define        CRYPT_TARGET    "crypt"
-
-#define UDEVSETTLE     "/sbin/udevsettle"
-
-static void run_udevsettle(void)
-{
-       system(UDEVSETTLE);
-}
+#define        RETRY_COUNT     5
 
 static void set_dm_error(int level, const char *file, int line,
                          const char *f, ...)
@@ -57,16 +51,6 @@ static void dm_exit(void)
        dm_lib_release();
 }
 
-static void flush_dm_workqueue(void)
-{
-       /* 
-        * Unfortunately this is the only way to trigger libdevmapper's
-        * update_nodes function 
-        */ 
-       dm_exit(); 
-       dm_init();
-}
-
 static char *__lookup_dev(char *path, dev_t dev)
 {
        struct dirent *entry;
@@ -159,6 +143,89 @@ out:
        return params;
 }
 
+/* DM helpers */
+static int _dm_simple(int task, const char *name)
+{
+       int r = 0;
+       struct dm_task *dmt;
+
+       if (!(dmt = dm_task_create(task)))
+               return 0;
+
+       if (!dm_task_set_name(dmt, name))
+               goto out;
+
+       r = dm_task_run(dmt);
+
+      out:
+       dm_task_destroy(dmt);
+       return r;
+}
+
+static int _error_device(struct crypt_options *options)
+{
+       struct dm_task *dmt;
+       int r = 0;
+
+       if (!(dmt = dm_task_create(DM_DEVICE_RELOAD)))
+               return 0;
+
+       if (!dm_task_set_name(dmt, options->name))
+               goto error;
+
+       if (!dm_task_add_target(dmt, UINT64_C(0), options->size, "error", ""))
+               goto error;
+
+       if (!dm_task_set_ro(dmt))
+               goto error;
+
+       if (!dm_task_no_open_count(dmt))
+               goto error;
+
+       if (!dm_task_run(dmt))
+               goto error;
+
+       if (!_dm_simple(DM_DEVICE_RESUME, options->name)) {
+               _dm_simple(DM_DEVICE_CLEAR, options->name);
+               goto error;
+       }
+
+       r = 1;
+
+error:
+       dm_task_destroy(dmt);
+       return r;
+}
+
+static int _dm_remove(struct crypt_options *options, int force)
+{
+       int r = -EINVAL;
+       int retries = force ? RETRY_COUNT : 1;
+
+       /* If force flag is set, replace device with error, read-only target.
+        * it should stop processes from reading it and also removed underlying
+        * device from mapping, so it is usable again.
+        * Force flag should be used only for temporary devices, which are
+        * intended to work inside cryptsetup only!
+        * Anyway, if some process try to read temporary cryptsetup device,
+        * it is bug - no other process should try touch it (e.g. udev).
+        */
+       if (force) {
+                _error_device(options);
+               retries = RETRY_COUNT;
+       }
+
+       do {
+               r = _dm_simple(DM_DEVICE_REMOVE, options->name) ? 0 : -EINVAL;
+               if (--retries)
+                       sleep(1);
+       } while (r == -EINVAL && retries);
+
+       dm_task_update_nodes();
+
+       return r;
+}
+
 static int dm_create_device(int reload, struct crypt_options *options,
                             const char *key)
 {
@@ -198,24 +265,14 @@ static int dm_create_device(int reload, struct crypt_options *options,
        if (dmi.read_only)
                options->flags |= CRYPT_FLAG_READONLY;
 
-       /* run udevsettle to avoid a race in libdevmapper causing busy dm devices */
-       run_udevsettle();
-
        r = 0;
-       
 out:
        if (r < 0 && !reload) {
                char *error = (char *)get_error();
                if (error)
                        error = strdup(error);
-               if (dmt)
-                       dm_task_destroy(dmt);
 
-               if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
-                       goto out_restore_error;
-               if (!dm_task_set_name(dmt, options->name))
-                       goto out_restore_error;
-               if (!dm_task_run(dmt))
+               if (!_dm_remove(options, 0))
                        goto out_restore_error;
 
 out_restore_error:
@@ -231,7 +288,7 @@ out_no_removal:
                dm_task_destroy(dmt);
        if(dmt_query)
                dm_task_destroy(dmt_query);
-       flush_dm_workqueue();
+       dm_task_update_nodes();
        return r;
 }
 
@@ -359,25 +416,12 @@ out:
        return r;
 }
 
-static int dm_remove_device(struct crypt_options *options)
+static int dm_remove_device(int force, struct crypt_options *options)
 {
-       struct dm_task *dmt;
-       int r = -EINVAL;
+       if (!options || !options->name)
+               return -EINVAL;
 
-       if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
-               goto out;
-       if (!dm_task_set_name(dmt, options->name))
-               goto out;
-       if (!dm_task_run(dmt))
-               goto out;
-
-       r = 0;
-
-out:   
-       if (dmt)
-               dm_task_destroy(dmt);
-       flush_dm_workqueue();
-       return r;
+       return _dm_remove(options, force);;
 }
 
 
index db4af13..f3b1656 100644 (file)
@@ -396,7 +396,7 @@ static int __crypt_remove_device(int arg, struct setup_backend *backend,
                return -EBUSY;
        }
 
-       return backend->remove(options);
+       return backend->remove(0, options);
 }
 
 static int __crypt_luks_format(int arg, struct setup_backend *backend, struct crypt_options *options)
index 107b89a..94af4a8 100644 (file)
@@ -45,6 +45,11 @@ static inline int round_up_modulo(int x, int m) {
        return div_round_up(x, m) * m;
 }
 
+static struct setup_backend *cleaner_backend=NULL;
+static const char *cleaner_name=NULL;
+static uint64_t cleaner_size = 0;
+static int devfd=-1;
+
 static int setup_mapping(const char *cipher, const char *name, 
                         const char *device, unsigned int payloadOffset,
                         const char *key, size_t keyLength, 
@@ -52,7 +57,7 @@ static int setup_mapping(const char *cipher, const char *name,
                         struct setup_backend *backend,
                         int mode)
 {
-       struct crypt_options k;
+       struct crypt_options k = {0};
        struct crypt_options *options = &k;
        int device_sector_size = sector_size_for_device(device);
        int r;
@@ -66,6 +71,7 @@ static int setup_mapping(const char *cipher, const char *name,
                return -EINVAL;
        }
        options->size = round_up_modulo(srcLength,device_sector_size)/SECTOR_SIZE;
+       cleaner_size = options->size;
 
        options->offset = sector;
        options->cipher = cipher;
@@ -87,25 +93,21 @@ static int setup_mapping(const char *cipher, const char *name,
        return r;
 }
 
-static int clear_mapping(const char *name, struct setup_backend *backend)
+static int clear_mapping(const char *name, uint64_t size, struct setup_backend *backend)
 {
-       struct crypt_options options;
+       struct crypt_options options = {0};
        options.name=name;
-       return backend->remove(&options);
+       options.size = size;
+       return backend->remove(1, &options);
 }
 
-/* I miss closures in C! */
-static struct setup_backend *cleaner_backend=NULL;
-static const char *cleaner_name=NULL; 
-static int devfd=-1;
-
 static void sigint_handler(int sig)
 {
         if(devfd >= 0)
                 close(devfd);
         devfd = -1;
         if(cleaner_backend && cleaner_name) 
-                clear_mapping(cleaner_name, cleaner_backend);
+                clear_mapping(cleaner_name, cleaner_size, cleaner_backend);
         signal(SIGINT, SIG_DFL);
         kill(getpid(), SIGINT);
 }
@@ -163,11 +165,12 @@ static int LUKS_endec_template(char *src, size_t srcLength,
        close(devfd);
        devfd = -1;
  out2:
-       clear_mapping(name,backend);
+       clear_mapping(cleaner_name, cleaner_size, cleaner_backend);
  out1:
        signal(SIGINT, SIG_DFL);
        cleaner_name = NULL;
        cleaner_backend = NULL;
+       cleaner_size = 0;
        free(dmCipherSpec);
        free(fullpath); 
        free(name);