IoCtx data_ctx, md_ctx;
WatchCtx *wctx;
bool needs_refresh;
- Mutex lock;
+ Mutex refresh_lock;
+ Mutex lock; // protects access to snapshot and header information
ImageCtx(std::string imgname, IoCtx& p) : snapid(CEPH_NOSNAP),
name(imgname),
needs_refresh(true),
+ refresh_lock("librbd::ImageCtx::refresh_lock"),
lock("librbd::ImageCtx::lock") {
md_ctx.dup(p);
data_ctx.dup(p);
Mutex::Locker l(lock);
dout(1) << " got notification opcode=" << (int)opcode << " ver=" << ver << " cookie=" << cookie << dendl;
if (valid) {
- Mutex::Locker lictx(ictx->lock);
+ Mutex::Locker lictx(ictx->refresh_lock);
ictx->needs_refresh = true;
}
}
uint64_t ver;
if (ictx) {
- ictx->lock.Lock();
+ assert(ictx->lock.is_locked());
+ ictx->refresh_lock.Lock();
ictx->needs_refresh = true;
- ictx->lock.Unlock();
+ ictx->refresh_lock.Unlock();
}
if (pver)
int rollback_image(ImageCtx *ictx, uint64_t snapid)
{
+ assert(ictx->lock.is_locked());
uint64_t numseg = get_max_block(ictx->header);
for (uint64_t i = 0; i < numseg; i++) {
if (r < 0)
return r;
+ Mutex::Locker l(ictx->lock);
r = add_snap(ictx, snap_name);
+
if (r < 0)
return r;
if (r < 0)
return r;
+ Mutex::Locker l(ictx->lock);
snap_t snapid = ictx->get_snapid(snap_name);
if (snapid == CEPH_NOSNAP)
return -ENOENT;
return r;
r = ictx->data_ctx.selfmanaged_snap_remove(snapid);
+
if (r < 0)
return r;
int r = ictx_check(ictx);
if (r < 0)
return r;
+
+ Mutex::Locker l(ictx->lock);
image_info(ictx->header, info, infosize);
return 0;
}
if (r < 0)
return r;
+ Mutex::Locker l(ictx->lock);
// trim
if (size == ictx->header.image_size) {
dout(2) << "no change in size (" << size << " -> " << ictx->header.image_size << ")" << dendl;
bufferlist bl;
bl.append((const char *)&(ictx->header), sizeof(ictx->header));
r = ictx->md_ctx.write(ictx->md_oid(), bl, bl.length(), 0);
+
if (r == -ERANGE)
derr << "operation might have conflicted with another client!" << dendl;
if (r < 0) {
}
dout(2) << "done." << dendl;
+
return 0;
}
return r;
bufferlist bl, bl2;
+ Mutex::Locker l(ictx->lock);
for (std::map<std::string, struct SnapInfo>::iterator it = ictx->snaps_by_name.begin();
it != ictx->snaps_by_name.end(); ++it) {
snap_info_t info;
int add_snap(ImageCtx *ictx, const char *snap_name)
{
+ assert(ictx->lock.is_locked());
+
bufferlist bl, bl2;
uint64_t snap_id;
int rm_snap(ImageCtx *ictx, const char *snap_name)
{
+ assert(ictx->lock.is_locked());
+
bufferlist bl, bl2;
::encode(snap_name, bl);
int ictx_check(ImageCtx *ictx)
{
dout(20) << "ictx_check " << ictx << dendl;
- ictx->lock.Lock();
+ ictx->refresh_lock.Lock();
bool needs_refresh = ictx->needs_refresh;
- ictx->lock.Unlock();
+ ictx->refresh_lock.Unlock();
if (needs_refresh) {
+ Mutex::Locker l(ictx->lock);
const char *snap = NULL;
if (ictx->snapid != CEPH_NOSNAP)
snap = ictx->snapname.c_str();
int ictx_refresh(ImageCtx *ictx, const char *snap_name)
{
+ assert(ictx->lock.is_locked());
bufferlist bl, bl2;
if (snap_name) {
ictx->data_ctx.selfmanaged_snap_set_write_ctx(ictx->snapc.seq, ictx->snaps);
- ictx->lock.Lock();
+ ictx->refresh_lock.Lock();
ictx->needs_refresh = false;
- ictx->lock.Unlock();
+ ictx->refresh_lock.Unlock();
return 0;
}
if (r < 0)
return r;
+ Mutex::Locker l(ictx->lock);
snap_t snapid = ictx->get_snapid(snap_name);
if (snapid == CEPH_NOSNAP) {
derr << "No such snapshot found." << dendl;
if (r < 0)
return r;
+ Mutex::Locker l(ictx->lock);
if (snap_name)
ictx->snap_set(snap_name);
else
dout(20) << "open_image " << &io_ctx << " ictx = " << ictx
<< " name = " << name << " snap_name = " << (snap_name ? snap_name : "NULL") << dendl;
+ ictx->lock.Lock();
int r = ictx_refresh(ictx, snap_name);
+ ictx->lock.Unlock();
if (r < 0)
return r;
void close_image(ImageCtx *ictx)
{
dout(20) << "close_image " << ictx << dendl;
-
+ ictx->lock.Lock();
ictx->wctx->invalidate();
ictx->md_ctx.unwatch(ictx->md_oid(), ictx->wctx->cookie);
delete ictx->wctx;
+ ictx->lock.Unlock();
delete ictx;
- ictx = NULL;
}
int64_t read_iterate(ImageCtx *ictx, uint64_t off, size_t len,
int64_t ret;
int64_t total_read = 0;
+ ictx->lock.Lock();
uint64_t start_block = get_block_num(ictx->header, off);
uint64_t end_block = get_block_num(ictx->header, off + len);
uint64_t block_size = get_block_size(ictx->header);
+ ictx->lock.Unlock();
uint64_t left = len;
for (uint64_t i = start_block; i <= end_block; i++) {
bufferlist bl;
+ ictx->lock.Lock();
string oid = get_block_oid(ictx->header, i);
uint64_t block_ofs = get_block_ofs(ictx->header, off + total_read);
+ ictx->lock.Unlock();
uint64_t read_len = min(block_size - block_ofs, left);
map<uint64_t, uint64_t> m;
return r;
size_t total_write = 0;
+ ictx->lock.Lock();
uint64_t start_block = get_block_num(ictx->header, off);
uint64_t end_block = get_block_num(ictx->header, off + len - 1);
uint64_t block_size = get_block_size(ictx->header);
+ ictx->lock.Unlock();
uint64_t left = len;
for (uint64_t i = start_block; i <= end_block; i++) {
bufferlist bl;
+ ictx->lock.Lock();
string oid = get_block_oid(ictx->header, i);
uint64_t block_ofs = get_block_ofs(ictx->header, off + total_write);
+ ictx->lock.Unlock();
uint64_t write_len = min(block_size - block_ofs, left);
bl.append(buf + total_write, write_len);
r = ictx->data_ctx.write(oid, bl, write_len, block_ofs);
int check_io(ImageCtx *ictx, uint64_t off, uint64_t len)
{
- if ((uint64_t)(off + len) > (uint64_t)ictx->header.image_size)
+ ictx->lock.Lock();
+ uint64_t image_size = ictx->header.image_size;
+ ictx->lock.Unlock();
+
+ if ((uint64_t)(off + len) > image_size)
return -EINVAL;
return 0;
}
return r;
size_t total_write = 0;
+ ictx->lock.Lock();
uint64_t start_block = get_block_num(ictx->header, off);
uint64_t end_block = get_block_num(ictx->header, off + len - 1);
uint64_t block_size = get_block_size(ictx->header);
+ ictx->lock.Unlock();
uint64_t left = len;
r = check_io(ictx, off, len);
for (uint64_t i = start_block; i <= end_block; i++) {
bufferlist bl;
+ ictx->lock.Lock();
string oid = get_block_oid(ictx->header, i);
uint64_t block_ofs = get_block_ofs(ictx->header, off + total_write);
+ ictx->lock.Unlock();
uint64_t write_len = min(block_size - block_ofs, left);
bl.append(buf + total_write, write_len);
AioBlockCompletion *block_completion = new AioBlockCompletion(c, off, len, NULL);
int64_t ret;
int total_read = 0;
+ ictx->lock.Lock();
uint64_t start_block = get_block_num(ictx->header, off);
uint64_t end_block = get_block_num(ictx->header, off + len);
uint64_t block_size = get_block_size(ictx->header);
+ ictx->lock.Unlock();
uint64_t left = len;
for (uint64_t i = start_block; i <= end_block; i++) {
bufferlist bl;
+ ictx->lock.Lock();
string oid = get_block_oid(ictx->header, i);
uint64_t block_ofs = get_block_ofs(ictx->header, off + total_read);
+ ictx->lock.Unlock();
uint64_t read_len = min(block_size - block_ofs, left);
map<uint64_t,uint64_t> m;