summaryrefslogtreecommitdiff
path: root/fs
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 /fs
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>
Diffstat (limited to 'fs')
-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__ */