Rev 3 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Project: HARTIK (HA-rd R-eal TI-me K-ernel)
*
* Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
* Gerardo Lamastra <gerardo@sssup.it>
*
* Authors : Massimiliano Giorgi <massy@hartik.sssup.it>
* (see authors.txt for full list of hartik's authors)
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://hartik.sssup.it
*/
/*
* Copyright (C) 1999 Massimiliano Giorgi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* CVS : $Id: inode.c,v 1.1.1.1 2002-03-29 14:12:50 pj Exp $
*
* File: $File$
* Revision: $Revision: 1.1.1.1 $
* Last update: $Date: 2002-03-29 14:12:50 $
*/
#include <fs/util.h>
#include <fs/magic.h>
#include <fs/assert.h>
#include "fs.h"
#include "dentry.h"
#include "inode.h"
#include "inodeop.h"
#include "mutex.h"
#include "super.h"
#include "superop.h"
#include "debug.h"
#define MAXHASH 64
#define MAXHASHMASK 0x3f
static struct inode
*ihash
[MAXHASH
];
static __fs_mutex_t hashmutex
;
/* WARNING: must be greather than MAXDENTRY */
#define MAXINODES 256
static __fs_mutex_t mutex
;
static struct inode
*freeinode
;
static struct inode ino
[MAXINODES
];
#ifdef FSMUTEXCHECK
void debug_dump_inode_mutex
(void)
{
//printk(KERN_DEBUG "inode mutex: %i",(int)mutex);
//printk(KERN_DEBUG "inode mutex hasm: %i",(int)hashmutex);
}
static __fs_mutex_t regmutex
;
static __fs_mutex_t reghashmutex
;
int debug_check_inode_mutex
(void)
{
/*
if (mutex!=regmutex) {
printk(KERN_DEBUG "inode mutex CHANGED!");
return 0;
}
if (hashmutex!=reghashmutex) {
printk(KERN_DEBUG "inode hasmmutex CHANGED!");
return 0;
}
*/
return -1;
}
void debug_save_inode_mutex
(void)
{
regmutex
=mutex
;
reghashmutex
=hashmutex
;
}
#endif
/* WARNIG: if you want to aquire "mutex" and "hashmutex" you MUST
* aquire first "hashmutex" and then "mutex" (if you do not want
* a deadlock)
*/
void inode_stats
(void)
{
struct inode
*ptr
;
int c
,i
,l
,d
;
__fs_mutex_lock
(&hashmutex
);
__fs_mutex_lock
(&mutex
);
printk
(KERN_INFO
"max inodes: %4i",MAXINODES
);
c
=0;
ptr
=freeinode
;
while (ptr
!=NULL
) {
c
++;
ptr
=ptr
->i_next
;
}
printk
(KERN_INFO
" free inodes: %4i",c
);
for (i
=0,l
=0,c
=0,d
=0;i
<MAXHASH
;i
++) {
ptr
=ihash
[i
];
while (ptr
!=NULL
) {
c
++;
if (ptr
->i_dlink
!=0) l
++;
if (ptr
->i_dirty
) d
++;
ptr
=ptr
->i_next
;
}
}
printk
(KERN_INFO
" cached inodes: %4i",c
);
printk
(KERN_INFO
" linked inodes: %4i",l
);
printk
(KERN_INFO
" dirty inodes: %4i",d
);
__fs_mutex_unlock
(&mutex
);
__fs_mutex_unlock
(&hashmutex
);
}
int inode_init
(void)
{
int i
;
__fs_mutex_init
(&mutex
);
__fs_mutex_init
(&hashmutex
);
#ifdef FSMUTEXCHECK
debug_save_inode_mutex
();
#endif
for (i
=0;i
<MAXINODES
;i
++) {
/* for safety */
memset(ino
+i
,0,sizeof(struct inode
));
magic_clr
(ino
[i
].
magic);
__rwlock_init
(&ino
[i
].
i_lock);
ino
[i
].
i_next=&ino
[i
+1];
}
freeinode
=&ino
[0];
ino
[MAXINODES
-1].
i_next=NULL
;
for (i
=0;i
<MAXHASH
;i
++)
ihash
[i
]=NULL
;
return 0;
}
static struct inode
*__get_inode
(void)
{
struct inode
*ptr
;
//if (debug_info) cprintf("__get_inode start\n");
ptr
=freeinode
;
if (freeinode
!=NULL
) freeinode
=freeinode
->i_next
;
//if (debug_info) cprintf("__get_inode middle\n");
if (ptr
!=NULL
) {
//if (debug_info) cprintf("__get_inode assert\n");
magic_assert_ext
(ptr
->magic
,ZERO_MAGIC
,inode_stats
,
"inode_get: inode MAGIC number failed!\n");
//magic_assert(ptr->magic,ZERO_MAGIC,
// "inode_get: inode MAGIC number failed!\n");
//if (debug_info) cprintf("__get_inode assert ok\n");
magic_set
(ptr
->magic
,INODE_MAGIC
);
//if (debug_info) cprintf("__get_inode magic setted\n");
}
//if (debug_info) cprintf("__get_inode end\n");
return ptr
;
}
struct inode
*get_inode
(void)
{
struct inode
*ptr
;
__fs_mutex_lock
(&mutex
);
ptr
=__get_inode
();
__fs_mutex_unlock
(&mutex
);
return ptr
;
}
void free_inode
(struct inode
*ptr
)
{
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"inode_free: inode MAGIC number failed!\n");
magic_clr
(ptr
->magic
);
__fs_mutex_lock
(&mutex
);
ptr
->i_next
=freeinode
;
freeinode
=ptr
;
__fs_mutex_unlock
(&mutex
);
}
/*-------*/
static int hash_fun
(__dev_t device
, __ino_t inode
)
{
static __uint32_t table
[8]={3,5,7,11,13,17,19,23};
return (table
[device
&0x07]*(inode
+1))&MAXHASHMASK
;
}
void __insert_inode
(struct inode
*ptr
)
{
int h
;
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"inode_insert: inode MAGIC number failed!\n");
/* these could be done with no mutex syncronization */
h
=hash_fun
(ptr
->i_st.
st_dev,ptr
->i_st.
st_ino);
ptr
->i_hash
=h
;
ptr
->i_prev
=NULL
;
/* these NO */
ptr
->i_next
=ihash
[h
];
if (ihash
[h
]!=NULL
) ihash
[h
]->i_prev
=ptr
;
ihash
[h
]=ptr
;
ptr
->i_dlink
=1;
}
void insert_inode
(struct inode
*ptr
)
{
__fs_mutex_lock
(&hashmutex
);
__insert_inode
(ptr
);
__fs_mutex_unlock
(&hashmutex
);
}
static void __remove_inode
(struct inode
*ptr
)
{
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"inode_remove: inode MAGIC number failed!\n");
if (ptr
->i_next
!=NULL
) ptr
->i_next
->i_prev
=ptr
->i_prev
;
if (ptr
->i_prev
!=NULL
) ptr
->i_prev
->i_next
=ptr
->i_next
;
else ihash
[ptr
->i_hash
]=ptr
->i_next
;
}
void remove_inode
(struct inode
*ptr
)
{
__fs_mutex_lock
(&hashmutex
);
_assert
(ptr
->i_dlink
==0);
__remove_inode
(ptr
);
__fs_mutex_unlock
(&hashmutex
);
}
static struct inode
*__purge_inode
(void)
{
struct inode
*ptr
;
int i
;
/* Well, this can be implemented better; actually a scan for the
* unused inode into the buckets is done.
* (for examples the unused inodes can be mantained into an unused
* queue)
*/
for (i
=0;i
<MAXHASH
;i
++) {
ptr
=ihash
[i
];
while (ptr
!=NULL
) {
if (ptr
->i_dlink
==0) {
__remove_inode
(ptr
);
return ptr
;
}
ptr
=ptr
->i_next
;
}
}
return NULL
;
}
/* find & remove the oldest dentry from the tree */
/*
static struct inode *purge_inode(void)
{
struct inode *act;
__fs_mutex_lock(&hashmutex);
act=__purge_inode();
__fs_mutex_unlock(&hashmutex);
return act;
}
*/
static struct inode
*__catch_inode
(void)
{
struct inode
*ptr
;
//if (debug_info) cprintf("get\n");
ptr
=get_inode
(); /* aquiring "mutex" is required!! don't call __get_inode */
if (ptr
==NULL
) {
//if (debug_info) cprintf("get FAIL\n");
ptr
=__purge_inode
();
//if (debug_info) cprintf("catch\n");
if (ptr
==NULL
) {
//if (debug_info) cprintf("catch FAIL\n");
}
}
return ptr
;
}
/* get an inode by searching into the free space or purging an old one */
struct inode
*catch_inode
(void)
{
struct inode
*ptr
;
//if (debug_info) cprintf("catch called\n");
__fs_mutex_lock
(&hashmutex
);
//if (debug_info) cprintf("calling __catch...\n");
ptr
=__catch_inode
();
//if (debug_info) cprintf("__catch exiting\n");
__fs_mutex_unlock
(&hashmutex
);
return ptr
;
}
struct inode
*find_inode
(__dev_t device
, __ino_t ino
)
{
struct inode
*ptr
;
int h
;
//h=hash_fun(ptr->i_st.st_dev,ptr->i_st.st_ino);
h
=hash_fun
(device
,ino
);
__fs_mutex_lock
(&hashmutex
);
ptr
=ihash
[h
];
while (ptr
!=NULL
) {
if (ptr
->i_st.
st_dev==device
&&ptr
->i_st.
st_ino==ino
) {
ptr
->i_dlink
++;
break;
}
ptr
=ptr
->i_next
;
}
if (ptr
==NULL
) {
ptr
=__catch_inode
();
if (ptr
!=NULL
) {
ptr
->i_st.
st_dev=device
;
ptr
->i_st.
st_ino=ino
;
__insert_inode
(ptr
);
}
} else
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"find_inode: inode MAGIC number failed!\n");
__fs_mutex_unlock
(&hashmutex
);
return ptr
;
}
/* unlock inode */
void unlock_inode
(struct inode
*ptr
)
{
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"unlock_inode: inode MAGIC number failed!\n");
__fs_mutex_lock
(&hashmutex
);
_assert
(ptr
->i_dlink
>0);
ptr
->i_dlink
--;
__fs_mutex_unlock
(&hashmutex
);
}
/* unlock & remove inode from hash table */
int destroy_inode
(struct inode
*ptr
)
{
int ret
;
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"unlock_inode: inode MAGIC number failed!\n");
__fs_mutex_lock
(&hashmutex
);
_assert
(ptr
->i_dlink
>0);
if (ptr
->i_dlink
!=1) {
__fs_mutex_unlock
(&hashmutex
);
return -1;
}
if (ptr
->i_dirty
) {
ret
=ptr
->i_sb
->sb_op
->write_inode
(ptr
);
if (ret
!=0) {
__fs_mutex_unlock
(&hashmutex
);
return -1;
}
}
ptr
->i_dlink
--;
__remove_inode
(ptr
);
__fs_mutex_unlock
(&hashmutex
);
return 0;
}
/* unlock, remove the inode from the hast table
* erase inode on disk
*/
int erase_inode
(struct inode
*ptr
)
{
int ret
;
magic_assert_ext
(ptr
->magic
,INODE_MAGIC
,inode_stats
,
"erase_inode: inode MAGIC number failed!\n");
__fs_mutex_lock
(&hashmutex
);
_assert
(ptr
->i_dlink
>0);
if (ptr
->i_dlink
!=1) {
__fs_mutex_unlock
(&hashmutex
);
return -1;
}
ptr
->i_op
->destroy
(ptr
);
ret
=ptr
->i_sb
->sb_op
->delete_inode
(ptr
);
if (ret
==0) {
ptr
->i_dlink
--;
__remove_inode
(ptr
);
}
__fs_mutex_unlock
(&hashmutex
);
return ret
;
}