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

#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>
#include <asm/uaccess.h>
#include "bfs.h"

21
MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
L
Linus Torvalds 已提交
22 23 24 25 26 27 28 29 30 31 32
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

33
static void bfs_write_super(struct super_block *s);
34
void dump_imap(const char *prefix, struct super_block *s);
L
Linus Torvalds 已提交
35

36
struct inode *bfs_iget(struct super_block *sb, unsigned long ino)
L
Linus Torvalds 已提交
37
{
38
	struct bfs_inode *di;
39
	struct inode *inode;
40
	struct buffer_head *bh;
L
Linus Torvalds 已提交
41 42
	int block, off;

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

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

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

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

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

77 78
	BFS_I(inode)->i_sblock =  le32_to_cpu(di->i_sblock);
	BFS_I(inode)->i_eblock =  le32_to_cpu(di->i_eblock);
79
	BFS_I(inode)->i_dsk_ino = le16_to_cpu(di->i_ino);
80 81 82
	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);
L
Linus Torvalds 已提交
83 84
	inode->i_size = BFS_FILESIZE(di);
	inode->i_blocks = BFS_FILEBLOCKS(di);
85 86 87
	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);
L
Linus Torvalds 已提交
88 89 90 91 92
	inode->i_atime.tv_nsec = 0;
	inode->i_mtime.tv_nsec = 0;
	inode->i_ctime.tv_nsec = 0;

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

error:
	iget_failed(inode);
	return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
99 100
}

101
static int bfs_write_inode(struct inode *inode, int unused)
L
Linus Torvalds 已提交
102
{
103 104
	unsigned int ino = (u16)inode->i_ino;
        unsigned long i_sblock;
105 106
	struct bfs_inode *di;
	struct buffer_head *bh;
L
Linus Torvalds 已提交
107
	int block, off;
D
Dmitri Vorobiev 已提交
108
	struct bfs_sb_info *info = BFS_SB(inode->i_sb);
L
Linus Torvalds 已提交
109

110 111
        dprintf("ino=%08x\n", ino);

112
	if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) {
113
		printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino);
L
Linus Torvalds 已提交
114 115 116
		return -EIO;
	}

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

127
	off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
L
Linus Torvalds 已提交
128 129
	di = (struct bfs_inode *)bh->b_data + off;

130 131
	if (ino == BFS_ROOT_INO)
		di->i_vtype = cpu_to_le32(BFS_VDIR);
L
Linus Torvalds 已提交
132
	else
133 134 135 136 137 138 139 140 141 142 143 144 145 146
		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);
L
Linus Torvalds 已提交
147 148 149

	mark_buffer_dirty(bh);
	brelse(bh);
D
Dmitri Vorobiev 已提交
150
	mutex_unlock(&info->bfs_lock);
L
Linus Torvalds 已提交
151 152 153
	return 0;
}

154
static void bfs_delete_inode(struct inode *inode)
L
Linus Torvalds 已提交
155 156
{
	unsigned long ino = inode->i_ino;
157 158
	struct bfs_inode *di;
	struct buffer_head *bh;
L
Linus Torvalds 已提交
159
	int block, off;
160 161 162
	struct super_block *s = inode->i_sb;
	struct bfs_sb_info *info = BFS_SB(s);
	struct bfs_inode_info *bi = BFS_I(inode);
L
Linus Torvalds 已提交
163

164
	dprintf("ino=%08lx\n", ino);
L
Linus Torvalds 已提交
165

166 167
	truncate_inode_pages(&inode->i_data, 0);

168
	if ((ino < BFS_ROOT_INO) || (ino > info->si_lasti)) {
169
		printf("invalid ino=%08lx\n", ino);
L
Linus Torvalds 已提交
170 171 172 173 174
		return;
	}
	
	inode->i_size = 0;
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
D
Dmitri Vorobiev 已提交
175
	mutex_lock(&info->bfs_lock);
L
Linus Torvalds 已提交
176
	mark_inode_dirty(inode);
177 178

	block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
L
Linus Torvalds 已提交
179 180
	bh = sb_bread(s, block);
	if (!bh) {
181 182
		printf("Unable to read inode %s:%08lx\n",
					inode->i_sb->s_id, ino);
D
Dmitri Vorobiev 已提交
183
		mutex_unlock(&info->bfs_lock);
L
Linus Torvalds 已提交
184 185
		return;
	}
186 187 188 189 190 191
	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);

192
        if (bi->i_dsk_ino) {
A
Al Viro 已提交
193 194
		if (bi->i_sblock)
			info->si_freeb += bi->i_eblock + 1 - bi->i_sblock;
L
Linus Torvalds 已提交
195
		info->si_freei++;
196
		clear_bit(ino, info->si_imap);
L
Linus Torvalds 已提交
197
		dump_imap("delete_inode", s);
198
        }
L
Linus Torvalds 已提交
199

200 201 202 203 204 205 206
	/*
	 * 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;
L
Linus Torvalds 已提交
207 208
		mark_buffer_dirty(info->si_sbh);
	}
D
Dmitri Vorobiev 已提交
209
	mutex_unlock(&info->bfs_lock);
L
Linus Torvalds 已提交
210 211 212 213 214 215
	clear_inode(inode);
}

static void bfs_put_super(struct super_block *s)
{
	struct bfs_sb_info *info = BFS_SB(s);
D
Dmitri Vorobiev 已提交
216

217 218 219
	if (!info)
		return;

220 221 222
	if (s->s_dirt)
		bfs_write_super(s);

L
Linus Torvalds 已提交
223
	brelse(info->si_sbh);
D
Dmitri Vorobiev 已提交
224
	mutex_destroy(&info->bfs_lock);
L
Linus Torvalds 已提交
225 226 227 228 229
	kfree(info->si_imap);
	kfree(info);
	s->s_fs_info = NULL;
}

230
static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf)
L
Linus Torvalds 已提交
231
{
232
	struct super_block *s = dentry->d_sb;
L
Linus Torvalds 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
	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;
}

static void bfs_write_super(struct super_block *s)
{
D
Dmitri Vorobiev 已提交
249 250 251
	struct bfs_sb_info *info = BFS_SB(s);

	mutex_lock(&info->bfs_lock);
L
Linus Torvalds 已提交
252
	if (!(s->s_flags & MS_RDONLY))
D
Dmitri Vorobiev 已提交
253
		mark_buffer_dirty(info->si_sbh);
L
Linus Torvalds 已提交
254
	s->s_dirt = 0;
D
Dmitri Vorobiev 已提交
255
	mutex_unlock(&info->bfs_lock);
L
Linus Torvalds 已提交
256 257
}

258
static struct kmem_cache *bfs_inode_cachep;
L
Linus Torvalds 已提交
259 260 261 262

static struct inode *bfs_alloc_inode(struct super_block *sb)
{
	struct bfs_inode_info *bi;
263
	bi = kmem_cache_alloc(bfs_inode_cachep, GFP_KERNEL);
L
Linus Torvalds 已提交
264 265 266 267 268 269 270 271 272 273
	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));
}

274
static void init_once(void *foo)
L
Linus Torvalds 已提交
275 276 277
{
	struct bfs_inode_info *bi = foo;

C
Christoph Lameter 已提交
278
	inode_init_once(&bi->vfs_inode);
L
Linus Torvalds 已提交
279
}
280

L
Linus Torvalds 已提交
281 282 283 284
static int init_inodecache(void)
{
	bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
					     sizeof(struct bfs_inode_info),
285 286
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD),
287
					     init_once);
L
Linus Torvalds 已提交
288 289 290 291 292 293 294
	if (bfs_inode_cachep == NULL)
		return -ENOMEM;
	return 0;
}

static void destroy_inodecache(void)
{
295
	kmem_cache_destroy(bfs_inode_cachep);
L
Linus Torvalds 已提交
296 297
}

298
static const struct super_operations bfs_sops = {
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307
	.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,
	.statfs		= bfs_statfs,
};

308
void dump_imap(const char *prefix, struct super_block *s)
L
Linus Torvalds 已提交
309
{
310
#ifdef DEBUG
L
Linus Torvalds 已提交
311 312 313 314 315
	int i;
	char *tmpbuf = (char *)get_zeroed_page(GFP_KERNEL);

	if (!tmpbuf)
		return;
316 317
	for (i = BFS_SB(s)->si_lasti; i >= 0; i--) {
		if (i > PAGE_SIZE - 100) break;
L
Linus Torvalds 已提交
318 319 320 321 322
		if (test_bit(i, BFS_SB(s)->si_imap))
			strcat(tmpbuf, "1");
		else
			strcat(tmpbuf, "0");
	}
323 324
	printf("BFS-fs: %s: lasti=%08lx <%s>\n",
				prefix, BFS_SB(s)->si_lasti, tmpbuf);
L
Linus Torvalds 已提交
325 326 327 328 329 330
	free_page((unsigned long)tmpbuf);
#endif
}

static int bfs_fill_super(struct super_block *s, void *data, int silent)
{
331 332 333
	struct buffer_head *bh;
	struct bfs_super_block *bfs_sb;
	struct inode *inode;
334
	unsigned i, imap_len;
335
	struct bfs_sb_info *info;
336
	long ret = -EINVAL;
337
	unsigned long i_sblock, i_eblock, i_eoff, s_size;
L
Linus Torvalds 已提交
338

339
	info = kzalloc(sizeof(*info), GFP_KERNEL);
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349
	if (!info)
		return -ENOMEM;
	s->s_fs_info = info;

	sb_set_blocksize(s, BFS_BSIZE);

	bh = sb_bread(s, 0);
	if(!bh)
		goto out;
	bfs_sb = (struct bfs_super_block *)bh->b_data;
350
	if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) {
L
Linus Torvalds 已提交
351 352
		if (!silent)
			printf("No BFS filesystem on %s (magic=%08x)\n", 
353
				s->s_id,  le32_to_cpu(bfs_sb->s_magic));
L
Linus Torvalds 已提交
354 355 356 357 358 359 360
		goto out;
	}
	if (BFS_UNCLEAN(bfs_sb, s) && !silent)
		printf("%s is unclean, continuing\n", s->s_id);

	s->s_magic = BFS_MAGIC;
	info->si_sbh = bh;
361 362 363 364 365 366

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

367 368 369 370
	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;
371
	info->si_imap = kzalloc(imap_len, GFP_KERNEL);
L
Linus Torvalds 已提交
372 373
	if (!info->si_imap)
		goto out;
374
	for (i = 0; i < BFS_ROOT_INO; i++)
L
Linus Torvalds 已提交
375 376 377
		set_bit(i, info->si_imap);

	s->s_op = &bfs_sops;
378 379 380
	inode = bfs_iget(s, BFS_ROOT_INO);
	if (IS_ERR(inode)) {
		ret = PTR_ERR(inode);
L
Linus Torvalds 已提交
381 382 383 384 385 386
		kfree(info->si_imap);
		goto out;
	}
	s->s_root = d_alloc_root(inode);
	if (!s->s_root) {
		iput(inode);
387
		ret = -ENOMEM;
L
Linus Torvalds 已提交
388 389 390 391
		kfree(info->si_imap);
		goto out;
	}

392 393 394
	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;
L
Linus Torvalds 已提交
395 396
	info->si_freei = 0;
	info->si_lf_eblk = 0;
397 398 399 400 401 402 403 404 405 406 407 408

	/* 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);
		iput(inode);
		ret = -EIO;
		kfree(info->si_imap);
		goto out;
	}
	brelse(bh);

A
Al Viro 已提交
409
	bh = NULL;
410
	for (i = BFS_ROOT_INO; i <= info->si_lasti; i++) {
A
Al Viro 已提交
411
		struct bfs_inode *di;
412
		int block = (i - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1;
A
Al Viro 已提交
413
		int off = (i - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK;
D
Dmitri Vorobiev 已提交
414
		unsigned long eblock;
A
Al Viro 已提交
415 416 417 418 419 420 421 422 423 424 425

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

		if (!bh)
			continue;

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

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
		/* 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);
			s->s_root = NULL;
			kfree(info->si_imap);
			kfree(info);
			s->s_fs_info = NULL;
			return -EIO;
		}

A
Al Viro 已提交
449
		if (!di->i_ino) {
L
Linus Torvalds 已提交
450
			info->si_freei++;
A
Al Viro 已提交
451 452 453 454 455 456
			continue;
		}
		set_bit(i, info->si_imap);
		info->si_freeb -= BFS_FILEBLOCKS(di);

		eblock =  le32_to_cpu(di->i_eblock);
457
		if (eblock > info->si_lf_eblk)
A
Al Viro 已提交
458
			info->si_lf_eblk = eblock;
L
Linus Torvalds 已提交
459
	}
A
Al Viro 已提交
460
	brelse(bh);
L
Linus Torvalds 已提交
461
	if (!(s->s_flags & MS_RDONLY)) {
A
Al Viro 已提交
462
		mark_buffer_dirty(info->si_sbh);
L
Linus Torvalds 已提交
463 464 465
		s->s_dirt = 1;
	} 
	dump_imap("read_super", s);
D
Dmitri Vorobiev 已提交
466
	mutex_init(&info->bfs_lock);
L
Linus Torvalds 已提交
467 468 469 470 471 472
	return 0;

out:
	brelse(bh);
	kfree(info);
	s->s_fs_info = NULL;
473
	return ret;
L
Linus Torvalds 已提交
474 475
}

476 477
static int bfs_get_sb(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
L
Linus Torvalds 已提交
478
{
479
	return get_sb_bdev(fs_type, flags, dev_name, data, bfs_fill_super, mnt);
L
Linus Torvalds 已提交
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
}

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)