OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k_old/trunk/rc203soc/sw/uClinux/fs/minix
    from Rev 1765 to Rev 1782
    Reverse comparison

Rev 1765 → Rev 1782

/dir.c
0,0 → 1,95
/*
* linux/fs/minix/dir.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* minix directory handling functions
*/
 
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
 
#include <asm/segment.h>
 
static int minix_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
{
return -EISDIR;
}
 
static int minix_readdir(struct inode *, struct file *, void *, filldir_t);
 
static struct file_operations minix_dir_operations = {
NULL, /* lseek - default */
minix_dir_read, /* read */
NULL, /* write - bad */
minix_readdir, /* readdir */
NULL, /* select - default */
NULL, /* ioctl - default */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
file_fsync /* default fsync */
};
 
/*
* directories can handle most operations...
*/
struct inode_operations minix_dir_inode_operations = {
&minix_dir_operations, /* default directory file-ops */
minix_create, /* create */
minix_lookup, /* lookup */
minix_link, /* link */
minix_unlink, /* unlink */
minix_symlink, /* symlink */
minix_mkdir, /* mkdir */
minix_rmdir, /* rmdir */
minix_mknod, /* mknod */
minix_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
minix_truncate, /* truncate */
NULL /* permission */
};
 
static int minix_readdir(struct inode * inode, struct file * filp,
void * dirent, filldir_t filldir)
{
unsigned int offset;
struct buffer_head * bh;
struct minix_dir_entry * de;
struct minix_sb_info * info;
 
if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
return -EBADF;
info = &inode->i_sb->u.minix_sb;
if (filp->f_pos & (info->s_dirsize - 1))
return -EBADF;
while (filp->f_pos < inode->i_size) {
offset = filp->f_pos & 1023;
bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0);
if (!bh) {
filp->f_pos += 1024-offset;
continue;
}
do {
de = (struct minix_dir_entry *) (offset + bh->b_data);
if (de->inode) {
int size = strnlen(de->name, info->s_namelen);
if (filldir(dirent, de->name, size, filp->f_pos, de->inode) < 0) {
brelse(bh);
return 0;
}
}
offset += info->s_dirsize;
filp->f_pos += info->s_dirsize;
} while (offset < 1024 && filp->f_pos < inode->i_size);
brelse(bh);
}
return 0;
}
/inode.c
0,0 → 1,967
/*
* linux/fs/minix/inode.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
* Minix V2 fs support.
*/
 
#include <linux/module.h>
 
#include <linux/sched.h>
#include <linux/minix_fs.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>
 
void minix_put_inode(struct inode *inode)
{
if (inode->i_nlink)
return;
inode->i_size = 0;
minix_truncate(inode);
minix_free_inode(inode);
}
 
static void minix_commit_super (struct super_block * sb,
struct minix_super_block * ms)
{
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
sb->s_dirt = 0;
}
 
void minix_write_super (struct super_block * sb)
{
struct minix_super_block * ms;
 
if (!(sb->s_flags & MS_RDONLY)) {
ms = sb->u.minix_sb.s_ms;
 
if (ms->s_state & MINIX_VALID_FS)
ms->s_state &= ~MINIX_VALID_FS;
minix_commit_super (sb, ms);
}
sb->s_dirt = 0;
}
 
 
void minix_put_super(struct super_block *sb)
{
int i;
 
lock_super(sb);
if (!(sb->s_flags & MS_RDONLY)) {
sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
}
sb->s_dev = 0;
for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++)
brelse(sb->u.minix_sb.s_imap[i]);
for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
brelse(sb->u.minix_sb.s_zmap[i]);
brelse (sb->u.minix_sb.s_sbh);
unlock_super(sb);
MOD_DEC_USE_COUNT;
return;
}
 
static struct super_operations minix_sops = {
minix_read_inode,
NULL,
minix_write_inode,
minix_put_inode,
minix_put_super,
minix_write_super,
minix_statfs,
minix_remount
};
 
int minix_remount (struct super_block * sb, int * flags, char * data)
{
struct minix_super_block * ms;
 
ms = sb->u.minix_sb.s_ms;
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0;
if (*flags & MS_RDONLY) {
if (ms->s_state & MINIX_VALID_FS ||
!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS))
return 0;
/* Mounting a rw partition read-only. */
ms->s_state = sb->u.minix_sb.s_mount_state;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
sb->s_dirt = 1;
minix_commit_super (sb, ms);
}
else {
/* Mount a partition which is read-only, read-write. */
sb->u.minix_sb.s_mount_state = ms->s_state;
ms->s_state &= ~MINIX_VALID_FS;
mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
sb->s_dirt = 1;
 
if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS))
printk ("MINIX-fs warning: remounting unchecked fs, "
"running fsck is recommended.\n");
else if ((sb->u.minix_sb.s_mount_state & MINIX_ERROR_FS))
printk ("MINIX-fs warning: remounting fs with errors, "
"running fsck is recommended.\n");
}
return 0;
}
 
/*
* Check the root directory of the filesystem to make sure
* it really _is_ a minix filesystem, and to check the size
* of the directory entry.
*/
static const char * minix_checkroot(struct super_block *s)
{
struct inode * dir;
struct buffer_head *bh;
struct minix_dir_entry *de;
const char * errmsg;
int dirsize;
 
dir = s->s_mounted;
if (!S_ISDIR(dir->i_mode))
return "root directory is not a directory";
 
bh = minix_bread(dir, 0, 0);
if (!bh)
return "unable to read root directory";
 
de = (struct minix_dir_entry *) bh->b_data;
errmsg = "bad root directory '.' entry";
dirsize = BLOCK_SIZE;
if (de->inode == MINIX_ROOT_INO && strcmp(de->name, ".") == 0) {
errmsg = "bad root directory '..' entry";
dirsize = 8;
}
 
while ((dirsize <<= 1) < BLOCK_SIZE) {
de = (struct minix_dir_entry *) (bh->b_data + dirsize);
if (de->inode != MINIX_ROOT_INO)
continue;
if (strcmp(de->name, ".."))
continue;
s->u.minix_sb.s_dirsize = dirsize;
s->u.minix_sb.s_namelen = dirsize - 2;
errmsg = NULL;
break;
}
brelse(bh);
return errmsg;
}
 
struct super_block *minix_read_super(struct super_block *s,void *data,
int silent)
{
struct buffer_head *bh;
struct minix_super_block *ms;
int i, block;
kdev_t dev = s->s_dev;
const char * errmsg;
 
if (32 != sizeof (struct minix_inode))
panic("bad V1 i-node size");
if (64 != sizeof(struct minix2_inode))
panic("bad V2 i-node size");
MOD_INC_USE_COUNT;
lock_super(s);
set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev = 0;
unlock_super(s);
printk("MINIX-fs: unable to read superblock\n");
MOD_DEC_USE_COUNT;
return NULL;
}
ms = (struct minix_super_block *) bh->b_data;
s->u.minix_sb.s_ms = ms;
s->u.minix_sb.s_sbh = bh;
s->u.minix_sb.s_mount_state = ms->s_state;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
s->u.minix_sb.s_ninodes = ms->s_ninodes;
s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks;
s->u.minix_sb.s_zmap_blocks = ms->s_zmap_blocks;
s->u.minix_sb.s_firstdatazone = ms->s_firstdatazone;
s->u.minix_sb.s_log_zone_size = ms->s_log_zone_size;
s->u.minix_sb.s_max_size = ms->s_max_size;
s->s_magic = ms->s_magic;
if (s->s_magic == MINIX_SUPER_MAGIC) {
s->u.minix_sb.s_version = MINIX_V1;
s->u.minix_sb.s_nzones = ms->s_nzones;
s->u.minix_sb.s_dirsize = 16;
s->u.minix_sb.s_namelen = 14;
} else if (s->s_magic == MINIX_SUPER_MAGIC2) {
s->u.minix_sb.s_version = MINIX_V1;
s->u.minix_sb.s_nzones = ms->s_nzones;
s->u.minix_sb.s_dirsize = 32;
s->u.minix_sb.s_namelen = 30;
} else if (s->s_magic == MINIX2_SUPER_MAGIC) {
s->u.minix_sb.s_version = MINIX_V2;
s->u.minix_sb.s_nzones = ms->s_zones;
s->u.minix_sb.s_dirsize = 16;
s->u.minix_sb.s_namelen = 14;
} else if (s->s_magic == MINIX2_SUPER_MAGIC2) {
s->u.minix_sb.s_version = MINIX_V2;
s->u.minix_sb.s_nzones = ms->s_zones;
s->u.minix_sb.s_dirsize = 32;
s->u.minix_sb.s_namelen = 30;
} else {
s->s_dev = 0;
unlock_super(s);
brelse(bh);
if (!silent)
printk("VFS: Can't find a minix or minix V2 filesystem on dev "
"%s.\n", kdevname(dev));
MOD_DEC_USE_COUNT;
return NULL;
}
for (i=0;i < MINIX_I_MAP_SLOTS;i++)
s->u.minix_sb.s_imap[i] = NULL;
for (i=0;i < MINIX_Z_MAP_SLOTS;i++)
s->u.minix_sb.s_zmap[i] = NULL;
if (s->u.minix_sb.s_zmap_blocks > MINIX_Z_MAP_SLOTS) {
s->s_dev = 0;
unlock_super (s);
brelse (bh);
if (!silent)
printk ("MINIX-fs: filesystem too big\n");
MOD_DEC_USE_COUNT;
return NULL;
}
block=2;
for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++)
if ((s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE)) != NULL)
block++;
else
break;
for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++)
if ((s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE)) != NULL)
block++;
else
break;
if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) {
for(i=0;i<MINIX_I_MAP_SLOTS;i++)
brelse(s->u.minix_sb.s_imap[i]);
for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(s->u.minix_sb.s_zmap[i]);
s->s_dev = 0;
unlock_super(s);
brelse(bh);
printk("MINIX-fs: bad superblock or unable to read bitmaps\n");
MOD_DEC_USE_COUNT;
return NULL;
}
set_bit(0,s->u.minix_sb.s_imap[0]->b_data);
set_bit(0,s->u.minix_sb.s_zmap[0]->b_data);
unlock_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &minix_sops;
s->s_mounted = iget(s,MINIX_ROOT_INO);
if (!s->s_mounted) {
s->s_dev = 0;
brelse(bh);
if (!silent)
printk("MINIX-fs: get root inode failed\n");
MOD_DEC_USE_COUNT;
return NULL;
}
 
errmsg = minix_checkroot(s);
if (errmsg) {
if (!silent)
printk("MINIX-fs: %s\n", errmsg);
iput (s->s_mounted);
s->s_dev = 0;
brelse (bh);
MOD_DEC_USE_COUNT;
return NULL;
}
 
if (!(s->s_flags & MS_RDONLY)) {
ms->s_state &= ~MINIX_VALID_FS;
mark_buffer_dirty(bh, 1);
s->s_dirt = 1;
}
if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS))
printk ("MINIX-fs: mounting unchecked file system, "
"running fsck is recommended.\n");
else if (s->u.minix_sb.s_mount_state & MINIX_ERROR_FS)
printk ("MINIX-fs: mounting file system with errors, "
"running fsck is recommended.\n");
return s;
}
 
void minix_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
 
tmp.f_type = sb->s_magic;
tmp.f_bsize = sb->s_blocksize;
tmp.f_blocks = (sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone) << sb->u.minix_sb.s_log_zone_size;
tmp.f_bfree = minix_count_free_blocks(sb);
tmp.f_bavail = tmp.f_bfree;
tmp.f_files = sb->u.minix_sb.s_ninodes;
tmp.f_ffree = minix_count_free_inodes(sb);
tmp.f_namelen = sb->u.minix_sb.s_namelen;
memcpy_tofs(buf, &tmp, bufsiz);
}
 
/*
* The minix V1 fs bmap functions.
*/
#define V1_inode_bmap(inode,nr) (((unsigned short *)(inode)->u.minix_i.u.i1_data)[(nr)])
 
static int V1_block_bmap(struct buffer_head * bh, int nr)
{
int tmp;
 
if (!bh)
return 0;
tmp = ((unsigned short *) bh->b_data)[nr];
brelse(bh);
return tmp;
}
 
static int V1_minix_bmap(struct inode * inode,int block)
{
int i;
 
if (block<0) {
printk("minix_bmap: block<0");
return 0;
}
if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
printk("minix_bmap: block>big");
return 0;
}
if (block < 7)
return V1_inode_bmap(inode,block);
block -= 7;
if (block < 512) {
i = V1_inode_bmap(inode,7);
if (!i)
return 0;
return V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
}
block -= 512;
i = V1_inode_bmap(inode,8);
if (!i)
return 0;
i = V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9);
if (!i)
return 0;
return V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 511);
}
 
/*
* The minix V2 fs bmap functions.
*/
#define V2_inode_bmap(inode,nr) (((unsigned long *)(inode)->u.minix_i.u.i2_data)[(nr)])
static int V2_block_bmap(struct buffer_head * bh, int nr)
{
int tmp;
 
if (!bh)
return 0;
tmp = ((unsigned long *) bh->b_data)[nr];
brelse(bh);
return tmp;
}
 
static int V2_minix_bmap(struct inode * inode,int block)
{
int i;
 
if (block<0) {
printk("minix_bmap: block<0");
return 0;
}
if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
printk("minix_bmap: block>big");
return 0;
}
if (block < 7)
return V2_inode_bmap(inode,block);
block -= 7;
if (block < 256) {
i = V2_inode_bmap(inode,7);
if (!i)
return 0;
return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
}
block -= 256;
if (block < 256*256) {
i = V2_inode_bmap(inode,8);
if (!i)
return 0;
i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block >> 8);
if (!i)
return 0;
return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255);
}
block -= 256*256;
i = V2_inode_bmap(inode,9);
if (!i)
return 0;
i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block >> 16);
if (!i)
return 0;
i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),(block >> 8) & 255);
if (!i)
return 0;
return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255);
}
 
/*
* The global minix fs bmap function.
*/
int minix_bmap(struct inode * inode,int block)
{
if (INODE_VERSION(inode) == MINIX_V1)
return V1_minix_bmap(inode, block);
else
return V2_minix_bmap(inode, block);
}
 
/*
* The minix V1 fs getblk functions.
*/
static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr,
int create)
{
int tmp;
unsigned short *p;
struct buffer_head * result;
 
p = inode->u.minix_i.u.i1_data + nr;
repeat:
tmp = *p;
if (tmp) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp == *p)
return result;
brelse(result);
goto repeat;
}
if (!create)
return NULL;
tmp = minix_new_block(inode->i_sb);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
return result;
}
 
static struct buffer_head * V1_block_getblk(struct inode * inode,
struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned short *p;
struct buffer_head * result;
 
if (!bh)
return NULL;
if (!buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
brelse(bh);
return NULL;
}
}
p = nr + (unsigned short *) bh->b_data;
repeat:
tmp = *p;
if (tmp) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (tmp == *p) {
brelse(bh);
return result;
}
brelse(result);
goto repeat;
}
if (!create) {
brelse(bh);
return NULL;
}
tmp = minix_new_block(inode->i_sb);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
*p = tmp;
mark_buffer_dirty(bh, 1);
brelse(bh);
return result;
}
 
static struct buffer_head * V1_minix_getblk(struct inode * inode, int block,
int create)
{
struct buffer_head * bh;
 
if (block<0) {
printk("minix_getblk: block<0");
return NULL;
}
if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) {
printk("minix_getblk: block>big");
return NULL;
}
if (block < 7)
return V1_inode_getblk(inode,block,create);
block -= 7;
if (block < 512) {
bh = V1_inode_getblk(inode,7,create);
return V1_block_getblk(inode, bh, block, create);
}
block -= 512;
bh = V1_inode_getblk(inode,8,create);
bh = V1_block_getblk(inode, bh, (block>>9) & 511, create);
return V1_block_getblk(inode, bh, block & 511, create);
}
 
/*
* The minix V2 fs getblk functions.
*/
static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr,
int create)
{
int tmp;
unsigned long *p;
struct buffer_head * result;
 
p = (unsigned long *) inode->u.minix_i.u.i2_data + nr;
repeat:
tmp = *p;
if (tmp) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp == *p)
return result;
brelse(result);
goto repeat;
}
if (!create)
return NULL;
tmp = minix_new_block(inode->i_sb);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
*p = tmp;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
return result;
}
 
static struct buffer_head * V2_block_getblk(struct inode * inode,
struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned long *p;
struct buffer_head * result;
 
if (!bh)
return NULL;
if (!buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
brelse(bh);
return NULL;
}
}
p = nr + (unsigned long *) bh->b_data;
repeat:
tmp = *p;
if (tmp) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (tmp == *p) {
brelse(bh);
return result;
}
brelse(result);
goto repeat;
}
if (!create) {
brelse(bh);
return NULL;
}
tmp = minix_new_block(inode->i_sb);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
*p = tmp;
mark_buffer_dirty(bh, 1);
brelse(bh);
return result;
}
 
static struct buffer_head * V2_minix_getblk(struct inode * inode, int block,
int create)
{
struct buffer_head * bh;
 
if (block<0) {
printk("minix_getblk: block<0");
return NULL;
}
if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) {
printk("minix_getblk: block>big");
return NULL;
}
if (block < 7)
return V2_inode_getblk(inode,block,create);
block -= 7;
if (block < 256) {
bh = V2_inode_getblk(inode,7,create);
return V2_block_getblk(inode, bh, block, create);
}
block -= 256;
if (block < 256*256) {
bh = V2_inode_getblk(inode,8,create);
bh = V2_block_getblk(inode, bh, (block>>8) & 255, create);
return V2_block_getblk(inode, bh, block & 255, create);
}
block -= 256*256;
bh = V2_inode_getblk(inode,9,create);
bh = V2_block_getblk(inode, bh, (block >> 16) & 255, create);
bh = V2_block_getblk(inode, bh, (block >> 8) & 255, create);
return V2_block_getblk(inode, bh, block & 255, create);
}
 
/*
* the global minix fs getblk function.
*/
struct buffer_head * minix_getblk(struct inode * inode, int block, int create)
{
if (INODE_VERSION(inode) == MINIX_V1)
return V1_minix_getblk(inode,block,create);
else
return V2_minix_getblk(inode,block,create);
}
 
struct buffer_head * minix_bread(struct inode * inode, int block, int create)
{
struct buffer_head * bh;
 
bh = minix_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;
}
 
/*
* The minix V1 function to read an inode.
*/
static void V1_minix_read_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
int block, ino;
 
ino = inode->i_ino;
inode->i_op = NULL;
inode->i_mode = 0;
if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
return;
}
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks +
inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE))) {
printk("Major problem: unable to read inode from dev "
"%s\n", kdevname(inode->i_dev));
return;
}
raw_inode = ((struct minix_inode *) bh->b_data) +
(ino-1)%MINIX_INODES_PER_BLOCK;
inode->i_mode = raw_inode->i_mode;
inode->i_uid = raw_inode->i_uid;
inode->i_gid = raw_inode->i_gid;
inode->i_nlink = raw_inode->i_nlinks;
inode->i_size = raw_inode->i_size;
inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time;
inode->i_blocks = inode->i_blksize = 0;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
inode->i_rdev = to_kdev_t(raw_inode->i_zone[0]);
else for (block = 0; block < 9; block++)
inode->u.minix_i.u.i1_data[block] = raw_inode->i_zone[block];
brelse(bh);
if (S_ISREG(inode->i_mode))
inode->i_op = &minix_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &minix_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &minix_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode))
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
 
/*
* The minix V2 function to read an inode.
*/
static void V2_minix_read_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix2_inode * raw_inode;
int block, ino;
 
ino = inode->i_ino;
inode->i_op = NULL;
inode->i_mode = 0;
if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
return;
}
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks +
inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX2_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE))) {
printk("Major problem: unable to read inode from dev "
"%s\n", kdevname(inode->i_dev));
return;
}
raw_inode = ((struct minix2_inode *) bh->b_data) +
(ino-1)%MINIX2_INODES_PER_BLOCK;
inode->i_mode = raw_inode->i_mode;
inode->i_uid = raw_inode->i_uid;
inode->i_gid = raw_inode->i_gid;
inode->i_nlink = raw_inode->i_nlinks;
inode->i_size = raw_inode->i_size;
inode->i_mtime = raw_inode->i_mtime;
inode->i_atime = raw_inode->i_atime;
inode->i_ctime = raw_inode->i_ctime;
inode->i_blocks = inode->i_blksize = 0;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
inode->i_rdev = to_kdev_t(raw_inode->i_zone[0]);
else for (block = 0; block < 10; block++)
inode->u.minix_i.u.i2_data[block] = raw_inode->i_zone[block];
brelse(bh);
if (S_ISREG(inode->i_mode))
inode->i_op = &minix_file_inode_operations;
else if (S_ISDIR(inode->i_mode))
inode->i_op = &minix_dir_inode_operations;
else if (S_ISLNK(inode->i_mode))
inode->i_op = &minix_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode))
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
}
 
/*
* The global function to read an inode.
*/
void minix_read_inode(struct inode * inode)
{
if (INODE_VERSION(inode) == MINIX_V1)
V1_minix_read_inode(inode);
else
V2_minix_read_inode(inode);
}
 
/*
* The minix V1 function to synchronize an inode.
*/
static struct buffer_head * V1_minix_update_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix_inode * raw_inode;
int ino, block;
 
ino = inode->i_ino;
if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
inode->i_dirt = 0;
return 0;
}
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) {
printk("unable to read i-node block\n");
inode->i_dirt = 0;
return 0;
}
raw_inode = ((struct minix_inode *)bh->b_data) +
(ino-1)%MINIX_INODES_PER_BLOCK;
raw_inode->i_mode = inode->i_mode;
raw_inode->i_uid = inode->i_uid;
raw_inode->i_gid = inode->i_gid;
raw_inode->i_nlinks = inode->i_nlink;
raw_inode->i_size = inode->i_size;
raw_inode->i_time = inode->i_mtime;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
else for (block = 0; block < 9; block++)
raw_inode->i_zone[block] = inode->u.minix_i.u.i1_data[block];
inode->i_dirt=0;
mark_buffer_dirty(bh, 1);
return bh;
}
 
/*
* The minix V2 function to synchronize an inode.
*/
static struct buffer_head * V2_minix_update_inode(struct inode * inode)
{
struct buffer_head * bh;
struct minix2_inode * raw_inode;
int ino, block;
 
ino = inode->i_ino;
if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s"
": %d is out of range\n",
kdevname(inode->i_dev), ino);
inode->i_dirt = 0;
return 0;
}
block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino-1)/MINIX2_INODES_PER_BLOCK;
if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) {
printk("unable to read i-node block\n");
inode->i_dirt = 0;
return 0;
}
raw_inode = ((struct minix2_inode *)bh->b_data) +
(ino-1)%MINIX2_INODES_PER_BLOCK;
raw_inode->i_mode = inode->i_mode;
raw_inode->i_uid = inode->i_uid;
raw_inode->i_gid = inode->i_gid;
raw_inode->i_nlinks = inode->i_nlink;
raw_inode->i_size = inode->i_size;
raw_inode->i_mtime = inode->i_mtime;
raw_inode->i_atime = inode->i_atime;
raw_inode->i_ctime = inode->i_ctime;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = kdev_t_to_nr(inode->i_rdev);
else for (block = 0; block < 10; block++)
raw_inode->i_zone[block] = inode->u.minix_i.u.i2_data[block];
inode->i_dirt=0;
mark_buffer_dirty(bh, 1);
return bh;
}
 
struct buffer_head *minix_update_inode(struct inode *inode)
{
if (INODE_VERSION(inode) == MINIX_V1)
return V1_minix_update_inode(inode);
else
return V2_minix_update_inode(inode);
}
 
void minix_write_inode(struct inode * inode)
{
struct buffer_head *bh;
 
bh = minix_update_inode(inode);
brelse(bh);
}
 
int minix_sync_inode(struct inode * inode)
{
int err = 0;
struct buffer_head *bh;
 
bh = minix_update_inode(inode);
if (bh && buffer_dirty(bh))
{
ll_rw_block(WRITE, 1, &bh);
wait_on_buffer(bh);
if (buffer_req(bh) && !buffer_uptodate(bh))
{
printk ("IO error syncing minix inode ["
"%s:%08lx]\n",
kdevname(inode->i_dev), inode->i_ino);
err = -1;
}
}
else if (!bh)
err = -1;
brelse (bh);
return err;
}
 
static struct file_system_type minix_fs_type = {
minix_read_super, "minix", 1, NULL
};
 
int init_minix_fs(void)
{
return register_filesystem(&minix_fs_type);
}
 
#ifdef MODULE
int init_module(void)
{
int status;
 
if ((status = init_minix_fs()) == 0)
register_symtab(0);
return status;
}
 
void cleanup_module(void)
{
unregister_filesystem(&minix_fs_type);
}
 
#endif
/file.c
0,0 → 1,125
/*
* linux/fs/minix/file.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* minix regular file handling primitives
*/
 
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
 
#include <asm/segment.h>
#include <asm/system.h>
 
#define NBUF 32
 
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
 
#include <linux/fs.h>
#include <linux/minix_fs.h>
 
static int minix_file_write(struct inode *, struct file *, const char *, int);
 
/*
* We have mostly NULL's here: the current defaults are ok for
* the minix filesystem.
*/
static struct file_operations minix_file_operations = {
NULL, /* lseek - default */
generic_file_read, /* read */
minix_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
minix_sync_file /* fsync */
};
 
struct inode_operations minix_file_inode_operations = {
&minix_file_operations, /* default file operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
generic_readpage, /* readpage */
NULL, /* writepage */
minix_bmap, /* bmap */
minix_truncate, /* truncate */
NULL /* permission */
};
 
static int minix_file_write(struct inode * inode, struct file * filp, const char * buf, int count)
{
off_t pos;
int written,c;
struct buffer_head * bh;
char * p;
 
if (!inode) {
printk("minix_file_write: inode = NULL\n");
return -EINVAL;
}
if (!S_ISREG(inode->i_mode)) {
printk("minix_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = filp->f_pos;
written = 0;
while (written < count) {
bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
if (!bh) {
if (!written)
written = -ENOSPC;
break;
}
c = BLOCK_SIZE - (pos % BLOCK_SIZE);
if (c > count-written)
c = count-written;
if (c != BLOCK_SIZE && !buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
brelse(bh);
if (!written)
written = -EIO;
break;
}
}
p = (pos % BLOCK_SIZE) + bh->b_data;
memcpy_fromfs(p,buf,c);
update_vm_cache(inode, pos, p, c);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 0);
brelse(bh);
pos += c;
written += c;
buf += c;
}
if (pos > inode->i_size)
inode->i_size = pos;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
filp->f_pos = pos;
inode->i_dirt = 1;
return written;
}
/fsync.c
0,0 → 1,339
/*
* linux/fs/minix/fsync.c
*
* Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk)
* from
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
* Minix V2 fs support
*
* minix fsync primitive
*/
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/locks.h>
 
#include <linux/fs.h>
#include <linux/minix_fs.h>
 
#include <asm/segment.h>
#include <asm/system.h>
 
#define blocksize BLOCK_SIZE
 
/*
* The functions for minix V1 fs file synchronization.
*/
static int V1_sync_block (struct inode * inode, unsigned short * block, int wait)
{
struct buffer_head * bh;
unsigned short tmp;
if (!*block)
return 0;
tmp = *block;
bh = get_hash_table(inode->i_dev, *block, blocksize);
if (!bh)
return 0;
if (*block != tmp) {
brelse (bh);
return 1;
}
if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
brelse(bh);
return -1;
}
if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh))
{
brelse(bh);
return 0;
}
ll_rw_block(WRITE, 1, &bh);
bh->b_count--;
return 0;
}
 
static int V1_sync_iblock (struct inode * inode, unsigned short * iblock,
struct buffer_head **bh, int wait)
{
int rc;
unsigned short tmp;
*bh = NULL;
tmp = *iblock;
if (!tmp)
return 0;
rc = V1_sync_block (inode, iblock, wait);
if (rc)
return rc;
*bh = bread(inode->i_dev, tmp, blocksize);
if (tmp != *iblock) {
brelse(*bh);
*bh = NULL;
return 1;
}
if (!*bh)
return -1;
return 0;
}
 
static int V1_sync_direct(struct inode *inode, int wait)
{
int i;
int rc, err = 0;
 
for (i = 0; i < 7; i++) {
rc = V1_sync_block (inode,
(unsigned short *) inode->u.minix_i.u.i1_data + i, wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
return err;
}
 
static int V1_sync_indirect(struct inode *inode, unsigned short *iblock, int wait)
{
int i;
struct buffer_head * ind_bh;
int rc, err = 0;
 
rc = V1_sync_iblock (inode, iblock, &ind_bh, wait);
if (rc || !ind_bh)
return rc;
 
for (i = 0; i < 512; i++) {
rc = V1_sync_block (inode,
((unsigned short *) ind_bh->b_data) + i,
wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
brelse(ind_bh);
return err;
}
 
static int V1_sync_dindirect(struct inode *inode, unsigned short *diblock,
int wait)
{
int i;
struct buffer_head * dind_bh;
int rc, err = 0;
 
rc = V1_sync_iblock (inode, diblock, &dind_bh, wait);
if (rc || !dind_bh)
return rc;
 
for (i = 0; i < 512; i++) {
rc = V1_sync_indirect (inode,
((unsigned short *) dind_bh->b_data) + i,
wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
brelse(dind_bh);
return err;
}
 
int V1_minix_sync_file(struct inode * inode, struct file * file)
{
int wait, err = 0;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return -EINVAL;
 
for (wait=0; wait<=1; wait++)
{
err |= V1_sync_direct(inode, wait);
err |= V1_sync_indirect(inode, inode->u.minix_i.u.i1_data + 7, wait);
err |= V1_sync_dindirect(inode, inode->u.minix_i.u.i1_data + 8, wait);
}
err |= minix_sync_inode (inode);
return (err < 0) ? -EIO : 0;
}
 
/*
* The functions for minix V2 fs file synchronization.
*/
static int V2_sync_block (struct inode * inode, unsigned long * block, int wait)
{
struct buffer_head * bh;
unsigned long tmp;
if (!*block)
return 0;
tmp = *block;
bh = get_hash_table(inode->i_dev, *block, blocksize);
if (!bh)
return 0;
if (*block != tmp) {
brelse (bh);
return 1;
}
if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
brelse(bh);
return -1;
}
if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh))
{
brelse(bh);
return 0;
}
ll_rw_block(WRITE, 1, &bh);
bh->b_count--;
return 0;
}
 
static int V2_sync_iblock (struct inode * inode, unsigned long * iblock,
struct buffer_head **bh, int wait)
{
int rc;
unsigned long tmp;
*bh = NULL;
tmp = *iblock;
if (!tmp)
return 0;
rc = V2_sync_block (inode, iblock, wait);
if (rc)
return rc;
*bh = bread(inode->i_dev, tmp, blocksize);
if (tmp != *iblock) {
brelse(*bh);
*bh = NULL;
return 1;
}
if (!*bh)
return -1;
return 0;
}
 
static int V2_sync_direct(struct inode *inode, int wait)
{
int i;
int rc, err = 0;
 
for (i = 0; i < 7; i++) {
rc = V2_sync_block (inode,
(unsigned long *)inode->u.minix_i.u.i2_data + i, wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
return err;
}
 
static int V2_sync_indirect(struct inode *inode, unsigned long *iblock, int wait)
{
int i;
struct buffer_head * ind_bh;
int rc, err = 0;
 
rc = V2_sync_iblock (inode, iblock, &ind_bh, wait);
if (rc || !ind_bh)
return rc;
 
for (i = 0; i < 256; i++) {
rc = V2_sync_block (inode,
((unsigned long *) ind_bh->b_data) + i,
wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
brelse(ind_bh);
return err;
}
 
static int V2_sync_dindirect(struct inode *inode, unsigned long *diblock,
int wait)
{
int i;
struct buffer_head * dind_bh;
int rc, err = 0;
 
rc = V2_sync_iblock (inode, diblock, &dind_bh, wait);
if (rc || !dind_bh)
return rc;
 
for (i = 0; i < 256; i++) {
rc = V2_sync_indirect (inode,
((unsigned long *) dind_bh->b_data) + i,
wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
brelse(dind_bh);
return err;
}
 
static int V2_sync_tindirect(struct inode *inode, unsigned long *tiblock,
int wait)
{
int i;
struct buffer_head * tind_bh;
int rc, err = 0;
 
rc = V2_sync_iblock (inode, tiblock, &tind_bh, wait);
if (rc || !tind_bh)
return rc;
 
for (i = 0; i < 256; i++) {
rc = V2_sync_dindirect (inode,
((unsigned long *) tind_bh->b_data) + i,
wait);
if (rc > 0)
break;
if (rc)
err = rc;
}
brelse(tind_bh);
return err;
}
 
int V2_minix_sync_file(struct inode * inode, struct file * file)
{
int wait, err = 0;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return -EINVAL;
 
for (wait=0; wait<=1; wait++)
{
err |= V2_sync_direct(inode, wait);
err |= V2_sync_indirect(inode,
(unsigned long *) inode->u.minix_i.u.i2_data + 7, wait);
err |= V2_sync_dindirect(inode,
(unsigned long *) inode->u.minix_i.u.i2_data + 8, wait);
err |= V2_sync_tindirect(inode,
(unsigned long *) inode->u.minix_i.u.i2_data + 9, wait);
}
err |= minix_sync_inode (inode);
return (err < 0) ? -EIO : 0;
}
 
/*
* The function which is called for file synchronization.
*/
int minix_sync_file(struct inode * inode, struct file * file)
{
if (INODE_VERSION(inode) == MINIX_V1)
return V1_minix_sync_file(inode, file);
else
return V2_minix_sync_file(inode, file);
}
/truncate.c
0,0 → 1,417
/*
* linux/fs/truncate.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl)
* Minix V2 fs support.
*/
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
 
#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10)
#define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset)
#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9)
#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8)
#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8)
 
/*
* Truncate has the most races in the whole filesystem: coding it is
* a pain in the a**. Especially as I don't do any locking...
*
* The code may look a bit weird, but that's just because I've tried to
* handle things like file-size changes in a somewhat graceful manner.
* Anyway, truncating a file at the same time somebody else writes to it
* is likely to result in pretty weird behaviour...
*
* The new code handles normal truncates (size = 0) as well as the more
* general case (size = XXX). I hope.
*/
 
/*
* The functions for minix V1 fs truncation.
*/
static int V1_trunc_direct(struct inode * inode)
{
unsigned short * p;
struct buffer_head * bh;
int i, tmp;
int retry = 0;
 
repeat:
for (i = DIRECT_BLOCK ; i < 7 ; i++) {
p = i + inode->u.minix_i.u.i1_data;
if (!(tmp = *p))
continue;
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
if (i < DIRECT_BLOCK) {
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *p) {
retry = 1;
brelse(bh);
continue;
}
*p = 0;
inode->i_dirt = 1;
if (bh) {
mark_buffer_clean(bh);
brelse(bh);
}
minix_free_block(inode->i_sb,tmp);
}
return retry;
}
 
static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p)
{
struct buffer_head * bh;
int i, tmp;
struct buffer_head * ind_bh;
unsigned short * ind;
int retry = 0;
 
tmp = *p;
if (!tmp)
return 0;
ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp != *p) {
brelse(ind_bh);
return 1;
}
if (!ind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) {
if (i < 0)
i = 0;
if (i < INDIRECT_BLOCK(offset))
goto repeat;
ind = i+(unsigned short *) ind_bh->b_data;
tmp = *ind;
if (!tmp)
continue;
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
if (i < INDIRECT_BLOCK(offset)) {
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *ind) {
retry = 1;
brelse(bh);
continue;
}
*ind = 0;
mark_buffer_dirty(ind_bh, 1);
brelse(bh);
minix_free_block(inode->i_sb,tmp);
}
ind = (unsigned short *) ind_bh->b_data;
for (i = 0; i < 512; i++)
if (*(ind++))
break;
if (i >= 512)
if (ind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
minix_free_block(inode->i_sb,tmp);
}
brelse(ind_bh);
return retry;
}
 
static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p)
{
int i, tmp;
struct buffer_head * dind_bh;
unsigned short * dind;
int retry = 0;
 
if (!(tmp = *p))
return 0;
dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp != *p) {
brelse(dind_bh);
return 1;
}
if (!dind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) {
if (i < 0)
i = 0;
if (i < V1_DINDIRECT_BLOCK(offset))
goto repeat;
dind = i+(unsigned short *) dind_bh->b_data;
retry |= V1_trunc_indirect(inode,offset+(i<<9),dind);
mark_buffer_dirty(dind_bh, 1);
}
dind = (unsigned short *) dind_bh->b_data;
for (i = 0; i < 512; i++)
if (*(dind++))
break;
if (i >= 512)
if (dind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
inode->i_dirt = 1;
minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
return retry;
}
 
void V1_minix_truncate(struct inode * inode)
{
int retry;
 
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
while (1) {
retry = V1_trunc_direct(inode);
retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7);
retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8);
if (!retry)
break;
current->counter = 0;
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
 
/*
* The functions for minix V2 fs truncation.
*/
static int V2_trunc_direct(struct inode * inode)
{
unsigned long * p;
struct buffer_head * bh;
int i, tmp;
int retry = 0;
 
repeat:
for (i = DIRECT_BLOCK ; i < 7 ; i++) {
p = (unsigned long *) inode->u.minix_i.u.i2_data + i;
if (!(tmp = *p))
continue;
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
if (i < DIRECT_BLOCK) {
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *p) {
retry = 1;
brelse(bh);
continue;
}
*p = 0;
inode->i_dirt = 1;
if (bh) {
mark_buffer_clean(bh);
brelse(bh);
}
minix_free_block(inode->i_sb,tmp);
}
return retry;
}
 
static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p)
{
struct buffer_head * bh;
int i, tmp;
struct buffer_head * ind_bh;
unsigned long * ind;
int retry = 0;
 
tmp = *p;
if (!tmp)
return 0;
ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp != *p) {
brelse(ind_bh);
return 1;
}
if (!ind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) {
if (i < 0)
i = 0;
if (i < INDIRECT_BLOCK(offset))
goto repeat;
ind = i+(unsigned long *) ind_bh->b_data;
tmp = *ind;
if (!tmp)
continue;
bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE);
if (i < INDIRECT_BLOCK(offset)) {
brelse(bh);
goto repeat;
}
if ((bh && bh->b_count != 1) || tmp != *ind) {
retry = 1;
brelse(bh);
continue;
}
*ind = 0;
mark_buffer_dirty(ind_bh, 1);
brelse(bh);
minix_free_block(inode->i_sb,tmp);
}
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < 256; i++)
if (*(ind++))
break;
if (i >= 256)
if (ind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
minix_free_block(inode->i_sb,tmp);
}
brelse(ind_bh);
return retry;
}
 
static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p)
{
int i, tmp;
struct buffer_head * dind_bh;
unsigned long * dind;
int retry = 0;
 
if (!(tmp = *p))
return 0;
dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp != *p) {
brelse(dind_bh);
return 1;
}
if (!dind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
if (i < 0)
i = 0;
if (i < V2_DINDIRECT_BLOCK(offset))
goto repeat;
dind = i+(unsigned long *) dind_bh->b_data;
retry |= V2_trunc_indirect(inode,offset+(i<<8),dind);
mark_buffer_dirty(dind_bh, 1);
}
dind = (unsigned long *) dind_bh->b_data;
for (i = 0; i < 256; i++)
if (*(dind++))
break;
if (i >= 256)
if (dind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
inode->i_dirt = 1;
minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
return retry;
}
 
static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p)
{
int i, tmp;
struct buffer_head * tind_bh;
unsigned long * tind;
int retry = 0;
 
if (!(tmp = *p))
return 0;
tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE);
if (tmp != *p) {
brelse(tind_bh);
return 1;
}
if (!tind_bh) {
*p = 0;
return 0;
}
repeat:
for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) {
if (i < 0)
i = 0;
if (i < TINDIRECT_BLOCK(offset))
goto repeat;
tind = i+(unsigned long *) tind_bh->b_data;
retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind);
mark_buffer_dirty(tind_bh, 1);
}
tind = (unsigned long *) tind_bh->b_data;
for (i = 0; i < 256; i++)
if (*(tind++))
break;
if (i >= 256)
if (tind_bh->b_count != 1)
retry = 1;
else {
tmp = *p;
*p = 0;
inode->i_dirt = 1;
minix_free_block(inode->i_sb,tmp);
}
brelse(tind_bh);
return retry;
}
 
static void V2_minix_truncate(struct inode * inode)
{
int retry;
 
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return;
while (1) {
retry = V2_trunc_direct(inode);
retry |= V2_trunc_indirect(inode,7,
(unsigned long *) inode->u.minix_i.u.i2_data + 7);
retry |= V2_trunc_dindirect(inode, 7+256,
(unsigned long *) inode->u.minix_i.u.i2_data + 8);
retry |= V2_trunc_tindirect(inode, 7+256+256*256,
(unsigned long *) inode->u.minix_i.u.i2_data + 9);
if (!retry)
break;
current->counter = 0;
schedule();
}
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
}
 
/*
* The function that is called for file truncation.
*/
void minix_truncate(struct inode * inode)
{
if (INODE_VERSION(inode) == MINIX_V1)
V1_minix_truncate(inode);
else
V2_minix_truncate(inode);
}
/symlink.c
0,0 → 1,104
/*
* linux/fs/minix/symlink.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* minix symlink handling code
*/
 
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
 
#include <asm/segment.h>
 
static int minix_readlink(struct inode *, char *, int);
static int minix_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
/*
* symlinks can't do much...
*/
struct inode_operations minix_symlink_inode_operations = {
NULL, /* no file-operations */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* unlink */
NULL, /* symlink */
NULL, /* mkdir */
NULL, /* rmdir */
NULL, /* mknod */
NULL, /* rename */
minix_readlink, /* readlink */
minix_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
NULL /* permission */
};
 
static int minix_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
int error;
struct buffer_head * bh;
 
*res_inode = NULL;
if (!dir) {
dir = current->fs->root;
dir->i_count++;
}
if (!inode) {
iput(dir);
return -ENOENT;
}
if (!S_ISLNK(inode->i_mode)) {
iput(dir);
*res_inode = inode;
return 0;
}
if (current->link_count > 5) {
iput(inode);
iput(dir);
return -ELOOP;
}
if (!(bh = minix_bread(inode, 0, 0))) {
iput(inode);
iput(dir);
return -EIO;
}
iput(inode);
current->link_count++;
error = open_namei(bh->b_data,flag,mode,res_inode,dir);
current->link_count--;
brelse(bh);
return error;
}
 
static int minix_readlink(struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh;
int i;
char c;
 
if (!S_ISLNK(inode->i_mode)) {
iput(inode);
return -EINVAL;
}
if (buflen > 1023)
buflen = 1023;
bh = minix_bread(inode, 0, 0);
iput(inode);
if (!bh)
return 0;
i = 0;
while (i<buflen && (c = bh->b_data[i])) {
i++;
put_user(c,buffer++);
}
brelse(bh);
return i;
}
/namei.c
0,0 → 1,836
/*
* linux/fs/minix/namei.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
 
#include <asm/segment.h>
 
/*
* comment out this line if you want names > info->s_namelen chars to be
* truncated. Else they will be disallowed (ENAMETOOLONG).
*/
/* #define NO_TRUNCATE */
 
static inline int namecompare(int len, int maxlen,
const char * name, const char * buffer)
{
if (len > maxlen)
return 0;
if (len < maxlen && buffer[len])
return 0;
return !memcmp(name, buffer, len);
}
 
/*
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use minix_match. No big problem. Match also makes
* some sanity tests.
*
* NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure.
*/
static int minix_match(int len, const char * name,
struct buffer_head * bh, unsigned long * offset,
struct minix_sb_info * info)
{
struct minix_dir_entry * de;
 
de = (struct minix_dir_entry *) (bh->b_data + *offset);
*offset += info->s_dirsize;
if (!de->inode || len > info->s_namelen)
return 0;
/* "" means "." ---> so paths like "/usr/lib//libc.a" work */
if (!len && (de->name[0]=='.') && (de->name[1]=='\0'))
return 1;
return namecompare(len,info->s_namelen,name,de->name);
}
 
/*
* minix_find_entry()
*
* finds an entry in the specified directory with the wanted name. It
* returns the cache buffer in which the entry was found, and the entry
* itself (as a parameter - res_dir). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
static struct buffer_head * minix_find_entry(struct inode * dir,
const char * name, int namelen, struct minix_dir_entry ** res_dir)
{
unsigned long block, offset;
struct buffer_head * bh;
struct minix_sb_info * info;
 
*res_dir = NULL;
if (!dir || !dir->i_sb)
return NULL;
info = &dir->i_sb->u.minix_sb;
if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
return NULL;
#else
namelen = info->s_namelen;
#endif
}
bh = NULL;
block = offset = 0;
while (block*BLOCK_SIZE+offset < dir->i_size) {
if (!bh) {
bh = minix_bread(dir,block,0);
if (!bh) {
block++;
continue;
}
}
*res_dir = (struct minix_dir_entry *) (bh->b_data + offset);
if (minix_match(namelen,name,bh,&offset,info))
return bh;
if (offset < bh->b_size)
continue;
brelse(bh);
bh = NULL;
offset = 0;
block++;
}
brelse(bh);
*res_dir = NULL;
return NULL;
}
 
int minix_lookup(struct inode * dir,const char * name, int len,
struct inode ** result)
{
int ino;
struct minix_dir_entry * de;
struct buffer_head * bh;
 
*result = NULL;
if (!dir)
return -ENOENT;
if (!S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
}
if (!(bh = minix_find_entry(dir,name,len,&de))) {
iput(dir);
return -ENOENT;
}
ino = de->inode;
brelse(bh);
if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
iput(dir);
return 0;
}
 
/*
* minix_add_entry()
*
* adds a file entry to the specified directory, returning a possible
* error value if it fails.
*
* NOTE!! The inode part of 'de' is left at 0 - which means you
* may not sleep between calling this and putting something into
* the entry, as someone else might have used it while you slept.
*/
static int minix_add_entry(struct inode * dir,
const char * name, int namelen,
struct buffer_head ** res_buf,
struct minix_dir_entry ** res_dir)
{
int i;
unsigned long block, offset;
struct buffer_head * bh;
struct minix_dir_entry * de;
struct minix_sb_info * info;
 
*res_buf = NULL;
*res_dir = NULL;
if (!dir || !dir->i_sb)
return -ENOENT;
info = &dir->i_sb->u.minix_sb;
if (namelen > info->s_namelen) {
#ifdef NO_TRUNCATE
return -ENAMETOOLONG;
#else
namelen = info->s_namelen;
#endif
}
if (!namelen)
return -ENOENT;
bh = NULL;
block = offset = 0;
while (1) {
if (!bh) {
bh = minix_bread(dir,block,1);
if (!bh)
return -ENOSPC;
}
de = (struct minix_dir_entry *) (bh->b_data + offset);
offset += info->s_dirsize;
if (block*bh->b_size + offset > dir->i_size) {
de->inode = 0;
dir->i_size = block*bh->b_size + offset;
dir->i_dirt = 1;
}
if (de->inode) {
if (namecompare(namelen, info->s_namelen, name, de->name)) {
brelse(bh);
return -EEXIST;
}
} else {
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
dir->i_dirt = 1;
for (i = 0; i < info->s_namelen ; i++)
de->name[i] = (i < namelen) ? name[i] : 0;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
*res_dir = de;
break;
}
if (offset < bh->b_size)
continue;
brelse(bh);
bh = NULL;
offset = 0;
block++;
}
*res_buf = bh;
return 0;
}
 
int minix_create(struct inode * dir,const char * name, int len, int mode,
struct inode ** result)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
 
*result = NULL;
if (!dir)
return -ENOENT;
inode = minix_new_inode(dir);
if (!inode) {
iput(dir);
return -ENOSPC;
}
inode->i_op = &minix_file_inode_operations;
inode->i_mode = mode;
inode->i_dirt = 1;
error = minix_add_entry(dir,name,len, &bh ,&de);
if (error) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
*result = inode;
return 0;
}
 
int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev)
{
int error;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
 
if (!dir)
return -ENOENT;
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
iput(dir);
return -EEXIST;
}
inode = minix_new_inode(dir);
if (!inode) {
iput(dir);
return -ENOSPC;
}
inode->i_uid = current->fsuid;
inode->i_mode = mode;
inode->i_op = NULL;
if (S_ISREG(inode->i_mode))
inode->i_op = &minix_file_inode_operations;
else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &minix_dir_inode_operations;
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
}
else if (S_ISLNK(inode->i_mode))
inode->i_op = &minix_symlink_inode_operations;
else if (S_ISCHR(inode->i_mode))
inode->i_op = &chrdev_inode_operations;
else if (S_ISBLK(inode->i_mode))
inode->i_op = &blkdev_inode_operations;
else if (S_ISFIFO(inode->i_mode))
init_fifo(inode);
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = to_kdev_t(rdev);
inode->i_dirt = 1;
error = minix_add_entry(dir, name, len, &bh, &de);
if (error) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
iput(dir);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
return 0;
}
 
int minix_mkdir(struct inode * dir, const char * name, int len, int mode)
{
int error;
struct inode * inode;
struct buffer_head * bh, *dir_block;
struct minix_dir_entry * de;
struct minix_sb_info * info;
 
if (!dir || !dir->i_sb) {
iput(dir);
return -EINVAL;
}
info = &dir->i_sb->u.minix_sb;
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
iput(dir);
return -EEXIST;
}
if (dir->i_nlink >= MINIX_LINK_MAX) {
iput(dir);
return -EMLINK;
}
inode = minix_new_inode(dir);
if (!inode) {
iput(dir);
return -ENOSPC;
}
inode->i_op = &minix_dir_inode_operations;
inode->i_size = 2 * info->s_dirsize;
dir_block = minix_bread(inode,0,1);
if (!dir_block) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
de = (struct minix_dir_entry *) dir_block->b_data;
de->inode=inode->i_ino;
strcpy(de->name,".");
de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize);
de->inode = dir->i_ino;
strcpy(de->name,"..");
inode->i_nlink = 2;
mark_buffer_dirty(dir_block, 1);
brelse(dir_block);
inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
inode->i_dirt = 1;
error = minix_add_entry(dir, name, len, &bh, &de);
if (error) {
iput(dir);
inode->i_nlink=0;
iput(inode);
return error;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
dir->i_nlink++;
dir->i_dirt = 1;
iput(dir);
iput(inode);
brelse(bh);
return 0;
}
 
/*
* routine to check that the specified directory is empty (for rmdir)
*/
static int empty_dir(struct inode * inode)
{
unsigned int block, offset;
struct buffer_head * bh;
struct minix_dir_entry * de;
struct minix_sb_info * info;
 
if (!inode || !inode->i_sb)
return 1;
info = &inode->i_sb->u.minix_sb;
block = 0;
bh = NULL;
offset = 2*info->s_dirsize;
if (inode->i_size & (info->s_dirsize-1))
goto bad_dir;
if (inode->i_size < offset)
goto bad_dir;
bh = minix_bread(inode,0,0);
if (!bh)
goto bad_dir;
de = (struct minix_dir_entry *) bh->b_data;
if (!de->inode || strcmp(de->name,"."))
goto bad_dir;
de = (struct minix_dir_entry *) (bh->b_data + info->s_dirsize);
if (!de->inode || strcmp(de->name,".."))
goto bad_dir;
while (block*BLOCK_SIZE+offset < inode->i_size) {
if (!bh) {
bh = minix_bread(inode,block,0);
if (!bh) {
block++;
continue;
}
}
de = (struct minix_dir_entry *) (bh->b_data + offset);
offset += info->s_dirsize;
if (de->inode) {
brelse(bh);
return 0;
}
if (offset < bh->b_size)
continue;
brelse(bh);
bh = NULL;
offset = 0;
block++;
}
brelse(bh);
return 1;
bad_dir:
brelse(bh);
printk("Bad directory on device %s\n",
kdevname(inode->i_dev));
return 1;
}
 
int minix_rmdir(struct inode * dir, const char * name, int len)
{
int retval;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
 
inode = NULL;
bh = minix_find_entry(dir,name,len,&de);
retval = -ENOENT;
if (!bh)
goto end_rmdir;
retval = -EPERM;
if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
goto end_rmdir;
if (inode->i_dev != dir->i_dev)
goto end_rmdir;
if (inode == dir) /* we may not delete ".", but "../dir" is ok */
goto end_rmdir;
if (!S_ISDIR(inode->i_mode)) {
retval = -ENOTDIR;
goto end_rmdir;
}
if (!empty_dir(inode)) {
retval = -ENOTEMPTY;
goto end_rmdir;
}
if (de->inode != inode->i_ino) {
retval = -ENOENT;
goto end_rmdir;
}
if (inode->i_count > 1) {
retval = -EBUSY;
goto end_rmdir;
}
if (inode->i_nlink != 2)
printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
de->inode = 0;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
inode->i_nlink=0;
inode->i_dirt=1;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_nlink--;
dir->i_dirt=1;
retval = 0;
end_rmdir:
iput(dir);
iput(inode);
brelse(bh);
return retval;
}
 
int minix_unlink(struct inode * dir, const char * name, int len)
{
int retval;
struct inode * inode;
struct buffer_head * bh;
struct minix_dir_entry * de;
 
repeat:
retval = -ENOENT;
inode = NULL;
bh = minix_find_entry(dir,name,len,&de);
if (!bh)
goto end_unlink;
if (!(inode = iget(dir->i_sb, de->inode)))
goto end_unlink;
retval = -EPERM;
if (S_ISDIR(inode->i_mode))
goto end_unlink;
if (de->inode != inode->i_ino) {
iput(inode);
brelse(bh);
current->counter = 0;
schedule();
goto repeat;
}
if ((dir->i_mode & S_ISVTX) && !fsuser() &&
current->fsuid != inode->i_uid &&
current->fsuid != dir->i_uid)
goto end_unlink;
if (de->inode != inode->i_ino) {
retval = -ENOENT;
goto end_unlink;
}
if (!inode->i_nlink) {
printk("Deleting nonexistent file (%s:%lu), %d\n",
kdevname(inode->i_dev),
inode->i_ino, inode->i_nlink);
inode->i_nlink=1;
}
de->inode = 0;
dir->i_version = ++event;
mark_buffer_dirty(bh, 1);
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
inode->i_dirt = 1;
retval = 0;
end_unlink:
brelse(bh);
iput(inode);
iput(dir);
return retval;
}
 
int minix_symlink(struct inode * dir, const char * name, int len, const char * symname)
{
struct minix_dir_entry * de;
struct inode * inode = NULL;
struct buffer_head * bh = NULL, * name_block = NULL;
int i;
char c;
 
if (!(inode = minix_new_inode(dir))) {
iput(dir);
return -ENOSPC;
}
inode->i_mode = S_IFLNK | 0777;
inode->i_op = &minix_symlink_inode_operations;
name_block = minix_bread(inode,0,1);
if (!name_block) {
iput(dir);
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
return -ENOSPC;
}
i = 0;
while (i < 1023 && (c=*(symname++)))
name_block->b_data[i++] = c;
name_block->b_data[i] = 0;
mark_buffer_dirty(name_block, 1);
brelse(name_block);
inode->i_size = i;
inode->i_dirt = 1;
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
brelse(bh);
iput(dir);
return -EEXIST;
}
i = minix_add_entry(dir, name, len, &bh, &de);
if (i) {
inode->i_nlink--;
inode->i_dirt = 1;
iput(inode);
iput(dir);
return i;
}
de->inode = inode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
iput(inode);
return 0;
}
 
int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len)
{
int error;
struct minix_dir_entry * de;
struct buffer_head * bh;
 
if (S_ISDIR(oldinode->i_mode)) {
iput(oldinode);
iput(dir);
return -EPERM;
}
if (oldinode->i_nlink >= MINIX_LINK_MAX) {
iput(oldinode);
iput(dir);
return -EMLINK;
}
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
iput(dir);
iput(oldinode);
return -EEXIST;
}
error = minix_add_entry(dir, name, len, &bh, &de);
if (error) {
iput(dir);
iput(oldinode);
return error;
}
de->inode = oldinode->i_ino;
mark_buffer_dirty(bh, 1);
brelse(bh);
iput(dir);
oldinode->i_nlink++;
oldinode->i_ctime = CURRENT_TIME;
oldinode->i_dirt = 1;
iput(oldinode);
return 0;
}
 
static int subdir(struct inode * new_inode, struct inode * old_inode)
{
int ino;
int result;
 
new_inode->i_count++;
result = 0;
for (;;) {
if (new_inode == old_inode) {
result = 1;
break;
}
if (new_inode->i_dev != old_inode->i_dev)
break;
ino = new_inode->i_ino;
if (minix_lookup(new_inode,"..",2,&new_inode))
break;
if (new_inode->i_ino == ino)
break;
}
iput(new_inode);
return result;
}
 
#define PARENT_INO(buffer) \
(((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode)
 
/*
* rename uses retrying to avoid race-conditions: at least they should be minimal.
* it tries to allocate all the blocks, then sanity-checks, and if the sanity-
* checks fail, it tries to restart itself again. Very practical - no changes
* are done until we know everything works ok.. and then all the changes can be
* done in one fell swoop when we have claimed all the buffers needed.
*
* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
{
struct inode * old_inode, * new_inode;
struct buffer_head * old_bh, * new_bh, * dir_bh;
struct minix_dir_entry * old_de, * new_de;
struct minix_sb_info * info;
int retval;
 
info = &old_dir->i_sb->u.minix_sb;
goto start_up;
try_again:
brelse(old_bh);
brelse(new_bh);
brelse(dir_bh);
iput(old_inode);
iput(new_inode);
current->counter = 0;
schedule();
start_up:
old_inode = new_inode = NULL;
old_bh = new_bh = dir_bh = NULL;
old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
if (!old_inode)
goto end_rename;
if (must_be_dir && !S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EPERM;
if ((old_dir->i_mode & S_ISVTX) &&
current->fsuid != old_inode->i_uid &&
current->fsuid != old_dir->i_uid && !fsuser())
goto end_rename;
new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
if (new_bh) {
new_inode = __iget(new_dir->i_sb, new_de->inode, 0);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
}
}
if (new_inode == old_inode) {
retval = 0;
goto end_rename;
}
if (new_inode && S_ISDIR(new_inode->i_mode)) {
retval = -EISDIR;
if (!S_ISDIR(old_inode->i_mode))
goto end_rename;
retval = -EINVAL;
if (subdir(new_dir, old_inode))
goto end_rename;
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
retval = -EBUSY;
if (new_inode->i_count > 1)
goto end_rename;
}
retval = -EPERM;
if (new_inode && (new_dir->i_mode & S_ISVTX) &&
current->fsuid != new_inode->i_uid &&
current->fsuid != new_dir->i_uid && !fsuser())
goto end_rename;
if (S_ISDIR(old_inode->i_mode)) {
retval = -ENOTDIR;
if (new_inode && !S_ISDIR(new_inode->i_mode))
goto end_rename;
retval = -EINVAL;
if (subdir(new_dir, old_inode))
goto end_rename;
retval = -EIO;
dir_bh = minix_bread(old_inode,0,0);
if (!dir_bh)
goto end_rename;
if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX)
goto end_rename;
}
if (!new_bh) {
retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de);
if (retval)
goto end_rename;
}
/* sanity checking before doing the rename - avoid races */
if (new_inode && (new_de->inode != new_inode->i_ino))
goto try_again;
if (new_de->inode && !new_inode)
goto try_again;
if (old_de->inode != old_inode->i_ino)
goto try_again;
/* ok, that's it */
old_de->inode = 0;
new_de->inode = old_inode->i_ino;
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
old_dir->i_dirt = 1;
old_dir->i_version = ++event;
new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
new_dir->i_dirt = 1;
new_dir->i_version = ++event;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME;
new_inode->i_dirt = 1;
}
mark_buffer_dirty(old_bh, 1);
mark_buffer_dirty(new_bh, 1);
if (dir_bh) {
PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
mark_buffer_dirty(dir_bh, 1);
old_dir->i_nlink--;
old_dir->i_dirt = 1;
if (new_inode) {
new_inode->i_nlink--;
new_inode->i_dirt = 1;
} else {
new_dir->i_nlink++;
new_dir->i_dirt = 1;
}
}
retval = 0;
end_rename:
brelse(dir_bh);
brelse(old_bh);
brelse(new_bh);
iput(old_inode);
iput(new_inode);
iput(old_dir);
iput(new_dir);
return retval;
}
 
/*
* Ok, rename also locks out other renames, as they can change the parent of
* a directory, and we don't want any races. Other races are checked for by
* "do_rename()", which restarts if there are inconsistencies.
*
* Note that there is no race between different filesystems: it's only within
* the same device that races occur: many renames can happen at once, as long
* as they are on different partitions.
*/
int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len,
int must_be_dir)
{
static struct wait_queue * wait = NULL;
static int lock = 0;
int result;
 
while (lock)
sleep_on(&wait);
lock = 1;
result = do_minix_rename(old_dir, old_name, old_len,
new_dir, new_name, new_len, must_be_dir);
lock = 0;
wake_up(&wait);
return result;
}
/.depend
0,0 → 1,72
bitmap.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/bitops.h
dir.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h
file.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fcntl.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/locks.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/pagemap.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h
fsync.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fcntl.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/locks.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h
inode.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/module.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/mm.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/locks.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/system.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/bitops.h
namei.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/kernel.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/string.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fcntl.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h
symlink.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/asm/segment.h
truncate.o: \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/errno.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/sched.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/minix_fs.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/stat.h \
/home/javier/opencores/or1k/rc203soc/sw/uClinux/include/linux/fcntl.h
/Makefile
0,0 → 1,14
#
# Makefile for the linux minix-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
# Note 2! The CFLAGS definitions are now in the main makefile...
 
O_TARGET := minix.o
O_OBJS := bitmap.o truncate.o namei.o inode.o file.o dir.o symlink.o fsync.o
M_OBJS := $(O_TARGET)
 
include $(TOPDIR)/Rules.make
/bitmap.c
0,0 → 1,266
/*
* linux/fs/minix/bitmap.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
 
/* bitmap.c contains the code that handles the inode and block bitmaps */
 
#include <linux/sched.h>
#include <linux/minix_fs.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/string.h>
 
#include <asm/bitops.h>
 
static int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
 
static unsigned long count_free(struct buffer_head *map[], unsigned numblocks)
{
unsigned i, j, sum = 0;
struct buffer_head *bh;
for (i=0; i<numblocks; i++) {
if (!(bh=map[i]))
return(0);
for (j=0; j<BLOCK_SIZE; j++)
sum += nibblemap[bh->b_data[j] & 0xf]
+ nibblemap[(bh->b_data[j]>>4)&0xf];
}
return(sum);
}
 
void minix_free_block(struct super_block * sb, int block)
{
struct buffer_head * bh;
unsigned int bit,zone;
 
if (!sb) {
printk("trying to free block on nonexistent device\n");
return;
}
if (block < sb->u.minix_sb.s_firstdatazone ||
block >= sb->u.minix_sb.s_nzones) {
printk("trying to free block not in datazone\n");
return;
}
bh = get_hash_table(sb->s_dev,block,BLOCK_SIZE);
if (bh)
clear_bit(BH_Dirty, &bh->b_state);
brelse(bh);
zone = block - sb->u.minix_sb.s_firstdatazone + 1;
bit = zone & 8191;
zone >>= 13;
bh = sb->u.minix_sb.s_zmap[zone];
if (!bh) {
printk("minix_free_block: nonexistent bitmap buffer\n");
return;
}
if (!clear_bit(bit,bh->b_data))
printk("free_block (%s:%d): bit already cleared\n",
kdevname(sb->s_dev), block);
mark_buffer_dirty(bh, 1);
return;
}
 
int minix_new_block(struct super_block * sb)
{
struct buffer_head * bh;
int i,j;
 
if (!sb) {
printk("trying to get new block from nonexistent device\n");
return 0;
}
repeat:
j = 8192;
for (i=0 ; i<64 ; i++)
if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL)
if ((j=find_first_zero_bit(bh->b_data, 8192)) < 8192)
break;
if (i>=64 || !bh || j>=8192)
return 0;
if (set_bit(j,bh->b_data)) {
printk("new_block: bit already set");
goto repeat;
}
mark_buffer_dirty(bh, 1);
j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
if (j < sb->u.minix_sb.s_firstdatazone ||
j >= sb->u.minix_sb.s_nzones)
return 0;
if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) {
printk("new_block: cannot get block");
return 0;
}
memset(bh->b_data, 0, BLOCK_SIZE);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
brelse(bh);
return j;
}
 
unsigned long minix_count_free_blocks(struct super_block *sb)
{
return (count_free(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks)
<< sb->u.minix_sb.s_log_zone_size);
}
 
static struct buffer_head *V1_minix_clear_inode(struct inode *inode)
{
struct buffer_head *bh;
struct minix_inode *raw_inode;
int ino, block;
 
ino = inode->i_ino;
if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
kdevname(inode->i_dev), ino);
return 0;
}
block = (2 + inode->i_sb->u.minix_sb.s_imap_blocks +
inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino - 1) / MINIX_INODES_PER_BLOCK);
bh = bread(inode->i_dev, block, BLOCK_SIZE);
if (!bh) {
printk("unable to read i-node block\n");
return 0;
}
raw_inode = ((struct minix_inode *)bh->b_data +
(ino - 1) % MINIX_INODES_PER_BLOCK);
raw_inode->i_nlinks = 0;
raw_inode->i_mode = 0;
mark_buffer_dirty(bh, 1);
return bh;
}
 
static struct buffer_head *V2_minix_clear_inode(struct inode *inode)
{
struct buffer_head *bh;
struct minix2_inode *raw_inode;
int ino, block;
 
ino = inode->i_ino;
if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("Bad inode number on dev %s: %d is out of range\n",
kdevname(inode->i_dev), ino);
return 0;
}
block = (2 + inode->i_sb->u.minix_sb.s_imap_blocks +
inode->i_sb->u.minix_sb.s_zmap_blocks +
(ino - 1) / MINIX2_INODES_PER_BLOCK);
bh = bread(inode->i_dev, block, BLOCK_SIZE);
if (!bh) {
printk("unable to read i-node block\n");
return 0;
}
raw_inode = ((struct minix2_inode *) bh->b_data +
(ino - 1) % MINIX2_INODES_PER_BLOCK);
raw_inode->i_nlinks = 0;
raw_inode->i_mode = 0;
mark_buffer_dirty(bh, 1);
return bh;
}
 
/* Clear the link count and mode of a deleted inode on disk. */
 
static void minix_clear_inode(struct inode *inode)
{
struct buffer_head *bh;
if (INODE_VERSION(inode) == MINIX_V1)
bh = V1_minix_clear_inode(inode);
else
bh = V2_minix_clear_inode(inode);
brelse (bh);
}
 
void minix_free_inode(struct inode * inode)
{
struct buffer_head * bh;
unsigned long ino;
 
if (!inode)
return;
if (!inode->i_dev) {
printk("free_inode: inode has no device\n");
return;
}
if (inode->i_count != 1) {
printk("free_inode: inode has count=%ld\n",inode->i_count);
return;
}
if (inode->i_nlink) {
printk("free_inode: inode has nlink=%d\n",inode->i_nlink);
return;
}
if (!inode->i_sb) {
printk("free_inode: inode on nonexistent device\n");
return;
}
if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
return;
}
ino = inode->i_ino;
if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) {
printk("free_inode: nonexistent imap in superblock\n");
return;
}
minix_clear_inode(inode);
clear_inode(inode);
if (!clear_bit(ino & 8191, bh->b_data))
printk("free_inode: bit %lu already cleared.\n",ino);
mark_buffer_dirty(bh, 1);
}
 
struct inode * minix_new_inode(const struct inode * dir)
{
struct super_block * sb;
struct inode * inode;
struct buffer_head * bh;
int i,j;
 
if (!dir || !(inode = get_empty_inode()))
return NULL;
sb = dir->i_sb;
inode->i_sb = sb;
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL)
if ((j=find_first_zero_bit(bh->b_data, 8192)) < 8192)
break;
if (!bh || j >= 8192) {
iput(inode);
return NULL;
}
if (set_bit(j,bh->b_data)) { /* shouldn't happen */
printk("new_inode: bit already set");
iput(inode);
return NULL;
}
mark_buffer_dirty(bh, 1);
j += i*8192;
if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) {
iput(inode);
return NULL;
}
inode->i_count = 1;
inode->i_nlink = 1;
inode->i_dev = sb->s_dev;
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_dirt = 1;
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = NULL;
inode->i_blocks = inode->i_blksize = 0;
insert_inode_hash(inode);
return inode;
}
 
unsigned long minix_count_free_inodes(struct super_block *sb)
{
return count_free(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks);
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.