// // $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 // From the "Developer Connection Device Driver Kit" version 2.0 #include #include #include #include #include #include #include #include #include #include #include #include /* Prototypes des fonctions de log.c */ #include /* 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; }