--- lib/setup.c (revision 29) +++ lib/setup.c (revision 32) @@ -396,7 +396,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) @@ -705,7 +705,10 @@ static int crypt_job(int (*job)(int arg, backend = get_setup_backend(default_backend); - setup_enter(backend,options->icb->log); + if (setup_enter(backend,options->icb->log) < 0) { + r = -ENOSYS; + goto out; + } if (!backend) { set_error("No setup backend available"); --- lib/internal.h (revision 29) +++ lib/internal.h (revision 32) @@ -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); }; --- lib/libdevmapper.c (revision 29) +++ lib/libdevmapper.c (revision 32) @@ -17,13 +17,7 @@ #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, ...) @@ -38,9 +32,16 @@ static void set_dm_error(int level, cons va_end(va); } +static int _dm_simple(int task, const char *name); + static int dm_init(void) { dm_log_init(set_dm_error); + if (!_dm_simple(DM_DEVICE_LIST_VERSIONS, "test")) { + set_error("Cannot communicate with device-mapper. Is the dm_mod module loaded?"); + return -1; + } + return 1; /* unsafe memory */ } @@ -50,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; @@ -152,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) { @@ -191,24 +265,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: @@ -224,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; } @@ -352,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 (!(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; + if (!options || !options->name) + return -EINVAL; -out: - if (dmt) - dm_task_destroy(dmt); - flush_dm_workqueue(); - return r; + return _dm_remove(options, force);; } --- luks/keyencryption.c (revision 29) +++ luks/keyencryption.c (revision 32) @@ -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,24 +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=0; - static void sigint_handler(int sig) { - if(devfd) + 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); } @@ -160,13 +163,14 @@ static int LUKS_endec_template(char *src r = 0; out3: close(devfd); - devfd = 0; + 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);