summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub/blob.c
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-01-16 10:12:05 -0800
committerDarrick J. Wong <darrick.wong@oracle.com>2019-04-15 17:02:45 -0700
commitd059a892c058f19f7bdd681ca99d2441b7d7a3ac (patch)
tree7f9a8ed29d73c9f2cac867eb14a70a34994867d0 /fs/xfs/scrub/blob.c
parente33e4050b1b4a15ca20300fc32deb5075ab8ff52 (diff)
xfs: convert big array and blob array to use memfd backendrepair-part-one_2019-04-15
There are several problems with the initial implementations of the big array and the blob array data structures. First, using linked lists imposes a two-pointer overhead on every record stored. For blobs this isn't serious, but for fixed-size records this increases memory requirements by 40-60%. Second, we're using kernel memory to store the intermediate records. Kernel memory cannot be paged out, which means we run the risk of OOMing the machine when we run out of physical memory. Therefore, replace the linked lists in both structures with memfd files. Random access becomes much easier, memory overhead drops to a negligible amount, and because memfd pages can be swapped, we have considerably more flexibility for memory use. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs/scrub/blob.c')
-rw-r--r--fs/xfs/scrub/blob.c94
1 files changed, 59 insertions, 35 deletions
diff --git a/fs/xfs/scrub/blob.c b/fs/xfs/scrub/blob.c
index 7113e14a90fc..dbae83ca390c 100644
--- a/fs/xfs/scrub/blob.c
+++ b/fs/xfs/scrub/blob.c
@@ -8,38 +8,48 @@
#include "xfs_shared.h"
#include "scrub/array.h"
#include "scrub/blob.h"
+#include "scrub/xfile.h"
/*
* XFS Blob Storage
* ================
- * Stores and retrieves blobs using a list. Objects are appended to
- * the list and the pointer is returned as a magic cookie for retrieval.
+ * Stores and retrieves blobs using a memfd object. Objects are appended to
+ * the file and the offset is returned as a magic cookie for retrieval.
*/
#define XB_KEY_MAGIC 0xABAADDAD
struct xb_key {
- struct list_head list;
uint32_t magic;
uint32_t size;
+ loff_t offset;
/* blob comes after here */
} __attribute__((packed));
-#define XB_KEY_SIZE(sz) (sizeof(struct xb_key) + (sz))
-
/* Initialize a blob storage object. */
struct xblob *
xblob_init(void)
{
struct xblob *blob;
+ struct file *filp;
int error;
+ filp = xfile_create("blob storage");
+ if (!filp)
+ return ERR_PTR(-ENOMEM);
+ if (IS_ERR(filp))
+ return ERR_CAST(filp);
+
error = -ENOMEM;
blob = kmem_alloc(sizeof(struct xblob), KM_NOFS | KM_MAYFAIL);
if (!blob)
- return ERR_PTR(error);
+ goto out_filp;
- INIT_LIST_HEAD(&blob->list);
+ blob->filp = filp;
+ blob->last_offset = PAGE_SIZE;
return blob;
+out_filp:
+ fput(filp);
+ return ERR_PTR(error);
}
/* Destroy a blob storage object. */
@@ -47,12 +57,7 @@ void
xblob_destroy(
struct xblob *blob)
{
- struct xb_key *key, *n;
-
- list_for_each_entry_safe(key, n, &blob->list, list) {
- list_del(&key->list);
- kmem_free(key);
- }
+ xfile_destroy(blob->filp);
kmem_free(blob);
}
@@ -64,19 +69,24 @@ xblob_get(
void *ptr,
uint32_t size)
{
- struct xb_key *key = (struct xb_key *)cookie;
+ struct xb_key key;
+ loff_t pos = cookie;
+ int error;
+
+ error = xfile_io(blob->filp, XFILE_IO_READ, &pos, &key, sizeof(key));
+ if (error)
+ return error;
- if (key->magic != XB_KEY_MAGIC) {
+ if (key.magic != XB_KEY_MAGIC || key.offset != cookie) {
ASSERT(0);
return -ENODATA;
}
- if (size < key->size) {
+ if (size < key.size) {
ASSERT(0);
return -EFBIG;
}
- memcpy(ptr, key + 1, key->size);
- return 0;
+ return xfile_io(blob->filp, XFILE_IO_READ, &pos, ptr, key.size);
}
/* Store a blob. */
@@ -87,19 +97,28 @@ xblob_put(
void *ptr,
uint32_t size)
{
- struct xb_key *key;
-
- key = kmem_alloc(XB_KEY_SIZE(size), KM_NOFS | KM_MAYFAIL);
- if (!key)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&key->list);
- list_add_tail(&key->list, &blob->list);
- key->magic = XB_KEY_MAGIC;
- key->size = size;
- memcpy(key + 1, ptr, size);
- *cookie = (xblob_cookie)key;
+ struct xb_key key = {
+ .offset = blob->last_offset,
+ .magic = XB_KEY_MAGIC,
+ .size = size,
+ };
+ loff_t pos = blob->last_offset;
+ int error;
+
+ error = xfile_io(blob->filp, XFILE_IO_WRITE, &pos, &key, sizeof(key));
+ if (error)
+ goto out_err;
+
+ error = xfile_io(blob->filp, XFILE_IO_WRITE, &pos, ptr, size);
+ if (error)
+ goto out_err;
+
+ *cookie = blob->last_offset;
+ blob->last_offset = pos;
return 0;
+out_err:
+ xfile_discard(blob->filp, blob->last_offset, pos - 1);
+ return -ENOMEM;
}
/* Free a blob. */
@@ -108,14 +127,19 @@ xblob_free(
struct xblob *blob,
xblob_cookie cookie)
{
- struct xb_key *key = (struct xb_key *)cookie;
+ struct xb_key key;
+ loff_t pos = cookie;
+ int error;
+
+ error = xfile_io(blob->filp, XFILE_IO_READ, &pos, &key, sizeof(key));
+ if (error)
+ return error;
- if (key->magic != XB_KEY_MAGIC) {
+ if (key.magic != XB_KEY_MAGIC || key.offset != cookie) {
ASSERT(0);
return -ENODATA;
}
- key->magic = 0;
- list_del(&key->list);
- kmem_free(key);
+
+ xfile_discard(blob->filp, cookie, cookie + sizeof(key) + key.size - 1);
return 0;
}