| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- // 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;
- }
- /* How many bytes is this blob storage object consuming? */
- unsigned long long
- xfblob_bytes(
- struct xfblob *blob)
- {
- return xfile_bytes(blob->xfile);
- }
- /* Drop all the blobs. */
- void
- xfblob_truncate(
- struct xfblob *blob)
- {
- xfile_discard(blob->xfile, PAGE_SIZE, MAX_LFS_FILESIZE - PAGE_SIZE);
- blob->last_offset = PAGE_SIZE;
- }
|