mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-02-23 00:00:02 +03:00
Update bcachefs sources to f638850417 bcachefs: bch2_trans_log_msg()
This commit is contained in:
parent
59abea5776
commit
e240b4ae86
@ -1 +1 @@
|
||||
7786034caa4ee7d10d25202284220513c0944ce2
|
||||
f638850417c9042dab40511e3c3ed0b1be355301
|
||||
|
@ -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.
|
@ -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;
|
||||
}
|
@ -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);
|
||||
*/
|
@ -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[])
|
||||
|
30
cmd_format.c
30
cmd_format.c
@ -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;
|
||||
}
|
||||
|
15
cmd_fs.c
15
cmd_fs.c
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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,
|
||||
|
@ -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
76
libbcachefs/darray.h
Normal 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 */
|
@ -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;
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -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 {
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
s->size = new_size;
|
||||
s->d = d;
|
||||
}
|
||||
|
||||
s->d[s->nr++] = id;
|
||||
return 0;
|
||||
int ret = darray_push(s->ids, id);
|
||||
if (ret)
|
||||
bch_err(c, "error reallocating snapshots_seen table (size %zu)",
|
||||
s->ids.size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
2
qcow2.c
2
qcow2.c
@ -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) {
|
||||
|
17
tools-util.c
17
tools-util.c
@ -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);
|
||||
|
12
tools-util.h
12
tools-util.h
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user