Skip to content

Commit

Permalink
Merge tag 'zonefs-6.5-rc6' of git://git.kernel.org/pub/scm/linux/kern…
Browse files Browse the repository at this point in the history
…el/git/dlemoal/zonefs

Pull zonefs fix from Damien Le Moal:

 - The switch to using iomap for executing a direct synchronous write to
   sequential files using a zone append BIO overlooked cases where the
   BIO built by iomap is too large and needs splitting, which is not
   allowed with zone append.

   Fix this by using regular write commands instead. The use of zone
   append commands will be reintroduced later with proper support from
   iomap.

* tag 'zonefs-6.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs:
  zonefs: fix synchronous direct writes to sequential files
  • Loading branch information
Linus Torvalds committed Aug 12, 2023
2 parents 5512c33 + fe9da61 commit 0725a70
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 118 deletions.
111 changes: 3 additions & 108 deletions fs/zonefs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,77 +341,6 @@ static loff_t zonefs_file_llseek(struct file *file, loff_t offset, int whence)
return generic_file_llseek_size(file, offset, whence, isize, isize);
}

struct zonefs_zone_append_bio {
/* The target inode of the BIO */
struct inode *inode;

/* For sync writes, the target append write offset */
u64 append_offset;

/*
* This member must come last, bio_alloc_bioset will allocate enough
* bytes for entire zonefs_bio but relies on bio being last.
*/
struct bio bio;
};

static inline struct zonefs_zone_append_bio *
zonefs_zone_append_bio(struct bio *bio)
{
return container_of(bio, struct zonefs_zone_append_bio, bio);
}

static void zonefs_file_zone_append_dio_bio_end_io(struct bio *bio)
{
struct zonefs_zone_append_bio *za_bio = zonefs_zone_append_bio(bio);
struct zonefs_zone *z = zonefs_inode_zone(za_bio->inode);
sector_t za_sector;

if (bio->bi_status != BLK_STS_OK)
goto bio_end;

/*
* If the file zone was written underneath the file system, the zone
* append operation can still succedd (if the zone is not full) but
* the write append location will not be where we expect it to be.
* Check that we wrote where we intended to, that is, at z->z_wpoffset.
*/
za_sector = z->z_sector + (za_bio->append_offset >> SECTOR_SHIFT);
if (bio->bi_iter.bi_sector != za_sector) {
zonefs_warn(za_bio->inode->i_sb,
"Invalid write sector %llu for zone at %llu\n",
bio->bi_iter.bi_sector, z->z_sector);
bio->bi_status = BLK_STS_IOERR;
}

bio_end:
iomap_dio_bio_end_io(bio);
}

static void zonefs_file_zone_append_dio_submit_io(const struct iomap_iter *iter,
struct bio *bio,
loff_t file_offset)
{
struct zonefs_zone_append_bio *za_bio = zonefs_zone_append_bio(bio);
struct inode *inode = iter->inode;
struct zonefs_zone *z = zonefs_inode_zone(inode);

/*
* Issue a zone append BIO to process sync dio writes. The append
* file offset is saved to check the zone append write location
* on completion of the BIO.
*/
za_bio->inode = inode;
za_bio->append_offset = file_offset;

bio->bi_opf &= ~REQ_OP_WRITE;
bio->bi_opf |= REQ_OP_ZONE_APPEND;
bio->bi_iter.bi_sector = z->z_sector;
bio->bi_end_io = zonefs_file_zone_append_dio_bio_end_io;

submit_bio(bio);
}

static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
int error, unsigned int flags)
{
Expand Down Expand Up @@ -442,14 +371,6 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
return 0;
}

static struct bio_set zonefs_zone_append_bio_set;

static const struct iomap_dio_ops zonefs_zone_append_dio_ops = {
.submit_io = zonefs_file_zone_append_dio_submit_io,
.end_io = zonefs_file_write_dio_end_io,
.bio_set = &zonefs_zone_append_bio_set,
};

static const struct iomap_dio_ops zonefs_write_dio_ops = {
.end_io = zonefs_file_write_dio_end_io,
};
Expand Down Expand Up @@ -533,17 +454,15 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
struct zonefs_inode_info *zi = ZONEFS_I(inode);
struct zonefs_zone *z = zonefs_inode_zone(inode);
struct super_block *sb = inode->i_sb;
const struct iomap_dio_ops *dio_ops;
bool sync = is_sync_kiocb(iocb);
bool append = false;
ssize_t ret, count;

/*
* For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
* as this can cause write reordering (e.g. the first aio gets EAGAIN
* on the inode lock but the second goes through but is now unaligned).
*/
if (zonefs_zone_is_seq(z) && !sync && (iocb->ki_flags & IOCB_NOWAIT))
if (zonefs_zone_is_seq(z) && !is_sync_kiocb(iocb) &&
(iocb->ki_flags & IOCB_NOWAIT))
return -EOPNOTSUPP;

if (iocb->ki_flags & IOCB_NOWAIT) {
Expand Down Expand Up @@ -573,18 +492,6 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
goto inode_unlock;
}
mutex_unlock(&zi->i_truncate_mutex);
append = sync;
}

if (append) {
unsigned int max = bdev_max_zone_append_sectors(sb->s_bdev);

max = ALIGN_DOWN(max << SECTOR_SHIFT, sb->s_blocksize);
iov_iter_truncate(from, max);

dio_ops = &zonefs_zone_append_dio_ops;
} else {
dio_ops = &zonefs_write_dio_ops;
}

/*
Expand All @@ -593,7 +500,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
* the user can make sense of the error.
*/
ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
dio_ops, 0, NULL, 0);
&zonefs_write_dio_ops, 0, NULL, 0);
if (ret == -ENOTBLK)
ret = -EBUSY;

Expand Down Expand Up @@ -938,15 +845,3 @@ const struct file_operations zonefs_file_operations = {
.splice_write = iter_file_splice_write,
.iopoll = iocb_bio_iopoll,
};

int zonefs_file_bioset_init(void)
{
return bioset_init(&zonefs_zone_append_bio_set, BIO_POOL_SIZE,
offsetof(struct zonefs_zone_append_bio, bio),
BIOSET_NEED_BVECS);
}

void zonefs_file_bioset_exit(void)
{
bioset_exit(&zonefs_zone_append_bio_set);
}
9 changes: 1 addition & 8 deletions fs/zonefs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1412,13 +1412,9 @@ static int __init zonefs_init(void)

BUILD_BUG_ON(sizeof(struct zonefs_super) != ZONEFS_SUPER_SIZE);

ret = zonefs_file_bioset_init();
if (ret)
return ret;

ret = zonefs_init_inodecache();
if (ret)
goto destroy_bioset;
return ret;

ret = zonefs_sysfs_init();
if (ret)
Expand All @@ -1434,8 +1430,6 @@ static int __init zonefs_init(void)
zonefs_sysfs_exit();
destroy_inodecache:
zonefs_destroy_inodecache();
destroy_bioset:
zonefs_file_bioset_exit();

return ret;
}
Expand All @@ -1445,7 +1439,6 @@ static void __exit zonefs_exit(void)
unregister_filesystem(&zonefs_type);
zonefs_sysfs_exit();
zonefs_destroy_inodecache();
zonefs_file_bioset_exit();
}

MODULE_AUTHOR("Damien Le Moal");
Expand Down
2 changes: 0 additions & 2 deletions fs/zonefs/zonefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,6 @@ extern const struct file_operations zonefs_dir_operations;
extern const struct address_space_operations zonefs_file_aops;
extern const struct file_operations zonefs_file_operations;
int zonefs_file_truncate(struct inode *inode, loff_t isize);
int zonefs_file_bioset_init(void);
void zonefs_file_bioset_exit(void);

/* In sysfs.c */
int zonefs_sysfs_register(struct super_block *sb);
Expand Down

0 comments on commit 0725a70

Please sign in to comment.