Skip to content

Commit 5414f3f

Browse files
committed
Merge tag 'fs_for_v7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull ext2, udf, quota updates from Jan Kara: - A fix for a race in quota code that can expose ocfs2 to use-after-free issues - UDF fix to avoid memory corruption in face of corrupted format - Couple of ext2 fixes for better handling of fs corruption - Some more various code cleanups in UDF & ext2 * tag 'fs_for_v7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: ext2: reject inodes with zero i_nlink and valid mode in ext2_iget() ext2: use get_random_u32() where appropriate quota: Fix race of dquot_scan_active() with quota deactivation udf: fix partition descriptor append bookkeeping ext2: avoid drop_nlink() during unlink of zero-nlink inode in ext2_unlink() ext2: guard reservation window dump with EXT2FS_DEBUG ext2: replace BUG_ON with WARN_ON_ONCE in ext2_get_blocks ext2: remove stale TODO about kmap fs: udf: avoid assignment in condition when selecting allocation goal
2 parents c4ef28f + 25947cc commit 5414f3f

8 files changed

Lines changed: 59 additions & 33 deletions

File tree

fs/ext2/balloc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ static void group_adjust_blocks(struct super_block *sb, int group_no,
201201
* windows(start, end). Otherwise, it will only print out the "bad" windows,
202202
* those windows that overlap with their immediate neighbors.
203203
*/
204-
#if 1
204+
#ifdef EXT2FS_DEBUG
205205
static void __rsv_window_dump(struct rb_root *root, int verbose,
206206
const char *fn)
207207
{
@@ -248,7 +248,7 @@ static void __rsv_window_dump(struct rb_root *root, int verbose,
248248
__rsv_window_dump((root), (verbose), __func__)
249249
#else
250250
#define rsv_window_dump(root, verbose) do {} while (0)
251-
#endif
251+
#endif /* EXT2FS_DEBUG */
252252

253253
/**
254254
* goal_in_my_reservation()

fs/ext2/inode.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,8 @@ static int ext2_get_blocks(struct inode *inode,
639639
int count = 0;
640640
ext2_fsblk_t first_block = 0;
641641

642-
BUG_ON(maxblocks == 0);
642+
if (WARN_ON_ONCE(maxblocks == 0))
643+
return -EINVAL;
643644

644645
depth = ext2_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
645646

@@ -1433,9 +1434,17 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
14331434
* the test is that same one that e2fsck uses
14341435
* NeilBrown 1999oct15
14351436
*/
1436-
if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
1437-
/* this inode is deleted */
1438-
ret = -ESTALE;
1437+
if (inode->i_nlink == 0) {
1438+
if (inode->i_mode == 0 || ei->i_dtime) {
1439+
/* this inode is deleted */
1440+
ret = -ESTALE;
1441+
} else {
1442+
ext2_error(sb, __func__,
1443+
"inode %lu has zero i_nlink with mode 0%o and no dtime, "
1444+
"filesystem may be corrupt",
1445+
ino, inode->i_mode);
1446+
ret = -EFSCORRUPTED;
1447+
}
14391448
goto bad_inode;
14401449
}
14411450
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);

fs/ext2/namei.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
*
1515
* The only non-static object here is ext2_dir_inode_operations.
1616
*
17-
* TODO: get rid of kmap() use, add readahead.
18-
*
1917
* Copyright (C) 1992, 1993, 1994, 1995
2018
* Remy Card (card@masi.ibp.fr)
2119
* Laboratoire MASI - Institut Blaise Pascal
@@ -293,7 +291,10 @@ static int ext2_unlink(struct inode *dir, struct dentry *dentry)
293291
goto out;
294292

295293
inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
296-
inode_dec_link_count(inode);
294+
295+
if (inode->i_nlink)
296+
inode_dec_link_count(inode);
297+
297298
err = 0;
298299
out:
299300
return err;

fs/ext2/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ static int ext2_fill_super(struct super_block *sb, struct fs_context *fc)
11521152
goto failed_mount2;
11531153
}
11541154
sbi->s_gdb_count = db_count;
1155-
get_random_bytes(&sbi->s_next_generation, sizeof(u32));
1155+
sbi->s_next_generation = get_random_u32();
11561156
spin_lock_init(&sbi->s_next_gen_lock);
11571157

11581158
/* per filesystem reservation list head & lock */

fs/quota/dquot.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,31 @@ static inline int dquot_active(struct dquot *dquot)
363363
return test_bit(DQ_ACTIVE_B, &dquot->dq_flags);
364364
}
365365

366+
static struct dquot *__dqgrab(struct dquot *dquot)
367+
{
368+
lockdep_assert_held(&dq_list_lock);
369+
if (!atomic_read(&dquot->dq_count))
370+
remove_free_dquot(dquot);
371+
atomic_inc(&dquot->dq_count);
372+
return dquot;
373+
}
374+
375+
/*
376+
* Get reference to dquot when we got pointer to it by some other means. The
377+
* dquot has to be active and the caller has to make sure it cannot get
378+
* deactivated under our hands.
379+
*/
380+
struct dquot *dqgrab(struct dquot *dquot)
381+
{
382+
spin_lock(&dq_list_lock);
383+
WARN_ON_ONCE(!dquot_active(dquot));
384+
dquot = __dqgrab(dquot);
385+
spin_unlock(&dq_list_lock);
386+
387+
return dquot;
388+
}
389+
EXPORT_SYMBOL_GPL(dqgrab);
390+
366391
static inline int dquot_dirty(struct dquot *dquot)
367392
{
368393
return test_bit(DQ_MOD_B, &dquot->dq_flags);
@@ -641,15 +666,14 @@ int dquot_scan_active(struct super_block *sb,
641666
continue;
642667
if (dquot->dq_sb != sb)
643668
continue;
644-
/* Now we have active dquot so we can just increase use count */
645-
atomic_inc(&dquot->dq_count);
669+
__dqgrab(dquot);
646670
spin_unlock(&dq_list_lock);
647671
dqput(old_dquot);
648672
old_dquot = dquot;
649673
/*
650674
* ->release_dquot() can be racing with us. Our reference
651-
* protects us from new calls to it so just wait for any
652-
* outstanding call and recheck the DQ_ACTIVE_B after that.
675+
* protects us from dquot_release() proceeding so just wait for
676+
* any outstanding call and recheck the DQ_ACTIVE_B after that.
653677
*/
654678
wait_on_dquot(dquot);
655679
if (dquot_active(dquot)) {
@@ -717,7 +741,7 @@ int dquot_writeback_dquots(struct super_block *sb, int type)
717741
/* Now we have active dquot from which someone is
718742
* holding reference so we can safely just increase
719743
* use count */
720-
dqgrab(dquot);
744+
__dqgrab(dquot);
721745
spin_unlock(&dq_list_lock);
722746
err = dquot_write_dquot(dquot);
723747
if (err && !ret)
@@ -963,9 +987,7 @@ struct dquot *dqget(struct super_block *sb, struct kqid qid)
963987
spin_unlock(&dq_list_lock);
964988
dqstats_inc(DQST_LOOKUPS);
965989
} else {
966-
if (!atomic_read(&dquot->dq_count))
967-
remove_free_dquot(dquot);
968-
atomic_inc(&dquot->dq_count);
990+
__dqgrab(dquot);
969991
spin_unlock(&dq_list_lock);
970992
dqstats_inc(DQST_CACHE_HITS);
971993
dqstats_inc(DQST_LOOKUPS);

fs/udf/inode.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
733733
sector_t offset = 0;
734734
int8_t etype, tmpetype;
735735
struct udf_inode_info *iinfo = UDF_I(inode);
736-
udf_pblk_t goal = 0, pgoal = iinfo->i_location.logicalBlockNum;
736+
udf_pblk_t goal = 0, pgoal = 0;
737737
int lastblock = 0;
738738
bool isBeyondEOF = false;
739739
int ret = 0;
@@ -892,11 +892,10 @@ static int inode_getblk(struct inode *inode, struct udf_map_rq *map)
892892
else { /* otherwise, allocate a new block */
893893
if (iinfo->i_next_alloc_block == map->lblk)
894894
goal = iinfo->i_next_alloc_goal;
895-
896-
if (!goal) {
897-
if (!(goal = pgoal)) /* XXX: what was intended here? */
898-
goal = iinfo->i_location.logicalBlockNum + 1;
899-
}
895+
if (!goal)
896+
goal = pgoal;
897+
if (!goal)
898+
goal = iinfo->i_location.logicalBlockNum + 1;
900899

901900
newblocknum = udf_new_block(inode->i_sb, inode,
902901
iinfo->i_location.partitionReferenceNum,

fs/udf/super.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1695,8 +1695,9 @@ static struct udf_vds_record *handle_partition_descriptor(
16951695
return &(data->part_descs_loc[i].rec);
16961696
if (data->num_part_descs >= data->size_part_descs) {
16971697
struct part_desc_seq_scan_data *new_loc;
1698-
unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
1698+
unsigned int new_size;
16991699

1700+
new_size = data->num_part_descs + PART_DESC_ALLOC_STEP;
17001701
new_loc = kzalloc_objs(*new_loc, new_size);
17011702
if (!new_loc)
17021703
return ERR_PTR(-ENOMEM);
@@ -1706,6 +1707,7 @@ static struct udf_vds_record *handle_partition_descriptor(
17061707
data->part_descs_loc = new_loc;
17071708
data->size_part_descs = new_size;
17081709
}
1710+
data->part_descs_loc[data->num_part_descs].partnum = partnum;
17091711
return &(data->part_descs_loc[data->num_part_descs++].rec);
17101712
}
17111713

include/linux/quotaops.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,7 @@ int dquot_initialize(struct inode *inode);
4444
bool dquot_initialize_needed(struct inode *inode);
4545
void dquot_drop(struct inode *inode);
4646
struct dquot *dqget(struct super_block *sb, struct kqid qid);
47-
static inline struct dquot *dqgrab(struct dquot *dquot)
48-
{
49-
/* Make sure someone else has active reference to dquot */
50-
WARN_ON_ONCE(!atomic_read(&dquot->dq_count));
51-
WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags));
52-
atomic_inc(&dquot->dq_count);
53-
return dquot;
54-
}
47+
struct dquot *dqgrab(struct dquot *dquot);
5548

5649
static inline bool dquot_is_busy(struct dquot *dquot)
5750
{

0 commit comments

Comments
 (0)