summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/gnu/ext2fs/ext2_bitmap.c3
-rw-r--r--sys/gnu/ext2fs/ext2_fs.h261
-rw-r--r--sys/gnu/ext2fs/ext2_fs_i.h4
-rw-r--r--sys/gnu/ext2fs/ext2_fs_sb.h12
-rw-r--r--sys/gnu/ext2fs/ext2_linux_balloc.c451
-rw-r--r--sys/gnu/ext2fs/ext2_linux_ialloc.c374
-rw-r--r--sys/gnu/ext2fs/ext2_super.c524
-rw-r--r--sys/gnu/ext2fs/i386-bitops.h180
8 files changed, 1123 insertions, 686 deletions
diff --git a/sys/gnu/ext2fs/ext2_bitmap.c b/sys/gnu/ext2fs/ext2_bitmap.c
index 8b9b5d2..c0ffb68c 100644
--- a/sys/gnu/ext2fs/ext2_bitmap.c
+++ b/sys/gnu/ext2fs/ext2_bitmap.c
@@ -8,7 +8,8 @@
*/
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
+
+
static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
diff --git a/sys/gnu/ext2fs/ext2_fs.h b/sys/gnu/ext2fs/ext2_fs.h
index 1129d1c..836038e 100644
--- a/sys/gnu/ext2fs/ext2_fs.h
+++ b/sys/gnu/ext2fs/ext2_fs.h
@@ -28,30 +28,16 @@
#undef EXT2FS_DEBUG
/*
- * Define EXT2FS_DEBUG_CACHE to produce cache debug messages
- */
-#undef EXT2FS_DEBUG_CACHE
-
-/*
- * Define EXT2FS_CHECK_CACHE to add some checks to the name cache code
- */
-#undef EXT2FS_CHECK_CACHE
-
-/*
- * Define EXT2FS_PRE_02B_COMPAT to convert ext 2 fs prior to 0.2b
- */
-#undef EXT2FS_PRE_02B_COMPAT
-
-/*
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
*/
#define EXT2_PREALLOCATE
+#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
/*
* The second extended file system version
*/
-#define EXT2FS_DATE "95/03/19"
-#define EXT2FS_VERSION "0.5a"
+#define EXT2FS_DATE "95/08/09"
+#define EXT2FS_VERSION "0.5b"
/*
* Debug code
@@ -75,12 +61,13 @@
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
-#define EXT2_FIRST_INO 11 /* First non reserved inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
/*
* The second extended file system magic number
*/
-#define EXT2_PRE_02B_MAGIC 0xEF51
#define EXT2_SUPER_MAGIC 0xEF53
/*
@@ -102,11 +89,22 @@
#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))
#ifdef __KERNEL__
-# define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10)
+# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
#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))
+#ifdef __KERNEL__
+#define EXT2_ADDR_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_addr_per_block_bits)
+#define EXT2_INODE_SIZE(s) ((s)->u.ext2_sb.s_inode_size)
+#define EXT2_FIRST_INO(s) ((s)->u.ext2_sb.s_first_ino)
+#else
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : \
+ (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : \
+ (s)->s_first_ino)
+#endif
/*
* Macro-instructions used to manage fragments
@@ -147,15 +145,6 @@ struct ext2_acl_entry /* Access Control List Entry */
/*
* Structure of a blocks group descriptor
*/
-struct ext2_old_group_desc
-{
- __u32 bg_block_bitmap; /* Blocks bitmap block */
- __u32 bg_inode_bitmap; /* Inodes bitmap block */
- __u32 bg_inode_table; /* Inodes table block */
- __u16 bg_free_blocks_count; /* Free blocks count */
- __u16 bg_free_inodes_count; /* Free inodes count */
-};
-
struct ext2_group_desc
{
__u32 bg_block_bitmap; /* Blocks bitmap block */
@@ -175,6 +164,7 @@ struct ext2_group_desc
# 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)
+# define EXT2_DESC_PER_BLOCK_BITS(s) ((s)->u.ext2_sb.s_desc_per_block_bits)
#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))
@@ -200,6 +190,18 @@ struct ext2_group_desc
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x00001FFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */
/*
* ioctl commands
@@ -213,17 +215,17 @@ struct ext2_group_desc
* 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 */
+ __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;
@@ -236,10 +238,10 @@ struct ext2_inode {
} masix1;
} osd1; /* OS dependent 1 */
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
- __u32 i_version; /* File version (for NFS) */
+ __u32 i_generation; /* File version (for NFS) */
__u32 i_file_acl; /* File ACL */
__u32 i_dir_acl; /* Directory ACL */
- __u32 i_faddr; /* Fragment address */
+ __u32 i_faddr; /* Fragment address */
union {
struct {
__u8 l_i_frag; /* Fragment number */
@@ -264,6 +266,8 @@ struct ext2_inode {
} osd2; /* OS dependent 2 */
};
+#define i_size_high i_dir_acl
+
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
@@ -347,22 +351,104 @@ struct ext2_super_block {
__u16 s_magic; /* Magic signature */
__u16 s_state; /* File system state */
__u16 s_errors; /* Behaviour when detecting errors */
- __u16 s_pad;
+ __u16 s_minor_rev_level; /* minor revision level */
__u32 s_lastcheck; /* time of last check */
__u32 s_checkinterval; /* max. time between checks */
__u32 s_creator_os; /* OS */
__u32 s_rev_level; /* Revision level */
__u16 s_def_resuid; /* Default uid for reserved blocks */
__u16 s_def_resgid; /* Default gid for reserved blocks */
- __u32 s_reserved[235]; /* Padding to the end of the block */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_padding1;
+ __u32 s_reserved[204]; /* Padding to the end of the block */
};
+#ifdef __KERNEL__
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+#endif
+
+/*
+ * Codes for operating systems
+ */
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
-#define EXT2_CURRENT_REV 0
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
#define EXT2_DEF_RESUID 0
#define EXT2_DEF_RESGID 0
@@ -379,6 +465,35 @@ struct ext2_dir_entry {
};
/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
* EXT2_DIR_PAD defines the directory entries boundaries
*
* NOTE: It must be a multiple of 4
@@ -397,33 +512,31 @@ struct ext2_dir_entry {
* Ok, these declarations are also in <linux/kernel.h> 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,
+extern int ext2_group_sparse(int group);
+extern int ext2_new_block (const struct inode *, unsigned long,
+ __u32 *, __u32 *, int *);
+extern void ext2_free_blocks (const struct inode *, unsigned long,
unsigned long);
extern unsigned long ext2_count_free_blocks (struct super_block *);
extern void ext2_check_blocks_bitmap (struct super_block *);
+extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
/* 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 *,
+extern int ext2_check_dir_entry (const char *, struct inode *,
+ struct ext2_dir_entry_2 *, struct buffer_head *,
unsigned long);
/* file.c */
@@ -431,24 +544,27 @@ 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 *);
+extern int ext2_sync_file (struct file *, struct dentry *);
/* ialloc.c */
-extern struct inode * ext2_new_inode (const struct inode *, int);
+extern struct inode * ext2_new_inode (const struct inode *, int, 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 long ext2_bmap (struct inode *, long);
+extern int ext2_get_block (struct inode *, long, struct buffer_head *, int);
extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
+extern int ext2_getblk_block (struct inode *, long, int, 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 void ext2_delete_inode (struct inode *);
extern int ext2_sync_inode (struct inode *);
extern void ext2_discard_prealloc (struct inode *);
@@ -458,17 +574,16 @@ extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
/* 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);
+extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
+extern int ext2_create (struct inode *,struct dentry *,int);
+extern int ext2_mkdir (struct inode *,struct dentry *,int);
+extern int ext2_rmdir (struct inode *,struct dentry *);
+extern int ext2_unlink (struct inode *,struct dentry *);
+extern int ext2_symlink (struct inode *,struct dentry *,const char *);
+extern int ext2_link (struct dentry *, struct inode *, struct dentry *);
+extern int ext2_mknod (struct inode *, struct dentry *, int, int);
+extern int ext2_rename (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
/* super.c */
extern void ext2_error (struct super_block *, const char *, const char *, ...)
@@ -482,7 +597,8 @@ 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 *);
+extern int init_ext2_fs(void);
+extern int ext2_statfs (struct super_block *, struct statfs *, int);
/* truncate.c */
extern void ext2_truncate (struct inode *);
@@ -499,6 +615,7 @@ extern struct inode_operations ext2_file_inode_operations;
/* symlink.c */
extern struct inode_operations ext2_symlink_inode_operations;
+extern struct inode_operations ext2_fast_symlink_inode_operations;
#endif /* __KERNEL__ */
diff --git a/sys/gnu/ext2fs/ext2_fs_i.h b/sys/gnu/ext2fs/ext2_fs_i.h
index f3eca44..72bcd5c 100644
--- a/sys/gnu/ext2fs/ext2_fs_i.h
+++ b/sys/gnu/ext2fs/ext2_fs_i.h
@@ -29,12 +29,14 @@ struct ext2_inode_info {
__u32 i_file_acl;
__u32 i_dir_acl;
__u32 i_dtime;
- __u32 i_version;
+ __u32 not_used_1; /* FIX: not used/ 2.2 placeholder */
__u32 i_block_group;
__u32 i_next_alloc_block;
__u32 i_next_alloc_goal;
__u32 i_prealloc_block;
__u32 i_prealloc_count;
+ __u32 i_high_size;
+ int i_new_inode:1; /* Is a freshly allocated inode */
};
#endif /* _LINUX_EXT2_FS_I */
diff --git a/sys/gnu/ext2fs/ext2_fs_sb.h b/sys/gnu/ext2fs/ext2_fs_sb.h
index 685efeb..2072163 100644
--- a/sys/gnu/ext2fs/ext2_fs_sb.h
+++ b/sys/gnu/ext2fs/ext2_fs_sb.h
@@ -16,6 +16,8 @@
#ifndef _LINUX_EXT2_FS_SB
#define _LINUX_EXT2_FS_SB
+#include <linux/ext2_fs.h>
+
/*
* The following is not needed anymore since the descriptors buffer
* heads are now dynamically allocated
@@ -47,12 +49,18 @@ struct ext2_sb_info {
struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
- int s_rename_lock;
- struct wait_queue * s_rename_wait;
unsigned long s_mount_opt;
unsigned short s_resuid;
unsigned short s_resgid;
unsigned short s_mount_state;
+ unsigned short s_pad;
+ int s_addr_per_block_bits;
+ int s_desc_per_block_bits;
+ int s_inode_size;
+ int s_first_ino;
+ int s_feature_compat;
+ int s_feature_incompat;
+ int s_feature_ro_compat;
};
#endif /* _LINUX_EXT2_FS_SB */
diff --git a/sys/gnu/ext2fs/ext2_linux_balloc.c b/sys/gnu/ext2fs/ext2_linux_balloc.c
index c476fa2..43a425b 100644
--- a/sys/gnu/ext2fs/ext2_linux_balloc.c
+++ b/sys/gnu/ext2fs/ext2_linux_balloc.c
@@ -7,8 +7,15 @@
* Universite Pierre et Marie Curie (Paris VI)
*
* Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
/*
* balloc.c contains the blocks allocation and deallocation routines
*/
@@ -24,38 +31,36 @@
* when a file system is mounted (see ext2_read_super).
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-
-#include <asm/bitops.h>
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
-static struct ext2_group_desc * get_group_desc (struct super_block * sb,
- unsigned int block_group,
- struct buffer_head ** bh)
+struct ext2_group_desc * ext2_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;
- if (block_group >= sb->u.ext2_sb.s_groups_count)
- ext2_panic (sb, "get_group_desc",
+ if (block_group >= sb->u.ext2_sb.s_groups_count) {
+ ext2_error (sb, "ext2_get_group_desc",
"block_group >= groups_count - "
"block_group = %d, groups_count = %lu",
block_group, sb->u.ext2_sb.s_groups_count);
+ return NULL;
+ }
+
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",
+ if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+ ext2_error (sb, "ext2_get_group_desc",
"Group descriptor not loaded - "
"block_group = %d, group_desc = %lu, desc = %lu",
block_group, group_desc, desc);
+ return NULL;
+ }
+
gdp = (struct ext2_group_desc *)
sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
if (bh)
@@ -63,22 +68,41 @@ static struct ext2_group_desc * get_group_desc (struct super_block * sb,
return gdp + desc;
}
-static void read_block_bitmap (struct super_block * sb,
+/*
+ * Read the bitmap for a given block_group, reading into the specified
+ * slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+
+static int read_block_bitmap (struct super_block * sb,
unsigned int block_group,
unsigned long bitmap_nr)
{
struct ext2_group_desc * gdp;
- struct buffer_head * bh;
+ struct buffer_head * bh = NULL;
+ int retval = -EIO;
- 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",
+ gdp = ext2_get_group_desc (sb, block_group, NULL);
+ if (!gdp)
+ goto error_out;
+ retval = 0;
+ bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
+ if (!bh) {
+ ext2_error (sb, "read_block_bitmap",
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %lu",
block_group, (unsigned long) gdp->bg_block_bitmap);
+ retval = -EIO;
+ }
+ /*
+ * On IO error, just leave a zero in the superblock's block pointer for
+ * this group. The IO will be retried next time.
+ */
+error_out:
sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
+ return retval;
}
/*
@@ -91,11 +115,13 @@ static void read_block_bitmap (struct super_block * sb,
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
+ *
+ * Return the slot used to store the bitmap, or a -ve error code.
*/
-static int load__block_bitmap (struct super_block * sb,
- unsigned int block_group)
+static int __load_block_bitmap (struct super_block * sb,
+ unsigned int block_group)
{
- int i, j;
+ int i, j, retval = 0;
unsigned long block_bitmap_number;
struct buffer_head * block_bitmap;
@@ -107,16 +133,16 @@ static int load__block_bitmap (struct super_block * sb,
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] !=
+ if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
block_group)
- ext2_panic (sb, "load_block_bitmap",
- "block_group != block_bitmap_number");
- else
return block_group;
- } else {
- read_block_bitmap (sb, block_group, block_group);
- return block_group;
+ ext2_error (sb, "__load_block_bitmap",
+ "block_group != block_bitmap_number");
}
+ retval = read_block_bitmap (sb, block_group, block_group);
+ if (retval < 0)
+ return retval;
+ return block_group;
}
for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
@@ -134,6 +160,14 @@ static int load__block_bitmap (struct super_block * sb,
}
sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
+
+ /*
+ * There's still one special case here --- if block_bitmap == 0
+ * then our last attempt to read the bitmap failed and we have
+ * just ended up caching that failure. Try again to read it.
+ */
+ if (!block_bitmap)
+ retval = read_block_bitmap (sb, block_group, 0);
} else {
if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_block_bitmaps++;
@@ -145,27 +179,74 @@ static int load__block_bitmap (struct super_block * sb,
sb->u.ext2_sb.s_block_bitmap[j] =
sb->u.ext2_sb.s_block_bitmap[j - 1];
}
- read_block_bitmap (sb, block_group, 0);
+ retval = read_block_bitmap (sb, block_group, 0);
}
- return 0;
+ return retval;
}
+/*
+ * Load the block bitmap for a given block group. First of all do a couple
+ * of fast lookups for common cases and then pass the request onto the guts
+ * of the bitmap loader.
+ *
+ * Return the slot number of the group in the superblock bitmap cache's on
+ * success, or a -ve error code.
+ *
+ * There is still one inconsistency here --- if the number of groups in this
+ * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of
+ * differentiating between a group for which we have never performed a bitmap
+ * IO request, and a group for which the last bitmap read request failed.
+ */
static inline int load_block_bitmap (struct super_block * sb,
unsigned int block_group)
{
+ int slot;
+
+ /*
+ * Do the lookup for the slot. First of all, check if we're asking
+ * for the same slot as last time, and did we succeed that last time?
+ */
if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
- sb->u.ext2_sb.s_block_bitmap_number[0] == block_group)
+ sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
+ sb->u.ext2_sb.s_block_bitmap[block_group]) {
return 0;
-
- 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;
+ }
+ /*
+ * Or can we do a fast lookup based on a loaded group on a filesystem
+ * small enough to be mapped directly into the superblock?
+ */
+ else 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]) {
+ slot = block_group;
+ }
+ /*
+ * If not, then do a full lookup for this block group.
+ */
+ else {
+ slot = __load_block_bitmap (sb, block_group);
+ }
- return load__block_bitmap (sb, block_group);
+ /*
+ * <0 means we just got an error
+ */
+ if (slot < 0)
+ return slot;
+
+ /*
+ * If it's a valid slot, we may still have cached a previous IO error,
+ * in which case the bh in the superblock cache will be zero.
+ */
+ if (!sb->u.ext2_sb.s_block_bitmap[slot])
+ return -EIO;
+
+ /*
+ * Must have been read in OK to get this far.
+ */
+ return slot;
}
-void ext2_free_blocks (struct super_block * sb, unsigned long block,
+void ext2_free_blocks (const struct inode * inode, unsigned long block,
unsigned long count)
{
struct buffer_head * bh;
@@ -174,44 +255,57 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
unsigned long bit;
unsigned long i;
int bitmap_nr;
+ unsigned long overflow;
+ struct super_block * sb;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
+ sb = inode->i_sb;
if (!sb) {
printk ("ext2_free_blocks: nonexistent device");
return;
}
lock_super (sb);
es = sb->u.ext2_sb.s_es;
- if (block < es->s_first_data_block ||
- (block + count) > es->s_blocks_count) {
+ if (block < le32_to_cpu(es->s_first_data_block) ||
+ (block + count) > le32_to_cpu(es->s_blocks_count)) {
ext2_error (sb, "ext2_free_blocks",
"Freeing blocks not in datazone - "
"block = %lu, count = %lu", block, count);
- unlock_super (sb);
- return;
+ goto error_return;
}
ext2_debug ("freeing block %lu\n", block);
- block_group = (block - es->s_first_data_block) /
+do_more:
+ overflow = 0;
+ block_group = (block - le32_to_cpu(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))
- ext2_panic (sb, "ext2_free_blocks",
- "Freeing blocks across group boundary - "
- "Block = %lu, count = %lu",
- block, count);
+ bit = (block - le32_to_cpu(es->s_first_data_block)) %
+ EXT2_BLOCKS_PER_GROUP(sb);
+ /*
+ * Check to see if we are freeing blocks across a group
+ * boundary.
+ */
+ if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) {
+ overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
+ count -= overflow;
+ }
bitmap_nr = load_block_bitmap (sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- gdp = get_group_desc (sb, block_group, &bh2);
+ gdp = ext2_get_group_desc (sb, block_group, &bh2);
+ if (!gdp)
+ goto error_return;
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,
+ (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
+ in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
+ in_range (block, le32_to_cpu(gdp->bg_inode_table),
sb->u.ext2_sb.s_itb_per_group) ||
- in_range (block + count - 1, gdp->bg_inode_table,
+ in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
sb->u.ext2_sb.s_itb_per_group)))
ext2_panic (sb, "ext2_free_blocks",
"Freeing blocks in system zones - "
@@ -219,13 +313,16 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
block, count);
for (i = 0; i < count; i++) {
- if (!clear_bit (bit + i, bh->b_data))
+ if (!ext2_clear_bit (bit + i, bh->b_data))
ext2_warning (sb, "ext2_free_blocks",
"bit already cleared for block %lu",
block);
else {
- gdp->bg_free_blocks_count++;
- es->s_free_blocks_count++;
+ DQUOT_FREE_BLOCK(sb, inode, 1);
+ gdp->bg_free_blocks_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1);
+ es->s_free_blocks_count =
+ cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1);
}
}
@@ -237,7 +334,13 @@ void ext2_free_blocks (struct super_block * sb, unsigned long block,
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
+ if (overflow) {
+ block += count;
+ count = overflow;
+ goto do_more;
+ }
sb->s_dirt = 1;
+error_return:
unlock_super (sb);
return;
}
@@ -249,32 +352,34 @@ void ext2_free_blocks (struct super_block * sb, 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 super_block * sb, unsigned long goal,
- u32 * prealloc_count,
- u32 * prealloc_block)
+int ext2_new_block (const struct inode * inode, unsigned long goal,
+ u32 * prealloc_count, u32 * prealloc_block, int * err)
{
struct buffer_head * bh;
struct buffer_head * bh2;
char * p, * r;
int i, j, k, tmp;
- unsigned long lmap;
int bitmap_nr;
+ struct super_block * sb;
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
-
#ifdef EXT2FS_DEBUG
static int goal_hits = 0, goal_attempts = 0;
#endif
+ *err = -ENOSPC;
+ sb = inode->i_sb;
if (!sb) {
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) &&
+ if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
+ ((sb->u.ext2_sb.s_resuid != current->fsuid) &&
(sb->u.ext2_sb.s_resgid == 0 ||
- !in_group_p (sb->u.ext2_sb.s_resgid)))) {
+ !in_group_p (sb->u.ext2_sb.s_resgid)) &&
+ !capable(CAP_SYS_RESOURCE))) {
unlock_super (sb);
return 0;
}
@@ -285,22 +390,29 @@ repeat:
/*
* First, test whether the goal block is free.
*/
- 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 (sb, i, &bh2);
- if (gdp->bg_free_blocks_count > 0) {
- j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
+ if (goal < le32_to_cpu(es->s_first_data_block) ||
+ goal >= le32_to_cpu(es->s_blocks_count))
+ goal = le32_to_cpu(es->s_first_data_block);
+ i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT2_BLOCKS_PER_GROUP(sb);
+ gdp = ext2_get_group_desc (sb, i, &bh2);
+ if (!gdp)
+ goto io_error;
+
+ if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
+ j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb));
#ifdef EXT2FS_DEBUG
if (j)
goal_attempts++;
#endif
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ goto io_error;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
ext2_debug ("goal is at %d:%d.\n", i, j);
- if (!test_bit(j, bh->b_data)) {
+ if (!ext2_test_bit(j, bh->b_data)) {
#ifdef EXT2FS_DEBUG
goal_hits++;
ext2_debug ("goal bit allocated.\n");
@@ -310,22 +422,16 @@ repeat:
if (j) {
/*
* The goal was occupied; search forward for a free
- * block within the next 32 blocks
+ * 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..
*/
- 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;
- }
- }
+ int end_goal = (j + 63) & ~63;
+ j = ext2_find_next_zero_bit(bh->b_data, end_goal, j);
+ if (j < end_goal)
+ goto got_block;
}
ext2_debug ("Bit not found near goal\n");
@@ -346,7 +452,8 @@ repeat:
j = k;
goto search_back;
}
- k = find_next_zero_bit ((unsigned long *) bh->b_data,
+
+ k = ext2_find_next_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb),
j);
if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
@@ -365,8 +472,13 @@ repeat:
i++;
if (i >= sb->u.ext2_sb.s_groups_count)
i = 0;
- gdp = get_group_desc (sb, i, &bh2);
- if (gdp->bg_free_blocks_count > 0)
+ gdp = ext2_get_group_desc (sb, i, &bh2);
+ if (!gdp) {
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+ }
+ if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
break;
}
if (k >= sb->u.ext2_sb.s_groups_count) {
@@ -374,13 +486,16 @@ repeat:
return 0;
}
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ goto io_error;
+
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,
+ j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
EXT2_BLOCKS_PER_GROUP(sb));
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
ext2_error (sb, "ext2_new_block",
@@ -395,25 +510,35 @@ search_back:
* bitmap. Now search backwards up to 7 bits to find the
* start of this group of free blocks.
*/
- for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--);
+ for (k = 0; k < 7 && j > 0 && !ext2_test_bit (j - 1, bh->b_data); k++, j--);
got_block:
ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
- tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
+ /*
+ * Check quota for allocation of this block.
+ */
+ if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) {
+ unlock_super(sb);
+ *err = -EDQUOT;
+ return 0;
+ }
+
+ tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block);
if (test_opt (sb, CHECK_STRICT) &&
- (tmp == gdp->bg_block_bitmap ||
- tmp == gdp->bg_inode_bitmap ||
- in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group)))
+ (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
+ tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
+ in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group)))
ext2_panic (sb, "ext2_new_block",
"Allocating block in system zone - "
"block = %u", tmp);
- if (set_bit (j, bh->b_data)) {
+ if (ext2_set_bit (j, bh->b_data)) {
ext2_warning (sb, "ext2_new_block",
"bit already set for block %d", j);
+ DQUOT_FREE_BLOCK(sb, inode, 1);
goto repeat;
}
@@ -424,16 +549,30 @@ got_block:
*/
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
+ int prealloc_goal;
+
+ prealloc_goal = es->s_prealloc_blocks ?
+ es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS;
+
*prealloc_count = 0;
*prealloc_block = tmp + 1;
for (k = 1;
- k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) {
- if (set_bit (j + k, bh->b_data))
+ k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
+ k++) {
+ if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
break;
+ if (ext2_set_bit (j + k, bh->b_data)) {
+ DQUOT_FREE_BLOCK(sb, inode, 1);
+ break;
+ }
(*prealloc_count)++;
}
- gdp->bg_free_blocks_count -= *prealloc_count;
- es->s_free_blocks_count -= *prealloc_count;
+ gdp->bg_free_blocks_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
+ *prealloc_count);
+ es->s_free_blocks_count =
+ cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
+ *prealloc_count);
ext2_debug ("Preallocated a further %lu bits.\n",
*prealloc_count);
}
@@ -447,33 +586,32 @@ got_block:
wait_on_buffer (bh);
}
- if (j >= es->s_blocks_count) {
+ if (j >= le32_to_cpu(es->s_blocks_count)) {
ext2_error (sb, "ext2_new_block",
- "block >= blocks count - "
- "block_group = %d, block=%d", i, j);
- 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);
+ "block(%d) >= blocks count(%d) - "
+ "block_group = %d, es == %p ",j,
+ le32_to_cpu(es->s_blocks_count), i, es);
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);
- gdp->bg_free_blocks_count--;
+ gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
mark_buffer_dirty(bh2, 1);
- es->s_free_blocks_count--;
+ es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
sb->s_dirt = 1;
unlock_super (sb);
+ *err = 0;
return j;
+
+io_error:
+ *err = -EIO;
+ unlock_super (sb);
+ return 0;
+
}
unsigned long ext2_count_free_blocks (struct super_block * sb)
@@ -491,21 +629,26 @@ unsigned long ext2_count_free_blocks (struct super_block * sb)
bitmap_count = 0;
gdp = 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;
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
sb->s_blocksize);
printk ("group %d: stored = %d, counted = %lu\n",
- i, gdp->bg_free_blocks_count, x);
+ i, le16_to_cpu(gdp->bg_free_blocks_count), x);
bitmap_count += x;
}
printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
- es->s_free_blocks_count, desc_count, bitmap_count);
+ le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
unlock_super (sb);
return bitmap_count;
#else
- return sb->u.ext2_sb.s_es->s_free_blocks_count;
+ return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_blocks_count);
#endif
}
@@ -513,10 +656,29 @@ static inline int block_in_use (unsigned long block,
struct super_block * sb,
unsigned char * map)
{
- return test_bit ((block - sb->u.ext2_sb.s_es->s_first_data_block) %
+ return ext2_test_bit ((block - le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block)) %
EXT2_BLOCKS_PER_GROUP(sb), map);
}
+static int test_root(int a, int b)
+{
+ if (a == 0)
+ return 1;
+ while (1) {
+ if (a == 1)
+ return 1;
+ if (a % b)
+ return 0;
+ a = a / b;
+ }
+}
+
+int ext2_group_sparse(int group)
+{
+ return (test_root(group, 3) || test_root(group, 5) ||
+ test_root(group, 7));
+}
+
void ext2_check_blocks_bitmap (struct super_block * sb)
{
struct buffer_head * bh;
@@ -535,49 +697,60 @@ void ext2_check_blocks_bitmap (struct super_block * sb)
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->u.ext2_sb.s_groups_count; i++) {
- gdp = get_group_desc (sb, i, NULL);
- desc_count += gdp->bg_free_blocks_count;
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
bitmap_nr = load_block_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- if (!test_bit (0, bh->b_data))
- 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))
+ if (!(sb->u.ext2_sb.s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+ ext2_group_sparse(i)) {
+ if (!ext2_test_bit (0, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
+ "Superblock in group %d "
+ "is marked free", i);
+
+ for (j = 0; j < desc_blocks; j++)
+ if (!ext2_test_bit (j + 1, bh->b_data))
+ 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))
+ if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data))
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))
+ if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
"Inode bitmap for group %d is marked free",
i);
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))
+ if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data))
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)
+ if (le16_to_cpu(gdp->bg_free_blocks_count) != x)
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);
+ le16_to_cpu(gdp->bg_free_blocks_count), x);
bitmap_count += x;
}
- if (es->s_free_blocks_count != bitmap_count)
+ if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
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);
+ (unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count);
unlock_super (sb);
}
diff --git a/sys/gnu/ext2fs/ext2_linux_ialloc.c b/sys/gnu/ext2fs/ext2_linux_ialloc.c
index 9102d02..d519f60 100644
--- a/sys/gnu/ext2fs/ext2_linux_ialloc.c
+++ b/sys/gnu/ext2fs/ext2_linux_ialloc.c
@@ -8,8 +8,15 @@
*
* BSD ufs-inspired inode and directory allocation by
* Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
*/
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
/*
* ialloc.c contains the inodes allocation and deallocation routines
*/
@@ -25,59 +32,42 @@
* when a file system is mounted (see ext2_read_super).
*/
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-
-#include <asm/bitops.h>
-
-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;
-
- 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_inode_bitmap (struct super_block * sb,
+/*
+ * Read the inode allocation bitmap for a given block_group, reading
+ * into the specified slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+static int read_inode_bitmap (struct super_block * sb,
unsigned long block_group,
unsigned int bitmap_nr)
{
struct ext2_group_desc * gdp;
- struct buffer_head * bh;
+ struct buffer_head * bh = NULL;
+ int retval = 0;
- 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",
+ gdp = ext2_get_group_desc (sb, block_group, NULL);
+ if (!gdp) {
+ retval = -EIO;
+ goto error_out;
+ }
+ bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize);
+ if (!bh) {
+ ext2_error (sb, "read_inode_bitmap",
"Cannot read inode bitmap - "
"block_group = %lu, inode_bitmap = %lu",
block_group, (unsigned long) gdp->bg_inode_bitmap);
+ retval = -EIO;
+ }
+ /*
+ * On IO error, just leave a zero in the superblock's block pointer for
+ * this group. The IO will be retried next time.
+ */
+error_out:
sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
+ return retval;
}
/*
@@ -90,11 +80,13 @@ static void read_inode_bitmap (struct super_block * sb,
* 1/ There is one cache per mounted file system.
* 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
* this function reads the bitmap without maintaining a LRU cache.
+ *
+ * Return the slot used to store the bitmap, or a -ve error code.
*/
static int load_inode_bitmap (struct super_block * sb,
unsigned int block_group)
{
- int i, j;
+ int i, j, retval = 0;
unsigned long inode_bitmap_number;
struct buffer_head * inode_bitmap;
@@ -104,7 +96,8 @@ static int load_inode_bitmap (struct super_block * sb,
"block_group = %d, groups_count = %lu",
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)
+ sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group &&
+ sb->u.ext2_sb.s_inode_bitmap[0] != NULL)
return 0;
if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
if (sb->u.ext2_sb.s_inode_bitmap[block_group]) {
@@ -114,7 +107,10 @@ static int load_inode_bitmap (struct super_block * sb,
else
return block_group;
} else {
- read_inode_bitmap (sb, block_group, block_group);
+ retval = read_inode_bitmap (sb, block_group,
+ block_group);
+ if (retval < 0)
+ return retval;
return block_group;
}
}
@@ -135,6 +131,15 @@ static int load_inode_bitmap (struct super_block * sb,
}
sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap;
+
+ /*
+ * There's still one special case here --- if inode_bitmap == 0
+ * then our last attempt to read the bitmap failed and we have
+ * just ended up caching that failure. Try again to read it.
+ */
+ if (!inode_bitmap)
+ retval = read_inode_bitmap (sb, block_group, 0);
+
} else {
if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
sb->u.ext2_sb.s_loaded_inode_bitmaps++;
@@ -146,49 +151,32 @@ static int load_inode_bitmap (struct super_block * sb,
sb->u.ext2_sb.s_inode_bitmap[j] =
sb->u.ext2_sb.s_inode_bitmap[j - 1];
}
- read_inode_bitmap (sb, block_group, 0);
+ retval = read_inode_bitmap (sb, block_group, 0);
}
- return 0;
+ return retval;
}
/*
- * This function sets the deletion time for the inode
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
*
- * This may be used one day by an 'undelete' program
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
*/
-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 super_block * sb;
+ struct super_block * sb = inode->i_sb;
+ int is_directory;
+ unsigned long ino;
struct buffer_head * bh;
struct buffer_head * bh2;
unsigned long block_group;
@@ -197,15 +185,12 @@ void ext2_free_inode (struct inode * inode)
struct ext2_group_desc * gdp;
struct ext2_super_block * es;
- 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);
+ printk ("ext2_free_inode: inode has count=%d\n", inode->i_count);
return;
}
if (inode->i_nlink) {
@@ -213,87 +198,71 @@ void ext2_free_inode (struct inode * inode)
inode->i_nlink);
return;
}
- if (!inode->i_sb) {
+ if (!sb) {
printk("ext2_free_inode: inode on nonexistent device\n");
return;
}
- ext2_debug ("freeing inode %lu\n", inode->i_ino);
+ ino = inode->i_ino;
+ ext2_debug ("freeing inode %lu\n", ino);
+
+ /*
+ * Note: we must free any quota before locking the superblock,
+ * as writing the quota to disk may need the lock as well.
+ */
+ DQUOT_FREE_INODE(sb, inode);
+ DQUOT_DROP(inode);
- 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) {
+ es = sb->u.ext2_sb.s_es;
+ if (ino < EXT2_FIRST_INO(sb) ||
+ ino > le32_to_cpu(es->s_inodes_count)) {
ext2_error (sb, "free_inode",
"reserved inode or nonexistent inode");
- unlock_super (sb);
- return;
+ goto error_return;
}
- 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);
+ block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
+ bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
bitmap_nr = load_inode_bitmap (sb, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
- if (!clear_bit (bit, bh->b_data))
+
+ is_directory = S_ISDIR(inode->i_mode);
+
+ /* Do this BEFORE marking the inode not in use */
+ clear_inode (inode);
+
+ /* Ok, now we can actually update the inode bitmaps.. */
+ if (!ext2_clear_bit (bit, bh->b_data))
ext2_warning (sb, "ext2_free_inode",
- "bit already cleared for inode %lu", inode->i_ino);
+ "bit already cleared for inode %lu", 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--;
+ gdp = ext2_get_group_desc (sb, block_group, &bh2);
+ if (gdp) {
+ gdp->bg_free_inodes_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
+ if (is_directory)
+ gdp->bg_used_dirs_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+ }
mark_buffer_dirty(bh2, 1);
- es->s_free_inodes_count++;
+ es->s_free_inodes_count =
+ cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
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;
- clear_inode (inode);
+error_return:
unlock_super (sb);
}
/*
- * This function increments the inode version number
- *
- * This may be used one day by the NFS server
- */
-static void inc_inode_version (struct inode * inode,
- struct ext2_group_desc *gdp,
- int mode)
-{
- 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_error (inode->i_sb, "inc_inode_version",
- "Cannot load inode table block - "
- "inode=%lu, inode_block=%lu\n",
- inode->i_ino, inode_block);
- inode->u.ext2_i.i_version = 1;
- return;
- }
- 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_version++;
- inode->u.ext2_i.i_version = raw_inode->i_version;
- mark_buffer_dirty(bh, 1);
- brelse (bh);
-}
-
-/*
* 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
* free space and a low directory-to-inode ratio; if that fails, then of
@@ -303,7 +272,7 @@ 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.
*/
-struct inode * ext2_new_inode (const struct inode * dir, int mode)
+struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
{
struct super_block * sb;
struct buffer_head * bh;
@@ -315,25 +284,37 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode)
struct ext2_group_desc * tmp;
struct ext2_super_block * es;
- if (!dir || !(inode = get_empty_inode ()))
+ /* Cannot create files in a deleted directory */
+ if (!dir || !dir->i_nlink) {
+ *err = -EPERM;
+ return NULL;
+ }
+
+ inode = get_empty_inode ();
+ if (!inode) {
+ *err = -ENOMEM;
return NULL;
+ }
+
sb = dir->i_sb;
inode->i_sb = sb;
- inode->i_flags = sb->s_flags;
+ inode->i_flags = 0;
lock_super (sb);
es = sb->u.ext2_sb.s_es;
repeat:
gdp = NULL; i=0;
+ *err = -ENOSPC;
if (S_ISDIR(mode)) {
- avefreei = es->s_free_inodes_count /
+ avefreei = le32_to_cpu(es->s_free_inodes_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++) {
- tmp = get_group_desc (sb, i, &bh2);
- if ((tmp->bg_used_dirs_count << 8) <
- tmp->bg_free_inodes_count) {
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp &&
+ (le16_to_cpu(tmp->bg_used_dirs_count) << 8) <
+ le16_to_cpu(tmp->bg_free_inodes_count)) {
gdp = tmp;
break;
}
@@ -343,12 +324,13 @@ repeat:
*/
if (!gdp) {
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) {
+ tmp = ext2_get_group_desc (sb, j, &bh2);
+ if (tmp &&
+ le16_to_cpu(tmp->bg_free_inodes_count) &&
+ le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) {
if (!gdp ||
- (tmp->bg_free_blocks_count >
- gdp->bg_free_blocks_count)) {
+ (le16_to_cpu(tmp->bg_free_blocks_count) >
+ le16_to_cpu(gdp->bg_free_blocks_count))) {
i = j;
gdp = tmp;
}
@@ -362,8 +344,8 @@ repeat:
* Try to place the inode in its parent directory
*/
i = dir->u.ext2_i.i_block_group;
- tmp = get_group_desc (sb, i, &bh2);
- if (tmp->bg_free_inodes_count)
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
gdp = tmp;
else
{
@@ -375,8 +357,9 @@ repeat:
i += j;
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) {
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp &&
+ le16_to_cpu(tmp->bg_free_inodes_count)) {
gdp = tmp;
break;
}
@@ -390,8 +373,9 @@ repeat:
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 (sb, i, &bh2);
- if (tmp->bg_free_inodes_count) {
+ tmp = ext2_get_group_desc (sb, i, &bh2);
+ if (tmp &&
+ le16_to_cpu(tmp->bg_free_inodes_count)) {
gdp = tmp;
break;
}
@@ -405,11 +389,18 @@ repeat:
return NULL;
}
bitmap_nr = load_inode_bitmap (sb, i);
+ if (bitmap_nr < 0) {
+ unlock_super (sb);
+ iput(inode);
+ *err = -EIO;
+ return NULL;
+ }
+
bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
- if ((j = find_first_zero_bit ((unsigned long *) bh->b_data,
+ if ((j = ext2_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)) {
+ if (ext2_set_bit (j, bh->b_data)) {
ext2_warning (sb, "ext2_new_inode",
"bit already set for inode %d", j);
goto repeat;
@@ -420,7 +411,7 @@ repeat:
wait_on_buffer (bh);
}
} else {
- if (gdp->bg_free_inodes_count != 0) {
+ if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
ext2_error (sb, "ext2_new_inode",
"Free inodes count corrupted in group %d",
i);
@@ -431,7 +422,7 @@ repeat:
goto repeat;
}
j += i * EXT2_INODES_PER_GROUP(sb) + 1;
- if (j < EXT2_FIRST_INO || j > es->s_inodes_count) {
+ if (j < EXT2_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) {
ext2_error (sb, "ext2_new_inode",
"reserved inode or inode > inodes count - "
"block_group = %d,inode=%d", i, j);
@@ -439,16 +430,18 @@ repeat:
iput (inode);
return NULL;
}
- gdp->bg_free_inodes_count--;
+ gdp->bg_free_inodes_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
if (S_ISDIR(mode))
- gdp->bg_used_dirs_count++;
+ gdp->bg_used_dirs_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
mark_buffer_dirty(bh2, 1);
- es->s_free_inodes_count--;
+ es->s_free_inodes_count =
+ cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
sb->s_dirt = 1;
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;
@@ -460,11 +453,12 @@ repeat:
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_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->u.ext2_i.i_new_inode = 1;
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);
@@ -479,11 +473,20 @@ repeat:
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);
+ inode->i_generation = event++;
+ mark_inode_dirty(inode);
+ unlock_super (sb);
+ if(DQUOT_ALLOC_INODE(sb, inode)) {
+ sb->dq_op->drop(inode);
+ inode->i_nlink = 0;
+ iput(inode);
+ *err = -EDQUOT;
+ return NULL;
+ }
ext2_debug ("allocating inode %lu\n", inode->i_ino);
- unlock_super (sb);
+ *err = 0;
return inode;
}
@@ -502,21 +505,26 @@ unsigned long ext2_count_free_inodes (struct super_block * sb)
bitmap_count = 0;
gdp = 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;
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
bitmap_nr = load_inode_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
EXT2_INODES_PER_GROUP(sb) / 8);
printk ("group %d: stored = %d, counted = %lu\n",
- i, gdp->bg_free_inodes_count, x);
+ i, le16_to_cpu(gdp->bg_free_inodes_count), x);
bitmap_count += x;
}
printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
- es->s_free_inodes_count, desc_count, bitmap_count);
+ le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
unlock_super (sb);
return desc_count;
#else
- return sb->u.ext2_sb.s_es->s_free_inodes_count;
+ return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_inodes_count);
#endif
}
@@ -534,22 +542,28 @@ void ext2_check_inodes_bitmap (struct super_block * sb)
bitmap_count = 0;
gdp = 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;
+ gdp = ext2_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
bitmap_nr = load_inode_bitmap (sb, i);
+ if (bitmap_nr < 0)
+ continue;
+
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)
+ if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
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);
+ le16_to_cpu(gdp->bg_free_inodes_count), x);
bitmap_count += x;
}
- if (es->s_free_inodes_count != bitmap_count)
+ if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
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);
+ (unsigned long) le32_to_cpu(es->s_free_inodes_count),
+ bitmap_count);
unlock_super (sb);
}
diff --git a/sys/gnu/ext2fs/ext2_super.c b/sys/gnu/ext2fs/ext2_super.c
index b73cc52..11f99b4 100644
--- a/sys/gnu/ext2fs/ext2_super.c
+++ b/sys/gnu/ext2fs/ext2_super.c
@@ -11,21 +11,20 @@
* linux/fs/minix/inode.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
*/
-#include <stdarg.h>
-
-#include <asm/segment.h>
-#include <asm/system.h>
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/malloc.h>
-#include <linux/sched.h>
-#include <linux/stat.h>
+#include <linux/module.h>
#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/init.h>
#include <linux/locks.h>
+#include <asm/uaccess.h>
+
+
static char error_buf[1024];
@@ -36,7 +35,8 @@ void ext2_error (struct super_block * sb, const char * function,
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;
+ sb->u.ext2_sb.s_es->s_state =
+ cpu_to_le16(le16_to_cpu(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;
}
@@ -44,14 +44,14 @@ void ext2_error (struct super_block * sb, const char * function,
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 &&
+ (le16_to_cpu(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);
+ panic ("EXT2-fs panic (device %s): %s: %s\n",
+ bdevname(sb->s_dev), function, error_buf);
+ printk (KERN_CRIT "EXT2-fs error (device %s): %s: %s\n",
+ bdevname(sb->s_dev), function, error_buf);
if (test_opt (sb, ERRORS_RO) ||
- (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO &&
+ (le16_to_cpu(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;
@@ -65,15 +65,20 @@ NORET_TYPE void ext2_panic (struct super_block * sb, const char * function,
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;
+ sb->u.ext2_sb.s_es->s_state =
+ cpu_to_le16(le16_to_cpu(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);
+ /* this is to prevent panic from syncing this filesystem */
+ if (sb->s_lock)
+ sb->s_lock=0;
+ sb->s_flags |= MS_RDONLY;
+ panic ("EXT2-fs panic (device %s): %s: %s\n",
+ bdevname(sb->s_dev), function, error_buf);
}
void ext2_warning (struct super_block * sb, const char * function,
@@ -84,8 +89,8 @@ void ext2_warning (struct super_block * sb, const char * function,
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);
+ printk (KERN_WARNING "EXT2-fs warning (device %s): %s: %s\n",
+ bdevname(sb->s_dev), function, error_buf);
}
void ext2_put_super (struct super_block * sb)
@@ -93,12 +98,10 @@ 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;
+ sb->u.ext2_sb.s_es->s_state = le16_to_cpu(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])
@@ -112,63 +115,23 @@ void ext2_put_super (struct super_block * sb)
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);
+
+ MOD_DEC_USE_COUNT;
return;
}
-static struct super_operations ext2_sops = {
+static struct super_operations ext2_sops = {
ext2_read_inode,
- NULL,
ext2_write_inode,
ext2_put_inode,
+ ext2_delete_inode,
+ NULL,
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
*/
@@ -195,9 +158,9 @@ static int parse_options (char * options, unsigned long * sb_block,
clear_opt (*mount_options, CHECK_NORMAL);
clear_opt (*mount_options, CHECK_STRICT);
}
- else if (strcmp (value, "normal"))
+ else if (!strcmp (value, "normal"))
set_opt (*mount_options, CHECK_NORMAL);
- else if (strcmp (value, "strict")) {
+ else if (!strcmp (value, "strict")) {
set_opt (*mount_options, CHECK_NORMAL);
set_opt (*mount_options, CHECK_STRICT);
}
@@ -287,6 +250,12 @@ static int parse_options (char * options, unsigned long * sb_block,
return 0;
}
}
+ /* Silently ignore the quota options */
+ else if (!strcmp (this_char, "grpquota")
+ || !strcmp (this_char, "noquota")
+ || !strcmp (this_char, "quota")
+ || !strcmp (this_char, "usrquota"))
+ /* Don't do anything ;-) */ ;
else {
printk ("EXT2-fs: Unrecognized mount option %s\n", this_char);
return 0;
@@ -298,7 +267,7 @@ static int parse_options (char * options, unsigned long * sb_block,
static void ext2_setup_super (struct super_block * sb,
struct ext2_super_block * es)
{
- if (es->s_rev_level > EXT2_CURRENT_REV) {
+ if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) {
printk ("EXT2-fs warning: revision level too high, "
"forcing read/only mode\n");
sb->s_flags |= MS_RDONLY;
@@ -310,19 +279,20 @@ static void ext2_setup_super (struct super_block * sb,
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)
+ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+ le16_to_cpu(es->s_mnt_count) >=
+ (unsigned short) (__s16) le16_to_cpu(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))
+ else if (le32_to_cpu(es->s_checkinterval) &&
+ (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(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;
+ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+ if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+ es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
+ es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+ es->s_mtime = cpu_to_le32(CURRENT_TIME);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
sb->s_dirt = 1;
if (test_opt (sb, DEBUG))
@@ -339,13 +309,20 @@ static void ext2_setup_super (struct super_block * sb,
ext2_check_inodes_bitmap (sb);
}
}
+#if 0 /* ibasket's still have unresolved bugs... -DaveM */
+
+ /* [T. Schoebel-Theuer] This limit should be maintained on disk.
+ * This is just provisionary.
+ */
+ sb->s_ibasket_max = 100;
+#endif
}
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;
+ unsigned long block = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block);
struct ext2_group_desc * gdp = NULL;
ext2_debug ("Checking group descriptors");
@@ -354,32 +331,32 @@ static int ext2_check_descriptors (struct super_block * sb)
{
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))
+ if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
+ le32_to_cpu(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);
+ i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
return 0;
}
- if (gdp->bg_inode_bitmap < block ||
- gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
+ le32_to_cpu(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);
+ i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
return 0;
}
- if (gdp->bg_inode_table < block ||
- gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >=
+ if (le32_to_cpu(gdp->bg_inode_table) < block ||
+ le32_to_cpu(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);
+ i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
return 0;
}
block += EXT2_BLOCKS_PER_GROUP(sb);
@@ -388,6 +365,8 @@ static int ext2_check_descriptors (struct super_block * sb)
return 1;
}
+#define log2(n) ffz(~(n))
+
struct super_block * ext2_read_super (struct super_block * sb, void * data,
int silent)
{
@@ -397,13 +376,27 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
unsigned short resuid = EXT2_DEF_RESUID;
unsigned short resgid = EXT2_DEF_RESGID;
unsigned long logic_sb_block = 1;
- int dev = sb->s_dev;
+ unsigned long offset = 0;
+ kdev_t dev = sb->s_dev;
+ int blocksize = BLOCK_SIZE;
+ int hblock;
int db_count;
int i, j;
-#ifdef EXT2FS_PRE_02B_COMPAT
- int fs_converted = 0;
-#endif
+ /*
+ * See what the current blocksize for the device is, and
+ * use that as the blocksize. Otherwise (or if the blocksize
+ * is smaller than the default) use the default.
+ * This is important for devices that have a hardware
+ * sectorsize that is larger than the default.
+ */
+ blocksize = get_hardblocksize(dev);
+ if( blocksize == 0 || blocksize < BLOCK_SIZE )
+ {
+ blocksize = BLOCK_SIZE;
+ }
+
+ sb->u.ext2_sb.s_mount_opt = 0;
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)) {
@@ -411,212 +404,206 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
return NULL;
}
+ MOD_INC_USE_COUNT;
lock_super (sb);
- set_blocksize (dev, BLOCK_SIZE);
- if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) {
+ set_blocksize (dev, blocksize);
+
+ /*
+ * If the superblock doesn't start on a sector boundary,
+ * calculate the offset. FIXME(eric) this doesn't make sense
+ * that we would have to do this.
+ */
+ if (blocksize != BLOCK_SIZE) {
+ logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
+ offset = (sb_block*BLOCK_SIZE) % blocksize;
+ }
+
+ if (!(bh = bread (dev, logic_sb_block, blocksize))) {
sb->s_dev = 0;
unlock_super (sb);
printk ("EXT2-fs: unable to read superblock\n");
+ MOD_DEC_USE_COUNT;
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;
+ es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
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_magic = le16_to_cpu(es->s_magic);
+ if (sb->s_magic != EXT2_SUPER_MAGIC) {
+ if (!silent)
+ printk ("VFS: Can't find an ext2 filesystem on dev "
+ "%s.\n", bdevname(dev));
+ failed_mount:
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));
+ if (bh)
+ brelse(bh);
+ MOD_DEC_USE_COUNT;
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 ||
+ if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) {
+ if (le32_to_cpu(es->s_feature_incompat) & ~EXT2_FEATURE_INCOMPAT_SUPP) {
+ printk("EXT2-fs: %s: couldn't mount because of "
+ "unsupported optional features.\n",
+ bdevname(dev));
+ goto failed_mount;
+ }
+ if (!(sb->s_flags & MS_RDONLY) &&
+ (le32_to_cpu(es->s_feature_ro_compat) & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
+ printk("EXT2-fs: %s: couldn't mount RDWR because of "
+ "unsupported optional features.\n",
+ bdevname(dev));
+ goto failed_mount;
+ }
+ }
+ sb->s_blocksize_bits = le32_to_cpu(sb->u.ext2_sb.s_es->s_log_block_size) + 10;
+ sb->s_blocksize = 1 << sb->s_blocksize_bits;
+ if (sb->s_blocksize != BLOCK_SIZE &&
+ (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||
sb->s_blocksize == 4096)) {
- unsigned long offset;
+ /*
+ * Make sure the blocksize for the filesystem is larger
+ * than the hardware sectorsize for the machine.
+ */
+ hblock = get_hardblocksize(dev);
+ if( (hblock != 0)
+ && (sb->s_blocksize < hblock) )
+ {
+ printk("EXT2-fs: blocksize too small for device.\n");
+ goto failed_mount;
+ }
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;
+ if(!bh) {
+ printk("EXT2-fs: Couldn't read superblock on "
+ "2nd try.\n");
+ goto failed_mount;
+ }
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);
+ if (es->s_magic != le16_to_cpu(EXT2_SUPER_MAGIC)) {
printk ("EXT2-fs: Magic mismatch, very weird !\n");
- return NULL;
+ goto failed_mount;
}
}
+ if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
+ sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
+ sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
+ } else {
+ sb->u.ext2_sb.s_inode_size = le16_to_cpu(es->s_inode_size);
+ sb->u.ext2_sb.s_first_ino = le32_to_cpu(es->s_first_ino);
+ if (sb->u.ext2_sb.s_inode_size != EXT2_GOOD_OLD_INODE_SIZE) {
+ printk ("EXT2-fs: unsupported inode size: %d\n",
+ sb->u.ext2_sb.s_inode_size);
+ goto failed_mount;
+ }
+ }
+ sb->u.ext2_sb.s_feature_compat = le32_to_cpu(es->s_feature_compat);
+ sb->u.ext2_sb.s_feature_incompat = le32_to_cpu(es->s_feature_incompat);
+ sb->u.ext2_sb.s_feature_ro_compat = le32_to_cpu(es->s_feature_ro_compat);
sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
- es->s_log_frag_size;
+ le32_to_cpu(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_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
+ sb->u.ext2_sb.s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
+ sb->u.ext2_sb.s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize /
- sizeof (struct ext2_inode);
+ EXT2_INODE_SIZE(sb);
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;
+ sb->u.ext2_sb.s_resuid = le16_to_cpu(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
+ sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid);
+ sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
+ sb->u.ext2_sb.s_addr_per_block_bits =
+ log2 (EXT2_ADDR_PER_BLOCK(sb));
+ sb->u.ext2_sb.s_desc_per_block_bits =
+ log2 (EXT2_DESC_PER_BLOCK(sb));
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;
+ printk ("VFS: Can't find an ext2 filesystem on dev "
+ "%s.\n",
+ bdevname(dev));
+ goto failed_mount;
}
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;
+ printk ("VFS: Unsupported blocksize on dev "
+ "%s.\n", bdevname(dev));
+ goto failed_mount;
}
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;
+ goto failed_mount;
}
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;
+ goto failed_mount;
}
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;
+ goto failed_mount;
}
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;
+ goto failed_mount;
}
- sb->u.ext2_sb.s_groups_count = (es->s_blocks_count -
- es->s_first_data_block +
+ sb->u.ext2_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) -
+ le32_to_cpu(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;
+ goto failed_mount;
}
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;
+ goto failed_mount;
}
}
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;
+ goto failed_mount;
}
for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) {
sb->u.ext2_sb.s_inode_bitmap_number[i] = 0;
@@ -633,7 +620,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
*/
sb->s_dev = dev;
sb->s_op = &ext2_sops;
- if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) {
+ sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO));
+ if (!sb->s_root) {
sb->s_dev = 0;
for (i = 0; i < db_count; i++)
if (sb->u.ext2_sb.s_group_desc[i])
@@ -642,15 +630,9 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
db_count * sizeof (struct buffer_head *));
brelse (bh);
printk ("EXT2-fs: get root inode failed\n");
+ MOD_DEC_USE_COUNT;
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;
}
@@ -658,7 +640,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
static void ext2_commit_super (struct super_block * sb,
struct ext2_super_block * es)
{
- es->s_wtime = CURRENT_TIME;
+ es->s_wtime = cpu_to_le32(CURRENT_TIME);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
sb->s_dirt = 0;
}
@@ -683,9 +665,9 @@ void ext2_write_super (struct super_block * sb)
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;
+ if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) {
+ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+ es->s_mtime = cpu_to_le32(CURRENT_TIME);
}
ext2_commit_super (sb, es);
}
@@ -703,7 +685,7 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
/*
* Allow the "check" option to be passed as a remount option.
*/
- set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL);
+ new_mount_opt = EXT2_MOUNT_CHECK_NORMAL;
if (!parse_options (data, &tmp, &resuid, &resgid,
&new_mount_opt))
return -EINVAL;
@@ -715,15 +697,15 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0;
if (*flags & MS_RDONLY) {
- if (es->s_state & EXT2_VALID_FS ||
+ if (le16_to_cpu(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;
+ es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state);
+ es->s_mtime = cpu_to_le32(CURRENT_TIME);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
sb->s_dirt = 1;
ext2_commit_super (sb, es);
@@ -731,21 +713,21 @@ int ext2_remount (struct super_block * sb, int * flags, char * data)
else {
/*
* Mounting a RDONLY partition read-write, so reread and
- * store the current valid flag. (It may have been changed
+ * 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->u.ext2_sb.s_mount_state = le16_to_cpu(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)
+int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
{
- long tmp;
unsigned long overhead;
- unsigned long overhead_per_group;
+ struct statfs tmp;
+ int ngroups, i;
if (test_opt (sb, MINIX_DF))
overhead = 0;
@@ -753,28 +735,68 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf)
/*
* 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;
+
+ /*
+ * All of the blocks before first_data_block are
+ * overhead
+ */
+ overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block);
+
+ /*
+ * Add the overhead attributed to the superblock and
+ * block group descriptors. If this is sparse
+ * superblocks is turned on, then not all groups have
+ * this.
+ */
+ if (sb->u.ext2_sb.s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
+ ngroups = 0;
+ for (i=0 ; i < sb->u.ext2_sb.s_groups_count; i++)
+ if (ext2_group_sparse(i))
+ ngroups++;
+ } else
+ ngroups = sb->u.ext2_sb.s_groups_count;
+ overhead += ngroups * (1 + sb->u.ext2_sb.s_db_per_group);
+
+ /*
+ * Every block group has an inode bitmap, a block
+ * bitmap, and an inode table.
+ */
+ overhead += (sb->u.ext2_sb.s_groups_count *
+ (2 + sb->u.ext2_sb.s_itb_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 */
+ tmp.f_type = EXT2_SUPER_MAGIC;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead;
+ tmp.f_bfree = ext2_count_free_blocks (sb);
+ tmp.f_bavail = tmp.f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
+ if (tmp.f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count))
+ tmp.f_bavail = 0;
+ tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
+ tmp.f_ffree = ext2_count_free_inodes (sb);
+ tmp.f_namelen = EXT2_NAME_LEN;
+ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+
+static struct file_system_type ext2_fs_type = {
+ "ext2",
+ FS_REQUIRES_DEV /* | FS_IBASKET */, /* ibaskets have unresolved bugs */
+ ext2_read_super,
+ NULL
+};
+
+static int __init init_ext2_fs(void)
+{
+ return register_filesystem(&ext2_fs_type);
}
+
+static int __exit exit_ext2_fs(void)
+{
+ unregister_filesystem(&ext2_fs_type);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_ext2_fs)
+module_exit(exit_ext2_fs)
diff --git a/sys/gnu/ext2fs/i386-bitops.h b/sys/gnu/ext2fs/i386-bitops.h
index ee339bd..86068d0 100644
--- a/sys/gnu/ext2fs/i386-bitops.h
+++ b/sys/gnu/ext2fs/i386-bitops.h
@@ -13,86 +13,141 @@
* bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
*/
+#ifdef __SMP__
+#define LOCK_PREFIX "lock ; "
+#else
+#define LOCK_PREFIX ""
+#endif
+
+/*
+ * Function prototypes to keep gcc -Wall happy
+ */
+extern void set_bit(int nr, volatile void * addr);
+extern void clear_bit(int nr, volatile void * addr);
+extern void change_bit(int nr, volatile void * addr);
+extern int test_and_set_bit(int nr, volatile void * addr);
+extern int test_and_clear_bit(int nr, volatile void * addr);
+extern int test_and_change_bit(int nr, volatile void * addr);
+extern int __constant_test_bit(int nr, const volatile void * addr);
+extern int __test_bit(int nr, volatile void * addr);
+extern int find_first_zero_bit(void * addr, unsigned size);
+extern int find_next_zero_bit (void * addr, int size, int offset);
+extern unsigned long ffz(unsigned long word);
+
/*
* Some hacks to defeat gcc over-optimizations..
*/
struct __dummy { unsigned long a[100]; };
-#define ADDR (*(struct __dummy *) addr)
+#define ADDR (*(volatile struct __dummy *) addr)
+#define CONST_ADDR (*(volatile const struct __dummy *) addr)
-extern __inline__ int set_bit(int nr, void * addr)
+extern __inline__ void set_bit(int nr, volatile void * addr)
+{
+ __asm__ __volatile__( LOCK_PREFIX
+ "btsl %1,%0"
+ :"=m" (ADDR)
+ :"Ir" (nr));
+}
+
+extern __inline__ void clear_bit(int nr, volatile void * addr)
+{
+ __asm__ __volatile__( LOCK_PREFIX
+ "btrl %1,%0"
+ :"=m" (ADDR)
+ :"Ir" (nr));
+}
+
+extern __inline__ void change_bit(int nr, volatile void * addr)
+{
+ __asm__ __volatile__( LOCK_PREFIX
+ "btcl %1,%0"
+ :"=m" (ADDR)
+ :"Ir" (nr));
+}
+
+extern __inline__ int test_and_set_bit(int nr, volatile void * addr)
{
int oldbit;
- __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
+ __asm__ __volatile__( LOCK_PREFIX
+ "btsl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
- :"r" (nr));
+ :"Ir" (nr));
return oldbit;
}
-extern __inline__ int clear_bit(int nr, void * addr)
+extern __inline__ int test_and_clear_bit(int nr, volatile void * addr)
{
int oldbit;
- __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
+ __asm__ __volatile__( LOCK_PREFIX
+ "btrl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
- :"r" (nr));
+ :"Ir" (nr));
return oldbit;
}
-extern __inline__ int change_bit(int nr, void * addr)
+extern __inline__ int test_and_change_bit(int nr, volatile void * addr)
{
int oldbit;
- __asm__ __volatile__("btcl %2,%1\n\tsbbl %0,%0"
+ __asm__ __volatile__( LOCK_PREFIX
+ "btcl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit),"=m" (ADDR)
- :"r" (nr));
+ :"Ir" (nr));
return oldbit;
}
/*
- * This routine doesn't need to be atomic, but it's faster to code it
- * this way.
+ * This routine doesn't need to be atomic.
*/
-extern __inline__ int test_bit(int nr, void * addr)
+extern __inline__ int __constant_test_bit(int nr, const volatile void * addr)
+{
+ return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
+}
+
+extern __inline__ int __test_bit(int nr, volatile void * addr)
{
int oldbit;
- __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
+ __asm__ __volatile__(
+ "btl %2,%1\n\tsbbl %0,%0"
:"=r" (oldbit)
- :"m" (ADDR),"r" (nr));
+ :"m" (ADDR),"Ir" (nr));
return oldbit;
}
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ __constant_test_bit((nr),(addr)) : \
+ __test_bit((nr),(addr)))
+
/*
* Find-bit routines..
*/
-extern inline int find_first_zero_bit(void * addr, unsigned size)
+extern __inline__ int find_first_zero_bit(void * addr, unsigned size)
{
+ int d0, d1, d2;
int res;
if (!size)
return 0;
- __asm__("
- cld
- movl $-1,%%eax
- repe; scasl
- je 1f
- subl $4,%%edi
- movl (%%edi),%%eax
- notl %%eax
- bsfl %%eax,%%edx
- jmp 2f
-1: xorl %%edx,%%edx
-2: subl %%ebx,%%edi
- shll $3,%%edi
- addl %%edi,%%edx"
- :"=d" (res)
- :"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
- :"ax", "bx", "cx", "di");
+ __asm__("movl $-1,%%eax\n\t"
+ "xorl %%edx,%%edx\n\t"
+ "repe; scasl\n\t"
+ "je 1f\n\t"
+ "xorl -4(%%edi),%%eax\n\t"
+ "subl $4,%%edi\n\t"
+ "bsfl %%eax,%%edx\n"
+ "1:\tsubl %%ebx,%%edi\n\t"
+ "shll $3,%%edi\n\t"
+ "addl %%edi,%%edx"
+ :"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+ :"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
return res;
}
-extern inline int find_next_zero_bit (void * addr, int size, int offset)
+extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
{
unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
int set = 0, bit = offset & 31, res;
@@ -101,11 +156,10 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset)
/*
* Look for zero in first byte
*/
- __asm__("
- bsfl %1,%0
- jne 1f
- movl $32, %0
-1: "
+ __asm__("bsfl %1,%0\n\t"
+ "jne 1f\n\t"
+ "movl $32, %0\n"
+ "1:"
: "=r" (set)
: "r" (~(*p >> bit)));
if (set < (32 - bit))
@@ -124,7 +178,7 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset)
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
-extern inline unsigned long ffz(unsigned long word)
+extern __inline__ unsigned long ffz(unsigned long word)
{
__asm__("bsfl %1,%0"
:"=r" (word)
@@ -132,4 +186,50 @@ extern inline unsigned long ffz(unsigned long word)
return word;
}
+#ifdef __KERNEL__
+
+/*
+ * ffs: find first bit set. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+extern __inline__ int ffs(int x)
+{
+ int r;
+
+ __asm__("bsfl %1,%0\n\t"
+ "jnz 1f\n\t"
+ "movl $-1,%0\n"
+ "1:" : "=r" (r) : "g" (x));
+ return r+1;
+}
+
+/*
+ * hweightN: returns the hamming weight (i.e. the number
+ * of bits set) of a N-bit word
+ */
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+#endif /* __KERNEL__ */
+
+#ifdef __KERNEL__
+
+#define ext2_set_bit test_and_set_bit
+#define ext2_clear_bit test_and_clear_bit
+#define ext2_test_bit test_bit
+#define ext2_find_first_zero_bit find_first_zero_bit
+#define ext2_find_next_zero_bit find_next_zero_bit
+
+/* Bitmap functions for the minix filesystem. */
+#define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+
+#endif /* __KERNEL__ */
+
#endif /* _I386_BITOPS_H */
OpenPOWER on IntegriCloud