Rev 3 |
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: fs.c,v 1.2 2003-01-07 17:14:05 pj Exp $
*
* File: $File$
* Revision: $Revision: 1.2 $
* Last update: $Date: 2003-01-07 17:14:05 $
*/
#include "dentry.h"
#include <kernel/func.h>
#include <fs/util.h>
#include <fs/types.h>
#include <fs/const.h>
#include <fs/bdev.h>
#include <fs/fsconf.h>
#include <fs/fsinit.h>
#include <fs/major.h>
#include <fs/fs.h>
#include <fs/sysmacro.h>
#include <fs/fsind.h>
#include <fs/assert.h>
#include <fs/mount.h>
#include <fs/errno.h>
#include <fs/task.h>
#include "mutex.h"
#include "fs.h"
#include "dcache.h"
#include "inode.h"
#include "super.h"
#include "superop.h"
#include "file.h"
#include "fileop.h"
#include "fsconst.h"
#include "debug.h"
// number of filesystem types supported
#define MAXFILESYSTEMS 8
// pointer into "fst"
static int nextfs
=0;
// file system that are registered
static struct file_system_type
*fst
[MAXFILESYSTEMS
];
NOP_mutexattr_t fsdef_mutexattr
=NOP_MUTEXATTR_INITIALIZER
;
//static __fs_mutex_t mutex;
void *fsmutexattr
=NULL
;
/* if an assert fails into this module this go UP */
int fs_crash
=0;
/*
* used to block all filesystem calls
*/
/*+ state of the fs +*/
/*+ -1: before initialization 0:system calls allowed 1:calls rejected +*/
int fssysstate
=-1;
/*+ number of syscalls in progress +*/
long fssyscounter
=0;
/*+ mutex to update the above two variables +*/
__fs_fastmutex_t fssysmutex
;
/*+ syncronization semaphore to change fssysstate from 0 to 1 +*/
__fs_sem_t fssyssync
;
/*+ number of task waiting for fs +*/
long fssysinitcounter
=0;
/*+ syncronization semaphore to change fssysstate from -1 to 0 +*/
__fs_sem_t fssysinit
;
/*
* variables needed to have a proper filesystem shutdown
*/
/*+ number of module that needs filesystem support +*/
long needcounter
=0;
/*+ syncronization semaphore to start a filesystem shutdown +*/
__fs_sem_t needsync
;
/**
This is the first function that must be called prior to call
another function if the filesystem module; it initialize every
sub-module of the filesystem.
@memo
@param ptr
a pointer to a structure that contains information on how initialize
the filesystem
@return
0 on success else another value in case of error
*/
void filesystem_end
(void *);
int filesystem_init
(FILESYSTEM_PARMS
*ptr
)
{
int result
;
int i
,fd
;
printk
(KERN_INFO
"initializing filesystems...");
printkb
("fs_init: START");
//__fs_mutex_init(&mutex);
__fs_fastmutex_init
(&fssysmutex
);
__fs_sem_init
(&fssyssync
,0);
__fs_sem_init
(&needsync
,0);
__fs_sem_init
(&fssysinit
,0);
fsmutexattr
=ptr
->fs_mutexattr
;
if (fsmutexattr
==NULL
) {
printk
(KERN_ERR
"filesystem_init failed: mutex attribute not specified!");
printkb
("fs_init: END");
return -1;
}
nextfs
=0;
for (i
=0;i
<MAXFILESYSTEMS
;i
++)
fst
[i
]=NULL
;
printkb
("fs_init: initiating cache...");
dcache_init
();
printkb
("fs_init: initiating supers...");
super_init
();
printkb
("fs_init: initiating inodes...");
inode_init
();
printkb
("fs_init: initiating dentries...");
dentry_init
();
/*--*/
#ifdef MSDOS_FILESYSTEM
printkb
("fs_init: initiating FAT16 filesystem...");
msdos_fs_init
(ptr
);
#endif
/*--*/
printkb
("fs_init: mounting root...");
result
=mount_root
(ptr
->device
,ptr
->fs_ind
,ptr
->fs_opts
);
if (result
!=0) {
/*if (ptr->fs_showinfo)*/
printk
(KERN_CRIT
"Mounting root FAILED! (error: %i)",result
);
/* for safety */
_assert
(result
==0);
printkb
("fs_init: END");
return result
;
}
/*--*/
/* must be done after mounting of the root filesystem because
* the file descriptors table of every process contains a
* pointer to a 'struct dentry' (the current working directory)
*/
printkb
("fs_init: initiating files...");
file_init
();
/*--*/
/* to do better: reserve the first 3 file descriptors for
* console I/O
*/
printkb
("fs_init: initiating console descriptors...");
for (i
=0;i
<3;i
++) {
fd
=get_fd
(__get_pid
(),(void*)-1);
if (fd
!=i
) {
printk
(KERN_CRIT
"Can't reserve file descriptor %i for console i/o",fd
);
_assert
(fd
==i
);
return -1;
}
}
/*--*/
printkb
("fs_init: initiating shutdown routines...");
sys_atrunlevel
(filesystem_end
,NULL
,RUNLEVEL_SHUTDOWN
);
/* -- */
permit_all_fs_calls
();
printkb
("fs_init: END");
return 0;
}
/*+
This function is used to find what filesystem module manage the
requested file system indicator
@memo
@param fs_ind
the file system to find
@return
the file system struct or NULL in case of error
+*/
struct file_system_type
*filesystem_find_byid
(BYTE fs_ind
)
{
int i
;
for (i
=0;i
<nextfs
;i
++)
if (fst
[i
]->fs_ind
==fs_ind
) return fst
[i
];
return NULL
;
}
/*+
This function is used by a filesystem to register itself to the
filesystem manager; can be called more than one time.
@memo
@param ptr
a pointer to the strutc file\_system\_type of that filesystem
@return
0 on success, -1 on failure
@see file\_system\_type
+*/
int filesystem_register
(struct file_system_type
*ptr
)
{
if (nextfs
==MAXFILESYSTEMS
) return -1;
fst
[nextfs
]=ptr
;
nextfs
++;
return 0;
}
__uint8_t filesystem_find_byname
(char *name
)
{
int i
;
for (i
=0;i
<nextfs
;i
++)
if (!strcmp(name
,(char *)fst
[i
]->name
)) return fst
[i
]->fs_ind
;
return 255;
}
/* --- */
int mount_root
(__dev_t device
, __uint8_t fs_ind
,
struct mount_opts
*opts
)
{
struct super_block
*sb
;
struct file_system_type
*ptr
;
int res
;
printk9
("START mount_root()");
ptr
=filesystem_find_byid
(fs_ind
);
if (ptr
==NULL
) {
printk
(KERN_CRIT
"mount_root(): errore -2");
return -2;
}
printk9
("mount_root(): filesystem type '%s'",ptr
->name
);
printk9
("mount_root(): filesystem entry at %p",(void *)ptr
->read_super
);
printk9
("mount_root(): filesystem found");
res
=dcache_lockdevice
(device
);
_assert
(res
!=DCACHE_ERR
);
if (res
==DCACHE_FAIL
) {
printk
(KERN_CRIT
"mount_root(): errore -6");
return -6;
}
printk9
("mount_root(): device locked");
sb
=ptr
->read_super
(device
,fs_ind
,opts
);
if (sb
==NULL
) {
printk
(KERN_CRIT
"mount_root(): errore -4");
return -4;
}
sb
->sb_dev
=device
;
sb
->sb_fs
=ptr
;
sb
->sb_parent
=NULL
;
sb
->sb_childs
=NULL
;
sb
->sb_next
=NULL
;
printk9
("mount_root(): super read");
set_root_superblock
(sb
);
res
=set_root_dentry
(sb
);
if (res
) {
printk
(KERN_CRIT
"mount_root(): errore -5");
return -5;
}
printk9
("mount_root(): root dentry set");
/* so other task can use this superblock */
super_release
(sb
);
printk9
("mount_root(): super available");
{
char *n0
,*n1
;
bdev_findname
(device
,&n0
,&n1
);
printk
(KERN_INFO
"mounted %s%c%s (%s) on /",
n0
,DIRDELIMCHAR
,n1
,
opts
->flags
&MOUNT_FLAG_RW
?"rw":"ro");
}
printk9
("END mount_root()");
return 0;
}
/* --- */
int mount_device
(__dev_t device
, __uint8_t fs_ind
, char *pathname
,
struct mount_opts
*opts
)
{
struct file_system_type
*fs
;
struct super_block
*sb
,*psb
;
struct dentry
*de
;
int ret
,res
;
printk9
("START mount_device()");
fs
=filesystem_find_byid
(fs_ind
);
if (fs
==NULL
) {
printk
(KERN_ERR
"mount_device(): can't find filesystem");
return -ENODEV
;
}
de
=find_dentry_from
(NULL
,pathname
);
if (de
==NULL
) {
printk
(KERN_ERR
"mount_device(): can't find directory entry");
return -ENOENT
;
}
if (!__S_ISDIR
(de
->d_inode
->i_st.
st_mode)) {
printk
(KERN_ERR
"mount_device(): pathname is not a directory");
unlock_dentry
(de
);
return -ENOTDIR
;
}
res
=dcache_lockdevice
(device
);
_assert
(res
!=DCACHE_ERR
);
if (res
==DCACHE_FAIL
) {
unlock_dentry
(de
);
printk
(KERN_ERR
"mount_device(): can't lock device");
return -EBUSY
;
}
sb
=fs
->read_super
(device
,fs_ind
,opts
);
if (sb
==NULL
) {
unlock_dentry
(de
);
printk
(KERN_ERR
"mount_device(): can't read superblock");
return -EINVAL
;
}
sb
->sb_dev
=device
;
sb
->sb_fs
=fs
;
psb
=de
->d_sb
;
ret
=mount_dentry
(sb
,de
);
if (ret
) {
unlock_dentry
(de
);
super_freeblock
(sb
);
printk
(KERN_ERR
"mount_device(): can't associate directory entry with superblock");
return -EBUSY
;
}
/* insert superblock into tree */
super_insertintotree
(sb
,psb
);
/* so other task can use this superblock */
super_release
(sb
);
{
char *n0
,*n1
;
bdev_findname
(device
,&n0
,&n1
);
printk
(KERN_INFO
"mounted %s%c%s (%s) on %s",
n0
,DIRDELIMCHAR
,n1
,
opts
->flags
&MOUNT_FLAG_RW
?"rw":"ro",
pathname
);
}
printk9
("END mount_device()");
return 0;
}
/*
int mount_device(__dev_t device, __uint8_t fs_ind, char *pathname,
struct mount_opts *opts)
{
int res;
//__fs_mutex_lock(&mutex);
res=__mount_device(device,fs_ind,pathname,opts);
//__fs_mutex_unlock(&mutex);
return res;
}
*/
int umount_device
(__dev_t device
)
{
char path
[1024];
struct super_block
*sb
;
int res
;
char *n0
,*n1
;
printk9
("START umount_device()");
if (device
==get_root_device
()) {
printk9
(KERN_ERR
"umount_device(): can't umount root");
return -EBUSY
;
}
sb
=super_aquire
(device
);
if (sb
==NULL
) {
printk9
(KERN_ERR
"umount_device(): can't aquire super block");
printk
(KERN_ERR
"can't unmount device 0x%04x",device
);
return -EBUSY
;
}
printk9
("getting pathname");
/* get names for logging */
getfullname_dentry
(sb
->sb_droot
,path
,sizeof(path
));
bdev_findname
(device
,&n0
,&n1
);
printk9
("checking for childs super_blocks");
if (sb
->sb_childs
!=NULL
) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_device(): super block has childs");
printk
(KERN_ERR
"can't unmount %s%c%s from %s",n0
,DIRDELIMCHAR
,n1
,path
);
return -EBUSY
;
}
printk9
("calling virtual function put_super");
res
=sb
->sb_op
->put_super
(sb
);
if (res
!=0) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_device(): can't put_super");
printk
(KERN_ERR
"can't unmount %s%c%s from %s",n0
,DIRDELIMCHAR
,n1
,path
);
return -EIO
;
}
printk9
("calling umount_dentry");
res
=umount_dentry
(sb
);
if (res
!=0) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_device(): can't umount directory tree");
printk
(KERN_ERR
"can't unmount %s%c%s from %s",n0
,DIRDELIMCHAR
,n1
,path
);
return -EBUSY
;
}
/* this is not needed but allows sync of cache with hard-diskes */
res
=dcache_purgedevice
(device
,0);
/*
the dentry has been unmounted so we must continue
if (res!=0) {
super_release(sb);
printk(KERN_ERR
"umount_device(): can't sync cache with hard-disk");
return -EIO;
}
*/
res
=dcache_unlockdevice
(device
);
_assert
(res
!=DCACHE_ERR
);
if (res
!=DCACHE_OK
) {
// we must not go here
_assert
(0==-1);
super_release
(sb
);
printk9
(KERN_ERR
"umount_device(): can't unlock device.cache");
printk
(KERN_ERR
"can't unmount %s%c%s from %s",n0
,DIRDELIMCHAR
,n1
,path
);
return -EBUSY
;
}
/* remove superblock from tree */
super_removefromtree
(sb
);
/* free superblock! */
super_freeblock
(sb
);
printk
(KERN_INFO
"unmounted %s%c%s from %s",n0
,DIRDELIMCHAR
,n1
,path
);
printk9
("END umount_device()");
return EOK
;
}
/*
int umount_device(__dev_t device)
{
int res;
//__fs_mutex_lock(&mutex);
res=__umount_device(device);
//__fs_mutex_unlock(&mutex);
return res;
}
*/
int umount_root
(void)
{
struct super_block
*sb
;
__dev_t device
;
int res
;
char *n0
,*n1
;
printk9
("START umount_root()");
device
=get_root_device
();
sb
=super_aquire
(device
);
if (sb
==NULL
) {
printk9
(KERN_ERR
"umount_root(): can't aquire super block");
printk
(KERN_ERR
"can't unmount device 0x%04x",device
);
return -EBUSY
;
}
/* get names for logging */
bdev_findname
(device
,&n0
,&n1
);
printk9
("unsetting root");
set_root_superblock
(NULL
);
set_root_dentry
(NULL
);
printk9
("calling umount_dentry");
res
=umount_dentry
(sb
);
printk9
("called umount_dentry");
if (res
!=0) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_root(): can't umount directory tree");
printk
(KERN_ERR
"can't unmount %s%c%s from /",n0
,DIRDELIMCHAR
,n1
);
return -EBUSY
;
}
printk9
("calling virtual function put_super");
/* */
res
=sb
->sb_op
->put_super
(sb
);
if (res
!=0) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_root(): can't put_super");
printk
(KERN_ERR
"can't unmount %s%c%s from /",n0
,DIRDELIMCHAR
,n1
);
return -EIO
;
}
/* this is not needed but allows sync of cache with hard-diskes */
res
=dcache_purgedevice
(device
,0);
if (res
!=0) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_root(): can't sync cache with hard-disk");
printk
(KERN_ERR
"can't unmount %s%c%s from /",n0
,DIRDELIMCHAR
,n1
);
return -EIO
;
}
res
=dcache_unlockdevice
(device
);
_assert
(res
!=DCACHE_ERR
);
if (res
!=DCACHE_OK
) {
super_release
(sb
);
printk9
(KERN_ERR
"umount_root(): can't unlock device.cache");
printk
(KERN_ERR
"can't unmount %s%c%s from /",n0
,DIRDELIMCHAR
,n1
);
return -EBUSY
;
}
/* free superblock! */
super_freeblock
(sb
);
printk
(KERN_INFO
"unmounted %s%c%s from /",n0
,DIRDELIMCHAR
,n1
);
printk9
("END umount_root()");
return EOK
;
}
/* -- */
int suspend_fs_shutdown
(void)
{
SYS_FLAGS f
;
_printk0
("<ssd%i>",exec_shadow
);
f
=kern_fsave
();
if (needcounter
==-1) {
kern_frestore
(f
);
_printk0
("<ssd%ifail>",exec_shadow
);
return -1;
}
needcounter
++;
kern_frestore
(f
);
_printk0
("<ssd%i,%li>",exec_shadow
,needcounter
);
return 0;
}
void resume_fs_shutdown
(void)
{
SYS_FLAGS f
;
_printk0
("<rfs%i>",exec_shadow
);
f
=kern_fsave
();
needcounter
--;
if (needcounter
==0) {
needcounter
=-1;
kern_frestore
(f
);
_printk0
("<rfs%isig>",exec_shadow
);
__fs_sem_signal
(&needsync
);
return;
}
kern_frestore
(f
);
}
/*+ wait the initialization of the fs +*/
int wait_for_fs_initialization
(void)
{
int ret
=0;
_printk0
("<wfi%i>",exec_shadow
);
__fs_fastmutex_lock
(&fssysmutex
);
if (fssysstate
==-1) {
fssysinitcounter
++;
__fs_fastmutex_unlock
(&fssysmutex
);
_printk0
("<wfi%ib>",exec_shadow
);
__fs_sem_wait
(&fssysinit
);
_printk0
("<wfi%ir>",exec_shadow
);
return 0;
} else if (fssysstate
==1) ret
=-1;
__fs_fastmutex_unlock
(&fssysmutex
);
_printk0
("<wfi%i,%i>",exec_shadow
,ret
);
return ret
;
}
void wait_for_notneed
(void)
{
SYS_FLAGS f
;
f
=kern_fsave
();
printkc
("fs_shut: needcounter=%li",needcounter
);
if (needcounter
>0) {
printkc
("fs_shut%i: synch needed (sem=%i)",exec_shadow
,
internal_sem_getvalue
(&needsync
));
kern_frestore
(f
);
__fs_sem_wait
(&needsync
);
printkc
("fs_shut%i: synch OK",exec_shadow
);
return ;
}
needcounter
=-1;
kern_frestore
(f
);
}
/* -- */
static int filecount
=0;
static void func2
(struct file
*f
)
{
filecount
++;
f
->f_op
->close
(f
->f_dentry
->d_inode
,f
);
unlock_dentry
(f
->f_dentry
);
/* so operations on this file fail */
f
->f_count
=0;
return;
}
static int func
(__dev_t device
)
{
int res
;
if (device
==get_root_device
()) return 0;
res
=umount_device
(device
);
if (res
) return -1;
return 0;
}
TASK filesystem_shutdown
(void *dummy
)
{
int res
;
printkc
("fs_shut%i: START",exec_shadow
);
/*
for (res=0;res<4*3;res++) {
cprintf("Û");
task_delay(250000l);
}
printk(KERN_DEBUG "TASK %i",exec_shadow);
*/
/* wait for modules */
printkc
("fs_shut%i: waiting for modules that use filesystems",exec_shadow
);
wait_for_notneed
();
/* block all filesystem calls */
printkc
("fs_shut%i: blocking all filesystem system calls",exec_shadow
);
printkc
("fs_shut: task into filesystems primitives are %li",fssyscounter
);
block_all_fs_calls
();
/* close all files */
printkc
("fs_shut%i: closing all files",exec_shadow
);
enums_file
(func2
);
printkc
("fs_shut%i: closed %i files",exec_shadow
,filecount
);
/* umount all devices */
printkc
("fs_shut: umounting all devices");
res
=super_enumdevice
(func
);
if (res
!=0) {
printk
(KERN_INFO
"filesystems shutdown aborted!");
printkc
("fs_shut: ABORTING");
return (void*)-1;
}
/* umount root device */
printkc
("fs_shut: umount root");
res
=umount_root
();
if (res
!=0) {
char *n0
,*n1
;
bdev_findname
(get_root_device
(),&n0
,&n1
);
printk
(KERN_ERR
"can't unmount %s%c%s from /",n0
,DIRDELIMCHAR
,n1
);
printk
(KERN_INFO
"filesystems shutdown aborted!");
printkc
("fs_shut: ABORTING");
return (void*)-1;
}
printkc
("fs_shut: END");
return (void*)0;
}
void filesystem_end
(void *dummy
)
{
SOFT_TASK_MODEL model
;
PID pid
;
printkc
("fs_end: START");
if (fs_crash
) {
printkc
("fs_end: END");
return;
}
printk
(KERN_INFO
"shuting down filesystems...");
//nrt_task_default_model(model);
//nrt_task_def_system(model);
soft_task_default_model
(model
);
soft_task_def_system
(model
);
soft_task_def_notrace
(model
);
soft_task_def_periodic
(model
);
soft_task_def_period
(model
,50000);
soft_task_def_met
(model
,10000);
soft_task_def_wcet
(model
,10000);
pid
=task_create
("ShutFS",filesystem_shutdown
,&model
,NULL
);
if (pid
==-1)
printk
(KERN_ERR
"can't start filesystem shutdown task");
else {
printkc
("fs_end: shutting down task %i activated",pid
);
task_activate
(pid
);
}
printkc
("fs_end: END");
}