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