162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Simple zone file system for zoned block devices. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019 Western Digital Corporation or its affiliates. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#ifndef __ZONEFS_H__ 862306a36Sopenharmony_ci#define __ZONEFS_H__ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/magic.h> 1262306a36Sopenharmony_ci#include <linux/uuid.h> 1362306a36Sopenharmony_ci#include <linux/mutex.h> 1462306a36Sopenharmony_ci#include <linux/rwsem.h> 1562306a36Sopenharmony_ci#include <linux/kobject.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Maximum length of file names: this only needs to be large enough to fit 1962306a36Sopenharmony_ci * the zone group directory names and a decimal zone number for file names. 2062306a36Sopenharmony_ci * 16 characters is plenty. 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_ci#define ZONEFS_NAME_MAX 16 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Zone types: ZONEFS_ZTYPE_SEQ is used for all sequential zone types 2662306a36Sopenharmony_ci * defined in linux/blkzoned.h, that is, BLK_ZONE_TYPE_SEQWRITE_REQ and 2762306a36Sopenharmony_ci * BLK_ZONE_TYPE_SEQWRITE_PREF. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cienum zonefs_ztype { 3062306a36Sopenharmony_ci ZONEFS_ZTYPE_CNV, 3162306a36Sopenharmony_ci ZONEFS_ZTYPE_SEQ, 3262306a36Sopenharmony_ci ZONEFS_ZTYPE_MAX, 3362306a36Sopenharmony_ci}; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic inline enum zonefs_ztype zonefs_zone_type(struct blk_zone *zone) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) 3862306a36Sopenharmony_ci return ZONEFS_ZTYPE_CNV; 3962306a36Sopenharmony_ci return ZONEFS_ZTYPE_SEQ; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define ZONEFS_ZONE_INIT_MODE (1U << 0) 4362306a36Sopenharmony_ci#define ZONEFS_ZONE_OPEN (1U << 1) 4462306a36Sopenharmony_ci#define ZONEFS_ZONE_ACTIVE (1U << 2) 4562306a36Sopenharmony_ci#define ZONEFS_ZONE_OFFLINE (1U << 3) 4662306a36Sopenharmony_ci#define ZONEFS_ZONE_READONLY (1U << 4) 4762306a36Sopenharmony_ci#define ZONEFS_ZONE_CNV (1U << 31) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * In-memory per-file inode zone data. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_cistruct zonefs_zone { 5362306a36Sopenharmony_ci /* Zone state flags */ 5462306a36Sopenharmony_ci unsigned int z_flags; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* Zone start sector (512B unit) */ 5762306a36Sopenharmony_ci sector_t z_sector; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Zone size (bytes) */ 6062306a36Sopenharmony_ci loff_t z_size; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Zone capacity (file maximum size, bytes) */ 6362306a36Sopenharmony_ci loff_t z_capacity; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Write pointer offset in the zone (sequential zones only, bytes) */ 6662306a36Sopenharmony_ci loff_t z_wpoffset; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Saved inode uid, gid and access rights */ 6962306a36Sopenharmony_ci umode_t z_mode; 7062306a36Sopenharmony_ci kuid_t z_uid; 7162306a36Sopenharmony_ci kgid_t z_gid; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * In memory zone group information: all zones of a group are exposed 7662306a36Sopenharmony_ci * as files, one file per zone. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistruct zonefs_zone_group { 7962306a36Sopenharmony_ci struct inode *g_inode; 8062306a36Sopenharmony_ci unsigned int g_nr_zones; 8162306a36Sopenharmony_ci struct zonefs_zone *g_zones; 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* 8562306a36Sopenharmony_ci * In-memory inode data. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_cistruct zonefs_inode_info { 8862306a36Sopenharmony_ci struct inode i_vnode; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* 9162306a36Sopenharmony_ci * To serialise fully against both syscall and mmap based IO and 9262306a36Sopenharmony_ci * sequential file truncation, two locks are used. For serializing 9362306a36Sopenharmony_ci * zonefs_seq_file_truncate() against zonefs_iomap_begin(), that is, 9462306a36Sopenharmony_ci * file truncate operations against block mapping, i_truncate_mutex is 9562306a36Sopenharmony_ci * used. i_truncate_mutex also protects against concurrent accesses 9662306a36Sopenharmony_ci * and changes to the inode private data, and in particular changes to 9762306a36Sopenharmony_ci * a sequential file size on completion of direct IO writes. 9862306a36Sopenharmony_ci * Serialization of mmap read IOs with truncate and syscall IO 9962306a36Sopenharmony_ci * operations is done with invalidate_lock in addition to 10062306a36Sopenharmony_ci * i_truncate_mutex. Only zonefs_seq_file_truncate() takes both lock 10162306a36Sopenharmony_ci * (invalidate_lock first, i_truncate_mutex second). 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci struct mutex i_truncate_mutex; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* guarded by i_truncate_mutex */ 10662306a36Sopenharmony_ci unsigned int i_wr_refcnt; 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic inline struct zonefs_inode_info *ZONEFS_I(struct inode *inode) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci return container_of(inode, struct zonefs_inode_info, i_vnode); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic inline bool zonefs_zone_is_cnv(struct zonefs_zone *z) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return z->z_flags & ZONEFS_ZONE_CNV; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic inline bool zonefs_zone_is_seq(struct zonefs_zone *z) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci return !zonefs_zone_is_cnv(z); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic inline struct zonefs_zone *zonefs_inode_zone(struct inode *inode) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci return inode->i_private; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic inline bool zonefs_inode_is_cnv(struct inode *inode) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci return zonefs_zone_is_cnv(zonefs_inode_zone(inode)); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic inline bool zonefs_inode_is_seq(struct inode *inode) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci return zonefs_zone_is_seq(zonefs_inode_zone(inode)); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * On-disk super block (block 0). 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci#define ZONEFS_LABEL_LEN 64 14362306a36Sopenharmony_ci#define ZONEFS_UUID_SIZE 16 14462306a36Sopenharmony_ci#define ZONEFS_SUPER_SIZE 4096 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistruct zonefs_super { 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* Magic number */ 14962306a36Sopenharmony_ci __le32 s_magic; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Checksum */ 15262306a36Sopenharmony_ci __le32 s_crc; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Volume label */ 15562306a36Sopenharmony_ci char s_label[ZONEFS_LABEL_LEN]; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 128-bit uuid */ 15862306a36Sopenharmony_ci __u8 s_uuid[ZONEFS_UUID_SIZE]; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Features */ 16162306a36Sopenharmony_ci __le64 s_features; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* UID/GID to use for files */ 16462306a36Sopenharmony_ci __le32 s_uid; 16562306a36Sopenharmony_ci __le32 s_gid; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* File permissions */ 16862306a36Sopenharmony_ci __le32 s_perm; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Padding to ZONEFS_SUPER_SIZE bytes */ 17162306a36Sopenharmony_ci __u8 s_reserved[3988]; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci} __packed; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * Feature flags: specified in the s_features field of the on-disk super 17762306a36Sopenharmony_ci * block struct zonefs_super and in-memory in the s_feartures field of 17862306a36Sopenharmony_ci * struct zonefs_sb_info. 17962306a36Sopenharmony_ci */ 18062306a36Sopenharmony_cienum zonefs_features { 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * Aggregate contiguous conventional zones into a single file. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci ZONEFS_F_AGGRCNV = 1ULL << 0, 18562306a36Sopenharmony_ci /* 18662306a36Sopenharmony_ci * Use super block specified UID for files instead of default 0. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci ZONEFS_F_UID = 1ULL << 1, 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Use super block specified GID for files instead of default 0. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci ZONEFS_F_GID = 1ULL << 2, 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * Use super block specified file permissions instead of default 640. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci ZONEFS_F_PERM = 1ULL << 3, 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#define ZONEFS_F_DEFINED_FEATURES \ 20062306a36Sopenharmony_ci (ZONEFS_F_AGGRCNV | ZONEFS_F_UID | ZONEFS_F_GID | ZONEFS_F_PERM) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* 20362306a36Sopenharmony_ci * Mount options for zone write pointer error handling. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci#define ZONEFS_MNTOPT_ERRORS_RO (1 << 0) /* Make zone file readonly */ 20662306a36Sopenharmony_ci#define ZONEFS_MNTOPT_ERRORS_ZRO (1 << 1) /* Make zone file offline */ 20762306a36Sopenharmony_ci#define ZONEFS_MNTOPT_ERRORS_ZOL (1 << 2) /* Make zone file offline */ 20862306a36Sopenharmony_ci#define ZONEFS_MNTOPT_ERRORS_REPAIR (1 << 3) /* Remount read-only */ 20962306a36Sopenharmony_ci#define ZONEFS_MNTOPT_ERRORS_MASK \ 21062306a36Sopenharmony_ci (ZONEFS_MNTOPT_ERRORS_RO | ZONEFS_MNTOPT_ERRORS_ZRO | \ 21162306a36Sopenharmony_ci ZONEFS_MNTOPT_ERRORS_ZOL | ZONEFS_MNTOPT_ERRORS_REPAIR) 21262306a36Sopenharmony_ci#define ZONEFS_MNTOPT_EXPLICIT_OPEN (1 << 4) /* Explicit open/close of zones on open/close */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* 21562306a36Sopenharmony_ci * In-memory Super block information. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_cistruct zonefs_sb_info { 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci unsigned long s_mount_opts; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci spinlock_t s_lock; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci unsigned long long s_features; 22462306a36Sopenharmony_ci kuid_t s_uid; 22562306a36Sopenharmony_ci kgid_t s_gid; 22662306a36Sopenharmony_ci umode_t s_perm; 22762306a36Sopenharmony_ci uuid_t s_uuid; 22862306a36Sopenharmony_ci unsigned int s_zone_sectors_shift; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci struct zonefs_zone_group s_zgroup[ZONEFS_ZTYPE_MAX]; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci loff_t s_blocks; 23362306a36Sopenharmony_ci loff_t s_used_blocks; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci unsigned int s_max_wro_seq_files; 23662306a36Sopenharmony_ci atomic_t s_wro_seq_files; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci unsigned int s_max_active_seq_files; 23962306a36Sopenharmony_ci atomic_t s_active_seq_files; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci bool s_sysfs_registered; 24262306a36Sopenharmony_ci struct kobject s_kobj; 24362306a36Sopenharmony_ci struct completion s_kobj_unregister; 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic inline struct zonefs_sb_info *ZONEFS_SB(struct super_block *sb) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci return sb->s_fs_info; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci#define zonefs_info(sb, format, args...) \ 25262306a36Sopenharmony_ci pr_info("zonefs (%s): " format, sb->s_id, ## args) 25362306a36Sopenharmony_ci#define zonefs_err(sb, format, args...) \ 25462306a36Sopenharmony_ci pr_err("zonefs (%s) ERROR: " format, sb->s_id, ## args) 25562306a36Sopenharmony_ci#define zonefs_warn(sb, format, args...) \ 25662306a36Sopenharmony_ci pr_warn("zonefs (%s) WARNING: " format, sb->s_id, ## args) 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* In super.c */ 25962306a36Sopenharmony_civoid zonefs_inode_account_active(struct inode *inode); 26062306a36Sopenharmony_ciint zonefs_inode_zone_mgmt(struct inode *inode, enum req_op op); 26162306a36Sopenharmony_civoid zonefs_i_size_write(struct inode *inode, loff_t isize); 26262306a36Sopenharmony_civoid zonefs_update_stats(struct inode *inode, loff_t new_isize); 26362306a36Sopenharmony_civoid __zonefs_io_error(struct inode *inode, bool write); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void zonefs_io_error(struct inode *inode, bool write) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct zonefs_inode_info *zi = ZONEFS_I(inode); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci mutex_lock(&zi->i_truncate_mutex); 27062306a36Sopenharmony_ci __zonefs_io_error(inode, write); 27162306a36Sopenharmony_ci mutex_unlock(&zi->i_truncate_mutex); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* In super.c */ 27562306a36Sopenharmony_ciextern const struct inode_operations zonefs_dir_inode_operations; 27662306a36Sopenharmony_ciextern const struct file_operations zonefs_dir_operations; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* In file.c */ 27962306a36Sopenharmony_ciextern const struct address_space_operations zonefs_file_aops; 28062306a36Sopenharmony_ciextern const struct file_operations zonefs_file_operations; 28162306a36Sopenharmony_ciint zonefs_file_truncate(struct inode *inode, loff_t isize); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* In sysfs.c */ 28462306a36Sopenharmony_ciint zonefs_sysfs_register(struct super_block *sb); 28562306a36Sopenharmony_civoid zonefs_sysfs_unregister(struct super_block *sb); 28662306a36Sopenharmony_ciint zonefs_sysfs_init(void); 28762306a36Sopenharmony_civoid zonefs_sysfs_exit(void); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci#endif 290