libceph: add support for CEPH_OSD_OP_SETALLOCHINT osd op
authorIlya Dryomov <ilya.dryomov@inktank.com>
Tue, 25 Feb 2014 14:22:27 +0000 (16:22 +0200)
committerYan, Zheng <zheng.z.yan@intel.com>
Thu, 3 Apr 2014 02:33:51 +0000 (10:33 +0800)
This is primarily for rbd's benefit and is supposed to combat
fragmentation:

"... knowing that rbd images have a 4m size, librbd can pass a hint
that will let the osd do the xfs allocation size ioctl on new files so
that they are allocated in 1m or 4m chunks.  We've seen cases where
users with rbd workloads have very high levels of fragmentation in xfs
and this would mitigate that and probably have a pretty nice
performance benefit."

SETALLOCHINT is considered advisory, so our backwards compatibility
mechanism here is to set FAILOK flag for all SETALLOCHINT ops.

Signed-off-by: Ilya Dryomov <ilya.dryomov@inktank.com>
Reviewed-by: Sage Weil <sage@inktank.com>
Reviewed-by: Alex Elder <elder@linaro.org>
include/linux/ceph/osd_client.h
include/linux/ceph/rados.h
net/ceph/osd_client.c

index e94f5da251d6a0d518b72db0d2e6517e2c527b04..c42d1ada685f188b51d54ed8795beaead24e70de 100644 (file)
@@ -103,6 +103,10 @@ struct ceph_osd_req_op {
                        u32 timeout;
                        __u8 flag;
                } watch;
+               struct {
+                       u64 expected_object_size;
+                       u64 expected_write_size;
+               } alloc_hint;
        };
 };
 
@@ -294,6 +298,10 @@ extern void osd_req_op_cls_init(struct ceph_osd_request *osd_req,
 extern void osd_req_op_watch_init(struct ceph_osd_request *osd_req,
                                        unsigned int which, u16 opcode,
                                        u64 cookie, u64 version, int flag);
+extern void osd_req_op_alloc_hint_init(struct ceph_osd_request *osd_req,
+                                      unsigned int which,
+                                      u64 expected_object_size,
+                                      u64 expected_write_size);
 
 extern struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
                                               struct ceph_snap_context *snapc,
index 8f9bf4570215b0bad7f3ef1a3149f402b105f9b8..2caabef8d3699f5be195ae0ebce95be3fdc540a6 100644 (file)
@@ -227,6 +227,9 @@ enum {
        CEPH_OSD_OP_OMAPRMKEYS    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 24,
        CEPH_OSD_OP_OMAP_CMP      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 25,
 
+       /* hints */
+       CEPH_OSD_OP_SETALLOCHINT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 35,
+
        /** multi **/
        CEPH_OSD_OP_CLONERANGE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_MULTI | 1,
        CEPH_OSD_OP_ASSERT_SRC_VERSION = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_MULTI | 2,
@@ -416,6 +419,10 @@ struct ceph_osd_op {
                        __le64 offset, length;
                        __le64 src_offset;
                } __attribute__ ((packed)) clonerange;
+               struct {
+                       __le64 expected_object_size;
+                       __le64 expected_write_size;
+               } __attribute__ ((packed)) alloc_hint;
        };
        __le32 payload_len;
 } __attribute__ ((packed));
index 5d7fd0b8c1c8024c665df1a3e3ad6bd06f01ab06..71830d79b0f4fc63f45cf8474db190dec3037249 100644 (file)
@@ -436,6 +436,7 @@ static bool osd_req_opcode_valid(u16 opcode)
        case CEPH_OSD_OP_OMAPCLEAR:
        case CEPH_OSD_OP_OMAPRMKEYS:
        case CEPH_OSD_OP_OMAP_CMP:
+       case CEPH_OSD_OP_SETALLOCHINT:
        case CEPH_OSD_OP_CLONERANGE:
        case CEPH_OSD_OP_ASSERT_SRC_VERSION:
        case CEPH_OSD_OP_SRC_CMPXATTR:
@@ -591,6 +592,26 @@ void osd_req_op_watch_init(struct ceph_osd_request *osd_req,
 }
 EXPORT_SYMBOL(osd_req_op_watch_init);
 
+void osd_req_op_alloc_hint_init(struct ceph_osd_request *osd_req,
+                               unsigned int which,
+                               u64 expected_object_size,
+                               u64 expected_write_size)
+{
+       struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which,
+                                                     CEPH_OSD_OP_SETALLOCHINT);
+
+       op->alloc_hint.expected_object_size = expected_object_size;
+       op->alloc_hint.expected_write_size = expected_write_size;
+
+       /*
+        * CEPH_OSD_OP_SETALLOCHINT op is advisory and therefore deemed
+        * not worth a feature bit.  Set FAILOK per-op flag to make
+        * sure older osds don't trip over an unsupported opcode.
+        */
+       op->flags |= CEPH_OSD_OP_FLAG_FAILOK;
+}
+EXPORT_SYMBOL(osd_req_op_alloc_hint_init);
+
 static void ceph_osdc_msg_data_add(struct ceph_msg *msg,
                                struct ceph_osd_data *osd_data)
 {
@@ -681,6 +702,12 @@ static u64 osd_req_encode_op(struct ceph_osd_request *req,
                dst->watch.ver = cpu_to_le64(src->watch.ver);
                dst->watch.flag = src->watch.flag;
                break;
+       case CEPH_OSD_OP_SETALLOCHINT:
+               dst->alloc_hint.expected_object_size =
+                   cpu_to_le64(src->alloc_hint.expected_object_size);
+               dst->alloc_hint.expected_write_size =
+                   cpu_to_le64(src->alloc_hint.expected_write_size);
+               break;
        default:
                pr_err("unsupported osd opcode %s\n",
                        ceph_osd_op_name(src->op));