diff --git a/sys/gnu/ext2fs/ext2_bitmap.c b/sys/gnu/ext2fs/ext2_bitmap.c new file mode 100644 index 000000000000..8b9b5d233064 --- /dev/null +++ b/sys/gnu/ext2fs/ext2_bitmap.c @@ -0,0 +1,26 @@ +/* + * linux/fs/ext2/bitmap.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include + +static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + +unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) +{ + unsigned int i; + unsigned long sum = 0; + + if (!map) + return (0); + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; + return (sum); +} diff --git a/sys/gnu/ext2fs/ext2_fs.h b/sys/gnu/ext2fs/ext2_fs.h index 56a85756f75c..1129d1cf2a51 100644 --- a/sys/gnu/ext2fs/ext2_fs.h +++ b/sys/gnu/ext2fs/ext2_fs.h @@ -1,9 +1,3 @@ -/* - * modified for EXT2FS support in Lites 1.1 - * - * Aug 1995, Godmar Back (gback@cs.utah.edu) - * University of Utah, Department of Computer Science - */ /* * linux/include/linux/ext2_fs.h * @@ -18,45 +12,11 @@ * * Copyright (C) 1991, 1992 Linus Torvalds */ + #ifndef _LINUX_EXT2_FS_H #define _LINUX_EXT2_FS_H -#include - -#ifdef i386 -#if defined(__FreeBSD__) -#include -#else -#include -#endif -#else -#error need processor specific types -#endif - -#define __u32 u_int32_t -#define u32 u_int32_t -#define __u16 u_int16_t -#define __u8 u_int8_t - -#define __s32 int32_t -#define __s16 int16_t -#define __s8 int8_t - -#define umode_t mode_t -#define loff_t off_t - -/* the Linux implementation of EXT2 stores some information about - * an inode in a ext2_inode_info structure which is part of the incore - * inode in Linux - * I decided to use the i_spare[11] fields instead - we'll see how this - * works out - */ - -#define i_block_group i_spare[0] -#define i_next_alloc_block i_spare[1] -#define i_next_alloc_goal i_spare[2] -#define i_prealloc_block i_spare[3] -#define i_prealloc_count i_spare[4] +#include /* * The second extended filesystem constants/structures @@ -96,11 +56,11 @@ /* * Debug code */ -#ifdef EXT2FS_DEBUG +#ifdef EXT2FS_DEBUG # define ext2_debug(f, a...) { \ - printf ("EXT2-fs DEBUG (%s, %d): %s:", \ + printk ("EXT2-fs DEBUG (%s, %d): %s:", \ __FILE__, __LINE__, __FUNCTION__); \ - printf (f, ## a); \ + printk (f, ## a); \ } #else # define ext2_debug(f, a...) /**/ @@ -134,16 +94,19 @@ #define EXT2_MIN_BLOCK_SIZE 1024 #define EXT2_MAX_BLOCK_SIZE 4096 #define EXT2_MIN_BLOCK_LOG_SIZE 10 - -#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) -#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / \ - sizeof (struct ext2_acl_entry)) +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) -#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) - -#define EXT2_INODE_SIZE 128 - /* ought to be sizeof (struct ext2_inode)) */ -#define EXT2_INODES_PER_BLOCK(s) ((s)->s_inodes_per_block) +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10) +#else +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode)) /* * Macro-instructions used to manage fragments @@ -151,8 +114,13 @@ #define EXT2_MIN_FRAG_SIZE 1024 #define EXT2_MAX_FRAG_SIZE 4096 #define EXT2_MIN_FRAG_LOG_SIZE 10 -#define EXT2_FRAG_SIZE(s) ((s)->s_frag_size) -#define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) +#ifdef __KERNEL__ +# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) +#else +# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) +#endif /* * ACL structures @@ -203,9 +171,15 @@ struct ext2_group_desc /* * Macro-instructions used to manage group descriptors */ -#define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) -#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) -#define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +#ifdef __KERNEL__ +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) +# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) +#else +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif /* * Constants relative to the data blocks @@ -215,7 +189,6 @@ struct ext2_group_desc #define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) #define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) #define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) -#define EXT2_MAXSYMLINKLEN (EXT2_N_BLOCKS * sizeof (__u32)) /* * Inode flags @@ -236,6 +209,84 @@ struct ext2_group_desc #define EXT2_IOC_GETVERSION _IOR('v', 1, long) #define EXT2_IOC_SETVERSION _IOW('v', 2, long) +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + __u32 i_version; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u32 l_i_reserved2[2]; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_reserved2 osd2.linux2.l_i_reserved2 +#endif + +#ifdef __hurd__ +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author +#endif + +#ifdef __masix__ +#define i_reserved1 osd1.masix1.m_i_reserved1 +#define i_frag osd2.masix2.m_i_frag +#define i_fsize osd2.masix2.m_i_fsize +#define i_reserved2 osd2.masix2.m_i_reserved2 +#endif + /* * File system states */ @@ -337,4 +388,118 @@ struct ext2_dir_entry { #define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ~EXT2_DIR_ROUND) +#ifdef __KERNEL__ +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in but none of the + * ext2 source programs needs to include it so they are duplicated here. + */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define NORET_TYPE __volatile__ +# define ATTRIB_NORET /**/ +# define NORET_AND /**/ +#else +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, +#endif + +/* acl.c */ +extern int ext2_permission (struct inode *, int); + +/* balloc.c */ +extern int ext2_new_block (struct super_block *, unsigned long, + __u32 *, __u32 *); +extern void ext2_free_blocks (struct super_block *, unsigned long, + unsigned long); +extern unsigned long ext2_count_free_blocks (struct super_block *); +extern void ext2_check_blocks_bitmap (struct super_block *); + +/* bitmap.c */ +extern unsigned long ext2_count_free (struct buffer_head *, unsigned); + +/* dir.c */ +extern int ext2_check_dir_entry (char *, struct inode *, + struct ext2_dir_entry *, struct buffer_head *, + unsigned long); + +/* file.c */ +extern int ext2_read (struct inode *, struct file *, char *, int); +extern int ext2_write (struct inode *, struct file *, char *, int); + +/* fsync.c */ +extern int ext2_sync_file (struct inode *, struct file *); + +/* ialloc.c */ +extern struct inode * ext2_new_inode (const struct inode *, int); +extern void ext2_free_inode (struct inode *); +extern unsigned long ext2_count_free_inodes (struct super_block *); +extern void ext2_check_inodes_bitmap (struct super_block *); + +/* inode.c */ +extern int ext2_bmap (struct inode *, int); + +extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *); +extern struct buffer_head * ext2_bread (struct inode *, int, int, int *); + +extern int ext2_getcluster (struct inode * inode, long block); +extern void ext2_read_inode (struct inode *); +extern void ext2_write_inode (struct inode *); +extern void ext2_put_inode (struct inode *); +extern int ext2_sync_inode (struct inode *); +extern void ext2_discard_prealloc (struct inode *); + +/* ioctl.c */ +extern int ext2_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); + +/* namei.c */ +extern void ext2_release (struct inode *, struct file *); +extern int ext2_lookup (struct inode *,const char *, int, struct inode **); +extern int ext2_create (struct inode *,const char *, int, int, + struct inode **); +extern int ext2_mkdir (struct inode *, const char *, int, int); +extern int ext2_rmdir (struct inode *, const char *, int); +extern int ext2_unlink (struct inode *, const char *, int); +extern int ext2_symlink (struct inode *, const char *, int, const char *); +extern int ext2_link (struct inode *, struct inode *, const char *, int); +extern int ext2_mknod (struct inode *, const char *, int, int, int); +extern int ext2_rename (struct inode *, const char *, int, + struct inode *, const char *, int); + +/* super.c */ +extern void ext2_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void ext2_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); +extern void ext2_warning (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void ext2_put_super (struct super_block *); +extern void ext2_write_super (struct super_block *); +extern int ext2_remount (struct super_block *, int *, char *); +extern struct super_block * ext2_read_super (struct super_block *,void *,int); +extern void ext2_statfs (struct super_block *, struct statfs *); + +/* truncate.c */ +extern void ext2_truncate (struct inode *); + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern struct inode_operations ext2_dir_inode_operations; + +/* file.c */ +extern struct inode_operations ext2_file_inode_operations; + +/* symlink.c */ +extern struct inode_operations ext2_symlink_inode_operations; + +#endif /* __KERNEL__ */ + #endif /* _LINUX_EXT2_FS_H */ diff --git a/sys/gnu/ext2fs/ext2_fs_i.h b/sys/gnu/ext2fs/ext2_fs_i.h index 800b2d404024..f3eca4480a1b 100644 --- a/sys/gnu/ext2fs/ext2_fs_i.h +++ b/sys/gnu/ext2fs/ext2_fs_i.h @@ -1,15 +1,3 @@ -/* - * added for EXT2FS support in Lites 1.1 - * - * Aug 1995, Godmar Back (gback@cs.utah.edu) - * University of Utah, Department of Computer Science - * - * Note that this started out to be ext2_fs_i.h. In reality it - * doesn't have anything to do with. I put the declaration of - * the on disk ext2 format here from ext2_fs.h because this is - * something that would name clash with other stuff. - * This is used only in ext2_inode_cnv.c - */ /* * linux/include/linux/ext2_fs_i.h * @@ -25,62 +13,28 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#ifndef _EXT2_FS_I -#define _EXT2_FS_I +#ifndef _LINUX_EXT2_FS_I +#define _LINUX_EXT2_FS_I /* - * Structure of an inode on the disk + * second extended file system inode data in memory */ -struct ext2_inode { - __u16 i_mode; /* File mode */ - __u16 i_uid; /* Owner Uid */ - __u32 i_size; /* Size in bytes */ - __u32 i_atime; /* Access time */ - __u32 i_ctime; /* Creation time */ - __u32 i_mtime; /* Modification time */ - __u32 i_dtime; /* Deletion Time */ - __u16 i_gid; /* Group Id */ - __u16 i_links_count; /* Links count */ - __u32 i_blocks; /* Blocks count */ - __u32 i_flags; /* File flags */ - union { - struct { - __u32 l_i_reserved1; - } linux1; - struct { - __u32 h_i_translator; - } hurd1; - struct { - __u32 m_i_reserved1; - } masix1; - } osd1; /* OS dependent 1 */ - __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ - __u32 i_version; /* File version (for NFS) */ - __u32 i_file_acl; /* File ACL */ - __u32 i_dir_acl; /* Directory ACL */ - __u32 i_faddr; /* Fragment address */ - union { - struct { - __u8 l_i_frag; /* Fragment number */ - __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; - __u32 l_i_reserved2[2]; - } linux2; - struct { - __u8 h_i_frag; /* Fragment number */ - __u8 h_i_fsize; /* Fragment size */ - __u16 h_i_mode_high; - __u16 h_i_uid_high; - __u16 h_i_gid_high; - __u32 h_i_author; - } hurd2; - struct { - __u8 m_i_frag; /* Fragment number */ - __u8 m_i_fsize; /* Fragment size */ - __u16 m_pad1; - __u32 m_i_reserved2[2]; - } masix2; - } osd2; /* OS dependent 2 */ +struct ext2_inode_info { + __u32 i_data[15]; + __u32 i_flags; + __u32 i_faddr; + __u8 i_frag_no; + __u8 i_frag_size; + __u16 i_osync; + __u32 i_file_acl; + __u32 i_dir_acl; + __u32 i_dtime; + __u32 i_version; + __u32 i_block_group; + __u32 i_next_alloc_block; + __u32 i_next_alloc_goal; + __u32 i_prealloc_block; + __u32 i_prealloc_count; }; -#endif /* _EXT2_FS_I */ +#endif /* _LINUX_EXT2_FS_I */ diff --git a/sys/gnu/ext2fs/ext2_fs_sb.h b/sys/gnu/ext2fs/ext2_fs_sb.h index f475ce279d82..685efeb348f4 100644 --- a/sys/gnu/ext2fs/ext2_fs_sb.h +++ b/sys/gnu/ext2fs/ext2_fs_sb.h @@ -1,9 +1,3 @@ -/* - * modified for EXT2FS support in Lites 1.1 - * - * Aug 1995, Godmar Back (gback@cs.utah.edu) - * University of Utah, Department of Computer Science - */ /* * linux/include/linux/ext2_fs_sb.h * @@ -30,11 +24,6 @@ #define EXT2_MAX_GROUP_LOADED 8 -#if defined(LITES) || defined(__FreeBSD__) -#define buffer_head buf -#define MAXMNTLEN 512 -#endif - /* * second extended-fs super-block data in memory */ @@ -59,29 +48,11 @@ struct ext2_sb_info { unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED]; struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED]; int s_rename_lock; -#if !defined(LITES) && !defined(__FreeBSD__) struct wait_queue * s_rename_wait; -#endif unsigned long s_mount_opt; unsigned short s_resuid; unsigned short s_resgid; unsigned short s_mount_state; -#if defined(LITES) || defined(__FreeBSD__) - /* - stuff that FFS keeps in its super block or that linux - has in its non-ext2 specific super block and which is - generally considered useful - */ - unsigned long s_blocksize; - unsigned long s_blocksize_bits; - unsigned int s_bshift; /* = log2(s_blocksize) */ - quad_t s_qbmask; /* = s_blocksize - 1 */ - unsigned int s_fsbtodb; /* shift to get disk block */ - char s_rd_only; /* read-only */ - char s_dirt; /* fs modified flag */ - - char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ -#endif }; #endif /* _LINUX_EXT2_FS_SB */ diff --git a/sys/gnu/ext2fs/ext2_linux_balloc.c b/sys/gnu/ext2fs/ext2_linux_balloc.c index 25b98913d706..c476fa2b256c 100644 --- a/sys/gnu/ext2fs/ext2_linux_balloc.c +++ b/sys/gnu/ext2fs/ext2_linux_balloc.c @@ -1,9 +1,3 @@ -/* - * modified for Lites 1.1 - * - * Aug 1995, Godmar Back (gback@cs.utah.edu) - * University of Utah, Department of Computer Science - */ /* * linux/fs/ext2/balloc.c * @@ -15,6 +9,10 @@ * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 */ +/* + * balloc.c contains the blocks allocation and deallocation routines + */ + /* * The free blocks are managed by bitmaps. A file system contains several * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap @@ -26,53 +24,61 @@ * when a file system is mounted (see ext2_read_super). */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef i386 -#include -#else -#error Provide an bitops.h file, please ! -#endif - -unsigned long ext2_count_free __P((struct buffer_head *, unsigned int)); +#include #define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) -/* got rid of get_group_desc since it can already be found in - * ext2_linux_ialloc.c - */ +static struct ext2_group_desc * get_group_desc (struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) +{ + unsigned long group_desc; + unsigned long desc; + struct ext2_group_desc * gdp; -static void read_block_bitmap (struct mount * mp, + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "get_group_desc", + "block_group >= groups_count - " + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + if (!sb->u.ext2_sb.s_group_desc[group_desc]) + ext2_panic (sb, "get_group_desc", + "Group descriptor not loaded - " + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.ext2_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +static void read_block_bitmap (struct super_block * sb, unsigned int block_group, unsigned long bitmap_nr) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; struct ext2_group_desc * gdp; struct buffer_head * bh; - int error; - gdp = get_group_desc (mp, block_group, NULL); - if(error = bread (VFSTOUFS(mp)->um_devvp, - fsbtodb(sb, gdp->bg_block_bitmap),sb->s_blocksize, NOCRED, &bh)) - panic ( "read_block_bitmap: " + gdp = get_group_desc (sb, block_group, NULL); + bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize); + if (!bh) + ext2_panic (sb, "read_block_bitmap", "Cannot read block bitmap - " "block_group = %d, block_bitmap = %lu", block_group, (unsigned long) gdp->bg_block_bitmap); - sb->s_block_bitmap_number[bitmap_nr] = block_group; - sb->s_block_bitmap[bitmap_nr] = bh; + sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; + sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; } /* @@ -86,86 +92,82 @@ static void read_block_bitmap (struct mount * mp, * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, * this function reads the bitmap without maintaining a LRU cache. */ -static int load__block_bitmap (struct mount * mp, +static int load__block_bitmap (struct super_block * sb, unsigned int block_group) { int i, j; - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; unsigned long block_bitmap_number; struct buffer_head * block_bitmap; - int error; - if (block_group >= sb->s_groups_count) - panic ( "load_block_bitmap: " + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "load_block_bitmap", "block_group >= groups_count - " "block_group = %d, groups_count = %lu", - block_group, sb->s_groups_count); + block_group, sb->u.ext2_sb.s_groups_count); - if (sb->s_groups_count <= EXT2_MAX_GROUP_LOADED) { - if (sb->s_block_bitmap[block_group]) { - if (sb->s_block_bitmap_number[block_group] != + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { + if (sb->u.ext2_sb.s_block_bitmap[block_group]) { + if (sb->u.ext2_sb.s_block_bitmap_number[block_group] != block_group) - panic ( "load_block_bitmap: " + ext2_panic (sb, "load_block_bitmap", "block_group != block_bitmap_number"); else return block_group; } else { - read_block_bitmap (mp, block_group, block_group); + read_block_bitmap (sb, block_group, block_group); return block_group; } } - for (i = 0; i < sb->s_loaded_block_bitmaps && - sb->s_block_bitmap_number[i] != block_group; i++) + for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps && + sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++) ; - if (i < sb->s_loaded_block_bitmaps && - sb->s_block_bitmap_number[i] == block_group) { - block_bitmap_number = sb->s_block_bitmap_number[i]; - block_bitmap = sb->s_block_bitmap[i]; + if (i < sb->u.ext2_sb.s_loaded_block_bitmaps && + sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) { + block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i]; + block_bitmap = sb->u.ext2_sb.s_block_bitmap[i]; for (j = i; j > 0; j--) { - sb->s_block_bitmap_number[j] = - sb->s_block_bitmap_number[j - 1]; - sb->s_block_bitmap[j] = - sb->s_block_bitmap[j - 1]; + sb->u.ext2_sb.s_block_bitmap_number[j] = + sb->u.ext2_sb.s_block_bitmap_number[j - 1]; + sb->u.ext2_sb.s_block_bitmap[j] = + sb->u.ext2_sb.s_block_bitmap[j - 1]; } - sb->s_block_bitmap_number[0] = block_bitmap_number; - sb->s_block_bitmap[0] = block_bitmap; + sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number; + sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap; } else { - if (sb->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED) - sb->s_loaded_block_bitmaps++; + if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED) + sb->u.ext2_sb.s_loaded_block_bitmaps++; else - brelse (sb->s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]); - for (j = sb->s_loaded_block_bitmaps - 1; j > 0; j--) { - sb->s_block_bitmap_number[j] = - sb->s_block_bitmap_number[j - 1]; - sb->s_block_bitmap[j] = - sb->s_block_bitmap[j - 1]; + brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { + sb->u.ext2_sb.s_block_bitmap_number[j] = + sb->u.ext2_sb.s_block_bitmap_number[j - 1]; + sb->u.ext2_sb.s_block_bitmap[j] = + sb->u.ext2_sb.s_block_bitmap[j - 1]; } - read_block_bitmap (mp, block_group, 0); + read_block_bitmap (sb, block_group, 0); } return 0; } -static inline int load_block_bitmap (struct mount * mp, +static inline int load_block_bitmap (struct super_block * sb, unsigned int block_group) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; - if (sb->s_loaded_block_bitmaps > 0 && - sb->s_block_bitmap_number[0] == block_group) + if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 && + sb->u.ext2_sb.s_block_bitmap_number[0] == block_group) return 0; - if (sb->s_groups_count <= EXT2_MAX_GROUP_LOADED && - sb->s_block_bitmap_number[block_group] == block_group && - sb->s_block_bitmap[block_group]) + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && + sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group && + sb->u.ext2_sb.s_block_bitmap[block_group]) return block_group; - return load__block_bitmap (mp, block_group); + return load__block_bitmap (sb, block_group); } -void ext2_free_blocks (struct mount * mp, unsigned long block, +void ext2_free_blocks (struct super_block * sb, unsigned long block, unsigned long count) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; struct buffer_head * bh; struct buffer_head * bh2; unsigned long block_group; @@ -173,51 +175,52 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, unsigned long i; int bitmap_nr; struct ext2_group_desc * gdp; - struct ext2_super_block * es = sb->s_es; + struct ext2_super_block * es; if (!sb) { - printf ("ext2_free_blocks: nonexistent device"); + printk ("ext2_free_blocks: nonexistent device"); return; } - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (sb); + es = sb->u.ext2_sb.s_es; if (block < es->s_first_data_block || (block + count) > es->s_blocks_count) { - printf ( "ext2_free_blocks: " + ext2_error (sb, "ext2_free_blocks", "Freeing blocks not in datazone - " "block = %lu, count = %lu", block, count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); return; } - ext2_debug ("freeing blocks %lu to %lu\n", block, block+count-1); + ext2_debug ("freeing block %lu\n", block); block_group = (block - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb); bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb); if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) - panic ( "ext2_free_blocks: " + ext2_panic (sb, "ext2_free_blocks", "Freeing blocks across group boundary - " "Block = %lu, count = %lu", block, count); - bitmap_nr = load_block_bitmap (mp, block_group); - bh = sb->s_block_bitmap[bitmap_nr]; - gdp = get_group_desc (mp, block_group, &bh2); + bitmap_nr = load_block_bitmap (sb, block_group); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + gdp = get_group_desc (sb, block_group, &bh2); - if (/* test_opt (sb, CHECK_STRICT) && assume always strict ! */ + if (test_opt (sb, CHECK_STRICT) && (in_range (gdp->bg_block_bitmap, block, count) || in_range (gdp->bg_inode_bitmap, block, count) || in_range (block, gdp->bg_inode_table, - sb->s_itb_per_group) || + sb->u.ext2_sb.s_itb_per_group) || in_range (block + count - 1, gdp->bg_inode_table, - sb->s_itb_per_group))) - panic ( "ext2_free_blocks: " + sb->u.ext2_sb.s_itb_per_group))) + ext2_panic (sb, "ext2_free_blocks", "Freeing blocks in system zones - " "Block = %lu, count = %lu", block, count); for (i = 0; i < count; i++) { if (!clear_bit (bit + i, bh->b_data)) - printf ("ext2_free_blocks: " + ext2_warning (sb, "ext2_free_blocks", "bit already cleared for block %lu", block); else { @@ -225,17 +228,17 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, es->s_free_blocks_count++; } } + + mark_buffer_dirty(bh2, 1); + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); - mark_buffer_dirty(bh2); mark_buffer_dirty(bh, 1); -/**** if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } -****/ sb->s_dirt = 1; - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); return; } @@ -246,29 +249,37 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, * each block group the search first looks for an entire free byte in the block * bitmap, and then for any free bit if that fails. */ -int ext2_new_block (struct mount * mp, unsigned long goal, - long * prealloc_count, - long * prealloc_block) +int ext2_new_block (struct super_block * sb, unsigned long goal, + u32 * prealloc_count, + u32 * prealloc_block) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; struct buffer_head * bh; struct buffer_head * bh2; char * p, * r; int i, j, k, tmp; + unsigned long lmap; int bitmap_nr; struct ext2_group_desc * gdp; - struct ext2_super_block * es = sb->s_es; + struct ext2_super_block * es; #ifdef EXT2FS_DEBUG static int goal_hits = 0, goal_attempts = 0; #endif if (!sb) { - printf ("ext2_new_block: nonexistent device"); + printk ("ext2_new_block: nonexistent device"); + return 0; + } + lock_super (sb); + es = sb->u.ext2_sb.s_es; + if (es->s_free_blocks_count <= es->s_r_blocks_count && + (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) && + (sb->u.ext2_sb.s_resgid == 0 || + !in_group_p (sb->u.ext2_sb.s_resgid)))) { + unlock_super (sb); return 0; } - lock_super (VFSTOUFS(mp)->um_devvp); - ext2_debug ("goal=%lu.\n", goal); + ext2_debug ("goal=%lu.\n", goal); repeat: /* @@ -277,17 +288,17 @@ repeat: if (goal < es->s_first_data_block || goal >= es->s_blocks_count) goal = es->s_first_data_block; i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb); - gdp = get_group_desc (mp, i, &bh2); + gdp = get_group_desc (sb, i, &bh2); if (gdp->bg_free_blocks_count > 0) { j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb)); #ifdef EXT2FS_DEBUG if (j) goal_attempts++; #endif - bitmap_nr = load_block_bitmap (mp, i); - bh = sb->s_block_bitmap[bitmap_nr]; + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; - ext2_debug ("goal is at %d:%d.\n", i, j); + ext2_debug ("goal is at %d:%d.\n", i, j); if (!test_bit(j, bh->b_data)) { #ifdef EXT2FS_DEBUG @@ -299,16 +310,22 @@ repeat: if (j) { /* * The goal was occupied; search forward for a free - * block within the next XX blocks. - * - * end_goal is more or less random, but it has to be - * less than EXT2_BLOCKS_PER_GROUP. Aligning up to the - * next 64-bit boundary is simple.. + * block within the next 32 blocks */ - int end_goal = (j + 63) & ~63; - j = find_next_zero_bit(bh->b_data, end_goal, j); - if (j < end_goal) - goto got_block; + lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >> + ((j & 31) + 1)); + if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32) + lmap |= (((unsigned long *) bh->b_data)[(j >> 5) + 1]) << + (31 - (j & 31)); + else + lmap |= 0xffffffff << (31 - (j & 31)); + if (lmap != 0xffffffffl) { + k = ffz(lmap) + 1; + if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) { + j += k; + goto got_block; + } + } } ext2_debug ("Bit not found near goal\n"); @@ -338,38 +355,37 @@ repeat: } } - ext2_debug ("Bit not found in block group %d.\n", i); + ext2_debug ("Bit not found in block group %d.\n", i); /* * Now search the rest of the groups. We assume that * i and gdp correctly point to the last group visited. */ - for (k = 0; k < sb->s_groups_count; k++) { + for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) { i++; - if (i >= sb->s_groups_count) + if (i >= sb->u.ext2_sb.s_groups_count) i = 0; - gdp = get_group_desc (mp, i, &bh2); + gdp = get_group_desc (sb, i, &bh2); if (gdp->bg_free_blocks_count > 0) break; } - if (k >= sb->s_groups_count) { - unlock_super (VFSTOUFS(mp)->um_devvp); + if (k >= sb->u.ext2_sb.s_groups_count) { + unlock_super (sb); return 0; } - bitmap_nr = load_block_bitmap (mp, i); - bh = sb->s_block_bitmap[bitmap_nr]; + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3); j = (r - bh->b_data) << 3; - if (j < EXT2_BLOCKS_PER_GROUP(sb)) goto search_back; else j = find_first_zero_bit ((unsigned long *) bh->b_data, EXT2_BLOCKS_PER_GROUP(sb)); if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { - printf ( "ext2_new_block: " - "Free blocks count corrupted for block group %d", i); - unlock_super (VFSTOUFS(mp)->um_devvp); + ext2_error (sb, "ext2_new_block", + "Free blocks count corrupted for block group %d", i); + unlock_super (sb); return 0; } @@ -387,17 +403,17 @@ got_block: tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; - if (/* test_opt (sb, CHECK_STRICT) && we are always strict. */ + if (test_opt (sb, CHECK_STRICT) && (tmp == gdp->bg_block_bitmap || tmp == gdp->bg_inode_bitmap || - in_range (tmp, gdp->bg_inode_table, sb->s_itb_per_group))) - panic ( "ext2_new_block: " + in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) + ext2_panic (sb, "ext2_new_block", "Allocating block in system zone - " - "%dth block = %u in group %u", j, tmp, i); + "block = %u", tmp); if (set_bit (j, bh->b_data)) { - printf ( "ext2_new_block: " - "bit already set for block %d", j); + ext2_warning (sb, "ext2_new_block", + "bit already set for block %d", j); goto repeat; } @@ -419,26 +435,34 @@ got_block: gdp->bg_free_blocks_count -= *prealloc_count; es->s_free_blocks_count -= *prealloc_count; ext2_debug ("Preallocated a further %lu bits.\n", - *prealloc_count); + *prealloc_count); } #endif j = tmp; - mark_buffer_dirty(bh); -/**** + mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } -****/ + if (j >= es->s_blocks_count) { - printf ( "ext2_new_block: " + ext2_error (sb, "ext2_new_block", "block >= blocks count - " "block_group = %d, block=%d", i, j); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); return 0; } + if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) { + ext2_error (sb, "ext2_new_block", "cannot get block %d", j); + unlock_super (sb); + return 0; + } + memset(bh->b_data, 0, sb->s_blocksize); + bh->b_uptodate = 1; + mark_buffer_dirty(bh, 1); + brelse (bh); ext2_debug ("allocating block %d. " "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); @@ -446,14 +470,14 @@ got_block: gdp->bg_free_blocks_count--; mark_buffer_dirty(bh2, 1); es->s_free_blocks_count--; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); return j; } -unsigned long ext2_count_free_blocks (struct mount * mp) +unsigned long ext2_count_free_blocks (struct super_block * sb) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; #ifdef EXT2FS_DEBUG struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -461,42 +485,40 @@ unsigned long ext2_count_free_blocks (struct mount * mp) struct ext2_group_desc * gdp; int i; - lock_super (VFSTOUFS(mp)->um_devvp); - es = sb->s_es; + lock_super (sb); + es = sb->u.ext2_sb.s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; - for (i = 0; i < sb->s_groups_count; i++) { - gdp = get_group_desc (mp, i, NULL); + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_blocks_count; - bitmap_nr = load_block_bitmap (mp, i); - x = ext2_count_free (sb->s_block_bitmap[bitmap_nr], + bitmap_nr = load_block_bitmap (sb, i); + x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], sb->s_blocksize); - ext2_debug ("group %d: stored = %d, counted = %lu\n", + printk ("group %d: stored = %d, counted = %lu\n", i, gdp->bg_free_blocks_count, x); bitmap_count += x; } - ext2_debug( "stored = %lu, computed = %lu, %lu\n", + printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", es->s_free_blocks_count, desc_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); return bitmap_count; #else - return sb->s_es->s_free_blocks_count; + return sb->u.ext2_sb.s_es->s_free_blocks_count; #endif } - static inline int block_in_use (unsigned long block, - struct ext2_sb_info * sb, + struct super_block * sb, unsigned char * map) { - return test_bit ((block - sb->s_es->s_first_data_block) % + return test_bit ((block - sb->u.ext2_sb.s_es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb), map); } -void ext2_check_blocks_bitmap (struct mount * mp) +void ext2_check_blocks_bitmap (struct super_block * sb) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; struct buffer_head * bh; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -505,78 +527,57 @@ void ext2_check_blocks_bitmap (struct mount * mp) struct ext2_group_desc * gdp; int i, j; - lock_super (VFSTOUFS(mp)->um_devvp); - es = sb->s_es; + lock_super (sb); + es = sb->u.ext2_sb.s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; - desc_blocks = (sb->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / + desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / EXT2_DESC_PER_BLOCK(sb); - for (i = 0; i < sb->s_groups_count; i++) { - gdp = get_group_desc (mp, i, NULL); + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_blocks_count; - bitmap_nr = load_block_bitmap (mp, i); - bh = sb->s_block_bitmap[bitmap_nr]; + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; if (!test_bit (0, bh->b_data)) - printf ( "ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Superblock in group %d is marked free", i); for (j = 0; j < desc_blocks; j++) if (!test_bit (j + 1, bh->b_data)) - printf ("ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Descriptor block #%d in group " "%d is marked free", j, i); if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data)) - printf ("ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Block bitmap for group %d is marked free", i); if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data)) - printf ("ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Inode bitmap for group %d is marked free", i); - for (j = 0; j < sb->s_itb_per_group; j++) + for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++) if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data)) - printf ("ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Block #%d of the inode table in " "group %d is marked free", j, i); x = ext2_count_free (bh, sb->s_blocksize); if (gdp->bg_free_blocks_count != x) - printf ("ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Wrong free blocks count for group %d, " "stored = %d, counted = %lu", i, gdp->bg_free_blocks_count, x); bitmap_count += x; } if (es->s_free_blocks_count != bitmap_count) - printf ("ext2_check_blocks_bitmap: " + ext2_error (sb, "ext2_check_blocks_bitmap", "Wrong free blocks count in super block, " "stored = %lu, counted = %lu", (unsigned long) es->s_free_blocks_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); } - -/* - * this function is taken from - * linux/fs/ext2/bitmap.c - */ - -static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; - -unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) -{ - unsigned int i; - unsigned long sum = 0; - - if (!map) - return (0); - for (i = 0; i < numchars; i++) - sum += nibblemap[map->b_data[i] & 0xf] + - nibblemap[(map->b_data[i] >> 4) & 0xf]; - return (sum); -} - diff --git a/sys/gnu/ext2fs/ext2_linux_ialloc.c b/sys/gnu/ext2fs/ext2_linux_ialloc.c index 62e79387da35..9102d02b2d96 100644 --- a/sys/gnu/ext2fs/ext2_linux_ialloc.c +++ b/sys/gnu/ext2fs/ext2_linux_ialloc.c @@ -1,9 +1,3 @@ -/* - * modified for Lites 1.1 - * - * Aug 1995, Godmar Back (gback@cs.utah.edu) - * University of Utah, Department of Computer Science - */ /* * linux/fs/ext2/ialloc.c * @@ -16,6 +10,10 @@ * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 */ +/* + * ialloc.c contains the inodes allocation and deallocation routines + */ + /* * The free inodes are managed by bitmaps. A file system contains several * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap @@ -27,99 +25,59 @@ * when a file system is mounted (see ext2_read_super). */ -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include -#include -#include -#include -#include -#include -#include -#include +#include -#if (i386) -#include -#else -#error please provide bit operation functions -#endif - -/* this is supposed to mark a buffer dirty on ready for delayed writing - */ -void mark_buffer_dirty(struct buf *bh) -{ - bh->b_flags |= B_DELWRI; - bh->b_flags &= ~(B_READ | B_ERROR); -} - -/* - this should write a buffer immediately w/o releasing it - */ -int ll_w_block(struct buf * bp, int waitfor) -{ - bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); - bp->b_flags |= B_WRITEINPROG; - bp->b_vp->v_numoutput++; -#if defined(__FreeBSD__) - vfs_busy_pages(bp, 1); -#endif - VOP_STRATEGY(bp); - return waitfor ? biowait(bp) : 0; -} - -struct ext2_group_desc * get_group_desc (struct mount * mp, +static struct ext2_group_desc * get_group_desc (struct super_block * sb, unsigned int block_group, struct buffer_head ** bh) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; unsigned long group_desc; unsigned long desc; struct ext2_group_desc * gdp; - if (block_group >= sb->s_groups_count) - panic ("get_group_desc: " + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "get_group_desc", "block_group >= groups_count - " "block_group = %d, groups_count = %lu", - block_group, sb->s_groups_count); + block_group, sb->u.ext2_sb.s_groups_count); group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); desc = block_group % EXT2_DESC_PER_BLOCK(sb); - if (!sb->s_group_desc[group_desc]) - panic ( "get_group_desc:" + if (!sb->u.ext2_sb.s_group_desc[group_desc]) + ext2_panic (sb, "get_group_desc", "Group descriptor not loaded - " "block_group = %d, group_desc = %lu, desc = %lu", block_group, group_desc, desc); gdp = (struct ext2_group_desc *) - sb->s_group_desc[group_desc]->b_data; + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; if (bh) - *bh = sb->s_group_desc[group_desc]; + *bh = sb->u.ext2_sb.s_group_desc[group_desc]; return gdp + desc; } -static void read_inode_bitmap (struct mount * mp, +static void read_inode_bitmap (struct super_block * sb, unsigned long block_group, unsigned int bitmap_nr) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; struct ext2_group_desc * gdp; struct buffer_head * bh; - int error; - gdp = get_group_desc (mp, block_group, NULL); - if (error = bread (VFSTOUFS(mp)->um_devvp, - fsbtodb(sb, gdp->bg_inode_bitmap), - sb->s_blocksize, - NOCRED, &bh)) - panic ( "read_inode_bitmap:" + gdp = get_group_desc (sb, block_group, NULL); + bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize); + if (!bh) + ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap - " "block_group = %lu, inode_bitmap = %lu", block_group, (unsigned long) gdp->bg_inode_bitmap); - sb->s_inode_bitmap_number[bitmap_nr] = block_group; - sb->s_inode_bitmap[bitmap_nr] = bh; + sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; + sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; } /* @@ -133,72 +91,104 @@ static void read_inode_bitmap (struct mount * mp, * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, * this function reads the bitmap without maintaining a LRU cache. */ -static int load_inode_bitmap (struct mount * mp, +static int load_inode_bitmap (struct super_block * sb, unsigned int block_group) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; int i, j; unsigned long inode_bitmap_number; struct buffer_head * inode_bitmap; - if (block_group >= sb->s_groups_count) - panic ("load_inode_bitmap:" + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "load_inode_bitmap", "block_group >= groups_count - " "block_group = %d, groups_count = %lu", - block_group, sb->s_groups_count); - if (sb->s_loaded_inode_bitmaps > 0 && - sb->s_inode_bitmap_number[0] == block_group) + block_group, sb->u.ext2_sb.s_groups_count); + if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 && + sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group) return 0; - if (sb->s_groups_count <= EXT2_MAX_GROUP_LOADED) { - if (sb->s_inode_bitmap[block_group]) { - if (sb->s_inode_bitmap_number[block_group] != - block_group) - panic ( "load_inode_bitmap:" - "block_group != inode_bitmap_number"); + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { + if (sb->u.ext2_sb.s_inode_bitmap[block_group]) { + if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != block_group) + ext2_panic (sb, "load_inode_bitmap", + "block_group != inode_bitmap_number"); else return block_group; } else { - read_inode_bitmap (mp, block_group, block_group); + read_inode_bitmap (sb, block_group, block_group); return block_group; } } - for (i = 0; i < sb->s_loaded_inode_bitmaps && - sb->s_inode_bitmap_number[i] != block_group; + for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps && + sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group; i++) ; - if (i < sb->s_loaded_inode_bitmaps && - sb->s_inode_bitmap_number[i] == block_group) { - inode_bitmap_number = sb->s_inode_bitmap_number[i]; - inode_bitmap = sb->s_inode_bitmap[i]; + if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps && + sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) { + inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i]; + inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i]; for (j = i; j > 0; j--) { - sb->s_inode_bitmap_number[j] = - sb->s_inode_bitmap_number[j - 1]; - sb->s_inode_bitmap[j] = - sb->s_inode_bitmap[j - 1]; + sb->u.ext2_sb.s_inode_bitmap_number[j] = + sb->u.ext2_sb.s_inode_bitmap_number[j - 1]; + sb->u.ext2_sb.s_inode_bitmap[j] = + sb->u.ext2_sb.s_inode_bitmap[j - 1]; } - sb->s_inode_bitmap_number[0] = inode_bitmap_number; - sb->s_inode_bitmap[0] = inode_bitmap; + sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number; + sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap; } else { - if (sb->s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED) - sb->s_loaded_inode_bitmaps++; + if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED) + sb->u.ext2_sb.s_loaded_inode_bitmaps++; else - brelse (sb->s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]); - for (j = sb->s_loaded_inode_bitmaps - 1; j > 0; j--) { - sb->s_inode_bitmap_number[j] = - sb->s_inode_bitmap_number[j - 1]; - sb->s_inode_bitmap[j] = - sb->s_inode_bitmap[j - 1]; + brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) { + sb->u.ext2_sb.s_inode_bitmap_number[j] = + sb->u.ext2_sb.s_inode_bitmap_number[j - 1]; + sb->u.ext2_sb.s_inode_bitmap[j] = + sb->u.ext2_sb.s_inode_bitmap[j - 1]; } - read_inode_bitmap (mp, block_group, 0); + read_inode_bitmap (sb, block_group, 0); } return 0; } +/* + * This function sets the deletion time for the inode + * + * This may be used one day by an 'undelete' program + */ +static void set_inode_dtime (struct inode * inode, + struct ext2_group_desc * gdp) +{ + unsigned long inode_block; + struct buffer_head * bh; + struct ext2_inode * raw_inode; + + inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) / + EXT2_INODES_PER_BLOCK(inode->i_sb)); + bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); + if (!bh) + ext2_panic (inode->i_sb, "set_inode_dtime", + "Cannot load inode table block - " + "inode=%lu, inode_block=%lu", + inode->i_ino, inode_block); + raw_inode = ((struct ext2_inode *) bh->b_data) + + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) % + EXT2_INODES_PER_BLOCK(inode->i_sb)); + raw_inode->i_links_count = 0; + raw_inode->i_dtime = CURRENT_TIME; + mark_buffer_dirty(bh, 1); + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); +} void ext2_free_inode (struct inode * inode) { - struct ext2_sb_info * sb; + struct super_block * sb; struct buffer_head * bh; struct buffer_head * bh2; unsigned long block_group; @@ -209,51 +199,65 @@ void ext2_free_inode (struct inode * inode) if (!inode) return; - + if (!inode->i_dev) { + printk ("ext2_free_inode: inode has no device\n"); + return; + } + if (inode->i_count > 1) { + printk ("ext2_free_inode: inode has count=%d\n", + inode->i_count); + return; + } if (inode->i_nlink) { - printf ("ext2_free_inode: inode has nlink=%d\n", + printk ("ext2_free_inode: inode has nlink=%d\n", inode->i_nlink); return; } - - ext2_debug ("freeing inode %lu\n", inode->i_number); - - sb = inode->i_e2fs; - lock_super (DEVVP(inode)); - if (inode->i_number < EXT2_FIRST_INO || - inode->i_number > sb->s_es->s_inodes_count) { - printf ("free_inode reserved inode or nonexistent inode"); - unlock_super (DEVVP(inode)); + if (!inode->i_sb) { + printk("ext2_free_inode: inode on nonexistent device\n"); return; } - es = sb->s_es; - block_group = (inode->i_number - 1) / EXT2_INODES_PER_GROUP(sb); - bit = (inode->i_number - 1) % EXT2_INODES_PER_GROUP(sb); - bitmap_nr = load_inode_bitmap (ITOV(inode)->v_mount, block_group); - bh = sb->s_inode_bitmap[bitmap_nr]; - if (!clear_bit (bit, bh->b_data)) - printf ( "ext2_free_inode:" - "bit already cleared for inode %lu", inode->i_number); - else { - gdp = get_group_desc (ITOV(inode)->v_mount, block_group, &bh2); - gdp->bg_free_inodes_count++; - if (S_ISDIR(inode->i_mode)) - gdp->bg_used_dirs_count--; - mark_buffer_dirty(bh2); - es->s_free_inodes_count++; + + ext2_debug ("freeing inode %lu\n", inode->i_ino); + + sb = inode->i_sb; + lock_super (sb); + if (inode->i_ino < EXT2_FIRST_INO || + inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (sb, "free_inode", + "reserved inode or nonexistent inode"); + unlock_super (sb); + return; } - mark_buffer_dirty(bh); -/*** XXX + es = sb->u.ext2_sb.s_es; + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb); + bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); + bitmap_nr = load_inode_bitmap (sb, block_group); + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + if (!clear_bit (bit, bh->b_data)) + ext2_warning (sb, "ext2_free_inode", + "bit already cleared for inode %lu", inode->i_ino); + else { + gdp = get_group_desc (sb, block_group, &bh2); + gdp->bg_free_inodes_count++; + if (S_ISDIR(inode->i_mode)) + gdp->bg_used_dirs_count--; + mark_buffer_dirty(bh2, 1); + es->s_free_inodes_count++; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + set_inode_dtime (inode, gdp); + } + mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } -***/ + sb->s_dirt = 1; - unlock_super (DEVVP(inode)); + clear_inode (inode); + unlock_super (sb); } -#if linux /* * This function increments the inode version number * @@ -267,19 +271,20 @@ static void inc_inode_version (struct inode * inode, struct buffer_head * bh; struct ext2_inode * raw_inode; - inode_block = gdp->bg_inode_table + (((inode->i_number - 1) % + inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) / EXT2_INODES_PER_BLOCK(inode->i_sb)); bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); if (!bh) { - printf ("inc_inode_version Cannot load inode table block - " + ext2_error (inode->i_sb, "inc_inode_version", + "Cannot load inode table block - " "inode=%lu, inode_block=%lu\n", - inode->i_number, inode_block); + inode->i_ino, inode_block); inode->u.ext2_i.i_version = 1; return; } raw_inode = ((struct ext2_inode *) bh->b_data) + - (((inode->i_number - 1) % + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) % EXT2_INODES_PER_BLOCK(inode->i_sb)); raw_inode->i_version++; @@ -288,8 +293,6 @@ static void inc_inode_version (struct inode * inode, brelse (bh); } -#endif /* linux */ - /* * There are two policies for allocating an inode. If the new inode is * a directory, then a forward search is made for a block group with both @@ -300,32 +303,31 @@ static void inc_inode_version (struct inode * inode, * For other inodes, search forward from the parent directory\'s block * group to find a free inode. */ -/* - * this functino has been reduced to the actual 'find the inode number' part - */ -ino_t ext2_new_inode (const struct inode * dir, int mode) +struct inode * ext2_new_inode (const struct inode * dir, int mode) { - struct ext2_sb_info * sb; + struct super_block * sb; struct buffer_head * bh; struct buffer_head * bh2; int i, j, avefreei; + struct inode * inode; int bitmap_nr; struct ext2_group_desc * gdp; struct ext2_group_desc * tmp; struct ext2_super_block * es; - if (!dir) - return 0; - sb = dir->i_e2fs; - - lock_super (DEVVP(dir)); - es = sb->s_es; + if (!dir || !(inode = get_empty_inode ())) + return NULL; + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + lock_super (sb); + es = sb->u.ext2_sb.s_es; repeat: - gdp = NULL; i=0; - - if (S_ISDIR(mode)) { + gdp = NULL; i=0; + + if (S_ISDIR(mode)) { avefreei = es->s_free_inodes_count / - sb->s_groups_count; + sb->u.ext2_sb.s_groups_count; /* I am not yet convinced that this next bit is necessary. i = dir->u.ext2_i.i_block_group; for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { @@ -340,8 +342,8 @@ repeat: } */ if (!gdp) { - for (j = 0; j < sb->s_groups_count; j++) { - tmp = get_group_desc(ITOV(dir)->v_mount,j,&bh2); + for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { + tmp = get_group_desc (sb, j, &bh2); if (tmp->bg_free_inodes_count && tmp->bg_free_inodes_count >= avefreei) { if (!gdp || @@ -359,8 +361,8 @@ repeat: /* * Try to place the inode in its parent directory */ - i = dir->i_block_group; - tmp = get_group_desc (ITOV(dir)->v_mount, i, &bh2); + i = dir->u.ext2_i.i_block_group; + tmp = get_group_desc (sb, i, &bh2); if (tmp->bg_free_inodes_count) gdp = tmp; else @@ -369,11 +371,11 @@ repeat: * Use a quadratic hash to find a group with a * free inode */ - for (j = 1; j < sb->s_groups_count; j <<= 1) { + for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) { i += j; - if (i >= sb->s_groups_count) - i -= sb->s_groups_count; - tmp = get_group_desc(ITOV(dir)->v_mount,i,&bh2); + if (i >= sb->u.ext2_sb.s_groups_count) + i -= sb->u.ext2_sb.s_groups_count; + tmp = get_group_desc (sb, i, &bh2); if (tmp->bg_free_inodes_count) { gdp = tmp; break; @@ -384,11 +386,11 @@ repeat: /* * That failed: try linear search for a free inode */ - i = dir->i_block_group + 1; - for (j = 2; j < sb->s_groups_count; j++) { - if (++i >= sb->s_groups_count) + i = dir->u.ext2_i.i_block_group + 1; + for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) { + if (++i >= sb->u.ext2_sb.s_groups_count) i = 0; - tmp = get_group_desc(ITOV(dir)->v_mount,i,&bh2); + tmp = get_group_desc (sb, i, &bh2); if (tmp->bg_free_inodes_count) { gdp = tmp; break; @@ -398,92 +400,127 @@ repeat: } if (!gdp) { - unlock_super (DEVVP(dir)); - return 0; + unlock_super (sb); + iput(inode); + return NULL; } - bitmap_nr = load_inode_bitmap (ITOV(dir)->v_mount, i); - bh = sb->s_inode_bitmap[bitmap_nr]; + bitmap_nr = load_inode_bitmap (sb, i); + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; if ((j = find_first_zero_bit ((unsigned long *) bh->b_data, EXT2_INODES_PER_GROUP(sb))) < EXT2_INODES_PER_GROUP(sb)) { if (set_bit (j, bh->b_data)) { - printf ( "ext2_new_inode:" + ext2_warning (sb, "ext2_new_inode", "bit already set for inode %d", j); goto repeat; } -/* Linux now does the following: mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } -*/ - mark_buffer_dirty(bh); } else { if (gdp->bg_free_inodes_count != 0) { - printf ( "ext2_new_inode:" + ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", i); - unlock_super (DEVVP(dir)); - return 0; + unlock_super (sb); + iput (inode); + return NULL; } goto repeat; } j += i * EXT2_INODES_PER_GROUP(sb) + 1; if (j < EXT2_FIRST_INO || j > es->s_inodes_count) { - printf ( "ext2_new_inode:" + ext2_error (sb, "ext2_new_inode", "reserved inode or inode > inodes count - " "block_group = %d,inode=%d", i, j); - unlock_super (DEVVP(dir)); - return 0; + unlock_super (sb); + iput (inode); + return NULL; } gdp->bg_free_inodes_count--; if (S_ISDIR(mode)) gdp->bg_used_dirs_count++; - mark_buffer_dirty(bh2); + mark_buffer_dirty(bh2, 1); es->s_free_inodes_count--; - /* mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); */ + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; - unlock_super (DEVVP(dir)); - return j; + inode->i_mode = mode; + inode->i_sb = sb; + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->fsuid; + if (test_opt (sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->fsgid; + inode->i_dirt = 1; + inode->i_ino = j; + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags; + if (S_ISLNK(mode)) + inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL | EXT2_APPEND_FL); + inode->u.ext2_i.i_faddr = 0; + inode->u.ext2_i.i_frag_no = 0; + inode->u.ext2_i.i_frag_size = 0; + inode->u.ext2_i.i_file_acl = 0; + inode->u.ext2_i.i_dir_acl = 0; + inode->u.ext2_i.i_dtime = 0; + inode->u.ext2_i.i_block_group = i; + inode->i_op = NULL; + if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) + inode->i_flags |= MS_SYNCHRONOUS; + insert_inode_hash(inode); + inc_inode_version (inode, gdp, mode); + + ext2_debug ("allocating inode %lu\n", inode->i_ino); + + unlock_super (sb); + return inode; } -unsigned long ext2_count_free_inodes (struct mount * mp) +unsigned long ext2_count_free_inodes (struct super_block * sb) { #ifdef EXT2FS_DEBUG - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; int bitmap_nr; struct ext2_group_desc * gdp; int i; - lock_super (VFSTOUFS(mp)->um_devvp); - es = sb->s_es; + lock_super (sb); + es = sb->u.ext2_sb.s_es; desc_count = 0; bitmap_count = 0; gdp = NULL; - for (i = 0; i < sb->s_groups_count; i++) { - gdp = get_group_desc (mp, i, NULL); + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); desc_count += gdp->bg_free_inodes_count; - bitmap_nr = load_inode_bitmap (mp, i); - x = ext2_count_free (sb->s_inode_bitmap[bitmap_nr], + bitmap_nr = load_inode_bitmap (sb, i); + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], EXT2_INODES_PER_GROUP(sb) / 8); - ext2_debug ("group %d: stored = %d, counted = %lu\n", + printk ("group %d: stored = %d, counted = %lu\n", i, gdp->bg_free_inodes_count, x); bitmap_count += x; } - ext2_debug("stored = %lu, computed = %lu, %lu\n", + printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", es->s_free_inodes_count, desc_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (sb); return desc_count; #else - return VFSTOUFS(mp)->um_e2fsb->s_free_inodes_count; + return sb->u.ext2_sb.s_es->s_free_inodes_count; #endif } -#ifdef LATER -void ext2_check_inodes_bitmap (struct mount * mp) +void ext2_check_inodes_bitmap (struct super_block * sb) { struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -503,18 +540,16 @@ void ext2_check_inodes_bitmap (struct mount * mp) x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], EXT2_INODES_PER_GROUP(sb) / 8); if (gdp->bg_free_inodes_count != x) - printf ( "ext2_check_inodes_bitmap:" + ext2_error (sb, "ext2_check_inodes_bitmap", "Wrong free inodes count in group %d, " "stored = %d, counted = %lu", i, gdp->bg_free_inodes_count, x); bitmap_count += x; } if (es->s_free_inodes_count != bitmap_count) - printf ( "ext2_check_inodes_bitmap:" + ext2_error (sb, "ext2_check_inodes_bitmap", "Wrong free inodes count in super block, " "stored = %lu, counted = %lu", (unsigned long) es->s_free_inodes_count, bitmap_count); unlock_super (sb); } -#endif - diff --git a/sys/gnu/ext2fs/ext2_super.c b/sys/gnu/ext2fs/ext2_super.c new file mode 100644 index 000000000000..b73cc521cb37 --- /dev/null +++ b/sys/gnu/ext2fs/ext2_super.c @@ -0,0 +1,780 @@ +/* + * linux/fs/ext2/super.c + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static char error_buf[1024]; + +void ext2_error (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + if (test_opt (sb, ERRORS_PANIC) || + (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC && + !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO))) + panic ("EXT2-fs panic (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf); + printk (KERN_CRIT "EXT2-fs error (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf); + if (test_opt (sb, ERRORS_RO) || + (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO && + !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) { + printk ("Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + } +} + +NORET_TYPE void ext2_panic (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + panic ("EXT2-fs panic (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf); +} + +void ext2_warning (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + va_list args; + + va_start (args, fmt); + vsprintf (error_buf, fmt, args); + va_end (args); + printk (KERN_WARNING "EXT2-fs warning (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, error_buf); +} + +void ext2_put_super (struct super_block * sb) +{ + int db_count; + int i; + + lock_super (sb); + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + } + sb->s_dev = 0; + db_count = sb->u.ext2_sb.s_db_per_group; + for (i = 0; i < db_count; i++) + if (sb->u.ext2_sb.s_group_desc[i]) + brelse (sb->u.ext2_sb.s_group_desc[i]); + kfree_s (sb->u.ext2_sb.s_group_desc, + db_count * sizeof (struct buffer_head *)); + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) + if (sb->u.ext2_sb.s_inode_bitmap[i]) + brelse (sb->u.ext2_sb.s_inode_bitmap[i]); + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) + if (sb->u.ext2_sb.s_block_bitmap[i]) + brelse (sb->u.ext2_sb.s_block_bitmap[i]); + brelse (sb->u.ext2_sb.s_sbh); + unlock_super (sb); + return; +} + +static struct super_operations ext2_sops = { + ext2_read_inode, + NULL, + ext2_write_inode, + ext2_put_inode, + ext2_put_super, + ext2_write_super, + ext2_statfs, + ext2_remount +}; + +#ifdef EXT2FS_PRE_02B_COMPAT + +static int convert_pre_02b_fs (struct super_block * sb, + struct buffer_head * bh) +{ + struct ext2_super_block * es; + struct ext2_old_group_desc old_group_desc [BLOCK_SIZE / sizeof (struct ext2_old_group_desc)]; + struct ext2_group_desc * gdp; + struct buffer_head * bh2; + int groups_count; + int i; + + es = (struct ext2_super_block *) bh->b_data; + bh2 = bread (sb->s_dev, 2, BLOCK_SIZE); + if (!bh2) { + printk ("Cannot read descriptor blocks while converting !\n"); + return 0; + } + memcpy (old_group_desc, bh2->b_data, BLOCK_SIZE); + groups_count = (sb->u.ext2_sb.s_blocks_count - + sb->u.ext2_sb.s_first_data_block + + (EXT2_BLOCK_SIZE(sb) * 8) - 1) / + (EXT2_BLOCK_SIZE(sb) * 8); + memset (bh2->b_data, 0, BLOCK_SIZE); + gdp = (struct ext2_group_desc *) bh2->b_data; + for (i = 0; i < groups_count; i++) { + gdp[i].bg_block_bitmap = old_group_desc[i].bg_block_bitmap; + gdp[i].bg_inode_bitmap = old_group_desc[i].bg_inode_bitmap; + gdp[i].bg_inode_table = old_group_desc[i].bg_inode_table; + gdp[i].bg_free_blocks_count = old_group_desc[i].bg_free_blocks_count; + gdp[i].bg_free_inodes_count = old_group_desc[i].bg_free_inodes_count; + } + mark_buffer_dirty(bh2, 1); + brelse (bh2); + es->s_magic = EXT2_SUPER_MAGIC; + mark_buffer_dirty(bh, 1); + sb->s_magic = EXT2_SUPER_MAGIC; + return 1; +} + +#endif + +/* + * This function has been shamelessly adapted from the msdos fs + */ +static int parse_options (char * options, unsigned long * sb_block, + unsigned short *resuid, unsigned short * resgid, + unsigned long * mount_options) +{ + char * this_char; + char * value; + + if (!options) + return 1; + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; + if (!strcmp (this_char, "bsddf")) + clear_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "check")) { + if (!value || !*value) + set_opt (*mount_options, CHECK_NORMAL); + else if (!strcmp (value, "none")) { + clear_opt (*mount_options, CHECK_NORMAL); + clear_opt (*mount_options, CHECK_STRICT); + } + else if (strcmp (value, "normal")) + set_opt (*mount_options, CHECK_NORMAL); + else if (strcmp (value, "strict")) { + set_opt (*mount_options, CHECK_NORMAL); + set_opt (*mount_options, CHECK_STRICT); + } + else { + printk ("EXT2-fs: Invalid check option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "debug")) + set_opt (*mount_options, DEBUG); + else if (!strcmp (this_char, "errors")) { + if (!value || !*value) { + printk ("EXT2-fs: the errors option requires " + "an argument"); + return 0; + } + if (!strcmp (value, "continue")) { + clear_opt (*mount_options, ERRORS_RO); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_CONT); + } + else if (!strcmp (value, "remount-ro")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_RO); + } + else if (!strcmp (value, "panic")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_RO); + set_opt (*mount_options, ERRORS_PANIC); + } + else { + printk ("EXT2-fs: Invalid errors option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "grpid") || + !strcmp (this_char, "bsdgroups")) + set_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "minixdf")) + set_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nocheck")) { + clear_opt (*mount_options, CHECK_NORMAL); + clear_opt (*mount_options, CHECK_STRICT); + } + else if (!strcmp (this_char, "nogrpid") || + !strcmp (this_char, "sysvgroups")) + clear_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "resgid")) { + if (!value || !*value) { + printk ("EXT2-fs: the resgid option requires " + "an argument"); + return 0; + } + *resgid = simple_strtoul (value, &value, 0); + if (*value) { + printk ("EXT2-fs: Invalid resgid option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "resuid")) { + if (!value || !*value) { + printk ("EXT2-fs: the resuid option requires " + "an argument"); + return 0; + } + *resuid = simple_strtoul (value, &value, 0); + if (*value) { + printk ("EXT2-fs: Invalid resuid option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "sb")) { + if (!value || !*value) { + printk ("EXT2-fs: the sb option requires " + "an argument"); + return 0; + } + *sb_block = simple_strtoul (value, &value, 0); + if (*value) { + printk ("EXT2-fs: Invalid sb option: %s\n", + value); + return 0; + } + } + else { + printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); + return 0; + } + } + return 1; +} + +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; + es->s_mnt_count++; + es->s_mtime = CURRENT_TIME; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + if (test_opt (sb, DEBUG)) + 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); + if (test_opt (sb, CHECK)) { + ext2_check_blocks_bitmap (sb); + ext2_check_inodes_bitmap (sb); + } + } +} + +static int ext2_check_descriptors (struct super_block * sb) +{ + int i; + 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 * ext2_read_super (struct super_block * sb, void * data, + int silent) +{ + struct buffer_head * bh; + struct ext2_super_block * es; + unsigned long sb_block = 1; + unsigned short resuid = EXT2_DEF_RESUID; + unsigned short resgid = EXT2_DEF_RESGID; + unsigned long logic_sb_block = 1; + int dev = sb->s_dev; + int db_count; + int i, j; +#ifdef EXT2FS_PRE_02B_COMPAT + int fs_converted = 0; +#endif + + set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); + if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, + &sb->u.ext2_sb.s_mount_opt)) { + sb->s_dev = 0; + return NULL; + } + + lock_super (sb); + set_blocksize (dev, BLOCK_SIZE); + if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) { + sb->s_dev = 0; + unlock_super (sb); + printk ("EXT2-fs: unable to read superblock\n"); + return NULL; + } + /* + * Note: s_es must be initialized s_es as soon as possible because + * some ext2 macro-instructions depend on its value + */ + es = (struct ext2_super_block *) bh->b_data; + sb->u.ext2_sb.s_es = es; + sb->s_magic = es->s_magic; + if (sb->s_magic != EXT2_SUPER_MAGIC +#ifdef EXT2FS_PRE_02B_COMPAT + && sb->s_magic != EXT2_PRE_02B_MAGIC +#endif + ) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + if (!silent) + printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size; + sb->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(sb); + if (sb->s_blocksize != BLOCK_SIZE && + (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || + sb->s_blocksize == 4096)) { + unsigned long offset; + + brelse (bh); + set_blocksize (dev, sb->s_blocksize); + logic_sb_block = (sb_block*BLOCK_SIZE) / sb->s_blocksize; + offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize; + bh = bread (dev, logic_sb_block, sb->s_blocksize); + if(!bh) + return NULL; + es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); + sb->u.ext2_sb.s_es = es; + if (es->s_magic != EXT2_SUPER_MAGIC) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: Magic mismatch, very weird !\n"); + return NULL; + } + } + sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << + es->s_log_frag_size; + if (sb->u.ext2_sb.s_frag_size) + sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize / + sb->u.ext2_sb.s_frag_size; + else + sb->s_magic = 0; + sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group; + sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group; + sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group; + sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize / + sizeof (struct ext2_inode); + sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group / + sb->u.ext2_sb.s_inodes_per_block; + sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize / + sizeof (struct ext2_group_desc); + sb->u.ext2_sb.s_sbh = bh; + sb->u.ext2_sb.s_es = es; + if (resuid != EXT2_DEF_RESUID) + sb->u.ext2_sb.s_resuid = resuid; + else + sb->u.ext2_sb.s_resuid = es->s_def_resuid; + if (resgid != EXT2_DEF_RESGID) + sb->u.ext2_sb.s_resgid = resgid; + else + sb->u.ext2_sb.s_resgid = es->s_def_resgid; + sb->u.ext2_sb.s_mount_state = es->s_state; + sb->u.ext2_sb.s_rename_lock = 0; + sb->u.ext2_sb.s_rename_wait = NULL; +#ifdef EXT2FS_PRE_02B_COMPAT + if (sb->s_magic == EXT2_PRE_02B_MAGIC) { + if (es->s_blocks_count > 262144) { + /* + * fs > 256 MB can't be converted + */ + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: trying to mount a pre-0.2b file" + "system which cannot be converted\n"); + return NULL; + } + printk ("EXT2-fs: mounting a pre 0.2b file system, " + "will try to convert the structure\n"); + if (!(sb->s_flags & MS_RDONLY)) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: cannot convert a read-only fs\n"); + return NULL; + } + if (!convert_pre_02b_fs (sb, bh)) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: conversion failed !!!\n"); + return NULL; + } + printk ("EXT2-fs: conversion succeeded !!!\n"); + fs_converted = 1; + } +#endif + if (sb->s_magic != EXT2_SUPER_MAGIC) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + if (!silent) + printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + if (sb->s_blocksize != bh->b_size) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + if (!silent) + printk ("VFS: Unsupported blocksize on dev 0x%04x.\n", + dev); + return NULL; + } + + if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n", + sb->u.ext2_sb.s_frag_size, sb->s_blocksize); + return NULL; + } + + if (sb->u.ext2_sb.s_blocks_per_group > sb->s_blocksize * 8) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: #blocks per group too big: %lu\n", + sb->u.ext2_sb.s_blocks_per_group); + return NULL; + } + if (sb->u.ext2_sb.s_frags_per_group > sb->s_blocksize * 8) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: #fragments per group too big: %lu\n", + sb->u.ext2_sb.s_frags_per_group); + return NULL; + } + if (sb->u.ext2_sb.s_inodes_per_group > sb->s_blocksize * 8) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: #inodes per group too big: %lu\n", + sb->u.ext2_sb.s_inodes_per_group); + return NULL; + } + + sb->u.ext2_sb.s_groups_count = (es->s_blocks_count - + es->s_first_data_block + + EXT2_BLOCKS_PER_GROUP(sb) - 1) / + EXT2_BLOCKS_PER_GROUP(sb); + db_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / + EXT2_DESC_PER_BLOCK(sb); + sb->u.ext2_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); + if (sb->u.ext2_sb.s_group_desc == NULL) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: not enough memory\n"); + return NULL; + } + for (i = 0; i < db_count; i++) { + sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, + sb->s_blocksize); + if (!sb->u.ext2_sb.s_group_desc[i]) { + sb->s_dev = 0; + unlock_super (sb); + for (j = 0; j < i; j++) + brelse (sb->u.ext2_sb.s_group_desc[j]); + kfree_s (sb->u.ext2_sb.s_group_desc, + db_count * sizeof (struct buffer_head *)); + brelse (bh); + printk ("EXT2-fs: unable to read group descriptors\n"); + return NULL; + } + } + if (!ext2_check_descriptors (sb)) { + sb->s_dev = 0; + unlock_super (sb); + for (j = 0; j < db_count; j++) + brelse (sb->u.ext2_sb.s_group_desc[j]); + kfree_s (sb->u.ext2_sb.s_group_desc, + db_count * sizeof (struct buffer_head *)); + brelse (bh); + printk ("EXT2-fs: group descriptors corrupted !\n"); + return NULL; + } + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { + sb->u.ext2_sb.s_inode_bitmap_number[i] = 0; + sb->u.ext2_sb.s_inode_bitmap[i] = NULL; + sb->u.ext2_sb.s_block_bitmap_number[i] = 0; + sb->u.ext2_sb.s_block_bitmap[i] = NULL; + } + sb->u.ext2_sb.s_loaded_inode_bitmaps = 0; + sb->u.ext2_sb.s_loaded_block_bitmaps = 0; + sb->u.ext2_sb.s_db_per_group = db_count; + unlock_super (sb); + /* + * set up enough so that it can read an inode + */ + sb->s_dev = dev; + sb->s_op = &ext2_sops; + if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) { + sb->s_dev = 0; + for (i = 0; i < db_count; i++) + if (sb->u.ext2_sb.s_group_desc[i]) + brelse (sb->u.ext2_sb.s_group_desc[i]); + kfree_s (sb->u.ext2_sb.s_group_desc, + db_count * sizeof (struct buffer_head *)); + brelse (bh); + printk ("EXT2-fs: get root inode failed\n"); + return NULL; + } +#ifdef EXT2FS_PRE_02B_COMPAT + if (fs_converted) { + for (i = 0; i < db_count; i++) + mark_buffer_dirty(sb->u.ext2_sb.s_group_desc[i], 1); + sb->s_dirt = 1; + } +#endif + ext2_setup_super (sb, es); + return sb; +} + +static void ext2_commit_super (struct super_block * sb, + struct ext2_super_block * es) +{ + es->s_wtime = CURRENT_TIME; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 0; +} + +/* + * In the second extended file system, it is not necessary to + * write the super block since we use a mapping of the + * disk super block in a buffer. + * + * However, this function is still used to set the fs valid + * flags to 0. We need to set this flag to 0 since the fs + * may have been checked while mounted and e2fsck may have + * set s_state to EXT2_VALID_FS after some corrections. + */ + +void ext2_write_super (struct super_block * sb) +{ + struct ext2_super_block * es; + + if (!(sb->s_flags & MS_RDONLY)) { + es = sb->u.ext2_sb.s_es; + + ext2_debug ("setting valid to 0\n"); + + if (es->s_state & EXT2_VALID_FS) { + es->s_state &= ~EXT2_VALID_FS; + es->s_mtime = CURRENT_TIME; + } + ext2_commit_super (sb, es); + } + sb->s_dirt = 0; +} + +int ext2_remount (struct super_block * sb, int * flags, char * data) +{ + struct ext2_super_block * es; + unsigned short resuid = sb->u.ext2_sb.s_resuid; + unsigned short resgid = sb->u.ext2_sb.s_resgid; + unsigned long new_mount_opt; + unsigned long tmp; + + /* + * Allow the "check" option to be passed as a remount option. + */ + set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); + if (!parse_options (data, &tmp, &resuid, &resgid, + &new_mount_opt)) + return -EINVAL; + + sb->u.ext2_sb.s_mount_opt = new_mount_opt; + sb->u.ext2_sb.s_resuid = resuid; + sb->u.ext2_sb.s_resgid = resgid; + es = sb->u.ext2_sb.s_es; + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + if (es->s_state & EXT2_VALID_FS || + !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + return 0; + /* + * OK, we are remounting a valid rw partition rdonly, so set + * the rdonly flag and then mark the partition as valid again. + */ + es->s_state = sb->u.ext2_sb.s_mount_state; + es->s_mtime = CURRENT_TIME; + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + ext2_commit_super (sb, es); + } + else { + /* + * Mounting a RDONLY partition read-write, so reread and + * store the current valid flag. (It may have been changed + * by e2fsck since we originally mounted the partition.) + */ + sb->u.ext2_sb.s_mount_state = es->s_state; + sb->s_flags &= ~MS_RDONLY; + ext2_setup_super (sb, es); + } + return 0; +} + +void ext2_statfs (struct super_block * sb, struct statfs * buf) +{ + long tmp; + unsigned long overhead; + unsigned long overhead_per_group; + + if (test_opt (sb, MINIX_DF)) + overhead = 0; + else { + /* + * Compute the overhead (FS structures) + */ + overhead_per_group = 1 /* super block */ + + sb->u.ext2_sb.s_db_per_group /* descriptors */ + + 1 /* block bitmap */ + + 1 /* inode bitmap */ + + sb->u.ext2_sb.s_itb_per_group /* inode table */; + overhead = sb->u.ext2_sb.s_es->s_first_data_block + + sb->u.ext2_sb.s_groups_count * overhead_per_group; + } + + put_fs_long (EXT2_SUPER_MAGIC, &buf->f_type); + put_fs_long (sb->s_blocksize, &buf->f_bsize); + put_fs_long (sb->u.ext2_sb.s_es->s_blocks_count - overhead, + &buf->f_blocks); + tmp = ext2_count_free_blocks (sb); + put_fs_long (tmp, &buf->f_bfree); + if (tmp >= sb->u.ext2_sb.s_es->s_r_blocks_count) + put_fs_long (tmp - sb->u.ext2_sb.s_es->s_r_blocks_count, + &buf->f_bavail); + else + put_fs_long (0, &buf->f_bavail); + put_fs_long (sb->u.ext2_sb.s_es->s_inodes_count, &buf->f_files); + put_fs_long (ext2_count_free_inodes (sb), &buf->f_ffree); + put_fs_long (EXT2_NAME_LEN, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ +}