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.