mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
for-6.9-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmXvUekACgkQxWXV+ddt WDuDpA//QiTipyU+v2b0aV2iOQs66YxFU0D9suQnin2paAU9YHzT6cLr9uYLAnPE Hs57jfZiWiCKSTVJwezJJb5azKmC9M9Fm0uSny51O7EKibcyLEDuHGrMB4C+O/9e 7PQD6K6WCRfH7PzLPeDYSK8tdHyj8hu1YbW/o/iBfQGyCxZVejCuOr/tItnO9JxY km8pwmcREzOTGyBBjA19QKiC1hY4cARtLqtzxCBrfFcMgT2H6KbAciXzBabdMf8D 8NpP98HOFpi5sOVauSQDz8t0aQkGVWyP1yIBZ0rdQesTp7kqkXLCJOSLAw8M2Q4c la0zywlOb4hjh0vO1gyzyJ+HPA+UZtkebeMvm0BtNukMKi2hn/AF94af4jVuR6e5 fjK79q3EU87RjluMW6wPux/MFJBJdDJrdhwZVkYFNf6yMv+L94NOcCDD3d346Hgr hk5gOFhZ38Me9zC3/4z0NboiSxnoTk1W0hz1Je8e1vXdeIEzexkJQM6AhP8ovAjL S9dl2po2SNLo9qvzg8rPkWKktAcI7gDZhM6mMBZispTC7JgtByHC2gd8yiys0ss0 cs0gAkL2SqOCQNNEQuf7lz7p3dhXBDkPJBmISEi4Fsnxxo7ltPECcR9kYXJ7gnqK Hcamuc2XD8oncJ6NuqplBwmgLrjZP9I2ckUGdd5bUQPYJegx3Vw= =dgEi -----END PGP SIGNATURE----- Merge tag 'for-6.9-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs updates from David Sterba: "Mostly stabilization, refactoring and cleanup changes. There rest are minor performance optimizations due to caching or lock contention reduction and a few notable fixes. Performance improvements: - minor speedup in logging when repeatedly allocated structure is preallocated only once, improves latency and decreases lock contention - minor throughput increase (+6%), reduced lock contention after clearing delayed allocation bits, applies to several common workload types - skip full quota rescan if a new relation is added in the same transaction Fixes: - zstd fix for inline compressed file in subpage mode, updated version from the 6.8 time - proper qgroup inheritance ioctl parameter validation - more fiemap followup fixes after reduced locking done in 6.8: - fix race when detecting delalloc ranges Core changes: - more debugging code: - added assertions for a very rare crash in raid56 calculation - tree-checker dumps page state to give more insights into possible reference counting issues - add checksum calculation offloading sysfs knob, for now enabled under DEBUG only to determine a good heuristic for deciding the offload or synchronous, depends on various factors (block group profile, device speed) and is not as clear as initially thought (checksum type) - error handling improvements, added assertions - more page to folio conversion (defrag, truncate), cached size and shift - preparation for more fine grained locking of sectors in subpage mode - cleanups and refactoring: - include cleanups, forward declarations - pointer-to-structure helpers - redundant argument removals - removed unused code - slab cache updates, last use of SLAB_MEM_SPREAD removed" * tag 'for-6.9-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (114 commits) btrfs: reuse cloned extent buffer during fiemap to avoid re-allocations btrfs: fix race when detecting delalloc ranges during fiemap btrfs: fix off-by-one chunk length calculation at contains_pending_extent() btrfs: qgroup: allow quick inherit if snapshot is created and added to the same parent btrfs: qgroup: validate btrfs_qgroup_inherit parameter btrfs: include device major and minor numbers in the device scan notice btrfs: mark btrfs_put_caching_control() static btrfs: remove SLAB_MEM_SPREAD flag use btrfs: qgroup: always free reserved space for extent records btrfs: tree-checker: dump the page status if hit something wrong btrfs: compression: remove dead comments in btrfs_compress_heuristic() btrfs: subpage: make writer lock utilize bitmap btrfs: subpage: make reader lock utilize bitmap btrfs: unexport btrfs_subpage_start_writer() and btrfs_subpage_end_and_test_writer() btrfs: pass a valid extent map cache pointer to __get_extent_map() btrfs: merge btrfs_del_delalloc_inode() helpers btrfs: pass btrfs_device to btrfs_scratch_superblocks() btrfs: handle transaction commit errors in flush_reservations() btrfs: use KMEM_CACHE() to create btrfs_free_space cache btrfs: use KMEM_CACHE() to create delayed ref caches ...
This commit is contained in:
commit
43a7548e28
@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "ctree.h"
|
#include "extent_io.h"
|
||||||
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
|
|
||||||
static bool check_setget_bounds(const struct extent_buffer *eb,
|
static bool check_setget_bounds(const struct extent_buffer *eb,
|
||||||
@ -63,8 +64,8 @@ u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \
|
|||||||
const unsigned long idx = get_eb_folio_index(token->eb, member_offset); \
|
const unsigned long idx = get_eb_folio_index(token->eb, member_offset); \
|
||||||
const unsigned long oil = get_eb_offset_in_folio(token->eb, \
|
const unsigned long oil = get_eb_offset_in_folio(token->eb, \
|
||||||
member_offset);\
|
member_offset);\
|
||||||
const int unit_size = folio_size(token->eb->folios[0]); \
|
const int unit_size = token->eb->folio_size; \
|
||||||
const int unit_shift = folio_shift(token->eb->folios[0]); \
|
const int unit_shift = token->eb->folio_shift; \
|
||||||
const int size = sizeof(u##bits); \
|
const int size = sizeof(u##bits); \
|
||||||
u8 lebytes[sizeof(u##bits)]; \
|
u8 lebytes[sizeof(u##bits)]; \
|
||||||
const int part = unit_size - oil; \
|
const int part = unit_size - oil; \
|
||||||
@ -94,7 +95,7 @@ u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
|
|||||||
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
|
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
|
||||||
const unsigned long oil = get_eb_offset_in_folio(eb, \
|
const unsigned long oil = get_eb_offset_in_folio(eb, \
|
||||||
member_offset);\
|
member_offset);\
|
||||||
const int unit_size = folio_size(eb->folios[0]); \
|
const int unit_size = eb->folio_size; \
|
||||||
char *kaddr = folio_address(eb->folios[idx]); \
|
char *kaddr = folio_address(eb->folios[idx]); \
|
||||||
const int size = sizeof(u##bits); \
|
const int size = sizeof(u##bits); \
|
||||||
const int part = unit_size - oil; \
|
const int part = unit_size - oil; \
|
||||||
@ -117,8 +118,8 @@ void btrfs_set_token_##bits(struct btrfs_map_token *token, \
|
|||||||
const unsigned long idx = get_eb_folio_index(token->eb, member_offset); \
|
const unsigned long idx = get_eb_folio_index(token->eb, member_offset); \
|
||||||
const unsigned long oil = get_eb_offset_in_folio(token->eb, \
|
const unsigned long oil = get_eb_offset_in_folio(token->eb, \
|
||||||
member_offset);\
|
member_offset);\
|
||||||
const int unit_size = folio_size(token->eb->folios[0]); \
|
const int unit_size = token->eb->folio_size; \
|
||||||
const int unit_shift = folio_shift(token->eb->folios[0]); \
|
const int unit_shift = token->eb->folio_shift; \
|
||||||
const int size = sizeof(u##bits); \
|
const int size = sizeof(u##bits); \
|
||||||
u8 lebytes[sizeof(u##bits)]; \
|
u8 lebytes[sizeof(u##bits)]; \
|
||||||
const int part = unit_size - oil; \
|
const int part = unit_size - oil; \
|
||||||
@ -151,7 +152,7 @@ void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
|
|||||||
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
|
const unsigned long idx = get_eb_folio_index(eb, member_offset);\
|
||||||
const unsigned long oil = get_eb_offset_in_folio(eb, \
|
const unsigned long oil = get_eb_offset_in_folio(eb, \
|
||||||
member_offset);\
|
member_offset);\
|
||||||
const int unit_size = folio_size(eb->folios[0]); \
|
const int unit_size = eb->folio_size; \
|
||||||
char *kaddr = folio_address(eb->folios[idx]); \
|
char *kaddr = folio_address(eb->folios[idx]); \
|
||||||
const int size = sizeof(u##bits); \
|
const int size = sizeof(u##bits); \
|
||||||
const int part = unit_size - oil; \
|
const int part = unit_size - oil; \
|
||||||
|
@ -3,8 +3,17 @@
|
|||||||
#ifndef BTRFS_ACCESSORS_H
|
#ifndef BTRFS_ACCESSORS_H
|
||||||
#define BTRFS_ACCESSORS_H
|
#define BTRFS_ACCESSORS_H
|
||||||
|
|
||||||
#include <linux/stddef.h>
|
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
#include <linux/stddef.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/align.h>
|
||||||
|
#include <linux/build_bug.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
|
|
||||||
|
struct extent_buffer;
|
||||||
|
|
||||||
struct btrfs_map_token {
|
struct btrfs_map_token {
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
@ -844,45 +853,6 @@ static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
|
|||||||
write_eb_member(eb, bi, struct btrfs_balance_item, sys, 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 */
|
/* struct btrfs_super_block */
|
||||||
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
|
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_flags, struct btrfs_super_block, flags, 64);
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include <linux/sched/mm.h>
|
#include <linux/sched/mm.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "btrfs_inode.h"
|
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
#include "acl.h"
|
#include "acl.h"
|
||||||
|
|
||||||
|
@ -3,8 +3,15 @@
|
|||||||
#ifndef BTRFS_ACL_H
|
#ifndef BTRFS_ACL_H
|
||||||
#define BTRFS_ACL_H
|
#define BTRFS_ACL_H
|
||||||
|
|
||||||
|
struct posix_acl;
|
||||||
|
struct inode;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
|
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
|
||||||
|
|
||||||
|
struct mnt_idmap;
|
||||||
|
struct dentry;
|
||||||
|
|
||||||
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
|
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
|
||||||
int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||||
struct posix_acl *acl, int type);
|
struct posix_acl *acl, int type);
|
||||||
@ -13,6 +20,10 @@ int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
#include <linux/errno.h>
|
||||||
|
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
#define btrfs_get_acl NULL
|
#define btrfs_get_acl NULL
|
||||||
#define btrfs_set_acl NULL
|
#define btrfs_set_acl NULL
|
||||||
static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
|
static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
#include <trace/events/btrfs.h>
|
#include <trace/events/btrfs.h>
|
||||||
#include "async-thread.h"
|
#include "async-thread.h"
|
||||||
#include "ctree.h"
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
WORK_DONE_BIT,
|
WORK_DONE_BIT,
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
#ifndef BTRFS_ASYNC_THREAD_H
|
#ifndef BTRFS_ASYNC_THREAD_H
|
||||||
#define BTRFS_ASYNC_THREAD_H
|
#define BTRFS_ASYNC_THREAD_H
|
||||||
|
|
||||||
|
#include <linux/compiler_types.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
|
||||||
struct btrfs_fs_info;
|
struct btrfs_fs_info;
|
||||||
struct btrfs_workqueue;
|
struct btrfs_workqueue;
|
||||||
struct btrfs_work;
|
struct btrfs_work;
|
||||||
|
|
||||||
typedef void (*btrfs_func_t)(struct btrfs_work *arg);
|
typedef void (*btrfs_func_t)(struct btrfs_work *arg);
|
||||||
typedef void (*btrfs_ordered_func_t)(struct btrfs_work *arg, bool);
|
typedef void (*btrfs_ordered_func_t)(struct btrfs_work *arg, bool);
|
||||||
|
|
||||||
|
@ -198,10 +198,7 @@ static struct kmem_cache *btrfs_prelim_ref_cache;
|
|||||||
int __init btrfs_prelim_ref_init(void)
|
int __init btrfs_prelim_ref_init(void)
|
||||||
{
|
{
|
||||||
btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
|
btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
|
||||||
sizeof(struct prelim_ref),
|
sizeof(struct prelim_ref), 0, 0, NULL);
|
||||||
0,
|
|
||||||
SLAB_MEM_SPREAD,
|
|
||||||
NULL);
|
|
||||||
if (!btrfs_prelim_ref_cache)
|
if (!btrfs_prelim_ref_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1036,8 +1033,6 @@ static int add_inline_refs(struct btrfs_backref_walk_ctx *ctx,
|
|||||||
slot = path->slots[0];
|
slot = path->slots[0];
|
||||||
|
|
||||||
item_size = btrfs_item_size(leaf, slot);
|
item_size = btrfs_item_size(leaf, slot);
|
||||||
BUG_ON(item_size < sizeof(*ei));
|
|
||||||
|
|
||||||
ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
|
ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item);
|
||||||
|
|
||||||
if (ctx->check_extent_item) {
|
if (ctx->check_extent_item) {
|
||||||
@ -1435,8 +1430,10 @@ again:
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
/* This shouldn't happen, indicates a bug or fs corruption. */
|
/*
|
||||||
ASSERT(ret != 0);
|
* Key with offset -1 found, there would have to exist an extent
|
||||||
|
* item with such offset, but this is out of the valid range.
|
||||||
|
*/
|
||||||
ret = -EUCLEAN;
|
ret = -EUCLEAN;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2225,6 +2222,13 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
|
|||||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist an extent
|
||||||
|
* item with such offset, but this is out of the valid range.
|
||||||
|
*/
|
||||||
|
return -EUCLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_previous_extent_item(extent_root, path, 0);
|
ret = btrfs_previous_extent_item(extent_root, path, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -2247,7 +2251,6 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
|
|||||||
|
|
||||||
eb = path->nodes[0];
|
eb = path->nodes[0];
|
||||||
item_size = btrfs_item_size(eb, path->slots[0]);
|
item_size = btrfs_item_size(eb, path->slots[0]);
|
||||||
BUG_ON(item_size < sizeof(*ei));
|
|
||||||
|
|
||||||
ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
|
ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
|
||||||
flags = btrfs_extent_flags(eb, ei);
|
flags = btrfs_extent_flags(eb, ei);
|
||||||
@ -2850,6 +2853,16 @@ struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_inf
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void btrfs_backref_iter_release(struct btrfs_backref_iter *iter)
|
||||||
|
{
|
||||||
|
iter->bytenr = 0;
|
||||||
|
iter->item_ptr = 0;
|
||||||
|
iter->cur_ptr = 0;
|
||||||
|
iter->end_ptr = 0;
|
||||||
|
btrfs_release_path(iter->path);
|
||||||
|
memset(&iter->cur_key, 0, sizeof(iter->cur_key));
|
||||||
|
}
|
||||||
|
|
||||||
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
|
int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = iter->fs_info;
|
struct btrfs_fs_info *fs_info = iter->fs_info;
|
||||||
@ -2868,6 +2881,10 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist an extent
|
||||||
|
* item with such offset, but this is out of the valid range.
|
||||||
|
*/
|
||||||
ret = -EUCLEAN;
|
ret = -EUCLEAN;
|
||||||
goto release;
|
goto release;
|
||||||
}
|
}
|
||||||
@ -2938,6 +2955,14 @@ release:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool btrfs_backref_iter_is_inline_ref(struct btrfs_backref_iter *iter)
|
||||||
|
{
|
||||||
|
if (iter->cur_key.type == BTRFS_EXTENT_ITEM_KEY ||
|
||||||
|
iter->cur_key.type == BTRFS_METADATA_ITEM_KEY)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go to the next backref item of current bytenr, can be either inlined or
|
* Go to the next backref item of current bytenr, can be either inlined or
|
||||||
* keyed.
|
* keyed.
|
||||||
@ -2950,7 +2975,7 @@ release:
|
|||||||
*/
|
*/
|
||||||
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
|
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter)
|
||||||
{
|
{
|
||||||
struct extent_buffer *eb = btrfs_backref_get_eb(iter);
|
struct extent_buffer *eb = iter->path->nodes[0];
|
||||||
struct btrfs_root *extent_root;
|
struct btrfs_root *extent_root;
|
||||||
struct btrfs_path *path = iter->path;
|
struct btrfs_path *path = iter->path;
|
||||||
struct btrfs_extent_inline_ref *iref;
|
struct btrfs_extent_inline_ref *iref;
|
||||||
@ -3038,6 +3063,19 @@ struct btrfs_backref_node *btrfs_backref_alloc_node(
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_backref_free_node(struct btrfs_backref_cache *cache,
|
||||||
|
struct btrfs_backref_node *node)
|
||||||
|
{
|
||||||
|
if (node) {
|
||||||
|
ASSERT(list_empty(&node->list));
|
||||||
|
ASSERT(list_empty(&node->lower));
|
||||||
|
ASSERT(node->eb == NULL);
|
||||||
|
cache->nr_nodes--;
|
||||||
|
btrfs_put_root(node->root);
|
||||||
|
kfree(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct btrfs_backref_edge *btrfs_backref_alloc_edge(
|
struct btrfs_backref_edge *btrfs_backref_alloc_edge(
|
||||||
struct btrfs_backref_cache *cache)
|
struct btrfs_backref_cache *cache)
|
||||||
{
|
{
|
||||||
@ -3049,6 +3087,52 @@ struct btrfs_backref_edge *btrfs_backref_alloc_edge(
|
|||||||
return edge;
|
return edge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_backref_free_edge(struct btrfs_backref_cache *cache,
|
||||||
|
struct btrfs_backref_edge *edge)
|
||||||
|
{
|
||||||
|
if (edge) {
|
||||||
|
cache->nr_edges--;
|
||||||
|
kfree(edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void btrfs_backref_unlock_node_buffer(struct btrfs_backref_node *node)
|
||||||
|
{
|
||||||
|
if (node->locked) {
|
||||||
|
btrfs_tree_unlock(node->eb);
|
||||||
|
node->locked = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void btrfs_backref_drop_node_buffer(struct btrfs_backref_node *node)
|
||||||
|
{
|
||||||
|
if (node->eb) {
|
||||||
|
btrfs_backref_unlock_node_buffer(node);
|
||||||
|
free_extent_buffer(node->eb);
|
||||||
|
node->eb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Drop the backref node from cache without cleaning up its children
|
||||||
|
* edges.
|
||||||
|
*
|
||||||
|
* This can only be called on node without parent edges.
|
||||||
|
* The children edges are still kept as is.
|
||||||
|
*/
|
||||||
|
void btrfs_backref_drop_node(struct btrfs_backref_cache *tree,
|
||||||
|
struct btrfs_backref_node *node)
|
||||||
|
{
|
||||||
|
ASSERT(list_empty(&node->upper));
|
||||||
|
|
||||||
|
btrfs_backref_drop_node_buffer(node);
|
||||||
|
list_del_init(&node->list);
|
||||||
|
list_del_init(&node->lower);
|
||||||
|
if (!RB_EMPTY_NODE(&node->rb_node))
|
||||||
|
rb_erase(&node->rb_node, &tree->rb_root);
|
||||||
|
btrfs_backref_free_node(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop the backref node from cache, also cleaning up all its
|
* Drop the backref node from cache, also cleaning up all its
|
||||||
* upper edges and any uncached nodes in the path.
|
* upper edges and any uncached nodes in the path.
|
||||||
@ -3120,6 +3204,19 @@ void btrfs_backref_release_cache(struct btrfs_backref_cache *cache)
|
|||||||
ASSERT(!cache->nr_edges);
|
ASSERT(!cache->nr_edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_backref_link_edge(struct btrfs_backref_edge *edge,
|
||||||
|
struct btrfs_backref_node *lower,
|
||||||
|
struct btrfs_backref_node *upper,
|
||||||
|
int link_which)
|
||||||
|
{
|
||||||
|
ASSERT(upper && lower && upper->level == lower->level + 1);
|
||||||
|
edge->node[LOWER] = lower;
|
||||||
|
edge->node[UPPER] = upper;
|
||||||
|
if (link_which & LINK_LOWER)
|
||||||
|
list_add_tail(&edge->list[LOWER], &lower->upper);
|
||||||
|
if (link_which & LINK_UPPER)
|
||||||
|
list_add_tail(&edge->list[UPPER], &upper->lower);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Handle direct tree backref
|
* Handle direct tree backref
|
||||||
*
|
*
|
||||||
@ -3428,7 +3525,7 @@ int btrfs_backref_add_tree_node(struct btrfs_trans_handle *trans,
|
|||||||
int type;
|
int type;
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
eb = btrfs_backref_get_eb(iter);
|
eb = iter->path->nodes[0];
|
||||||
|
|
||||||
key.objectid = iter->bytenr;
|
key.objectid = iter->bytenr;
|
||||||
if (btrfs_backref_iter_is_inline_ref(iter)) {
|
if (btrfs_backref_iter_is_inline_ref(iter)) {
|
||||||
|
@ -6,11 +6,23 @@
|
|||||||
#ifndef BTRFS_BACKREF_H
|
#ifndef BTRFS_BACKREF_H
|
||||||
#define BTRFS_BACKREF_H
|
#define BTRFS_BACKREF_H
|
||||||
|
|
||||||
#include <linux/btrfs.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <uapi/linux/btrfs.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "ulist.h"
|
#include "locking.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
|
#include "ctree.h"
|
||||||
|
|
||||||
|
struct extent_inode_elem;
|
||||||
|
struct ulist;
|
||||||
|
struct btrfs_extent_item;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used by implementations of iterate_extent_inodes_t (see definition below) to
|
* Used by implementations of iterate_extent_inodes_t (see definition below) to
|
||||||
@ -271,22 +283,6 @@ struct btrfs_backref_iter {
|
|||||||
|
|
||||||
struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info);
|
struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info);
|
||||||
|
|
||||||
static inline void btrfs_backref_iter_free(struct btrfs_backref_iter *iter)
|
|
||||||
{
|
|
||||||
if (!iter)
|
|
||||||
return;
|
|
||||||
btrfs_free_path(iter->path);
|
|
||||||
kfree(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct extent_buffer *btrfs_backref_get_eb(
|
|
||||||
struct btrfs_backref_iter *iter)
|
|
||||||
{
|
|
||||||
if (!iter)
|
|
||||||
return NULL;
|
|
||||||
return iter->path->nodes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For metadata with EXTENT_ITEM key (non-skinny) case, the first inline data
|
* For metadata with EXTENT_ITEM key (non-skinny) case, the first inline data
|
||||||
* is btrfs_tree_block_info, without a btrfs_extent_inline_ref header.
|
* is btrfs_tree_block_info, without a btrfs_extent_inline_ref header.
|
||||||
@ -306,25 +302,6 @@ int btrfs_backref_iter_start(struct btrfs_backref_iter *iter, u64 bytenr);
|
|||||||
|
|
||||||
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter);
|
int btrfs_backref_iter_next(struct btrfs_backref_iter *iter);
|
||||||
|
|
||||||
static inline bool btrfs_backref_iter_is_inline_ref(
|
|
||||||
struct btrfs_backref_iter *iter)
|
|
||||||
{
|
|
||||||
if (iter->cur_key.type == BTRFS_EXTENT_ITEM_KEY ||
|
|
||||||
iter->cur_key.type == BTRFS_METADATA_ITEM_KEY)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_backref_iter_release(struct btrfs_backref_iter *iter)
|
|
||||||
{
|
|
||||||
iter->bytenr = 0;
|
|
||||||
iter->item_ptr = 0;
|
|
||||||
iter->cur_ptr = 0;
|
|
||||||
iter->end_ptr = 0;
|
|
||||||
btrfs_release_path(iter->path);
|
|
||||||
memset(&iter->cur_key, 0, sizeof(iter->cur_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Backref cache related structures
|
* Backref cache related structures
|
||||||
*
|
*
|
||||||
@ -452,83 +429,22 @@ struct btrfs_backref_edge *btrfs_backref_alloc_edge(
|
|||||||
|
|
||||||
#define LINK_LOWER (1 << 0)
|
#define LINK_LOWER (1 << 0)
|
||||||
#define LINK_UPPER (1 << 1)
|
#define LINK_UPPER (1 << 1)
|
||||||
static inline void btrfs_backref_link_edge(struct btrfs_backref_edge *edge,
|
|
||||||
struct btrfs_backref_node *lower,
|
|
||||||
struct btrfs_backref_node *upper,
|
|
||||||
int link_which)
|
|
||||||
{
|
|
||||||
ASSERT(upper && lower && upper->level == lower->level + 1);
|
|
||||||
edge->node[LOWER] = lower;
|
|
||||||
edge->node[UPPER] = upper;
|
|
||||||
if (link_which & LINK_LOWER)
|
|
||||||
list_add_tail(&edge->list[LOWER], &lower->upper);
|
|
||||||
if (link_which & LINK_UPPER)
|
|
||||||
list_add_tail(&edge->list[UPPER], &upper->lower);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_backref_free_node(struct btrfs_backref_cache *cache,
|
void btrfs_backref_link_edge(struct btrfs_backref_edge *edge,
|
||||||
struct btrfs_backref_node *node)
|
struct btrfs_backref_node *lower,
|
||||||
{
|
struct btrfs_backref_node *upper,
|
||||||
if (node) {
|
int link_which);
|
||||||
ASSERT(list_empty(&node->list));
|
void btrfs_backref_free_node(struct btrfs_backref_cache *cache,
|
||||||
ASSERT(list_empty(&node->lower));
|
struct btrfs_backref_node *node);
|
||||||
ASSERT(node->eb == NULL);
|
void btrfs_backref_free_edge(struct btrfs_backref_cache *cache,
|
||||||
cache->nr_nodes--;
|
struct btrfs_backref_edge *edge);
|
||||||
btrfs_put_root(node->root);
|
void btrfs_backref_unlock_node_buffer(struct btrfs_backref_node *node);
|
||||||
kfree(node);
|
void btrfs_backref_drop_node_buffer(struct btrfs_backref_node *node);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_backref_free_edge(struct btrfs_backref_cache *cache,
|
|
||||||
struct btrfs_backref_edge *edge)
|
|
||||||
{
|
|
||||||
if (edge) {
|
|
||||||
cache->nr_edges--;
|
|
||||||
kfree(edge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_backref_unlock_node_buffer(
|
|
||||||
struct btrfs_backref_node *node)
|
|
||||||
{
|
|
||||||
if (node->locked) {
|
|
||||||
btrfs_tree_unlock(node->eb);
|
|
||||||
node->locked = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_backref_drop_node_buffer(
|
|
||||||
struct btrfs_backref_node *node)
|
|
||||||
{
|
|
||||||
if (node->eb) {
|
|
||||||
btrfs_backref_unlock_node_buffer(node);
|
|
||||||
free_extent_buffer(node->eb);
|
|
||||||
node->eb = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Drop the backref node from cache without cleaning up its children
|
|
||||||
* edges.
|
|
||||||
*
|
|
||||||
* This can only be called on node without parent edges.
|
|
||||||
* The children edges are still kept as is.
|
|
||||||
*/
|
|
||||||
static inline void btrfs_backref_drop_node(struct btrfs_backref_cache *tree,
|
|
||||||
struct btrfs_backref_node *node)
|
|
||||||
{
|
|
||||||
ASSERT(list_empty(&node->upper));
|
|
||||||
|
|
||||||
btrfs_backref_drop_node_buffer(node);
|
|
||||||
list_del_init(&node->list);
|
|
||||||
list_del_init(&node->lower);
|
|
||||||
if (!RB_EMPTY_NODE(&node->rb_node))
|
|
||||||
rb_erase(&node->rb_node, &tree->rb_root);
|
|
||||||
btrfs_backref_free_node(tree, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
void btrfs_backref_cleanup_node(struct btrfs_backref_cache *cache,
|
void btrfs_backref_cleanup_node(struct btrfs_backref_cache *cache,
|
||||||
struct btrfs_backref_node *node);
|
struct btrfs_backref_node *node);
|
||||||
|
void btrfs_backref_drop_node(struct btrfs_backref_cache *tree,
|
||||||
|
struct btrfs_backref_node *node);
|
||||||
|
|
||||||
void btrfs_backref_release_cache(struct btrfs_backref_cache *cache);
|
void btrfs_backref_release_cache(struct btrfs_backref_cache *cache);
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "raid56.h"
|
#include "raid56.h"
|
||||||
#include "async-thread.h"
|
#include "async-thread.h"
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
#include "rcu-string.h"
|
|
||||||
#include "zoned.h"
|
#include "zoned.h"
|
||||||
#include "file-item.h"
|
#include "file-item.h"
|
||||||
#include "raid-stripe-tree.h"
|
#include "raid-stripe-tree.h"
|
||||||
@ -509,8 +508,6 @@ static void __btrfs_submit_bio(struct bio *bio, struct btrfs_io_context *bioc,
|
|||||||
if (!bioc) {
|
if (!bioc) {
|
||||||
/* Single mirror read/write fast path. */
|
/* Single mirror read/write fast path. */
|
||||||
btrfs_bio(bio)->mirror_num = mirror_num;
|
btrfs_bio(bio)->mirror_num = mirror_num;
|
||||||
if (bio_op(bio) != REQ_OP_READ)
|
|
||||||
btrfs_bio(bio)->orig_physical = smap->physical;
|
|
||||||
bio->bi_iter.bi_sector = smap->physical >> SECTOR_SHIFT;
|
bio->bi_iter.bi_sector = smap->physical >> SECTOR_SHIFT;
|
||||||
if (bio_op(bio) != REQ_OP_READ)
|
if (bio_op(bio) != REQ_OP_READ)
|
||||||
btrfs_bio(bio)->orig_physical = smap->physical;
|
btrfs_bio(bio)->orig_physical = smap->physical;
|
||||||
@ -611,8 +608,20 @@ static void run_one_async_done(struct btrfs_work *work, bool do_free)
|
|||||||
|
|
||||||
static bool should_async_write(struct btrfs_bio *bbio)
|
static bool should_async_write(struct btrfs_bio *bbio)
|
||||||
{
|
{
|
||||||
|
bool auto_csum_mode = true;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_DEBUG
|
||||||
|
struct btrfs_fs_devices *fs_devices = bbio->fs_info->fs_devices;
|
||||||
|
enum btrfs_offload_csum_mode csum_mode = READ_ONCE(fs_devices->offload_csum_mode);
|
||||||
|
|
||||||
|
if (csum_mode == BTRFS_OFFLOAD_CSUM_FORCE_OFF)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto_csum_mode = (csum_mode == BTRFS_OFFLOAD_CSUM_AUTO);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Submit synchronously if the checksum implementation is fast. */
|
/* Submit synchronously if the checksum implementation is fast. */
|
||||||
if (test_bit(BTRFS_FS_CSUM_IMPL_FAST, &bbio->fs_info->flags))
|
if (auto_csum_mode && test_bit(BTRFS_FS_CSUM_IMPL_FAST, &bbio->fs_info->flags))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,12 +7,14 @@
|
|||||||
#ifndef BTRFS_BIO_H
|
#ifndef BTRFS_BIO_H
|
||||||
#define BTRFS_BIO_H
|
#define BTRFS_BIO_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include <linux/bio.h>
|
#include <linux/bio.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include "tree-checker.h"
|
#include "tree-checker.h"
|
||||||
|
|
||||||
struct btrfs_bio;
|
struct btrfs_bio;
|
||||||
struct btrfs_fs_info;
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_inode;
|
||||||
|
|
||||||
#define BTRFS_BIO_INLINE_CSUM_SIZE 64
|
#define BTRFS_BIO_INLINE_CSUM_SIZE 64
|
||||||
|
|
||||||
|
@ -418,7 +418,7 @@ struct btrfs_caching_control *btrfs_get_caching_control(
|
|||||||
return ctl;
|
return ctl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_put_caching_control(struct btrfs_caching_control *ctl)
|
static void btrfs_put_caching_control(struct btrfs_caching_control *ctl)
|
||||||
{
|
{
|
||||||
if (refcount_dec_and_test(&ctl->count))
|
if (refcount_dec_and_test(&ctl->count))
|
||||||
kfree(ctl);
|
kfree(ctl);
|
||||||
@ -1063,7 +1063,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
|||||||
bool remove_rsv = false;
|
bool remove_rsv = false;
|
||||||
|
|
||||||
block_group = btrfs_lookup_block_group(fs_info, map->start);
|
block_group = btrfs_lookup_block_group(fs_info, map->start);
|
||||||
BUG_ON(!block_group);
|
if (!block_group)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
BUG_ON(!block_group->ro);
|
BUG_ON(!block_group->ro);
|
||||||
|
|
||||||
trace_btrfs_remove_block_group(block_group);
|
trace_btrfs_remove_block_group(block_group);
|
||||||
@ -1429,7 +1431,7 @@ static bool clean_pinned_extents(struct btrfs_trans_handle *trans,
|
|||||||
* group in pinned_extents before we were able to clear the whole block
|
* group in pinned_extents before we were able to clear the whole block
|
||||||
* group range from pinned_extents. This means that task can lookup for
|
* group range from pinned_extents. This means that task can lookup for
|
||||||
* the block group after we unpinned it from pinned_extents and removed
|
* the block group after we unpinned it from pinned_extents and removed
|
||||||
* it, leading to a BUG_ON() at unpin_extent_range().
|
* it, leading to an error at unpin_extent_range().
|
||||||
*/
|
*/
|
||||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||||
if (prev_trans) {
|
if (prev_trans) {
|
||||||
@ -1522,6 +1524,13 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
|||||||
* outstanding allocations in this block group. We do
|
* outstanding allocations in this block group. We do
|
||||||
* the ro check in case balance is currently acting on
|
* the ro check in case balance is currently acting on
|
||||||
* this block group.
|
* this block group.
|
||||||
|
*
|
||||||
|
* Also bail out if this is the only block group for its
|
||||||
|
* type, because otherwise we would lose profile
|
||||||
|
* information from fs_info->avail_*_alloc_bits and the
|
||||||
|
* next block group of this type would be created with a
|
||||||
|
* "single" profile (even if we're in a raid fs) because
|
||||||
|
* fs_info->avail_*_alloc_bits would be 0.
|
||||||
*/
|
*/
|
||||||
trace_btrfs_skip_unused_block_group(block_group);
|
trace_btrfs_skip_unused_block_group(block_group);
|
||||||
spin_unlock(&block_group->lock);
|
spin_unlock(&block_group->lock);
|
||||||
|
@ -3,9 +3,22 @@
|
|||||||
#ifndef BTRFS_BLOCK_GROUP_H
|
#ifndef BTRFS_BLOCK_GROUP_H
|
||||||
#define BTRFS_BLOCK_GROUP_H
|
#define BTRFS_BLOCK_GROUP_H
|
||||||
|
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include "free-space-cache.h"
|
#include "free-space-cache.h"
|
||||||
|
|
||||||
struct btrfs_chunk_map;
|
struct btrfs_chunk_map;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
enum btrfs_disk_cache_state {
|
enum btrfs_disk_cache_state {
|
||||||
BTRFS_DC_WRITTEN,
|
BTRFS_DC_WRITTEN,
|
||||||
@ -297,7 +310,6 @@ void btrfs_wait_nocow_writers(struct btrfs_block_group *bg);
|
|||||||
void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
|
void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
|
||||||
u64 num_bytes);
|
u64 num_bytes);
|
||||||
int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait);
|
int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait);
|
||||||
void btrfs_put_caching_control(struct btrfs_caching_control *ctl);
|
|
||||||
struct btrfs_caching_control *btrfs_get_caching_control(
|
struct btrfs_caching_control *btrfs_get_caching_control(
|
||||||
struct btrfs_block_group *cache);
|
struct btrfs_block_group *cache);
|
||||||
int btrfs_add_new_free_space(struct btrfs_block_group *block_group,
|
int btrfs_add_new_free_space(struct btrfs_block_group *block_group,
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "block-group.h"
|
#include "block-group.h"
|
||||||
#include "disk-io.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
|
|
||||||
|
@ -3,8 +3,15 @@
|
|||||||
#ifndef BTRFS_BLOCK_RSV_H
|
#ifndef BTRFS_BLOCK_RSV_H
|
||||||
#define BTRFS_BLOCK_RSV_H
|
#define BTRFS_BLOCK_RSV_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
struct btrfs_root;
|
struct btrfs_root;
|
||||||
|
struct btrfs_space_info;
|
||||||
|
struct btrfs_block_rsv;
|
||||||
|
struct btrfs_fs_info;
|
||||||
enum btrfs_reserve_flush_enum;
|
enum btrfs_reserve_flush_enum;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,13 +8,32 @@
|
|||||||
|
|
||||||
#include <linux/hash.h>
|
#include <linux/hash.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
#include <linux/fscrypt.h>
|
#include <linux/fscrypt.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include <trace/events/btrfs.h>
|
#include <trace/events/btrfs.h>
|
||||||
|
#include "block-rsv.h"
|
||||||
|
#include "btrfs_inode.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
|
#include "extent-io-tree.h"
|
||||||
#include "ordered-data.h"
|
#include "ordered-data.h"
|
||||||
#include "delayed-inode.h"
|
#include "delayed-inode.h"
|
||||||
|
|
||||||
|
struct extent_state;
|
||||||
|
struct posix_acl;
|
||||||
|
struct iov_iter;
|
||||||
|
struct writeback_control;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we search a directory based on f_pos (struct dir_context::pos) we have
|
* Since we search a directory based on f_pos (struct dir_context::pos) we have
|
||||||
* to start at 2 since '.' and '..' have f_pos of 0 and 1 respectively, so
|
* to start at 2 since '.' and '..' have f_pos of 0 and 1 respectively, so
|
||||||
@ -41,7 +60,6 @@ enum {
|
|||||||
*/
|
*/
|
||||||
BTRFS_INODE_NEEDS_FULL_SYNC,
|
BTRFS_INODE_NEEDS_FULL_SYNC,
|
||||||
BTRFS_INODE_COPY_EVERYTHING,
|
BTRFS_INODE_COPY_EVERYTHING,
|
||||||
BTRFS_INODE_IN_DELALLOC_LIST,
|
|
||||||
BTRFS_INODE_HAS_PROPS,
|
BTRFS_INODE_HAS_PROPS,
|
||||||
BTRFS_INODE_SNAPSHOT_FLUSH,
|
BTRFS_INODE_SNAPSHOT_FLUSH,
|
||||||
/*
|
/*
|
||||||
@ -428,7 +446,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
|
|||||||
u64 *orig_start, u64 *orig_block_len,
|
u64 *orig_start, u64 *orig_block_len,
|
||||||
u64 *ram_bytes, bool nowait, bool strict);
|
u64 *ram_bytes, bool nowait, bool strict);
|
||||||
|
|
||||||
void __btrfs_del_delalloc_inode(struct btrfs_root *root, struct btrfs_inode *inode);
|
void btrfs_del_delalloc_inode(struct btrfs_inode *inode);
|
||||||
struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry);
|
struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry);
|
||||||
int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index);
|
int btrfs_set_inode_index(struct btrfs_inode *dir, u64 *index);
|
||||||
int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
|
int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
|
||||||
@ -490,8 +508,7 @@ struct inode *btrfs_iget_path(struct super_block *s, u64 ino,
|
|||||||
struct btrfs_root *root, struct btrfs_path *path);
|
struct btrfs_root *root, struct btrfs_path *path);
|
||||||
struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root);
|
struct inode *btrfs_iget(struct super_block *s, u64 ino, struct btrfs_root *root);
|
||||||
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
|
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
|
||||||
struct page *page, size_t pg_offset,
|
struct page *page, u64 start, u64 len);
|
||||||
u64 start, u64 len);
|
|
||||||
int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_inode *inode);
|
struct btrfs_inode *inode);
|
||||||
int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
|
int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans,
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "disk-io.h"
|
|
||||||
#include "transaction.h"
|
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
#include "ordered-data.h"
|
#include "ordered-data.h"
|
||||||
@ -34,8 +32,7 @@
|
|||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "subpage.h"
|
#include "subpage.h"
|
||||||
#include "zoned.h"
|
#include "messages.h"
|
||||||
#include "file-item.h"
|
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
|
|
||||||
static struct bio_set btrfs_compressed_bioset;
|
static struct bio_set btrfs_compressed_bioset;
|
||||||
@ -284,7 +281,7 @@ static void end_bbio_comprssed_read(struct btrfs_bio *bbio)
|
|||||||
static noinline void end_compressed_writeback(const struct compressed_bio *cb)
|
static noinline void end_compressed_writeback(const struct compressed_bio *cb)
|
||||||
{
|
{
|
||||||
struct inode *inode = &cb->bbio.inode->vfs_inode;
|
struct inode *inode = &cb->bbio.inode->vfs_inode;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
unsigned long index = cb->start >> PAGE_SHIFT;
|
unsigned long index = cb->start >> PAGE_SHIFT;
|
||||||
unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_SHIFT;
|
unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_SHIFT;
|
||||||
struct folio_batch fbatch;
|
struct folio_batch fbatch;
|
||||||
@ -415,7 +412,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
|||||||
struct compressed_bio *cb,
|
struct compressed_bio *cb,
|
||||||
int *memstall, unsigned long *pflags)
|
int *memstall, unsigned long *pflags)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
unsigned long end_index;
|
unsigned long end_index;
|
||||||
struct bio *orig_bio = &cb->orig_bbio->bio;
|
struct bio *orig_bio = &cb->orig_bbio->bio;
|
||||||
u64 cur = cb->orig_bbio->file_offset + orig_bio->bi_iter.bi_size;
|
u64 cur = cb->orig_bbio->file_offset + orig_bio->bi_iter.bi_size;
|
||||||
@ -441,7 +438,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
|
|||||||
* This makes readahead less effective, so here disable readahead for
|
* This makes readahead less effective, so here disable readahead for
|
||||||
* subpage for now, until full compressed write is supported.
|
* subpage for now, until full compressed write is supported.
|
||||||
*/
|
*/
|
||||||
if (btrfs_sb(inode->i_sb)->sectorsize < PAGE_SIZE)
|
if (fs_info->sectorsize < PAGE_SIZE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
end_index = (i_size_read(inode) - 1) >> PAGE_SHIFT;
|
end_index = (i_size_read(inode) - 1) >> PAGE_SHIFT;
|
||||||
@ -1039,7 +1036,7 @@ static int btrfs_decompress_bio(struct compressed_bio *cb)
|
|||||||
int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page,
|
int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page,
|
||||||
unsigned long dest_pgoff, size_t srclen, size_t destlen)
|
unsigned long dest_pgoff, size_t srclen, size_t destlen)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dest_page->mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = page_to_fs_info(dest_page);
|
||||||
struct list_head *workspace;
|
struct list_head *workspace;
|
||||||
const u32 sectorsize = fs_info->sectorsize;
|
const u32 sectorsize = fs_info->sectorsize;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1479,11 +1476,6 @@ static void heuristic_collect_sample(struct inode *inode, u64 start, u64 end,
|
|||||||
/*
|
/*
|
||||||
* Compression heuristic.
|
* Compression heuristic.
|
||||||
*
|
*
|
||||||
* For now is's a naive and optimistic 'return true', we'll extend the logic to
|
|
||||||
* quickly (compared to direct compression) detect data characteristics
|
|
||||||
* (compressible/incompressible) to avoid wasting CPU time on incompressible
|
|
||||||
* data.
|
|
||||||
*
|
|
||||||
* The following types of analysis can be performed:
|
* The following types of analysis can be performed:
|
||||||
* - detect mostly zero data
|
* - detect mostly zero data
|
||||||
* - detect data with low "byte set" size (text, etc)
|
* - detect data with low "byte set" size (text, etc)
|
||||||
|
@ -7,10 +7,18 @@
|
|||||||
#define BTRFS_COMPRESSION_H
|
#define BTRFS_COMPRESSION_H
|
||||||
|
|
||||||
#include <linux/sizes.h>
|
#include <linux/sizes.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
|
|
||||||
|
struct address_space;
|
||||||
|
struct page;
|
||||||
|
struct inode;
|
||||||
struct btrfs_inode;
|
struct btrfs_inode;
|
||||||
struct btrfs_ordered_extent;
|
struct btrfs_ordered_extent;
|
||||||
|
struct btrfs_bio;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to make sure that amount of RAM required to uncompress an extent is
|
* We want to make sure that amount of RAM required to uncompress an extent is
|
||||||
@ -32,8 +40,6 @@ static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0);
|
|||||||
|
|
||||||
#define BTRFS_ZLIB_DEFAULT_LEVEL 3
|
#define BTRFS_ZLIB_DEFAULT_LEVEL 3
|
||||||
|
|
||||||
struct page;
|
|
||||||
|
|
||||||
struct compressed_bio {
|
struct compressed_bio {
|
||||||
/* Number of compressed pages in the array */
|
/* Number of compressed pages in the array */
|
||||||
unsigned int nr_pages;
|
unsigned int nr_pages;
|
||||||
@ -169,7 +175,7 @@ int zstd_compress_pages(struct list_head *ws, struct address_space *mapping,
|
|||||||
unsigned long *total_in, unsigned long *total_out);
|
unsigned long *total_in, unsigned long *total_out);
|
||||||
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
|
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
|
||||||
int zstd_decompress(struct list_head *ws, const u8 *data_in,
|
int zstd_decompress(struct list_head *ws, const u8 *data_in,
|
||||||
struct page *dest_page, unsigned long start_byte, size_t srclen,
|
struct page *dest_page, unsigned long dest_pgoff, size_t srclen,
|
||||||
size_t destlen);
|
size_t destlen);
|
||||||
void zstd_init_workspace_manager(void);
|
void zstd_init_workspace_manager(void);
|
||||||
void zstd_cleanup_workspace_manager(void);
|
void zstd_cleanup_workspace_manager(void);
|
||||||
|
@ -820,7 +820,7 @@ int btrfs_bin_search(struct extent_buffer *eb, int first_slot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (low < high) {
|
while (low < high) {
|
||||||
const int unit_size = folio_size(eb->folios[0]);
|
const int unit_size = eb->folio_size;
|
||||||
unsigned long oil;
|
unsigned long oil;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
struct btrfs_disk_key *tmp;
|
struct btrfs_disk_key *tmp;
|
||||||
@ -4280,6 +4280,10 @@ void btrfs_setup_item_for_insert(struct btrfs_trans_handle *trans,
|
|||||||
/*
|
/*
|
||||||
* Given a key and some data, insert items into the tree.
|
* Given a key and some data, insert items into the tree.
|
||||||
* This does all the path init required, making room in the tree if needed.
|
* This does all the path init required, making room in the tree if needed.
|
||||||
|
*
|
||||||
|
* Returns: 0 on success
|
||||||
|
* -EEXIST if the first key already exists
|
||||||
|
* < 0 on other errors
|
||||||
*/
|
*/
|
||||||
int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
|
int btrfs_insert_empty_items(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
@ -5082,9 +5086,7 @@ int btrfs_previous_extent_item(struct btrfs_root *root,
|
|||||||
|
|
||||||
int __init btrfs_ctree_init(void)
|
int __init btrfs_ctree_init(void)
|
||||||
{
|
{
|
||||||
btrfs_path_cachep = kmem_cache_create("btrfs_path",
|
btrfs_path_cachep = KMEM_CACHE(btrfs_path, 0);
|
||||||
sizeof(struct btrfs_path), 0,
|
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_path_cachep)
|
if (!btrfs_path_cachep)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -7,25 +7,24 @@
|
|||||||
#define BTRFS_CTREE_H
|
#define BTRFS_CTREE_H
|
||||||
|
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/xarray.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
|
#include "extent-io-tree.h"
|
||||||
|
|
||||||
|
struct extent_buffer;
|
||||||
|
struct btrfs_block_rsv;
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
struct btrfs_transaction;
|
|
||||||
struct btrfs_pending_snapshot;
|
|
||||||
struct btrfs_delayed_ref_root;
|
|
||||||
struct btrfs_space_info;
|
|
||||||
struct btrfs_block_group;
|
struct btrfs_block_group;
|
||||||
struct btrfs_ordered_sum;
|
|
||||||
struct btrfs_ref;
|
|
||||||
struct btrfs_bio;
|
|
||||||
struct btrfs_ioctl_encoded_io_args;
|
|
||||||
struct btrfs_device;
|
|
||||||
struct btrfs_fs_devices;
|
|
||||||
struct btrfs_balance_control;
|
|
||||||
struct btrfs_delayed_root;
|
|
||||||
struct reloc_control;
|
|
||||||
|
|
||||||
/* Read ahead values for struct btrfs_path.reada */
|
/* Read ahead values for struct btrfs_path.reada */
|
||||||
enum {
|
enum {
|
||||||
@ -478,8 +477,7 @@ static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping)
|
|||||||
return mapping_gfp_constraint(mapping, ~__GFP_FS);
|
return mapping_gfp_constraint(mapping, ~__GFP_FS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
|
void btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, u64 start, u64 end);
|
||||||
u64 start, u64 end);
|
|
||||||
int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
|
int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||||
u64 num_bytes, u64 *actual_bytes);
|
u64 num_bytes, u64 *actual_bytes);
|
||||||
int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
|
int btrfs_trim_fs(struct btrfs_fs_info *fs_info, struct fstrim_range *range);
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
@ -521,7 +520,7 @@ static int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
|||||||
* keep_locks set and lowest_level is 1, regardless of the value of
|
* keep_locks set and lowest_level is 1, regardless of the value of
|
||||||
* path->slots[1].
|
* path->slots[1].
|
||||||
*/
|
*/
|
||||||
BUG_ON(path->locks[1] == 0);
|
ASSERT(path->locks[1] != 0);
|
||||||
ret = btrfs_realloc_node(trans, root,
|
ret = btrfs_realloc_node(trans, root,
|
||||||
path->nodes[1], 0,
|
path->nodes[1], 0,
|
||||||
&last_ret,
|
&last_ret,
|
||||||
@ -810,7 +809,7 @@ static u32 get_extent_max_capacity(const struct btrfs_fs_info *fs_info,
|
|||||||
static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
|
static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em,
|
||||||
u32 extent_thresh, u64 newer_than, bool locked)
|
u32 extent_thresh, u64 newer_than, bool locked)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct extent_map *next;
|
struct extent_map *next;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
@ -861,20 +860,21 @@ out:
|
|||||||
* NOTE: Caller should also wait for page writeback after the cluster is
|
* NOTE: Caller should also wait for page writeback after the cluster is
|
||||||
* prepared, here we don't do writeback wait for each page.
|
* prepared, here we don't do writeback wait for each page.
|
||||||
*/
|
*/
|
||||||
static struct page *defrag_prepare_one_page(struct btrfs_inode *inode, pgoff_t index)
|
static struct folio *defrag_prepare_one_folio(struct btrfs_inode *inode, pgoff_t index)
|
||||||
{
|
{
|
||||||
struct address_space *mapping = inode->vfs_inode.i_mapping;
|
struct address_space *mapping = inode->vfs_inode.i_mapping;
|
||||||
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
||||||
u64 page_start = (u64)index << PAGE_SHIFT;
|
u64 page_start = (u64)index << PAGE_SHIFT;
|
||||||
u64 page_end = page_start + PAGE_SIZE - 1;
|
u64 page_end = page_start + PAGE_SIZE - 1;
|
||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
struct page *page;
|
struct folio *folio;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
page = find_or_create_page(mapping, index, mask);
|
folio = __filemap_get_folio(mapping, index,
|
||||||
if (!page)
|
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, mask);
|
||||||
return ERR_PTR(-ENOMEM);
|
if (IS_ERR(folio))
|
||||||
|
return folio;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we can defragment files opened read-only, we can encounter
|
* Since we can defragment files opened read-only, we can encounter
|
||||||
@ -884,16 +884,16 @@ again:
|
|||||||
* executables that explicitly enable them, so this isn't very
|
* executables that explicitly enable them, so this isn't very
|
||||||
* restrictive.
|
* restrictive.
|
||||||
*/
|
*/
|
||||||
if (PageCompound(page)) {
|
if (folio_test_large(folio)) {
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
return ERR_PTR(-ETXTBSY);
|
return ERR_PTR(-ETXTBSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = set_page_extent_mapped(page);
|
ret = set_folio_extent_mapped(folio);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,17 +908,17 @@ again:
|
|||||||
if (!ordered)
|
if (!ordered)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
btrfs_start_ordered_extent(ordered);
|
btrfs_start_ordered_extent(ordered);
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
lock_page(page);
|
folio_lock(folio);
|
||||||
/*
|
/*
|
||||||
* We unlocked the page above, so we need check if it was
|
* We unlocked the folio above, so we need check if it was
|
||||||
* released or not.
|
* released or not.
|
||||||
*/
|
*/
|
||||||
if (page->mapping != mapping || !PagePrivate(page)) {
|
if (folio->mapping != mapping || !folio->private) {
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -927,21 +927,21 @@ again:
|
|||||||
* Now the page range has no ordered extent any more. Read the page to
|
* Now the page range has no ordered extent any more. Read the page to
|
||||||
* make it uptodate.
|
* make it uptodate.
|
||||||
*/
|
*/
|
||||||
if (!PageUptodate(page)) {
|
if (!folio_test_uptodate(folio)) {
|
||||||
btrfs_read_folio(NULL, page_folio(page));
|
btrfs_read_folio(NULL, folio);
|
||||||
lock_page(page);
|
folio_lock(folio);
|
||||||
if (page->mapping != mapping || !PagePrivate(page)) {
|
if (folio->mapping != mapping || !folio->private) {
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
if (!PageUptodate(page)) {
|
if (!folio_test_uptodate(folio)) {
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
return ERR_PTR(-EIO);
|
return ERR_PTR(-EIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return page;
|
return folio;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct defrag_target_range {
|
struct defrag_target_range {
|
||||||
@ -1162,7 +1162,7 @@ static_assert(PAGE_ALIGNED(CLUSTER_SIZE));
|
|||||||
*/
|
*/
|
||||||
static int defrag_one_locked_target(struct btrfs_inode *inode,
|
static int defrag_one_locked_target(struct btrfs_inode *inode,
|
||||||
struct defrag_target_range *target,
|
struct defrag_target_range *target,
|
||||||
struct page **pages, int nr_pages,
|
struct folio **folios, int nr_pages,
|
||||||
struct extent_state **cached_state)
|
struct extent_state **cached_state)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||||
@ -1171,7 +1171,7 @@ static int defrag_one_locked_target(struct btrfs_inode *inode,
|
|||||||
const u64 len = target->len;
|
const u64 len = target->len;
|
||||||
unsigned long last_index = (start + len - 1) >> PAGE_SHIFT;
|
unsigned long last_index = (start + len - 1) >> PAGE_SHIFT;
|
||||||
unsigned long start_index = start >> PAGE_SHIFT;
|
unsigned long start_index = start >> PAGE_SHIFT;
|
||||||
unsigned long first_index = page_index(pages[0]);
|
unsigned long first_index = folios[0]->index;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1188,8 +1188,8 @@ static int defrag_one_locked_target(struct btrfs_inode *inode,
|
|||||||
|
|
||||||
/* Update the page status */
|
/* Update the page status */
|
||||||
for (i = start_index - first_index; i <= last_index - first_index; i++) {
|
for (i = start_index - first_index; i <= last_index - first_index; i++) {
|
||||||
ClearPageChecked(pages[i]);
|
folio_clear_checked(folios[i]);
|
||||||
btrfs_folio_clamp_set_dirty(fs_info, page_folio(pages[i]), start, len);
|
btrfs_folio_clamp_set_dirty(fs_info, folios[i], start, len);
|
||||||
}
|
}
|
||||||
btrfs_delalloc_release_extents(inode, len);
|
btrfs_delalloc_release_extents(inode, len);
|
||||||
extent_changeset_free(data_reserved);
|
extent_changeset_free(data_reserved);
|
||||||
@ -1205,7 +1205,7 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
|
|||||||
struct defrag_target_range *entry;
|
struct defrag_target_range *entry;
|
||||||
struct defrag_target_range *tmp;
|
struct defrag_target_range *tmp;
|
||||||
LIST_HEAD(target_list);
|
LIST_HEAD(target_list);
|
||||||
struct page **pages;
|
struct folio **folios;
|
||||||
const u32 sectorsize = inode->root->fs_info->sectorsize;
|
const u32 sectorsize = inode->root->fs_info->sectorsize;
|
||||||
u64 last_index = (start + len - 1) >> PAGE_SHIFT;
|
u64 last_index = (start + len - 1) >> PAGE_SHIFT;
|
||||||
u64 start_index = start >> PAGE_SHIFT;
|
u64 start_index = start >> PAGE_SHIFT;
|
||||||
@ -1216,21 +1216,21 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
|
|||||||
ASSERT(nr_pages <= CLUSTER_SIZE / PAGE_SIZE);
|
ASSERT(nr_pages <= CLUSTER_SIZE / PAGE_SIZE);
|
||||||
ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(len, sectorsize));
|
ASSERT(IS_ALIGNED(start, sectorsize) && IS_ALIGNED(len, sectorsize));
|
||||||
|
|
||||||
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
|
folios = kcalloc(nr_pages, sizeof(struct folio *), GFP_NOFS);
|
||||||
if (!pages)
|
if (!folios)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Prepare all pages */
|
/* Prepare all pages */
|
||||||
for (i = 0; i < nr_pages; i++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
pages[i] = defrag_prepare_one_page(inode, start_index + i);
|
folios[i] = defrag_prepare_one_folio(inode, start_index + i);
|
||||||
if (IS_ERR(pages[i])) {
|
if (IS_ERR(folios[i])) {
|
||||||
ret = PTR_ERR(pages[i]);
|
ret = PTR_ERR(folios[i]);
|
||||||
pages[i] = NULL;
|
nr_pages = i;
|
||||||
goto free_pages;
|
goto free_folios;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < nr_pages; i++)
|
for (i = 0; i < nr_pages; i++)
|
||||||
wait_on_page_writeback(pages[i]);
|
folio_wait_writeback(folios[i]);
|
||||||
|
|
||||||
/* Lock the pages range */
|
/* Lock the pages range */
|
||||||
lock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
|
lock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
|
||||||
@ -1250,7 +1250,7 @@ static int defrag_one_range(struct btrfs_inode *inode, u64 start, u32 len,
|
|||||||
goto unlock_extent;
|
goto unlock_extent;
|
||||||
|
|
||||||
list_for_each_entry(entry, &target_list, list) {
|
list_for_each_entry(entry, &target_list, list) {
|
||||||
ret = defrag_one_locked_target(inode, entry, pages, nr_pages,
|
ret = defrag_one_locked_target(inode, entry, folios, nr_pages,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
@ -1264,14 +1264,12 @@ unlock_extent:
|
|||||||
unlock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
|
unlock_extent(&inode->io_tree, start_index << PAGE_SHIFT,
|
||||||
(last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
|
(last_index << PAGE_SHIFT) + PAGE_SIZE - 1,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
free_pages:
|
free_folios:
|
||||||
for (i = 0; i < nr_pages; i++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
if (pages[i]) {
|
folio_unlock(folios[i]);
|
||||||
unlock_page(pages[i]);
|
folio_put(folios[i]);
|
||||||
put_page(pages[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
kfree(pages);
|
kfree(folios);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1366,7 +1364,7 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
|||||||
struct btrfs_ioctl_defrag_range_args *range,
|
struct btrfs_ioctl_defrag_range_args *range,
|
||||||
u64 newer_than, unsigned long max_to_defrag)
|
u64 newer_than, unsigned long max_to_defrag)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
unsigned long sectors_defragged = 0;
|
unsigned long sectors_defragged = 0;
|
||||||
u64 isize = i_size_read(inode);
|
u64 isize = i_size_read(inode);
|
||||||
u64 cur;
|
u64 cur;
|
||||||
@ -1512,9 +1510,7 @@ void __cold btrfs_auto_defrag_exit(void)
|
|||||||
int __init btrfs_auto_defrag_init(void)
|
int __init btrfs_auto_defrag_init(void)
|
||||||
{
|
{
|
||||||
btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag",
|
btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag",
|
||||||
sizeof(struct inode_defrag), 0,
|
sizeof(struct inode_defrag), 0, 0, NULL);
|
||||||
SLAB_MEM_SPREAD,
|
|
||||||
NULL);
|
|
||||||
if (!btrfs_inode_defrag_cachep)
|
if (!btrfs_inode_defrag_cachep)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -3,6 +3,16 @@
|
|||||||
#ifndef BTRFS_DEFRAG_H
|
#ifndef BTRFS_DEFRAG_H
|
||||||
#define BTRFS_DEFRAG_H
|
#define BTRFS_DEFRAG_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/compiler_types.h>
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct file_ra_state;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_ioctl_defrag_range_args;
|
||||||
|
|
||||||
int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||||
struct btrfs_ioctl_defrag_range_args *range,
|
struct btrfs_ioctl_defrag_range_args *range,
|
||||||
u64 newer_than, unsigned long max_to_defrag);
|
u64 newer_than, unsigned long max_to_defrag);
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
#include "block-rsv.h"
|
#include "block-rsv.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "transaction.h"
|
|
||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "block-group.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3,7 +3,11 @@
|
|||||||
#ifndef BTRFS_DELALLOC_SPACE_H
|
#ifndef BTRFS_DELALLOC_SPACE_H
|
||||||
#define BTRFS_DELALLOC_SPACE_H
|
#define BTRFS_DELALLOC_SPACE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
struct extent_changeset;
|
struct extent_changeset;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes);
|
int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes);
|
||||||
int btrfs_check_data_free_space(struct btrfs_inode *inode,
|
int btrfs_check_data_free_space(struct btrfs_inode *inode,
|
||||||
|
@ -28,11 +28,7 @@ static struct kmem_cache *delayed_node_cache;
|
|||||||
|
|
||||||
int __init btrfs_delayed_inode_init(void)
|
int __init btrfs_delayed_inode_init(void)
|
||||||
{
|
{
|
||||||
delayed_node_cache = kmem_cache_create("btrfs_delayed_node",
|
delayed_node_cache = KMEM_CACHE(btrfs_delayed_node, 0);
|
||||||
sizeof(struct btrfs_delayed_node),
|
|
||||||
0,
|
|
||||||
SLAB_MEM_SPREAD,
|
|
||||||
NULL);
|
|
||||||
if (!delayed_node_cache)
|
if (!delayed_node_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
@ -43,6 +39,17 @@ void __cold btrfs_delayed_inode_exit(void)
|
|||||||
kmem_cache_destroy(delayed_node_cache);
|
kmem_cache_destroy(delayed_node_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_init_delayed_root(struct btrfs_delayed_root *delayed_root)
|
||||||
|
{
|
||||||
|
atomic_set(&delayed_root->items, 0);
|
||||||
|
atomic_set(&delayed_root->items_seq, 0);
|
||||||
|
delayed_root->nodes = 0;
|
||||||
|
spin_lock_init(&delayed_root->lock);
|
||||||
|
init_waitqueue_head(&delayed_root->wait);
|
||||||
|
INIT_LIST_HEAD(&delayed_root->node_list);
|
||||||
|
INIT_LIST_HEAD(&delayed_root->prepare_list);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void btrfs_init_delayed_node(
|
static inline void btrfs_init_delayed_node(
|
||||||
struct btrfs_delayed_node *delayed_node,
|
struct btrfs_delayed_node *delayed_node,
|
||||||
struct btrfs_root *root, u64 inode_id)
|
struct btrfs_root *root, u64 inode_id)
|
||||||
@ -430,8 +437,6 @@ static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item)
|
|||||||
|
|
||||||
delayed_root = delayed_node->root->fs_info->delayed_root;
|
delayed_root = delayed_node->root->fs_info->delayed_root;
|
||||||
|
|
||||||
BUG_ON(!delayed_root);
|
|
||||||
|
|
||||||
if (delayed_item->type == BTRFS_DELAYED_INSERTION_ITEM)
|
if (delayed_item->type == BTRFS_DELAYED_INSERTION_ITEM)
|
||||||
root = &delayed_node->ins_root;
|
root = &delayed_node->ins_root;
|
||||||
else
|
else
|
||||||
@ -980,7 +985,7 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
|
|||||||
|
|
||||||
if (delayed_node &&
|
if (delayed_node &&
|
||||||
test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
|
test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
|
||||||
BUG_ON(!delayed_node->root);
|
ASSERT(delayed_node->root);
|
||||||
clear_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
|
clear_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
|
||||||
delayed_node->count--;
|
delayed_node->count--;
|
||||||
|
|
||||||
|
@ -7,15 +7,23 @@
|
|||||||
#ifndef BTRFS_DELAYED_INODE_H
|
#ifndef BTRFS_DELAYED_INODE_H
|
||||||
#define BTRFS_DELAYED_INODE_H
|
#define BTRFS_DELAYED_INODE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
|
|
||||||
|
struct btrfs_disk_key;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
enum btrfs_delayed_item_type {
|
enum btrfs_delayed_item_type {
|
||||||
BTRFS_DELAYED_INSERTION_ITEM,
|
BTRFS_DELAYED_INSERTION_ITEM,
|
||||||
BTRFS_DELAYED_DELETION_ITEM
|
BTRFS_DELAYED_DELETION_ITEM
|
||||||
@ -98,18 +106,7 @@ struct btrfs_delayed_item {
|
|||||||
char data[] __counted_by(data_len);
|
char data[] __counted_by(data_len);
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void btrfs_init_delayed_root(
|
void btrfs_init_delayed_root(struct btrfs_delayed_root *delayed_root);
|
||||||
struct btrfs_delayed_root *delayed_root)
|
|
||||||
{
|
|
||||||
atomic_set(&delayed_root->items, 0);
|
|
||||||
atomic_set(&delayed_root->items_seq, 0);
|
|
||||||
delayed_root->nodes = 0;
|
|
||||||
spin_lock_init(&delayed_root->lock);
|
|
||||||
init_waitqueue_head(&delayed_root->wait);
|
|
||||||
INIT_LIST_HEAD(&delayed_root->node_list);
|
|
||||||
INIT_LIST_HEAD(&delayed_root->prepare_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||||
const char *name, int name_len,
|
const char *name, int name_len,
|
||||||
struct btrfs_inode *dir,
|
struct btrfs_inode *dir,
|
||||||
|
@ -1004,6 +1004,52 @@ static void init_delayed_ref_common(struct btrfs_fs_info *fs_info,
|
|||||||
INIT_LIST_HEAD(&ref->add_list);
|
INIT_LIST_HEAD(&ref->add_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_init_generic_ref(struct btrfs_ref *generic_ref, int action, u64 bytenr,
|
||||||
|
u64 len, u64 parent, u64 owning_root)
|
||||||
|
{
|
||||||
|
generic_ref->action = action;
|
||||||
|
generic_ref->bytenr = bytenr;
|
||||||
|
generic_ref->len = len;
|
||||||
|
generic_ref->parent = parent;
|
||||||
|
generic_ref->owning_root = owning_root;
|
||||||
|
}
|
||||||
|
|
||||||
|
void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, int level, u64 root,
|
||||||
|
u64 mod_root, bool skip_qgroup)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
|
||||||
|
/* If @real_root not set, use @root as fallback */
|
||||||
|
generic_ref->real_root = mod_root ?: root;
|
||||||
|
#endif
|
||||||
|
generic_ref->tree_ref.level = level;
|
||||||
|
generic_ref->tree_ref.ref_root = root;
|
||||||
|
generic_ref->type = BTRFS_REF_METADATA;
|
||||||
|
if (skip_qgroup || !(is_fstree(root) &&
|
||||||
|
(!mod_root || is_fstree(mod_root))))
|
||||||
|
generic_ref->skip_qgroup = true;
|
||||||
|
else
|
||||||
|
generic_ref->skip_qgroup = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void btrfs_init_data_ref(struct btrfs_ref *generic_ref, u64 ref_root, u64 ino,
|
||||||
|
u64 offset, u64 mod_root, bool skip_qgroup)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
|
||||||
|
/* If @real_root not set, use @root as fallback */
|
||||||
|
generic_ref->real_root = mod_root ?: ref_root;
|
||||||
|
#endif
|
||||||
|
generic_ref->data_ref.ref_root = ref_root;
|
||||||
|
generic_ref->data_ref.ino = ino;
|
||||||
|
generic_ref->data_ref.offset = offset;
|
||||||
|
generic_ref->type = BTRFS_REF_DATA;
|
||||||
|
if (skip_qgroup || !(is_fstree(ref_root) &&
|
||||||
|
(!mod_root || is_fstree(mod_root))))
|
||||||
|
generic_ref->skip_qgroup = true;
|
||||||
|
else
|
||||||
|
generic_ref->skip_qgroup = false;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add a delayed tree ref. This does all of the accounting required
|
* add a delayed tree ref. This does all of the accounting required
|
||||||
* to make sure the delayed ref is eventually processed before this
|
* to make sure the delayed ref is eventually processed before this
|
||||||
@ -1220,6 +1266,25 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
|
||||||
|
{
|
||||||
|
if (refcount_dec_and_test(&ref->refs)) {
|
||||||
|
WARN_ON(!RB_EMPTY_NODE(&ref->ref_node));
|
||||||
|
switch (ref->type) {
|
||||||
|
case BTRFS_TREE_BLOCK_REF_KEY:
|
||||||
|
case BTRFS_SHARED_BLOCK_REF_KEY:
|
||||||
|
kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref);
|
||||||
|
break;
|
||||||
|
case BTRFS_EXTENT_DATA_REF_KEY:
|
||||||
|
case BTRFS_SHARED_DATA_REF_KEY:
|
||||||
|
kmem_cache_free(btrfs_delayed_data_ref_cachep, ref);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This does a simple search for the head node for a given extent. Returns the
|
* This does a simple search for the head node for a given extent. Returns the
|
||||||
* head node if found, or NULL if not.
|
* head node if found, or NULL if not.
|
||||||
@ -1242,31 +1307,19 @@ void __cold btrfs_delayed_ref_exit(void)
|
|||||||
|
|
||||||
int __init btrfs_delayed_ref_init(void)
|
int __init btrfs_delayed_ref_init(void)
|
||||||
{
|
{
|
||||||
btrfs_delayed_ref_head_cachep = kmem_cache_create(
|
btrfs_delayed_ref_head_cachep = KMEM_CACHE(btrfs_delayed_ref_head, 0);
|
||||||
"btrfs_delayed_ref_head",
|
|
||||||
sizeof(struct btrfs_delayed_ref_head), 0,
|
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_delayed_ref_head_cachep)
|
if (!btrfs_delayed_ref_head_cachep)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
btrfs_delayed_tree_ref_cachep = kmem_cache_create(
|
btrfs_delayed_tree_ref_cachep = KMEM_CACHE(btrfs_delayed_tree_ref, 0);
|
||||||
"btrfs_delayed_tree_ref",
|
|
||||||
sizeof(struct btrfs_delayed_tree_ref), 0,
|
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_delayed_tree_ref_cachep)
|
if (!btrfs_delayed_tree_ref_cachep)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
btrfs_delayed_data_ref_cachep = kmem_cache_create(
|
btrfs_delayed_data_ref_cachep = KMEM_CACHE(btrfs_delayed_data_ref, 0);
|
||||||
"btrfs_delayed_data_ref",
|
|
||||||
sizeof(struct btrfs_delayed_data_ref), 0,
|
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_delayed_data_ref_cachep)
|
if (!btrfs_delayed_data_ref_cachep)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
btrfs_delayed_extent_op_cachep = kmem_cache_create(
|
btrfs_delayed_extent_op_cachep = KMEM_CACHE(btrfs_delayed_extent_op, 0);
|
||||||
"btrfs_delayed_extent_op",
|
|
||||||
sizeof(struct btrfs_delayed_extent_op), 0,
|
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_delayed_extent_op_cachep)
|
if (!btrfs_delayed_extent_op_cachep)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -6,7 +6,17 @@
|
|||||||
#ifndef BTRFS_DELAYED_REF_H
|
#ifndef BTRFS_DELAYED_REF_H
|
||||||
#define BTRFS_DELAYED_REF_H
|
#define BTRFS_DELAYED_REF_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
|
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
/* these are the possible values of struct btrfs_delayed_ref_node->action */
|
/* these are the possible values of struct btrfs_delayed_ref_node->action */
|
||||||
enum btrfs_delayed_ref_action {
|
enum btrfs_delayed_ref_action {
|
||||||
@ -308,53 +318,12 @@ static inline u64 btrfs_calc_delayed_ref_csum_bytes(const struct btrfs_fs_info *
|
|||||||
return btrfs_calc_metadata_size(fs_info, num_csum_items);
|
return btrfs_calc_metadata_size(fs_info, num_csum_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void btrfs_init_generic_ref(struct btrfs_ref *generic_ref,
|
void btrfs_init_generic_ref(struct btrfs_ref *generic_ref, int action, u64 bytenr,
|
||||||
int action, u64 bytenr, u64 len,
|
u64 len, u64 parent, u64 owning_root);
|
||||||
u64 parent, u64 owning_root)
|
void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, int level, u64 root,
|
||||||
{
|
u64 mod_root, bool skip_qgroup);
|
||||||
generic_ref->action = action;
|
void btrfs_init_data_ref(struct btrfs_ref *generic_ref, u64 ref_root, u64 ino,
|
||||||
generic_ref->bytenr = bytenr;
|
u64 offset, u64 mod_root, bool skip_qgroup);
|
||||||
generic_ref->len = len;
|
|
||||||
generic_ref->parent = parent;
|
|
||||||
generic_ref->owning_root = owning_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, int level,
|
|
||||||
u64 root, u64 mod_root, bool skip_qgroup)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
|
|
||||||
/* If @real_root not set, use @root as fallback */
|
|
||||||
generic_ref->real_root = mod_root ?: root;
|
|
||||||
#endif
|
|
||||||
generic_ref->tree_ref.level = level;
|
|
||||||
generic_ref->tree_ref.ref_root = root;
|
|
||||||
generic_ref->type = BTRFS_REF_METADATA;
|
|
||||||
if (skip_qgroup || !(is_fstree(root) &&
|
|
||||||
(!mod_root || is_fstree(mod_root))))
|
|
||||||
generic_ref->skip_qgroup = true;
|
|
||||||
else
|
|
||||||
generic_ref->skip_qgroup = false;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_init_data_ref(struct btrfs_ref *generic_ref,
|
|
||||||
u64 ref_root, u64 ino, u64 offset, u64 mod_root,
|
|
||||||
bool skip_qgroup)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
|
|
||||||
/* If @real_root not set, use @root as fallback */
|
|
||||||
generic_ref->real_root = mod_root ?: ref_root;
|
|
||||||
#endif
|
|
||||||
generic_ref->data_ref.ref_root = ref_root;
|
|
||||||
generic_ref->data_ref.ino = ino;
|
|
||||||
generic_ref->data_ref.offset = offset;
|
|
||||||
generic_ref->type = BTRFS_REF_DATA;
|
|
||||||
if (skip_qgroup || !(is_fstree(ref_root) &&
|
|
||||||
(!mod_root || is_fstree(mod_root))))
|
|
||||||
generic_ref->skip_qgroup = true;
|
|
||||||
else
|
|
||||||
generic_ref->skip_qgroup = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct btrfs_delayed_extent_op *
|
static inline struct btrfs_delayed_extent_op *
|
||||||
btrfs_alloc_delayed_extent_op(void)
|
btrfs_alloc_delayed_extent_op(void)
|
||||||
@ -369,24 +338,7 @@ btrfs_free_delayed_extent_op(struct btrfs_delayed_extent_op *op)
|
|||||||
kmem_cache_free(btrfs_delayed_extent_op_cachep, op);
|
kmem_cache_free(btrfs_delayed_extent_op_cachep, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
|
void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref);
|
||||||
{
|
|
||||||
if (refcount_dec_and_test(&ref->refs)) {
|
|
||||||
WARN_ON(!RB_EMPTY_NODE(&ref->ref_node));
|
|
||||||
switch (ref->type) {
|
|
||||||
case BTRFS_TREE_BLOCK_REF_KEY:
|
|
||||||
case BTRFS_SHARED_BLOCK_REF_KEY:
|
|
||||||
kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref);
|
|
||||||
break;
|
|
||||||
case BTRFS_EXTENT_DATA_REF_KEY:
|
|
||||||
case BTRFS_SHARED_DATA_REF_KEY:
|
|
||||||
kmem_cache_free(btrfs_delayed_data_ref_cachep, ref);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u64 btrfs_ref_head_to_space_flags(
|
static inline u64 btrfs_ref_head_to_space_flags(
|
||||||
struct btrfs_delayed_ref_head *head_ref)
|
struct btrfs_delayed_ref_head *head_ref)
|
||||||
|
@ -11,10 +11,8 @@
|
|||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent_map.h"
|
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
#include "async-thread.h"
|
#include "async-thread.h"
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
@ -1000,8 +998,7 @@ error:
|
|||||||
btrfs_sysfs_remove_device(src_device);
|
btrfs_sysfs_remove_device(src_device);
|
||||||
btrfs_sysfs_update_devid(tgt_device);
|
btrfs_sysfs_update_devid(tgt_device);
|
||||||
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &src_device->dev_state))
|
if (test_bit(BTRFS_DEV_STATE_WRITEABLE, &src_device->dev_state))
|
||||||
btrfs_scratch_superblocks(fs_info, src_device->bdev,
|
btrfs_scratch_superblocks(fs_info, src_device);
|
||||||
src_device->name->str);
|
|
||||||
|
|
||||||
/* write back the superblocks */
|
/* write back the superblocks */
|
||||||
trans = btrfs_start_transaction(root, 0);
|
trans = btrfs_start_transaction(root, 0);
|
||||||
|
@ -6,11 +6,15 @@
|
|||||||
#ifndef BTRFS_DEV_REPLACE_H
|
#ifndef BTRFS_DEV_REPLACE_H
|
||||||
#define BTRFS_DEV_REPLACE_H
|
#define BTRFS_DEV_REPLACE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/compiler_types.h>
|
||||||
|
|
||||||
struct btrfs_ioctl_dev_replace_args;
|
struct btrfs_ioctl_dev_replace_args;
|
||||||
struct btrfs_fs_info;
|
struct btrfs_fs_info;
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
struct btrfs_dev_replace;
|
struct btrfs_dev_replace;
|
||||||
struct btrfs_block_group;
|
struct btrfs_block_group;
|
||||||
|
struct btrfs_device;
|
||||||
|
|
||||||
int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
|
int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
|
||||||
int btrfs_run_dev_replace(struct btrfs_trans_handle *trans);
|
int btrfs_run_dev_replace(struct btrfs_trans_handle *trans);
|
||||||
|
@ -3,9 +3,15 @@
|
|||||||
#ifndef BTRFS_DIR_ITEM_H
|
#ifndef BTRFS_DIR_ITEM_H
|
||||||
#define BTRFS_DIR_ITEM_H
|
#define BTRFS_DIR_ITEM_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include <linux/crc32c.h>
|
#include <linux/crc32c.h>
|
||||||
|
|
||||||
struct fscrypt_str;
|
struct fscrypt_str;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_key;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||||
const struct fscrypt_str *name);
|
const struct fscrypt_str *name);
|
||||||
|
@ -29,7 +29,6 @@
|
|||||||
#include "tree-log.h"
|
#include "tree-log.h"
|
||||||
#include "free-space-cache.h"
|
#include "free-space-cache.h"
|
||||||
#include "free-space-tree.h"
|
#include "free-space-tree.h"
|
||||||
#include "rcu-string.h"
|
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
#include "raid56.h"
|
#include "raid56.h"
|
||||||
#include "sysfs.h"
|
#include "sysfs.h"
|
||||||
@ -193,7 +192,7 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
|
|||||||
struct folio *folio = eb->folios[i];
|
struct folio *folio = eb->folios[i];
|
||||||
u64 start = max_t(u64, eb->start, folio_pos(folio));
|
u64 start = max_t(u64, eb->start, folio_pos(folio));
|
||||||
u64 end = min_t(u64, eb->start + eb->len,
|
u64 end = min_t(u64, eb->start + eb->len,
|
||||||
folio_pos(folio) + folio_size(folio));
|
folio_pos(folio) + eb->folio_size);
|
||||||
u32 len = end - start;
|
u32 len = end - start;
|
||||||
|
|
||||||
ret = btrfs_repair_io_failure(fs_info, 0, start, len,
|
ret = btrfs_repair_io_failure(fs_info, 0, start, len,
|
||||||
@ -498,15 +497,15 @@ static int btree_migrate_folio(struct address_space *mapping,
|
|||||||
static int btree_writepages(struct address_space *mapping,
|
static int btree_writepages(struct address_space *mapping,
|
||||||
struct writeback_control *wbc)
|
struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (wbc->sync_mode == WB_SYNC_NONE) {
|
if (wbc->sync_mode == WB_SYNC_NONE) {
|
||||||
|
struct btrfs_fs_info *fs_info;
|
||||||
|
|
||||||
if (wbc->for_kupdate)
|
if (wbc->for_kupdate)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fs_info = BTRFS_I(mapping->host)->root->fs_info;
|
fs_info = inode_to_fs_info(mapping->host);
|
||||||
/* this is a bit racy, but that's ok */
|
/* this is a bit racy, but that's ok */
|
||||||
ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes,
|
ret = __percpu_counter_compare(&fs_info->dirty_metadata_bytes,
|
||||||
BTRFS_DIRTY_METADATA_THRESH,
|
BTRFS_DIRTY_METADATA_THRESH,
|
||||||
@ -529,11 +528,12 @@ static void btree_invalidate_folio(struct folio *folio, size_t offset,
|
|||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
struct extent_io_tree *tree;
|
struct extent_io_tree *tree;
|
||||||
tree = &BTRFS_I(folio->mapping->host)->io_tree;
|
|
||||||
|
tree = &folio_to_inode(folio)->io_tree;
|
||||||
extent_invalidate_folio(tree, folio, offset);
|
extent_invalidate_folio(tree, folio, offset);
|
||||||
btree_release_folio(folio, GFP_NOFS);
|
btree_release_folio(folio, GFP_NOFS);
|
||||||
if (folio_get_private(folio)) {
|
if (folio_get_private(folio)) {
|
||||||
btrfs_warn(BTRFS_I(folio->mapping->host)->root->fs_info,
|
btrfs_warn(folio_to_fs_info(folio),
|
||||||
"folio private not zero on folio %llu",
|
"folio private not zero on folio %llu",
|
||||||
(unsigned long long)folio_pos(folio));
|
(unsigned long long)folio_pos(folio));
|
||||||
folio_detach_private(folio);
|
folio_detach_private(folio);
|
||||||
@ -544,7 +544,7 @@ static void btree_invalidate_folio(struct folio *folio, size_t offset,
|
|||||||
static bool btree_dirty_folio(struct address_space *mapping,
|
static bool btree_dirty_folio(struct address_space *mapping,
|
||||||
struct folio *folio)
|
struct folio *folio)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(mapping->host);
|
||||||
struct btrfs_subpage_info *spi = fs_info->subpage_info;
|
struct btrfs_subpage_info *spi = fs_info->subpage_info;
|
||||||
struct btrfs_subpage *subpage;
|
struct btrfs_subpage *subpage;
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
@ -1244,6 +1244,7 @@ void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info)
|
|||||||
btrfs_err(fs_info, "leaked root %s refcount %d",
|
btrfs_err(fs_info, "leaked root %s refcount %d",
|
||||||
btrfs_root_name(&root->root_key, buf),
|
btrfs_root_name(&root->root_key, buf),
|
||||||
refcount_read(&root->refs));
|
refcount_read(&root->refs));
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
while (refcount_read(&root->refs) > 1)
|
while (refcount_read(&root->refs) > 1)
|
||||||
btrfs_put_root(root);
|
btrfs_put_root(root);
|
||||||
btrfs_put_root(root);
|
btrfs_put_root(root);
|
||||||
@ -2239,7 +2240,7 @@ static int btrfs_read_roots(struct btrfs_fs_info *fs_info)
|
|||||||
struct btrfs_key location;
|
struct btrfs_key location;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
BUG_ON(!fs_info->tree_root);
|
ASSERT(fs_info->tree_root);
|
||||||
|
|
||||||
ret = load_global_roots(tree_root);
|
ret = load_global_roots(tree_root);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -2839,6 +2840,7 @@ static int init_mount_fs_info(struct btrfs_fs_info *fs_info, struct super_block
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
fs_info->sb = sb;
|
fs_info->sb = sb;
|
||||||
|
/* Temporary fixed values for block size until we read the superblock. */
|
||||||
sb->s_blocksize = BTRFS_BDEV_BLOCKSIZE;
|
sb->s_blocksize = BTRFS_BDEV_BLOCKSIZE;
|
||||||
sb->s_blocksize_bits = blksize_bits(BTRFS_BDEV_BLOCKSIZE);
|
sb->s_blocksize_bits = blksize_bits(BTRFS_BDEV_BLOCKSIZE);
|
||||||
|
|
||||||
@ -3356,6 +3358,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
|||||||
sb->s_bdi->ra_pages *= btrfs_super_num_devices(disk_super);
|
sb->s_bdi->ra_pages *= btrfs_super_num_devices(disk_super);
|
||||||
sb->s_bdi->ra_pages = max(sb->s_bdi->ra_pages, SZ_4M / PAGE_SIZE);
|
sb->s_bdi->ra_pages = max(sb->s_bdi->ra_pages, SZ_4M / PAGE_SIZE);
|
||||||
|
|
||||||
|
/* Update the values for the current filesystem. */
|
||||||
sb->s_blocksize = sectorsize;
|
sb->s_blocksize = sectorsize;
|
||||||
sb->s_blocksize_bits = blksize_bits(sectorsize);
|
sb->s_blocksize_bits = blksize_bits(sectorsize);
|
||||||
memcpy(&sb->s_uuid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE);
|
memcpy(&sb->s_uuid, fs_info->fs_devices->fsid, BTRFS_FSID_SIZE);
|
||||||
@ -4626,7 +4629,7 @@ static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
|
|||||||
struct inode *inode = NULL;
|
struct inode *inode = NULL;
|
||||||
btrfs_inode = list_first_entry(&splice, struct btrfs_inode,
|
btrfs_inode = list_first_entry(&splice, struct btrfs_inode,
|
||||||
delalloc_inodes);
|
delalloc_inodes);
|
||||||
__btrfs_del_delalloc_inode(root, btrfs_inode);
|
btrfs_del_delalloc_inode(btrfs_inode);
|
||||||
spin_unlock(&root->delalloc_lock);
|
spin_unlock(&root->delalloc_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4925,7 +4928,14 @@ int btrfs_init_root_free_objectid(struct btrfs_root *root)
|
|||||||
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
BUG_ON(ret == 0); /* Corruption */
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist a root
|
||||||
|
* with such id, but this is out of valid range.
|
||||||
|
*/
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
if (path->slots[0] > 0) {
|
if (path->slots[0] > 0) {
|
||||||
slot = path->slots[0] - 1;
|
slot = path->slots[0] - 1;
|
||||||
l = path->nodes[0];
|
l = path->nodes[0];
|
||||||
|
@ -6,6 +6,22 @@
|
|||||||
#ifndef BTRFS_DISK_IO_H
|
#ifndef BTRFS_DISK_IO_H
|
||||||
#define BTRFS_DISK_IO_H
|
#define BTRFS_DISK_IO_H
|
||||||
|
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
#include <linux/compiler_types.h>
|
||||||
|
#include "ctree.h"
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
struct block_device;
|
||||||
|
struct super_block;
|
||||||
|
struct extent_buffer;
|
||||||
|
struct btrfs_device;
|
||||||
|
struct btrfs_fs_devices;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_super_block;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_tree_parent_check;
|
||||||
|
struct btrfs_transaction;
|
||||||
|
|
||||||
#define BTRFS_SUPER_MIRROR_MAX 3
|
#define BTRFS_SUPER_MIRROR_MAX 3
|
||||||
#define BTRFS_SUPER_MIRROR_SHIFT 12
|
#define BTRFS_SUPER_MIRROR_SHIFT 12
|
||||||
|
|
||||||
@ -25,10 +41,6 @@ static inline u64 btrfs_sb_offset(int mirror)
|
|||||||
return BTRFS_SUPER_INFO_OFFSET;
|
return BTRFS_SUPER_INFO_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btrfs_device;
|
|
||||||
struct btrfs_fs_devices;
|
|
||||||
struct btrfs_tree_parent_check;
|
|
||||||
|
|
||||||
void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info);
|
void btrfs_check_leaked_roots(struct btrfs_fs_info *fs_info);
|
||||||
void btrfs_init_fs_info(struct btrfs_fs_info *fs_info);
|
void btrfs_init_fs_info(struct btrfs_fs_info *fs_info);
|
||||||
struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
|
struct extent_buffer *read_tree_block(struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
@ -174,8 +173,15 @@ struct dentry *btrfs_get_parent(struct dentry *child)
|
|||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset of -1 found, there would have to exist an
|
||||||
|
* inode with such number or a root with such id.
|
||||||
|
*/
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
BUG_ON(ret == 0); /* Key with offset of -1 found */
|
|
||||||
if (path->slots[0] == 0) {
|
if (path->slots[0] == 0) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -215,7 +221,7 @@ static int btrfs_get_name(struct dentry *parent, char *name,
|
|||||||
{
|
{
|
||||||
struct inode *inode = d_inode(child);
|
struct inode *inode = d_inode(child);
|
||||||
struct inode *dir = d_inode(parent);
|
struct inode *dir = d_inode(parent);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct btrfs_inode_ref *iref;
|
struct btrfs_inode_ref *iref;
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
#define BTRFS_EXPORT_H
|
#define BTRFS_EXPORT_H
|
||||||
|
|
||||||
#include <linux/exportfs.h>
|
#include <linux/exportfs.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct dentry;
|
||||||
|
struct super_block;
|
||||||
|
|
||||||
extern const struct export_operations btrfs_export_ops;
|
extern const struct export_operations btrfs_export_ops;
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent-io-tree.h"
|
#include "extent-io-tree.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "misc.h"
|
|
||||||
|
|
||||||
static struct kmem_cache *extent_state_cache;
|
static struct kmem_cache *extent_state_cache;
|
||||||
|
|
||||||
@ -48,6 +47,7 @@ static inline void btrfs_extent_state_leak_debug_check(void)
|
|||||||
extent_state_in_tree(state),
|
extent_state_in_tree(state),
|
||||||
refcount_read(&state->refs));
|
refcount_read(&state->refs));
|
||||||
list_del(&state->leak_list);
|
list_del(&state->leak_list);
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
kmem_cache_free(extent_state_cache, state);
|
kmem_cache_free(extent_state_cache, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1883,8 +1883,8 @@ void __cold extent_state_free_cachep(void)
|
|||||||
int __init extent_state_init_cachep(void)
|
int __init extent_state_init_cachep(void)
|
||||||
{
|
{
|
||||||
extent_state_cache = kmem_cache_create("btrfs_extent_state",
|
extent_state_cache = kmem_cache_create("btrfs_extent_state",
|
||||||
sizeof(struct extent_state), 0,
|
sizeof(struct extent_state), 0, 0,
|
||||||
SLAB_MEM_SPREAD, NULL);
|
NULL);
|
||||||
if (!extent_state_cache)
|
if (!extent_state_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -3,9 +3,16 @@
|
|||||||
#ifndef BTRFS_EXTENT_IO_TREE_H
|
#ifndef BTRFS_EXTENT_IO_TREE_H
|
||||||
#define BTRFS_EXTENT_IO_TREE_H
|
#define BTRFS_EXTENT_IO_TREE_H
|
||||||
|
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
struct extent_changeset;
|
struct extent_changeset;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_inode;
|
||||||
|
|
||||||
/* Bits for the extent state */
|
/* Bits for the extent state */
|
||||||
enum {
|
enum {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#include <linux/crc32c.h>
|
#include <linux/crc32c.h>
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent-tree.h"
|
#include "extent-tree.h"
|
||||||
#include "tree-log.h"
|
#include "transaction.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
@ -26,14 +26,11 @@
|
|||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "free-space-cache.h"
|
#include "free-space-cache.h"
|
||||||
#include "free-space-tree.h"
|
#include "free-space-tree.h"
|
||||||
#include "sysfs.h"
|
|
||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "ref-verify.h"
|
#include "ref-verify.h"
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "block-rsv.h"
|
#include "block-rsv.h"
|
||||||
#include "delalloc-space.h"
|
|
||||||
#include "discard.h"
|
#include "discard.h"
|
||||||
#include "rcu-string.h"
|
|
||||||
#include "zoned.h"
|
#include "zoned.h"
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@ -2399,7 +2396,14 @@ static noinline int check_committed_ref(struct btrfs_root *root,
|
|||||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
BUG_ON(ret == 0); /* Corruption */
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist an extent
|
||||||
|
* item with such offset, but this is out of the valid range.
|
||||||
|
*/
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
if (path->slots[0] == 0)
|
if (path->slots[0] == 0)
|
||||||
@ -2780,6 +2784,7 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
|
|||||||
u64 total_unpinned = 0;
|
u64 total_unpinned = 0;
|
||||||
u64 empty_cluster = 0;
|
u64 empty_cluster = 0;
|
||||||
bool readonly;
|
bool readonly;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
readonly = false;
|
readonly = false;
|
||||||
@ -2789,7 +2794,11 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
|
|||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
total_unpinned = 0;
|
total_unpinned = 0;
|
||||||
cache = btrfs_lookup_block_group(fs_info, start);
|
cache = btrfs_lookup_block_group(fs_info, start);
|
||||||
BUG_ON(!cache); /* Logic error */
|
if (cache == NULL) {
|
||||||
|
/* Logic error, something removed the block group. */
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
cluster = fetch_cluster_info(fs_info,
|
cluster = fetch_cluster_info(fs_info,
|
||||||
cache->space_info,
|
cache->space_info,
|
||||||
@ -2858,7 +2867,8 @@ static int unpin_extent_range(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
if (cache)
|
if (cache)
|
||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
return 0;
|
out:
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
||||||
@ -2888,7 +2898,8 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
|||||||
end + 1 - start, NULL);
|
end + 1 - start, NULL);
|
||||||
|
|
||||||
clear_extent_dirty(unpin, start, end, &cached_state);
|
clear_extent_dirty(unpin, start, end, &cached_state);
|
||||||
unpin_extent_range(fs_info, start, end, true);
|
ret = unpin_extent_range(fs_info, start, end, true);
|
||||||
|
BUG_ON(ret);
|
||||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||||
free_extent_state(cached_state);
|
free_extent_state(cached_state);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
@ -3447,16 +3458,17 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|||||||
u64 parent, int last_ref)
|
u64 parent, int last_ref)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||||
struct btrfs_ref generic_ref = { 0 };
|
|
||||||
struct btrfs_block_group *bg;
|
struct btrfs_block_group *bg;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
|
|
||||||
buf->start, buf->len, parent, btrfs_header_owner(buf));
|
|
||||||
btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
|
|
||||||
root_id, 0, false);
|
|
||||||
|
|
||||||
if (root_id != BTRFS_TREE_LOG_OBJECTID) {
|
if (root_id != BTRFS_TREE_LOG_OBJECTID) {
|
||||||
|
struct btrfs_ref generic_ref = { 0 };
|
||||||
|
|
||||||
|
btrfs_init_generic_ref(&generic_ref, BTRFS_DROP_DELAYED_REF,
|
||||||
|
buf->start, buf->len, parent,
|
||||||
|
btrfs_header_owner(buf));
|
||||||
|
btrfs_init_tree_ref(&generic_ref, btrfs_header_level(buf),
|
||||||
|
root_id, 0, false);
|
||||||
btrfs_ref_tree_mod(fs_info, &generic_ref);
|
btrfs_ref_tree_mod(fs_info, &generic_ref);
|
||||||
ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL);
|
ret = btrfs_add_delayed_tree_ref(trans, &generic_ref, NULL);
|
||||||
BUG_ON(ret); /* -ENOMEM */
|
BUG_ON(ret); /* -ENOMEM */
|
||||||
@ -4950,7 +4962,7 @@ int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
|||||||
u64 root_objectid = root->root_key.objectid;
|
u64 root_objectid = root->root_key.objectid;
|
||||||
u64 owning_root = root_objectid;
|
u64 owning_root = root_objectid;
|
||||||
|
|
||||||
BUG_ON(root_objectid == BTRFS_TREE_LOG_OBJECTID);
|
ASSERT(root_objectid != BTRFS_TREE_LOG_OBJECTID);
|
||||||
|
|
||||||
if (btrfs_is_data_reloc_root(root) && is_fstree(root->relocation_src_root))
|
if (btrfs_is_data_reloc_root(root) && is_fstree(root->relocation_src_root))
|
||||||
owning_root = root->relocation_src_root;
|
owning_root = root->relocation_src_root;
|
||||||
@ -6167,10 +6179,13 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info,
|
/*
|
||||||
u64 start, u64 end)
|
* Unpin the extent range in an error context and don't add the space back.
|
||||||
|
* Errors are not propagated further.
|
||||||
|
*/
|
||||||
|
void btrfs_error_unpin_extent_range(struct btrfs_fs_info *fs_info, u64 start, u64 end)
|
||||||
{
|
{
|
||||||
return unpin_extent_range(fs_info, start, end, false);
|
unpin_extent_range(fs_info, start, end, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3,11 +3,21 @@
|
|||||||
#ifndef BTRFS_EXTENT_TREE_H
|
#ifndef BTRFS_EXTENT_TREE_H
|
||||||
#define BTRFS_EXTENT_TREE_H
|
#define BTRFS_EXTENT_TREE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "block-group.h"
|
#include "block-group.h"
|
||||||
|
#include "locking.h"
|
||||||
|
|
||||||
|
struct extent_buffer;
|
||||||
struct btrfs_free_cluster;
|
struct btrfs_free_cluster;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_ref;
|
||||||
|
struct btrfs_disk_key;
|
||||||
struct btrfs_delayed_ref_head;
|
struct btrfs_delayed_ref_head;
|
||||||
|
struct btrfs_delayed_ref_root;
|
||||||
|
struct btrfs_extent_inline_ref;
|
||||||
|
|
||||||
enum btrfs_extent_allocation_policy {
|
enum btrfs_extent_allocation_policy {
|
||||||
BTRFS_EXTENT_ALLOC_CLUSTERED,
|
BTRFS_EXTENT_ALLOC_CLUSTERED,
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include <linux/pagevec.h>
|
#include <linux/pagevec.h>
|
||||||
#include <linux/prefetch.h>
|
#include <linux/prefetch.h>
|
||||||
#include <linux/fsverity.h>
|
#include <linux/fsverity.h>
|
||||||
#include "misc.h"
|
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
#include "extent-io-tree.h"
|
#include "extent-io-tree.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
@ -22,7 +21,6 @@
|
|||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "rcu-string.h"
|
|
||||||
#include "backref.h"
|
#include "backref.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "subpage.h"
|
#include "subpage.h"
|
||||||
@ -78,10 +76,11 @@ void btrfs_extent_buffer_leak_debug_check(struct btrfs_fs_info *fs_info)
|
|||||||
eb = list_first_entry(&fs_info->allocated_ebs,
|
eb = list_first_entry(&fs_info->allocated_ebs,
|
||||||
struct extent_buffer, leak_list);
|
struct extent_buffer, leak_list);
|
||||||
pr_err(
|
pr_err(
|
||||||
"BTRFS: buffer leak start %llu len %lu refs %d bflags %lu owner %llu\n",
|
"BTRFS: buffer leak start %llu len %u refs %d bflags %lu owner %llu\n",
|
||||||
eb->start, eb->len, atomic_read(&eb->refs), eb->bflags,
|
eb->start, eb->len, atomic_read(&eb->refs), eb->bflags,
|
||||||
btrfs_header_owner(eb));
|
btrfs_header_owner(eb));
|
||||||
list_del(&eb->leak_list);
|
list_del(&eb->leak_list);
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
kmem_cache_free(extent_buffer_cache, eb);
|
kmem_cache_free(extent_buffer_cache, eb);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&fs_info->eb_leak_lock, flags);
|
spin_unlock_irqrestore(&fs_info->eb_leak_lock, flags);
|
||||||
@ -147,8 +146,8 @@ static void submit_write_bio(struct btrfs_bio_ctrl *bio_ctrl, int ret)
|
|||||||
int __init extent_buffer_init_cachep(void)
|
int __init extent_buffer_init_cachep(void)
|
||||||
{
|
{
|
||||||
extent_buffer_cache = kmem_cache_create("btrfs_extent_buffer",
|
extent_buffer_cache = kmem_cache_create("btrfs_extent_buffer",
|
||||||
sizeof(struct extent_buffer), 0,
|
sizeof(struct extent_buffer), 0, 0,
|
||||||
SLAB_MEM_SPREAD, NULL);
|
NULL);
|
||||||
if (!extent_buffer_cache)
|
if (!extent_buffer_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -207,7 +206,7 @@ static void __process_pages_contig(struct address_space *mapping,
|
|||||||
struct page *locked_page, u64 start, u64 end,
|
struct page *locked_page, u64 start, u64 end,
|
||||||
unsigned long page_ops)
|
unsigned long page_ops)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(mapping->host);
|
||||||
pgoff_t start_index = start >> PAGE_SHIFT;
|
pgoff_t start_index = start >> PAGE_SHIFT;
|
||||||
pgoff_t end_index = end >> PAGE_SHIFT;
|
pgoff_t end_index = end >> PAGE_SHIFT;
|
||||||
pgoff_t index = start_index;
|
pgoff_t index = start_index;
|
||||||
@ -251,7 +250,7 @@ static noinline int lock_delalloc_pages(struct inode *inode,
|
|||||||
u64 start,
|
u64 start,
|
||||||
u64 end)
|
u64 end)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct address_space *mapping = inode->i_mapping;
|
struct address_space *mapping = inode->i_mapping;
|
||||||
pgoff_t start_index = start >> PAGE_SHIFT;
|
pgoff_t start_index = start >> PAGE_SHIFT;
|
||||||
pgoff_t end_index = end >> PAGE_SHIFT;
|
pgoff_t end_index = end >> PAGE_SHIFT;
|
||||||
@ -323,7 +322,7 @@ noinline_for_stack bool find_lock_delalloc_range(struct inode *inode,
|
|||||||
struct page *locked_page, u64 *start,
|
struct page *locked_page, u64 *start,
|
||||||
u64 *end)
|
u64 *end)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
|
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
|
||||||
const u64 orig_start = *start;
|
const u64 orig_start = *start;
|
||||||
const u64 orig_end = *end;
|
const u64 orig_end = *end;
|
||||||
@ -433,7 +432,7 @@ static bool btrfs_verify_page(struct page *page, u64 start)
|
|||||||
|
|
||||||
static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
|
static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = page_to_fs_info(page);
|
||||||
struct folio *folio = page_folio(page);
|
struct folio *folio = page_folio(page);
|
||||||
|
|
||||||
ASSERT(page_offset(page) <= start &&
|
ASSERT(page_offset(page) <= start &&
|
||||||
@ -462,16 +461,15 @@ static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
|
|||||||
*/
|
*/
|
||||||
static void end_bbio_data_write(struct btrfs_bio *bbio)
|
static void end_bbio_data_write(struct btrfs_bio *bbio)
|
||||||
{
|
{
|
||||||
|
struct btrfs_fs_info *fs_info = bbio->fs_info;
|
||||||
struct bio *bio = &bbio->bio;
|
struct bio *bio = &bbio->bio;
|
||||||
int error = blk_status_to_errno(bio->bi_status);
|
int error = blk_status_to_errno(bio->bi_status);
|
||||||
struct folio_iter fi;
|
struct folio_iter fi;
|
||||||
|
const u32 sectorsize = fs_info->sectorsize;
|
||||||
|
|
||||||
ASSERT(!bio_flagged(bio, BIO_CLONED));
|
ASSERT(!bio_flagged(bio, BIO_CLONED));
|
||||||
bio_for_each_folio_all(fi, bio) {
|
bio_for_each_folio_all(fi, bio) {
|
||||||
struct folio *folio = fi.folio;
|
struct folio *folio = fi.folio;
|
||||||
struct inode *inode = folio->mapping->host;
|
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
|
||||||
const u32 sectorsize = fs_info->sectorsize;
|
|
||||||
u64 start = folio_pos(folio) + fi.offset;
|
u64 start = folio_pos(folio) + fi.offset;
|
||||||
u32 len = fi.length;
|
u32 len = fi.length;
|
||||||
|
|
||||||
@ -593,22 +591,17 @@ static void begin_page_read(struct btrfs_fs_info *fs_info, struct page *page)
|
|||||||
*/
|
*/
|
||||||
static void end_bbio_data_read(struct btrfs_bio *bbio)
|
static void end_bbio_data_read(struct btrfs_bio *bbio)
|
||||||
{
|
{
|
||||||
|
struct btrfs_fs_info *fs_info = bbio->fs_info;
|
||||||
struct bio *bio = &bbio->bio;
|
struct bio *bio = &bbio->bio;
|
||||||
struct processed_extent processed = { 0 };
|
struct processed_extent processed = { 0 };
|
||||||
struct folio_iter fi;
|
struct folio_iter fi;
|
||||||
/*
|
const u32 sectorsize = fs_info->sectorsize;
|
||||||
* The offset to the beginning of a bio, since one bio can never be
|
|
||||||
* larger than UINT_MAX, u32 here is enough.
|
|
||||||
*/
|
|
||||||
u32 bio_offset = 0;
|
|
||||||
|
|
||||||
ASSERT(!bio_flagged(bio, BIO_CLONED));
|
ASSERT(!bio_flagged(bio, BIO_CLONED));
|
||||||
bio_for_each_folio_all(fi, &bbio->bio) {
|
bio_for_each_folio_all(fi, &bbio->bio) {
|
||||||
bool uptodate = !bio->bi_status;
|
bool uptodate = !bio->bi_status;
|
||||||
struct folio *folio = fi.folio;
|
struct folio *folio = fi.folio;
|
||||||
struct inode *inode = folio->mapping->host;
|
struct inode *inode = folio->mapping->host;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
|
||||||
const u32 sectorsize = fs_info->sectorsize;
|
|
||||||
u64 start;
|
u64 start;
|
||||||
u64 end;
|
u64 end;
|
||||||
u32 len;
|
u32 len;
|
||||||
@ -667,10 +660,6 @@ static void end_bbio_data_read(struct btrfs_bio *bbio)
|
|||||||
end_page_read(folio_page(folio, 0), uptodate, start, len);
|
end_page_read(folio_page(folio, 0), uptodate, start, len);
|
||||||
endio_readpage_release_extent(&processed, BTRFS_I(inode),
|
endio_readpage_release_extent(&processed, BTRFS_I(inode),
|
||||||
start, end, uptodate);
|
start, end, uptodate);
|
||||||
|
|
||||||
ASSERT(bio_offset + len > bio_offset);
|
|
||||||
bio_offset += len;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
/* Release the last extent */
|
/* Release the last extent */
|
||||||
endio_readpage_release_extent(&processed, NULL, 0, 0, false);
|
endio_readpage_release_extent(&processed, NULL, 0, 0, false);
|
||||||
@ -738,6 +727,8 @@ static int alloc_eb_folio_array(struct extent_buffer *eb, gfp_t extra_gfp)
|
|||||||
|
|
||||||
for (int i = 0; i < num_pages; i++)
|
for (int i = 0; i < num_pages; i++)
|
||||||
eb->folios[i] = page_folio(page_array[i]);
|
eb->folios[i] = page_folio(page_array[i]);
|
||||||
|
eb->folio_size = PAGE_SIZE;
|
||||||
|
eb->folio_shift = PAGE_SHIFT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -827,7 +818,7 @@ static void submit_extent_page(struct btrfs_bio_ctrl *bio_ctrl,
|
|||||||
u64 disk_bytenr, struct page *page,
|
u64 disk_bytenr, struct page *page,
|
||||||
size_t size, unsigned long pg_offset)
|
size_t size, unsigned long pg_offset)
|
||||||
{
|
{
|
||||||
struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
|
struct btrfs_inode *inode = page_to_inode(page);
|
||||||
|
|
||||||
ASSERT(pg_offset + size <= PAGE_SIZE);
|
ASSERT(pg_offset + size <= PAGE_SIZE);
|
||||||
ASSERT(bio_ctrl->end_io_func);
|
ASSERT(bio_ctrl->end_io_func);
|
||||||
@ -936,17 +927,21 @@ static int attach_extent_buffer_folio(struct extent_buffer *eb,
|
|||||||
|
|
||||||
int set_page_extent_mapped(struct page *page)
|
int set_page_extent_mapped(struct page *page)
|
||||||
{
|
{
|
||||||
struct folio *folio = page_folio(page);
|
return set_folio_extent_mapped(page_folio(page));
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_folio_extent_mapped(struct folio *folio)
|
||||||
|
{
|
||||||
struct btrfs_fs_info *fs_info;
|
struct btrfs_fs_info *fs_info;
|
||||||
|
|
||||||
ASSERT(page->mapping);
|
ASSERT(folio->mapping);
|
||||||
|
|
||||||
if (folio_test_private(folio))
|
if (folio_test_private(folio))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fs_info = btrfs_sb(page->mapping->host->i_sb);
|
fs_info = folio_to_fs_info(folio);
|
||||||
|
|
||||||
if (btrfs_is_subpage(fs_info, page->mapping))
|
if (btrfs_is_subpage(fs_info, folio->mapping))
|
||||||
return btrfs_attach_subpage(fs_info, folio, BTRFS_SUBPAGE_DATA);
|
return btrfs_attach_subpage(fs_info, folio, BTRFS_SUBPAGE_DATA);
|
||||||
|
|
||||||
folio_attach_private(folio, (void *)EXTENT_FOLIO_PRIVATE);
|
folio_attach_private(folio, (void *)EXTENT_FOLIO_PRIVATE);
|
||||||
@ -963,20 +958,21 @@ void clear_page_extent_mapped(struct page *page)
|
|||||||
if (!folio_test_private(folio))
|
if (!folio_test_private(folio))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fs_info = btrfs_sb(page->mapping->host->i_sb);
|
fs_info = page_to_fs_info(page);
|
||||||
if (btrfs_is_subpage(fs_info, page->mapping))
|
if (btrfs_is_subpage(fs_info, page->mapping))
|
||||||
return btrfs_detach_subpage(fs_info, folio);
|
return btrfs_detach_subpage(fs_info, folio);
|
||||||
|
|
||||||
folio_detach_private(folio);
|
folio_detach_private(folio);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct extent_map *
|
static struct extent_map *__get_extent_map(struct inode *inode, struct page *page,
|
||||||
__get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
|
|
||||||
u64 start, u64 len, struct extent_map **em_cached)
|
u64 start, u64 len, struct extent_map **em_cached)
|
||||||
{
|
{
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
|
|
||||||
if (em_cached && *em_cached) {
|
ASSERT(em_cached);
|
||||||
|
|
||||||
|
if (*em_cached) {
|
||||||
em = *em_cached;
|
em = *em_cached;
|
||||||
if (extent_map_in_tree(em) && start >= em->start &&
|
if (extent_map_in_tree(em) && start >= em->start &&
|
||||||
start < extent_map_end(em)) {
|
start < extent_map_end(em)) {
|
||||||
@ -988,8 +984,8 @@ __get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
|
|||||||
*em_cached = NULL;
|
*em_cached = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), page, pg_offset, start, len);
|
em = btrfs_get_extent(BTRFS_I(inode), page, start, len);
|
||||||
if (em_cached && !IS_ERR(em)) {
|
if (!IS_ERR(em)) {
|
||||||
BUG_ON(*em_cached);
|
BUG_ON(*em_cached);
|
||||||
refcount_inc(&em->refs);
|
refcount_inc(&em->refs);
|
||||||
*em_cached = em;
|
*em_cached = em;
|
||||||
@ -1007,7 +1003,7 @@ static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
|
|||||||
struct btrfs_bio_ctrl *bio_ctrl, u64 *prev_em_start)
|
struct btrfs_bio_ctrl *bio_ctrl, u64 *prev_em_start)
|
||||||
{
|
{
|
||||||
struct inode *inode = page->mapping->host;
|
struct inode *inode = page->mapping->host;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
u64 start = page_offset(page);
|
u64 start = page_offset(page);
|
||||||
const u64 end = start + PAGE_SIZE - 1;
|
const u64 end = start + PAGE_SIZE - 1;
|
||||||
u64 cur = start;
|
u64 cur = start;
|
||||||
@ -1018,7 +1014,7 @@ static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
size_t pg_offset = 0;
|
size_t pg_offset = 0;
|
||||||
size_t iosize;
|
size_t iosize;
|
||||||
size_t blocksize = inode->i_sb->s_blocksize;
|
size_t blocksize = fs_info->sectorsize;
|
||||||
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
|
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
|
||||||
|
|
||||||
ret = set_page_extent_mapped(page);
|
ret = set_page_extent_mapped(page);
|
||||||
@ -1051,8 +1047,7 @@ static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
|
|||||||
end_page_read(page, true, cur, iosize);
|
end_page_read(page, true, cur, iosize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
em = __get_extent_map(inode, page, pg_offset, cur,
|
em = __get_extent_map(inode, page, cur, end - cur + 1, em_cached);
|
||||||
end - cur + 1, em_cached);
|
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
unlock_extent(tree, cur, end, NULL);
|
unlock_extent(tree, cur, end, NULL);
|
||||||
end_page_read(page, false, cur, end + 1 - cur);
|
end_page_read(page, false, cur, end + 1 - cur);
|
||||||
@ -1157,15 +1152,18 @@ static int btrfs_do_readpage(struct page *page, struct extent_map **em_cached,
|
|||||||
int btrfs_read_folio(struct file *file, struct folio *folio)
|
int btrfs_read_folio(struct file *file, struct folio *folio)
|
||||||
{
|
{
|
||||||
struct page *page = &folio->page;
|
struct page *page = &folio->page;
|
||||||
struct btrfs_inode *inode = BTRFS_I(page->mapping->host);
|
struct btrfs_inode *inode = page_to_inode(page);
|
||||||
u64 start = page_offset(page);
|
u64 start = page_offset(page);
|
||||||
u64 end = start + PAGE_SIZE - 1;
|
u64 end = start + PAGE_SIZE - 1;
|
||||||
struct btrfs_bio_ctrl bio_ctrl = { .opf = REQ_OP_READ };
|
struct btrfs_bio_ctrl bio_ctrl = { .opf = REQ_OP_READ };
|
||||||
|
struct extent_map *em_cached = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
|
btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
|
||||||
|
|
||||||
ret = btrfs_do_readpage(page, NULL, &bio_ctrl, NULL);
|
ret = btrfs_do_readpage(page, &em_cached, &bio_ctrl, NULL);
|
||||||
|
free_extent_map(em_cached);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If btrfs_do_readpage() failed we will want to submit the assembled
|
* If btrfs_do_readpage() failed we will want to submit the assembled
|
||||||
* bio to do the cleanup.
|
* bio to do the cleanup.
|
||||||
@ -1180,9 +1178,11 @@ static inline void contiguous_readpages(struct page *pages[], int nr_pages,
|
|||||||
struct btrfs_bio_ctrl *bio_ctrl,
|
struct btrfs_bio_ctrl *bio_ctrl,
|
||||||
u64 *prev_em_start)
|
u64 *prev_em_start)
|
||||||
{
|
{
|
||||||
struct btrfs_inode *inode = BTRFS_I(pages[0]->mapping->host);
|
struct btrfs_inode *inode = page_to_inode(pages[0]);
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
ASSERT(em_cached);
|
||||||
|
|
||||||
btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
|
btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
|
||||||
|
|
||||||
for (index = 0; index < nr_pages; index++) {
|
for (index = 0; index < nr_pages; index++) {
|
||||||
@ -1371,7 +1371,7 @@ static noinline_for_stack int __extent_writepage_io(struct btrfs_inode *inode,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
em = btrfs_get_extent(inode, NULL, 0, cur, len);
|
em = btrfs_get_extent(inode, NULL, cur, len);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR_OR_ZERO(em);
|
ret = PTR_ERR_OR_ZERO(em);
|
||||||
goto out_error;
|
goto out_error;
|
||||||
@ -1739,10 +1739,10 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
|
|||||||
folio_lock(folio);
|
folio_lock(folio);
|
||||||
folio_clear_dirty_for_io(folio);
|
folio_clear_dirty_for_io(folio);
|
||||||
folio_start_writeback(folio);
|
folio_start_writeback(folio);
|
||||||
ret = bio_add_folio(&bbio->bio, folio, folio_size(folio), 0);
|
ret = bio_add_folio(&bbio->bio, folio, eb->folio_size, 0);
|
||||||
ASSERT(ret);
|
ASSERT(ret);
|
||||||
wbc_account_cgroup_owner(wbc, folio_page(folio, 0),
|
wbc_account_cgroup_owner(wbc, folio_page(folio, 0),
|
||||||
folio_size(folio));
|
eb->folio_size);
|
||||||
wbc->nr_to_write -= folio_nr_pages(folio);
|
wbc->nr_to_write -= folio_nr_pages(folio);
|
||||||
folio_unlock(folio);
|
folio_unlock(folio);
|
||||||
}
|
}
|
||||||
@ -1766,7 +1766,7 @@ static noinline_for_stack void write_one_eb(struct extent_buffer *eb,
|
|||||||
*/
|
*/
|
||||||
static int submit_eb_subpage(struct page *page, struct writeback_control *wbc)
|
static int submit_eb_subpage(struct page *page, struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = page_to_fs_info(page);
|
||||||
struct folio *folio = page_folio(page);
|
struct folio *folio = page_folio(page);
|
||||||
int submitted = 0;
|
int submitted = 0;
|
||||||
u64 page_start = page_offset(page);
|
u64 page_start = page_offset(page);
|
||||||
@ -1857,7 +1857,7 @@ static int submit_eb_page(struct page *page, struct btrfs_eb_write_context *ctx)
|
|||||||
if (!folio_test_private(folio))
|
if (!folio_test_private(folio))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (btrfs_sb(page->mapping->host->i_sb)->nodesize < PAGE_SIZE)
|
if (page_to_fs_info(page)->nodesize < PAGE_SIZE)
|
||||||
return submit_eb_subpage(page, wbc);
|
return submit_eb_subpage(page, wbc);
|
||||||
|
|
||||||
spin_lock(&mapping->i_private_lock);
|
spin_lock(&mapping->i_private_lock);
|
||||||
@ -1915,7 +1915,7 @@ int btree_write_cache_pages(struct address_space *mapping,
|
|||||||
struct writeback_control *wbc)
|
struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
struct btrfs_eb_write_context ctx = { .wbc = wbc };
|
struct btrfs_eb_write_context ctx = { .wbc = wbc };
|
||||||
struct btrfs_fs_info *fs_info = BTRFS_I(mapping->host)->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(mapping->host);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
int nr_to_write_done = 0;
|
int nr_to_write_done = 0;
|
||||||
@ -2203,7 +2203,7 @@ void extent_write_locked_range(struct inode *inode, struct page *locked_page,
|
|||||||
bool found_error = false;
|
bool found_error = false;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct address_space *mapping = inode->i_mapping;
|
struct address_space *mapping = inode->i_mapping;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
const u32 sectorsize = fs_info->sectorsize;
|
const u32 sectorsize = fs_info->sectorsize;
|
||||||
loff_t i_size = i_size_read(inode);
|
loff_t i_size = i_size_read(inode);
|
||||||
u64 cur = start;
|
u64 cur = start;
|
||||||
@ -2309,7 +2309,7 @@ int extent_invalidate_folio(struct extent_io_tree *tree,
|
|||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
u64 start = folio_pos(folio);
|
u64 start = folio_pos(folio);
|
||||||
u64 end = start + folio_size(folio) - 1;
|
u64 end = start + folio_size(folio) - 1;
|
||||||
size_t blocksize = folio->mapping->host->i_sb->s_blocksize;
|
size_t blocksize = folio_to_fs_info(folio)->sectorsize;
|
||||||
|
|
||||||
/* This function is only called for the btree inode */
|
/* This function is only called for the btree inode */
|
||||||
ASSERT(tree->owner == IO_TREE_BTREE_INODE_IO);
|
ASSERT(tree->owner == IO_TREE_BTREE_INODE_IO);
|
||||||
@ -2378,7 +2378,7 @@ int try_release_extent_mapping(struct page *page, gfp_t mask)
|
|||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
u64 start = page_offset(page);
|
u64 start = page_offset(page);
|
||||||
u64 end = start + PAGE_SIZE - 1;
|
u64 end = start + PAGE_SIZE - 1;
|
||||||
struct btrfs_inode *btrfs_inode = BTRFS_I(page->mapping->host);
|
struct btrfs_inode *btrfs_inode = page_to_inode(page);
|
||||||
struct extent_io_tree *tree = &btrfs_inode->io_tree;
|
struct extent_io_tree *tree = &btrfs_inode->io_tree;
|
||||||
struct extent_map_tree *map = &btrfs_inode->extent_tree;
|
struct extent_map_tree *map = &btrfs_inode->extent_tree;
|
||||||
|
|
||||||
@ -2453,12 +2453,65 @@ next:
|
|||||||
return try_release_extent_state(tree, page, mask);
|
return try_release_extent_state(tree, page, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct btrfs_fiemap_entry {
|
||||||
|
u64 offset;
|
||||||
|
u64 phys;
|
||||||
|
u64 len;
|
||||||
|
u32 flags;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To cache previous fiemap extent
|
* Indicate the caller of emit_fiemap_extent() that it needs to unlock the file
|
||||||
|
* range from the inode's io tree, unlock the subvolume tree search path, flush
|
||||||
|
* the fiemap cache and relock the file range and research the subvolume tree.
|
||||||
|
* The value here is something negative that can't be confused with a valid
|
||||||
|
* errno value and different from 1 because that's also a return value from
|
||||||
|
* fiemap_fill_next_extent() and also it's often used to mean some btree search
|
||||||
|
* did not find a key, so make it some distinct negative value.
|
||||||
|
*/
|
||||||
|
#define BTRFS_FIEMAP_FLUSH_CACHE (-(MAX_ERRNO + 1))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to:
|
||||||
*
|
*
|
||||||
* Will be used for merging fiemap extent
|
* - Cache the next entry to be emitted to the fiemap buffer, so that we can
|
||||||
|
* merge extents that are contiguous and can be grouped as a single one;
|
||||||
|
*
|
||||||
|
* - Store extents ready to be written to the fiemap buffer in an intermediary
|
||||||
|
* buffer. This intermediary buffer is to ensure that in case the fiemap
|
||||||
|
* buffer is memory mapped to the fiemap target file, we don't deadlock
|
||||||
|
* during btrfs_page_mkwrite(). This is because during fiemap we are locking
|
||||||
|
* an extent range in order to prevent races with delalloc flushing and
|
||||||
|
* ordered extent completion, which is needed in order to reliably detect
|
||||||
|
* delalloc in holes and prealloc extents. And this can lead to a deadlock
|
||||||
|
* if the fiemap buffer is memory mapped to the file we are running fiemap
|
||||||
|
* against (a silly, useless in practice scenario, but possible) because
|
||||||
|
* btrfs_page_mkwrite() will try to lock the same extent range.
|
||||||
*/
|
*/
|
||||||
struct fiemap_cache {
|
struct fiemap_cache {
|
||||||
|
/* An array of ready fiemap entries. */
|
||||||
|
struct btrfs_fiemap_entry *entries;
|
||||||
|
/* Number of entries in the entries array. */
|
||||||
|
int entries_size;
|
||||||
|
/* Index of the next entry in the entries array to write to. */
|
||||||
|
int entries_pos;
|
||||||
|
/*
|
||||||
|
* Once the entries array is full, this indicates what's the offset for
|
||||||
|
* the next file extent item we must search for in the inode's subvolume
|
||||||
|
* tree after unlocking the extent range in the inode's io tree and
|
||||||
|
* releasing the search path.
|
||||||
|
*/
|
||||||
|
u64 next_search_offset;
|
||||||
|
/*
|
||||||
|
* This matches struct fiemap_extent_info::fi_mapped_extents, we use it
|
||||||
|
* to count ourselves emitted extents and stop instead of relying on
|
||||||
|
* fiemap_fill_next_extent() because we buffer ready fiemap entries at
|
||||||
|
* the @entries array, and we want to stop as soon as we hit the max
|
||||||
|
* amount of extents to map, not just to save time but also to make the
|
||||||
|
* logic at extent_fiemap() simpler.
|
||||||
|
*/
|
||||||
|
unsigned int extents_mapped;
|
||||||
|
/* Fields for the cached extent (unsubmitted, not ready, extent). */
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 phys;
|
u64 phys;
|
||||||
u64 len;
|
u64 len;
|
||||||
@ -2466,6 +2519,28 @@ struct fiemap_cache {
|
|||||||
bool cached;
|
bool cached;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int flush_fiemap_cache(struct fiemap_extent_info *fieinfo,
|
||||||
|
struct fiemap_cache *cache)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < cache->entries_pos; i++) {
|
||||||
|
struct btrfs_fiemap_entry *entry = &cache->entries[i];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = fiemap_fill_next_extent(fieinfo, entry->offset,
|
||||||
|
entry->phys, entry->len,
|
||||||
|
entry->flags);
|
||||||
|
/*
|
||||||
|
* Ignore 1 (reached max entries) because we keep track of that
|
||||||
|
* ourselves in emit_fiemap_extent().
|
||||||
|
*/
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
cache->entries_pos = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper to submit fiemap extent.
|
* Helper to submit fiemap extent.
|
||||||
*
|
*
|
||||||
@ -2480,8 +2555,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
|
|||||||
struct fiemap_cache *cache,
|
struct fiemap_cache *cache,
|
||||||
u64 offset, u64 phys, u64 len, u32 flags)
|
u64 offset, u64 phys, u64 len, u32 flags)
|
||||||
{
|
{
|
||||||
|
struct btrfs_fiemap_entry *entry;
|
||||||
u64 cache_end;
|
u64 cache_end;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/* Set at the end of extent_fiemap(). */
|
/* Set at the end of extent_fiemap(). */
|
||||||
ASSERT((flags & FIEMAP_EXTENT_LAST) == 0);
|
ASSERT((flags & FIEMAP_EXTENT_LAST) == 0);
|
||||||
@ -2494,7 +2569,9 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
|
|||||||
* find an extent that starts at an offset behind the end offset of the
|
* find an extent that starts at an offset behind the end offset of the
|
||||||
* previous extent we processed. This happens if fiemap is called
|
* previous extent we processed. This happens if fiemap is called
|
||||||
* without FIEMAP_FLAG_SYNC and there are ordered extents completing
|
* without FIEMAP_FLAG_SYNC and there are ordered extents completing
|
||||||
* while we call btrfs_next_leaf() (through fiemap_next_leaf_item()).
|
* after we had to unlock the file range, release the search path, emit
|
||||||
|
* the fiemap extents stored in the buffer (cache->entries array) and
|
||||||
|
* the lock the remainder of the range and re-search the btree.
|
||||||
*
|
*
|
||||||
* For example we are in leaf X processing its last item, which is the
|
* For example we are in leaf X processing its last item, which is the
|
||||||
* file extent item for file range [512K, 1M[, and after
|
* file extent item for file range [512K, 1M[, and after
|
||||||
@ -2607,11 +2684,35 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo,
|
|||||||
|
|
||||||
emit:
|
emit:
|
||||||
/* Not mergeable, need to submit cached one */
|
/* Not mergeable, need to submit cached one */
|
||||||
ret = fiemap_fill_next_extent(fieinfo, cache->offset, cache->phys,
|
|
||||||
cache->len, cache->flags);
|
if (cache->entries_pos == cache->entries_size) {
|
||||||
cache->cached = false;
|
/*
|
||||||
if (ret)
|
* We will need to research for the end offset of the last
|
||||||
return ret;
|
* stored extent and not from the current offset, because after
|
||||||
|
* unlocking the range and releasing the path, if there's a hole
|
||||||
|
* between that end offset and this current offset, a new extent
|
||||||
|
* may have been inserted due to a new write, so we don't want
|
||||||
|
* to miss it.
|
||||||
|
*/
|
||||||
|
entry = &cache->entries[cache->entries_size - 1];
|
||||||
|
cache->next_search_offset = entry->offset + entry->len;
|
||||||
|
cache->cached = false;
|
||||||
|
|
||||||
|
return BTRFS_FIEMAP_FLUSH_CACHE;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = &cache->entries[cache->entries_pos];
|
||||||
|
entry->offset = cache->offset;
|
||||||
|
entry->phys = cache->phys;
|
||||||
|
entry->len = cache->len;
|
||||||
|
entry->flags = cache->flags;
|
||||||
|
cache->entries_pos++;
|
||||||
|
cache->extents_mapped++;
|
||||||
|
|
||||||
|
if (cache->extents_mapped == fieinfo->fi_extents_max) {
|
||||||
|
cache->cached = false;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
assign:
|
assign:
|
||||||
cache->cached = true;
|
cache->cached = true;
|
||||||
cache->offset = offset;
|
cache->offset = offset;
|
||||||
@ -2651,7 +2752,7 @@ static int emit_last_fiemap_cache(struct fiemap_extent_info *fieinfo,
|
|||||||
|
|
||||||
static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *path)
|
static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *path)
|
||||||
{
|
{
|
||||||
struct extent_buffer *clone;
|
struct extent_buffer *clone = path->nodes[0];
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
int slot;
|
int slot;
|
||||||
int ret;
|
int ret;
|
||||||
@ -2660,29 +2761,45 @@ static int fiemap_next_leaf_item(struct btrfs_inode *inode, struct btrfs_path *p
|
|||||||
if (path->slots[0] < btrfs_header_nritems(path->nodes[0]))
|
if (path->slots[0] < btrfs_header_nritems(path->nodes[0]))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a temporary extra ref to an already cloned extent buffer to
|
||||||
|
* prevent btrfs_next_leaf() freeing it, we want to reuse it to avoid
|
||||||
|
* the cost of allocating a new one.
|
||||||
|
*/
|
||||||
|
ASSERT(test_bit(EXTENT_BUFFER_UNMAPPED, &clone->bflags));
|
||||||
|
atomic_inc(&clone->refs);
|
||||||
|
|
||||||
ret = btrfs_next_leaf(inode->root, path);
|
ret = btrfs_next_leaf(inode->root, path);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't bother with cloning if there are no more file extent items for
|
* Don't bother with cloning if there are no more file extent items for
|
||||||
* our inode.
|
* our inode.
|
||||||
*/
|
*/
|
||||||
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
|
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
|
||||||
if (key.objectid != btrfs_ino(inode) || key.type != BTRFS_EXTENT_DATA_KEY)
|
if (key.objectid != btrfs_ino(inode) || key.type != BTRFS_EXTENT_DATA_KEY) {
|
||||||
return 1;
|
ret = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* See the comment at fiemap_search_slot() about why we clone. */
|
/* See the comment at fiemap_search_slot() about why we clone. */
|
||||||
clone = btrfs_clone_extent_buffer(path->nodes[0]);
|
copy_extent_buffer_full(clone, path->nodes[0]);
|
||||||
if (!clone)
|
/*
|
||||||
return -ENOMEM;
|
* Important to preserve the start field, for the optimizations when
|
||||||
|
* checking if extents are shared (see extent_fiemap()).
|
||||||
|
*/
|
||||||
|
clone->start = path->nodes[0]->start;
|
||||||
|
|
||||||
slot = path->slots[0];
|
slot = path->slots[0];
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
path->nodes[0] = clone;
|
path->nodes[0] = clone;
|
||||||
path->slots[0] = slot;
|
path->slots[0] = slot;
|
||||||
|
out:
|
||||||
|
if (ret)
|
||||||
|
free_extent_buffer(clone);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2737,8 +2854,8 @@ static int fiemap_search_slot(struct btrfs_inode *inode, struct btrfs_path *path
|
|||||||
* neighbour leaf).
|
* neighbour leaf).
|
||||||
* We also need the private clone because holding a read lock on an
|
* We also need the private clone because holding a read lock on an
|
||||||
* extent buffer of the subvolume's b+tree will make lockdep unhappy
|
* extent buffer of the subvolume's b+tree will make lockdep unhappy
|
||||||
* when we call fiemap_fill_next_extent(), because that may cause a page
|
* when we check if extents are shared, as backref walking may need to
|
||||||
* fault when filling the user space buffer with fiemap data.
|
* lock the same leaf we are processing.
|
||||||
*/
|
*/
|
||||||
clone = btrfs_clone_extent_buffer(path->nodes[0]);
|
clone = btrfs_clone_extent_buffer(path->nodes[0]);
|
||||||
if (!clone)
|
if (!clone)
|
||||||
@ -2778,34 +2895,16 @@ static int fiemap_process_hole(struct btrfs_inode *inode,
|
|||||||
* it beyond i_size.
|
* it beyond i_size.
|
||||||
*/
|
*/
|
||||||
while (cur_offset < end && cur_offset < i_size) {
|
while (cur_offset < end && cur_offset < i_size) {
|
||||||
struct extent_state *cached_state = NULL;
|
|
||||||
u64 delalloc_start;
|
u64 delalloc_start;
|
||||||
u64 delalloc_end;
|
u64 delalloc_end;
|
||||||
u64 prealloc_start;
|
u64 prealloc_start;
|
||||||
u64 lockstart;
|
|
||||||
u64 lockend;
|
|
||||||
u64 prealloc_len = 0;
|
u64 prealloc_len = 0;
|
||||||
bool delalloc;
|
bool delalloc;
|
||||||
|
|
||||||
lockstart = round_down(cur_offset, inode->root->fs_info->sectorsize);
|
|
||||||
lockend = round_up(end, inode->root->fs_info->sectorsize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We are only locking for the delalloc range because that's the
|
|
||||||
* only thing that can change here. With fiemap we have a lock
|
|
||||||
* on the inode, so no buffered or direct writes can happen.
|
|
||||||
*
|
|
||||||
* However mmaps and normal page writeback will cause this to
|
|
||||||
* change arbitrarily. We have to lock the extent lock here to
|
|
||||||
* make sure that nobody messes with the tree while we're doing
|
|
||||||
* btrfs_find_delalloc_in_range.
|
|
||||||
*/
|
|
||||||
lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
|
|
||||||
delalloc = btrfs_find_delalloc_in_range(inode, cur_offset, end,
|
delalloc = btrfs_find_delalloc_in_range(inode, cur_offset, end,
|
||||||
delalloc_cached_state,
|
delalloc_cached_state,
|
||||||
&delalloc_start,
|
&delalloc_start,
|
||||||
&delalloc_end);
|
&delalloc_end);
|
||||||
unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
|
|
||||||
if (!delalloc)
|
if (!delalloc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2973,6 +3072,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
|||||||
u64 start, u64 len)
|
u64 start, u64 len)
|
||||||
{
|
{
|
||||||
const u64 ino = btrfs_ino(inode);
|
const u64 ino = btrfs_ino(inode);
|
||||||
|
struct extent_state *cached_state = NULL;
|
||||||
struct extent_state *delalloc_cached_state = NULL;
|
struct extent_state *delalloc_cached_state = NULL;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct fiemap_cache cache = { 0 };
|
struct fiemap_cache cache = { 0 };
|
||||||
@ -2985,26 +3085,33 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
|||||||
bool stopped = false;
|
bool stopped = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
cache.entries_size = PAGE_SIZE / sizeof(struct btrfs_fiemap_entry);
|
||||||
|
cache.entries = kmalloc_array(cache.entries_size,
|
||||||
|
sizeof(struct btrfs_fiemap_entry),
|
||||||
|
GFP_KERNEL);
|
||||||
backref_ctx = btrfs_alloc_backref_share_check_ctx();
|
backref_ctx = btrfs_alloc_backref_share_check_ctx();
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!backref_ctx || !path) {
|
if (!cache.entries || !backref_ctx || !path) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restart:
|
||||||
range_start = round_down(start, sectorsize);
|
range_start = round_down(start, sectorsize);
|
||||||
range_end = round_up(start + len, sectorsize);
|
range_end = round_up(start + len, sectorsize);
|
||||||
prev_extent_end = range_start;
|
prev_extent_end = range_start;
|
||||||
|
|
||||||
|
lock_extent(&inode->io_tree, range_start, range_end, &cached_state);
|
||||||
|
|
||||||
ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end);
|
ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out_unlock;
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
path->reada = READA_FORWARD;
|
path->reada = READA_FORWARD;
|
||||||
ret = fiemap_search_slot(inode, path, range_start);
|
ret = fiemap_search_slot(inode, path, range_start);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out_unlock;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
/*
|
/*
|
||||||
* No file extent item found, but we may have delalloc between
|
* No file extent item found, but we may have delalloc between
|
||||||
@ -3051,7 +3158,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
|||||||
backref_ctx, 0, 0, 0,
|
backref_ctx, 0, 0, 0,
|
||||||
prev_extent_end, hole_end);
|
prev_extent_end, hole_end);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out_unlock;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
/* fiemap_fill_next_extent() told us to stop. */
|
/* fiemap_fill_next_extent() told us to stop. */
|
||||||
stopped = true;
|
stopped = true;
|
||||||
@ -3107,7 +3214,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
|||||||
extent_gen,
|
extent_gen,
|
||||||
backref_ctx);
|
backref_ctx);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out_unlock;
|
||||||
else if (ret > 0)
|
else if (ret > 0)
|
||||||
flags |= FIEMAP_EXTENT_SHARED;
|
flags |= FIEMAP_EXTENT_SHARED;
|
||||||
}
|
}
|
||||||
@ -3118,9 +3225,9 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out_unlock;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
/* fiemap_fill_next_extent() told us to stop. */
|
/* emit_fiemap_extent() told us to stop. */
|
||||||
stopped = true;
|
stopped = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3129,12 +3236,12 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
|||||||
next_item:
|
next_item:
|
||||||
if (fatal_signal_pending(current)) {
|
if (fatal_signal_pending(current)) {
|
||||||
ret = -EINTR;
|
ret = -EINTR;
|
||||||
goto out;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fiemap_next_leaf_item(inode, path);
|
ret = fiemap_next_leaf_item(inode, path);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto out;
|
goto out_unlock;
|
||||||
} else if (ret > 0) {
|
} else if (ret > 0) {
|
||||||
/* No more file extent items for this inode. */
|
/* No more file extent items for this inode. */
|
||||||
break;
|
break;
|
||||||
@ -3143,22 +3250,12 @@ next_item:
|
|||||||
}
|
}
|
||||||
|
|
||||||
check_eof_delalloc:
|
check_eof_delalloc:
|
||||||
/*
|
|
||||||
* Release (and free) the path before emitting any final entries to
|
|
||||||
* fiemap_fill_next_extent() to keep lockdep happy. This is because
|
|
||||||
* once we find no more file extent items exist, we may have a
|
|
||||||
* non-cloned leaf, and fiemap_fill_next_extent() can trigger page
|
|
||||||
* faults when copying data to the user space buffer.
|
|
||||||
*/
|
|
||||||
btrfs_free_path(path);
|
|
||||||
path = NULL;
|
|
||||||
|
|
||||||
if (!stopped && prev_extent_end < range_end) {
|
if (!stopped && prev_extent_end < range_end) {
|
||||||
ret = fiemap_process_hole(inode, fieinfo, &cache,
|
ret = fiemap_process_hole(inode, fieinfo, &cache,
|
||||||
&delalloc_cached_state, backref_ctx,
|
&delalloc_cached_state, backref_ctx,
|
||||||
0, 0, 0, prev_extent_end, range_end - 1);
|
0, 0, 0, prev_extent_end, range_end - 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out_unlock;
|
||||||
prev_extent_end = range_end;
|
prev_extent_end = range_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3166,28 +3263,16 @@ check_eof_delalloc:
|
|||||||
const u64 i_size = i_size_read(&inode->vfs_inode);
|
const u64 i_size = i_size_read(&inode->vfs_inode);
|
||||||
|
|
||||||
if (prev_extent_end < i_size) {
|
if (prev_extent_end < i_size) {
|
||||||
struct extent_state *cached_state = NULL;
|
|
||||||
u64 delalloc_start;
|
u64 delalloc_start;
|
||||||
u64 delalloc_end;
|
u64 delalloc_end;
|
||||||
u64 lockstart;
|
|
||||||
u64 lockend;
|
|
||||||
bool delalloc;
|
bool delalloc;
|
||||||
|
|
||||||
lockstart = round_down(prev_extent_end, sectorsize);
|
|
||||||
lockend = round_up(i_size, sectorsize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* See the comment in fiemap_process_hole as to why
|
|
||||||
* we're doing the locking here.
|
|
||||||
*/
|
|
||||||
lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
|
|
||||||
delalloc = btrfs_find_delalloc_in_range(inode,
|
delalloc = btrfs_find_delalloc_in_range(inode,
|
||||||
prev_extent_end,
|
prev_extent_end,
|
||||||
i_size - 1,
|
i_size - 1,
|
||||||
&delalloc_cached_state,
|
&delalloc_cached_state,
|
||||||
&delalloc_start,
|
&delalloc_start,
|
||||||
&delalloc_end);
|
&delalloc_end);
|
||||||
unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
|
|
||||||
if (!delalloc)
|
if (!delalloc)
|
||||||
cache.flags |= FIEMAP_EXTENT_LAST;
|
cache.flags |= FIEMAP_EXTENT_LAST;
|
||||||
} else {
|
} else {
|
||||||
@ -3195,9 +3280,39 @@ check_eof_delalloc:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
unlock_extent(&inode->io_tree, range_start, range_end, &cached_state);
|
||||||
|
|
||||||
|
if (ret == BTRFS_FIEMAP_FLUSH_CACHE) {
|
||||||
|
btrfs_release_path(path);
|
||||||
|
ret = flush_fiemap_cache(fieinfo, &cache);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
len -= cache.next_search_offset - start;
|
||||||
|
start = cache.next_search_offset;
|
||||||
|
goto restart;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must free the path before emitting to the fiemap buffer because we
|
||||||
|
* may have a non-cloned leaf and if the fiemap buffer is memory mapped
|
||||||
|
* to a file, a write into it (through btrfs_page_mkwrite()) may trigger
|
||||||
|
* waiting for an ordered extent that in order to complete needs to
|
||||||
|
* modify that leaf, therefore leading to a deadlock.
|
||||||
|
*/
|
||||||
|
btrfs_free_path(path);
|
||||||
|
path = NULL;
|
||||||
|
|
||||||
|
ret = flush_fiemap_cache(fieinfo, &cache);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
ret = emit_last_fiemap_cache(fieinfo, &cache);
|
ret = emit_last_fiemap_cache(fieinfo, &cache);
|
||||||
out:
|
out:
|
||||||
free_extent_state(delalloc_cached_state);
|
free_extent_state(delalloc_cached_state);
|
||||||
|
kfree(cache.entries);
|
||||||
btrfs_free_backref_share_ctx(backref_ctx);
|
btrfs_free_backref_share_ctx(backref_ctx);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
@ -3646,7 +3761,7 @@ retry:
|
|||||||
/* For now, we should only have single-page folios for btree inode. */
|
/* For now, we should only have single-page folios for btree inode. */
|
||||||
ASSERT(folio_nr_pages(existing_folio) == 1);
|
ASSERT(folio_nr_pages(existing_folio) == 1);
|
||||||
|
|
||||||
if (folio_size(existing_folio) != folio_size(eb->folios[0])) {
|
if (folio_size(existing_folio) != eb->folio_size) {
|
||||||
folio_unlock(existing_folio);
|
folio_unlock(existing_folio);
|
||||||
folio_put(existing_folio);
|
folio_put(existing_folio);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
@ -3789,6 +3904,8 @@ reallocate:
|
|||||||
* and free the allocated page.
|
* and free the allocated page.
|
||||||
*/
|
*/
|
||||||
folio = eb->folios[i];
|
folio = eb->folios[i];
|
||||||
|
eb->folio_size = folio_size(folio);
|
||||||
|
eb->folio_shift = folio_shift(folio);
|
||||||
spin_lock(&mapping->i_private_lock);
|
spin_lock(&mapping->i_private_lock);
|
||||||
/* Should not fail, as we have preallocated the memory */
|
/* Should not fail, as we have preallocated the memory */
|
||||||
ret = attach_extent_buffer_folio(eb, folio, prealloc);
|
ret = attach_extent_buffer_folio(eb, folio, prealloc);
|
||||||
@ -4238,7 +4355,7 @@ int read_extent_buffer_pages(struct extent_buffer *eb, int wait, int mirror_num,
|
|||||||
for (int i = 0; i < num_folios; i++) {
|
for (int i = 0; i < num_folios; i++) {
|
||||||
struct folio *folio = eb->folios[i];
|
struct folio *folio = eb->folios[i];
|
||||||
|
|
||||||
ret = bio_add_folio(&bbio->bio, folio, folio_size(folio), 0);
|
ret = bio_add_folio(&bbio->bio, folio, eb->folio_size, 0);
|
||||||
ASSERT(ret);
|
ASSERT(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4258,7 +4375,7 @@ static bool report_eb_range(const struct extent_buffer *eb, unsigned long start,
|
|||||||
unsigned long len)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
btrfs_warn(eb->fs_info,
|
btrfs_warn(eb->fs_info,
|
||||||
"access to eb bytenr %llu len %lu out of range start %lu len %lu",
|
"access to eb bytenr %llu len %u out of range start %lu len %lu",
|
||||||
eb->start, eb->len, start, len);
|
eb->start, eb->len, start, len);
|
||||||
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG));
|
||||||
|
|
||||||
@ -4287,7 +4404,7 @@ static inline int check_eb_range(const struct extent_buffer *eb,
|
|||||||
void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
|
void read_extent_buffer(const struct extent_buffer *eb, void *dstv,
|
||||||
unsigned long start, unsigned long len)
|
unsigned long start, unsigned long len)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(eb->folios[0]);
|
const int unit_size = eb->folio_size;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
char *dst = (char *)dstv;
|
char *dst = (char *)dstv;
|
||||||
@ -4327,7 +4444,7 @@ int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
|
|||||||
void __user *dstv,
|
void __user *dstv,
|
||||||
unsigned long start, unsigned long len)
|
unsigned long start, unsigned long len)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(eb->folios[0]);
|
const int unit_size = eb->folio_size;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
char __user *dst = (char __user *)dstv;
|
char __user *dst = (char __user *)dstv;
|
||||||
@ -4367,7 +4484,7 @@ int read_extent_buffer_to_user_nofault(const struct extent_buffer *eb,
|
|||||||
int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
|
int memcmp_extent_buffer(const struct extent_buffer *eb, const void *ptrv,
|
||||||
unsigned long start, unsigned long len)
|
unsigned long start, unsigned long len)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(eb->folios[0]);
|
const int unit_size = eb->folio_size;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
char *kaddr;
|
char *kaddr;
|
||||||
@ -4438,7 +4555,7 @@ static void __write_extent_buffer(const struct extent_buffer *eb,
|
|||||||
const void *srcv, unsigned long start,
|
const void *srcv, unsigned long start,
|
||||||
unsigned long len, bool use_memmove)
|
unsigned long len, bool use_memmove)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(eb->folios[0]);
|
const int unit_size = eb->folio_size;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
char *kaddr;
|
char *kaddr;
|
||||||
@ -4487,7 +4604,7 @@ void write_extent_buffer(const struct extent_buffer *eb, const void *srcv,
|
|||||||
static void memset_extent_buffer(const struct extent_buffer *eb, int c,
|
static void memset_extent_buffer(const struct extent_buffer *eb, int c,
|
||||||
unsigned long start, unsigned long len)
|
unsigned long start, unsigned long len)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(eb->folios[0]);
|
const int unit_size = eb->folio_size;
|
||||||
unsigned long cur = start;
|
unsigned long cur = start;
|
||||||
|
|
||||||
if (eb->addr) {
|
if (eb->addr) {
|
||||||
@ -4518,7 +4635,7 @@ void memzero_extent_buffer(const struct extent_buffer *eb, unsigned long start,
|
|||||||
void copy_extent_buffer_full(const struct extent_buffer *dst,
|
void copy_extent_buffer_full(const struct extent_buffer *dst,
|
||||||
const struct extent_buffer *src)
|
const struct extent_buffer *src)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(src->folios[0]);
|
const int unit_size = src->folio_size;
|
||||||
unsigned long cur = 0;
|
unsigned long cur = 0;
|
||||||
|
|
||||||
ASSERT(dst->len == src->len);
|
ASSERT(dst->len == src->len);
|
||||||
@ -4540,7 +4657,7 @@ void copy_extent_buffer(const struct extent_buffer *dst,
|
|||||||
unsigned long dst_offset, unsigned long src_offset,
|
unsigned long dst_offset, unsigned long src_offset,
|
||||||
unsigned long len)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(dst->folios[0]);
|
const int unit_size = dst->folio_size;
|
||||||
u64 dst_len = dst->len;
|
u64 dst_len = dst->len;
|
||||||
size_t cur;
|
size_t cur;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
@ -4596,10 +4713,10 @@ static inline void eb_bitmap_offset(const struct extent_buffer *eb,
|
|||||||
* the bitmap item in the extent buffer + the offset of the byte in the
|
* the bitmap item in the extent buffer + the offset of the byte in the
|
||||||
* bitmap item.
|
* bitmap item.
|
||||||
*/
|
*/
|
||||||
offset = start + offset_in_folio(eb->folios[0], eb->start) + byte_offset;
|
offset = start + offset_in_eb_folio(eb, eb->start) + byte_offset;
|
||||||
|
|
||||||
*folio_index = offset >> folio_shift(eb->folios[0]);
|
*folio_index = offset >> eb->folio_shift;
|
||||||
*folio_offset = offset_in_folio(eb->folios[0], offset);
|
*folio_offset = offset_in_eb_folio(eb, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4713,7 +4830,7 @@ void memcpy_extent_buffer(const struct extent_buffer *dst,
|
|||||||
unsigned long dst_offset, unsigned long src_offset,
|
unsigned long dst_offset, unsigned long src_offset,
|
||||||
unsigned long len)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
const int unit_size = folio_size(dst->folios[0]);
|
const int unit_size = dst->folio_size;
|
||||||
unsigned long cur_off = 0;
|
unsigned long cur_off = 0;
|
||||||
|
|
||||||
if (check_eb_range(dst, dst_offset, len) ||
|
if (check_eb_range(dst, dst_offset, len) ||
|
||||||
@ -4837,7 +4954,7 @@ out:
|
|||||||
|
|
||||||
static int try_release_subpage_extent_buffer(struct page *page)
|
static int try_release_subpage_extent_buffer(struct page *page)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = page_to_fs_info(page);
|
||||||
u64 cur = page_offset(page);
|
u64 cur = page_offset(page);
|
||||||
const u64 end = page_offset(page) + PAGE_SIZE;
|
const u64 end = page_offset(page) + PAGE_SIZE;
|
||||||
int ret;
|
int ret;
|
||||||
@ -4910,7 +5027,7 @@ int try_release_extent_buffer(struct page *page)
|
|||||||
struct folio *folio = page_folio(page);
|
struct folio *folio = page_folio(page);
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
|
|
||||||
if (btrfs_sb(page->mapping->host->i_sb)->nodesize < PAGE_SIZE)
|
if (page_to_fs_info(page)->nodesize < PAGE_SIZE)
|
||||||
return try_release_subpage_extent_buffer(page);
|
return try_release_subpage_extent_buffer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,11 +7,32 @@
|
|||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
#include <linux/fiemap.h>
|
#include <linux/fiemap.h>
|
||||||
#include <linux/btrfs_tree.h>
|
#include <linux/btrfs_tree.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
|
#include "messages.h"
|
||||||
#include "ulist.h"
|
#include "ulist.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
struct page;
|
||||||
|
struct file;
|
||||||
|
struct folio;
|
||||||
|
struct inode;
|
||||||
|
struct fiemap_extent_info;
|
||||||
|
struct readahead_control;
|
||||||
|
struct address_space;
|
||||||
|
struct writeback_control;
|
||||||
|
struct extent_io_tree;
|
||||||
|
struct extent_map_tree;
|
||||||
|
struct btrfs_block_group;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_root;
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_tree_parent_check;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
EXTENT_BUFFER_UPTODATE,
|
EXTENT_BUFFER_UPTODATE,
|
||||||
@ -63,11 +84,6 @@ enum {
|
|||||||
#define BITMAP_LAST_BYTE_MASK(nbits) \
|
#define BITMAP_LAST_BYTE_MASK(nbits) \
|
||||||
(BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1)))
|
(BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1)))
|
||||||
|
|
||||||
struct btrfs_root;
|
|
||||||
struct btrfs_inode;
|
|
||||||
struct btrfs_fs_info;
|
|
||||||
struct extent_io_tree;
|
|
||||||
struct btrfs_tree_parent_check;
|
|
||||||
|
|
||||||
int __init extent_buffer_init_cachep(void);
|
int __init extent_buffer_init_cachep(void);
|
||||||
void __cold extent_buffer_free_cachep(void);
|
void __cold extent_buffer_free_cachep(void);
|
||||||
@ -75,7 +91,8 @@ void __cold extent_buffer_free_cachep(void);
|
|||||||
#define INLINE_EXTENT_BUFFER_PAGES (BTRFS_MAX_METADATA_BLOCKSIZE / PAGE_SIZE)
|
#define INLINE_EXTENT_BUFFER_PAGES (BTRFS_MAX_METADATA_BLOCKSIZE / PAGE_SIZE)
|
||||||
struct extent_buffer {
|
struct extent_buffer {
|
||||||
u64 start;
|
u64 start;
|
||||||
unsigned long len;
|
u32 len;
|
||||||
|
u32 folio_size;
|
||||||
unsigned long bflags;
|
unsigned long bflags;
|
||||||
struct btrfs_fs_info *fs_info;
|
struct btrfs_fs_info *fs_info;
|
||||||
|
|
||||||
@ -90,6 +107,7 @@ struct extent_buffer {
|
|||||||
int read_mirror;
|
int read_mirror;
|
||||||
/* >= 0 if eb belongs to a log tree, -1 otherwise */
|
/* >= 0 if eb belongs to a log tree, -1 otherwise */
|
||||||
s8 log_index;
|
s8 log_index;
|
||||||
|
u8 folio_shift;
|
||||||
struct rcu_head rcu_head;
|
struct rcu_head rcu_head;
|
||||||
|
|
||||||
struct rw_semaphore lock;
|
struct rw_semaphore lock;
|
||||||
@ -113,6 +131,13 @@ struct btrfs_eb_write_context {
|
|||||||
struct btrfs_block_group *zoned_bg;
|
struct btrfs_block_group *zoned_bg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline unsigned long offset_in_eb_folio(const struct extent_buffer *eb,
|
||||||
|
u64 start)
|
||||||
|
{
|
||||||
|
ASSERT(eb->folio_size);
|
||||||
|
return start & (eb->folio_size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the correct offset inside the page of extent buffer.
|
* Get the correct offset inside the page of extent buffer.
|
||||||
*
|
*
|
||||||
@ -151,13 +176,13 @@ static inline unsigned long get_eb_folio_index(const struct extent_buffer *eb,
|
|||||||
* the folio_shift would be large enough to always make us
|
* the folio_shift would be large enough to always make us
|
||||||
* return 0 as index.
|
* return 0 as index.
|
||||||
* 1.2) Several page sized folios
|
* 1.2) Several page sized folios
|
||||||
* The folio_shift() would be PAGE_SHIFT, giving us the correct
|
* The folio_shift would be PAGE_SHIFT, giving us the correct
|
||||||
* index.
|
* index.
|
||||||
*
|
*
|
||||||
* 2) sectorsize < PAGE_SIZE and nodesize < PAGE_SIZE case
|
* 2) sectorsize < PAGE_SIZE and nodesize < PAGE_SIZE case
|
||||||
* The folio would only be page sized, and always give us 0 as index.
|
* The folio would only be page sized, and always give us 0 as index.
|
||||||
*/
|
*/
|
||||||
return offset >> folio_shift(eb->folios[0]);
|
return offset >> eb->folio_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -205,8 +230,6 @@ static inline void extent_changeset_free(struct extent_changeset *changeset)
|
|||||||
kfree(changeset);
|
kfree(changeset);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct extent_map_tree;
|
|
||||||
|
|
||||||
int try_release_extent_mapping(struct page *page, gfp_t mask);
|
int try_release_extent_mapping(struct page *page, gfp_t mask);
|
||||||
int try_release_extent_buffer(struct page *page);
|
int try_release_extent_buffer(struct page *page);
|
||||||
|
|
||||||
@ -221,6 +244,7 @@ int btree_write_cache_pages(struct address_space *mapping,
|
|||||||
void extent_readahead(struct readahead_control *rac);
|
void extent_readahead(struct readahead_control *rac);
|
||||||
int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
u64 start, u64 len);
|
u64 start, u64 len);
|
||||||
|
int set_folio_extent_mapped(struct folio *folio);
|
||||||
int set_page_extent_mapped(struct page *page);
|
int set_page_extent_mapped(struct page *page);
|
||||||
void clear_page_extent_mapped(struct page *page);
|
void clear_page_extent_mapped(struct page *page);
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "volumes.h"
|
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
@ -16,8 +15,7 @@ static struct kmem_cache *extent_map_cache;
|
|||||||
int __init extent_map_init(void)
|
int __init extent_map_init(void)
|
||||||
{
|
{
|
||||||
extent_map_cache = kmem_cache_create("btrfs_extent_map",
|
extent_map_cache = kmem_cache_create("btrfs_extent_map",
|
||||||
sizeof(struct extent_map), 0,
|
sizeof(struct extent_map), 0, 0, NULL);
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!extent_map_cache)
|
if (!extent_map_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
@ -291,6 +289,10 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
|
|||||||
* Called after an extent has been written to disk properly. Set the generation
|
* Called after an extent has been written to disk properly. Set the generation
|
||||||
* to the generation that actually added the file item to the inode so we know
|
* to the generation that actually added the file item to the inode so we know
|
||||||
* we need to sync this extent when we call fsync().
|
* we need to sync this extent when we call fsync().
|
||||||
|
*
|
||||||
|
* Returns: 0 on success
|
||||||
|
* -ENOENT when the extent is not found in the tree
|
||||||
|
* -EUCLEAN if the found extent does not match the expected start
|
||||||
*/
|
*/
|
||||||
int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
||||||
{
|
{
|
||||||
@ -308,14 +310,18 @@ int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen)
|
|||||||
"no extent map found for inode %llu (root %lld) when unpinning extent range [%llu, %llu), generation %llu",
|
"no extent map found for inode %llu (root %lld) when unpinning extent range [%llu, %llu), generation %llu",
|
||||||
btrfs_ino(inode), btrfs_root_id(inode->root),
|
btrfs_ino(inode), btrfs_root_id(inode->root),
|
||||||
start, len, gen);
|
start, len, gen);
|
||||||
|
ret = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WARN_ON(em->start != start))
|
if (WARN_ON(em->start != start)) {
|
||||||
btrfs_warn(fs_info,
|
btrfs_warn(fs_info,
|
||||||
"found extent map for inode %llu (root %lld) with unexpected start offset %llu when unpinning extent range [%llu, %llu), generation %llu",
|
"found extent map for inode %llu (root %lld) with unexpected start offset %llu when unpinning extent range [%llu, %llu), generation %llu",
|
||||||
btrfs_ino(inode), btrfs_root_id(inode->root),
|
btrfs_ino(inode), btrfs_root_id(inode->root),
|
||||||
em->start, start, len, gen);
|
em->start, start, len, gen);
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
em->generation = gen;
|
em->generation = gen;
|
||||||
em->flags &= ~EXTENT_FLAG_PINNED;
|
em->flags &= ~EXTENT_FLAG_PINNED;
|
||||||
@ -531,7 +537,8 @@ static noinline int merge_extent_mapping(struct extent_map_tree *em_tree,
|
|||||||
u64 end;
|
u64 end;
|
||||||
u64 start_diff;
|
u64 start_diff;
|
||||||
|
|
||||||
BUG_ON(map_start < em->start || map_start >= extent_map_end(em));
|
if (map_start < em->start || map_start >= extent_map_end(em))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (existing->start > map_start) {
|
if (existing->start > map_start) {
|
||||||
next = existing;
|
next = existing;
|
||||||
@ -626,9 +633,9 @@ int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info,
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
*em_in = NULL;
|
*em_in = NULL;
|
||||||
WARN_ONCE(ret,
|
WARN_ONCE(ret,
|
||||||
"unexpected error %d: merge existing(start %llu len %llu) with em(start %llu len %llu)\n",
|
"extent map merge error existing [%llu, %llu) with em [%llu, %llu) start %llu\n",
|
||||||
ret, existing->start, existing->len,
|
existing->start, existing->len,
|
||||||
orig_start, orig_len);
|
orig_start, orig_len, start);
|
||||||
}
|
}
|
||||||
free_extent_map(existing);
|
free_extent_map(existing);
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,18 @@
|
|||||||
#ifndef BTRFS_EXTENT_MAP_H
|
#ifndef BTRFS_EXTENT_MAP_H
|
||||||
#define BTRFS_EXTENT_MAP_H
|
#define BTRFS_EXTENT_MAP_H
|
||||||
|
|
||||||
|
#include <linux/compiler_types.h>
|
||||||
|
#include <linux/rwlock_types.h>
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/list.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
|
#include "misc.h"
|
||||||
|
#include "extent_map.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
|
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
#define EXTENT_MAP_LAST_BYTE ((u64)-4)
|
#define EXTENT_MAP_LAST_BYTE ((u64)-4)
|
||||||
#define EXTENT_MAP_HOLE ((u64)-3)
|
#define EXTENT_MAP_HOLE ((u64)-3)
|
||||||
#define EXTENT_MAP_INLINE ((u64)-2)
|
#define EXTENT_MAP_INLINE ((u64)-2)
|
||||||
|
@ -10,17 +10,14 @@
|
|||||||
#include <linux/sched/mm.h>
|
#include <linux/sched/mm.h>
|
||||||
#include <crypto/hash.h>
|
#include <crypto/hash.h>
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "misc.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "file-item.h"
|
#include "file-item.h"
|
||||||
#include "super.h"
|
|
||||||
|
|
||||||
#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
|
#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
|
||||||
sizeof(struct btrfs_item) * 2) / \
|
sizeof(struct btrfs_item) * 2) / \
|
||||||
@ -179,7 +176,6 @@ int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
|
|||||||
sizeof(*item));
|
sizeof(*item));
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
BUG_ON(ret); /* Can't happen */
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item = btrfs_item_ptr(leaf, path->slots[0],
|
item = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
@ -1229,8 +1225,6 @@ insert:
|
|||||||
ins_size);
|
ins_size);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (WARN_ON(ret != 0))
|
|
||||||
goto out;
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
csum:
|
csum:
|
||||||
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
|
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
|
||||||
|
@ -3,8 +3,21 @@
|
|||||||
#ifndef BTRFS_FILE_ITEM_H
|
#ifndef BTRFS_FILE_ITEM_H
|
||||||
#define BTRFS_FILE_ITEM_H
|
#define BTRFS_FILE_ITEM_H
|
||||||
|
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
|
|
||||||
|
struct extent_map;
|
||||||
|
struct btrfs_file_extent_item;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_bio;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_ordered_sum;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_inode;
|
||||||
|
|
||||||
#define BTRFS_FILE_EXTENT_INLINE_DATA_START \
|
#define BTRFS_FILE_EXTENT_INLINE_DATA_START \
|
||||||
(offsetof(struct btrfs_file_extent_item, disk_bytenr))
|
(offsetof(struct btrfs_file_extent_item, disk_bytenr))
|
||||||
|
|
||||||
|
@ -22,10 +22,8 @@
|
|||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "tree-log.h"
|
#include "tree-log.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "volumes.h"
|
|
||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "delalloc-space.h"
|
#include "delalloc-space.h"
|
||||||
@ -1137,7 +1135,7 @@ static int btrfs_write_check(struct kiocb *iocb, struct iov_iter *from,
|
|||||||
{
|
{
|
||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
loff_t pos = iocb->ki_pos;
|
loff_t pos = iocb->ki_pos;
|
||||||
int ret;
|
int ret;
|
||||||
loff_t oldsize;
|
loff_t oldsize;
|
||||||
@ -1185,7 +1183,7 @@ static noinline ssize_t btrfs_buffered_write(struct kiocb *iocb,
|
|||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct page **pages = NULL;
|
struct page **pages = NULL;
|
||||||
struct extent_changeset *data_reserved = NULL;
|
struct extent_changeset *data_reserved = NULL;
|
||||||
u64 release_bytes = 0;
|
u64 release_bytes = 0;
|
||||||
@ -1461,7 +1459,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
|
|||||||
{
|
{
|
||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
ssize_t written = 0;
|
ssize_t written = 0;
|
||||||
ssize_t written_buffered;
|
ssize_t written_buffered;
|
||||||
@ -1787,7 +1785,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
{
|
{
|
||||||
struct dentry *dentry = file_dentry(file);
|
struct dentry *dentry = file_dentry(file);
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct btrfs_log_ctx ctx;
|
struct btrfs_log_ctx ctx;
|
||||||
@ -1912,6 +1910,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
goto out_release_extents;
|
goto out_release_extents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btrfs_init_log_ctx_scratch_eb(&ctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use start here because we will need to wait on the IO to complete
|
* We use start here because we will need to wait on the IO to complete
|
||||||
* in btrfs_sync_log, which could require joining a transaction (for
|
* in btrfs_sync_log, which could require joining a transaction (for
|
||||||
@ -1931,6 +1931,15 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
trans->in_fsync = true;
|
trans->in_fsync = true;
|
||||||
|
|
||||||
ret = btrfs_log_dentry_safe(trans, dentry, &ctx);
|
ret = btrfs_log_dentry_safe(trans, dentry, &ctx);
|
||||||
|
/*
|
||||||
|
* Scratch eb no longer needed, release before syncing log or commit
|
||||||
|
* transaction, to avoid holding unnecessary memory during such long
|
||||||
|
* operations.
|
||||||
|
*/
|
||||||
|
if (ctx.scratch_eb) {
|
||||||
|
free_extent_buffer(ctx.scratch_eb);
|
||||||
|
ctx.scratch_eb = NULL;
|
||||||
|
}
|
||||||
btrfs_release_log_ctx_extents(&ctx);
|
btrfs_release_log_ctx_extents(&ctx);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* Fallthrough and commit/free transaction. */
|
/* Fallthrough and commit/free transaction. */
|
||||||
@ -2006,6 +2015,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
|
|
||||||
ret = btrfs_commit_transaction(trans);
|
ret = btrfs_commit_transaction(trans);
|
||||||
out:
|
out:
|
||||||
|
free_extent_buffer(ctx.scratch_eb);
|
||||||
ASSERT(list_empty(&ctx.list));
|
ASSERT(list_empty(&ctx.list));
|
||||||
ASSERT(list_empty(&ctx.conflict_inodes));
|
ASSERT(list_empty(&ctx.conflict_inodes));
|
||||||
err = file_check_and_advance_wb_err(file);
|
err = file_check_and_advance_wb_err(file);
|
||||||
@ -2176,7 +2186,7 @@ static int find_first_non_hole(struct btrfs_inode *inode, u64 *start, u64 *len)
|
|||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
em = btrfs_get_extent(inode, NULL, 0,
|
em = btrfs_get_extent(inode, NULL,
|
||||||
round_down(*start, fs_info->sectorsize),
|
round_down(*start, fs_info->sectorsize),
|
||||||
round_up(*len, fs_info->sectorsize));
|
round_up(*len, fs_info->sectorsize));
|
||||||
if (IS_ERR(em))
|
if (IS_ERR(em))
|
||||||
@ -2593,7 +2603,7 @@ out:
|
|||||||
static int btrfs_punch_hole(struct file *file, loff_t offset, loff_t len)
|
static int btrfs_punch_hole(struct file *file, loff_t offset, loff_t len)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
@ -2835,7 +2845,7 @@ static int btrfs_zero_range_check_range_boundary(struct btrfs_inode *inode,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
offset = round_down(offset, sectorsize);
|
offset = round_down(offset, sectorsize);
|
||||||
em = btrfs_get_extent(inode, NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(inode, NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em))
|
if (IS_ERR(em))
|
||||||
return PTR_ERR(em);
|
return PTR_ERR(em);
|
||||||
|
|
||||||
@ -2866,7 +2876,7 @@ static int btrfs_zero_range(struct inode *inode,
|
|||||||
u64 bytes_to_reserve = 0;
|
u64 bytes_to_reserve = 0;
|
||||||
bool space_reserved = false;
|
bool space_reserved = false;
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, alloc_start,
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, alloc_start,
|
||||||
alloc_end - alloc_start);
|
alloc_end - alloc_start);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
@ -2909,8 +2919,7 @@ static int btrfs_zero_range(struct inode *inode,
|
|||||||
|
|
||||||
if (BTRFS_BYTES_TO_BLKS(fs_info, offset) ==
|
if (BTRFS_BYTES_TO_BLKS(fs_info, offset) ==
|
||||||
BTRFS_BYTES_TO_BLKS(fs_info, offset + len - 1)) {
|
BTRFS_BYTES_TO_BLKS(fs_info, offset + len - 1)) {
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, alloc_start,
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, alloc_start, sectorsize);
|
||||||
sectorsize);
|
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
goto out;
|
goto out;
|
||||||
@ -3005,7 +3014,7 @@ reserve_space:
|
|||||||
}
|
}
|
||||||
ret = btrfs_prealloc_file_range(inode, mode, alloc_start,
|
ret = btrfs_prealloc_file_range(inode, mode, alloc_start,
|
||||||
alloc_end - alloc_start,
|
alloc_end - alloc_start,
|
||||||
i_blocksize(inode),
|
fs_info->sectorsize,
|
||||||
offset + len, &alloc_hint);
|
offset + len, &alloc_hint);
|
||||||
unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
@ -3049,7 +3058,7 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Do not allow fallocate in ZONED mode */
|
/* Do not allow fallocate in ZONED mode */
|
||||||
if (btrfs_is_zoned(btrfs_sb(inode->i_sb)))
|
if (btrfs_is_zoned(inode_to_fs_info(inode)))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
alloc_start = round_down(offset, blocksize);
|
alloc_start = round_down(offset, blocksize);
|
||||||
@ -3126,7 +3135,7 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||||||
|
|
||||||
/* First, check if we exceed the qgroup limit */
|
/* First, check if we exceed the qgroup limit */
|
||||||
while (cur_offset < alloc_end) {
|
while (cur_offset < alloc_end) {
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, cur_offset,
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, cur_offset,
|
||||||
alloc_end - cur_offset);
|
alloc_end - cur_offset);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
@ -3177,7 +3186,7 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = btrfs_prealloc_file_range(inode, mode,
|
ret = btrfs_prealloc_file_range(inode, mode,
|
||||||
range->start,
|
range->start,
|
||||||
range->len, i_blocksize(inode),
|
range->len, blocksize,
|
||||||
offset + len, &alloc_hint);
|
offset + len, &alloc_hint);
|
||||||
/*
|
/*
|
||||||
* btrfs_prealloc_file_range() releases space even
|
* btrfs_prealloc_file_range() releases space even
|
||||||
@ -3754,7 +3763,7 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
|
|||||||
if (fsverity_active(inode))
|
if (fsverity_active(inode))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (check_direct_read(btrfs_sb(inode->i_sb), to, iocb->ki_pos))
|
if (check_direct_read(inode_to_fs_info(inode), to, iocb->ki_pos))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
|
btrfs_inode_lock(BTRFS_I(inode), BTRFS_ILOCK_SHARED);
|
||||||
|
@ -3,6 +3,21 @@
|
|||||||
#ifndef BTRFS_FILE_H
|
#ifndef BTRFS_FILE_H
|
||||||
#define BTRFS_FILE_H
|
#define BTRFS_FILE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct file;
|
||||||
|
struct extent_state;
|
||||||
|
struct kiocb;
|
||||||
|
struct iov_iter;
|
||||||
|
struct page;
|
||||||
|
struct btrfs_ioctl_encoded_io_args;
|
||||||
|
struct btrfs_drop_extents_args;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_replace_extent_info;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
extern const struct file_operations btrfs_file_operations;
|
extern const struct file_operations btrfs_file_operations;
|
||||||
|
|
||||||
int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
|
int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
|
||||||
|
@ -19,9 +19,7 @@
|
|||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
#include "volumes.h"
|
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "delalloc-space.h"
|
|
||||||
#include "block-group.h"
|
#include "block-group.h"
|
||||||
#include "discard.h"
|
#include "discard.h"
|
||||||
#include "subpage.h"
|
#include "subpage.h"
|
||||||
@ -399,7 +397,7 @@ static int io_ctl_init(struct btrfs_io_ctl *io_ctl, struct inode *inode,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
io_ctl->num_pages = num_pages;
|
io_ctl->num_pages = num_pages;
|
||||||
io_ctl->fs_info = btrfs_sb(inode->i_sb);
|
io_ctl->fs_info = inode_to_fs_info(inode);
|
||||||
io_ctl->inode = inode;
|
io_ctl->inode = inode;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -2621,7 +2619,7 @@ static void steal_from_bitmap(struct btrfs_free_space_ctl *ctl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int __btrfs_add_free_space(struct btrfs_block_group *block_group,
|
static int __btrfs_add_free_space(struct btrfs_block_group *block_group,
|
||||||
u64 offset, u64 bytes,
|
u64 offset, u64 bytes,
|
||||||
enum btrfs_trim_state trim_state)
|
enum btrfs_trim_state trim_state)
|
||||||
{
|
{
|
||||||
@ -4156,15 +4154,13 @@ out:
|
|||||||
|
|
||||||
int __init btrfs_free_space_init(void)
|
int __init btrfs_free_space_init(void)
|
||||||
{
|
{
|
||||||
btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space",
|
btrfs_free_space_cachep = KMEM_CACHE(btrfs_free_space, 0);
|
||||||
sizeof(struct btrfs_free_space), 0,
|
|
||||||
SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_free_space_cachep)
|
if (!btrfs_free_space_cachep)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
|
btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
|
||||||
PAGE_SIZE, PAGE_SIZE,
|
PAGE_SIZE, PAGE_SIZE,
|
||||||
SLAB_MEM_SPREAD, NULL);
|
0, NULL);
|
||||||
if (!btrfs_free_space_bitmap_cachep) {
|
if (!btrfs_free_space_bitmap_cachep) {
|
||||||
kmem_cache_destroy(btrfs_free_space_cachep);
|
kmem_cache_destroy(btrfs_free_space_cachep);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -6,6 +6,19 @@
|
|||||||
#ifndef BTRFS_FREE_SPACE_CACHE_H
|
#ifndef BTRFS_FREE_SPACE_CACHE_H
|
||||||
#define BTRFS_FREE_SPACE_CACHE_H
|
#define BTRFS_FREE_SPACE_CACHE_H
|
||||||
|
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct page;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_trim_block_group;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the trim state of an extent or bitmap.
|
* This is the trim state of an extent or bitmap.
|
||||||
*
|
*
|
||||||
@ -114,8 +127,6 @@ int btrfs_write_out_cache(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group,
|
void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group,
|
||||||
struct btrfs_free_space_ctl *ctl);
|
struct btrfs_free_space_ctl *ctl);
|
||||||
int __btrfs_add_free_space(struct btrfs_block_group *block_group, u64 bytenr,
|
|
||||||
u64 size, enum btrfs_trim_state trim_state);
|
|
||||||
int btrfs_add_free_space(struct btrfs_block_group *block_group,
|
int btrfs_add_free_space(struct btrfs_block_group *block_group,
|
||||||
u64 bytenr, u64 size);
|
u64 bytenr, u64 size);
|
||||||
int btrfs_add_free_space_unused(struct btrfs_block_group *block_group,
|
int btrfs_add_free_space_unused(struct btrfs_block_group *block_group,
|
||||||
|
@ -1176,12 +1176,16 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
BTRFS_FREE_SPACE_TREE_OBJECTID);
|
BTRFS_FREE_SPACE_TREE_OBJECTID);
|
||||||
if (IS_ERR(free_space_root)) {
|
if (IS_ERR(free_space_root)) {
|
||||||
ret = PTR_ERR(free_space_root);
|
ret = PTR_ERR(free_space_root);
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
goto out_clear;
|
||||||
}
|
}
|
||||||
ret = btrfs_global_root_insert(free_space_root);
|
ret = btrfs_global_root_insert(free_space_root);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
btrfs_put_root(free_space_root);
|
btrfs_put_root(free_space_root);
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
goto out_clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = rb_first_cached(&fs_info->block_group_cache_tree);
|
node = rb_first_cached(&fs_info->block_group_cache_tree);
|
||||||
@ -1189,8 +1193,11 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
block_group = rb_entry(node, struct btrfs_block_group,
|
block_group = rb_entry(node, struct btrfs_block_group,
|
||||||
cache_node);
|
cache_node);
|
||||||
ret = populate_free_space_tree(trans, block_group);
|
ret = populate_free_space_tree(trans, block_group);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
goto out_clear;
|
||||||
|
}
|
||||||
node = rb_next(node);
|
node = rb_next(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1206,11 +1213,9 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
abort:
|
out_clear:
|
||||||
clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
|
clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags);
|
||||||
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
||||||
btrfs_abort_transaction(trans, ret);
|
|
||||||
btrfs_end_transaction(trans);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1273,12 +1278,18 @@ int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
|
btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID);
|
||||||
|
|
||||||
ret = clear_free_space_tree(trans, free_space_root);
|
ret = clear_free_space_tree(trans, free_space_root);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_del_root(trans, &free_space_root->root_key);
|
ret = btrfs_del_root(trans, &free_space_root->root_key);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_global_root_delete(free_space_root);
|
btrfs_global_root_delete(free_space_root);
|
||||||
|
|
||||||
@ -1295,11 +1306,6 @@ int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
btrfs_put_root(free_space_root);
|
btrfs_put_root(free_space_root);
|
||||||
|
|
||||||
return btrfs_commit_transaction(trans);
|
return btrfs_commit_transaction(trans);
|
||||||
|
|
||||||
abort:
|
|
||||||
btrfs_abort_transaction(trans, ret);
|
|
||||||
btrfs_end_transaction(trans);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
|
int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
|
||||||
@ -1322,8 +1328,11 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
set_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
set_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
||||||
|
|
||||||
ret = clear_free_space_tree(trans, free_space_root);
|
ret = clear_free_space_tree(trans, free_space_root);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
node = rb_first_cached(&fs_info->block_group_cache_tree);
|
node = rb_first_cached(&fs_info->block_group_cache_tree);
|
||||||
while (node) {
|
while (node) {
|
||||||
@ -1332,8 +1341,11 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
block_group = rb_entry(node, struct btrfs_block_group,
|
block_group = rb_entry(node, struct btrfs_block_group,
|
||||||
cache_node);
|
cache_node);
|
||||||
ret = populate_free_space_tree(trans, block_group);
|
ret = populate_free_space_tree(trans, block_group);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto abort;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
node = rb_next(node);
|
node = rb_next(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1344,10 +1356,6 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info)
|
|||||||
ret = btrfs_commit_transaction(trans);
|
ret = btrfs_commit_transaction(trans);
|
||||||
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags);
|
||||||
return ret;
|
return ret;
|
||||||
abort:
|
|
||||||
btrfs_abort_transaction(trans, ret);
|
|
||||||
btrfs_end_transaction(trans);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
|
static int __add_block_group_free_space(struct btrfs_trans_handle *trans,
|
||||||
|
@ -6,7 +6,13 @@
|
|||||||
#ifndef BTRFS_FREE_SPACE_TREE_H
|
#ifndef BTRFS_FREE_SPACE_TREE_H
|
||||||
#define BTRFS_FREE_SPACE_TREE_H
|
#define BTRFS_FREE_SPACE_TREE_H
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
|
|
||||||
struct btrfs_caching_control;
|
struct btrfs_caching_control;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_block_group;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default size for new free space bitmap items. The last bitmap in a block
|
* The default size for new free space bitmap items. The last bitmap in a block
|
||||||
|
@ -4,13 +4,50 @@
|
|||||||
#define BTRFS_FS_H
|
#define BTRFS_FS_H
|
||||||
|
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/btrfs_tree.h>
|
|
||||||
#include <linux/sizes.h>
|
#include <linux/sizes.h>
|
||||||
|
#include <linux/time64.h>
|
||||||
|
#include <linux/compiler.h>
|
||||||
|
#include <linux/math.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/percpu_counter.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/rwlock_types.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/radix-tree.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/wait_bit.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <uapi/linux/btrfs.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include "extent-io-tree.h"
|
#include "extent-io-tree.h"
|
||||||
#include "extent_map.h"
|
|
||||||
#include "async-thread.h"
|
#include "async-thread.h"
|
||||||
#include "block-rsv.h"
|
#include "block-rsv.h"
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct super_block;
|
||||||
|
struct kobject;
|
||||||
|
struct reloc_control;
|
||||||
|
struct crypto_shash;
|
||||||
|
struct ulist;
|
||||||
|
struct btrfs_device;
|
||||||
|
struct btrfs_block_group;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_fs_devices;
|
||||||
|
struct btrfs_transaction;
|
||||||
|
struct btrfs_delayed_root;
|
||||||
|
struct btrfs_balance_control;
|
||||||
|
struct btrfs_subpage_info;
|
||||||
|
struct btrfs_stripe_hash_table;
|
||||||
|
struct btrfs_space_info;
|
||||||
|
|
||||||
#define BTRFS_MAX_EXTENT_SIZE SZ_128M
|
#define BTRFS_MAX_EXTENT_SIZE SZ_128M
|
||||||
|
|
||||||
@ -732,10 +769,13 @@ struct btrfs_fs_info {
|
|||||||
|
|
||||||
/* Reclaim partially filled block groups in the background */
|
/* Reclaim partially filled block groups in the background */
|
||||||
struct work_struct reclaim_bgs_work;
|
struct work_struct reclaim_bgs_work;
|
||||||
|
/* Protected by unused_bgs_lock. */
|
||||||
struct list_head reclaim_bgs;
|
struct list_head reclaim_bgs;
|
||||||
int bg_reclaim_threshold;
|
int bg_reclaim_threshold;
|
||||||
|
|
||||||
|
/* Protects the lists unused_bgs and reclaim_bgs. */
|
||||||
spinlock_t unused_bgs_lock;
|
spinlock_t unused_bgs_lock;
|
||||||
|
/* Protected by unused_bgs_lock. */
|
||||||
struct list_head unused_bgs;
|
struct list_head unused_bgs;
|
||||||
struct mutex unused_bg_unpin_mutex;
|
struct mutex unused_bg_unpin_mutex;
|
||||||
/* Protect block groups that are going to be deleted */
|
/* Protect block groups that are going to be deleted */
|
||||||
@ -829,6 +869,17 @@ struct btrfs_fs_info {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define page_to_inode(_page) (BTRFS_I(_Generic((_page), \
|
||||||
|
struct page *: (_page))->mapping->host))
|
||||||
|
#define folio_to_inode(_folio) (BTRFS_I(_Generic((_folio), \
|
||||||
|
struct folio *: (_folio))->mapping->host))
|
||||||
|
|
||||||
|
#define page_to_fs_info(_page) (page_to_inode(_page)->root->fs_info)
|
||||||
|
#define folio_to_fs_info(_folio) (folio_to_inode(_folio)->root->fs_info)
|
||||||
|
|
||||||
|
#define inode_to_fs_info(_inode) (BTRFS_I(_Generic((_inode), \
|
||||||
|
struct inode *: (_inode)))->root->fs_info)
|
||||||
|
|
||||||
static inline u64 btrfs_get_fs_generation(const struct btrfs_fs_info *fs_info)
|
static inline u64 btrfs_get_fs_generation(const struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
return READ_ONCE(fs_info->generation);
|
return READ_ONCE(fs_info->generation);
|
||||||
@ -922,6 +973,8 @@ void btrfs_exclop_finish(struct btrfs_fs_info *fs_info);
|
|||||||
void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
|
void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
|
||||||
enum btrfs_exclusive_operation op);
|
enum btrfs_exclusive_operation op);
|
||||||
|
|
||||||
|
int btrfs_check_ioctl_vol_args_path(const struct btrfs_ioctl_vol_args *vol_args);
|
||||||
|
|
||||||
/* Compatibility and incompatibility defines */
|
/* Compatibility and incompatibility defines */
|
||||||
void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
|
void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "inode-item.h"
|
#include "inode-item.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "extent-tree.h"
|
#include "extent-tree.h"
|
||||||
|
@ -6,14 +6,15 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/crc32c.h>
|
#include <linux/crc32c.h>
|
||||||
|
|
||||||
|
struct fscrypt_str;
|
||||||
|
struct extent_buffer;
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
struct btrfs_root;
|
struct btrfs_root;
|
||||||
struct btrfs_path;
|
struct btrfs_path;
|
||||||
struct btrfs_key;
|
struct btrfs_key;
|
||||||
struct btrfs_inode_extref;
|
struct btrfs_inode_extref;
|
||||||
struct btrfs_inode;
|
struct btrfs_inode;
|
||||||
struct extent_buffer;
|
struct btrfs_truncate_control;
|
||||||
struct fscrypt_str;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return this if we need to call truncate_block for the last bit of the
|
* Return this if we need to call truncate_block for the last bit of the
|
||||||
|
238
fs/btrfs/inode.c
238
fs/btrfs/inode.c
@ -39,14 +39,12 @@
|
|||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "ordered-data.h"
|
#include "ordered-data.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
#include "tree-log.h"
|
#include "tree-log.h"
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "free-space-cache.h"
|
|
||||||
#include "props.h"
|
#include "props.h"
|
||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "delalloc-space.h"
|
#include "delalloc-space.h"
|
||||||
@ -740,7 +738,8 @@ static noinline int add_async_extent(struct async_chunk *cow,
|
|||||||
struct async_extent *async_extent;
|
struct async_extent *async_extent;
|
||||||
|
|
||||||
async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
|
async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS);
|
||||||
BUG_ON(!async_extent); /* -ENOMEM */
|
if (!async_extent)
|
||||||
|
return -ENOMEM;
|
||||||
async_extent->start = start;
|
async_extent->start = start;
|
||||||
async_extent->ram_size = ram_size;
|
async_extent->ram_size = ram_size;
|
||||||
async_extent->compressed_size = compressed_size;
|
async_extent->compressed_size = compressed_size;
|
||||||
@ -1027,8 +1026,9 @@ again:
|
|||||||
* The async work queues will take care of doing actual allocation on
|
* The async work queues will take care of doing actual allocation on
|
||||||
* disk for these compressed pages, and will submit the bios.
|
* disk for these compressed pages, and will submit the bios.
|
||||||
*/
|
*/
|
||||||
add_async_extent(async_chunk, start, total_in, total_compressed, pages,
|
ret = add_async_extent(async_chunk, start, total_in, total_compressed, pages,
|
||||||
nr_pages, compress_type);
|
nr_pages, compress_type);
|
||||||
|
BUG_ON(ret);
|
||||||
if (start + total_in < end) {
|
if (start + total_in < end) {
|
||||||
start += total_in;
|
start += total_in;
|
||||||
cond_resched();
|
cond_resched();
|
||||||
@ -1040,8 +1040,9 @@ mark_incompressible:
|
|||||||
if (!btrfs_test_opt(fs_info, FORCE_COMPRESS) && !inode->prop_compress)
|
if (!btrfs_test_opt(fs_info, FORCE_COMPRESS) && !inode->prop_compress)
|
||||||
inode->flags |= BTRFS_INODE_NOCOMPRESS;
|
inode->flags |= BTRFS_INODE_NOCOMPRESS;
|
||||||
cleanup_and_bail_uncompressed:
|
cleanup_and_bail_uncompressed:
|
||||||
add_async_extent(async_chunk, start, end - start + 1, 0, NULL, 0,
|
ret = add_async_extent(async_chunk, start, end - start + 1, 0, NULL, 0,
|
||||||
BTRFS_COMPRESS_NONE);
|
BTRFS_COMPRESS_NONE);
|
||||||
|
BUG_ON(ret);
|
||||||
free_pages:
|
free_pages:
|
||||||
if (pages) {
|
if (pages) {
|
||||||
for (i = 0; i < nr_pages; i++) {
|
for (i = 0; i < nr_pages; i++) {
|
||||||
@ -2302,6 +2303,8 @@ void btrfs_split_delalloc_extent(struct btrfs_inode *inode,
|
|||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||||
u64 size;
|
u64 size;
|
||||||
|
|
||||||
|
lockdep_assert_held(&inode->io_tree.lock);
|
||||||
|
|
||||||
/* not delalloc, ignore it */
|
/* not delalloc, ignore it */
|
||||||
if (!(orig->state & EXTENT_DELALLOC))
|
if (!(orig->state & EXTENT_DELALLOC))
|
||||||
return;
|
return;
|
||||||
@ -2340,6 +2343,8 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state
|
|||||||
u64 new_size, old_size;
|
u64 new_size, old_size;
|
||||||
u32 num_extents;
|
u32 num_extents;
|
||||||
|
|
||||||
|
lockdep_assert_held(&inode->io_tree.lock);
|
||||||
|
|
||||||
/* not delalloc, ignore it */
|
/* not delalloc, ignore it */
|
||||||
if (!(other->state & EXTENT_DELALLOC))
|
if (!(other->state & EXTENT_DELALLOC))
|
||||||
return;
|
return;
|
||||||
@ -2387,55 +2392,50 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state
|
|||||||
spin_unlock(&inode->lock);
|
spin_unlock(&inode->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btrfs_add_delalloc_inodes(struct btrfs_root *root,
|
static void btrfs_add_delalloc_inode(struct btrfs_inode *inode)
|
||||||
struct btrfs_inode *inode)
|
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_root *root = inode->root;
|
||||||
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
|
|
||||||
spin_lock(&root->delalloc_lock);
|
spin_lock(&root->delalloc_lock);
|
||||||
if (list_empty(&inode->delalloc_inodes)) {
|
ASSERT(list_empty(&inode->delalloc_inodes));
|
||||||
list_add_tail(&inode->delalloc_inodes, &root->delalloc_inodes);
|
list_add_tail(&inode->delalloc_inodes, &root->delalloc_inodes);
|
||||||
set_bit(BTRFS_INODE_IN_DELALLOC_LIST, &inode->runtime_flags);
|
root->nr_delalloc_inodes++;
|
||||||
root->nr_delalloc_inodes++;
|
if (root->nr_delalloc_inodes == 1) {
|
||||||
if (root->nr_delalloc_inodes == 1) {
|
spin_lock(&fs_info->delalloc_root_lock);
|
||||||
spin_lock(&fs_info->delalloc_root_lock);
|
ASSERT(list_empty(&root->delalloc_root));
|
||||||
BUG_ON(!list_empty(&root->delalloc_root));
|
list_add_tail(&root->delalloc_root, &fs_info->delalloc_roots);
|
||||||
list_add_tail(&root->delalloc_root,
|
spin_unlock(&fs_info->delalloc_root_lock);
|
||||||
&fs_info->delalloc_roots);
|
|
||||||
spin_unlock(&fs_info->delalloc_root_lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
spin_unlock(&root->delalloc_lock);
|
spin_unlock(&root->delalloc_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void __btrfs_del_delalloc_inode(struct btrfs_root *root,
|
void btrfs_del_delalloc_inode(struct btrfs_inode *inode)
|
||||||
struct btrfs_inode *inode)
|
|
||||||
{
|
{
|
||||||
|
struct btrfs_root *root = inode->root;
|
||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
|
|
||||||
|
lockdep_assert_held(&root->delalloc_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We may be called after the inode was already deleted from the list,
|
||||||
|
* namely in the transaction abort path btrfs_destroy_delalloc_inodes(),
|
||||||
|
* and then later through btrfs_clear_delalloc_extent() while the inode
|
||||||
|
* still has ->delalloc_bytes > 0.
|
||||||
|
*/
|
||||||
if (!list_empty(&inode->delalloc_inodes)) {
|
if (!list_empty(&inode->delalloc_inodes)) {
|
||||||
list_del_init(&inode->delalloc_inodes);
|
list_del_init(&inode->delalloc_inodes);
|
||||||
clear_bit(BTRFS_INODE_IN_DELALLOC_LIST,
|
|
||||||
&inode->runtime_flags);
|
|
||||||
root->nr_delalloc_inodes--;
|
root->nr_delalloc_inodes--;
|
||||||
if (!root->nr_delalloc_inodes) {
|
if (!root->nr_delalloc_inodes) {
|
||||||
ASSERT(list_empty(&root->delalloc_inodes));
|
ASSERT(list_empty(&root->delalloc_inodes));
|
||||||
spin_lock(&fs_info->delalloc_root_lock);
|
spin_lock(&fs_info->delalloc_root_lock);
|
||||||
BUG_ON(list_empty(&root->delalloc_root));
|
ASSERT(!list_empty(&root->delalloc_root));
|
||||||
list_del_init(&root->delalloc_root);
|
list_del_init(&root->delalloc_root);
|
||||||
spin_unlock(&fs_info->delalloc_root_lock);
|
spin_unlock(&fs_info->delalloc_root_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btrfs_del_delalloc_inode(struct btrfs_root *root,
|
|
||||||
struct btrfs_inode *inode)
|
|
||||||
{
|
|
||||||
spin_lock(&root->delalloc_lock);
|
|
||||||
__btrfs_del_delalloc_inode(root, inode);
|
|
||||||
spin_unlock(&root->delalloc_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Properly track delayed allocation bytes in the inode and to maintain the
|
* Properly track delayed allocation bytes in the inode and to maintain the
|
||||||
* list of inodes that have pending delalloc work to be done.
|
* list of inodes that have pending delalloc work to be done.
|
||||||
@ -2445,6 +2445,8 @@ void btrfs_set_delalloc_extent(struct btrfs_inode *inode, struct extent_state *s
|
|||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||||
|
|
||||||
|
lockdep_assert_held(&inode->io_tree.lock);
|
||||||
|
|
||||||
if ((bits & EXTENT_DEFRAG) && !(bits & EXTENT_DELALLOC))
|
if ((bits & EXTENT_DEFRAG) && !(bits & EXTENT_DELALLOC))
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
/*
|
/*
|
||||||
@ -2453,10 +2455,9 @@ void btrfs_set_delalloc_extent(struct btrfs_inode *inode, struct extent_state *s
|
|||||||
* bit, which is only set or cleared with irqs on
|
* bit, which is only set or cleared with irqs on
|
||||||
*/
|
*/
|
||||||
if (!(state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
|
if (!(state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
|
||||||
struct btrfs_root *root = inode->root;
|
|
||||||
u64 len = state->end + 1 - state->start;
|
u64 len = state->end + 1 - state->start;
|
||||||
|
u64 prev_delalloc_bytes;
|
||||||
u32 num_extents = count_max_extents(fs_info, len);
|
u32 num_extents = count_max_extents(fs_info, len);
|
||||||
bool do_list = !btrfs_is_free_space_inode(inode);
|
|
||||||
|
|
||||||
spin_lock(&inode->lock);
|
spin_lock(&inode->lock);
|
||||||
btrfs_mod_outstanding_extents(inode, num_extents);
|
btrfs_mod_outstanding_extents(inode, num_extents);
|
||||||
@ -2469,13 +2470,20 @@ void btrfs_set_delalloc_extent(struct btrfs_inode *inode, struct extent_state *s
|
|||||||
percpu_counter_add_batch(&fs_info->delalloc_bytes, len,
|
percpu_counter_add_batch(&fs_info->delalloc_bytes, len,
|
||||||
fs_info->delalloc_batch);
|
fs_info->delalloc_batch);
|
||||||
spin_lock(&inode->lock);
|
spin_lock(&inode->lock);
|
||||||
|
prev_delalloc_bytes = inode->delalloc_bytes;
|
||||||
inode->delalloc_bytes += len;
|
inode->delalloc_bytes += len;
|
||||||
if (bits & EXTENT_DEFRAG)
|
if (bits & EXTENT_DEFRAG)
|
||||||
inode->defrag_bytes += len;
|
inode->defrag_bytes += len;
|
||||||
if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST,
|
|
||||||
&inode->runtime_flags))
|
|
||||||
btrfs_add_delalloc_inodes(root, inode);
|
|
||||||
spin_unlock(&inode->lock);
|
spin_unlock(&inode->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't need to be under the protection of the inode's lock,
|
||||||
|
* because we are called while holding the inode's io_tree lock
|
||||||
|
* and are therefore protected against concurrent calls of this
|
||||||
|
* function and btrfs_clear_delalloc_extent().
|
||||||
|
*/
|
||||||
|
if (!btrfs_is_free_space_inode(inode) && prev_delalloc_bytes == 0)
|
||||||
|
btrfs_add_delalloc_inode(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(state->state & EXTENT_DELALLOC_NEW) &&
|
if (!(state->state & EXTENT_DELALLOC_NEW) &&
|
||||||
@ -2497,6 +2505,8 @@ void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
|
|||||||
u64 len = state->end + 1 - state->start;
|
u64 len = state->end + 1 - state->start;
|
||||||
u32 num_extents = count_max_extents(fs_info, len);
|
u32 num_extents = count_max_extents(fs_info, len);
|
||||||
|
|
||||||
|
lockdep_assert_held(&inode->io_tree.lock);
|
||||||
|
|
||||||
if ((state->state & EXTENT_DEFRAG) && (bits & EXTENT_DEFRAG)) {
|
if ((state->state & EXTENT_DEFRAG) && (bits & EXTENT_DEFRAG)) {
|
||||||
spin_lock(&inode->lock);
|
spin_lock(&inode->lock);
|
||||||
inode->defrag_bytes -= len;
|
inode->defrag_bytes -= len;
|
||||||
@ -2510,7 +2520,7 @@ void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
|
|||||||
*/
|
*/
|
||||||
if ((state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
|
if ((state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
|
||||||
struct btrfs_root *root = inode->root;
|
struct btrfs_root *root = inode->root;
|
||||||
bool do_list = !btrfs_is_free_space_inode(inode);
|
u64 new_delalloc_bytes;
|
||||||
|
|
||||||
spin_lock(&inode->lock);
|
spin_lock(&inode->lock);
|
||||||
btrfs_mod_outstanding_extents(inode, -num_extents);
|
btrfs_mod_outstanding_extents(inode, -num_extents);
|
||||||
@ -2530,7 +2540,8 @@ void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!btrfs_is_data_reloc_root(root) &&
|
if (!btrfs_is_data_reloc_root(root) &&
|
||||||
do_list && !(state->state & EXTENT_NORESERVE) &&
|
!btrfs_is_free_space_inode(inode) &&
|
||||||
|
!(state->state & EXTENT_NORESERVE) &&
|
||||||
(bits & EXTENT_CLEAR_DATA_RESV))
|
(bits & EXTENT_CLEAR_DATA_RESV))
|
||||||
btrfs_free_reserved_data_space_noquota(fs_info, len);
|
btrfs_free_reserved_data_space_noquota(fs_info, len);
|
||||||
|
|
||||||
@ -2538,11 +2549,20 @@ void btrfs_clear_delalloc_extent(struct btrfs_inode *inode,
|
|||||||
fs_info->delalloc_batch);
|
fs_info->delalloc_batch);
|
||||||
spin_lock(&inode->lock);
|
spin_lock(&inode->lock);
|
||||||
inode->delalloc_bytes -= len;
|
inode->delalloc_bytes -= len;
|
||||||
if (do_list && inode->delalloc_bytes == 0 &&
|
new_delalloc_bytes = inode->delalloc_bytes;
|
||||||
test_bit(BTRFS_INODE_IN_DELALLOC_LIST,
|
|
||||||
&inode->runtime_flags))
|
|
||||||
btrfs_del_delalloc_inode(root, inode);
|
|
||||||
spin_unlock(&inode->lock);
|
spin_unlock(&inode->lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't need to be under the protection of the inode's lock,
|
||||||
|
* because we are called while holding the inode's io_tree lock
|
||||||
|
* and are therefore protected against concurrent calls of this
|
||||||
|
* function and btrfs_set_delalloc_extent().
|
||||||
|
*/
|
||||||
|
if (!btrfs_is_free_space_inode(inode) && new_delalloc_bytes == 0) {
|
||||||
|
spin_lock(&root->delalloc_lock);
|
||||||
|
btrfs_del_delalloc_inode(inode);
|
||||||
|
spin_unlock(&root->delalloc_lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((state->state & EXTENT_DELALLOC_NEW) &&
|
if ((state->state & EXTENT_DELALLOC_NEW) &&
|
||||||
@ -2632,7 +2652,7 @@ static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode,
|
|||||||
u64 em_len;
|
u64 em_len;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
em = btrfs_get_extent(inode, NULL, 0, search_start, search_len);
|
em = btrfs_get_extent(inode, NULL, search_start, search_len);
|
||||||
if (IS_ERR(em))
|
if (IS_ERR(em))
|
||||||
return PTR_ERR(em);
|
return PTR_ERR(em);
|
||||||
|
|
||||||
@ -2829,7 +2849,7 @@ out_page:
|
|||||||
int btrfs_writepage_cow_fixup(struct page *page)
|
int btrfs_writepage_cow_fixup(struct page *page)
|
||||||
{
|
{
|
||||||
struct inode *inode = page->mapping->host;
|
struct inode *inode = page->mapping->host;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_writepage_fixup *fixup;
|
struct btrfs_writepage_fixup *fixup;
|
||||||
|
|
||||||
/* This page has ordered extent covering it already */
|
/* This page has ordered extent covering it already */
|
||||||
@ -3127,8 +3147,13 @@ int btrfs_finish_one_ordered(struct btrfs_ordered_extent *ordered_extent)
|
|||||||
ordered_extent->disk_num_bytes);
|
ordered_extent->disk_num_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unpin_extent_cache(inode, ordered_extent->file_offset,
|
if (ret < 0) {
|
||||||
ordered_extent->num_bytes, trans->transid);
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = unpin_extent_cache(inode, ordered_extent->file_offset,
|
||||||
|
ordered_extent->num_bytes, trans->transid);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
btrfs_abort_transaction(trans, ret);
|
btrfs_abort_transaction(trans, ret);
|
||||||
goto out;
|
goto out;
|
||||||
@ -3254,7 +3279,7 @@ out:
|
|||||||
|
|
||||||
int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered)
|
int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered)
|
||||||
{
|
{
|
||||||
if (btrfs_is_zoned(btrfs_sb(ordered->inode->i_sb)) &&
|
if (btrfs_is_zoned(inode_to_fs_info(ordered->inode)) &&
|
||||||
!test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) &&
|
!test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) &&
|
||||||
list_empty(&ordered->bioc_list))
|
list_empty(&ordered->bioc_list))
|
||||||
btrfs_finish_ordered_zoned(ordered);
|
btrfs_finish_ordered_zoned(ordered);
|
||||||
@ -3739,7 +3764,7 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
|
|||||||
static int btrfs_read_locked_inode(struct inode *inode,
|
static int btrfs_read_locked_inode(struct inode *inode,
|
||||||
struct btrfs_path *in_path)
|
struct btrfs_path *in_path)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_path *path = in_path;
|
struct btrfs_path *path = in_path;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_inode_item *inode_item;
|
struct btrfs_inode_item *inode_item;
|
||||||
@ -4383,7 +4408,14 @@ static noinline int may_destroy_subvol(struct btrfs_root *root)
|
|||||||
ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
BUG_ON(ret == 0);
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist a root
|
||||||
|
* with such id, but this is out of valid range.
|
||||||
|
*/
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (path->slots[0] > 0) {
|
if (path->slots[0] > 0) {
|
||||||
@ -4464,8 +4496,8 @@ again:
|
|||||||
|
|
||||||
int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
|
int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb);
|
|
||||||
struct btrfs_root *root = dir->root;
|
struct btrfs_root *root = dir->root;
|
||||||
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
struct btrfs_root *dest = BTRFS_I(inode)->root;
|
struct btrfs_root *dest = BTRFS_I(inode)->root;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
@ -4695,7 +4727,7 @@ int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
|
|||||||
u32 blocksize = fs_info->sectorsize;
|
u32 blocksize = fs_info->sectorsize;
|
||||||
pgoff_t index = from >> PAGE_SHIFT;
|
pgoff_t index = from >> PAGE_SHIFT;
|
||||||
unsigned offset = from & (blocksize - 1);
|
unsigned offset = from & (blocksize - 1);
|
||||||
struct page *page;
|
struct folio *folio;
|
||||||
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
||||||
size_t write_bytes = blocksize;
|
size_t write_bytes = blocksize;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -4727,8 +4759,9 @@ int btrfs_truncate_block(struct btrfs_inode *inode, loff_t from, loff_t len,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
again:
|
again:
|
||||||
page = find_or_create_page(mapping, index, mask);
|
folio = __filemap_get_folio(mapping, index,
|
||||||
if (!page) {
|
FGP_LOCK | FGP_ACCESSED | FGP_CREAT, mask);
|
||||||
|
if (IS_ERR(folio)) {
|
||||||
btrfs_delalloc_release_space(inode, data_reserved, block_start,
|
btrfs_delalloc_release_space(inode, data_reserved, block_start,
|
||||||
blocksize, true);
|
blocksize, true);
|
||||||
btrfs_delalloc_release_extents(inode, blocksize);
|
btrfs_delalloc_release_extents(inode, blocksize);
|
||||||
@ -4736,15 +4769,15 @@ again:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PageUptodate(page)) {
|
if (!folio_test_uptodate(folio)) {
|
||||||
ret = btrfs_read_folio(NULL, page_folio(page));
|
ret = btrfs_read_folio(NULL, folio);
|
||||||
lock_page(page);
|
folio_lock(folio);
|
||||||
if (page->mapping != mapping) {
|
if (folio->mapping != mapping) {
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
if (!PageUptodate(page)) {
|
if (!folio_test_uptodate(folio)) {
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
@ -4756,19 +4789,19 @@ again:
|
|||||||
* folio private, but left the page in the mapping. Set the page mapped
|
* folio private, but left the page in the mapping. Set the page mapped
|
||||||
* here to make sure it's properly set for the subpage stuff.
|
* here to make sure it's properly set for the subpage stuff.
|
||||||
*/
|
*/
|
||||||
ret = set_page_extent_mapped(page);
|
ret = set_folio_extent_mapped(folio);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
wait_on_page_writeback(page);
|
folio_wait_writeback(folio);
|
||||||
|
|
||||||
lock_extent(io_tree, block_start, block_end, &cached_state);
|
lock_extent(io_tree, block_start, block_end, &cached_state);
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, block_start);
|
ordered = btrfs_lookup_ordered_extent(inode, block_start);
|
||||||
if (ordered) {
|
if (ordered) {
|
||||||
unlock_extent(io_tree, block_start, block_end, &cached_state);
|
unlock_extent(io_tree, block_start, block_end, &cached_state);
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
btrfs_start_ordered_extent(ordered);
|
btrfs_start_ordered_extent(ordered);
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
goto again;
|
goto again;
|
||||||
@ -4789,15 +4822,16 @@ again:
|
|||||||
if (!len)
|
if (!len)
|
||||||
len = blocksize - offset;
|
len = blocksize - offset;
|
||||||
if (front)
|
if (front)
|
||||||
memzero_page(page, (block_start - page_offset(page)),
|
folio_zero_range(folio, block_start - folio_pos(folio),
|
||||||
offset);
|
offset);
|
||||||
else
|
else
|
||||||
memzero_page(page, (block_start - page_offset(page)) + offset,
|
folio_zero_range(folio,
|
||||||
len);
|
(block_start - folio_pos(folio)) + offset,
|
||||||
|
len);
|
||||||
}
|
}
|
||||||
btrfs_folio_clear_checked(fs_info, page_folio(page), block_start,
|
btrfs_folio_clear_checked(fs_info, folio, block_start,
|
||||||
block_end + 1 - block_start);
|
block_end + 1 - block_start);
|
||||||
btrfs_folio_set_dirty(fs_info, page_folio(page), block_start,
|
btrfs_folio_set_dirty(fs_info, folio, block_start,
|
||||||
block_end + 1 - block_start);
|
block_end + 1 - block_start);
|
||||||
unlock_extent(io_tree, block_start, block_end, &cached_state);
|
unlock_extent(io_tree, block_start, block_end, &cached_state);
|
||||||
|
|
||||||
@ -4814,8 +4848,8 @@ out_unlock:
|
|||||||
block_start, blocksize, true);
|
block_start, blocksize, true);
|
||||||
}
|
}
|
||||||
btrfs_delalloc_release_extents(inode, blocksize);
|
btrfs_delalloc_release_extents(inode, blocksize);
|
||||||
unlock_page(page);
|
folio_unlock(folio);
|
||||||
put_page(page);
|
folio_put(folio);
|
||||||
out:
|
out:
|
||||||
if (only_release_metadata)
|
if (only_release_metadata)
|
||||||
btrfs_check_nocow_unlock(inode);
|
btrfs_check_nocow_unlock(inode);
|
||||||
@ -4907,8 +4941,7 @@ int btrfs_cont_expand(struct btrfs_inode *inode, loff_t oldsize, loff_t size)
|
|||||||
&cached_state);
|
&cached_state);
|
||||||
cur_offset = hole_start;
|
cur_offset = hole_start;
|
||||||
while (1) {
|
while (1) {
|
||||||
em = btrfs_get_extent(inode, NULL, 0, cur_offset,
|
em = btrfs_get_extent(inode, NULL, cur_offset, block_end - cur_offset);
|
||||||
block_end - cur_offset);
|
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
err = PTR_ERR(em);
|
err = PTR_ERR(em);
|
||||||
em = NULL;
|
em = NULL;
|
||||||
@ -5019,7 +5052,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
|
|||||||
btrfs_drew_write_unlock(&root->snapshot_lock);
|
btrfs_drew_write_unlock(&root->snapshot_lock);
|
||||||
btrfs_end_transaction(trans);
|
btrfs_end_transaction(trans);
|
||||||
} else {
|
} else {
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
|
|
||||||
if (btrfs_is_zoned(fs_info)) {
|
if (btrfs_is_zoned(fs_info)) {
|
||||||
ret = btrfs_wait_ordered_range(inode,
|
ret = btrfs_wait_ordered_range(inode,
|
||||||
@ -5222,7 +5255,7 @@ static struct btrfs_trans_handle *evict_refill_and_join(struct btrfs_root *root,
|
|||||||
|
|
||||||
void btrfs_evict_inode(struct inode *inode)
|
void btrfs_evict_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_block_rsv *rsv = NULL;
|
struct btrfs_block_rsv *rsv = NULL;
|
||||||
@ -5236,6 +5269,7 @@ void btrfs_evict_inode(struct inode *inode)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs_info = inode_to_fs_info(inode);
|
||||||
evict_inode_truncate_pages(inode);
|
evict_inode_truncate_pages(inode);
|
||||||
|
|
||||||
if (inode->i_nlink &&
|
if (inode->i_nlink &&
|
||||||
@ -5533,7 +5567,6 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
|
|||||||
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
|
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
|
||||||
BTRFS_I(inode)->location.offset = 0;
|
BTRFS_I(inode)->location.offset = 0;
|
||||||
BTRFS_I(inode)->root = btrfs_grab_root(args->root);
|
BTRFS_I(inode)->root = btrfs_grab_root(args->root);
|
||||||
BUG_ON(args->root && !BTRFS_I(inode)->root);
|
|
||||||
|
|
||||||
if (args->root && args->root == args->root->fs_info->tree_root &&
|
if (args->root && args->root == args->root->fs_info->tree_root &&
|
||||||
args->ino != BTRFS_BTREE_INODE_OBJECTID)
|
args->ino != BTRFS_BTREE_INODE_OBJECTID)
|
||||||
@ -5661,7 +5694,7 @@ static inline u8 btrfs_inode_type(struct inode *inode)
|
|||||||
|
|
||||||
struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
|
struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct btrfs_root *sub_root = root;
|
struct btrfs_root *sub_root = root;
|
||||||
@ -6200,7 +6233,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
|
|||||||
struct inode *dir = args->dir;
|
struct inode *dir = args->dir;
|
||||||
struct inode *inode = args->inode;
|
struct inode *inode = args->inode;
|
||||||
const struct fscrypt_str *name = args->orphan ? NULL : &args->fname.disk_name;
|
const struct fscrypt_str *name = args->orphan ? NULL : &args->fname.disk_name;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct btrfs_inode_item *inode_item;
|
struct btrfs_inode_item *inode_item;
|
||||||
struct btrfs_key *location;
|
struct btrfs_key *location;
|
||||||
@ -6522,7 +6555,7 @@ fail_dir_item:
|
|||||||
static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
|
static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct btrfs_new_inode_args new_inode_args = {
|
struct btrfs_new_inode_args new_inode_args = {
|
||||||
.dir = dir,
|
.dir = dir,
|
||||||
@ -6592,7 +6625,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|||||||
struct btrfs_trans_handle *trans = NULL;
|
struct btrfs_trans_handle *trans = NULL;
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct inode *inode = d_inode(old_dentry);
|
struct inode *inode = d_inode(old_dentry);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct fscrypt_name fname;
|
struct fscrypt_name fname;
|
||||||
u64 index;
|
u64 index;
|
||||||
int err;
|
int err;
|
||||||
@ -6756,7 +6789,6 @@ static int read_inline_extent(struct btrfs_inode *inode, struct btrfs_path *path
|
|||||||
*
|
*
|
||||||
* @inode: file to search in
|
* @inode: file to search in
|
||||||
* @page: page to read extent data into if the extent is inline
|
* @page: page to read extent data into if the extent is inline
|
||||||
* @pg_offset: offset into @page to copy to
|
|
||||||
* @start: file offset
|
* @start: file offset
|
||||||
* @len: length of range starting at @start
|
* @len: length of range starting at @start
|
||||||
*
|
*
|
||||||
@ -6770,8 +6802,7 @@ static int read_inline_extent(struct btrfs_inode *inode, struct btrfs_path *path
|
|||||||
* Return: ERR_PTR on error, non-NULL extent_map on success.
|
* Return: ERR_PTR on error, non-NULL extent_map on success.
|
||||||
*/
|
*/
|
||||||
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
|
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
|
||||||
struct page *page, size_t pg_offset,
|
struct page *page, u64 start, u64 len)
|
||||||
u64 start, u64 len)
|
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -6914,7 +6945,6 @@ next:
|
|||||||
* ensured by tree-checker and inline extent creation path.
|
* ensured by tree-checker and inline extent creation path.
|
||||||
* Thus all members representing file offsets should be zero.
|
* Thus all members representing file offsets should be zero.
|
||||||
*/
|
*/
|
||||||
ASSERT(pg_offset == 0);
|
|
||||||
ASSERT(extent_start == 0);
|
ASSERT(extent_start == 0);
|
||||||
ASSERT(em->start == 0);
|
ASSERT(em->start == 0);
|
||||||
|
|
||||||
@ -7078,7 +7108,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
|
|||||||
u64 *orig_start, u64 *orig_block_len,
|
u64 *orig_start, u64 *orig_block_len,
|
||||||
u64 *ram_bytes, bool nowait, bool strict)
|
u64 *ram_bytes, bool nowait, bool strict)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct can_nocow_file_extent_args nocow_args = { 0 };
|
struct can_nocow_file_extent_args nocow_args = { 0 };
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
int ret;
|
int ret;
|
||||||
@ -7317,7 +7347,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
|||||||
unsigned int iomap_flags)
|
unsigned int iomap_flags)
|
||||||
{
|
{
|
||||||
const bool nowait = (iomap_flags & IOMAP_NOWAIT);
|
const bool nowait = (iomap_flags & IOMAP_NOWAIT);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct extent_map *em = *map;
|
struct extent_map *em = *map;
|
||||||
int type;
|
int type;
|
||||||
u64 block_start, orig_start, orig_block_len, ram_bytes;
|
u64 block_start, orig_start, orig_block_len, ram_bytes;
|
||||||
@ -7457,7 +7487,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
|||||||
struct iomap *srcmap)
|
struct iomap *srcmap)
|
||||||
{
|
{
|
||||||
struct iomap_iter *iter = container_of(iomap, struct iomap_iter, iomap);
|
struct iomap_iter *iter = container_of(iomap, struct iomap_iter, iomap);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
struct btrfs_dio_data *dio_data = iter->private;
|
struct btrfs_dio_data *dio_data = iter->private;
|
||||||
@ -7555,7 +7585,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, start, len);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
goto unlock_err;
|
goto unlock_err;
|
||||||
@ -7903,7 +7933,7 @@ static void btrfs_readahead(struct readahead_control *rac)
|
|||||||
*/
|
*/
|
||||||
static void wait_subpage_spinlock(struct page *page)
|
static void wait_subpage_spinlock(struct page *page)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = page_to_fs_info(page);
|
||||||
struct folio *folio = page_folio(page);
|
struct folio *folio = page_folio(page);
|
||||||
struct btrfs_subpage *subpage;
|
struct btrfs_subpage *subpage;
|
||||||
|
|
||||||
@ -7970,7 +8000,7 @@ static int btrfs_migrate_folio(struct address_space *mapping,
|
|||||||
static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
|
static void btrfs_invalidate_folio(struct folio *folio, size_t offset,
|
||||||
size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
struct btrfs_inode *inode = BTRFS_I(folio->mapping->host);
|
struct btrfs_inode *inode = folio_to_inode(folio);
|
||||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||||
struct extent_io_tree *tree = &inode->io_tree;
|
struct extent_io_tree *tree = &inode->io_tree;
|
||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
@ -8154,7 +8184,7 @@ vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
|
|||||||
struct page *page = vmf->page;
|
struct page *page = vmf->page;
|
||||||
struct folio *folio = page_folio(page);
|
struct folio *folio = page_folio(page);
|
||||||
struct inode *inode = file_inode(vmf->vma->vm_file);
|
struct inode *inode = file_inode(vmf->vma->vm_file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
|
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
@ -8700,7 +8730,7 @@ int __init btrfs_init_cachep(void)
|
|||||||
{
|
{
|
||||||
btrfs_inode_cachep = kmem_cache_create("btrfs_inode",
|
btrfs_inode_cachep = kmem_cache_create("btrfs_inode",
|
||||||
sizeof(struct btrfs_inode), 0,
|
sizeof(struct btrfs_inode), 0,
|
||||||
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT,
|
SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,
|
||||||
init_once);
|
init_once);
|
||||||
if (!btrfs_inode_cachep)
|
if (!btrfs_inode_cachep)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -8723,7 +8753,7 @@ static int btrfs_getattr(struct mnt_idmap *idmap,
|
|||||||
u64 delalloc_bytes;
|
u64 delalloc_bytes;
|
||||||
u64 inode_bytes;
|
u64 inode_bytes;
|
||||||
struct inode *inode = d_inode(path->dentry);
|
struct inode *inode = d_inode(path->dentry);
|
||||||
u32 blocksize = inode->i_sb->s_blocksize;
|
u32 blocksize = btrfs_sb(inode->i_sb)->sectorsize;
|
||||||
u32 bi_flags = BTRFS_I(inode)->flags;
|
u32 bi_flags = BTRFS_I(inode)->flags;
|
||||||
u32 bi_ro_flags = BTRFS_I(inode)->ro_flags;
|
u32 bi_ro_flags = BTRFS_I(inode)->ro_flags;
|
||||||
|
|
||||||
@ -8763,7 +8793,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
|
|||||||
struct inode *new_dir,
|
struct inode *new_dir,
|
||||||
struct dentry *new_dentry)
|
struct dentry *new_dentry)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(old_dir);
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
unsigned int trans_num_items;
|
unsigned int trans_num_items;
|
||||||
struct btrfs_root *root = BTRFS_I(old_dir)->root;
|
struct btrfs_root *root = BTRFS_I(old_dir)->root;
|
||||||
@ -9015,7 +9045,7 @@ static int btrfs_rename(struct mnt_idmap *idmap,
|
|||||||
struct inode *new_dir, struct dentry *new_dentry,
|
struct inode *new_dir, struct dentry *new_dentry,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(old_dir);
|
||||||
struct btrfs_new_inode_args whiteout_args = {
|
struct btrfs_new_inode_args whiteout_args = {
|
||||||
.dir = old_dir,
|
.dir = old_dir,
|
||||||
.dentry = old_dentry,
|
.dentry = old_dentry,
|
||||||
@ -9457,7 +9487,7 @@ out:
|
|||||||
static int btrfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
static int btrfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
struct dentry *dentry, const char *symname)
|
struct dentry *dentry, const char *symname)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
@ -9638,7 +9668,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
|||||||
loff_t actual_len, u64 *alloc_hint,
|
loff_t actual_len, u64 *alloc_hint,
|
||||||
struct btrfs_trans_handle *trans)
|
struct btrfs_trans_handle *trans)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct extent_map *em;
|
struct extent_map *em;
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_key ins;
|
struct btrfs_key ins;
|
||||||
@ -9790,7 +9820,7 @@ static int btrfs_permission(struct mnt_idmap *idmap,
|
|||||||
static int btrfs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
|
static int btrfs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
|
||||||
struct file *file, umode_t mode)
|
struct file *file, umode_t mode)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
@ -10164,7 +10194,7 @@ ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
|
|||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
em = btrfs_get_extent(inode, NULL, 0, start, lockend - start + 1);
|
em = btrfs_get_extent(inode, NULL, start, lockend - start + 1);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
goto out_unlock_extent;
|
goto out_unlock_extent;
|
||||||
@ -10744,7 +10774,7 @@ static int btrfs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
|||||||
struct btrfs_block_group *bg;
|
struct btrfs_block_group *bg;
|
||||||
u64 len = isize - start;
|
u64 len = isize - start;
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, start, len);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
goto out;
|
goto out;
|
||||||
|
120
fs/btrfs/ioctl.c
120
fs/btrfs/ioctl.c
@ -34,11 +34,9 @@
|
|||||||
#include "export.h"
|
#include "export.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "backref.h"
|
#include "backref.h"
|
||||||
#include "rcu-string.h"
|
|
||||||
#include "send.h"
|
#include "send.h"
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
#include "props.h"
|
#include "props.h"
|
||||||
@ -47,9 +45,7 @@
|
|||||||
#include "tree-log.h"
|
#include "tree-log.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "delalloc-space.h"
|
|
||||||
#include "block-group.h"
|
#include "block-group.h"
|
||||||
#include "subpage.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "extent-tree.h"
|
#include "extent-tree.h"
|
||||||
@ -231,6 +227,20 @@ static int check_fsflags_compatible(struct btrfs_fs_info *fs_info,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btrfs_check_ioctl_vol_args_path(const struct btrfs_ioctl_vol_args *vol_args)
|
||||||
|
{
|
||||||
|
if (memchr(vol_args->name, 0, sizeof(vol_args->name)) == NULL)
|
||||||
|
return -ENAMETOOLONG;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int btrfs_check_ioctl_vol_args2_subvol_name(const struct btrfs_ioctl_vol_args_v2 *vol_args2)
|
||||||
|
{
|
||||||
|
if (memchr(vol_args2->name, 0, sizeof(vol_args2->name)) == NULL)
|
||||||
|
return -ENAMETOOLONG;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set flags/xflags from the internal inode flags. The remaining items of
|
* Set flags/xflags from the internal inode flags. The remaining items of
|
||||||
* fsxattr are zeroed.
|
* fsxattr are zeroed.
|
||||||
@ -247,7 +257,7 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
|||||||
struct dentry *dentry, struct fileattr *fa)
|
struct dentry *dentry, struct fileattr *fa)
|
||||||
{
|
{
|
||||||
struct inode *inode = d_inode(dentry);
|
struct inode *inode = d_inode(dentry);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_inode *binode = BTRFS_I(inode);
|
struct btrfs_inode *binode = BTRFS_I(inode);
|
||||||
struct btrfs_root *root = binode->root;
|
struct btrfs_root *root = binode->root;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
@ -528,7 +538,7 @@ static noinline int btrfs_ioctl_fitrim(struct btrfs_fs_info *fs_info,
|
|||||||
* block group is in the logical address space, which can be any
|
* block group is in the logical address space, which can be any
|
||||||
* sectorsize aligned bytenr in the range [0, U64_MAX].
|
* sectorsize aligned bytenr in the range [0, U64_MAX].
|
||||||
*/
|
*/
|
||||||
if (range.len < fs_info->sb->s_blocksize)
|
if (range.len < fs_info->sectorsize)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
range.minlen = max(range.minlen, minlen);
|
range.minlen = max(range.minlen, minlen);
|
||||||
@ -584,7 +594,7 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
|
|||||||
struct inode *dir, struct dentry *dentry,
|
struct inode *dir, struct dentry *dentry,
|
||||||
struct btrfs_qgroup_inherit *inherit)
|
struct btrfs_qgroup_inherit *inherit)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_root_item *root_item;
|
struct btrfs_root_item *root_item;
|
||||||
@ -776,7 +786,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
|
|||||||
struct dentry *dentry, bool readonly,
|
struct dentry *dentry, bool readonly,
|
||||||
struct btrfs_qgroup_inherit *inherit)
|
struct btrfs_qgroup_inherit *inherit)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct btrfs_pending_snapshot *pending_snapshot;
|
struct btrfs_pending_snapshot *pending_snapshot;
|
||||||
unsigned int trans_num_items;
|
unsigned int trans_num_items;
|
||||||
@ -910,7 +920,9 @@ static int btrfs_may_delete(struct mnt_idmap *idmap,
|
|||||||
if (d_really_is_negative(victim))
|
if (d_really_is_negative(victim))
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
BUG_ON(d_inode(victim->d_parent) != dir);
|
/* The @victim is not inside @dir. */
|
||||||
|
if (d_inode(victim->d_parent) != dir)
|
||||||
|
return -EINVAL;
|
||||||
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
|
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
|
||||||
|
|
||||||
error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
|
error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC);
|
||||||
@ -962,7 +974,7 @@ static noinline int btrfs_mksubvol(const struct path *parent,
|
|||||||
struct btrfs_qgroup_inherit *inherit)
|
struct btrfs_qgroup_inherit *inherit)
|
||||||
{
|
{
|
||||||
struct inode *dir = d_inode(parent->dentry);
|
struct inode *dir = d_inode(parent->dentry);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct fscrypt_str name_str = FSTR_INIT((char *)name, namelen);
|
struct fscrypt_str name_str = FSTR_INIT((char *)name, namelen);
|
||||||
int error;
|
int error;
|
||||||
@ -1097,7 +1109,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
|||||||
{
|
{
|
||||||
BTRFS_DEV_LOOKUP_ARGS(args);
|
BTRFS_DEV_LOOKUP_ARGS(args);
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
u64 new_size;
|
u64 new_size;
|
||||||
u64 old_size;
|
u64 old_size;
|
||||||
u64 devid = 1;
|
u64 devid = 1;
|
||||||
@ -1128,7 +1140,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
|||||||
ret = PTR_ERR(vol_args);
|
ret = PTR_ERR(vol_args);
|
||||||
goto out_drop;
|
goto out_drop;
|
||||||
}
|
}
|
||||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args_path(vol_args);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
sizestr = vol_args->name;
|
sizestr = vol_args->name;
|
||||||
cancel = (strcmp("cancel", sizestr) == 0);
|
cancel = (strcmp("cancel", sizestr) == 0);
|
||||||
ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_RESIZE, cancel);
|
ret = exclop_start_or_cancel_reloc(fs_info, BTRFS_EXCLOP_RESIZE, cancel);
|
||||||
@ -1328,12 +1343,15 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
|
|||||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||||
if (IS_ERR(vol_args))
|
if (IS_ERR(vol_args))
|
||||||
return PTR_ERR(vol_args);
|
return PTR_ERR(vol_args);
|
||||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args_path(vol_args);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
ret = __btrfs_ioctl_snap_create(file, file_mnt_idmap(file),
|
ret = __btrfs_ioctl_snap_create(file, file_mnt_idmap(file),
|
||||||
vol_args->name, vol_args->fd, subvol,
|
vol_args->name, vol_args->fd, subvol,
|
||||||
false, NULL);
|
false, NULL);
|
||||||
|
|
||||||
|
out:
|
||||||
kfree(vol_args);
|
kfree(vol_args);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1352,7 +1370,9 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
|
|||||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||||
if (IS_ERR(vol_args))
|
if (IS_ERR(vol_args))
|
||||||
return PTR_ERR(vol_args);
|
return PTR_ERR(vol_args);
|
||||||
vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args2_subvol_name(vol_args);
|
||||||
|
if (ret < 0)
|
||||||
|
goto free_args;
|
||||||
|
|
||||||
if (vol_args->flags & ~BTRFS_SUBVOL_CREATE_ARGS_MASK) {
|
if (vol_args->flags & ~BTRFS_SUBVOL_CREATE_ARGS_MASK) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
@ -1362,7 +1382,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
|
|||||||
if (vol_args->flags & BTRFS_SUBVOL_RDONLY)
|
if (vol_args->flags & BTRFS_SUBVOL_RDONLY)
|
||||||
readonly = true;
|
readonly = true;
|
||||||
if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
|
if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) {
|
||||||
u64 nums;
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(file_inode(file));
|
||||||
|
|
||||||
if (vol_args->size < sizeof(*inherit) ||
|
if (vol_args->size < sizeof(*inherit) ||
|
||||||
vol_args->size > PAGE_SIZE) {
|
vol_args->size > PAGE_SIZE) {
|
||||||
@ -1375,19 +1395,9 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file,
|
|||||||
goto free_args;
|
goto free_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inherit->num_qgroups > PAGE_SIZE ||
|
ret = btrfs_qgroup_check_inherit(fs_info, inherit, vol_args->size);
|
||||||
inherit->num_ref_copies > PAGE_SIZE ||
|
if (ret < 0)
|
||||||
inherit->num_excl_copies > PAGE_SIZE) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto free_inherit;
|
goto free_inherit;
|
||||||
}
|
|
||||||
|
|
||||||
nums = inherit->num_qgroups + 2 * inherit->num_ref_copies +
|
|
||||||
2 * inherit->num_excl_copies;
|
|
||||||
if (vol_args->size != struct_size(inherit, qgroups, nums)) {
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto free_inherit;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = __btrfs_ioctl_snap_create(file, file_mnt_idmap(file),
|
ret = __btrfs_ioctl_snap_create(file, file_mnt_idmap(file),
|
||||||
@ -1405,7 +1415,7 @@ free_args:
|
|||||||
static noinline int btrfs_ioctl_subvol_getflags(struct inode *inode,
|
static noinline int btrfs_ioctl_subvol_getflags(struct inode *inode,
|
||||||
void __user *arg)
|
void __user *arg)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u64 flags = 0;
|
u64 flags = 0;
|
||||||
@ -1428,7 +1438,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
|
|||||||
void __user *arg)
|
void __user *arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
u64 root_flags;
|
u64 root_flags;
|
||||||
@ -1675,7 +1685,7 @@ static noinline int search_ioctl(struct inode *inode,
|
|||||||
u64 *buf_size,
|
u64 *buf_size,
|
||||||
char __user *ubuf)
|
char __user *ubuf)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
@ -2346,9 +2356,9 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
|||||||
bool destroy_v2)
|
bool destroy_v2)
|
||||||
{
|
{
|
||||||
struct dentry *parent = file->f_path.dentry;
|
struct dentry *parent = file->f_path.dentry;
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(parent->d_sb);
|
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct inode *dir = d_inode(parent);
|
struct inode *dir = d_inode(parent);
|
||||||
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dir);
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||||
struct btrfs_root *dest = NULL;
|
struct btrfs_root *dest = NULL;
|
||||||
@ -2382,7 +2392,9 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
|||||||
* name, same as v1 currently does.
|
* name, same as v1 currently does.
|
||||||
*/
|
*/
|
||||||
if (!(vol_args2->flags & BTRFS_SUBVOL_SPEC_BY_ID)) {
|
if (!(vol_args2->flags & BTRFS_SUBVOL_SPEC_BY_ID)) {
|
||||||
vol_args2->name[BTRFS_SUBVOL_NAME_MAX] = 0;
|
err = btrfs_check_ioctl_vol_args2_subvol_name(vol_args2);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
subvol_name = vol_args2->name;
|
subvol_name = vol_args2->name;
|
||||||
|
|
||||||
err = mnt_want_write_file(file);
|
err = mnt_want_write_file(file);
|
||||||
@ -2466,7 +2478,10 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
|||||||
if (IS_ERR(vol_args))
|
if (IS_ERR(vol_args))
|
||||||
return PTR_ERR(vol_args);
|
return PTR_ERR(vol_args);
|
||||||
|
|
||||||
vol_args->name[BTRFS_PATH_NAME_MAX] = 0;
|
err = btrfs_check_ioctl_vol_args_path(vol_args);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
subvol_name = vol_args->name;
|
subvol_name = vol_args->name;
|
||||||
|
|
||||||
err = mnt_want_write_file(file);
|
err = mnt_want_write_file(file);
|
||||||
@ -2677,12 +2692,16 @@ static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args_path(vol_args);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
ret = btrfs_init_new_device(fs_info, vol_args->name);
|
ret = btrfs_init_new_device(fs_info, vol_args->name);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
btrfs_info(fs_info, "disk added %s", vol_args->name);
|
btrfs_info(fs_info, "disk added %s", vol_args->name);
|
||||||
|
|
||||||
|
out_free:
|
||||||
kfree(vol_args);
|
kfree(vol_args);
|
||||||
out:
|
out:
|
||||||
if (restore_op)
|
if (restore_op)
|
||||||
@ -2696,7 +2715,7 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
|
|||||||
{
|
{
|
||||||
BTRFS_DEV_LOOKUP_ARGS(args);
|
BTRFS_DEV_LOOKUP_ARGS(args);
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_ioctl_vol_args_v2 *vol_args;
|
struct btrfs_ioctl_vol_args_v2 *vol_args;
|
||||||
struct file *bdev_file = NULL;
|
struct file *bdev_file = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -2714,7 +2733,10 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args2_subvol_name(vol_args);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) {
|
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) {
|
||||||
args.devid = vol_args->devid;
|
args.devid = vol_args->devid;
|
||||||
} else if (!strcmp("cancel", vol_args->name)) {
|
} else if (!strcmp("cancel", vol_args->name)) {
|
||||||
@ -2761,7 +2783,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
|
|||||||
{
|
{
|
||||||
BTRFS_DEV_LOOKUP_ARGS(args);
|
BTRFS_DEV_LOOKUP_ARGS(args);
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_ioctl_vol_args *vol_args;
|
struct btrfs_ioctl_vol_args *vol_args;
|
||||||
struct file *bdev_file = NULL;
|
struct file *bdev_file = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -2774,7 +2796,10 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
|
|||||||
if (IS_ERR(vol_args))
|
if (IS_ERR(vol_args))
|
||||||
return PTR_ERR(vol_args);
|
return PTR_ERR(vol_args);
|
||||||
|
|
||||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args_path(vol_args);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
if (!strcmp("cancel", vol_args->name)) {
|
if (!strcmp("cancel", vol_args->name)) {
|
||||||
cancel = true;
|
cancel = true;
|
||||||
} else {
|
} else {
|
||||||
@ -2801,6 +2826,7 @@ static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg)
|
|||||||
fput(bdev_file);
|
fput(bdev_file);
|
||||||
out:
|
out:
|
||||||
btrfs_put_dev_args_from_path(&args);
|
btrfs_put_dev_args_from_path(&args);
|
||||||
|
out_free:
|
||||||
kfree(vol_args);
|
kfree(vol_args);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -2904,7 +2930,7 @@ out:
|
|||||||
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
|
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_root *new_root;
|
struct btrfs_root *new_root;
|
||||||
struct btrfs_dir_item *di;
|
struct btrfs_dir_item *di;
|
||||||
@ -3178,7 +3204,7 @@ static noinline long btrfs_ioctl_wait_sync(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
static long btrfs_ioctl_scrub(struct file *file, void __user *arg)
|
static long btrfs_ioctl_scrub(struct file *file, void __user *arg)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(file_inode(file)->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(file_inode(file));
|
||||||
struct btrfs_ioctl_scrub_args *sa;
|
struct btrfs_ioctl_scrub_args *sa;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -3696,7 +3722,7 @@ out:
|
|||||||
static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
|
static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_ioctl_quota_ctl_args *sa;
|
struct btrfs_ioctl_quota_ctl_args *sa;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -3738,7 +3764,7 @@ drop_write:
|
|||||||
static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
|
static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_ioctl_qgroup_assign_args *sa;
|
struct btrfs_ioctl_qgroup_assign_args *sa;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
@ -3894,7 +3920,7 @@ drop_write:
|
|||||||
static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg)
|
static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_ioctl_quota_rescan_args *qsa;
|
struct btrfs_ioctl_quota_rescan_args *qsa;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -3958,7 +3984,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
|
|||||||
struct btrfs_ioctl_received_subvol_args *sa)
|
struct btrfs_ioctl_received_subvol_args *sa)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_root_item *root_item = &root->root_item;
|
struct btrfs_root_item *root_item = &root->root_item;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
@ -4146,7 +4172,7 @@ static int btrfs_ioctl_get_fslabel(struct btrfs_fs_info *fs_info,
|
|||||||
static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
|
static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_super_block *super_block = fs_info->super_copy;
|
struct btrfs_super_block *super_block = fs_info->super_copy;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
@ -4289,7 +4315,7 @@ check_feature_bits(fs_info, FEAT_##mask_base, change_mask, flags, \
|
|||||||
static int btrfs_ioctl_set_features(struct file *file, void __user *arg)
|
static int btrfs_ioctl_set_features(struct file *file, void __user *arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_super_block *super_block = fs_info->super_copy;
|
struct btrfs_super_block *super_block = fs_info->super_copy;
|
||||||
struct btrfs_ioctl_feature_flags flags[2];
|
struct btrfs_ioctl_feature_flags flags[2];
|
||||||
@ -4580,7 +4606,7 @@ long btrfs_ioctl(struct file *file, unsigned int
|
|||||||
cmd, unsigned long arg)
|
cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
|
|
||||||
|
@ -3,6 +3,15 @@
|
|||||||
#ifndef BTRFS_IOCTL_H
|
#ifndef BTRFS_IOCTL_H
|
||||||
#define BTRFS_IOCTL_H
|
#define BTRFS_IOCTL_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct file;
|
||||||
|
struct dentry;
|
||||||
|
struct mnt_idmap;
|
||||||
|
struct fileattr;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_ioctl_balance_args;
|
||||||
|
|
||||||
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||||
long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||||
int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
|
int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "accessors.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lockdep class keys for extent_buffer->lock's in this root. For a given
|
* Lockdep class keys for extent_buffer->lock's in this root. For a given
|
||||||
@ -85,7 +84,7 @@ void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int
|
|||||||
{
|
{
|
||||||
struct btrfs_lockdep_keyset *ks;
|
struct btrfs_lockdep_keyset *ks;
|
||||||
|
|
||||||
BUG_ON(level >= ARRAY_SIZE(ks->keys));
|
ASSERT(level < ARRAY_SIZE(ks->keys));
|
||||||
|
|
||||||
/* Find the matching keyset, id 0 is the default entry */
|
/* Find the matching keyset, id 0 is the default entry */
|
||||||
for (ks = btrfs_lockdep_keysets; ks->id; ks++)
|
for (ks = btrfs_lockdep_keysets; ks->id; ks++)
|
||||||
|
@ -8,8 +8,14 @@
|
|||||||
|
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
#include <linux/percpu_counter.h>
|
#include <linux/percpu_counter.h>
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
|
#include "locking.h"
|
||||||
|
|
||||||
|
struct extent_buffer;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_root;
|
||||||
|
|
||||||
#define BTRFS_WRITE_LOCK 1
|
#define BTRFS_WRITE_LOCK 1
|
||||||
#define BTRFS_READ_LOCK 2
|
#define BTRFS_READ_LOCK 2
|
||||||
@ -157,8 +163,6 @@ enum btrfs_lockdep_trans_states {
|
|||||||
static_assert(BTRFS_NESTING_MAX <= MAX_LOCKDEP_SUBCLASSES,
|
static_assert(BTRFS_NESTING_MAX <= MAX_LOCKDEP_SUBCLASSES,
|
||||||
"too many lock subclasses defined");
|
"too many lock subclasses defined");
|
||||||
|
|
||||||
struct btrfs_path;
|
|
||||||
|
|
||||||
void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest);
|
void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest);
|
||||||
void btrfs_tree_lock(struct extent_buffer *eb);
|
void btrfs_tree_lock(struct extent_buffer *eb);
|
||||||
void btrfs_tree_unlock(struct extent_buffer *eb);
|
void btrfs_tree_unlock(struct extent_buffer *eb);
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
#ifndef BTRFS_LRU_CACHE_H
|
#ifndef BTRFS_LRU_CACHE_H
|
||||||
#define BTRFS_LRU_CACHE_H
|
#define BTRFS_LRU_CACHE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include <linux/maple_tree.h>
|
#include <linux/maple_tree.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include "lru_cache.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A cache entry. This is meant to be embedded in a structure of a user of
|
* A cache entry. This is meant to be embedded in a structure of a user of
|
||||||
@ -50,11 +52,6 @@ struct btrfs_lru_cache {
|
|||||||
#define btrfs_lru_cache_for_each_entry_safe(cache, entry, tmp) \
|
#define btrfs_lru_cache_for_each_entry_safe(cache, entry, tmp) \
|
||||||
list_for_each_entry_safe_reverse((entry), (tmp), &(cache)->lru_list, lru_list)
|
list_for_each_entry_safe_reverse((entry), (tmp), &(cache)->lru_list, lru_list)
|
||||||
|
|
||||||
static inline unsigned int btrfs_lru_cache_size(const struct btrfs_lru_cache *cache)
|
|
||||||
{
|
|
||||||
return cache->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct btrfs_lru_cache_entry *btrfs_lru_cache_lru_entry(
|
static inline struct btrfs_lru_cache_entry *btrfs_lru_cache_lru_entry(
|
||||||
struct btrfs_lru_cache *cache)
|
struct btrfs_lru_cache *cache)
|
||||||
{
|
{
|
||||||
|
@ -214,7 +214,7 @@ int lzo_compress_pages(struct list_head *ws, struct address_space *mapping,
|
|||||||
unsigned long *total_in, unsigned long *total_out)
|
unsigned long *total_in, unsigned long *total_out)
|
||||||
{
|
{
|
||||||
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
const u32 sectorsize = btrfs_sb(mapping->host->i_sb)->sectorsize;
|
const u32 sectorsize = inode_to_fs_info(mapping->host)->sectorsize;
|
||||||
struct page *page_in = NULL;
|
struct page *page_in = NULL;
|
||||||
char *sizes_ptr;
|
char *sizes_ptr;
|
||||||
const unsigned long max_nr_page = *out_pages;
|
const unsigned long max_nr_page = *out_pages;
|
||||||
@ -429,7 +429,7 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
|
|||||||
size_t destlen)
|
size_t destlen)
|
||||||
{
|
{
|
||||||
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
struct workspace *workspace = list_entry(ws, struct workspace, list);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dest_page->mapping->host->i_sb);
|
struct btrfs_fs_info *fs_info = page_to_fs_info(dest_page);
|
||||||
const u32 sectorsize = fs_info->sectorsize;
|
const u32 sectorsize = fs_info->sectorsize;
|
||||||
size_t in_len;
|
size_t in_len;
|
||||||
size_t out_len;
|
size_t out_len;
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "discard.h"
|
#include "discard.h"
|
||||||
#include "transaction.h"
|
|
||||||
#include "space-info.h"
|
|
||||||
#include "super.h"
|
#include "super.h"
|
||||||
|
|
||||||
#ifdef CONFIG_PRINTK
|
#ifdef CONFIG_PRINTK
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#ifndef BTRFS_MISC_H
|
#ifndef BTRFS_MISC_H
|
||||||
#define BTRFS_MISC_H
|
#define BTRFS_MISC_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/bitmap.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "subpage.h"
|
#include "subpage.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "super.h"
|
|
||||||
|
|
||||||
static struct kmem_cache *btrfs_ordered_extent_cache;
|
static struct kmem_cache *btrfs_ordered_extent_cache;
|
||||||
|
|
||||||
@ -1236,10 +1235,7 @@ struct btrfs_ordered_extent *btrfs_split_ordered_extent(
|
|||||||
|
|
||||||
int __init ordered_data_init(void)
|
int __init ordered_data_init(void)
|
||||||
{
|
{
|
||||||
btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent",
|
btrfs_ordered_extent_cache = KMEM_CACHE(btrfs_ordered_extent, 0);
|
||||||
sizeof(struct btrfs_ordered_extent), 0,
|
|
||||||
SLAB_MEM_SPREAD,
|
|
||||||
NULL);
|
|
||||||
if (!btrfs_ordered_extent_cache)
|
if (!btrfs_ordered_extent_cache)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -6,6 +6,21 @@
|
|||||||
#ifndef BTRFS_ORDERED_DATA_H
|
#ifndef BTRFS_ORDERED_DATA_H
|
||||||
#define BTRFS_ORDERED_DATA_H
|
#define BTRFS_ORDERED_DATA_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include "async-thread.h"
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct page;
|
||||||
|
struct extent_state;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
struct btrfs_ordered_sum {
|
struct btrfs_ordered_sum {
|
||||||
/*
|
/*
|
||||||
* Logical start address and length for of the blocks covered by
|
* Logical start address and length for of the blocks covered by
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
|
||||||
#include "orphan.h"
|
#include "orphan.h"
|
||||||
|
|
||||||
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
|
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
#ifndef BTRFS_ORPHAN_H
|
#ifndef BTRFS_ORPHAN_H
|
||||||
#define BTRFS_ORPHAN_H
|
#define BTRFS_ORPHAN_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_root;
|
||||||
|
|
||||||
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
|
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, u64 offset);
|
struct btrfs_root *root, u64 offset);
|
||||||
int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
|
int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
/* Buffer size to contain tree name and possibly additional data (offset) */
|
/* Buffer size to contain tree name and possibly additional data (offset) */
|
||||||
#define BTRFS_ROOT_NAME_BUF_LEN 48
|
#define BTRFS_ROOT_NAME_BUF_LEN 48
|
||||||
|
|
||||||
|
struct extent_buffer;
|
||||||
|
struct btrfs_key;
|
||||||
|
|
||||||
void btrfs_print_leaf(const struct extent_buffer *l);
|
void btrfs_print_leaf(const struct extent_buffer *l);
|
||||||
void btrfs_print_tree(const struct extent_buffer *c, bool follow);
|
void btrfs_print_tree(const struct extent_buffer *c, bool follow);
|
||||||
const char *btrfs_root_name(const struct btrfs_key *key, char *buf);
|
const char *btrfs_root_name(const struct btrfs_key *key, char *buf);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
|
#include <linux/xattr.h>
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "props.h"
|
#include "props.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
@ -302,7 +303,7 @@ static int prop_compression_validate(const struct btrfs_inode *inode,
|
|||||||
static int prop_compression_apply(struct inode *inode, const char *value,
|
static int prop_compression_apply(struct inode *inode, const char *value,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
/* Reset to defaults */
|
/* Reset to defaults */
|
||||||
|
@ -6,7 +6,12 @@
|
|||||||
#ifndef BTRFS_PROPS_H
|
#ifndef BTRFS_PROPS_H
|
||||||
#define BTRFS_PROPS_H
|
#define BTRFS_PROPS_H
|
||||||
|
|
||||||
#include "ctree.h"
|
#include <linux/compiler_types.h>
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct btrfs_inode;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
int __init btrfs_props_init(void);
|
int __init btrfs_props_init(void);
|
||||||
|
|
||||||
|
@ -1324,7 +1324,7 @@ static int flush_reservations(struct btrfs_fs_info *fs_info)
|
|||||||
trans = btrfs_join_transaction(fs_info->tree_root);
|
trans = btrfs_join_transaction(fs_info->tree_root);
|
||||||
if (IS_ERR(trans))
|
if (IS_ERR(trans))
|
||||||
return PTR_ERR(trans);
|
return PTR_ERR(trans);
|
||||||
btrfs_commit_transaction(trans);
|
ret = btrfs_commit_transaction(trans);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -2505,8 +2505,8 @@ int btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans,
|
|||||||
struct extent_buffer *eb = root_eb;
|
struct extent_buffer *eb = root_eb;
|
||||||
struct btrfs_path *path = NULL;
|
struct btrfs_path *path = NULL;
|
||||||
|
|
||||||
BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL);
|
ASSERT(0 <= root_level && root_level < BTRFS_MAX_LEVEL);
|
||||||
BUG_ON(root_eb == NULL);
|
ASSERT(root_eb != NULL);
|
||||||
|
|
||||||
if (!btrfs_qgroup_full_accounting(fs_info))
|
if (!btrfs_qgroup_full_accounting(fs_info))
|
||||||
return 0;
|
return 0;
|
||||||
@ -2861,8 +2861,6 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
|
|||||||
if (nr_old_roots == 0 && nr_new_roots == 0)
|
if (nr_old_roots == 0 && nr_new_roots == 0)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
BUG_ON(!fs_info->quota_root);
|
|
||||||
|
|
||||||
trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr,
|
trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr,
|
||||||
num_bytes, nr_old_roots, nr_new_roots);
|
num_bytes, nr_old_roots, nr_new_roots);
|
||||||
|
|
||||||
@ -2959,11 +2957,6 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
|
|||||||
ctx.roots = NULL;
|
ctx.roots = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the reserved data space */
|
|
||||||
btrfs_qgroup_free_refroot(fs_info,
|
|
||||||
record->data_rsv_refroot,
|
|
||||||
record->data_rsv,
|
|
||||||
BTRFS_QGROUP_RSV_DATA);
|
|
||||||
/*
|
/*
|
||||||
* Use BTRFS_SEQ_LAST as time_seq to do special search,
|
* Use BTRFS_SEQ_LAST as time_seq to do special search,
|
||||||
* which doesn't lock tree or delayed_refs and search
|
* which doesn't lock tree or delayed_refs and search
|
||||||
@ -2987,6 +2980,11 @@ int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans)
|
|||||||
record->old_roots = NULL;
|
record->old_roots = NULL;
|
||||||
new_roots = NULL;
|
new_roots = NULL;
|
||||||
}
|
}
|
||||||
|
/* Free the reserved data space */
|
||||||
|
btrfs_qgroup_free_refroot(fs_info,
|
||||||
|
record->data_rsv_refroot,
|
||||||
|
record->data_rsv,
|
||||||
|
BTRFS_QGROUP_RSV_DATA);
|
||||||
cleanup:
|
cleanup:
|
||||||
ulist_free(record->old_roots);
|
ulist_free(record->old_roots);
|
||||||
ulist_free(new_roots);
|
ulist_free(new_roots);
|
||||||
@ -3048,6 +3046,57 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btrfs_qgroup_check_inherit(struct btrfs_fs_info *fs_info,
|
||||||
|
struct btrfs_qgroup_inherit *inherit,
|
||||||
|
size_t size)
|
||||||
|
{
|
||||||
|
if (inherit->flags & ~BTRFS_QGROUP_INHERIT_FLAGS_SUPP)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (size < sizeof(*inherit) || size > PAGE_SIZE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In the past we allowed btrfs_qgroup_inherit to specify to copy
|
||||||
|
* rfer/excl numbers directly from other qgroups. This behavior has
|
||||||
|
* been disabled in userspace for a very long time, but here we should
|
||||||
|
* also disable it in kernel, as this behavior is known to mark qgroup
|
||||||
|
* inconsistent, and a rescan would wipe out the changes anyway.
|
||||||
|
*
|
||||||
|
* Reject any btrfs_qgroup_inherit with num_ref_copies or num_excl_copies.
|
||||||
|
*/
|
||||||
|
if (inherit->num_ref_copies > 0 || inherit->num_excl_copies > 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (inherit->num_qgroups > PAGE_SIZE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (size != struct_size(inherit, qgroups, inherit->num_qgroups))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now check all the remaining qgroups, they should all:
|
||||||
|
*
|
||||||
|
* - Exist
|
||||||
|
* - Be higher level qgroups.
|
||||||
|
*/
|
||||||
|
for (int i = 0; i < inherit->num_qgroups; i++) {
|
||||||
|
struct btrfs_qgroup *qgroup;
|
||||||
|
u64 qgroupid = inherit->qgroups[i];
|
||||||
|
|
||||||
|
if (btrfs_qgroup_level(qgroupid) == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock(&fs_info->qgroup_lock);
|
||||||
|
qgroup = find_qgroup_rb(fs_info, qgroupid);
|
||||||
|
if (!qgroup) {
|
||||||
|
spin_unlock(&fs_info->qgroup_lock);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
spin_unlock(&fs_info->qgroup_lock);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int qgroup_auto_inherit(struct btrfs_fs_info *fs_info,
|
static int qgroup_auto_inherit(struct btrfs_fs_info *fs_info,
|
||||||
u64 inode_rootid,
|
u64 inode_rootid,
|
||||||
struct btrfs_qgroup_inherit **inherit)
|
struct btrfs_qgroup_inherit **inherit)
|
||||||
@ -3089,6 +3138,62 @@ static int qgroup_auto_inherit(struct btrfs_fs_info *fs_info,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if we can skip rescan when inheriting qgroups. If @src has a single
|
||||||
|
* @parent, and that @parent is owning all its bytes exclusively, we can skip
|
||||||
|
* the full rescan, by just adding nodesize to the @parent's excl/rfer.
|
||||||
|
*
|
||||||
|
* Return <0 for fatal errors (like srcid/parentid has no qgroup).
|
||||||
|
* Return 0 if a quick inherit is done.
|
||||||
|
* Return >0 if a quick inherit is not possible, and a full rescan is needed.
|
||||||
|
*/
|
||||||
|
static int qgroup_snapshot_quick_inherit(struct btrfs_fs_info *fs_info,
|
||||||
|
u64 srcid, u64 parentid)
|
||||||
|
{
|
||||||
|
struct btrfs_qgroup *src;
|
||||||
|
struct btrfs_qgroup *parent;
|
||||||
|
struct btrfs_qgroup_list *list;
|
||||||
|
int nr_parents = 0;
|
||||||
|
|
||||||
|
src = find_qgroup_rb(fs_info, srcid);
|
||||||
|
if (!src)
|
||||||
|
return -ENOENT;
|
||||||
|
parent = find_qgroup_rb(fs_info, parentid);
|
||||||
|
if (!parent)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Source has no parent qgroup, but our new qgroup would have one.
|
||||||
|
* Qgroup numbers would become inconsistent.
|
||||||
|
*/
|
||||||
|
if (list_empty(&src->groups))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
list_for_each_entry(list, &src->groups, next_group) {
|
||||||
|
/* The parent is not the same, quick update is not possible. */
|
||||||
|
if (list->group->qgroupid != parentid)
|
||||||
|
return 1;
|
||||||
|
nr_parents++;
|
||||||
|
/*
|
||||||
|
* More than one parent qgroup, we can't be sure about accounting
|
||||||
|
* consistency.
|
||||||
|
*/
|
||||||
|
if (nr_parents > 1)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The parent is not exclusively owning all its bytes. We're not sure
|
||||||
|
* if the source has any bytes not fully owned by the parent.
|
||||||
|
*/
|
||||||
|
if (parent->excl != parent->rfer)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
parent->excl += fs_info->nodesize;
|
||||||
|
parent->rfer += fs_info->nodesize;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy the accounting information between qgroups. This is necessary
|
* Copy the accounting information between qgroups. This is necessary
|
||||||
* when a snapshot or a subvolume is created. Throwing an error will
|
* when a snapshot or a subvolume is created. Throwing an error will
|
||||||
@ -3257,6 +3362,13 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
|||||||
|
|
||||||
qgroup_dirty(fs_info, dstgroup);
|
qgroup_dirty(fs_info, dstgroup);
|
||||||
qgroup_dirty(fs_info, srcgroup);
|
qgroup_dirty(fs_info, srcgroup);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the source qgroup has parent but the new one doesn't,
|
||||||
|
* we need a full rescan.
|
||||||
|
*/
|
||||||
|
if (!inherit && !list_empty(&srcgroup->groups))
|
||||||
|
need_rescan = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inherit)
|
if (!inherit)
|
||||||
@ -3271,14 +3383,16 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
if (srcid) {
|
||||||
|
/* Check if we can do a quick inherit. */
|
||||||
|
ret = qgroup_snapshot_quick_inherit(fs_info, srcid, *i_qgroups);
|
||||||
|
if (ret < 0)
|
||||||
|
goto unlock;
|
||||||
|
if (ret > 0)
|
||||||
|
need_rescan = true;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
++i_qgroups;
|
++i_qgroups;
|
||||||
|
|
||||||
/*
|
|
||||||
* If we're doing a snapshot, and adding the snapshot to a new
|
|
||||||
* qgroup, the numbers are guaranteed to be incorrect.
|
|
||||||
*/
|
|
||||||
if (srcid)
|
|
||||||
need_rescan = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < inherit->num_ref_copies; ++i, i_qgroups += 2) {
|
for (i = 0; i < inherit->num_ref_copies; ++i, i_qgroups += 2) {
|
||||||
|
@ -6,12 +6,22 @@
|
|||||||
#ifndef BTRFS_QGROUP_H
|
#ifndef BTRFS_QGROUP_H
|
||||||
#define BTRFS_QGROUP_H
|
#define BTRFS_QGROUP_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
#include <linux/kobject.h>
|
#include <linux/kobject.h>
|
||||||
#include "ulist.h"
|
#include <linux/list.h>
|
||||||
#include "delayed-ref.h"
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
#include "misc.h"
|
|
||||||
|
struct extent_buffer;
|
||||||
|
struct extent_changeset;
|
||||||
|
struct btrfs_delayed_extent_op;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_ioctl_quota_ctl_args;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_delayed_ref_root;
|
||||||
|
struct btrfs_inode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Btrfs qgroup overview
|
* Btrfs qgroup overview
|
||||||
@ -321,7 +331,6 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid,
|
|||||||
struct btrfs_qgroup_limit *limit);
|
struct btrfs_qgroup_limit *limit);
|
||||||
int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info);
|
int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info);
|
||||||
void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info);
|
void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info);
|
||||||
struct btrfs_delayed_extent_op;
|
|
||||||
|
|
||||||
int btrfs_qgroup_trace_extent_nolock(
|
int btrfs_qgroup_trace_extent_nolock(
|
||||||
struct btrfs_fs_info *fs_info,
|
struct btrfs_fs_info *fs_info,
|
||||||
@ -341,6 +350,9 @@ int btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr,
|
|||||||
struct ulist *new_roots);
|
struct ulist *new_roots);
|
||||||
int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans);
|
int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans);
|
||||||
int btrfs_run_qgroups(struct btrfs_trans_handle *trans);
|
int btrfs_run_qgroups(struct btrfs_trans_handle *trans);
|
||||||
|
int btrfs_qgroup_check_inherit(struct btrfs_fs_info *fs_info,
|
||||||
|
struct btrfs_qgroup_inherit *inherit,
|
||||||
|
size_t size);
|
||||||
int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
|
||||||
u64 objectid, u64 inode_rootid,
|
u64 objectid, u64 inode_rootid,
|
||||||
struct btrfs_qgroup_inherit *inherit);
|
struct btrfs_qgroup_inherit *inherit);
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "raid-stripe-tree.h"
|
#include "raid-stripe-tree.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
#include "misc.h"
|
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
|
|
||||||
int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 length)
|
int btrfs_delete_raid_extent(struct btrfs_trans_handle *trans, u64 start, u64 length)
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
#ifndef BTRFS_RAID_STRIPE_TREE_H
|
#ifndef BTRFS_RAID_STRIPE_TREE_H
|
||||||
#define BTRFS_RAID_STRIPE_TREE_H
|
#define BTRFS_RAID_STRIPE_TREE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <uapi/linux/btrfs_tree.h>
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
#define BTRFS_RST_SUPP_BLOCK_GROUP_MASK (BTRFS_BLOCK_GROUP_DUP | \
|
#define BTRFS_RST_SUPP_BLOCK_GROUP_MASK (BTRFS_BLOCK_GROUP_DUP | \
|
||||||
BTRFS_BLOCK_GROUP_RAID1_MASK | \
|
BTRFS_BLOCK_GROUP_RAID1_MASK | \
|
||||||
BTRFS_BLOCK_GROUP_RAID0 | \
|
BTRFS_BLOCK_GROUP_RAID0 | \
|
||||||
@ -13,6 +17,7 @@
|
|||||||
|
|
||||||
struct btrfs_io_context;
|
struct btrfs_io_context;
|
||||||
struct btrfs_io_stripe;
|
struct btrfs_io_stripe;
|
||||||
|
struct btrfs_fs_info;
|
||||||
struct btrfs_ordered_extent;
|
struct btrfs_ordered_extent;
|
||||||
struct btrfs_trans_handle;
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include <linux/raid/xor.h>
|
#include <linux/raid/xor.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "misc.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
@ -918,6 +917,13 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
|
|||||||
*/
|
*/
|
||||||
ASSERT(stripe_nsectors <= BITS_PER_LONG);
|
ASSERT(stripe_nsectors <= BITS_PER_LONG);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Real stripes must be between 2 (2 disks RAID5, aka RAID1) and 256
|
||||||
|
* (limited by u8).
|
||||||
|
*/
|
||||||
|
ASSERT(real_stripes >= 2);
|
||||||
|
ASSERT(real_stripes <= U8_MAX);
|
||||||
|
|
||||||
rbio = kzalloc(sizeof(*rbio), GFP_NOFS);
|
rbio = kzalloc(sizeof(*rbio), GFP_NOFS);
|
||||||
if (!rbio)
|
if (!rbio)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
@ -955,6 +961,7 @@ static struct btrfs_raid_bio *alloc_rbio(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
ASSERT(btrfs_nr_parity_stripes(bioc->map_type));
|
ASSERT(btrfs_nr_parity_stripes(bioc->map_type));
|
||||||
rbio->nr_data = real_stripes - btrfs_nr_parity_stripes(bioc->map_type);
|
rbio->nr_data = real_stripes - btrfs_nr_parity_stripes(bioc->map_type);
|
||||||
|
ASSERT(rbio->nr_data > 0);
|
||||||
|
|
||||||
return rbio;
|
return rbio;
|
||||||
}
|
}
|
||||||
@ -1181,6 +1188,26 @@ static inline void bio_list_put(struct bio_list *bio_list)
|
|||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void assert_rbio(struct btrfs_raid_bio *rbio)
|
||||||
|
{
|
||||||
|
if (!IS_ENABLED(CONFIG_BTRFS_DEBUG) ||
|
||||||
|
!IS_ENABLED(CONFIG_BTRFS_ASSERT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At least two stripes (2 disks RAID5), and since real_stripes is U8,
|
||||||
|
* we won't go beyond 256 disks anyway.
|
||||||
|
*/
|
||||||
|
ASSERT(rbio->real_stripes >= 2);
|
||||||
|
ASSERT(rbio->nr_data > 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is another check to make sure nr data stripes is smaller
|
||||||
|
* than total stripes.
|
||||||
|
*/
|
||||||
|
ASSERT(rbio->nr_data < rbio->real_stripes);
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate PQ for one vertical stripe. */
|
/* Generate PQ for one vertical stripe. */
|
||||||
static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
|
static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
|
||||||
{
|
{
|
||||||
@ -1212,6 +1239,7 @@ static void generate_pq_vertical(struct btrfs_raid_bio *rbio, int sectornr)
|
|||||||
pointers[stripe++] = kmap_local_page(sector->page) +
|
pointers[stripe++] = kmap_local_page(sector->page) +
|
||||||
sector->pgoff;
|
sector->pgoff;
|
||||||
|
|
||||||
|
assert_rbio(rbio);
|
||||||
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
|
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
|
||||||
pointers);
|
pointers);
|
||||||
} else {
|
} else {
|
||||||
@ -2473,6 +2501,7 @@ static int finish_parity_scrub(struct btrfs_raid_bio *rbio)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (has_qstripe) {
|
if (has_qstripe) {
|
||||||
|
assert_rbio(rbio);
|
||||||
/* RAID6, call the library function to fill in our P/Q */
|
/* RAID6, call the library function to fill in our P/Q */
|
||||||
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
|
raid6_call.gen_syndrome(rbio->real_stripes, sectorsize,
|
||||||
pointers);
|
pointers);
|
||||||
|
@ -7,9 +7,18 @@
|
|||||||
#ifndef BTRFS_RAID56_H
|
#ifndef BTRFS_RAID56_H
|
||||||
#define BTRFS_RAID56_H
|
#define BTRFS_RAID56_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/bio.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
|
|
||||||
|
struct page;
|
||||||
|
struct sector_ptr;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
enum btrfs_rbio_ops {
|
enum btrfs_rbio_ops {
|
||||||
BTRFS_RBIO_WRITE,
|
BTRFS_RBIO_WRITE,
|
||||||
BTRFS_RBIO_READ_REBUILD,
|
BTRFS_RBIO_READ_REBUILD,
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
#ifndef BTRFS_RCU_STRING_H
|
#ifndef BTRFS_RCU_STRING_H
|
||||||
#define BTRFS_RCU_STRING_H
|
#define BTRFS_RCU_STRING_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/rcupdate.h>
|
||||||
|
#include <linux/printk.h>
|
||||||
|
|
||||||
struct rcu_string {
|
struct rcu_string {
|
||||||
struct rcu_head rcu;
|
struct rcu_head rcu;
|
||||||
char str[];
|
char str[];
|
||||||
|
@ -6,7 +6,16 @@
|
|||||||
#ifndef BTRFS_REF_VERIFY_H
|
#ifndef BTRFS_REF_VERIFY_H
|
||||||
#define BTRFS_REF_VERIFY_H
|
#define BTRFS_REF_VERIFY_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/rbtree_types.h>
|
||||||
|
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_ref;
|
||||||
|
|
||||||
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
|
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
|
||||||
|
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
int btrfs_build_ref_tree(struct btrfs_fs_info *fs_info);
|
int btrfs_build_ref_tree(struct btrfs_fs_info *fs_info);
|
||||||
void btrfs_free_ref_cache(struct btrfs_fs_info *fs_info);
|
void btrfs_free_ref_cache(struct btrfs_fs_info *fs_info);
|
||||||
int btrfs_ref_tree_mod(struct btrfs_fs_info *fs_info,
|
int btrfs_ref_tree_mod(struct btrfs_fs_info *fs_info,
|
||||||
|
@ -174,7 +174,7 @@ static int clone_copy_inline_extent(struct inode *dst,
|
|||||||
char *inline_data,
|
char *inline_data,
|
||||||
struct btrfs_trans_handle **trans_out)
|
struct btrfs_trans_handle **trans_out)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(dst->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(dst);
|
||||||
struct btrfs_root *root = BTRFS_I(dst)->root;
|
struct btrfs_root *root = BTRFS_I(dst)->root;
|
||||||
const u64 aligned_end = ALIGN(new_key->offset + datal,
|
const u64 aligned_end = ALIGN(new_key->offset + datal,
|
||||||
fs_info->sectorsize);
|
fs_info->sectorsize);
|
||||||
@ -337,7 +337,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
|
|||||||
const u64 off, const u64 olen, const u64 olen_aligned,
|
const u64 off, const u64 olen, const u64 olen_aligned,
|
||||||
const u64 destoff, int no_time_update)
|
const u64 destoff, int no_time_update)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
struct btrfs_path *path = NULL;
|
struct btrfs_path *path = NULL;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
@ -663,7 +663,7 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,
|
|||||||
struct inode *dst, u64 dst_loff)
|
struct inode *dst, u64 dst_loff)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = BTRFS_I(src)->root->fs_info;
|
struct btrfs_fs_info *fs_info = BTRFS_I(src)->root->fs_info;
|
||||||
const u64 bs = fs_info->sb->s_blocksize;
|
const u64 bs = fs_info->sectorsize;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -726,11 +726,11 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
|
|||||||
{
|
{
|
||||||
struct inode *inode = file_inode(file);
|
struct inode *inode = file_inode(file);
|
||||||
struct inode *src = file_inode(file_src);
|
struct inode *src = file_inode(file_src);
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
int ret;
|
int ret;
|
||||||
int wb_ret;
|
int wb_ret;
|
||||||
u64 len = olen;
|
u64 len = olen;
|
||||||
u64 bs = fs_info->sb->s_blocksize;
|
u64 bs = fs_info->sectorsize;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VFS's generic_remap_file_range_prep() protects us from cloning the
|
* VFS's generic_remap_file_range_prep() protects us from cloning the
|
||||||
@ -796,7 +796,7 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
|||||||
{
|
{
|
||||||
struct inode *inode_in = file_inode(file_in);
|
struct inode *inode_in = file_inode(file_in);
|
||||||
struct inode *inode_out = file_inode(file_out);
|
struct inode *inode_out = file_inode(file_out);
|
||||||
u64 bs = BTRFS_I(inode_out)->root->fs_info->sb->s_blocksize;
|
u64 bs = BTRFS_I(inode_out)->root->fs_info->sectorsize;
|
||||||
u64 wb_len;
|
u64 wb_len;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#ifndef BTRFS_REFLINK_H
|
#ifndef BTRFS_REFLINK_H
|
||||||
#define BTRFS_REFLINK_H
|
#define BTRFS_REFLINK_H
|
||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct file;
|
||||||
|
|
||||||
loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
|
loff_t btrfs_remap_file_range(struct file *file_in, loff_t pos_in,
|
||||||
struct file *file_out, loff_t pos_out,
|
struct file *file_out, loff_t pos_out,
|
||||||
|
@ -523,7 +523,8 @@ static noinline_for_stack struct btrfs_backref_node *build_backref_tree(
|
|||||||
if (handle_useless_nodes(rc, node))
|
if (handle_useless_nodes(rc, node))
|
||||||
node = NULL;
|
node = NULL;
|
||||||
out:
|
out:
|
||||||
btrfs_backref_iter_free(iter);
|
btrfs_free_path(iter->path);
|
||||||
|
kfree(iter);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
if (err) {
|
if (err) {
|
||||||
btrfs_backref_error_cleanup(cache, node);
|
btrfs_backref_error_cleanup(cache, node);
|
||||||
@ -2987,7 +2988,7 @@ static int relocate_one_page(struct inode *inode, struct file_ra_state *ra,
|
|||||||
const struct file_extent_cluster *cluster,
|
const struct file_extent_cluster *cluster,
|
||||||
int *cluster_nr, unsigned long page_index)
|
int *cluster_nr, unsigned long page_index)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||||
u64 offset = BTRFS_I(inode)->index_cnt;
|
u64 offset = BTRFS_I(inode)->index_cnt;
|
||||||
const unsigned long last_index = (cluster->end - offset) >> PAGE_SHIFT;
|
const unsigned long last_index = (cluster->end - offset) >> PAGE_SHIFT;
|
||||||
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
|
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
|
||||||
|
@ -3,6 +3,15 @@
|
|||||||
#ifndef BTRFS_RELOCATION_H
|
#ifndef BTRFS_RELOCATION_H
|
||||||
#define BTRFS_RELOCATION_H
|
#define BTRFS_RELOCATION_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct extent_buffer;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
struct btrfs_ordered_extent;
|
||||||
|
struct btrfs_pending_snapshot;
|
||||||
|
|
||||||
int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start);
|
int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start);
|
||||||
int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, struct btrfs_root *root);
|
int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, struct btrfs_root *root);
|
||||||
int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
|
int btrfs_update_reloc_root(struct btrfs_trans_handle *trans,
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
@ -82,7 +81,14 @@ int btrfs_find_root(struct btrfs_root *root, const struct btrfs_key *search_key,
|
|||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
BUG_ON(ret == 0); /* Logical error */
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist a root
|
||||||
|
* with such id, but this is out of the valid range.
|
||||||
|
*/
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (path->slots[0] == 0)
|
if (path->slots[0] == 0)
|
||||||
goto out;
|
goto out;
|
||||||
path->slots[0]--;
|
path->slots[0]--;
|
||||||
@ -323,8 +329,11 @@ int btrfs_del_root(struct btrfs_trans_handle *trans,
|
|||||||
ret = btrfs_search_slot(trans, root, key, path, -1, 1);
|
ret = btrfs_search_slot(trans, root, key, path, -1, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
if (ret != 0) {
|
||||||
BUG_ON(ret != 0);
|
/* The root must exist but we did not find it by the key. */
|
||||||
|
ret = -EUCLEAN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_del_item(trans, root, path);
|
ret = btrfs_del_item(trans, root, path);
|
||||||
out:
|
out:
|
||||||
|
@ -3,7 +3,17 @@
|
|||||||
#ifndef BTRFS_ROOT_TREE_H
|
#ifndef BTRFS_ROOT_TREE_H
|
||||||
#define BTRFS_ROOT_TREE_H
|
#define BTRFS_ROOT_TREE_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
struct fscrypt_str;
|
struct fscrypt_str;
|
||||||
|
struct extent_buffer;
|
||||||
|
struct btrfs_key;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_root_item;
|
||||||
|
struct btrfs_path;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_block_rsv;
|
||||||
|
struct btrfs_trans_handle;
|
||||||
|
|
||||||
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
||||||
struct btrfs_block_rsv *rsv,
|
struct btrfs_block_rsv *rsv,
|
||||||
|
@ -1390,8 +1390,15 @@ static int find_first_extent_item(struct btrfs_root *extent_root,
|
|||||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
if (ret == 0) {
|
||||||
|
/*
|
||||||
|
* Key with offset -1 found, there would have to exist an extent
|
||||||
|
* item with such offset, but this is out of the valid range.
|
||||||
|
*/
|
||||||
|
btrfs_release_path(path);
|
||||||
|
return -EUCLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(ret > 0);
|
|
||||||
/*
|
/*
|
||||||
* Here we intentionally pass 0 as @min_objectid, as there could be
|
* Here we intentionally pass 0 as @min_objectid, as there could be
|
||||||
* an extent item starting before @search_start.
|
* an extent item starting before @search_start.
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
#ifndef BTRFS_SCRUB_H
|
#ifndef BTRFS_SCRUB_H
|
||||||
#define BTRFS_SCRUB_H
|
#define BTRFS_SCRUB_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_device;
|
||||||
|
struct btrfs_scrub_progress;
|
||||||
|
|
||||||
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
u64 end, struct btrfs_scrub_progress *progress,
|
u64 end, struct btrfs_scrub_progress *progress,
|
||||||
int readonly, int is_dev_replace);
|
int readonly, int is_dev_replace);
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "xattr.h"
|
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "dir-item.h"
|
#include "dir-item.h"
|
||||||
@ -777,7 +776,12 @@ static int begin_cmd(struct send_ctx *sctx, int cmd)
|
|||||||
if (WARN_ON(!sctx->send_buf))
|
if (WARN_ON(!sctx->send_buf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
BUG_ON(sctx->send_size);
|
if (unlikely(sctx->send_size != 0)) {
|
||||||
|
btrfs_err(sctx->send_root->fs_info,
|
||||||
|
"send: command header buffer not empty cmd %d offset %llu",
|
||||||
|
cmd, sctx->send_off);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
sctx->send_size += sizeof(*hdr);
|
sctx->send_size += sizeof(*hdr);
|
||||||
hdr = (struct btrfs_cmd_header *)sctx->send_buf;
|
hdr = (struct btrfs_cmd_header *)sctx->send_buf;
|
||||||
@ -1070,7 +1074,15 @@ static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path,
|
|||||||
ret = PTR_ERR(start);
|
ret = PTR_ERR(start);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
BUG_ON(start < p->buf);
|
if (unlikely(start < p->buf)) {
|
||||||
|
btrfs_err(root->fs_info,
|
||||||
|
"send: path ref buffer underflow for key (%llu %u %llu)",
|
||||||
|
found_key->objectid,
|
||||||
|
found_key->type,
|
||||||
|
found_key->offset);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p->start = start;
|
p->start = start;
|
||||||
} else {
|
} else {
|
||||||
@ -1406,7 +1418,7 @@ static bool lookup_backref_cache(u64 leaf_bytenr, void *ctx,
|
|||||||
struct btrfs_lru_cache_entry *raw_entry;
|
struct btrfs_lru_cache_entry *raw_entry;
|
||||||
struct backref_cache_entry *entry;
|
struct backref_cache_entry *entry;
|
||||||
|
|
||||||
if (btrfs_lru_cache_size(&sctx->backref_cache) == 0)
|
if (sctx->backref_cache.size == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1504,7 +1516,7 @@ static void store_backref_cache(u64 leaf_bytenr, const struct ulist *root_ids,
|
|||||||
* transaction handle or holding fs_info->commit_root_sem, so no need
|
* transaction handle or holding fs_info->commit_root_sem, so no need
|
||||||
* to take any lock here.
|
* to take any lock here.
|
||||||
*/
|
*/
|
||||||
if (btrfs_lru_cache_size(&sctx->backref_cache) == 1)
|
if (sctx->backref_cache.size == 1)
|
||||||
sctx->backref_cache_last_reloc_trans = fs_info->last_reloc_trans;
|
sctx->backref_cache_last_reloc_trans = fs_info->last_reloc_trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2809,8 +2821,7 @@ static int cache_dir_utimes(struct send_ctx *sctx, u64 dir, u64 gen)
|
|||||||
|
|
||||||
static int trim_dir_utimes_cache(struct send_ctx *sctx)
|
static int trim_dir_utimes_cache(struct send_ctx *sctx)
|
||||||
{
|
{
|
||||||
while (btrfs_lru_cache_size(&sctx->dir_utimes_cache) >
|
while (sctx->dir_utimes_cache.size > SEND_MAX_DIR_UTIMES_CACHE_SIZE) {
|
||||||
SEND_MAX_DIR_UTIMES_CACHE_SIZE) {
|
|
||||||
struct btrfs_lru_cache_entry *lru;
|
struct btrfs_lru_cache_entry *lru;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -4182,7 +4193,13 @@ static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
|
|||||||
* This should never happen as the root dir always has the same ref
|
* This should never happen as the root dir always has the same ref
|
||||||
* which is always '..'
|
* which is always '..'
|
||||||
*/
|
*/
|
||||||
BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID);
|
if (unlikely(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID)) {
|
||||||
|
btrfs_err(fs_info,
|
||||||
|
"send: unexpected inode %llu in process_recorded_refs()",
|
||||||
|
sctx->cur_ino);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
valid_path = fs_path_alloc();
|
valid_path = fs_path_alloc();
|
||||||
if (!valid_path) {
|
if (!valid_path) {
|
||||||
@ -6140,7 +6157,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
u64 offset = key->offset;
|
u64 offset = key->offset;
|
||||||
u64 end;
|
u64 end;
|
||||||
u64 bs = sctx->send_root->fs_info->sb->s_blocksize;
|
u64 bs = sctx->send_root->fs_info->sectorsize;
|
||||||
|
|
||||||
end = min_t(u64, btrfs_file_extent_end(path), sctx->cur_inode_size);
|
end = min_t(u64, btrfs_file_extent_end(path), sctx->cur_inode_size);
|
||||||
if (offset >= end)
|
if (offset >= end)
|
||||||
@ -6458,21 +6475,18 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
|
|||||||
if (sctx->cur_ino != key->objectid || !need_send_hole(sctx))
|
if (sctx->cur_ino != key->objectid || !need_send_hole(sctx))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (sctx->cur_inode_last_extent == (u64)-1) {
|
/*
|
||||||
ret = get_last_extent(sctx, key->offset - 1);
|
* Get last extent's end offset (exclusive) if we haven't determined it
|
||||||
if (ret)
|
* yet (we're processing the first file extent item that is new), or if
|
||||||
return ret;
|
* we're at the first slot of a leaf and the last extent's end is less
|
||||||
}
|
* than the current extent's offset, because we might have skipped
|
||||||
|
* entire leaves that contained only file extent items for our current
|
||||||
if (path->slots[0] == 0 &&
|
* inode. These leaves have a generation number smaller (older) than the
|
||||||
sctx->cur_inode_last_extent < key->offset) {
|
* one in the current leaf and the leaf our last extent came from, and
|
||||||
/*
|
* are located between these 2 leaves.
|
||||||
* We might have skipped entire leafs that contained only
|
*/
|
||||||
* file extent items for our current inode. These leafs have
|
if ((sctx->cur_inode_last_extent == (u64)-1) ||
|
||||||
* a generation number smaller (older) than the one in the
|
(path->slots[0] == 0 && sctx->cur_inode_last_extent < key->offset)) {
|
||||||
* current leaf and the leaf our last extent came from, and
|
|
||||||
* are located between these 2 leafs.
|
|
||||||
*/
|
|
||||||
ret = get_last_extent(sctx, key->offset - 1);
|
ret = get_last_extent(sctx, key->offset - 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -7429,8 +7443,8 @@ static int tree_move_down(struct btrfs_path *path, int *level, u64 reada_min_gen
|
|||||||
u64 reada_done = 0;
|
u64 reada_done = 0;
|
||||||
|
|
||||||
lockdep_assert_held_read(&parent->fs_info->commit_root_sem);
|
lockdep_assert_held_read(&parent->fs_info->commit_root_sem);
|
||||||
|
ASSERT(*level != 0);
|
||||||
|
|
||||||
BUG_ON(*level == 0);
|
|
||||||
eb = btrfs_read_node_slot(parent, slot);
|
eb = btrfs_read_node_slot(parent, slot);
|
||||||
if (IS_ERR(eb))
|
if (IS_ERR(eb))
|
||||||
return PTR_ERR(eb);
|
return PTR_ERR(eb);
|
||||||
|
@ -8,6 +8,11 @@
|
|||||||
#define BTRFS_SEND_H
|
#define BTRFS_SEND_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
#include <linux/align.h>
|
||||||
|
|
||||||
|
struct inode;
|
||||||
|
struct btrfs_ioctl_send_args;
|
||||||
|
|
||||||
#define BTRFS_SEND_STREAM_MAGIC "btrfs-stream"
|
#define BTRFS_SEND_STREAM_MAGIC "btrfs-stream"
|
||||||
/* Conditional support for the upcoming protocol version. */
|
/* Conditional support for the upcoming protocol version. */
|
||||||
@ -25,9 +30,6 @@
|
|||||||
#define BTRFS_SEND_BUF_SIZE_V1 SZ_64K
|
#define BTRFS_SEND_BUF_SIZE_V1 SZ_64K
|
||||||
#define BTRFS_SEND_BUF_SIZE_V2 ALIGN(SZ_16K + BTRFS_MAX_COMPRESSED, PAGE_SIZE)
|
#define BTRFS_SEND_BUF_SIZE_V2 ALIGN(SZ_16K + BTRFS_MAX_COMPRESSED, PAGE_SIZE)
|
||||||
|
|
||||||
struct inode;
|
|
||||||
struct btrfs_ioctl_send_args;
|
|
||||||
|
|
||||||
enum btrfs_tlv_type {
|
enum btrfs_tlv_type {
|
||||||
BTRFS_TLV_U8,
|
BTRFS_TLV_U8,
|
||||||
BTRFS_TLV_U16,
|
BTRFS_TLV_U16,
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "ordered-data.h"
|
#include "ordered-data.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "block-group.h"
|
#include "block-group.h"
|
||||||
#include "zoned.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "extent-tree.h"
|
#include "extent-tree.h"
|
||||||
|
@ -4,8 +4,17 @@
|
|||||||
#define BTRFS_SPACE_INFO_H
|
#define BTRFS_SPACE_INFO_H
|
||||||
|
|
||||||
#include <trace/events/btrfs.h>
|
#include <trace/events/btrfs.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/kobject.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/rwsem.h>
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
|
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_block_group;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Different levels for to flush space when doing space reservations.
|
* Different levels for to flush space when doing space reservations.
|
||||||
*
|
*
|
||||||
|
@ -111,6 +111,9 @@ void btrfs_init_subpage_info(struct btrfs_subpage_info *subpage_info, u32 sector
|
|||||||
subpage_info->checked_offset = cur;
|
subpage_info->checked_offset = cur;
|
||||||
cur += nr_bits;
|
cur += nr_bits;
|
||||||
|
|
||||||
|
subpage_info->locked_offset = cur;
|
||||||
|
cur += nr_bits;
|
||||||
|
|
||||||
subpage_info->total_nr_bits = cur;
|
subpage_info->total_nr_bits = cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,28 +240,58 @@ static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
|
|||||||
start + len <= folio_pos(folio) + PAGE_SIZE);
|
start + len <= folio_pos(folio) + PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define subpage_calc_start_bit(fs_info, folio, name, start, len) \
|
||||||
|
({ \
|
||||||
|
unsigned int start_bit; \
|
||||||
|
\
|
||||||
|
btrfs_subpage_assert(fs_info, folio, start, len); \
|
||||||
|
start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
|
||||||
|
start_bit += fs_info->subpage_info->name##_offset; \
|
||||||
|
start_bit; \
|
||||||
|
})
|
||||||
|
|
||||||
void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
|
void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
|
||||||
struct folio *folio, u64 start, u32 len)
|
struct folio *folio, u64 start, u32 len)
|
||||||
{
|
{
|
||||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||||
|
const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
|
||||||
const int nbits = len >> fs_info->sectorsize_bits;
|
const int nbits = len >> fs_info->sectorsize_bits;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
|
||||||
btrfs_subpage_assert(fs_info, folio, start, len);
|
btrfs_subpage_assert(fs_info, folio, start, len);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&subpage->lock, flags);
|
||||||
|
/*
|
||||||
|
* Even though it's just for reading the page, no one should have
|
||||||
|
* locked the subpage range.
|
||||||
|
*/
|
||||||
|
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
|
||||||
|
bitmap_set(subpage->bitmaps, start_bit, nbits);
|
||||||
atomic_add(nbits, &subpage->readers);
|
atomic_add(nbits, &subpage->readers);
|
||||||
|
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
||||||
struct folio *folio, u64 start, u32 len)
|
struct folio *folio, u64 start, u32 len)
|
||||||
{
|
{
|
||||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||||
|
const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
|
||||||
const int nbits = len >> fs_info->sectorsize_bits;
|
const int nbits = len >> fs_info->sectorsize_bits;
|
||||||
|
unsigned long flags;
|
||||||
bool is_data;
|
bool is_data;
|
||||||
bool last;
|
bool last;
|
||||||
|
|
||||||
btrfs_subpage_assert(fs_info, folio, start, len);
|
btrfs_subpage_assert(fs_info, folio, start, len);
|
||||||
is_data = is_data_inode(folio->mapping->host);
|
is_data = is_data_inode(folio->mapping->host);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&subpage->lock, flags);
|
||||||
|
|
||||||
|
/* The range should have already been locked. */
|
||||||
|
ASSERT(bitmap_test_range_all_set(subpage->bitmaps, start_bit, nbits));
|
||||||
ASSERT(atomic_read(&subpage->readers) >= nbits);
|
ASSERT(atomic_read(&subpage->readers) >= nbits);
|
||||||
|
|
||||||
|
bitmap_clear(subpage->bitmaps, start_bit, nbits);
|
||||||
last = atomic_sub_and_test(nbits, &subpage->readers);
|
last = atomic_sub_and_test(nbits, &subpage->readers);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -270,6 +303,7 @@ void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
|||||||
*/
|
*/
|
||||||
if (is_data && last)
|
if (is_data && last)
|
||||||
folio_unlock(folio);
|
folio_unlock(folio);
|
||||||
|
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btrfs_subpage_clamp_range(struct folio *folio, u64 *start, u32 *len)
|
static void btrfs_subpage_clamp_range(struct folio *folio, u64 *start, u32 *len)
|
||||||
@ -290,28 +324,38 @@ static void btrfs_subpage_clamp_range(struct folio *folio, u64 *start, u32 *len)
|
|||||||
orig_start + orig_len) - *start;
|
orig_start + orig_len) - *start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
|
static void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
|
||||||
struct folio *folio, u64 start, u32 len)
|
struct folio *folio, u64 start, u32 len)
|
||||||
{
|
{
|
||||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||||
|
const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
|
||||||
const int nbits = (len >> fs_info->sectorsize_bits);
|
const int nbits = (len >> fs_info->sectorsize_bits);
|
||||||
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
btrfs_subpage_assert(fs_info, folio, start, len);
|
btrfs_subpage_assert(fs_info, folio, start, len);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&subpage->lock, flags);
|
||||||
ASSERT(atomic_read(&subpage->readers) == 0);
|
ASSERT(atomic_read(&subpage->readers) == 0);
|
||||||
|
ASSERT(bitmap_test_range_all_zero(subpage->bitmaps, start_bit, nbits));
|
||||||
|
bitmap_set(subpage->bitmaps, start_bit, nbits);
|
||||||
ret = atomic_add_return(nbits, &subpage->writers);
|
ret = atomic_add_return(nbits, &subpage->writers);
|
||||||
ASSERT(ret == nbits);
|
ASSERT(ret == nbits);
|
||||||
|
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
|
static bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
|
||||||
struct folio *folio, u64 start, u32 len)
|
struct folio *folio, u64 start, u32 len)
|
||||||
{
|
{
|
||||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||||
|
const int start_bit = subpage_calc_start_bit(fs_info, folio, locked, start, len);
|
||||||
const int nbits = (len >> fs_info->sectorsize_bits);
|
const int nbits = (len >> fs_info->sectorsize_bits);
|
||||||
|
unsigned long flags;
|
||||||
|
bool last;
|
||||||
|
|
||||||
btrfs_subpage_assert(fs_info, folio, start, len);
|
btrfs_subpage_assert(fs_info, folio, start, len);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&subpage->lock, flags);
|
||||||
/*
|
/*
|
||||||
* We have call sites passing @lock_page into
|
* We have call sites passing @lock_page into
|
||||||
* extent_clear_unlock_delalloc() for compression path.
|
* extent_clear_unlock_delalloc() for compression path.
|
||||||
@ -319,11 +363,18 @@ bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
|
|||||||
* This @locked_page is locked by plain lock_page(), thus its
|
* This @locked_page is locked by plain lock_page(), thus its
|
||||||
* subpage::writers is 0. Handle them in a special way.
|
* subpage::writers is 0. Handle them in a special way.
|
||||||
*/
|
*/
|
||||||
if (atomic_read(&subpage->writers) == 0)
|
if (atomic_read(&subpage->writers) == 0) {
|
||||||
|
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(atomic_read(&subpage->writers) >= nbits);
|
ASSERT(atomic_read(&subpage->writers) >= nbits);
|
||||||
return atomic_sub_and_test(nbits, &subpage->writers);
|
/* The target range should have been locked. */
|
||||||
|
ASSERT(bitmap_test_range_all_set(subpage->bitmaps, start_bit, nbits));
|
||||||
|
bitmap_clear(subpage->bitmaps, start_bit, nbits);
|
||||||
|
last = atomic_sub_and_test(nbits, &subpage->writers);
|
||||||
|
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||||
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -365,16 +416,6 @@ void btrfs_folio_end_writer_lock(const struct btrfs_fs_info *fs_info,
|
|||||||
folio_unlock(folio);
|
folio_unlock(folio);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define subpage_calc_start_bit(fs_info, folio, name, start, len) \
|
|
||||||
({ \
|
|
||||||
unsigned int start_bit; \
|
|
||||||
\
|
|
||||||
btrfs_subpage_assert(fs_info, folio, start, len); \
|
|
||||||
start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
|
|
||||||
start_bit += fs_info->subpage_info->name##_offset; \
|
|
||||||
start_bit; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define subpage_test_bitmap_all_set(fs_info, subpage, name) \
|
#define subpage_test_bitmap_all_set(fs_info, subpage, name) \
|
||||||
bitmap_test_range_all_set(subpage->bitmaps, \
|
bitmap_test_range_all_set(subpage->bitmaps, \
|
||||||
fs_info->subpage_info->name##_offset, \
|
fs_info->subpage_info->name##_offset, \
|
||||||
@ -751,6 +792,7 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
|
|||||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, writeback, &writeback_bitmap);
|
GET_SUBPAGE_BITMAP(subpage, subpage_info, writeback, &writeback_bitmap);
|
||||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, ordered, &ordered_bitmap);
|
GET_SUBPAGE_BITMAP(subpage, subpage_info, ordered, &ordered_bitmap);
|
||||||
GET_SUBPAGE_BITMAP(subpage, subpage_info, checked, &checked_bitmap);
|
GET_SUBPAGE_BITMAP(subpage, subpage_info, checked, &checked_bitmap);
|
||||||
|
GET_SUBPAGE_BITMAP(subpage, subpage_info, locked, &checked_bitmap);
|
||||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||||
|
|
||||||
dump_page(folio_page(folio, 0), "btrfs subpage dump");
|
dump_page(folio_page(folio, 0), "btrfs subpage dump");
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
#define BTRFS_SUBPAGE_H
|
#define BTRFS_SUBPAGE_H
|
||||||
|
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
|
struct address_space;
|
||||||
|
struct folio;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extra info for subpapge bitmap.
|
* Extra info for subpapge bitmap.
|
||||||
@ -28,7 +33,7 @@ struct btrfs_subpage_info {
|
|||||||
unsigned int total_nr_bits;
|
unsigned int total_nr_bits;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* *_start indicates where the bitmap starts, the length is always
|
* *_offset indicates where the bitmap starts, the length is always
|
||||||
* @bitmap_size, which is calculated from PAGE_SIZE / sectorsize.
|
* @bitmap_size, which is calculated from PAGE_SIZE / sectorsize.
|
||||||
*/
|
*/
|
||||||
unsigned int uptodate_offset;
|
unsigned int uptodate_offset;
|
||||||
@ -36,6 +41,16 @@ struct btrfs_subpage_info {
|
|||||||
unsigned int writeback_offset;
|
unsigned int writeback_offset;
|
||||||
unsigned int ordered_offset;
|
unsigned int ordered_offset;
|
||||||
unsigned int checked_offset;
|
unsigned int checked_offset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For locked bitmaps, normally it's subpage representation for folio
|
||||||
|
* Locked flag, but metadata is different:
|
||||||
|
*
|
||||||
|
* - Metadata doesn't really lock the folio
|
||||||
|
* It's just to prevent page::private get cleared before the last
|
||||||
|
* end_page_read().
|
||||||
|
*/
|
||||||
|
unsigned int locked_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -93,10 +108,6 @@ void btrfs_subpage_start_reader(const struct btrfs_fs_info *fs_info,
|
|||||||
void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
void btrfs_subpage_end_reader(const struct btrfs_fs_info *fs_info,
|
||||||
struct folio *folio, u64 start, u32 len);
|
struct folio *folio, u64 start, u32 len);
|
||||||
|
|
||||||
void btrfs_subpage_start_writer(const struct btrfs_fs_info *fs_info,
|
|
||||||
struct folio *folio, u64 start, u32 len);
|
|
||||||
bool btrfs_subpage_end_and_test_writer(const struct btrfs_fs_info *fs_info,
|
|
||||||
struct folio *folio, u64 start, u32 len);
|
|
||||||
int btrfs_folio_start_writer_lock(const struct btrfs_fs_info *fs_info,
|
int btrfs_folio_start_writer_lock(const struct btrfs_fs_info *fs_info,
|
||||||
struct folio *folio, u64 start, u32 len);
|
struct folio *folio, u64 start, u32 len);
|
||||||
void btrfs_folio_end_writer_lock(const struct btrfs_fs_info *fs_info,
|
void btrfs_folio_end_writer_lock(const struct btrfs_fs_info *fs_info,
|
||||||
|
@ -34,13 +34,11 @@
|
|||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "print-tree.h"
|
|
||||||
#include "props.h"
|
#include "props.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
#include "bio.h"
|
#include "bio.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "rcu-string.h"
|
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
#include "free-space-cache.h"
|
#include "free-space-cache.h"
|
||||||
#include "backref.h"
|
#include "backref.h"
|
||||||
@ -1767,7 +1765,7 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||||||
buf->f_bavail = 0;
|
buf->f_bavail = 0;
|
||||||
|
|
||||||
buf->f_type = BTRFS_SUPER_MAGIC;
|
buf->f_type = BTRFS_SUPER_MAGIC;
|
||||||
buf->f_bsize = dentry->d_sb->s_blocksize;
|
buf->f_bsize = fs_info->sectorsize;
|
||||||
buf->f_namelen = BTRFS_NAME_LEN;
|
buf->f_namelen = BTRFS_NAME_LEN;
|
||||||
|
|
||||||
/* We treat it as constant endianness (it doesn't matter _which_)
|
/* We treat it as constant endianness (it doesn't matter _which_)
|
||||||
@ -2203,7 +2201,9 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
|
|||||||
vol = memdup_user((void __user *)arg, sizeof(*vol));
|
vol = memdup_user((void __user *)arg, sizeof(*vol));
|
||||||
if (IS_ERR(vol))
|
if (IS_ERR(vol))
|
||||||
return PTR_ERR(vol);
|
return PTR_ERR(vol);
|
||||||
vol->name[BTRFS_PATH_NAME_MAX] = '\0';
|
ret = btrfs_check_ioctl_vol_args_path(vol);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case BTRFS_IOC_SCAN_DEV:
|
case BTRFS_IOC_SCAN_DEV:
|
||||||
@ -2245,6 +2245,7 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
kfree(vol);
|
kfree(vol);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,13 @@
|
|||||||
#ifndef BTRFS_SUPER_H
|
#ifndef BTRFS_SUPER_H
|
||||||
#define BTRFS_SUPER_H
|
#define BTRFS_SUPER_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include "fs.h"
|
||||||
|
|
||||||
|
struct super_block;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
|
||||||
bool btrfs_check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
|
bool btrfs_check_options(struct btrfs_fs_info *info, unsigned long *mount_opt,
|
||||||
unsigned long flags);
|
unsigned long flags);
|
||||||
int btrfs_sync_fs(struct super_block *sb, int wait);
|
int btrfs_sync_fs(struct super_block *sb, int wait);
|
||||||
|
@ -421,7 +421,7 @@ BTRFS_ATTR(static_feature, supported_sectorsizes,
|
|||||||
|
|
||||||
static ssize_t acl_show(struct kobject *kobj, struct kobj_attribute *a, char *buf)
|
static ssize_t acl_show(struct kobject *kobj, struct kobj_attribute *a, char *buf)
|
||||||
{
|
{
|
||||||
return sysfs_emit(buf, "%d\n", !!IS_ENABLED(CONFIG_BTRFS_FS_POSIX_ACL));
|
return sysfs_emit(buf, "%d\n", IS_ENABLED(CONFIG_BTRFS_FS_POSIX_ACL));
|
||||||
}
|
}
|
||||||
BTRFS_ATTR(static_feature, acl, acl_show);
|
BTRFS_ATTR(static_feature, acl, acl_show);
|
||||||
|
|
||||||
@ -1228,11 +1228,12 @@ static ssize_t btrfs_read_policy_show(struct kobject *kobj,
|
|||||||
struct kobj_attribute *a, char *buf)
|
struct kobj_attribute *a, char *buf)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
|
struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
|
||||||
|
const enum btrfs_read_policy policy = READ_ONCE(fs_devices->read_policy);
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
|
for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
|
||||||
if (fs_devices->read_policy == i)
|
if (policy == i)
|
||||||
ret += sysfs_emit_at(buf, ret, "%s[%s]",
|
ret += sysfs_emit_at(buf, ret, "%s[%s]",
|
||||||
(ret == 0 ? "" : " "),
|
(ret == 0 ? "" : " "),
|
||||||
btrfs_read_policy_name[i]);
|
btrfs_read_policy_name[i]);
|
||||||
@ -1256,8 +1257,8 @@ static ssize_t btrfs_read_policy_store(struct kobject *kobj,
|
|||||||
|
|
||||||
for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
|
for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
|
||||||
if (sysfs_streq(buf, btrfs_read_policy_name[i])) {
|
if (sysfs_streq(buf, btrfs_read_policy_name[i])) {
|
||||||
if (i != fs_devices->read_policy) {
|
if (i != READ_ONCE(fs_devices->read_policy)) {
|
||||||
fs_devices->read_policy = i;
|
WRITE_ONCE(fs_devices->read_policy, i);
|
||||||
btrfs_info(fs_devices->fs_info,
|
btrfs_info(fs_devices->fs_info,
|
||||||
"read policy set to '%s'",
|
"read policy set to '%s'",
|
||||||
btrfs_read_policy_name[i]);
|
btrfs_read_policy_name[i]);
|
||||||
@ -1306,6 +1307,47 @@ static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj,
|
|||||||
BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
|
BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
|
||||||
btrfs_bg_reclaim_threshold_store);
|
btrfs_bg_reclaim_threshold_store);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_DEBUG
|
||||||
|
static ssize_t btrfs_offload_csum_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *a, char *buf)
|
||||||
|
{
|
||||||
|
struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
|
||||||
|
|
||||||
|
switch (READ_ONCE(fs_devices->offload_csum_mode)) {
|
||||||
|
case BTRFS_OFFLOAD_CSUM_AUTO:
|
||||||
|
return sysfs_emit(buf, "auto\n");
|
||||||
|
case BTRFS_OFFLOAD_CSUM_FORCE_ON:
|
||||||
|
return sysfs_emit(buf, "1\n");
|
||||||
|
case BTRFS_OFFLOAD_CSUM_FORCE_OFF:
|
||||||
|
return sysfs_emit(buf, "0\n");
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t btrfs_offload_csum_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *a, const char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
|
||||||
|
int ret;
|
||||||
|
bool val;
|
||||||
|
|
||||||
|
ret = kstrtobool(buf, &val);
|
||||||
|
if (ret == 0)
|
||||||
|
WRITE_ONCE(fs_devices->offload_csum_mode,
|
||||||
|
val ? BTRFS_OFFLOAD_CSUM_FORCE_ON : BTRFS_OFFLOAD_CSUM_FORCE_OFF);
|
||||||
|
else if (ret == -EINVAL && sysfs_streq(buf, "auto"))
|
||||||
|
WRITE_ONCE(fs_devices->offload_csum_mode, BTRFS_OFFLOAD_CSUM_AUTO);
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
BTRFS_ATTR_RW(, offload_csum, btrfs_offload_csum_show, btrfs_offload_csum_store);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-filesystem information and stats.
|
* Per-filesystem information and stats.
|
||||||
*
|
*
|
||||||
@ -1325,6 +1367,9 @@ static const struct attribute *btrfs_attrs[] = {
|
|||||||
BTRFS_ATTR_PTR(, bg_reclaim_threshold),
|
BTRFS_ATTR_PTR(, bg_reclaim_threshold),
|
||||||
BTRFS_ATTR_PTR(, commit_stats),
|
BTRFS_ATTR_PTR(, commit_stats),
|
||||||
BTRFS_ATTR_PTR(, temp_fsid),
|
BTRFS_ATTR_PTR(, temp_fsid),
|
||||||
|
#ifdef CONFIG_BTRFS_DEBUG
|
||||||
|
BTRFS_ATTR_PTR(, offload_csum),
|
||||||
|
#endif
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3,8 +3,17 @@
|
|||||||
#ifndef BTRFS_SYSFS_H
|
#ifndef BTRFS_SYSFS_H
|
||||||
#define BTRFS_SYSFS_H
|
#define BTRFS_SYSFS_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/compiler_types.h>
|
||||||
#include <linux/kobject.h>
|
#include <linux/kobject.h>
|
||||||
|
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_device;
|
||||||
|
struct btrfs_fs_devices;
|
||||||
|
struct btrfs_block_group;
|
||||||
|
struct btrfs_space_info;
|
||||||
|
struct btrfs_qgroup;
|
||||||
|
|
||||||
enum btrfs_feature_set {
|
enum btrfs_feature_set {
|
||||||
FEAT_COMPAT,
|
FEAT_COMPAT,
|
||||||
FEAT_COMPAT_RO,
|
FEAT_COMPAT_RO,
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "btrfs-tests.h"
|
#include "btrfs-tests.h"
|
||||||
#include "../ctree.h"
|
#include "../ctree.h"
|
||||||
#include "../extent_io.h"
|
#include "../extent_io.h"
|
||||||
|
#include "../disk-io.h"
|
||||||
#include "../btrfs_inode.h"
|
#include "../btrfs_inode.h"
|
||||||
|
|
||||||
#define PROCESS_UNLOCK (1 << 0)
|
#define PROCESS_UNLOCK (1 << 0)
|
||||||
@ -105,9 +106,11 @@ static void dump_extent_io_tree(const struct extent_io_tree *tree)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_find_delalloc(u32 sectorsize)
|
static int test_find_delalloc(u32 sectorsize, u32 nodesize)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct btrfs_fs_info *fs_info;
|
||||||
|
struct btrfs_root *root = NULL;
|
||||||
|
struct inode *inode = NULL;
|
||||||
struct extent_io_tree *tmp;
|
struct extent_io_tree *tmp;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct page *locked_page = NULL;
|
struct page *locked_page = NULL;
|
||||||
@ -121,12 +124,27 @@ static int test_find_delalloc(u32 sectorsize)
|
|||||||
|
|
||||||
test_msg("running find delalloc tests");
|
test_msg("running find delalloc tests");
|
||||||
|
|
||||||
|
fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
|
||||||
|
if (!fs_info) {
|
||||||
|
test_std_err(TEST_ALLOC_FS_INFO);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
root = btrfs_alloc_dummy_root(fs_info);
|
||||||
|
if (IS_ERR(root)) {
|
||||||
|
test_std_err(TEST_ALLOC_ROOT);
|
||||||
|
ret = PTR_ERR(root);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
inode = btrfs_new_test_inode();
|
inode = btrfs_new_test_inode();
|
||||||
if (!inode) {
|
if (!inode) {
|
||||||
test_std_err(TEST_ALLOC_INODE);
|
test_std_err(TEST_ALLOC_INODE);
|
||||||
return -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
tmp = &BTRFS_I(inode)->io_tree;
|
tmp = &BTRFS_I(inode)->io_tree;
|
||||||
|
BTRFS_I(inode)->root = root;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Passing NULL as we don't have fs_info but tracepoints are not used
|
* Passing NULL as we don't have fs_info but tracepoints are not used
|
||||||
@ -316,6 +334,8 @@ out:
|
|||||||
process_page_range(inode, 0, total_dirty - 1,
|
process_page_range(inode, 0, total_dirty - 1,
|
||||||
PROCESS_UNLOCK | PROCESS_RELEASE);
|
PROCESS_UNLOCK | PROCESS_RELEASE);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
|
btrfs_free_dummy_root(root);
|
||||||
|
btrfs_free_dummy_fs_info(fs_info);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +814,7 @@ int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
|
|||||||
|
|
||||||
test_msg("running extent I/O tests");
|
test_msg("running extent I/O tests");
|
||||||
|
|
||||||
ret = test_find_delalloc(sectorsize);
|
ret = test_find_delalloc(sectorsize, nodesize);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
|
|
||||||
/* First with no extents */
|
/* First with no extents */
|
||||||
BTRFS_I(inode)->root = root;
|
BTRFS_I(inode)->root = root;
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 0, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
em = NULL;
|
em = NULL;
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
@ -278,7 +278,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
*/
|
*/
|
||||||
setup_file_extents(root, sectorsize);
|
setup_file_extents(root, sectorsize);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 0, (u64)-1);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, (u64)-1);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -316,7 +316,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -339,7 +339,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* Regular extent */
|
/* Regular extent */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -367,7 +367,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* The next 3 are split extents */
|
/* The next 3 are split extents */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -396,7 +396,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -418,7 +418,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -452,7 +452,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* Prealloc extent */
|
/* Prealloc extent */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -481,7 +481,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* The next 3 are a half written prealloc extent */
|
/* The next 3 are a half written prealloc extent */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -511,7 +511,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -544,7 +544,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -579,7 +579,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* Now for the compressed extent */
|
/* Now for the compressed extent */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -613,7 +613,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* Split compressed extent */
|
/* Split compressed extent */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -648,7 +648,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -675,7 +675,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -710,7 +710,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
/* A hole between regular extents but no hole extent */
|
/* A hole between regular extents but no hole extent */
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset + 6, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset + 6, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -737,7 +737,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, SZ_4M);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, SZ_4M);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -770,7 +770,7 @@ static noinline int test_btrfs_get_extent(u32 sectorsize, u32 nodesize)
|
|||||||
offset = em->start + em->len;
|
offset = em->start + em->len;
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, offset, sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, offset, sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -850,7 +850,7 @@ static int test_hole_first(u32 sectorsize, u32 nodesize)
|
|||||||
insert_inode_item_key(root);
|
insert_inode_item_key(root);
|
||||||
insert_extent(root, sectorsize, sectorsize, sectorsize, 0, sectorsize,
|
insert_extent(root, sectorsize, sectorsize, sectorsize, 0, sectorsize,
|
||||||
sectorsize, BTRFS_FILE_EXTENT_REG, 0, 1);
|
sectorsize, BTRFS_FILE_EXTENT_REG, 0, 1);
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 0, 2 * sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, 2 * sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
@ -872,7 +872,7 @@ static int test_hole_first(u32 sectorsize, u32 nodesize)
|
|||||||
}
|
}
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
|
||||||
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, sectorsize, 2 * sectorsize);
|
em = btrfs_get_extent(BTRFS_I(inode), NULL, sectorsize, 2 * sectorsize);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
test_err("got an error when we shouldn't have");
|
test_err("got an error when we shouldn't have");
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -23,12 +23,10 @@
|
|||||||
#include "qgroup.h"
|
#include "qgroup.h"
|
||||||
#include "block-group.h"
|
#include "block-group.h"
|
||||||
#include "space-info.h"
|
#include "space-info.h"
|
||||||
#include "zoned.h"
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "accessors.h"
|
#include "accessors.h"
|
||||||
#include "extent-tree.h"
|
#include "extent-tree.h"
|
||||||
#include "root-tree.h"
|
#include "root-tree.h"
|
||||||
#include "defrag.h"
|
|
||||||
#include "dir-item.h"
|
#include "dir-item.h"
|
||||||
#include "uuid-tree.h"
|
#include "uuid-tree.h"
|
||||||
#include "ioctl.h"
|
#include "ioctl.h"
|
||||||
@ -1959,19 +1957,6 @@ static void update_super_roots(struct btrfs_fs_info *fs_info)
|
|||||||
super->uuid_tree_generation = root_item->generation;
|
super->uuid_tree_generation = root_item->generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
|
|
||||||
{
|
|
||||||
struct btrfs_transaction *trans;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
spin_lock(&info->trans_lock);
|
|
||||||
trans = info->running_transaction;
|
|
||||||
if (trans)
|
|
||||||
ret = (trans->state >= TRANS_STATE_COMMIT_START);
|
|
||||||
spin_unlock(&info->trans_lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int btrfs_transaction_blocked(struct btrfs_fs_info *info)
|
int btrfs_transaction_blocked(struct btrfs_fs_info *info)
|
||||||
{
|
{
|
||||||
struct btrfs_transaction *trans;
|
struct btrfs_transaction *trans;
|
||||||
@ -2686,9 +2671,7 @@ void __cold __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
int __init btrfs_transaction_init(void)
|
int __init btrfs_transaction_init(void)
|
||||||
{
|
{
|
||||||
btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle",
|
btrfs_trans_handle_cachep = KMEM_CACHE(btrfs_trans_handle, SLAB_TEMPORARY);
|
||||||
sizeof(struct btrfs_trans_handle), 0,
|
|
||||||
SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
|
|
||||||
if (!btrfs_trans_handle_cachep)
|
if (!btrfs_trans_handle_cachep)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -6,12 +6,27 @@
|
|||||||
#ifndef BTRFS_TRANSACTION_H
|
#ifndef BTRFS_TRANSACTION_H
|
||||||
#define BTRFS_TRANSACTION_H
|
#define BTRFS_TRANSACTION_H
|
||||||
|
|
||||||
|
#include <linux/atomic.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/time64.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "delayed-ref.h"
|
#include "delayed-ref.h"
|
||||||
#include "ctree.h"
|
#include "extent-io-tree.h"
|
||||||
|
#include "block-rsv.h"
|
||||||
|
#include "messages.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
struct dentry;
|
||||||
|
struct inode;
|
||||||
|
struct btrfs_pending_snapshot;
|
||||||
|
struct btrfs_fs_info;
|
||||||
|
struct btrfs_root_item;
|
||||||
|
struct btrfs_root;
|
||||||
|
struct btrfs_path;
|
||||||
|
|
||||||
/* Radix-tree tag for roots that are part of the trasaction. */
|
/* Radix-tree tag for roots that are part of the trasaction. */
|
||||||
#define BTRFS_ROOT_TRANS_TAG 0
|
#define BTRFS_ROOT_TRANS_TAG 0
|
||||||
|
|
||||||
@ -262,7 +277,6 @@ int btrfs_write_marked_extents(struct btrfs_fs_info *fs_info,
|
|||||||
struct extent_io_tree *dirty_pages, int mark);
|
struct extent_io_tree *dirty_pages, int mark);
|
||||||
int btrfs_wait_tree_log_extents(struct btrfs_root *root, int mark);
|
int btrfs_wait_tree_log_extents(struct btrfs_root *root, int mark);
|
||||||
int btrfs_transaction_blocked(struct btrfs_fs_info *info);
|
int btrfs_transaction_blocked(struct btrfs_fs_info *info);
|
||||||
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
|
|
||||||
void btrfs_put_transaction(struct btrfs_transaction *transaction);
|
void btrfs_put_transaction(struct btrfs_transaction *transaction);
|
||||||
void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
|
void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "messages.h"
|
#include "messages.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "tree-checker.h"
|
#include "tree-checker.h"
|
||||||
#include "disk-io.h"
|
|
||||||
#include "compression.h"
|
#include "compression.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
@ -30,7 +29,6 @@
|
|||||||
#include "file-item.h"
|
#include "file-item.h"
|
||||||
#include "inode-item.h"
|
#include "inode-item.h"
|
||||||
#include "dir-item.h"
|
#include "dir-item.h"
|
||||||
#include "raid-stripe-tree.h"
|
|
||||||
#include "extent-tree.h"
|
#include "extent-tree.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -67,6 +65,7 @@ static void generic_err(const struct extent_buffer *eb, int slot,
|
|||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
|
dump_page(folio_page(eb->folios[0], 0), "eb page dump");
|
||||||
btrfs_crit(fs_info,
|
btrfs_crit(fs_info,
|
||||||
"corrupt %s: root=%llu block=%llu slot=%d, %pV",
|
"corrupt %s: root=%llu block=%llu slot=%d, %pV",
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
@ -94,6 +93,7 @@ static void file_extent_err(const struct extent_buffer *eb, int slot,
|
|||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
|
dump_page(folio_page(eb->folios[0], 0), "eb page dump");
|
||||||
btrfs_crit(fs_info,
|
btrfs_crit(fs_info,
|
||||||
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
|
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu file_offset=%llu, %pV",
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
@ -154,6 +154,7 @@ static void dir_item_err(const struct extent_buffer *eb, int slot,
|
|||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
|
dump_page(folio_page(eb->folios[0], 0), "eb page dump");
|
||||||
btrfs_crit(fs_info,
|
btrfs_crit(fs_info,
|
||||||
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
|
"corrupt %s: root=%llu block=%llu slot=%d ino=%llu, %pV",
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
@ -649,6 +650,7 @@ static void block_group_err(const struct extent_buffer *eb, int slot,
|
|||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
|
dump_page(folio_page(eb->folios[0], 0), "eb page dump");
|
||||||
btrfs_crit(fs_info,
|
btrfs_crit(fs_info,
|
||||||
"corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
|
"corrupt %s: root=%llu block=%llu slot=%d bg_start=%llu bg_len=%llu, %pV",
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
@ -1005,6 +1007,7 @@ static void dev_item_err(const struct extent_buffer *eb, int slot,
|
|||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
|
dump_page(folio_page(eb->folios[0], 0), "eb page dump");
|
||||||
btrfs_crit(eb->fs_info,
|
btrfs_crit(eb->fs_info,
|
||||||
"corrupt %s: root=%llu block=%llu slot=%d devid=%llu %pV",
|
"corrupt %s: root=%llu block=%llu slot=%d devid=%llu %pV",
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
@ -1260,6 +1263,7 @@ static void extent_err(const struct extent_buffer *eb, int slot,
|
|||||||
vaf.fmt = fmt;
|
vaf.fmt = fmt;
|
||||||
vaf.va = &args;
|
vaf.va = &args;
|
||||||
|
|
||||||
|
dump_page(folio_page(eb->folios[0], 0), "eb page dump");
|
||||||
btrfs_crit(eb->fs_info,
|
btrfs_crit(eb->fs_info,
|
||||||
"corrupt %s: block=%llu slot=%d extent bytenr=%llu len=%llu %pV",
|
"corrupt %s: block=%llu slot=%d extent bytenr=%llu len=%llu %pV",
|
||||||
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
btrfs_header_level(eb) == 0 ? "leaf" : "node",
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user