]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: create a blob array data structure
authorDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:54:43 +0000 (14:54 -0700)
committerDarrick J. Wong <djwong@kernel.org>
Mon, 15 Apr 2024 21:58:53 +0000 (14:58 -0700)
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 <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/Makefile
fs/xfs/scrub/xfblob.c [new file with mode: 0644]
fs/xfs/scrub/xfblob.h [new file with mode: 0644]

index 5e3ac7ec8fa5b05b20b0755817cbeeed713513d3..bc27757702fe89d3e7cc31351fbaa8d8f648924d 100644 (file)
@@ -208,6 +208,7 @@ xfs-y                               += $(addprefix scrub/, \
                                   repair.o \
                                   rmap_repair.o \
                                   tempfile.o \
+                                  xfblob.o \
                                   )
 
 xfs-$(CONFIG_XFS_RT)           += $(addprefix scrub/, \
diff --git a/fs/xfs/scrub/xfblob.c b/fs/xfs/scrub/xfblob.c
new file mode 100644 (file)
index 0000000..cec668d
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021-2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "scrub/scrub.h"
+#include "scrub/xfile.h"
+#include "scrub/xfarray.h"
+#include "scrub/xfblob.h"
+
+/*
+ * XFS Blob Storage
+ * ================
+ * Stores and retrieves blobs using an xfile.  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                xb_magic;  /* XB_KEY_MAGIC */
+       uint32_t                xb_size;   /* size of the blob, in bytes */
+       loff_t                  xb_offset; /* byte offset of this key */
+       /* blob comes after here */
+} __packed;
+
+/* Initialize a blob storage object. */
+int
+xfblob_create(
+       const char              *description,
+       struct xfblob           **blobp)
+{
+       struct xfblob           *blob;
+       struct xfile            *xfile;
+       int                     error;
+
+       error = xfile_create(description, 0, &xfile);
+       if (error)
+               return error;
+
+       blob = kmalloc(sizeof(struct xfblob), XCHK_GFP_FLAGS);
+       if (!blob) {
+               error = -ENOMEM;
+               goto out_xfile;
+       }
+
+       blob->xfile = xfile;
+       blob->last_offset = PAGE_SIZE;
+
+       *blobp = blob;
+       return 0;
+
+out_xfile:
+       xfile_destroy(xfile);
+       return error;
+}
+
+/* Destroy a blob storage object. */
+void
+xfblob_destroy(
+       struct xfblob   *blob)
+{
+       xfile_destroy(blob->xfile);
+       kfree(blob);
+}
+
+/* Retrieve a blob. */
+int
+xfblob_load(
+       struct xfblob   *blob,
+       xfblob_cookie   cookie,
+       void            *ptr,
+       uint32_t        size)
+{
+       struct xb_key   key;
+       int             error;
+
+       error = xfile_load(blob->xfile, &key, sizeof(key), cookie);
+       if (error)
+               return error;
+
+       if (key.xb_magic != XB_KEY_MAGIC || key.xb_offset != cookie) {
+               ASSERT(0);
+               return -ENODATA;
+       }
+       if (size < key.xb_size) {
+               ASSERT(0);
+               return -EFBIG;
+       }
+
+       return xfile_load(blob->xfile, ptr, key.xb_size,
+                       cookie + sizeof(key));
+}
+
+/* Store a blob. */
+int
+xfblob_store(
+       struct xfblob   *blob,
+       xfblob_cookie   *cookie,
+       const void      *ptr,
+       uint32_t        size)
+{
+       struct xb_key   key = {
+               .xb_offset = blob->last_offset,
+               .xb_magic = XB_KEY_MAGIC,
+               .xb_size = size,
+       };
+       loff_t          pos = blob->last_offset;
+       int             error;
+
+       error = xfile_store(blob->xfile, &key, sizeof(key), pos);
+       if (error)
+               return error;
+
+       pos += sizeof(key);
+       error = xfile_store(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, sizeof(key));
+       return error;
+}
+
+/* Free a blob. */
+int
+xfblob_free(
+       struct xfblob   *blob,
+       xfblob_cookie   cookie)
+{
+       struct xb_key   key;
+       int             error;
+
+       error = xfile_load(blob->xfile, &key, sizeof(key), cookie);
+       if (error)
+               return error;
+
+       if (key.xb_magic != XB_KEY_MAGIC || key.xb_offset != cookie) {
+               ASSERT(0);
+               return -ENODATA;
+       }
+
+       xfile_discard(blob->xfile, cookie, sizeof(key) + key.xb_size);
+       return 0;
+}
diff --git a/fs/xfs/scrub/xfblob.h b/fs/xfs/scrub/xfblob.h
new file mode 100644 (file)
index 0000000..bd98647
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2021-2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_SCRUB_XFBLOB_H__
+#define __XFS_SCRUB_XFBLOB_H__
+
+struct xfblob {
+       struct xfile    *xfile;
+       loff_t          last_offset;
+};
+
+typedef loff_t         xfblob_cookie;
+
+int xfblob_create(const char *descr, struct xfblob **blobp);
+void xfblob_destroy(struct xfblob *blob);
+int xfblob_load(struct xfblob *blob, xfblob_cookie cookie, void *ptr,
+               uint32_t size);
+int xfblob_store(struct xfblob *blob, xfblob_cookie *cookie, const void *ptr,
+               uint32_t size);
+int xfblob_free(struct xfblob *blob, xfblob_cookie cookie);
+
+#endif /* __XFS_SCRUB_XFBLOB_H__ */