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); |
} |