Commit ed90ed56 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'erofs-for-6.13-rc4-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs

Pull erofs fixes from Gao Xiang:
 "The first one fixes a syzbot UAF report caused by a commit introduced
  in this cycle, but it also addresses a longstanding memory leak. The
  second one resolves a PSI memstall mis-accounting issue.

  The remaining patches switch file-backed mounts to use buffered I/Os
  by default instead of direct I/Os, since the page cache of underlay
  files is typically valid and maybe even dirty. This change also aligns
  with the default policy of loopback devices. A mount option has been
  added to try to use direct I/Os explicitly.

  Summary:

   - Fix (pcluster) memory leak and (sbi) UAF after umounting

   - Fix a case of PSI memstall mis-accounting

   - Use buffered I/Os by default for file-backed mounts"

* tag 'erofs-for-6.13-rc4-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
  erofs: use buffered I/O for file-backed mounts by default
  erofs: reference `struct erofs_device_info` for erofs_map_dev
  erofs: use `struct erofs_device_info` for the primary device
  erofs: add erofs_sb_free() helper
  MAINTAINERS: erofs: update Yue Hu's email address
  erofs: fix PSI memstall accounting
  erofs: fix rare pcluster memory leak after unmounting
parents 1f13c38a 6422cde1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8453,7 +8453,7 @@ F: include/video/s1d13xxxfb.h
EROFS FILE SYSTEM
M:	Gao Xiang <xiang@kernel.org>
M:	Chao Yu <chao@kernel.org>
R:	Yue Hu <huyue2@coolpad.com>
R:	Yue Hu <zbestahu@gmail.com>
R:	Jeffle Xu <jefflexu@linux.alibaba.com>
R:	Sandeep Dhavale <dhavale@google.com>
L:	linux-erofs@lists.ozlabs.org
+13 −23
Original line number Diff line number Diff line
@@ -56,10 +56,10 @@ void erofs_init_metabuf(struct erofs_buf *buf, struct super_block *sb)

	buf->file = NULL;
	if (erofs_is_fileio_mode(sbi)) {
		buf->file = sbi->fdev;		/* some fs like FUSE needs it */
		buf->file = sbi->dif0.file;	/* some fs like FUSE needs it */
		buf->mapping = buf->file->f_mapping;
	} else if (erofs_is_fscache_mode(sb))
		buf->mapping = sbi->s_fscache->inode->i_mapping;
		buf->mapping = sbi->dif0.fscache->inode->i_mapping;
	else
		buf->mapping = sb->s_bdev->bd_mapping;
}
@@ -179,19 +179,13 @@ int erofs_map_blocks(struct inode *inode, struct erofs_map_blocks *map)
}

static void erofs_fill_from_devinfo(struct erofs_map_dev *map,
				    struct erofs_device_info *dif)
		struct super_block *sb, struct erofs_device_info *dif)
{
	map->m_sb = sb;
	map->m_dif = dif;
	map->m_bdev = NULL;
	map->m_fp = NULL;
	if (dif->file) {
		if (S_ISBLK(file_inode(dif->file)->i_mode))
	if (dif->file && S_ISBLK(file_inode(dif->file)->i_mode))
		map->m_bdev = file_bdev(dif->file);
		else
			map->m_fp = dif->file;
	}
	map->m_daxdev = dif->dax_dev;
	map->m_dax_part_off = dif->dax_part_off;
	map->m_fscache = dif->fscache;
}

int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
@@ -201,12 +195,8 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
	erofs_off_t startoff, length;
	int id;

	map->m_bdev = sb->s_bdev;
	map->m_daxdev = EROFS_SB(sb)->dax_dev;
	map->m_dax_part_off = EROFS_SB(sb)->dax_part_off;
	map->m_fscache = EROFS_SB(sb)->s_fscache;
	map->m_fp = EROFS_SB(sb)->fdev;

	erofs_fill_from_devinfo(map, sb, &EROFS_SB(sb)->dif0);
	map->m_bdev = sb->s_bdev;	/* use s_bdev for the primary device */
	if (map->m_deviceid) {
		down_read(&devs->rwsem);
		dif = idr_find(&devs->tree, map->m_deviceid - 1);
@@ -219,7 +209,7 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
			up_read(&devs->rwsem);
			return 0;
		}
		erofs_fill_from_devinfo(map, dif);
		erofs_fill_from_devinfo(map, sb, dif);
		up_read(&devs->rwsem);
	} else if (devs->extra_devices && !devs->flatdev) {
		down_read(&devs->rwsem);
@@ -232,7 +222,7 @@ int erofs_map_dev(struct super_block *sb, struct erofs_map_dev *map)
			if (map->m_pa >= startoff &&
			    map->m_pa < startoff + length) {
				map->m_pa -= startoff;
				erofs_fill_from_devinfo(map, dif);
				erofs_fill_from_devinfo(map, sb, dif);
				break;
			}
		}
@@ -302,7 +292,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,

	iomap->offset = map.m_la;
	if (flags & IOMAP_DAX)
		iomap->dax_dev = mdev.m_daxdev;
		iomap->dax_dev = mdev.m_dif->dax_dev;
	else
		iomap->bdev = mdev.m_bdev;
	iomap->length = map.m_llen;
@@ -331,7 +321,7 @@ static int erofs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
		iomap->type = IOMAP_MAPPED;
		iomap->addr = mdev.m_pa;
		if (flags & IOMAP_DAX)
			iomap->addr += mdev.m_dax_part_off;
			iomap->addr += mdev.m_dif->dax_part_off;
	}
	return 0;
}
+6 −3
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ struct erofs_fileio_rq {
	struct bio_vec bvecs[BIO_MAX_VECS];
	struct bio bio;
	struct kiocb iocb;
	struct super_block *sb;
};

struct erofs_fileio {
@@ -52,8 +53,9 @@ static void erofs_fileio_rq_submit(struct erofs_fileio_rq *rq)
	rq->iocb.ki_pos = rq->bio.bi_iter.bi_sector << SECTOR_SHIFT;
	rq->iocb.ki_ioprio = get_current_ioprio();
	rq->iocb.ki_complete = erofs_fileio_ki_complete;
	rq->iocb.ki_flags = (rq->iocb.ki_filp->f_mode & FMODE_CAN_ODIRECT) ?
				IOCB_DIRECT : 0;
	if (test_opt(&EROFS_SB(rq->sb)->opt, DIRECT_IO) &&
	    rq->iocb.ki_filp->f_mode & FMODE_CAN_ODIRECT)
		rq->iocb.ki_flags = IOCB_DIRECT;
	iov_iter_bvec(&iter, ITER_DEST, rq->bvecs, rq->bio.bi_vcnt,
		      rq->bio.bi_iter.bi_size);
	ret = vfs_iocb_iter_read(rq->iocb.ki_filp, &rq->iocb, &iter);
@@ -67,7 +69,8 @@ static struct erofs_fileio_rq *erofs_fileio_rq_alloc(struct erofs_map_dev *mdev)
					     GFP_KERNEL | __GFP_NOFAIL);

	bio_init(&rq->bio, NULL, rq->bvecs, BIO_MAX_VECS, REQ_OP_READ);
	rq->iocb.ki_filp = mdev->m_fp;
	rq->iocb.ki_filp = mdev->m_dif->file;
	rq->sb = mdev->m_sb;
	return rq;
}

+5 −5
Original line number Diff line number Diff line
@@ -198,7 +198,7 @@ struct bio *erofs_fscache_bio_alloc(struct erofs_map_dev *mdev)

	io = kmalloc(sizeof(*io), GFP_KERNEL | __GFP_NOFAIL);
	bio_init(&io->bio, NULL, io->bvecs, BIO_MAX_VECS, REQ_OP_READ);
	io->io.private = mdev->m_fscache->cookie;
	io->io.private = mdev->m_dif->fscache->cookie;
	io->io.end_io = erofs_fscache_bio_endio;
	refcount_set(&io->io.ref, 1);
	return &io->bio;
@@ -316,7 +316,7 @@ static int erofs_fscache_data_read_slice(struct erofs_fscache_rq *req)
	if (!io)
		return -ENOMEM;
	iov_iter_xarray(&io->iter, ITER_DEST, &mapping->i_pages, pos, count);
	ret = erofs_fscache_read_io_async(mdev.m_fscache->cookie,
	ret = erofs_fscache_read_io_async(mdev.m_dif->fscache->cookie,
			mdev.m_pa + (pos - map.m_la), io);
	erofs_fscache_req_io_put(io);

@@ -657,7 +657,7 @@ int erofs_fscache_register_fs(struct super_block *sb)
	if (IS_ERR(fscache))
		return PTR_ERR(fscache);

	sbi->s_fscache = fscache;
	sbi->dif0.fscache = fscache;
	return 0;
}

@@ -665,14 +665,14 @@ void erofs_fscache_unregister_fs(struct super_block *sb)
{
	struct erofs_sb_info *sbi = EROFS_SB(sb);

	erofs_fscache_unregister_cookie(sbi->s_fscache);
	erofs_fscache_unregister_cookie(sbi->dif0.fscache);

	if (sbi->domain)
		erofs_fscache_domain_put(sbi->domain);
	else
		fscache_relinquish_volume(sbi->volume, NULL, false);

	sbi->s_fscache = NULL;
	sbi->dif0.fscache = NULL;
	sbi->volume = NULL;
	sbi->domain = NULL;
}
+5 −10
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ struct erofs_xattr_prefix_item {
};

struct erofs_sb_info {
	struct erofs_device_info dif0;
	struct erofs_mount_opts opt;	/* options */
#ifdef CONFIG_EROFS_FS_ZIP
	/* list for all registered superblocks, mainly for shrinker */
@@ -124,13 +125,9 @@ struct erofs_sb_info {

	struct erofs_sb_lz4_info lz4;
#endif	/* CONFIG_EROFS_FS_ZIP */
	struct file *fdev;
	struct inode *packed_inode;
	struct erofs_dev_context *devs;
	struct dax_device *dax_dev;
	u64 dax_part_off;
	u64 total_blocks;
	u32 primarydevice_blocks;

	u32 meta_blkaddr;
#ifdef CONFIG_EROFS_FS_XATTR
@@ -166,7 +163,6 @@ struct erofs_sb_info {

	/* fscache support */
	struct fscache_volume *volume;
	struct erofs_fscache *s_fscache;
	struct erofs_domain *domain;
	char *fsid;
	char *domain_id;
@@ -180,6 +176,7 @@ struct erofs_sb_info {
#define EROFS_MOUNT_POSIX_ACL		0x00000020
#define EROFS_MOUNT_DAX_ALWAYS		0x00000040
#define EROFS_MOUNT_DAX_NEVER		0x00000080
#define EROFS_MOUNT_DIRECT_IO		0x00000100

#define clear_opt(opt, option)	((opt)->mount_opt &= ~EROFS_MOUNT_##option)
#define set_opt(opt, option)	((opt)->mount_opt |= EROFS_MOUNT_##option)
@@ -187,7 +184,7 @@ struct erofs_sb_info {

static inline bool erofs_is_fileio_mode(struct erofs_sb_info *sbi)
{
	return IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) && sbi->fdev;
	return IS_ENABLED(CONFIG_EROFS_FS_BACKED_BY_FILE) && sbi->dif0.file;
}

static inline bool erofs_is_fscache_mode(struct super_block *sb)
@@ -357,11 +354,9 @@ enum {
};

struct erofs_map_dev {
	struct erofs_fscache *m_fscache;
	struct super_block *m_sb;
	struct erofs_device_info *m_dif;
	struct block_device *m_bdev;
	struct dax_device *m_daxdev;
	struct file *m_fp;
	u64 m_dax_part_off;

	erofs_off_t m_pa;
	unsigned int m_deviceid;
Loading