summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-08-30 15:44:53 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2019-11-22 21:35:02 -0800
commit4f3f488fe394cf7a6643c66a4a833f19ccaa81f1 (patch)
tree19a61847b0d035ad60271a4aa16be1dc866d8493
parentdf7f080a42a06b4775b633a6288c3233442af00a (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>
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/scrub/blob.c145
-rw-r--r--fs/xfs/scrub/blob.h24
3 files changed, 170 insertions, 0 deletions
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 3fbdbd23990e..3a078d2c7b45 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -163,6 +163,7 @@ xfs-y += $(addprefix scrub/, \
alloc_repair.o \
array.o \
bitmap.o \
+ blob.o \
bmap_repair.o \
ialloc_repair.o \
inode_repair.o \
diff --git a/fs/xfs/scrub/blob.c b/fs/xfs/scrub/blob.c
new file mode 100644
index 000000000000..94912fcb1fd1
--- /dev/null
+++ b/fs/xfs/scrub/blob.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 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(void)
+{
+ struct xblob *blob;
+ struct file *filp;
+ int error;
+
+ filp = xfile_create("blob storage");
+ if (!filp)
+ return ERR_PTR(-ENOMEM);
+ if (IS_ERR(filp))
+ return ERR_CAST(filp);
+
+ error = -ENOMEM;
+ blob = kmem_alloc(sizeof(struct xblob), KM_NOFS | KM_MAYFAIL);
+ if (!blob)
+ goto out_filp;
+
+ blob->filp = filp;
+ blob->last_offset = PAGE_SIZE;
+ return blob;
+out_filp:
+ fput(filp);
+ return ERR_PTR(error);
+}
+
+/* Destroy a blob storage object. */
+void
+xblob_destroy(
+ struct xblob *blob)
+{
+ xfile_destroy(blob->filp);
+ kmem_free(blob);
+}
+
+/* Retrieve a blob. */
+int
+xblob_get(
+ struct xblob *blob,
+ xblob_cookie cookie,
+ void *ptr,
+ uint32_t size)
+{
+ struct xb_key key;
+ loff_t pos = cookie;
+ int error;
+
+ error = xfile_io(blob->filp, XFILE_IO_READ, &pos, &key, sizeof(key));
+ 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_io(blob->filp, XFILE_IO_READ, &pos, ptr, key.size);
+}
+
+/* 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_io(blob->filp, XFILE_IO_WRITE, &pos, &key, sizeof(key));
+ if (error)
+ goto out_err;
+
+ error = xfile_io(blob->filp, XFILE_IO_WRITE, &pos, ptr, size);
+ if (error)
+ goto out_err;
+
+ *cookie = blob->last_offset;
+ blob->last_offset = pos;
+ return 0;
+out_err:
+ xfile_discard(blob->filp, blob->last_offset, pos - 1);
+ return -ENOMEM;
+}
+
+/* Free a blob. */
+int
+xblob_free(
+ struct xblob *blob,
+ xblob_cookie cookie)
+{
+ struct xb_key key;
+ loff_t pos = cookie;
+ int error;
+
+ error = xfile_io(blob->filp, XFILE_IO_READ, &pos, &key, sizeof(key));
+ if (error)
+ return error;
+
+ if (key.magic != XB_KEY_MAGIC || key.offset != cookie) {
+ ASSERT(0);
+ return -ENODATA;
+ }
+
+ xfile_discard(blob->filp, cookie, cookie + sizeof(key) + key.size - 1);
+ return 0;
+}
diff --git a/fs/xfs/scrub/blob.h b/fs/xfs/scrub/blob.h
new file mode 100644
index 000000000000..c6f6c6a2e084
--- /dev/null
+++ b/fs/xfs/scrub/blob.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <darrick.wong@oracle.com>
+ */
+#ifndef __XFS_SCRUB_BLOB_H__
+#define __XFS_SCRUB_BLOB_H__
+
+struct xblob {
+ struct file *filp;
+ loff_t last_offset;
+};
+
+typedef loff_t xblob_cookie;
+
+struct xblob *xblob_init(void);
+void xblob_destroy(struct xblob *blob);
+int xblob_get(struct xblob *blob, xblob_cookie cookie, void *ptr,
+ uint32_t size);
+int xblob_put(struct xblob *blob, xblob_cookie *cookie, void *ptr,
+ uint32_t size);
+int xblob_free(struct xblob *blob, xblob_cookie cookie);
+
+#endif /* __XFS_SCRUB_BLOB_H__ */