From patchwork Wed Apr 19 21:17:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217386 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 44B5FC77B73 for ; Wed, 19 Apr 2023 21:17:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230398AbjDSVRg (ORCPT ); Wed, 19 Apr 2023 17:17:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229951AbjDSVRb (ORCPT ); Wed, 19 Apr 2023 17:17:31 -0400 Received: from mail-qv1-xf2d.google.com (mail-qv1-xf2d.google.com [IPv6:2607:f8b0:4864:20::f2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D776D4EE3 for ; Wed, 19 Apr 2023 14:17:26 -0700 (PDT) Received: by mail-qv1-xf2d.google.com with SMTP id dd8so959391qvb.13 for ; Wed, 19 Apr 2023 14:17:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939045; x=1684531045; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=dFFaX60skZLvb/H5t5wGCjQZF9PslGWVWS6CF85ozQc=; b=5aGGk+Yz2gD9Td0KYWdDHR/Nkf76GvFsp78OQPq6Q37EsW34Jy2LFiVHUEeYOLW0g/ 6q9FKT6KMDuB5WC48VxIGya1yq+kSvNarcKyTr8OwFXLQ9GtMwDBCE48HVvjynfGu301 SCsn/UtBKcFiynrqGYS0nUUTl89ObLtxuJOwza02lil5NAhtyZY6jDbt0sISdW6aulN0 8ose17AHE7sCxtPjR9/CkLreEVEh1yqI/NDxAnrzEPIrFvcWDzL8ROyUaoa5tbSLk7Gm ys6jdn0cI2a3wFGwviO3F9MHLDTxDlgtbgzPmQccas+tt9lyOFlehCiZX/X6TiMrSOVO QAHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939045; x=1684531045; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dFFaX60skZLvb/H5t5wGCjQZF9PslGWVWS6CF85ozQc=; b=Nmgo5+6XeVx5B0ZAVBdmtnxFG55CuhxQNRnqG75UImxlSaxcRv2IAUh5Hgz1GvG7/L VowKQMejOvgTKBNgp2Fm/xsROT98zFKt6cDhta+bDeFSdVgffpIxG5luBsPCgze/5FPg zozE2nFuQhqSjlC9fGWkuzyV8yI/Bvlk/dznHxOFdR6E95rEdb6XsUdf2ra6MK7iFdU1 XCjeVS/+9EW1omiU870fpAyd6560s/oG5/yLz8ewSOru3DZhCJvK6JLGk2juqMDaU9tO P3qRCbne4wijPf4FWE4S+YtDYH7Pm46HqDqkJ4Kfzwl5SjiII8TbblZlkI2iB6uQyzML afEQ== X-Gm-Message-State: AAQBX9e/DM/EqKtQ1PmtO2Pfxg0hV3Zgge+8I9Cv5a3r7VyNvq242iIz rHoJg4nmuWohViyWbieUyi5PN5Dg/pB/BlgkMEOhUw== X-Google-Smtp-Source: AKy350asToS4bqs1UgnPWBJl7gQs0Xq1tTkoVpDbEfZ07CSlVT8DB+sIFsvWcgFBYkCkukiFsV7DRg== X-Received: by 2002:a05:6214:1bcd:b0:5ef:423b:1f4c with SMTP id m13-20020a0562141bcd00b005ef423b1f4cmr30875812qvc.50.1681939044689; Wed, 19 Apr 2023 14:17:24 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id v8-20020a0ccd88000000b005dd8b9345d7sm4607846qvm.111.2023.04.19.14.17.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:24 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 1/8] btrfs-progs: sync uapi/btrfs.h into btrfs-progs Date: Wed, 19 Apr 2023 17:17:12 -0400 Message-Id: <93f8af4b6a6164504f0aeb1221d57c59673f6df5.1681938911.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org We want to keep this file locally as we want to be uptodate with upstream, so we can build btrfs-progs regardless of which kernel is currently installed. Sync this with the upstream version and put it in kernel-shared/uapi to maintain some semblance of where this file comes from. Signed-off-by: Josef Bacik --- btrfs-fragments.c | 2 +- check/main.c | 2 +- cmds/balance.c | 2 +- cmds/device.c | 2 +- cmds/filesystem-usage.h | 2 +- cmds/filesystem.c | 2 +- cmds/inspect.c | 2 +- cmds/property.c | 2 +- cmds/qgroup.c | 2 +- cmds/qgroup.h | 2 +- cmds/quota.c | 2 +- cmds/receive.c | 2 +- cmds/replace.c | 2 +- cmds/rescue-chunk-recover.c | 2 +- cmds/scrub.c | 2 +- cmds/send.c | 2 +- cmds/subvolume-list.c | 2 +- cmds/subvolume.c | 2 +- common/device-scan.c | 2 +- common/device-scan.h | 2 +- common/fsfeatures.c | 2 +- common/send-stream.c | 2 +- common/send-utils.c | 2 +- common/utils.c | 2 +- common/utils.h | 2 +- convert/common.c | 2 +- image/main.c | 2 +- include/kerncompat.h | 1 + kernel-shared/ctree.h | 2 +- include/ioctl.h => kernel-shared/uapi/btrfs.h | 566 ++++++++++-------- mkfs/common.c | 2 +- tests/ioctl-test.c | 2 +- tune/change-metadata-uuid.c | 2 +- tune/change-uuid.c | 2 +- 34 files changed, 365 insertions(+), 266 deletions(-) rename include/ioctl.h => kernel-shared/uapi/btrfs.h (72%) diff --git a/btrfs-fragments.c b/btrfs-fragments.c index df8ad352..970b49e5 100644 --- a/btrfs-fragments.c +++ b/btrfs-fragments.c @@ -31,7 +31,7 @@ #include #include "kernel-shared/ctree.h" #include "common/utils.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int use_color; static void diff --git a/check/main.c b/check/main.c index 467c8a57..b5748d85 100644 --- a/check/main.c +++ b/check/main.c @@ -61,7 +61,7 @@ #include "check/mode-lowmem.h" #include "check/qgroup-verify.h" #include "check/clear-cache.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" /* Global context variables */ struct btrfs_fs_info *gfs_info; diff --git a/cmds/balance.c b/cmds/balance.c index 2fc38164..d7f5cde4 100644 --- a/cmds/balance.c +++ b/cmds/balance.c @@ -33,7 +33,7 @@ #include "common/messages.h" #include "common/help.h" #include "cmds/commands.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static const char * const balance_cmd_group_usage[] = { "btrfs balance [options] ", diff --git a/cmds/device.c b/cmds/device.c index ec70bb33..38b1d692 100644 --- a/cmds/device.c +++ b/cmds/device.c @@ -41,7 +41,7 @@ #include "cmds/commands.h" #include "cmds/filesystem-usage.h" #include "mkfs/common.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static const char * const device_cmd_group_usage[] = { "btrfs device []", diff --git a/cmds/filesystem-usage.h b/cmds/filesystem-usage.h index 902c3384..2c0db9dc 100644 --- a/cmds/filesystem-usage.h +++ b/cmds/filesystem-usage.h @@ -20,7 +20,7 @@ #define __CMDS_FI_USAGE_H__ #include "kerncompat.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" struct device_info { u64 devid; diff --git a/cmds/filesystem.c b/cmds/filesystem.c index c3c6ee3e..2a2c9a8a 100644 --- a/cmds/filesystem.c +++ b/cmds/filesystem.c @@ -57,7 +57,7 @@ #include "common/format-output.h" #include "cmds/commands.h" #include "cmds/filesystem-usage.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" /* * for btrfs fi show, we maintain a hash of fsids we've already printed. diff --git a/cmds/inspect.c b/cmds/inspect.c index 20f433b9..d610b906 100644 --- a/cmds/inspect.c +++ b/cmds/inspect.c @@ -43,7 +43,7 @@ #include "common/string-utils.h" #include "common/string-table.h" #include "cmds/commands.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static const char * const inspect_cmd_group_usage[] = { "btrfs inspect-internal ", diff --git a/cmds/property.c b/cmds/property.c index e4cb3037..0883be99 100644 --- a/cmds/property.c +++ b/cmds/property.c @@ -38,7 +38,7 @@ #include "common/filesystem-utils.h" #include "cmds/commands.h" #include "cmds/props.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #define XATTR_BTRFS_PREFIX "btrfs." #define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1) diff --git a/cmds/qgroup.c b/cmds/qgroup.c index ab4e9ecf..e53f3934 100644 --- a/cmds/qgroup.c +++ b/cmds/qgroup.c @@ -39,7 +39,7 @@ #include "common/messages.h" #include "cmds/commands.h" #include "cmds/qgroup.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #define BTRFS_QGROUP_NFILTERS_INCREASE (2 * BTRFS_QGROUP_FILTER_MAX) #define BTRFS_QGROUP_NCOMPS_INCREASE (2 * BTRFS_QGROUP_COMP_MAX) diff --git a/cmds/qgroup.h b/cmds/qgroup.h index 69b8c11f..db48c0c2 100644 --- a/cmds/qgroup.h +++ b/cmds/qgroup.h @@ -20,7 +20,7 @@ #define __CMDS_QGROUP_H__ #include "kerncompat.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" struct btrfs_qgroup_info { u64 generation; diff --git a/cmds/quota.c b/cmds/quota.c index 0178a242..3559290c 100644 --- a/cmds/quota.c +++ b/cmds/quota.c @@ -27,7 +27,7 @@ #include "common/open-utils.h" #include "common/messages.h" #include "cmds/commands.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static const char * const quota_cmd_group_usage[] = { "btrfs quota [options] ", diff --git a/cmds/receive.c b/cmds/receive.c index ef40d91c..83fedb7e 100644 --- a/cmds/receive.c +++ b/cmds/receive.c @@ -55,7 +55,7 @@ #include "common/string-utils.h" #include "cmds/commands.h" #include "cmds/receive-dump.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" struct btrfs_receive { diff --git a/cmds/replace.c b/cmds/replace.c index 2748b7fb..ebe366e8 100644 --- a/cmds/replace.c +++ b/cmds/replace.c @@ -39,7 +39,7 @@ #include "common/messages.h" #include "cmds/commands.h" #include "mkfs/common.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int print_replace_status(int fd, const char *path, int once); static char *time2string(char *buf, size_t s, __u64 t); diff --git a/cmds/rescue-chunk-recover.c b/cmds/rescue-chunk-recover.c index 6a1b6734..728f7194 100644 --- a/cmds/rescue-chunk-recover.c +++ b/cmds/rescue-chunk-recover.c @@ -37,7 +37,7 @@ #include "common/utils.h" #include "cmds/rescue.h" #include "check/common.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" struct recover_control { int verbose; diff --git a/cmds/scrub.c b/cmds/scrub.c index 4e64ccfc..3cef08b7 100644 --- a/cmds/scrub.c +++ b/cmds/scrub.c @@ -51,7 +51,7 @@ #include "common/units.h" #include "common/help.h" #include "cmds/commands.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static unsigned unit_mode = UNITS_DEFAULT; diff --git a/cmds/send.c b/cmds/send.c index caddb6dd..829d9d8c 100644 --- a/cmds/send.c +++ b/cmds/send.c @@ -35,7 +35,7 @@ #include "common/string-utils.h" #include "common/messages.h" #include "cmds/commands.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #define BTRFS_SEND_BUF_SIZE_V1 (SZ_64K) #define BTRFS_MAX_COMPRESSED (SZ_128K) diff --git a/cmds/subvolume-list.c b/cmds/subvolume-list.c index e0a7b339..82204e3e 100644 --- a/cmds/subvolume-list.c +++ b/cmds/subvolume-list.c @@ -35,7 +35,7 @@ #include "common/string-utils.h" #include "common/utils.h" #include "cmds/commands.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" /* * Naming of options: diff --git a/cmds/subvolume.c b/cmds/subvolume.c index 8bb21f9f..0d109621 100644 --- a/cmds/subvolume.c +++ b/cmds/subvolume.c @@ -42,7 +42,7 @@ #include "common/units.h" #include "cmds/commands.h" #include "cmds/qgroup.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int wait_for_subvolume_cleaning(int fd, size_t count, uint64_t *ids, int sleep_interval) diff --git a/common/device-scan.c b/common/device-scan.c index 8e5ee8ef..84640c00 100644 --- a/common/device-scan.c +++ b/common/device-scan.c @@ -50,7 +50,7 @@ #include "common/defs.h" #include "common/open-utils.h" #include "common/units.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int btrfs_scan_done = 0; diff --git a/common/device-scan.h b/common/device-scan.h index 13a16e0a..f805b489 100644 --- a/common/device-scan.h +++ b/common/device-scan.h @@ -19,7 +19,7 @@ #include "kerncompat.h" #include -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #define BTRFS_SCAN_MOUNTED (1ULL << 0) #define BTRFS_SCAN_LBLKID (1ULL << 1) diff --git a/common/fsfeatures.c b/common/fsfeatures.c index 5a585664..13468818 100644 --- a/common/fsfeatures.c +++ b/common/fsfeatures.c @@ -29,7 +29,7 @@ #include "common/string-utils.h" #include "common/utils.h" #include "common/messages.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" /* * Insert a root item for temporary tree root diff --git a/common/send-stream.c b/common/send-stream.c index e9f565e6..c745d97e 100644 --- a/common/send-stream.c +++ b/common/send-stream.c @@ -26,7 +26,7 @@ #include "crypto/crc32c.h" #include "common/send-stream.h" #include "common/messages.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" struct btrfs_send_attribute { u16 tlv_type; diff --git a/common/send-utils.c b/common/send-utils.c index 85c7f6ee..0ce437c1 100644 --- a/common/send-utils.c +++ b/common/send-utils.c @@ -28,7 +28,7 @@ #include "common/send-utils.h" #include "common/messages.h" #include "common/utils.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len, u64 subvol_id); diff --git a/common/utils.c b/common/utils.c index 2c359dcf..1ab232ea 100644 --- a/common/utils.c +++ b/common/utils.c @@ -38,7 +38,7 @@ #include "common/messages.h" #include "cmds/commands.h" #include "mkfs/common.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int rand_seed_initialized = 0; static unsigned short rand_seed[3]; diff --git a/common/utils.h b/common/utils.h index c06d41bf..531b3c96 100644 --- a/common/utils.h +++ b/common/utils.h @@ -29,7 +29,7 @@ #include "common/internal.h" #include "common/messages.h" #include "common/fsfeatures.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" enum exclusive_operation { BTRFS_EXCLOP_NONE, diff --git a/convert/common.c b/convert/common.c index f104d93f..ec614584 100644 --- a/convert/common.c +++ b/convert/common.c @@ -29,7 +29,7 @@ #include "common/messages.h" #include "mkfs/common.h" #include "convert/common.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #define BTRFS_CONVERT_META_GROUP_SIZE SZ_32M diff --git a/image/main.c b/image/main.c index 7fa215c1..9144cf50 100644 --- a/image/main.c +++ b/image/main.c @@ -54,7 +54,7 @@ #include "cmds/commands.h" #include "image/metadump.h" #include "image/sanitize.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #define MAX_WORKER_THREADS (32) diff --git a/include/kerncompat.h b/include/kerncompat.h index cb2a9400..edb00276 100644 --- a/include/kerncompat.h +++ b/include/kerncompat.h @@ -576,5 +576,6 @@ typedef struct wait_queue_head_s { #define __init #define __cold +#define __user #endif diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index d81d7c02..f31db57b 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -25,7 +25,7 @@ #include "kerncompat.h" #include "common/extent-cache.h" #include "kernel-shared/extent_io.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" struct btrfs_root; struct btrfs_trans_handle; diff --git a/include/ioctl.h b/kernel-shared/uapi/btrfs.h similarity index 72% rename from include/ioctl.h rename to kernel-shared/uapi/btrfs.h index cbcc0672..6473e362 100644 --- a/include/ioctl.h +++ b/kernel-shared/uapi/btrfs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Copyright (C) 2007 Oracle. All rights reserved. * @@ -16,28 +17,20 @@ * Boston, MA 021110-1307, USA. */ -#ifndef __BTRFS_IOCTL_H__ -#define __BTRFS_IOCTL_H__ +#ifndef _UAPI_LINUX_BTRFS_H +#define _UAPI_LINUX_BTRFS_H #ifdef __cplusplus extern "C" { #endif -#include +#include #include -#include - -#ifndef __user -#define __user -#endif - -/* We don't want to include entire kerncompat.h */ -#ifndef BUILD_ASSERT -#define BUILD_ASSERT(x) -#endif +#include #define BTRFS_IOCTL_MAGIC 0x94 #define BTRFS_VOL_NAME_MAX 255 +#define BTRFS_LABEL_SIZE 256 /* this should be 4k */ #define BTRFS_PATH_NAME_MAX 4087 @@ -45,18 +38,20 @@ struct btrfs_ioctl_vol_args { __s64 fd; char name[BTRFS_PATH_NAME_MAX + 1]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_vol_args) == 4096); -#define BTRFS_DEVICE_PATH_NAME_MAX 1024 +#define BTRFS_DEVICE_PATH_NAME_MAX 1024 +#define BTRFS_SUBVOL_NAME_MAX 4039 -/* - * Obsolete since 5.15, functionality removed in kernel 5.7: - * BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) - */ +#ifndef __KERNEL__ +/* Deprecated since 5.7 */ +# define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) +#endif #define BTRFS_SUBVOL_RDONLY (1ULL << 1) #define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) + #define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3) -#define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4) + +#define BTRFS_SUBVOL_SPEC_BY_ID (1ULL << 4) #define BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED \ (BTRFS_SUBVOL_RDONLY | \ @@ -66,8 +61,21 @@ BUILD_ASSERT(sizeof(struct btrfs_ioctl_vol_args) == 4096); #define BTRFS_FSID_SIZE 16 #define BTRFS_UUID_SIZE 16 +#define BTRFS_UUID_UNPARSED_SIZE 37 -#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0) +/* + * flags definition for qgroup limits + * + * Used by: + * struct btrfs_qgroup_limit.flags + * struct btrfs_qgroup_limit_item.flags + */ +#define BTRFS_QGROUP_LIMIT_MAX_RFER (1ULL << 0) +#define BTRFS_QGROUP_LIMIT_MAX_EXCL (1ULL << 1) +#define BTRFS_QGROUP_LIMIT_RSV_RFER (1ULL << 2) +#define BTRFS_QGROUP_LIMIT_RSV_EXCL (1ULL << 3) +#define BTRFS_QGROUP_LIMIT_RFER_CMPR (1ULL << 4) +#define BTRFS_QGROUP_LIMIT_EXCL_CMPR (1ULL << 5) struct btrfs_qgroup_limit { __u64 flags; @@ -76,7 +84,14 @@ struct btrfs_qgroup_limit { __u64 rsv_referenced; __u64 rsv_exclusive; }; -BUILD_ASSERT(sizeof(struct btrfs_qgroup_limit) == 40); + +/* + * flags definition for qgroup inheritance + * + * Used by: + * struct btrfs_qgroup_inherit.flags + */ +#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0) struct btrfs_qgroup_inherit { __u64 flags; @@ -84,17 +99,38 @@ struct btrfs_qgroup_inherit { __u64 num_ref_copies; __u64 num_excl_copies; struct btrfs_qgroup_limit lim; - __u64 qgroups[0]; + __u64 qgroups[]; }; -BUILD_ASSERT(sizeof(struct btrfs_qgroup_inherit) == 72); struct btrfs_ioctl_qgroup_limit_args { __u64 qgroupid; struct btrfs_qgroup_limit lim; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_qgroup_limit_args) == 48); -#define BTRFS_SUBVOL_NAME_MAX 4039 +/* + * Arguments for specification of subvolumes or devices, supporting by-name or + * by-id and flags + * + * The set of supported flags depends on the ioctl + * + * BTRFS_SUBVOL_RDONLY is also provided/consumed by the following ioctls: + * - BTRFS_IOC_SUBVOL_GETFLAGS + * - BTRFS_IOC_SUBVOL_SETFLAGS + */ + +/* Supported flags for BTRFS_IOC_RM_DEV_V2 */ +#define BTRFS_DEVICE_REMOVE_ARGS_MASK \ + (BTRFS_DEVICE_SPEC_BY_ID) + +/* Supported flags for BTRFS_IOC_SNAP_CREATE_V2 and BTRFS_IOC_SUBVOL_CREATE_V2 */ +#define BTRFS_SUBVOL_CREATE_ARGS_MASK \ + (BTRFS_SUBVOL_RDONLY | \ + BTRFS_SUBVOL_QGROUP_INHERIT) + +/* Supported flags for BTRFS_IOC_SNAP_DESTROY_V2 */ +#define BTRFS_SUBVOL_DELETE_ARGS_MASK \ + (BTRFS_SUBVOL_SPEC_BY_ID) + struct btrfs_ioctl_vol_args_v2 { __s64 fd; __u64 transid; @@ -112,7 +148,6 @@ struct btrfs_ioctl_vol_args_v2 { __u64 subvolid; }; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_vol_args_v2) == 4096); /* * structure to report errors and progress to userspace, either as a @@ -161,7 +196,6 @@ struct btrfs_ioctl_scrub_args { /* pad to 1k */ __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_scrub_args) == 1024); #define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 #define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 @@ -172,7 +206,6 @@ struct btrfs_ioctl_dev_replace_start_params { __u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1]; /* in */ __u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1]; /* in */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_replace_start_params) == 2072); #define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED 0 #define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED 1 @@ -187,7 +220,6 @@ struct btrfs_ioctl_dev_replace_status_params { __u64 num_write_errors; /* out */ __u64 num_uncorrectable_read_errors; /* out */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_replace_status_params) == 48); #define BTRFS_IOCTL_DEV_REPLACE_CMD_START 0 #define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS 1 @@ -207,7 +239,6 @@ struct btrfs_ioctl_dev_replace_args { __u64 spare[64]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_replace_args) == 2600); struct btrfs_ioctl_dev_info_args { __u64 devid; /* in/out */ @@ -227,7 +258,18 @@ struct btrfs_ioctl_dev_info_args { __u64 unused[377]; /* pad to 4k */ __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_dev_info_args) == 4096); + +/* + * Retrieve information about the filesystem + */ + +/* Request information about checksum type and size */ +#define BTRFS_FS_INFO_FLAG_CSUM_INFO (1 << 0) + +/* Request information about filesystem generation */ +#define BTRFS_FS_INFO_FLAG_GENERATION (1 << 1) +/* Request information about filesystem metadata UUID */ +#define BTRFS_FS_INFO_FLAG_METADATA_UUID (1 << 2) struct btrfs_ioctl_fs_info_args { __u64 max_id; /* out */ @@ -236,22 +278,70 @@ struct btrfs_ioctl_fs_info_args { __u32 nodesize; /* out */ __u32 sectorsize; /* out */ __u32 clone_alignment; /* out */ - __u32 reserved32; - __u64 reserved[122]; /* pad to 1k */ + /* See BTRFS_FS_INFO_FLAG_* */ + __u16 csum_type; /* out */ + __u16 csum_size; /* out */ + __u64 flags; /* in/out */ + __u64 generation; /* out */ + __u8 metadata_uuid[BTRFS_FSID_SIZE]; /* out */ + __u8 reserved[944]; /* pad to 1k */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_fs_info_args) == 1024); + +/* + * feature flags + * + * Used by: + * struct btrfs_ioctl_feature_flags + */ +#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) +/* + * Older kernels (< 4.9) on big-endian systems produced broken free space tree + * bitmaps, and btrfs-progs also used to corrupt the free space tree (versions + * < 4.7.3). If this bit is clear, then the free space tree cannot be trusted. + * btrfs-progs can also intentionally clear this bit to ask the kernel to + * rebuild the free space tree, however this might not work on older kernels + * that do not know about this bit. If not sure, clear the cache manually on + * first mount when booting older kernel versions. + */ +#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) +#define BTRFS_FEATURE_COMPAT_RO_VERITY (1ULL << 2) + +/* + * Put all block group items into a dedicated block group tree, greatly + * reducing mount time for large filesystem due to better locality. + */ +#define BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE (1ULL << 3) + +#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) +#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) +#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) +#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) +#define BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD (1ULL << 4) + +/* + * older kernels tried to do bigger metadata blocks, but the + * code was pretty buggy. Lets not let them try anymore. + */ +#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA (1ULL << 5) + +#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) +#define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) +#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) +#define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) +#define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10) +#define BTRFS_FEATURE_INCOMPAT_RAID1C34 (1ULL << 11) +#define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12) +#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13) struct btrfs_ioctl_feature_flags { __u64 compat_flags; __u64 compat_ro_flags; __u64 incompat_flags; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_feature_flags) == 24); /* balance control ioctl modes */ #define BTRFS_BALANCE_CTL_PAUSE 1 #define BTRFS_BALANCE_CTL_CANCEL 2 -#define BTRFS_BALANCE_CTL_RESUME 3 /* * this is packed, because it should be exactly the same as its disk @@ -272,7 +362,6 @@ struct btrfs_balance_args { __u32 usage_max; }; }; - __u64 devid; __u64 pstart; __u64 pend; @@ -295,19 +384,89 @@ struct btrfs_balance_args { __u32 limit_max; }; }; + + /* + * Process chunks that cross stripes_min..stripes_max devices, + * BTRFS_BALANCE_ARGS_STRIPES_RANGE + */ __u32 stripes_min; __u32 stripes_max; + __u64 unused[6]; } __attribute__ ((__packed__)); /* report balance progress to userspace */ struct btrfs_balance_progress { __u64 expected; /* estimated # of chunks that will be - * relocated to fulfil the request */ + * relocated to fulfill the request */ __u64 considered; /* # of chunks we have considered so far */ __u64 completed; /* # of chunks relocated so far */ }; +/* + * flags definition for balance + * + * Restriper's general type filter + * + * Used by: + * btrfs_ioctl_balance_args.flags + * btrfs_balance_control.flags (internal) + */ +#define BTRFS_BALANCE_DATA (1ULL << 0) +#define BTRFS_BALANCE_SYSTEM (1ULL << 1) +#define BTRFS_BALANCE_METADATA (1ULL << 2) + +#define BTRFS_BALANCE_TYPE_MASK (BTRFS_BALANCE_DATA | \ + BTRFS_BALANCE_SYSTEM | \ + BTRFS_BALANCE_METADATA) + +#define BTRFS_BALANCE_FORCE (1ULL << 3) +#define BTRFS_BALANCE_RESUME (1ULL << 4) + +/* + * flags definitions for per-type balance args + * + * Balance filters + * + * Used by: + * struct btrfs_balance_args + */ +#define BTRFS_BALANCE_ARGS_PROFILES (1ULL << 0) +#define BTRFS_BALANCE_ARGS_USAGE (1ULL << 1) +#define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2) +#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) +#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) +#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5) +#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6) +#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7) +#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 10) + +#define BTRFS_BALANCE_ARGS_MASK \ + (BTRFS_BALANCE_ARGS_PROFILES | \ + BTRFS_BALANCE_ARGS_USAGE | \ + BTRFS_BALANCE_ARGS_DEVID | \ + BTRFS_BALANCE_ARGS_DRANGE | \ + BTRFS_BALANCE_ARGS_VRANGE | \ + BTRFS_BALANCE_ARGS_LIMIT | \ + BTRFS_BALANCE_ARGS_LIMIT_RANGE | \ + BTRFS_BALANCE_ARGS_STRIPES_RANGE | \ + BTRFS_BALANCE_ARGS_USAGE_RANGE) + +/* + * Profile changing flags. When SOFT is set we won't relocate chunk if + * it already has the target profile (even though it may be + * half-filled). + */ +#define BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8) +#define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9) + + +/* + * flags definition for balance state + * + * Used by: + * struct btrfs_ioctl_balance_args.state + */ #define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0) #define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1) #define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2) @@ -324,7 +483,6 @@ struct btrfs_ioctl_balance_args { __u64 unused[72]; /* pad to 1k */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_balance_args) == 1024); #define BTRFS_INO_LOOKUP_PATH_MAX 4080 struct btrfs_ioctl_ino_lookup_args { @@ -332,9 +490,8 @@ struct btrfs_ioctl_ino_lookup_args { __u64 objectid; char name[BTRFS_INO_LOOKUP_PATH_MAX]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_ino_lookup_args) == 4096); -#define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080 - BTRFS_VOL_NAME_MAX - 1) +#define BTRFS_INO_LOOKUP_USER_PATH_MAX (4080 - BTRFS_VOL_NAME_MAX - 1) struct btrfs_ioctl_ino_lookup_user_args { /* in, inode number containing the subvolume of 'subvolid' */ __u64 dirid; @@ -348,33 +505,55 @@ struct btrfs_ioctl_ino_lookup_user_args { */ char path[BTRFS_INO_LOOKUP_USER_PATH_MAX]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_ino_lookup_user_args) == 4096); +/* Search criteria for the btrfs SEARCH ioctl family. */ struct btrfs_ioctl_search_key { - /* which root are we searching. 0 is the tree of tree roots */ - __u64 tree_id; - - /* keys returned will be >= min and <= max */ - __u64 min_objectid; - __u64 max_objectid; - - /* keys returned will be >= min and <= max */ - __u64 min_offset; - __u64 max_offset; - - /* max and min transids to search for */ - __u64 min_transid; - __u64 max_transid; + /* + * The tree we're searching in. 1 is the tree of tree roots, 2 is the + * extent tree, etc... + * + * A special tree_id value of 0 will cause a search in the subvolume + * tree that the inode which is passed to the ioctl is part of. + */ + __u64 tree_id; /* in */ - /* keys returned will be >= min and <= max */ - __u32 min_type; - __u32 max_type; + /* + * When doing a tree search, we're actually taking a slice from a + * linear search space of 136-bit keys. + * + * A full 136-bit tree key is composed as: + * (objectid << 72) + (type << 64) + offset + * + * The individual min and max values for objectid, type and offset + * define the min_key and max_key values for the search range. All + * metadata items with a key in the interval [min_key, max_key] will be + * returned. + * + * Additionally, we can filter the items returned on transaction id of + * the metadata block they're stored in by specifying a transid range. + * Be aware that this transaction id only denotes when the metadata + * page that currently contains the item got written the last time as + * result of a COW operation. The number does not have any meaning + * related to the transaction in which an individual item that is being + * returned was created or changed. + */ + __u64 min_objectid; /* in */ + __u64 max_objectid; /* in */ + __u64 min_offset; /* in */ + __u64 max_offset; /* in */ + __u64 min_transid; /* in */ + __u64 max_transid; /* in */ + __u32 min_type; /* in */ + __u32 max_type; /* in */ /* - * how many items did userland ask for, and how many are we - * returning + * input: The maximum amount of results desired. + * output: The actual amount of items returned, restricted by any of: + * - reaching the upper bound of the search range + * - reaching the input nr_items amount of items + * - completely filling the supplied memory buffer */ - __u32 nr_items; + __u32 nr_items; /* in/out */ /* align to 64 bits */ __u32 unused; @@ -392,7 +571,7 @@ struct btrfs_ioctl_search_header { __u64 offset; __u32 type; __u32 len; -} __attribute__((may_alias)); +} __attribute__ ((__may_alias__)); #define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) /* @@ -410,13 +589,12 @@ struct btrfs_ioctl_search_args { * The allocated size of the buffer is set in buf_size. */ struct btrfs_ioctl_search_args_v2 { - struct btrfs_ioctl_search_key key; /* in/out - search parameters */ - __u64 buf_size; /* in - size of buffer - * out - on EOVERFLOW: needed size - * to store item */ - __u64 buf[0]; /* out - found items */ + struct btrfs_ioctl_search_key key; /* in/out - search parameters */ + __u64 buf_size; /* in - size of buffer + * out - on EOVERFLOW: needed size + * to store item */ + __u64 buf[]; /* out - found items */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_search_args_v2) == 112); /* With a @src_length of zero, the range from @src_offset->EOF is cloned! */ struct btrfs_ioctl_clone_range_args { @@ -424,38 +602,15 @@ struct btrfs_ioctl_clone_range_args { __u64 src_offset, src_length; __u64 dest_offset; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_clone_range_args) == 32); -/* flags for the defrag range ioctl */ +/* + * flags definition for the defrag range ioctl + * + * Used by: + * struct btrfs_ioctl_defrag_range_args.flags + */ #define BTRFS_DEFRAG_RANGE_COMPRESS 1 #define BTRFS_DEFRAG_RANGE_START_IO 2 - -#define BTRFS_SAME_DATA_DIFFERS 1 -/* For extent-same ioctl */ -struct btrfs_ioctl_same_extent_info { - __s64 fd; /* in - destination file */ - __u64 logical_offset; /* in - start of extent in destination */ - __u64 bytes_deduped; /* out - total # of bytes we were able - * to dedupe from this file */ - /* status of this dedupe operation: - * 0 if dedup succeeds - * < 0 for error - * == BTRFS_SAME_DATA_DIFFERS if data differs - */ - __s32 status; /* out - see above description */ - __u32 reserved; -}; - -struct btrfs_ioctl_same_args { - __u64 logical_offset; /* in - start of extent in source */ - __u64 length; /* in - length of extent */ - __u16 dest_count; /* in - total elements in info array */ - __u16 reserved1; - __u32 reserved2; - struct btrfs_ioctl_same_extent_info info[0]; -}; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_same_args) == 24); - struct btrfs_ioctl_defrag_range_args { /* start of the defrag operation */ __u64 start; @@ -486,7 +641,32 @@ struct btrfs_ioctl_defrag_range_args { /* spare for later */ __u32 unused[4]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_defrag_range_args) == 48); + + +#define BTRFS_SAME_DATA_DIFFERS 1 +/* For extent-same ioctl */ +struct btrfs_ioctl_same_extent_info { + __s64 fd; /* in - destination file */ + __u64 logical_offset; /* in - start of extent in destination */ + __u64 bytes_deduped; /* out - total # of bytes we were able + * to dedupe from this file */ + /* status of this dedupe operation: + * 0 if dedup succeeds + * < 0 for error + * == BTRFS_SAME_DATA_DIFFERS if data differs + */ + __s32 status; /* out - see above description */ + __u32 reserved; +}; + +struct btrfs_ioctl_same_args { + __u64 logical_offset; /* in - start of extent in source */ + __u64 length; /* in - length of extent */ + __u16 dest_count; /* in - total elements in info array */ + __u16 reserved1; + __u32 reserved2; + struct btrfs_ioctl_same_extent_info info[]; +}; struct btrfs_ioctl_space_info { __u64 flags; @@ -497,16 +677,15 @@ struct btrfs_ioctl_space_info { struct btrfs_ioctl_space_args { __u64 space_slots; __u64 total_spaces; - struct btrfs_ioctl_space_info spaces[0]; + struct btrfs_ioctl_space_info spaces[]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_space_args) == 16); struct btrfs_data_container { __u32 bytes_left; /* out -- bytes not needed to deliver output */ __u32 bytes_missing; /* out -- additional bytes needed for result */ __u32 elem_cnt; /* out */ __u32 elem_missed; /* out */ - __u64 val[0]; /* out */ + __u64 val[]; /* out */ }; struct btrfs_ioctl_ino_path_args { @@ -516,13 +695,12 @@ struct btrfs_ioctl_ino_path_args { /* struct btrfs_data_container *fspath; out */ __u64 fspath; /* out */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_ino_path_args) == 56); struct btrfs_ioctl_logical_ino_args { __u64 logical; /* in */ __u64 size; /* in */ - __u64 reserved[3]; - __u64 flags; /* in */ + __u64 reserved[3]; /* must be 0 for now */ + __u64 flags; /* in, v2 only */ /* struct btrfs_data_container *inodes; out */ __u64 inodes; }; @@ -531,7 +709,7 @@ struct btrfs_ioctl_logical_ino_args { * Return every ref to the extent, not just those containing logical block. * Requires logical == extent bytenr. */ -#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET (1ULL << 0) +#define BTRFS_LOGICAL_INO_ARGS_IGNORE_OFFSET (1ULL << 0) enum btrfs_dev_stat_values { /* disk I/O failure stats */ @@ -563,26 +741,27 @@ struct btrfs_ioctl_get_dev_stats { /* out values: */ __u64 values[BTRFS_DEV_STAT_VALUES_MAX]; - __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k + 8B */ + /* + * This pads the struct to 1032 bytes. It was originally meant to pad to + * 1024 bytes, but when adding the flags field, the padding calculation + * was not adjusted. + */ + __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_get_dev_stats) == 1032); -/* BTRFS_IOC_SNAP_CREATE is no longer used by the btrfs command */ #define BTRFS_QUOTA_CTL_ENABLE 1 #define BTRFS_QUOTA_CTL_DISABLE 2 -/* 3 has formerly been reserved for BTRFS_QUOTA_CTL_RESCAN */ +#define BTRFS_QUOTA_CTL_RESCAN__NOTUSED 3 struct btrfs_ioctl_quota_ctl_args { __u64 cmd; __u64 status; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_quota_ctl_args) == 16); struct btrfs_ioctl_quota_rescan_args { __u64 flags; __u64 progress; __u64 reserved[6]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_quota_rescan_args) == 64); struct btrfs_ioctl_qgroup_assign_args { __u64 assign; @@ -594,8 +773,6 @@ struct btrfs_ioctl_qgroup_create_args { __u64 create; __u64 qgroupid; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_qgroup_create_args) == 16); - struct btrfs_ioctl_timespec { __u64 sec; __u32 nsec; @@ -610,39 +787,6 @@ struct btrfs_ioctl_received_subvol_args { __u64 flags; /* in */ __u64 reserved[16]; /* in */ }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_received_subvol_args) == 200); - -/* - * If we have a 32-bit userspace and 64-bit kernel, then the UAPI - * structures are incorrect, as the timespec structure from userspace - * is 4 bytes too small. We define these alternatives here for backward - * compatibility, the kernel understands both values. - */ - -/* - * Structure size is different on 32bit and 64bit, has some padding if the - * structure is embedded. Packing makes sure the size is same on both, but will - * be misaligned on 64bit. - * - * NOTE: do not use in your code, this is for testing only - */ -struct btrfs_ioctl_timespec_32 { - __u64 sec; - __u32 nsec; -} __attribute__ ((__packed__)); - -struct btrfs_ioctl_received_subvol_args_32 { - char uuid[BTRFS_UUID_SIZE]; /* in */ - __u64 stransid; /* in */ - __u64 rtransid; /* out */ - struct btrfs_ioctl_timespec_32 stime; /* in */ - struct btrfs_ioctl_timespec_32 rtime; /* out */ - __u64 flags; /* in */ - __u64 reserved[16]; /* in */ -} __attribute__ ((__packed__)); -BUILD_ASSERT(sizeof(struct btrfs_ioctl_received_subvol_args_32) == 192); - -#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32_COMPAT_DEFINED 1 /* * Caller doesn't want file data in the send stream, even if the @@ -690,39 +834,8 @@ struct btrfs_ioctl_send_args { __u64 parent_root; /* in */ __u64 flags; /* in */ __u32 version; /* in */ - __u8 reserved[28]; /* in */ + __u8 reserved[28]; /* in */ }; -/* - * Size of structure depends on pointer width, was not caught in the early - * days. Kernel handles pointer width differences transparently. - */ -BUILD_ASSERT(sizeof(__u64 *) == 8 - ? sizeof(struct btrfs_ioctl_send_args) == 72 - : (sizeof(void *) == 4 - ? sizeof(struct btrfs_ioctl_send_args) == 68 - : 0)); - -/* - * Different pointer width leads to structure size change. Kernel should accept - * both ioctl values (derived from the structures) for backward compatibility. - * Size of this structure is same on 32bit and 64bit though. - * - * NOTE: do not use in your code, this is for testing only - */ -struct btrfs_ioctl_send_args_64 { - __s64 send_fd; /* in */ - __u64 clone_sources_count; /* in */ - union { - __u64 __user *clone_sources; /* in */ - __u64 __clone_sources_alignment; - }; - __u64 parent_root; /* in */ - __u64 flags; /* in */ - __u64 reserved[4]; /* in */ -} __attribute__((packed)); -BUILD_ASSERT(sizeof(struct btrfs_ioctl_send_args_64) == 72); - -#define BTRFS_IOC_SEND_64_COMPAT_DEFINED 1 /* * Information about a fs tree root. @@ -784,22 +897,21 @@ struct btrfs_ioctl_get_subvol_info_args { __u64 reserved[8]; }; -#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255 +#define BTRFS_MAX_ROOTREF_BUFFER_NUM 255 struct btrfs_ioctl_get_subvol_rootref_args { - /* in/out, minimum id of rootref's treeid to be searched */ - __u64 min_treeid; - - /* out */ - struct { - __u64 treeid; - __u64 dirid; - } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM]; - - /* out, number of found items */ - __u8 num_items; - __u8 align[7]; + /* in/out, minimum id of rootref's treeid to be searched */ + __u64 min_treeid; + + /* out */ + struct { + __u64 treeid; + __u64 dirid; + } rootref[BTRFS_MAX_ROOTREF_BUFFER_NUM]; + + /* out, number of found items */ + __u8 num_items; + __u8 align[7]; }; -BUILD_ASSERT(sizeof(struct btrfs_ioctl_get_subvol_rootref_args) == 4096); /* * Data and metadata for an encoded read or write. @@ -931,8 +1043,7 @@ struct btrfs_ioctl_encoded_io_args { /* Error codes as returned by the kernel */ enum btrfs_err_code { - notused, - BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET, + BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET, BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET, BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET, @@ -954,12 +1065,12 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args) #define BTRFS_IOC_FORGET_DEV _IOW(BTRFS_IOCTL_MAGIC, 5, \ struct btrfs_ioctl_vol_args) -/* - * Removed in kernel since 4.17: - * BTRFS_IOC_TRANS_START _IO(BTRFS_IOCTL_MAGIC, 6) - * BTRFS_IOC_TRANS_END _IO(BTRFS_IOCTL_MAGIC, 7) +/* trans start and trans end are dangerous, and only for + * use by applications that know how to avoid the + * resulting deadlocks */ - +#define BTRFS_IOC_TRANS_START _IO(BTRFS_IOCTL_MAGIC, 6) +#define BTRFS_IOC_TRANS_END _IO(BTRFS_IOCTL_MAGIC, 7) #define BTRFS_IOC_SYNC _IO(BTRFS_IOCTL_MAGIC, 8) #define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int) @@ -971,18 +1082,18 @@ enum btrfs_err_code { struct btrfs_ioctl_vol_args) #define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ - struct btrfs_ioctl_clone_range_args) + struct btrfs_ioctl_clone_range_args) #define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ - struct btrfs_ioctl_vol_args) + struct btrfs_ioctl_vol_args) #define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \ struct btrfs_ioctl_defrag_range_args) #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ struct btrfs_ioctl_search_args) #define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \ - struct btrfs_ioctl_search_args_v2) + struct btrfs_ioctl_search_args_v2) #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ struct btrfs_ioctl_ino_lookup_args) #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) @@ -997,14 +1108,14 @@ enum btrfs_err_code { #define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64) #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) #define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \ - struct btrfs_ioctl_scrub_args) + struct btrfs_ioctl_scrub_args) #define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28) #define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \ - struct btrfs_ioctl_scrub_args) + struct btrfs_ioctl_scrub_args) #define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ - struct btrfs_ioctl_dev_info_args) + struct btrfs_ioctl_dev_info_args) #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ - struct btrfs_ioctl_fs_info_args) + struct btrfs_ioctl_fs_info_args) #define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ struct btrfs_ioctl_balance_args) #define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) @@ -1016,37 +1127,24 @@ enum btrfs_err_code { struct btrfs_ioctl_logical_ino_args) #define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \ struct btrfs_ioctl_received_subvol_args) - -#ifdef BTRFS_IOC_SET_RECEIVED_SUBVOL_32_COMPAT_DEFINED -#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \ - struct btrfs_ioctl_received_subvol_args_32) -#endif - -#ifdef BTRFS_IOC_SEND_64_COMPAT_DEFINED -#define BTRFS_IOC_SEND_64 _IOW(BTRFS_IOCTL_MAGIC, 38, \ - struct btrfs_ioctl_send_args_64) -#endif - #define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args) #define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \ struct btrfs_ioctl_vol_args) #define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \ - struct btrfs_ioctl_quota_ctl_args) + struct btrfs_ioctl_quota_ctl_args) #define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \ - struct btrfs_ioctl_qgroup_assign_args) + struct btrfs_ioctl_qgroup_assign_args) #define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \ - struct btrfs_ioctl_qgroup_create_args) + struct btrfs_ioctl_qgroup_create_args) #define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \ - struct btrfs_ioctl_qgroup_limit_args) + struct btrfs_ioctl_qgroup_limit_args) #define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \ struct btrfs_ioctl_quota_rescan_args) #define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \ struct btrfs_ioctl_quota_rescan_args) #define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46) -#define BTRFS_IOC_GET_FSLABEL _IOR(BTRFS_IOCTL_MAGIC, 49, \ - char[BTRFS_LABEL_SIZE]) -#define BTRFS_IOC_SET_FSLABEL _IOW(BTRFS_IOCTL_MAGIC, 50, \ - char[BTRFS_LABEL_SIZE]) +#define BTRFS_IOC_GET_FSLABEL FS_IOC_GETFSLABEL +#define BTRFS_IOC_SET_FSLABEL FS_IOC_SETFSLABEL #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ struct btrfs_ioctl_get_dev_stats) #define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \ @@ -1054,15 +1152,15 @@ enum btrfs_err_code { #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ struct btrfs_ioctl_same_args) #define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ - struct btrfs_ioctl_feature_flags) + struct btrfs_ioctl_feature_flags) #define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \ - struct btrfs_ioctl_feature_flags[2]) + struct btrfs_ioctl_feature_flags[2]) #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ - struct btrfs_ioctl_feature_flags[3]) -#define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \ + struct btrfs_ioctl_feature_flags[3]) +#define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \ struct btrfs_ioctl_vol_args_v2) #define BTRFS_IOC_LOGICAL_INO_V2 _IOWR(BTRFS_IOCTL_MAGIC, 59, \ - struct btrfs_ioctl_logical_ino_args) + struct btrfs_ioctl_logical_ino_args) #define BTRFS_IOC_GET_SUBVOL_INFO _IOR(BTRFS_IOCTL_MAGIC, 60, \ struct btrfs_ioctl_get_subvol_info_args) #define BTRFS_IOC_GET_SUBVOL_ROOTREF _IOWR(BTRFS_IOCTL_MAGIC, 61, \ @@ -1070,7 +1168,7 @@ enum btrfs_err_code { #define BTRFS_IOC_INO_LOOKUP_USER _IOWR(BTRFS_IOCTL_MAGIC, 62, \ struct btrfs_ioctl_ino_lookup_user_args) #define BTRFS_IOC_SNAP_DESTROY_V2 _IOW(BTRFS_IOCTL_MAGIC, 63, \ - struct btrfs_ioctl_vol_args_v2) + struct btrfs_ioctl_vol_args_v2) #define BTRFS_IOC_ENCODED_READ _IOR(BTRFS_IOCTL_MAGIC, 64, \ struct btrfs_ioctl_encoded_io_args) #define BTRFS_IOC_ENCODED_WRITE _IOW(BTRFS_IOCTL_MAGIC, 64, \ @@ -1080,4 +1178,4 @@ enum btrfs_err_code { } #endif -#endif +#endif /* _UAPI_LINUX_BTRFS_H */ diff --git a/mkfs/common.c b/mkfs/common.c index 5238f006..40d07deb 100644 --- a/mkfs/common.c +++ b/mkfs/common.c @@ -38,7 +38,7 @@ #include "common/device-utils.h" #include "common/open-utils.h" #include "mkfs/common.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static u64 reference_root_table[] = { [MKFS_ROOT_TREE] = BTRFS_ROOT_TREE_OBJECTID, diff --git a/tests/ioctl-test.c b/tests/ioctl-test.c index a8a120ac..8452684a 100644 --- a/tests/ioctl-test.c +++ b/tests/ioctl-test.c @@ -18,7 +18,7 @@ #include #include -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" #include "kernel-shared/ctree.h" #define LIST_32_COMPAT \ diff --git a/tune/change-metadata-uuid.c b/tune/change-metadata-uuid.c index 0ce008ab..e6faf7db 100644 --- a/tune/change-metadata-uuid.c +++ b/tune/change-metadata-uuid.c @@ -22,7 +22,7 @@ #include "kernel-shared/transaction.h" #include "common/messages.h" #include "tune/tune.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" int set_metadata_uuid(struct btrfs_root *root, const char *uuid_string) { diff --git a/tune/change-uuid.c b/tune/change-uuid.c index f148b9e5..628a1bba 100644 --- a/tune/change-uuid.c +++ b/tune/change-uuid.c @@ -25,7 +25,7 @@ #include "kernel-shared/volumes.h" #include "common/defs.h" #include "common/messages.h" -#include "ioctl.h" +#include "kernel-shared/uapi/btrfs.h" static int change_fsid_prepare(struct btrfs_fs_info *fs_info, uuid_t new_fsid) { From patchwork Wed Apr 19 21:17:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217388 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA8D9C77B7A for ; Wed, 19 Apr 2023 21:17:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230480AbjDSVRi (ORCPT ); Wed, 19 Apr 2023 17:17:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230041AbjDSVRd (ORCPT ); Wed, 19 Apr 2023 17:17:33 -0400 Received: from mail-qv1-xf33.google.com (mail-qv1-xf33.google.com [IPv6:2607:f8b0:4864:20::f33]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3D47C59FE for ; Wed, 19 Apr 2023 14:17:28 -0700 (PDT) Received: by mail-qv1-xf33.google.com with SMTP id h14so1022461qvr.7 for ; Wed, 19 Apr 2023 14:17:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939047; x=1684531047; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=oh1dpq/rgodqSThtaPqj+w/HM7CjssLAdjoDpUJRqEo=; b=jnrg5K+yr8shurKJPy/lABAOMSUs9tRHDL2qbcSqjbU4GpMdqumRU/XyH7pZ24enBV +GeCVcxkNvOgO9XHhB96CS2qHmbwfhh73L21nRhmAyP3mvJ2ruutj4NOENohv0I0sBiP +3tsLgL4kkhZQdt57lQ9+Xw1CHCm1/DiiI6VZdsx6S2etPQYWSjBopu3+83zMS2qTAfS Smmh5l5i7J56UhpPF6mlEVPQWsehaTzXbjkBQKrSlaYE0VZwZ6iifQXciJqoUZeptZR7 PFY2YFgZZ+UAw/rOzAAFt8i8urfm4/E8r6097e2Yz2xd7ud66OgNFfekXlyenZPfSTrk l1nw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939047; x=1684531047; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=oh1dpq/rgodqSThtaPqj+w/HM7CjssLAdjoDpUJRqEo=; b=RPcLNMWfWVCL08Q3iSE75hZ03Wb7aAPSEO+0iwC1PUuGVFZPb28HnY0MqW/77ROL84 u2Lp7mdSpwvXUBgiXri5W83UaoFcs4bsEJrbd7tSS/aHdp0iVQd/NAY+RwbVzkirR68P ZNPaKSCs9tKBoROVOA7fVTKQNxLfiG/yYAT88ldJ9a3LnfZPYLWw+tRhta0STL2W8GCJ D4ipdPr4JBvNKDh3ipWp0/lxd9R/cY1V1YrvyenRtAWmqEZUbH78sDs1ckfSEBeP+3LO G/gCjRU4Scdb0LdXWqt0rRE1vHKvdkwS77jlPSUACw8JfIaBC48dPULA+Bm3+KrtzUZD Uk9g== X-Gm-Message-State: AAQBX9f7oP1HP6Xl84/n+MArBMBWH92QdLpUnIqjGgesm+apH18jrr2P DHg58ov5DSyNEqtdr63/ffAZmPr+oC0YqMbGuAUbRg== X-Google-Smtp-Source: AKy350Yp0wRIZi1Q2vWRhx65gnFkHVWdagxsqj0cLoNO1Ypn9Fw/dODAzGc2csAtOjTMHH93RDaAkw== X-Received: by 2002:ad4:5c83:0:b0:5f1:6c2c:1d75 with SMTP id o3-20020ad45c83000000b005f16c2c1d75mr6917692qvh.28.1681939046235; Wed, 19 Apr 2023 14:17:26 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id w4-20020a05620a094400b0074e003c55f0sm1754592qkw.102.2023.04.19.14.17.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:25 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 2/8] btrfs-progs: sync ondisk definitions from the kernel Date: Wed, 19 Apr 2023 17:17:13 -0400 Message-Id: X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org This pulls in the kernel's btrfs_tree.h, which now has all of the ondisk definitions. Include this into ctree.h, and then yank out all the duplicate code from ctree.h. Signed-off-by: Josef Bacik --- kernel-shared/ctree.h | 954 +---------------------- kernel-shared/uapi/btrfs_tree.h | 1259 +++++++++++++++++++++++++++++++ 2 files changed, 1261 insertions(+), 952 deletions(-) create mode 100644 kernel-shared/uapi/btrfs_tree.h diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index f31db57b..a5bcc9bc 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -26,11 +26,11 @@ #include "common/extent-cache.h" #include "kernel-shared/extent_io.h" #include "kernel-shared/uapi/btrfs.h" +#include "kernel-shared/uapi/btrfs_tree.h" struct btrfs_root; struct btrfs_trans_handle; struct btrfs_free_space_ctl; -#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */ /* * Fake signature for an unfinalized filesystem, which only has barebone tree @@ -42,272 +42,10 @@ struct btrfs_free_space_ctl; #define BTRFS_MAX_MIRRORS 3 -#define BTRFS_MAX_LEVEL 8 - -/* holds pointers to all of the tree roots */ -#define BTRFS_ROOT_TREE_OBJECTID 1ULL - -/* stores information about which extents are in use, and reference counts */ -#define BTRFS_EXTENT_TREE_OBJECTID 2ULL - -/* - * chunk tree stores translations from logical -> physical block numbering - * the super block points to the chunk tree - */ -#define BTRFS_CHUNK_TREE_OBJECTID 3ULL - -/* - * stores information about which areas of a given device are in use. - * one per device. The tree of tree roots points to the device tree - */ -#define BTRFS_DEV_TREE_OBJECTID 4ULL - -/* one per subvolume, storing files and directories */ -#define BTRFS_FS_TREE_OBJECTID 5ULL - -/* directory objectid inside the root tree */ -#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL -/* holds checksums of all the data extents */ -#define BTRFS_CSUM_TREE_OBJECTID 7ULL -#define BTRFS_QUOTA_TREE_OBJECTID 8ULL - -/* for storing items that use the BTRFS_UUID_KEY* */ -#define BTRFS_UUID_TREE_OBJECTID 9ULL - -/* tracks free space in block groups. */ -#define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL - -/* hold the block group items. */ -#define BTRFS_BLOCK_GROUP_TREE_OBJECTID 11ULL - -/* device stats in the device tree */ -#define BTRFS_DEV_STATS_OBJECTID 0ULL - -/* for storing balance parameters in the root tree */ -#define BTRFS_BALANCE_OBJECTID -4ULL - -/* orphan objectid for tracking unlinked/truncated files */ -#define BTRFS_ORPHAN_OBJECTID -5ULL - -/* does write ahead logging to speed up fsyncs */ -#define BTRFS_TREE_LOG_OBJECTID -6ULL -#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL - -/* space balancing */ -#define BTRFS_TREE_RELOC_OBJECTID -8ULL -#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL - -/* - * extent checksums all have this objectid - * this allows them to share the logging tree - * for fsyncs - */ -#define BTRFS_EXTENT_CSUM_OBJECTID -10ULL - -/* For storing free space cache */ -#define BTRFS_FREE_SPACE_OBJECTID -11ULL - -/* - * The inode number assigned to the special inode for storing - * free ino cache - */ -#define BTRFS_FREE_INO_OBJECTID -12ULL - -/* dummy objectid represents multiple objectids */ -#define BTRFS_MULTIPLE_OBJECTIDS -255ULL - -/* - * All files have objectids in this range. - */ -#define BTRFS_FIRST_FREE_OBJECTID 256ULL -#define BTRFS_LAST_FREE_OBJECTID -256ULL -#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL - - - -/* - * the device items go into the chunk tree. The key is in the form - * [ 1 BTRFS_DEV_ITEM_KEY device_id ] - */ -#define BTRFS_DEV_ITEMS_OBJECTID 1ULL - -#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2ULL - -/* - * the max metadata block size. This limit is somewhat artificial, - * but the memmove costs go through the roof for larger blocks. - */ -#define BTRFS_MAX_METADATA_BLOCKSIZE 65536 - -/* - * we can actually store much bigger names, but lets not confuse the rest - * of linux - */ -#define BTRFS_NAME_LEN 255 - -/* - * Theoretical limit is larger, but we keep this down to a sane - * value. That should limit greatly the possibility of collisions on - * inode ref items. - */ -#define BTRFS_LINK_MAX 65535U - -/* 32 bytes in various csum fields */ -#define BTRFS_CSUM_SIZE 32 - -/* csum types */ -enum btrfs_csum_type { - BTRFS_CSUM_TYPE_CRC32 = 0, - BTRFS_CSUM_TYPE_XXHASH = 1, - BTRFS_CSUM_TYPE_SHA256 = 2, - BTRFS_CSUM_TYPE_BLAKE2 = 3, -}; - -#define BTRFS_EMPTY_DIR_SIZE 0 - -#define BTRFS_FT_UNKNOWN 0 -#define BTRFS_FT_REG_FILE 1 -#define BTRFS_FT_DIR 2 -#define BTRFS_FT_CHRDEV 3 -#define BTRFS_FT_BLKDEV 4 -#define BTRFS_FT_FIFO 5 -#define BTRFS_FT_SOCK 6 -#define BTRFS_FT_SYMLINK 7 -#define BTRFS_FT_XATTR 8 -#define BTRFS_FT_MAX 9 - -#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) - -/* - * the key defines the order in the tree, and so it also defines (optimal) - * block layout. objectid corresponds to the inode number. The flags - * tells us things about the object, and is a kind of stream selector. - * so for a given inode, keys with flags of 1 might refer to the inode - * data, flags of 2 may point to file data in the btree and flags == 3 - * may point to extents. - * - * offset is the starting byte offset for this key in the stream. - * - * btrfs_disk_key is in disk byte order. struct btrfs_key is always - * in cpu native order. Otherwise they are identical and their sizes - * should be the same (ie both packed) - */ -struct btrfs_disk_key { - __le64 objectid; - u8 type; - __le64 offset; -} __attribute__ ((__packed__)); - -struct btrfs_key { - u64 objectid; - u8 type; - u64 offset; -} __attribute__ ((__packed__)); - struct btrfs_mapping_tree { struct cache_tree cache_tree; }; -#define BTRFS_UUID_SIZE 16 -struct btrfs_dev_item { - /* the internal btrfs device id */ - __le64 devid; - - /* size of the device */ - __le64 total_bytes; - - /* bytes used */ - __le64 bytes_used; - - /* optimal io alignment for this device */ - __le32 io_align; - - /* optimal io width for this device */ - __le32 io_width; - - /* minimal io size for this device */ - __le32 sector_size; - - /* type and info about this device */ - __le64 type; - - /* expected generation for this device */ - __le64 generation; - - /* - * starting byte of this partition on the device, - * to allow for stripe alignment in the future - */ - __le64 start_offset; - - /* grouping information for allocation decisions */ - __le32 dev_group; - - /* seek speed 0-100 where 100 is fastest */ - u8 seek_speed; - - /* bandwidth 0-100 where 100 is fastest */ - u8 bandwidth; - - /* btrfs generated uuid for this device */ - u8 uuid[BTRFS_UUID_SIZE]; - - /* uuid of FS who owns this device */ - u8 fsid[BTRFS_UUID_SIZE]; -} __attribute__ ((__packed__)); - -struct btrfs_stripe { - __le64 devid; - __le64 offset; - u8 dev_uuid[BTRFS_UUID_SIZE]; -} __attribute__ ((__packed__)); - -struct btrfs_chunk { - /* size of this chunk in bytes */ - __le64 length; - - /* objectid of the root referencing this chunk */ - __le64 owner; - - __le64 stripe_len; - __le64 type; - - /* optimal io alignment for this chunk */ - __le32 io_align; - - /* optimal io width for this chunk */ - __le32 io_width; - - /* minimal io size for this chunk */ - __le32 sector_size; - - /* 2^16 stripes is quite a lot, a second limit is the size of a single - * item in the btree - */ - __le16 num_stripes; - - /* sub stripes only matter for raid10 */ - __le16 sub_stripes; - struct btrfs_stripe stripe; - /* additional stripes go here */ -} __attribute__ ((__packed__)); - -#define BTRFS_FREE_SPACE_EXTENT 1 -#define BTRFS_FREE_SPACE_BITMAP 2 - -struct btrfs_free_space_entry { - __le64 offset; - __le64 bytes; - u8 type; -} __attribute__ ((__packed__)); - -struct btrfs_free_space_header { - struct btrfs_disk_key location; - __le64 generation; - __le64 num_entries; - __le64 num_bitmaps; -} __attribute__ ((__packed__)); - static inline unsigned long btrfs_chunk_item_size(int num_stripes) { BUG_ON(num_stripes == 0); @@ -315,17 +53,8 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) sizeof(struct btrfs_stripe) * (num_stripes - 1); } -#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) -#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) - /* Temporary flag not on-disk for blocks that have changed csum already */ -#define BTRFS_HEADER_FLAG_CSUM_NEW (1ULL << 16) - -#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) -#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) -#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) -#define BTRFS_SUPER_FLAG_CHANGING_FSID (1ULL << 35) -#define BTRFS_SUPER_FLAG_CHANGING_FSID_V2 (1ULL << 36) +#define BTRFS_HEADER_FLAG_CSUM_NEW (1ULL << 16) #define BTRFS_SUPER_FLAG_CHANGING_CSUM (1ULL << 37) /* @@ -335,32 +64,6 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes) */ #define BTRFS_SUPER_FLAG_CHANGING_BG_TREE (1ULL << 38) -#define BTRFS_BACKREF_REV_MAX 256 -#define BTRFS_BACKREF_REV_SHIFT 56 -#define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \ - BTRFS_BACKREF_REV_SHIFT) - -#define BTRFS_OLD_BACKREF_REV 0 -#define BTRFS_MIXED_BACKREF_REV 1 - -/* - * every tree block (leaf or node) starts with this header. - */ -struct btrfs_header { - /* these first four must match the super block */ - u8 csum[BTRFS_CSUM_SIZE]; - u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ - __le64 bytenr; /* which block this node is supposed to live in */ - __le64 flags; - - /* allowed to be different from the super from here on down */ - u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; - __le64 generation; - __le64 owner; - __le32 nritems; - u8 level; -} __attribute__ ((__packed__)); - static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 nodesize) { return nodesize - sizeof(struct btrfs_header); @@ -368,160 +71,9 @@ static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 nodesize) #define BTRFS_LEAF_DATA_SIZE(fs_info) (fs_info->leaf_data_size) -/* - * this is a very generous portion of the super block, giving us - * room to translate 14 chunks with 3 stripes each. - */ -#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 -#define BTRFS_LABEL_SIZE 256 - -/* - * just in case we somehow lose the roots and are not able to mount, - * we store an array of the roots from previous transactions - * in the super. - */ -#define BTRFS_NUM_BACKUP_ROOTS 4 -struct btrfs_root_backup { - __le64 tree_root; - __le64 tree_root_gen; - - __le64 chunk_root; - __le64 chunk_root_gen; - - __le64 extent_root; - __le64 extent_root_gen; - - __le64 fs_root; - __le64 fs_root_gen; - - __le64 dev_root; - __le64 dev_root_gen; - - __le64 csum_root; - __le64 csum_root_gen; - - __le64 total_bytes; - __le64 bytes_used; - __le64 num_devices; - /* future */ - __le64 unsed_64[4]; - - u8 tree_root_level; - u8 chunk_root_level; - u8 extent_root_level; - u8 fs_root_level; - u8 dev_root_level; - u8 csum_root_level; - /* future and to align */ - u8 unused_8[10]; -} __attribute__ ((__packed__)); - #define BTRFS_SUPER_INFO_OFFSET (65536) #define BTRFS_SUPER_INFO_SIZE (4096) -/* - * the super block basically lists the main trees of the FS - * it currently lacks any block count etc etc - */ -struct btrfs_super_block { - u8 csum[BTRFS_CSUM_SIZE]; - /* the first 3 fields must match struct btrfs_header */ - u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ - __le64 bytenr; /* this block number */ - __le64 flags; - - /* allowed to be different from the btrfs_header from here own down */ - __le64 magic; - __le64 generation; - __le64 root; - __le64 chunk_root; - __le64 log_root; - - /* - * This has never been used and is 0 in all versions. We always use - * generation + 1 to read log tree root. - */ - __le64 __unused_log_root_transid; - __le64 total_bytes; - __le64 bytes_used; - __le64 root_dir_objectid; - __le64 num_devices; - __le32 sectorsize; - __le32 nodesize; - /* Unused and must be equal to nodesize */ - __le32 __unused_leafsize; - __le32 stripesize; - __le32 sys_chunk_array_size; - __le64 chunk_root_generation; - __le64 compat_flags; - __le64 compat_ro_flags; - __le64 incompat_flags; - __le16 csum_type; - u8 root_level; - u8 chunk_root_level; - u8 log_root_level; - struct btrfs_dev_item dev_item; - - char label[BTRFS_LABEL_SIZE]; - - __le64 cache_generation; - __le64 uuid_tree_generation; - - u8 metadata_uuid[BTRFS_FSID_SIZE]; - - __le64 nr_global_roots; - - __le64 reserved[27]; - u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; - struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; - /* Padded to 4096 bytes */ - u8 padding[565]; -} __attribute__ ((__packed__)); -BUILD_ASSERT(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE); - -/* - * Compat flags that we support. If any incompat flags are set other than the - * ones specified below then we will fail to mount - */ -#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) -/* - * Older kernels on big-endian systems produced broken free space tree bitmaps, - * and btrfs-progs also used to corrupt the free space tree. If this bit is - * clear, then the free space tree cannot be trusted. btrfs-progs can also - * intentionally clear this bit to ask the kernel to rebuild the free space - * tree. - */ -#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) -#define BTRFS_FEATURE_COMPAT_RO_VERITY (1ULL << 2) - -/* - * Save all block group items into a dedicated block group tree, to greatly - * reduce mount time for large fs. - */ -#define BTRFS_FEATURE_COMPAT_RO_BLOCK_GROUP_TREE (1ULL << 3) - -#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) -#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) -#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) -#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) -#define BTRFS_FEATURE_INCOMPAT_COMPRESS_ZSTD (1ULL << 4) - -/* - * older kernels tried to do bigger metadata blocks, but the - * code was pretty buggy. Lets not let them try anymore. - */ -#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA (1ULL << 5) -#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) -#define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) -#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) -#define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) -#define BTRFS_FEATURE_INCOMPAT_METADATA_UUID (1ULL << 10) -#define BTRFS_FEATURE_INCOMPAT_RAID1C34 (1ULL << 11) -#define BTRFS_FEATURE_INCOMPAT_ZONED (1ULL << 12) -#define BTRFS_FEATURE_INCOMPAT_EXTENT_TREE_V2 (1ULL << 13) - -#define BTRFS_FEATURE_COMPAT_SUPP 0ULL - /* * The FREE_SPACE_TREE and FREE_SPACE_TREE_VALID compat_ro bits must not be * added here until read-write support for the free space tree is implemented in @@ -566,43 +118,6 @@ BUILD_ASSERT(sizeof(struct btrfs_super_block) == BTRFS_SUPER_INFO_SIZE); BTRFS_FEATURE_INCOMPAT_ZONED) #endif -/* - * A leaf is full of items. offset and size tell us where to find - * the item in the leaf (relative to the start of the data area) - */ -struct btrfs_item { - struct btrfs_disk_key key; - __le32 offset; - __le32 size; -} __attribute__ ((__packed__)); - -/* - * leaves have an item area and a data area: - * [item0, item1....itemN] [free space] [dataN...data1, data0] - * - * The data is separate from the items to get the keys closer together - * during searches. - */ -struct btrfs_leaf { - struct btrfs_header header; - struct btrfs_item items[]; -} __attribute__ ((__packed__)); - -/* - * all non-leaf blocks are nodes, they hold only keys and pointers to - * other blocks - */ -struct btrfs_key_ptr { - struct btrfs_disk_key key; - __le64 blockptr; - __le64 generation; -} __attribute__ ((__packed__)); - -struct btrfs_node { - struct btrfs_header header; - struct btrfs_key_ptr ptrs[]; -} __attribute__ ((__packed__)); - /* * btrfs_paths remember the path taken from the root down to the leaf. * level 0 is always the leaf, and nodes[1...BTRFS_MAX_LEVEL] will point @@ -631,98 +146,11 @@ struct btrfs_path { u8 skip_check_block; }; -/* - * items in the extent btree are used to record the objectid of the - * owner of the block and the number of references - */ - -struct btrfs_extent_item { - __le64 refs; - __le64 generation; - __le64 flags; -} __attribute__ ((__packed__)); - -struct btrfs_extent_item_v0 { - __le32 refs; -} __attribute__ ((__packed__)); - #define BTRFS_MAX_EXTENT_ITEM_SIZE(r) \ ((BTRFS_LEAF_DATA_SIZE(r->fs_info) >> 4) - \ sizeof(struct btrfs_item)) #define BTRFS_MAX_EXTENT_SIZE 128UL * 1024 * 1024 -#define BTRFS_EXTENT_FLAG_DATA (1ULL << 0) -#define BTRFS_EXTENT_FLAG_TREE_BLOCK (1ULL << 1) - -/* following flags only apply to tree blocks */ - -/* use full backrefs for extent pointers in the block*/ -#define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8) - -struct btrfs_tree_block_info { - struct btrfs_disk_key key; - u8 level; -} __attribute__ ((__packed__)); - -struct btrfs_extent_data_ref { - __le64 root; - __le64 objectid; - __le64 offset; - __le32 count; -} __attribute__ ((__packed__)); - -struct btrfs_shared_data_ref { - __le32 count; -} __attribute__ ((__packed__)); - -struct btrfs_extent_inline_ref { - u8 type; - __le64 offset; -} __attribute__ ((__packed__)); - -struct btrfs_extent_ref_v0 { - __le64 root; - __le64 generation; - __le64 objectid; - __le32 count; -} __attribute__ ((__packed__)); - -/* dev extents record free space on individual devices. The owner - * field points back to the chunk allocation mapping tree that allocated - * the extent. The chunk tree uuid field is a way to double check the owner - */ -struct btrfs_dev_extent { - __le64 chunk_tree; - __le64 chunk_objectid; - __le64 chunk_offset; - __le64 length; - u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; -} __attribute__ ((__packed__)); - -struct btrfs_inode_ref { - __le64 index; - __le16 name_len; - /* name goes here */ -} __attribute__ ((__packed__)); - -struct btrfs_inode_extref { - __le64 parent_objectid; - __le64 index; - __le16 name_len; - __u8 name[0]; /* name goes here */ -} __attribute__ ((__packed__)); - -struct btrfs_timespec { - __le64 sec; - __le32 nsec; -} __attribute__ ((__packed__)); - -/* we don't understand any encryption methods right now */ -typedef enum { - BTRFS_ENCRYPTION_NONE = 0, - BTRFS_ENCRYPTION_LAST = 1, -} btrfs_encryption_type; - enum btrfs_tree_block_status { BTRFS_TREE_BLOCK_CLEAN, BTRFS_TREE_BLOCK_INVALID_NRITEMS, @@ -734,269 +162,6 @@ enum btrfs_tree_block_status { BTRFS_TREE_BLOCK_INVALID_BLOCKPTR, }; -struct btrfs_inode_item { - /* nfs style generation number */ - __le64 generation; - /* transid that last touched this inode */ - __le64 transid; - __le64 size; - __le64 nbytes; - __le64 block_group; - __le32 nlink; - __le32 uid; - __le32 gid; - __le32 mode; - __le64 rdev; - __le64 flags; - - /* modification sequence number for NFS */ - __le64 sequence; - - /* - * a little future expansion, for more than this we can - * just grow the inode item and version it - */ - __le64 reserved[4]; - struct btrfs_timespec atime; - struct btrfs_timespec ctime; - struct btrfs_timespec mtime; - struct btrfs_timespec otime; -} __attribute__ ((__packed__)); - -struct btrfs_dir_log_item { - __le64 end; -} __attribute__ ((__packed__)); - -struct btrfs_dir_item { - struct btrfs_disk_key location; - __le64 transid; - __le16 data_len; - __le16 name_len; - u8 type; -} __attribute__ ((__packed__)); - -struct btrfs_root_item_v0 { - struct btrfs_inode_item inode; - __le64 generation; - __le64 root_dirid; - __le64 bytenr; - __le64 byte_limit; - __le64 bytes_used; - __le64 last_snapshot; - __le64 flags; - __le32 refs; - struct btrfs_disk_key drop_progress; - u8 drop_level; - u8 level; -} __attribute__ ((__packed__)); - -struct btrfs_root_item { - struct btrfs_inode_item inode; - __le64 generation; - __le64 root_dirid; - __le64 bytenr; - __le64 byte_limit; - __le64 bytes_used; - __le64 last_snapshot; - __le64 flags; - __le32 refs; - struct btrfs_disk_key drop_progress; - u8 drop_level; - u8 level; - - /* - * The following fields appear after subvol_uuids+subvol_times - * were introduced. - */ - - /* - * This generation number is used to test if the new fields are valid - * and up to date while reading the root item. Every time the root item - * is written out, the "generation" field is copied into this field. If - * anyone ever mounted the fs with an older kernel, we will have - * mismatching generation values here and thus must invalidate the - * new fields. See btrfs_update_root and btrfs_find_last_root for - * details. - * the offset of generation_v2 is also used as the start for the memset - * when invalidating the fields. - */ - __le64 generation_v2; - u8 uuid[BTRFS_UUID_SIZE]; - u8 parent_uuid[BTRFS_UUID_SIZE]; - u8 received_uuid[BTRFS_UUID_SIZE]; - __le64 ctransid; /* updated when an inode changes */ - __le64 otransid; /* trans when created */ - __le64 stransid; /* trans when sent. non-zero for received subvol */ - __le64 rtransid; /* trans when received. non-zero for received subvol */ - struct btrfs_timespec ctime; - struct btrfs_timespec otime; - struct btrfs_timespec stime; - struct btrfs_timespec rtime; - - /* - * If we want to use a specific set of fst/checksum/extent roots for - * this root. - */ - __le64 global_tree_id; - __le64 reserved[7]; /* for future */ -} __attribute__ ((__packed__)); - -/* - * this is used for both forward and backward root refs - */ -struct btrfs_root_ref { - __le64 dirid; - __le64 sequence; - __le16 name_len; -} __attribute__ ((__packed__)); - -struct btrfs_disk_balance_args { - /* - * profiles to operate on, single is denoted by - * BTRFS_AVAIL_ALLOC_BIT_SINGLE - */ - __le64 profiles; - - /* - * usage filter - * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N' - * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max - */ - union { - __le64 usage; - struct { - __le32 usage_min; - __le32 usage_max; - }; - }; - - /* devid filter */ - __le64 devid; - - /* devid subset filter [pstart..pend) */ - __le64 pstart; - __le64 pend; - - /* btrfs virtual address space subset filter [vstart..vend) */ - __le64 vstart; - __le64 vend; - - /* - * profile to convert to, single is denoted by - * BTRFS_AVAIL_ALLOC_BIT_SINGLE - */ - __le64 target; - - /* BTRFS_BALANCE_ARGS_* */ - __le64 flags; - - /* - * BTRFS_BALANCE_ARGS_LIMIT with value 'limit' - * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum - * and maximum - */ - union { - __le64 limit; - struct { - __le32 limit_min; - __le32 limit_max; - }; - }; - - /* - * Process chunks that cross stripes_min..stripes_max devices, - * BTRFS_BALANCE_ARGS_STRIPES_RANGE - */ - __le32 stripes_min; - __le32 stripes_max; - - __le64 unused[6]; -} __attribute__ ((__packed__)); - -/* - * store balance parameters to disk so that balance can be properly - * resumed after crash or unmount - */ -struct btrfs_balance_item { - /* BTRFS_BALANCE_* */ - __le64 flags; - - struct btrfs_disk_balance_args data; - struct btrfs_disk_balance_args meta; - struct btrfs_disk_balance_args sys; - - __le64 unused[4]; -} __attribute__ ((__packed__)); - -#define BTRFS_FILE_EXTENT_INLINE 0 -#define BTRFS_FILE_EXTENT_REG 1 -#define BTRFS_FILE_EXTENT_PREALLOC 2 - -struct btrfs_file_extent_item { - /* - * transaction id that created this extent - */ - __le64 generation; - /* - * max number of bytes to hold this extent in ram - * when we split a compressed extent we can't know how big - * each of the resulting pieces will be. So, this is - * an upper limit on the size of the extent in ram instead of - * an exact limit. - */ - __le64 ram_bytes; - - /* - * 32 bits for the various ways we might encode the data, - * including compression and encryption. If any of these - * are set to something a given disk format doesn't understand - * it is treated like an incompat flag for reading and writing, - * but not for stat. - */ - u8 compression; - u8 encryption; - __le16 other_encoding; /* spare for later use */ - - /* are we inline data or a real extent? */ - u8 type; - - /* - * Disk space consumed by the data extent - * Data checksum is stored in csum tree, thus no bytenr/length takes - * csum into consideration. - * - * The inline extent data starts at this offset in the structure. - */ - __le64 disk_bytenr; - __le64 disk_num_bytes; - /* - * The logical offset in file blocks. - * this extent record is for. This allows a file extent to point - * into the middle of an existing extent on disk, sharing it - * between two snapshots (useful if some bytes in the middle of the - * extent have changed - */ - __le64 offset; - /* - * The logical number of file blocks. This always reflects the size - * uncompressed and without encoding. - */ - __le64 num_bytes; - -} __attribute__ ((__packed__)); - -struct btrfs_dev_stats_item { - /* - * grow this item struct at the end for future enhancements and keep - * the existing values unchanged - */ - __le64 values[BTRFS_DEV_STAT_VALUES_MAX]; -} __attribute__ ((__packed__)); - -struct btrfs_csum_item { - u8 csum; -} __attribute__ ((__packed__)); - /* * We don't want to overwrite 1M at the beginning of device, even though * there is our 1st superblock at 64k. Some possible reasons: @@ -1005,20 +170,6 @@ struct btrfs_csum_item { */ #define BTRFS_BLOCK_RESERVED_1M_FOR_SUPER ((u64)1 * 1024 * 1024) -#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) -#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) -#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2) -#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3) -#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) -#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) -#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) -#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) -#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) -#define BTRFS_BLOCK_GROUP_RAID1C3 (1ULL << 9) -#define BTRFS_BLOCK_GROUP_RAID1C4 (1ULL << 10) -#define BTRFS_BLOCK_GROUP_RESERVED (BTRFS_AVAIL_ALLOC_BIT_SINGLE | \ - BTRFS_SPACE_INFO_GLOBAL_RSV) - enum btrfs_raid_types { BTRFS_RAID_RAID10, BTRFS_RAID_RAID1, @@ -1032,32 +183,6 @@ enum btrfs_raid_types { BTRFS_NR_RAID_TYPES }; -#define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ - BTRFS_BLOCK_GROUP_SYSTEM | \ - BTRFS_BLOCK_GROUP_METADATA) - -#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ - BTRFS_BLOCK_GROUP_RAID1 | \ - BTRFS_BLOCK_GROUP_RAID5 | \ - BTRFS_BLOCK_GROUP_RAID6 | \ - BTRFS_BLOCK_GROUP_RAID1C3 | \ - BTRFS_BLOCK_GROUP_RAID1C4 | \ - BTRFS_BLOCK_GROUP_DUP | \ - BTRFS_BLOCK_GROUP_RAID10) - -#define BTRFS_BLOCK_GROUP_RAID56_MASK (BTRFS_BLOCK_GROUP_RAID5 | \ - BTRFS_BLOCK_GROUP_RAID6) - -#define BTRFS_BLOCK_GROUP_RAID1_MASK (BTRFS_BLOCK_GROUP_RAID1 | \ - BTRFS_BLOCK_GROUP_RAID1C3 | \ - BTRFS_BLOCK_GROUP_RAID1C4) - -/* used in struct btrfs_balance_args fields */ -#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) - -#define BTRFS_EXTENDED_PROFILE_MASK (BTRFS_BLOCK_GROUP_PROFILE_MASK | \ - BTRFS_AVAIL_ALLOC_BIT_SINGLE) - /* * GLOBAL_RSV does not exist as a on-disk block group type and is used * internally for exporting info about global block reserve from space infos @@ -1066,65 +191,11 @@ enum btrfs_raid_types { #define BTRFS_QGROUP_LEVEL_SHIFT 48 -static inline __u16 btrfs_qgroup_level(u64 qgroupid) -{ - return qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT; -} - static inline u64 btrfs_qgroup_subvolid(u64 qgroupid) { return qgroupid & ((1ULL << BTRFS_QGROUP_LEVEL_SHIFT) - 1); } -#define BTRFS_QGROUP_STATUS_FLAG_ON (1ULL << 0) -#define BTRFS_QGROUP_STATUS_FLAG_RESCAN (1ULL << 1) -#define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT (1ULL << 2) - -struct btrfs_qgroup_status_item { - __le64 version; - __le64 generation; - __le64 flags; - __le64 rescan; /* progress during scanning */ -} __attribute__ ((__packed__)); - -#define BTRFS_QGROUP_STATUS_VERSION 1 -struct btrfs_block_group_item { - __le64 used; - __le64 chunk_objectid; - __le64 flags; -} __attribute__ ((__packed__)); - -struct btrfs_free_space_info { - __le32 extent_count; - __le32 flags; -} __attribute__ ((__packed__)); - -#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0) - -struct btrfs_qgroup_info_item { - __le64 generation; - __le64 rfer; - __le64 rfer_cmpr; - __le64 excl; - __le64 excl_cmpr; -} __attribute__ ((__packed__)); - -/* flags definition for qgroup limits */ -#define BTRFS_QGROUP_LIMIT_MAX_RFER (1ULL << 0) -#define BTRFS_QGROUP_LIMIT_MAX_EXCL (1ULL << 1) -#define BTRFS_QGROUP_LIMIT_RSV_RFER (1ULL << 2) -#define BTRFS_QGROUP_LIMIT_RSV_EXCL (1ULL << 3) -#define BTRFS_QGROUP_LIMIT_RFER_CMPR (1ULL << 4) -#define BTRFS_QGROUP_LIMIT_EXCL_CMPR (1ULL << 5) - -struct btrfs_qgroup_limit_item { - __le64 flags; - __le64 max_rfer; - __le64 max_excl; - __le64 rsv_rfer; - __le64 rsv_excl; -} __attribute__ ((__packed__)); - struct btrfs_space_info { u64 flags; u64 total_bytes; @@ -1564,21 +635,6 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info) * data in the FS */ #define BTRFS_STRING_ITEM_KEY 253 -/* - * Inode flags - */ -#define BTRFS_INODE_NODATASUM (1 << 0) -#define BTRFS_INODE_NODATACOW (1 << 1) -#define BTRFS_INODE_READONLY (1 << 2) -#define BTRFS_INODE_NOCOMPRESS (1 << 3) -#define BTRFS_INODE_PREALLOC (1 << 4) -#define BTRFS_INODE_SYNC (1 << 5) -#define BTRFS_INODE_IMMUTABLE (1 << 6) -#define BTRFS_INODE_APPEND (1 << 7) -#define BTRFS_INODE_NODUMP (1 << 8) -#define BTRFS_INODE_NOATIME (1 << 9) -#define BTRFS_INODE_DIRSYNC (1 << 10) -#define BTRFS_INODE_COMPRESS (1 << 11) #define read_eb_member(eb, ptr, type, member, result) ( \ read_extent_buffer(eb, (char *)(result), \ @@ -1948,12 +1004,6 @@ static inline u32 btrfs_extent_inline_ref_size(int type) return 0; } -BTRFS_SETGET_FUNCS(ref_root_v0, struct btrfs_extent_ref_v0, root, 64); -BTRFS_SETGET_FUNCS(ref_generation_v0, struct btrfs_extent_ref_v0, - generation, 64); -BTRFS_SETGET_FUNCS(ref_objectid_v0, struct btrfs_extent_ref_v0, objectid, 64); -BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32); - /* struct btrfs_node */ BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); diff --git a/kernel-shared/uapi/btrfs_tree.h b/kernel-shared/uapi/btrfs_tree.h new file mode 100644 index 00000000..42744d2b --- /dev/null +++ b/kernel-shared/uapi/btrfs_tree.h @@ -0,0 +1,1259 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _BTRFS_CTREE_H_ +#define _BTRFS_CTREE_H_ + +#include "btrfs.h" +#include +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/* ASCII for _BHRfS_M, no terminating nul */ +#define BTRFS_MAGIC 0x4D5F53665248425FULL + +#define BTRFS_MAX_LEVEL 8 + +/* + * We can actually store much bigger names, but lets not confuse the rest of + * linux. + */ +#define BTRFS_NAME_LEN 255 + +/* + * Theoretical limit is larger, but we keep this down to a sane value. That + * should limit greatly the possibility of collisions on inode ref items. + */ +#define BTRFS_LINK_MAX 65535U + +/* + * This header contains the structure definitions and constants used + * by file system objects that can be retrieved using + * the BTRFS_IOC_SEARCH_TREE ioctl. That means basically anything that + * is needed to describe a leaf node's key or item contents. + */ + +/* holds pointers to all of the tree roots */ +#define BTRFS_ROOT_TREE_OBJECTID 1ULL + +/* stores information about which extents are in use, and reference counts */ +#define BTRFS_EXTENT_TREE_OBJECTID 2ULL + +/* + * chunk tree stores translations from logical -> physical block numbering + * the super block points to the chunk tree + */ +#define BTRFS_CHUNK_TREE_OBJECTID 3ULL + +/* + * stores information about which areas of a given device are in use. + * one per device. The tree of tree roots points to the device tree + */ +#define BTRFS_DEV_TREE_OBJECTID 4ULL + +/* one per subvolume, storing files and directories */ +#define BTRFS_FS_TREE_OBJECTID 5ULL + +/* directory objectid inside the root tree */ +#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL + +/* holds checksums of all the data extents */ +#define BTRFS_CSUM_TREE_OBJECTID 7ULL + +/* holds quota configuration and tracking */ +#define BTRFS_QUOTA_TREE_OBJECTID 8ULL + +/* for storing items that use the BTRFS_UUID_KEY* types */ +#define BTRFS_UUID_TREE_OBJECTID 9ULL + +/* tracks free space in block groups. */ +#define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL + +/* Holds the block group items for extent tree v2. */ +#define BTRFS_BLOCK_GROUP_TREE_OBJECTID 11ULL + +/* device stats in the device tree */ +#define BTRFS_DEV_STATS_OBJECTID 0ULL + +/* for storing balance parameters in the root tree */ +#define BTRFS_BALANCE_OBJECTID -4ULL + +/* orphan objectid for tracking unlinked/truncated files */ +#define BTRFS_ORPHAN_OBJECTID -5ULL + +/* does write ahead logging to speed up fsyncs */ +#define BTRFS_TREE_LOG_OBJECTID -6ULL +#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL + +/* for space balancing */ +#define BTRFS_TREE_RELOC_OBJECTID -8ULL +#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL + +/* + * extent checksums all have this objectid + * this allows them to share the logging tree + * for fsyncs + */ +#define BTRFS_EXTENT_CSUM_OBJECTID -10ULL + +/* For storing free space cache */ +#define BTRFS_FREE_SPACE_OBJECTID -11ULL + +/* + * The inode number assigned to the special inode for storing + * free ino cache + */ +#define BTRFS_FREE_INO_OBJECTID -12ULL + +/* dummy objectid represents multiple objectids */ +#define BTRFS_MULTIPLE_OBJECTIDS -255ULL + +/* + * All files have objectids in this range. + */ +#define BTRFS_FIRST_FREE_OBJECTID 256ULL +#define BTRFS_LAST_FREE_OBJECTID -256ULL +#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL + + +/* + * the device items go into the chunk tree. The key is in the form + * [ 1 BTRFS_DEV_ITEM_KEY device_id ] + */ +#define BTRFS_DEV_ITEMS_OBJECTID 1ULL + +#define BTRFS_BTREE_INODE_OBJECTID 1 + +#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2 + +#define BTRFS_DEV_REPLACE_DEVID 0ULL + +/* + * inode items have the data typically returned from stat and store other + * info about object characteristics. There is one for every file and dir in + * the FS + */ +#define BTRFS_INODE_ITEM_KEY 1 +#define BTRFS_INODE_REF_KEY 12 +#define BTRFS_INODE_EXTREF_KEY 13 +#define BTRFS_XATTR_ITEM_KEY 24 + +/* + * fs verity items are stored under two different key types on disk. + * The descriptor items: + * [ inode objectid, BTRFS_VERITY_DESC_ITEM_KEY, offset ] + * + * At offset 0, we store a btrfs_verity_descriptor_item which tracks the size + * of the descriptor item and some extra data for encryption. + * Starting at offset 1, these hold the generic fs verity descriptor. The + * latter are opaque to btrfs, we just read and write them as a blob for the + * higher level verity code. The most common descriptor size is 256 bytes. + * + * The merkle tree items: + * [ inode objectid, BTRFS_VERITY_MERKLE_ITEM_KEY, offset ] + * + * These also start at offset 0, and correspond to the merkle tree bytes. When + * fsverity asks for page 0 of the merkle tree, we pull up one page starting at + * offset 0 for this key type. These are also opaque to btrfs, we're blindly + * storing whatever fsverity sends down. + */ +#define BTRFS_VERITY_DESC_ITEM_KEY 36 +#define BTRFS_VERITY_MERKLE_ITEM_KEY 37 + +#define BTRFS_ORPHAN_ITEM_KEY 48 +/* reserve 2-15 close to the inode for later flexibility */ + +/* + * dir items are the name -> inode pointers in a directory. There is one + * for every name in a directory. BTRFS_DIR_LOG_ITEM_KEY is no longer used + * but it's still defined here for documentation purposes and to help avoid + * having its numerical value reused in the future. + */ +#define BTRFS_DIR_LOG_ITEM_KEY 60 +#define BTRFS_DIR_LOG_INDEX_KEY 72 +#define BTRFS_DIR_ITEM_KEY 84 +#define BTRFS_DIR_INDEX_KEY 96 +/* + * extent data is for file data + */ +#define BTRFS_EXTENT_DATA_KEY 108 + +/* + * extent csums are stored in a separate tree and hold csums for + * an entire extent on disk. + */ +#define BTRFS_EXTENT_CSUM_KEY 128 + +/* + * root items point to tree roots. They are typically in the root + * tree used by the super block to find all the other trees + */ +#define BTRFS_ROOT_ITEM_KEY 132 + +/* + * root backrefs tie subvols and snapshots to the directory entries that + * reference them + */ +#define BTRFS_ROOT_BACKREF_KEY 144 + +/* + * root refs make a fast index for listing all of the snapshots and + * subvolumes referenced by a given root. They point directly to the + * directory item in the root that references the subvol + */ +#define BTRFS_ROOT_REF_KEY 156 + +/* + * extent items are in the extent map tree. These record which blocks + * are used, and how many references there are to each block + */ +#define BTRFS_EXTENT_ITEM_KEY 168 + +/* + * The same as the BTRFS_EXTENT_ITEM_KEY, except it's metadata we already know + * the length, so we save the level in key->offset instead of the length. + */ +#define BTRFS_METADATA_ITEM_KEY 169 + +#define BTRFS_TREE_BLOCK_REF_KEY 176 + +#define BTRFS_EXTENT_DATA_REF_KEY 178 + +#define BTRFS_EXTENT_REF_V0_KEY 180 + +#define BTRFS_SHARED_BLOCK_REF_KEY 182 + +#define BTRFS_SHARED_DATA_REF_KEY 184 + +/* + * block groups give us hints into the extent allocation trees. Which + * blocks are free etc etc + */ +#define BTRFS_BLOCK_GROUP_ITEM_KEY 192 + +/* + * Every block group is represented in the free space tree by a free space info + * item, which stores some accounting information. It is keyed on + * (block_group_start, FREE_SPACE_INFO, block_group_length). + */ +#define BTRFS_FREE_SPACE_INFO_KEY 198 + +/* + * A free space extent tracks an extent of space that is free in a block group. + * It is keyed on (start, FREE_SPACE_EXTENT, length). + */ +#define BTRFS_FREE_SPACE_EXTENT_KEY 199 + +/* + * When a block group becomes very fragmented, we convert it to use bitmaps + * instead of extents. A free space bitmap is keyed on + * (start, FREE_SPACE_BITMAP, length); the corresponding item is a bitmap with + * (length / sectorsize) bits. + */ +#define BTRFS_FREE_SPACE_BITMAP_KEY 200 + +#define BTRFS_DEV_EXTENT_KEY 204 +#define BTRFS_DEV_ITEM_KEY 216 +#define BTRFS_CHUNK_ITEM_KEY 228 + +/* + * Records the overall state of the qgroups. + * There's only one instance of this key present, + * (0, BTRFS_QGROUP_STATUS_KEY, 0) + */ +#define BTRFS_QGROUP_STATUS_KEY 240 +/* + * Records the currently used space of the qgroup. + * One key per qgroup, (0, BTRFS_QGROUP_INFO_KEY, qgroupid). + */ +#define BTRFS_QGROUP_INFO_KEY 242 +/* + * Contains the user configured limits for the qgroup. + * One key per qgroup, (0, BTRFS_QGROUP_LIMIT_KEY, qgroupid). + */ +#define BTRFS_QGROUP_LIMIT_KEY 244 +/* + * Records the child-parent relationship of qgroups. For + * each relation, 2 keys are present: + * (childid, BTRFS_QGROUP_RELATION_KEY, parentid) + * (parentid, BTRFS_QGROUP_RELATION_KEY, childid) + */ +#define BTRFS_QGROUP_RELATION_KEY 246 + +/* + * Obsolete name, see BTRFS_TEMPORARY_ITEM_KEY. + */ +#define BTRFS_BALANCE_ITEM_KEY 248 + +/* + * The key type for tree items that are stored persistently, but do not need to + * exist for extended period of time. The items can exist in any tree. + * + * [subtype, BTRFS_TEMPORARY_ITEM_KEY, data] + * + * Existing items: + * + * - balance status item + * (BTRFS_BALANCE_OBJECTID, BTRFS_TEMPORARY_ITEM_KEY, 0) + */ +#define BTRFS_TEMPORARY_ITEM_KEY 248 + +/* + * Obsolete name, see BTRFS_PERSISTENT_ITEM_KEY + */ +#define BTRFS_DEV_STATS_KEY 249 + +/* + * The key type for tree items that are stored persistently and usually exist + * for a long period, eg. filesystem lifetime. The item kinds can be status + * information, stats or preference values. The item can exist in any tree. + * + * [subtype, BTRFS_PERSISTENT_ITEM_KEY, data] + * + * Existing items: + * + * - device statistics, store IO stats in the device tree, one key for all + * stats + * (BTRFS_DEV_STATS_OBJECTID, BTRFS_DEV_STATS_KEY, 0) + */ +#define BTRFS_PERSISTENT_ITEM_KEY 249 + +/* + * Persistently stores the device replace state in the device tree. + * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0). + */ +#define BTRFS_DEV_REPLACE_KEY 250 + +/* + * Stores items that allow to quickly map UUIDs to something else. + * These items are part of the filesystem UUID tree. + * The key is built like this: + * (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits). + */ +#if BTRFS_UUID_SIZE != 16 +#error "UUID items require BTRFS_UUID_SIZE == 16!" +#endif +#define BTRFS_UUID_KEY_SUBVOL 251 /* for UUIDs assigned to subvols */ +#define BTRFS_UUID_KEY_RECEIVED_SUBVOL 252 /* for UUIDs assigned to + * received subvols */ + +/* + * string items are for debugging. They just store a short string of + * data in the FS + */ +#define BTRFS_STRING_ITEM_KEY 253 + +/* Maximum metadata block size (nodesize) */ +#define BTRFS_MAX_METADATA_BLOCKSIZE 65536 + +/* 32 bytes in various csum fields */ +#define BTRFS_CSUM_SIZE 32 + +/* csum types */ +enum btrfs_csum_type { + BTRFS_CSUM_TYPE_CRC32 = 0, + BTRFS_CSUM_TYPE_XXHASH = 1, + BTRFS_CSUM_TYPE_SHA256 = 2, + BTRFS_CSUM_TYPE_BLAKE2 = 3, +}; + +/* + * flags definitions for directory entry item type + * + * Used by: + * struct btrfs_dir_item.type + * + * Values 0..7 must match common file type values in fs_types.h. + */ +#define BTRFS_FT_UNKNOWN 0 +#define BTRFS_FT_REG_FILE 1 +#define BTRFS_FT_DIR 2 +#define BTRFS_FT_CHRDEV 3 +#define BTRFS_FT_BLKDEV 4 +#define BTRFS_FT_FIFO 5 +#define BTRFS_FT_SOCK 6 +#define BTRFS_FT_SYMLINK 7 +#define BTRFS_FT_XATTR 8 +#define BTRFS_FT_MAX 9 +/* Directory contains encrypted data */ +#define BTRFS_FT_ENCRYPTED 0x80 + +static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags) +{ + return flags & ~BTRFS_FT_ENCRYPTED; +} + +/* + * Inode flags + */ +#define BTRFS_INODE_NODATASUM (1U << 0) +#define BTRFS_INODE_NODATACOW (1U << 1) +#define BTRFS_INODE_READONLY (1U << 2) +#define BTRFS_INODE_NOCOMPRESS (1U << 3) +#define BTRFS_INODE_PREALLOC (1U << 4) +#define BTRFS_INODE_SYNC (1U << 5) +#define BTRFS_INODE_IMMUTABLE (1U << 6) +#define BTRFS_INODE_APPEND (1U << 7) +#define BTRFS_INODE_NODUMP (1U << 8) +#define BTRFS_INODE_NOATIME (1U << 9) +#define BTRFS_INODE_DIRSYNC (1U << 10) +#define BTRFS_INODE_COMPRESS (1U << 11) + +#define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31) + +#define BTRFS_INODE_FLAG_MASK \ + (BTRFS_INODE_NODATASUM | \ + BTRFS_INODE_NODATACOW | \ + BTRFS_INODE_READONLY | \ + BTRFS_INODE_NOCOMPRESS | \ + BTRFS_INODE_PREALLOC | \ + BTRFS_INODE_SYNC | \ + BTRFS_INODE_IMMUTABLE | \ + BTRFS_INODE_APPEND | \ + BTRFS_INODE_NODUMP | \ + BTRFS_INODE_NOATIME | \ + BTRFS_INODE_DIRSYNC | \ + BTRFS_INODE_COMPRESS | \ + BTRFS_INODE_ROOT_ITEM_INIT) + +#define BTRFS_INODE_RO_VERITY (1U << 0) + +#define BTRFS_INODE_RO_FLAG_MASK (BTRFS_INODE_RO_VERITY) + +/* + * The key defines the order in the tree, and so it also defines (optimal) + * block layout. + * + * objectid corresponds to the inode number. + * + * type tells us things about the object, and is a kind of stream selector. + * so for a given inode, keys with type of 1 might refer to the inode data, + * type of 2 may point to file data in the btree and type == 3 may point to + * extents. + * + * offset is the starting byte offset for this key in the stream. + * + * btrfs_disk_key is in disk byte order. struct btrfs_key is always + * in cpu native order. Otherwise they are identical and their sizes + * should be the same (ie both packed) + */ +struct btrfs_disk_key { + __le64 objectid; + __u8 type; + __le64 offset; +} __attribute__ ((__packed__)); + +struct btrfs_key { + __u64 objectid; + __u8 type; + __u64 offset; +} __attribute__ ((__packed__)); + +/* + * Every tree block (leaf or node) starts with this header. + */ +struct btrfs_header { + /* These first four must match the super block */ + __u8 csum[BTRFS_CSUM_SIZE]; + /* FS specific uuid */ + __u8 fsid[BTRFS_FSID_SIZE]; + /* Which block this node is supposed to live in */ + __le64 bytenr; + __le64 flags; + + /* Allowed to be different from the super from here on down */ + __u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; + __le64 generation; + __le64 owner; + __le32 nritems; + __u8 level; +} __attribute__ ((__packed__)); + +/* + * This is a very generous portion of the super block, giving us room to + * translate 14 chunks with 3 stripes each. + */ +#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 + +/* + * Just in case we somehow lose the roots and are not able to mount, we store + * an array of the roots from previous transactions in the super. + */ +#define BTRFS_NUM_BACKUP_ROOTS 4 +struct btrfs_root_backup { + __le64 tree_root; + __le64 tree_root_gen; + + __le64 chunk_root; + __le64 chunk_root_gen; + + __le64 extent_root; + __le64 extent_root_gen; + + __le64 fs_root; + __le64 fs_root_gen; + + __le64 dev_root; + __le64 dev_root_gen; + + __le64 csum_root; + __le64 csum_root_gen; + + __le64 total_bytes; + __le64 bytes_used; + __le64 num_devices; + /* future */ + __le64 unused_64[4]; + + __u8 tree_root_level; + __u8 chunk_root_level; + __u8 extent_root_level; + __u8 fs_root_level; + __u8 dev_root_level; + __u8 csum_root_level; + /* future and to align */ + __u8 unused_8[10]; +} __attribute__ ((__packed__)); + +/* + * A leaf is full of items. offset and size tell us where to find the item in + * the leaf (relative to the start of the data area) + */ +struct btrfs_item { + struct btrfs_disk_key key; + __le32 offset; + __le32 size; +} __attribute__ ((__packed__)); + +/* + * Leaves have an item area and a data area: + * [item0, item1....itemN] [free space] [dataN...data1, data0] + * + * The data is separate from the items to get the keys closer together during + * searches. + */ +struct btrfs_leaf { + struct btrfs_header header; + struct btrfs_item items[]; +} __attribute__ ((__packed__)); + +/* + * All non-leaf blocks are nodes, they hold only keys and pointers to other + * blocks. + */ +struct btrfs_key_ptr { + struct btrfs_disk_key key; + __le64 blockptr; + __le64 generation; +} __attribute__ ((__packed__)); + +struct btrfs_node { + struct btrfs_header header; + struct btrfs_key_ptr ptrs[]; +} __attribute__ ((__packed__)); + +struct btrfs_dev_item { + /* the internal btrfs device id */ + __le64 devid; + + /* size of the device */ + __le64 total_bytes; + + /* bytes used */ + __le64 bytes_used; + + /* optimal io alignment for this device */ + __le32 io_align; + + /* optimal io width for this device */ + __le32 io_width; + + /* minimal io size for this device */ + __le32 sector_size; + + /* type and info about this device */ + __le64 type; + + /* expected generation for this device */ + __le64 generation; + + /* + * starting byte of this partition on the device, + * to allow for stripe alignment in the future + */ + __le64 start_offset; + + /* grouping information for allocation decisions */ + __le32 dev_group; + + /* seek speed 0-100 where 100 is fastest */ + __u8 seek_speed; + + /* bandwidth 0-100 where 100 is fastest */ + __u8 bandwidth; + + /* btrfs generated uuid for this device */ + __u8 uuid[BTRFS_UUID_SIZE]; + + /* uuid of FS who owns this device */ + __u8 fsid[BTRFS_UUID_SIZE]; +} __attribute__ ((__packed__)); + +struct btrfs_stripe { + __le64 devid; + __le64 offset; + __u8 dev_uuid[BTRFS_UUID_SIZE]; +} __attribute__ ((__packed__)); + +struct btrfs_chunk { + /* size of this chunk in bytes */ + __le64 length; + + /* objectid of the root referencing this chunk */ + __le64 owner; + + __le64 stripe_len; + __le64 type; + + /* optimal io alignment for this chunk */ + __le32 io_align; + + /* optimal io width for this chunk */ + __le32 io_width; + + /* minimal io size for this chunk */ + __le32 sector_size; + + /* 2^16 stripes is quite a lot, a second limit is the size of a single + * item in the btree + */ + __le16 num_stripes; + + /* sub stripes only matter for raid10 */ + __le16 sub_stripes; + struct btrfs_stripe stripe; + /* additional stripes go here */ +} __attribute__ ((__packed__)); + +/* + * The super block basically lists the main trees of the FS. + */ +struct btrfs_super_block { + /* The first 4 fields must match struct btrfs_header */ + __u8 csum[BTRFS_CSUM_SIZE]; + /* FS specific UUID, visible to user */ + __u8 fsid[BTRFS_FSID_SIZE]; + /* This block number */ + __le64 bytenr; + __le64 flags; + + /* Allowed to be different from the btrfs_header from here own down */ + __le64 magic; + __le64 generation; + __le64 root; + __le64 chunk_root; + __le64 log_root; + + /* + * This member has never been utilized since the very beginning, thus + * it's always 0 regardless of kernel version. We always use + * generation + 1 to read log tree root. So here we mark it deprecated. + */ + __le64 __unused_log_root_transid; + __le64 total_bytes; + __le64 bytes_used; + __le64 root_dir_objectid; + __le64 num_devices; + __le32 sectorsize; + __le32 nodesize; + __le32 __unused_leafsize; + __le32 stripesize; + __le32 sys_chunk_array_size; + __le64 chunk_root_generation; + __le64 compat_flags; + __le64 compat_ro_flags; + __le64 incompat_flags; + __le16 csum_type; + __u8 root_level; + __u8 chunk_root_level; + __u8 log_root_level; + struct btrfs_dev_item dev_item; + + char label[BTRFS_LABEL_SIZE]; + + __le64 cache_generation; + __le64 uuid_tree_generation; + + /* The UUID written into btree blocks */ + __u8 metadata_uuid[BTRFS_FSID_SIZE]; + + __u64 nr_global_roots; + + __le64 reserved[27]; + __u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; + struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; + + /* Padded to 4096 bytes */ + __u8 padding[565]; +} __attribute__ ((__packed__)); + +#define BTRFS_FREE_SPACE_EXTENT 1 +#define BTRFS_FREE_SPACE_BITMAP 2 + +struct btrfs_free_space_entry { + __le64 offset; + __le64 bytes; + __u8 type; +} __attribute__ ((__packed__)); + +struct btrfs_free_space_header { + struct btrfs_disk_key location; + __le64 generation; + __le64 num_entries; + __le64 num_bitmaps; +} __attribute__ ((__packed__)); + +#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) +#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) + +/* Super block flags */ +/* Errors detected */ +#define BTRFS_SUPER_FLAG_ERROR (1ULL << 2) + +#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) +#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) +#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) +#define BTRFS_SUPER_FLAG_CHANGING_FSID (1ULL << 35) +#define BTRFS_SUPER_FLAG_CHANGING_FSID_V2 (1ULL << 36) + + +/* + * items in the extent btree are used to record the objectid of the + * owner of the block and the number of references + */ + +struct btrfs_extent_item { + __le64 refs; + __le64 generation; + __le64 flags; +} __attribute__ ((__packed__)); + +struct btrfs_extent_item_v0 { + __le32 refs; +} __attribute__ ((__packed__)); + + +#define BTRFS_EXTENT_FLAG_DATA (1ULL << 0) +#define BTRFS_EXTENT_FLAG_TREE_BLOCK (1ULL << 1) + +/* following flags only apply to tree blocks */ + +/* use full backrefs for extent pointers in the block */ +#define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8) + +#define BTRFS_BACKREF_REV_MAX 256 +#define BTRFS_BACKREF_REV_SHIFT 56 +#define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \ + BTRFS_BACKREF_REV_SHIFT) + +#define BTRFS_OLD_BACKREF_REV 0 +#define BTRFS_MIXED_BACKREF_REV 1 + +/* + * this flag is only used internally by scrub and may be changed at any time + * it is only declared here to avoid collisions + */ +#define BTRFS_EXTENT_FLAG_SUPER (1ULL << 48) + +struct btrfs_tree_block_info { + struct btrfs_disk_key key; + __u8 level; +} __attribute__ ((__packed__)); + +struct btrfs_extent_data_ref { + __le64 root; + __le64 objectid; + __le64 offset; + __le32 count; +} __attribute__ ((__packed__)); + +struct btrfs_shared_data_ref { + __le32 count; +} __attribute__ ((__packed__)); + +struct btrfs_extent_inline_ref { + __u8 type; + __le64 offset; +} __attribute__ ((__packed__)); + +/* dev extents record free space on individual devices. The owner + * field points back to the chunk allocation mapping tree that allocated + * the extent. The chunk tree uuid field is a way to double check the owner + */ +struct btrfs_dev_extent { + __le64 chunk_tree; + __le64 chunk_objectid; + __le64 chunk_offset; + __le64 length; + __u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; +} __attribute__ ((__packed__)); + +struct btrfs_inode_ref { + __le64 index; + __le16 name_len; + /* name goes here */ +} __attribute__ ((__packed__)); + +struct btrfs_inode_extref { + __le64 parent_objectid; + __le64 index; + __le16 name_len; + __u8 name[]; + /* name goes here */ +} __attribute__ ((__packed__)); + +struct btrfs_timespec { + __le64 sec; + __le32 nsec; +} __attribute__ ((__packed__)); + +struct btrfs_inode_item { + /* nfs style generation number */ + __le64 generation; + /* transid that last touched this inode */ + __le64 transid; + __le64 size; + __le64 nbytes; + __le64 block_group; + __le32 nlink; + __le32 uid; + __le32 gid; + __le32 mode; + __le64 rdev; + __le64 flags; + + /* modification sequence number for NFS */ + __le64 sequence; + + /* + * a little future expansion, for more than this we can + * just grow the inode item and version it + */ + __le64 reserved[4]; + struct btrfs_timespec atime; + struct btrfs_timespec ctime; + struct btrfs_timespec mtime; + struct btrfs_timespec otime; +} __attribute__ ((__packed__)); + +struct btrfs_dir_log_item { + __le64 end; +} __attribute__ ((__packed__)); + +struct btrfs_dir_item { + struct btrfs_disk_key location; + __le64 transid; + __le16 data_len; + __le16 name_len; + __u8 type; +} __attribute__ ((__packed__)); + +#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) + +/* + * Internal in-memory flag that a subvolume has been marked for deletion but + * still visible as a directory + */ +#define BTRFS_ROOT_SUBVOL_DEAD (1ULL << 48) + +struct btrfs_root_item { + struct btrfs_inode_item inode; + __le64 generation; + __le64 root_dirid; + __le64 bytenr; + __le64 byte_limit; + __le64 bytes_used; + __le64 last_snapshot; + __le64 flags; + __le32 refs; + struct btrfs_disk_key drop_progress; + __u8 drop_level; + __u8 level; + + /* + * The following fields appear after subvol_uuids+subvol_times + * were introduced. + */ + + /* + * This generation number is used to test if the new fields are valid + * and up to date while reading the root item. Every time the root item + * is written out, the "generation" field is copied into this field. If + * anyone ever mounted the fs with an older kernel, we will have + * mismatching generation values here and thus must invalidate the + * new fields. See btrfs_update_root and btrfs_find_last_root for + * details. + * the offset of generation_v2 is also used as the start for the memset + * when invalidating the fields. + */ + __le64 generation_v2; + __u8 uuid[BTRFS_UUID_SIZE]; + __u8 parent_uuid[BTRFS_UUID_SIZE]; + __u8 received_uuid[BTRFS_UUID_SIZE]; + __le64 ctransid; /* updated when an inode changes */ + __le64 otransid; /* trans when created */ + __le64 stransid; /* trans when sent. non-zero for received subvol */ + __le64 rtransid; /* trans when received. non-zero for received subvol */ + struct btrfs_timespec ctime; + struct btrfs_timespec otime; + struct btrfs_timespec stime; + struct btrfs_timespec rtime; + __le64 reserved[8]; /* for future */ +} __attribute__ ((__packed__)); + +/* + * Btrfs root item used to be smaller than current size. The old format ends + * at where member generation_v2 is. + */ +static inline __u32 btrfs_legacy_root_item_size(void) +{ + return offsetof(struct btrfs_root_item, generation_v2); +} + +/* + * this is used for both forward and backward root refs + */ +struct btrfs_root_ref { + __le64 dirid; + __le64 sequence; + __le16 name_len; +} __attribute__ ((__packed__)); + +struct btrfs_disk_balance_args { + /* + * profiles to operate on, single is denoted by + * BTRFS_AVAIL_ALLOC_BIT_SINGLE + */ + __le64 profiles; + + /* + * usage filter + * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N' + * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max + */ + union { + __le64 usage; + struct { + __le32 usage_min; + __le32 usage_max; + }; + }; + + /* devid filter */ + __le64 devid; + + /* devid subset filter [pstart..pend) */ + __le64 pstart; + __le64 pend; + + /* btrfs virtual address space subset filter [vstart..vend) */ + __le64 vstart; + __le64 vend; + + /* + * profile to convert to, single is denoted by + * BTRFS_AVAIL_ALLOC_BIT_SINGLE + */ + __le64 target; + + /* BTRFS_BALANCE_ARGS_* */ + __le64 flags; + + /* + * BTRFS_BALANCE_ARGS_LIMIT with value 'limit' + * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum + * and maximum + */ + union { + __le64 limit; + struct { + __le32 limit_min; + __le32 limit_max; + }; + }; + + /* + * Process chunks that cross stripes_min..stripes_max devices, + * BTRFS_BALANCE_ARGS_STRIPES_RANGE + */ + __le32 stripes_min; + __le32 stripes_max; + + __le64 unused[6]; +} __attribute__ ((__packed__)); + +/* + * store balance parameters to disk so that balance can be properly + * resumed after crash or unmount + */ +struct btrfs_balance_item { + /* BTRFS_BALANCE_* */ + __le64 flags; + + struct btrfs_disk_balance_args data; + struct btrfs_disk_balance_args meta; + struct btrfs_disk_balance_args sys; + + __le64 unused[4]; +} __attribute__ ((__packed__)); + +enum { + BTRFS_FILE_EXTENT_INLINE = 0, + BTRFS_FILE_EXTENT_REG = 1, + BTRFS_FILE_EXTENT_PREALLOC = 2, + BTRFS_NR_FILE_EXTENT_TYPES = 3, +}; + +struct btrfs_file_extent_item { + /* + * transaction id that created this extent + */ + __le64 generation; + /* + * max number of bytes to hold this extent in ram + * when we split a compressed extent we can't know how big + * each of the resulting pieces will be. So, this is + * an upper limit on the size of the extent in ram instead of + * an exact limit. + */ + __le64 ram_bytes; + + /* + * 32 bits for the various ways we might encode the data, + * including compression and encryption. If any of these + * are set to something a given disk format doesn't understand + * it is treated like an incompat flag for reading and writing, + * but not for stat. + */ + __u8 compression; + __u8 encryption; + __le16 other_encoding; /* spare for later use */ + + /* are we inline data or a real extent? */ + __u8 type; + + /* + * disk space consumed by the extent, checksum blocks are included + * in these numbers + * + * At this offset in the structure, the inline extent data start. + */ + __le64 disk_bytenr; + __le64 disk_num_bytes; + /* + * the logical offset in file blocks (no csums) + * this extent record is for. This allows a file extent to point + * into the middle of an existing extent on disk, sharing it + * between two snapshots (useful if some bytes in the middle of the + * extent have changed + */ + __le64 offset; + /* + * the logical number of file blocks (no csums included). This + * always reflects the size uncompressed and without encoding. + */ + __le64 num_bytes; + +} __attribute__ ((__packed__)); + +struct btrfs_csum_item { + __u8 csum; +} __attribute__ ((__packed__)); + +struct btrfs_dev_stats_item { + /* + * grow this item struct at the end for future enhancements and keep + * the existing values unchanged + */ + __le64 values[BTRFS_DEV_STAT_VALUES_MAX]; +} __attribute__ ((__packed__)); + +#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 +#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 + +struct btrfs_dev_replace_item { + /* + * grow this item struct at the end for future enhancements and keep + * the existing values unchanged + */ + __le64 src_devid; + __le64 cursor_left; + __le64 cursor_right; + __le64 cont_reading_from_srcdev_mode; + + __le64 replace_state; + __le64 time_started; + __le64 time_stopped; + __le64 num_write_errors; + __le64 num_uncorrectable_read_errors; +} __attribute__ ((__packed__)); + +/* different types of block groups (and chunks) */ +#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) +#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) +#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2) +#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3) +#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) +#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) +#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) +#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) +#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) +#define BTRFS_BLOCK_GROUP_RAID1C3 (1ULL << 9) +#define BTRFS_BLOCK_GROUP_RAID1C4 (1ULL << 10) +#define BTRFS_BLOCK_GROUP_RESERVED (BTRFS_AVAIL_ALLOC_BIT_SINGLE | \ + BTRFS_SPACE_INFO_GLOBAL_RSV) + +#define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ + BTRFS_BLOCK_GROUP_SYSTEM | \ + BTRFS_BLOCK_GROUP_METADATA) + +#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ + BTRFS_BLOCK_GROUP_RAID1 | \ + BTRFS_BLOCK_GROUP_RAID1C3 | \ + BTRFS_BLOCK_GROUP_RAID1C4 | \ + BTRFS_BLOCK_GROUP_RAID5 | \ + BTRFS_BLOCK_GROUP_RAID6 | \ + BTRFS_BLOCK_GROUP_DUP | \ + BTRFS_BLOCK_GROUP_RAID10) +#define BTRFS_BLOCK_GROUP_RAID56_MASK (BTRFS_BLOCK_GROUP_RAID5 | \ + BTRFS_BLOCK_GROUP_RAID6) + +#define BTRFS_BLOCK_GROUP_RAID1_MASK (BTRFS_BLOCK_GROUP_RAID1 | \ + BTRFS_BLOCK_GROUP_RAID1C3 | \ + BTRFS_BLOCK_GROUP_RAID1C4) + +/* + * We need a bit for restriper to be able to tell when chunks of type + * SINGLE are available. This "extended" profile format is used in + * fs_info->avail_*_alloc_bits (in-memory) and balance item fields + * (on-disk). The corresponding on-disk bit in chunk.type is reserved + * to avoid remappings between two formats in future. + */ +#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) + +/* + * A fake block group type that is used to communicate global block reserve + * size to userspace via the SPACE_INFO ioctl. + */ +#define BTRFS_SPACE_INFO_GLOBAL_RSV (1ULL << 49) + +#define BTRFS_EXTENDED_PROFILE_MASK (BTRFS_BLOCK_GROUP_PROFILE_MASK | \ + BTRFS_AVAIL_ALLOC_BIT_SINGLE) + +static inline __u64 chunk_to_extended(__u64 flags) +{ + if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0) + flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE; + + return flags; +} +static inline __u64 extended_to_chunk(__u64 flags) +{ + return flags & ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; +} + +struct btrfs_block_group_item { + __le64 used; + __le64 chunk_objectid; + __le64 flags; +} __attribute__ ((__packed__)); + +struct btrfs_free_space_info { + __le32 extent_count; + __le32 flags; +} __attribute__ ((__packed__)); + +#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0) + +#define BTRFS_QGROUP_LEVEL_SHIFT 48 +static inline __u16 btrfs_qgroup_level(__u64 qgroupid) +{ + return (__u16)(qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT); +} + +/* + * is subvolume quota turned on? + */ +#define BTRFS_QGROUP_STATUS_FLAG_ON (1ULL << 0) +/* + * RESCAN is set during the initialization phase + */ +#define BTRFS_QGROUP_STATUS_FLAG_RESCAN (1ULL << 1) +/* + * Some qgroup entries are known to be out of date, + * either because the configuration has changed in a way that + * makes a rescan necessary, or because the fs has been mounted + * with a non-qgroup-aware version. + * Turning qouta off and on again makes it inconsistent, too. + */ +#define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT (1ULL << 2) + +#define BTRFS_QGROUP_STATUS_FLAGS_MASK (BTRFS_QGROUP_STATUS_FLAG_ON | \ + BTRFS_QGROUP_STATUS_FLAG_RESCAN | \ + BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) + +#define BTRFS_QGROUP_STATUS_VERSION 1 + +struct btrfs_qgroup_status_item { + __le64 version; + /* + * the generation is updated during every commit. As older + * versions of btrfs are not aware of qgroups, it will be + * possible to detect inconsistencies by checking the + * generation on mount time + */ + __le64 generation; + + /* flag definitions see above */ + __le64 flags; + + /* + * only used during scanning to record the progress + * of the scan. It contains a logical address + */ + __le64 rescan; +} __attribute__ ((__packed__)); + +struct btrfs_qgroup_info_item { + __le64 generation; + __le64 rfer; + __le64 rfer_cmpr; + __le64 excl; + __le64 excl_cmpr; +} __attribute__ ((__packed__)); + +struct btrfs_qgroup_limit_item { + /* + * only updated when any of the other values change + */ + __le64 flags; + __le64 max_rfer; + __le64 max_excl; + __le64 rsv_rfer; + __le64 rsv_excl; +} __attribute__ ((__packed__)); + +struct btrfs_verity_descriptor_item { + /* Size of the verity descriptor in bytes */ + __le64 size; + /* + * When we implement support for fscrypt, we will need to encrypt the + * Merkle tree for encrypted verity files. These 128 bits are for the + * eventual storage of an fscrypt initialization vector. + */ + __le64 reserved[2]; + __u8 encryption; +} __attribute__ ((__packed__)); + +#endif /* _BTRFS_CTREE_H_ */ From patchwork Wed Apr 19 21:17:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217385 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EF85FC77B78 for ; Wed, 19 Apr 2023 21:17:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230358AbjDSVRf (ORCPT ); Wed, 19 Apr 2023 17:17:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39834 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229960AbjDSVRc (ORCPT ); Wed, 19 Apr 2023 17:17:32 -0400 Received: from mail-qv1-xf29.google.com (mail-qv1-xf29.google.com [IPv6:2607:f8b0:4864:20::f29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 45E5344BE for ; Wed, 19 Apr 2023 14:17:29 -0700 (PDT) Received: by mail-qv1-xf29.google.com with SMTP id qf26so1033113qvb.6 for ; Wed, 19 Apr 2023 14:17:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939048; x=1684531048; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=9sbBrf8utOVP80ngJU4efviDe0xd8fiX32mWCaQHoVM=; b=uvb/vRv9iQA6Q3kxWKPaZ803cThKW0HCap9srSWOns/c+2TZeY6bjiXFAwqCvZ1e2f gcpFxjPnFTzQL2fvSCFHGdfrD7pzbNS4NaZcLvAjFo7HpZ1hJaLdu4oOMTdTTFJAToK6 F+bebQ88AhM70SE8EnD6b81h+ML0WrPGW69iYJuFwOqcsTtK4EH7GaAR0k9FS9h9CH/G IklEM4mOg6SzcDYS+JEpGFyKsjjMCT+Y/5TMzH77I2eUV1PxQVasthge/9O0R79pgf8x 4sbCDD74xcVhYQjyL3m4M5YwNhdNpLiCJWJmj55DC59G6Cr1j2wJS/n3tJN2WJUTgBf5 pcOA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939048; x=1684531048; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9sbBrf8utOVP80ngJU4efviDe0xd8fiX32mWCaQHoVM=; b=XGUcOUyn2H4/8JzJpNgaq3lWbExl/k28cVfGS+0xAgxHZEHtnuXdXt0hR/nJTMMCZe C+0Sh5hC6r9emrA2dmBeYAfp63j1zMd8/c5peswoTnV2GrdeUdkVnm9IxJn/xZsJi6YR XvpyuqFGCVl+zrVa70sraqcOp73EN4EQwfxOOFSwVQu8URZDL+BR1JX4P+qRQuYSVjzM S2F3oXaHlbdJ0droyD8Ic3Zem+jExIucsJz4QVwYbtfe73sUgBkVZpiIy0zg13j8wXjQ rKJ10CIBLisODbsrEQvXTJ8coXxgsuM9sPfH9p/T9Hn3j/nByF9xsZhQaViBOsLc7721 Ekjw== X-Gm-Message-State: AAQBX9c4WqiL6oDRXc8CZDjaPKhJxukRo1QiyHS/uZRND9ZjPcuJmSgD g9c8Sc3eU+EWCUIrRFD8LVEDhBSxyrpMU+9hO6j/5Q== X-Google-Smtp-Source: AKy350YgmUFggwrFs9ArvBA5Ec6fdZ0i2gQikZpsSf8Tt7mF8w5eZ+ynO85+TGvsvH3u7/cicEcyfg== X-Received: by 2002:a05:6214:20ed:b0:5c5:c835:c8f1 with SMTP id 13-20020a05621420ed00b005c5c835c8f1mr33234874qvk.22.1681939047878; Wed, 19 Apr 2023 14:17:27 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id z9-20020a0ce609000000b005dd8b9345c7sm4643543qvm.95.2023.04.19.14.17.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:27 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 3/8] btrfs-progs: sync messages.* from the kernel Date: Wed, 19 Apr 2023 17:17:14 -0400 Message-Id: <0a0542fd7abb9fed5f87148ac849cfb7e9577100.1681938911.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org These are the printk helpers from the kernel. There were a few modifications, the hi-lights are - We do not have fs_info::fs_state, so that needed to be removed. - We do not have discard.h sync'ed yet, so that dependency was dropped. - Anything related to struct super_block was commented out. - The transaction abort had to be modified to fit with the current btrfs-progs code. - Added a btrfs_no_printk() helper to common/messages.* so that the print statements still worked. Additionally there were kerncompat.h changes that needed to be made to handle the dependencies properly. Those are easier to spot. Any function that needed to be modified has a MODIFIED tag in the comment section with a list of things that were changed. Signed-off-by: Josef Bacik --- Makefile | 1 + common/messages.c | 11 ++ common/messages.h | 18 ++ include/kerncompat.h | 44 +++-- kernel-shared/backref.c | 1 + kernel-shared/ctree.h | 2 + kernel-shared/delayed-ref.c | 1 + kernel-shared/extent_io.c | 1 + kernel-shared/free-space-tree.c | 1 + kernel-shared/messages.c | 336 ++++++++++++++++++++++++++++++++ kernel-shared/messages.h | 216 ++++++++++++++++++++ kernel-shared/ulist.c | 1 + kernel-shared/zoned.h | 1 + libbtrfs/kerncompat.h | 20 -- 14 files changed, 614 insertions(+), 40 deletions(-) create mode 100644 kernel-shared/messages.c create mode 100644 kernel-shared/messages.h diff --git a/Makefile b/Makefile index 4b0a869b..45e2e1e6 100644 --- a/Makefile +++ b/Makefile @@ -179,6 +179,7 @@ objects = \ kernel-shared/free-space-tree.o \ kernel-shared/inode-item.o \ kernel-shared/inode.o \ + kernel-shared/messages.o \ kernel-shared/print-tree.o \ kernel-shared/root-tree.o \ kernel-shared/transaction.o \ diff --git a/common/messages.c b/common/messages.c index d6dc219b..8bcfcc6a 100644 --- a/common/messages.c +++ b/common/messages.c @@ -35,6 +35,17 @@ void __btrfs_printf(const char *fmt, ...) va_end(args); } +__attribute__ ((format (printf, 2, 3))) +void btrfs_no_printk(const void *fs_info, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fputc('\n', stderr); +} + static bool should_print(int level) { if (bconf.verbose == BTRFS_BCONF_QUIET || level == BTRFS_BCONF_QUIET) diff --git a/common/messages.h b/common/messages.h index 4bb9866e..d21f6250 100644 --- a/common/messages.h +++ b/common/messages.h @@ -111,6 +111,9 @@ __attribute__ ((format (printf, 1, 2))) void __btrfs_printf(const char *fmt, ...); +__attribute__ ((format (printf, 2, 3))) +void btrfs_no_printk(const void *fs_info, const char *fmt, ...); + /* * Level of messages that must be printed by default (in case the verbosity * options haven't been set by the user) due to backward compatibility reasons @@ -154,6 +157,21 @@ __attribute__ ((format (printf, 2, 3))) void error_msg(enum common_error error, const char *msg, ...); #ifndef BTRFS_DISABLE_BACKTRACE +static inline void assert_trace(const char *assertion, const char *filename, + const char *func, unsigned line, long val) +{ + if (val) + return; + fprintf(stderr, + "%s:%d: %s: Assertion `%s` failed, value %ld\n", + filename, line, func, assertion, val); +#ifndef BTRFS_DISABLE_BACKTRACE + print_trace(); +#endif + abort(); + exit(1); +} + #define UASSERT(c) assert_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) #else #define UASSERT(c) assert(c) diff --git a/include/kerncompat.h b/include/kerncompat.h index edb00276..d7eba985 100644 --- a/include/kerncompat.h +++ b/include/kerncompat.h @@ -36,6 +36,8 @@ #include #include #include +#include + #include /* @@ -320,6 +322,12 @@ static inline int IS_ERR_OR_NULL(const void *ptr) #define printk(fmt, args...) fprintf(stderr, fmt, ##args) #define KERN_CRIT "" #define KERN_ERR "" +#define KERN_EMERG "" +#define KERN_ALERT "" +#define KERN_CRIT "" +#define KERN_NOTICE "" +#define KERN_INFO "" +#define KERN_WARNING "" /* * kmalloc/kfree @@ -335,26 +343,6 @@ static inline int IS_ERR_OR_NULL(const void *ptr) #define memalloc_nofs_save() (0) #define memalloc_nofs_restore(x) ((void)(x)) -#ifndef BTRFS_DISABLE_BACKTRACE -static inline void assert_trace(const char *assertion, const char *filename, - const char *func, unsigned line, long val) -{ - if (val) - return; - fprintf(stderr, - "%s:%d: %s: Assertion `%s` failed, value %ld\n", - filename, line, func, assertion, val); -#ifndef BTRFS_DISABLE_BACKTRACE - print_trace(); -#endif - abort(); - exit(1); -} -#define ASSERT(c) assert_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) -#else -#define ASSERT(c) assert(c) -#endif - #define BUG_ON(c) bugon_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) #define BUG() \ do { \ @@ -574,8 +562,24 @@ struct work_struct { typedef struct wait_queue_head_s { } wait_queue_head_t; +struct super_block { + char *s_id; +}; + +struct va_format { + const char *fmt; + va_list *va; +}; + #define __init #define __cold #define __user +#define __printf(a, b) __attribute__((__format__(printf, a, b))) + +static inline bool sb_rdonly(struct super_block *sb) +{ + return false; +} + #endif diff --git a/kernel-shared/backref.c b/kernel-shared/backref.c index 9c5a3895..897cd089 100644 --- a/kernel-shared/backref.c +++ b/kernel-shared/backref.c @@ -23,6 +23,7 @@ #include "kernel-shared/ulist.h" #include "kernel-shared/transaction.h" #include "common/internal.h" +#include "messages.h" #define pr_debug(...) do { } while (0) diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index a5bcc9bc..1ac6ee3f 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -377,6 +377,8 @@ struct btrfs_fs_info { u64 zone_size; u64 zoned; }; + + struct super_block *sb; }; static inline bool btrfs_is_zoned(const struct btrfs_fs_info *fs_info) diff --git a/kernel-shared/delayed-ref.c b/kernel-shared/delayed-ref.c index 5b041ac6..f148b5f2 100644 --- a/kernel-shared/delayed-ref.c +++ b/kernel-shared/delayed-ref.c @@ -20,6 +20,7 @@ #include "kernel-shared/ctree.h" #include "kernel-shared/delayed-ref.h" #include "kernel-shared/transaction.h" +#include "messages.h" /* * delayed back reference update tracking. For subvolume trees diff --git a/kernel-shared/extent_io.c b/kernel-shared/extent_io.c index 016aa698..ab80700a 100644 --- a/kernel-shared/extent_io.c +++ b/kernel-shared/extent_io.c @@ -34,6 +34,7 @@ #include "common/utils.h" #include "common/device-utils.h" #include "common/internal.h" +#include "messages.h" static void free_extent_buffer_final(struct extent_buffer *eb); diff --git a/kernel-shared/free-space-tree.c b/kernel-shared/free-space-tree.c index 656de3fa..4064b7cb 100644 --- a/kernel-shared/free-space-tree.c +++ b/kernel-shared/free-space-tree.c @@ -24,6 +24,7 @@ #include "kernel-shared/transaction.h" #include "kernel-lib/bitops.h" #include "common/internal.h" +#include "messages.h" static struct btrfs_root *btrfs_free_space_root(struct btrfs_fs_info *fs_info, struct btrfs_block_group *block_group) diff --git a/kernel-shared/messages.c b/kernel-shared/messages.c new file mode 100644 index 00000000..ce022619 --- /dev/null +++ b/kernel-shared/messages.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "kerncompat.h" +#include "kernel-lib/bitops.h" +#include "ctree.h" +#include "messages.h" +#include "transaction.h" + +#ifdef CONFIG_PRINTK + +#define STATE_STRING_PREFACE ": state " +#define STATE_STRING_BUF_LEN (sizeof(STATE_STRING_PREFACE) + BTRFS_FS_STATE_COUNT) + +/* + * Characters to print to indicate error conditions or uncommon filesystem state. + * RO is not an error. + */ +static const char fs_state_chars[] = { + [BTRFS_FS_STATE_ERROR] = 'E', + [BTRFS_FS_STATE_REMOUNTING] = 'M', + [BTRFS_FS_STATE_RO] = 0, + [BTRFS_FS_STATE_TRANS_ABORTED] = 'A', + [BTRFS_FS_STATE_DEV_REPLACING] = 'R', + [BTRFS_FS_STATE_DUMMY_FS_INFO] = 0, + [BTRFS_FS_STATE_NO_CSUMS] = 'C', + [BTRFS_FS_STATE_LOG_CLEANUP_ERROR] = 'L', +}; + +static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf) +{ + unsigned int bit; + bool states_printed = false; + unsigned long fs_state = READ_ONCE(info->fs_state); + char *curr = buf; + + memcpy(curr, STATE_STRING_PREFACE, sizeof(STATE_STRING_PREFACE)); + curr += sizeof(STATE_STRING_PREFACE) - 1; + + for_each_set_bit(bit, &fs_state, sizeof(fs_state)) { + WARN_ON_ONCE(bit >= BTRFS_FS_STATE_COUNT); + if ((bit < BTRFS_FS_STATE_COUNT) && fs_state_chars[bit]) { + *curr++ = fs_state_chars[bit]; + states_printed = true; + } + } + + /* If no states were printed, reset the buffer */ + if (!states_printed) + curr = buf; + + *curr++ = 0; +} +#endif + +/* + * Generally the error codes correspond to their respective errors, but there + * are a few special cases. + * + * EUCLEAN: Any sort of corruption that we encounter. The tree-checker for + * instance will return EUCLEAN if any of the blocks are corrupted in + * a way that is problematic. We want to reserve EUCLEAN for these + * sort of corruptions. + * + * EROFS: If we check BTRFS_FS_STATE_ERROR and fail out with a return error, we + * need to use EROFS for this case. We will have no idea of the + * original failure, that will have been reported at the time we tripped + * over the error. Each subsequent error that doesn't have any context + * of the original error should use EROFS when handling BTRFS_FS_STATE_ERROR. + */ +const char * __attribute_const__ btrfs_decode_error(int error) +{ + char *errstr = "unknown"; + + switch (error) { + case -ENOENT: /* -2 */ + errstr = "No such entry"; + break; + case -EIO: /* -5 */ + errstr = "IO failure"; + break; + case -ENOMEM: /* -12*/ + errstr = "Out of memory"; + break; + case -EEXIST: /* -17 */ + errstr = "Object already exists"; + break; + case -ENOSPC: /* -28 */ + errstr = "No space left"; + break; + case -EROFS: /* -30 */ + errstr = "Readonly filesystem"; + break; + case -EOPNOTSUPP: /* -95 */ + errstr = "Operation not supported"; + break; + case -EUCLEAN: /* -117 */ + errstr = "Filesystem corrupted"; + break; + case -EDQUOT: /* -122 */ + errstr = "Quota exceeded"; + break; + } + + return errstr; +} + +/* + * __btrfs_handle_fs_error decodes expected errors from the caller and + * invokes the appropriate error response. + */ +__cold +void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, + unsigned int line, int error, const char *fmt, ...) +{ + struct super_block *sb = fs_info->sb; +#ifdef CONFIG_PRINTK + char statestr[STATE_STRING_BUF_LEN]; + const char *errstr; +#endif + +#ifdef CONFIG_PRINTK_INDEX + printk_index_subsys_emit( + "BTRFS: error (device %s%s) in %s:%d: error=%d %s", KERN_CRIT, fmt); +#endif + + /* + * Special case: if the error is EROFS, and we're already under + * SB_RDONLY, then it is safe here. + */ + if (error == -EROFS && sb_rdonly(sb)) + return; + +#ifdef CONFIG_PRINTK + errstr = btrfs_decode_error(error); + btrfs_state_to_string(fs_info, statestr); + if (fmt) { + struct va_format vaf; + va_list args; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s (%pV)\n", + sb->s_id, statestr, function, line, error, errstr, &vaf); + va_end(args); + } else { + pr_crit("BTRFS: error (device %s%s) in %s:%d: error=%d %s\n", + sb->s_id, statestr, function, line, error, errstr); + } +#endif + + /* + * We don't have fs_info::fs_state yet, and the rest of this is more + * kernel related cleanup, so for now comment it out. + */ +#if 0 + /* + * Today we only save the error info to memory. Long term we'll also + * send it down to the disk. + */ + set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state); + + /* Don't go through full error handling during mount. */ + if (!(sb->s_flags & SB_BORN)) + return; + + if (sb_rdonly(sb)) + return; + + btrfs_discard_stop(fs_info); + + /* Handle error by forcing the filesystem readonly. */ + btrfs_set_sb_rdonly(sb); +#endif + + btrfs_info(fs_info, "forced readonly"); + /* + * Note that a running device replace operation is not canceled here + * although there is no way to update the progress. It would add the + * risk of a deadlock, therefore the canceling is omitted. The only + * penalty is that some I/O remains active until the procedure + * completes. The next time when the filesystem is mounted writable + * again, the device replace operation continues. + */ +} + +#ifdef CONFIG_PRINTK +static const char * const logtypes[] = { + "emergency", + "alert", + "critical", + "error", + "warning", + "notice", + "info", + "debug", +}; + +/* + * Use one ratelimit state per log level so that a flood of less important + * messages doesn't cause more important ones to be dropped. + */ +static struct ratelimit_state printk_limits[] = { + RATELIMIT_STATE_INIT(printk_limits[0], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[1], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[2], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[3], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[4], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[5], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[6], DEFAULT_RATELIMIT_INTERVAL, 100), + RATELIMIT_STATE_INIT(printk_limits[7], DEFAULT_RATELIMIT_INTERVAL, 100), +}; + +void __cold _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) +{ + char lvl[PRINTK_MAX_SINGLE_HEADER_LEN + 1] = "\0"; + struct va_format vaf; + va_list args; + int kern_level; + const char *type = logtypes[4]; + struct ratelimit_state *ratelimit = &printk_limits[4]; + +#ifdef CONFIG_PRINTK_INDEX + printk_index_subsys_emit("%sBTRFS %s (device %s): ", NULL, fmt); +#endif + + va_start(args, fmt); + + while ((kern_level = printk_get_level(fmt)) != 0) { + size_t size = printk_skip_level(fmt) - fmt; + + if (kern_level >= '0' && kern_level <= '7') { + memcpy(lvl, fmt, size); + lvl[size] = '\0'; + type = logtypes[kern_level - '0']; + ratelimit = &printk_limits[kern_level - '0']; + } + fmt += size; + } + + vaf.fmt = fmt; + vaf.va = &args; + + if (__ratelimit(ratelimit)) { + if (fs_info) { + char statestr[STATE_STRING_BUF_LEN]; + + btrfs_state_to_string(fs_info, statestr); + _printk("%sBTRFS %s (device %s%s): %pV\n", lvl, type, + fs_info->sb->s_id, statestr, &vaf); + } else { + _printk("%sBTRFS %s: %pV\n", lvl, type, &vaf); + } + } + + va_end(args); +} +#endif + +#ifdef CONFIG_BTRFS_ASSERT +void __cold btrfs_assertfail(const char *expr, const char *file, int line) +{ + pr_err("assertion failed: %s, in %s:%d\n", expr, file, line); + BUG(); +} +#endif + +void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info) +{ + btrfs_err(fs_info, +"Unsupported V0 extent filesystem detected. Aborting. Please re-create your filesystem with a newer kernel"); +} + +#if BITS_PER_LONG == 32 +void __cold btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info) +{ + if (!test_and_set_bit(BTRFS_FS_32BIT_WARN, &fs_info->flags)) { + btrfs_warn(fs_info, "reaching 32bit limit for logical addresses"); + btrfs_warn(fs_info, +"due to page cache limit on 32bit systems, btrfs can't access metadata at or beyond %lluT", + BTRFS_32BIT_MAX_FILE_SIZE >> 40); + btrfs_warn(fs_info, + "please consider upgrading to 64bit kernel/hardware"); + } +} + +void __cold btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info) +{ + if (!test_and_set_bit(BTRFS_FS_32BIT_ERROR, &fs_info->flags)) { + btrfs_err(fs_info, "reached 32bit limit for logical addresses"); + btrfs_err(fs_info, +"due to page cache limit on 32bit systems, metadata beyond %lluT can't be accessed", + BTRFS_32BIT_MAX_FILE_SIZE >> 40); + btrfs_err(fs_info, + "please consider upgrading to 64bit kernel/hardware"); + } +} +#endif + +/* + * __btrfs_panic decodes unexpected, fatal errors from the caller, issues an + * alert, and either panics or BUGs, depending on mount options. + * + * MODIFIED: + * - We don't have btrfs_test_opt() yet, kill that and s_id. + */ +__cold +void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, + unsigned int line, int error, const char *fmt, ...) +{ + const char *errstr; + struct va_format vaf = { .fmt = fmt }; + va_list args; +#if 0 + char *s_id = ""; + + if (fs_info) + s_id = fs_info->sb->s_id; +#endif + + va_start(args, fmt); + vaf.va = &args; + + errstr = btrfs_decode_error(error); +#if 0 + if (fs_info && (btrfs_test_opt(fs_info, PANIC_ON_FATAL_ERROR))) + panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (error=%d %s)\n", + s_id, function, line, &vaf, error, errstr); +#endif + + btrfs_crit(fs_info, "panic in %s:%d: %pV (error=%d %s)", + function, line, &vaf, error, errstr); + va_end(args); + /* Caller calls BUG() */ +} diff --git a/kernel-shared/messages.h b/kernel-shared/messages.h new file mode 100644 index 00000000..879cbf95 --- /dev/null +++ b/kernel-shared/messages.h @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BTRFS_MESSAGES_H +#define BTRFS_MESSAGES_H + +#include "kerncompat.h" +#include "common/messages.h" +#include + +struct btrfs_fs_info; +struct btrfs_trans_handle; + +#ifdef __KERNEL__ +static inline __printf(2, 3) __cold +void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) +{ +} +#endif + +#ifdef CONFIG_PRINTK + +#define btrfs_printk(fs_info, fmt, args...) \ + _btrfs_printk(fs_info, fmt, ##args) + +__printf(2, 3) +__cold +void _btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...); + +#else + +#define btrfs_printk(fs_info, fmt, args...) \ + btrfs_no_printk(fs_info, fmt, ##args) +#endif + +#define btrfs_emerg(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_EMERG fmt, ##args) +#define btrfs_alert(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_ALERT fmt, ##args) +#define btrfs_crit(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_CRIT fmt, ##args) +#define btrfs_err(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_ERR fmt, ##args) +#define btrfs_warn(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_WARNING fmt, ##args) +#define btrfs_notice(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_NOTICE fmt, ##args) +#define btrfs_info(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_INFO fmt, ##args) + +/* + * Wrappers that use printk_in_rcu + */ +#define btrfs_emerg_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_EMERG fmt, ##args) +#define btrfs_alert_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_ALERT fmt, ##args) +#define btrfs_crit_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_CRIT fmt, ##args) +#define btrfs_err_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_ERR fmt, ##args) +#define btrfs_warn_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_WARNING fmt, ##args) +#define btrfs_notice_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_NOTICE fmt, ##args) +#define btrfs_info_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_INFO fmt, ##args) + +/* + * Wrappers that use a ratelimited printk_in_rcu + */ +#define btrfs_emerg_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_EMERG fmt, ##args) +#define btrfs_alert_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_ALERT fmt, ##args) +#define btrfs_crit_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_CRIT fmt, ##args) +#define btrfs_err_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_ERR fmt, ##args) +#define btrfs_warn_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_WARNING fmt, ##args) +#define btrfs_notice_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_NOTICE fmt, ##args) +#define btrfs_info_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_INFO fmt, ##args) + +/* + * Wrappers that use a ratelimited printk + */ +#define btrfs_emerg_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_EMERG fmt, ##args) +#define btrfs_alert_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_ALERT fmt, ##args) +#define btrfs_crit_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_CRIT fmt, ##args) +#define btrfs_err_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_ERR fmt, ##args) +#define btrfs_warn_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_WARNING fmt, ##args) +#define btrfs_notice_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_NOTICE fmt, ##args) +#define btrfs_info_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_INFO fmt, ##args) + +#if defined(CONFIG_DYNAMIC_DEBUG) +#define btrfs_debug(fs_info, fmt, args...) \ + _dynamic_func_call_no_desc(fmt, btrfs_printk, \ + fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_in_rcu(fs_info, fmt, args...) \ + _dynamic_func_call_no_desc(fmt, btrfs_printk_in_rcu, \ + fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \ + _dynamic_func_call_no_desc(fmt, btrfs_printk_rl_in_rcu, \ + fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_rl(fs_info, fmt, args...) \ + _dynamic_func_call_no_desc(fmt, btrfs_printk_ratelimited, \ + fs_info, KERN_DEBUG fmt, ##args) +#elif defined(DEBUG) +#define btrfs_debug(fs_info, fmt, args...) \ + btrfs_printk(fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_printk_rl_in_rcu(fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_rl(fs_info, fmt, args...) \ + btrfs_printk_ratelimited(fs_info, KERN_DEBUG fmt, ##args) +#else +#define btrfs_debug(fs_info, fmt, args...) \ + btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_in_rcu(fs_info, fmt, args...) \ + btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \ + btrfs_no_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args) +#define btrfs_debug_rl(fs_info, fmt, args...) \ + btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args) +#endif + +#define btrfs_printk_in_rcu(fs_info, fmt, args...) \ +do { \ + rcu_read_lock(); \ + btrfs_printk(fs_info, fmt, ##args); \ + rcu_read_unlock(); \ +} while (0) + +#define btrfs_no_printk_in_rcu(fs_info, fmt, args...) \ +do { \ + rcu_read_lock(); \ + btrfs_no_printk(fs_info, fmt, ##args); \ + rcu_read_unlock(); \ +} while (0) + +#define btrfs_printk_ratelimited(fs_info, fmt, args...) \ +do { \ + static DEFINE_RATELIMIT_STATE(_rs, \ + DEFAULT_RATELIMIT_INTERVAL, \ + DEFAULT_RATELIMIT_BURST); \ + if (__ratelimit(&_rs)) \ + btrfs_printk(fs_info, fmt, ##args); \ +} while (0) + +#define btrfs_printk_rl_in_rcu(fs_info, fmt, args...) \ +do { \ + rcu_read_lock(); \ + btrfs_printk_ratelimited(fs_info, fmt, ##args); \ + rcu_read_unlock(); \ +} while (0) + +#ifdef CONFIG_BTRFS_ASSERT +void __cold btrfs_assertfail(const char *expr, const char *file, int line); + +#define ASSERT(expr) \ + (likely(expr) ? (void)0 : btrfs_assertfail(#expr, __FILE__, __LINE__)) +#else +#define ASSERT(expr) (void)(expr) +#endif + +void __cold btrfs_print_v0_err(struct btrfs_fs_info *fs_info); + +__printf(5, 6) +__cold +void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, + unsigned int line, int error, const char *fmt, ...); + +const char * __attribute_const__ btrfs_decode_error(int error); + +#define btrfs_handle_fs_error(fs_info, error, fmt, args...) \ + __btrfs_handle_fs_error((fs_info), __func__, __LINE__, \ + (error), fmt, ##args) + +__printf(5, 6) +__cold +void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, + unsigned int line, int error, const char *fmt, ...); +/* + * If BTRFS_MOUNT_PANIC_ON_FATAL_ERROR is in mount_opt, __btrfs_panic + * will panic(). Otherwise we BUG() here. + */ +#define btrfs_panic(fs_info, error, fmt, args...) \ +do { \ + __btrfs_panic(fs_info, __func__, __LINE__, error, fmt, ##args); \ + BUG(); \ +} while (0) + +#if BITS_PER_LONG == 32 +#define BTRFS_32BIT_MAX_FILE_SIZE (((u64)ULONG_MAX + 1) << PAGE_SHIFT) +/* + * The warning threshold is 5/8th of the MAX_LFS_FILESIZE that limits the logical + * addresses of extents. + * + * For 4K page size it's about 10T, for 64K it's 160T. + */ +#define BTRFS_32BIT_EARLY_WARN_THRESHOLD (BTRFS_32BIT_MAX_FILE_SIZE * 5 / 8) +void btrfs_warn_32bit_limit(struct btrfs_fs_info *fs_info); +void btrfs_err_32bit_limit(struct btrfs_fs_info *fs_info); +#endif + +#endif diff --git a/kernel-shared/ulist.c b/kernel-shared/ulist.c index e193b02d..0cd4f74f 100644 --- a/kernel-shared/ulist.c +++ b/kernel-shared/ulist.c @@ -21,6 +21,7 @@ #include "kerncompat.h" #include "ulist.h" #include "kernel-shared/ctree.h" +#include "messages.h" /* * ulist is a generic data structure to hold a collection of unique u64 diff --git a/kernel-shared/zoned.h b/kernel-shared/zoned.h index 770f5889..2fbe1802 100644 --- a/kernel-shared/zoned.h +++ b/kernel-shared/zoned.h @@ -22,6 +22,7 @@ #include #include "kernel-shared/disk-io.h" #include "kernel-shared/volumes.h" +#include "messages.h" #ifdef BTRFS_ZONED #include diff --git a/libbtrfs/kerncompat.h b/libbtrfs/kerncompat.h index f7598627..a8ba07f0 100644 --- a/libbtrfs/kerncompat.h +++ b/libbtrfs/kerncompat.h @@ -325,26 +325,6 @@ static inline int IS_ERR_OR_NULL(const void *ptr) #define memalloc_nofs_save() (0) #define memalloc_nofs_restore(x) ((void)(x)) -#ifndef BTRFS_DISABLE_BACKTRACE -static inline void assert_trace(const char *assertion, const char *filename, - const char *func, unsigned line, long val) -{ - if (val) - return; - fprintf(stderr, - "%s:%d: %s: Assertion `%s` failed, value %ld\n", - filename, line, func, assertion, val); -#ifndef BTRFS_DISABLE_BACKTRACE - print_trace(); -#endif - abort(); - exit(1); -} -#define ASSERT(c) assert_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) -#else -#define ASSERT(c) assert(c) -#endif - #define BUG_ON(c) bugon_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) #define BUG() \ do { \ From patchwork Wed Apr 19 21:17:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217384 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 684F5C6FD18 for ; Wed, 19 Apr 2023 21:17:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230086AbjDSVRd (ORCPT ); Wed, 19 Apr 2023 17:17:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39830 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229602AbjDSVRb (ORCPT ); Wed, 19 Apr 2023 17:17:31 -0400 Received: from mail-qk1-x736.google.com (mail-qk1-x736.google.com [IPv6:2607:f8b0:4864:20::736]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A1CC14C37 for ; Wed, 19 Apr 2023 14:17:30 -0700 (PDT) Received: by mail-qk1-x736.google.com with SMTP id af79cd13be357-74dd7f52f18so304785a.0 for ; Wed, 19 Apr 2023 14:17:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939049; x=1684531049; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=T3GO2XLvZPNia8l2y6FQ8F/ozta7KsGyMfyHU4RwaX8=; b=ty66nLS/D/FoXGm+0vZyUyuqIz7nFyMyD1PbgoNKBKmuLnuO/4LOmVXRqimdckzQ7l TCBvWqKLsH9kyNzICc8aoGtHAvxHQ9Y+8hnqyU+5NFmFKhHtRLlntEbS8Fd43ft8NHcS d+WuZIDjeJx/tbPlD+W367cmqrfp3uwYMqnVv6j+q0vtFdT7Cv1miI4bFGexald6NX2Z TShzAlhcWmtVznEYlWe9G7MCkdLp3r/WyRfr+P9iTQnITOPAfQiU7hSWNBAw8u5vrpDP 6nOOuflRRw3Ynw0yUuPV9J7tWplDqgr2qj8SBKj02PRLRNbyKndLBCHI+mbSuGvEyifk iNKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939049; x=1684531049; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=T3GO2XLvZPNia8l2y6FQ8F/ozta7KsGyMfyHU4RwaX8=; b=CRcFfBALfGFaga9+mBEr90e96s+hIhLJ5Ly+VHoMV7xxL5NmQfEo4WFcRpXRfrwcIg 4kGaJ+L9i45kcFkaQqEQMLeTgZNl8XmkqFiEk+7v/tD0DuYH8nBLI7G/57zYz9+A1tzJ AtPAq0kO+UTJsATOBrgPYKUfj93jqnbGTKvfA2oLoSL85HZkQAE+4PPiSJQXFGWTi6Ti IECoAYLCxBoJwzr6RPMtX9JHefxNUkiVl/RTEhxXqKZ8MuXTNE/zP3kYdz23QgVsp+rN m6Js6Y16wM5rcooAIJy+J9SPyUDC1I46A6i5PJTwIb8AdZCl1WxdJqsmRm2Qp5JMT5Gs 2gvg== X-Gm-Message-State: AAQBX9fRy8+gLwcTLHOF/YFhikmJ2b37vcqpJqBnuhtkekRFhe6W0dS4 mkPj1+6zVKlzbJJlTUJcJinPQFRA+4743D5NNOpT4g== X-Google-Smtp-Source: AKy350ZEkw4xE6NFesfDHUROj3IgBeUhbwJR6rbZnlIS3VUXj44Nbv06WwWLxybJalsgvyPo883R6Q== X-Received: by 2002:ac8:7f07:0:b0:3db:9289:6949 with SMTP id f7-20020ac87f07000000b003db92896949mr24530qtk.3.1681939049353; Wed, 19 Apr 2023 14:17:29 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id u28-20020a05620a085c00b0074df7857e72sm2211740qku.34.2023.04.19.14.17.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:29 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 4/8] btrfs-progs: add struct va_format support to our btrfs_no_printk helper Date: Wed, 19 Apr 2023 17:17:15 -0400 Message-Id: <4e645609d525e855ca2a0b87d23c5fc2d1329d54.1681938911.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org We use the struct va_format to do nested printk's internally with our message handling. Add the appropriate user space code to make this work properly so when we start copying this code into btrfs-progs we get the proper messages. Signed-off-by: Josef Bacik --- common/messages.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/common/messages.c b/common/messages.c index 8bcfcc6a..aff5ce48 100644 --- a/common/messages.c +++ b/common/messages.c @@ -16,6 +16,7 @@ #include #include +#include #include "common/messages.h" #include "common/utils.h" @@ -25,6 +26,8 @@ static const char *common_error_string[] = { [ERROR_MSG_COMMIT_TRANS] = "failed to commit transaction", }; +static int va_modifier = -1; + __attribute__ ((format (printf, 1, 2))) void __btrfs_printf(const char *fmt, ...) { @@ -35,11 +38,39 @@ void __btrfs_printf(const char *fmt, ...) va_end(args); } +static int print_va_format(FILE *stream, const struct printf_info *info, + const void *const *args) +{ + const struct va_format *fmt; + + if (!(info->user & va_modifier)) + return -2; + + fmt = *((const struct va_format **)(args[0])); + return vfprintf(stream, fmt->fmt, *(fmt->va)); +} + +static int print_va_format_arginfo(const struct printf_info *info, + size_t n, int *argtypes, int *size) +{ + if (n > 0) { + argtypes[0] = PA_POINTER; + size[0] = sizeof(struct va_format *); + } + return 1; + } + __attribute__ ((format (printf, 2, 3))) void btrfs_no_printk(const void *fs_info, const char *fmt, ...) { va_list args; + if (va_modifier == -1) { + register_printf_specifier('V', print_va_format, + print_va_format_arginfo); + va_modifier = register_printf_modifier(L"p"); + } + va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); From patchwork Wed Apr 19 21:17:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217390 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7C9E3C77B78 for ; Wed, 19 Apr 2023 21:17:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230410AbjDSVRk (ORCPT ); Wed, 19 Apr 2023 17:17:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230434AbjDSVRi (ORCPT ); Wed, 19 Apr 2023 17:17:38 -0400 Received: from mail-qv1-xf2c.google.com (mail-qv1-xf2c.google.com [IPv6:2607:f8b0:4864:20::f2c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED85544B9 for ; Wed, 19 Apr 2023 14:17:32 -0700 (PDT) Received: by mail-qv1-xf2c.google.com with SMTP id h14so1022626qvr.7 for ; Wed, 19 Apr 2023 14:17:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939052; x=1684531052; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=PNK1ytEqynut8/xqhmlUlW7nrCYp7tXHXPwhKYLodjA=; b=YpEJK9uLz+UhdMUYgp3yXpsNI8cg++vqJejCxxXPeAPzzVosFLQP7rU8pHA0zJMiCM qz/OnerJiWaf0rWatTPPUP42g+bveLBdcDqT0h64QG0p49ltL1/gNheZ5v8lbdRcbb4I JSuZLWXWxqj28bIP2i2SrXaDVYbL5jZReXbD1eL94/WYPv/7fZDsmQvw1hQyrqM+r138 6FYOKw5bk/hpgCKxnrn2oN9NGMP3hxw2njYqCaJKSGAj72bHP7EWv3Lp6MKSbUrZeeZR WGFiAynxPGamF7VH/At2y6+JcywAz/b6B5vMm1NuHSka2xiDy7Ccl2tgcegM8m5YtPSo jBwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939052; x=1684531052; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=PNK1ytEqynut8/xqhmlUlW7nrCYp7tXHXPwhKYLodjA=; b=dYVcX0sVn5S4ElbiV4INOOpIMZMrWxE22jZokiwPUFKIza66o3buTC39kkDJVz/qE0 FcjmkrpdIQpTkH86Qy5HM5W4NwDWep0g+7y7C6Xhh4L/MhBT/7RIAw0WmWsykwJALYef NYsrCFIqYJDWkWM47Iwf54psKI5RyK4YFhrUJkwDHG9OVupvjkkh0yiK6p/MjShZqBXK Irooe7xVZ0q3D9TSWYvCoa0bpG68k4c5XcZwP+jM/Y7dotXTBz5LgSXmfFBf0eEqSvda 6Ql0ZyXY/CKBAbWYdUh7mB3jy7BZtUuvwe9ZmVmOer8x4A7xBtVIwWn0REWHah3hRQmE 7BQQ== X-Gm-Message-State: AAQBX9dtvtZmi5y7sBYPGClTq6pV32z5j+566aJO3gQcKAq8m5YlYjgS Q5FnIUALndlAqcs6LswMInm+QXgym1lByGqHc2xVng== X-Google-Smtp-Source: AKy350b537EtRlv8tmdo/etb2dAZ/NIUCi36gFySyJIRsqx9hGJAEmszX0JLjGm0mnXOnlmJFCzvwA== X-Received: by 2002:a05:6214:27ce:b0:5ef:8c85:6c67 with SMTP id ge14-20020a05621427ce00b005ef8c856c67mr12910952qvb.52.1681939051110; Wed, 19 Apr 2023 14:17:31 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id w5-20020a0c8e45000000b005ef5b1006c5sm2810qvb.38.2023.04.19.14.17.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:30 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 5/8] btrfs-progs: sync accessors.[ch] from the kernel Date: Wed, 19 Apr 2023 17:17:16 -0400 Message-Id: X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org This syncs accessors.[ch] from the kernel. For the most part accessors.h will remain the same, there's just some helpers that need to be adjusted for eb->data instead of eb->pages. Additionally accessors.c needed to be completely updated to deal with this as well. This is a set of files where we will likely only sync the header going forward, and leave the c file in place as it needs to be specific to btrfs-progs. This forced a few "unrelated" changes - Using btrfs_dir_item_ftype() instead of btrfs_dir_item_type(). This is due to the encryption changes, and was simpler to just do in this patch. - Adjusting some of the print tree code to use the actual helpers and not the btrfs-progs ones. Signed-off-by: Josef Bacik --- Makefile | 1 + check/main.c | 4 +- check/mode-common.c | 4 +- check/mode-lowmem.c | 6 +- cmds/restore.c | 2 +- include/kerncompat.h | 6 +- kernel-shared/accessors.c | 117 ++++ kernel-shared/accessors.h | 1087 ++++++++++++++++++++++++++++++++++++ kernel-shared/ctree.h | 886 +---------------------------- kernel-shared/dir-item.c | 8 +- kernel-shared/inode.c | 2 +- kernel-shared/print-tree.c | 16 +- mkfs/common.c | 1 + 13 files changed, 1241 insertions(+), 899 deletions(-) create mode 100644 kernel-shared/accessors.c create mode 100644 kernel-shared/accessors.h diff --git a/Makefile b/Makefile index 45e2e1e6..668f4e91 100644 --- a/Makefile +++ b/Makefile @@ -166,6 +166,7 @@ objects = \ kernel-lib/raid56.o \ kernel-lib/rbtree.o \ kernel-lib/tables.o \ + kernel-shared/accessors.o \ kernel-shared/backref.o \ kernel-shared/ctree.o \ kernel-shared/delayed-ref.o \ diff --git a/check/main.c b/check/main.c index b5748d85..5683fb1b 100644 --- a/check/main.c +++ b/check/main.c @@ -1434,7 +1434,7 @@ static int process_dir_item(struct extent_buffer *eb, btrfs_dir_item_key_to_cpu(eb, di, &location); name_len = btrfs_dir_name_len(eb, di); data_len = btrfs_dir_data_len(eb, di); - filetype = btrfs_dir_type(eb, di); + filetype = btrfs_dir_ftype(eb, di); rec->found_size += name_len; if (cur + sizeof(*di) + name_len > total || @@ -2135,7 +2135,7 @@ static int add_missing_dir_index(struct btrfs_root *root, disk_key.offset = 0; btrfs_set_dir_item_key(leaf, dir_item, &disk_key); - btrfs_set_dir_type(leaf, dir_item, imode_to_type(rec->imode)); + btrfs_set_dir_flags(leaf, dir_item, imode_to_type(rec->imode)); btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_name_len(leaf, dir_item, backref->namelen); name_ptr = (unsigned long)(dir_item + 1); diff --git a/check/mode-common.c b/check/mode-common.c index ef272368..412a9fd5 100644 --- a/check/mode-common.c +++ b/check/mode-common.c @@ -764,7 +764,7 @@ static int find_file_type_dir_index(struct btrfs_root *root, u64 ino, u64 dirid, if (location.objectid != ino || location.type != BTRFS_INODE_ITEM_KEY || location.offset != 0) goto out; - filetype = btrfs_dir_type(path.nodes[0], di); + filetype = btrfs_dir_ftype(path.nodes[0], di); if (filetype >= BTRFS_FT_MAX || filetype == BTRFS_FT_UNKNOWN) goto out; len = min_t(u32, BTRFS_NAME_LEN, @@ -823,7 +823,7 @@ static int find_file_type_dir_item(struct btrfs_root *root, u64 ino, u64 dirid, location.type != BTRFS_INODE_ITEM_KEY || location.offset != 0) continue; - filetype = btrfs_dir_type(path.nodes[0], di); + filetype = btrfs_dir_ftype(path.nodes[0], di); if (filetype >= BTRFS_FT_MAX || filetype == BTRFS_FT_UNKNOWN) continue; len = min_t(u32, BTRFS_NAME_LEN, diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c index 3cf8d97f..18eac047 100644 --- a/check/mode-lowmem.c +++ b/check/mode-lowmem.c @@ -868,7 +868,7 @@ loop: location.offset != 0) goto next; - filetype = btrfs_dir_type(node, di); + filetype = btrfs_dir_ftype(node, di); if (file_type != filetype) goto next; @@ -966,7 +966,7 @@ static int find_dir_item(struct btrfs_root *root, struct btrfs_key *key, location.offset != location_key->offset) goto next; - filetype = btrfs_dir_type(node, di); + filetype = btrfs_dir_ftype(node, di); if (file_type != filetype) goto next; @@ -1759,7 +1759,7 @@ begin: (*size) += name_len; read_extent_buffer(node, namebuf, (unsigned long)(di + 1), len); - filetype = btrfs_dir_type(node, di); + filetype = btrfs_dir_ftype(node, di); if (di_key->type == BTRFS_DIR_ITEM_KEY && di_key->offset != btrfs_name_hash(namebuf, len)) { diff --git a/cmds/restore.c b/cmds/restore.c index 02ff5e6a..da5bafd1 100644 --- a/cmds/restore.c +++ b/cmds/restore.c @@ -993,7 +993,7 @@ static int search_dir(struct btrfs_root *root, struct btrfs_key *key, name_len = btrfs_dir_name_len(leaf, dir_item); read_extent_buffer(leaf, filename, name_ptr, name_len); filename[name_len] = '\0'; - type = btrfs_dir_type(leaf, dir_item); + type = btrfs_dir_ftype(leaf, dir_item); btrfs_dir_item_key_to_cpu(leaf, dir_item, &location); /* full path from root of btrfs being restored */ diff --git a/include/kerncompat.h b/include/kerncompat.h index d7eba985..42e81223 100644 --- a/include/kerncompat.h +++ b/include/kerncompat.h @@ -505,10 +505,6 @@ struct __una_u16 { __le16 x; } __attribute__((__packed__)); struct __una_u32 { __le32 x; } __attribute__((__packed__)); struct __una_u64 { __le64 x; } __attribute__((__packed__)); -#define get_unaligned_le8(p) (*((u8 *)(p))) -#define get_unaligned_8(p) (*((u8 *)(p))) -#define put_unaligned_le8(val,p) ((*((u8 *)(p))) = (val)) -#define put_unaligned_8(val,p) ((*((u8 *)(p))) = (val)) #define get_unaligned_le16(p) le16_to_cpu(((const struct __una_u16 *)(p))->x) #define get_unaligned_16(p) (((const struct __una_u16 *)(p))->x) #define put_unaligned_le16(val,p) (((struct __una_u16 *)(p))->x = cpu_to_le16(val)) @@ -582,4 +578,6 @@ static inline bool sb_rdonly(struct super_block *sb) return false; } +#define unlikely(cond) (cond) + #endif diff --git a/kernel-shared/accessors.c b/kernel-shared/accessors.c new file mode 100644 index 00000000..06c976a6 --- /dev/null +++ b/kernel-shared/accessors.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2007 Oracle. All rights reserved. + */ + +#include "kerncompat.h" +#include "messages.h" +#include "ctree.h" +#include "accessors.h" + +static bool check_setget_bounds(const struct extent_buffer *eb, + const void *ptr, unsigned off, int size) +{ + const unsigned long member_offset = (unsigned long)ptr + off; + + if (unlikely(member_offset + size > eb->len)) { + btrfs_warn(eb->fs_info, + "bad eb member %s: ptr 0x%lx start %llu member offset %lu size %d", + (member_offset > eb->len ? "start" : "end"), + (unsigned long)ptr, eb->start, member_offset, size); + return false; + } + + return true; +} + +/* + * MODIFIED: + * - We don't have eb->pages. + */ +void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb) +{ + token->eb = eb; + token->kaddr = eb->data; + token->offset = 0; +} + +/* + * MODIFIED: + * - We don't have eb->pages, simply wrap the set/get helpers. + */ + +/* + * Macro templates that define helpers to read/write extent buffer data of a + * given size, that are also used via ctree.h for access to item members by + * specialized helpers. + * + * Generic helpers: + * - btrfs_set_8 (for 8/16/32/64) + * - btrfs_get_8 (for 8/16/32/64) + * + * Generic helpers with a token (cached address of the most recently accessed + * page): + * - btrfs_set_token_8 (for 8/16/32/64) + * - btrfs_get_token_8 (for 8/16/32/64) + * + * The set/get functions handle data spanning two pages transparently, in case + * metadata block size is larger than page. Every pointer to metadata items is + * an offset into the extent buffer page array, cast to a specific type. This + * gives us all the type checking. + * + * The extent buffer pages stored in the array pages do not form a contiguous + * phyusical range, but the API functions assume the linear offset to the range + * from 0 to metadata node size. + */ + +#define DEFINE_BTRFS_SETGET_BITS(bits) \ +u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \ + const void *ptr, unsigned long off) \ +{ \ + const unsigned long member_offset = (unsigned long)ptr + off; \ + const int size = sizeof(u##bits); \ + ASSERT(token); \ + ASSERT(token->kaddr); \ + ASSERT(check_setget_bounds(token->eb, ptr, off, size)); \ + return get_unaligned_le##bits(token->kaddr + member_offset); \ +} \ +u##bits btrfs_get_##bits(const struct extent_buffer *eb, \ + const void *ptr, unsigned long off) \ +{ \ + const unsigned long member_offset = (unsigned long)ptr + off; \ + const int size = sizeof(u##bits); \ + ASSERT(check_setget_bounds(eb, ptr, off, size)); \ + return get_unaligned_le##bits(eb->data + member_offset); \ +} \ +void btrfs_set_token_##bits(struct btrfs_map_token *token, \ + const void *ptr, unsigned long off, \ + u##bits val) \ +{ \ + unsigned long member_offset = (unsigned long)ptr + off; \ + const int size = sizeof(u##bits); \ + ASSERT(token); \ + ASSERT(token->kaddr); \ + ASSERT(check_setget_bounds(token->eb, ptr, off, size)); \ + put_unaligned_le##bits(val, token->kaddr + member_offset); \ +} \ +void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \ + unsigned long off, u##bits val) \ +{ \ + unsigned long member_offset = (unsigned long)ptr + off; \ + const int size = sizeof(u##bits); \ + ASSERT(check_setget_bounds(eb, ptr, off, size)); \ + put_unaligned_le##bits(val, (void *)eb->data + member_offset); \ +} + +DEFINE_BTRFS_SETGET_BITS(8) +DEFINE_BTRFS_SETGET_BITS(16) +DEFINE_BTRFS_SETGET_BITS(32) +DEFINE_BTRFS_SETGET_BITS(64) + +void btrfs_node_key(const struct extent_buffer *eb, + struct btrfs_disk_key *disk_key, int nr) +{ + unsigned long ptr = btrfs_node_key_ptr_offset(eb, nr); + read_eb_member(eb, (struct btrfs_key_ptr *)ptr, + struct btrfs_key_ptr, key, disk_key); +} diff --git a/kernel-shared/accessors.h b/kernel-shared/accessors.h new file mode 100644 index 00000000..667dcbb8 --- /dev/null +++ b/kernel-shared/accessors.h @@ -0,0 +1,1087 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BTRFS_ACCESSORS_H +#define BTRFS_ACCESSORS_H + +struct btrfs_map_token { + struct extent_buffer *eb; + char *kaddr; + unsigned long offset; +}; + +void btrfs_init_map_token(struct btrfs_map_token *token, struct extent_buffer *eb); + +/* + * Some macros to generate set/get functions for the struct fields. This + * assumes there is a lefoo_to_cpu for every type, so lets make a simple one + * for u8: + */ +#define le8_to_cpu(v) (v) +#define cpu_to_le8(v) (v) +#define __le8 u8 + +static inline u8 get_unaligned_le8(const void *p) +{ + return *(u8 *)p; +} + +static inline void put_unaligned_le8(u8 val, void *p) +{ + *(u8 *)p = val; +} + +#define read_eb_member(eb, ptr, type, member, result) (\ + read_extent_buffer(eb, (char *)(result), \ + ((unsigned long)(ptr)) + \ + offsetof(type, member), \ + sizeof(((type *)0)->member))) + +#define write_eb_member(eb, ptr, type, member, result) (\ + write_extent_buffer(eb, (char *)(result), \ + ((unsigned long)(ptr)) + \ + offsetof(type, member), \ + sizeof(((type *)0)->member))) + +#define DECLARE_BTRFS_SETGET_BITS(bits) \ +u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \ + const void *ptr, unsigned long off); \ +void btrfs_set_token_##bits(struct btrfs_map_token *token, \ + const void *ptr, unsigned long off, \ + u##bits val); \ +u##bits btrfs_get_##bits(const struct extent_buffer *eb, \ + const void *ptr, unsigned long off); \ +void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \ + unsigned long off, u##bits val); + +DECLARE_BTRFS_SETGET_BITS(8) +DECLARE_BTRFS_SETGET_BITS(16) +DECLARE_BTRFS_SETGET_BITS(32) +DECLARE_BTRFS_SETGET_BITS(64) + +#define BTRFS_SETGET_FUNCS(name, type, member, bits) \ +static inline u##bits btrfs_##name(const struct extent_buffer *eb, \ + const type *s) \ +{ \ + static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \ + return btrfs_get_##bits(eb, s, offsetof(type, member)); \ +} \ +static inline void btrfs_set_##name(const struct extent_buffer *eb, type *s, \ + u##bits val) \ +{ \ + static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \ + btrfs_set_##bits(eb, s, offsetof(type, member), val); \ +} \ +static inline u##bits btrfs_token_##name(struct btrfs_map_token *token, \ + const type *s) \ +{ \ + static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \ + return btrfs_get_token_##bits(token, s, offsetof(type, member));\ +} \ +static inline void btrfs_set_token_##name(struct btrfs_map_token *token,\ + type *s, u##bits val) \ +{ \ + static_assert(sizeof(u##bits) == sizeof(((type *)0))->member); \ + btrfs_set_token_##bits(token, s, offsetof(type, member), val); \ +} + +/* + * MODIFIED: + * - We have eb->data, not eb->pages[0] + */ +#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ +static inline u##bits btrfs_##name(const struct extent_buffer *eb) \ +{ \ + const type *p = (type *)eb->data; \ + return get_unaligned_le##bits(&p->member); \ +} \ +static inline void btrfs_set_##name(const struct extent_buffer *eb, \ + u##bits val) \ +{ \ + type *p = (type *)eb->data; \ + put_unaligned_le##bits(val, &p->member); \ +} + +#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ +static inline u##bits btrfs_##name(const type *s) \ +{ \ + return get_unaligned_le##bits(&s->member); \ +} \ +static inline void btrfs_set_##name(type *s, u##bits val) \ +{ \ + put_unaligned_le##bits(val, &s->member); \ +} + +static inline u64 btrfs_device_total_bytes(const struct extent_buffer *eb, + struct btrfs_dev_item *s) +{ + static_assert(sizeof(u64) == + sizeof(((struct btrfs_dev_item *)0))->total_bytes); + return btrfs_get_64(eb, s, offsetof(struct btrfs_dev_item, + total_bytes)); +} + +/* + * MODIFIED + * - Removed WARN_ON(!IS_ALIGNED(val, eb->fs_info->sectorsize)); + */ +static inline void btrfs_set_device_total_bytes(const struct extent_buffer *eb, + struct btrfs_dev_item *s, + u64 val) +{ + static_assert(sizeof(u64) == + sizeof(((struct btrfs_dev_item *)0))->total_bytes); + btrfs_set_64(eb, s, offsetof(struct btrfs_dev_item, total_bytes), val); +} + +BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64); +BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64); +BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32); +BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32); +BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item, start_offset, 64); +BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); +BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); +BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32); +BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8); +BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8); +BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64); + +BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item, + total_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item, + bytes_used, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item, + io_align, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item, + io_width, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item, + sector_size, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item, dev_group, 32); +BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item, + seek_speed, 8); +BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item, + bandwidth, 8); +BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item, + generation, 64); + +static inline unsigned long btrfs_device_uuid(struct btrfs_dev_item *d) +{ + return (unsigned long)d + offsetof(struct btrfs_dev_item, uuid); +} + +static inline unsigned long btrfs_device_fsid(struct btrfs_dev_item *d) +{ + return (unsigned long)d + offsetof(struct btrfs_dev_item, fsid); +} + +BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64); +BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64); +BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64); +BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32); +BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32); +BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32); +BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64); +BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16); +BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16); +BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64); +BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64); + +static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s) +{ + return (char *)s + offsetof(struct btrfs_stripe, dev_uuid); +} + +BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk, + stripe_len, 64); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk, io_align, 32); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk, io_width, 32); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk, + sector_size, 32); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk, + num_stripes, 16); +BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk, + sub_stripes, 16); +BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64); + +static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c, int nr) +{ + unsigned long offset = (unsigned long)c; + + offset += offsetof(struct btrfs_chunk, stripe); + offset += nr * sizeof(struct btrfs_stripe); + return (struct btrfs_stripe *)offset; +} + +static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr) +{ + return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr)); +} + +static inline u64 btrfs_stripe_offset_nr(const struct extent_buffer *eb, + struct btrfs_chunk *c, int nr) +{ + return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr)); +} + +static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb, + struct btrfs_chunk *c, int nr, + u64 val) +{ + btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val); +} + +static inline u64 btrfs_stripe_devid_nr(const struct extent_buffer *eb, + struct btrfs_chunk *c, int nr) +{ + return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr)); +} + +static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb, + struct btrfs_chunk *c, int nr, + u64 val) +{ + btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val); +} + +/* struct btrfs_block_group_item */ +BTRFS_SETGET_STACK_FUNCS(stack_block_group_used, struct btrfs_block_group_item, + used, 64); +BTRFS_SETGET_FUNCS(block_group_used, struct btrfs_block_group_item, used, 64); +BTRFS_SETGET_STACK_FUNCS(stack_block_group_chunk_objectid, + struct btrfs_block_group_item, chunk_objectid, 64); + +BTRFS_SETGET_FUNCS(block_group_chunk_objectid, + struct btrfs_block_group_item, chunk_objectid, 64); +BTRFS_SETGET_FUNCS(block_group_flags, struct btrfs_block_group_item, flags, 64); +BTRFS_SETGET_STACK_FUNCS(stack_block_group_flags, + struct btrfs_block_group_item, flags, 64); + +/* struct btrfs_free_space_info */ +BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info, + extent_count, 32); +BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32); + +/* struct btrfs_inode_ref */ +BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); +BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); +BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_index, struct btrfs_inode_ref, index, 64); + +/* struct btrfs_inode_extref */ +BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref, + parent_objectid, 64); +BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref, + name_len, 16); +BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64); + +/* struct btrfs_inode_item */ +BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64); +BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64); +BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64); +BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64); +BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64); +BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64); +BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32); +BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32); +BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); +BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); +BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); +BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item, + generation, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item, + sequence, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item, + transid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item, nbytes, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item, + block_group, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32); +BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32); +BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32); +BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32); +BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64); +BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64); +BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); +BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); +BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64); +BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32); + +/* struct btrfs_dev_extent */ +BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, chunk_tree, 64); +BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent, + chunk_objectid, 64); +BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent, + chunk_offset, 64); +BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_chunk_tree, struct btrfs_dev_extent, + chunk_tree, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_chunk_objectid, struct btrfs_dev_extent, + chunk_objectid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_chunk_offset, struct btrfs_dev_extent, + chunk_offset, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_length, struct btrfs_dev_extent, length, 64); + +BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64); +BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item, generation, 64); +BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64); + +BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8); + +static inline void btrfs_tree_block_key(const struct extent_buffer *eb, + struct btrfs_tree_block_info *item, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, item, struct btrfs_tree_block_info, key, key); +} + +static inline void btrfs_set_tree_block_key(const struct extent_buffer *eb, + struct btrfs_tree_block_info *item, + struct btrfs_disk_key *key) +{ + write_eb_member(eb, item, struct btrfs_tree_block_info, key, key); +} + +BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref, root, 64); +BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref, + objectid, 64); +BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref, + offset, 64); +BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref, count, 32); + +BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref, count, 32); + +BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref, + type, 8); +BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref, + offset, 64); + +static inline u32 btrfs_extent_inline_ref_size(int type) +{ + if (type == BTRFS_TREE_BLOCK_REF_KEY || + type == BTRFS_SHARED_BLOCK_REF_KEY) + return sizeof(struct btrfs_extent_inline_ref); + if (type == BTRFS_SHARED_DATA_REF_KEY) + return sizeof(struct btrfs_shared_data_ref) + + sizeof(struct btrfs_extent_inline_ref); + if (type == BTRFS_EXTENT_DATA_REF_KEY) + return sizeof(struct btrfs_extent_data_ref) + + offsetof(struct btrfs_extent_inline_ref, offset); + return 0; +} + +/* struct btrfs_node */ +BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); +BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); +BTRFS_SETGET_STACK_FUNCS(stack_key_blockptr, struct btrfs_key_ptr, blockptr, 64); +BTRFS_SETGET_STACK_FUNCS(stack_key_generation, struct btrfs_key_ptr, + generation, 64); + +static inline u64 btrfs_node_blockptr(const struct extent_buffer *eb, int nr) +{ + unsigned long ptr; + + ptr = offsetof(struct btrfs_node, ptrs) + + sizeof(struct btrfs_key_ptr) * nr; + return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr); +} + +static inline void btrfs_set_node_blockptr(const struct extent_buffer *eb, + int nr, u64 val) +{ + unsigned long ptr; + + ptr = offsetof(struct btrfs_node, ptrs) + + sizeof(struct btrfs_key_ptr) * nr; + btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val); +} + +static inline u64 btrfs_node_ptr_generation(const struct extent_buffer *eb, int nr) +{ + unsigned long ptr; + + ptr = offsetof(struct btrfs_node, ptrs) + + sizeof(struct btrfs_key_ptr) * nr; + return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr); +} + +static inline void btrfs_set_node_ptr_generation(const struct extent_buffer *eb, + int nr, u64 val) +{ + unsigned long ptr; + + ptr = offsetof(struct btrfs_node, ptrs) + + sizeof(struct btrfs_key_ptr) * nr; + btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val); +} + +static inline unsigned long btrfs_node_key_ptr_offset(const struct extent_buffer *eb, int nr) +{ + return offsetof(struct btrfs_node, ptrs) + + sizeof(struct btrfs_key_ptr) * nr; +} + +void btrfs_node_key(const struct extent_buffer *eb, + struct btrfs_disk_key *disk_key, int nr); + +static inline void btrfs_set_node_key(const struct extent_buffer *eb, + struct btrfs_disk_key *disk_key, int nr) +{ + unsigned long ptr; + + ptr = btrfs_node_key_ptr_offset(eb, nr); + write_eb_member(eb, (struct btrfs_key_ptr *)ptr, + struct btrfs_key_ptr, key, disk_key); +} + +/* struct btrfs_item */ +BTRFS_SETGET_FUNCS(raw_item_offset, struct btrfs_item, offset, 32); +BTRFS_SETGET_FUNCS(raw_item_size, struct btrfs_item, size, 32); +BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32); +BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32); + +static inline unsigned long btrfs_item_nr_offset(const struct extent_buffer *eb, int nr) +{ + return offsetof(struct btrfs_leaf, items) + + sizeof(struct btrfs_item) * nr; +} + +static inline struct btrfs_item *btrfs_item_nr(const struct extent_buffer *eb, int nr) +{ + return (struct btrfs_item *)btrfs_item_nr_offset(eb, nr); +} + +#define BTRFS_ITEM_SETGET_FUNCS(member) \ +static inline u32 btrfs_item_##member(const struct extent_buffer *eb, int slot) \ +{ \ + return btrfs_raw_item_##member(eb, btrfs_item_nr(eb, slot)); \ +} \ +static inline void btrfs_set_item_##member(const struct extent_buffer *eb, \ + int slot, u32 val) \ +{ \ + btrfs_set_raw_item_##member(eb, btrfs_item_nr(eb, slot), val); \ +} \ +static inline u32 btrfs_token_item_##member(struct btrfs_map_token *token, \ + int slot) \ +{ \ + struct btrfs_item *item = btrfs_item_nr(token->eb, slot); \ + return btrfs_token_raw_item_##member(token, item); \ +} \ +static inline void btrfs_set_token_item_##member(struct btrfs_map_token *token, \ + int slot, u32 val) \ +{ \ + struct btrfs_item *item = btrfs_item_nr(token->eb, slot); \ + btrfs_set_token_raw_item_##member(token, item, val); \ +} + +BTRFS_ITEM_SETGET_FUNCS(offset) +BTRFS_ITEM_SETGET_FUNCS(size); + +static inline u32 btrfs_item_data_end(const struct extent_buffer *eb, int nr) +{ + return btrfs_item_offset(eb, nr) + btrfs_item_size(eb, nr); +} + +static inline void btrfs_item_key(const struct extent_buffer *eb, + struct btrfs_disk_key *disk_key, int nr) +{ + struct btrfs_item *item = btrfs_item_nr(eb, nr); + + read_eb_member(eb, item, struct btrfs_item, key, disk_key); +} + +static inline void btrfs_set_item_key(struct extent_buffer *eb, + struct btrfs_disk_key *disk_key, int nr) +{ + struct btrfs_item *item = btrfs_item_nr(eb, nr); + + write_eb_member(eb, item, struct btrfs_item, key, disk_key); +} + +BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64); + +/* struct btrfs_root_ref */ +BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64); +BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64); +BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16); +BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64); +BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16); + +/* struct btrfs_dir_item */ +BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16); +BTRFS_SETGET_FUNCS(dir_flags, struct btrfs_dir_item, type, 8); +BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16); +BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dir_flags, struct btrfs_dir_item, type, 8); +BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item, data_len, 16); +BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16); +BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, transid, 64); + +static inline u8 btrfs_dir_ftype(const struct extent_buffer *eb, + const struct btrfs_dir_item *item) +{ + return btrfs_dir_flags_to_ftype(btrfs_dir_flags(eb, item)); +} + +static inline u8 btrfs_stack_dir_ftype(const struct btrfs_dir_item *item) +{ + return btrfs_dir_flags_to_ftype(btrfs_stack_dir_flags(item)); +} + +static inline void btrfs_dir_item_key(const struct extent_buffer *eb, + const struct btrfs_dir_item *item, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, item, struct btrfs_dir_item, location, key); +} + +static inline void btrfs_set_dir_item_key(struct extent_buffer *eb, + struct btrfs_dir_item *item, + const struct btrfs_disk_key *key) +{ + write_eb_member(eb, item, struct btrfs_dir_item, location, key); +} + +BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header, + num_entries, 64); +BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header, + num_bitmaps, 64); +BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header, + generation, 64); + +static inline void btrfs_free_space_key(const struct extent_buffer *eb, + const struct btrfs_free_space_header *h, + struct btrfs_disk_key *key) +{ + read_eb_member(eb, h, struct btrfs_free_space_header, location, key); +} + +static inline void btrfs_set_free_space_key(struct extent_buffer *eb, + struct btrfs_free_space_header *h, + const struct btrfs_disk_key *key) +{ + write_eb_member(eb, h, struct btrfs_free_space_header, location, key); +} + +/* struct btrfs_disk_key */ +BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, objectid, 64); +BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64); +BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8); + +#ifdef __LITTLE_ENDIAN + +/* + * Optimized helpers for little-endian architectures where CPU and on-disk + * structures have the same endianness and we can skip conversions. + */ + +static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu_key, + const struct btrfs_disk_key *disk_key) +{ + memcpy(cpu_key, disk_key, sizeof(struct btrfs_key)); +} + +static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk_key, + const struct btrfs_key *cpu_key) +{ + memcpy(disk_key, cpu_key, sizeof(struct btrfs_key)); +} + +static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb, + struct btrfs_key *cpu_key, int nr) +{ + struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key; + + btrfs_node_key(eb, disk_key, nr); +} + +static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb, + struct btrfs_key *cpu_key, int nr) +{ + struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key; + + btrfs_item_key(eb, disk_key, nr); +} + +static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb, + const struct btrfs_dir_item *item, + struct btrfs_key *cpu_key) +{ + struct btrfs_disk_key *disk_key = (struct btrfs_disk_key *)cpu_key; + + btrfs_dir_item_key(eb, item, disk_key); +} + +#else + +static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu, + const struct btrfs_disk_key *disk) +{ + cpu->offset = le64_to_cpu(disk->offset); + cpu->type = disk->type; + cpu->objectid = le64_to_cpu(disk->objectid); +} + +static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk, + const struct btrfs_key *cpu) +{ + disk->offset = cpu_to_le64(cpu->offset); + disk->type = cpu->type; + disk->objectid = cpu_to_le64(cpu->objectid); +} + +static inline void btrfs_node_key_to_cpu(const struct extent_buffer *eb, + struct btrfs_key *key, int nr) +{ + struct btrfs_disk_key disk_key; + + btrfs_node_key(eb, &disk_key, nr); + btrfs_disk_key_to_cpu(key, &disk_key); +} + +static inline void btrfs_item_key_to_cpu(const struct extent_buffer *eb, + struct btrfs_key *key, int nr) +{ + struct btrfs_disk_key disk_key; + + btrfs_item_key(eb, &disk_key, nr); + btrfs_disk_key_to_cpu(key, &disk_key); +} + +static inline void btrfs_dir_item_key_to_cpu(const struct extent_buffer *eb, + const struct btrfs_dir_item *item, + struct btrfs_key *key) +{ + struct btrfs_disk_key disk_key; + + btrfs_dir_item_key(eb, item, &disk_key); + btrfs_disk_key_to_cpu(key, &disk_key); +} + +#endif + +/* struct btrfs_header */ +BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64); +BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, generation, 64); +BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); +BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); +BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64); +BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); +BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header, + generation, 64); +BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64); +BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header, nritems, 32); +BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64); + +static inline int btrfs_header_flag(const struct extent_buffer *eb, u64 flag) +{ + return (btrfs_header_flags(eb) & flag) == flag; +} + +static inline void btrfs_set_header_flag(struct extent_buffer *eb, u64 flag) +{ + u64 flags = btrfs_header_flags(eb); + + btrfs_set_header_flags(eb, flags | flag); +} + +static inline void btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag) +{ + u64 flags = btrfs_header_flags(eb); + + btrfs_set_header_flags(eb, flags & ~flag); +} + +static inline int btrfs_header_backref_rev(const struct extent_buffer *eb) +{ + u64 flags = btrfs_header_flags(eb); + + return flags >> BTRFS_BACKREF_REV_SHIFT; +} + +static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb, int rev) +{ + u64 flags = btrfs_header_flags(eb); + + flags &= ~BTRFS_BACKREF_REV_MASK; + flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT; + btrfs_set_header_flags(eb, flags); +} + +static inline int btrfs_is_leaf(const struct extent_buffer *eb) +{ + return btrfs_header_level(eb) == 0; +} + +/* struct btrfs_root_item */ +BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item, generation, 64); +BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32); +BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64); +BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8); + +BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item, generation, 64); +BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64); +BTRFS_SETGET_STACK_FUNCS(root_drop_level, struct btrfs_root_item, drop_level, 8); +BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8); +BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64); +BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32); +BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64); +BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); +BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); +BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, + last_snapshot, 64); +BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item, + generation_v2, 64); +BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item, ctransid, 64); +BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item, otransid, 64); +BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item, stransid, 64); +BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item, rtransid, 64); + +/* struct btrfs_root_backup */ +BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, + tree_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup, + tree_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup, + tree_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup, + chunk_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup, + chunk_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup, + chunk_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup, + extent_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup, + extent_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup, + extent_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup, + fs_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup, + fs_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup, + fs_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup, + dev_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup, + dev_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup, + dev_root_level, 8); + +BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup, + csum_root, 64); +BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup, + csum_root_gen, 64); +BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup, + csum_root_level, 8); +BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup, + total_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, + bytes_used, 64); +BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, + num_devices, 64); + +/* struct btrfs_balance_item */ +BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64); + +static inline void btrfs_balance_data(const struct extent_buffer *eb, + const struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + read_eb_member(eb, bi, struct btrfs_balance_item, data, ba); +} + +static inline void btrfs_set_balance_data(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + const struct btrfs_disk_balance_args *ba) +{ + write_eb_member(eb, bi, struct btrfs_balance_item, data, ba); +} + +static inline void btrfs_balance_meta(const struct extent_buffer *eb, + const struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); +} + +static inline void btrfs_set_balance_meta(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + const struct btrfs_disk_balance_args *ba) +{ + write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); +} + +static inline void btrfs_balance_sys(const struct extent_buffer *eb, + const struct btrfs_balance_item *bi, + struct btrfs_disk_balance_args *ba) +{ + read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); +} + +static inline void btrfs_set_balance_sys(struct extent_buffer *eb, + struct btrfs_balance_item *bi, + const struct btrfs_disk_balance_args *ba) +{ + write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); +} + +static inline void btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu, + const struct btrfs_disk_balance_args *disk) +{ + memset(cpu, 0, sizeof(*cpu)); + + cpu->profiles = le64_to_cpu(disk->profiles); + cpu->usage = le64_to_cpu(disk->usage); + cpu->devid = le64_to_cpu(disk->devid); + cpu->pstart = le64_to_cpu(disk->pstart); + cpu->pend = le64_to_cpu(disk->pend); + cpu->vstart = le64_to_cpu(disk->vstart); + cpu->vend = le64_to_cpu(disk->vend); + cpu->target = le64_to_cpu(disk->target); + cpu->flags = le64_to_cpu(disk->flags); + cpu->limit = le64_to_cpu(disk->limit); + cpu->stripes_min = le32_to_cpu(disk->stripes_min); + cpu->stripes_max = le32_to_cpu(disk->stripes_max); +} + +static inline void btrfs_cpu_balance_args_to_disk( + struct btrfs_disk_balance_args *disk, + const struct btrfs_balance_args *cpu) +{ + memset(disk, 0, sizeof(*disk)); + + disk->profiles = cpu_to_le64(cpu->profiles); + disk->usage = cpu_to_le64(cpu->usage); + disk->devid = cpu_to_le64(cpu->devid); + disk->pstart = cpu_to_le64(cpu->pstart); + disk->pend = cpu_to_le64(cpu->pend); + disk->vstart = cpu_to_le64(cpu->vstart); + disk->vend = cpu_to_le64(cpu->vend); + disk->target = cpu_to_le64(cpu->target); + disk->flags = cpu_to_le64(cpu->flags); + disk->limit = cpu_to_le64(cpu->limit); + disk->stripes_min = cpu_to_le32(cpu->stripes_min); + disk->stripes_max = cpu_to_le32(cpu->stripes_max); +} + +/* struct btrfs_super_block */ +BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); +BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64); +BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block, + generation, 64); +BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64); +BTRFS_SETGET_STACK_FUNCS(super_sys_array_size, + struct btrfs_super_block, sys_chunk_array_size, 32); +BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation, + struct btrfs_super_block, chunk_root_generation, 64); +BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block, + root_level, 8); +BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block, + chunk_root, 64); +BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block, + chunk_root_level, 8); +BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block, log_root, 64); +BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block, + log_root_level, 8); +BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block, + total_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block, + bytes_used, 64); +BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block, + sectorsize, 32); +BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block, + nodesize, 32); +BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block, + stripesize, 32); +BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, + root_dir_objectid, 64); +BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block, + num_devices, 64); +BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block, + compat_flags, 64); +BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block, + compat_ro_flags, 64); +BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block, + incompat_flags, 64); +BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, + csum_type, 16); +BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, + cache_generation, 64); +BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64); +BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block, + uuid_tree_generation, 64); +BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block, + nr_global_roots, 64); + +/* struct btrfs_file_extent_item */ +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item, + type, 8); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, + struct btrfs_file_extent_item, disk_bytenr, 64); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, + struct btrfs_file_extent_item, offset, 64); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, + struct btrfs_file_extent_item, generation, 64); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, + struct btrfs_file_extent_item, num_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, + struct btrfs_file_extent_item, ram_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes, + struct btrfs_file_extent_item, disk_num_bytes, 64); +BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, + struct btrfs_file_extent_item, compression, 8); + +BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8); +BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item, + disk_bytenr, 64); +BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item, + generation, 64); +BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item, + disk_num_bytes, 64); +BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item, + offset, 64); +BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item, + num_bytes, 64); +BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item, + ram_bytes, 64); +BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item, + compression, 8); +BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, + encryption, 8); +BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, + other_encoding, 16); + +/* btrfs_qgroup_status_item */ +BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item, + generation, 64); +BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item, + version, 64); +BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item, + flags, 64); +BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item, + rescan, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_generation, + struct btrfs_qgroup_status_item, generation, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_version, + struct btrfs_qgroup_status_item, version, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_flags, + struct btrfs_qgroup_status_item, flags, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_rescan, + struct btrfs_qgroup_status_item, rescan, 64); + +/* btrfs_qgroup_info_item */ +BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item, + generation, 64); +BTRFS_SETGET_FUNCS(qgroup_info_rfer, struct btrfs_qgroup_info_item, rfer, 64); +BTRFS_SETGET_FUNCS(qgroup_info_rfer_cmpr, struct btrfs_qgroup_info_item, + rfer_cmpr, 64); +BTRFS_SETGET_FUNCS(qgroup_info_excl, struct btrfs_qgroup_info_item, excl, 64); +BTRFS_SETGET_FUNCS(qgroup_info_excl_cmpr, struct btrfs_qgroup_info_item, + excl_cmpr, 64); + +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation, + struct btrfs_qgroup_info_item, generation, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer, struct btrfs_qgroup_info_item, + rfer, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer_cmpr, + struct btrfs_qgroup_info_item, rfer_cmpr, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl, struct btrfs_qgroup_info_item, + excl, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl_cmpr, + struct btrfs_qgroup_info_item, excl_cmpr, 64); + +/* btrfs_qgroup_limit_item */ +BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item, flags, 64); +BTRFS_SETGET_FUNCS(qgroup_limit_max_rfer, struct btrfs_qgroup_limit_item, + max_rfer, 64); +BTRFS_SETGET_FUNCS(qgroup_limit_max_excl, struct btrfs_qgroup_limit_item, + max_excl, 64); +BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item, + rsv_rfer, 64); +BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item, + rsv_excl, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags, + struct btrfs_qgroup_limit_item, flags, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_rfer, + struct btrfs_qgroup_limit_item, max_rfer, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_excl, + struct btrfs_qgroup_limit_item, max_excl, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_rfer, + struct btrfs_qgroup_limit_item, rsv_rfer, 64); +BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_excl, + struct btrfs_qgroup_limit_item, rsv_excl, 64); + +/* btrfs_dev_replace_item */ +BTRFS_SETGET_FUNCS(dev_replace_src_devid, + struct btrfs_dev_replace_item, src_devid, 64); +BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode, + struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode, + 64); +BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item, + replace_state, 64); +BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item, + time_started, 64); +BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item, + time_stopped, 64); +BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item, + num_write_errors, 64); +BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors, + struct btrfs_dev_replace_item, num_uncorrectable_read_errors, + 64); +BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item, + cursor_left, 64); +BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item, + cursor_right, 64); + +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid, + struct btrfs_dev_replace_item, src_devid, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode, + struct btrfs_dev_replace_item, + cont_reading_from_srcdev_mode, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state, + struct btrfs_dev_replace_item, replace_state, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started, + struct btrfs_dev_replace_item, time_started, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped, + struct btrfs_dev_replace_item, time_stopped, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors, + struct btrfs_dev_replace_item, num_write_errors, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors, + struct btrfs_dev_replace_item, + num_uncorrectable_read_errors, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left, + struct btrfs_dev_replace_item, cursor_left, 64); +BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right, + struct btrfs_dev_replace_item, cursor_right, 64); + +/* btrfs_verity_descriptor_item */ +BTRFS_SETGET_FUNCS(verity_descriptor_encryption, struct btrfs_verity_descriptor_item, + encryption, 8); +BTRFS_SETGET_FUNCS(verity_descriptor_size, struct btrfs_verity_descriptor_item, + size, 64); +BTRFS_SETGET_STACK_FUNCS(stack_verity_descriptor_encryption, + struct btrfs_verity_descriptor_item, encryption, 8); +BTRFS_SETGET_STACK_FUNCS(stack_verity_descriptor_size, + struct btrfs_verity_descriptor_item, size, 64); + +/* Cast into the data area of the leaf. */ +#define btrfs_item_ptr(leaf, slot, type) \ + ((type *)(btrfs_item_nr_offset(leaf, 0) + btrfs_item_offset(leaf, slot))) + +#define btrfs_item_ptr_offset(leaf, slot) \ + ((unsigned long)(btrfs_item_nr_offset(leaf, 0) + btrfs_item_offset(leaf, slot))) + +#endif diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index 1ac6ee3f..7a17dbe0 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -27,6 +27,7 @@ #include "kernel-shared/extent_io.h" #include "kernel-shared/uapi/btrfs.h" #include "kernel-shared/uapi/btrfs_tree.h" +#include "accessors.h" struct btrfs_root; struct btrfs_trans_handle; @@ -638,254 +639,16 @@ static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info) */ #define BTRFS_STRING_ITEM_KEY 253 -#define read_eb_member(eb, ptr, type, member, result) ( \ - read_extent_buffer(eb, (char *)(result), \ - ((unsigned long)(ptr)) + \ - offsetof(type, member), \ - sizeof(((type *)0)->member))) - -#define write_eb_member(eb, ptr, type, member, result) ( \ - write_extent_buffer(eb, (char *)(result), \ - ((unsigned long)(ptr)) + \ - offsetof(type, member), \ - sizeof(((type *)0)->member))) - -#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(const struct extent_buffer *eb) \ -{ \ - const struct btrfs_header *h = (struct btrfs_header *)eb->data; \ - return le##bits##_to_cpu(h->member); \ -} \ -static inline void btrfs_set_##name(struct extent_buffer *eb, \ - u##bits val) \ -{ \ - struct btrfs_header *h = (struct btrfs_header *)eb->data; \ - h->member = cpu_to_le##bits(val); \ -} - -#define BTRFS_SETGET_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(const struct extent_buffer *eb, \ - const type *s) \ -{ \ - unsigned long offset = (unsigned long)s; \ - const type *p = (type *) (eb->data + offset); \ - return get_unaligned_le##bits(&p->member); \ -} \ -static inline void btrfs_set_##name(struct extent_buffer *eb, \ - type *s, u##bits val) \ -{ \ - unsigned long offset = (unsigned long)s; \ - type *p = (type *) (eb->data + offset); \ - put_unaligned_le##bits(val, &p->member); \ -} - -#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(const type *s) \ -{ \ - return le##bits##_to_cpu(s->member); \ -} \ -static inline void btrfs_set_##name(type *s, u##bits val) \ -{ \ - s->member = cpu_to_le##bits(val); \ -} - -BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64); -BTRFS_SETGET_FUNCS(device_total_bytes, struct btrfs_dev_item, total_bytes, 64); -BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64); -BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32); -BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32); -BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item, - start_offset, 64); -BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); -BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); -BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32); -BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8); -BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8); -BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item, - total_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item, - bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item, - io_align, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item, - io_width, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item, - sector_size, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item, - dev_group, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item, - seek_speed, 8); -BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item, - bandwidth, 8); -BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item, - generation, 64); - -static inline char *btrfs_device_uuid(struct btrfs_dev_item *d) -{ - return (char *)d + offsetof(struct btrfs_dev_item, uuid); -} - -static inline char *btrfs_device_fsid(struct btrfs_dev_item *d) -{ - return (char *)d + offsetof(struct btrfs_dev_item, fsid); -} - -BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64); -BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64); -BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64); -BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32); -BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32); -BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32); -BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64); -BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16); -BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16); -BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64); -BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64); - -static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s) -{ - return (char *)s + offsetof(struct btrfs_stripe, dev_uuid); -} - -BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk, - stripe_len, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk, - io_align, 32); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk, - io_width, 32); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk, - sector_size, 32); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk, - num_stripes, 16); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk, - sub_stripes, 16); -BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64); - -static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c, - int nr) -{ - unsigned long offset = (unsigned long)c; - offset += offsetof(struct btrfs_chunk, stripe); - offset += nr * sizeof(struct btrfs_stripe); - return (struct btrfs_stripe *)offset; -} - -static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr) -{ - return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr)); -} - -static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb, - struct btrfs_chunk *c, int nr) -{ - return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr)); -} - -static inline void btrfs_set_stripe_offset_nr(struct extent_buffer *eb, - struct btrfs_chunk *c, int nr, - u64 val) -{ - btrfs_set_stripe_offset(eb, btrfs_stripe_nr(c, nr), val); -} - -static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb, - struct btrfs_chunk *c, int nr) +static inline unsigned long btrfs_header_fsid(void) { - return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr)); + return offsetof(struct btrfs_header, fsid); } -static inline void btrfs_set_stripe_devid_nr(struct extent_buffer *eb, - struct btrfs_chunk *c, int nr, - u64 val) +static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb) { - btrfs_set_stripe_devid(eb, btrfs_stripe_nr(c, nr), val); + return offsetof(struct btrfs_header, chunk_tree_uuid); } -/* struct btrfs_block_group_item */ -BTRFS_SETGET_STACK_FUNCS(stack_block_group_used, struct btrfs_block_group_item, - used, 64); -BTRFS_SETGET_FUNCS(block_group_used, struct btrfs_block_group_item, - used, 64); -BTRFS_SETGET_STACK_FUNCS(stack_block_group_chunk_objectid, - struct btrfs_block_group_item, chunk_objectid, 64); - -BTRFS_SETGET_FUNCS(block_group_chunk_objectid, - struct btrfs_block_group_item, chunk_objectid, 64); -BTRFS_SETGET_FUNCS(block_group_flags, - struct btrfs_block_group_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(stack_block_group_flags, - struct btrfs_block_group_item, flags, 64); - -/* extent tree v2 uses chunk_objectid for the global tree id. */ -BTRFS_SETGET_STACK_FUNCS(stack_block_group_global_tree_id, - struct btrfs_block_group_item, chunk_objectid, 64); -BTRFS_SETGET_FUNCS(block_group_global_tree_id, struct btrfs_block_group_item, - chunk_objectid, 64); - -/* struct btrfs_free_space_info */ -BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info, - extent_count, 32); -BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32); - -/* struct btrfs_inode_ref */ -BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); -BTRFS_SETGET_STACK_FUNCS(stack_inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); -BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64); - -/* struct btrfs_inode_extref */ -BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref, - parent_objectid, 64); -BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref, - name_len, 16); -BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64); - -/* struct btrfs_inode_item */ -BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64); -BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64); -BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64); -BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64); -BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64); -BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64); -BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32); -BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32); -BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); -BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); -BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); -BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, - struct btrfs_inode_item, generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, - struct btrfs_inode_item, sequence, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, - struct btrfs_inode_item, transid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_size, - struct btrfs_inode_item, size, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, - struct btrfs_inode_item, nbytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, - struct btrfs_inode_item, block_group, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, - struct btrfs_inode_item, nlink, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, - struct btrfs_inode_item, uid, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, - struct btrfs_inode_item, gid, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, - struct btrfs_inode_item, mode, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, - struct btrfs_inode_item, rdev, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, - struct btrfs_inode_item, flags, 64); - static inline struct btrfs_timespec * btrfs_inode_atime(struct btrfs_inode_item *inode_item) { @@ -918,399 +681,6 @@ btrfs_inode_otime(struct btrfs_inode_item *inode_item) return (struct btrfs_timespec *)ptr; } -BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); -BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); -BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, - sec, 64); -BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, - nsec, 32); - -/* struct btrfs_dev_extent */ -BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, - chunk_tree, 64); -BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent, - chunk_objectid, 64); -BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent, - chunk_offset, 64); -BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_dev_extent_length, struct btrfs_dev_extent, - length, 64); - -static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev) -{ - unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid); - return (u8 *)((unsigned long)dev + ptr); -} - - -/* struct btrfs_extent_item */ -BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64); -BTRFS_SETGET_STACK_FUNCS(stack_extent_refs, struct btrfs_extent_item, refs, 64); -BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item, - generation, 64); -BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(stack_extent_flags, struct btrfs_extent_item, flags, 64); - -BTRFS_SETGET_FUNCS(extent_refs_v0, struct btrfs_extent_item_v0, refs, 32); - -BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8); - -static inline void btrfs_tree_block_key(struct extent_buffer *eb, - struct btrfs_tree_block_info *item, - struct btrfs_disk_key *key) -{ - read_eb_member(eb, item, struct btrfs_tree_block_info, key, key); -} - -static inline void btrfs_set_tree_block_key(struct extent_buffer *eb, - struct btrfs_tree_block_info *item, - struct btrfs_disk_key *key) -{ - write_eb_member(eb, item, struct btrfs_tree_block_info, key, key); -} - -BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref, - root, 64); -BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref, - objectid, 64); -BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref, - offset, 64); -BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref, - count, 32); - -BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref, - count, 32); - -BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref, - type, 8); -BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref, - offset, 64); -BTRFS_SETGET_STACK_FUNCS(stack_extent_inline_ref_type, - struct btrfs_extent_inline_ref, type, 8); -BTRFS_SETGET_STACK_FUNCS(stack_extent_inline_ref_offset, - struct btrfs_extent_inline_ref, offset, 64); - -static inline u32 btrfs_extent_inline_ref_size(int type) -{ - if (type == BTRFS_TREE_BLOCK_REF_KEY || - type == BTRFS_SHARED_BLOCK_REF_KEY) - return sizeof(struct btrfs_extent_inline_ref); - if (type == BTRFS_SHARED_DATA_REF_KEY) - return sizeof(struct btrfs_shared_data_ref) + - sizeof(struct btrfs_extent_inline_ref); - if (type == BTRFS_EXTENT_DATA_REF_KEY) - return sizeof(struct btrfs_extent_data_ref) + - offsetof(struct btrfs_extent_inline_ref, offset); - BUG(); - return 0; -} - -/* struct btrfs_node */ -BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); -BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); - -static inline unsigned long btrfs_node_key_ptr_offset(const struct extent_buffer *eb, int nr) -{ - return offsetof(struct btrfs_node, ptrs) + - sizeof(struct btrfs_key_ptr) * nr; -} - -static inline struct btrfs_key_ptr *btrfs_node_key_ptr(const struct extent_buffer *eb, int nr) -{ - return (struct btrfs_key_ptr *)btrfs_node_key_ptr_offset(eb, nr); -} - -static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr) -{ - return btrfs_key_blockptr(eb, btrfs_node_key_ptr(eb, nr)); -} - -static inline void btrfs_set_node_blockptr(struct extent_buffer *eb, - int nr, u64 val) -{ - btrfs_set_key_blockptr(eb, btrfs_node_key_ptr(eb, nr), val); -} - -static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr) -{ - return btrfs_key_generation(eb, btrfs_node_key_ptr(eb, nr)); -} - -static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb, - int nr, u64 val) -{ - btrfs_set_key_generation(eb, btrfs_node_key_ptr(eb, nr), val); -} - -static inline void btrfs_node_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - read_eb_member(eb, btrfs_node_key_ptr(eb, nr), struct btrfs_key_ptr, - key, disk_key); -} - -static inline void btrfs_set_node_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - write_eb_member(eb, btrfs_node_key_ptr(eb, nr), struct btrfs_key_ptr, - key, disk_key); -} - -/* struct btrfs_item */ -BTRFS_SETGET_FUNCS(raw_item_offset, struct btrfs_item, offset, 32); -BTRFS_SETGET_FUNCS(raw_item_size, struct btrfs_item, size, 32); - -static inline unsigned long btrfs_item_nr_offset(const struct extent_buffer *eb, int nr) -{ - return offsetof(struct btrfs_leaf, items) + - sizeof(struct btrfs_item) * nr; -} - -static inline struct btrfs_item *btrfs_item_nr(const struct extent_buffer *eb, int nr) -{ - return (struct btrfs_item *)btrfs_item_nr_offset(eb, nr); -} - -#define BTRFS_ITEM_SETGET_FUNCS(member) \ -static inline u32 btrfs_item_##member(const struct extent_buffer *eb, int slot) \ -{ \ - return btrfs_raw_item_##member(eb, btrfs_item_nr(eb, slot)); \ -} \ -static inline void btrfs_set_item_##member(struct extent_buffer *eb, \ - int slot, u32 val) \ -{ \ - btrfs_set_raw_item_##member(eb, btrfs_item_nr(eb, slot), val); \ -} - -BTRFS_ITEM_SETGET_FUNCS(size) -BTRFS_ITEM_SETGET_FUNCS(offset) - -static inline u32 btrfs_item_data_end(struct extent_buffer *eb, int nr) -{ - return btrfs_item_offset(eb, nr) + btrfs_item_size(eb, nr); -} - -static inline void btrfs_item_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - struct btrfs_item *item = btrfs_item_nr(eb, nr); - read_eb_member(eb, item, struct btrfs_item, key, disk_key); -} - -static inline void btrfs_set_item_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - struct btrfs_item *item = btrfs_item_nr(eb, nr); - write_eb_member(eb, item, struct btrfs_item, key, disk_key); -} - -BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64); - -/* - * struct btrfs_root_ref - */ -BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64); -BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64); -BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16); - -BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64); -BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16); - -/* struct btrfs_dir_item */ -BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16); -BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8); -BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16); -BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item, data_len, 16); -BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8); -BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, name_len, 16); -BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, transid, 64); - -static inline void btrfs_dir_item_key(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_disk_key *key) -{ - read_eb_member(eb, item, struct btrfs_dir_item, location, key); -} - -static inline void btrfs_set_dir_item_key(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_disk_key *key) -{ - write_eb_member(eb, item, struct btrfs_dir_item, location, key); -} - -/* struct btrfs_free_space_header */ -BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header, - num_entries, 64); -BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header, - num_bitmaps, 64); -BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header, - generation, 64); - -static inline void btrfs_free_space_key(struct extent_buffer *eb, - struct btrfs_free_space_header *h, - struct btrfs_disk_key *key) -{ - read_eb_member(eb, h, struct btrfs_free_space_header, location, key); -} - -static inline void btrfs_set_free_space_key(struct extent_buffer *eb, - struct btrfs_free_space_header *h, - struct btrfs_disk_key *key) -{ - write_eb_member(eb, h, struct btrfs_free_space_header, location, key); -} - -/* struct btrfs_disk_key */ -BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, - objectid, 64); -BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64); -BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8); - -static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu, - struct btrfs_disk_key *disk) -{ - cpu->offset = le64_to_cpu(disk->offset); - cpu->type = disk->type; - cpu->objectid = le64_to_cpu(disk->objectid); -} - -static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk, - const struct btrfs_key *cpu) -{ - disk->offset = cpu_to_le64(cpu->offset); - disk->type = cpu->type; - disk->objectid = cpu_to_le64(cpu->objectid); -} - -static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb, - struct btrfs_key *key, int nr) -{ - struct btrfs_disk_key disk_key; - btrfs_node_key(eb, &disk_key, nr); - btrfs_disk_key_to_cpu(key, &disk_key); -} - -static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb, - struct btrfs_key *key, int nr) -{ - struct btrfs_disk_key disk_key; - btrfs_item_key(eb, &disk_key, nr); - btrfs_disk_key_to_cpu(key, &disk_key); -} - -static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_key *key) -{ - struct btrfs_disk_key disk_key; - btrfs_dir_item_key(eb, item, &disk_key); - btrfs_disk_key_to_cpu(key, &disk_key); -} - -/* struct btrfs_header */ -BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64); -BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, - generation, 64); -BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); -BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); -BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64); -BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); -BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header, nritems, - 32); -BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64); -BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header, - generation, 64); - -static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag) -{ - return (btrfs_header_flags(eb) & flag) == flag; -} - -static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag) -{ - u64 flags = btrfs_header_flags(eb); - btrfs_set_header_flags(eb, flags | flag); - return (flags & flag) == flag; -} - -static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag) -{ - u64 flags = btrfs_header_flags(eb); - btrfs_set_header_flags(eb, flags & ~flag); - return (flags & flag) == flag; -} - -static inline int btrfs_header_backref_rev(struct extent_buffer *eb) -{ - u64 flags = btrfs_header_flags(eb); - return flags >> BTRFS_BACKREF_REV_SHIFT; -} - -static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb, - int rev) -{ - u64 flags = btrfs_header_flags(eb); - flags &= ~BTRFS_BACKREF_REV_MASK; - flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT; - btrfs_set_header_flags(eb, flags); -} - -static inline unsigned long btrfs_header_fsid(void) -{ - return offsetof(struct btrfs_header, fsid); -} - -static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb) -{ - return offsetof(struct btrfs_header, chunk_tree_uuid); -} - -static inline u8 *btrfs_header_csum(struct extent_buffer *eb) -{ - unsigned long ptr = offsetof(struct btrfs_header, csum); - return (u8 *)ptr; -} - -static inline int btrfs_is_leaf(struct extent_buffer *eb) -{ - return (btrfs_header_level(eb) == 0); -} - -/* struct btrfs_root_item */ -BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item, - generation, 64); -BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32); -BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64); -BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8); - -BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8); -BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64); -BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32); -BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); -BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, - last_snapshot, 64); -BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item, - generation_v2, 64); -BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item, - ctransid, 64); -BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item, - otransid, 64); -BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item, - stransid, 64); -BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item, - rtransid, 64); - static inline struct btrfs_timespec* btrfs_root_ctime( struct btrfs_root_item *root_item) { @@ -1343,115 +713,12 @@ static inline struct btrfs_timespec* btrfs_root_rtime( return (struct btrfs_timespec *)ptr; } -/* struct btrfs_root_backup */ -BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, - tree_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup, - tree_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup, - tree_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup, - chunk_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup, - chunk_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup, - chunk_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup, - extent_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup, - extent_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup, - extent_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup, - fs_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup, - fs_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup, - fs_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup, - dev_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup, - dev_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup, - dev_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup, - csum_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup, - csum_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup, - csum_root_level, 8); -BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup, - total_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, - bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, - num_devices, 64); - -/* struct btrfs_super_block */ - -BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64); -BTRFS_SETGET_STACK_FUNCS(super_sys_array_size, - struct btrfs_super_block, sys_chunk_array_size, 32); -BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation, - struct btrfs_super_block, chunk_root_generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block, - root_level, 8); -BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block, - chunk_root, 64); -BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block, - chunk_root_level, 8); -BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block, - log_root, 64); -BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block, - log_root_level, 8); -BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block, - total_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block, - bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block, - sectorsize, 32); -BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block, - nodesize, 32); -BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block, - stripesize, 32); -BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, - root_dir_objectid, 64); -BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block, - num_devices, 64); -BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block, - compat_flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block, - compat_ro_flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block, - incompat_flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, - csum_type, 16); -BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, - cache_generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block, - uuid_tree_generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64); -BTRFS_SETGET_STACK_FUNCS(super_nr_global_roots, struct btrfs_super_block, - nr_global_roots, 64); - -static inline unsigned long btrfs_leaf_data(struct extent_buffer *l) +static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev) { - return offsetof(struct btrfs_leaf, items); + unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid); + return (u8 *)((unsigned long)dev + ptr); } -/* struct btrfs_file_extent_item */ -BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_type, struct btrfs_file_extent_item, type, 8); - static inline unsigned long btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e) { @@ -1465,132 +732,6 @@ static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize) return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize; } -BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item, - disk_bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, struct btrfs_file_extent_item, - disk_bytenr, 64); -BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, struct btrfs_file_extent_item, - generation, 64); -BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item, - disk_num_bytes, 64); -BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item, - offset, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, struct btrfs_file_extent_item, - offset, 64); -BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item, - num_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, struct btrfs_file_extent_item, - num_bytes, 64); -BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item, - ram_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_ram_bytes, struct btrfs_file_extent_item, - ram_bytes, 64); -BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item, - compression, 8); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, struct btrfs_file_extent_item, - compression, 8); -BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, - encryption, 8); -BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, - other_encoding, 16); - -/* btrfs_qgroup_status_item */ -BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item, - version, 64); -BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item, - generation, 64); -BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item, - flags, 64); -BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item, - rescan, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_version, - struct btrfs_qgroup_status_item, version, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_generation, - struct btrfs_qgroup_status_item, generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_flags, - struct btrfs_qgroup_status_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_status_rescan, - struct btrfs_qgroup_status_item, rescan, 64); - -/* btrfs_qgroup_info_item */ -BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item, - generation, 64); -BTRFS_SETGET_FUNCS(qgroup_info_rfer, struct btrfs_qgroup_info_item, - rfer, 64); -BTRFS_SETGET_FUNCS(qgroup_info_rfer_cmpr, - struct btrfs_qgroup_info_item, rfer_cmpr, 64); -BTRFS_SETGET_FUNCS(qgroup_info_excl, struct btrfs_qgroup_info_item, - excl, 64); -BTRFS_SETGET_FUNCS(qgroup_info_excl_cmpr, - struct btrfs_qgroup_info_item, excl_cmpr, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation, - struct btrfs_qgroup_info_item, generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer, - struct btrfs_qgroup_info_item, rfer, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer_cmpr, - struct btrfs_qgroup_info_item, rfer_cmpr, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl, - struct btrfs_qgroup_info_item, excl, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl_cmpr, - struct btrfs_qgroup_info_item, excl_cmpr, 64); - -/* btrfs_qgroup_limit_item */ -BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item, - flags, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_max_rfer, struct btrfs_qgroup_limit_item, - max_rfer, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_max_excl, struct btrfs_qgroup_limit_item, - max_excl, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item, - rsv_rfer, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item, - rsv_excl, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_flags, - struct btrfs_qgroup_limit_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_rfer, - struct btrfs_qgroup_limit_item, max_rfer, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_max_excl, - struct btrfs_qgroup_limit_item, max_excl, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_rfer, - struct btrfs_qgroup_limit_item, rsv_rfer, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_limit_rsv_excl, - struct btrfs_qgroup_limit_item, rsv_excl, 64); - -/* btrfs_balance_item */ -BTRFS_SETGET_FUNCS(balance_item_flags, struct btrfs_balance_item, flags, 64); - -static inline struct btrfs_disk_balance_args* btrfs_balance_item_data( - struct extent_buffer *eb, struct btrfs_balance_item *bi) -{ - unsigned long offset = (unsigned long)bi; - struct btrfs_balance_item *p; - p = (struct btrfs_balance_item *)(eb->data + offset); - return &p->data; -} - -static inline struct btrfs_disk_balance_args* btrfs_balance_item_meta( - struct extent_buffer *eb, struct btrfs_balance_item *bi) -{ - unsigned long offset = (unsigned long)bi; - struct btrfs_balance_item *p; - p = (struct btrfs_balance_item *)(eb->data + offset); - return &p->meta; -} - -static inline struct btrfs_disk_balance_args* btrfs_balance_item_sys( - struct extent_buffer *eb, struct btrfs_balance_item *bi) -{ - unsigned long offset = (unsigned long)bi; - struct btrfs_balance_item *p; - p = (struct btrfs_balance_item *)(eb->data + offset); - return &p->sys; -} - static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, const struct btrfs_dev_stats_item *ptr, int index) @@ -1599,7 +740,7 @@ static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, read_extent_buffer(eb, &val, offsetof(struct btrfs_dev_stats_item, values) + - ((unsigned long)ptr) + (index * sizeof(u64)), + ((unsigned long)ptr) + (index * sizeof(u64)), sizeof(val)); return val; } @@ -1661,15 +802,6 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag) return !!(btrfs_super_compat_ro_flags(disk_super) & flag); } -/* helper function to cast into the data area of the leaf. */ -#define btrfs_item_ptr(leaf, slot, type) \ - ((type *)(btrfs_leaf_data(leaf) + \ - btrfs_item_offset(leaf, slot))) - -#define btrfs_item_ptr_offset(leaf, slot) \ - ((unsigned long)(btrfs_leaf_data(leaf) + \ - btrfs_item_offset(leaf, slot))) - u64 btrfs_name_hash(const char *name, int len); u64 btrfs_extref_hash(u64 parent_objectid, const char *name, int len); diff --git a/kernel-shared/dir-item.c b/kernel-shared/dir-item.c index 27dfb362..ef49441c 100644 --- a/kernel-shared/dir-item.c +++ b/kernel-shared/dir-item.c @@ -89,7 +89,7 @@ int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, &location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); - btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); + btrfs_set_dir_flags(leaf, dir_item, BTRFS_FT_XATTR); btrfs_set_dir_name_len(leaf, dir_item, name_len); btrfs_set_dir_data_len(leaf, dir_item, data_len); name_ptr = (unsigned long)(dir_item + 1); @@ -141,7 +141,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); - btrfs_set_dir_type(leaf, dir_item, type); + btrfs_set_dir_flags(leaf, dir_item, type); btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_name_len(leaf, dir_item, name_len); name_ptr = (unsigned long)(dir_item + 1); @@ -170,7 +170,7 @@ insert: leaf = path->nodes[0]; btrfs_cpu_key_to_disk(&disk_key, location); btrfs_set_dir_item_key(leaf, dir_item, &disk_key); - btrfs_set_dir_type(leaf, dir_item, type); + btrfs_set_dir_flags(leaf, dir_item, type); btrfs_set_dir_data_len(leaf, dir_item, 0); btrfs_set_dir_name_len(leaf, dir_item, name_len); name_ptr = (unsigned long)(dir_item + 1); @@ -292,7 +292,7 @@ static int verify_dir_item(struct btrfs_root *root, struct btrfs_dir_item *dir_item) { u16 namelen = BTRFS_NAME_LEN; - u8 type = btrfs_dir_type(leaf, dir_item); + u8 type = btrfs_dir_ftype(leaf, dir_item); if (type == BTRFS_FT_XATTR) namelen = XATTR_NAME_MAX; diff --git a/kernel-shared/inode.c b/kernel-shared/inode.c index d1786c7a..1430cf33 100644 --- a/kernel-shared/inode.c +++ b/kernel-shared/inode.c @@ -548,7 +548,7 @@ int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root, */ btrfs_dir_item_key_to_cpu(path->nodes[0], dir_item, &found_key); ret_ino = found_key.objectid; - if (btrfs_dir_type(path->nodes[0], dir_item) != BTRFS_FT_DIR) + if (btrfs_dir_ftype(path->nodes[0], dir_item) != BTRFS_FT_DIR) ret = -EEXIST; goto out; } diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c index 37a1f74c..b5343462 100644 --- a/kernel-shared/print-tree.c +++ b/kernel-shared/print-tree.c @@ -27,11 +27,12 @@ #include "kernel-shared/volumes.h" #include "kernel-shared/compression.h" #include "common/utils.h" +#include "accessors.h" static void print_dir_item_type(struct extent_buffer *eb, struct btrfs_dir_item *di) { - u8 type = btrfs_dir_type(eb, di); + u8 type = btrfs_dir_ftype(eb, di); static const char* dir_item_str[] = { [BTRFS_FT_REG_FILE] = "FILE", [BTRFS_FT_DIR] = "DIR", @@ -959,15 +960,20 @@ static void print_disk_balance_args(struct btrfs_disk_balance_args *ba) static void print_balance_item(struct extent_buffer *eb, struct btrfs_balance_item *bi) { + struct btrfs_disk_balance_args ba; + printf("\t\tbalance status flags %llu\n", - btrfs_balance_item_flags(eb, bi)); + btrfs_balance_flags(eb, bi)); printf("\t\tDATA\n"); - print_disk_balance_args(btrfs_balance_item_data(eb, bi)); + btrfs_balance_data(eb, bi, &ba); + print_disk_balance_args(&ba); printf("\t\tMETADATA\n"); - print_disk_balance_args(btrfs_balance_item_meta(eb, bi)); + btrfs_balance_meta(eb, bi, &ba); + print_disk_balance_args(&ba); printf("\t\tSYSTEM\n"); - print_disk_balance_args(btrfs_balance_item_sys(eb, bi)); + btrfs_balance_sys(eb, bi, &ba); + print_disk_balance_args(&ba); } static void print_dev_stats(struct extent_buffer *eb, diff --git a/mkfs/common.c b/mkfs/common.c index 40d07deb..3c3e6bec 100644 --- a/mkfs/common.c +++ b/mkfs/common.c @@ -39,6 +39,7 @@ #include "common/open-utils.h" #include "mkfs/common.h" #include "kernel-shared/uapi/btrfs.h" +#include "kernel-shared/accessors.h" static u64 reference_root_table[] = { [MKFS_ROOT_TREE] = BTRFS_ROOT_TREE_OBJECTID, From patchwork Wed Apr 19 21:17:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217387 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DE4C4C6FD18 for ; Wed, 19 Apr 2023 21:17:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230476AbjDSVRj (ORCPT ); Wed, 19 Apr 2023 17:17:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39866 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229960AbjDSVRg (ORCPT ); Wed, 19 Apr 2023 17:17:36 -0400 Received: from mail-qv1-xf2e.google.com (mail-qv1-xf2e.google.com [IPv6:2607:f8b0:4864:20::f2e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0B6744BE for ; Wed, 19 Apr 2023 14:17:33 -0700 (PDT) Received: by mail-qv1-xf2e.google.com with SMTP id l17so994241qvq.10 for ; Wed, 19 Apr 2023 14:17:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939053; x=1684531053; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=4+U+0WSawAMs1teeq4bz8GVRzzfl1AEW3Q7VonhcEO4=; b=Yc+g0HN/jl/924trUO0BovFZfjKIR9T4mLSjWgWPkgTTLSoWos1lRyH+zBgiC6tC6B bRa0ZHlNnOHWfFkI3/K3dZ8a+MEfEFAgZ+4T0PHOwZooUn9G6w7iAamAS/DRQ5s1/msl Sy01xDYivJuXBkc2sUGDBbZ8ToK+wblaUwoIZZ+Gix2J10Wr+oITE/SPJHd/7f+RYaHj 5BWF6pbhGBg6eMKe/x1+vQkVXnkkPvEjwhOVVoE3fBnLIlArxhP9M8sw7heHFG2GJMzG Lax7dzw6H04nT8ssSmemRORanwBTeMREIMlbOkLuWVuTOtadxwNCCiU5tDPqz3CRJikx uKkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939053; x=1684531053; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4+U+0WSawAMs1teeq4bz8GVRzzfl1AEW3Q7VonhcEO4=; b=UlO6tfHHS3hqxeaNGvuyDjIzTthmvQ00syB4SHTwpB8snx8nK7eg3ntg1LSqaWRS+z pnTrM0tdL/wx7OrFQPV/CjeLeZXk+soZCZuoxNQVJph++uBupr+71vDK6Lt6Ug36/S7T rIgycM6mEdjTOAjTOr02dbR/MetdHj59fZ/OOdsEz1l01dabUrOClpT51MSAhtEHWu/Q ddqzISXnOvoJd9c3AnwJAZkVPchtuHAXAXYzB5QbPADwlVAK9MU99fc5gYriFTaMcaKJ OSll4eNMOO1NM9FkgMniSHRmYtItumL4tUlOeEGWjTrboeddTCmivr/stUvsE7pOAd+0 zEcA== X-Gm-Message-State: AAQBX9etJ8yE1Fevskc8tZ+Wbz+ukX3gWYqlpDKyX6X+OUpis4cvaTw9 KfCE2sRRnmYFzUURUf+81h/pAktjO+/K122BDpOkWA== X-Google-Smtp-Source: AKy350ZpMVzjih+DivzqfDmPVesvqUXkdCpmjAgmTTGKyW5bFXUE3WSd0Rk9iXgywyUH+Lc8i9VZaQ== X-Received: by 2002:a05:6214:21e7:b0:5ef:653e:16a5 with SMTP id p7-20020a05621421e700b005ef653e16a5mr21683033qvj.39.1681939052681; Wed, 19 Apr 2023 14:17:32 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id dl15-20020ad44e0f000000b005ef72557902sm2528109qvb.58.2023.04.19.14.17.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:32 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 6/8] btrfs-progs: sync file-item.h into progs Date: Wed, 19 Apr 2023 17:17:17 -0400 Message-Id: <371fd51f9b97e565b4d25ae50897d05da740b52d.1681938911.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org This patch syncs file-item.h into btrfs-progs. This carries with it an API change for btrfs_del_csums, which takes a root argument in the kernel, so all callsites have been updated accordingly. I didn't sync file-item.c because it carries with it a bunch of bio related helpers which are difficult to adapt to the kernel. Additionally there's a few helpers in the local copy of file-item.c that aren't in the kernel that are required for different tools. This requires more cleanups in both the kernel and progs in order to sync file-item.c, so for now just do file-item.h in order to pull things out of ctree.h. Signed-off-by: Josef Bacik --- btrfs-corrupt-block.c | 3 +- check/clear-cache.c | 7 ++- check/main.c | 1 + check/mode-common.c | 6 ++- check/mode-lowmem.c | 1 + cmds/inspect-tree-stats.c | 1 + cmds/restore.c | 1 + convert/main.c | 1 + convert/source-ext2.c | 1 + image/main.c | 1 + kernel-shared/ctree.h | 45 ------------------- kernel-shared/extent-tree.c | 7 ++- kernel-shared/file-item.c | 13 +++--- kernel-shared/file-item.h | 89 +++++++++++++++++++++++++++++++++++++ kernel-shared/file.c | 1 + kernel-shared/print-tree.c | 1 + mkfs/rootdir.c | 1 + 17 files changed, 124 insertions(+), 56 deletions(-) create mode 100644 kernel-shared/file-item.h diff --git a/btrfs-corrupt-block.c b/btrfs-corrupt-block.c index 91e5c7dd..35933854 100644 --- a/btrfs-corrupt-block.c +++ b/btrfs-corrupt-block.c @@ -28,6 +28,7 @@ #include "kernel-shared/disk-io.h" #include "kernel-shared/transaction.h" #include "kernel-shared/extent_io.h" +#include "kernel-shared/file-item.h" #include "common/utils.h" #include "common/help.h" #include "common/extent-cache.h" @@ -1098,7 +1099,7 @@ static int delete_csum(struct btrfs_root *root, u64 bytenr, u64 bytes) return ret; } - ret = btrfs_del_csums(trans, bytenr, bytes); + ret = btrfs_del_csums(trans, root, bytenr, bytes); if (ret) error("error deleting csums %d", ret); btrfs_commit_transaction(trans, root); diff --git a/check/clear-cache.c b/check/clear-cache.c index ecc95167..9074557e 100644 --- a/check/clear-cache.c +++ b/check/clear-cache.c @@ -21,6 +21,7 @@ #include "kernel-shared/free-space-tree.h" #include "kernel-shared/volumes.h" #include "kernel-shared/transaction.h" +#include "kernel-shared/file-item.h" #include "common/internal.h" #include "common/messages.h" #include "check/common.h" @@ -462,6 +463,7 @@ int truncate_free_ino_items(struct btrfs_root *root) while (1) { struct extent_buffer *leaf; struct btrfs_file_extent_item *fi; + struct btrfs_root *csum_root; struct btrfs_key found_key; u8 found_type; @@ -520,7 +522,10 @@ int truncate_free_ino_items(struct btrfs_root *root) goto out; } - ret = btrfs_del_csums(trans, extent_disk_bytenr, + csum_root = btrfs_csum_root(trans->fs_info, + extent_disk_bytenr); + ret = btrfs_del_csums(trans, csum_root, + extent_disk_bytenr, extent_num_bytes); if (ret < 0) { btrfs_abort_transaction(trans, ret); diff --git a/check/main.c b/check/main.c index 5683fb1b..513fa553 100644 --- a/check/main.c +++ b/check/main.c @@ -41,6 +41,7 @@ #include "kernel-shared/free-space-tree.h" #include "kernel-shared/backref.h" #include "kernel-shared/ulist.h" +#include "kernel-shared/file-item.h" #include "common/defs.h" #include "common/extent-cache.h" #include "common/internal.h" diff --git a/check/mode-common.c b/check/mode-common.c index 412a9fd5..120165aa 100644 --- a/check/mode-common.c +++ b/check/mode-common.c @@ -28,6 +28,7 @@ #include "kernel-shared/volumes.h" #include "kernel-shared/backref.h" #include "kernel-shared/compression.h" +#include "kernel-shared/file-item.h" #include "common/internal.h" #include "common/messages.h" #include "common/utils.h" @@ -1311,7 +1312,7 @@ static int fill_csum_tree_from_one_fs_root(struct btrfs_trans_handle *trans, if (type == BTRFS_FILE_EXTENT_PREALLOC) { start += btrfs_file_extent_offset(node, fi); len = btrfs_file_extent_num_bytes(node, fi); - ret = btrfs_del_csums(trans, start, len); + ret = btrfs_del_csums(trans, csum_root, start, len); if (ret < 0) goto out; } @@ -1473,7 +1474,8 @@ static int remove_csum_for_file_extent(u64 ino, u64 offset, u64 rootid, void *ct btrfs_release_path(&path); /* Now delete the csum for the preallocated or nodatasum range */ - ret = btrfs_del_csums(trans, disk_bytenr, disk_len); + root = btrfs_csum_root(fs_info, disk_bytenr); + ret = btrfs_del_csums(trans, root, disk_bytenr, disk_len); out: btrfs_release_path(&path); return ret; diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c index 18eac047..237e0fdb 100644 --- a/check/mode-lowmem.c +++ b/check/mode-lowmem.c @@ -30,6 +30,7 @@ #include "kernel-shared/backref.h" #include "kernel-shared/compression.h" #include "kernel-shared/volumes.h" +#include "kernel-shared/file-item.h" #include "common/messages.h" #include "common/internal.h" #include "common/utils.h" diff --git a/cmds/inspect-tree-stats.c b/cmds/inspect-tree-stats.c index 4c6104c1..08be1686 100644 --- a/cmds/inspect-tree-stats.c +++ b/cmds/inspect-tree-stats.c @@ -28,6 +28,7 @@ #include "kernel-shared/ctree.h" #include "kernel-shared/disk-io.h" #include "kernel-shared/extent_io.h" +#include "kernel-shared/file-item.h" #include "common/utils.h" #include "common/help.h" #include "common/messages.h" diff --git a/cmds/restore.c b/cmds/restore.c index da5bafd1..c38cb541 100644 --- a/cmds/restore.c +++ b/cmds/restore.c @@ -44,6 +44,7 @@ #include "kernel-shared/volumes.h" #include "kernel-shared/extent_io.h" #include "kernel-shared/compression.h" +#include "kernel-shared/file-item.h" #include "common/utils.h" #include "common/help.h" #include "common/open-utils.h" diff --git a/convert/main.c b/convert/main.c index 16520914..941b5ce3 100644 --- a/convert/main.c +++ b/convert/main.c @@ -99,6 +99,7 @@ #include "kernel-shared/disk-io.h" #include "kernel-shared/volumes.h" #include "kernel-shared/transaction.h" +#include "kernel-shared/file-item.h" #include "crypto/hash.h" #include "common/defs.h" #include "common/extent-cache.h" diff --git a/convert/source-ext2.c b/convert/source-ext2.c index 02f1d68b..cfffc9e2 100644 --- a/convert/source-ext2.c +++ b/convert/source-ext2.c @@ -27,6 +27,7 @@ #include #include "kernel-lib/sizes.h" #include "kernel-shared/transaction.h" +#include "kernel-shared/file-item.h" #include "common/extent-cache.h" #include "common/messages.h" #include "convert/common.h" diff --git a/image/main.c b/image/main.c index 9144cf50..a90e6ff0 100644 --- a/image/main.c +++ b/image/main.c @@ -39,6 +39,7 @@ #include "kernel-shared/transaction.h" #include "kernel-shared/volumes.h" #include "kernel-shared/extent_io.h" +#include "kernel-shared/file-item.h" #include "crypto/crc32c.h" #include "crypto/hash.h" #include "common/internal.h" diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index 7a17dbe0..6365a1f6 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -431,14 +431,6 @@ static inline u32 BTRFS_NODEPTRS_PER_EXTENT_BUFFER(const struct extent_buffer *e return BTRFS_LEAF_DATA_SIZE(eb->fs_info) / sizeof(struct btrfs_key_ptr); } -#define BTRFS_FILE_EXTENT_INLINE_DATA_START \ - (offsetof(struct btrfs_file_extent_item, disk_bytenr)) -static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info) -{ - return BTRFS_MAX_ITEM_SIZE(info) - - BTRFS_FILE_EXTENT_INLINE_DATA_START; -} - static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_fs_info *info) { return BTRFS_MAX_ITEM_SIZE(info) - sizeof(struct btrfs_dir_item); @@ -719,19 +711,6 @@ static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev) return (u8 *)((unsigned long)dev + ptr); } -static inline unsigned long btrfs_file_extent_inline_start(struct - btrfs_file_extent_item *e) -{ - unsigned long offset = (unsigned long)e; - offset += offsetof(struct btrfs_file_extent_item, disk_bytenr); - return offset; -} - -static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize) -{ - return offsetof(struct btrfs_file_extent_item, disk_bytenr) + datasize; -} - static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, const struct btrfs_dev_stats_item *ptr, int index) @@ -745,17 +724,6 @@ static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, return val; } -/* - * this returns the number of bytes used by the item on disk, minus the - * size of any extent headers. If a file is compressed on disk, this is - * the compressed size - */ -static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, - int nr) -{ - return btrfs_item_size(eb, nr) - BTRFS_FILE_EXTENT_INLINE_DATA_START; -} - /* struct btrfs_ioctl_search_header */ static inline u64 btrfs_search_header_transid(struct btrfs_ioctl_search_header *sh) { @@ -1091,19 +1059,6 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, const char *name, int name_len, u64 ino, u64 parent_ino, u64 *index); -/* file-item.c */ -int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len); -int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 pos, u64 offset, - u64 disk_num_bytes, - u64 num_bytes); -int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 objectid, - u64 offset, const char *buffer, size_t size); -int btrfs_csum_file_block(struct btrfs_trans_handle *trans, u64 alloc_end, - u64 bytenr, char *data, size_t len); - /* uuid-tree.c, interface for mounted mounted filesystem */ int btrfs_lookup_uuid_subvol_item(int fd, const u8 *uuid, u64 *subvol_id); int btrfs_lookup_uuid_received_subvol_item(int fd, const u8 *uuid, diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c index c134ce59..5613012c 100644 --- a/kernel-shared/extent-tree.c +++ b/kernel-shared/extent-tree.c @@ -33,6 +33,7 @@ #include "kernel-shared/free-space-tree.h" #include "kernel-shared/zoned.h" #include "common/utils.h" +#include "file-item.h" #define PENDING_EXTENT_INSERT 0 #define PENDING_EXTENT_DELETE 1 @@ -2115,7 +2116,11 @@ static int __free_extent(struct btrfs_trans_handle *trans, btrfs_release_path(path); if (is_data) { - ret = btrfs_del_csums(trans, bytenr, num_bytes); + struct btrfs_root *csum_root; + + csum_root = btrfs_csum_root(trans->fs_info, bytenr); + ret = btrfs_del_csums(trans, csum_root, bytenr, + num_bytes); BUG_ON(ret); } diff --git a/kernel-shared/file-item.c b/kernel-shared/file-item.c index 0a870495..9f8a3296 100644 --- a/kernel-shared/file-item.c +++ b/kernel-shared/file-item.c @@ -25,6 +25,7 @@ #include "kernel-shared/print-tree.h" #include "crypto/crc32c.h" #include "common/internal.h" +#include "file-item.h" #define MAX_CSUM_ITEMS(r, size) ((((BTRFS_LEAF_DATA_SIZE(r->fs_info) - \ sizeof(struct btrfs_item) * 2) / \ @@ -400,7 +401,8 @@ static noinline int truncate_one_csum(struct btrfs_root *root, * deletes the csum items from the csum tree for a given * range of bytes. */ -int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len) +int btrfs_del_csums(struct btrfs_trans_handle *trans, struct btrfs_root *root, + u64 bytenr, u64 len) { struct btrfs_path *path; struct btrfs_key key; @@ -410,7 +412,6 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len) int ret; u16 csum_size = trans->fs_info->csum_size; int blocksize = trans->fs_info->sectorsize; - struct btrfs_root *csum_root = btrfs_csum_root(trans->fs_info, bytenr); path = btrfs_alloc_path(); if (!path) @@ -421,7 +422,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len) key.offset = end_byte - 1; key.type = BTRFS_EXTENT_CSUM_KEY; - ret = btrfs_search_slot(trans, csum_root, &key, path, -1, 1); + ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret > 0) { if (path->slots[0] == 0) goto out; @@ -448,7 +449,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len) /* delete the entire item, it is inside our range */ if (key.offset >= bytenr && csum_end <= end_byte) { - ret = btrfs_del_item(trans, csum_root, path); + ret = btrfs_del_item(trans, root, path); BUG_ON(ret); } else if (key.offset < bytenr && csum_end > end_byte) { unsigned long offset; @@ -488,13 +489,13 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, u64 bytenr, u64 len) * btrfs_split_item returns -EAGAIN when the * item changed size or key */ - ret = btrfs_split_item(trans, csum_root, path, &key, + ret = btrfs_split_item(trans, root, path, &key, offset); BUG_ON(ret && ret != -EAGAIN); key.offset = end_byte - 1; } else { - ret = truncate_one_csum(csum_root, path, &key, bytenr, + ret = truncate_one_csum(root, path, &key, bytenr, len); BUG_ON(ret); } diff --git a/kernel-shared/file-item.h b/kernel-shared/file-item.h new file mode 100644 index 00000000..048e0be7 --- /dev/null +++ b/kernel-shared/file-item.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BTRFS_FILE_ITEM_H +#define BTRFS_FILE_ITEM_H + +#include "kerncompat.h" +#include "accessors.h" + +struct bio; +struct inode; +struct btrfs_ordered_sum; +struct btrfs_inode; +struct extent_map; + +#define BTRFS_FILE_EXTENT_INLINE_DATA_START \ + (offsetof(struct btrfs_file_extent_item, disk_bytenr)) + +static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_fs_info *info) +{ + return BTRFS_MAX_ITEM_SIZE(info) - + BTRFS_FILE_EXTENT_INLINE_DATA_START; +} + +/* + * Returns the number of bytes used by the item on disk, minus the size of any + * extent headers. If a file is compressed on disk, this is the compressed + * size. + */ +static inline u32 btrfs_file_extent_inline_item_len( + const struct extent_buffer *eb, + int nr) +{ + return btrfs_item_size(eb, nr) - BTRFS_FILE_EXTENT_INLINE_DATA_START; +} + +static inline unsigned long btrfs_file_extent_inline_start( + const struct btrfs_file_extent_item *e) +{ + return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START; +} + +static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize) +{ + return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize; +} + +int btrfs_del_csums(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 bytenr, u64 len); +blk_status_t btrfs_lookup_bio_sums(struct inode *inode, struct bio *bio, u8 *dst); +int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 objectid, u64 pos, + u64 num_bytes); +int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, u64 objectid, + u64 bytenr, int mod); +int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_ordered_sum *sums); +blk_status_t btrfs_csum_one_bio(struct btrfs_inode *inode, struct bio *bio, + u64 offset, bool one_ordered); +int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, + struct list_head *list, int search_commit, + bool nowait); +void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, + const struct btrfs_path *path, + struct btrfs_file_extent_item *fi, + struct extent_map *em); +int btrfs_inode_clear_file_extent_range(struct btrfs_inode *inode, u64 start, + u64 len); +int btrfs_inode_set_file_extent_range(struct btrfs_inode *inode, u64 start, u64 len); +void btrfs_inode_safe_disk_i_size_write(struct btrfs_inode *inode, u64 new_i_size); +u64 btrfs_file_extent_end(const struct btrfs_path *path); + +/* + * MODIFIED: + * - This function doesn't exist in the kernel. + */ +int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 objectid, u64 pos, u64 offset, + u64 disk_num_bytes, u64 num_bytes); +int btrfs_csum_file_block(struct btrfs_trans_handle *trans, + u64 alloc_end, u64 bytenr, char *data, size_t len); +int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 objectid, + u64 offset, const char *buffer, size_t size); + +#endif diff --git a/kernel-shared/file.c b/kernel-shared/file.c index 1e5a9e98..100ea31c 100644 --- a/kernel-shared/file.c +++ b/kernel-shared/file.c @@ -22,6 +22,7 @@ #include "kernel-shared/disk-io.h" #include "kernel-shared/transaction.h" #include "kernel-shared/compression.h" +#include "kernel-shared/file-item.h" #include "common/utils.h" /* diff --git a/kernel-shared/print-tree.c b/kernel-shared/print-tree.c index b5343462..d536b2ff 100644 --- a/kernel-shared/print-tree.c +++ b/kernel-shared/print-tree.c @@ -28,6 +28,7 @@ #include "kernel-shared/compression.h" #include "common/utils.h" #include "accessors.h" +#include "file-item.h" static void print_dir_item_type(struct extent_buffer *eb, struct btrfs_dir_item *di) diff --git a/mkfs/rootdir.c b/mkfs/rootdir.c index 1ddc1138..aa2577ad 100644 --- a/mkfs/rootdir.c +++ b/mkfs/rootdir.c @@ -35,6 +35,7 @@ #include "kernel-shared/volumes.h" #include "kernel-shared/disk-io.h" #include "kernel-shared/transaction.h" +#include "kernel-shared/file-item.h" #include "common/internal.h" #include "common/messages.h" #include "common/path-utils.h" From patchwork Wed Apr 19 21:17:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217389 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF7A7C77B73 for ; Wed, 19 Apr 2023 21:17:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230521AbjDSVRm (ORCPT ); Wed, 19 Apr 2023 17:17:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39920 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230514AbjDSVRi (ORCPT ); Wed, 19 Apr 2023 17:17:38 -0400 Received: from mail-qt1-x829.google.com (mail-qt1-x829.google.com [IPv6:2607:f8b0:4864:20::829]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 551934C20 for ; Wed, 19 Apr 2023 14:17:35 -0700 (PDT) Received: by mail-qt1-x829.google.com with SMTP id br19so626677qtb.7 for ; Wed, 19 Apr 2023 14:17:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939054; x=1684531054; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=uUE84y6iZ2S8cBXqd+wgR4qFPug50k55xJC1Ltk+XL4=; b=nyH5ETYV46gvEVdt4SZ29DuHET8lbuduJYrQ7u8nwvmYSbIW1fpH/XcDyHUvhdH9e7 J/JLdPBBYanDgBqUu139ky55LQLF1tMjD5cg4L4GDsfG74uVxWvofbL9N+2OS0ECCsQn DGF7pTjww1S5MTs3KJQgTrl2BHDF3iJGZCNJPhwEGCvRMd0/BV4YUEbl2bVJyf40QjOO CnOSDXhS4CmSD9RVrdvdvQENFjnwsFVfEBZ4xPNMJURvIVLiPLd9LywqFCqGsvU6ihyU eMCqVDfisQrS6bVfM3Ou7ercy8f5JsRI0uFkUiZrzEhNWEFs4r9Px9glumIlwnUJLVUz fiXg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939054; x=1684531054; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=uUE84y6iZ2S8cBXqd+wgR4qFPug50k55xJC1Ltk+XL4=; b=bi6rEm3Xhsw5ADvoDJgacxft8IoW8Jvw3U9OFLb3ay0Xwsjhouba2wG5Drx02x9DZW r3k0eClqgn5hrUTeGmUF2e1xVnvp8CqMvbXNmTe1ClCxWCUXwsRYFB6P/DoMwvTryw5o ZVAEIuBaFAIH+hWMfStMhBUE7lKcpi4Q4Y0xYgORMi26m6otvcqCNiqXhqasBQ51VjWW cpixllZX8ujM5Gs+MV9o5xgYESxujRjmXOni7gzX0AJtKUUMHIlkc708EU2FtGTsUfQX MqIZ1078A+luWYJoj8M2kyyLTikGnzgJphGBJWiOodinF+q1bzxQSVHb0hWCUtanNimN 2K5A== X-Gm-Message-State: AAQBX9chMLXSnXHjpFX8T81dP2PxVweUdkkfHtFP6Rouk0IsKVhPpzNt 2bGZ/8o/szEvafA1+A49lITVy+dLZbvpgxXVEDB4Jw== X-Google-Smtp-Source: AKy350YIL9JRBp29xw1ud8L0eQVM/Qfo7DLYx0QheZSDe+qZDrbvj4Gh4dsj8hMgIE8jp2yEzfgebQ== X-Received: by 2002:ac8:7dc7:0:b0:3e4:ed57:7fd3 with SMTP id c7-20020ac87dc7000000b003e4ed577fd3mr8978597qte.51.1681939054072; Wed, 19 Apr 2023 14:17:34 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id x6-20020ac87306000000b003e4d9c91106sm33381qto.57.2023.04.19.14.17.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:33 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 7/8] btrfs-progs: sync async-thread.[ch] from the kernel Date: Wed, 19 Apr 2023 17:17:18 -0400 Message-Id: X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org We won't actually use the async code in progs, however we call the helpers and such all over the normal code, so sync this into btrfs-progs to make syncing other parts of the kernel easier. Signed-off-by: Josef Bacik --- Makefile | 1 + common/internal.h | 4 + include/kerncompat.h | 79 ++++++++ kernel-lib/bitops.h | 12 ++ kernel-lib/trace.h | 29 +++ kernel-shared/async-thread.c | 339 +++++++++++++++++++++++++++++++++++ kernel-shared/async-thread.h | 46 +++++ 7 files changed, 510 insertions(+) create mode 100644 kernel-lib/trace.h create mode 100644 kernel-shared/async-thread.c create mode 100644 kernel-shared/async-thread.h diff --git a/Makefile b/Makefile index 668f4e91..b9bc4fec 100644 --- a/Makefile +++ b/Makefile @@ -167,6 +167,7 @@ objects = \ kernel-lib/rbtree.o \ kernel-lib/tables.o \ kernel-shared/accessors.o \ + kernel-shared/async-thread.o \ kernel-shared/backref.o \ kernel-shared/ctree.o \ kernel-shared/delayed-ref.o \ diff --git a/common/internal.h b/common/internal.h index d5ea9986..81729964 100644 --- a/common/internal.h +++ b/common/internal.h @@ -39,4 +39,8 @@ #define max_t(type,x,y) \ ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) +#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi) + +#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi) + #endif diff --git a/include/kerncompat.h b/include/kerncompat.h index 42e81223..6321446d 100644 --- a/include/kerncompat.h +++ b/include/kerncompat.h @@ -214,6 +214,28 @@ static inline int mutex_is_locked(struct mutex *m) return (m->lock != 1); } +static inline void spin_lock_init(spinlock_t *lock) +{ + lock->lock = 0; +} + +static inline void spin_lock(spinlock_t *lock) +{ + lock->lock++; +} + +static inline void spin_unlock(spinlock_t *lock) +{ + lock->lock--; +} + +#define spin_lock_irqsave(_l, _f) do { _f = 0; spin_lock((_l)); } while (0) + +static inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) +{ + spin_unlock(lock); +} + #define cond_resched() do { } while (0) #define preempt_enable() do { } while (0) #define preempt_disable() do { } while (0) @@ -544,6 +566,9 @@ do { \ (x) = (val); \ } while (0) +#define smp_rmb() do {} while (0) +#define smp_mb__before_atomic() do {} while (0) + typedef struct refcount_struct { int refs; } refcount_t; @@ -552,9 +577,18 @@ typedef u32 blk_status_t; typedef u32 blk_opf_t; typedef int atomic_t; +struct work_struct; +typedef void (*work_func_t)(struct work_struct *work); + +struct workqueue_struct { +}; + struct work_struct { + work_func_t func; }; +#define INIT_WORK(_w, _f) do { (_w)->func = (_f); } while (0) + typedef struct wait_queue_head_s { } wait_queue_head_t; @@ -570,6 +604,7 @@ struct va_format { #define __init #define __cold #define __user +#define __pure #define __printf(a, b) __attribute__((__format__(printf, a, b))) @@ -580,4 +615,48 @@ static inline bool sb_rdonly(struct super_block *sb) #define unlikely(cond) (cond) +static inline void atomic_set(atomic_t *a, int val) +{ + *a = val; +} + +static inline int atomic_read(const atomic_t *a) +{ + return *a; +} + +static inline void atomic_inc(atomic_t *a) +{ + (*a)++; +} + +static inline void atomic_dec(atomic_t *a) +{ + (*a)--; +} + +static inline struct workqueue_struct *alloc_workqueue(const char *name, + unsigned long flags, + int max_active, ...) +{ + return (struct workqueue_struct *)5; +} + +static inline void destroy_workqueue(struct workqueue_struct *wq) +{ +} + +static inline void flush_workqueue(struct workqueue_struct *wq) +{ +} + +static inline void workqueue_set_max_active(struct workqueue_struct *wq, + int max_active) +{ +} + +static inline void queue_work(struct workqueue_struct *wq, struct work_struct *work) +{ +} + #endif diff --git a/kernel-lib/bitops.h b/kernel-lib/bitops.h index e0b85215..b9bf3b38 100644 --- a/kernel-lib/bitops.h +++ b/kernel-lib/bitops.h @@ -12,6 +12,8 @@ #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) #define for_each_set_bit(bit, addr, size) \ for ((bit) = find_first_bit((addr), (size)); \ @@ -34,6 +36,16 @@ static inline void clear_bit(int nr, unsigned long *addr) addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG)); } +static inline bool test_and_set_bit(unsigned long nr, unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old | mask; + return (old & mask) != 0; +} + /** * hweightN - returns the hamming weight of a N-bit word * @x: the word to weigh diff --git a/kernel-lib/trace.h b/kernel-lib/trace.h new file mode 100644 index 00000000..086bcd10 --- /dev/null +++ b/kernel-lib/trace.h @@ -0,0 +1,29 @@ +#ifndef __PROGS_TRACE_H__ +#define __PROGS_TRACE_H__ + +static inline void trace_btrfs_workqueue_alloc(void *ret, const char *name) +{ +} + +static inline void trace_btrfs_ordered_sched(struct btrfs_work *work) +{ +} + +static inline void trace_btrfs_all_work_done(struct btrfs_fs_info *fs_info, + struct btrfs_work *work) +{ +} + +static inline void trace_btrfs_work_sched(struct btrfs_work *work) +{ +} + +static inline void trace_btrfs_work_queued(struct btrfs_work *work) +{ +} + +static inline void trace_btrfs_workqueue_destroy(void *wq) +{ +} + +#endif /* __PROGS_TRACE_H__ */ diff --git a/kernel-shared/async-thread.c b/kernel-shared/async-thread.c new file mode 100644 index 00000000..811668da --- /dev/null +++ b/kernel-shared/async-thread.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2007 Oracle. All rights reserved. + * Copyright (C) 2014 Fujitsu. All rights reserved. + */ + +#include "kerncompat.h" +#include "async-thread.h" +#include "ctree.h" +#include "kernel-lib/trace.h" +#include "kernel-lib/bitops.h" + +enum { + WORK_DONE_BIT, + WORK_ORDER_DONE_BIT, +}; + +#define NO_THRESHOLD (-1) +#define DFT_THRESHOLD (32) + +struct btrfs_workqueue { + struct workqueue_struct *normal_wq; + + /* File system this workqueue services */ + struct btrfs_fs_info *fs_info; + + /* List head pointing to ordered work list */ + struct list_head ordered_list; + + /* Spinlock for ordered_list */ + spinlock_t list_lock; + + /* Thresholding related variants */ + atomic_t pending; + + /* Up limit of concurrency workers */ + int limit_active; + + /* Current number of concurrency workers */ + int current_active; + + /* Threshold to change current_active */ + int thresh; + unsigned int count; + spinlock_t thres_lock; +}; + +struct btrfs_fs_info * __pure btrfs_workqueue_owner(const struct btrfs_workqueue *wq) +{ + return wq->fs_info; +} + +struct btrfs_fs_info * __pure btrfs_work_owner(const struct btrfs_work *work) +{ + return work->wq->fs_info; +} + +bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq) +{ + /* + * We could compare wq->pending with num_online_cpus() + * to support "thresh == NO_THRESHOLD" case, but it requires + * moving up atomic_inc/dec in thresh_queue/exec_hook. Let's + * postpone it until someone needs the support of that case. + */ + if (wq->thresh == NO_THRESHOLD) + return false; + + return atomic_read(&wq->pending) > wq->thresh * 2; +} + +struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, + const char *name, unsigned int flags, + int limit_active, int thresh) +{ + struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); + + if (!ret) + return NULL; + + ret->fs_info = fs_info; + ret->limit_active = limit_active; + atomic_set(&ret->pending, 0); + if (thresh == 0) + thresh = DFT_THRESHOLD; + /* For low threshold, disabling threshold is a better choice */ + if (thresh < DFT_THRESHOLD) { + ret->current_active = limit_active; + ret->thresh = NO_THRESHOLD; + } else { + /* + * For threshold-able wq, let its concurrency grow on demand. + * Use minimal max_active at alloc time to reduce resource + * usage. + */ + ret->current_active = 1; + ret->thresh = thresh; + } + + ret->normal_wq = alloc_workqueue("btrfs-%s", flags, ret->current_active, + name); + if (!ret->normal_wq) { + kfree(ret); + return NULL; + } + + INIT_LIST_HEAD(&ret->ordered_list); + spin_lock_init(&ret->list_lock); + spin_lock_init(&ret->thres_lock); + trace_btrfs_workqueue_alloc(ret, name); + return ret; +} + +/* + * Hook for threshold which will be called in btrfs_queue_work. + * This hook WILL be called in IRQ handler context, + * so workqueue_set_max_active MUST NOT be called in this hook + */ +static inline void thresh_queue_hook(struct btrfs_workqueue *wq) +{ + if (wq->thresh == NO_THRESHOLD) + return; + atomic_inc(&wq->pending); +} + +/* + * Hook for threshold which will be called before executing the work, + * This hook is called in kthread content. + * So workqueue_set_max_active is called here. + */ +static inline void thresh_exec_hook(struct btrfs_workqueue *wq) +{ + int new_current_active; + long pending; + int need_change = 0; + + if (wq->thresh == NO_THRESHOLD) + return; + + atomic_dec(&wq->pending); + spin_lock(&wq->thres_lock); + /* + * Use wq->count to limit the calling frequency of + * workqueue_set_max_active. + */ + wq->count++; + wq->count %= (wq->thresh / 4); + if (!wq->count) + goto out; + new_current_active = wq->current_active; + + /* + * pending may be changed later, but it's OK since we really + * don't need it so accurate to calculate new_max_active. + */ + pending = atomic_read(&wq->pending); + if (pending > wq->thresh) + new_current_active++; + if (pending < wq->thresh / 2) + new_current_active--; + new_current_active = clamp_val(new_current_active, 1, wq->limit_active); + if (new_current_active != wq->current_active) { + need_change = 1; + wq->current_active = new_current_active; + } +out: + spin_unlock(&wq->thres_lock); + + if (need_change) { + workqueue_set_max_active(wq->normal_wq, wq->current_active); + } +} + +static void run_ordered_work(struct btrfs_workqueue *wq, + struct btrfs_work *self) +{ + struct list_head *list = &wq->ordered_list; + struct btrfs_work *work; + spinlock_t *lock = &wq->list_lock; + unsigned long flags; + bool free_self = false; + + while (1) { + spin_lock_irqsave(lock, flags); + if (list_empty(list)) + break; + work = list_entry(list->next, struct btrfs_work, + ordered_list); + if (!test_bit(WORK_DONE_BIT, &work->flags)) + break; + /* + * Orders all subsequent loads after reading WORK_DONE_BIT, + * paired with the smp_mb__before_atomic in btrfs_work_helper + * this guarantees that the ordered function will see all + * updates from ordinary work function. + */ + smp_rmb(); + + /* + * we are going to call the ordered done function, but + * we leave the work item on the list as a barrier so + * that later work items that are done don't have their + * functions called before this one returns + */ + if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) + break; + trace_btrfs_ordered_sched(work); + spin_unlock_irqrestore(lock, flags); + work->ordered_func(work); + + /* now take the lock again and drop our item from the list */ + spin_lock_irqsave(lock, flags); + list_del(&work->ordered_list); + spin_unlock_irqrestore(lock, flags); + + if (work == self) { + /* + * This is the work item that the worker is currently + * executing. + * + * The kernel workqueue code guarantees non-reentrancy + * of work items. I.e., if a work item with the same + * address and work function is queued twice, the second + * execution is blocked until the first one finishes. A + * work item may be freed and recycled with the same + * work function; the workqueue code assumes that the + * original work item cannot depend on the recycled work + * item in that case (see find_worker_executing_work()). + * + * Note that different types of Btrfs work can depend on + * each other, and one type of work on one Btrfs + * filesystem may even depend on the same type of work + * on another Btrfs filesystem via, e.g., a loop device. + * Therefore, we must not allow the current work item to + * be recycled until we are really done, otherwise we + * break the above assumption and can deadlock. + */ + free_self = true; + } else { + /* + * We don't want to call the ordered free functions with + * the lock held. + */ + work->ordered_free(work); + /* NB: work must not be dereferenced past this point. */ + trace_btrfs_all_work_done(wq->fs_info, work); + } + } + spin_unlock_irqrestore(lock, flags); + + if (free_self) { + self->ordered_free(self); + /* NB: self must not be dereferenced past this point. */ + trace_btrfs_all_work_done(wq->fs_info, self); + } +} + +static void btrfs_work_helper(struct work_struct *normal_work) +{ + struct btrfs_work *work = container_of(normal_work, struct btrfs_work, + normal_work); + struct btrfs_workqueue *wq = work->wq; + int need_order = 0; + + /* + * We should not touch things inside work in the following cases: + * 1) after work->func() if it has no ordered_free + * Since the struct is freed in work->func(). + * 2) after setting WORK_DONE_BIT + * The work may be freed in other threads almost instantly. + * So we save the needed things here. + */ + if (work->ordered_func) + need_order = 1; + + trace_btrfs_work_sched(work); + thresh_exec_hook(wq); + work->func(work); + if (need_order) { + /* + * Ensures all memory accesses done in the work function are + * ordered before setting the WORK_DONE_BIT. Ensuring the thread + * which is going to executed the ordered work sees them. + * Pairs with the smp_rmb in run_ordered_work. + */ + smp_mb__before_atomic(); + set_bit(WORK_DONE_BIT, &work->flags); + run_ordered_work(wq, work); + } else { + /* NB: work must not be dereferenced past this point. */ + trace_btrfs_all_work_done(wq->fs_info, work); + } +} + +void btrfs_init_work(struct btrfs_work *work, btrfs_func_t func, + btrfs_func_t ordered_func, btrfs_func_t ordered_free) +{ + work->func = func; + work->ordered_func = ordered_func; + work->ordered_free = ordered_free; + INIT_WORK(&work->normal_work, btrfs_work_helper); + INIT_LIST_HEAD(&work->ordered_list); + work->flags = 0; +} + +void btrfs_queue_work(struct btrfs_workqueue *wq, struct btrfs_work *work) +{ + unsigned long flags; + + work->wq = wq; + thresh_queue_hook(wq); + if (work->ordered_func) { + spin_lock_irqsave(&wq->list_lock, flags); + list_add_tail(&work->ordered_list, &wq->ordered_list); + spin_unlock_irqrestore(&wq->list_lock, flags); + } + trace_btrfs_work_queued(work); + queue_work(wq->normal_wq, &work->normal_work); +} + +void btrfs_destroy_workqueue(struct btrfs_workqueue *wq) +{ + if (!wq) + return; + destroy_workqueue(wq->normal_wq); + trace_btrfs_workqueue_destroy(wq); + kfree(wq); +} + +void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int limit_active) +{ + if (wq) + wq->limit_active = limit_active; +} + +void btrfs_flush_workqueue(struct btrfs_workqueue *wq) +{ + flush_workqueue(wq->normal_wq); +} diff --git a/kernel-shared/async-thread.h b/kernel-shared/async-thread.h new file mode 100644 index 00000000..90657605 --- /dev/null +++ b/kernel-shared/async-thread.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2007 Oracle. All rights reserved. + * Copyright (C) 2014 Fujitsu. All rights reserved. + */ + +#ifndef BTRFS_ASYNC_THREAD_H +#define BTRFS_ASYNC_THREAD_H + +#include "kerncompat.h" +#include "kernel-lib/list.h" + +struct btrfs_fs_info; +struct btrfs_workqueue; +struct btrfs_work; +typedef void (*btrfs_func_t)(struct btrfs_work *arg); + +struct btrfs_work { + btrfs_func_t func; + btrfs_func_t ordered_func; + btrfs_func_t ordered_free; + + /* Don't touch things below */ + struct work_struct normal_work; + struct list_head ordered_list; + struct btrfs_workqueue *wq; + unsigned long flags; +}; + +struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, + const char *name, + unsigned int flags, + int limit_active, + int thresh); +void btrfs_init_work(struct btrfs_work *work, btrfs_func_t func, + btrfs_func_t ordered_func, btrfs_func_t ordered_free); +void btrfs_queue_work(struct btrfs_workqueue *wq, + struct btrfs_work *work); +void btrfs_destroy_workqueue(struct btrfs_workqueue *wq); +void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max); +struct btrfs_fs_info * __pure btrfs_work_owner(const struct btrfs_work *work); +struct btrfs_fs_info * __pure btrfs_workqueue_owner(const struct btrfs_workqueue *wq); +bool btrfs_workqueue_normal_congested(const struct btrfs_workqueue *wq); +void btrfs_flush_workqueue(struct btrfs_workqueue *wq); + +#endif From patchwork Wed Apr 19 21:17:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Josef Bacik X-Patchwork-Id: 13217391 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 41D4BC77B7A for ; Wed, 19 Apr 2023 21:17:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231239AbjDSVRp (ORCPT ); Wed, 19 Apr 2023 17:17:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40026 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230519AbjDSVRn (ORCPT ); Wed, 19 Apr 2023 17:17:43 -0400 Received: from mail-qt1-x834.google.com (mail-qt1-x834.google.com [IPv6:2607:f8b0:4864:20::834]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7FED944B9 for ; Wed, 19 Apr 2023 14:17:38 -0700 (PDT) Received: by mail-qt1-x834.google.com with SMTP id a23so617094qtj.8 for ; Wed, 19 Apr 2023 14:17:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20221208.gappssmtp.com; s=20221208; t=1681939057; x=1684531057; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=8YXUPG4aLkp9XGOCHoo+6PYOF0Lh9Nehd+48is+0oCg=; b=Ydd/iEB8sRcS1xvUaym1U0OjEm8P2VI9UG7ylTpguAXyepUAoi2yYNFt0JYPHug4bH jFuhGL0nXgGHWvkv/XnG2CSh0Eg+VZXSzlNGXAcRTnpHIFDxKtxBxg7SUEPbhwyDmKLv gIwm0544zNW2/CqY5YOOQZp2s69XaUmUihfmklazpp9W+AomkEPs/PkpV1VxBVfhRWTK 9V9zOxgKrm3pJ8jHrH112KM6gIvJYiAi2ZH4SzbR+6Ej6r/Aj7MxNERzZxsJ0CUSL71o 7Rjziup6MhvPJQa4C0qbJtmNaOtSD9qxbaXjSaGUXE6p8UlNeT4DifJXCjzH7dXSRQ9/ F58A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681939057; x=1684531057; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8YXUPG4aLkp9XGOCHoo+6PYOF0Lh9Nehd+48is+0oCg=; b=bUw467h5tO6yu5f1ebRFJAHd3VY8zkbVKEt1u0bpQH/VQnwVppZswpYBc/TmoaVXWj MvrHXXYraiCSY01zOKT28kgpntRVKseeU4XundYPxAvxa96JoRZhyxanJ9hJzYo/16g3 KHJ/j9X73f1wziBBQJHhZa99+IQlmsQMT4PJBQeEHgTcTQmfK4MKBJocjuA9kKyilsLz W0zdgn1fF3CiqO91ppYk8yUBEaa0cqHA/Y3peASalsXzOvf4KmsUVlQ5fU6Mkzs7J4Ez P2nDtPO3/pqQhpWimOQHxIyUhduTPT+2yJGBFAsV9nxqIqz87mZy0gSrTjMLVdVNXUNm 6ygA== X-Gm-Message-State: AAQBX9cIh/JZEDho4JyCuzlbcIj5VdMl46bkc9h0TfJsOxLfROkv4kTN SE/RnLGmpJhEu7EzzQwvShMu1Mmk5SvIV0+6Co/qyg== X-Google-Smtp-Source: AKy350aOHlnlRR4+149dtlsqUVK++Q+aR0MLtsJ71gmkZE1XS32Ym6ncC8EJFOi+JgrHDoaKVIz4Zg== X-Received: by 2002:a05:622a:38d:b0:3e1:b06d:e9e0 with SMTP id j13-20020a05622a038d00b003e1b06de9e0mr7604109qtx.56.1681939055779; Wed, 19 Apr 2023 14:17:35 -0700 (PDT) Received: from localhost (cpe-174-109-170-245.nc.res.rr.com. [174.109.170.245]) by smtp.gmail.com with ESMTPSA id y19-20020a05620a44d300b0074adca3206asm704037qkp.90.2023.04.19.14.17.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Apr 2023 14:17:35 -0700 (PDT) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Subject: [PATCH 8/8] btrfs-progs: sync extent-io-tree.[ch] and misc.h from the kernel Date: Wed, 19 Apr 2023 17:17:19 -0400 Message-Id: <7be6046b0c4b3a85ab443ebf821b479c20cc90b2.1681938911.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.40.0 In-Reply-To: References: MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org This is a bit larger than the previous syncs, because we use extent_io_tree's everywhere. There's a lot of stuff added to kerncompat.h, and then I went through and cleaned up all the API changes, which were - extent_io_tree_init takes an fs_info and an owner now. - extent_io_tree_cleanup is now extent_io_tree_release. - set_extent_dirty takes a gfpmask. - clear_extent_dirty takes a cached_state. - find_first_extent_bit takes a cached_state. The diffstat looks insane for this, but keep in mind extent-io-tree.c and extent-io-tree.h are ~2000 loc just by themselves. Signed-off-by: Josef Bacik --- Makefile | 1 + check/clear-cache.c | 8 +- check/common.h | 2 +- check/main.c | 27 +- check/mode-common.c | 9 +- check/mode-lowmem.c | 4 +- check/repair.c | 16 +- cmds/rescue-chunk-recover.c | 2 +- image/main.c | 9 +- include/kerncompat.h | 161 ++- kernel-lib/trace.h | 26 + kernel-shared/ctree.h | 1 + kernel-shared/disk-io.c | 16 +- kernel-shared/extent-io-tree.c | 1733 ++++++++++++++++++++++++++++++++ kernel-shared/extent-io-tree.h | 239 +++++ kernel-shared/extent-tree.c | 45 +- kernel-shared/extent_io.c | 473 +-------- kernel-shared/extent_io.h | 39 +- kernel-shared/misc.h | 143 +++ kernel-shared/transaction.c | 5 +- 20 files changed, 2387 insertions(+), 572 deletions(-) create mode 100644 kernel-shared/extent-io-tree.c create mode 100644 kernel-shared/extent-io-tree.h create mode 100644 kernel-shared/misc.h diff --git a/Makefile b/Makefile index b9bc4fec..43dfd296 100644 --- a/Makefile +++ b/Makefile @@ -173,6 +173,7 @@ objects = \ kernel-shared/delayed-ref.o \ kernel-shared/dir-item.o \ kernel-shared/disk-io.o \ + kernel-shared/extent-io-tree.o \ kernel-shared/extent-tree.o \ kernel-shared/extent_io.o \ kernel-shared/file-item.o \ diff --git a/check/clear-cache.c b/check/clear-cache.c index 9074557e..5ffdd430 100644 --- a/check/clear-cache.c +++ b/check/clear-cache.c @@ -310,7 +310,7 @@ static int verify_space_cache(struct btrfs_root *root, while (start < bg_end) { ret = find_first_extent_bit(used, cache->start, &start, &end, - EXTENT_DIRTY); + EXTENT_DIRTY, NULL); if (ret || start >= bg_end) { ret = 0; break; @@ -322,7 +322,7 @@ static int verify_space_cache(struct btrfs_root *root, return ret; } end = min(end, bg_end - 1); - clear_extent_dirty(used, start, end); + clear_extent_dirty(used, start, end, NULL); start = end + 1; last_end = start; } @@ -349,7 +349,7 @@ static int check_space_cache(struct btrfs_root *root) int ret; int error = 0; - extent_io_tree_init(&used); + extent_io_tree_init(root->fs_info, &used, 0); ret = btrfs_mark_used_blocks(gfs_info, &used); if (ret) return ret; @@ -405,7 +405,7 @@ static int check_space_cache(struct btrfs_root *root) error++; } } - extent_io_tree_cleanup(&used); + extent_io_tree_release(&used); return error ? -EINVAL : 0; } diff --git a/check/common.h b/check/common.h index 645c4539..2d5db213 100644 --- a/check/common.h +++ b/check/common.h @@ -147,7 +147,7 @@ u64 calc_stripe_length(u64 type, u64 length, int num_stripes); static inline void block_group_tree_init(struct block_group_tree *tree) { cache_tree_init(&tree->tree); - extent_io_tree_init(&tree->pending_extents); + extent_io_tree_init(NULL, &tree->pending_extents, 0); INIT_LIST_HEAD(&tree->block_groups); } diff --git a/check/main.c b/check/main.c index 513fa553..99ff3bc3 100644 --- a/check/main.c +++ b/check/main.c @@ -5200,7 +5200,7 @@ static void free_block_group_record(struct cache_extent *cache) void free_block_group_tree(struct block_group_tree *tree) { - extent_io_tree_cleanup(&tree->pending_extents); + extent_io_tree_release(&tree->pending_extents); cache_tree_free_extents(&tree->tree, free_block_group_record); } @@ -5213,7 +5213,7 @@ static void update_block_group_used(struct block_group_tree *tree, bg_item = lookup_cache_extent(&tree->tree, bytenr, num_bytes); if (!bg_item) { set_extent_dirty(&tree->pending_extents, bytenr, - bytenr + num_bytes - 1); + bytenr + num_bytes - 1, GFP_NOFS); return; } bg_rec = container_of(bg_item, struct block_group_record, cache); @@ -5452,7 +5452,8 @@ static int process_block_group_item(struct block_group_tree *block_group_cache, } while (!find_first_extent_bit(&block_group_cache->pending_extents, - rec->objectid, &start, &end, EXTENT_DIRTY)) { + rec->objectid, &start, &end, EXTENT_DIRTY, + NULL)) { u64 len; if (start >= rec->objectid + rec->offset) @@ -5461,7 +5462,7 @@ static int process_block_group_item(struct block_group_tree *block_group_cache, len = min(end - start + 1, rec->objectid + rec->offset - start); rec->actual_used += len; clear_extent_dirty(&block_group_cache->pending_extents, start, - start + len - 1); + start + len - 1, NULL); } return ret; @@ -8057,7 +8058,8 @@ static int check_extent_refs(struct btrfs_root *root, rec = container_of(cache, struct extent_record, cache); set_extent_dirty(gfs_info->excluded_extents, rec->start, - rec->start + rec->max_size - 1); + rec->start + rec->max_size - 1, + GFP_NOFS); cache = next_cache_extent(cache); } @@ -8066,7 +8068,8 @@ static int check_extent_refs(struct btrfs_root *root, while (cache) { set_extent_dirty(gfs_info->excluded_extents, cache->start, - cache->start + cache->size - 1); + cache->start + cache->size - 1, + GFP_NOFS); cache = next_cache_extent(cache); } prune_corrupt_blocks(); @@ -8221,7 +8224,8 @@ next: if (!init_extent_tree && opt_check_repair && (!cur_err || fix)) clear_extent_dirty(gfs_info->excluded_extents, rec->start, - rec->start + rec->max_size - 1); + rec->start + rec->max_size - 1, + NULL); free(rec); } repair_abort: @@ -8927,7 +8931,7 @@ static int check_chunks_and_extents(void) cache_tree_init(&nodes); cache_tree_init(&reada); cache_tree_init(&corrupt_blocks); - extent_io_tree_init(&excluded_extents); + extent_io_tree_init(gfs_info, &excluded_extents, 0); INIT_LIST_HEAD(&dropping_trees); INIT_LIST_HEAD(&normal_trees); @@ -9015,7 +9019,7 @@ again: out: if (opt_check_repair) { free_corrupt_blocks_tree(gfs_info->corrupt_blocks); - extent_io_tree_cleanup(&excluded_extents); + extent_io_tree_release(&excluded_extents); gfs_info->fsck_extent_cache = NULL; gfs_info->free_extent_hook = NULL; gfs_info->corrupt_blocks = NULL; @@ -9046,7 +9050,7 @@ loop: free_extent_record_cache(&extent_cache); free_root_item_list(&normal_trees); free_root_item_list(&dropping_trees); - extent_io_tree_cleanup(&excluded_extents); + extent_io_tree_release(&excluded_extents); goto again; } @@ -9215,7 +9219,8 @@ static int reset_block_groups(void) btrfs_chunk_type(leaf, chunk), key.offset, btrfs_chunk_length(leaf, chunk)); set_extent_dirty(&gfs_info->free_space_cache, key.offset, - key.offset + btrfs_chunk_length(leaf, chunk)); + key.offset + btrfs_chunk_length(leaf, chunk), + GFP_NOFS); path.slots[0]++; } start = 0; diff --git a/check/mode-common.c b/check/mode-common.c index 120165aa..394c35fe 100644 --- a/check/mode-common.c +++ b/check/mode-common.c @@ -596,10 +596,11 @@ void reset_cached_block_groups() while (1) { ret = find_first_extent_bit(&gfs_info->free_space_cache, 0, - &start, &end, EXTENT_DIRTY); + &start, &end, EXTENT_DIRTY, NULL); if (ret) break; - clear_extent_dirty(&gfs_info->free_space_cache, start, end); + clear_extent_dirty(&gfs_info->free_space_cache, start, end, + NULL); } start = 0; @@ -626,7 +627,7 @@ int exclude_metadata_blocks(void) excluded_extents = malloc(sizeof(*excluded_extents)); if (!excluded_extents) return -ENOMEM; - extent_io_tree_init(excluded_extents); + extent_io_tree_init(gfs_info, excluded_extents, 0); gfs_info->excluded_extents = excluded_extents; return btrfs_mark_used_tree_blocks(gfs_info, excluded_extents); @@ -635,7 +636,7 @@ int exclude_metadata_blocks(void) void cleanup_excluded_extents(void) { if (gfs_info->excluded_extents) { - extent_io_tree_cleanup(gfs_info->excluded_extents); + extent_io_tree_release(gfs_info->excluded_extents); free(gfs_info->excluded_extents); } gfs_info->excluded_extents = NULL; diff --git a/check/mode-lowmem.c b/check/mode-lowmem.c index 237e0fdb..0bc95930 100644 --- a/check/mode-lowmem.c +++ b/check/mode-lowmem.c @@ -260,12 +260,12 @@ static int modify_block_group_cache(struct btrfs_block_group *block_group, int c if (cache && !block_group->cached) { block_group->cached = 1; - clear_extent_dirty(free_space_cache, start, end - 1); + clear_extent_dirty(free_space_cache, start, end - 1, NULL); } if (!cache && block_group->cached) { block_group->cached = 0; - clear_extent_dirty(free_space_cache, start, end - 1); + clear_extent_dirty(free_space_cache, start, end - 1, NULL); } return 0; } diff --git a/check/repair.c b/check/repair.c index 8c1e2027..07c432b3 100644 --- a/check/repair.c +++ b/check/repair.c @@ -79,13 +79,13 @@ static int traverse_tree_blocks(struct extent_io_tree *tree, * This can not only avoid forever loop with broken filesystem * but also give us some speedups. */ - if (test_range_bit(tree, eb->start, end - 1, EXTENT_DIRTY, 0)) + if (test_range_bit(tree, eb->start, end - 1, EXTENT_DIRTY, 0, NULL)) return 0; if (pin) btrfs_pin_extent(fs_info, eb->start, eb->len); else - set_extent_dirty(tree, eb->start, end - 1); + set_extent_dirty(tree, eb->start, end - 1, GFP_NOFS); nritems = btrfs_header_nritems(eb); for (i = 0; i < nritems; i++) { @@ -129,7 +129,7 @@ static int traverse_tree_blocks(struct extent_io_tree *tree, btrfs_pin_extent(fs_info, bytenr, fs_info->nodesize); else - set_extent_dirty(tree, bytenr, end); + set_extent_dirty(tree, bytenr, end, GFP_NOFS); continue; } @@ -211,7 +211,7 @@ static int populate_used_from_extent_root(struct btrfs_root *root, ret = -EINVAL; break; } - set_extent_dirty(io_tree, start, end); + set_extent_dirty(io_tree, start, end, GFP_NOFS); } path.slots[0]++; @@ -260,7 +260,7 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans) if (ret) return ret; - extent_io_tree_init(&used); + extent_io_tree_init(fs_info, &used, 0); ret = btrfs_mark_used_blocks(fs_info, &used); if (ret) @@ -282,7 +282,7 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans) start = 0; while (1) { ret = find_first_extent_bit(&used, 0, &start, &end, - EXTENT_DIRTY); + EXTENT_DIRTY, NULL); if (ret) break; @@ -291,12 +291,12 @@ int btrfs_fix_block_accounting(struct btrfs_trans_handle *trans) 1, 0); if (ret) goto out; - clear_extent_dirty(&used, start, end); + clear_extent_dirty(&used, start, end, NULL); } btrfs_set_super_bytes_used(fs_info->super_copy, bytes_used); ret = 0; out: - extent_io_tree_cleanup(&used); + extent_io_tree_release(&used); return ret; } diff --git a/cmds/rescue-chunk-recover.c b/cmds/rescue-chunk-recover.c index 728f7194..ce53da2e 100644 --- a/cmds/rescue-chunk-recover.c +++ b/cmds/rescue-chunk-recover.c @@ -1099,7 +1099,7 @@ static int block_group_free_all_extent(struct btrfs_trans_handle *trans, if (list_empty(&cache->dirty_list)) list_add_tail(&cache->dirty_list, &trans->dirty_bgs); - set_extent_dirty(&info->free_space_cache, start, end); + set_extent_dirty(&info->free_space_cache, start, end, GFP_NOFS); cache->used = 0; diff --git a/image/main.c b/image/main.c index a90e6ff0..ae7acb96 100644 --- a/image/main.c +++ b/image/main.c @@ -475,7 +475,7 @@ static void metadump_destroy(struct metadump_struct *md, int num_threads) free(name->sub); free(name); } - extent_io_tree_cleanup(&md->seen); + extent_io_tree_release(&md->seen); } static int metadump_init(struct metadump_struct *md, struct btrfs_root *root, @@ -491,7 +491,7 @@ static int metadump_init(struct metadump_struct *md, struct btrfs_root *root, memset(md, 0, sizeof(*md)); INIT_LIST_HEAD(&md->list); INIT_LIST_HEAD(&md->ordered); - extent_io_tree_init(&md->seen); + extent_io_tree_init(NULL, &md->seen, 0); md->root = root; md->out = out; md->pending_start = (u64)-1; @@ -784,11 +784,12 @@ static int copy_tree_blocks(struct btrfs_root *root, struct extent_buffer *eb, bytenr = btrfs_header_bytenr(eb); if (test_range_bit(&metadump->seen, bytenr, - bytenr + fs_info->nodesize - 1, EXTENT_DIRTY, 1)) + bytenr + fs_info->nodesize - 1, EXTENT_DIRTY, 1, + NULL)) return 0; set_extent_dirty(&metadump->seen, bytenr, - bytenr + fs_info->nodesize - 1); + bytenr + fs_info->nodesize - 1, GFP_NOFS); ret = add_extent(btrfs_header_bytenr(eb), fs_info->nodesize, metadump, 0); diff --git a/include/kerncompat.h b/include/kerncompat.h index 6321446d..68007915 100644 --- a/include/kerncompat.h +++ b/include/kerncompat.h @@ -75,10 +75,17 @@ #define BITS_PER_LONG (__SIZEOF_LONG__ * BITS_PER_BYTE) #define __GFP_BITS_SHIFT 20 #define __GFP_BITS_MASK ((int)((1 << __GFP_BITS_SHIFT) - 1)) +#define __GFP_DMA32 0 +#define __GFP_HIGHMEM 0 #define GFP_KERNEL 0 #define GFP_NOFS 0 +#define GFP_NOWAIT 0 +#define GFP_ATOMIC 0 #define __read_mostly #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define _RET_IP_ 0 +#define TASK_UNINTERRUPTIBLE 0 +#define SLAB_MEM_SPREAD 0 #ifndef ULONG_MAX #define ULONG_MAX (~0UL) @@ -364,6 +371,38 @@ static inline int IS_ERR_OR_NULL(const void *ptr) #define kvfree(x) free(x) #define memalloc_nofs_save() (0) #define memalloc_nofs_restore(x) ((void)(x)) +#define __releases(x) +#define __acquires(x) + +struct kmem_cache { + size_t size; +}; + +static inline struct kmem_cache *kmem_cache_create(const char *name, + size_t size, unsigned long idk, + unsigned long flags, void *private) +{ + struct kmem_cache *ret = malloc(sizeof(*ret)); + if (!ret) + return ret; + ret->size = size; + return ret; +} + +static inline void kmem_cache_destroy(struct kmem_cache *cache) +{ + free(cache); +} + +static inline void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t mask) +{ + return malloc(cache->size); +} + +static inline void kmem_cache_free(struct kmem_cache *cache, void *ptr) +{ + free(ptr); +} #define BUG_ON(c) bugon_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) #define BUG() \ @@ -371,7 +410,13 @@ do { \ BUG_ON(1); \ __builtin_unreachable(); \ } while (0) -#define WARN_ON(c) warning_trace(#c, __FILE__, __func__, __LINE__, (long)(c)) + +#define WARN_ON(c) ({ \ + int __ret_warn_on = !!(c); \ + warning_trace(#c, __FILE__, __func__, __LINE__, \ + (long)(__ret_warn_on)); \ + __ret_warn_on; \ +}) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ @@ -568,11 +613,33 @@ do { \ #define smp_rmb() do {} while (0) #define smp_mb__before_atomic() do {} while (0) +#define smp_mb() do {} while (0) typedef struct refcount_struct { int refs; } refcount_t; +static inline void refcount_set(refcount_t *ref, int val) +{ + ref->refs = val; +} + +static inline void refcount_inc(refcount_t *ref) +{ + ref->refs++; +} + +static inline void refcount_dec(refcount_t *ref) +{ + ref->refs--; +} + +static inline bool refcount_dec_and_test(refcount_t *ref) +{ + ref->refs--; + return ref->refs == 0; +} + typedef u32 blk_status_t; typedef u32 blk_opf_t; typedef int atomic_t; @@ -589,9 +656,14 @@ struct work_struct { #define INIT_WORK(_w, _f) do { (_w)->func = (_f); } while (0) -typedef struct wait_queue_head_s { +typedef struct wait_queue_head { } wait_queue_head_t; +struct wait_queue_entry { +}; + +#define DEFINE_WAIT(name) struct wait_queue_entry name = {} + struct super_block { char *s_id; }; @@ -601,6 +673,9 @@ struct va_format { va_list *va; }; +struct lock_class_key { +}; + #define __init #define __cold #define __user @@ -659,4 +734,86 @@ static inline void queue_work(struct workqueue_struct *wq, struct work_struct *w { } +static inline bool wq_has_sleeper(struct wait_queue_head *wq) +{ + return false; +} + +static inline bool waitqueue_active(struct wait_queue_head *wq) +{ + return false; +} + +static inline void wake_up(struct wait_queue_head *wq) +{ +} + +static inline void lockdep_set_class(spinlock_t *lock, struct lock_class_key *lclass) +{ +} + +static inline bool cond_resched_lock(spinlock_t *lock) +{ + return false; +} + +static inline void init_waitqueue_head(wait_queue_head_t *wqh) +{ +} + +static inline bool need_resched(void) +{ + return false; +} + +static inline bool gfpflags_allow_blocking(gfp_t mask) +{ + return true; +} + +static inline void prepare_to_wait(wait_queue_head_t *wqh, + struct wait_queue_entry *entry, + unsigned long flags) +{ +} + +static inline void finish_wait(wait_queue_head_t *wqh, + struct wait_queue_entry *entry) +{ +} + +static inline void schedule(void) +{ +} + +/* + * Temporary definitions while syncing. + */ +struct btrfs_inode; +struct extent_state; + +static inline void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, + struct extent_state *state, + struct extent_state *other) +{ +} + +static inline void btrfs_set_delalloc_extent(struct btrfs_inode *inode, + struct extent_state *state, + u32 bits) +{ +} + +static inline void btrfs_split_delalloc_extent(struct btrfs_inode *inode, + struct extent_state *orig, + u64 split) +{ +} + +static inline void btrfs_clear_delalloc_extent(struct btrfs_inode *inode, + struct extent_state *state, + u32 bits) +{ +} + #endif diff --git a/kernel-lib/trace.h b/kernel-lib/trace.h index 086bcd10..99bee344 100644 --- a/kernel-lib/trace.h +++ b/kernel-lib/trace.h @@ -26,4 +26,30 @@ static inline void trace_btrfs_workqueue_destroy(void *wq) { } +static inline void trace_alloc_extent_state(struct extent_state *state, + gfp_t mask, unsigned long ip) +{ +} + +static inline void trace_free_extent_state(struct extent_state *state, + unsigned long ip) +{ +} + +static inline void trace_btrfs_clear_extent_bit(struct extent_io_tree *tree, + u64 start, u64 end, u32 bits) +{ +} + +static inline void trace_btrfs_set_extent_bit(struct extent_io_tree *tree, + u64 start, u64 end, u32 bits) +{ +} + +static inline void trace_btrfs_convert_extent_bit(struct extent_io_tree *tree, + u64 start, u64 end, u32 bits, + u32 clear_bits) +{ +} + #endif /* __PROGS_TRACE_H__ */ diff --git a/kernel-shared/ctree.h b/kernel-shared/ctree.h index 6365a1f6..8de1fba4 100644 --- a/kernel-shared/ctree.h +++ b/kernel-shared/ctree.h @@ -28,6 +28,7 @@ #include "kernel-shared/uapi/btrfs.h" #include "kernel-shared/uapi/btrfs_tree.h" #include "accessors.h" +#include "extent-io-tree.h" struct btrfs_root; struct btrfs_trans_handle; diff --git a/kernel-shared/disk-io.c b/kernel-shared/disk-io.c index 7d165720..030bc780 100644 --- a/kernel-shared/disk-io.c +++ b/kernel-shared/disk-io.c @@ -866,10 +866,10 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr) goto free_all; extent_buffer_init_cache(fs_info); - extent_io_tree_init(&fs_info->dirty_buffers); - extent_io_tree_init(&fs_info->free_space_cache); - extent_io_tree_init(&fs_info->pinned_extents); - extent_io_tree_init(&fs_info->extent_ins); + extent_io_tree_init(fs_info, &fs_info->dirty_buffers, 0); + extent_io_tree_init(fs_info, &fs_info->free_space_cache, 0); + extent_io_tree_init(fs_info, &fs_info->pinned_extents, 0); + extent_io_tree_init(fs_info, &fs_info->extent_ins, 0); fs_info->block_group_cache_tree = RB_ROOT; fs_info->excluded_extents = NULL; @@ -1350,11 +1350,11 @@ void btrfs_cleanup_all_caches(struct btrfs_fs_info *fs_info) free_extent_buffer(eb); } free_mapping_cache_tree(&fs_info->mapping_tree.cache_tree); - extent_io_tree_cleanup(&fs_info->dirty_buffers); + extent_io_tree_release(&fs_info->dirty_buffers); extent_buffer_free_cache(fs_info); - extent_io_tree_cleanup(&fs_info->free_space_cache); - extent_io_tree_cleanup(&fs_info->pinned_extents); - extent_io_tree_cleanup(&fs_info->extent_ins); + extent_io_tree_release(&fs_info->free_space_cache); + extent_io_tree_release(&fs_info->pinned_extents); + extent_io_tree_release(&fs_info->extent_ins); } int btrfs_scan_fs_devices(int fd, const char *path, diff --git a/kernel-shared/extent-io-tree.c b/kernel-shared/extent-io-tree.c new file mode 100644 index 00000000..206d154f --- /dev/null +++ b/kernel-shared/extent-io-tree.c @@ -0,0 +1,1733 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "messages.h" +#include "ctree.h" +#include "async-thread.h" +#include "extent-io-tree.h" +#include "misc.h" +#include "ulist.h" +#include "kernel-lib/trace.h" +#include "common/internal.h" + +/* + * MODIFIED: + * - temporarily define this until we can sync everything. + */ +struct extent_changeset { + u64 bytes_changed; + struct ulist range_changed; +}; + +/* + * MODIFIED: + * - Need to set this to NULL so we init this when we init an extent_io_tree + * for the first time. + */ +static struct kmem_cache *extent_state_cache = NULL; + +static inline bool extent_state_in_tree(const struct extent_state *state) +{ + return !RB_EMPTY_NODE(&state->rb_node); +} + +#ifdef CONFIG_BTRFS_DEBUG +static LIST_HEAD(states); +static DEFINE_SPINLOCK(leak_lock); + +static inline void btrfs_leak_debug_add_state(struct extent_state *state) +{ + unsigned long flags; + + spin_lock_irqsave(&leak_lock, flags); + list_add(&state->leak_list, &states); + spin_unlock_irqrestore(&leak_lock, flags); +} + +static inline void btrfs_leak_debug_del_state(struct extent_state *state) +{ + unsigned long flags; + + spin_lock_irqsave(&leak_lock, flags); + list_del(&state->leak_list); + spin_unlock_irqrestore(&leak_lock, flags); +} + +static inline void btrfs_extent_state_leak_debug_check(void) +{ + struct extent_state *state; + + while (!list_empty(&states)) { + state = list_entry(states.next, struct extent_state, leak_list); + pr_err("BTRFS: state leak: start %llu end %llu state %u in tree %d refs %d\n", + state->start, state->end, state->state, + extent_state_in_tree(state), + refcount_read(&state->refs)); + list_del(&state->leak_list); + kmem_cache_free(extent_state_cache, state); + } +} + +#define btrfs_debug_check_extent_io_range(tree, start, end) \ + __btrfs_debug_check_extent_io_range(__func__, (tree), (start), (end)) +static inline void __btrfs_debug_check_extent_io_range(const char *caller, + struct extent_io_tree *tree, + u64 start, u64 end) +{ + struct btrfs_inode *inode = tree->inode; + u64 isize; + + if (!inode) + return; + + isize = i_size_read(&inode->vfs_inode); + if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) { + btrfs_debug_rl(inode->root->fs_info, + "%s: ino %llu isize %llu odd range [%llu,%llu]", + caller, btrfs_ino(inode), isize, start, end); + } +} +#else +#define btrfs_leak_debug_add_state(state) do {} while (0) +#define btrfs_leak_debug_del_state(state) do {} while (0) +#define btrfs_extent_state_leak_debug_check() do {} while (0) +#define btrfs_debug_check_extent_io_range(c, s, e) do {} while (0) +#endif + +/* + * For the file_extent_tree, we want to hold the inode lock when we lookup and + * update the disk_i_size, but lockdep will complain because our io_tree we hold + * the tree lock and get the inode lock when setting delalloc. These two things + * are unrelated, so make a class for the file_extent_tree so we don't get the + * two locking patterns mixed up. + */ +static struct lock_class_key file_extent_tree_class; + +struct tree_entry { + u64 start; + u64 end; + struct rb_node rb_node; +}; + +/* + * MODIFIED: + * - We use this as an entry point for init'ing the kmem_cache. + */ +void extent_io_tree_init(struct btrfs_fs_info *fs_info, + struct extent_io_tree *tree, unsigned int owner) +{ + extent_state_init_cachep(); + tree->fs_info = fs_info; + tree->state = RB_ROOT; + spin_lock_init(&tree->lock); + tree->inode = NULL; + tree->owner = owner; + if (owner == IO_TREE_INODE_FILE_EXTENT) + lockdep_set_class(&tree->lock, &file_extent_tree_class); +} + +void extent_io_tree_release(struct extent_io_tree *tree) +{ + spin_lock(&tree->lock); + /* + * Do a single barrier for the waitqueue_active check here, the state + * of the waitqueue should not change once extent_io_tree_release is + * called. + */ + smp_mb(); + while (!RB_EMPTY_ROOT(&tree->state)) { + struct rb_node *node; + struct extent_state *state; + + node = rb_first(&tree->state); + state = rb_entry(node, struct extent_state, rb_node); + rb_erase(&state->rb_node, &tree->state); + RB_CLEAR_NODE(&state->rb_node); + /* + * btree io trees aren't supposed to have tasks waiting for + * changes in the flags of extent states ever. + */ + ASSERT(!waitqueue_active(&state->wq)); + free_extent_state(state); + + cond_resched_lock(&tree->lock); + } + spin_unlock(&tree->lock); +} + +static struct extent_state *alloc_extent_state(gfp_t mask) +{ + struct extent_state *state; + + /* + * The given mask might be not appropriate for the slab allocator, + * drop the unsupported bits + */ + mask &= ~(__GFP_DMA32|__GFP_HIGHMEM); + state = kmem_cache_alloc(extent_state_cache, mask); + if (!state) + return state; + state->state = 0; + RB_CLEAR_NODE(&state->rb_node); + btrfs_leak_debug_add_state(state); + refcount_set(&state->refs, 1); + init_waitqueue_head(&state->wq); + trace_alloc_extent_state(state, mask, _RET_IP_); + return state; +} + +static struct extent_state *alloc_extent_state_atomic(struct extent_state *prealloc) +{ + if (!prealloc) + prealloc = alloc_extent_state(GFP_ATOMIC); + + return prealloc; +} + +void free_extent_state(struct extent_state *state) +{ + if (!state) + return; + if (refcount_dec_and_test(&state->refs)) { + WARN_ON(extent_state_in_tree(state)); + btrfs_leak_debug_del_state(state); + trace_free_extent_state(state, _RET_IP_); + kmem_cache_free(extent_state_cache, state); + } +} + +static int add_extent_changeset(struct extent_state *state, u32 bits, + struct extent_changeset *changeset, + int set) +{ + int ret; + + if (!changeset) + return 0; + if (set && (state->state & bits) == bits) + return 0; + if (!set && (state->state & bits) == 0) + return 0; + changeset->bytes_changed += state->end - state->start + 1; + ret = ulist_add(&changeset->range_changed, state->start, state->end, + GFP_ATOMIC); + return ret; +} + +static inline struct extent_state *next_state(struct extent_state *state) +{ + struct rb_node *next = rb_next(&state->rb_node); + + if (next) + return rb_entry(next, struct extent_state, rb_node); + else + return NULL; +} + +static inline struct extent_state *prev_state(struct extent_state *state) +{ + struct rb_node *next = rb_prev(&state->rb_node); + + if (next) + return rb_entry(next, struct extent_state, rb_node); + else + return NULL; +} + +/* + * Search @tree for an entry that contains @offset. Such entry would have + * entry->start <= offset && entry->end >= offset. + * + * @tree: the tree to search + * @offset: offset that should fall within an entry in @tree + * @node_ret: pointer where new node should be anchored (used when inserting an + * entry in the tree) + * @parent_ret: points to entry which would have been the parent of the entry, + * containing @offset + * + * Return a pointer to the entry that contains @offset byte address and don't change + * @node_ret and @parent_ret. + * + * If no such entry exists, return pointer to entry that ends before @offset + * and fill parameters @node_ret and @parent_ret, ie. does not return NULL. + */ +static inline struct extent_state *tree_search_for_insert(struct extent_io_tree *tree, + u64 offset, + struct rb_node ***node_ret, + struct rb_node **parent_ret) +{ + struct rb_root *root = &tree->state; + struct rb_node **node = &root->rb_node; + struct rb_node *prev = NULL; + struct extent_state *entry = NULL; + + while (*node) { + prev = *node; + entry = rb_entry(prev, struct extent_state, rb_node); + + if (offset < entry->start) + node = &(*node)->rb_left; + else if (offset > entry->end) + node = &(*node)->rb_right; + else + return entry; + } + + if (node_ret) + *node_ret = node; + if (parent_ret) + *parent_ret = prev; + + /* Search neighbors until we find the first one past the end */ + while (entry && offset > entry->end) + entry = next_state(entry); + + return entry; +} + +/* + * Search offset in the tree or fill neighbor rbtree node pointers. + * + * @tree: the tree to search + * @offset: offset that should fall within an entry in @tree + * @next_ret: pointer to the first entry whose range ends after @offset + * @prev_ret: pointer to the first entry whose range begins before @offset + * + * Return a pointer to the entry that contains @offset byte address. If no + * such entry exists, then return NULL and fill @prev_ret and @next_ret. + * Otherwise return the found entry and other pointers are left untouched. + */ +static struct extent_state *tree_search_prev_next(struct extent_io_tree *tree, + u64 offset, + struct extent_state **prev_ret, + struct extent_state **next_ret) +{ + struct rb_root *root = &tree->state; + struct rb_node **node = &root->rb_node; + struct extent_state *orig_prev; + struct extent_state *entry = NULL; + + ASSERT(prev_ret); + ASSERT(next_ret); + + while (*node) { + entry = rb_entry(*node, struct extent_state, rb_node); + + if (offset < entry->start) + node = &(*node)->rb_left; + else if (offset > entry->end) + node = &(*node)->rb_right; + else + return entry; + } + + orig_prev = entry; + while (entry && offset > entry->end) + entry = next_state(entry); + *next_ret = entry; + entry = orig_prev; + + while (entry && offset < entry->start) + entry = prev_state(entry); + *prev_ret = entry; + + return NULL; +} + +/* + * Inexact rb-tree search, return the next entry if @offset is not found + */ +static inline struct extent_state *tree_search(struct extent_io_tree *tree, u64 offset) +{ + return tree_search_for_insert(tree, offset, NULL, NULL); +} + +static void extent_io_tree_panic(struct extent_io_tree *tree, int err) +{ + btrfs_panic(tree->fs_info, err, + "locking error: extent tree was modified by another thread while locked"); +} + +/* + * Utility function to look for merge candidates inside a given range. Any + * extents with matching state are merged together into a single extent in the + * tree. Extents with EXTENT_IO in their state field are not merged because + * the end_io handlers need to be able to do operations on them without + * sleeping (or doing allocations/splits). + * + * This should be called with the tree lock held. + */ +static void merge_state(struct extent_io_tree *tree, struct extent_state *state) +{ + struct extent_state *other; + + if (state->state & (EXTENT_LOCKED | EXTENT_BOUNDARY)) + return; + + other = prev_state(state); + if (other && other->end == state->start - 1 && + other->state == state->state) { + if (tree->inode) + btrfs_merge_delalloc_extent(tree->inode, state, other); + state->start = other->start; + rb_erase(&other->rb_node, &tree->state); + RB_CLEAR_NODE(&other->rb_node); + free_extent_state(other); + } + other = next_state(state); + if (other && other->start == state->end + 1 && + other->state == state->state) { + if (tree->inode) + btrfs_merge_delalloc_extent(tree->inode, state, other); + state->end = other->end; + rb_erase(&other->rb_node, &tree->state); + RB_CLEAR_NODE(&other->rb_node); + free_extent_state(other); + } +} + +static void set_state_bits(struct extent_io_tree *tree, + struct extent_state *state, + u32 bits, struct extent_changeset *changeset) +{ + u32 bits_to_set = bits & ~EXTENT_CTLBITS; + int ret; + + if (tree->inode) + btrfs_set_delalloc_extent(tree->inode, state, bits); + + ret = add_extent_changeset(state, bits_to_set, changeset, 1); + BUG_ON(ret < 0); + state->state |= bits_to_set; +} + +/* + * Insert an extent_state struct into the tree. 'bits' are set on the + * struct before it is inserted. + * + * This may return -EEXIST if the extent is already there, in which case the + * state struct is freed. + * + * The tree lock is not taken internally. This is a utility function and + * probably isn't what you want to call (see set/clear_extent_bit). + */ +static int insert_state(struct extent_io_tree *tree, + struct extent_state *state, + u32 bits, struct extent_changeset *changeset) +{ + struct rb_node **node; + struct rb_node *parent = NULL; + const u64 end = state->end; + + set_state_bits(tree, state, bits, changeset); + + node = &tree->state.rb_node; + while (*node) { + struct extent_state *entry; + + parent = *node; + entry = rb_entry(parent, struct extent_state, rb_node); + + if (end < entry->start) { + node = &(*node)->rb_left; + } else if (end > entry->end) { + node = &(*node)->rb_right; + } else { + btrfs_err(tree->fs_info, + "found node %llu %llu on insert of %llu %llu", + entry->start, entry->end, state->start, end); + return -EEXIST; + } + } + + rb_link_node(&state->rb_node, parent, node); + rb_insert_color(&state->rb_node, &tree->state); + + merge_state(tree, state); + return 0; +} + +/* + * Insert state to @tree to the location given by @node and @parent. + */ +static void insert_state_fast(struct extent_io_tree *tree, + struct extent_state *state, struct rb_node **node, + struct rb_node *parent, unsigned bits, + struct extent_changeset *changeset) +{ + set_state_bits(tree, state, bits, changeset); + rb_link_node(&state->rb_node, parent, node); + rb_insert_color(&state->rb_node, &tree->state); + merge_state(tree, state); +} + +/* + * Split a given extent state struct in two, inserting the preallocated + * struct 'prealloc' as the newly created second half. 'split' indicates an + * offset inside 'orig' where it should be split. + * + * Before calling, + * the tree has 'orig' at [orig->start, orig->end]. After calling, there + * are two extent state structs in the tree: + * prealloc: [orig->start, split - 1] + * orig: [ split, orig->end ] + * + * The tree locks are not taken by this function. They need to be held + * by the caller. + */ +static int split_state(struct extent_io_tree *tree, struct extent_state *orig, + struct extent_state *prealloc, u64 split) +{ + struct rb_node *parent = NULL; + struct rb_node **node; + + if (tree->inode) + btrfs_split_delalloc_extent(tree->inode, orig, split); + + prealloc->start = orig->start; + prealloc->end = split - 1; + prealloc->state = orig->state; + orig->start = split; + + parent = &orig->rb_node; + node = &parent; + while (*node) { + struct extent_state *entry; + + parent = *node; + entry = rb_entry(parent, struct extent_state, rb_node); + + if (prealloc->end < entry->start) { + node = &(*node)->rb_left; + } else if (prealloc->end > entry->end) { + node = &(*node)->rb_right; + } else { + free_extent_state(prealloc); + return -EEXIST; + } + } + + rb_link_node(&prealloc->rb_node, parent, node); + rb_insert_color(&prealloc->rb_node, &tree->state); + + return 0; +} + +/* + * Utility function to clear some bits in an extent state struct. It will + * optionally wake up anyone waiting on this state (wake == 1). + * + * If no bits are set on the state struct after clearing things, the + * struct is freed and removed from the tree + */ +static struct extent_state *clear_state_bit(struct extent_io_tree *tree, + struct extent_state *state, + u32 bits, int wake, + struct extent_changeset *changeset) +{ + struct extent_state *next; + u32 bits_to_clear = bits & ~EXTENT_CTLBITS; + int ret; + + if (tree->inode) + btrfs_clear_delalloc_extent(tree->inode, state, bits); + + ret = add_extent_changeset(state, bits_to_clear, changeset, 0); + BUG_ON(ret < 0); + state->state &= ~bits_to_clear; + if (wake) + wake_up(&state->wq); + if (state->state == 0) { + next = next_state(state); + if (extent_state_in_tree(state)) { + rb_erase(&state->rb_node, &tree->state); + RB_CLEAR_NODE(&state->rb_node); + free_extent_state(state); + } else { + WARN_ON(1); + } + } else { + merge_state(tree, state); + next = next_state(state); + } + return next; +} + +/* + * Clear some bits on a range in the tree. This may require splitting or + * inserting elements in the tree, so the gfp mask is used to indicate which + * allocations or sleeping are allowed. + * + * Pass 'wake' == 1 to kick any sleepers, and 'delete' == 1 to remove the given + * range from the tree regardless of state (ie for truncate). + * + * The range [start, end] is inclusive. + * + * This takes the tree lock, and returns 0 on success and < 0 on error. + */ +int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_state **cached_state, + gfp_t mask, struct extent_changeset *changeset) +{ + struct extent_state *state; + struct extent_state *cached; + struct extent_state *prealloc = NULL; + u64 last_end; + int err; + int clear = 0; + int wake; + int delete = (bits & EXTENT_CLEAR_ALL_BITS); + + btrfs_debug_check_extent_io_range(tree, start, end); + trace_btrfs_clear_extent_bit(tree, start, end - start + 1, bits); + + if (delete) + bits |= ~EXTENT_CTLBITS; + + if (bits & EXTENT_DELALLOC) + bits |= EXTENT_NORESERVE; + + wake = (bits & EXTENT_LOCKED) ? 1 : 0; + if (bits & (EXTENT_LOCKED | EXTENT_BOUNDARY)) + clear = 1; +again: + if (!prealloc) { + /* + * Don't care for allocation failure here because we might end + * up not needing the pre-allocated extent state at all, which + * is the case if we only have in the tree extent states that + * cover our input range and don't cover too any other range. + * If we end up needing a new extent state we allocate it later. + */ + prealloc = alloc_extent_state(mask); + } + + spin_lock(&tree->lock); + if (cached_state) { + cached = *cached_state; + + if (clear) { + *cached_state = NULL; + cached_state = NULL; + } + + if (cached && extent_state_in_tree(cached) && + cached->start <= start && cached->end > start) { + if (clear) + refcount_dec(&cached->refs); + state = cached; + goto hit_next; + } + if (clear) + free_extent_state(cached); + } + + /* This search will find the extents that end after our range starts. */ + state = tree_search(tree, start); + if (!state) + goto out; +hit_next: + if (state->start > end) + goto out; + WARN_ON(state->end < start); + last_end = state->end; + + /* The state doesn't have the wanted bits, go ahead. */ + if (!(state->state & bits)) { + state = next_state(state); + goto next; + } + + /* + * | ---- desired range ---- | + * | state | or + * | ------------- state -------------- | + * + * We need to split the extent we found, and may flip bits on second + * half. + * + * If the extent we found extends past our range, we just split and + * search again. It'll get split again the next time though. + * + * If the extent we found is inside our range, we clear the desired bit + * on it. + */ + + if (state->start < start) { + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) + goto search_again; + err = split_state(tree, state, prealloc, start); + if (err) + extent_io_tree_panic(tree, err); + + prealloc = NULL; + if (err) + goto out; + if (state->end <= end) { + state = clear_state_bit(tree, state, bits, wake, changeset); + goto next; + } + goto search_again; + } + /* + * | ---- desired range ---- | + * | state | + * We need to split the extent, and clear the bit on the first half. + */ + if (state->start <= end && state->end > end) { + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) + goto search_again; + err = split_state(tree, state, prealloc, end + 1); + if (err) + extent_io_tree_panic(tree, err); + + if (wake) + wake_up(&state->wq); + + clear_state_bit(tree, prealloc, bits, wake, changeset); + + prealloc = NULL; + goto out; + } + + state = clear_state_bit(tree, state, bits, wake, changeset); +next: + if (last_end == (u64)-1) + goto out; + start = last_end + 1; + if (start <= end && state && !need_resched()) + goto hit_next; + +search_again: + if (start > end) + goto out; + spin_unlock(&tree->lock); + if (gfpflags_allow_blocking(mask)) + cond_resched(); + goto again; + +out: + spin_unlock(&tree->lock); + if (prealloc) + free_extent_state(prealloc); + + return 0; + +} + +static void wait_on_state(struct extent_io_tree *tree, + struct extent_state *state) + __releases(tree->lock) + __acquires(tree->lock) +{ + DEFINE_WAIT(wait); + prepare_to_wait(&state->wq, &wait, TASK_UNINTERRUPTIBLE); + spin_unlock(&tree->lock); + schedule(); + spin_lock(&tree->lock); + finish_wait(&state->wq, &wait); +} + +/* + * Wait for one or more bits to clear on a range in the state tree. + * The range [start, end] is inclusive. + * The tree lock is taken by this function + */ +void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits, + struct extent_state **cached_state) +{ + struct extent_state *state; + + btrfs_debug_check_extent_io_range(tree, start, end); + + spin_lock(&tree->lock); +again: + /* + * Maintain cached_state, as we may not remove it from the tree if there + * are more bits than the bits we're waiting on set on this state. + */ + if (cached_state && *cached_state) { + state = *cached_state; + if (extent_state_in_tree(state) && + state->start <= start && start < state->end) + goto process_node; + } + while (1) { + /* + * This search will find all the extents that end after our + * range starts. + */ + state = tree_search(tree, start); +process_node: + if (!state) + break; + if (state->start > end) + goto out; + + if (state->state & bits) { + start = state->start; + refcount_inc(&state->refs); + wait_on_state(tree, state); + free_extent_state(state); + goto again; + } + start = state->end + 1; + + if (start > end) + break; + + if (!cond_resched_lock(&tree->lock)) { + state = next_state(state); + goto process_node; + } + } +out: + /* This state is no longer useful, clear it and free it up. */ + if (cached_state && *cached_state) { + state = *cached_state; + *cached_state = NULL; + free_extent_state(state); + } + spin_unlock(&tree->lock); +} + +static void cache_state_if_flags(struct extent_state *state, + struct extent_state **cached_ptr, + unsigned flags) +{ + if (cached_ptr && !(*cached_ptr)) { + if (!flags || (state->state & flags)) { + *cached_ptr = state; + refcount_inc(&state->refs); + } + } +} + +static void cache_state(struct extent_state *state, + struct extent_state **cached_ptr) +{ + return cache_state_if_flags(state, cached_ptr, + EXTENT_LOCKED | EXTENT_BOUNDARY); +} + +/* + * Find the first state struct with 'bits' set after 'start', and return it. + * tree->lock must be held. NULL will returned if nothing was found after + * 'start'. + */ +static struct extent_state *find_first_extent_bit_state(struct extent_io_tree *tree, + u64 start, u32 bits) +{ + struct extent_state *state; + + /* + * This search will find all the extents that end after our range + * starts. + */ + state = tree_search(tree, start); + while (state) { + if (state->end >= start && (state->state & bits)) + return state; + state = next_state(state); + } + return NULL; +} + +/* + * Find the first offset in the io tree with one or more @bits set. + * + * Note: If there are multiple bits set in @bits, any of them will match. + * + * Return 0 if we find something, and update @start_ret and @end_ret. + * Return 1 if we found nothing. + */ +int find_first_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, u32 bits, + struct extent_state **cached_state) +{ + struct extent_state *state; + int ret = 1; + + spin_lock(&tree->lock); + if (cached_state && *cached_state) { + state = *cached_state; + if (state->end == start - 1 && extent_state_in_tree(state)) { + while ((state = next_state(state)) != NULL) { + if (state->state & bits) + goto got_it; + } + free_extent_state(*cached_state); + *cached_state = NULL; + goto out; + } + free_extent_state(*cached_state); + *cached_state = NULL; + } + + state = find_first_extent_bit_state(tree, start, bits); +got_it: + if (state) { + cache_state_if_flags(state, cached_state, 0); + *start_ret = state->start; + *end_ret = state->end; + ret = 0; + } +out: + spin_unlock(&tree->lock); + return ret; +} + +/* + * Find a contiguous area of bits + * + * @tree: io tree to check + * @start: offset to start the search from + * @start_ret: the first offset we found with the bits set + * @end_ret: the final contiguous range of the bits that were set + * @bits: bits to look for + * + * set_extent_bit and clear_extent_bit can temporarily split contiguous ranges + * to set bits appropriately, and then merge them again. During this time it + * will drop the tree->lock, so use this helper if you want to find the actual + * contiguous area for given bits. We will search to the first bit we find, and + * then walk down the tree until we find a non-contiguous area. The area + * returned will be the full contiguous area with the bits set. + */ +int find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, u32 bits) +{ + struct extent_state *state; + int ret = 1; + + spin_lock(&tree->lock); + state = find_first_extent_bit_state(tree, start, bits); + if (state) { + *start_ret = state->start; + *end_ret = state->end; + while ((state = next_state(state)) != NULL) { + if (state->start > (*end_ret + 1)) + break; + *end_ret = state->end; + } + ret = 0; + } + spin_unlock(&tree->lock); + return ret; +} + +/* + * Find a contiguous range of bytes in the file marked as delalloc, not more + * than 'max_bytes'. start and end are used to return the range, + * + * True is returned if we find something, false if nothing was in the tree. + */ +bool btrfs_find_delalloc_range(struct extent_io_tree *tree, u64 *start, + u64 *end, u64 max_bytes, + struct extent_state **cached_state) +{ + struct extent_state *state; + u64 cur_start = *start; + bool found = false; + u64 total_bytes = 0; + + spin_lock(&tree->lock); + + /* + * This search will find all the extents that end after our range + * starts. + */ + state = tree_search(tree, cur_start); + if (!state) { + *end = (u64)-1; + goto out; + } + + while (state) { + if (found && (state->start != cur_start || + (state->state & EXTENT_BOUNDARY))) { + goto out; + } + if (!(state->state & EXTENT_DELALLOC)) { + if (!found) + *end = state->end; + goto out; + } + if (!found) { + *start = state->start; + *cached_state = state; + refcount_inc(&state->refs); + } + found = true; + *end = state->end; + cur_start = state->end + 1; + total_bytes += state->end - state->start + 1; + if (total_bytes >= max_bytes) + break; + state = next_state(state); + } +out: + spin_unlock(&tree->lock); + return found; +} + +/* + * Set some bits on a range in the tree. This may require allocations or + * sleeping, so the gfp mask is used to indicate what is allowed. + * + * If any of the exclusive bits are set, this will fail with -EEXIST if some + * part of the range already has the desired bits set. The extent_state of the + * existing range is returned in failed_state in this case, and the start of the + * existing range is returned in failed_start. failed_state is used as an + * optimization for wait_extent_bit, failed_start must be used as the source of + * truth as failed_state may have changed since we returned. + * + * [start, end] is inclusive This takes the tree lock. + */ +static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, u64 *failed_start, + struct extent_state **failed_state, + struct extent_state **cached_state, + struct extent_changeset *changeset, gfp_t mask) +{ + struct extent_state *state; + struct extent_state *prealloc = NULL; + struct rb_node **p; + struct rb_node *parent; + int err = 0; + u64 last_start; + u64 last_end; + u32 exclusive_bits = (bits & EXTENT_LOCKED); + + btrfs_debug_check_extent_io_range(tree, start, end); + trace_btrfs_set_extent_bit(tree, start, end - start + 1, bits); + + if (exclusive_bits) + ASSERT(failed_start); + else + ASSERT(failed_start == NULL && failed_state == NULL); +again: + if (!prealloc) { + /* + * Don't care for allocation failure here because we might end + * up not needing the pre-allocated extent state at all, which + * is the case if we only have in the tree extent states that + * cover our input range and don't cover too any other range. + * If we end up needing a new extent state we allocate it later. + */ + prealloc = alloc_extent_state(mask); + } + + spin_lock(&tree->lock); + if (cached_state && *cached_state) { + state = *cached_state; + if (state->start <= start && state->end > start && + extent_state_in_tree(state)) + goto hit_next; + } + /* + * This search will find all the extents that end after our range + * starts. + */ + state = tree_search_for_insert(tree, start, &p, &parent); + if (!state) { + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) + goto search_again; + prealloc->start = start; + prealloc->end = end; + insert_state_fast(tree, prealloc, p, parent, bits, changeset); + cache_state(prealloc, cached_state); + prealloc = NULL; + goto out; + } +hit_next: + last_start = state->start; + last_end = state->end; + + /* + * | ---- desired range ---- | + * | state | + * + * Just lock what we found and keep going + */ + if (state->start == start && state->end <= end) { + if (state->state & exclusive_bits) { + *failed_start = state->start; + cache_state(state, failed_state); + err = -EEXIST; + goto out; + } + + set_state_bits(tree, state, bits, changeset); + cache_state(state, cached_state); + merge_state(tree, state); + if (last_end == (u64)-1) + goto out; + start = last_end + 1; + state = next_state(state); + if (start < end && state && state->start == start && + !need_resched()) + goto hit_next; + goto search_again; + } + + /* + * | ---- desired range ---- | + * | state | + * or + * | ------------- state -------------- | + * + * We need to split the extent we found, and may flip bits on second + * half. + * + * If the extent we found extends past our range, we just split and + * search again. It'll get split again the next time though. + * + * If the extent we found is inside our range, we set the desired bit + * on it. + */ + if (state->start < start) { + if (state->state & exclusive_bits) { + *failed_start = start; + cache_state(state, failed_state); + err = -EEXIST; + goto out; + } + + /* + * If this extent already has all the bits we want set, then + * skip it, not necessary to split it or do anything with it. + */ + if ((state->state & bits) == bits) { + start = state->end + 1; + cache_state(state, cached_state); + goto search_again; + } + + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) + goto search_again; + err = split_state(tree, state, prealloc, start); + if (err) + extent_io_tree_panic(tree, err); + + prealloc = NULL; + if (err) + goto out; + if (state->end <= end) { + set_state_bits(tree, state, bits, changeset); + cache_state(state, cached_state); + merge_state(tree, state); + if (last_end == (u64)-1) + goto out; + start = last_end + 1; + state = next_state(state); + if (start < end && state && state->start == start && + !need_resched()) + goto hit_next; + } + goto search_again; + } + /* + * | ---- desired range ---- | + * | state | or | state | + * + * There's a hole, we need to insert something in it and ignore the + * extent we found. + */ + if (state->start > start) { + u64 this_end; + if (end < last_start) + this_end = end; + else + this_end = last_start - 1; + + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) + goto search_again; + + /* + * Avoid to free 'prealloc' if it can be merged with the later + * extent. + */ + prealloc->start = start; + prealloc->end = this_end; + err = insert_state(tree, prealloc, bits, changeset); + if (err) + extent_io_tree_panic(tree, err); + + cache_state(prealloc, cached_state); + prealloc = NULL; + start = this_end + 1; + goto search_again; + } + /* + * | ---- desired range ---- | + * | state | + * + * We need to split the extent, and set the bit on the first half + */ + if (state->start <= end && state->end > end) { + if (state->state & exclusive_bits) { + *failed_start = start; + cache_state(state, failed_state); + err = -EEXIST; + goto out; + } + + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) + goto search_again; + err = split_state(tree, state, prealloc, end + 1); + if (err) + extent_io_tree_panic(tree, err); + + set_state_bits(tree, prealloc, bits, changeset); + cache_state(prealloc, cached_state); + merge_state(tree, prealloc); + prealloc = NULL; + goto out; + } + +search_again: + if (start > end) + goto out; + spin_unlock(&tree->lock); + if (gfpflags_allow_blocking(mask)) + cond_resched(); + goto again; + +out: + spin_unlock(&tree->lock); + if (prealloc) + free_extent_state(prealloc); + + return err; + +} + +int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_state **cached_state, gfp_t mask) +{ + return __set_extent_bit(tree, start, end, bits, NULL, NULL, + cached_state, NULL, mask); +} + +/* + * Convert all bits in a given range from one bit to another + * + * @tree: the io tree to search + * @start: the start offset in bytes + * @end: the end offset in bytes (inclusive) + * @bits: the bits to set in this range + * @clear_bits: the bits to clear in this range + * @cached_state: state that we're going to cache + * + * This will go through and set bits for the given range. If any states exist + * already in this range they are set with the given bit and cleared of the + * clear_bits. This is only meant to be used by things that are mergeable, ie. + * converting from say DELALLOC to DIRTY. This is not meant to be used with + * boundary bits like LOCK. + * + * All allocations are done with GFP_NOFS. + */ +int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, u32 clear_bits, + struct extent_state **cached_state) +{ + struct extent_state *state; + struct extent_state *prealloc = NULL; + struct rb_node **p; + struct rb_node *parent; + int err = 0; + u64 last_start; + u64 last_end; + bool first_iteration = true; + + btrfs_debug_check_extent_io_range(tree, start, end); + trace_btrfs_convert_extent_bit(tree, start, end - start + 1, bits, + clear_bits); + +again: + if (!prealloc) { + /* + * Best effort, don't worry if extent state allocation fails + * here for the first iteration. We might have a cached state + * that matches exactly the target range, in which case no + * extent state allocations are needed. We'll only know this + * after locking the tree. + */ + prealloc = alloc_extent_state(GFP_NOFS); + if (!prealloc && !first_iteration) + return -ENOMEM; + } + + spin_lock(&tree->lock); + if (cached_state && *cached_state) { + state = *cached_state; + if (state->start <= start && state->end > start && + extent_state_in_tree(state)) + goto hit_next; + } + + /* + * This search will find all the extents that end after our range + * starts. + */ + state = tree_search_for_insert(tree, start, &p, &parent); + if (!state) { + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) { + err = -ENOMEM; + goto out; + } + prealloc->start = start; + prealloc->end = end; + insert_state_fast(tree, prealloc, p, parent, bits, NULL); + cache_state(prealloc, cached_state); + prealloc = NULL; + goto out; + } +hit_next: + last_start = state->start; + last_end = state->end; + + /* + * | ---- desired range ---- | + * | state | + * + * Just lock what we found and keep going. + */ + if (state->start == start && state->end <= end) { + set_state_bits(tree, state, bits, NULL); + cache_state(state, cached_state); + state = clear_state_bit(tree, state, clear_bits, 0, NULL); + if (last_end == (u64)-1) + goto out; + start = last_end + 1; + if (start < end && state && state->start == start && + !need_resched()) + goto hit_next; + goto search_again; + } + + /* + * | ---- desired range ---- | + * | state | + * or + * | ------------- state -------------- | + * + * We need to split the extent we found, and may flip bits on second + * half. + * + * If the extent we found extends past our range, we just split and + * search again. It'll get split again the next time though. + * + * If the extent we found is inside our range, we set the desired bit + * on it. + */ + if (state->start < start) { + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) { + err = -ENOMEM; + goto out; + } + err = split_state(tree, state, prealloc, start); + if (err) + extent_io_tree_panic(tree, err); + prealloc = NULL; + if (err) + goto out; + if (state->end <= end) { + set_state_bits(tree, state, bits, NULL); + cache_state(state, cached_state); + state = clear_state_bit(tree, state, clear_bits, 0, NULL); + if (last_end == (u64)-1) + goto out; + start = last_end + 1; + if (start < end && state && state->start == start && + !need_resched()) + goto hit_next; + } + goto search_again; + } + /* + * | ---- desired range ---- | + * | state | or | state | + * + * There's a hole, we need to insert something in it and ignore the + * extent we found. + */ + if (state->start > start) { + u64 this_end; + if (end < last_start) + this_end = end; + else + this_end = last_start - 1; + + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) { + err = -ENOMEM; + goto out; + } + + /* + * Avoid to free 'prealloc' if it can be merged with the later + * extent. + */ + prealloc->start = start; + prealloc->end = this_end; + err = insert_state(tree, prealloc, bits, NULL); + if (err) + extent_io_tree_panic(tree, err); + cache_state(prealloc, cached_state); + prealloc = NULL; + start = this_end + 1; + goto search_again; + } + /* + * | ---- desired range ---- | + * | state | + * + * We need to split the extent, and set the bit on the first half. + */ + if (state->start <= end && state->end > end) { + prealloc = alloc_extent_state_atomic(prealloc); + if (!prealloc) { + err = -ENOMEM; + goto out; + } + + err = split_state(tree, state, prealloc, end + 1); + if (err) + extent_io_tree_panic(tree, err); + + set_state_bits(tree, prealloc, bits, NULL); + cache_state(prealloc, cached_state); + clear_state_bit(tree, prealloc, clear_bits, 0, NULL); + prealloc = NULL; + goto out; + } + +search_again: + if (start > end) + goto out; + spin_unlock(&tree->lock); + cond_resched(); + first_iteration = false; + goto again; + +out: + spin_unlock(&tree->lock); + if (prealloc) + free_extent_state(prealloc); + + return err; +} + +/* + * Find the first range that has @bits not set. This range could start before + * @start. + * + * @tree: the tree to search + * @start: offset at/after which the found extent should start + * @start_ret: records the beginning of the range + * @end_ret: records the end of the range (inclusive) + * @bits: the set of bits which must be unset + * + * Since unallocated range is also considered one which doesn't have the bits + * set it's possible that @end_ret contains -1, this happens in case the range + * spans (last_range_end, end of device]. In this case it's up to the caller to + * trim @end_ret to the appropriate size. + */ +void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, u32 bits) +{ + struct extent_state *state; + struct extent_state *prev = NULL, *next = NULL; + + spin_lock(&tree->lock); + + /* Find first extent with bits cleared */ + while (1) { + state = tree_search_prev_next(tree, start, &prev, &next); + if (!state && !next && !prev) { + /* + * Tree is completely empty, send full range and let + * caller deal with it + */ + *start_ret = 0; + *end_ret = -1; + goto out; + } else if (!state && !next) { + /* + * We are past the last allocated chunk, set start at + * the end of the last extent. + */ + *start_ret = prev->end + 1; + *end_ret = -1; + goto out; + } else if (!state) { + state = next; + } + + /* + * At this point 'state' either contains 'start' or start is + * before 'state' + */ + if (in_range(start, state->start, state->end - state->start + 1)) { + if (state->state & bits) { + /* + * |--range with bits sets--| + * | + * start + */ + start = state->end + 1; + } else { + /* + * 'start' falls within a range that doesn't + * have the bits set, so take its start as the + * beginning of the desired range + * + * |--range with bits cleared----| + * | + * start + */ + *start_ret = state->start; + break; + } + } else { + /* + * |---prev range---|---hole/unset---|---node range---| + * | + * start + * + * or + * + * |---hole/unset--||--first node--| + * 0 | + * start + */ + if (prev) + *start_ret = prev->end + 1; + else + *start_ret = 0; + break; + } + } + + /* + * Find the longest stretch from start until an entry which has the + * bits set + */ + while (state) { + if (state->end >= start && !(state->state & bits)) { + *end_ret = state->end; + } else { + *end_ret = state->start - 1; + break; + } + state = next_state(state); + } +out: + spin_unlock(&tree->lock); +} + +/* + * Count the number of bytes in the tree that have a given bit(s) set. This + * can be fairly slow, except for EXTENT_DIRTY which is cached. The total + * number found is returned. + */ +u64 count_range_bits(struct extent_io_tree *tree, + u64 *start, u64 search_end, u64 max_bytes, + u32 bits, int contig) +{ + struct extent_state *state; + u64 cur_start = *start; + u64 total_bytes = 0; + u64 last = 0; + int found = 0; + + if (WARN_ON(search_end <= cur_start)) + return 0; + + spin_lock(&tree->lock); + + /* + * This search will find all the extents that end after our range + * starts. + */ + state = tree_search(tree, cur_start); + while (state) { + if (state->start > search_end) + break; + if (contig && found && state->start > last + 1) + break; + if (state->end >= cur_start && (state->state & bits) == bits) { + total_bytes += min(search_end, state->end) + 1 - + max(cur_start, state->start); + if (total_bytes >= max_bytes) + break; + if (!found) { + *start = max(cur_start, state->start); + found = 1; + } + last = state->end; + } else if (contig && found) { + break; + } + state = next_state(state); + } + spin_unlock(&tree->lock); + return total_bytes; +} + +/* + * Searche a range in the state tree for a given mask. If 'filled' == 1, this + * returns 1 only if every extent in the tree has the bits set. Otherwise, 1 + * is returned if any bit in the range is found set. + */ +int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, int filled, struct extent_state *cached) +{ + struct extent_state *state = NULL; + int bitset = 0; + + spin_lock(&tree->lock); + if (cached && extent_state_in_tree(cached) && cached->start <= start && + cached->end > start) + state = cached; + else + state = tree_search(tree, start); + while (state && start <= end) { + if (filled && state->start > start) { + bitset = 0; + break; + } + + if (state->start > end) + break; + + if (state->state & bits) { + bitset = 1; + if (!filled) + break; + } else if (filled) { + bitset = 0; + break; + } + + if (state->end == (u64)-1) + break; + + start = state->end + 1; + if (start > end) + break; + state = next_state(state); + } + + /* We ran out of states and were still inside of our range. */ + if (filled && !state) + bitset = 0; + spin_unlock(&tree->lock); + return bitset; +} + +/* Wrappers around set/clear extent bit */ +int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_changeset *changeset) +{ + /* + * We don't support EXTENT_LOCKED yet, as current changeset will + * record any bits changed, so for EXTENT_LOCKED case, it will + * either fail with -EEXIST or changeset will record the whole + * range. + */ + ASSERT(!(bits & EXTENT_LOCKED)); + + return __set_extent_bit(tree, start, end, bits, NULL, NULL, NULL, + changeset, GFP_NOFS); +} + +int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_changeset *changeset) +{ + /* + * Don't support EXTENT_LOCKED case, same reason as + * set_record_extent_bits(). + */ + ASSERT(!(bits & EXTENT_LOCKED)); + + return __clear_extent_bit(tree, start, end, bits, NULL, GFP_NOFS, + changeset); +} + +int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end, + struct extent_state **cached) +{ + int err; + u64 failed_start; + + err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start, + NULL, cached, NULL, GFP_NOFS); + if (err == -EEXIST) { + if (failed_start > start) + clear_extent_bit(tree, start, failed_start - 1, + EXTENT_LOCKED, cached); + return 0; + } + return 1; +} + +/* + * Either insert or lock state struct between start and end use mask to tell + * us if waiting is desired. + */ +int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, + struct extent_state **cached_state) +{ + struct extent_state *failed_state = NULL; + int err; + u64 failed_start; + + err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, &failed_start, + &failed_state, cached_state, NULL, GFP_NOFS); + while (err == -EEXIST) { + if (failed_start != start) + clear_extent_bit(tree, start, failed_start - 1, + EXTENT_LOCKED, cached_state); + + wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED, + &failed_state); + err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, + &failed_start, &failed_state, + cached_state, NULL, GFP_NOFS); + } + return err; +} + +void __cold extent_state_free_cachep(void) +{ + btrfs_extent_state_leak_debug_check(); + kmem_cache_destroy(extent_state_cache); +} + +/* + * MODIFIED: + * - This gets called by extent_io_tree_init, so only init if the cache isn't + * NULL. + */ +int __init extent_state_init_cachep(void) +{ + if (extent_state_cache) + return 0; + + extent_state_cache = kmem_cache_create("btrfs_extent_state", + sizeof(struct extent_state), 0, + SLAB_MEM_SPREAD, NULL); + if (!extent_state_cache) + return -ENOMEM; + + return 0; +} diff --git a/kernel-shared/extent-io-tree.h b/kernel-shared/extent-io-tree.h new file mode 100644 index 00000000..cdee8c08 --- /dev/null +++ b/kernel-shared/extent-io-tree.h @@ -0,0 +1,239 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BTRFS_EXTENT_IO_TREE_H +#define BTRFS_EXTENT_IO_TREE_H + +#include "misc.h" + +struct extent_changeset; +struct io_failure_record; + +/* Bits for the extent state */ +enum { + ENUM_BIT(EXTENT_DIRTY), + ENUM_BIT(EXTENT_UPTODATE), + ENUM_BIT(EXTENT_LOCKED), + ENUM_BIT(EXTENT_NEW), + ENUM_BIT(EXTENT_DELALLOC), + ENUM_BIT(EXTENT_DEFRAG), + ENUM_BIT(EXTENT_BOUNDARY), + ENUM_BIT(EXTENT_NODATASUM), + ENUM_BIT(EXTENT_CLEAR_META_RESV), + ENUM_BIT(EXTENT_NEED_WAIT), + ENUM_BIT(EXTENT_NORESERVE), + ENUM_BIT(EXTENT_QGROUP_RESERVED), + ENUM_BIT(EXTENT_CLEAR_DATA_RESV), + /* + * Must be cleared only during ordered extent completion or on error + * paths if we did not manage to submit bios and create the ordered + * extents for the range. Should not be cleared during page release + * and page invalidation (if there is an ordered extent in flight), + * that is left for the ordered extent completion. + */ + ENUM_BIT(EXTENT_DELALLOC_NEW), + /* + * When an ordered extent successfully completes for a region marked as + * a new delalloc range, use this flag when clearing a new delalloc + * range to indicate that the VFS' inode number of bytes should be + * incremented and the inode's new delalloc bytes decremented, in an + * atomic way to prevent races with stat(2). + */ + ENUM_BIT(EXTENT_ADD_INODE_BYTES), + /* + * Set during truncate when we're clearing an entire range and we just + * want the extent states to go away. + */ + ENUM_BIT(EXTENT_CLEAR_ALL_BITS), +}; + +#define EXTENT_DO_ACCOUNTING (EXTENT_CLEAR_META_RESV | \ + EXTENT_CLEAR_DATA_RESV) +#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | \ + EXTENT_ADD_INODE_BYTES | \ + EXTENT_CLEAR_ALL_BITS) + +/* + * Redefined bits above which are used only in the device allocation tree, + * shouldn't be using EXTENT_LOCKED / EXTENT_BOUNDARY / EXTENT_CLEAR_META_RESV + * / EXTENT_CLEAR_DATA_RESV because they have special meaning to the bit + * manipulation functions + */ +#define CHUNK_ALLOCATED EXTENT_DIRTY +#define CHUNK_TRIMMED EXTENT_DEFRAG +#define CHUNK_STATE_MASK (CHUNK_ALLOCATED | \ + CHUNK_TRIMMED) + +enum { + IO_TREE_FS_PINNED_EXTENTS, + IO_TREE_FS_EXCLUDED_EXTENTS, + IO_TREE_BTREE_INODE_IO, + IO_TREE_INODE_IO, + IO_TREE_RELOC_BLOCKS, + IO_TREE_TRANS_DIRTY_PAGES, + IO_TREE_ROOT_DIRTY_LOG_PAGES, + IO_TREE_INODE_FILE_EXTENT, + IO_TREE_LOG_CSUM_RANGE, + IO_TREE_SELFTEST, + IO_TREE_DEVICE_ALLOC_STATE, +}; + +struct extent_io_tree { + struct rb_root state; + struct btrfs_fs_info *fs_info; + /* Inode associated with this tree, or NULL. */ + struct btrfs_inode *inode; + + /* Who owns this io tree, should be one of IO_TREE_* */ + u8 owner; + + spinlock_t lock; +}; + +struct extent_state { + u64 start; + u64 end; /* inclusive */ + struct rb_node rb_node; + + /* ADD NEW ELEMENTS AFTER THIS */ + wait_queue_head_t wq; + refcount_t refs; + u32 state; + +#ifdef CONFIG_BTRFS_DEBUG + struct list_head leak_list; +#endif +}; + +void extent_io_tree_init(struct btrfs_fs_info *fs_info, + struct extent_io_tree *tree, unsigned int owner); +void extent_io_tree_release(struct extent_io_tree *tree); + +int lock_extent(struct extent_io_tree *tree, u64 start, u64 end, + struct extent_state **cached); + +int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end, + struct extent_state **cached); + +int __init extent_state_init_cachep(void); +void __cold extent_state_free_cachep(void); + +u64 count_range_bits(struct extent_io_tree *tree, + u64 *start, u64 search_end, + u64 max_bytes, u32 bits, int contig); + +void free_extent_state(struct extent_state *state); +int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, int filled, struct extent_state *cached_state); +int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_changeset *changeset); +int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_state **cached, gfp_t mask, + struct extent_changeset *changeset); + +static inline int clear_extent_bit(struct extent_io_tree *tree, u64 start, + u64 end, u32 bits, + struct extent_state **cached) +{ + return __clear_extent_bit(tree, start, end, bits, cached, + GFP_NOFS, NULL); +} + +static inline int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end, + struct extent_state **cached) +{ + return __clear_extent_bit(tree, start, end, EXTENT_LOCKED, cached, + GFP_NOFS, NULL); +} + +static inline int clear_extent_bits(struct extent_io_tree *tree, u64 start, + u64 end, u32 bits) +{ + return clear_extent_bit(tree, start, end, bits, NULL); +} + +int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_changeset *changeset); +int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, struct extent_state **cached_state, gfp_t mask); + +static inline int set_extent_bits_nowait(struct extent_io_tree *tree, u64 start, + u64 end, u32 bits) +{ + return set_extent_bit(tree, start, end, bits, NULL, GFP_NOWAIT); +} + +static inline int set_extent_bits(struct extent_io_tree *tree, u64 start, + u64 end, u32 bits) +{ + return set_extent_bit(tree, start, end, bits, NULL, GFP_NOFS); +} + +static inline int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, + u64 end, struct extent_state **cached_state) +{ + return __clear_extent_bit(tree, start, end, EXTENT_UPTODATE, + cached_state, GFP_NOFS, NULL); +} + +static inline int set_extent_dirty(struct extent_io_tree *tree, u64 start, + u64 end, gfp_t mask) +{ + return set_extent_bit(tree, start, end, EXTENT_DIRTY, NULL, mask); +} + +static inline int clear_extent_dirty(struct extent_io_tree *tree, u64 start, + u64 end, struct extent_state **cached) +{ + return clear_extent_bit(tree, start, end, + EXTENT_DIRTY | EXTENT_DELALLOC | + EXTENT_DO_ACCOUNTING, cached); +} + +int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, + u32 bits, u32 clear_bits, + struct extent_state **cached_state); + +static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start, + u64 end, u32 extra_bits, + struct extent_state **cached_state) +{ + return set_extent_bit(tree, start, end, + EXTENT_DELALLOC | extra_bits, + cached_state, GFP_NOFS); +} + +static inline int set_extent_defrag(struct extent_io_tree *tree, u64 start, + u64 end, struct extent_state **cached_state) +{ + return set_extent_bit(tree, start, end, + EXTENT_DELALLOC | EXTENT_DEFRAG, + cached_state, GFP_NOFS); +} + +static inline int set_extent_new(struct extent_io_tree *tree, u64 start, + u64 end) +{ + return set_extent_bit(tree, start, end, EXTENT_NEW, NULL, GFP_NOFS); +} + +static inline int set_extent_uptodate(struct extent_io_tree *tree, u64 start, + u64 end, struct extent_state **cached_state, gfp_t mask) +{ + return set_extent_bit(tree, start, end, EXTENT_UPTODATE, + cached_state, mask); +} + +int find_first_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, u32 bits, + struct extent_state **cached_state); +void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, u32 bits); +int find_contiguous_extent_bit(struct extent_io_tree *tree, u64 start, + u64 *start_ret, u64 *end_ret, u32 bits); +bool btrfs_find_delalloc_range(struct extent_io_tree *tree, u64 *start, + u64 *end, u64 max_bytes, + struct extent_state **cached_state); +void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, u32 bits, + struct extent_state **cached_state); + +#endif /* BTRFS_EXTENT_IO_TREE_H */ diff --git a/kernel-shared/extent-tree.c b/kernel-shared/extent-tree.c index 5613012c..2a71b97a 100644 --- a/kernel-shared/extent-tree.c +++ b/kernel-shared/extent-tree.c @@ -34,6 +34,7 @@ #include "kernel-shared/zoned.h" #include "common/utils.h" #include "file-item.h" +#include "extent-io-tree.h" #define PENDING_EXTENT_INSERT 0 #define PENDING_EXTENT_DELETE 1 @@ -74,7 +75,7 @@ static int remove_sb_from_cache(struct btrfs_root *root, BUG_ON(ret); while (nr--) { clear_extent_dirty(free_space_cache, logical[nr], - logical[nr] + stripe_len - 1); + logical[nr] + stripe_len - 1, NULL); } kfree(logical); } @@ -142,7 +143,7 @@ static int cache_block_group(struct btrfs_root *root, if (key.objectid > last) { hole_size = key.objectid - last; set_extent_dirty(free_space_cache, last, - last + hole_size - 1); + last + hole_size - 1, GFP_NOFS); } if (key.type == BTRFS_METADATA_ITEM_KEY) last = key.objectid + root->fs_info->nodesize; @@ -155,7 +156,8 @@ next: if (block_group->start + block_group->length > last) { hole_size = block_group->start + block_group->length - last; - set_extent_dirty(free_space_cache, last, last + hole_size - 1); + set_extent_dirty(free_space_cache, last, last + hole_size - 1, + GFP_NOFS); } remove_sb_from_cache(root, block_group); block_group->cached = 1; @@ -295,7 +297,8 @@ again: while(1) { ret = find_first_extent_bit(&root->fs_info->free_space_cache, - last, &start, &end, EXTENT_DIRTY); + last, &start, &end, EXTENT_DIRTY, + NULL); if (ret) { goto new_group; } @@ -1803,7 +1806,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, u64 bytenr, cache->space_info->bytes_used -= num_bytes; if (mark_free) { set_extent_dirty(&info->free_space_cache, - bytenr, bytenr + num_bytes - 1); + bytenr, bytenr + num_bytes - 1, + GFP_NOFS); } } cache->used = old_val; @@ -1821,10 +1825,10 @@ static int update_pinned_extents(struct btrfs_fs_info *fs_info, if (pin) { set_extent_dirty(&fs_info->pinned_extents, - bytenr, bytenr + num - 1); + bytenr, bytenr + num - 1, GFP_NOFS); } else { clear_extent_dirty(&fs_info->pinned_extents, - bytenr, bytenr + num - 1); + bytenr, bytenr + num - 1, NULL); } while (num > 0) { cache = btrfs_lookup_block_group(fs_info, bytenr); @@ -1861,13 +1865,13 @@ void btrfs_finish_extent_commit(struct btrfs_trans_handle *trans) while(1) { ret = find_first_extent_bit(pinned_extents, 0, &start, &end, - EXTENT_DIRTY); + EXTENT_DIRTY, NULL); if (ret) break; update_pinned_extents(trans->fs_info, start, end + 1 - start, 0); - clear_extent_dirty(pinned_extents, start, end); - set_extent_dirty(free_space_cache, start, end); + clear_extent_dirty(pinned_extents, start, end, NULL); + set_extent_dirty(free_space_cache, start, end, GFP_NOFS); } } @@ -2254,20 +2258,23 @@ check_failed: } if (test_range_bit(&info->extent_ins, ins->objectid, - ins->objectid + num_bytes -1, EXTENT_LOCKED, 0)) { + ins->objectid + num_bytes -1, EXTENT_LOCKED, 0, + NULL)) { search_start = ins->objectid + num_bytes; goto new_group; } if (test_range_bit(&info->pinned_extents, ins->objectid, - ins->objectid + num_bytes -1, EXTENT_DIRTY, 0)) { + ins->objectid + num_bytes -1, EXTENT_DIRTY, 0, + NULL)) { search_start = ins->objectid + num_bytes; goto new_group; } if (info->excluded_extents && test_range_bit(info->excluded_extents, ins->objectid, - ins->objectid + num_bytes -1, EXTENT_DIRTY, 0)) { + ins->objectid + num_bytes -1, EXTENT_DIRTY, 0, + NULL)) { search_start = ins->objectid + num_bytes; goto new_group; } @@ -2377,7 +2384,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans, if (ret < 0) return ret; clear_extent_dirty(&info->free_space_cache, - ins->objectid, ins->objectid + ins->offset - 1); + ins->objectid, ins->objectid + ins->offset - 1, + NULL); return ret; } @@ -2418,7 +2426,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, if (ref->root == BTRFS_EXTENT_TREE_OBJECTID) { ret = find_first_extent_bit(&trans->fs_info->extent_ins, node->bytenr, &start, &end, - EXTENT_LOCKED); + EXTENT_LOCKED, NULL); ASSERT(!ret); ASSERT(start == node->bytenr); ASSERT(end == node->bytenr + node->num_bytes - 1); @@ -2600,10 +2608,10 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) while(1) { ret = find_first_extent_bit(&info->free_space_cache, 0, - &start, &end, EXTENT_DIRTY); + &start, &end, EXTENT_DIRTY, NULL); if (ret) break; - clear_extent_dirty(&info->free_space_cache, start, end); + clear_extent_dirty(&info->free_space_cache, start, end, NULL); } while (!list_empty(&info->space_info)) { @@ -3838,7 +3846,8 @@ u64 add_new_free_space(struct btrfs_block_group *block_group, while (start < end) { ret = find_first_extent_bit(&info->pinned_extents, start, &extent_start, &extent_end, - EXTENT_DIRTY | EXTENT_UPTODATE); + EXTENT_DIRTY | EXTENT_UPTODATE, + NULL); if (ret) break; diff --git a/kernel-shared/extent_io.c b/kernel-shared/extent_io.c index ab80700a..46c0fb3f 100644 --- a/kernel-shared/extent_io.c +++ b/kernel-shared/extent_io.c @@ -70,174 +70,6 @@ void extent_buffer_free_cache(struct btrfs_fs_info *fs_info) fs_info->cache_size = 0; } -void extent_io_tree_init(struct extent_io_tree *tree) -{ - cache_tree_init(&tree->state); - cache_tree_init(&tree->cache); - INIT_LIST_HEAD(&tree->lru); -} - -static struct extent_state *alloc_extent_state(void) -{ - struct extent_state *state; - - state = malloc(sizeof(*state)); - if (!state) - return NULL; - state->cache_node.objectid = 0; - state->refs = 1; - state->state = 0; - state->xprivate = 0; - return state; -} - -static void btrfs_free_extent_state(struct extent_state *state) -{ - state->refs--; - BUG_ON(state->refs < 0); - if (state->refs == 0) - free(state); -} - -static void free_extent_state_func(struct cache_extent *cache) -{ - struct extent_state *es; - - es = container_of(cache, struct extent_state, cache_node); - btrfs_free_extent_state(es); -} - -void extent_io_tree_cleanup(struct extent_io_tree *tree) -{ - struct extent_buffer *eb; - - while(!list_empty(&tree->lru)) { - eb = list_entry(tree->lru.next, struct extent_buffer, lru); - if (eb->refs) { - /* - * Reset extent buffer refs to 1, so the - * free_extent_buffer_nocache() can free it for sure. - */ - eb->refs = 1; - fprintf(stderr, - "extent buffer leak: start %llu len %u\n", - (unsigned long long)eb->start, eb->len); - free_extent_buffer_nocache(eb); - } else { - free_extent_buffer_final(eb); - } - } - - cache_tree_free_extents(&tree->state, free_extent_state_func); -} - -static inline void update_extent_state(struct extent_state *state) -{ - state->cache_node.start = state->start; - state->cache_node.size = state->end + 1 - state->start; -} - -/* - * Utility function to look for merge candidates inside a given range. - * Any extents with matching state are merged together into a single - * extent in the tree. Extents with EXTENT_IO in their state field are - * not merged - */ -static int merge_state(struct extent_io_tree *tree, - struct extent_state *state) -{ - struct extent_state *other; - struct cache_extent *other_node; - - if (state->state & EXTENT_IOBITS) - return 0; - - other_node = prev_cache_extent(&state->cache_node); - if (other_node) { - other = container_of(other_node, struct extent_state, - cache_node); - if (other->end == state->start - 1 && - other->state == state->state) { - state->start = other->start; - update_extent_state(state); - remove_cache_extent(&tree->state, &other->cache_node); - btrfs_free_extent_state(other); - } - } - other_node = next_cache_extent(&state->cache_node); - if (other_node) { - other = container_of(other_node, struct extent_state, - cache_node); - if (other->start == state->end + 1 && - other->state == state->state) { - other->start = state->start; - update_extent_state(other); - remove_cache_extent(&tree->state, &state->cache_node); - btrfs_free_extent_state(state); - } - } - return 0; -} - -/* - * insert an extent_state struct into the tree. 'bits' are set on the - * struct before it is inserted. - */ -static int insert_state(struct extent_io_tree *tree, - struct extent_state *state, u64 start, u64 end, - int bits) -{ - int ret; - - BUG_ON(end < start); - state->state |= bits; - state->start = start; - state->end = end; - update_extent_state(state); - ret = insert_cache_extent(&tree->state, &state->cache_node); - BUG_ON(ret); - merge_state(tree, state); - return 0; -} - -/* - * split a given extent state struct in two, inserting the preallocated - * struct 'prealloc' as the newly created second half. 'split' indicates an - * offset inside 'orig' where it should be split. - */ -static int split_state(struct extent_io_tree *tree, struct extent_state *orig, - struct extent_state *prealloc, u64 split) -{ - int ret; - prealloc->start = orig->start; - prealloc->end = split - 1; - prealloc->state = orig->state; - update_extent_state(prealloc); - orig->start = split; - update_extent_state(orig); - ret = insert_cache_extent(&tree->state, &prealloc->cache_node); - BUG_ON(ret); - return 0; -} - -/* - * clear some bits on a range in the tree. - */ -static int clear_state_bit(struct extent_io_tree *tree, - struct extent_state *state, int bits) -{ - int ret = state->state & bits; - - state->state &= ~bits; - if (state->state == 0) { - remove_cache_extent(&tree->state, &state->cache_node); - btrfs_free_extent_state(state); - } else { - merge_state(tree, state); - } - return ret; -} - /* * extent_buffer_bitmap_set - set an area of a bitmap * @eb: the extent buffer @@ -294,305 +126,6 @@ void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, } } -/* - * clear some bits on a range in the tree. - */ -int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits) -{ - struct extent_state *state; - struct extent_state *prealloc = NULL; - struct cache_extent *node; - u64 last_end; - int err; - int set = 0; - -again: - if (!prealloc) { - prealloc = alloc_extent_state(); - if (!prealloc) - return -ENOMEM; - } - - /* - * this search will find the extents that end after - * our range starts - */ - node = search_cache_extent(&tree->state, start); - if (!node) - goto out; - state = container_of(node, struct extent_state, cache_node); - if (state->start > end) - goto out; - last_end = state->end; - - /* - * | ---- desired range ---- | - * | state | or - * | ------------- state -------------- | - * - * We need to split the extent we found, and may flip - * bits on second half. - * - * If the extent we found extends past our range, we - * just split and search again. It'll get split again - * the next time though. - * - * If the extent we found is inside our range, we clear - * the desired bit on it. - */ - if (state->start < start) { - err = split_state(tree, state, prealloc, start); - BUG_ON(err == -EEXIST); - prealloc = NULL; - if (err) - goto out; - if (state->end <= end) { - set |= clear_state_bit(tree, state, bits); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - } else { - start = state->start; - } - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | - * We need to split the extent, and clear the bit - * on the first half - */ - if (state->start <= end && state->end > end) { - err = split_state(tree, state, prealloc, end + 1); - BUG_ON(err == -EEXIST); - - set |= clear_state_bit(tree, prealloc, bits); - prealloc = NULL; - goto out; - } - - start = state->end + 1; - set |= clear_state_bit(tree, state, bits); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - goto search_again; -out: - if (prealloc) - btrfs_free_extent_state(prealloc); - return set; - -search_again: - if (start > end) - goto out; - goto again; -} - -/* - * set some bits on a range in the tree. - */ -int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits) -{ - struct extent_state *state; - struct extent_state *prealloc = NULL; - struct cache_extent *node; - int err = 0; - u64 last_start; - u64 last_end; -again: - if (!prealloc) { - prealloc = alloc_extent_state(); - if (!prealloc) - return -ENOMEM; - } - - /* - * this search will find the extents that end after - * our range starts - */ - node = search_cache_extent(&tree->state, start); - if (!node) { - err = insert_state(tree, prealloc, start, end, bits); - BUG_ON(err == -EEXIST); - prealloc = NULL; - goto out; - } - - state = container_of(node, struct extent_state, cache_node); - last_start = state->start; - last_end = state->end; - - /* - * | ---- desired range ---- | - * | state | - * - * Just lock what we found and keep going - */ - if (state->start == start && state->end <= end) { - state->state |= bits; - merge_state(tree, state); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | - * or - * | ------------- state -------------- | - * - * We need to split the extent we found, and may flip bits on - * second half. - * - * If the extent we found extends past our - * range, we just split and search again. It'll get split - * again the next time though. - * - * If the extent we found is inside our range, we set the - * desired bit on it. - */ - if (state->start < start) { - err = split_state(tree, state, prealloc, start); - BUG_ON(err == -EEXIST); - prealloc = NULL; - if (err) - goto out; - if (state->end <= end) { - state->state |= bits; - start = state->end + 1; - merge_state(tree, state); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - } else { - start = state->start; - } - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | or | state | - * - * There's a hole, we need to insert something in it and - * ignore the extent we found. - */ - if (state->start > start) { - u64 this_end; - if (end < last_start) - this_end = end; - else - this_end = last_start -1; - err = insert_state(tree, prealloc, start, this_end, - bits); - BUG_ON(err == -EEXIST); - prealloc = NULL; - if (err) - goto out; - start = this_end + 1; - goto search_again; - } - /* - * | ---- desired range ---- | - * | ---------- state ---------- | - * We need to split the extent, and set the bit - * on the first half - */ - err = split_state(tree, state, prealloc, end + 1); - BUG_ON(err == -EEXIST); - - state->state |= bits; - merge_state(tree, prealloc); - prealloc = NULL; -out: - if (prealloc) - btrfs_free_extent_state(prealloc); - return err; -search_again: - if (start > end) - goto out; - goto again; -} - -int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end) -{ - return set_extent_bits(tree, start, end, EXTENT_DIRTY); -} - -int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end) -{ - return clear_extent_bits(tree, start, end, EXTENT_DIRTY); -} - -int find_first_extent_bit(struct extent_io_tree *tree, u64 start, - u64 *start_ret, u64 *end_ret, int bits) -{ - struct cache_extent *node; - struct extent_state *state; - int ret = 1; - - /* - * this search will find all the extents that end after - * our range starts. - */ - node = search_cache_extent(&tree->state, start); - if (!node) - goto out; - - while(1) { - state = container_of(node, struct extent_state, cache_node); - if (state->end >= start && (state->state & bits)) { - *start_ret = state->start; - *end_ret = state->end; - ret = 0; - break; - } - node = next_cache_extent(node); - if (!node) - break; - } -out: - return ret; -} - -int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, - int bits, int filled) -{ - struct extent_state *state = NULL; - struct cache_extent *node; - int bitset = 0; - - node = search_cache_extent(&tree->state, start); - while (node && start <= end) { - state = container_of(node, struct extent_state, cache_node); - - if (filled && state->start > start) { - bitset = 0; - break; - } - if (state->start > end) - break; - if (state->state & bits) { - bitset = 1; - if (!filled) - break; - } else if (filled) { - bitset = 0; - break; - } - start = state->end + 1; - if (start > end) - break; - node = next_cache_extent(node); - if (!node) { - if (filled) - bitset = 0; - break; - } - } - return bitset; -} - static struct extent_buffer *__alloc_extent_buffer(struct btrfs_fs_info *info, u64 bytenr, u32 blocksize) { @@ -1039,7 +572,8 @@ int set_extent_buffer_dirty(struct extent_buffer *eb) struct extent_io_tree *tree = &eb->fs_info->dirty_buffers; if (!(eb->flags & EXTENT_BUFFER_DIRTY)) { eb->flags |= EXTENT_BUFFER_DIRTY; - set_extent_dirty(tree, eb->start, eb->start + eb->len - 1); + set_extent_dirty(tree, eb->start, eb->start + eb->len - 1, + GFP_NOFS); extent_buffer_get(eb); } return 0; @@ -1050,7 +584,8 @@ int clear_extent_buffer_dirty(struct extent_buffer *eb) struct extent_io_tree *tree = &eb->fs_info->dirty_buffers; if (eb->flags & EXTENT_BUFFER_DIRTY) { eb->flags &= ~EXTENT_BUFFER_DIRTY; - clear_extent_dirty(tree, eb->start, eb->start + eb->len - 1); + clear_extent_dirty(tree, eb->start, eb->start + eb->len - 1, + NULL); free_extent_buffer(eb); } return 0; diff --git a/kernel-shared/extent_io.h b/kernel-shared/extent_io.h index d824d467..8ba56eed 100644 --- a/kernel-shared/extent_io.h +++ b/kernel-shared/extent_io.h @@ -23,17 +23,7 @@ #include "common/extent-cache.h" #include "kernel-lib/list.h" -#define EXTENT_DIRTY (1U << 0) -#define EXTENT_WRITEBACK (1U << 1) -#define EXTENT_UPTODATE (1U << 2) -#define EXTENT_LOCKED (1U << 3) -#define EXTENT_NEW (1U << 4) -#define EXTENT_DELALLOC (1U << 5) -#define EXTENT_DEFRAG (1U << 6) -#define EXTENT_DEFRAG_DONE (1U << 7) -#define EXTENT_BUFFER_FILLED (1U << 8) -#define EXTENT_CSUM (1U << 9) -#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) +struct extent_io_tree; #define EXTENT_BUFFER_UPTODATE (1U << 0) #define EXTENT_BUFFER_DIRTY (1U << 1) @@ -65,23 +55,6 @@ static inline int le_test_bit(int nr, const u8 *addr) struct btrfs_fs_info; -struct extent_io_tree { - struct cache_tree state; - struct cache_tree cache; - struct list_head lru; - u64 cache_size; - u64 max_cache_size; -}; - -struct extent_state { - struct cache_extent cache_node; - u64 start; - u64 end; - int refs; - unsigned long state; - u64 xprivate; -}; - struct extent_buffer { struct cache_extent cache_node; u64 start; @@ -99,16 +72,6 @@ static inline void extent_buffer_get(struct extent_buffer *eb) eb->refs++; } -void extent_io_tree_init(struct extent_io_tree *tree); -void extent_io_tree_cleanup(struct extent_io_tree *tree); -int set_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits); -int clear_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, int bits); -int find_first_extent_bit(struct extent_io_tree *tree, u64 start, - u64 *start_ret, u64 *end_ret, int bits); -int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, - int bits, int filled); -int set_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end); -int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end); static inline int set_extent_buffer_uptodate(struct extent_buffer *eb) { eb->flags |= EXTENT_BUFFER_UPTODATE; diff --git a/kernel-shared/misc.h b/kernel-shared/misc.h new file mode 100644 index 00000000..99c4951b --- /dev/null +++ b/kernel-shared/misc.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef BTRFS_MISC_H +#define BTRFS_MISC_H + +#include "kerncompat.h" + +#define in_range(b, first, len) ((b) >= (first) && (b) < (first) + (len)) + +/* + * Enumerate bits using enum autoincrement. Define the @name as the n-th bit. + */ +#define ENUM_BIT(name) \ + __ ## name ## _BIT, \ + name = (1U << __ ## name ## _BIT), \ + __ ## name ## _SEQ = __ ## name ## _BIT + +static inline void cond_wake_up(struct wait_queue_head *wq) +{ + /* + * This implies a full smp_mb barrier, see comments for + * waitqueue_active why. + */ + if (wq_has_sleeper(wq)) + wake_up(wq); +} + +static inline void cond_wake_up_nomb(struct wait_queue_head *wq) +{ + /* + * Special case for conditional wakeup where the barrier required for + * waitqueue_active is implied by some of the preceding code. Eg. one + * of such atomic operations (atomic_dec_and_return, ...), or a + * unlock/lock sequence, etc. + */ + if (waitqueue_active(wq)) + wake_up(wq); +} + +static inline u64 mult_perc(u64 num, u32 percent) +{ + return div_u64(num * percent, 100); +} +/* Copy of is_power_of_two that is 64bit safe */ +static inline bool is_power_of_two_u64(u64 n) +{ + return n != 0 && (n & (n - 1)) == 0; +} + +static inline bool has_single_bit_set(u64 n) +{ + return is_power_of_two_u64(n); +} + +/* + * Simple bytenr based rb_tree relate structures + * + * Any structure wants to use bytenr as single search index should have their + * structure start with these members. + */ +struct rb_simple_node { + struct rb_node rb_node; + u64 bytenr; +}; + +static inline struct rb_node *rb_simple_search(struct rb_root *root, u64 bytenr) +{ + struct rb_node *node = root->rb_node; + struct rb_simple_node *entry; + + while (node) { + entry = rb_entry(node, struct rb_simple_node, rb_node); + + if (bytenr < entry->bytenr) + node = node->rb_left; + else if (bytenr > entry->bytenr) + node = node->rb_right; + else + return node; + } + return NULL; +} + +/* + * Search @root from an entry that starts or comes after @bytenr. + * + * @root: the root to search. + * @bytenr: bytenr to search from. + * + * Return the rb_node that start at or after @bytenr. If there is no entry at + * or after @bytner return NULL. + */ +static inline struct rb_node *rb_simple_search_first(struct rb_root *root, + u64 bytenr) +{ + struct rb_node *node = root->rb_node, *ret = NULL; + struct rb_simple_node *entry, *ret_entry = NULL; + + while (node) { + entry = rb_entry(node, struct rb_simple_node, rb_node); + + if (bytenr < entry->bytenr) { + if (!ret || entry->bytenr < ret_entry->bytenr) { + ret = node; + ret_entry = entry; + } + + node = node->rb_left; + } else if (bytenr > entry->bytenr) { + node = node->rb_right; + } else { + return node; + } + } + + return ret; +} + +static inline struct rb_node *rb_simple_insert(struct rb_root *root, u64 bytenr, + struct rb_node *node) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + struct rb_simple_node *entry; + + while (*p) { + parent = *p; + entry = rb_entry(parent, struct rb_simple_node, rb_node); + + if (bytenr < entry->bytenr) + p = &(*p)->rb_left; + else if (bytenr > entry->bytenr) + p = &(*p)->rb_right; + else + return parent; + } + + rb_link_node(node, parent, p); + rb_insert_color(node, root); + return NULL; +} + +#endif diff --git a/kernel-shared/transaction.c b/kernel-shared/transaction.c index c1364d69..b16c07c3 100644 --- a/kernel-shared/transaction.c +++ b/kernel-shared/transaction.c @@ -142,7 +142,7 @@ int __commit_transaction(struct btrfs_trans_handle *trans, while(1) { again: ret = find_first_extent_bit(tree, 0, &start, &end, - EXTENT_DIRTY); + EXTENT_DIRTY, NULL); if (ret) break; @@ -174,7 +174,8 @@ cleanup: while (1) { int find_ret; - find_ret = find_first_extent_bit(tree, 0, &start, &end, EXTENT_DIRTY); + find_ret = find_first_extent_bit(tree, 0, &start, &end, + EXTENT_DIRTY, NULL); if (find_ret) break;