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 23 struct 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. */ 31 int 32 xfblob_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 56 out_xfile: 57 xfile_destroy(xfile); 58 return error; 59 } 60 61 /* Destroy a blob storage object. */ 62 void 63 xfblob_destroy( 64 struct xfblob *blob) 65 { 66 xfile_destroy(blob->xfile); 67 kfree(blob); 68 } 69 70 /* Retrieve a blob. */ 71 int 72 xfblob_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. */ 99 int 100 xfblob_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; 126 out_err: 127 xfile_discard(blob->xfile, blob->last_offset, sizeof(key)); 128 return error; 129 } 130 131 /* Free a blob. */ 132 int 133 xfblob_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? */ 154 unsigned long long 155 xfblob_bytes( 156 struct xfblob *blob) 157 { 158 return xfile_bytes(blob->xfile); 159 } 160 161 /* Drop all the blobs. */ 162 void 163 xfblob_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