Re: [RFC PATCH] cryptsetup: replace udevsettle calls with temporary device error remapping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Clemens Fruhwirth wrote:
> Also I should start to rewrite the backends to get rid of the options
> struct. However, in the mean time could you just remove the use of
> crypt_option except before that actual backend call? Then, the patch
> is ready to merge (at least from my perspective)

I replaced size with static variables for now (name, size) - ugly, but works:)
See attachment.

If you plan rewrite backend, maybe the whole identification of dm device
could be changed to UUID - also cryptsetup should set this UUID for
kernel device (+some prefix - LVM uses LVM, there can be probably LUKS...
LUKS has alredy uuid in header, so it is just adding parameter to dm-ioctl call.)
(This is nice for udev later for example.)

Milan
--
mbroz@xxxxxxxxxx

Use remapping to error target instead of calling udevsettle.
---
 lib/internal.h       |    2 
 lib/libdevmapper.c   |  143 ++++++++++++++++++++++++++++++++-------------------
 lib/setup.c          |    2 
 luks/keyencryption.c |   25 ++++----
 4 files changed, 106 insertions(+), 66 deletions(-)

Index: cryptsetup.my/lib/libdevmapper.c
===================================================================
--- cryptsetup.my.orig/lib/libdevmapper.c	2008-09-09 23:22:16.000000000 +0200
+++ cryptsetup.my/lib/libdevmapper.c	2008-09-09 23:23:31.000000000 +0200
@@ -17,20 +17,7 @@
 #define DEVICE_DIR	"/dev"
 
 #define	CRYPT_TARGET	"crypt"
-
-#define UDEVSETTLE	"/sbin/udevsettle"
-#define UDEVADM		"/sbin/udevadm"
-#define UDEVADM_ARGS	"settle --timeout=30"
-
-static void run_udevsettle(void)
-{
-#ifndef SKIP_UDEVSETTLE
-	if (!access(UDEVADM, X_OK))
-		system(UDEVADM " " UDEVADM_ARGS);
-	else if (!access(UDEVSETTLE, X_OK))
-		system(UDEVSETTLE);
-#endif
-}
+#define RETRY_COUNT	5
 
 static void set_dm_error(int level, const char *file, int line,
                          const char *f, ...)
@@ -57,16 +44,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 +136,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 +258,14 @@ static int dm_create_device(int reload, 
 	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 +281,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 +409,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: cryptsetup.my/lib/internal.h
===================================================================
--- cryptsetup.my.orig/lib/internal.h	2008-09-09 23:22:16.000000000 +0200
+++ cryptsetup.my/lib/internal.h	2008-09-09 23:23:31.000000000 +0200
@@ -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: cryptsetup.my/lib/setup.c
===================================================================
--- cryptsetup.my.orig/lib/setup.c	2008-09-09 23:22:16.000000000 +0200
+++ cryptsetup.my/lib/setup.c	2008-09-09 23:23:31.000000000 +0200
@@ -369,7 +369,7 @@ static int __crypt_remove_device(int arg
 		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: cryptsetup.my/luks/keyencryption.c
===================================================================
--- cryptsetup.my.orig/luks/keyencryption.c	2008-09-09 23:22:16.000000000 +0200
+++ cryptsetup.my/luks/keyencryption.c	2008-09-09 23:32:35.000000000 +0200
@@ -45,6 +45,11 @@ static inline int round_up_modulo(int x,
 	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 *cip
 			 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 *cip
 		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 *cip
 	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
 	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); 

---------------------------------------------------------------------
dm-crypt mailing list - http://www.saout.de/misc/dm-crypt/
To unsubscribe, e-mail: dm-crypt-unsubscribe@xxxxxxxx
For additional commands, e-mail: dm-crypt-help@xxxxxxxx

[Index of Archives]     [Device Mapper Devel]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Packaging]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]     [Fedora Docs]

  Powered by Linux