ftp.nice.ch/pub/next/unix/disk/ufs-NeXT.0.3.s.tar.gz#/linux/fs/ufs/inode.c

This is inode.c in view mode; [Download] [Up]

/*
 *  linux/fs/ufs/inode.c
 *
 *  Copyright (C) 1994 Yossi Gottlieb (yogo@math.tau.ac.il)
 *
 *  Based on code and information:
 *	BSD code,  Copyright (c) 1982, 1986 Regents of the University of California.
 *		   All rights reserved.
 *	linux/fs/minix	Copyright (C) 1991, 1992, 1993  Linus Torvalds
 *
 *  Copyright (C) 1995  Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>
 *    1995-01-09	modularized
 *    1995-01-20	added endianness support
 *    1995-01-21	recognize NeXTstep diskettes
 */

#include <linux/fs.h>

#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/locks.h>

#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>

#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif

#include <linux/ufs_fs.h>
#include <linux/ufs_fs_sb.h>
#include "ufs.h"



void ufs_read_inode(struct inode *inode)
{
	struct buffer_head *bh;
	struct ufs_sb_info *sb = &inode->i_sb->u.ufs_sb;
	struct dinode *dinode;
	int dev = inode->i_dev;
	int ino = inode->i_ino;
	int block;

	if (!(bh = bread(dev, sb->fs_block_base + fsbtodb(sb, itod(sb, ino)) + (itoo(sb, ino)/NIPB), BLOCK_SIZE))) {
		printk("ufs: Unable to read inode from dev %d/%d\n", MAJOR(dev), MINOR(dev));
		return;
	}

	dinode = ((struct dinode *) bh->b_data) + itoo(sb, ino) % NIPB;
	inode->i_mode = dtohs(sb,dinode->di_mode);
	inode->i_uid = dtohs(sb,dinode->di_uid);
	inode->i_gid = dtohs(sb,dinode->di_gid);
	inode->i_nlink = dtohs(sb,dinode->di_nlink);
	inode->i_size = dtohq(sb,dinode->di_qsize);
	inode->i_atime = dtohl(sb,dinode->di_atime);
	inode->i_mtime = dtohl(sb,dinode->di_mtime);
	inode->i_ctime = dtohl(sb,dinode->di_ctime);
	inode->i_blocks = dtohl(sb,dinode->di_blocks);

	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
		inode->i_rdev = 0; /* XXX figure out where dev number is stored */
	else {
		for (block = 0; block<NDADDR; block++)
			inode->u.ufs_i.i_un.i_addr.i_udb[block] =
				dtohl(sb,dinode->di_un.di_addr.di_udb[block]);
		for (block = 0; block<NIADDR; block++)
			inode->u.ufs_i.i_un.i_addr.i_uib[block] =
				dtohl(sb,dinode->di_un.di_addr.di_uib[block]);
		for (block = 0; block<4; block++)
			inode->u.ufs_i.i_spare[block] =
				dtohl(sb,dinode->di_spare[block]);
	}
	brelse(bh);

	/* register file/inode operations table according to inode type */
	if (S_ISREG(inode->i_mode))
		inode->i_op = &ufs_file_inode_operations;
	else
	if (S_ISDIR(inode->i_mode))
		inode->i_op = &ufs_dir_inode_operations;
	else
	if (S_ISLNK(inode->i_mode))
		inode->i_op = &ufs_symlink_inode_operations;
	else
	if (S_ISFIFO(inode->i_mode))
		init_fifo(inode);
}

void ufs_put_super(struct super_block *sb)
{
	lock_super(sb);
	sb->s_dev = 0;
	brelse(sb->u.ufs_sb.s_sbh[0]);
	brelse(sb->u.ufs_sb.s_sbh[1]);
	unlock_super(sb);
	MOD_DEC_USE_COUNT;
}

void ufs_count_csum(struct super_block *sb, struct csum *sum)
{
	struct ufs_sb_info *fs = &sb->u.ufs_sb;
	struct buffer_head *bh;
	struct cg *cg;
	int n;

	for (n=0; n<fs->fs_ncg; n++)
		if (!(bh = bread(sb->s_dev, fs->fs_block_base + fsbtodb(fs, cgtod(fs, n)), BLOCK_SIZE)))
			printk("ufs: could not read cylinder group %d, dev %d/%d\n", n, MAJOR(sb->s_dev), MINOR(sb->s_dev));
		else {
			cg = (struct cg *)bh->b_data;
			if (!cg_chkmagic(fs,cg))
				printk("ufs: warning, bad magic number for cylinder group %d, dev %d/%d\n", n, MAJOR(sb->s_dev), MINOR(sb->s_dev));
			sum->cs_ndir += dtohl(fs,cg->cg_cs.cs_ndir);
			sum->cs_nbfree += dtohl(fs,cg->cg_cs.cs_nbfree);
			sum->cs_nifree += dtohl(fs,cg->cg_cs.cs_nifree);
			sum->cs_nffree += dtohl(fs,cg->cg_cs.cs_nffree);
			brelse(bh);
		}
}


void ufs_statfs(struct super_block *sb, struct statfs *buf)
{
	struct ufs_sb_info *fs = &sb->u.ufs_sb;
	struct csum cs;
	int tmp;

	memset(&cs, 0, sizeof(cs));
	ufs_count_csum(sb, &cs);

	put_fs_long(FS_MAGIC, &buf->f_type);
	put_fs_long(fs->fs_fsize, &buf->f_bsize);
	put_fs_long(fs->fs_dsize, &buf->f_blocks);
	tmp = cs.cs_nbfree * fs->fs_frag + cs.cs_nffree;
	put_fs_long(tmp, &buf->f_bfree);
	put_fs_long(tmp * (100-fs->fs_minfree) / 100, &buf->f_bavail);
	put_fs_long(fs->fs_ncg * fs->fs_ipg, &buf->f_files);
	put_fs_long(cs.cs_nifree, &buf->f_ffree);
	put_fs_long(MAXNAMLEN, &buf->f_namelen);
}



static struct super_operations ufs_super_block_operations = {
	ufs_read_inode,
	NULL,
	NULL,
	NULL,
	ufs_put_super,
	NULL,
	ufs_statfs, /* ufs_statfs, */
	NULL  /* remount fs */
};


/*
 * Reading whole ufs blocks is impossible, they're too big. Fragments however,
 * are good enough (512/1024 bytes).
 *
 *
 *    ufs_blknum()
 *
 *    translates a logical fragment number (for file) into absolute
 *    fragment number (based on BSD's ufs_bmap).
 */
daddr_t ufs_blknum(struct inode *inode, int bn)
{
	struct buffer_head *bh;
	int nb;	/* disk block */
	struct ufs_sb_info *sb = &inode->i_sb->u.ufs_sb;
	int i, j, sh, dev = inode->i_sb->s_dev;
	int fragofs = fragnum(sb, bn); /* where in block fragment is located */
	daddr_t *bap;

	bn = fragstoblks(sb, bn);
	if (bn < NDADDR) {
		nb = inode->u.ufs_i.i_un.i_addr.i_udb[bn];
		if (nb == 0)
			return -1;
		return nb + fragofs;
	}

	/*
	 * Determine the number of levels of indirection.
	 */
	sh = 1;
	bn -= NDADDR;
	for (j = NIADDR; j > 0; j--) {
		sh *= NINDIR(sb);
		if (bn < sh)
			break;
		bn -= sh;
	}
	if (j == 0)
		return -1;
	/*
	 * Fetch through the indirect blocks.
	 */
	nb = inode->u.ufs_i.i_un.i_addr.i_uib[NIADDR - j];
	if (nb == 0)
		return -1;
	for (; j <= NIADDR; j++) {
		sh /= NINDIR(sb);
		i = (bn / sh) % NINDIR(sb);

		if (!(bh = bread(dev, sb->fs_block_base + fsbtodb(sb, nb+(i/DNINDIR(sb))), BLOCK_SIZE))) {
			brelse(bh);
			return -1;
		}

		bap = (daddr_t *)bh->b_data;
		nb = dtohl(sb, bap[i % DNINDIR(sb)]);
		brelse(bh);

		if (nb == 0)
			return -1;
	}

	return nb + fragofs;
}

/*
 * ufs_bread(), ufs_getblk() -- does what the name implies, on specified
 * inode's fragment.
 */

struct buffer_head *ufs_bread(struct inode *inode, int bn)
{
	register int blk = ufs_blknum(inode, bn);
	return blk == -1 ? NULL : bread(inode->i_sb->s_dev, inode->i_sb->u.ufs_sb.fs_block_base + fsbtodb(&inode->i_sb->u.ufs_sb, blk) , BLOCK_SIZE);
}

struct buffer_head *ufs_getblk(struct inode *inode, int bn)
{
	register int blk = ufs_blknum(inode, bn);
	return blk == -1 ? NULL : getblk(inode->i_sb->s_dev, inode->i_sb->u.ufs_sb.fs_block_base + fsbtodb(&inode->i_sb->u.ufs_sb, blk) , BLOCK_SIZE);
}



struct super_block *ufs_read_super(struct super_block *s,void *data,
				     int silent)
{
	struct buffer_head *bh1 = NULL, *bh2 = NULL;
	struct ufs_super_block us;
	int dev = s->s_dev;
	struct ufs_sb_info * sb = &s->u.ufs_sb;
	static int offsets[] = { 0, 96, 160 }; /* try different superblock locations */
	int i;

	if (128 != sizeof (struct dinode))
		panic("ufs: bad i-node size");
	MOD_INC_USE_COUNT;
	lock_super(s);
	/* ufs superblock is bigger than 1024 bytes, therefore read in 2
	 * parts. most primitive and simple way...
	 */
	for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
		if (!(bh1 = bread(dev, offsets[i] + SBOFF/BLOCK_SIZE, BLOCK_SIZE)) ||
		    !(bh2 = bread(dev, offsets[i] + SBOFF/BLOCK_SIZE + 1, BLOCK_SIZE))) {
			s->s_dev = 0;
			unlock_super(s);
			if (bh1) brelse(bh1);
			printk("ufs: unable to read superblock\n");
			MOD_DEC_USE_COUNT;
			return NULL;
		}

		memcpy(&us, bh1->b_data, BLOCK_SIZE);
		memcpy(((char *)&us) + BLOCK_SIZE, bh2->b_data, sizeof(struct ufs_super_block)-BLOCK_SIZE);

		/* Verify superblock;
		 * No current support for some filesystem referred to the "old filesystem"
		 * in BSD sources.
		 */
		if (us.fs_magic == FS_MAGIC) {
			sb->fs_convert = 0;
			goto found;
		}
		else if (us.fs_magic == 0x54190100) {
			sb->fs_convert = 1;
			goto found;
		}
		brelse(bh1); brelse(bh2);
	}
	s->s_dev = 0;
	unlock_super(s);
	if (!silent)
		printk("VFS: Unable to find ufs filesystem on device %d/%d\n", MAJOR(dev), MINOR(dev));
	MOD_DEC_USE_COUNT;
	return NULL;

found:
	/* Some of the following information is not needed, I don't think
	 * the structure as whole is bigger than the other fs's ones, so
	 * no harm is done to the superblock info union.
	 */
	sb->fs_block_base = offsets[i];
	sb->fs_sblkno = dtohl(sb, us.fs_sblkno);
	sb->fs_cblkno = dtohl(sb, us.fs_cblkno);
	sb->fs_iblkno = dtohl(sb, us.fs_iblkno);
	sb->fs_dblkno = dtohl(sb, us.fs_dblkno);
	sb->fs_cgoffset = dtohl(sb, us.fs_cgoffset);
	sb->fs_cgmask = dtohl(sb, us.fs_cgmask);
	sb->fs_size = dtohl(sb, us.fs_size);
	sb->fs_dsize = dtohl(sb, us.fs_dsize);
	sb->fs_ncg = dtohl(sb, us.fs_ncg);
	sb->fs_bsize = dtohl(sb, us.fs_bsize);
	sb->fs_fsize = dtohl(sb, us.fs_fsize);
	sb->fs_frag = dtohl(sb, us.fs_frag);
	sb->fs_fsbtodb = dtohl(sb, us.fs_fsbtodb);
	sb->fs_cpg = dtohl(sb, us.fs_cpg);
	sb->fs_ipg = dtohl(sb, us.fs_ipg);
	sb->fs_fpg = dtohl(sb, us.fs_fpg);
	sb->fs_fragshift = dtohl(sb, us.fs_fragshift);
	sb->fs_nindir = dtohl(sb, us.fs_nindir);
	sb->fs_inopb = dtohl(sb, us.fs_inopb);
	sb->fs_nspf = dtohl(sb, us.fs_nspf);
	sb->fs_bshift = dtohl(sb, us.fs_bshift);
	sb->fs_fshift = dtohl(sb, us.fs_fshift);
	sb->fs_bmask = dtohl(sb, us.fs_bmask);
	sb->fs_fmask = dtohl(sb, us.fs_fmask);
	sb->fs_minfree = dtohl(sb, us.fs_minfree);
	sb->s_sbh[0] = bh1; sb->s_sbh[1] = bh2;
	sb->fs_cg_magic = htodl(sb, CG_MAGIC);

	if (!silent) {
		printk("VFS: Found a %sUFS (block size = %ld, %s endian) on device %d/%d\n", sb->fs_block_base>0 ? "NeXTstep " : "", s->s_blocksize, sb->fs_convert ? "other" : "native", MAJOR(dev), MINOR(dev));
		printk("ufs: block_base = %ld\n", sb->fs_block_base);
		printk("ufs: sblkno = %ld, cblkno = %ld, iblkno = %ld, dblkno = %ld\n", (long)sb->fs_sblkno, (long)sb->fs_cblkno, (long)sb->fs_iblkno, (long)sb->fs_dblkno);
		printk("ufs: cgoffset = %ld, cgmask = %ld, size = %ld, dsize = %ld, ncg = %ld\n", sb->fs_cgoffset, sb->fs_cgmask, sb->fs_size, sb->fs_dsize, sb->fs_ncg);
		printk("ufs: bsize = %ld, fsize = %ld, frag = %ld, fsbtodb = %ld\n", sb->fs_bsize, sb->fs_fsize, sb->fs_frag, sb->fs_fsbtodb);
		printk("ufs: cpg = %ld, ipg = %ld, fpg = %ld\n", sb->fs_cpg, sb->fs_ipg, sb->fs_fpg);
		printk("ufs: fragshift = %ld, nindir = %ld, inopb = %ld, nspf = %ld\n", sb->fs_fragshift, sb->fs_nindir, sb->fs_inopb, sb->fs_nspf);
		printk("ufs: bshift = %ld, fshift = %ld, bmask = %ld, fmask = %ld\n", sb->fs_bshift, sb->fs_fshift, sb->fs_bmask, sb->fs_fmask);
		printk("ufs: minfree = %ld\n", sb->fs_minfree);
	}

	/* consistency checks */
	if (!(
		/* theoretically there may be a ufs with a different fragment size,
		 * but currently this is what is supported.
		 */
			(sb->fs_bsize == 8192)
		&&	(sb->fs_fsize == 1024)

		&&	(sb->fs_bsize == sb->fs_fsize * sb->fs_frag)
		&&	(sb->fs_bsize == 1L << sb->fs_bshift)
		&&	(sb->fs_fsize == 1L << sb->fs_fshift)
		&&	(sb->fs_frag == 1L << sb->fs_fragshift)
		&&	(sb->fs_bmask == ~(sb->fs_bsize - 1))
		&&	(sb->fs_fmask == ~(sb->fs_fsize - 1))
		&&	(sb->fs_nindir == sb->fs_bsize / sizeof(daddr_t))
		&&	(sb->fs_inopb == sb->fs_bsize / sizeof(struct dinode))

		&&	(sb->fs_ncg > 0)
		&&	(sb->fs_ipg == (sb->fs_dblkno - sb->fs_iblkno) * sb->fs_fsize / sizeof(struct dinode))
	   ) ) {
		s->s_dev = 0;
		unlock_super(s);
		brelse(bh1); brelse(bh2);
		printk("ufs: inconsistent super-block data\n");
		MOD_DEC_USE_COUNT;
		return NULL;
	}

	/* fs_fsbtodb sometimes assumes 512 byte blocks, sometimes 1024 byte blocks.
	 * We need it w.r.t. BLOCK_SIZE.
	 */
	sb->fs_fsbtodb = sb->fs_fshift - BLOCK_SIZE_BITS; /* hopefully == 0 */

	s->s_blocksize = sb->fs_fsize; /* or should it be fs_bsize? what is this used for? */
	s->s_blocksize_bits = __builtin_ffs(s->s_blocksize)-1; /* log2(s->s_blocksize) */
	s->s_magic = dtohl(sb, us.fs_magic); /* = FS_MAGIC */
	s->s_flags |= MS_RDONLY;
	s->s_dirt = 0;
	s->s_rd_only = 1;
	unlock_super(s);

	/* set up enough so that it can read an inode */
	s->s_dev = dev;
	s->s_op = &ufs_super_block_operations;
	s->s_mounted = iget(s,ROOTINO);
	if (!s->s_mounted) {
		s->s_dev = 0;
		unlock_super(s);
		brelse(bh1); brelse(bh2);
		printk("ufs: get root inode failed\n");
		MOD_DEC_USE_COUNT;
		return NULL;
	}
	return s;
}

#ifdef MODULE

/* Every kernel module contains stuff like this. */

char kernel_version[] = UTS_RELEASE;

static struct file_system_type ufs_fs_type = {
	ufs_read_super, "ufs", 1, NULL
};

int init_module(void)
{
	register_filesystem(&ufs_fs_type);
	return 0;
}

void cleanup_module(void)
{
	unregister_filesystem(&ufs_fs_type);
}

#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.