169 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2021-2024 Oracle. All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "scrub/scrub.h"11#include "scrub/xfile.h"12#include "scrub/xfarray.h"13#include "scrub/xfblob.h"14 15/*16 * XFS Blob Storage17 * ================18 * Stores and retrieves blobs using an xfile. Objects are appended to the file19 * and the offset is returned as a magic cookie for retrieval.20 */21 22#define XB_KEY_MAGIC 0xABAADDAD23struct xb_key {24 uint32_t xb_magic; /* XB_KEY_MAGIC */25 uint32_t xb_size; /* size of the blob, in bytes */26 loff_t xb_offset; /* byte offset of this key */27 /* blob comes after here */28} __packed;29 30/* Initialize a blob storage object. */31int32xfblob_create(33 const char *description,34 struct xfblob **blobp)35{36 struct xfblob *blob;37 struct xfile *xfile;38 int error;39 40 error = xfile_create(description, 0, &xfile);41 if (error)42 return error;43 44 blob = kmalloc(sizeof(struct xfblob), XCHK_GFP_FLAGS);45 if (!blob) {46 error = -ENOMEM;47 goto out_xfile;48 }49 50 blob->xfile = xfile;51 blob->last_offset = PAGE_SIZE;52 53 *blobp = blob;54 return 0;55 56out_xfile:57 xfile_destroy(xfile);58 return error;59}60 61/* Destroy a blob storage object. */62void63xfblob_destroy(64 struct xfblob *blob)65{66 xfile_destroy(blob->xfile);67 kfree(blob);68}69 70/* Retrieve a blob. */71int72xfblob_load(73 struct xfblob *blob,74 xfblob_cookie cookie,75 void *ptr,76 uint32_t size)77{78 struct xb_key key;79 int error;80 81 error = xfile_load(blob->xfile, &key, sizeof(key), cookie);82 if (error)83 return error;84 85 if (key.xb_magic != XB_KEY_MAGIC || key.xb_offset != cookie) {86 ASSERT(0);87 return -ENODATA;88 }89 if (size < key.xb_size) {90 ASSERT(0);91 return -EFBIG;92 }93 94 return xfile_load(blob->xfile, ptr, key.xb_size,95 cookie + sizeof(key));96}97 98/* Store a blob. */99int100xfblob_store(101 struct xfblob *blob,102 xfblob_cookie *cookie,103 const void *ptr,104 uint32_t size)105{106 struct xb_key key = {107 .xb_offset = blob->last_offset,108 .xb_magic = XB_KEY_MAGIC,109 .xb_size = size,110 };111 loff_t pos = blob->last_offset;112 int error;113 114 error = xfile_store(blob->xfile, &key, sizeof(key), pos);115 if (error)116 return error;117 118 pos += sizeof(key);119 error = xfile_store(blob->xfile, ptr, size, pos);120 if (error)121 goto out_err;122 123 *cookie = blob->last_offset;124 blob->last_offset += sizeof(key) + size;125 return 0;126out_err:127 xfile_discard(blob->xfile, blob->last_offset, sizeof(key));128 return error;129}130 131/* Free a blob. */132int133xfblob_free(134 struct xfblob *blob,135 xfblob_cookie cookie)136{137 struct xb_key key;138 int error;139 140 error = xfile_load(blob->xfile, &key, sizeof(key), cookie);141 if (error)142 return error;143 144 if (key.xb_magic != XB_KEY_MAGIC || key.xb_offset != cookie) {145 ASSERT(0);146 return -ENODATA;147 }148 149 xfile_discard(blob->xfile, cookie, sizeof(key) + key.xb_size);150 return 0;151}152 153/* How many bytes is this blob storage object consuming? */154unsigned long long155xfblob_bytes(156 struct xfblob *blob)157{158 return xfile_bytes(blob->xfile);159}160 161/* Drop all the blobs. */162void163xfblob_truncate(164 struct xfblob *blob)165{166 xfile_discard(blob->xfile, PAGE_SIZE, MAX_LFS_FILESIZE - PAGE_SIZE);167 blob->last_offset = PAGE_SIZE;168}169