328 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2#ifdef pr_fmt3#undef pr_fmt4#endif5 6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt7 8#include <linux/types.h>9#include <linux/fs.h>10#include <linux/buffer_head.h>11#include "amigaffs.h"12#include <linux/mutex.h>13#include <linux/workqueue.h>14 15/* Ugly macros make the code more pretty. */16 17#define AFFS_BLOCK(sb, bh, blk) (AFFS_HEAD(bh)->table[AFFS_SB(sb)->s_hashsize-1-(blk)])18 19#define AFFS_HEAD(bh) ((struct affs_head *)(bh)->b_data)20#define AFFS_TAIL(sb, bh) ((struct affs_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_tail)))21#define AFFS_ROOT_HEAD(bh) ((struct affs_root_head *)(bh)->b_data)22#define AFFS_ROOT_TAIL(sb, bh) ((struct affs_root_tail *)((bh)->b_data+(sb)->s_blocksize-sizeof(struct affs_root_tail)))23#define AFFS_DATA_HEAD(bh) ((struct affs_data_head *)(bh)->b_data)24#define AFFS_DATA(bh) (((struct affs_data_head *)(bh)->b_data)->data)25 26#define AFFS_CACHE_SIZE PAGE_SIZE27 28#define AFFS_LC_SIZE (AFFS_CACHE_SIZE/sizeof(u32)/2)29#define AFFS_AC_SIZE (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2)30#define AFFS_AC_MASK (AFFS_AC_SIZE-1)31 32#define AFFSNAMEMAX 30U33 34struct affs_ext_key {35 u32 ext; /* idx of the extended block */36 u32 key; /* block number */37};38 39/*40 * affs fs inode data in memory41 */42struct affs_inode_info {43 atomic_t i_opencnt;44 struct mutex i_link_lock; /* Protects internal inode access. */45 struct mutex i_ext_lock; /* Protects internal inode access. */46#define i_hash_lock i_ext_lock47 u32 i_blkcnt; /* block count */48 u32 i_extcnt; /* extended block count */49 u32 *i_lc; /* linear cache of extended blocks */50 u32 i_lc_size;51 u32 i_lc_shift;52 u32 i_lc_mask;53 struct affs_ext_key *i_ac; /* associative cache of extended blocks */54 u32 i_ext_last; /* last accessed extended block */55 struct buffer_head *i_ext_bh; /* bh of last extended block */56 loff_t mmu_private;57 u32 i_protect; /* unused attribute bits */58 u32 i_lastalloc; /* last allocated block */59 int i_pa_cnt; /* number of preallocated blocks */60 struct inode vfs_inode;61};62 63/* short cut to get to the affs specific inode data */64static inline struct affs_inode_info *AFFS_I(struct inode *inode)65{66 return container_of(inode, struct affs_inode_info, vfs_inode);67}68 69/*70 * super-block data in memory71 *72 * Block numbers are adjusted for their actual size73 *74 */75 76struct affs_bm_info {77 u32 bm_key; /* Disk block number */78 u32 bm_free; /* Free blocks in here */79};80 81struct affs_sb_info {82 int s_partition_size; /* Partition size in blocks. */83 int s_reserved; /* Number of reserved blocks. */84 //u32 s_blksize; /* Initial device blksize */85 u32 s_data_blksize; /* size of the data block w/o header */86 u32 s_root_block; /* FFS root block number. */87 int s_hashsize; /* Size of hash table. */88 unsigned long s_flags; /* See below. */89 kuid_t s_uid; /* uid to override */90 kgid_t s_gid; /* gid to override */91 umode_t s_mode; /* mode to override */92 struct buffer_head *s_root_bh; /* Cached root block. */93 struct mutex s_bmlock; /* Protects bitmap access. */94 struct affs_bm_info *s_bitmap; /* Bitmap infos. */95 u32 s_bmap_count; /* # of bitmap blocks. */96 u32 s_bmap_bits; /* # of bits in one bitmap blocks */97 u32 s_last_bmap;98 struct buffer_head *s_bmap_bh;99 char *s_prefix; /* Prefix for volumes and assigns. */100 char s_volume[32]; /* Volume prefix for absolute symlinks. */101 spinlock_t symlink_lock; /* protects the previous two */102 struct super_block *sb; /* the VFS superblock object */103 int work_queued; /* non-zero delayed work is queued */104 struct delayed_work sb_work; /* superblock flush delayed work */105 spinlock_t work_lock; /* protects sb_work and work_queued */106 struct rcu_head rcu;107};108 109#define AFFS_MOUNT_SF_INTL 0x0001 /* International filesystem. */110#define AFFS_MOUNT_SF_BM_VALID 0x0002 /* Bitmap is valid. */111#define AFFS_MOUNT_SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */112#define AFFS_MOUNT_SF_QUIET 0x0008 /* chmod errors will be not reported */113#define AFFS_MOUNT_SF_SETUID 0x0010 /* Ignore Amiga uid */114#define AFFS_MOUNT_SF_SETGID 0x0020 /* Ignore Amiga gid */115#define AFFS_MOUNT_SF_SETMODE 0x0040 /* Ignore Amiga protection bits */116#define AFFS_MOUNT_SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */117#define AFFS_MOUNT_SF_OFS 0x0200 /* Old filesystem */118#define AFFS_MOUNT_SF_PREFIX 0x0400 /* Buffer for prefix is allocated */119#define AFFS_MOUNT_SF_VERBOSE 0x0800 /* Talk about fs when mounting */120#define AFFS_MOUNT_SF_NO_TRUNCATE 0x1000 /* Don't truncate filenames */121 122#define affs_clear_opt(o, opt) (o &= ~AFFS_MOUNT_##opt)123#define affs_set_opt(o, opt) (o |= AFFS_MOUNT_##opt)124#define affs_test_opt(o, opt) ((o) & AFFS_MOUNT_##opt)125 126/* short cut to get to the affs specific sb data */127static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)128{129 return sb->s_fs_info;130}131 132void affs_mark_sb_dirty(struct super_block *sb);133 134/* amigaffs.c */135 136extern int affs_insert_hash(struct inode *inode, struct buffer_head *bh);137extern int affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh);138extern int affs_remove_header(struct dentry *dentry);139extern u32 affs_checksum_block(struct super_block *sb, struct buffer_head *bh);140extern void affs_fix_checksum(struct super_block *sb, struct buffer_head *bh);141extern void affs_secs_to_datestamp(time64_t secs, struct affs_date *ds);142extern umode_t affs_prot_to_mode(u32 prot);143extern void affs_mode_to_prot(struct inode *inode);144__printf(3, 4)145extern void affs_error(struct super_block *sb, const char *function,146 const char *fmt, ...);147__printf(3, 4)148extern void affs_warning(struct super_block *sb, const char *function,149 const char *fmt, ...);150extern bool affs_nofilenametruncate(const struct dentry *dentry);151extern int affs_check_name(const unsigned char *name, int len,152 bool notruncate);153extern int affs_copy_name(unsigned char *bstr, struct dentry *dentry);154 155/* bitmap. c */156 157extern u32 affs_count_free_blocks(struct super_block *s);158extern void affs_free_block(struct super_block *sb, u32 block);159extern u32 affs_alloc_block(struct inode *inode, u32 goal);160extern int affs_init_bitmap(struct super_block *sb, int *flags);161extern void affs_free_bitmap(struct super_block *sb);162 163/* namei.c */164 165extern const struct export_operations affs_export_ops;166extern int affs_hash_name(struct super_block *sb, const u8 *name, unsigned int len);167extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int);168extern int affs_unlink(struct inode *dir, struct dentry *dentry);169extern int affs_create(struct mnt_idmap *idmap, struct inode *dir,170 struct dentry *dentry, umode_t mode, bool);171extern int affs_mkdir(struct mnt_idmap *idmap, struct inode *dir,172 struct dentry *dentry, umode_t mode);173extern int affs_rmdir(struct inode *dir, struct dentry *dentry);174extern int affs_link(struct dentry *olddentry, struct inode *dir,175 struct dentry *dentry);176extern int affs_symlink(struct mnt_idmap *idmap,177 struct inode *dir, struct dentry *dentry,178 const char *symname);179extern int affs_rename2(struct mnt_idmap *idmap,180 struct inode *old_dir, struct dentry *old_dentry,181 struct inode *new_dir, struct dentry *new_dentry,182 unsigned int flags);183 184/* inode.c */185 186extern struct inode *affs_new_inode(struct inode *dir);187extern int affs_notify_change(struct mnt_idmap *idmap,188 struct dentry *dentry, struct iattr *attr);189extern void affs_evict_inode(struct inode *inode);190extern struct inode *affs_iget(struct super_block *sb,191 unsigned long ino);192extern int affs_write_inode(struct inode *inode,193 struct writeback_control *wbc);194extern int affs_add_entry(struct inode *dir, struct inode *inode,195 struct dentry *dentry, s32 type);196 197/* file.c */198 199void affs_free_prealloc(struct inode *inode);200extern void affs_truncate(struct inode *);201int affs_file_fsync(struct file *, loff_t, loff_t, int);202 203/* dir.c */204 205extern void affs_dir_truncate(struct inode *);206 207/* jump tables */208 209extern const struct inode_operations affs_file_inode_operations;210extern const struct inode_operations affs_dir_inode_operations;211extern const struct inode_operations affs_symlink_inode_operations;212extern const struct file_operations affs_file_operations;213extern const struct file_operations affs_file_operations_ofs;214extern const struct file_operations affs_dir_operations;215extern const struct address_space_operations affs_symlink_aops;216extern const struct address_space_operations affs_aops;217extern const struct address_space_operations affs_aops_ofs;218 219extern const struct dentry_operations affs_dentry_operations;220extern const struct dentry_operations affs_intl_dentry_operations;221 222static inline bool affs_validblock(struct super_block *sb, int block)223{224 return(block >= AFFS_SB(sb)->s_reserved &&225 block < AFFS_SB(sb)->s_partition_size);226}227 228static inline void229affs_set_blocksize(struct super_block *sb, int size)230{231 sb_set_blocksize(sb, size);232}233static inline struct buffer_head *234affs_bread(struct super_block *sb, int block)235{236 pr_debug("%s: %d\n", __func__, block);237 if (affs_validblock(sb, block))238 return sb_bread(sb, block);239 return NULL;240}241static inline struct buffer_head *242affs_getblk(struct super_block *sb, int block)243{244 pr_debug("%s: %d\n", __func__, block);245 if (affs_validblock(sb, block))246 return sb_getblk(sb, block);247 return NULL;248}249static inline struct buffer_head *250affs_getzeroblk(struct super_block *sb, int block)251{252 struct buffer_head *bh;253 pr_debug("%s: %d\n", __func__, block);254 if (affs_validblock(sb, block)) {255 bh = sb_getblk(sb, block);256 lock_buffer(bh);257 memset(bh->b_data, 0 , sb->s_blocksize);258 set_buffer_uptodate(bh);259 unlock_buffer(bh);260 return bh;261 }262 return NULL;263}264static inline struct buffer_head *265affs_getemptyblk(struct super_block *sb, int block)266{267 struct buffer_head *bh;268 pr_debug("%s: %d\n", __func__, block);269 if (affs_validblock(sb, block)) {270 bh = sb_getblk(sb, block);271 wait_on_buffer(bh);272 set_buffer_uptodate(bh);273 return bh;274 }275 return NULL;276}277static inline void278affs_brelse(struct buffer_head *bh)279{280 if (bh)281 pr_debug("%s: %lld\n", __func__, (long long) bh->b_blocknr);282 brelse(bh);283}284 285static inline void286affs_adjust_checksum(struct buffer_head *bh, u32 val)287{288 u32 tmp = be32_to_cpu(((__be32 *)bh->b_data)[5]);289 ((__be32 *)bh->b_data)[5] = cpu_to_be32(tmp - val);290}291static inline void292affs_adjust_bitmapchecksum(struct buffer_head *bh, u32 val)293{294 u32 tmp = be32_to_cpu(((__be32 *)bh->b_data)[0]);295 ((__be32 *)bh->b_data)[0] = cpu_to_be32(tmp - val);296}297 298static inline void299affs_lock_link(struct inode *inode)300{301 mutex_lock(&AFFS_I(inode)->i_link_lock);302}303static inline void304affs_unlock_link(struct inode *inode)305{306 mutex_unlock(&AFFS_I(inode)->i_link_lock);307}308static inline void309affs_lock_dir(struct inode *inode)310{311 mutex_lock_nested(&AFFS_I(inode)->i_hash_lock, SINGLE_DEPTH_NESTING);312}313static inline void314affs_unlock_dir(struct inode *inode)315{316 mutex_unlock(&AFFS_I(inode)->i_hash_lock);317}318static inline void319affs_lock_ext(struct inode *inode)320{321 mutex_lock(&AFFS_I(inode)->i_ext_lock);322}323static inline void324affs_unlock_ext(struct inode *inode)325{326 mutex_unlock(&AFFS_I(inode)->i_ext_lock);327}328