From fd4b1bfc8286025c6d392e9ef787f3bb55f664af Mon Sep 17 00:00:00 2001
From: David Disseldorp <ddiss@suse.de>
Date: Sat, 22 Aug 2015 15:26:22 +0200
Subject: [PATCH] rbd: add rbd_dev_cmpsetxattr helper
Patch-mainline: Not yet, SES2 clustered LIO/RBD
References: fate#318836
Allows for the atomic update of an xattr, by comparing against an
existing string, and writing the new value only if the old value is
matching.
Signed-off-by: David Disseldorp <ddiss@suse.de>
---
drivers/block/rbd.c | 58 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/ceph/librbd.h | 3 ++
2 files changed, 61 insertions(+)
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -1850,6 +1850,7 @@ static void rbd_osd_req_callback(struct
rbd_osd_call_callback(obj_request);
break;
case CEPH_OSD_OP_SETXATTR:
+ case CEPH_OSD_OP_CMPXATTR:
obj_request_done_set(obj_request);
break;
default:
@@ -4759,6 +4760,63 @@ out:
}
EXPORT_SYMBOL(rbd_dev_setxattr);
+int rbd_dev_cmpsetxattr(struct rbd_device *rbd_dev, char *key, void *oldval,
+ int oldval_len, void *newval, int newval_len)
+{
+ struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+ struct rbd_obj_request *obj_request;
+ int ret;
+
+ obj_request = rbd_obj_request_create(rbd_dev->header_name, 0, 0,
+ OBJ_REQUEST_NODATA);
+ if (!obj_request)
+ return -ENOMEM;
+
+ /* XXX need a new op_type? CMPXATTR is a read operation */
+ obj_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_WRITE, 2,
+ obj_request);
+ if (!obj_request->osd_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = osd_req_op_xattr_init(obj_request->osd_req, 0,
+ CEPH_OSD_OP_CMPXATTR,
+ key, oldval, oldval_len,
+ CEPH_OSD_CMPXATTR_OP_EQ,
+ CEPH_OSD_CMPXATTR_MODE_STRING);
+ if (ret)
+ goto out;
+
+ ret = osd_req_op_xattr_init(obj_request->osd_req, 1,
+ CEPH_OSD_OP_SETXATTR,
+ key, newval, newval_len, 0, 0);
+ if (ret)
+ goto out;
+
+ rbd_osd_req_format_write(obj_request);
+
+ ret = rbd_obj_request_submit(osdc, obj_request);
+ if (ret)
+ goto out;
+
+ ret = rbd_obj_request_wait(obj_request);
+ if (ret)
+ goto out;
+
+ ret = obj_request->result;
+ if (ret) {
+ goto out;
+ }
+
+ ret = 0;
+out:
+ rbd_obj_request_put(obj_request);
+
+ return ret;
+}
+EXPORT_SYMBOL(rbd_dev_cmpsetxattr);
+
/*
* TODO: remove me or move to debugfs for final merge.
*/
--- a/include/linux/ceph/librbd.h
+++ b/include/linux/ceph/librbd.h
@@ -201,5 +201,8 @@ extern int rbd_img_request_submit(struct
extern void rbd_img_request_put(struct rbd_img_request *img_request);
extern int rbd_dev_setxattr(struct rbd_device *rbd_dev, char *key, void *val,
int val_len);
+extern int rbd_dev_cmpsetxattr(struct rbd_device *rbd_dev, char *key,
+ void *oldval, int oldval_len, void *newval,
+ int newval_len);
#endif