Commit 1500e7e0 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 63580f66 df1ae36a
...@@ -18085,7 +18085,7 @@ F: include/linux/regmap.h ...@@ -18085,7 +18085,7 @@ F: include/linux/regmap.h
REISERFS FILE SYSTEM REISERFS FILE SYSTEM
L: reiserfs-devel@vger.kernel.org L: reiserfs-devel@vger.kernel.org
S: Supported S: Obsolete
F: fs/reiserfs/ F: fs/reiserfs/
REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
......
...@@ -472,8 +472,8 @@ void ext2_discard_reservation(struct inode *inode) ...@@ -472,8 +472,8 @@ void ext2_discard_reservation(struct inode *inode)
* @block: start physical block to free * @block: start physical block to free
* @count: number of blocks to free * @count: number of blocks to free
*/ */
void ext2_free_blocks (struct inode * inode, unsigned long block, void ext2_free_blocks(struct inode * inode, ext2_fsblk_t block,
unsigned long count) unsigned long count)
{ {
struct buffer_head *bitmap_bh = NULL; struct buffer_head *bitmap_bh = NULL;
struct buffer_head * bh2; struct buffer_head * bh2;
...@@ -716,36 +716,34 @@ ext2_try_to_allocate(struct super_block *sb, int group, ...@@ -716,36 +716,34 @@ ext2_try_to_allocate(struct super_block *sb, int group,
} }
/** /**
* find_next_reservable_window(): * find_next_reservable_window - Find a reservable space within the given range.
* find a reservable space within the given range. * @search_head: The list to search.
* It does not allocate the reservation window for now: * @my_rsv: The reservation we're currently using.
* alloc_new_reservation() will do the work later. * @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; * It does not allocate the reservation window: alloc_new_reservation()
* This is not necessarily the list head of the whole filesystem * will do the work later.
* *
* We have both head and start_block to assist the search * We search the given range, rather than the whole reservation double
* for the reservable space. The list starts from head, * linked list, (start_block, last_block) to find a free region that is
* but we will shift to the place where start_block is, * of my size and has not been reserved.
* then start from there, when looking for a reservable space.
* *
* @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 is normally the last block in this group. The search will end
* * when we found the start of next possible reservable space is out
* @last_block: * of this boundary. This could handle the cross boundary reservation
* the maximum block number that our goal reservable space * window request.
* 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.
* *
* 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( static int find_next_reservable_window(
struct ext2_reserve_window_node *search_head, struct ext2_reserve_window_node *search_head,
...@@ -833,41 +831,34 @@ static int find_next_reservable_window( ...@@ -833,41 +831,34 @@ static int find_next_reservable_window(
} }
/** /**
* alloc_new_reservation()--allocate a new reservation window * alloc_new_reservation - Allocate a new reservation window.
* * @my_rsv: The reservation we're currently using.
* To make a new reservation, we search part of the filesystem * @grp_goal: The goal block relative to the start of the group.
* reservation list (the list that inside the group). We try to * @sb: The super block.
* allocate a new reservation window near the allocation goal, * @group: The group we are trying to allocate in.
* or the beginning of the group, if there is no goal. * @bitmap_bh: The block group block bitmap.
*
* 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.
* *
* on succeed, a new reservation will be found and inserted into the list * To make a new reservation, we search part of the filesystem reservation
* It contains at least one free block, and it does not overlap with other * list (the list inside the group). We try to allocate a new
* reservation windows. * 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 * on succeed, a new reservation will be found and inserted into the
* free reservable space should start from. * list. It contains at least one free block, and it does not overlap
* if we have a goal(goal >0 ), then start from there, * with other reservation windows.
* 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
* *
* 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, static int alloc_new_reservation(struct ext2_reserve_window_node *my_rsv,
ext2_grpblk_t grp_goal, struct super_block *sb, 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, ...@@ -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) || if ((my_rsv->rsv_start > group_last_block) ||
(my_rsv->rsv_end < group_first_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); 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, ret = ext2_try_to_allocate(sb, group, bitmap_bh, grp_goal,
&num, &my_rsv->rsv_window); &num, &my_rsv->rsv_window);
...@@ -1193,6 +1189,7 @@ int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk, ...@@ -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) * @goal: given target block(filesystem wide)
* @count: target number of blocks to allocate * @count: target number of blocks to allocate
* @errp: error code * @errp: error code
* @flags: allocate flags
* *
* ext2_new_blocks uses a goal block to assist allocation. If the goal is * 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 * 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, ...@@ -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. * This function also updates quota and i_blocks field.
*/ */
ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, 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 *bitmap_bh = NULL;
struct buffer_head *gdp_bh; struct buffer_head *gdp_bh;
...@@ -1241,15 +1238,15 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, ...@@ -1241,15 +1238,15 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
es = EXT2_SB(sb)->s_es; es = EXT2_SB(sb)->s_es;
ext2_debug("goal=%lu.\n", goal); ext2_debug("goal=%lu.\n", goal);
/* /*
* Allocate a block from reservation only when * Allocate a block from reservation only when the filesystem is
* filesystem is mounted with reservation(default,-o reservation), and * mounted with reservation(default,-o reservation), and it's a regular
* it's a regular file, and * file, and the desired window size is greater than 0 (One could use
* the desired window size is greater than 0 (One could use ioctl * ioctl command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn
* command EXT2_IOC_SETRSVSZ to set the window size to 0 to turn off * off reservation on that particular file). Also do not use the
* reservation on that particular file) * reservation window if the caller asked us not to do it.
*/ */
block_i = EXT2_I(inode)->i_block_alloc_info; 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; windowsz = block_i->rsv_window_node.rsv_goal_size;
if (windowsz > 0) if (windowsz > 0)
my_rsv = &block_i->rsv_window_node; my_rsv = &block_i->rsv_window_node;
...@@ -1429,13 +1426,6 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal, ...@@ -1429,13 +1426,6 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
return 0; 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 #ifdef EXT2FS_DEBUG
unsigned long ext2_count_free(struct buffer_head *map, unsigned int numchars) unsigned long ext2_count_free(struct buffer_head *map, unsigned int numchars)
......
...@@ -398,6 +398,12 @@ struct ext2_inode { ...@@ -398,6 +398,12 @@ struct ext2_inode {
#define EXT2_ERRORS_PANIC 3 /* Panic */ #define EXT2_ERRORS_PANIC 3 /* Panic */
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE #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 * Structure of the super block
*/ */
...@@ -695,13 +701,11 @@ static inline struct ext2_inode_info *EXT2_I(struct inode *inode) ...@@ -695,13 +701,11 @@ static inline struct ext2_inode_info *EXT2_I(struct inode *inode)
/* balloc.c */ /* balloc.c */
extern int ext2_bg_has_super(struct super_block *sb, int group); 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 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 *, ext2_fsblk_t,
extern ext2_fsblk_t ext2_new_blocks(struct inode *, unsigned long, unsigned long *, int *, unsigned int);
unsigned long *, int *);
extern int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk, extern int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk,
unsigned int count); unsigned int count);
extern void ext2_free_blocks (struct inode *, unsigned long, extern void ext2_free_blocks(struct inode *, ext2_fsblk_t, unsigned long);
unsigned long);
extern unsigned long ext2_count_free_blocks (struct super_block *); extern unsigned long ext2_count_free_blocks (struct super_block *);
extern unsigned long ext2_count_dirs (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, extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
......
...@@ -273,7 +273,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ...@@ -273,7 +273,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
if ((parent == d_inode(sb->s_root)) || if ((parent == d_inode(sb->s_root)) ||
(EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) { (EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) {
struct ext2_group_desc *best_desc = NULL;
int best_ndir = inodes_per_group; int best_ndir = inodes_per_group;
int best_group = -1; int best_group = -1;
...@@ -291,10 +290,8 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ...@@ -291,10 +290,8 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
continue; continue;
best_group = group; best_group = group;
best_ndir = le16_to_cpu(desc->bg_used_dirs_count); best_ndir = le16_to_cpu(desc->bg_used_dirs_count);
best_desc = desc;
} }
if (best_group >= 0) { if (best_group >= 0) {
desc = best_desc;
group = best_group; group = best_group;
goto found; goto found;
} }
......
...@@ -385,12 +385,16 @@ ext2_blks_to_allocate(Indirect * branch, int k, unsigned long blks, ...@@ -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 * ext2_alloc_blocks: Allocate multiple blocks needed for a branch.
* @indirect_blks: the number of blocks need to allocate for indirect * @inode: Owner.
* blocks * @goal: Preferred place for allocation.
* @blks: the number of blocks need to allocate for direct blocks * @indirect_blks: The number of blocks needed to allocate for indirect blocks.
* @new_blocks: on return it will store the new block numbers for * @blks: The number of blocks need to allocate for direct blocks.
* the indirect blocks(if needed) and the first direct block, * @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, static int ext2_alloc_blocks(struct inode *inode,
ext2_fsblk_t goal, int indirect_blks, int blks, ext2_fsblk_t goal, int indirect_blks, int blks,
...@@ -415,7 +419,7 @@ static int ext2_alloc_blocks(struct inode *inode, ...@@ -415,7 +419,7 @@ static int ext2_alloc_blocks(struct inode *inode,
while (1) { while (1) {
count = target; count = target;
/* allocating blocks for indirect blocks and direct blocks */ /* 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) if (*err)
goto failed_out; goto failed_out;
...@@ -1082,8 +1086,8 @@ static Indirect *ext2_find_shared(struct inode *inode, ...@@ -1082,8 +1086,8 @@ static Indirect *ext2_find_shared(struct inode *inode,
*/ */
static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
{ {
unsigned long block_to_free = 0, count = 0; ext2_fsblk_t block_to_free = 0, count = 0;
unsigned long nr; ext2_fsblk_t nr;
for ( ; p < q ; p++) { for ( ; p < q ; p++) {
nr = le32_to_cpu(*p); nr = le32_to_cpu(*p);
...@@ -1123,7 +1127,7 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) ...@@ -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) static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth)
{ {
struct buffer_head * bh; struct buffer_head * bh;
unsigned long nr; ext2_fsblk_t nr;
if (depth--) { if (depth--) {
int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
......
...@@ -742,10 +742,13 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, ...@@ -742,10 +742,13 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh,
/* We need to allocate a new block */ /* We need to allocate a new block */
ext2_fsblk_t goal = ext2_group_first_block_no(sb, ext2_fsblk_t goal = ext2_group_first_block_no(sb,
EXT2_I(inode)->i_block_group); 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) if (error)
goto cleanup; goto cleanup;
ea_idebug(inode, "creating block %d", block); ea_idebug(inode, "creating block %lu", block);
new_bh = sb_getblk(sb, block); new_bh = sb_getblk(sb, block);
if (unlikely(!new_bh)) { if (unlikely(!new_bh)) {
......
...@@ -225,13 +225,22 @@ static void put_quota_format(struct quota_format_type *fmt) ...@@ -225,13 +225,22 @@ static void put_quota_format(struct quota_format_type *fmt)
/* /*
* Dquot List Management: * Dquot List Management:
* The quota code uses four lists for dquot management: the inuse_list, * The quota code uses five lists for dquot management: the inuse_list,
* free_dquots, dqi_dirty_list, and dquot_hash[] array. A single dquot * releasing_dquots, free_dquots, dqi_dirty_list, and dquot_hash[] array.
* structure may be on some of those lists, depending on its current state. * A single dquot structure may be on some of those lists, depending on
* its current state.
* *
* All dquots are placed to the end of inuse_list when first created, and this * All dquots are placed to the end of inuse_list when first created, and this
* list is used for invalidate operation, which must look at every dquot. * list is used for invalidate operation, which must look at every dquot.
* *
* When the last reference of a dquot will be dropped, the dquot will be
* added to releasing_dquots. We'd then queue work item which would call
* synchronize_srcu() and after that perform the final cleanup of all the
* dquots on the list. Both releasing_dquots and free_dquots use the
* dq_free list_head in the dquot struct. When a dquot is removed from
* releasing_dquots, a reference count is always subtracted, and if
* dq_count == 0 at that point, the dquot will be added to the free_dquots.
*
* Unused dquots (dq_count == 0) are added to the free_dquots list when freed, * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
* and this list is searched whenever we need an available dquot. Dquots are * and this list is searched whenever we need an available dquot. Dquots are
* removed from the list as soon as they are used again, and * removed from the list as soon as they are used again, and
...@@ -250,6 +259,7 @@ static void put_quota_format(struct quota_format_type *fmt) ...@@ -250,6 +259,7 @@ static void put_quota_format(struct quota_format_type *fmt)
static LIST_HEAD(inuse_list); static LIST_HEAD(inuse_list);
static LIST_HEAD(free_dquots); static LIST_HEAD(free_dquots);
static LIST_HEAD(releasing_dquots);
static unsigned int dq_hash_bits, dq_hash_mask; static unsigned int dq_hash_bits, dq_hash_mask;
static struct hlist_head *dquot_hash; static struct hlist_head *dquot_hash;
...@@ -260,6 +270,9 @@ static qsize_t inode_get_rsv_space(struct inode *inode); ...@@ -260,6 +270,9 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
static qsize_t __inode_get_rsv_space(struct inode *inode); static qsize_t __inode_get_rsv_space(struct inode *inode);
static int __dquot_initialize(struct inode *inode, int type); static int __dquot_initialize(struct inode *inode, int type);
static void quota_release_workfn(struct work_struct *work);
static DECLARE_DELAYED_WORK(quota_release_work, quota_release_workfn);
static inline unsigned int static inline unsigned int
hashfn(const struct super_block *sb, struct kqid qid) hashfn(const struct super_block *sb, struct kqid qid)
{ {
...@@ -305,12 +318,18 @@ static inline void put_dquot_last(struct dquot *dquot) ...@@ -305,12 +318,18 @@ static inline void put_dquot_last(struct dquot *dquot)
dqstats_inc(DQST_FREE_DQUOTS); dqstats_inc(DQST_FREE_DQUOTS);
} }
static inline void put_releasing_dquots(struct dquot *dquot)
{
list_add_tail(&dquot->dq_free, &releasing_dquots);
}
static inline void remove_free_dquot(struct dquot *dquot) static inline void remove_free_dquot(struct dquot *dquot)
{ {
if (list_empty(&dquot->dq_free)) if (list_empty(&dquot->dq_free))
return; return;
list_del_init(&dquot->dq_free); list_del_init(&dquot->dq_free);
dqstats_dec(DQST_FREE_DQUOTS); if (!atomic_read(&dquot->dq_count))
dqstats_dec(DQST_FREE_DQUOTS);
} }
static inline void put_inuse(struct dquot *dquot) static inline void put_inuse(struct dquot *dquot)
...@@ -336,6 +355,11 @@ static void wait_on_dquot(struct dquot *dquot) ...@@ -336,6 +355,11 @@ static void wait_on_dquot(struct dquot *dquot)
mutex_unlock(&dquot->dq_lock); mutex_unlock(&dquot->dq_lock);
} }
static inline int dquot_active(struct dquot *dquot)
{
return test_bit(DQ_ACTIVE_B, &dquot->dq_flags);
}
static inline int dquot_dirty(struct dquot *dquot) static inline int dquot_dirty(struct dquot *dquot)
{ {
return test_bit(DQ_MOD_B, &dquot->dq_flags); return test_bit(DQ_MOD_B, &dquot->dq_flags);
...@@ -351,14 +375,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot) ...@@ -351,14 +375,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
{ {
int ret = 1; int ret = 1;
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) if (!dquot_active(dquot))
return 0; return 0;
if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NOLIST_DIRTY) if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NOLIST_DIRTY)
return test_and_set_bit(DQ_MOD_B, &dquot->dq_flags); return test_and_set_bit(DQ_MOD_B, &dquot->dq_flags);
/* If quota is dirty already, we don't have to acquire dq_list_lock */ /* If quota is dirty already, we don't have to acquire dq_list_lock */
if (test_bit(DQ_MOD_B, &dquot->dq_flags)) if (dquot_dirty(dquot))
return 1; return 1;
spin_lock(&dq_list_lock); spin_lock(&dq_list_lock);
...@@ -440,7 +464,7 @@ int dquot_acquire(struct dquot *dquot) ...@@ -440,7 +464,7 @@ int dquot_acquire(struct dquot *dquot)
smp_mb__before_atomic(); smp_mb__before_atomic();
set_bit(DQ_READ_B, &dquot->dq_flags); set_bit(DQ_READ_B, &dquot->dq_flags);
/* Instantiate dquot if needed */ /* Instantiate dquot if needed */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && !dquot->dq_off) { if (!dquot_active(dquot) && !dquot->dq_off) {
ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
/* Write the info if needed */ /* Write the info if needed */
if (info_dirty(&dqopt->info[dquot->dq_id.type])) { if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
...@@ -482,7 +506,7 @@ int dquot_commit(struct dquot *dquot) ...@@ -482,7 +506,7 @@ int dquot_commit(struct dquot *dquot)
goto out_lock; goto out_lock;
/* Inactive dquot can be only if there was error during read/init /* Inactive dquot can be only if there was error during read/init
* => we have better not writing it */ * => we have better not writing it */
if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) if (dquot_active(dquot))
ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot); ret = dqopt->ops[dquot->dq_id.type]->commit_dqblk(dquot);
else else
ret = -EIO; ret = -EIO;
...@@ -547,6 +571,8 @@ static void invalidate_dquots(struct super_block *sb, int type) ...@@ -547,6 +571,8 @@ static void invalidate_dquots(struct super_block *sb, int type)
struct dquot *dquot, *tmp; struct dquot *dquot, *tmp;
restart: restart:
flush_delayed_work(&quota_release_work);
spin_lock(&dq_list_lock); spin_lock(&dq_list_lock);
list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
if (dquot->dq_sb != sb) if (dquot->dq_sb != sb)
...@@ -555,6 +581,12 @@ static void invalidate_dquots(struct super_block *sb, int type) ...@@ -555,6 +581,12 @@ static void invalidate_dquots(struct super_block *sb, int type)
continue; continue;
/* Wait for dquot users */ /* Wait for dquot users */
if (atomic_read(&dquot->dq_count)) { if (atomic_read(&dquot->dq_count)) {
/* dquot in releasing_dquots, flush and retry */
if (!list_empty(&dquot->dq_free)) {
spin_unlock(&dq_list_lock);
goto restart;
}
atomic_inc(&dquot->dq_count); atomic_inc(&dquot->dq_count);
spin_unlock(&dq_list_lock); spin_unlock(&dq_list_lock);
/* /*
...@@ -597,7 +629,7 @@ int dquot_scan_active(struct super_block *sb, ...@@ -597,7 +629,7 @@ int dquot_scan_active(struct super_block *sb,
spin_lock(&dq_list_lock); spin_lock(&dq_list_lock);
list_for_each_entry(dquot, &inuse_list, dq_inuse) { list_for_each_entry(dquot, &inuse_list, dq_inuse) {
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) if (!dquot_active(dquot))
continue; continue;
if (dquot->dq_sb != sb) if (dquot->dq_sb != sb)
continue; continue;
...@@ -612,7 +644,7 @@ int dquot_scan_active(struct super_block *sb, ...@@ -612,7 +644,7 @@ int dquot_scan_active(struct super_block *sb,
* outstanding call and recheck the DQ_ACTIVE_B after that. * outstanding call and recheck the DQ_ACTIVE_B after that.
*/ */
wait_on_dquot(dquot); wait_on_dquot(dquot);
if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { if (dquot_active(dquot)) {
ret = fn(dquot, priv); ret = fn(dquot, priv);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -628,6 +660,18 @@ int dquot_scan_active(struct super_block *sb, ...@@ -628,6 +660,18 @@ int dquot_scan_active(struct super_block *sb,
} }
EXPORT_SYMBOL(dquot_scan_active); EXPORT_SYMBOL(dquot_scan_active);
static inline int dquot_write_dquot(struct dquot *dquot)
{
int ret = dquot->dq_sb->dq_op->write_dquot(dquot);
if (ret < 0) {
quota_error(dquot->dq_sb, "Can't write quota structure "
"(error %d). Quota may get out of sync!", ret);
/* Clear dirty bit anyway to avoid infinite loop. */
clear_dquot_dirty(dquot);
}
return ret;
}
/* Write all dquot structures to quota files */ /* Write all dquot structures to quota files */
int dquot_writeback_dquots(struct super_block *sb, int type) int dquot_writeback_dquots(struct super_block *sb, int type)
{ {
...@@ -651,23 +695,16 @@ int dquot_writeback_dquots(struct super_block *sb, int type) ...@@ -651,23 +695,16 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
dquot = list_first_entry(&dirty, struct dquot, dquot = list_first_entry(&dirty, struct dquot,
dq_dirty); dq_dirty);
WARN_ON(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); WARN_ON(!dquot_active(dquot));
/* Now we have active dquot from which someone is /* Now we have active dquot from which someone is
* holding reference so we can safely just increase * holding reference so we can safely just increase
* use count */ * use count */
dqgrab(dquot); dqgrab(dquot);
spin_unlock(&dq_list_lock); spin_unlock(&dq_list_lock);
err = sb->dq_op->write_dquot(dquot); err = dquot_write_dquot(dquot);
if (err) { if (err && !ret)
/* ret = err;
* Clear dirty bit anyway to avoid infinite
* loop here.
*/
clear_dquot_dirty(dquot);
if (!ret)
ret = err;
}
dqput(dquot); dqput(dquot);
spin_lock(&dq_list_lock); spin_lock(&dq_list_lock);
} }
...@@ -760,13 +797,54 @@ static struct shrinker dqcache_shrinker = { ...@@ -760,13 +797,54 @@ static struct shrinker dqcache_shrinker = {
.seeks = DEFAULT_SEEKS, .seeks = DEFAULT_SEEKS,
}; };
/*
* Safely release dquot and put reference to dquot.
*/
static void quota_release_workfn(struct work_struct *work)
{
struct dquot *dquot;
struct list_head rls_head;
spin_lock(&dq_list_lock);
/* Exchange the list head to avoid livelock. */
list_replace_init(&releasing_dquots, &rls_head);
spin_unlock(&dq_list_lock);
restart:
synchronize_srcu(&dquot_srcu);
spin_lock(&dq_list_lock);
while (!list_empty(&rls_head)) {
dquot = list_first_entry(&rls_head, struct dquot, dq_free);
/* Dquot got used again? */
if (atomic_read(&dquot->dq_count) > 1) {
remove_free_dquot(dquot);
atomic_dec(&dquot->dq_count);
continue;
}
if (dquot_dirty(dquot)) {
spin_unlock(&dq_list_lock);
/* Commit dquot before releasing */
dquot_write_dquot(dquot);
goto restart;
}
if (dquot_active(dquot)) {
spin_unlock(&dq_list_lock);
dquot->dq_sb->dq_op->release_dquot(dquot);
goto restart;
}
/* Dquot is inactive and clean, now move it to free list */
remove_free_dquot(dquot);
atomic_dec(&dquot->dq_count);
put_dquot_last(dquot);
}
spin_unlock(&dq_list_lock);
}
/* /*
* Put reference to dquot * Put reference to dquot
*/ */
void dqput(struct dquot *dquot) void dqput(struct dquot *dquot)
{ {
int ret;
if (!dquot) if (!dquot)
return; return;
#ifdef CONFIG_QUOTA_DEBUG #ifdef CONFIG_QUOTA_DEBUG
...@@ -778,7 +856,7 @@ void dqput(struct dquot *dquot) ...@@ -778,7 +856,7 @@ void dqput(struct dquot *dquot)
} }
#endif #endif
dqstats_inc(DQST_DROPS); dqstats_inc(DQST_DROPS);
we_slept:
spin_lock(&dq_list_lock); spin_lock(&dq_list_lock);
if (atomic_read(&dquot->dq_count) > 1) { if (atomic_read(&dquot->dq_count) > 1) {
/* We have more than one user... nothing to do */ /* We have more than one user... nothing to do */
...@@ -790,35 +868,15 @@ void dqput(struct dquot *dquot) ...@@ -790,35 +868,15 @@ void dqput(struct dquot *dquot)
spin_unlock(&dq_list_lock); spin_unlock(&dq_list_lock);
return; return;
} }
/* Need to release dquot? */ /* Need to release dquot? */
if (dquot_dirty(dquot)) {
spin_unlock(&dq_list_lock);
/* Commit dquot before releasing */
ret = dquot->dq_sb->dq_op->write_dquot(dquot);
if (ret < 0) {
quota_error(dquot->dq_sb, "Can't write quota structure"
" (error %d). Quota may get out of sync!",
ret);
/*
* We clear dirty bit anyway, so that we avoid
* infinite loop here
*/
clear_dquot_dirty(dquot);
}
goto we_slept;
}
if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
spin_unlock(&dq_list_lock);
dquot->dq_sb->dq_op->release_dquot(dquot);
goto we_slept;
}
atomic_dec(&dquot->dq_count);
#ifdef CONFIG_QUOTA_DEBUG #ifdef CONFIG_QUOTA_DEBUG
/* sanity check */ /* sanity check */
BUG_ON(!list_empty(&dquot->dq_free)); BUG_ON(!list_empty(&dquot->dq_free));
#endif #endif
put_dquot_last(dquot); put_releasing_dquots(dquot);
spin_unlock(&dq_list_lock); spin_unlock(&dq_list_lock);
queue_delayed_work(system_unbound_wq, &quota_release_work, 1);
} }
EXPORT_SYMBOL(dqput); EXPORT_SYMBOL(dqput);
...@@ -908,7 +966,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid) ...@@ -908,7 +966,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
* already finished or it will be canceled due to dq_count > 1 test */ * already finished or it will be canceled due to dq_count > 1 test */
wait_on_dquot(dquot); wait_on_dquot(dquot);
/* Read the dquot / allocate space in quota file */ /* Read the dquot / allocate space in quota file */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { if (!dquot_active(dquot)) {
int err; int err;
err = sb->dq_op->acquire_dquot(dquot); err = sb->dq_op->acquire_dquot(dquot);
...@@ -1014,59 +1072,7 @@ static int add_dquot_ref(struct super_block *sb, int type) ...@@ -1014,59 +1072,7 @@ static int add_dquot_ref(struct super_block *sb, int type)
return err; return err;
} }
/* static void remove_dquot_ref(struct super_block *sb, int type)
* Remove references to dquots from inode and add dquot to list for freeing
* if we have the last reference to dquot
*/
static void remove_inode_dquot_ref(struct inode *inode, int type,
struct list_head *tofree_head)
{
struct dquot **dquots = i_dquot(inode);
struct dquot *dquot = dquots[type];
if (!dquot)
return;
dquots[type] = NULL;
if (list_empty(&dquot->dq_free)) {
/*
* The inode still has reference to dquot so it can't be in the
* free list
*/
spin_lock(&dq_list_lock);
list_add(&dquot->dq_free, tofree_head);
spin_unlock(&dq_list_lock);
} else {
/*
* Dquot is already in a list to put so we won't drop the last
* reference here.
*/
dqput(dquot);
}
}
/*
* Free list of dquots
* Dquots are removed from inodes and no new references can be got so we are
* the only ones holding reference
*/
static void put_dquot_list(struct list_head *tofree_head)
{
struct list_head *act_head;
struct dquot *dquot;
act_head = tofree_head->next;
while (act_head != tofree_head) {
dquot = list_entry(act_head, struct dquot, dq_free);
act_head = act_head->next;
/* Remove dquot from the list so we won't have problems... */
list_del_init(&dquot->dq_free);
dqput(dquot);
}
}
static void remove_dquot_ref(struct super_block *sb, int type,
struct list_head *tofree_head)
{ {
struct inode *inode; struct inode *inode;
#ifdef CONFIG_QUOTA_DEBUG #ifdef CONFIG_QUOTA_DEBUG
...@@ -1083,11 +1089,16 @@ static void remove_dquot_ref(struct super_block *sb, int type, ...@@ -1083,11 +1089,16 @@ static void remove_dquot_ref(struct super_block *sb, int type,
*/ */
spin_lock(&dq_data_lock); spin_lock(&dq_data_lock);
if (!IS_NOQUOTA(inode)) { if (!IS_NOQUOTA(inode)) {
struct dquot **dquots = i_dquot(inode);
struct dquot *dquot = dquots[type];
#ifdef CONFIG_QUOTA_DEBUG #ifdef CONFIG_QUOTA_DEBUG
if (unlikely(inode_get_rsv_space(inode) > 0)) if (unlikely(inode_get_rsv_space(inode) > 0))
reserved = 1; reserved = 1;
#endif #endif
remove_inode_dquot_ref(inode, type, tofree_head); dquots[type] = NULL;
if (dquot)
dqput(dquot);
} }
spin_unlock(&dq_data_lock); spin_unlock(&dq_data_lock);
} }
...@@ -1104,13 +1115,8 @@ static void remove_dquot_ref(struct super_block *sb, int type, ...@@ -1104,13 +1115,8 @@ static void remove_dquot_ref(struct super_block *sb, int type,
/* Gather all references from inodes and drop them */ /* Gather all references from inodes and drop them */
static void drop_dquot_ref(struct super_block *sb, int type) static void drop_dquot_ref(struct super_block *sb, int type)
{ {
LIST_HEAD(tofree_head); if (sb->dq_op)
remove_dquot_ref(sb, type);
if (sb->dq_op) {
remove_dquot_ref(sb, type, &tofree_head);
synchronize_srcu(&dquot_srcu);
put_dquot_list(&tofree_head);
}
} }
static inline static inline
...@@ -1425,7 +1431,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space) ...@@ -1425,7 +1431,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
return QUOTA_NL_NOWARN; return QUOTA_NL_NOWARN;
} }
static int dquot_active(const struct inode *inode) static int inode_quota_active(const struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
...@@ -1448,7 +1454,7 @@ static int __dquot_initialize(struct inode *inode, int type) ...@@ -1448,7 +1454,7 @@ static int __dquot_initialize(struct inode *inode, int type)
qsize_t rsv; qsize_t rsv;
int ret = 0; int ret = 0;
if (!dquot_active(inode)) if (!inode_quota_active(inode))
return 0; return 0;
dquots = i_dquot(inode); dquots = i_dquot(inode);
...@@ -1556,7 +1562,7 @@ bool dquot_initialize_needed(struct inode *inode) ...@@ -1556,7 +1562,7 @@ bool dquot_initialize_needed(struct inode *inode)
struct dquot **dquots; struct dquot **dquots;
int i; int i;
if (!dquot_active(inode)) if (!inode_quota_active(inode))
return false; return false;
dquots = i_dquot(inode); dquots = i_dquot(inode);
...@@ -1667,7 +1673,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags) ...@@ -1667,7 +1673,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
int reserve = flags & DQUOT_SPACE_RESERVE; int reserve = flags & DQUOT_SPACE_RESERVE;
struct dquot **dquots; struct dquot **dquots;
if (!dquot_active(inode)) { if (!inode_quota_active(inode)) {
if (reserve) { if (reserve) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
*inode_reserved_space(inode) += number; *inode_reserved_space(inode) += number;
...@@ -1737,7 +1743,7 @@ int dquot_alloc_inode(struct inode *inode) ...@@ -1737,7 +1743,7 @@ int dquot_alloc_inode(struct inode *inode)
struct dquot_warn warn[MAXQUOTAS]; struct dquot_warn warn[MAXQUOTAS];
struct dquot * const *dquots; struct dquot * const *dquots;
if (!dquot_active(inode)) if (!inode_quota_active(inode))
return 0; return 0;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) for (cnt = 0; cnt < MAXQUOTAS; cnt++)
warn[cnt].w_type = QUOTA_NL_NOWARN; warn[cnt].w_type = QUOTA_NL_NOWARN;
...@@ -1780,7 +1786,7 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) ...@@ -1780,7 +1786,7 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
struct dquot **dquots; struct dquot **dquots;
int cnt, index; int cnt, index;
if (!dquot_active(inode)) { if (!inode_quota_active(inode)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
*inode_reserved_space(inode) -= number; *inode_reserved_space(inode) -= number;
__inode_add_bytes(inode, number); __inode_add_bytes(inode, number);
...@@ -1822,7 +1828,7 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number) ...@@ -1822,7 +1828,7 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
struct dquot **dquots; struct dquot **dquots;
int cnt, index; int cnt, index;
if (!dquot_active(inode)) { if (!inode_quota_active(inode)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
*inode_reserved_space(inode) += number; *inode_reserved_space(inode) += number;
__inode_sub_bytes(inode, number); __inode_sub_bytes(inode, number);
...@@ -1866,7 +1872,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags) ...@@ -1866,7 +1872,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
struct dquot **dquots; struct dquot **dquots;
int reserve = flags & DQUOT_SPACE_RESERVE, index; int reserve = flags & DQUOT_SPACE_RESERVE, index;
if (!dquot_active(inode)) { if (!inode_quota_active(inode)) {
if (reserve) { if (reserve) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
*inode_reserved_space(inode) -= number; *inode_reserved_space(inode) -= number;
...@@ -1921,7 +1927,7 @@ void dquot_free_inode(struct inode *inode) ...@@ -1921,7 +1927,7 @@ void dquot_free_inode(struct inode *inode)
struct dquot * const *dquots; struct dquot * const *dquots;
int index; int index;
if (!dquot_active(inode)) if (!inode_quota_active(inode))
return; return;
dquots = i_dquot(inode); dquots = i_dquot(inode);
...@@ -2093,7 +2099,7 @@ int dquot_transfer(struct mnt_idmap *idmap, struct inode *inode, ...@@ -2093,7 +2099,7 @@ int dquot_transfer(struct mnt_idmap *idmap, struct inode *inode,
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
int ret; int ret;
if (!dquot_active(inode)) if (!inode_quota_active(inode))
return 0; return 0;
if (i_uid_needs_update(idmap, iattr, inode)) { if (i_uid_needs_update(idmap, iattr, inode)) {
...@@ -2359,11 +2365,10 @@ int dquot_load_quota_sb(struct super_block *sb, int type, int format_id, ...@@ -2359,11 +2365,10 @@ int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
struct quota_info *dqopt = sb_dqopt(sb); struct quota_info *dqopt = sb_dqopt(sb);
int error; int error;
lockdep_assert_held_write(&sb->s_umount);
/* Just unsuspend quotas? */ /* Just unsuspend quotas? */
BUG_ON(flags & DQUOT_SUSPENDED); BUG_ON(flags & DQUOT_SUSPENDED);
/* s_umount should be held in exclusive mode */
if (WARN_ON_ONCE(down_read_trylock(&sb->s_umount)))
up_read(&sb->s_umount);
if (!fmt) if (!fmt)
return -ESRCH; return -ESRCH;
......
...@@ -95,7 +95,7 @@ static int udf_copy_fi(struct udf_fileident_iter *iter) ...@@ -95,7 +95,7 @@ static int udf_copy_fi(struct udf_fileident_iter *iter)
} }
off = iter->pos & (blksize - 1); off = iter->pos & (blksize - 1);
len = min_t(int, sizeof(struct fileIdentDesc), blksize - off); len = min_t(u32, sizeof(struct fileIdentDesc), blksize - off);
memcpy(&iter->fi, iter->bh[0]->b_data + off, len); memcpy(&iter->fi, iter->bh[0]->b_data + off, len);
if (len < sizeof(struct fileIdentDesc)) if (len < sizeof(struct fileIdentDesc))
memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data, memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data,
......
...@@ -352,8 +352,6 @@ int udf_expand_file_adinicb(struct inode *inode) ...@@ -352,8 +352,6 @@ int udf_expand_file_adinicb(struct inode *inode)
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
/* from now on we have normal address_space methods */
inode->i_data.a_ops = &udf_aops;
up_write(&iinfo->i_data_sem); up_write(&iinfo->i_data_sem);
mark_inode_dirty(inode); mark_inode_dirty(inode);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment