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.