xref: /linux/fs/xfs/scrub/xfblob.c (revision 24168c5e6dfbdd5b414f048f47f75d64533296ca)
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