Blob Blame History Raw
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