Metropoli BBS
VIEWER: volume.c MODE: TEXT (CP437)
//
// $Header: D:/ext2-os2/RCS/volume.c,v 1.12 1995/08/16 17:38:04 Willm Exp Willm $
//

// Linux ext2 file system driver for OS/2 2.x and WARP - Allows OS/2 to     
// access your Linux ext2fs partitions as normal drive letters.
// OS/2 implementation : Copyright (C) 1995  Matthieu WILLM
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.

//
// Will be eventually moved to ext2/super.c, and openvolume will be split into
// ext2_read_super() and its calling VFS routine
//
 
    extern unsigned long inode_init(unsigned long start, unsigned long end);

#define INCL_DOS
#define INCL_DOSERRORS
#include <os2.h>		// From the "Developer Connection Device Driver Kit" version 2.0


#include <fsd.h>
#include <fsh.h>

#include <os2/errors.h>


#include <os2/types.h>
#include <os2/os2proto.h>
#include <os2/os2misc.h>


#include <linux/fs.h>
#include <linux/e2_fs.h>
#include <linux/fs_proto.h>
#include <linux/e2_proto.h>
#include <linux/sched.h>

#include <os2/log.h>         /* Prototypes des fonctions de log.c                      */
#include <os2/volume.h>      /* Prototypes des fonctions de volume.c                   */

extern int auto_fsck;

static struct super_operations ext2_sops = { 
	ext2_read_inode,
	NULL,
	ext2_write_inode,
	ext2_put_inode,
	NULL, // ext2_put_super,
	NULL, // ext2_write_super,
	NULL, // ext2_statfs,
	NULL  // ext2_remount
};

//
// Initializations that can't be done in FS_INIT() because they need some ring 0 
// interfaces (FSHelpers ...)
// 
static int initialized = 0;

int init_ext2_os2(void) {
    if (!initialized) {
        initialized = 1;
        name_cache_init(0, 0);
        inode_init(0, 0);
    }
    return NO_ERROR;
}


static void ext2_setup_super (struct super_block * sb,
			      struct ext2_super_block * es)
{
	if (es->s_rev_level > EXT2_CURRENT_REV) {
			printk ("EXT2-fs warning: revision level too high, "
				"forcing read/only mode\n");
			sb->s_flags |= MS_RDONLY;
	}
	if (!(sb->s_flags & MS_RDONLY)) {
		if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
			printk ("EXT2-fs warning: mounting unchecked fs, "
				"running e2fsck is recommended\n");
		else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
			printk ("EXT2-fs warning: mounting fs with errors, "
				"running e2fsck is recommended\n");
		else if (es->s_max_mnt_count >= 0 &&
		         es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
			printk ("EXT2-fs warning: maximal mount count reached, "
				"running e2fsck is recommended\n");
		else if (es->s_checkinterval &&
			(es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME))
			printk ("EXT2-fs warning: checktime reached, "
				"running e2fsck is recommended\n");
		es->s_state &= ~EXT2_VALID_FS;
		if (!es->s_max_mnt_count)
			es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
#ifndef OS2
		es->s_mnt_count++;
#else
		//
		// This is to force Linux to autocheck the ext2fs partition "touched" by OS/2
		// this autocheck is enabled unless -no_auto_fsck is specified on the IFS cmd
		// line
		//
		if (auto_fsck) {
		    kernel_printf("e2fsck will be forced next time Linux will mount this partition");
  		    es->s_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
                } else {
		    es->s_mnt_count++;
                }
#endif
		es->s_mtime = CURRENT_TIME;
		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
		sb->s_dirt = 1;
#ifndef OS2 // For the moment .....
		if (test_opt (sb, DEBUG))
#endif
			printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
				"bpg=%lu, ipg=%lu, mo=%04lx]\n",
				EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
				sb->u.ext2_sb.s_frag_size,
				sb->u.ext2_sb.s_groups_count,
				EXT2_BLOCKS_PER_GROUP(sb),
				EXT2_INODES_PER_GROUP(sb),
				sb->u.ext2_sb.s_mount_opt);
#ifndef OS2 // For the moment .....
		if (test_opt (sb, CHECK)) {
#endif
			ext2_check_blocks_bitmap (sb);
			ext2_check_inodes_bitmap (sb);
#ifndef OS2 // For the moment .....
		}
#endif
	}
}

static int ext2_check_descriptors (struct super_block * sb)
{
#ifndef OS2
	int i;
#else
        blk_t i;
#endif
	int desc_block = 0;
	unsigned long block = sb->u.ext2_sb.s_es->s_first_data_block;
	struct ext2_group_desc * gdp = NULL;

	ext2_debug ("Checking group descriptors");
	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++)
	{
		if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
			gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[desc_block++]->b_data;
		if (gdp->bg_block_bitmap < block ||
		    gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
		{
			ext2_error (sb, "ext2_check_descriptors",
				    "Block bitmap for group %d"
				    " not in group (block %lu)!",
				    i, (unsigned long) gdp->bg_block_bitmap);
			return 0;
		}
		if (gdp->bg_inode_bitmap < block ||
		    gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
		{
			ext2_error (sb, "ext2_check_descriptors",
				    "Inode bitmap for group %d"
				    " not in group (block %lu)!",
				    i, (unsigned long) gdp->bg_inode_bitmap);
			return 0;
		}
		if (gdp->bg_inode_table < block ||
		    gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >=
		    block + EXT2_BLOCKS_PER_GROUP(sb))
		{
			ext2_error (sb, "ext2_check_descriptors",
				    "Inode table for group %d"
				    " not in group (block %lu)!",
				    i, (unsigned long) gdp->bg_inode_table);
			return 0;
		}
		block += EXT2_BLOCKS_PER_GROUP(sb);
		gdp++;
	}
	return 1;
}


struct super_block * openvolume(struct vpfsi _FS_PTR pvpfsi, unsigned short hVPB)
{
    struct super_block *         p_volume;
    int             rc;
    UINT32          time;
    pchar           Buf, Buf2 = 0;
    UINT16          nb_sec;
    pext2_super_block psb, psb2;
    UINT32          i;
    blk_t           db_count;
    blk_t logic_sb_block = 1, sb_block = 1;
    unsigned long offset;

    /************************************************************************/
    /*** Récupère le temps écoulé en secondes depuis le 1/1/1970          ***/
    /*** Valeur mise dans le champ timestamp de chaque bloc du cache pour ***/
    /*** l'algorithme de vieillissement                                   ***/
    /************************************************************************/
    if ((rc = gettime(&time)) != 0) {
        return 0;
    } /* end if */
    /************************************************************************/

    /************************************************************************/
    /*** Allocation d'un handle de volume                                 ***/
    /************************************************************************/
    if ((p_volume = (struct super_block *)G_malloc(sizeof(struct super_block))) == 0) {
        return 0;
    } /* end if */
    memset(p_volume, 0, sizeof(struct super_block));
    /************************************************************************/

    p_volume->sector_size       = (UINT32)pvpfsi->vpi_bsize;
    p_volume->nb_sectors        = (UINT32)pvpfsi->vpi_totsec;
    p_volume->drive             = (UINT32)pvpfsi->vpi_drive;

    p_volume->block_size        = BLOCK_SIZE;
    p_volume->s_blocksize       = p_volume->block_size;
    p_volume->sectors_per_block = p_volume->block_size / p_volume->sector_size;
    p_volume->s_dev             = hVPB;
    p_volume->s_op              = &ext2_sops;
    if (!Read_Write)
	p_volume->s_flags       = MS_RDONLY;
    FSH_SEMSET(&(p_volume->s_semerror));
    /************************************************************************/
    /*** Lecture et contrôle de superblock                                ***/
    /************************************************************************/
    if ((Buf = G_malloc(p_volume->block_size)) == 0) {
        G_free((pchar)p_volume);
        return 0;
    } /* end if */

    nb_sec = (UINT16)p_volume->sectors_per_block;
    if ((rc = FSH_DOVOLIO(
                          DVIO_OPREAD,
                          DVIO_ALLFAIL | DVIO_ALLABORT | DVIO_ALLRETRY,
                          hVPB,
                          Buf,
                          &nb_sec,
                          1 * p_volume->sectors_per_block
                         )) != NO_ERROR) {
        fs_log("Erreur FSH_DOVOLIO() dans validate_boot_sector()");
        G_free(Buf);
        G_free((pchar)p_volume);
        return 0;
    } /* end if */
    psb = (pext2_super_block)Buf;
    if (psb->s_magic != EXT2_SUPER_MAGIC) {
        fs_log("ext2 signature not found in superblock");
        if ((rc = G_free(Buf)) != NO_ERROR) {
            fs_log("erreur G_free");                    /*** FSH_INTERR() ***/
        } /* end if */
        if ((rc = G_free((pchar)p_volume)) != NO_ERROR) {
            fs_log("Erreur G_free");
        }
        return 0;
    } else {
        fs_log("ext2 signature found in superblock");
    }


    p_volume->block_size        = EXT2_MIN_BLOCK_SIZE << psb->s_log_block_size;
    p_volume->sectors_per_block = p_volume->block_size / p_volume->sector_size;
    p_volume->s_blocksize       = p_volume->block_size;

        if (p_volume->s_blocksize != BLOCK_SIZE &&
            (p_volume->s_blocksize == 1024 || p_volume->s_blocksize == 2048 ||
             p_volume->s_blocksize == 4096)) {
//                unsigned long offset;

    if ((Buf2 = G_malloc(p_volume->block_size)) == 0) {
       G_free(Buf);
       G_free((pchar)p_volume);
        return 0;
    } /* end if */

//              brelse (bh);
//              set_blocksize (dev, sb->s_blocksize);
                logic_sb_block = (sb_block*BLOCK_SIZE) / p_volume->s_blocksize;
                offset = (sb_block*BLOCK_SIZE) % p_volume->s_blocksize;
//              bh = bread (dev, logic_sb_block, psb->s_blocksize);
//              if(!bh)
//                      return NULL;
        nb_sec = (UINT16)p_volume->sectors_per_block;
        if ((rc = FSH_DOVOLIO(
                              DVIO_OPREAD,
                              DVIO_ALLFAIL | DVIO_ALLABORT | DVIO_ALLRETRY,
                              hVPB,
                              Buf2,
                              &nb_sec,
                              logic_sb_block * p_volume->sectors_per_block
                             )) != NO_ERROR) {
            fs_log("Erreur FSH_DOVOLIO() dans validate_boot_sector()");
            if ((rc = G_free(Buf)) != NO_ERROR) {
                fs_log("erreur G_free");                    /*** FSH_INTERR() ***/
            } /* end if */
            if ((rc = G_free(Buf2)) != NO_ERROR) {
                fs_log("erreur G_free");                    /*** FSH_INTERR() ***/
            } /* end if */
            G_free((pchar)p_volume);
            return 0;
        } /* end if */

                psb2 = (pext2_super_block) (Buf2 + offset);
//              sb->u.ext2_sb.s_es = es;
                if (psb2->s_magic != EXT2_SUPER_MAGIC) {
//                      sb->s_dev = 0;
//                      unlock_super (sb);
//                      brelse (bh);
                        fs_log ("EXT2-fs: Magic mismatch, very weird !\n");
                        return 0;
                }
        }

    /************************************************************************/

    /************************************************************************/
    /*** Allocation des buffers de fichier                                ***/
    /************************************************************************/
    if ((rc = init_bufs(p_volume)) != NO_ERROR) {
        fs_log("openvolume() Erreur init_bufs()");
        return 0;
    }
    /************************************************************************/

    /************************************************************************/
    /*** Allocation des file descriptors                                  ***/
    /************************************************************************/
    if ((rc = init_hfiles(p_volume)) != NO_ERROR) {
        fs_log("openvolume() Erreur init_hfiles()");
        return 0;
    }
    /************************************************************************/


    init_ext2_os2();

    /************************************************************************/
    /*** We copy the superblock into a buffer_head structure              ***/
    /************************************************************************/
    if ((p_volume->u.ext2_sb.s_sbh = alloc_filebuf(p_volume)) == 0) {
        fs_log("openvolume() Erreur alloc_filebuf()");
        return 0;
    }
    if (Buf2 != 0) {
        kernel_printf("Buf2 != 0");
        memcpy(p_volume->u.ext2_sb.s_sbh->b_data, Buf2 + offset, sizeof(struct ext2_super_block));
    } else {
        memcpy(p_volume->u.ext2_sb.s_sbh->b_data, Buf, BLOCK_SIZE);
    }

    p_volume->u.ext2_sb.s_sbh->b_blocknr  = logic_sb_block;
    p_volume->u.ext2_sb.s_sbh->b_count    = 1;
    p_volume->u.ext2_sb.s_sbh->b_dirt     = 0;
    p_volume->u.ext2_sb.s_sbh->b_size     = p_volume->block_size;
    p_volume->u.ext2_sb.s_sbh->b_uptodate = 1;
    p_volume->u.ext2_sb.s_sbh->b_dev      = p_volume->s_dev;      // System halt si absent
    p_volume->u.ext2_sb.s_sbh->dev        = p_volume;             // System halt si absent

    p_volume->u.ext2_sb.s_es = (pext2_super_block)(p_volume->u.ext2_sb.s_sbh->b_data);
    /************************************************************************/

    kernel_printf("\tSuperblock block no = %lu - blocksize = %lu", logic_sb_block, p_volume->s_blocksize);

    p_volume->u.ext2_sb.s_blocks_per_group = p_volume->u.ext2_sb.s_es->s_blocks_per_group;
    p_volume->u.ext2_sb.s_desc_per_block     = (EXT2_BLOCK_SIZE(p_volume) / sizeof (struct ext2_group_desc));
    p_volume->u.ext2_sb.s_inodes_per_group   = p_volume->u.ext2_sb.s_es->s_inodes_per_group;
    p_volume->u.ext2_sb.s_groups_count = (p_volume->u.ext2_sb.s_es->s_blocks_count -
                                        p_volume->u.ext2_sb.s_es->s_first_data_block +
                                       EXT2_BLOCKS_PER_GROUP(p_volume) - 1) /
                                       EXT2_BLOCKS_PER_GROUP(p_volume);
	p_volume->u.ext2_sb.s_frags_per_group = p_volume->u.ext2_sb.s_es->s_frags_per_group;
	p_volume->u.ext2_sb.s_inodes_per_block = p_volume->s_blocksize /
					   sizeof (struct ext2_inode);
	p_volume->u.ext2_sb.s_itb_per_group = p_volume->u.ext2_sb.s_inodes_per_group /
				        p_volume->u.ext2_sb.s_inodes_per_block;
	p_volume->u.ext2_sb.s_mount_state = p_volume->u.ext2_sb.s_es->s_state;

        db_count = (p_volume->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(p_volume) - 1) /
                   EXT2_DESC_PER_BLOCK(p_volume);
        for (i = 0; i < db_count; i++) {
                p_volume->u.ext2_sb.s_group_desc[i] = bread (p_volume, logic_sb_block + i + 1,
                                                       p_volume->block_size);
        }

	if (!ext2_check_descriptors (p_volume)) {
            blk_t j;
		p_volume->s_dev = 0;
		for (j = 0; j < db_count; j++)
			brelse (p_volume->u.ext2_sb.s_group_desc[j]);
		brelse (p_volume->u.ext2_sb.s_sbh);
                G_free(Buf);
                if (Buf2) G_free(Buf2);
                G_free((pchar)p_volume);
		kernel_printf ("EXT2-fs: group descriptors corrupted !");
		return 0;
        }

	for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
		p_volume->u.ext2_sb.s_inode_bitmap_number[i] = 0;
		p_volume->u.ext2_sb.s_inode_bitmap[i] = NULL;
		p_volume->u.ext2_sb.s_block_bitmap_number[i] = 0;
		p_volume->u.ext2_sb.s_block_bitmap[i] = NULL;
	}
	p_volume->u.ext2_sb.s_loaded_inode_bitmaps = 0;
	p_volume->u.ext2_sb.s_loaded_block_bitmaps = 0;
	p_volume->u.ext2_sb.s_db_per_group = db_count;
        p_volume->s_dev = hVPB;

	ext2_setup_super (p_volume, p_volume->u.ext2_sb.s_es);

	if ((rc = G_free(Buf)) != NO_ERROR) {
		fs_log("erreur G_free");                    /*** FSH_INTERR() ***/
	} /* end if */
	if (Buf2 != 0) {
		if ((rc = G_free(Buf2)) != NO_ERROR) {
			fs_log("erreur G_free");                    /*** FSH_INTERR() ***/
		} /* end if */
	}
	return p_volume;
}

int free_volume (struct super_block **psb) {
    struct super_block *sb = *psb;
    UINT32              i;
    int                 rc;

    for (i = 0 ; i < NB_MAX_SEL ; i++) {
        if (sb->GDTsels[i]) {
            if ((rc = G_free((char *)(sb->GDTsels[i]))) != NO_ERROR) {
                kernel_printf("free_volume - Error G_free");
            }
        }
    }
    if ((rc = G_free((char *)sb)) != NO_ERROR) {
        kernel_printf("free_volume - Error G_free(sb)");
    }
    kernel_printf("free_volume() OK");
    return NO_ERROR;
}

struct super_block * getvolume(unsigned short hVPB)
{
    struct vpfsi _FS_PTR pvpfsi;
    struct vpfsd _FS_PTR pvpfsd;

    if (!hVPB) {
	FSH_INTERR("getvolume() hVPB = 0", sizeof("getvolume() hVPB = 0"));
    }
    FSH_GETVOLPARM(hVPB, &pvpfsi, &pvpfsd);

    return ((hvolume _FS_PTR)pvpfsd)->p_volume;
}


int sync_volume(struct super_block *sb) {
    struct buffer_head *bh;
    long nb_written_total = 0;
    long nb_written = -1;

#if 0
    struct inode       *inode;
    inode = sb->LRU_freevinodes;

    while (inode) {
        if ((inode->i_dirt) && (inode->i_ino != ~0)) {
            kernel_printf("\tsync_volume() - Writing free dirty inode %lu", inode->i_ino);
            ext2_write_inode(inode);
        }
        inode = inode->pnext;
    }

    inode = sb->usedvinodes;

    while (inode) {
        if ((inode->i_dirt) && (inode->i_ino != ~0)) {
            kernel_printf("\tsync_volume() - Writing used dirty inode %lu", inode->i_ino);
            ext2_write_inode(inode);
        }
        inode = inode->pnext;
    }
#endif
    //
    // We do this loop because while waiting for a write operation to complete, the buffer
    // chain could have been modified (for instance by ext2_lw.exe)
    //
    while (nb_written) {
        nb_written = 0;
    if (sb->nusedbufs) {
        bh = sb->usedbuffers;

        while (bh) {
            if ((bh->b_dirt) && (bh->b_blocknr != ~0)) {
//                kernel_printf("\tsync_volume() - Writing used dirty disk block %lu", bh->b_blocknr);
                ll_rw_block(WRITE, 1, &bh);
                nb_written ++;
            }
            bh = bh->pnext;
        }
    }
    if (sb->nfreebufs) {
        bh = sb->LRU_freebuffers;
        while (bh) {
            if ((bh->b_dirt) && (bh->b_blocknr != ~0)) {
//                kernel_printf("\tsync_volume() - Writing free dirty disk block %lu", bh->b_blocknr);
                ll_rw_block(WRITE, 1, &bh);
                nb_written ++;
            }
            bh = bh->pnext;
        }
    }
    nb_written_total += nb_written;
    kernel_printf("sync_volume() - wrote %lu dirty buffers", nb_written);
    }
    kernel_printf("sync_volume() - total dirty buffers written is %lu", nb_written_total);
    return NO_ERROR;
}



void __wait_on_super(struct super_block * sb)
{
    cli();
    while (sb->s_lock) {
        FS_DevHelp_ProcBlock((unsigned long)(&(sb->s_wait)));
        cli();
    }
    sti();
}


int lazy_write(struct super_block *sb) {
    struct buffer_head *bh, *tmp;
    long                nb_written = 0;
    long                nb_max = (sb->nbufs / 10 > 10 ? sb->nbufs / 10 : 10);

    bh = sb->LRU_freebuffers;
    while ((bh) && (nb_written < nb_max)) {
        if ((bh->b_dirt) && (bh->b_blocknr != ~0)) {
            tmp = getblk(sb->s_dev, bh->b_blocknr, sb->s_blocksize);
            ll_rw_block(WRITE, 1, &tmp);
	    FSH_YIELD();
	    brelse(tmp);
            bh = sb->LRU_freebuffers;
	    nb_written ++;
        } else {
            bh = bh->pnext;
        }
    }
    kernel_printf("lazy_write() - Wrote %lu buffers", nb_written);
    return NO_ERROR;
}

int Check_Ext2fs_magic(struct vpfsi *pvpfsi, unsigned short hVPB) {
    int   nb_sec;
    int   rc;
    char *Buf;
    struct ext2_super_block *es;
    int found;

    //
    // Allocates a temporary buffer
    //
    if ((Buf = G_malloc(BLOCK_SIZE)) == 0) {
	kernel_printf("Check_Ext2fs_magic : G_malloc returned NULL");
        return 0;
    } /* end if */

    //
    // Reads disk block 1 (with blocksize = 1024)
    //
    nb_sec = BLOCK_SIZE / pvpfsi->vpi_bsize;
    if ((rc = FSH_DOVOLIO(
                          DVIO_OPREAD,
                          DVIO_ALLFAIL | DVIO_ALLABORT | DVIO_ALLRETRY,
                          hVPB,
                          Buf,
                          &nb_sec,
                          nb_sec		// Logical block 1
                         )) != NO_ERROR) {
        kernel_printf("Check_Ext2fs_magic() - FSH_DOVOLIO returned %d", rc);
        G_free(Buf);
        return 0;
    } /* end if */

    es = (struct ext2_super_block *)Buf;
    if (es->s_magic == EXT2_SUPER_MAGIC) {
        kernel_printf("ext2 signature found in superblock (hVPB = 0x%04X)", hVPB);
        found = 1;
    } else {
        kernel_printf("ext2 signature NOT found in superblock (hVPB = 0x%04X)", hVPB);
        found = 0;
    }

    if ((rc = G_free(Buf)) != NO_ERROR) {
	kernel_printf("Check_Ext2fs_magic : G_free returned %d", rc);
    }

    return found;
}



[ RETURN TO DIRECTORY ]