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