487 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * fs/bfs/inode.c4 * BFS superblock and inode operations.5 * Copyright (C) 1999-2018 Tigran Aivazian <aivazian.tigran@gmail.com>6 * From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.7 * Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005.8 */9 10#include <linux/module.h>11#include <linux/mm.h>12#include <linux/slab.h>13#include <linux/init.h>14#include <linux/fs.h>15#include <linux/buffer_head.h>16#include <linux/vfs.h>17#include <linux/writeback.h>18#include <linux/uio.h>19#include <linux/uaccess.h>20#include "bfs.h"21 22MODULE_AUTHOR("Tigran Aivazian <aivazian.tigran@gmail.com>");23MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");24MODULE_LICENSE("GPL");25 26#undef DEBUG27 28#ifdef DEBUG29#define dprintf(x...) printf(x)30#else31#define dprintf(x...)32#endif33 34struct inode *bfs_iget(struct super_block *sb, unsigned long ino)35{36 struct bfs_inode *di;37 struct inode *inode;38 struct buffer_head *bh;39 int block, off;40 41 inode = iget_locked(sb, ino);42 if (!inode)43 return ERR_PTR(-ENOMEM);44 if (!(inode->i_state & I_NEW))45 return inode;46 47 if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {48 printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);49 goto error;50 }51 52 block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;53 bh = sb_bread(inode->i_sb, block);54 if (!bh) {55 printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id,56 ino);57 goto error;58 }59 60 off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;61 di = (struct bfs_inode *)bh->b_data + off;62 63 inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode);64 if (le32_to_cpu(di->i_vtype) == BFS_VDIR) {65 inode->i_mode |= S_IFDIR;66 inode->i_op = &bfs_dir_inops;67 inode->i_fop = &bfs_dir_operations;68 } else if (le32_to_cpu(di->i_vtype) == BFS_VREG) {69 inode->i_mode |= S_IFREG;70 inode->i_op = &bfs_file_inops;71 inode->i_fop = &bfs_file_operations;72 inode->i_mapping->a_ops = &bfs_aops;73 }74 75 BFS_I(inode)->i_sblock = le32_to_cpu(di->i_sblock);76 BFS_I(inode)->i_eblock = le32_to_cpu(di->i_eblock);77 BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino);78 i_uid_write(inode, le32_to_cpu(di->i_uid));79 i_gid_write(inode, le32_to_cpu(di->i_gid));80 set_nlink(inode, le32_to_cpu(di->i_nlink));81 inode->i_size = BFS_FILESIZE(di);82 inode->i_blocks = BFS_FILEBLOCKS(di);83 inode_set_atime(inode, le32_to_cpu(di->i_atime), 0);84 inode_set_mtime(inode, le32_to_cpu(di->i_mtime), 0);85 inode_set_ctime(inode, le32_to_cpu(di->i_ctime), 0);86 87 brelse(bh);88 unlock_new_inode(inode);89 return inode;90 91error:92 iget_failed(inode);93 return ERR_PTR(-EIO);94}95 96static struct bfs_inode *find_inode(struct super_block *sb, u16 ino, struct buffer_head **p)97{98 if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(sb)->si_lasti)) {99 printf("Bad inode number %s:%08x\n", sb->s_id, ino);100 return ERR_PTR(-EIO);101 }102 103 ino -= BFS_ROOT_INO;104 105 *p = sb_bread(sb, 1 + ino / BFS_INODES_PER_BLOCK);106 if (!*p) {107 printf("Unable to read inode %s:%08x\n", sb->s_id, ino);108 return ERR_PTR(-EIO);109 }110 111 return (struct bfs_inode *)(*p)->b_data + ino % BFS_INODES_PER_BLOCK;112}113 114static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)115{116 struct bfs_sb_info *info = BFS_SB(inode->i_sb);117 unsigned int ino = (u16)inode->i_ino;118 unsigned long i_sblock;119 struct bfs_inode *di;120 struct buffer_head *bh;121 int err = 0;122 123 dprintf("ino=%08x\n", ino);124 125 di = find_inode(inode->i_sb, ino, &bh);126 if (IS_ERR(di))127 return PTR_ERR(di);128 129 mutex_lock(&info->bfs_lock);130 131 if (ino == BFS_ROOT_INO)132 di->i_vtype = cpu_to_le32(BFS_VDIR);133 else134 di->i_vtype = cpu_to_le32(BFS_VREG);135 136 di->i_ino = cpu_to_le16(ino);137 di->i_mode = cpu_to_le32(inode->i_mode);138 di->i_uid = cpu_to_le32(i_uid_read(inode));139 di->i_gid = cpu_to_le32(i_gid_read(inode));140 di->i_nlink = cpu_to_le32(inode->i_nlink);141 di->i_atime = cpu_to_le32(inode_get_atime_sec(inode));142 di->i_mtime = cpu_to_le32(inode_get_mtime_sec(inode));143 di->i_ctime = cpu_to_le32(inode_get_ctime_sec(inode));144 i_sblock = BFS_I(inode)->i_sblock;145 di->i_sblock = cpu_to_le32(i_sblock);146 di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock);147 di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1);148 149 mark_buffer_dirty(bh);150 if (wbc->sync_mode == WB_SYNC_ALL) {151 sync_dirty_buffer(bh);152 if (buffer_req(bh) && !buffer_uptodate(bh))153 err = -EIO;154 }155 brelse(bh);156 mutex_unlock(&info->bfs_lock);157 return err;158}159 160static void bfs_evict_inode(struct inode *inode)161{162 unsigned long ino = inode->i_ino;163 struct bfs_inode *di;164 struct buffer_head *bh;165 struct super_block *s = inode->i_sb;166 struct bfs_sb_info *info = BFS_SB(s);167 struct bfs_inode_info *bi = BFS_I(inode);168 169 dprintf("ino=%08lx\n", ino);170 171 truncate_inode_pages_final(&inode->i_data);172 invalidate_inode_buffers(inode);173 clear_inode(inode);174 175 if (inode->i_nlink)176 return;177 178 di = find_inode(s, inode->i_ino, &bh);179 if (IS_ERR(di))180 return;181 182 mutex_lock(&info->bfs_lock);183 /* clear on-disk inode */184 memset(di, 0, sizeof(struct bfs_inode));185 mark_buffer_dirty(bh);186 brelse(bh);187 188 if (bi->i_dsk_ino) {189 if (bi->i_sblock)190 info->si_freeb += bi->i_eblock + 1 - bi->i_sblock;191 info->si_freei++;192 clear_bit(ino, info->si_imap);193 bfs_dump_imap("evict_inode", s);194 }195 196 /*197 * If this was the last file, make the previous block198 * "last block of the last file" even if there is no199 * real file there, saves us 1 gap.200 */201 if (info->si_lf_eblk == bi->i_eblock)202 info->si_lf_eblk = bi->i_sblock - 1;203 mutex_unlock(&info->bfs_lock);204}205 206static void bfs_put_super(struct super_block *s)207{208 struct bfs_sb_info *info = BFS_SB(s);209 210 if (!info)211 return;212 213 mutex_destroy(&info->bfs_lock);214 kfree(info);215 s->s_fs_info = NULL;216}217 218static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)219{220 struct super_block *s = dentry->d_sb;221 struct bfs_sb_info *info = BFS_SB(s);222 u64 id = huge_encode_dev(s->s_bdev->bd_dev);223 buf->f_type = BFS_MAGIC;224 buf->f_bsize = s->s_blocksize;225 buf->f_blocks = info->si_blocks;226 buf->f_bfree = buf->f_bavail = info->si_freeb;227 buf->f_files = info->si_lasti + 1 - BFS_ROOT_INO;228 buf->f_ffree = info->si_freei;229 buf->f_fsid = u64_to_fsid(id);230 buf->f_namelen = BFS_NAMELEN;231 return 0;232}233 234static struct kmem_cache *bfs_inode_cachep;235 236static struct inode *bfs_alloc_inode(struct super_block *sb)237{238 struct bfs_inode_info *bi;239 bi = alloc_inode_sb(sb, bfs_inode_cachep, GFP_KERNEL);240 if (!bi)241 return NULL;242 return &bi->vfs_inode;243}244 245static void bfs_free_inode(struct inode *inode)246{247 kmem_cache_free(bfs_inode_cachep, BFS_I(inode));248}249 250static void init_once(void *foo)251{252 struct bfs_inode_info *bi = foo;253 254 inode_init_once(&bi->vfs_inode);255}256 257static int __init init_inodecache(void)258{259 bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",260 sizeof(struct bfs_inode_info),261 0, (SLAB_RECLAIM_ACCOUNT|262 SLAB_ACCOUNT),263 init_once);264 if (bfs_inode_cachep == NULL)265 return -ENOMEM;266 return 0;267}268 269static void destroy_inodecache(void)270{271 /*272 * Make sure all delayed rcu free inodes are flushed before we273 * destroy cache.274 */275 rcu_barrier();276 kmem_cache_destroy(bfs_inode_cachep);277}278 279static const struct super_operations bfs_sops = {280 .alloc_inode = bfs_alloc_inode,281 .free_inode = bfs_free_inode,282 .write_inode = bfs_write_inode,283 .evict_inode = bfs_evict_inode,284 .put_super = bfs_put_super,285 .statfs = bfs_statfs,286};287 288void bfs_dump_imap(const char *prefix, struct super_block *s)289{290#ifdef DEBUG291 int i;292 char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL);293 294 if (!tmpbuf)295 return;296 for (i = BFS_SB(s)->si_lasti; i >= 0; i--) {297 if (i > PAGE_SIZE - 100) break;298 if (test_bit(i, BFS_SB(s)->si_imap))299 strcat(tmpbuf, "1");300 else301 strcat(tmpbuf, "0");302 }303 printf("%s: lasti=%08lx <%s>\n", prefix, BFS_SB(s)->si_lasti, tmpbuf);304 free_page((unsigned long)tmpbuf);305#endif306}307 308static int bfs_fill_super(struct super_block *s, void *data, int silent)309{310 struct buffer_head *bh, *sbh;311 struct bfs_super_block *bfs_sb;312 struct inode *inode;313 unsigned i;314 struct bfs_sb_info *info;315 int ret = -EINVAL;316 unsigned long i_sblock, i_eblock, i_eoff, s_size;317 318 info = kzalloc(sizeof(*info), GFP_KERNEL);319 if (!info)320 return -ENOMEM;321 mutex_init(&info->bfs_lock);322 s->s_fs_info = info;323 s->s_time_min = 0;324 s->s_time_max = U32_MAX;325 326 sb_set_blocksize(s, BFS_BSIZE);327 328 sbh = sb_bread(s, 0);329 if (!sbh)330 goto out;331 bfs_sb = (struct bfs_super_block *)sbh->b_data;332 if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {333 if (!silent)334 printf("No BFS filesystem on %s (magic=%08x)\n", s->s_id, le32_to_cpu(bfs_sb->s_magic));335 goto out1;336 }337 if (BFS_UNCLEAN(bfs_sb, s) && !silent)338 printf("%s is unclean, continuing\n", s->s_id);339 340 s->s_magic = BFS_MAGIC;341 342 if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end) ||343 le32_to_cpu(bfs_sb->s_start) < sizeof(struct bfs_super_block) + sizeof(struct bfs_dirent)) {344 printf("Superblock is corrupted on %s\n", s->s_id);345 goto out1;346 }347 348 info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) / sizeof(struct bfs_inode) + BFS_ROOT_INO - 1;349 if (info->si_lasti == BFS_MAX_LASTI)350 printf("NOTE: filesystem %s was created with 512 inodes, the real maximum is 511, mounting anyway\n", s->s_id);351 else if (info->si_lasti > BFS_MAX_LASTI) {352 printf("Impossible last inode number %lu > %d on %s\n", info->si_lasti, BFS_MAX_LASTI, s->s_id);353 goto out1;354 }355 for (i = 0; i < BFS_ROOT_INO; i++)356 set_bit(i, info->si_imap);357 358 s->s_op = &bfs_sops;359 inode = bfs_iget(s, BFS_ROOT_INO);360 if (IS_ERR(inode)) {361 ret = PTR_ERR(inode);362 goto out1;363 }364 s->s_root = d_make_root(inode);365 if (!s->s_root) {366 ret = -ENOMEM;367 goto out1;368 }369 370 info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS;371 info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1 - le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS;372 info->si_freei = 0;373 info->si_lf_eblk = 0;374 375 /* can we read the last block? */376 bh = sb_bread(s, info->si_blocks - 1);377 if (!bh) {378 printf("Last block not available on %s: %lu\n", s->s_id, info->si_blocks - 1);379 ret = -EIO;380 goto out2;381 }382 brelse(bh);383 384 bh = NULL;385 for (i = BFS_ROOT_INO; i <= info->si_lasti; i++) {386 struct bfs_inode *di;387 int block = (i - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;388 int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;389 unsigned long eblock;390 391 if (!off) {392 brelse(bh);393 bh = sb_bread(s, block);394 }395 396 if (!bh)397 continue;398 399 di = (struct bfs_inode *)bh->b_data + off;400 401 /* test if filesystem is not corrupted */402 403 i_eoff = le32_to_cpu(di->i_eoffset);404 i_sblock = le32_to_cpu(di->i_sblock);405 i_eblock = le32_to_cpu(di->i_eblock);406 s_size = le32_to_cpu(bfs_sb->s_end);407 408 if (i_sblock > info->si_blocks ||409 i_eblock > info->si_blocks ||410 i_sblock > i_eblock ||411 (i_eoff != le32_to_cpu(-1) && i_eoff > s_size) ||412 i_sblock * BFS_BSIZE > i_eoff) {413 414 printf("Inode 0x%08x corrupted on %s\n", i, s->s_id);415 416 brelse(bh);417 ret = -EIO;418 goto out2;419 }420 421 if (!di->i_ino) {422 info->si_freei++;423 continue;424 }425 set_bit(i, info->si_imap);426 info->si_freeb -= BFS_FILEBLOCKS(di);427 428 eblock = le32_to_cpu(di->i_eblock);429 if (eblock > info->si_lf_eblk)430 info->si_lf_eblk = eblock;431 }432 brelse(bh);433 brelse(sbh);434 bfs_dump_imap("fill_super", s);435 return 0;436 437out2:438 dput(s->s_root);439 s->s_root = NULL;440out1:441 brelse(sbh);442out:443 mutex_destroy(&info->bfs_lock);444 kfree(info);445 s->s_fs_info = NULL;446 return ret;447}448 449static struct dentry *bfs_mount(struct file_system_type *fs_type,450 int flags, const char *dev_name, void *data)451{452 return mount_bdev(fs_type, flags, dev_name, data, bfs_fill_super);453}454 455static struct file_system_type bfs_fs_type = {456 .owner = THIS_MODULE,457 .name = "bfs",458 .mount = bfs_mount,459 .kill_sb = kill_block_super,460 .fs_flags = FS_REQUIRES_DEV,461};462MODULE_ALIAS_FS("bfs");463 464static int __init init_bfs_fs(void)465{466 int err = init_inodecache();467 if (err)468 goto out1;469 err = register_filesystem(&bfs_fs_type);470 if (err)471 goto out;472 return 0;473out:474 destroy_inodecache();475out1:476 return err;477}478 479static void __exit exit_bfs_fs(void)480{481 unregister_filesystem(&bfs_fs_type);482 destroy_inodecache();483}484 485module_init(init_bfs_fs)486module_exit(exit_bfs_fs)487