Merge tag 'for_v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 30 Aug 2023 19:10:50 +0000 (12:10 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 30 Aug 2023 19:10:50 +0000 (12:10 -0700)
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

MAINTAINERS
fs/ext2/balloc.c
fs/ext2/ext2.h
fs/ext2/ialloc.c
fs/ext2/inode.c
fs/ext2/xattr.c
fs/quota/dquot.c
fs/udf/directory.c
fs/udf/inode.c

index 2421788..b4df342 100644 (file)
@@ -18085,7 +18085,7 @@ F:      include/linux/regmap.h
 
 REISERFS FILE SYSTEM
 L:     reiserfs-devel@vger.kernel.org
-S:     Supported
+S:     Obsolete
 F:     fs/reiserfs/
 
 REMOTE PROCESSOR (REMOTEPROC) SUBSYSTEM
index c8049c9..e124f3d 100644 (file)
@@ -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)
index 35a041c..7fdd685 100644 (file)
@@ -398,6 +398,12 @@ struct ext2_inode {
 #define EXT2_ERRORS_PANIC              3       /* Panic */
 #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
  */
@@ -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,
index 124df89..c24d0de 100644 (file)
@@ -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;
                }
index acbab27..314b415 100644 (file)
@@ -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);
index 1c91871..20f7411 100644 (file)
@@ -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)) {
index 4d826c3..9e72bfe 100644 (file)
@@ -225,13 +225,22 @@ static void put_quota_format(struct quota_format_type *fmt)
 
 /*
  * Dquot List Management:
- * The quota code uses four lists for dquot management: the inuse_list,
- * free_dquots, dqi_dirty_list, and dquot_hash[] array. A single dquot
- * structure may be on some of those lists, depending on its current state.
+ * The quota code uses five lists for dquot management: the inuse_list,
+ * releasing_dquots, free_dquots, dqi_dirty_list, and dquot_hash[] array.
+ * 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
  * 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,
  * 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
@@ -250,6 +259,7 @@ static void put_quota_format(struct quota_format_type *fmt)
 
 static LIST_HEAD(inuse_list);
 static LIST_HEAD(free_dquots);
+static LIST_HEAD(releasing_dquots);
 static unsigned int dq_hash_bits, dq_hash_mask;
 static struct hlist_head *dquot_hash;
 
@@ -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 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
 hashfn(const struct super_block *sb, struct kqid qid)
 {
@@ -305,12 +318,18 @@ static inline void put_dquot_last(struct dquot *dquot)
        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)
 {
        if (list_empty(&dquot->dq_free))
                return;
        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)
@@ -336,6 +355,11 @@ static void wait_on_dquot(struct dquot *dquot)
        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)
 {
        return test_bit(DQ_MOD_B, &dquot->dq_flags);
@@ -351,14 +375,14 @@ int dquot_mark_dquot_dirty(struct dquot *dquot)
 {
        int ret = 1;
 
-       if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
+       if (!dquot_active(dquot))
                return 0;
 
        if (sb_dqopt(dquot->dq_sb)->flags & DQUOT_NOLIST_DIRTY)
                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 (test_bit(DQ_MOD_B, &dquot->dq_flags))
+       if (dquot_dirty(dquot))
                return 1;
 
        spin_lock(&dq_list_lock);
@@ -440,7 +464,7 @@ int dquot_acquire(struct dquot *dquot)
        smp_mb__before_atomic();
        set_bit(DQ_READ_B, &dquot->dq_flags);
        /* 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);
                /* Write the info if needed */
                if (info_dirty(&dqopt->info[dquot->dq_id.type])) {
@@ -482,7 +506,7 @@ int dquot_commit(struct dquot *dquot)
                goto out_lock;
        /* Inactive dquot can be only if there was error during read/init
         * => 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);
        else
                ret = -EIO;
@@ -547,6 +571,8 @@ static void invalidate_dquots(struct super_block *sb, int type)
        struct dquot *dquot, *tmp;
 
 restart:
+       flush_delayed_work(&quota_release_work);
+
        spin_lock(&dq_list_lock);
        list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
                if (dquot->dq_sb != sb)
@@ -555,6 +581,12 @@ restart:
                        continue;
                /* Wait for dquot users */
                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);
                        spin_unlock(&dq_list_lock);
                        /*
@@ -597,7 +629,7 @@ int dquot_scan_active(struct super_block *sb,
 
        spin_lock(&dq_list_lock);
        list_for_each_entry(dquot, &inuse_list, dq_inuse) {
-               if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
+               if (!dquot_active(dquot))
                        continue;
                if (dquot->dq_sb != sb)
                        continue;
@@ -612,7 +644,7 @@ int dquot_scan_active(struct super_block *sb,
                 * outstanding call and recheck the DQ_ACTIVE_B after that.
                 */
                wait_on_dquot(dquot);
-               if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+               if (dquot_active(dquot)) {
                        ret = fn(dquot, priv);
                        if (ret < 0)
                                goto out;
@@ -628,6 +660,18 @@ out:
 }
 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 */
 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,
                                                 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
                         * holding reference so we can safely just increase
                         * use count */
                        dqgrab(dquot);
                        spin_unlock(&dq_list_lock);
-                       err = sb->dq_op->write_dquot(dquot);
-                       if (err) {
-                               /*
-                                * Clear dirty bit anyway to avoid infinite
-                                * loop here.
-                                */
-                               clear_dquot_dirty(dquot);
-                               if (!ret)
-                                       ret = err;
-                       }
+                       err = dquot_write_dquot(dquot);
+                       if (err && !ret)
+                               ret = err;
                        dqput(dquot);
                        spin_lock(&dq_list_lock);
                }
@@ -760,13 +797,54 @@ static struct shrinker dqcache_shrinker = {
        .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
  */
 void dqput(struct dquot *dquot)
 {
-       int ret;
-
        if (!dquot)
                return;
 #ifdef CONFIG_QUOTA_DEBUG
@@ -778,7 +856,7 @@ void dqput(struct dquot *dquot)
        }
 #endif
        dqstats_inc(DQST_DROPS);
-we_slept:
+
        spin_lock(&dq_list_lock);
        if (atomic_read(&dquot->dq_count) > 1) {
                /* We have more than one user... nothing to do */
@@ -790,35 +868,15 @@ we_slept:
                spin_unlock(&dq_list_lock);
                return;
        }
+
        /* 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
        /* sanity check */
        BUG_ON(!list_empty(&dquot->dq_free));
 #endif
-       put_dquot_last(dquot);
+       put_releasing_dquots(dquot);
        spin_unlock(&dq_list_lock);
+       queue_delayed_work(system_unbound_wq, &quota_release_work, 1);
 }
 EXPORT_SYMBOL(dqput);
 
@@ -908,7 +966,7 @@ we_slept:
         * already finished or it will be canceled due to dq_count > 1 test */
        wait_on_dquot(dquot);
        /* Read the dquot / allocate space in quota file */
-       if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
+       if (!dquot_active(dquot)) {
                int err;
 
                err = sb->dq_op->acquire_dquot(dquot);
@@ -1014,59 +1072,7 @@ out:
        return err;
 }
 
-/*
- * 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)
+static void remove_dquot_ref(struct super_block *sb, int type)
 {
        struct inode *inode;
 #ifdef CONFIG_QUOTA_DEBUG
@@ -1083,11 +1089,16 @@ static void remove_dquot_ref(struct super_block *sb, int type,
                 */
                spin_lock(&dq_data_lock);
                if (!IS_NOQUOTA(inode)) {
+                       struct dquot **dquots = i_dquot(inode);
+                       struct dquot *dquot = dquots[type];
+
 #ifdef CONFIG_QUOTA_DEBUG
                        if (unlikely(inode_get_rsv_space(inode) > 0))
                                reserved = 1;
 #endif
-                       remove_inode_dquot_ref(inode, type, tofree_head);
+                       dquots[type] = NULL;
+                       if (dquot)
+                               dqput(dquot);
                }
                spin_unlock(&dq_data_lock);
        }
@@ -1104,13 +1115,8 @@ static void remove_dquot_ref(struct super_block *sb, int type,
 /* Gather all references from inodes and drop them */
 static void drop_dquot_ref(struct super_block *sb, int type)
 {
-       LIST_HEAD(tofree_head);
-
-       if (sb->dq_op) {
-               remove_dquot_ref(sb, type, &tofree_head);
-               synchronize_srcu(&dquot_srcu);
-               put_dquot_list(&tofree_head);
-       }
+       if (sb->dq_op)
+               remove_dquot_ref(sb, type);
 }
 
 static inline
@@ -1425,7 +1431,7 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
        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;
 
@@ -1448,7 +1454,7 @@ static int __dquot_initialize(struct inode *inode, int type)
        qsize_t rsv;
        int ret = 0;
 
-       if (!dquot_active(inode))
+       if (!inode_quota_active(inode))
                return 0;
 
        dquots = i_dquot(inode);
@@ -1556,7 +1562,7 @@ bool dquot_initialize_needed(struct inode *inode)
        struct dquot **dquots;
        int i;
 
-       if (!dquot_active(inode))
+       if (!inode_quota_active(inode))
                return false;
 
        dquots = i_dquot(inode);
@@ -1667,7 +1673,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
        int reserve = flags & DQUOT_SPACE_RESERVE;
        struct dquot **dquots;
 
-       if (!dquot_active(inode)) {
+       if (!inode_quota_active(inode)) {
                if (reserve) {
                        spin_lock(&inode->i_lock);
                        *inode_reserved_space(inode) += number;
@@ -1737,7 +1743,7 @@ int dquot_alloc_inode(struct inode *inode)
        struct dquot_warn warn[MAXQUOTAS];
        struct dquot * const *dquots;
 
-       if (!dquot_active(inode))
+       if (!inode_quota_active(inode))
                return 0;
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warn[cnt].w_type = QUOTA_NL_NOWARN;
@@ -1780,7 +1786,7 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
        struct dquot **dquots;
        int cnt, index;
 
-       if (!dquot_active(inode)) {
+       if (!inode_quota_active(inode)) {
                spin_lock(&inode->i_lock);
                *inode_reserved_space(inode) -= number;
                __inode_add_bytes(inode, number);
@@ -1822,7 +1828,7 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
        struct dquot **dquots;
        int cnt, index;
 
-       if (!dquot_active(inode)) {
+       if (!inode_quota_active(inode)) {
                spin_lock(&inode->i_lock);
                *inode_reserved_space(inode) += number;
                __inode_sub_bytes(inode, number);
@@ -1866,7 +1872,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
        struct dquot **dquots;
        int reserve = flags & DQUOT_SPACE_RESERVE, index;
 
-       if (!dquot_active(inode)) {
+       if (!inode_quota_active(inode)) {
                if (reserve) {
                        spin_lock(&inode->i_lock);
                        *inode_reserved_space(inode) -= number;
@@ -1921,7 +1927,7 @@ void dquot_free_inode(struct inode *inode)
        struct dquot * const *dquots;
        int index;
 
-       if (!dquot_active(inode))
+       if (!inode_quota_active(inode))
                return;
 
        dquots = i_dquot(inode);
@@ -2093,7 +2099,7 @@ int dquot_transfer(struct mnt_idmap *idmap, struct inode *inode,
        struct super_block *sb = inode->i_sb;
        int ret;
 
-       if (!dquot_active(inode))
+       if (!inode_quota_active(inode))
                return 0;
 
        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,
        struct quota_info *dqopt = sb_dqopt(sb);
        int error;
 
+       lockdep_assert_held_write(&sb->s_umount);
+
        /* Just unsuspend quotas? */
        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)
                return -ESRCH;
index 1c775e0..9315366 100644 (file)
@@ -95,7 +95,7 @@ static int udf_copy_fi(struct udf_fileident_iter *iter)
        }
 
        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);
        if (len < sizeof(struct fileIdentDesc))
                memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data,
index d089795..a17a618 100644 (file)
@@ -352,8 +352,6 @@ int udf_expand_file_adinicb(struct inode *inode)
                        iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
                else
                        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);
                mark_inode_dirty(inode);
                return 0;