Blob Blame History Raw
From be919cad35548f616ccce979b4ab3d4ed6e1e28d Mon Sep 17 00:00:00 2001
From: David Disseldorp <ddiss@suse.de>
Date: Sat, 22 Aug 2015 18:43:42 +0200
Subject: [PATCH] rbd: add rbd_dev_getxattr() helper
Patch-mainline: Not yet, SES2 clustered LIO/RBD
References: fate#318836

Signed-off-by: David Disseldorp <ddiss@suse.de>
---
 drivers/block/rbd.c         |   79 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/ceph/librbd.h |    2 +
 2 files changed, 81 insertions(+)

--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -1851,6 +1851,7 @@ static void rbd_osd_req_callback(struct
 		break;
 	case CEPH_OSD_OP_SETXATTR:
 	case CEPH_OSD_OP_CMPXATTR:
+	case CEPH_OSD_OP_GETXATTR:
 		obj_request_done_set(obj_request);
 		break;
 	default:
@@ -4805,6 +4806,84 @@ out:
 }
 EXPORT_SYMBOL(rbd_dev_cmpsetxattr);
 
+int rbd_dev_getxattr(struct rbd_device *rbd_dev, char *key, int max_val_len,
+		     void **_val, int *val_len)
+{
+	struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
+	struct rbd_obj_request *obj_request;
+	int page_count;
+	struct page **pages = NULL;
+	void *val;
+	int ret;
+
+	BUG_ON(!key);
+	BUG_ON(!_val || !val_len);
+
+	page_count = calc_pages_for(0, max_val_len);
+	pages = ceph_alloc_page_vector(page_count, GFP_KERNEL);
+	if (IS_ERR(pages))
+		return PTR_ERR(pages);
+
+	obj_request = rbd_obj_request_create(rbd_dev->header_name, 0,
+					     max_val_len, OBJ_REQUEST_PAGES);
+	if (!obj_request) {
+		ceph_release_page_vector(pages, page_count);
+		return -ENOMEM;
+	}
+
+	obj_request->pages = pages;
+	obj_request->page_count = page_count;
+
+	obj_request->osd_req = rbd_osd_req_create(rbd_dev, OBJ_OP_READ, 1,
+						  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_GETXATTR,
+				    key, NULL, 0, 0, 0);
+	if (ret)
+		goto out;
+
+	osd_req_op_xattr_response_data_pages(obj_request->osd_req, 0,
+					     obj_request->pages, max_val_len,
+					     0, false, false);
+	rbd_osd_req_format_read(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;
+
+	rbd_assert(obj_request->xferred <= (u64)max_val_len);
+
+	val = kmalloc(obj_request->xferred, GFP_KERNEL);
+	if (!val) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ceph_copy_from_page_vector(pages, val, 0, obj_request->xferred);
+	*_val = val;
+	*val_len = obj_request->xferred;
+
+	ret = 0;
+out:
+	rbd_obj_request_put(obj_request);
+
+	return ret;
+}
+EXPORT_SYMBOL(rbd_dev_getxattr);
+
 /*
  * TODO: remove me or move to debugfs for final merge.
  */
--- a/include/linux/ceph/librbd.h
+++ b/include/linux/ceph/librbd.h
@@ -204,5 +204,7 @@ extern int rbd_dev_setxattr(struct rbd_d
 extern int rbd_dev_cmpsetxattr(struct rbd_device *rbd_dev, char *key,
 			       void *oldval, int oldval_len, void *newval,
 			       int newval_len);
+extern int rbd_dev_getxattr(struct rbd_device *rbd_dev, char *key, int max_val_len,
+			    void **_val, int *val_len);
 
 #endif