inode.c 12.5 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3
/*
 *	fs/bfs/inode.c
 *	BFS superblock and inode operations.
4
 *	Copyright (C) 1999-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
Linus Torvalds's avatar
Linus Torvalds committed
5
 *	From fs/minix, Copyright (C) 1991, 1992 Linus Torvalds.
6 7
 *
 *      Made endianness-clean by Andrew Stribblehill <ads@wompom.org>, 2005.
Linus Torvalds's avatar
Linus Torvalds committed
8 9 10 11 12 13 14 15 16 17
 */

#include <linux/module.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
18
#include <linux/writeback.h>
Linus Torvalds's avatar
Linus Torvalds committed
19 20 21
#include <asm/uaccess.h>
#include "bfs.h"

22
MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
Linus Torvalds's avatar
Linus Torvalds committed
23 24 25 26 27 28 29 30 31 32 33
MODULE_DESCRIPTION("SCO UnixWare BFS filesystem for Linux");
MODULE_LICENSE("GPL");

#undef DEBUG

#ifdef DEBUG
#define dprintf(x...)	printf(x)
#else
#define dprintf(x...)
#endif

34
static void bfs_write_super(struct super_block *s);
35
void dump_imap(const char *prefix, struct super_block *s);
Linus Torvalds's avatar
Linus Torvalds committed
36

37
struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
Linus Torvalds's avatar
Linus Torvalds committed
38
{
39
	struct bfs_inode *di;
40
	struct inode *inode;
41
	struct buffer_head *bh;
Linus Torvalds's avatar
Linus Torvalds committed
42 43
	int block, off;

44 45 46 47 48 49
	inode = iget_locked(sb, ino);
	if (IS_ERR(inode))
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

50
	if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
Linus Torvalds's avatar
Linus Torvalds committed
51
		printf("Bad inode number %s:%08lx\n", inode->i_sb->s_id, ino);
52
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
53 54
	}

55
	block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
Linus Torvalds's avatar
Linus Torvalds committed
56 57
	bh = sb_bread(inode->i_sb, block);
	if (!bh) {
58 59
		printf("Unable to read inode %s:%08lx\n", inode->i_sb->s_id,
									ino);
60
		goto error;
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63 64 65
	}

	off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
	di = (struct bfs_inode *)bh->b_data + off;

66
	inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode);
67
	if (le32_to_cpu(di->i_vtype) == BFS_VDIR) {
Linus Torvalds's avatar
Linus Torvalds committed
68 69 70
		inode->i_mode |= S_IFDIR;
		inode->i_op = &bfs_dir_inops;
		inode->i_fop = &bfs_dir_operations;
71
	} else if (le32_to_cpu(di->i_vtype) == BFS_VREG) {
Linus Torvalds's avatar
Linus Torvalds committed
72 73 74 75 76 77
		inode->i_mode |= S_IFREG;
		inode->i_op = &bfs_file_inops;
		inode->i_fop = &bfs_file_operations;
		inode->i_mapping->a_ops = &bfs_aops;
	}

78 79
	BFS_I(inode)->i_sblock =  le32_to_cpu(di->i_sblock);
	BFS_I(inode)->i_eblock =  le32_to_cpu(di->i_eblock);
80
	BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino);
81 82 83
	inode->i_uid =  le32_to_cpu(di->i_uid);
	inode->i_gid =  le32_to_cpu(di->i_gid);
	inode->i_nlink =  le32_to_cpu(di->i_nlink);
Linus Torvalds's avatar
Linus Torvalds committed
84 85
	inode->i_size = BFS_FILESIZE(di);
	inode->i_blocks = BFS_FILEBLOCKS(di);
86 87 88
	inode->i_atime.tv_sec =  le32_to_cpu(di->i_atime);
	inode->i_mtime.tv_sec =  le32_to_cpu(di->i_mtime);
	inode->i_ctime.tv_sec =  le32_to_cpu(di->i_ctime);
Linus Torvalds's avatar
Linus Torvalds committed
89 90 91 92 93
	inode->i_atime.tv_nsec = 0;
	inode->i_mtime.tv_nsec = 0;
	inode->i_ctime.tv_nsec = 0;

	brelse(bh);
94 95 96 97 98 99
	unlock_new_inode(inode);
	return inode;

error:
	iget_failed(inode);
	return ERR_PTR(-EIO);
Linus Torvalds's avatar
Linus Torvalds committed
100 101
}

102
static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc)
Linus Torvalds's avatar
Linus Torvalds committed
103
{
104
	struct bfs_sb_info *info = BFS_SB(inode->i_sb);
105 106
	unsigned int ino = (u16)inode->i_ino;
        unsigned long i_sblock;
107 108
	struct bfs_inode *di;
	struct buffer_head *bh;
Linus Torvalds's avatar
Linus Torvalds committed
109
	int block, off;
110
	int err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
111

112 113
        dprintf("ino=%08x\n", ino);

114
	if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
115
		printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino);
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118
		return -EIO;
	}

Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
119
	mutex_lock(&info->bfs_lock);
120
	block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
Linus Torvalds's avatar
Linus Torvalds committed
121 122
	bh = sb_bread(inode->i_sb, block);
	if (!bh) {
123 124
		printf("Unable to read inode %s:%08x\n",
				inode->i_sb->s_id, ino);
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
125
		mutex_unlock(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
126 127 128
		return -EIO;
	}

129
	off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
Linus Torvalds's avatar
Linus Torvalds committed
130 131
	di = (struct bfs_inode *)bh->b_data + off;

132 133
	if (ino == BFS_ROOT_INO)
		di->i_vtype = cpu_to_le32(BFS_VDIR);
Linus Torvalds's avatar
Linus Torvalds committed
134
	else
135 136 137 138 139 140 141 142 143 144 145 146 147 148
		di->i_vtype = cpu_to_le32(BFS_VREG);

	di->i_ino = cpu_to_le16(ino);
	di->i_mode = cpu_to_le32(inode->i_mode);
	di->i_uid = cpu_to_le32(inode->i_uid);
	di->i_gid = cpu_to_le32(inode->i_gid);
	di->i_nlink = cpu_to_le32(inode->i_nlink);
	di->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
	di->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
	di->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
        i_sblock = BFS_I(inode)->i_sblock;
	di->i_sblock = cpu_to_le32(i_sblock);
	di->i_eblock = cpu_to_le32(BFS_I(inode)->i_eblock);
	di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1);
Linus Torvalds's avatar
Linus Torvalds committed
149 150

	mark_buffer_dirty(bh);
151
	if (wbc->sync_mode == WB_SYNC_ALL) {
152 153 154 155
		sync_dirty_buffer(bh);
		if (buffer_req(bh) && !buffer_uptodate(bh))
			err = -EIO;
	}
Linus Torvalds's avatar
Linus Torvalds committed
156
	brelse(bh);
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
157
	mutex_unlock(&info->bfs_lock);
158
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
159 160
}

161
static void bfs_delete_inode(struct inode *inode)
Linus Torvalds's avatar
Linus Torvalds committed
162 163
{
	unsigned long ino = inode->i_ino;
164 165
	struct bfs_inode *di;
	struct buffer_head *bh;
Linus Torvalds's avatar
Linus Torvalds committed
166
	int block, off;
167 168 169
	struct super_block *s = inode->i_sb;
	struct bfs_sb_info *info = BFS_SB(s);
	struct bfs_inode_info *bi = BFS_I(inode);
Linus Torvalds's avatar
Linus Torvalds committed
170

171
	dprintf("ino=%08lx\n", ino);
Linus Torvalds's avatar
Linus Torvalds committed
172

173 174
	truncate_inode_pages(&inode->i_data, 0);

175
	if ((ino < BFS_ROOT_INO) || (ino > info->si_lasti)) {
176
		printf("invalid ino=%08lx\n", ino);
Linus Torvalds's avatar
Linus Torvalds committed
177 178 179 180 181
		return;
	}
	
	inode->i_size = 0;
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
182
	mutex_lock(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
183
	mark_inode_dirty(inode);
184 185

	block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
Linus Torvalds's avatar
Linus Torvalds committed
186 187
	bh = sb_bread(s, block);
	if (!bh) {
188 189
		printf("Unable to read inode %s:%08lx\n",
					inode->i_sb->s_id, ino);
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
190
		mutex_unlock(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
191 192
		return;
	}
193 194 195 196 197 198
	off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
	di = (struct bfs_inode *)bh->b_data + off;
	memset((void *)di, 0, sizeof(struct bfs_inode));
	mark_buffer_dirty(bh);
	brelse(bh);

199
        if (bi->i_dsk_ino) {
Al Viro's avatar
Al Viro committed
200 201
		if (bi->i_sblock)
			info->si_freeb += bi->i_eblock + 1 - bi->i_sblock;
Linus Torvalds's avatar
Linus Torvalds committed
202
		info->si_freei++;
203
		clear_bit(ino, info->si_imap);
Linus Torvalds's avatar
Linus Torvalds committed
204
		dump_imap("delete_inode", s);
205
        }
Linus Torvalds's avatar
Linus Torvalds committed
206

207 208 209 210 211 212 213
	/*
	 * If this was the last file, make the previous block
	 * "last block of the last file" even if there is no
	 * real file there, saves us 1 gap.
	 */
	if (info->si_lf_eblk == bi->i_eblock) {
		info->si_lf_eblk = bi->i_sblock - 1;
Linus Torvalds's avatar
Linus Torvalds committed
214 215
		mark_buffer_dirty(info->si_sbh);
	}
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
216
	mutex_unlock(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
217 218 219
	clear_inode(inode);
}

Christoph Hellwig's avatar
Christoph Hellwig committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
static int bfs_sync_fs(struct super_block *sb, int wait)
{
	struct bfs_sb_info *info = BFS_SB(sb);

	mutex_lock(&info->bfs_lock);
	mark_buffer_dirty(info->si_sbh);
	sb->s_dirt = 0;
	mutex_unlock(&info->bfs_lock);

	return 0;
}

static void bfs_write_super(struct super_block *sb)
{
	if (!(sb->s_flags & MS_RDONLY))
		bfs_sync_fs(sb, 1);
	else
		sb->s_dirt = 0;
}

Linus Torvalds's avatar
Linus Torvalds committed
240 241 242
static void bfs_put_super(struct super_block *s)
{
	struct bfs_sb_info *info = BFS_SB(s);
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
243

244 245 246
	if (!info)
		return;

247 248
	lock_kernel();

249 250 251
	if (s->s_dirt)
		bfs_write_super(s);

Linus Torvalds's avatar
Linus Torvalds committed
252
	brelse(info->si_sbh);
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
253
	mutex_destroy(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
254 255 256
	kfree(info->si_imap);
	kfree(info);
	s->s_fs_info = NULL;
257 258

	unlock_kernel();
Linus Torvalds's avatar
Linus Torvalds committed
259 260
}

261
static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds's avatar
Linus Torvalds committed
262
{
263
	struct super_block *s = dentry->d_sb;
Linus Torvalds's avatar
Linus Torvalds committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277
	struct bfs_sb_info *info = BFS_SB(s);
	u64 id = huge_encode_dev(s->s_bdev->bd_dev);
	buf->f_type = BFS_MAGIC;
	buf->f_bsize = s->s_blocksize;
	buf->f_blocks = info->si_blocks;
	buf->f_bfree = buf->f_bavail = info->si_freeb;
	buf->f_files = info->si_lasti + 1 - BFS_ROOT_INO;
	buf->f_ffree = info->si_freei;
	buf->f_fsid.val[0] = (u32)id;
	buf->f_fsid.val[1] = (u32)(id >> 32);
	buf->f_namelen = BFS_NAMELEN;
	return 0;
}

278
static struct kmem_cache *bfs_inode_cachep;
Linus Torvalds's avatar
Linus Torvalds committed
279 280 281 282

static struct inode *bfs_alloc_inode(struct super_block *sb)
{
	struct bfs_inode_info *bi;
283
	bi = kmem_cache_alloc(bfs_inode_cachep, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
284 285 286 287 288 289 290 291 292 293
	if (!bi)
		return NULL;
	return &bi->vfs_inode;
}

static void bfs_destroy_inode(struct inode *inode)
{
	kmem_cache_free(bfs_inode_cachep, BFS_I(inode));
}

294
static void init_once(void *foo)
Linus Torvalds's avatar
Linus Torvalds committed
295 296 297
{
	struct bfs_inode_info *bi = foo;

298
	inode_init_once(&bi->vfs_inode);
Linus Torvalds's avatar
Linus Torvalds committed
299
}
300

Linus Torvalds's avatar
Linus Torvalds committed
301 302 303 304
static int init_inodecache(void)
{
	bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
					     sizeof(struct bfs_inode_info),
305 306
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD),
307
					     init_once);
Linus Torvalds's avatar
Linus Torvalds committed
308 309 310 311 312 313 314
	if (bfs_inode_cachep == NULL)
		return -ENOMEM;
	return 0;
}

static void destroy_inodecache(void)
{
315
	kmem_cache_destroy(bfs_inode_cachep);
Linus Torvalds's avatar
Linus Torvalds committed
316 317
}

318
static const struct super_operations bfs_sops = {
Linus Torvalds's avatar
Linus Torvalds committed
319 320 321 322 323 324
	.alloc_inode	= bfs_alloc_inode,
	.destroy_inode	= bfs_destroy_inode,
	.write_inode	= bfs_write_inode,
	.delete_inode	= bfs_delete_inode,
	.put_super	= bfs_put_super,
	.write_super	= bfs_write_super,
Christoph Hellwig's avatar
Christoph Hellwig committed
325
	.sync_fs	= bfs_sync_fs,
Linus Torvalds's avatar
Linus Torvalds committed
326 327 328
	.statfs		= bfs_statfs,
};

329
void dump_imap(const char *prefix, struct super_block *s)
Linus Torvalds's avatar
Linus Torvalds committed
330
{
331
#ifdef DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
332 333 334 335 336
	int i;
	char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL);

	if (!tmpbuf)
		return;
337 338
	for (i = BFS_SB(s)->si_lasti; i >= 0; i--) {
		if (i > PAGE_SIZE - 100) break;
Linus Torvalds's avatar
Linus Torvalds committed
339 340 341 342 343
		if (test_bit(i, BFS_SB(s)->si_imap))
			strcat(tmpbuf, "1");
		else
			strcat(tmpbuf, "0");
	}
344 345
	printf("BFS-fs: %s: lasti=%08lx <%s>\n",
				prefix, BFS_SB(s)->si_lasti, tmpbuf);
Linus Torvalds's avatar
Linus Torvalds committed
346 347 348 349 350 351
	free_page((unsigned long)tmpbuf);
#endif
}

static int bfs_fill_super(struct super_block *s, void *data, int silent)
{
352 353 354
	struct buffer_head *bh;
	struct bfs_super_block *bfs_sb;
	struct inode *inode;
355
	unsigned i, imap_len;
356
	struct bfs_sb_info *info;
357
	int ret = -EINVAL;
358
	unsigned long i_sblock, i_eblock, i_eoff, s_size;
Linus Torvalds's avatar
Linus Torvalds committed
359

360
	info = kzalloc(sizeof(*info), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
361 362
	if (!info)
		return -ENOMEM;
363
	mutex_init(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
364 365 366 367
	s->s_fs_info = info;

	sb_set_blocksize(s, BFS_BSIZE);

368 369
	info->si_sbh = sb_bread(s, 0);
	if (!info->si_sbh)
Linus Torvalds's avatar
Linus Torvalds committed
370
		goto out;
371
	bfs_sb = (struct bfs_super_block *)info->si_sbh->b_data;
372
	if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {
Linus Torvalds's avatar
Linus Torvalds committed
373 374
		if (!silent)
			printf("No BFS filesystem on %s (magic=%08x)\n", 
375
				s->s_id,  le32_to_cpu(bfs_sb->s_magic));
376
		goto out1;
Linus Torvalds's avatar
Linus Torvalds committed
377 378 379 380 381
	}
	if (BFS_UNCLEAN(bfs_sb, s) && !silent)
		printf("%s is unclean, continuing\n", s->s_id);

	s->s_magic = BFS_MAGIC;
382 383 384

	if (le32_to_cpu(bfs_sb->s_start) > le32_to_cpu(bfs_sb->s_end)) {
		printf("Superblock is corrupted\n");
385
		goto out1;
386 387
	}

388 389 390 391
	info->si_lasti = (le32_to_cpu(bfs_sb->s_start) - BFS_BSIZE) /
					sizeof(struct bfs_inode)
					+ BFS_ROOT_INO - 1;
	imap_len = (info->si_lasti / 8) + 1;
392
	info->si_imap = kzalloc(imap_len, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
393
	if (!info->si_imap)
394
		goto out1;
395
	for (i = 0; i < BFS_ROOT_INO; i++)
Linus Torvalds's avatar
Linus Torvalds committed
396 397 398
		set_bit(i, info->si_imap);

	s->s_op = &bfs_sops;
399 400 401
	inode = bfs_iget(s, BFS_ROOT_INO);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
402
		goto out2;
Linus Torvalds's avatar
Linus Torvalds committed
403 404 405 406
	}
	s->s_root = d_alloc_root(inode);
	if (!s->s_root) {
		iput(inode);
407
		ret = -ENOMEM;
408
		goto out2;
Linus Torvalds's avatar
Linus Torvalds committed
409 410
	}

411 412 413
	info->si_blocks = (le32_to_cpu(bfs_sb->s_end) + 1) >> BFS_BSIZE_BITS;
	info->si_freeb = (le32_to_cpu(bfs_sb->s_end) + 1
			- le32_to_cpu(bfs_sb->s_start)) >> BFS_BSIZE_BITS;
Linus Torvalds's avatar
Linus Torvalds committed
414 415
	info->si_freei = 0;
	info->si_lf_eblk = 0;
416 417 418 419 420 421

	/* can we read the last block? */
	bh = sb_bread(s, info->si_blocks - 1);
	if (!bh) {
		printf("Last block not available: %lu\n", info->si_blocks - 1);
		ret = -EIO;
422
		goto out3;
423 424 425
	}
	brelse(bh);

Al Viro's avatar
Al Viro committed
426
	bh = NULL;
427
	for (i = BFS_ROOT_INO; i <= info->si_lasti; i++) {
Al Viro's avatar
Al Viro committed
428
		struct bfs_inode *di;
429
		int block = (i - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
Al Viro's avatar
Al Viro committed
430
		int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
Dmitri Vorobiev's avatar
Dmitri Vorobiev committed
431
		unsigned long eblock;
Al Viro's avatar
Al Viro committed
432 433 434 435 436 437 438 439 440 441 442

		if (!off) {
			brelse(bh);
			bh = sb_bread(s, block);
		}

		if (!bh)
			continue;

		di = (struct bfs_inode *)bh->b_data + off;

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
		/* test if filesystem is not corrupted */

		i_eoff = le32_to_cpu(di->i_eoffset);
		i_sblock = le32_to_cpu(di->i_sblock);
		i_eblock = le32_to_cpu(di->i_eblock);
		s_size = le32_to_cpu(bfs_sb->s_end);

		if (i_sblock > info->si_blocks ||
			i_eblock > info->si_blocks ||
			i_sblock > i_eblock ||
			i_eoff > s_size ||
			i_sblock * BFS_BSIZE > i_eoff) {

			printf("Inode 0x%08x corrupted\n", i);

			brelse(bh);
459 460
			ret = -EIO;
			goto out3;
461 462
		}

Al Viro's avatar
Al Viro committed
463
		if (!di->i_ino) {
Linus Torvalds's avatar
Linus Torvalds committed
464
			info->si_freei++;
Al Viro's avatar
Al Viro committed
465 466 467 468 469 470
			continue;
		}
		set_bit(i, info->si_imap);
		info->si_freeb -= BFS_FILEBLOCKS(di);

		eblock =  le32_to_cpu(di->i_eblock);
471
		if (eblock > info->si_lf_eblk)
Al Viro's avatar
Al Viro committed
472
			info->si_lf_eblk = eblock;
Linus Torvalds's avatar
Linus Torvalds committed
473
	}
Al Viro's avatar
Al Viro committed
474
	brelse(bh);
Linus Torvalds's avatar
Linus Torvalds committed
475
	if (!(s->s_flags & MS_RDONLY)) {
Al Viro's avatar
Al Viro committed
476
		mark_buffer_dirty(info->si_sbh);
Linus Torvalds's avatar
Linus Torvalds committed
477 478 479 480 481
		s->s_dirt = 1;
	} 
	dump_imap("read_super", s);
	return 0;

482 483 484 485 486 487 488
out3:
	dput(s->s_root);
	s->s_root = NULL;
out2:
	kfree(info->si_imap);
out1:
	brelse(info->si_sbh);
Linus Torvalds's avatar
Linus Torvalds committed
489
out:
490
	mutex_destroy(&info->bfs_lock);
Linus Torvalds's avatar
Linus Torvalds committed
491 492
	kfree(info);
	s->s_fs_info = NULL;
493
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
494 495
}

496 497
static int bfs_get_sb(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
Linus Torvalds's avatar
Linus Torvalds committed
498
{
499
	return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super, mnt);
Linus Torvalds's avatar
Linus Torvalds committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
}

static struct file_system_type bfs_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "bfs",
	.get_sb		= bfs_get_sb,
	.kill_sb	= kill_block_super,
	.fs_flags	= FS_REQUIRES_DEV,
};

static int __init init_bfs_fs(void)
{
	int err = init_inodecache();
	if (err)
		goto out1;
        err = register_filesystem(&bfs_fs_type);
	if (err)
		goto out;
	return 0;
out:
	destroy_inodecache();
out1:
	return err;
}

static void __exit exit_bfs_fs(void)
{
	unregister_filesystem(&bfs_fs_type);
	destroy_inodecache();
}

module_init(init_bfs_fs)
module_exit(exit_bfs_fs)