1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 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 Storage 17 * ================ 18 * Stores and retrieves blobs using an xfile. Objects are appended to the file 19 * and the offset is returned as a magic cookie for retrieval. 20 */ 21 22#define XB_KEY_MAGIC 0xABAADDAD 23struct 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. */ 31int 32xfblob_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. */ 62void 63xfblob_destroy( 64 struct xfblob *blob) 65{ 66 xfile_destroy(blob->xfile); 67 kfree(blob); 68} 69 70/* Retrieve a blob. */ 71int 72xfblob_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. */ 99int 100xfblob_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. */ 132int 133xfblob_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 long 155xfblob_bytes( 156 struct xfblob *blob) 157{ 158 return xfile_bytes(blob->xfile); 159} 160 161/* Drop all the blobs. */ 162void 163xfblob_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