inode.c 12.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * QNX4 file system, Linux implementation.
 *
 * Version : 0.2.1
 *
 * Using parts of the xiafs filesystem.
 *
 * History :
 *
 * 01-06-1998 by Richard Frowijn : first release.
 * 20-06-1998 by Frank Denis : Linux 2.1.99+ support, boot signature, misc.
 * 30-06-1998 by Frank Denis : first step to write inodes.
 */

#include <linux/module.h>
#include <linux/init.h>
A
Al Viro 已提交
17
#include <linux/slab.h>
L
Linus Torvalds 已提交
18 19 20 21
#include <linux/highuid.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
A
Al Viro 已提交
22
#include <linux/writeback.h>
A
Al Viro 已提交
23 24
#include <linux/statfs.h>
#include "qnx4.h"
L
Linus Torvalds 已提交
25 26 27 28

#define QNX4_VERSION  4
#define QNX4_BMNAME   ".bitmap"

29
static const struct super_operations qnx4_sops;
L
Linus Torvalds 已提交
30 31 32 33 34

static void qnx4_put_super(struct super_block *sb);
static struct inode *qnx4_alloc_inode(struct super_block *sb);
static void qnx4_destroy_inode(struct inode *inode);
static int qnx4_remount(struct super_block *sb, int *flags, char *data);
35
static int qnx4_statfs(struct dentry *, struct kstatfs *);
L
Linus Torvalds 已提交
36

37
static const struct super_operations qnx4_sops =
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
{
	.alloc_inode	= qnx4_alloc_inode,
	.destroy_inode	= qnx4_destroy_inode,
	.put_super	= qnx4_put_super,
	.statfs		= qnx4_statfs,
	.remount_fs	= qnx4_remount,
};

static int qnx4_remount(struct super_block *sb, int *flags, char *data)
{
	struct qnx4_sb_info *qs;

	qs = qnx4_sb(sb);
	qs->Version = QNX4_VERSION;
	*flags |= MS_RDONLY;
	return 0;
}

static struct buffer_head *qnx4_getblk(struct inode *inode, int nr,
				       int create)
{
	struct buffer_head *result = NULL;

	if ( nr >= 0 )
		nr = qnx4_block_map( inode, nr );
	if (nr) {
		result = sb_getblk(inode->i_sb, nr);
		return result;
	}
67
	return NULL;
L
Linus Torvalds 已提交
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
}

struct buffer_head *qnx4_bread(struct inode *inode, int block, int create)
{
	struct buffer_head *bh;

	bh = qnx4_getblk(inode, block, create);
	if (!bh || buffer_uptodate(bh)) {
		return bh;
	}
	ll_rw_block(READ, 1, &bh);
	wait_on_buffer(bh);
	if (buffer_uptodate(bh)) {
		return bh;
	}
	brelse(bh);

	return NULL;
}

static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create )
{
	unsigned long phys;

92
	QNX4DEBUG((KERN_INFO "qnx4: qnx4_get_block inode=[%ld] iblock=[%ld]\n",inode->i_ino,iblock));
L
Linus Torvalds 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109

	phys = qnx4_block_map( inode, iblock );
	if ( phys ) {
		// logical block is before EOF
		map_bh(bh, inode->i_sb, phys);
	}
	return 0;
}

unsigned long qnx4_block_map( struct inode *inode, long iblock )
{
	int ix;
	long offset, i_xblk;
	unsigned long block = 0;
	struct buffer_head *bh = NULL;
	struct qnx4_xblk *xblk = NULL;
	struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
110
	u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
L
Linus Torvalds 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124

	if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
		// iblock is in the first extent. This is easy.
		block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1;
	} else {
		// iblock is beyond first extent. We have to follow the extent chain.
		i_xblk = le32_to_cpu(qnx4_inode->di_xblk);
		offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size);
		ix = 0;
		while ( --nxtnt > 0 ) {
			if ( ix == 0 ) {
				// read next xtnt block.
				bh = sb_bread(inode->i_sb, i_xblk - 1);
				if ( !bh ) {
125
					QNX4DEBUG((KERN_ERR "qnx4: I/O error reading xtnt block [%ld])\n", i_xblk - 1));
L
Linus Torvalds 已提交
126 127 128 129
					return -EIO;
				}
				xblk = (struct qnx4_xblk*)bh->b_data;
				if ( memcmp( xblk->xblk_signature, "IamXblk", 7 ) ) {
130
					QNX4DEBUG((KERN_ERR "qnx4: block at %ld is not a valid xtnt\n", qnx4_inode->i_xblk));
L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
					return -EIO;
				}
			}
			if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) {
				// got it!
				block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1;
				break;
			}
			offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size);
			if ( ++ix >= xblk->xblk_num_xtnts ) {
				i_xblk = le32_to_cpu(xblk->xblk_next_xblk);
				ix = 0;
				brelse( bh );
				bh = NULL;
			}
		}
		if ( bh )
			brelse( bh );
	}

151
	QNX4DEBUG((KERN_INFO "qnx4: mapping block %ld of inode %ld = %ld\n",iblock,inode->i_ino,block));
L
Linus Torvalds 已提交
152 153 154
	return block;
}

155
static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
L
Linus Torvalds 已提交
156
{
157
	struct super_block *sb = dentry->d_sb;
C
Coly Li 已提交
158
	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
159

L
Linus Torvalds 已提交
160 161 162 163 164 165 166 167
	lock_kernel();

	buf->f_type    = sb->s_magic;
	buf->f_bsize   = sb->s_blocksize;
	buf->f_blocks  = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size) * 8;
	buf->f_bfree   = qnx4_count_free_blocks(sb);
	buf->f_bavail  = buf->f_bfree;
	buf->f_namelen = QNX4_NAME_MAX;
C
Coly Li 已提交
168 169
	buf->f_fsid.val[0] = (u32)id;
	buf->f_fsid.val[1] = (u32)(id >> 32);
L
Linus Torvalds 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

	unlock_kernel();

	return 0;
}

/*
 * Check the root directory of the filesystem to make sure
 * it really _is_ a qnx4 filesystem, and to check the size
 * of the directory entry.
 */
static const char *qnx4_checkroot(struct super_block *sb)
{
	struct buffer_head *bh;
	struct qnx4_inode_entry *rootdir;
	int rd, rl;
	int i, j;
	int found = 0;

	if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/') {
		return "no qnx4 filesystem (no root dir).";
	} else {
192
		QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id));
L
Linus Torvalds 已提交
193 194 195 196 197 198 199 200 201 202
		rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
		rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
		for (j = 0; j < rl; j++) {
			bh = sb_bread(sb, rd + j);	/* root dir, first block */
			if (bh == NULL) {
				return "unable to read root entry.";
			}
			for (i = 0; i < QNX4_INODES_PER_BLOCK; i++) {
				rootdir = (struct qnx4_inode_entry *) (bh->b_data + i * QNX4_DIR_ENTRY_SIZE);
				if (rootdir->di_fname != NULL) {
203
					QNX4DEBUG((KERN_INFO "rootdir entry found : [%s]\n", rootdir->di_fname));
204 205
					if (!strcmp(rootdir->di_fname,
						    QNX4_BMNAME)) {
L
Linus Torvalds 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
						found = 1;
						qnx4_sb(sb)->BitMap = kmalloc( sizeof( struct qnx4_inode_entry ), GFP_KERNEL );
						if (!qnx4_sb(sb)->BitMap) {
							brelse (bh);
							return "not enough memory for bitmap inode";
						}
						memcpy( qnx4_sb(sb)->BitMap, rootdir, sizeof( struct qnx4_inode_entry ) );	/* keep bitmap inode known */
						break;
					}
				}
			}
			brelse(bh);
			if (found != 0) {
				break;
			}
		}
		if (found == 0) {
			return "bitmap file not found.";
		}
	}
	return NULL;
}

static int qnx4_fill_super(struct super_block *s, void *data, int silent)
{
	struct buffer_head *bh;
	struct inode *root;
	const char *errmsg;
	struct qnx4_sb_info *qs;
235
	int ret = -EINVAL;
L
Linus Torvalds 已提交
236

237 238
	lock_kernel();

239
	qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
240 241
	if (!qs) {
		unlock_kernel();
L
Linus Torvalds 已提交
242
		return -ENOMEM;
243
	}
L
Linus Torvalds 已提交
244 245 246 247 248 249 250 251 252
	s->s_fs_info = qs;

	sb_set_blocksize(s, QNX4_BLOCK_SIZE);

	/* Check the superblock signature. Since the qnx4 code is
	   dangerous, we should leave as quickly as possible
	   if we don't belong here... */
	bh = sb_bread(s, 1);
	if (!bh) {
253
		printk(KERN_ERR "qnx4: unable to read the superblock\n");
L
Linus Torvalds 已提交
254 255
		goto outnobh;
	}
256
	if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
L
Linus Torvalds 已提交
257
		if (!silent)
258
			printk(KERN_ERR "qnx4: wrong fsid in superblock.\n");
L
Linus Torvalds 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271
		goto out;
	}
	s->s_op = &qnx4_sops;
	s->s_magic = QNX4_SUPER_MAGIC;
	s->s_flags |= MS_RDONLY;	/* Yup, read-only yet */
	qnx4_sb(s)->sb_buf = bh;
	qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data;


 	/* check before allocating dentries, inodes, .. */
	errmsg = qnx4_checkroot(s);
	if (errmsg != NULL) {
 		if (!silent)
272
			printk(KERN_ERR "qnx4: %s\n", errmsg);
L
Linus Torvalds 已提交
273 274 275 276
		goto out;
	}

 	/* does root not have inode number QNX4_ROOT_INO ?? */
277 278
	root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
	if (IS_ERR(root)) {
279
		printk(KERN_ERR "qnx4: get inode failed\n");
280
		ret = PTR_ERR(root);
L
Linus Torvalds 已提交
281 282 283
 		goto out;
 	}

284
	ret = -ENOMEM;
L
Linus Torvalds 已提交
285 286 287 288 289 290
 	s->s_root = d_alloc_root(root);
 	if (s->s_root == NULL)
 		goto outi;

	brelse(bh);

291
	unlock_kernel();
L
Linus Torvalds 已提交
292 293 294 295 296 297 298 299 300
	return 0;

      outi:
	iput(root);
      out:
	brelse(bh);
      outnobh:
	kfree(qs);
	s->s_fs_info = NULL;
301
	unlock_kernel();
302
	return ret;
L
Linus Torvalds 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
}

static void qnx4_put_super(struct super_block *sb)
{
	struct qnx4_sb_info *qs = qnx4_sb(sb);
	kfree( qs->BitMap );
	kfree( qs );
	sb->s_fs_info = NULL;
	return;
}

static int qnx4_writepage(struct page *page, struct writeback_control *wbc)
{
	return block_write_full_page(page,qnx4_get_block, wbc);
}
N
Nick Piggin 已提交
318

L
Linus Torvalds 已提交
319 320 321 322
static int qnx4_readpage(struct file *file, struct page *page)
{
	return block_read_full_page(page,qnx4_get_block);
}
N
Nick Piggin 已提交
323 324 325 326

static int qnx4_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
L
Linus Torvalds 已提交
327
{
N
Nick Piggin 已提交
328
	struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host);
329 330
	int ret;

N
Nick Piggin 已提交
331
	*pagep = NULL;
332
	ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
N
Nick Piggin 已提交
333 334
				qnx4_get_block,
				&qnx4_inode->mmu_private);
335 336 337 338 339 340 341
	if (unlikely(ret)) {
		loff_t isize = mapping->host->i_size;
		if (pos + len > isize)
			vmtruncate(mapping->host, isize);
	}

	return ret;
L
Linus Torvalds 已提交
342 343 344 345 346
}
static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
{
	return generic_block_bmap(mapping,block,qnx4_get_block);
}
347
static const struct address_space_operations qnx4_aops = {
L
Linus Torvalds 已提交
348 349 350
	.readpage	= qnx4_readpage,
	.writepage	= qnx4_writepage,
	.sync_page	= block_sync_page,
N
Nick Piggin 已提交
351 352
	.write_begin	= qnx4_write_begin,
	.write_end	= generic_write_end,
L
Linus Torvalds 已提交
353 354 355
	.bmap		= qnx4_bmap
};

356
struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
L
Linus Torvalds 已提交
357 358 359
{
	struct buffer_head *bh;
	struct qnx4_inode_entry *raw_inode;
360 361 362
	int block;
	struct qnx4_inode_entry *qnx4_inode;
	struct inode *inode;
L
Linus Torvalds 已提交
363

364 365 366 367 368 369 370
	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

	qnx4_inode = qnx4_raw_inode(inode);
L
Linus Torvalds 已提交
371 372
	inode->i_mode = 0;

373
	QNX4DEBUG((KERN_INFO "reading inode : [%d]\n", ino));
L
Linus Torvalds 已提交
374
	if (!ino) {
375 376
		printk(KERN_ERR "qnx4: bad inode number on dev %s: %lu is "
				"out of range\n",
L
Linus Torvalds 已提交
377
		       sb->s_id, ino);
378 379
		iget_failed(inode);
		return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
380 381 382 383
	}
	block = ino / QNX4_INODES_PER_BLOCK;

	if (!(bh = sb_bread(sb, block))) {
384
		printk(KERN_ERR "qnx4: major problem: unable to read inode from dev "
L
Linus Torvalds 已提交
385
		       "%s\n", sb->s_id);
386 387
		iget_failed(inode);
		return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
	}
	raw_inode = ((struct qnx4_inode_entry *) bh->b_data) +
	    (ino % QNX4_INODES_PER_BLOCK);

	inode->i_mode    = le16_to_cpu(raw_inode->di_mode);
	inode->i_uid     = (uid_t)le16_to_cpu(raw_inode->di_uid);
	inode->i_gid     = (gid_t)le16_to_cpu(raw_inode->di_gid);
	inode->i_nlink   = le16_to_cpu(raw_inode->di_nlink);
	inode->i_size    = le32_to_cpu(raw_inode->di_size);
	inode->i_mtime.tv_sec   = le32_to_cpu(raw_inode->di_mtime);
	inode->i_mtime.tv_nsec = 0;
	inode->i_atime.tv_sec   = le32_to_cpu(raw_inode->di_atime);
	inode->i_atime.tv_nsec = 0;
	inode->i_ctime.tv_sec   = le32_to_cpu(raw_inode->di_ctime);
	inode->i_ctime.tv_nsec = 0;
	inode->i_blocks  = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);

	memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE);
	if (S_ISREG(inode->i_mode)) {
C
Christoph Hellwig 已提交
407
		inode->i_fop = &generic_ro_fops;
L
Linus Torvalds 已提交
408 409 410 411 412 413 414 415 416
		inode->i_mapping->a_ops = &qnx4_aops;
		qnx4_i(inode)->mmu_private = inode->i_size;
	} else if (S_ISDIR(inode->i_mode)) {
		inode->i_op = &qnx4_dir_inode_operations;
		inode->i_fop = &qnx4_dir_operations;
	} else if (S_ISLNK(inode->i_mode)) {
		inode->i_op = &page_symlink_inode_operations;
		inode->i_mapping->a_ops = &qnx4_aops;
		qnx4_i(inode)->mmu_private = inode->i_size;
417 418 419 420 421 422 423
	} else {
		printk(KERN_ERR "qnx4: bad inode %lu on dev %s\n",
			ino, sb->s_id);
		iget_failed(inode);
		brelse(bh);
		return ERR_PTR(-EIO);
	}
L
Linus Torvalds 已提交
424
	brelse(bh);
425 426
	unlock_new_inode(inode);
	return inode;
L
Linus Torvalds 已提交
427 428
}

429
static struct kmem_cache *qnx4_inode_cachep;
L
Linus Torvalds 已提交
430 431 432 433

static struct inode *qnx4_alloc_inode(struct super_block *sb)
{
	struct qnx4_inode_info *ei;
434
	ei = kmem_cache_alloc(qnx4_inode_cachep, GFP_KERNEL);
L
Linus Torvalds 已提交
435 436 437 438 439 440 441 442 443 444
	if (!ei)
		return NULL;
	return &ei->vfs_inode;
}

static void qnx4_destroy_inode(struct inode *inode)
{
	kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode));
}

445
static void init_once(void *foo)
L
Linus Torvalds 已提交
446 447 448
{
	struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo;

C
Christoph Lameter 已提交
449
	inode_init_once(&ei->vfs_inode);
L
Linus Torvalds 已提交
450 451 452 453 454 455
}

static int init_inodecache(void)
{
	qnx4_inode_cachep = kmem_cache_create("qnx4_inode_cache",
					     sizeof(struct qnx4_inode_info),
456 457
					     0, (SLAB_RECLAIM_ACCOUNT|
						SLAB_MEM_SPREAD),
458
					     init_once);
L
Linus Torvalds 已提交
459 460 461 462 463 464 465
	if (qnx4_inode_cachep == NULL)
		return -ENOMEM;
	return 0;
}

static void destroy_inodecache(void)
{
466
	kmem_cache_destroy(qnx4_inode_cachep);
L
Linus Torvalds 已提交
467 468
}

469 470
static int qnx4_get_sb(struct file_system_type *fs_type,
	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
L
Linus Torvalds 已提交
471
{
472 473
	return get_sb_bdev(fs_type, flags, dev_name, data, qnx4_fill_super,
			   mnt);
L
Linus Torvalds 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
}

static struct file_system_type qnx4_fs_type = {
	.owner		= THIS_MODULE,
	.name		= "qnx4",
	.get_sb		= qnx4_get_sb,
	.kill_sb	= kill_block_super,
	.fs_flags	= FS_REQUIRES_DEV,
};

static int __init init_qnx4_fs(void)
{
	int err;

	err = init_inodecache();
	if (err)
		return err;

	err = register_filesystem(&qnx4_fs_type);
	if (err) {
		destroy_inodecache();
		return err;
	}

498
	printk(KERN_INFO "QNX4 filesystem 0.2.3 registered.\n");
L
Linus Torvalds 已提交
499 500 501 502 503 504 505 506 507 508 509 510 511
	return 0;
}

static void __exit exit_qnx4_fs(void)
{
	unregister_filesystem(&qnx4_fs_type);
	destroy_inodecache();
}

module_init(init_qnx4_fs)
module_exit(exit_qnx4_fs)
MODULE_LICENSE("GPL");