summaryrefslogtreecommitdiffstats
path: root/fs/ext2
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext2')
-rw-r--r--fs/ext2/dir.c4
-rw-r--r--fs/ext2/file.c9
-rw-r--r--fs/ext2/fsync.c39
-rw-r--r--fs/ext2/inode.c86
-rw-r--r--fs/ext2/ioctl.c25
-rw-r--r--fs/ext2/super.c69
-rw-r--r--fs/ext2/symlink.c12
7 files changed, 102 insertions, 142 deletions
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 7de729e4b..fce6fc4c8 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -39,7 +39,7 @@ static struct file_operations ext2_dir_operations = {
ext2_dir_read, /* read */
NULL, /* write - bad */
ext2_readdir, /* readdir */
- NULL, /* select - default */
+ NULL, /* poll - default */
ext2_ioctl, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
@@ -211,7 +211,7 @@ revalidate:
offset = 0;
brelse (bh);
}
- if (!IS_RDONLY(inode)) {
+ if (DO_UPDATE_ATIME(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index c336a5ba6..274dc31fd 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -38,7 +38,7 @@
static long long ext2_file_lseek(struct inode *, struct file *, long long, int);
static long ext2_file_write (struct inode *, struct file *, const char *, unsigned long);
-static void ext2_release_file (struct inode *, struct file *);
+static int ext2_release_file (struct inode *, struct file *);
/*
* We have mostly NULL's here: the current defaults are ok for
@@ -49,7 +49,7 @@ static struct file_operations ext2_file_operations = {
generic_file_read, /* read */
ext2_file_write, /* write */
NULL, /* readdir - bad */
- NULL, /* select - default */
+ NULL, /* poll - default */
ext2_ioctl, /* ioctl */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
@@ -120,7 +120,7 @@ static inline void remove_suid(struct inode *inode)
/* was any of the uid bits set? */
mode &= inode->i_mode;
- if (mode && suser()) {
+ if (mode && !suser()) {
inode->i_mode &= ~mode;
inode->i_dirt = 1;
}
@@ -260,8 +260,9 @@ static long ext2_file_write (struct inode * inode, struct file * filp,
* from ext2_open: open gets called at every open, but release
* gets called only when /all/ the files are closed.
*/
-static void ext2_release_file (struct inode * inode, struct file * filp)
+static int ext2_release_file (struct inode * inode, struct file * filp)
{
if (filp->f_mode & 2)
ext2_discard_prealloc (inode);
+ return 0;
}
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 1d608d07d..9993af1a6 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -13,10 +13,15 @@
*
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
+ *
+ * Removed unnecessary code duplication for little endian machines
+ * and excessive __inline__s.
+ * Andi Kleen, 1997
*/
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/byteorder.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -30,7 +35,7 @@
#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
-static __inline__ int sync_block (struct inode * inode, u32 * block, int wait)
+static int sync_block (struct inode * inode, u32 * block, int wait)
{
struct buffer_head * bh;
int tmp;
@@ -58,7 +63,8 @@ static __inline__ int sync_block (struct inode * inode, u32 * block, int wait)
return 0;
}
-static __inline__ int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
+#ifndef __LITTLE_ENDIAN
+static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
{
struct buffer_head * bh;
int tmp;
@@ -85,8 +91,12 @@ static __inline__ int sync_block_swab32 (struct inode * inode, u32 * block, int
bh->b_count--;
return 0;
}
+#else
+#define sync_block_swab32 sync_block
+#endif
+
-static __inline__ int sync_iblock (struct inode * inode, u32 * iblock,
+static int sync_iblock (struct inode * inode, u32 * iblock,
struct buffer_head ** bh, int wait)
{
int rc, tmp;
@@ -109,7 +119,8 @@ static __inline__ int sync_iblock (struct inode * inode, u32 * iblock,
return 0;
}
-static __inline__ int sync_iblock_swab32 (struct inode * inode, u32 * iblock,
+#ifndef __LITTLE_ENDIAN
+static int sync_iblock_swab32 (struct inode * inode, u32 * iblock,
struct buffer_head ** bh, int wait)
{
int rc, tmp;
@@ -131,9 +142,11 @@ static __inline__ int sync_iblock_swab32 (struct inode * inode, u32 * iblock,
return -1;
return 0;
}
+#else
+#define sync_iblock_swab32 sync_iblock
+#endif
-
-static __inline__ int sync_direct (struct inode * inode, int wait)
+static int sync_direct (struct inode * inode, int wait)
{
int i;
int rc, err = 0;
@@ -148,7 +161,7 @@ static __inline__ int sync_direct (struct inode * inode, int wait)
return err;
}
-static __inline__ int sync_indirect (struct inode * inode, u32 * iblock, int wait)
+static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
{
int i;
struct buffer_head * ind_bh;
@@ -171,6 +184,7 @@ static __inline__ int sync_indirect (struct inode * inode, u32 * iblock, int wai
return err;
}
+#ifndef __LITTLE_ENDIAN
static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
{
int i;
@@ -193,8 +207,11 @@ static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock,
brelse (ind_bh);
return err;
}
+#else
+#define sync_indirect_swab32 sync_indirect
+#endif
-static __inline__ int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
+static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
{
int i;
struct buffer_head * dind_bh;
@@ -217,6 +234,7 @@ static __inline__ int sync_dindirect (struct inode * inode, u32 * diblock, int w
return err;
}
+#ifndef __LITTLE_ENDIAN
static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
{
int i;
@@ -239,8 +257,11 @@ static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock
brelse (dind_bh);
return err;
}
+#else
+#define sync_dindirect_swab32 sync_dindirect
+#endif
-static __inline__ int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
+static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
{
int i;
struct buffer_head * tind_bh;
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index eddcc5ab5..5a876261e 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -329,42 +329,6 @@ repeat:
return result;
}
-static int block_getcluster (struct inode * inode, struct buffer_head * bh,
- int nr,
- int blocksize)
-{
- u32 * p;
- int firstblock = 0;
- int result = 0;
- int i;
-
- /* Check to see if clustering possible here. */
-
- if(!bh) return 0;
-
- if((nr & ((PAGE_SIZE >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)) - 1)) != 0)
- goto out;
- if(nr + 3 > EXT2_ADDR_PER_BLOCK(inode->i_sb)) goto out;
-
- for(i=0; i< (PAGE_SIZE >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); i++) {
- p = (u32 *) bh->b_data + nr + i;
-
- /* All blocks in cluster must already be allocated */
- if(le32_to_cpu(*p) == 0) goto out;
-
- /* See if aligned correctly */
- if(i==0) firstblock = le32_to_cpu(*p);
- else if(le32_to_cpu(*p) != firstblock + i) goto out;
- }
-
- p = (u32 *) bh->b_data + nr;
- result = generate_cluster_swab32(bh->b_dev, (int *) p, blocksize);
-
- out:
- brelse(bh);
- return result;
-}
-
struct buffer_head * ext2_getblk (struct inode * inode, long block,
int create, int * err)
{
@@ -427,56 +391,6 @@ struct buffer_head * ext2_getblk (struct inode * inode, long block,
inode->i_sb->s_blocksize, b, err);
}
-int ext2_getcluster (struct inode * inode, long block)
-{
- struct buffer_head * bh;
- int err, create;
- unsigned long b;
- unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
- create = 0;
- err = -EIO;
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
- return 0;
- }
- if (block > EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
- return 0;
- }
-
- err = -ENOSPC;
- b = block;
- if (block < EXT2_NDIR_BLOCKS) return 0;
-
- block -= EXT2_NDIR_BLOCKS;
-
- if (block < addr_per_block) {
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, &err);
- return block_getcluster (inode, bh, block,
- inode->i_sb->s_blocksize);
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, &err);
- bh = block_getblk (inode, bh, block >> addr_per_block_bits,
- create, inode->i_sb->s_blocksize, b, &err);
- return block_getcluster (inode, bh, block & (addr_per_block - 1),
- inode->i_sb->s_blocksize);
- }
- block -= (1 << (addr_per_block_bits * 2));
- bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, &err);
- bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
- create, inode->i_sb->s_blocksize, b, &err);
- bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize, b, &err);
- return block_getcluster (inode, bh, block & (addr_per_block - 1),
- inode->i_sb->s_blocksize);
-}
-
struct buffer_head * ext2_bread (struct inode * inode, int block,
int create, int *err)
{
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 8235a6301..0892ce79f 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -19,23 +19,16 @@
int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
- int err;
unsigned long flags;
ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg);
switch (cmd) {
case EXT2_IOC_GETFLAGS:
- err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
- if (err)
- return err;
- put_user(inode->u.ext2_i.i_flags, (int *) arg);
- return 0;
+ return put_user(inode->u.ext2_i.i_flags, (int *) arg);
case EXT2_IOC_SETFLAGS:
- err = verify_area(VERIFY_READ, (int *) arg, sizeof(int));
- if (err)
- return err;
- get_user(flags, (int *) arg);
+ if (get_user(flags, (int *) arg))
+ return -EFAULT;
/*
* The IMMUTABLE and APPEND_ONLY flags can only be changed by
* the super user when the security level is zero.
@@ -64,20 +57,14 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
inode->i_dirt = 1;
return 0;
case EXT2_IOC_GETVERSION:
- err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
- if (err)
- return err;
- put_user(inode->u.ext2_i.i_version, (int *) arg);
- return 0;
+ return put_user(inode->u.ext2_i.i_version, (int *) arg);
case EXT2_IOC_SETVERSION:
if ((current->fsuid != inode->i_uid) && !fsuser())
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
- err = verify_area(VERIFY_READ, (int *) arg, sizeof(int));
- if (err)
- return err;
- get_user(inode->u.ext2_i.i_version, (int *) arg);
+ if (get_user(inode->u.ext2_i.i_version, (int *) arg))
+ return -EFAULT;
inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
return 0;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 6bcdb5e20..26e18852e 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -32,6 +32,8 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
static char error_buf[1024];
@@ -129,7 +131,7 @@ void ext2_put_super (struct super_block * sb)
return;
}
-static struct super_operations ext2_sops = {
+static struct super_operations ext2_sops = {
ext2_read_inode,
NULL,
ext2_write_inode,
@@ -377,10 +379,26 @@ 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;
+ unsigned long offset = 0;
kdev_t dev = sb->s_dev;
+ int blocksize = BLOCK_SIZE;
+ int hblock;
int db_count;
int i, j;
+ /*
+ * 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,
@@ -391,8 +409,19 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
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");
@@ -403,7 +432,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
* 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 = le16_to_cpu(es->s_magic);
if (sb->s_magic != EXT2_SUPER_MAGIC) {
@@ -421,24 +450,34 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data,
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",
+ "unsupported optional features.\n",
kdevname(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",
+ "unsupported optional features.\n",
kdevname(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 ||
+ 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);
@@ -675,7 +714,7 @@ 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 = le16_to_cpu(es->s_state);
@@ -689,19 +728,17 @@ static struct file_system_type ext2_fs_type = {
ext2_read_super, "ext2", 1, NULL
};
-int init_ext2_fs(void)
+__initfunc(int init_ext2_fs(void))
{
return register_filesystem(&ext2_fs_type);
}
#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
int init_module(void)
{
- int status;
-
- if ((status = init_ext2_fs()) == 0)
- register_symtab(0);
- return status;
+ return init_ext2_fs();
}
void cleanup_module(void)
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 461e038c2..31f8276b0 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -87,7 +87,7 @@ static int ext2_follow_link(struct inode * dir, struct inode * inode,
link = bh->b_data;
} else
link = (char *) inode->u.ext2_i.i_data;
- if (!IS_RDONLY(inode)) {
+ if (DO_UPDATE_ATIME(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}
@@ -105,7 +105,6 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
struct buffer_head * bh = NULL;
char * link;
int i, err;
- char c;
if (!S_ISLNK(inode->i_mode)) {
iput (inode);
@@ -123,12 +122,13 @@ static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
}
else
link = (char *) inode->u.ext2_i.i_data;
+
i = 0;
- while (i < buflen && (c = link[i])) {
+ while (i < buflen && link[i])
i++;
- put_user (c, buffer++);
- }
- if (!IS_RDONLY(inode)) {
+ if (copy_to_user(buffer, link, i))
+ i = -EFAULT;
+ if (DO_UPDATE_ATIME(inode)) {
inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
}