]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - fs/zonefs/super.c
net/mlx5: Fix some error handling paths in 'mlx5e_tc_add_fdb_flow()'
[mirror_ubuntu-jammy-kernel.git] / fs / zonefs / super.c
index ddc346a9df9ba53a40531b2465beb28c2eb99c94..ecf564d150b3c1cf3198f339fc931742f33fe052 100644 (file)
@@ -35,6 +35,17 @@ static inline int zonefs_zone_mgmt(struct inode *inode,
 
        lockdep_assert_held(&zi->i_truncate_mutex);
 
+       /*
+        * With ZNS drives, closing an explicitly open zone that has not been
+        * written will change the zone state to "closed", that is, the zone
+        * will remain active. Since this can then cause failure of explicit
+        * open operation on other zones if the drive active zone resources
+        * are exceeded, make sure that the zone does not remain active by
+        * resetting it.
+        */
+       if (op == REQ_OP_ZONE_CLOSE && !zi->i_wpoffset)
+               op = REQ_OP_ZONE_RESET;
+
        trace_zonefs_zone_mgmt(inode, op);
        ret = blkdev_zone_mgmt(inode->i_sb->s_bdev, op, zi->i_zsector,
                               zi->i_zone_size >> SECTOR_SHIFT, GFP_NOFS);
@@ -61,15 +72,51 @@ static inline void zonefs_i_size_write(struct inode *inode, loff_t isize)
                zi->i_flags &= ~ZONEFS_ZONE_OPEN;
 }
 
-static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
-                             unsigned int flags, struct iomap *iomap,
-                             struct iomap *srcmap)
+static int zonefs_read_iomap_begin(struct inode *inode, loff_t offset,
+                                  loff_t length, unsigned int flags,
+                                  struct iomap *iomap, struct iomap *srcmap)
+{
+       struct zonefs_inode_info *zi = ZONEFS_I(inode);
+       struct super_block *sb = inode->i_sb;
+       loff_t isize;
+
+       /*
+        * All blocks are always mapped below EOF. If reading past EOF,
+        * act as if there is a hole up to the file maximum size.
+        */
+       mutex_lock(&zi->i_truncate_mutex);
+       iomap->bdev = inode->i_sb->s_bdev;
+       iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
+       isize = i_size_read(inode);
+       if (iomap->offset >= isize) {
+               iomap->type = IOMAP_HOLE;
+               iomap->addr = IOMAP_NULL_ADDR;
+               iomap->length = length;
+       } else {
+               iomap->type = IOMAP_MAPPED;
+               iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
+               iomap->length = isize - iomap->offset;
+       }
+       mutex_unlock(&zi->i_truncate_mutex);
+
+       trace_zonefs_iomap_begin(inode, iomap);
+
+       return 0;
+}
+
+static const struct iomap_ops zonefs_read_iomap_ops = {
+       .iomap_begin    = zonefs_read_iomap_begin,
+};
+
+static int zonefs_write_iomap_begin(struct inode *inode, loff_t offset,
+                                   loff_t length, unsigned int flags,
+                                   struct iomap *iomap, struct iomap *srcmap)
 {
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
        struct super_block *sb = inode->i_sb;
        loff_t isize;
 
-       /* All I/Os should always be within the file maximum size */
+       /* All write I/Os should always be within the file maximum size */
        if (WARN_ON_ONCE(offset + length > zi->i_max_size))
                return -EIO;
 
@@ -79,7 +126,7 @@ static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
         * operation.
         */
        if (WARN_ON_ONCE(zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
-                        (flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)))
+                        !(flags & IOMAP_DIRECT)))
                return -EIO;
 
        /*
@@ -88,47 +135,44 @@ static int zonefs_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
         * write pointer) and unwriten beyond.
         */
        mutex_lock(&zi->i_truncate_mutex);
+       iomap->bdev = inode->i_sb->s_bdev;
+       iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
+       iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
        isize = i_size_read(inode);
-       if (offset >= isize)
+       if (iomap->offset >= isize) {
                iomap->type = IOMAP_UNWRITTEN;
-       else
+               iomap->length = zi->i_max_size - iomap->offset;
+       } else {
                iomap->type = IOMAP_MAPPED;
-       if (flags & IOMAP_WRITE)
-               length = zi->i_max_size - offset;
-       else
-               length = min(length, isize - offset);
+               iomap->length = isize - iomap->offset;
+       }
        mutex_unlock(&zi->i_truncate_mutex);
 
-       iomap->offset = ALIGN_DOWN(offset, sb->s_blocksize);
-       iomap->length = ALIGN(offset + length, sb->s_blocksize) - iomap->offset;
-       iomap->bdev = inode->i_sb->s_bdev;
-       iomap->addr = (zi->i_zsector << SECTOR_SHIFT) + iomap->offset;
-
        trace_zonefs_iomap_begin(inode, iomap);
 
        return 0;
 }
 
-static const struct iomap_ops zonefs_iomap_ops = {
-       .iomap_begin    = zonefs_iomap_begin,
+static const struct iomap_ops zonefs_write_iomap_ops = {
+       .iomap_begin    = zonefs_write_iomap_begin,
 };
 
 static int zonefs_readpage(struct file *unused, struct page *page)
 {
-       return iomap_readpage(page, &zonefs_iomap_ops);
+       return iomap_readpage(page, &zonefs_read_iomap_ops);
 }
 
 static void zonefs_readahead(struct readahead_control *rac)
 {
-       iomap_readahead(rac, &zonefs_iomap_ops);
+       iomap_readahead(rac, &zonefs_read_iomap_ops);
 }
 
 /*
  * Map blocks for page writeback. This is used only on conventional zone files,
  * which implies that the page range can only be within the fixed inode size.
  */
-static int zonefs_map_blocks(struct iomap_writepage_ctx *wpc,
-                            struct inode *inode, loff_t offset)
+static int zonefs_write_map_blocks(struct iomap_writepage_ctx *wpc,
+                                  struct inode *inode, loff_t offset)
 {
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
 
@@ -142,12 +186,12 @@ static int zonefs_map_blocks(struct iomap_writepage_ctx *wpc,
            offset < wpc->iomap.offset + wpc->iomap.length)
                return 0;
 
-       return zonefs_iomap_begin(inode, offset, zi->i_max_size - offset,
-                                 IOMAP_WRITE, &wpc->iomap, NULL);
+       return zonefs_write_iomap_begin(inode, offset, zi->i_max_size - offset,
+                                       IOMAP_WRITE, &wpc->iomap, NULL);
 }
 
 static const struct iomap_writeback_ops zonefs_writeback_ops = {
-       .map_blocks             = zonefs_map_blocks,
+       .map_blocks             = zonefs_write_map_blocks,
 };
 
 static int zonefs_writepage(struct page *page, struct writeback_control *wbc)
@@ -177,7 +221,8 @@ static int zonefs_swap_activate(struct swap_info_struct *sis,
                return -EINVAL;
        }
 
-       return iomap_swapfile_activate(sis, swap_file, span, &zonefs_iomap_ops);
+       return iomap_swapfile_activate(sis, swap_file, span,
+                                      &zonefs_read_iomap_ops);
 }
 
 static const struct address_space_operations zonefs_file_aops = {
@@ -596,7 +641,7 @@ static vm_fault_t zonefs_filemap_page_mkwrite(struct vm_fault *vmf)
 
        /* Serialize against truncates */
        filemap_invalidate_lock_shared(inode->i_mapping);
-       ret = iomap_page_mkwrite(vmf, &zonefs_iomap_ops);
+       ret = iomap_page_mkwrite(vmf, &zonefs_write_iomap_ops);
        filemap_invalidate_unlock_shared(inode->i_mapping);
 
        sb_end_pagefault(inode->i_sb);
@@ -851,8 +896,8 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
        if (append)
                ret = zonefs_file_dio_append(iocb, from);
        else
-               ret = iomap_dio_rw(iocb, from, &zonefs_iomap_ops,
-                                  &zonefs_write_dio_ops, 0);
+               ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
+                                  &zonefs_write_dio_ops, 0, 0);
        if (zi->i_ztype == ZONEFS_ZTYPE_SEQ &&
            (ret > 0 || ret == -EIOCBQUEUED)) {
                if (ret > 0)
@@ -893,7 +938,7 @@ static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
        if (ret <= 0)
                goto inode_unlock;
 
-       ret = iomap_file_buffered_write(iocb, from, &zonefs_iomap_ops);
+       ret = iomap_file_buffered_write(iocb, from, &zonefs_write_iomap_ops);
        if (ret > 0)
                iocb->ki_pos += ret;
        else if (ret == -EIO)
@@ -986,8 +1031,8 @@ static ssize_t zonefs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
                        goto inode_unlock;
                }
                file_accessed(iocb->ki_filp);
-               ret = iomap_dio_rw(iocb, to, &zonefs_iomap_ops,
-                                  &zonefs_read_dio_ops, 0);
+               ret = iomap_dio_rw(iocb, to, &zonefs_read_iomap_ops,
+                                  &zonefs_read_dio_ops, 0, 0);
        } else {
                ret = generic_file_read_iter(iocb, to);
                if (ret == -EIO)
@@ -1144,6 +1189,7 @@ static struct inode *zonefs_alloc_inode(struct super_block *sb)
        inode_init_once(&zi->i_vnode);
        mutex_init(&zi->i_truncate_mutex);
        zi->i_wr_refcnt = 0;
+       zi->i_flags = 0;
 
        return &zi->i_vnode;
 }
@@ -1295,12 +1341,13 @@ static void zonefs_init_dir_inode(struct inode *parent, struct inode *inode,
        inc_nlink(parent);
 }
 
-static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
-                                  enum zonefs_ztype type)
+static int zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
+                                 enum zonefs_ztype type)
 {
        struct super_block *sb = inode->i_sb;
        struct zonefs_sb_info *sbi = ZONEFS_SB(sb);
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
+       int ret = 0;
 
        inode->i_ino = zone->start >> sbi->s_zone_sectors_shift;
        inode->i_mode = S_IFREG | sbi->s_perm;
@@ -1325,6 +1372,22 @@ static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
        sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes);
        sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
        sbi->s_used_blocks += zi->i_wpoffset >> sb->s_blocksize_bits;
+
+       /*
+        * For sequential zones, make sure that any open zone is closed first
+        * to ensure that the initial number of open zones is 0, in sync with
+        * the open zone accounting done when the mount option
+        * ZONEFS_MNTOPT_EXPLICIT_OPEN is used.
+        */
+       if (type == ZONEFS_ZTYPE_SEQ &&
+           (zone->cond == BLK_ZONE_COND_IMP_OPEN ||
+            zone->cond == BLK_ZONE_COND_EXP_OPEN)) {
+               mutex_lock(&zi->i_truncate_mutex);
+               ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_CLOSE);
+               mutex_unlock(&zi->i_truncate_mutex);
+       }
+
+       return ret;
 }
 
 static struct dentry *zonefs_create_inode(struct dentry *parent,
@@ -1334,6 +1397,7 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
        struct inode *dir = d_inode(parent);
        struct dentry *dentry;
        struct inode *inode;
+       int ret;
 
        dentry = d_alloc_name(parent, name);
        if (!dentry)
@@ -1344,10 +1408,16 @@ static struct dentry *zonefs_create_inode(struct dentry *parent,
                goto dput;
 
        inode->i_ctime = inode->i_mtime = inode->i_atime = dir->i_ctime;
-       if (zone)
-               zonefs_init_file_inode(inode, zone, type);
-       else
+       if (zone) {
+               ret = zonefs_init_file_inode(inode, zone, type);
+               if (ret) {
+                       iput(inode);
+                       goto dput;
+               }
+       } else {
                zonefs_init_dir_inode(dir, inode, type);
+       }
+
        d_add(dentry, inode);
        dir->i_size++;
 
@@ -1658,11 +1728,6 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_mount_opts = ZONEFS_MNTOPT_ERRORS_RO;
        sbi->s_max_open_zones = bdev_max_open_zones(sb->s_bdev);
        atomic_set(&sbi->s_open_zones, 0);
-       if (!sbi->s_max_open_zones &&
-           sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) {
-               zonefs_info(sb, "No open zones limit. Ignoring explicit_open mount option\n");
-               sbi->s_mount_opts &= ~ZONEFS_MNTOPT_EXPLICIT_OPEN;
-       }
 
        ret = zonefs_read_super(sb);
        if (ret)
@@ -1681,6 +1746,12 @@ static int zonefs_fill_super(struct super_block *sb, void *data, int silent)
        zonefs_info(sb, "Mounting %u zones",
                    blkdev_nr_zones(sb->s_bdev->bd_disk));
 
+       if (!sbi->s_max_open_zones &&
+           sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) {
+               zonefs_info(sb, "No open zones limit. Ignoring explicit_open mount option\n");
+               sbi->s_mount_opts &= ~ZONEFS_MNTOPT_EXPLICIT_OPEN;
+       }
+
        /* Create root directory inode */
        ret = -ENOMEM;
        inode = new_inode(sb);
@@ -1787,5 +1858,6 @@ static void __exit zonefs_exit(void)
 MODULE_AUTHOR("Damien Le Moal");
 MODULE_DESCRIPTION("Zone file system for zoned block devices");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_FS("zonefs");
 module_init(zonefs_init);
 module_exit(zonefs_exit);