// SPDX-License-Identifier: GPL-2.0 /* * linux/fs/ext4/block_validity.c * * Copyright (C) 2009 * Theodore Ts'o (tytso@mit.edu) * * Track which blocks in the filesystem are metadata blocks that * should never be used as data blocks by files or directories.
*/
rbtree_postorder_for_each_entry_safe(entry, n,
&system_blks->root, node)
kmem_cache_free(ext4_system_zone_cachep, entry);
}
/* * Mark a range of blocks as belonging to the "system zone" --- that * is, filesystem metadata blocks which should never be used by * inodes.
*/ staticint add_system_zone(struct ext4_system_blocks *system_blks,
ext4_fsblk_t start_blk, unsignedint count, u32 ino)
{ struct ext4_system_zone *new_entry, *entry; struct rb_node **n = &system_blks->root.rb_node, *node; struct rb_node *parent = NULL, *new_node;
while (*n) {
parent = *n;
entry = rb_entry(parent, struct ext4_system_zone, node); if (start_blk < entry->start_blk)
n = &(*n)->rb_left; elseif (start_blk >= (entry->start_blk + entry->count))
n = &(*n)->rb_right; else/* Unexpected overlap of system zones. */ return -EFSCORRUPTED;
}
/* * Build system zone rbtree which is used for block validity checking. * * The update of system_blks pointer in this function is protected by * sb->s_umount semaphore. However we have to be careful as we can be * racing with ext4_inode_block_valid() calls reading system_blks rbtree * protected only by RCU. That's why we first build the rbtree and then * swap it in place.
*/ int ext4_setup_system_zone(struct super_block *sb)
{
ext4_group_t ngroups = ext4_get_groups_count(sb); struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_system_blocks *system_blks; struct ext4_group_desc *gdp;
ext4_group_t i; int ret;
system_blks = kzalloc(sizeof(*system_blks), GFP_KERNEL); if (!system_blks) return -ENOMEM;
for (i=0; i < ngroups; i++) { unsignedint meta_blks = ext4_num_base_meta_blocks(sb, i);
cond_resched(); if (meta_blks != 0) {
ret = add_system_zone(system_blks,
ext4_group_first_block_no(sb, i),
meta_blks, 0); if (ret) goto err;
}
gdp = ext4_get_group_desc(sb, i, NULL);
ret = add_system_zone(system_blks,
ext4_block_bitmap(sb, gdp), 1, 0); if (ret) goto err;
ret = add_system_zone(system_blks,
ext4_inode_bitmap(sb, gdp), 1, 0); if (ret) goto err;
ret = add_system_zone(system_blks,
ext4_inode_table(sb, gdp),
sbi->s_itb_per_group, 0); if (ret) goto err;
} if (ext4_has_feature_journal(sb) && sbi->s_es->s_journal_inum) {
ret = ext4_protect_reserved_inode(sb, system_blks,
le32_to_cpu(sbi->s_es->s_journal_inum)); if (ret) goto err;
}
/* * System blks rbtree complete, announce it once to prevent racing * with ext4_inode_block_valid() accessing the rbtree at the same * time.
*/
rcu_assign_pointer(sbi->s_system_blks, system_blks);
/* * Called when the filesystem is unmounted or when remounting it with * noblock_validity specified. * * The update of system_blks pointer in this function is protected by * sb->s_umount semaphore. However we have to be careful as we can be * racing with ext4_inode_block_valid() calls reading system_blks rbtree * protected only by RCU. So we first clear the system_blks pointer and * then free the rbtree only after RCU grace period expires.
*/ void ext4_release_system_zone(struct super_block *sb)
{ struct ext4_system_blocks *system_blks;
/* * Lock the system zone to prevent it being released concurrently * when doing a remount which inverse current "[no]block_validity" * mount option.
*/
rcu_read_lock();
system_blks = rcu_dereference(sbi->s_system_blks); if (system_blks == NULL) goto out_rcu;
n = system_blks->root.rb_node; while (n) {
entry = rb_entry(n, struct ext4_system_zone, node); if (start_blk + count - 1 < entry->start_blk)
n = n->rb_left; elseif (start_blk >= (entry->start_blk + entry->count))
n = n->rb_right; else {
ret = 0; if (inode)
ret = (entry->ino == inode->i_ino); break;
}
}
out_rcu:
rcu_read_unlock(); return ret;
}
/* * Returns 1 if the passed-in block region (start_blk, * start_blk+count) is valid; 0 if some part of the block region * overlaps with some other filesystem metadata blocks.
*/ int ext4_inode_block_valid(struct inode *inode, ext4_fsblk_t start_blk, unsignedint count)
{ return ext4_sb_block_valid(inode->i_sb, inode, start_blk, count);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.