summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub/blob.c
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2020-02-19 17:01:47 -0800
committerDarrick J. Wong <darrick.wong@oracle.com>2020-06-24 18:12:19 -0700
commit26f632dcc5b00c0d74078c56a339d8700cac93c4 (patch)
treeccca0e7a5a210bcd491ffc79bd484df5a8de8c8b /fs/xfs/scrub/blob.c
parent0902889428d08ac62c721942b74f45ae4bcf5af1 (diff)
xfs: create a blob array data structure
Create a simple 'blob array' data structure for storage of arbitrarily sized metadata objects that will be used to reconstruct metadata. For the intended usage (temporarily storing extended attribute names and values) we only have to support storing objects and retrieving them. Use the xfile abstraction to store the attribute information in memory that can be swapped out. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs/scrub/blob.c')
-rw-r--r--fs/xfs/scrub/blob.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/fs/xfs/scrub/blob.c b/fs/xfs/scrub/blob.c
new file mode 100644
index 000000000000..2abf3fa39e15
--- /dev/null
+++ b/fs/xfs/scrub/blob.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "scrub/array.h"
+#include "scrub/blob.h"
+#include "scrub/xfile.h"
+
+/*
+ * XFS Blob Storage
+ * ================
+ * Stores and retrieves blobs using a memfd object. Objects are appended to
+ * the file and the offset is returned as a magic cookie for retrieval.
+ */
+
+#define XB_KEY_MAGIC 0xABAADDAD
+struct xb_key {
+ uint32_t magic;
+ uint32_t size;
+ loff_t offset;
+ /* blob comes after here */
+} __packed;
+
+/* Initialize a blob storage object. */
+struct xblob *
+xblob_init(
+ const char *description)
+{
+ struct xblob *blob;
+ struct xfile *xfile;
+ int error;
+
+ xfile = xfile_create(description, 0);
+ if (IS_ERR(xfile))
+ return ERR_CAST(xfile);
+
+ error = -ENOMEM;
+ blob = kmem_alloc(sizeof(struct xblob), KM_NOFS | KM_MAYFAIL);
+ if (!blob)
+ goto out_xfile;
+
+ blob->xfile = xfile;
+ blob->last_offset = PAGE_SIZE;
+ return blob;
+out_xfile:
+ xfile_destroy(xfile);
+ return ERR_PTR(error);
+}
+
+/* Destroy a blob storage object. */
+void
+xblob_destroy(
+ struct xblob *blob)
+{
+ xfile_destroy(blob->xfile);
+ kmem_free(blob);
+}
+
+/* Retrieve a blob. */
+int
+xblob_get(
+ struct xblob *blob,
+ xblob_cookie cookie,
+ void *ptr,
+ uint32_t size)
+{
+ struct xb_key key;
+ int error;
+
+ error = xfile_pread(blob->xfile, &key, sizeof(key), cookie);
+ if (error)
+ return error;
+
+ if (key.magic != XB_KEY_MAGIC || key.offset != cookie) {
+ ASSERT(0);
+ return -ENODATA;
+ }
+ if (size < key.size) {
+ ASSERT(0);
+ return -EFBIG;
+ }
+
+ return xfile_pread(blob->xfile, ptr, key.size, cookie + sizeof(key));
+}
+
+/* Store a blob. */
+int
+xblob_put(
+ struct xblob *blob,
+ xblob_cookie *cookie,
+ void *ptr,
+ uint32_t size)
+{
+ struct xb_key key = {
+ .offset = blob->last_offset,
+ .magic = XB_KEY_MAGIC,
+ .size = size,
+ };
+ loff_t pos = blob->last_offset;
+ int error;
+
+ error = xfile_pwrite(blob->xfile, &key, sizeof(key), pos);
+ if (error)
+ goto out_err;
+
+ pos += sizeof(key);
+ error = xfile_pwrite(blob->xfile, ptr, size, pos);
+ if (error)
+ goto out_err;
+
+ *cookie = blob->last_offset;
+ blob->last_offset += sizeof(key) + size;
+ return 0;
+out_err:
+ xfile_discard(blob->xfile, blob->last_offset, pos - 1);
+ return -ENOMEM;
+}
+
+/* Free a blob. */
+int
+xblob_free(
+ struct xblob *blob,
+ xblob_cookie cookie)
+{
+ struct xb_key key;
+ int error;
+
+ error = xfile_pread(blob->xfile, &key, sizeof(key), cookie);
+ if (error)
+ return error;
+
+ if (key.magic != XB_KEY_MAGIC || key.offset != cookie) {
+ ASSERT(0);
+ return -ENODATA;
+ }
+
+ xfile_discard(blob->xfile, cookie, cookie + sizeof(key) + key.size - 1);
+ return 0;
+}