mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client
Pull Ceph updates from Sage Weil: "There is the long-awaited discard support for RBD (Guangliang Zhao, Josh Durgin), a pile of RBD bug fixes that didn't belong in late -rc's (Ilya Dryomov, Li RongQing), a pile of fs/ceph bug fixes and performance and debugging improvements (Yan, Zheng, John Spray), and a smattering of cleanups (Chao Yu, Fabian Frederick, Joe Perches)" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client: (40 commits) ceph: fix divide-by-zero in __validate_layout() rbd: rbd workqueues need a resque worker libceph: ceph-msgr workqueue needs a resque worker ceph: fix bool assignments libceph: separate multiple ops with commas in debugfs output libceph: sync osd op definitions in rados.h libceph: remove redundant declaration ceph: additional debugfs output ceph: export ceph_session_state_name function ceph: include the initial ACL in create/mkdir/mknod MDS requests ceph: use pagelist to present MDS request data libceph: reference counting pagelist ceph: fix llistxattr on symlink ceph: send client metadata to MDS ceph: remove redundant code for max file size verification ceph: remove redundant io_iter_advance() ceph: move ceph_find_inode() outside the s_mutex ceph: request xattrs if xattr_version is zero rbd: set the remaining discard properties to enable support rbd: use helpers to handle discard for layered images correctly ...
This commit is contained in:
commit
6b04908166
25 changed files with 948 additions and 623 deletions
|
|
@ -210,6 +210,12 @@ enum obj_request_type {
|
|||
OBJ_REQUEST_NODATA, OBJ_REQUEST_BIO, OBJ_REQUEST_PAGES
|
||||
};
|
||||
|
||||
enum obj_operation_type {
|
||||
OBJ_OP_WRITE,
|
||||
OBJ_OP_READ,
|
||||
OBJ_OP_DISCARD,
|
||||
};
|
||||
|
||||
enum obj_req_flags {
|
||||
OBJ_REQ_DONE, /* completion flag: not done = 0, done = 1 */
|
||||
OBJ_REQ_IMG_DATA, /* object usage: standalone = 0, image = 1 */
|
||||
|
|
@ -276,6 +282,7 @@ enum img_req_flags {
|
|||
IMG_REQ_WRITE, /* I/O direction: read = 0, write = 1 */
|
||||
IMG_REQ_CHILD, /* initiator: block = 0, child image = 1 */
|
||||
IMG_REQ_LAYERED, /* ENOENT handling: normal = 0, layered = 1 */
|
||||
IMG_REQ_DISCARD, /* discard: normal = 0, discard request = 1 */
|
||||
};
|
||||
|
||||
struct rbd_img_request {
|
||||
|
|
@ -785,6 +792,20 @@ static int parse_rbd_opts_token(char *c, void *private)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char* obj_op_name(enum obj_operation_type op_type)
|
||||
{
|
||||
switch (op_type) {
|
||||
case OBJ_OP_READ:
|
||||
return "read";
|
||||
case OBJ_OP_WRITE:
|
||||
return "write";
|
||||
case OBJ_OP_DISCARD:
|
||||
return "discard";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a ceph client with specific addr and configuration, if one does
|
||||
* not exist create it. Either way, ceph_opts is consumed by this
|
||||
|
|
@ -1600,6 +1621,21 @@ static bool img_request_write_test(struct rbd_img_request *img_request)
|
|||
return test_bit(IMG_REQ_WRITE, &img_request->flags) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the discard flag when the img_request is an discard request
|
||||
*/
|
||||
static void img_request_discard_set(struct rbd_img_request *img_request)
|
||||
{
|
||||
set_bit(IMG_REQ_DISCARD, &img_request->flags);
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
static bool img_request_discard_test(struct rbd_img_request *img_request)
|
||||
{
|
||||
smp_mb();
|
||||
return test_bit(IMG_REQ_DISCARD, &img_request->flags) != 0;
|
||||
}
|
||||
|
||||
static void img_request_child_set(struct rbd_img_request *img_request)
|
||||
{
|
||||
set_bit(IMG_REQ_CHILD, &img_request->flags);
|
||||
|
|
@ -1636,6 +1672,17 @@ static bool img_request_layered_test(struct rbd_img_request *img_request)
|
|||
return test_bit(IMG_REQ_LAYERED, &img_request->flags) != 0;
|
||||
}
|
||||
|
||||
static enum obj_operation_type
|
||||
rbd_img_request_op_type(struct rbd_img_request *img_request)
|
||||
{
|
||||
if (img_request_write_test(img_request))
|
||||
return OBJ_OP_WRITE;
|
||||
else if (img_request_discard_test(img_request))
|
||||
return OBJ_OP_DISCARD;
|
||||
else
|
||||
return OBJ_OP_READ;
|
||||
}
|
||||
|
||||
static void
|
||||
rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
|
||||
{
|
||||
|
|
@ -1722,6 +1769,21 @@ static void rbd_osd_write_callback(struct rbd_obj_request *obj_request)
|
|||
obj_request_done_set(obj_request);
|
||||
}
|
||||
|
||||
static void rbd_osd_discard_callback(struct rbd_obj_request *obj_request)
|
||||
{
|
||||
dout("%s: obj %p result %d %llu\n", __func__, obj_request,
|
||||
obj_request->result, obj_request->length);
|
||||
/*
|
||||
* There is no such thing as a successful short discard. Set
|
||||
* it to our originally-requested length.
|
||||
*/
|
||||
obj_request->xferred = obj_request->length;
|
||||
/* discarding a non-existent object is not a problem */
|
||||
if (obj_request->result == -ENOENT)
|
||||
obj_request->result = 0;
|
||||
obj_request_done_set(obj_request);
|
||||
}
|
||||
|
||||
/*
|
||||
* For a simple stat call there's nothing to do. We'll do more if
|
||||
* this is part of a write sequence for a layered image.
|
||||
|
|
@ -1773,6 +1835,11 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
|
|||
case CEPH_OSD_OP_STAT:
|
||||
rbd_osd_stat_callback(obj_request);
|
||||
break;
|
||||
case CEPH_OSD_OP_DELETE:
|
||||
case CEPH_OSD_OP_TRUNCATE:
|
||||
case CEPH_OSD_OP_ZERO:
|
||||
rbd_osd_discard_callback(obj_request);
|
||||
break;
|
||||
case CEPH_OSD_OP_CALL:
|
||||
case CEPH_OSD_OP_NOTIFY_ACK:
|
||||
case CEPH_OSD_OP_WATCH:
|
||||
|
|
@ -1823,7 +1890,7 @@ static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
|
|||
*/
|
||||
static struct ceph_osd_request *rbd_osd_req_create(
|
||||
struct rbd_device *rbd_dev,
|
||||
bool write_request,
|
||||
enum obj_operation_type op_type,
|
||||
unsigned int num_ops,
|
||||
struct rbd_obj_request *obj_request)
|
||||
{
|
||||
|
|
@ -1831,16 +1898,18 @@ static struct ceph_osd_request *rbd_osd_req_create(
|
|||
struct ceph_osd_client *osdc;
|
||||
struct ceph_osd_request *osd_req;
|
||||
|
||||
if (obj_request_img_data_test(obj_request)) {
|
||||
if (obj_request_img_data_test(obj_request) &&
|
||||
(op_type == OBJ_OP_DISCARD || op_type == OBJ_OP_WRITE)) {
|
||||
struct rbd_img_request *img_request = obj_request->img_request;
|
||||
|
||||
rbd_assert(write_request ==
|
||||
img_request_write_test(img_request));
|
||||
if (write_request)
|
||||
snapc = img_request->snapc;
|
||||
if (op_type == OBJ_OP_WRITE) {
|
||||
rbd_assert(img_request_write_test(img_request));
|
||||
} else {
|
||||
rbd_assert(img_request_discard_test(img_request));
|
||||
}
|
||||
snapc = img_request->snapc;
|
||||
}
|
||||
|
||||
rbd_assert(num_ops == 1 || (write_request && num_ops == 2));
|
||||
rbd_assert(num_ops == 1 || ((op_type == OBJ_OP_WRITE) && num_ops == 2));
|
||||
|
||||
/* Allocate and initialize the request, for the num_ops ops */
|
||||
|
||||
|
|
@ -1850,7 +1919,7 @@ static struct ceph_osd_request *rbd_osd_req_create(
|
|||
if (!osd_req)
|
||||
return NULL; /* ENOMEM */
|
||||
|
||||
if (write_request)
|
||||
if (op_type == OBJ_OP_WRITE || op_type == OBJ_OP_DISCARD)
|
||||
osd_req->r_flags = CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK;
|
||||
else
|
||||
osd_req->r_flags = CEPH_OSD_FLAG_READ;
|
||||
|
|
@ -1865,9 +1934,10 @@ static struct ceph_osd_request *rbd_osd_req_create(
|
|||
}
|
||||
|
||||
/*
|
||||
* Create a copyup osd request based on the information in the
|
||||
* object request supplied. A copyup request has three osd ops,
|
||||
* a copyup method call, a hint op, and a write op.
|
||||
* Create a copyup osd request based on the information in the object
|
||||
* request supplied. A copyup request has two or three osd ops, a
|
||||
* copyup method call, potentially a hint op, and a write or truncate
|
||||
* or zero op.
|
||||
*/
|
||||
static struct ceph_osd_request *
|
||||
rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
|
||||
|
|
@ -1877,18 +1947,24 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
|
|||
struct rbd_device *rbd_dev;
|
||||
struct ceph_osd_client *osdc;
|
||||
struct ceph_osd_request *osd_req;
|
||||
int num_osd_ops = 3;
|
||||
|
||||
rbd_assert(obj_request_img_data_test(obj_request));
|
||||
img_request = obj_request->img_request;
|
||||
rbd_assert(img_request);
|
||||
rbd_assert(img_request_write_test(img_request));
|
||||
rbd_assert(img_request_write_test(img_request) ||
|
||||
img_request_discard_test(img_request));
|
||||
|
||||
/* Allocate and initialize the request, for the three ops */
|
||||
if (img_request_discard_test(img_request))
|
||||
num_osd_ops = 2;
|
||||
|
||||
/* Allocate and initialize the request, for all the ops */
|
||||
|
||||
snapc = img_request->snapc;
|
||||
rbd_dev = img_request->rbd_dev;
|
||||
osdc = &rbd_dev->rbd_client->client->osdc;
|
||||
osd_req = ceph_osdc_alloc_request(osdc, snapc, 3, false, GFP_ATOMIC);
|
||||
osd_req = ceph_osdc_alloc_request(osdc, snapc, num_osd_ops,
|
||||
false, GFP_ATOMIC);
|
||||
if (!osd_req)
|
||||
return NULL; /* ENOMEM */
|
||||
|
||||
|
|
@ -2057,7 +2133,8 @@ static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
|
|||
static struct rbd_img_request *rbd_img_request_create(
|
||||
struct rbd_device *rbd_dev,
|
||||
u64 offset, u64 length,
|
||||
bool write_request)
|
||||
enum obj_operation_type op_type,
|
||||
struct ceph_snap_context *snapc)
|
||||
{
|
||||
struct rbd_img_request *img_request;
|
||||
|
||||
|
|
@ -2065,20 +2142,17 @@ static struct rbd_img_request *rbd_img_request_create(
|
|||
if (!img_request)
|
||||
return NULL;
|
||||
|
||||
if (write_request) {
|
||||
down_read(&rbd_dev->header_rwsem);
|
||||
ceph_get_snap_context(rbd_dev->header.snapc);
|
||||
up_read(&rbd_dev->header_rwsem);
|
||||
}
|
||||
|
||||
img_request->rq = NULL;
|
||||
img_request->rbd_dev = rbd_dev;
|
||||
img_request->offset = offset;
|
||||
img_request->length = length;
|
||||
img_request->flags = 0;
|
||||
if (write_request) {
|
||||
if (op_type == OBJ_OP_DISCARD) {
|
||||
img_request_discard_set(img_request);
|
||||
img_request->snapc = snapc;
|
||||
} else if (op_type == OBJ_OP_WRITE) {
|
||||
img_request_write_set(img_request);
|
||||
img_request->snapc = rbd_dev->header.snapc;
|
||||
img_request->snapc = snapc;
|
||||
} else {
|
||||
img_request->snap_id = rbd_dev->spec->snap_id;
|
||||
}
|
||||
|
|
@ -2093,8 +2167,7 @@ static struct rbd_img_request *rbd_img_request_create(
|
|||
kref_init(&img_request->kref);
|
||||
|
||||
dout("%s: rbd_dev %p %s %llu/%llu -> img %p\n", __func__, rbd_dev,
|
||||
write_request ? "write" : "read", offset, length,
|
||||
img_request);
|
||||
obj_op_name(op_type), offset, length, img_request);
|
||||
|
||||
return img_request;
|
||||
}
|
||||
|
|
@ -2118,7 +2191,8 @@ static void rbd_img_request_destroy(struct kref *kref)
|
|||
rbd_dev_parent_put(img_request->rbd_dev);
|
||||
}
|
||||
|
||||
if (img_request_write_test(img_request))
|
||||
if (img_request_write_test(img_request) ||
|
||||
img_request_discard_test(img_request))
|
||||
ceph_put_snap_context(img_request->snapc);
|
||||
|
||||
kmem_cache_free(rbd_img_request_cache, img_request);
|
||||
|
|
@ -2134,8 +2208,8 @@ static struct rbd_img_request *rbd_parent_request_create(
|
|||
rbd_assert(obj_request->img_request);
|
||||
rbd_dev = obj_request->img_request->rbd_dev;
|
||||
|
||||
parent_request = rbd_img_request_create(rbd_dev->parent,
|
||||
img_offset, length, false);
|
||||
parent_request = rbd_img_request_create(rbd_dev->parent, img_offset,
|
||||
length, OBJ_OP_READ, NULL);
|
||||
if (!parent_request)
|
||||
return NULL;
|
||||
|
||||
|
|
@ -2176,11 +2250,18 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request)
|
|||
result = obj_request->result;
|
||||
if (result) {
|
||||
struct rbd_device *rbd_dev = img_request->rbd_dev;
|
||||
enum obj_operation_type op_type;
|
||||
|
||||
if (img_request_discard_test(img_request))
|
||||
op_type = OBJ_OP_DISCARD;
|
||||
else if (img_request_write_test(img_request))
|
||||
op_type = OBJ_OP_WRITE;
|
||||
else
|
||||
op_type = OBJ_OP_READ;
|
||||
|
||||
rbd_warn(rbd_dev, "%s %llx at %llx (%llx)",
|
||||
img_request_write_test(img_request) ? "write" : "read",
|
||||
obj_request->length, obj_request->img_offset,
|
||||
obj_request->offset);
|
||||
obj_op_name(op_type), obj_request->length,
|
||||
obj_request->img_offset, obj_request->offset);
|
||||
rbd_warn(rbd_dev, " result %d xferred %x",
|
||||
result, xferred);
|
||||
if (!img_request->result)
|
||||
|
|
@ -2244,6 +2325,67 @@ out:
|
|||
rbd_img_request_complete(img_request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add individual osd ops to the given ceph_osd_request and prepare
|
||||
* them for submission. num_ops is the current number of
|
||||
* osd operations already to the object request.
|
||||
*/
|
||||
static void rbd_img_obj_request_fill(struct rbd_obj_request *obj_request,
|
||||
struct ceph_osd_request *osd_request,
|
||||
enum obj_operation_type op_type,
|
||||
unsigned int num_ops)
|
||||
{
|
||||
struct rbd_img_request *img_request = obj_request->img_request;
|
||||
struct rbd_device *rbd_dev = img_request->rbd_dev;
|
||||
u64 object_size = rbd_obj_bytes(&rbd_dev->header);
|
||||
u64 offset = obj_request->offset;
|
||||
u64 length = obj_request->length;
|
||||
u64 img_end;
|
||||
u16 opcode;
|
||||
|
||||
if (op_type == OBJ_OP_DISCARD) {
|
||||
if (!offset && length == object_size &&
|
||||
(!img_request_layered_test(img_request) ||
|
||||
!obj_request_overlaps_parent(obj_request))) {
|
||||
opcode = CEPH_OSD_OP_DELETE;
|
||||
} else if ((offset + length == object_size)) {
|
||||
opcode = CEPH_OSD_OP_TRUNCATE;
|
||||
} else {
|
||||
down_read(&rbd_dev->header_rwsem);
|
||||
img_end = rbd_dev->header.image_size;
|
||||
up_read(&rbd_dev->header_rwsem);
|
||||
|
||||
if (obj_request->img_offset + length == img_end)
|
||||
opcode = CEPH_OSD_OP_TRUNCATE;
|
||||
else
|
||||
opcode = CEPH_OSD_OP_ZERO;
|
||||
}
|
||||
} else if (op_type == OBJ_OP_WRITE) {
|
||||
opcode = CEPH_OSD_OP_WRITE;
|
||||
osd_req_op_alloc_hint_init(osd_request, num_ops,
|
||||
object_size, object_size);
|
||||
num_ops++;
|
||||
} else {
|
||||
opcode = CEPH_OSD_OP_READ;
|
||||
}
|
||||
|
||||
osd_req_op_extent_init(osd_request, num_ops, opcode, offset, length,
|
||||
0, 0);
|
||||
if (obj_request->type == OBJ_REQUEST_BIO)
|
||||
osd_req_op_extent_osd_data_bio(osd_request, num_ops,
|
||||
obj_request->bio_list, length);
|
||||
else if (obj_request->type == OBJ_REQUEST_PAGES)
|
||||
osd_req_op_extent_osd_data_pages(osd_request, num_ops,
|
||||
obj_request->pages, length,
|
||||
offset & ~PAGE_MASK, false, false);
|
||||
|
||||
/* Discards are also writes */
|
||||
if (op_type == OBJ_OP_WRITE || op_type == OBJ_OP_DISCARD)
|
||||
rbd_osd_req_format_write(obj_request);
|
||||
else
|
||||
rbd_osd_req_format_read(obj_request);
|
||||
}
|
||||
|
||||
/*
|
||||
* Split up an image request into one or more object requests, each
|
||||
* to a different object. The "type" parameter indicates whether
|
||||
|
|
@ -2259,28 +2401,26 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
|
|||
struct rbd_device *rbd_dev = img_request->rbd_dev;
|
||||
struct rbd_obj_request *obj_request = NULL;
|
||||
struct rbd_obj_request *next_obj_request;
|
||||
bool write_request = img_request_write_test(img_request);
|
||||
struct bio *bio_list = NULL;
|
||||
unsigned int bio_offset = 0;
|
||||
struct page **pages = NULL;
|
||||
enum obj_operation_type op_type;
|
||||
u64 img_offset;
|
||||
u64 resid;
|
||||
u16 opcode;
|
||||
|
||||
dout("%s: img %p type %d data_desc %p\n", __func__, img_request,
|
||||
(int)type, data_desc);
|
||||
|
||||
opcode = write_request ? CEPH_OSD_OP_WRITE : CEPH_OSD_OP_READ;
|
||||
img_offset = img_request->offset;
|
||||
resid = img_request->length;
|
||||
rbd_assert(resid > 0);
|
||||
op_type = rbd_img_request_op_type(img_request);
|
||||
|
||||
if (type == OBJ_REQUEST_BIO) {
|
||||
bio_list = data_desc;
|
||||
rbd_assert(img_offset ==
|
||||
bio_list->bi_iter.bi_sector << SECTOR_SHIFT);
|
||||
} else {
|
||||
rbd_assert(type == OBJ_REQUEST_PAGES);
|
||||
} else if (type == OBJ_REQUEST_PAGES) {
|
||||
pages = data_desc;
|
||||
}
|
||||
|
||||
|
|
@ -2289,7 +2429,6 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
|
|||
const char *object_name;
|
||||
u64 offset;
|
||||
u64 length;
|
||||
unsigned int which = 0;
|
||||
|
||||
object_name = rbd_segment_name(rbd_dev, img_offset);
|
||||
if (!object_name)
|
||||
|
|
@ -2321,7 +2460,7 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
|
|||
GFP_ATOMIC);
|
||||
if (!obj_request->bio_list)
|
||||
goto out_unwind;
|
||||
} else {
|
||||
} else if (type == OBJ_REQUEST_PAGES) {
|
||||
unsigned int page_count;
|
||||
|
||||
obj_request->pages = pages;
|
||||
|
|
@ -2332,39 +2471,20 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
|
|||
pages += page_count;
|
||||
}
|
||||
|
||||
osd_req = rbd_osd_req_create(rbd_dev, write_request,
|
||||
(write_request ? 2 : 1),
|
||||
obj_request);
|
||||
osd_req = rbd_osd_req_create(rbd_dev, op_type,
|
||||
(op_type == OBJ_OP_WRITE) ? 2 : 1,
|
||||
obj_request);
|
||||
if (!osd_req)
|
||||
goto out_unwind;
|
||||
|
||||
obj_request->osd_req = osd_req;
|
||||
obj_request->callback = rbd_img_obj_callback;
|
||||
rbd_img_request_get(img_request);
|
||||
|
||||
if (write_request) {
|
||||
osd_req_op_alloc_hint_init(osd_req, which,
|
||||
rbd_obj_bytes(&rbd_dev->header),
|
||||
rbd_obj_bytes(&rbd_dev->header));
|
||||
which++;
|
||||
}
|
||||
|
||||
osd_req_op_extent_init(osd_req, which, opcode, offset, length,
|
||||
0, 0);
|
||||
if (type == OBJ_REQUEST_BIO)
|
||||
osd_req_op_extent_osd_data_bio(osd_req, which,
|
||||
obj_request->bio_list, length);
|
||||
else
|
||||
osd_req_op_extent_osd_data_pages(osd_req, which,
|
||||
obj_request->pages, length,
|
||||
offset & ~PAGE_MASK, false, false);
|
||||
|
||||
if (write_request)
|
||||
rbd_osd_req_format_write(obj_request);
|
||||
else
|
||||
rbd_osd_req_format_read(obj_request);
|
||||
|
||||
obj_request->img_offset = img_offset;
|
||||
|
||||
rbd_img_obj_request_fill(obj_request, osd_req, op_type, 0);
|
||||
|
||||
rbd_img_request_get(img_request);
|
||||
|
||||
img_offset += length;
|
||||
resid -= length;
|
||||
}
|
||||
|
|
@ -2386,7 +2506,8 @@ rbd_img_obj_copyup_callback(struct rbd_obj_request *obj_request)
|
|||
struct page **pages;
|
||||
u32 page_count;
|
||||
|
||||
rbd_assert(obj_request->type == OBJ_REQUEST_BIO);
|
||||
rbd_assert(obj_request->type == OBJ_REQUEST_BIO ||
|
||||
obj_request->type == OBJ_REQUEST_NODATA);
|
||||
rbd_assert(obj_request_img_data_test(obj_request));
|
||||
img_request = obj_request->img_request;
|
||||
rbd_assert(img_request);
|
||||
|
|
@ -2424,11 +2545,10 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
|
|||
struct ceph_osd_client *osdc;
|
||||
struct rbd_device *rbd_dev;
|
||||
struct page **pages;
|
||||
enum obj_operation_type op_type;
|
||||
u32 page_count;
|
||||
int img_result;
|
||||
u64 parent_length;
|
||||
u64 offset;
|
||||
u64 length;
|
||||
|
||||
rbd_assert(img_request_child_test(img_request));
|
||||
|
||||
|
|
@ -2492,26 +2612,10 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
|
|||
osd_req_op_cls_request_data_pages(osd_req, 0, pages, parent_length, 0,
|
||||
false, false);
|
||||
|
||||
/* Then the hint op */
|
||||
/* Add the other op(s) */
|
||||
|
||||
osd_req_op_alloc_hint_init(osd_req, 1, rbd_obj_bytes(&rbd_dev->header),
|
||||
rbd_obj_bytes(&rbd_dev->header));
|
||||
|
||||
/* And the original write request op */
|
||||
|
||||
offset = orig_request->offset;
|
||||
length = orig_request->length;
|
||||
osd_req_op_extent_init(osd_req, 2, CEPH_OSD_OP_WRITE,
|
||||
offset, length, 0, 0);
|
||||
if (orig_request->type == OBJ_REQUEST_BIO)
|
||||
osd_req_op_extent_osd_data_bio(osd_req, 2,
|
||||
orig_request->bio_list, length);
|
||||
else
|
||||
osd_req_op_extent_osd_data_pages(osd_req, 2,
|
||||
orig_request->pages, length,
|
||||
offset & ~PAGE_MASK, false, false);
|
||||
|
||||
rbd_osd_req_format_write(orig_request);
|
||||
op_type = rbd_img_request_op_type(orig_request->img_request);
|
||||
rbd_img_obj_request_fill(orig_request, osd_req, op_type, 1);
|
||||
|
||||
/* All set, send it off. */
|
||||
|
||||
|
|
@ -2728,7 +2832,7 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
|
|||
|
||||
rbd_assert(obj_request->img_request);
|
||||
rbd_dev = obj_request->img_request->rbd_dev;
|
||||
stat_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
|
||||
stat_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
|
||||
stat_request);
|
||||
if (!stat_request->osd_req)
|
||||
goto out;
|
||||
|
|
@ -2748,11 +2852,10 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request)
|
||||
static bool img_obj_request_simple(struct rbd_obj_request *obj_request)
|
||||
{
|
||||
struct rbd_img_request *img_request;
|
||||
struct rbd_device *rbd_dev;
|
||||
bool known;
|
||||
|
||||
rbd_assert(obj_request_img_data_test(obj_request));
|
||||
|
||||
|
|
@ -2760,22 +2863,44 @@ static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request)
|
|||
rbd_assert(img_request);
|
||||
rbd_dev = img_request->rbd_dev;
|
||||
|
||||
/*
|
||||
* Only writes to layered images need special handling.
|
||||
* Reads and non-layered writes are simple object requests.
|
||||
* Layered writes that start beyond the end of the overlap
|
||||
* with the parent have no parent data, so they too are
|
||||
* simple object requests. Finally, if the target object is
|
||||
* known to already exist, its parent data has already been
|
||||
* copied, so a write to the object can also be handled as a
|
||||
* simple object request.
|
||||
*/
|
||||
if (!img_request_write_test(img_request) ||
|
||||
!img_request_layered_test(img_request) ||
|
||||
!obj_request_overlaps_parent(obj_request) ||
|
||||
((known = obj_request_known_test(obj_request)) &&
|
||||
obj_request_exists_test(obj_request))) {
|
||||
/* Reads */
|
||||
if (!img_request_write_test(img_request) &&
|
||||
!img_request_discard_test(img_request))
|
||||
return true;
|
||||
|
||||
/* Non-layered writes */
|
||||
if (!img_request_layered_test(img_request))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Layered writes outside of the parent overlap range don't
|
||||
* share any data with the parent.
|
||||
*/
|
||||
if (!obj_request_overlaps_parent(obj_request))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Entire-object layered writes - we will overwrite whatever
|
||||
* parent data there is anyway.
|
||||
*/
|
||||
if (!obj_request->offset &&
|
||||
obj_request->length == rbd_obj_bytes(&rbd_dev->header))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* If the object is known to already exist, its parent data has
|
||||
* already been copied.
|
||||
*/
|
||||
if (obj_request_known_test(obj_request) &&
|
||||
obj_request_exists_test(obj_request))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request)
|
||||
{
|
||||
if (img_obj_request_simple(obj_request)) {
|
||||
struct rbd_device *rbd_dev;
|
||||
struct ceph_osd_client *osdc;
|
||||
|
||||
|
|
@ -2791,7 +2916,7 @@ static int rbd_img_obj_request_submit(struct rbd_obj_request *obj_request)
|
|||
* start by reading the data for the full target object from
|
||||
* the parent so we can use it for a copyup to the target.
|
||||
*/
|
||||
if (known)
|
||||
if (obj_request_known_test(obj_request))
|
||||
return rbd_img_obj_parent_read_full(obj_request);
|
||||
|
||||
/* We don't know whether the target exists. Go find out. */
|
||||
|
|
@ -2932,7 +3057,7 @@ static int rbd_obj_notify_ack_sync(struct rbd_device *rbd_dev, u64 notify_id)
|
|||
return -ENOMEM;
|
||||
|
||||
ret = -ENOMEM;
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
|
||||
obj_request);
|
||||
if (!obj_request->osd_req)
|
||||
goto out;
|
||||
|
|
@ -2995,7 +3120,7 @@ static struct rbd_obj_request *rbd_obj_watch_request_helper(
|
|||
if (!obj_request)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, true, 1,
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_WRITE, 1,
|
||||
obj_request);
|
||||
if (!obj_request->osd_req) {
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -3133,7 +3258,7 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
|
|||
obj_request->pages = pages;
|
||||
obj_request->page_count = page_count;
|
||||
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
|
||||
obj_request);
|
||||
if (!obj_request->osd_req)
|
||||
goto out;
|
||||
|
|
@ -3183,11 +3308,20 @@ out:
|
|||
static void rbd_handle_request(struct rbd_device *rbd_dev, struct request *rq)
|
||||
{
|
||||
struct rbd_img_request *img_request;
|
||||
struct ceph_snap_context *snapc = NULL;
|
||||
u64 offset = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
|
||||
u64 length = blk_rq_bytes(rq);
|
||||
bool wr = rq_data_dir(rq) == WRITE;
|
||||
enum obj_operation_type op_type;
|
||||
u64 mapping_size;
|
||||
int result;
|
||||
|
||||
if (rq->cmd_flags & REQ_DISCARD)
|
||||
op_type = OBJ_OP_DISCARD;
|
||||
else if (rq->cmd_flags & REQ_WRITE)
|
||||
op_type = OBJ_OP_WRITE;
|
||||
else
|
||||
op_type = OBJ_OP_READ;
|
||||
|
||||
/* Ignore/skip any zero-length requests */
|
||||
|
||||
if (!length) {
|
||||
|
|
@ -3196,9 +3330,9 @@ static void rbd_handle_request(struct rbd_device *rbd_dev, struct request *rq)
|
|||
goto err_rq;
|
||||
}
|
||||
|
||||
/* Disallow writes to a read-only device */
|
||||
/* Only reads are allowed to a read-only device */
|
||||
|
||||
if (wr) {
|
||||
if (op_type != OBJ_OP_READ) {
|
||||
if (rbd_dev->mapping.read_only) {
|
||||
result = -EROFS;
|
||||
goto err_rq;
|
||||
|
|
@ -3226,21 +3360,35 @@ static void rbd_handle_request(struct rbd_device *rbd_dev, struct request *rq)
|
|||
goto err_rq; /* Shouldn't happen */
|
||||
}
|
||||
|
||||
if (offset + length > rbd_dev->mapping.size) {
|
||||
down_read(&rbd_dev->header_rwsem);
|
||||
mapping_size = rbd_dev->mapping.size;
|
||||
if (op_type != OBJ_OP_READ) {
|
||||
snapc = rbd_dev->header.snapc;
|
||||
ceph_get_snap_context(snapc);
|
||||
}
|
||||
up_read(&rbd_dev->header_rwsem);
|
||||
|
||||
if (offset + length > mapping_size) {
|
||||
rbd_warn(rbd_dev, "beyond EOD (%llu~%llu > %llu)", offset,
|
||||
length, rbd_dev->mapping.size);
|
||||
length, mapping_size);
|
||||
result = -EIO;
|
||||
goto err_rq;
|
||||
}
|
||||
|
||||
img_request = rbd_img_request_create(rbd_dev, offset, length, wr);
|
||||
img_request = rbd_img_request_create(rbd_dev, offset, length, op_type,
|
||||
snapc);
|
||||
if (!img_request) {
|
||||
result = -ENOMEM;
|
||||
goto err_rq;
|
||||
}
|
||||
img_request->rq = rq;
|
||||
|
||||
result = rbd_img_request_fill(img_request, OBJ_REQUEST_BIO, rq->bio);
|
||||
if (op_type == OBJ_OP_DISCARD)
|
||||
result = rbd_img_request_fill(img_request, OBJ_REQUEST_NODATA,
|
||||
NULL);
|
||||
else
|
||||
result = rbd_img_request_fill(img_request, OBJ_REQUEST_BIO,
|
||||
rq->bio);
|
||||
if (result)
|
||||
goto err_img_request;
|
||||
|
||||
|
|
@ -3255,7 +3403,9 @@ err_img_request:
|
|||
err_rq:
|
||||
if (result)
|
||||
rbd_warn(rbd_dev, "%s %llx at %llx result %d",
|
||||
wr ? "write" : "read", length, offset, result);
|
||||
obj_op_name(op_type), length, offset, result);
|
||||
if (snapc)
|
||||
ceph_put_snap_context(snapc);
|
||||
blk_end_request_all(rq, result);
|
||||
}
|
||||
|
||||
|
|
@ -3393,7 +3543,7 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
|
|||
obj_request->pages = pages;
|
||||
obj_request->page_count = page_count;
|
||||
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
|
||||
obj_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
|
||||
obj_request);
|
||||
if (!obj_request->osd_req)
|
||||
goto out;
|
||||
|
|
@ -3610,6 +3760,13 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
|
|||
blk_queue_io_min(q, segment_size);
|
||||
blk_queue_io_opt(q, segment_size);
|
||||
|
||||
/* enable the discard support */
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
|
||||
q->limits.discard_granularity = segment_size;
|
||||
q->limits.discard_alignment = segment_size;
|
||||
q->limits.max_discard_sectors = segment_size / SECTOR_SIZE;
|
||||
q->limits.discard_zeroes_data = 1;
|
||||
|
||||
blk_queue_merge_bvec(q, rbd_merge_bvec);
|
||||
disk->queue = q;
|
||||
|
||||
|
|
@ -4924,7 +5081,7 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev)
|
|||
ret = image_id ? 0 : -ENOMEM;
|
||||
if (!ret)
|
||||
rbd_dev->image_format = 1;
|
||||
} else if (ret > sizeof (__le32)) {
|
||||
} else if (ret >= 0) {
|
||||
void *p = response;
|
||||
|
||||
image_id = ceph_extract_encoded_string(&p, p + ret,
|
||||
|
|
@ -4932,8 +5089,6 @@ static int rbd_dev_image_id(struct rbd_device *rbd_dev)
|
|||
ret = PTR_ERR_OR_ZERO(image_id);
|
||||
if (!ret)
|
||||
rbd_dev->image_format = 2;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
|
|
@ -5087,7 +5242,8 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
|
|||
set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
|
||||
set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only);
|
||||
|
||||
rbd_dev->rq_wq = alloc_workqueue("%s", 0, 0, rbd_dev->disk->disk_name);
|
||||
rbd_dev->rq_wq = alloc_workqueue("%s", WQ_MEM_RECLAIM, 0,
|
||||
rbd_dev->disk->disk_name);
|
||||
if (!rbd_dev->rq_wq) {
|
||||
ret = -ENOMEM;
|
||||
goto err_out_mapping;
|
||||
|
|
|
|||
Loading…
Reference in a new issue