summaryrefslogtreecommitdiff
path: root/fs/ext2
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-08-30 12:10:50 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2023-08-30 12:10:50 -0700
commit1500e7e0726e963f64b9785a0cb0a820b2587bad (patch)
treeb79eb053bf7904dea5a984d3f7c30ff2719d5694 /fs/ext2
parent63580f669d7ff5aa5a1fa2e3994114770a491722 (diff)
parentdf1ae36a4a0e92340daea12e88d43eeb2eb013b1 (diff)
Merge tag 'for_v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull ext2, quota, and udf updates from Jan Kara: - fixes for possible use-after-free issues with quota when racing with chown - fixes for ext2 crashing when xattr allocation races with another block allocation to the same file from page writeback code - fix for block number overflow in ext2 - marking of reiserfs as obsolete in MAINTAINERS - assorted minor cleanups * tag 'for_v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: ext2: Fix kernel-doc warnings ext2: improve consistency of ext2_fsblk_t datatype usage ext2: dump current reservation window info ext2: fix race between setxattr and write back ext2: introduce new flags argument for ext2_new_blocks() ext2: remove ext2_new_block() ext2: fix datatype of block number in ext2_xattr_set2() udf: Drop pointless aops assignment quota: use lockdep_assert_held_write in dquot_load_quota_sb MAINTAINERS: change reiserfs status to obsolete udf: Fix -Wstringop-overflow warnings quota: simplify drop_dquot_ref() quota: fix dqput() to follow the guarantees dquot_srcu should provide quota: add new helper dquot_active() quota: rename dquot_active() to inode_quota_active() quota: factor out dquot_write_dquot() ext2: remove redundant assignment to variable desc and variable best_desc
Diffstat (limited to 'fs/ext2')
-rw-r--r--fs/ext2/balloc.c136
-rw-r--r--fs/ext2/ext2.h14
-rw-r--r--fs/ext2/ialloc.c3
-rw-r--r--fs/ext2/inode.c24
-rw-r--r--fs/ext2/xattr.c7
5 files changed, 91 insertions, 93 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index c8049c90323d..e124f3d709b2 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -472,8 +472,8 @@ void ext2_discard_reservation(struct inode *inode)
* @block: start physical block to free
* @count: number of blocks to free
*/
-void ext2_free_blocks (struct inode * inode, unsigned long block,
- unsigned long count)
+void ext2_free_blocks(struct inode * inode, ext2_fsblk_t block,
+ unsigned long count)
{
struct buffer_head *bitmap_bh = NULL;
struct buffer_head * bh2;
@@ -716,36 +716,34 @@ fail_access:
}
/**
- * find_next_reservable_window():
- * find a reservable space within the given range.
- * It does not allocate the reservation window for now:
- * alloc_new_reservation() will do the work later.
+ * find_next_reservable_window - Find a reservable space within the given range.
+ * @search_head: The list to search.
+ * @my_rsv: The reservation we're currently using.
+ * @sb: The super block.
+ * @start_block: The first block we consider to start the real search from
+ * @last_block: The maximum block number that our goal reservable space
+ * could start from.
*
- * @search_head: the head of the searching list;
- * This is not necessarily the list head of the whole filesystem
+ * It does not allocate the reservation window: alloc_new_reservation()
+ * will do the work later.
*
- * We have both head and start_block to assist the search
- * for the reservable space. The list starts from head,
- * but we will shift to the place where start_block is,
- * then start from there, when looking for a reservable space.
+ * We search the given range, rather than the whole reservation double
+ * linked list, (start_block, last_block) to find a free region that is
+ * of my size and has not been reserved.
*
- * @sb: the super block.
+ * @search_head is not necessarily the list head of the whole filesystem.
+ * We have both head and @start_block to assist the search for the
+ * reservable space. The list starts from head, but we will shift to
+ * the place where start_block is, then start from there, when looking
+ * for a reservable space.
*
- * @start_block: the first block we consider to start the real search from
- *
- * @last_block:
- * the maximum block number that our goal reservable space
- * could start from. This is normally the last block in this
- * group. The search will end when we found the start of next
- * possible reservable space is out of this boundary.
- * This could handle the cross boundary reservation window
- * request.
- *
- * basically we search from the given range, rather than the whole
- * reservation double linked list, (start_block, last_block)
- * to find a free region that is of my size and has not
- * been reserved.
+ * @last_block is normally the last block in this group. The search will end
+ * when we found the start of next possible reservable space is out
+ * of this boundary. This could handle the cross boundary reservation
+ * window request.
*
+ * Return: -1 if we could not find a range of sufficient size. If we could,
+ * return 0 and fill in @my_rsv with the range information.
*/
static int find_next_reservable_window(
struct ext2_reserve_window_node *search_head,
@@ -833,41 +831,34 @@ static int find_next_reservable_window(
}
/**
- * alloc_new_reservation()--allocate a new reservation window
- *
- * To make a new reservation, we search part of the filesystem
- * reservation list (the list that inside the group). We try to
- * allocate a new reservation window near the allocation goal,
- * or the beginning of the group, if there is no goal.
- *
- * We first find a reservable space after the goal, then from
- * there, we check the bitmap for the first free block after
- * it. If there is no free block until the end of group, then the
- * whole group is full, we failed. Otherwise, check if the free
- * block is inside the expected reservable space, if so, we
- * succeed.
- * If the first free block is outside the reservable space, then
- * start from the first free block, we search for next available
- * space, and go on.
+ * alloc_new_reservation - Allocate a new reservation window.
+ * @my_rsv: The reservation we're currently using.
+ * @grp_goal: The goal block relative to the start of the group.
+ * @sb: The super block.
+ * @group: The group we are trying to allocate in.
+ * @bitmap_bh: The block group block bitmap.
*
- * on succeed, a new reservation will be found and inserted into the list
- * It contains at least one free block, and it does not overlap with other
- * reservation windows.
+ * To make a new reservation, we search part of the filesystem reservation
+ * list (the list inside the group). We try to allocate a new
+ * reservation window near @grp_goal, or the beginning of the
+ * group, if @grp_goal is negative.
*
- * failed: we failed to find a reservation window in this group
+ * We first find a reservable space after the goal, then from there,
+ * we check the bitmap for the first free block after it. If there is
+ * no free block until the end of group, then the whole group is full,
+ * we failed. Otherwise, check if the free block is inside the expected
+ * reservable space, if so, we succeed.
*
- * @my_rsv: the reservation
+ * If the first free block is outside the reservable space, then start
+ * from the first free block, we search for next available space, and
+ * go on.
*
- * @grp_goal: The goal (group-relative). It is where the search for a
- * free reservable space should start from.
- * if we have a goal(goal >0 ), then start from there,
- * no goal(goal = -1), we start from the first block
- * of the group.
- *
- * @sb: the super block
- * @group: the group we are trying to allocate in
- * @bitmap_bh: the block group block bitmap
+ * on succeed, a new reservation will be found and inserted into the
+ * list. It contains at least one free block, and it does not overlap
+ * with other reservation windows.
*
+ * Return: 0 on success, -1 if we failed to find a reservation window
+ * in this group
*/
static int alloc_new_reservation(struct ext2_reserve_window_node *my_rsv,
ext2_grpblk_t grp_goal, struct super_block *sb,
@@ -1131,8 +1122,13 @@ ext2_try_to_allocate_with_rsv(struct super_block *sb, unsigned int group,
if ((my_rsv->rsv_start > group_last_block) ||
(my_rsv->rsv_end < group_first_block)) {
+ ext2_error(sb, __func__,
+ "Reservation out of group %u range goal %d fsb[%lu,%lu] rsv[%lu, %lu]",
+ group, grp_goal, group_first_block,
+ group_last_block, my_rsv->rsv_start,
+ my_rsv->rsv_end);
rsv_window_dump(&EXT2_SB(sb)->s_rsv_window_root, 1);
- BUG();
+ return -1;
}
ret = ext2_try_to_allocate(sb, group, bitmap_bh, grp_goal,
&num, &my_rsv->rsv_window);
@@ -1193,6 +1189,7 @@ int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk,
* @goal: given target block(filesystem wide)
* @count: target number of blocks to allocate
* @errp: error code
+ * @flags: allocate flags
*
* ext2_new_blocks uses a goal block to assist allocation. If the goal is
* free, or there is a free block within 32 blocks of the goal, that block
@@ -1202,7 +1199,7 @@ int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk,
* This function also updates quota and i_blocks field.
*/
ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
- unsigned long *count, int *errp)
+ unsigned long *count, int *errp, unsigned int flags)
{
struct buffer_head *bitmap_bh = NULL;
struct buffer_head *gdp_bh;
@@ -1241,15 +1238,15 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
es = EXT2_SB(sb)->s_es;
ext2_debug("goal=%lu.\n", goal);
/*
- * Allocate a block from reservation only when
- * filesystem is mounted with reservation(default,-o reservation), and
- * it's a regular file, and
- * the desired window size is greater than 0 (One could use ioctl
- * command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn off
- * reservation on that particular file)
+ * Allocate a block from reservation only when the filesystem is
+ * mounted with reservation(default,-o reservation), and it's a regular
+ * file, and the desired window size is greater than 0 (One could use
+ * ioctl command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn
+ * off reservation on that particular file). Also do not use the
+ * reservation window if the caller asked us not to do it.
*/
block_i = EXT2_I(inode)->i_block_alloc_info;
- if (block_i) {
+ if (!(flags & EXT2_ALLOC_NORESERVE) && block_i) {
windowsz = block_i->rsv_window_node.rsv_goal_size;
if (windowsz > 0)
my_rsv = &block_i->rsv_window_node;
@@ -1429,13 +1426,6 @@ out:
return 0;
}
-ext2_fsblk_t ext2_new_block(struct inode *inode, unsigned long goal, int *errp)
-{
- unsigned long count = 1;
-
- return ext2_new_blocks(inode, goal, &count, errp);
-}
-
#ifdef EXT2FS_DEBUG
unsigned long ext2_count_free(struct buffer_head *map, unsigned int numchars)
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 35a041c47c38..7fdd685c384d 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -399,6 +399,12 @@ struct ext2_inode {
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
/*
+ * Allocation flags
+ */
+#define EXT2_ALLOC_NORESERVE 0x1 /* Do not use reservation
+ * window for allocation */
+
+/*
* Structure of the super block
*/
struct ext2_super_block {
@@ -695,13 +701,11 @@ static inline struct ext2_inode_info *EXT2_I(struct inode *inode)
/* balloc.c */
extern int ext2_bg_has_super(struct super_block *sb, int group);
extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
-extern ext2_fsblk_t ext2_new_block(struct inode *, unsigned long, int *);
-extern ext2_fsblk_t ext2_new_blocks(struct inode *, unsigned long,
- unsigned long *, int *);
+extern ext2_fsblk_t ext2_new_blocks(struct inode *, ext2_fsblk_t,
+ unsigned long *, int *, unsigned int);
extern int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk,
unsigned int count);
-extern void ext2_free_blocks (struct inode *, unsigned long,
- unsigned long);
+extern void ext2_free_blocks(struct inode *, ext2_fsblk_t, unsigned long);
extern unsigned long ext2_count_free_blocks (struct super_block *);
extern unsigned long ext2_count_dirs (struct super_block *);
extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 124df89689e1..c24d0de95a83 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -273,7 +273,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
if ((parent == d_inode(sb->s_root)) ||
(EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) {
- struct ext2_group_desc *best_desc = NULL;
int best_ndir = inodes_per_group;
int best_group = -1;
@@ -291,10 +290,8 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
continue;
best_group = group;
best_ndir = le16_to_cpu(desc->bg_used_dirs_count);
- best_desc = desc;
}
if (best_group >= 0) {
- desc = best_desc;
group = best_group;
goto found;
}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index acbab27fe957..314b415ee518 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -385,12 +385,16 @@ ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks,
}
/**
- * ext2_alloc_blocks: multiple allocate blocks needed for a branch
- * @indirect_blks: the number of blocks need to allocate for indirect
- * blocks
- * @blks: the number of blocks need to allocate for direct blocks
- * @new_blocks: on return it will store the new block numbers for
- * the indirect blocks(if needed) and the first direct block,
+ * ext2_alloc_blocks: Allocate multiple blocks needed for a branch.
+ * @inode: Owner.
+ * @goal: Preferred place for allocation.
+ * @indirect_blks: The number of blocks needed to allocate for indirect blocks.
+ * @blks: The number of blocks need to allocate for direct blocks.
+ * @new_blocks: On return it will store the new block numbers for
+ * the indirect blocks(if needed) and the first direct block.
+ * @err: Error pointer.
+ *
+ * Return: Number of blocks allocated.
*/
static int ext2_alloc_blocks(struct inode *inode,
ext2_fsblk_t goal, int indirect_blks, int blks,
@@ -415,7 +419,7 @@ static int ext2_alloc_blocks(struct inode *inode,
while (1) {
count = target;
/* allocating blocks for indirect blocks and direct blocks */
- current_block = ext2_new_blocks(inode,goal,&count,err);
+ current_block = ext2_new_blocks(inode, goal, &count, err, 0);
if (*err)
goto failed_out;
@@ -1082,8 +1086,8 @@ no_top:
*/
static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
{
- unsigned long block_to_free = 0, count = 0;
- unsigned long nr;
+ ext2_fsblk_t block_to_free = 0, count = 0;
+ ext2_fsblk_t nr;
for ( ; p < q ; p++) {
nr = le32_to_cpu(*p);
@@ -1123,7 +1127,7 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth)
{
struct buffer_head * bh;
- unsigned long nr;
+ ext2_fsblk_t nr;
if (depth--) {
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 1c9187188d68..20f741184673 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -742,10 +742,13 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
/* We need to allocate a new block */
ext2_fsblk_t goal = ext2_group_first_block_no(sb,
EXT2_I(inode)->i_block_group);
- int block = ext2_new_block(inode, goal, &error);
+ unsigned long count = 1;
+ ext2_fsblk_t block = ext2_new_blocks(inode, goal,
+ &count, &error,
+ EXT2_ALLOC_NORESERVE);
if (error)
goto cleanup;
- ea_idebug(inode, "creating block %d", block);
+ ea_idebug(inode, "creating block %lu", block);
new_bh = sb_getblk(sb, block);
if (unlikely(!new_bh)) {