if (r < 0)
return r;
- r = check_io(ictx, off, len);
+ r = clip_io(ictx, off, &len);
if (r < 0)
return r;
bool done;
int ret;
+ int r = clip_io(ictx, off, &len);
+ if (r < 0)
+ return r;
+
Context *ctx = new C_SafeCond(&mylock, &cond, &done, &ret);
AioCompletion *c = aio_create_completion_internal(ctx, rbd_ctx_cb);
- int r = aio_write(ictx, off, len, buf, c);
+ r = aio_write(ictx, off, len, buf, c);
if (r < 0) {
c->release();
delete ctx;
req->complete(rados_aio_get_return_value(c));
}
- int check_io(ImageCtx *ictx, uint64_t off, uint64_t len)
+ // validate extent against image size; clip to image size if necessary
+ int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len)
{
ictx->md_lock.Lock();
ictx->snap_lock.Lock();
if (!snap_exists)
return -ENOENT;
- if ((uint64_t)(off + len) > image_size)
+ // can't start past end
+ if (off >= image_size)
return -EINVAL;
+
+ // clip requests that extend past end to just end
+ if ((off + *len) > image_size)
+ *len = image_size - off;
+
return 0;
}
if (r < 0)
return r;
- r = check_io(ictx, off, len);
+ r = clip_io(ictx, off, &len);
if (r < 0)
return r;
if (r < 0)
return r;
- r = check_io(ictx, off, len);
+ r = clip_io(ictx, off, &len);
if (r < 0)
return r;
for (vector<pair<uint64_t,uint64_t> >::const_iterator p = image_extents.begin();
p != image_extents.end();
++p) {
- r = check_io(ictx, p->first, p->second);
+ size_t len = p->second;
+ r = clip_io(ictx, p->first, &len);
if (r < 0)
return r;
-
+
Striper::file_to_extents(ictx->cct, ictx->format_string, &ictx->layout,
- p->first, p->second, object_extents, buffer_ofs);
- buffer_ofs += p->second;
+ p->first, len, object_extents, buffer_ofs);
+ buffer_ofs += len;
}
int64_t ret;
std::string get_block_oid(const std::string &object_prefix, uint64_t num,
bool old_format);
uint64_t oid_to_object_no(const string& oid, const string& object_prefix);
- int check_io(ImageCtx *ictx, uint64_t off, uint64_t len);
+ int clip_io(ImageCtx *ictx, uint64_t off, uint64_t *len);
int init_rbd_info(struct rbd_info *info);
void init_rbd_header(struct rbd_obj_header_ondisk& ondisk,
uint64_t size, int *order, uint64_t bid);
rbd_image_info_t info;
rbd_completion_t comp;
ASSERT_EQ(0, rbd_stat(image, &info, sizeof(info)));
+ // can't read or write starting past end
ASSERT_EQ(-EINVAL, rbd_write(image, info.size, 1, test_data));
ASSERT_EQ(-EINVAL, rbd_read(image, info.size, 1, test_data));
+ // reading through end returns amount up to end
+ ASSERT_EQ(10, rbd_read(image, info.size - 10, 100, test_data));
+ // writing through end returns amount up to end
+ ASSERT_EQ(10, rbd_write(image, info.size - 10, 100, test_data));
+
rbd_aio_create_completion(NULL, (rbd_callback_t) simple_read_cb, &comp);
ASSERT_EQ(-EINVAL, rbd_aio_write(image, info.size, 1, test_data, comp));
ASSERT_EQ(-EINVAL, rbd_aio_read(image, info.size, 1, test_data, comp));