Update bcachefs sources to f638850417 bcachefs: bch2_trans_log_msg()

This commit is contained in:
Kent Overstreet 2022-03-30 17:40:25 -04:00
parent 59abea5776
commit e240b4ae86
33 changed files with 447 additions and 757 deletions

View File

@ -1 +1 @@
7786034caa4ee7d10d25202284220513c0944ce2
f638850417c9042dab40511e3c3ed0b1be355301

View File

@ -1,17 +0,0 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,57 +0,0 @@
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "ccan/darray/darray.h"
/**
* darray - Generic resizable arrays
*
* darray is a set of macros for managing dynamically-allocated arrays.
* It removes the tedium of managing realloc'd arrays with pointer, size, and
* allocated size.
*
* Example:
* #include <ccan/darray/darray.h>
* #include <stdio.h>
*
* int main(void) {
* darray(int) numbers = darray_new();
* char buffer[32];
*
* for (;;) {
* int *i;
* darray_foreach(i, numbers)
* printf("%d ", *i);
* if (darray_size(numbers) > 0)
* puts("");
*
* printf("darray> ");
* fgets(buffer, sizeof(buffer), stdin);
* if (*buffer == '\0' || *buffer == '\n')
* break;
*
* darray_append(numbers, atoi(buffer));
* }
*
* darray_free(numbers);
*
* return 0;
* }
*
* Author: Joey Adams <joeyadams3.14159@gmail.com>
* License: MIT
* Version: 0.2
*/
int main(int argc, char *argv[])
{
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
/* Nothing. */
return 0;
}
return 1;
}

View File

@ -1,355 +0,0 @@
/*
* Copyright (C) 2011 Joseph Adams <joeyadams3.14159@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CCAN_DARRAY_H
#define CCAN_DARRAY_H
#include <stdlib.h>
#include <string.h>
#include "config.h"
/*
* SYNOPSIS
*
* Life cycle of a darray (dynamically-allocated array):
*
* darray(int) a = darray_new();
* darray_free(a);
*
* struct {darray(int) a;} foo;
* darray_init(foo.a);
* darray_free(foo.a);
*
* Typedefs for darrays of common types:
*
* darray_char, darray_schar, darray_uchar
* darray_short, darray_int, darray_long
* darray_ushort, darray_uint, darray_ulong
*
* Access:
*
* T darray_item(darray(T) arr, size_t index);
* size_t darray_size(darray(T) arr);
* size_t darray_alloc(darray(T) arr);
* bool darray_empty(darray(T) arr);
*
* Insertion (single item):
*
* void darray_append(darray(T) arr, T item);
* void darray_prepend(darray(T) arr, T item);
* void darray_push(darray(T) arr, T item); // same as darray_append
*
* Insertion (multiple items):
*
* void darray_append_items(darray(T) arr, T *items, size_t count);
* void darray_prepend_items(darray(T) arr, T *items, size_t count);
*
* void darray_appends(darray(T) arr, [T item, [...]]);
* void darray_prepends(darray(T) arr, [T item, [...]]);
*
* // Same functionality as above, but does not require typeof.
* void darray_appends_t(darray(T) arr, #T, [T item, [...]]);
* void darray_prepends_t(darray(T) arr, #T, [T item, [...]]);
*
* Removal:
*
* T darray_pop(darray(T) arr | darray_size(arr) != 0);
* T* darray_pop_check(darray(T*) arr);
* void darray_remove(darray(T) arr, size_t index);
*
* Replacement:
*
* void darray_from_items(darray(T) arr, T *items, size_t count);
* void darray_from_c(darray(T) arr, T c_array[N]);
*
* String buffer:
*
* void darray_append_string(darray(char) arr, const char *str);
* void darray_append_lit(darray(char) arr, char stringLiteral[N+1]);
*
* void darray_prepend_string(darray(char) arr, const char *str);
* void darray_prepend_lit(darray(char) arr, char stringLiteral[N+1]);
*
* void darray_from_string(darray(T) arr, const char *str);
* void darray_from_lit(darray(char) arr, char stringLiteral[N+1]);
*
* Size management:
*
* void darray_resize(darray(T) arr, size_t newSize);
* void darray_resize0(darray(T) arr, size_t newSize);
*
* void darray_realloc(darray(T) arr, size_t newAlloc);
* void darray_growalloc(darray(T) arr, size_t newAlloc);
*
* void darray_make_room(darray(T) arr, size_t room);
*
* Traversal:
*
* darray_foreach(T *&i, darray(T) arr) {...}
* darray_foreach_reverse(T *&i, darray(T) arr) {...}
*
* Except for darray_foreach, darray_foreach_reverse, and darray_remove,
* all macros evaluate their non-darray arguments only once.
*/
/*** Life cycle ***/
#define darray(type) struct {type *item; size_t size; size_t alloc;}
#define darray_new() {0,0,0}
#define darray_init(arr) do {(arr).item=0; (arr).size=0; (arr).alloc=0;} while(0)
#define darray_free(arr) do {free((arr).item);} while(0)
/*
* Typedefs for darrays of common types. These are useful
* when you want to pass a pointer to an darray(T) around.
*
* The following will produce an incompatible pointer warning:
*
* void foo(darray(int) *arr);
* darray(int) arr = darray_new();
* foo(&arr);
*
* The workaround:
*
* void foo(darray_int *arr);
* darray_int arr = darray_new();
* foo(&arr);
*/
typedef darray(char) darray_char;
typedef darray(signed char) darray_schar;
typedef darray(unsigned char) darray_uchar;
typedef darray(short) darray_short;
typedef darray(int) darray_int;
typedef darray(long) darray_long;
typedef darray(unsigned short) darray_ushort;
typedef darray(unsigned int) darray_uint;
typedef darray(unsigned long) darray_ulong;
/*** Access ***/
#define darray_item(arr, i) ((arr).item[i])
#define darray_size(arr) ((arr).size)
#define darray_alloc(arr) ((arr).alloc)
#define darray_empty(arr) ((arr).size == 0)
/*** Insertion (single item) ***/
#define darray_append(arr, ...) do { \
darray_resize(arr, (arr).size+1); \
(arr).item[(arr).size-1] = (__VA_ARGS__); \
} while(0)
#define darray_prepend(arr, ...) do { \
darray_resize(arr, (arr).size+1); \
memmove((arr).item+1, (arr).item, ((arr).size-1)*sizeof(*(arr).item)); \
(arr).item[0] = (__VA_ARGS__); \
} while(0)
#define darray_push(arr, ...) darray_append(arr, __VA_ARGS__)
/*** Insertion (multiple items) ***/
#define darray_append_items(arr, items, count) do { \
size_t __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __oldSize + __count); \
memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \
} while(0)
#define darray_prepend_items(arr, items, count) do { \
size_t __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __count + __oldSize); \
memmove((arr).item + __count, (arr).item, __oldSize * sizeof(*(arr).item)); \
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
} while(0)
#define darray_append_items_nullterminate(arr, items, count) do { \
size_t __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __oldSize + __count + 1); \
memcpy((arr).item + __oldSize, items, __count * sizeof(*(arr).item)); \
(arr).item[--(arr).size] = 0; \
} while(0)
#define darray_prepend_items_nullterminate(arr, items, count) do { \
size_t __count = (count), __oldSize = (arr).size; \
darray_resize(arr, __count + __oldSize + 1); \
memmove((arr).item + __count, (arr).item, __oldSize * sizeof(*(arr).item)); \
memcpy((arr).item, items, __count * sizeof(*(arr).item)); \
(arr).item[--(arr).size] = 0; \
} while(0)
#if HAVE_TYPEOF
#define darray_appends(arr, ...) darray_appends_t(arr, typeof((*(arr).item)), __VA_ARGS__)
#define darray_prepends(arr, ...) darray_prepends_t(arr, typeof((*(arr).item)), __VA_ARGS__)
#endif
#define darray_appends_t(arr, type, ...) do { \
type __src[] = {__VA_ARGS__}; \
darray_append_items(arr, __src, sizeof(__src)/sizeof(*__src)); \
} while(0)
#define darray_prepends_t(arr, type, ...) do { \
type __src[] = {__VA_ARGS__}; \
darray_prepend_items(arr, __src, sizeof(__src)/sizeof(*__src)); \
} while(0)
/*** Removal ***/
/* Warning: Do not call darray_pop on an empty darray. */
#define darray_pop(arr) ((arr).item[--(arr).size])
#define darray_pop_check(arr) ((arr).size ? darray_pop(arr) : NULL)
/* Warning, slow: Requires copying all elements after removed item. */
#define darray_remove(arr, index) do { \
if (index < arr.size-1) \
memmove(&(arr).item[index], &(arr).item[index+1], ((arr).size-1-i)*sizeof(*(arr).item)); \
(arr).size--; \
} while(0)
/*** Replacement ***/
#define darray_from_items(arr, items, count) do {size_t __count = (count); darray_resize(arr, __count); memcpy((arr).item, items, __count*sizeof(*(arr).item));} while(0)
#define darray_from_c(arr, c_array) darray_from_items(arr, c_array, sizeof(c_array)/sizeof(*(c_array)))
/*** String buffer ***/
#define darray_append_string(arr, str) do {const char *__str = (str); darray_append_items(arr, __str, strlen(__str)+1); (arr).size--;} while(0)
#define darray_append_lit(arr, stringLiteral) do {darray_append_items(arr, stringLiteral, sizeof(stringLiteral)); (arr).size--;} while(0)
#define darray_prepend_string(arr, str) do { \
const char *__str = (str); \
darray_prepend_items_nullterminate(arr, __str, strlen(__str)); \
} while(0)
#define darray_prepend_lit(arr, stringLiteral) \
darray_prepend_items_nullterminate(arr, stringLiteral, sizeof(stringLiteral) - 1)
#define darray_from_string(arr, str) do {const char *__str = (str); darray_from_items(arr, __str, strlen(__str)+1); (arr).size--;} while(0)
#define darray_from_lit(arr, stringLiteral) do {darray_from_items(arr, stringLiteral, sizeof(stringLiteral)); (arr).size--;} while(0)
/*** Size management ***/
#define darray_resize(arr, newSize) darray_growalloc(arr, (arr).size = (newSize))
#define darray_resize0(arr, newSize) do { \
size_t __oldSize = (arr).size, __newSize = (newSize); \
(arr).size = __newSize; \
if (__newSize > __oldSize) { \
darray_growalloc(arr, __newSize); \
memset(&(arr).item[__oldSize], 0, (__newSize - __oldSize) * sizeof(*(arr).item)); \
} \
} while(0)
#define darray_realloc(arr, newAlloc) do { \
(arr).item = realloc((arr).item, ((arr).alloc = (newAlloc)) * sizeof(*(arr).item)); \
} while(0)
#define darray_growalloc(arr, need) do { \
size_t __need = (need); \
if (__need > (arr).alloc) \
darray_realloc(arr, darray_next_alloc((arr).alloc, __need)); \
} while(0)
#if HAVE_STATEMENT_EXPR==1
#define darray_make_room(arr, room) ({size_t newAlloc = (arr).size+(room); if ((arr).alloc<newAlloc) darray_realloc(arr, newAlloc); (arr).item+(arr).size; })
#endif
static inline size_t darray_next_alloc(size_t alloc, size_t need)
{
if (alloc == 0)
alloc = 1;
while (alloc < need)
alloc *= 2;
return alloc;
}
/*** Traversal ***/
/*
* darray_foreach(T *&i, darray(T) arr) {...}
*
* Traverse a darray. `i` must be declared in advance as a pointer to an item.
*/
#define darray_foreach(i, arr) \
for ((i) = &(arr).item[0]; (i) < &(arr).item[(arr).size]; (i)++)
/*
* darray_foreach_reverse(T *&i, darray(T) arr) {...}
*
* Like darray_foreach, but traverse in reverse order.
*/
#define darray_foreach_reverse(i, arr) \
for ((i) = &(arr).item[(arr).size]; (i)-- > &(arr).item[0]; )
#endif /* CCAN_DARRAY_H */
/*
darray_growalloc(arr, newAlloc) sees if the darray can currently hold newAlloc items;
if not, it increases the alloc to satisfy this requirement, allocating slack
space to avoid having to reallocate for every size increment.
darray_from_string(arr, str) copies a string to an darray_char.
darray_push(arr, item) pushes an item to the end of the darray.
darray_pop(arr) pops it back out. Be sure there is at least one item in the darray before calling.
darray_pop_check(arr) does the same as darray_pop, but returns NULL if there are no more items left in the darray.
darray_make_room(arr, room) ensures there's 'room' elements of space after the end of the darray, and it returns a pointer to this space.
Currently requires HAVE_STATEMENT_EXPR, but I plan to remove this dependency by creating an inline function.
The following require HAVE_TYPEOF==1 :
darray_appends(arr, item0, item1...) appends a collection of comma-delimited items to the darray.
darray_prepends(arr, item0, item1...) prepends a collection of comma-delimited items to the darray.\
Examples:
darray(int) arr;
int *i;
darray_appends(arr, 0,1,2,3,4);
darray_appends(arr, -5,-4,-3,-2,-1);
darray_foreach(i, arr)
printf("%d ", *i);
printf("\n");
darray_free(arr);
typedef struct {int n,d;} Fraction;
darray(Fraction) fractions;
Fraction *i;
darray_appends(fractions, {3,4}, {3,5}, {2,1});
darray_foreach(i, fractions)
printf("%d/%d\n", i->n, i->d);
darray_free(fractions);
*/

View File

@ -38,12 +38,10 @@ static void dump_one_device(struct bch_fs *c, struct bch_dev *ca, int fd,
bool entire_journal)
{
struct bch_sb *sb = ca->disk_sb.sb;
ranges data;
ranges data = { 0 };
unsigned i;
int ret;
darray_init(data);
/* Superblock: */
range_add(&data, BCH_SB_LAYOUT_SECTOR << 9,
sizeof(struct bch_sb_layout));
@ -110,7 +108,7 @@ static void dump_one_device(struct bch_fs *c, struct bch_dev *ca, int fd,
qcow2_write_image(ca->disk_sb.bdev->bd_fd, fd, &data,
max_t(unsigned, btree_bytes(c) / 8, block_bytes(c)));
darray_free(data);
darray_exit(data);
}
int cmd_dump(int argc, char *argv[])

View File

@ -20,11 +20,10 @@
#include <uuid/uuid.h>
#include "ccan/darray/darray.h"
#include "cmds.h"
#include "libbcachefs.h"
#include "crypto.h"
#include "libbcachefs/darray.h"
#include "libbcachefs/opts.h"
#include "libbcachefs/super-io.h"
#include "libbcachefs/util.h"
@ -114,17 +113,14 @@ u64 read_flag_list_or_die(char *opt, const char * const list[],
int cmd_format(int argc, char *argv[])
{
darray(struct dev_opts) devices;
darray(char *) device_paths;
DARRAY(struct dev_opts) devices = { 0 };
DARRAY(char *) device_paths = { 0 };
struct format_opts opts = format_opts_default();
struct dev_opts dev_opts = dev_opts_default(), *dev;
bool force = false, no_passphrase = false, quiet = false, initialize = true, verbose = false;
unsigned v;
int opt;
darray_init(devices);
darray_init(device_paths);
struct bch_opt_strs fs_opt_strs =
bch2_cmdline_opts_get(&argc, argv, OPT_FORMAT);
struct bch_opts fs_opts = bch2_parse_opts(fs_opt_strs);
@ -201,9 +197,9 @@ int cmd_format(int argc, char *argv[])
initialize = false;
break;
case O_no_opt:
darray_append(device_paths, optarg);
darray_push(device_paths, optarg);
dev_opts.path = optarg;
darray_append(devices, dev_opts);
darray_push(devices, dev_opts);
dev_opts.size = 0;
break;
case O_quiet:
@ -222,7 +218,7 @@ int cmd_format(int argc, char *argv[])
break;
}
if (darray_empty(devices))
if (!devices.nr)
die("Please supply a device");
if (opts.encrypted && !no_passphrase) {
@ -230,14 +226,14 @@ int cmd_format(int argc, char *argv[])
initialize = false;
}
darray_foreach(dev, devices)
darray_for_each(devices, dev)
dev->fd = open_for_format(dev->path, force);
struct bch_sb *sb =
bch2_format(fs_opt_strs,
fs_opts,
opts,
devices.item, darray_size(devices));
devices.data, devices.nr);
bch2_opt_strs_free(&fs_opt_strs);
if (!quiet) {
@ -257,7 +253,7 @@ int cmd_format(int argc, char *argv[])
free(opts.passphrase);
}
darray_free(devices);
darray_exit(devices);
if (initialize) {
struct bch_opts mount_opts = bch2_opts_empty();
@ -269,17 +265,17 @@ int cmd_format(int argc, char *argv[])
* Start the filesystem once, to allocate the journal and create
* the root directory:
*/
struct bch_fs *c = bch2_fs_open(device_paths.item,
darray_size(device_paths),
struct bch_fs *c = bch2_fs_open(device_paths.data,
device_paths.nr,
mount_opts);
if (IS_ERR(c))
die("error opening %s: %s", device_paths.item[0],
die("error opening %s: %s", device_paths.data[0],
strerror(-PTR_ERR(c)));
bch2_fs_stop(c);
}
darray_free(device_paths);
darray_exit(device_paths);
return 0;
}

View File

@ -4,11 +4,10 @@
#include <uuid/uuid.h>
#include "ccan/darray/darray.h"
#include "linux/sort.h"
#include "libbcachefs/bcachefs_ioctl.h"
#include "libbcachefs/darray.h"
#include "libbcachefs/opts.h"
#include "cmds.h"
@ -115,7 +114,7 @@ static struct dev_name *dev_idx_to_name(dev_names *dev_names, unsigned idx)
{
struct dev_name *dev;
darray_foreach(dev, *dev_names)
darray_for_each(*dev_names, dev)
if (dev->idx == idx)
return dev;
@ -256,22 +255,22 @@ static void fs_usage_to_text(struct printbuf *out, const char *path)
free(u);
sort(&darray_item(dev_names, 0), darray_size(dev_names),
sizeof(darray_item(dev_names, 0)), dev_by_label_cmp, NULL);
sort(dev_names.data, dev_names.nr,
sizeof(dev_names.data[0]), dev_by_label_cmp, NULL);
out->tabstops[0] = 16;
out->tabstops[1] = 36;
out->tabstops[2] = 52;
out->tabstops[3] = 68;
darray_foreach(dev, dev_names)
darray_for_each(dev_names, dev)
dev_usage_to_text(out, fs, dev);
darray_foreach(dev, dev_names) {
darray_for_each(dev_names, dev) {
free(dev->dev);
free(dev->label);
}
darray_free(dev_names);
darray_exit(dev_names);
bcache_fs_close(fs);
}

View File

@ -530,7 +530,7 @@ static ranges reserve_new_fs_space(const char *file_path, unsigned block_size,
struct fiemap_iter iter;
struct fiemap_extent e;
ranges extents = { NULL };
ranges extents = { 0 };
fiemap_for_each(fd, iter, e) {
if (e.fe_flags & (FIEMAP_EXTENT_UNKNOWN|
@ -603,7 +603,7 @@ static void copy_fs(struct bch_fs *c, int src_fd, const char *src_path,
update_inode(c, &root_inode);
darray_free(s.extents);
darray_exit(s.extents);
genradix_free(&s.hardlinks);
}
@ -613,7 +613,7 @@ static void find_superblock_space(ranges extents,
{
struct range *i;
darray_foreach(i, extents) {
darray_for_each(extents, i) {
u64 start = round_up(max(256ULL << 10, i->start),
dev->bucket_size << 9);
u64 end = round_down(i->end,

View File

@ -7,10 +7,14 @@
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/overflow.h>
#include <linux/page.h>
#include <linux/shrinker.h>
#include <linux/types.h>
#include <stdlib.h>
#include <sys/mman.h>
#define ARCH_KMALLOC_MINALIGN 16
#define KMALLOC_MAX_SIZE SIZE_MAX
@ -58,6 +62,16 @@ static inline void *krealloc(void *old, size_t size, gfp_t flags)
return new;
}
static inline void *krealloc_array(void *p, size_t new_n, size_t new_size, gfp_t flags)
{
size_t bytes;
if (unlikely(check_mul_overflow(new_n, new_size, &bytes)))
return NULL;
return krealloc(p, bytes, flags);
}
#define kzalloc(size, flags) kmalloc(size, flags|__GFP_ZERO)
#define kmalloc_array(n, size, flags) \
((size) != 0 && (n) > SIZE_MAX / (size) \
@ -174,4 +188,53 @@ static inline struct kmem_cache *kmem_cache_create(size_t obj_size)
#define KMEM_CACHE(_struct, _flags) kmem_cache_create(sizeof(struct _struct))
#define PAGE_KERNEL 0
#define PAGE_KERNEL_EXEC 1
#define vfree(p) free(p)
static inline void *__vmalloc(unsigned long size, gfp_t gfp_mask)
{
unsigned i = 0;
void *p;
size = round_up(size, PAGE_SIZE);
do {
run_shrinkers(gfp_mask, i != 0);
p = aligned_alloc(PAGE_SIZE, size);
if (p && gfp_mask & __GFP_ZERO)
memset(p, 0, size);
} while (!p && i++ < 10);
return p;
}
static inline void *vmalloc_exec(unsigned long size, gfp_t gfp_mask)
{
void *p;
p = __vmalloc(size, gfp_mask);
if (!p)
return NULL;
if (mprotect(p, size, PROT_READ|PROT_WRITE|PROT_EXEC)) {
vfree(p);
return NULL;
}
return p;
}
static inline void *vmalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL);
}
static inline void *vzalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL|__GFP_ZERO);
}
#endif /* __TOOLS_LINUX_SLAB_H */

View File

@ -6,6 +6,7 @@
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */

View File

@ -1,59 +1,6 @@
#ifndef __TOOLS_LINUX_VMALLOC_H
#define __TOOLS_LINUX_VMALLOC_H
#include <stdlib.h>
#include <sys/mman.h>
#include "linux/slab.h"
#include "tools-util.h"
#define PAGE_KERNEL 0
#define PAGE_KERNEL_EXEC 1
#define vfree(p) free(p)
static inline void *__vmalloc(unsigned long size, gfp_t gfp_mask)
{
unsigned i = 0;
void *p;
size = round_up(size, PAGE_SIZE);
do {
run_shrinkers(gfp_mask, i != 0);
p = aligned_alloc(PAGE_SIZE, size);
if (p && gfp_mask & __GFP_ZERO)
memset(p, 0, size);
} while (!p && i++ < 10);
return p;
}
static inline void *vmalloc_exec(unsigned long size, gfp_t gfp_mask)
{
void *p;
p = __vmalloc(size, gfp_mask);
if (!p)
return NULL;
if (mprotect(p, size, PROT_READ|PROT_WRITE|PROT_EXEC)) {
vfree(p);
return NULL;
}
return p;
}
static inline void *vmalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL);
}
static inline void *vzalloc(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL|__GFP_ZERO);
}
#endif /* __TOOLS_LINUX_VMALLOC_H */

View File

@ -493,32 +493,49 @@ DEFINE_EVENT(bucket_alloc, bucket_alloc,
TRACE_EVENT(bucket_alloc_fail,
TP_PROTO(struct bch_dev *ca, const char *alloc_reserve,
u64 avail, u64 need_journal_commit,
bool nonblocking),
TP_ARGS(ca, alloc_reserve, avail, need_journal_commit, nonblocking),
u64 avail,
u64 seen,
u64 open,
u64 need_journal_commit,
u64 nouse,
bool nonblocking,
int ret),
TP_ARGS(ca, alloc_reserve, avail, seen, open, need_journal_commit, nouse, nonblocking, ret),
TP_STRUCT__entry(
__field(dev_t, dev )
__array(char, reserve, 16 )
__field(u64, avail )
__field(u64, seen )
__field(u64, open )
__field(u64, need_journal_commit )
__field(u64, nouse )
__field(bool, nonblocking )
__field(int, ret )
),
TP_fast_assign(
__entry->dev = ca->dev;
strlcpy(__entry->reserve, alloc_reserve, sizeof(__entry->reserve));
__entry->avail = avail;
__entry->seen = seen;
__entry->open = open;
__entry->need_journal_commit = need_journal_commit;
__entry->nouse = nouse;
__entry->nonblocking = nonblocking;
__entry->ret = ret;
),
TP_printk("%d,%d reserve %s avail %llu need_journal_commit %llu nonblocking %u",
TP_printk("%d,%d reserve %s avail %llu seen %llu open %llu need_journal_commit %llu nouse %llu nonblocking %u ret %i",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->reserve,
__entry->avail,
__entry->seen,
__entry->open,
__entry->need_journal_commit,
__entry->nonblocking)
__entry->nouse,
__entry->nonblocking,
__entry->ret)
);
DEFINE_EVENT(bucket_alloc, open_bucket_alloc_fail,

View File

@ -713,7 +713,7 @@ dev_names bchu_fs_get_devices(struct bchfs_handle fs)
n.label = read_file_str(fs.sysfs_fd, label_attr);
free(label_attr);
darray_append(devs, n);
darray_push(devs, n);
}
closedir(dir);

View File

@ -237,7 +237,7 @@ struct dev_name {
char *label;
uuid_le uuid;
};
typedef darray(struct dev_name) dev_names;
typedef DARRAY(struct dev_name) dev_names;
dev_names bchu_fs_get_devices(struct bchfs_handle);

View File

@ -862,7 +862,9 @@ static void bch2_do_discards_work(struct work_struct *work)
bch2_bucket_is_open_safe(c, k.k->p.inode, k.k->p.offset))
continue;
ret = __bch2_trans_do(&trans, NULL, NULL, 0,
ret = __bch2_trans_do(&trans, NULL, NULL,
BTREE_INSERT_USE_RESERVE|
BTREE_INSERT_NOFAIL,
bch2_clear_need_discard(&trans, k.k->p, ca, &discard_done));
if (ret)
break;
@ -954,6 +956,7 @@ static void bch2_do_invalidates_work(struct work_struct *work)
for_each_member_device(ca, c, i)
while (!ret && should_invalidate_buckets(ca))
ret = __bch2_trans_do(&trans, NULL, NULL,
BTREE_INSERT_USE_RESERVE|
BTREE_INSERT_NOFAIL,
invalidate_one_bucket(&trans, ca));

View File

@ -192,20 +192,26 @@ static inline unsigned open_buckets_reserved(enum alloc_reserve reserve)
static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *ca,
enum alloc_reserve reserve,
struct bkey_alloc_unpacked a,
size_t *need_journal_commit,
u64 *skipped_open,
u64 *skipped_need_journal_commit,
u64 *skipped_nouse,
struct closure *cl)
{
struct open_bucket *ob;
if (unlikely(ca->buckets_nouse && test_bit(a.bucket, ca->buckets_nouse)))
if (unlikely(ca->buckets_nouse && test_bit(a.bucket, ca->buckets_nouse))) {
(*skipped_nouse)++;
return NULL;
}
if (bch2_bucket_is_open(c, ca->dev_idx, a.bucket))
if (bch2_bucket_is_open(c, ca->dev_idx, a.bucket)) {
(*skipped_open)++;
return NULL;
}
if (bch2_bucket_needs_journal_commit(&c->buckets_waiting_for_journal,
c->journal.flushed_seq_ondisk, ca->dev_idx, a.bucket)) {
(*need_journal_commit)++;
(*skipped_need_journal_commit)++;
return NULL;
}
@ -227,6 +233,7 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
/* Recheck under lock: */
if (bch2_bucket_is_open(c, ca->dev_idx, a.bucket)) {
spin_unlock(&c->freelist_lock);
(*skipped_open)++;
return NULL;
}
@ -267,7 +274,9 @@ static struct open_bucket *__try_alloc_bucket(struct bch_fs *c, struct bch_dev *
static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bch_dev *ca,
enum alloc_reserve reserve, u64 free_entry,
size_t *need_journal_commit,
u64 *skipped_open,
u64 *skipped_need_journal_commit,
u64 *skipped_nouse,
struct closure *cl)
{
struct bch_fs *c = trans->c;
@ -317,7 +326,11 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc
goto err;
}
ob = __try_alloc_bucket(c, ca, reserve, a, need_journal_commit, cl);
ob = __try_alloc_bucket(c, ca, reserve, a,
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
cl);
err:
bch2_trans_iter_exit(trans, &iter);
printbuf_exit(&buf);
@ -360,8 +373,11 @@ static noinline struct open_bucket *
bch2_bucket_alloc_trans_early(struct btree_trans *trans,
struct bch_dev *ca,
enum alloc_reserve reserve,
u64 *b,
size_t *need_journal_commit,
u64 *cur_bucket,
u64 *buckets_seen,
u64 *skipped_open,
u64 *skipped_need_journal_commit,
u64 *skipped_nouse,
struct closure *cl)
{
struct btree_iter iter;
@ -369,10 +385,10 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
struct open_bucket *ob = NULL;
int ret;
*b = max_t(u64, *b, ca->mi.first_bucket);
*b = max_t(u64, *b, ca->new_fs_bucket_idx);
*cur_bucket = max_t(u64, *cur_bucket, ca->mi.first_bucket);
*cur_bucket = max_t(u64, *cur_bucket, ca->new_fs_bucket_idx);
for_each_btree_key(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, *b),
for_each_btree_key(trans, iter, BTREE_ID_alloc, POS(ca->dev_idx, *cur_bucket),
BTREE_ITER_SLOTS, k, ret) {
struct bkey_alloc_unpacked a;
@ -388,14 +404,19 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
if (bucket_state(a) != BUCKET_free)
continue;
(*buckets_seen)++;
ob = __try_alloc_bucket(trans->c, ca, reserve, a,
need_journal_commit, cl);
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
cl);
if (ob)
break;
}
bch2_trans_iter_exit(trans, &iter);
*b = iter.pos.offset;
*cur_bucket = iter.pos.offset;
return ob ?: ERR_PTR(ret ?: -FREELIST_EMPTY);
}
@ -403,8 +424,11 @@ bch2_bucket_alloc_trans_early(struct btree_trans *trans,
static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
struct bch_dev *ca,
enum alloc_reserve reserve,
u64 *b,
size_t *need_journal_commit,
u64 *cur_bucket,
u64 *buckets_seen,
u64 *skipped_open,
u64 *skipped_need_journal_commit,
u64 *skipped_nouse,
struct closure *cl)
{
struct btree_iter iter;
@ -413,26 +437,37 @@ static struct open_bucket *bch2_bucket_alloc_trans(struct btree_trans *trans,
int ret;
if (unlikely(!ca->mi.freespace_initialized))
return bch2_bucket_alloc_trans_early(trans, ca, reserve, b,
need_journal_commit, cl);
return bch2_bucket_alloc_trans_early(trans, ca, reserve,
cur_bucket,
buckets_seen,
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
cl);
BUG_ON(ca->new_fs_bucket_idx);
for_each_btree_key(trans, iter, BTREE_ID_freespace,
POS(ca->dev_idx, *b), 0, k, ret) {
POS(ca->dev_idx, *cur_bucket), 0, k, ret) {
if (k.k->p.inode != ca->dev_idx)
break;
for (*b = max(*b, bkey_start_offset(k.k));
*b != k.k->p.offset && !ob;
(*b)++) {
for (*cur_bucket = max(*cur_bucket, bkey_start_offset(k.k));
*cur_bucket != k.k->p.offset && !ob;
(*cur_bucket)++) {
if (btree_trans_too_many_iters(trans)) {
ob = ERR_PTR(-EINTR);
break;
}
ob = try_alloc_bucket(trans, ca, reserve, *b,
need_journal_commit, cl);
(*buckets_seen)++;
ob = try_alloc_bucket(trans, ca, reserve,
*cur_bucket,
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
cl);
}
if (ob)
break;
@ -453,9 +488,12 @@ struct open_bucket *bch2_bucket_alloc(struct bch_fs *c, struct bch_dev *ca,
struct closure *cl)
{
struct open_bucket *ob = NULL;
size_t need_journal_commit = 0;
u64 avail = dev_buckets_available(ca, reserve);
u64 b = 0;
u64 cur_bucket = 0;
u64 buckets_seen = 0;
u64 skipped_open = 0;
u64 skipped_need_journal_commit = 0;
u64 skipped_nouse = 0;
int ret;
if (may_alloc_partial) {
@ -483,19 +521,27 @@ again:
}
ret = bch2_trans_do(c, NULL, NULL, 0,
PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(&trans,
ca, reserve, &b,
&need_journal_commit, cl)));
PTR_ERR_OR_ZERO(ob = bch2_bucket_alloc_trans(&trans, ca, reserve,
&cur_bucket,
&buckets_seen,
&skipped_open,
&skipped_need_journal_commit,
&skipped_nouse,
cl)));
if (need_journal_commit * 2 > avail)
if (skipped_need_journal_commit * 2 > avail)
bch2_journal_flush_async(&c->journal, NULL);
err:
if (!ob)
ob = ERR_PTR(ret ?: -FREELIST_EMPTY);
if (ob == ERR_PTR(-FREELIST_EMPTY)) {
if (IS_ERR(ob)) {
trace_bucket_alloc_fail(ca, bch2_alloc_reserves[reserve], avail,
need_journal_commit, cl == NULL);
buckets_seen,
skipped_open,
skipped_need_journal_commit,
skipped_nouse,
cl == NULL, PTR_ERR(ob));
atomic_long_inc(&c->bucket_alloc_fail);
}

View File

@ -649,7 +649,7 @@ struct bch_fs {
struct mutex snapshot_table_lock;
struct work_struct snapshot_delete_work;
struct work_struct snapshot_wait_for_pagecache_and_delete_work;
struct snapshot_id_list snapshots_unlinked;
snapshot_id_list snapshots_unlinked;
struct mutex snapshots_unlinked_lock;
/* BTREE CACHE */

View File

@ -1686,6 +1686,7 @@ bch2_btree_path_make_mut(struct btree_trans *trans,
btree_trans_verify_sorted(trans);
}
path->should_be_locked = false;
return path;
}
@ -1706,7 +1707,6 @@ bch2_btree_path_set_pos(struct btree_trans *trans,
path = bch2_btree_path_make_mut(trans, path, intent, ip);
path->pos = new_pos;
path->should_be_locked = false;
bch2_btree_path_check_sort(trans, path, cmp);
@ -1720,6 +1720,7 @@ bch2_btree_path_set_pos(struct btree_trans *trans,
l = btree_path_up_until_good_node(trans, path, cmp);
if (btree_path_node(path, l)) {
BUG_ON(!btree_node_locked(path, l));
/*
* We might have to skip over many keys, or just a few: try
* advancing the node iterator, and if we have to skip over too
@ -1923,6 +1924,7 @@ struct btree_path *bch2_path_get(struct btree_trans *trans,
BUG_ON(trans->restarted);
btree_trans_verify_sorted(trans);
bch2_trans_verify_locks(trans);
trans_for_each_path_inorder(trans, path, i) {
if (__btree_path_cmp(path,
@ -2114,6 +2116,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
btree_node_unlock(path, path->level);
path->l[path->level].b = BTREE_ITER_NO_NODE_UP;
path->level++;
btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
return NULL;
}
@ -2121,6 +2124,7 @@ struct btree *bch2_btree_iter_next_node(struct btree_iter *iter)
__bch2_btree_path_unlock(path);
path->l[path->level].b = BTREE_ITER_NO_NODE_GET_LOCKS;
path->l[path->level + 1].b = BTREE_ITER_NO_NODE_GET_LOCKS;
btree_path_set_dirty(path, BTREE_ITER_NEED_TRAVERSE);
trace_trans_restart_relock_next_node(trans->fn, _THIS_IP_,
path->btree_id, &path->pos);
btree_trans_restart(trans);
@ -3055,8 +3059,7 @@ void bch2_trans_begin(struct btree_trans *trans)
trans->mem_top = 0;
trans->hooks = NULL;
trans->extra_journal_entries = NULL;
trans->extra_journal_entry_u64s = 0;
trans->extra_journal_entries.nr = 0;
if (trans->fs_usage_deltas) {
trans->fs_usage_deltas->used = 0;
@ -3189,6 +3192,8 @@ void bch2_trans_exit(struct btree_trans *trans)
bch2_journal_preres_put(&c->journal, &trans->journal_preres);
kfree(trans->extra_journal_entries.data);
if (trans->fs_usage_deltas) {
if (trans->fs_usage_deltas->size + sizeof(trans->fs_usage_deltas) ==
REPLICAS_DELTA_LIST_MAX)

View File

@ -8,6 +8,7 @@
#include "bkey_methods.h"
#include "buckets_types.h"
#include "darray.h"
#include "journal_types.h"
struct open_bucket;
@ -417,8 +418,7 @@ struct btree_trans {
/* update path: */
struct btree_trans_commit_hook *hooks;
struct jset_entry *extra_journal_entries;
unsigned extra_journal_entry_u64s;
DARRAY(u64) extra_journal_entries;
struct journal_entry_pin *journal_pin;
struct journal_res journal_res;

View File

@ -80,6 +80,8 @@ void bch2_trans_commit_hook(struct btree_trans *,
struct btree_trans_commit_hook *);
int __bch2_trans_commit(struct btree_trans *);
int bch2_trans_log_msg(struct btree_trans *, const char *);
/**
* bch2_trans_commit - insert keys at given iterator positions
*

View File

@ -532,8 +532,15 @@ static int btree_update_nodes_written_trans(struct btree_trans *trans,
struct bkey_i *k;
int ret;
trans->extra_journal_entries = (void *) &as->journal_entries[0];
trans->extra_journal_entry_u64s = as->journal_u64s;
ret = darray_make_room(trans->extra_journal_entries, as->journal_u64s);
if (ret)
return ret;
memcpy(&darray_top(trans->extra_journal_entries),
as->journal_entries,
as->journal_u64s * sizeof(u64));
trans->extra_journal_entries.nr += as->journal_u64s;
trans->journal_pin = &as->journal;
for_each_keylist_key(&as->new_keys, k) {
@ -1899,7 +1906,6 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
struct bch_fs *c = trans->c;
struct btree_iter iter2 = { NULL };
struct btree *parent;
u64 journal_entries[BKEY_BTREE_PTR_U64s_MAX];
int ret;
if (!skip_triggers) {
@ -1933,6 +1939,7 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
btree_node_unlock(iter2.path, iter2.path->level);
path_l(iter2.path)->b = BTREE_ITER_NO_NODE_UP;
iter2.path->level++;
btree_path_set_dirty(iter2.path, BTREE_ITER_NEED_TRAVERSE);
bch2_btree_path_check_sort(trans, iter2.path, 0);
@ -1943,12 +1950,16 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
} else {
BUG_ON(btree_node_root(c, b) != b);
trans->extra_journal_entries = (void *) &journal_entries[0];
trans->extra_journal_entry_u64s =
journal_entry_set((void *) &journal_entries[0],
ret = darray_make_room(trans->extra_journal_entries,
jset_u64s(new_key->k.u64s));
if (ret)
return ret;
journal_entry_set((void *) &darray_top(trans->extra_journal_entries),
BCH_JSET_ENTRY_btree_root,
b->c.btree_id, b->c.level,
new_key, new_key->k.u64s);
trans->extra_journal_entries.nr += jset_u64s(new_key->k.u64s);
}
ret = bch2_trans_commit(trans, NULL, NULL,

View File

@ -700,13 +700,13 @@ bch2_trans_commit_write_locked(struct btree_trans *trans,
trans->journal_res.seq = c->journal.replay_journal_seq;
}
if (unlikely(trans->extra_journal_entry_u64s)) {
if (unlikely(trans->extra_journal_entries.nr)) {
memcpy_u64s_small(journal_res_entry(&c->journal, &trans->journal_res),
trans->extra_journal_entries,
trans->extra_journal_entry_u64s);
trans->extra_journal_entries.data,
trans->extra_journal_entries.nr);
trans->journal_res.offset += trans->extra_journal_entry_u64s;
trans->journal_res.u64s -= trans->extra_journal_entry_u64s;
trans->journal_res.offset += trans->extra_journal_entries.nr;
trans->journal_res.u64s -= trans->extra_journal_entries.nr;
}
/*
@ -1088,7 +1088,7 @@ int __bch2_trans_commit(struct btree_trans *trans)
int ret = 0;
if (!trans->nr_updates &&
!trans->extra_journal_entry_u64s)
!trans->extra_journal_entries.nr)
goto out_reset;
if (trans->flags & BTREE_INSERT_GC_LOCK_HELD)
@ -1112,7 +1112,7 @@ int __bch2_trans_commit(struct btree_trans *trans)
memset(&trans->journal_preres, 0, sizeof(trans->journal_preres));
trans->journal_u64s = trans->extra_journal_entry_u64s;
trans->journal_u64s = trans->extra_journal_entries.nr;
trans->journal_preres_u64s = 0;
trans->journal_transaction_names = READ_ONCE(c->opts.journal_transaction_names);
@ -1170,8 +1170,7 @@ out_reset:
trans->extra_journal_res = 0;
trans->nr_updates = 0;
trans->hooks = NULL;
trans->extra_journal_entries = NULL;
trans->extra_journal_entry_u64s = 0;
trans->extra_journal_entries.nr = 0;
if (trans->fs_usage_deltas) {
trans->fs_usage_deltas->used = 0;
@ -1739,3 +1738,30 @@ int bch2_btree_delete_range(struct bch_fs *c, enum btree_id id,
bch2_btree_delete_range_trans(&trans, id, start, end,
update_flags, journal_seq));
}
int bch2_trans_log_msg(struct btree_trans *trans, const char *msg)
{
unsigned len = strlen(msg);
unsigned u64s = DIV_ROUND_UP(len, sizeof(u64));
struct jset_entry_log *l;
int ret;
ret = darray_make_room(trans->extra_journal_entries, jset_u64s(u64s));
if (ret)
return ret;
l = (void *) &darray_top(trans->extra_journal_entries);
l->entry.u64s = cpu_to_le16(u64s);
l->entry.btree_id = 0;
l->entry.level = 1;
l->entry.type = BCH_JSET_ENTRY_log;
l->entry.pad[0] = 0;
l->entry.pad[1] = 0;
l->entry.pad[2] = 0;
memcpy(l->d, msg, len);
while (len & 7)
l->d[len++] = '\0';
trans->extra_journal_entries.nr += jset_u64s(u64s);
return 0;
}

76
libbcachefs/darray.h Normal file
View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BCACHEFS_DARRAY_H
#define _BCACHEFS_DARRAY_H
/*
* Dynamic arrays:
*
* Inspired by CCAN's darray
*/
#include "util.h"
#include <linux/slab.h>
#define DARRAY(type) \
struct { \
size_t nr, size; \
type *data; \
}
typedef DARRAY(void) darray_void;
static inline int __darray_make_room(darray_void *d, size_t t_size, size_t more)
{
if (d->nr + more > d->size) {
size_t new_size = roundup_pow_of_two(d->nr + more);
void *data = krealloc_array(d->data, new_size, t_size, GFP_KERNEL);
if (!data)
return -ENOMEM;
d->data = data;
d->size = new_size;
}
return 0;
}
#define darray_make_room(_d, _more) \
__darray_make_room((darray_void *) &(_d), sizeof((_d).data[0]), (_more))
#define darray_top(_d) ((_d).data[(_d).nr])
#define darray_push(_d, _item) \
({ \
int _ret = darray_make_room((_d), 1); \
\
if (!_ret) \
(_d).data[(_d).nr++] = (_item); \
_ret; \
})
#define darray_insert_item(_d, _pos, _item) \
({ \
int _ret = darray_make_room((_d), 1); \
\
if (!_ret) \
array_insert_item((_d).data, (_d).nr, (_pos), (_item)); \
_ret; \
})
#define darray_for_each(_d, _i) \
for (_i = (_d).data; _i < (_d).data + (_d).nr; _i++)
#define darray_init(_d) \
do { \
(_d).data = NULL; \
(_d).nr = (_d).size = 0; \
} while (0)
#define darray_exit(_d) \
do { \
kfree((_d).data); \
darray_init(_d); \
} while (0)
#endif /* _BCACHEFS_DARRAY_H */

View File

@ -1477,7 +1477,7 @@ static void bch2_evict_inode(struct inode *vinode)
}
void bch2_evict_subvolume_inodes(struct bch_fs *c,
struct snapshot_id_list *s)
snapshot_id_list *s)
{
struct super_block *sb = c->vfs_sb;
struct inode *inode;

View File

@ -191,7 +191,7 @@ int bch2_setattr_nonsize(struct user_namespace *,
struct iattr *);
int __bch2_unlink(struct inode *, struct dentry *, bool);
void bch2_evict_subvolume_inodes(struct bch_fs *, struct snapshot_id_list *);
void bch2_evict_subvolume_inodes(struct bch_fs *, snapshot_id_list *);
void bch2_vfs_exit(void);
int bch2_vfs_init(void);
@ -199,7 +199,7 @@ int bch2_vfs_init(void);
#else
static inline void bch2_evict_subvolume_inodes(struct bch_fs *c,
struct snapshot_id_list *s) {}
snapshot_id_list *s) {}
static inline void bch2_vfs_exit(void) {}
static inline int bch2_vfs_init(void) { return 0; }

View File

@ -3,6 +3,7 @@
#include "bcachefs.h"
#include "bkey_buf.h"
#include "btree_update.h"
#include "darray.h"
#include "dirent.h"
#include "error.h"
#include "fs-common.h"
@ -471,11 +472,11 @@ static int snapshots_seen_update(struct bch_fs *c, struct snapshots_seen *s, str
pos.snapshot = snapshot_t(c, pos.snapshot)->equiv;
if (bkey_cmp(s->pos, pos))
s->nr = 0;
s->ids.nr = 0;
s->pos = pos;
/* Might get called multiple times due to lock restarts */
if (s->nr && s->d[s->nr - 1] == pos.snapshot)
if (s->ids.nr && s->ids.data[s->ids.nr - 1] == pos.snapshot)
return 0;
return snapshots_seen_add(c, s, pos.snapshot);
@ -498,7 +499,7 @@ static bool key_visible_in_snapshot(struct bch_fs *c, struct snapshots_seen *see
ancestor = snapshot_t(c, ancestor)->equiv;
/* @ancestor should be the snapshot most recently added to @seen */
BUG_ON(!seen->nr || seen->d[seen->nr - 1] != ancestor);
BUG_ON(!seen->ids.nr || seen->ids.data[seen->ids.nr - 1] != ancestor);
BUG_ON(seen->pos.snapshot != ancestor);
if (id == ancestor)
@ -507,11 +508,11 @@ static bool key_visible_in_snapshot(struct bch_fs *c, struct snapshots_seen *see
if (!bch2_snapshot_is_ancestor(c, id, ancestor))
return false;
for (i = seen->nr - 2;
i >= 0 && seen->d[i] >= id;
for (i = seen->ids.nr - 2;
i >= 0 && seen->ids.data[i] >= id;
--i)
if (bch2_snapshot_is_ancestor(c, id, seen->d[i]) &&
bch2_snapshot_is_ancestor(c, seen->d[i], ancestor))
if (bch2_snapshot_is_ancestor(c, id, seen->ids.data[i]) &&
bch2_snapshot_is_ancestor(c, seen->ids.data[i], ancestor))
return false;
return true;
@ -537,26 +538,25 @@ static int ref_visible(struct bch_fs *c, struct snapshots_seen *s,
}
#define for_each_visible_inode(_c, _s, _w, _snapshot, _i) \
for (_i = (_w)->d; _i < (_w)->d + (_w)->nr && (_i)->snapshot <= (_snapshot); _i++)\
for (_i = (_w)->inodes.data; _i < (_w)->inodes.data + (_w)->inodes.nr && (_i)->snapshot <= (_snapshot); _i++)\
if (key_visible_in_snapshot(_c, _s, _i->snapshot, _snapshot))
struct inode_walker_entry {
struct bch_inode_unpacked inode;
u32 snapshot;
u64 count;
};
struct inode_walker {
bool first_this_inode;
u64 cur_inum;
size_t nr;
size_t size;
struct inode_walker_entry {
struct bch_inode_unpacked inode;
u32 snapshot;
u64 count;
} *d;
DARRAY(struct inode_walker_entry) inodes;
};
static void inode_walker_exit(struct inode_walker *w)
{
kfree(w->d);
w->d = NULL;
darray_exit(w->inodes);
}
static struct inode_walker inode_walker_init(void)
@ -564,43 +564,17 @@ static struct inode_walker inode_walker_init(void)
return (struct inode_walker) { 0, };
}
static int inode_walker_realloc(struct bch_fs *c, struct inode_walker *w)
{
if (w->nr == w->size) {
size_t new_size = max_t(size_t, 8UL, w->size * 2);
void *d = krealloc(w->d, new_size * sizeof(w->d[0]),
GFP_KERNEL);
if (!d) {
bch_err(c, "fsck: error allocating memory for inode_walker, size %zu",
new_size);
return -ENOMEM;
}
w->d = d;
w->size = new_size;
}
return 0;
}
static int add_inode(struct bch_fs *c, struct inode_walker *w,
struct bkey_s_c inode)
{
struct bch_inode_unpacked u;
int ret;
ret = inode_walker_realloc(c, w);
if (ret)
return ret;
BUG_ON(bch2_inode_unpack(inode, &u));
w->d[w->nr++] = (struct inode_walker_entry) {
return darray_push(w->inodes, ((struct inode_walker_entry) {
.inode = u,
.snapshot = snapshot_t(c, inode.k->p.snapshot)->equiv,
};
return 0;
}));
}
static int __walk_inode(struct btree_trans *trans,
@ -619,7 +593,7 @@ static int __walk_inode(struct btree_trans *trans,
goto lookup_snapshot;
}
w->nr = 0;
w->inodes.nr = 0;
for_each_btree_key(trans, iter, BTREE_ID_inodes, POS(0, pos.inode),
BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
@ -637,26 +611,25 @@ static int __walk_inode(struct btree_trans *trans,
w->cur_inum = pos.inode;
w->first_this_inode = true;
lookup_snapshot:
for (i = 0; i < w->nr; i++)
if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->d[i].snapshot))
for (i = 0; i < w->inodes.nr; i++)
if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->inodes.data[i].snapshot))
goto found;
return INT_MAX;
found:
BUG_ON(pos.snapshot > w->d[i].snapshot);
BUG_ON(pos.snapshot > w->inodes.data[i].snapshot);
if (pos.snapshot != w->d[i].snapshot) {
if (pos.snapshot != w->inodes.data[i].snapshot) {
ancestor_pos = i;
while (i && w->d[i - 1].snapshot > pos.snapshot)
while (i && w->inodes.data[i - 1].snapshot > pos.snapshot)
--i;
ret = inode_walker_realloc(c, w);
ret = darray_insert_item(w->inodes, i, w->inodes.data[ancestor_pos]);
if (ret)
return ret;
array_insert_item(w->d, w->nr, i, w->d[ancestor_pos]);
w->d[i].snapshot = pos.snapshot;
w->d[i].count = 0;
w->inodes.data[i].snapshot = pos.snapshot;
w->inodes.data[i].count = 0;
}
return i;
@ -672,7 +645,7 @@ static int __get_visible_inodes(struct btree_trans *trans,
struct bkey_s_c k;
int ret;
w->nr = 0;
w->inodes.nr = 0;
for_each_btree_key(trans, iter, BTREE_ID_inodes, POS(0, inum),
BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
@ -1133,7 +1106,7 @@ static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
int ret = 0, ret2 = 0;
s64 count2;
for (i = w->d; i < w->d + w->nr; i++) {
darray_for_each(w->inodes, i) {
if (i->inode.bi_sectors == i->count)
continue;
@ -1232,7 +1205,7 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
goto out;
}
i = inode->d + ret;
i = inode->inodes.data + ret;
ret = 0;
if (fsck_err_on(!S_ISREG(i->inode.bi_mode) &&
@ -1333,7 +1306,7 @@ static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
int ret = 0, ret2 = 0;
s64 count2;
for (i = w->d; i < w->d + w->nr; i++) {
darray_for_each(w->inodes, i) {
if (i->inode.bi_nlink == i->count)
continue;
@ -1537,7 +1510,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
goto out;
}
i = dir->d + ret;
i = dir->inodes.data + ret;
ret = 0;
if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c,
@ -1550,7 +1523,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
}
if (dir->first_this_inode)
*hash_info = bch2_hash_info_init(c, &dir->d[0].inode);
*hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode);
ret = hash_check_key(trans, bch2_dirent_hash_desc,
hash_info, iter, k);
@ -1618,7 +1591,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
if (ret)
goto err;
if (fsck_err_on(!target->nr, c,
if (fsck_err_on(!target->inodes.nr, c,
"dirent points to missing inode:\n%s",
(printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k),
@ -1628,7 +1601,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
goto err;
}
for (i = target->d; i < target->d + target->nr; i++) {
darray_for_each(target->inodes, i) {
ret = check_dirent_target(trans, iter, d,
&i->inode, i->snapshot);
if (ret)
@ -1726,7 +1699,7 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
ret = 0;
if (inode->first_this_inode)
*hash_info = bch2_hash_info_init(c, &inode->d[0].inode);
*hash_info = bch2_hash_info_init(c, &inode->inodes.data[0].inode);
ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k);
fsck_err:
@ -1836,21 +1809,18 @@ static int check_root(struct bch_fs *c)
check_root_trans(&trans));
}
struct pathbuf {
size_t nr;
size_t size;
struct pathbuf_entry {
u64 inum;
u32 snapshot;
} *entries;
};
static bool path_is_dup(struct pathbuf *p, u64 inum, u32 snapshot)
typedef DARRAY(struct pathbuf_entry) pathbuf;
static bool path_is_dup(pathbuf *p, u64 inum, u32 snapshot)
{
struct pathbuf_entry *i;
for (i = p->entries; i < p->entries + p->nr; i++)
darray_for_each(*p, i)
if (i->inum == inum &&
i->snapshot == snapshot)
return true;
@ -1858,29 +1828,18 @@ static bool path_is_dup(struct pathbuf *p, u64 inum, u32 snapshot)
return false;
}
static int path_down(struct bch_fs *c, struct pathbuf *p,
static int path_down(struct bch_fs *c, pathbuf *p,
u64 inum, u32 snapshot)
{
if (p->nr == p->size) {
size_t new_size = max_t(size_t, 256UL, p->size * 2);
void *n = krealloc(p->entries,
new_size * sizeof(p->entries[0]),
GFP_KERNEL);
if (!n) {
bch_err(c, "fsck: error allocating memory for pathbuf, size %zu",
new_size);
return -ENOMEM;
}
p->entries = n;
p->size = new_size;
};
p->entries[p->nr++] = (struct pathbuf_entry) {
int ret = darray_push(*p, ((struct pathbuf_entry) {
.inum = inum,
.snapshot = snapshot,
};
return 0;
}));
if (ret)
bch_err(c, "fsck: error allocating memory for pathbuf, size %zu",
p->size);
return ret;
}
/*
@ -1889,7 +1848,7 @@ static int path_down(struct bch_fs *c, struct pathbuf *p,
* XXX: we should also be verifying that inodes are in the right subvolumes
*/
static int check_path(struct btree_trans *trans,
struct pathbuf *p,
pathbuf *p,
struct bch_inode_unpacked *inode,
u32 snapshot)
{
@ -1963,7 +1922,7 @@ static int check_path(struct btree_trans *trans,
/* XXX print path */
bch_err(c, "directory structure loop");
for (i = p->entries; i < p->entries + p->nr; i++)
darray_for_each(*p, i)
pr_err("%llu:%u", i->inum, i->snapshot);
pr_err("%llu:%u", inode->bi_inum, snapshot);
@ -2000,7 +1959,7 @@ static int check_directory_structure(struct bch_fs *c)
struct btree_iter iter;
struct bkey_s_c k;
struct bch_inode_unpacked u;
struct pathbuf path = { 0, 0, NULL };
pathbuf path = { 0, };
int ret;
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
@ -2030,7 +1989,7 @@ static int check_directory_structure(struct bch_fs *c)
BUG_ON(ret == -EINTR);
kfree(path.entries);
darray_exit(path);
bch2_trans_exit(&trans);
return ret;

View File

@ -92,10 +92,10 @@ next:
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, old_pos.snapshot)) {
struct bkey_i *update;
size_t i;
u32 *i;
for (i = 0; i < s.nr; i++)
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, s.d[i]))
darray_for_each(s.ids, i)
if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, *i))
goto next;
update = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
@ -125,7 +125,7 @@ next:
}
}
bch2_trans_iter_exit(trans, &iter);
kfree(s.d);
darray_exit(s.ids);
return ret;
}

View File

@ -545,36 +545,21 @@ err:
return ret;
}
static int snapshot_id_add(struct snapshot_id_list *s, u32 id)
static int snapshot_id_add(snapshot_id_list *s, u32 id)
{
BUG_ON(snapshot_list_has_id(s, id));
if (s->nr == s->size) {
size_t new_size = max(8U, s->size * 2);
void *n = krealloc(s->d,
new_size * sizeof(s->d[0]),
GFP_KERNEL);
if (!n) {
pr_err("error allocating snapshot ID list");
return -ENOMEM;
}
s->d = n;
s->size = new_size;
};
s->d[s->nr++] = id;
return 0;
return darray_push(*s, id);
}
static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans,
struct snapshot_id_list *deleted,
snapshot_id_list *deleted,
enum btree_id btree_id)
{
struct bch_fs *c = trans->c;
struct btree_iter iter;
struct bkey_s_c k;
struct snapshot_id_list equiv_seen = { 0 };
snapshot_id_list equiv_seen = { 0 };
struct bpos last_pos = POS_MIN;
int ret = 0;
@ -621,7 +606,7 @@ static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans,
}
bch2_trans_iter_exit(trans, &iter);
kfree(equiv_seen.d);
darray_exit(equiv_seen);
return ret;
}
@ -633,7 +618,7 @@ static void bch2_delete_dead_snapshots_work(struct work_struct *work)
struct btree_iter iter;
struct bkey_s_c k;
struct bkey_s_c_snapshot snap;
struct snapshot_id_list deleted = { 0 };
snapshot_id_list deleted = { 0 };
u32 i, id, children[2];
int ret = 0;
@ -713,15 +698,15 @@ static void bch2_delete_dead_snapshots_work(struct work_struct *work)
for (i = 0; i < deleted.nr; i++) {
ret = __bch2_trans_do(&trans, NULL, NULL, 0,
bch2_snapshot_node_delete(&trans, deleted.d[i]));
bch2_snapshot_node_delete(&trans, deleted.data[i]));
if (ret) {
bch_err(c, "error deleting snapshot %u: %i",
deleted.d[i], ret);
deleted.data[i], ret);
goto err;
}
}
err:
kfree(deleted.d);
darray_exit(deleted);
bch2_trans_exit(&trans);
percpu_ref_put(&c->writes);
}
@ -876,14 +861,14 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
{
struct bch_fs *c = container_of(work, struct bch_fs,
snapshot_wait_for_pagecache_and_delete_work);
struct snapshot_id_list s;
snapshot_id_list s;
u32 *id;
int ret = 0;
while (!ret) {
mutex_lock(&c->snapshots_unlinked_lock);
s = c->snapshots_unlinked;
memset(&c->snapshots_unlinked, 0, sizeof(c->snapshots_unlinked));
darray_init(c->snapshots_unlinked);
mutex_unlock(&c->snapshots_unlinked_lock);
if (!s.nr)
@ -891,7 +876,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
bch2_evict_subvolume_inodes(c, &s);
for (id = s.d; id < s.d + s.nr; id++) {
for (id = s.data; id < s.data + s.nr; id++) {
ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
bch2_subvolume_delete(&trans, *id));
if (ret) {
@ -900,7 +885,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
}
}
kfree(s.d);
darray_exit(s);
}
percpu_ref_put(&c->writes);

View File

@ -2,6 +2,7 @@
#ifndef _BCACHEFS_SUBVOLUME_H
#define _BCACHEFS_SUBVOLUME_H
#include "darray.h"
#include "subvolume_types.h"
void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
@ -58,15 +59,13 @@ static inline bool bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ances
struct snapshots_seen {
struct bpos pos;
size_t nr;
size_t size;
u32 *d;
DARRAY(u32) ids;
};
static inline void snapshots_seen_exit(struct snapshots_seen *s)
{
kfree(s->d);
s->d = NULL;
kfree(s->ids.data);
s->ids.data = NULL;
}
static inline void snapshots_seen_init(struct snapshots_seen *s)
@ -76,30 +75,19 @@ static inline void snapshots_seen_init(struct snapshots_seen *s)
static inline int snapshots_seen_add(struct bch_fs *c, struct snapshots_seen *s, u32 id)
{
if (s->nr == s->size) {
size_t new_size = max(s->size, (size_t) 128) * 2;
u32 *d = krealloc(s->d, new_size * sizeof(s->d[0]), GFP_KERNEL);
if (!d) {
bch_err(c, "error reallocating snapshots_seen table (new size %zu)",
new_size);
return -ENOMEM;
int ret = darray_push(s->ids, id);
if (ret)
bch_err(c, "error reallocating snapshots_seen table (size %zu)",
s->ids.size);
return ret;
}
s->size = new_size;
s->d = d;
}
s->d[s->nr++] = id;
return 0;
}
static inline bool snapshot_list_has_id(struct snapshot_id_list *s, u32 id)
static inline bool snapshot_list_has_id(snapshot_id_list *s, u32 id)
{
unsigned i;
u32 *i;
for (i = 0; i < s->nr; i++)
if (id == s->d[i])
darray_for_each(*s, i)
if (*i == id)
return true;
return false;
}

View File

@ -2,10 +2,8 @@
#ifndef _BCACHEFS_SUBVOLUME_TYPES_H
#define _BCACHEFS_SUBVOLUME_TYPES_H
struct snapshot_id_list {
u32 nr;
u32 size;
u32 *d;
};
#include "darray.h"
typedef DARRAY(u32) snapshot_id_list;
#endif /* _BCACHEFS_SUBVOLUME_TYPES_H */

View File

@ -94,7 +94,7 @@ void qcow2_write_image(int infd, int outfd, ranges *data,
ranges_sort_merge(data);
/* Write data: */
darray_foreach(r, *data)
darray_for_each(*data, r)
for (src_offset = r->start;
src_offset < r->end;
src_offset += block_size) {

View File

@ -295,22 +295,21 @@ static int range_cmp(const void *_l, const void *_r)
void ranges_sort_merge(ranges *r)
{
struct range *t, *i;
ranges tmp = { NULL };
ranges tmp = { 0 };
sort(&darray_item(*r, 0), darray_size(*r),
sizeof(darray_item(*r, 0)), range_cmp, NULL);
sort(r->data, r->nr, sizeof(r->data[0]), range_cmp, NULL);
/* Merge contiguous ranges: */
darray_foreach(i, *r) {
t = tmp.size ? &tmp.item[tmp.size - 1] : NULL;
darray_for_each(*r, i) {
t = tmp.nr ? &tmp.data[tmp.nr - 1] : NULL;
if (t && t->end >= i->start)
t->end = max(t->end, i->end);
else
darray_append(tmp, *i);
darray_push(tmp, *i);
}
darray_free(*r);
darray_exit(*r);
*r = tmp;
}
@ -318,7 +317,7 @@ void ranges_roundup(ranges *r, unsigned block_size)
{
struct range *i;
darray_foreach(i, *r) {
darray_for_each(*r, i) {
i->start = round_down(i->start, block_size);
i->end = round_up(i->end, block_size);
}
@ -328,7 +327,7 @@ void ranges_rounddown(ranges *r, unsigned block_size)
{
struct range *i;
darray_foreach(i, *r) {
darray_for_each(*r, i) {
i->start = round_up(i->start, block_size);
i->end = round_down(i->end, block_size);
i->end = max(i->end, i->start);

View File

@ -18,7 +18,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uuid.h>
#include "ccan/darray/darray.h"
#include "libbcachefs/darray.h"
#define noreturn __attribute__((noreturn))
@ -72,14 +72,14 @@ struct range {
u64 end;
};
typedef darray(struct range) ranges;
typedef DARRAY(struct range) ranges;
static inline void range_add(ranges *data, u64 offset, u64 size)
{
darray_append(*data, (struct range) {
darray_push(*data, ((struct range) {
.start = offset,
.end = offset + size
});
}));
}
void ranges_sort_merge(ranges *);
@ -95,9 +95,9 @@ struct hole_iter {
static inline struct range hole_iter_next(struct hole_iter *iter)
{
struct range r = {
.start = iter->idx ? iter->r.item[iter->idx - 1].end : 0,
.start = iter->idx ? iter->r.data[iter->idx - 1].end : 0,
.end = iter->idx < iter->r.size
? iter->r.item[iter->idx].start : iter->end,
? iter->r.data[iter->idx].start : iter->end,
};
BUG_ON(r.start > r.end);