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
xfblob_create(const char * description,struct xfblob ** blobp)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
xfblob_destroy(struct xfblob * blob)63 xfblob_destroy(
64 struct xfblob *blob)
65 {
66 xfile_destroy(blob->xfile);
67 kfree(blob);
68 }
69
70 /* Retrieve a blob. */
71 int
xfblob_load(struct xfblob * blob,xfblob_cookie cookie,void * ptr,uint32_t size)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
xfblob_store(struct xfblob * blob,xfblob_cookie * cookie,const void * ptr,uint32_t size)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
xfblob_free(struct xfblob * blob,xfblob_cookie cookie)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
xfblob_bytes(struct xfblob * blob)155 xfblob_bytes(
156 struct xfblob *blob)
157 {
158 return xfile_bytes(blob->xfile);
159 }
160
161 /* Drop all the blobs. */
162 void
xfblob_truncate(struct xfblob * blob)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