Commit 9ddcfce9 authored by Ondrej Kozina's avatar Ondrej Kozina

Refactor locking code.

parent 6ba35853
......@@ -128,13 +128,13 @@ static int open_resource(struct crypt_device *cd, const char *res)
return r < 0 ? -err : r;
}
static int acquire_lock_handle(struct crypt_device *cd, const char *device_path, struct crypt_lock_handle *h)
static int acquire_lock_handle(struct crypt_device *cd, struct device *device, struct crypt_lock_handle *h)
{
char res[PATH_MAX];
int dev_fd, fd;
struct stat st;
dev_fd = open(device_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
dev_fd = open(device_path(device), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (dev_fd < 0)
return -EINVAL;
......@@ -159,7 +159,7 @@ static int acquire_lock_handle(struct crypt_device *cd, const char *device_path,
h->mode = DEV_LOCK_BDEV;
} else if (S_ISREG(st.st_mode)) {
// FIXME: workaround for nfsv4
fd = open(device_path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
fd = open(device_path(device), O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (fd < 0)
h->flock_fd = dev_fd;
else {
......@@ -236,40 +236,27 @@ static unsigned device_lock_dec(struct crypt_lock_handle *h)
return --h->refcnt;
}
int device_read_lock_internal(struct crypt_device *cd, struct device *device)
static int acquire_and_verify(struct crypt_device *cd, struct device *device, int flock_op, struct crypt_lock_handle **lock)
{
int r;
struct crypt_lock_handle *h;
if (!device)
return -EINVAL;
h = device_get_lock_handle(device);
if (device_locked(h)) {
device_lock_inc(h);
log_dbg(cd, "Device %s READ lock (or higher) already held.", device_path(device));
return 0;
}
struct crypt_lock_handle *h = malloc(sizeof(*h));
if (!(h = malloc(sizeof(*h))))
if (!h)
return -ENOMEM;
do {
r = acquire_lock_handle(cd, device_path(device), h);
r = acquire_lock_handle(cd, device, h);
if (r)
break;
log_dbg(cd, "Acquiring read lock for device %s.", device_path(device));
if (flock(h->flock_fd, LOCK_SH)) {
log_dbg(cd, "Shared flock failed with errno %d.", errno);
if (flock(h->flock_fd, flock_op)) {
log_dbg(cd, "Flock on fd %d failed with errno %d.", h->flock_fd, errno);
r = -EINVAL;
release_lock_handle(cd, h);
break;
}
log_dbg(cd, "Verifying read lock handle for device %s.", device_path(device));
log_dbg(cd, "Verifying lock handle for %s.", device_path(device));
/*
* check whether another libcryptsetup process removed resource file before this
......@@ -279,7 +266,7 @@ int device_read_lock_internal(struct crypt_device *cd, struct device *device)
if (r) {
flock(h->flock_fd, LOCK_UN);
release_lock_handle(cd, h);
log_dbg(cd, "Read lock handle verification failed.");
log_dbg(cd, "Lock handle verification failed.");
}
} while (r == -EAGAIN);
......@@ -288,6 +275,33 @@ int device_read_lock_internal(struct crypt_device *cd, struct device *device)
return r;
}
*lock = h;
return 0;
}
int device_read_lock_internal(struct crypt_device *cd, struct device *device)
{
int r;
struct crypt_lock_handle *h;
if (!device)
return -EINVAL;
h = device_get_lock_handle(device);
if (device_locked(h)) {
device_lock_inc(h);
log_dbg(cd, "Device %s READ lock (or higher) already held.", device_path(device));
return 0;
}
log_dbg(cd, "Acquiring read lock for device %s.", device_path(device));
r = acquire_and_verify(cd, device, LOCK_SH, &h);
if (r < 0)
return r;
h->type = DEV_LOCK_READ;
h->refcnt = 1;
device_set_lock_handle(device, h);
......@@ -313,41 +327,11 @@ int device_write_lock_internal(struct crypt_device *cd, struct device *device)
return 0;
}
if (!(h = malloc(sizeof(*h))))
return -ENOMEM;
do {
r = acquire_lock_handle(cd, device_path(device), h);
if (r)
break;
log_dbg(cd, "Acquiring write lock for device %s.", device_path(device));
if (flock(h->flock_fd, LOCK_EX)) {
log_dbg(cd, "Exclusive flock failed with errno %d.", errno);
r = -EINVAL;
release_lock_handle(cd, h);
break;
}
log_dbg(cd, "Acquiring write lock for device %s.", device_path(device));
log_dbg(cd, "Verifying write lock handle for device %s.", device_path(device));
/*
* check whether another libcryptsetup process removed resource file before this
* one managed to flock() it. See release_lock_handle() for details
*/
r = verify_lock_handle(device_path(device), h);
if (r) {
flock(h->flock_fd, LOCK_UN);
release_lock_handle(cd, h);
log_dbg(cd, "Write lock handle verification failed.");
}
} while (r == -EAGAIN);
if (r) {
free(h);
r = acquire_and_verify(cd, device, LOCK_EX, &h);
if (r < 0)
return r;
}
h->type = DEV_LOCK_WRITE;
h->refcnt = 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment