summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-07-05 23:09:37 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-07-05 23:09:37 +0000
commitaba344fdfed81b2c03d6114c54cfd73a486aa10b (patch)
treed032d8430bf1234c3ecc6f6330d6de6e887e5963 /fs
parent40c138bfc6d37dbff5339f84575db1e3cec6e34e (diff)
Merge with Linux 2.3.9.
Diffstat (limited to 'fs')
-rw-r--r--fs/Makefile8
-rw-r--r--fs/adfs/dir.c6
-rw-r--r--fs/adfs/file.c8
-rw-r--r--fs/affs/dir.c3
-rw-r--r--fs/affs/file.c8
-rw-r--r--fs/affs/symlink.c6
-rw-r--r--fs/autofs/dir.c3
-rw-r--r--fs/autofs/root.c3
-rw-r--r--fs/autofs/symlink.c3
-rw-r--r--fs/bad_inode.c2
-rw-r--r--fs/binfmt_aout.c7
-rw-r--r--fs/binfmt_java.c196
-rw-r--r--fs/buffer.c1243
-rw-r--r--fs/coda/dir.c3
-rw-r--r--fs/coda/file.c8
-rw-r--r--fs/coda/pioctl.c4
-rw-r--r--fs/coda/symlink.c4
-rw-r--r--fs/devices.c9
-rw-r--r--fs/devpts/root.c3
-rw-r--r--fs/efs/dir.c8
-rw-r--r--fs/efs/file.c86
-rw-r--r--fs/efs/symlink.c6
-rw-r--r--fs/exec.c7
-rw-r--r--fs/ext2/dir.c2
-rw-r--r--fs/ext2/file.c20
-rw-r--r--fs/ext2/fsync.c2
-rw-r--r--fs/ext2/inode.c370
-rw-r--r--fs/ext2/namei.c2
-rw-r--r--fs/ext2/symlink.c2
-rw-r--r--fs/ext2/truncate.c33
-rw-r--r--fs/fat/file.c22
-rw-r--r--fs/fifo.c2
-rw-r--r--fs/file_table.c14
-rw-r--r--fs/hfs/dir_cap.c18
-rw-r--r--fs/hfs/dir_dbl.c6
-rw-r--r--fs/hfs/dir_nat.c6
-rw-r--r--fs/hfs/file.c5
-rw-r--r--fs/hfs/file_cap.c3
-rw-r--r--fs/hfs/file_hdr.c5
-rw-r--r--fs/hpfs/Makefile2
-rw-r--r--fs/hpfs/anode.c21
-rw-r--r--fs/hpfs/ea.c19
-rw-r--r--fs/hpfs/file.c210
-rw-r--r--fs/hpfs/hpfs_fn.h2
-rw-r--r--fs/hpfs/inode.c23
-rw-r--r--fs/hpfs/mmap.c128
-rw-r--r--fs/hpfs/super.c2
-rw-r--r--fs/inode.c16
-rw-r--r--fs/ioctl.c13
-rw-r--r--fs/isofs/dir.c7
-rw-r--r--fs/isofs/file.c6
-rw-r--r--fs/isofs/inode.c180
-rw-r--r--fs/isofs/symlink.c7
-rw-r--r--fs/lockd/host.c1
-rw-r--r--fs/locks.c13
-rw-r--r--fs/minix/dir.c7
-rw-r--r--fs/minix/file.c53
-rw-r--r--fs/minix/fsync.c4
-rw-r--r--fs/minix/inode.c567
-rw-r--r--fs/minix/symlink.c7
-rw-r--r--fs/minix/truncate.c12
-rw-r--r--fs/msdos/namei.c3
-rw-r--r--fs/ncpfs/dir.c3
-rw-r--r--fs/ncpfs/file.c11
-rw-r--r--fs/ncpfs/symlink.c6
-rw-r--r--fs/nfs/dir.c8
-rw-r--r--fs/nfs/file.c4
-rw-r--r--fs/nfs/symlink.c2
-rw-r--r--fs/nfs/write.c2
-rw-r--r--fs/nfsd/vfs.c4
-rw-r--r--fs/ntfs/fs.c11
-rw-r--r--fs/open.c2
-rw-r--r--fs/pipe.c43
-rw-r--r--fs/proc/array.c4
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/fd.c2
-rw-r--r--fs/proc/generic.c4
-rw-r--r--fs/proc/kmsg.c2
-rw-r--r--fs/proc/link.c2
-rw-r--r--fs/proc/mem.c2
-rw-r--r--fs/proc/net.c2
-rw-r--r--fs/proc/omirr.c2
-rw-r--r--fs/proc/openpromfs.c21
-rw-r--r--fs/proc/proc_devtree.c2
-rw-r--r--fs/proc/root.c12
-rw-r--r--fs/proc/scsi.c2
-rw-r--r--fs/proc/sysvipc.c2
-rw-r--r--fs/qnx4/dir.c6
-rw-r--r--fs/qnx4/file.c6
-rw-r--r--fs/qnx4/fsync.c2
-rw-r--r--fs/qnx4/symlinks.c7
-rw-r--r--fs/read_write.c66
-rw-r--r--fs/romfs/inode.c131
-rw-r--r--fs/select.c18
-rw-r--r--fs/smbfs/dir.c3
-rw-r--r--fs/smbfs/file.c3
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/sysv/balloc.c2
-rw-r--r--fs/sysv/dir.c7
-rw-r--r--fs/sysv/file.c50
-rw-r--r--fs/sysv/fsync.c2
-rw-r--r--fs/sysv/inode.c359
-rw-r--r--fs/sysv/symlink.c7
-rw-r--r--fs/sysv/truncate.c2
-rw-r--r--fs/ufs/dir.c10
-rw-r--r--fs/ufs/file.c58
-rw-r--r--fs/ufs/inode.c400
-rw-r--r--fs/ufs/super.c23
-rw-r--r--fs/ufs/symlink.c6
-rw-r--r--fs/ufs/truncate.c2
-rw-r--r--fs/ufs/util.c4
-rw-r--r--fs/umsdos/dir.c5
-rw-r--r--fs/umsdos/file.c16
-rw-r--r--fs/umsdos/rdir.c2
-rw-r--r--fs/umsdos/symlink.c5
-rw-r--r--fs/vfat/namei.c7
116 files changed, 2334 insertions, 2483 deletions
diff --git a/fs/Makefile b/fs/Makefile
index b94509a03..069b1a2a4 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -263,14 +263,6 @@ else
endif
endif
-ifeq ($(CONFIG_BINFMT_JAVA),y)
-BINFMTS += binfmt_java.o
-else
- ifeq ($(CONFIG_BINFMT_JAVA),m)
- M_OBJS += binfmt_java.o
- endif
-endif
-
ifeq ($(CONFIG_BINFMT_EM86),y)
BINFMTS += binfmt_em86.o
else
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 738bb40b8..0d0d11a06 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -51,12 +51,14 @@ struct inode_operations adfs_dir_inode_operations = {
NULL, /* rename */
NULL, /* read link */
NULL, /* follow link */
+ NULL, /* get_block */
NULL, /* read page */
NULL, /* write page */
- NULL, /* bmap */
+ NULL, /* flush page */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
unsigned int adfs_val (unsigned char *p, int len)
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index a886c68ce..c415597e3 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -61,10 +61,12 @@ struct inode_operations adfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ adfs_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- adfs_bmap, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/affs/dir.c b/fs/affs/dir.c
index ee08ff451..b88eac770 100644
--- a/fs/affs/dir.c
+++ b/fs/affs/dir.c
@@ -57,9 +57,10 @@ struct inode_operations affs_dir_inode_operations = {
affs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permissions */
NULL, /* smap */
diff --git a/fs/affs/file.c b/fs/affs/file.c
index bb1ce69c8..358c1c56c 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -74,9 +74,10 @@ struct inode_operations affs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ affs_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- affs_bmap, /* bmap */
+ NULL, /* flushpage */
affs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
@@ -114,9 +115,10 @@ struct inode_operations affs_file_inode_operations_ofs = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
affs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index c3da66d40..18c03730f 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -35,12 +35,14 @@ struct inode_operations affs_symlink_inode_operations = {
NULL, /* rename */
affs_readlink, /* readlink */
affs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index f6ccf8419..a8262e701 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -73,9 +73,10 @@ struct inode_operations autofs_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 011e3286f..c6034c754 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -54,9 +54,10 @@ struct inode_operations autofs_root_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index 0e46db365..6ca720527 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -49,9 +49,10 @@ struct inode_operations autofs_symlink_inode_operations = {
NULL, /* rename */
autofs_readlink, /* readlink */
autofs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 89711607b..2691953f2 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -60,7 +60,7 @@ struct inode_operations bad_inode_ops =
EIO_ERROR, /* rename */
EIO_ERROR, /* readlink */
bad_follow_link, /* follow_link */
- EIO_ERROR, /* bmap */
+ EIO_ERROR, /* get_block */
EIO_ERROR, /* readpage */
EIO_ERROR, /* writepage */
EIO_ERROR, /* flushpage */
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 2b886a147..4723c6802 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -323,7 +323,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
bprm->dentry->d_inode->i_op &&
- bprm->dentry->d_inode->i_op->bmap &&
+ bprm->dentry->d_inode->i_op->get_block &&
(fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
return -ENOEXEC;
@@ -396,7 +396,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
fd = open_dentry(bprm->dentry, O_RDONLY);
if (fd < 0)
return fd;
- file = fcheck(fd);
+ file = fget(fd);
if ((fd_offset & ~PAGE_MASK) != 0) {
printk(KERN_WARNING
@@ -406,6 +406,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
}
if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
+ fput(file);
sys_close(fd);
do_brk(0, ex.a_text+ex.a_data);
read_exec(bprm->dentry, fd_offset,
@@ -422,6 +423,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
fd_offset);
if (error != N_TXTADDR(ex)) {
+ fput(file);
sys_close(fd);
send_sig(SIGKILL, current, 0);
return error;
@@ -431,6 +433,7 @@ static inline int do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
fd_offset + ex.a_text);
+ fput(file);
sys_close(fd);
if (error != N_DATADDR(ex)) {
send_sig(SIGKILL, current, 0);
diff --git a/fs/binfmt_java.c b/fs/binfmt_java.c
deleted file mode 100644
index 2bd036d98..000000000
--- a/fs/binfmt_java.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * linux/fs/binfmt_java.c
- *
- * Copyright (C) 1996 Brian A. Lantz
- * derived from binfmt_script.c
- *
- * Simplified and modified to support binary java interpreters
- * by Tom May <ftom@netcom.com>.
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/malloc.h>
-#include <linux/binfmts.h>
-#include <linux/init.h>
-
-#define _PATH_JAVA "/usr/bin/java"
-#define _PATH_APPLET "/usr/bin/appletviewer"
-
-/* These paths can be modified with sysctl(). */
-
-char binfmt_java_interpreter[65] = _PATH_JAVA;
-char binfmt_java_appletviewer[65] = _PATH_APPLET;
-
-static int do_load_java(struct linux_binprm *bprm,struct pt_regs *regs)
-{
- char *i_name;
- int len;
- int retval;
- struct dentry * dentry;
- unsigned char *ucp = (unsigned char *) bprm->buf;
-
- if ((ucp[0] != 0xca) || (ucp[1] != 0xfe) || (ucp[2] != 0xba) || (ucp[3] != 0xbe))
- return -ENOEXEC;
-
- /*
- * Fail if we're called recursively, e.g., the Java interpreter
- * is a java binary.
- */
-
- if (bprm->java)
- return -ENOEXEC;
-
- bprm->java = 1;
-
- dput(bprm->dentry);
- bprm->dentry = NULL;
-
- /*
- * Set args: [0] the name of the java interpreter
- * [1] name of java class to execute, which is the
- * filename without the path and without trailing
- * ".class". Note that the interpreter will use
- * its own way to found the class file (typically using
- * environment variable CLASSPATH), and may in fact
- * execute a different file from the one we want.
- *
- * This is done in reverse order, because of how the
- * user environment and arguments are stored.
- */
- remove_arg_zero(bprm);
- len = strlen (bprm->filename);
- if (len >= 6 && !strcmp (bprm->filename + len - 6, ".class"))
- bprm->filename[len - 6] = 0;
- if ((i_name = strrchr (bprm->filename, '/')) != NULL)
- i_name++;
- else
- i_name = bprm->filename;
-
- retval = copy_strings_kernel(1, &i_name, bprm);
- if (retval < 0)
- return retval;
- bprm->argc++;
-
- i_name = binfmt_java_interpreter;
- retval = copy_strings_kernel(1, &i_name, bprm);
- if (retval < 0)
- return retval;
- bprm->argc++;
-
- /*
- * OK, now restart the process with the interpreter's dentry.
- */
- bprm->filename = binfmt_java_interpreter;
- dentry = open_namei(binfmt_java_interpreter, 0, 0);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- return retval;
-
- bprm->dentry = dentry;
- retval = prepare_binprm(bprm);
- if (retval < 0)
- return retval;
-
- return search_binary_handler(bprm,regs);
-}
-
-static int do_load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
-{
- char *i_name;
- struct dentry * dentry;
- int retval;
-
- if (strncmp (bprm->buf, "<!--applet", 10))
- return -ENOEXEC;
-
- dput(bprm->dentry);
- bprm->dentry = NULL;
-
- /*
- * Set args: [0] the name of the appletviewer
- * [1] filename of html file
- *
- * This is done in reverse order, because of how the
- * user environment and arguments are stored.
- */
- remove_arg_zero(bprm);
- i_name = bprm->filename;
- retval = copy_strings_kernel(1, &i_name, bprm);
- if (retval < 0) return retval;
- bprm->argc++;
-
- i_name = binfmt_java_appletviewer;
- retval = copy_strings_kernel(1, &i_name, bprm);
- if (retval < 0) return retval;
- bprm->argc++;
-
- /*
- * OK, now restart the process with the interpreter's dentry.
- */
- bprm->filename = binfmt_java_appletviewer;
- dentry = open_namei(binfmt_java_appletviewer, 0, 0);
- retval = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- return retval;
-
- bprm->dentry = dentry;
- retval = prepare_binprm(bprm);
- if (retval < 0)
- return retval;
-
- return search_binary_handler(bprm,regs);
-}
-
-static int load_java(struct linux_binprm *bprm,struct pt_regs *regs)
-{
- int retval;
- MOD_INC_USE_COUNT;
- retval = do_load_java(bprm,regs);
- MOD_DEC_USE_COUNT;
- return retval;
-}
-
-static struct linux_binfmt java_format = {
-#ifndef MODULE
- NULL, 0, load_java, NULL, NULL
-#else
- NULL, &__this_module, load_java, NULL, NULL
-#endif
-};
-
-static int load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
-{
- int retval;
- MOD_INC_USE_COUNT;
- retval = do_load_applet(bprm,regs);
- MOD_DEC_USE_COUNT;
- return retval;
-}
-
-static struct linux_binfmt applet_format = {
-#ifndef MODULE
- NULL, 0, load_applet, NULL, NULL
-#else
- NULL, &__this_module, load_applet, NULL, NULL
-#endif
-};
-
-int __init init_java_binfmt(void)
-{
- register_binfmt(&java_format);
- return register_binfmt(&applet_format);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- return init_java_binfmt();
-}
-
-void cleanup_module( void) {
- unregister_binfmt(&java_format);
- unregister_binfmt(&applet_format);
-}
-#endif
diff --git a/fs/buffer.c b/fs/buffer.c
index 9ffb8556a..108b385ea 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -24,6 +24,8 @@
* - RMK
*/
+/* Thread it... -DaveM */
+
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/malloc.h>
@@ -57,31 +59,39 @@ static char buffersize_index[65] =
#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this
number of unused buffer heads */
-/*
- * Hash table mask..
+/* Anti-deadlock ordering:
+ * lru_list_lock > hash_table_lock > free_list_lock > unused_list_lock
*/
-static unsigned long bh_hash_mask = 0;
-
-static int grow_buffers(int size);
-static struct buffer_head ** hash_table;
-static struct buffer_head * lru_list[NR_LIST] = {NULL, };
-static struct buffer_head * free_list[NR_SIZES] = {NULL, };
+/*
+ * Hash table gook..
+ */
+static unsigned int bh_hash_mask = 0;
+static unsigned int bh_hash_shift = 0;
+static struct buffer_head **hash_table;
+static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED;
-static kmem_cache_t *bh_cachep;
+static struct buffer_head *lru_list[NR_LIST];
+static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED;
+static int nr_buffers_type[NR_LIST] = {0,};
static struct buffer_head * unused_list = NULL;
-static struct buffer_head * reuse_list = NULL;
+static int nr_unused_buffer_heads = 0;
+static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
-static int nr_buffers = 0;
-static int nr_buffers_type[NR_LIST] = {0,};
-static int nr_buffer_heads = 0;
-static int nr_unused_buffer_heads = 0;
-static int nr_hashed_buffers = 0;
+struct bh_free_head {
+ struct buffer_head *list;
+ spinlock_t lock;
+};
+static struct bh_free_head free_list[NR_SIZES];
+
+static kmem_cache_t *bh_cachep;
+
+static int grow_buffers(int size);
/* This is used by some architectures to estimate available memory. */
-int buffermem = 0;
+atomic_t buffermem = ATOMIC_INIT(0);
/* Here is the parameter block for the bdflush process. If you add or
* remove any of the parameters, make sure to update kernel/sysctl.c.
@@ -131,7 +141,7 @@ void __wait_on_buffer(struct buffer_head * bh)
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
- bh->b_count++;
+ atomic_inc(&bh->b_count);
add_wait_queue(&bh->b_wait, &wait);
repeat:
tsk->state = TASK_UNINTERRUPTIBLE;
@@ -142,7 +152,7 @@ repeat:
}
tsk->state = TASK_RUNNING;
remove_wait_queue(&bh->b_wait, &wait);
- bh->b_count--;
+ atomic_dec(&bh->b_count);
}
/* Call sync_buffers with wait!=0 to ensure that the call does not
@@ -167,17 +177,19 @@ static int sync_buffers(kdev_t dev, int wait)
*/
do {
retry = 0;
-repeat:
+
/* We search all lists as a failsafe mechanism, not because we expect
* there to be dirty buffers on any of the other lists.
*/
+repeat:
+ spin_lock(&lru_list_lock);
bh = lru_list[BUF_DIRTY];
if (!bh)
goto repeat2;
+
for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) {
- if (bh->b_list != BUF_DIRTY)
- goto repeat;
next = bh->b_next_free;
+
if (!lru_list[BUF_DIRTY])
break;
if (dev && bh->b_dev != dev)
@@ -190,7 +202,10 @@ repeat:
retry = 1;
continue;
}
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
wait_on_buffer (bh);
+ atomic_dec(&bh->b_count);
goto repeat;
}
@@ -209,30 +224,24 @@ repeat:
if (!buffer_dirty(bh) || pass >= 2)
continue;
- /* Don't bother about locked buffers.
- *
- * XXX We checked if it was locked above and there is no
- * XXX way we could have slept in between. -DaveM
- */
- if (buffer_locked(bh))
- continue;
- bh->b_count++;
- next->b_count++;
+ atomic_inc(&bh->b_count);
bh->b_flushtime = 0;
+ spin_unlock(&lru_list_lock);
ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
- next->b_count--;
+ atomic_dec(&bh->b_count);
retry = 1;
+ goto repeat;
}
repeat2:
bh = lru_list[BUF_LOCKED];
- if (!bh)
+ if (!bh) {
+ spin_unlock(&lru_list_lock);
break;
+ }
for (i = nr_buffers_type[BUF_LOCKED]*2 ; i-- > 0 ; bh = next) {
- if (bh->b_list != BUF_LOCKED)
- goto repeat2;
next = bh->b_next_free;
+
if (!lru_list[BUF_LOCKED])
break;
if (dev && bh->b_dev != dev)
@@ -245,10 +254,15 @@ repeat:
retry = 1;
continue;
}
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
wait_on_buffer (bh);
+ spin_lock(&lru_list_lock);
+ atomic_dec(&bh->b_count);
goto repeat2;
}
}
+ spin_unlock(&lru_list_lock);
/* If we are waiting for the sync to succeed, and if any dirty
* blocks were written, then repeat; on the second pass, only
@@ -282,17 +296,19 @@ void sync_dev(kdev_t dev)
int fsync_dev(kdev_t dev)
{
sync_buffers(dev, 0);
+
+ lock_kernel();
sync_supers(dev);
sync_inodes(dev);
DQUOT_SYNC(dev);
+ unlock_kernel();
+
return sync_buffers(dev, 1);
}
asmlinkage int sys_sync(void)
{
- lock_kernel();
fsync_dev(0);
- unlock_kernel();
return 0;
}
@@ -396,19 +412,28 @@ out:
void invalidate_buffers(kdev_t dev)
{
- int i;
int nlist;
- struct buffer_head * bh;
+ spin_lock(&lru_list_lock);
for(nlist = 0; nlist < NR_LIST; nlist++) {
+ struct buffer_head * bh;
+ int i;
+ retry:
bh = lru_list[nlist];
+ if (!bh)
+ continue;
for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bh->b_next_free) {
if (bh->b_dev != dev)
continue;
- wait_on_buffer(bh);
- if (bh->b_dev != dev)
- continue;
- if (bh->b_count)
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ spin_lock(&lru_list_lock);
+ atomic_dec(&bh->b_count);
+ goto retry;
+ }
+ if (atomic_read(&bh->b_count))
continue;
bh->b_flushtime = 0;
clear_bit(BH_Protected, &bh->b_state);
@@ -417,157 +442,119 @@ void invalidate_buffers(kdev_t dev)
clear_bit(BH_Req, &bh->b_state);
}
}
+ spin_unlock(&lru_list_lock);
}
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
-#define hash(dev,block) hash_table[_hashfn(dev,block)]
+/* After several hours of tedious analysis, the following hash
+ * function won. Do not mess with it... -DaveM
+ */
+#define _hashfn(dev,block) \
+ ((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
+ (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12))))
+#define hash(dev,block) hash_table[(_hashfn(dev,block) & bh_hash_mask)]
-static void insert_into_hash_list(struct buffer_head * bh)
+static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **head)
{
- bh->b_next = NULL;
- bh->b_pprev = NULL;
- if (bh->b_dev) {
- struct buffer_head **bhp = &hash(bh->b_dev, bh->b_blocknr);
- struct buffer_head *next = *bhp;
-
- if (next) {
- bh->b_next = next;
- next->b_pprev = &bh->b_next;
- }
- *bhp = bh;
- bh->b_pprev = bhp;
- nr_hashed_buffers++;
- }
+ if ((bh->b_next = *head) != NULL)
+ bh->b_next->b_pprev = &bh->b_next;
+ *head = bh;
+ bh->b_pprev = head;
}
-static void remove_from_hash_queue(struct buffer_head * bh)
+static __inline__ void __hash_unlink(struct buffer_head *bh)
{
- struct buffer_head **pprev = bh->b_pprev;
- if (pprev) {
- struct buffer_head * next = bh->b_next;
- if (next) {
- next->b_pprev = pprev;
- bh->b_next = NULL;
- }
- *pprev = next;
- bh->b_pprev = NULL;
- nr_hashed_buffers--;
- }
+ if (bh->b_next)
+ bh->b_next->b_pprev = bh->b_pprev;
+ *(bh->b_pprev) = bh->b_next;
+ bh->b_pprev = NULL;
}
-static void insert_into_lru_list(struct buffer_head * bh)
+static void __insert_into_lru_list(struct buffer_head * bh, int blist)
{
- struct buffer_head **bhp = &lru_list[bh->b_list];
-
- if (bh->b_dev == B_FREE)
- BUG();
+ struct buffer_head **bhp = &lru_list[blist];
if(!*bhp) {
*bhp = bh;
bh->b_prev_free = bh;
}
-
- if (bh->b_next_free)
- panic("VFS: buffer LRU pointers corrupted");
-
bh->b_next_free = *bhp;
bh->b_prev_free = (*bhp)->b_prev_free;
(*bhp)->b_prev_free->b_next_free = bh;
(*bhp)->b_prev_free = bh;
-
- nr_buffers++;
- nr_buffers_type[bh->b_list]++;
+ nr_buffers_type[blist]++;
}
-static void remove_from_lru_list(struct buffer_head * bh)
+static void __remove_from_lru_list(struct buffer_head * bh, int blist)
{
- if (!(bh->b_prev_free) || !(bh->b_next_free))
- return;
-
- if (bh->b_dev == B_FREE) {
- printk("LRU list corrupted");
- *(int*)0 = 0;
+ if (bh->b_prev_free || bh->b_next_free) {
+ bh->b_prev_free->b_next_free = bh->b_next_free;
+ bh->b_next_free->b_prev_free = bh->b_prev_free;
+ if (lru_list[blist] == bh)
+ lru_list[blist] = bh->b_next_free;
+ if (lru_list[blist] == bh)
+ lru_list[blist] = NULL;
+ bh->b_next_free = bh->b_prev_free = NULL;
+ nr_buffers_type[blist]--;
}
- bh->b_prev_free->b_next_free = bh->b_next_free;
- bh->b_next_free->b_prev_free = bh->b_prev_free;
-
- if (lru_list[bh->b_list] == bh)
- lru_list[bh->b_list] = bh->b_next_free;
- if (lru_list[bh->b_list] == bh)
- lru_list[bh->b_list] = NULL;
- bh->b_next_free = bh->b_prev_free = NULL;
-
- nr_buffers--;
- nr_buffers_type[bh->b_list]--;
}
-static void remove_from_free_list(struct buffer_head * bh)
+static void __remove_from_free_list(struct buffer_head * bh, int index)
{
- int isize = BUFSIZE_INDEX(bh->b_size);
- if (!(bh->b_prev_free) || !(bh->b_next_free))
- panic("VFS: Free block list corrupted");
- if(bh->b_dev != B_FREE)
- panic("Free list corrupted");
- if(!free_list[isize])
- panic("Free list empty");
if(bh->b_next_free == bh)
- free_list[isize] = NULL;
+ free_list[index].list = NULL;
else {
bh->b_prev_free->b_next_free = bh->b_next_free;
bh->b_next_free->b_prev_free = bh->b_prev_free;
- if (free_list[isize] == bh)
- free_list[isize] = bh->b_next_free;
+ if (free_list[index].list == bh)
+ free_list[index].list = bh->b_next_free;
}
bh->b_next_free = bh->b_prev_free = NULL;
}
-static void remove_from_queues(struct buffer_head * bh)
+/* The following two functions must operate atomically
+ * because they control the visibility of a buffer head
+ * to the rest of the kernel.
+ */
+static __inline__ void __remove_from_queues(struct buffer_head *bh)
{
- if (bh->b_dev == B_FREE)
- BUG();
- remove_from_hash_queue(bh);
- remove_from_lru_list(bh);
+ write_lock(&hash_table_lock);
+ if (bh->b_pprev)
+ __hash_unlink(bh);
+ __remove_from_lru_list(bh, bh->b_list);
+ write_unlock(&hash_table_lock);
}
-static void put_last_free(struct buffer_head * bh)
+static void insert_into_queues(struct buffer_head *bh)
{
- if (bh) {
- struct buffer_head **bhp = &free_list[BUFSIZE_INDEX(bh->b_size)];
-
- if (bh->b_count)
- BUG();
-
- bh->b_dev = B_FREE; /* So it is obvious we are on the free list. */
-
- /* Add to back of free list. */
- if(!*bhp) {
- *bhp = bh;
- bh->b_prev_free = bh;
- }
-
- bh->b_next_free = *bhp;
- bh->b_prev_free = (*bhp)->b_prev_free;
- (*bhp)->b_prev_free->b_next_free = bh;
- (*bhp)->b_prev_free = bh;
- }
+ struct buffer_head **head = &hash(bh->b_dev, bh->b_blocknr);
+
+ spin_lock(&lru_list_lock);
+ write_lock(&hash_table_lock);
+ __hash_link(bh, head);
+ __insert_into_lru_list(bh, bh->b_list);
+ write_unlock(&hash_table_lock);
+ spin_unlock(&lru_list_lock);
}
-struct buffer_head * find_buffer(kdev_t dev, int block, int size)
-{
- struct buffer_head * next;
+/* This function must only run if there are no other
+ * references _anywhere_ to this buffer head.
+ */
+static void put_last_free(struct buffer_head * bh)
+{
+ struct bh_free_head *head = &free_list[BUFSIZE_INDEX(bh->b_size)];
+ struct buffer_head **bhp = &head->list;
- next = hash(dev,block);
- for (;;) {
- struct buffer_head *tmp = next;
- if (!next)
- break;
- next = tmp->b_next;
- if (tmp->b_blocknr != block || tmp->b_size != size || tmp->b_dev != dev)
- continue;
- next = tmp;
- break;
+ spin_lock(&head->lock);
+ bh->b_dev = B_FREE;
+ if(!*bhp) {
+ *bhp = bh;
+ bh->b_prev_free = bh;
}
- return next;
+ bh->b_next_free = *bhp;
+ bh->b_prev_free = (*bhp)->b_prev_free;
+ (*bhp)->b_prev_free->b_next_free = bh;
+ (*bhp)->b_prev_free = bh;
+ spin_unlock(&head->lock);
}
/*
@@ -579,10 +566,19 @@ struct buffer_head * find_buffer(kdev_t dev, int block, int size)
*/
struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
{
- struct buffer_head * bh;
- bh = find_buffer(dev,block,size);
+ struct buffer_head **head = &hash(dev, block);
+ struct buffer_head *bh;
+
+ read_lock(&hash_table_lock);
+ for(bh = *head; bh; bh = bh->b_next)
+ if (bh->b_blocknr == block &&
+ bh->b_size == size &&
+ bh->b_dev == dev)
+ break;
if (bh)
- bh->b_count++;
+ atomic_inc(&bh->b_count);
+ read_unlock(&hash_table_lock);
+
return bh;
}
@@ -631,6 +627,8 @@ void set_blocksize(kdev_t dev, int size)
* around on the free list, and we can get in a loop if we are not careful.
*/
for(nlist = 0; nlist < NR_LIST; nlist++) {
+ repeat:
+ spin_lock(&lru_list_lock);
bh = lru_list[nlist];
for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bhnext) {
if(!bh)
@@ -641,21 +639,25 @@ void set_blocksize(kdev_t dev, int size)
continue;
if (bh->b_size == size)
continue;
- bhnext->b_count++;
- bh->b_count++;
- wait_on_buffer(bh);
- bhnext->b_count--;
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ wait_on_buffer(bh);
+ atomic_dec(&bh->b_count);
+ goto repeat;
+ }
if (bh->b_dev == dev && bh->b_size != size) {
clear_bit(BH_Dirty, &bh->b_state);
clear_bit(BH_Uptodate, &bh->b_state);
clear_bit(BH_Req, &bh->b_state);
bh->b_flushtime = 0;
}
- if (--bh->b_count)
- continue;
- remove_from_queues(bh);
- put_last_free(bh);
+ if (atomic_read(&bh->b_count) == 0) {
+ __remove_from_queues(bh);
+ put_last_free(bh);
+ }
}
+ spin_unlock(&lru_list_lock);
}
}
@@ -671,13 +673,10 @@ static void refill_freelist(int size)
}
}
-void init_buffer(struct buffer_head *bh, kdev_t dev, int block,
- bh_end_io_t *handler, void *dev_id)
+void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *dev_id)
{
bh->b_list = BUF_CLEAN;
bh->b_flushtime = 0;
- bh->b_dev = dev;
- bh->b_blocknr = block;
bh->b_end_io = handler;
bh->b_dev_id = dev_id;
}
@@ -688,6 +687,92 @@ static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
unlock_buffer(bh);
}
+static void end_buffer_io_bad(struct buffer_head *bh, int uptodate)
+{
+ mark_buffer_uptodate(bh, uptodate);
+ unlock_buffer(bh);
+ BUG();
+}
+
+static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
+{
+ static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
+ unsigned long flags;
+ struct buffer_head *tmp;
+ struct page *page;
+ int free;
+
+ mark_buffer_uptodate(bh, uptodate);
+
+ /* This is a temporary buffer used for page I/O. */
+ page = mem_map + MAP_NR(bh->b_data);
+
+ if (!uptodate)
+ SetPageError(page);
+
+ /*
+ * Be _very_ careful from here on. Bad things can happen if
+ * two buffer heads end IO at almost the same time and both
+ * decide that the page is now completely done.
+ *
+ * Async buffer_heads are here only as labels for IO, and get
+ * thrown away once the IO for this page is complete. IO is
+ * deemed complete once all buffers have been visited
+ * (b_count==0) and are now unlocked. We must make sure that
+ * only the _last_ buffer that decrements its count is the one
+ * that free's the page..
+ */
+ spin_lock_irqsave(&page_uptodate_lock, flags);
+ unlock_buffer(bh);
+ atomic_dec(&bh->b_count);
+ tmp = bh->b_this_page;
+ while (tmp != bh) {
+ if (atomic_read(&tmp->b_count) &&
+ (tmp->b_end_io == end_buffer_io_async))
+ goto still_busy;
+ tmp = tmp->b_this_page;
+ }
+
+ /* OK, the async IO on this page is complete. */
+ spin_unlock_irqrestore(&page_uptodate_lock, flags);
+
+ /*
+ * if none of the buffers had errors then we can set the
+ * page uptodate:
+ */
+ if (!PageError(page))
+ SetPageUptodate(page);
+
+ /*
+ * Run the hooks that have to be done when a page I/O has completed.
+ *
+ * Note - we need to test the flags before we unlock the page, but
+ * we must not actually free the page until after the unlock!
+ */
+ if (test_and_clear_bit(PG_decr_after, &page->flags))
+ atomic_dec(&nr_async_pages);
+
+ if (test_and_clear_bit(PG_free_swap_after, &page->flags))
+ swap_free(page->offset);
+
+ free = test_and_clear_bit(PG_free_after, &page->flags);
+
+ if (page->owner != -1)
+ PAGE_BUG(page);
+ page->owner = (int)current;
+ UnlockPage(page);
+
+ if (free)
+ __free_page(page);
+
+ return;
+
+still_busy:
+ spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ return;
+}
+
+
/*
* Ok, this is getblk, and it isn't very clear, again to hinder
* race-conditions. Most of the code is seldom used, (ie repeating),
@@ -713,22 +798,26 @@ repeat:
}
isize = BUFSIZE_INDEX(size);
-get_free:
- bh = free_list[isize];
+ spin_lock(&free_list[isize].lock);
+ bh = free_list[isize].list;
+ if (bh) {
+ __remove_from_free_list(bh, isize);
+ atomic_set(&bh->b_count, 1);
+ }
+ spin_unlock(&free_list[isize].lock);
if (!bh)
goto refill;
- remove_from_free_list(bh);
/* OK, FINALLY we know that this buffer is the only one of its kind,
- * and that it's unused (b_count=0), unlocked, and clean.
+ * we hold a reference (b_count>0), it is unlocked, and it is clean.
*/
- init_buffer(bh, dev, block, end_buffer_io_sync, NULL);
- bh->b_count = 1;
- bh->b_state = 0;
+ init_buffer(bh, end_buffer_io_sync, NULL);
+ bh->b_dev = dev;
+ bh->b_blocknr = block;
+ bh->b_state = 1 << BH_Mapped;
/* Insert the buffer into the regular lists */
- insert_into_lru_list(bh);
- insert_into_hash_list(bh);
+ insert_into_queues(bh);
goto out;
/*
@@ -737,24 +826,12 @@ get_free:
*/
refill:
refill_freelist(size);
- if (!find_buffer(dev,block,size))
- goto get_free;
goto repeat;
out:
return bh;
}
/*
- * Put a buffer into the appropriate list, without side-effects.
- */
-static void file_buffer(struct buffer_head *bh, int list)
-{
- remove_from_lru_list(bh);
- bh->b_list = list;
- insert_into_lru_list(bh);
-}
-
-/*
* if a new dirty buffer is created we need to balance bdflush.
*
* in the future we might want to make bdflush aware of different
@@ -783,6 +860,7 @@ void balance_dirty(kdev_t dev)
static inline void __mark_dirty(struct buffer_head *bh, int flag)
{
bh->b_flushtime = jiffies + (flag ? bdf_prm.b_un.age_super : bdf_prm.b_un.age_buffer);
+ clear_bit(BH_New, &bh->b_state);
refile_buffer(bh);
}
@@ -791,34 +869,29 @@ void __mark_buffer_dirty(struct buffer_head *bh, int flag)
__mark_dirty(bh, flag);
}
-void __atomic_mark_buffer_dirty(struct buffer_head *bh, int flag)
-{
- lock_kernel();
- __mark_dirty(bh, flag);
- unlock_kernel();
-}
-
/*
* A buffer may need to be moved from one buffer list to another
* (e.g. in case it is not shared any more). Handle this.
*/
-void refile_buffer(struct buffer_head * buf)
+static __inline__ void __refile_buffer(struct buffer_head *bh)
{
- int dispose;
-
- if (buf->b_dev == B_FREE) {
- printk("Attempt to refile free buffer\n");
- return;
- }
-
- dispose = BUF_CLEAN;
- if (buffer_locked(buf))
+ int dispose = BUF_CLEAN;
+ if (buffer_locked(bh))
dispose = BUF_LOCKED;
- if (buffer_dirty(buf))
+ if (buffer_dirty(bh))
dispose = BUF_DIRTY;
+ if (dispose != bh->b_list) {
+ __remove_from_lru_list(bh, bh->b_list);
+ bh->b_list = dispose;
+ __insert_into_lru_list(bh, dispose);
+ }
+}
- if (dispose != buf->b_list)
- file_buffer(buf, dispose);
+void refile_buffer(struct buffer_head *bh)
+{
+ spin_lock(&lru_list_lock);
+ __refile_buffer(bh);
+ spin_unlock(&lru_list_lock);
}
/*
@@ -828,9 +901,8 @@ void __brelse(struct buffer_head * buf)
{
touch_buffer(buf);
- if (buf->b_count) {
- buf->b_count--;
- wake_up(&buffer_wait);
+ if (atomic_read(&buf->b_count)) {
+ atomic_dec(&buf->b_count);
return;
}
printk("VFS: brelse: Trying to free free buffer\n");
@@ -844,14 +916,21 @@ void __brelse(struct buffer_head * buf)
*/
void __bforget(struct buffer_head * buf)
{
- if (buf->b_count != 1 || buffer_locked(buf)) {
- __brelse(buf);
- return;
+ spin_lock(&lru_list_lock);
+ write_lock(&hash_table_lock);
+ if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) {
+ touch_buffer(buf);
+ atomic_dec(&buf->b_count);
+ } else {
+ atomic_set(&buf->b_count, 0);
+ buf->b_state = 0;
+ if (buf->b_pprev)
+ __hash_unlink(buf);
+ __remove_from_lru_list(buf, buf->b_list);
+ put_last_free(buf);
}
- buf->b_count = 0;
- buf->b_state = 0;
- remove_from_queues(buf);
- put_last_free(buf);
+ write_unlock(&hash_table_lock);
+ spin_unlock(&lru_list_lock);
}
/*
@@ -941,49 +1020,25 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
/*
* Note: the caller should wake up the buffer_wait list if needed.
*/
-static void put_unused_buffer_head(struct buffer_head * bh)
+static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
{
if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
- nr_buffer_heads--;
kmem_cache_free(bh_cachep, bh);
- return;
+ } else {
+ bh->b_blocknr = -1;
+ init_waitqueue_head(&bh->b_wait);
+ nr_unused_buffer_heads++;
+ bh->b_next_free = unused_list;
+ bh->b_this_page = NULL;
+ unused_list = bh;
}
-
-// memset(bh, 0, sizeof(*bh));
- bh->b_blocknr = -1;
- init_waitqueue_head(&bh->b_wait);
- nr_unused_buffer_heads++;
- bh->b_next_free = unused_list;
- unused_list = bh;
}
-/*
- * We can't put completed temporary IO buffer_heads directly onto the
- * unused_list when they become unlocked, since the device driver
- * end_request routines still expect access to the buffer_head's
- * fields after the final unlock. So, the device driver puts them on
- * the reuse_list instead once IO completes, and we recover these to
- * the unused_list here.
- *
- * Note that we don't do a wakeup here, but return a flag indicating
- * whether we got any buffer heads. A task ready to sleep can check
- * the returned value, and any tasks already sleeping will have been
- * awakened when the buffer heads were added to the reuse list.
- */
-static inline int recover_reusable_buffer_heads(void)
+static void put_unused_buffer_head(struct buffer_head *bh)
{
- struct buffer_head *head = xchg(&reuse_list, NULL);
- int found = 0;
-
- if (head) {
- do {
- struct buffer_head *bh = head;
- head = head->b_next_free;
- put_unused_buffer_head(bh);
- } while (head);
- found = 1;
- }
- return found;
+ spin_lock(&unused_list_lock);
+ __put_unused_buffer_head(bh);
+ spin_unlock(&unused_list_lock);
}
/*
@@ -995,13 +1050,15 @@ static struct buffer_head * get_unused_buffer_head(int async)
{
struct buffer_head * bh;
- recover_reusable_buffer_heads();
+ spin_lock(&unused_list_lock);
if (nr_unused_buffer_heads > NR_RESERVED) {
bh = unused_list;
unused_list = bh->b_next_free;
nr_unused_buffer_heads--;
+ spin_unlock(&unused_list_lock);
return bh;
}
+ spin_unlock(&unused_list_lock);
/* This is critical. We can't swap out pages to get
* more buffer heads, because the swap-out may need
@@ -1010,20 +1067,23 @@ static struct buffer_head * get_unused_buffer_head(int async)
if((bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER)) != NULL) {
memset(bh, 0, sizeof(*bh));
init_waitqueue_head(&bh->b_wait);
- nr_buffer_heads++;
return bh;
}
/*
* If we need an async buffer, use the reserved buffer heads.
*/
- if (async && unused_list) {
- bh = unused_list;
- unused_list = bh->b_next_free;
- nr_unused_buffer_heads--;
- return bh;
+ if (async) {
+ spin_lock(&unused_list_lock);
+ if (unused_list) {
+ bh = unused_list;
+ unused_list = bh->b_next_free;
+ nr_unused_buffer_heads--;
+ spin_unlock(&unused_list_lock);
+ return bh;
+ }
+ spin_unlock(&unused_list_lock);
}
-
#if 0
/*
* (Pending further analysis ...)
@@ -1035,7 +1095,6 @@ static struct buffer_head * get_unused_buffer_head(int async)
(bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL)) != NULL) {
memset(bh, 0, sizeof(*bh));
init_waitqueue_head(&bh->b_wait);
- nr_buffer_heads++;
return bh;
}
#endif
@@ -1052,8 +1111,7 @@ static struct buffer_head * get_unused_buffer_head(int async)
* from ordinary buffer allocations, and only async requests are allowed
* to sleep waiting for buffer heads.
*/
-static struct buffer_head * create_buffers(unsigned long page,
- unsigned long size, int async)
+static struct buffer_head * create_buffers(unsigned long page, unsigned long size, int async)
{
DECLARE_WAITQUEUE(wait, current);
struct buffer_head *bh, *head;
@@ -1073,11 +1131,14 @@ try_again:
bh->b_state = 0;
bh->b_next_free = NULL;
- bh->b_count = 0;
+ bh->b_pprev = NULL;
+ atomic_set(&bh->b_count, 0);
bh->b_size = size;
bh->b_data = (char *) (page+offset);
- bh->b_list = 0;
+ bh->b_list = BUF_CLEAN;
+ bh->b_flushtime = 0;
+ bh->b_end_io = end_buffer_io_bad;
}
return head;
/*
@@ -1118,115 +1179,16 @@ no_grow:
*/
add_wait_queue(&buffer_wait, &wait);
current->state = TASK_UNINTERRUPTIBLE;
- if (!recover_reusable_buffer_heads())
+ if (nr_unused_buffer_heads < MAX_BUF_PER_PAGE) {
+ current->policy |= SCHED_YIELD;
schedule();
+ }
remove_wait_queue(&buffer_wait, &wait);
current->state = TASK_RUNNING;
goto try_again;
}
-/* Run the hooks that have to be done when a page I/O has completed. */
-static inline void after_unlock_page (struct page * page)
-{
- if (test_and_clear_bit(PG_decr_after, &page->flags)) {
- atomic_dec(&nr_async_pages);
-#ifdef DEBUG_SWAP
- printk ("DebugVM: Finished IO on page %p, nr_async_pages %d\n",
- (char *) page_address(page),
- atomic_read(&nr_async_pages));
-#endif
- }
- if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
- swap_after_unlock_page(page->offset);
- if (test_and_clear_bit(PG_free_after, &page->flags))
- __free_page(page);
-}
-
-/*
- * Free all temporary buffers belonging to a page.
- * This needs to be called with interrupts disabled.
- */
-static inline void free_async_buffers (struct buffer_head * bh)
-{
- struct buffer_head *tmp, *tail;
-
- /*
- * Link all the buffers into the b_next_free list,
- * so we only have to do one xchg() operation ...
- */
- tail = bh;
- while ((tmp = tail->b_this_page) != bh) {
- tail->b_next_free = tmp;
- tail = tmp;
- };
-
- /* Update the reuse list */
- tail->b_next_free = xchg(&reuse_list, NULL);
- reuse_list = bh;
-
- /* Wake up any waiters ... */
- wake_up(&buffer_wait);
-}
-
-static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
-{
- unsigned long flags;
- struct buffer_head *tmp;
- struct page *page;
-
- mark_buffer_uptodate(bh, uptodate);
-
- /* This is a temporary buffer used for page I/O. */
- page = mem_map + MAP_NR(bh->b_data);
-
- if (!uptodate)
- SetPageError(page);
-
- /*
- * Be _very_ careful from here on. Bad things can happen if
- * two buffer heads end IO at almost the same time and both
- * decide that the page is now completely done.
- *
- * Async buffer_heads are here only as labels for IO, and get
- * thrown away once the IO for this page is complete. IO is
- * deemed complete once all buffers have been visited
- * (b_count==0) and are now unlocked. We must make sure that
- * only the _last_ buffer that decrements its count is the one
- * that free's the page..
- */
- save_flags(flags);
- cli();
- unlock_buffer(bh);
- tmp = bh->b_this_page;
- while (tmp != bh) {
- if (buffer_locked(tmp))
- goto still_busy;
- tmp = tmp->b_this_page;
- }
-
- /* OK, the async IO on this page is complete. */
- restore_flags(flags);
-
- after_unlock_page(page);
- /*
- * if none of the buffers had errors then we can set the
- * page uptodate:
- */
- if (!PageError(page))
- SetPageUptodate(page);
- if (page->owner != -1)
- PAGE_BUG(page);
- page->owner = (int)current;
- UnlockPage(page);
-
- return;
-
-still_busy:
- restore_flags(flags);
- return;
-}
-
-static int create_page_buffers (int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
+static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
{
struct buffer_head *head, *bh, *tail;
int block;
@@ -1240,9 +1202,7 @@ static int create_page_buffers (int rw, struct page *page, kdev_t dev, int b[],
* They show up in the buffer hash table and are registered in
* page->buffers.
*/
- lock_kernel();
head = create_buffers(page_address(page), size, 1);
- unlock_kernel();
if (page->buffers)
BUG();
if (!head)
@@ -1252,7 +1212,9 @@ static int create_page_buffers (int rw, struct page *page, kdev_t dev, int b[],
block = *(b++);
tail = bh;
- init_buffer(bh, dev, block, end_buffer_io_async, NULL);
+ init_buffer(bh, end_buffer_io_async, NULL);
+ bh->b_dev = dev;
+ bh->b_blocknr = block;
/*
* When we use bmap, we define block zero to represent
@@ -1261,9 +1223,11 @@ static int create_page_buffers (int rw, struct page *page, kdev_t dev, int b[],
* two cases.
*/
if (bmap && !block) {
- set_bit(BH_Uptodate, &bh->b_state);
memset(bh->b_data, 0, size);
+ set_bit(BH_Uptodate, &bh->b_state);
+ continue;
}
+ set_bit(BH_Mapped, &bh->b_state);
}
tail->b_this_page = head;
get_page(page);
@@ -1287,7 +1251,6 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
BUG();
if (!page->buffers)
return 0;
- lock_kernel();
head = page->buffers;
bh = head;
@@ -1299,14 +1262,16 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
* is this block fully flushed?
*/
if (offset <= curr_off) {
- if (bh->b_blocknr) {
- bh->b_count++;
+ if (buffer_mapped(bh)) {
+ atomic_inc(&bh->b_count);
wait_on_buffer(bh);
if (bh->b_dev == B_FREE)
BUG();
mark_buffer_clean(bh);
+ clear_bit(BH_Uptodate, &bh->b_state);
+ clear_bit(BH_Mapped, &bh->b_state);
bh->b_blocknr = 0;
- bh->b_count--;
+ atomic_dec(&bh->b_count);
}
}
curr_off = next_off;
@@ -1318,22 +1283,24 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
* the 'final' flushpage. We have invalidated the bmap
* cached value unconditionally, so real IO is not
* possible anymore.
+ *
+ * If the free doesn't work out, the buffers can be
+ * left around - they just turn into anonymous buffers
+ * instead.
*/
- if (!offset)
- try_to_free_buffers(page);
+ if (!offset) {
+ if (!try_to_free_buffers(page))
+ atomic_add(PAGE_CACHE_SIZE, &buffermem);
+ }
- unlock_kernel();
return 0;
}
-static void create_empty_buffers (struct page *page,
- struct inode *inode, unsigned long blocksize)
+static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize)
{
struct buffer_head *bh, *head, *tail;
- lock_kernel();
head = create_buffers(page_address(page), blocksize, 1);
- unlock_kernel();
if (page->buffers)
BUG();
@@ -1341,6 +1308,7 @@ static void create_empty_buffers (struct page *page,
do {
bh->b_dev = inode->i_dev;
bh->b_blocknr = 0;
+ bh->b_end_io = end_buffer_io_bad;
tail = bh;
bh = bh->b_this_page;
} while (bh);
@@ -1353,12 +1321,12 @@ static void create_empty_buffers (struct page *page,
* block_write_full_page() is SMP-safe - currently it's still
* being called with the kernel lock held, but the code is ready.
*/
-int block_write_full_page (struct file *file, struct page *page, fs_getblock_t fs_get_block)
+int block_write_full_page(struct file *file, struct page *page)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- int err, created, i;
- unsigned long block, phys, offset;
+ int err, i;
+ unsigned long block, offset;
struct buffer_head *bh, *head;
if (!PageLocked(page))
@@ -1381,23 +1349,22 @@ int block_write_full_page (struct file *file, struct page *page, fs_getblock_t f
if (!bh)
BUG();
- if (!bh->b_blocknr) {
- err = -EIO;
- phys = fs_get_block (inode, block, 1, &err, &created);
- if (!phys)
+ /*
+ * If the buffer isn't up-to-date, we can't be sure
+ * that the buffer has been initialized with the proper
+ * block number information etc..
+ *
+ * Leave it to the low-level FS to make all those
+ * decisions (block #0 may actually be a valid block)
+ */
+ bh->b_end_io = end_buffer_io_sync;
+ if (!buffer_mapped(bh)) {
+ err = inode->i_op->get_block(inode, block, bh, 1);
+ if (err)
goto out;
-
- init_buffer(bh, inode->i_dev, phys, end_buffer_io_sync, NULL);
- bh->b_state = (1<<BH_Uptodate);
- } else {
- /*
- * block already exists, just mark it uptodate and
- * dirty:
- */
- bh->b_end_io = end_buffer_io_sync;
- set_bit(BH_Uptodate, &bh->b_state);
}
- atomic_mark_buffer_dirty(bh,0);
+ set_bit(BH_Uptodate, &bh->b_state);
+ mark_buffer_dirty(bh,0);
bh = bh->b_this_page;
block++;
@@ -1410,15 +1377,15 @@ out:
return err;
}
-int block_write_partial_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf, fs_getblock_t fs_get_block)
+int block_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
unsigned long block;
- int err, created, partial;
+ int err, partial;
unsigned long blocksize, start_block, end_block;
unsigned long start_offset, start_bytes, end_bytes;
- unsigned long bbits, phys, blocks, i, len;
+ unsigned long bbits, blocks, i, len;
struct buffer_head *bh, *head;
char * target_buf;
@@ -1469,46 +1436,35 @@ int block_write_partial_page (struct file *file, struct page *page, unsigned lon
partial = 1;
goto skip;
}
- if (!bh->b_blocknr) {
- err = -EIO;
- phys = fs_get_block (inode, block, 1, &err, &created);
- if (!phys)
- goto out;
- init_buffer(bh, inode->i_dev, phys, end_buffer_io_sync, NULL);
+ /*
+ * If the buffer is not up-to-date, we need to ask the low-level
+ * FS to do something for us (we used to have assumptions about
+ * the meaning of b_blocknr etc, that's bad).
+ *
+ * If "update" is set, that means that the low-level FS should
+ * try to make sure that the block is up-to-date because we're
+ * not going to fill it completely.
+ */
+ bh->b_end_io = end_buffer_io_sync;
+ if (!buffer_mapped(bh)) {
+ err = inode->i_op->get_block(inode, block, bh, 1);
+ if (err)
+ goto out;
+ }
- /*
- * if partially written block which has contents on
- * disk, then we have to read it first.
- * We also rely on the fact that filesystem holes
- * cannot be written.
- */
- if (start_offset || (end_bytes && (i == end_block))) {
- if (created) {
- memset(bh->b_data, 0, bh->b_size);
- } else {
- bh->b_state = 0;
- ll_rw_block(READ, 1, &bh);
- lock_kernel();
- wait_on_buffer(bh);
- unlock_kernel();
- err = -EIO;
- if (!buffer_uptodate(bh))
- goto out;
- }
+ if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
+ if (buffer_new(bh)) {
+ memset(bh->b_data, 0, bh->b_size);
+ } else {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ err = -EIO;
+ if (!buffer_uptodate(bh))
+ goto out;
}
-
- bh->b_state = (1<<BH_Uptodate);
- } else {
- /*
- * block already exists, just mark it uptodate:
- */
- bh->b_end_io = end_buffer_io_sync;
- set_bit(BH_Uptodate, &bh->b_state);
- created = 0;
}
- err = -EFAULT;
len = blocksize;
if (start_offset) {
len = start_bytes;
@@ -1517,8 +1473,7 @@ int block_write_partial_page (struct file *file, struct page *page, unsigned lon
len = end_bytes;
end_bytes = 0;
}
- if (copy_from_user(target_buf, buf, len))
- goto out;
+ err = copy_from_user(target_buf, buf, len);
target_buf += len;
buf += len;
@@ -1538,12 +1493,18 @@ int block_write_partial_page (struct file *file, struct page *page, unsigned lon
* should not penalize them for somebody else writing
* lots of dirty pages.
*/
+ set_bit(BH_Uptodate, &bh->b_state);
if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
- __atomic_mark_buffer_dirty(bh, bdf_prm.b_un.age_buffer);
+ __mark_dirty(bh, 0);
if (too_many_dirty_buffers)
balance_dirty(bh->b_dev);
}
+ if (err) {
+ err = -EFAULT;
+ goto out;
+ }
+
skip:
i++;
block++;
@@ -1572,6 +1533,9 @@ out:
*
* brw_page() is SMP-safe, although it's being called with the
* kernel lock held - but the code is ready.
+ *
+ * FIXME: we need a swapper_inode->get_block function to remove
+ * some of the bmap kludges and interface ugliness here.
*/
int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
{
@@ -1600,7 +1564,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
do {
block = *(b++);
- if (fresh && (bh->b_count != 0))
+ if (fresh && (atomic_read(&bh->b_count) != 0))
BUG();
if (rw == READ) {
if (!fresh)
@@ -1613,6 +1577,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
BUG();
if (!buffer_uptodate(bh)) {
arr[nr++] = bh;
+ atomic_inc(&bh->b_count);
}
}
} else { /* WRITE */
@@ -1625,8 +1590,9 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
BUG();
}
set_bit(BH_Uptodate, &bh->b_state);
- atomic_mark_buffer_dirty(bh, 0);
+ set_bit(BH_Dirty, &bh->b_state);
arr[nr++] = bh;
+ atomic_inc(&bh->b_count);
}
bh = bh->b_this_page;
} while (bh != head);
@@ -1649,30 +1615,7 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
}
/*
- * This is called by end_request() when I/O has completed.
- */
-void mark_buffer_uptodate(struct buffer_head * bh, int on)
-{
- if (on) {
- struct buffer_head *tmp = bh;
- struct page *page;
- set_bit(BH_Uptodate, &bh->b_state);
- /* If a page has buffers and all these buffers are uptodate,
- * then the page is uptodate. */
- do {
- if (!test_bit(BH_Uptodate, &tmp->b_state))
- return;
- tmp=tmp->b_this_page;
- } while (tmp && tmp != bh);
- page = mem_map + MAP_NR(bh->b_data);
- SetPageUptodate(page);
- return;
- }
- clear_bit(BH_Uptodate, &bh->b_state);
-}
-
-/*
- * Generic "readpage" function for block devices that have the normal
+ * Generic "read page" function for block devices that have the normal
* bmap functionality. This is most of the block device filesystems.
* Reads the page asynchronously --- the unlock_buffer() and
* mark_buffer_uptodate() functions propagate buffer state into the
@@ -1682,7 +1625,7 @@ int block_read_full_page(struct file * file, struct page * page)
{
struct dentry *dentry = file->f_dentry;
struct inode *inode = dentry->d_inode;
- unsigned long iblock, phys_block;
+ unsigned long iblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
int nr;
@@ -1700,33 +1643,25 @@ int block_read_full_page(struct file * file, struct page * page)
head = page->buffers;
bh = head;
nr = 0;
+
do {
- phys_block = bh->b_blocknr;
- /*
- * important, we have to retry buffers that already have
- * their bnr cached but had an IO error!
- */
- if (!buffer_uptodate(bh)) {
- phys_block = inode->i_op->bmap(inode, iblock);
- /*
- * this is safe to do because we hold the page lock:
- */
- if (phys_block) {
- init_buffer(bh, inode->i_dev, phys_block,
- end_buffer_io_async, NULL);
- arr[nr] = bh;
- nr++;
- } else {
- /*
- * filesystem 'hole' represents zero-contents:
- */
+ if (buffer_uptodate(bh))
+ continue;
+
+ if (!buffer_mapped(bh)) {
+ inode->i_op->get_block(inode, iblock, bh, 0);
+ if (!buffer_mapped(bh)) {
memset(bh->b_data, 0, blocksize);
set_bit(BH_Uptodate, &bh->b_state);
+ continue;
}
}
- iblock++;
- bh = bh->b_this_page;
- } while (bh != head);
+
+ init_buffer(bh, end_buffer_io_async, NULL);
+ atomic_inc(&bh->b_count);
+ arr[nr] = bh;
+ nr++;
+ } while (iblock++, (bh = bh->b_this_page) != head);
++current->maj_flt;
if (nr) {
@@ -1770,8 +1705,9 @@ static int grow_buffers(int size)
}
isize = BUFSIZE_INDEX(size);
- insert_point = free_list[isize];
+ spin_lock(&free_list[isize].lock);
+ insert_point = free_list[isize].list;
tmp = bh;
while (1) {
if (insert_point) {
@@ -1790,9 +1726,11 @@ static int grow_buffers(int size)
break;
}
tmp->b_this_page = bh;
- free_list[isize] = bh;
+ free_list[isize].list = bh;
+ spin_unlock(&free_list[isize].lock);
+
mem_map[MAP_NR(page)].buffers = bh;
- buffermem += PAGE_SIZE;
+ atomic_add(PAGE_SIZE, &buffermem);
return 1;
}
@@ -1800,7 +1738,7 @@ static int grow_buffers(int size)
* Can the buffer be thrown out?
*/
#define BUFFER_BUSY_BITS ((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
-#define buffer_busy(bh) ((bh)->b_count || ((bh)->b_state & BUFFER_BUSY_BITS))
+#define buffer_busy(bh) (atomic_read(&(bh)->b_count) | ((bh)->b_state & BUFFER_BUSY_BITS))
/*
* try_to_free_buffers() checks if all the buffers on this particular page
@@ -1808,90 +1746,70 @@ static int grow_buffers(int size)
*
* Wake up bdflush() if this fails - if we're running low on memory due
* to dirty buffers, we need to flush them out as quickly as possible.
+ *
+ * NOTE: There are quite a number of ways that threads of control can
+ * obtain a reference to a buffer head within a page. So we must
+ * lock out all of these paths to cleanly toss the page.
*/
int try_to_free_buffers(struct page * page)
{
struct buffer_head * tmp, * bh = page->buffers;
+ int index = BUFSIZE_INDEX(bh->b_size);
+ int ret;
+ spin_lock(&lru_list_lock);
+ write_lock(&hash_table_lock);
+ spin_lock(&free_list[index].lock);
tmp = bh;
do {
struct buffer_head * p = tmp;
tmp = tmp->b_this_page;
- if (!buffer_busy(p))
- continue;
-
- too_many_dirty_buffers = 1;
- wakeup_bdflush(0);
- return 0;
+ if (buffer_busy(p))
+ goto busy_buffer_page;
} while (tmp != bh);
+ spin_lock(&unused_list_lock);
tmp = bh;
do {
struct buffer_head * p = tmp;
tmp = tmp->b_this_page;
- /* The buffer can be either on the regular queues or on the free list.. */
- if (p->b_dev == B_FREE)
- remove_from_free_list(p);
- else
- remove_from_queues(p);
-
- put_unused_buffer_head(p);
+ /* The buffer can be either on the regular
+ * queues or on the free list..
+ */
+ if (p->b_dev == B_FREE) {
+ __remove_from_free_list(p, index);
+ } else {
+ if (p->b_pprev)
+ __hash_unlink(p);
+ __remove_from_lru_list(p, p->b_list);
+ }
+ __put_unused_buffer_head(p);
} while (tmp != bh);
+ spin_unlock(&unused_list_lock);
/* Wake up anyone waiting for buffer heads */
wake_up(&buffer_wait);
/* And free the page */
page->buffers = NULL;
- if (__free_page(page)) {
- buffermem -= PAGE_SIZE;
- return 1;
- }
- return 0;
-}
-
-/* ================== Debugging =================== */
-
-void show_buffers(void)
-{
- struct buffer_head * bh;
- int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
- int protected = 0;
- int nlist;
- static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};
-
- printk("Buffer memory: %6dkB\n",buffermem>>10);
- printk("Buffer heads: %6d\n",nr_buffer_heads);
- printk("Buffer blocks: %6d\n",nr_buffers);
- printk("Buffer hashed: %6d\n",nr_hashed_buffers);
-
- for(nlist = 0; nlist < NR_LIST; nlist++) {
- found = locked = dirty = used = lastused = protected = 0;
- bh = lru_list[nlist];
- if(!bh) continue;
-
- do {
- found++;
- if (buffer_locked(bh))
- locked++;
- if (buffer_protected(bh))
- protected++;
- if (buffer_dirty(bh))
- dirty++;
- if (bh->b_count)
- used++, lastused = found;
- bh = bh->b_next_free;
- } while (bh != lru_list[nlist]);
- printk("%8s: %d buffers, %d used (last=%d), "
- "%d locked, %d protected, %d dirty\n",
- buf_types[nlist], found, used, lastused,
- locked, protected, dirty);
- };
+ __free_page(page);
+ ret = 1;
+out:
+ spin_unlock(&free_list[index].lock);
+ write_unlock(&hash_table_lock);
+ spin_unlock(&lru_list_lock);
+ return ret;
+
+busy_buffer_page:
+ /* Uhhuh, start writeback so that we don't end up with all dirty pages */
+ too_many_dirty_buffers = 1;
+ wakeup_bdflush(0);
+ ret = 0;
+ goto out;
}
-
/* ===================== Init ======================= */
/*
@@ -1901,31 +1819,53 @@ void show_buffers(void)
*/
void __init buffer_init(unsigned long memory_size)
{
- int order;
+ int order, i;
unsigned int nr_hash;
- /* we need to guess at the right sort of size for a buffer cache.
- the heuristic from working with large databases and getting
- fsync times (ext2) manageable, is the following */
-
- memory_size >>= 22;
- for (order = 5; (1UL << order) < memory_size; order++);
+ /* The buffer cache hash table is less important these days,
+ * trim it a bit.
+ */
+ memory_size >>= 14;
+ memory_size *= sizeof(struct buffer_head *);
+ for (order = 0; (PAGE_SIZE << order) < memory_size; order++)
+ ;
/* try to allocate something until we get it or we're asking
for something that is really too small */
do {
- nr_hash = (1UL << order) * PAGE_SIZE /
- sizeof(struct buffer_head *);
+ unsigned long tmp;
+
+ nr_hash = (PAGE_SIZE << order) / sizeof(struct buffer_head *);
+ bh_hash_mask = (nr_hash - 1);
+
+ tmp = nr_hash;
+ bh_hash_shift = 0;
+ while((tmp >>= 1UL) != 0UL)
+ bh_hash_shift++;
+
hash_table = (struct buffer_head **)
__get_free_pages(GFP_ATOMIC, order);
- } while (hash_table == NULL && --order > 4);
- printk("buffer-cache hash table entries: %d (order: %d, %ld bytes)\n", nr_hash, order, (1UL<<order) * PAGE_SIZE);
-
+ } while (hash_table == NULL && --order > 0);
+ printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
+ nr_hash, order, (1UL<<order) * PAGE_SIZE);
+
if (!hash_table)
panic("Failed to allocate buffer hash table\n");
- memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
- bh_hash_mask = nr_hash-1;
+
+ /* Setup hash chains. */
+ for(i = 0; i < nr_hash; i++)
+ hash_table[i] = NULL;
+
+ /* Setup free lists. */
+ for(i = 0; i < NR_SIZES; i++) {
+ free_list[i].list = NULL;
+ free_list[i].lock = SPIN_LOCK_UNLOCKED;
+ }
+
+ /* Setup lru lists. */
+ for(i = 0; i < NR_LIST; i++)
+ lru_list[i] = NULL;
bh_cachep = kmem_cache_create("buffer_head",
sizeof(struct buffer_head),
@@ -1933,21 +1873,6 @@ void __init buffer_init(unsigned long memory_size)
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!bh_cachep)
panic("Cannot create buffer head SLAB cache\n");
- /*
- * Allocate the reserved buffer heads.
- */
- while (nr_buffer_heads < NR_RESERVED) {
- struct buffer_head * bh;
-
- bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC);
- if (!bh)
- break;
- put_unused_buffer_head(bh);
- nr_buffer_heads++;
- }
-
- lru_list[BUF_CLEAN] = 0;
- grow_buffers(BLOCK_SIZE);
}
@@ -1983,70 +1908,49 @@ void wakeup_bdflush(int wait)
static int sync_old_buffers(void)
{
- int i;
- int ndirty, nwritten;
int nlist;
- int ncount;
- struct buffer_head * bh, *next;
+ lock_kernel();
sync_supers(0);
sync_inodes(0);
+ unlock_kernel();
- ncount = 0;
-#ifdef DEBUG
- for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
- for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
-#endif
- {
- ndirty = 0;
- nwritten = 0;
+ for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) {
+ struct buffer_head *bh;
repeat:
-
+ spin_lock(&lru_list_lock);
bh = lru_list[nlist];
- if(bh)
- for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
- /* We may have stalled while waiting for I/O to complete. */
- if(bh->b_list != nlist) goto repeat;
- next = bh->b_next_free;
- if(!lru_list[nlist]) {
- printk("Dirty list empty %d\n", i);
- break;
- }
-
- /* Clean buffer on dirty list? Refile it */
- if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
- refile_buffer(bh);
- continue;
- }
-
- /* Unlocked buffer on locked list? Refile it */
- if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
- refile_buffer(bh);
- continue;
- }
+ if(bh) {
+ struct buffer_head *next;
+ int i;
+ for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
+ next = bh->b_next_free;
+
+ /* If the buffer is not on the proper list,
+ * then refile it.
+ */
+ if ((nlist == BUF_DIRTY &&
+ (!buffer_dirty(bh) && !buffer_locked(bh))) ||
+ (nlist == BUF_LOCKED && !buffer_locked(bh))) {
+ __refile_buffer(bh);
+ continue;
+ }
- if (buffer_locked(bh) || !buffer_dirty(bh))
- continue;
- ndirty++;
- nwritten++;
- next->b_count++;
- bh->b_count++;
- bh->b_flushtime = 0;
-#ifdef DEBUG
- if(nlist != BUF_DIRTY) ncount++;
-#endif
- ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
- next->b_count--;
- }
+ if (buffer_locked(bh) || !buffer_dirty(bh))
+ continue;
+
+ /* OK, now we are committed to write it out. */
+ bh->b_flushtime = 0;
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
+ ll_rw_block(WRITE, 1, &bh);
+ atomic_dec(&bh->b_count);
+ goto repeat;
+ }
+ }
+ spin_unlock(&lru_list_lock);
}
run_task_queue(&tq_disk);
-#ifdef DEBUG
- if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
- printk("Wrote %d/%d buffers\n", nwritten, ndirty);
-#endif
- run_task_queue(&tq_disk);
return 0;
}
@@ -2060,7 +1964,6 @@ asmlinkage int sys_bdflush(int func, long data)
{
int i, error = -EPERM;
- lock_kernel();
if (!capable(CAP_SYS_ADMIN))
goto out;
@@ -2092,7 +1995,6 @@ asmlinkage int sys_bdflush(int func, long data)
*/
error = 0;
out:
- unlock_kernel();
return error;
}
@@ -2114,52 +2016,37 @@ int bdflush(void * unused)
sprintf(current->comm, "kflushd");
bdflush_tsk = current;
- /*
- * As a kernel thread we want to tamper with system buffers
- * and other internals and thus be subject to the SMP locking
- * rules. (On a uniprocessor box this does nothing).
- */
- lock_kernel();
-
for (;;) {
int nlist;
CHECK_EMERGENCY_SYNC
- for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
- {
- int nr;
- int written = 0;
+ for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) {
+ int nr, major, written = 0;
struct buffer_head *next;
- int major;
repeat:
+ spin_lock(&lru_list_lock);
next = lru_list[nlist];
nr = nr_buffers_type[nlist];
-
while (nr-- > 0) {
struct buffer_head *bh = next;
- /* We may have stalled while waiting for I/O to complete. */
- if (next->b_list != nlist)
- goto repeat;
+
next = next->b_next_free;
- /* Clean buffer on dirty list? Refile it */
- if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
- refile_buffer(bh);
- continue;
- }
-
- /* Unlocked buffer on locked list? Refile it */
- if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
- refile_buffer(bh);
+ /* If the buffer is not on the correct list,
+ * then refile it.
+ */
+ if ((nlist == BUF_DIRTY &&
+ (!buffer_dirty(bh) && !buffer_locked(bh))) ||
+ (nlist == BUF_LOCKED && !buffer_locked(bh))) {
+ __refile_buffer(bh);
continue;
}
- /*
- * If we aren't in panic mode, don't write out too much
- * at a time. Also, don't write out buffers we don't really
- * have to write out yet..
+ /* If we aren't in panic mode, don't write out too much
+ * at a time. Also, don't write out buffers we don't
+ * really have to write out yet..
*/
if (!too_many_dirty_buffers) {
if (written > bdf_prm.b_un.ndirty)
@@ -2172,9 +2059,6 @@ int bdflush(void * unused)
continue;
major = MAJOR(bh->b_dev);
- if (next)
- next->b_count++;
- bh->b_count++;
written++;
bh->b_flushtime = 0;
@@ -2182,18 +2066,18 @@ int bdflush(void * unused)
* For the loop major we can try to do asynchronous writes,
* but we have to guarantee that we're making some progress..
*/
+ atomic_inc(&bh->b_count);
+ spin_unlock(&lru_list_lock);
if (major == LOOP_MAJOR && written > 1) {
ll_rw_block(WRITEA, 1, &bh);
if (buffer_dirty(bh))
--written;
} else
ll_rw_block(WRITE, 1, &bh);
-
- bh->b_count--;
- if (next)
- next->b_count--;
- wake_up(&buffer_wait);
+ atomic_dec(&bh->b_count);
+ goto repeat;
}
+ spin_unlock(&lru_list_lock);
}
run_task_queue(&tq_disk);
wake_up(&bdflush_done);
@@ -2206,7 +2090,10 @@ int bdflush(void * unused)
*/
if (!too_many_dirty_buffers || nr_buffers_type[BUF_DIRTY] < bdf_prm.b_un.ndirty) {
too_many_dirty_buffers = 0;
- sleep_on_timeout(&bdflush_wait, 5*HZ);
+ spin_lock_irq(&current->sigmask_lock);
+ flush_signals(current);
+ spin_unlock_irq(&current->sigmask_lock);
+ interruptible_sleep_on_timeout(&bdflush_wait, 5*HZ);
}
}
}
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index b3c0195a3..4313edb69 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -77,9 +77,10 @@ struct inode_operations coda_dir_inode_operations =
coda_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
coda_permission, /* permission */
NULL, /* smap */
diff --git a/fs/coda/file.c b/fs/coda/file.c
index cbc81542f..7e83ea954 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -47,13 +47,13 @@ struct inode_operations coda_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
coda_readpage, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
coda_permission, /* permission */
NULL, /* smap */
- NULL, /* update page */
coda_revalidate_inode /* revalidate */
};
@@ -101,7 +101,7 @@ static int coda_readpage(struct file * coda_file, struct page * page)
CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n",
coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
- generic_readpage(&cont_file, page);
+ block_read_full_page(&cont_file, page);
EXIT;
return 0;
}
@@ -256,7 +256,7 @@ void coda_prepare_openfile(struct inode *i, struct file *coda_file,
cont_file->f_pos = coda_file->f_pos;
cont_file->f_mode = coda_file->f_mode;
cont_file->f_flags = coda_file->f_flags;
- cont_file->f_count = coda_file->f_count;
+ atomic_set(&cont_file->f_count, atomic_read(&coda_file->f_count));
cont_file->f_owner = coda_file->f_owner;
cont_file->f_op = cont_inode->i_op->default_file_ops;
cont_file->f_dentry = cont_dentry;
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c
index 4a98361aa..3e6924f15 100644
--- a/fs/coda/pioctl.c
+++ b/fs/coda/pioctl.c
@@ -46,13 +46,13 @@ struct inode_operations coda_ioctl_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
coda_ioctl_permission, /* permission */
NULL, /* smap */
- NULL, /* update page */
NULL /* revalidate */
};
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index b42555811..cfe0dbcb7 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -42,13 +42,13 @@ struct inode_operations coda_symlink_inode_operations = {
NULL, /* rename */
coda_readlink, /* readlink */
coda_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* update page */
NULL /* revalidate */
};
diff --git a/fs/devices.c b/fs/devices.c
index 934fe290f..7bdadd5fb 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -277,7 +277,7 @@ struct inode_operations blkdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -333,11 +333,14 @@ struct inode_operations chrdev_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
/*
diff --git a/fs/devpts/root.c b/fs/devpts/root.c
index c1c1a6000..9b5408235 100644
--- a/fs/devpts/root.c
+++ b/fs/devpts/root.c
@@ -51,9 +51,10 @@ struct inode_operations devpts_root_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/efs/dir.c b/fs/efs/dir.c
index ea484dab4..29f2ebbc3 100644
--- a/fs/efs/dir.c
+++ b/fs/efs/dir.c
@@ -25,6 +25,8 @@ static struct file_operations efs_dir_operations = {
NULL /* revalidate */
};
+extern int efs_get_block(struct inode *, long, struct buffer_head *, int);
+
struct inode_operations efs_dir_inode_operations = {
&efs_dir_operations, /* default directory file-ops */
NULL, /* create */
@@ -38,12 +40,14 @@ struct inode_operations efs_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ efs_get_block, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- efs_bmap, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
diff --git a/fs/efs/file.c b/fs/efs/file.c
index d97a420c5..b86965f8f 100644
--- a/fs/efs/file.c
+++ b/fs/efs/file.c
@@ -8,6 +8,59 @@
#include <linux/efs_fs.h>
+int efs_get_block(struct inode *inode, long iblock,
+ struct buffer_head *bh_result, int create)
+{
+ int error = -EROFS;
+ long phys;
+
+ if (create)
+ return error;
+ if (iblock >= inode->i_blocks) {
+#ifdef DEBUG
+ /*
+ * i have no idea why this happens as often as it does
+ */
+ printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
+ block,
+ inode->i_blocks,
+ inode->i_size);
+#endif
+ return 0;
+ }
+ phys = efs_map_block(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
+ return 0;
+}
+
+int efs_bmap(struct inode *inode, efs_block_t block) {
+
+ if (block < 0) {
+ printk(KERN_WARNING "EFS: bmap(): block < 0\n");
+ return 0;
+ }
+
+ /* are we about to read past the end of a file ? */
+ if (!(block < inode->i_blocks)) {
+#ifdef DEBUG
+ /*
+ * i have no idea why this happens as often as it does
+ */
+ printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
+ block,
+ inode->i_blocks,
+ inode->i_size);
+#endif
+ return 0;
+ }
+
+ return efs_map_block(inode, block);
+}
+
static struct file_operations efs_file_operations = {
NULL, /* lseek */
generic_file_read, /* read */
@@ -38,35 +91,12 @@ struct inode_operations efs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ efs_get_block, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- efs_bmap, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
-
-int efs_bmap(struct inode *inode, efs_block_t block) {
-
- if (block < 0) {
- printk(KERN_WARNING "EFS: bmap(): block < 0\n");
- return 0;
- }
-
- /* are we about to read past the end of a file ? */
- if (!(block < inode->i_blocks)) {
-#ifdef DEBUG
- /*
- * i have no idea why this happens as often as it does
- */
- printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
- block,
- inode->i_blocks,
- inode->i_size);
-#endif
- return 0;
- }
-
- return efs_map_block(inode, block);
-}
-
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 705599eb0..69ddda45b 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -26,12 +26,14 @@ struct inode_operations efs_symlink_inode_operations = {
NULL, /* rename */
efs_readlink, /* readlink */
efs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static char *efs_linktarget(struct inode *in, int *len) {
diff --git a/fs/exec.c b/fs/exec.c
index e5b55e247..83b1834de 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -72,10 +72,6 @@ void __init binfmt_setup(void)
init_aout32_binfmt();
#endif
-#ifdef CONFIG_BINFMT_JAVA
- init_java_binfmt();
-#endif
-
#ifdef CONFIG_BINFMT_EM86
init_em86_binfmt();
#endif
@@ -324,7 +320,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
/*
* Read in the complete executable. This is used for "-N" files
* that aren't on a block boundary, and for files on filesystems
- * without bmap support.
+ * without get_block support.
*/
int read_exec(struct dentry *dentry, unsigned long offset,
char * addr, unsigned long count, int to_kmem)
@@ -804,7 +800,6 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
bprm.dentry = dentry;
bprm.filename = filename;
bprm.sh_bang = 0;
- bprm.java = 0;
bprm.loader = 0;
bprm.exec = 0;
if ((bprm.argc = count(argv)) < 0) {
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 59f068b5e..cf9e615bd 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -67,7 +67,7 @@ struct inode_operations ext2_dir_inode_operations = {
ext2_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index c90419ce3..e223ce277 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -37,7 +37,6 @@
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
-static int ext2_writepage (struct file * file, struct page * page);
static long long ext2_file_lseek(struct file *, long long, int);
#if BITS_PER_LONG < 64
static int ext2_open_file (struct inode *, struct file *);
@@ -106,23 +105,16 @@ static inline void remove_suid(struct inode *inode)
}
}
-static int ext2_writepage (struct file * file, struct page * page)
-{
- return block_write_full_page(file, page, ext2_getblk_block);
-}
-
-static long ext2_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
-{
- return block_write_partial_page(file, page, offset, bytes, buf, ext2_getblk_block);
-}
-
/*
* Write to a file (through the page cache).
*/
static ssize_t
ext2_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- ssize_t retval = generic_file_write(file, buf, count, ppos, ext2_write_one_page);
+ ssize_t retval;
+
+ retval = generic_file_write(file, buf, count,
+ ppos, block_write_partial_page);
if (retval > 0) {
struct inode *inode = file->f_dentry->d_inode;
remove_suid(inode);
@@ -195,9 +187,9 @@ struct inode_operations ext2_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- ext2_bmap, /* bmap */
+ ext2_get_block, /* get_block */
block_read_full_page, /* readpage */
- ext2_writepage, /* writepage */
+ block_write_full_page, /* writepage */
block_flushpage, /* flushpage */
ext2_truncate, /* truncate */
ext2_permission, /* permission */
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 8ae361e73..3969e17e9 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -56,7 +56,7 @@ static int sync_indirect(struct inode * inode, u32 * block, int wait)
return 0;
}
ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
+ atomic_dec(&bh->b_count);
return 0;
}
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 02fb5b7b7..171f34a16 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -129,23 +129,22 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
return result;
}
-
-int ext2_bmap (struct inode * inode, int block)
+static inline long ext2_block_map (struct inode * inode, long block)
{
int i, ret;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
ret = 0;
lock_kernel();
if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
+ ext2_warning (inode->i_sb, "ext2_block_map", "block < 0");
goto out;
}
- 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_bmap", "block > big");
+ if (block >= EXT2_NDIR_BLOCKS + ptrs +
+ (1 << (ptrs_bits * 2)) +
+ ((1 << (ptrs_bits * 2)) << ptrs_bits)) {
+ ext2_warning (inode->i_sb, "ext2_block_map", "block > big");
goto out;
}
if (block < EXT2_NDIR_BLOCKS) {
@@ -153,7 +152,7 @@ int ext2_bmap (struct inode * inode, int block)
goto out;
}
block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
+ if (block < ptrs) {
i = inode_bmap (inode, EXT2_IND_BLOCK);
if (!i)
goto out;
@@ -161,122 +160,64 @@ int ext2_bmap (struct inode * inode, int block)
inode->i_sb->s_blocksize), block);
goto out;
}
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
+ block -= ptrs;
+ if (block < (1 << (ptrs_bits * 2))) {
i = inode_bmap (inode, EXT2_DIND_BLOCK);
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
- block >> addr_per_block_bits);
+ block >> ptrs_bits);
if (!i)
goto out;
ret = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
+ block & (ptrs - 1));
+ goto out;
}
- block -= (1 << (addr_per_block_bits * 2));
+ block -= (1 << (ptrs_bits * 2));
i = inode_bmap (inode, EXT2_TIND_BLOCK);
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (addr_per_block_bits * 2));
+ block >> (ptrs_bits * 2));
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> addr_per_block_bits) & (addr_per_block - 1));
+ (block >> ptrs_bits) & (ptrs - 1));
if (!i)
goto out;
ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
+ block & (ptrs - 1));
out:
unlock_kernel();
return ret;
}
-int ext2_bmap_create (struct inode * inode, int block)
-{
- int i;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_bmap", "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_bmap", "block > big");
- return 0;
- }
- if (block < EXT2_NDIR_BLOCKS)
- return inode_bmap (inode, block);
- block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
- i = inode_bmap (inode, EXT2_IND_BLOCK);
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize), block);
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- i = inode_bmap (inode, EXT2_DIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block >> addr_per_block_bits);
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
- }
- block -= (1 << (addr_per_block_bits * 2));
- i = inode_bmap (inode, EXT2_TIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (addr_per_block_bits * 2));
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> addr_per_block_bits) & (addr_per_block - 1));
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
-}
-
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
- int create, int new_block, int * err, int metadata,
- int *phys_block, int *created)
+ int new_block, int * err, int metadata, long *phys, int *new)
{
u32 * p;
int tmp, goal = 0;
struct buffer_head * result;
- int blocks = inode->i_sb->s_blocksize / 512;
+ int blocksize = inode->i_sb->s_blocksize;
p = inode->u.ext2_i.i_data + nr;
repeat:
tmp = le32_to_cpu(*p);
if (tmp) {
if (metadata) {
- struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ result = getblk (inode->i_dev, tmp, blocksize);
if (tmp == le32_to_cpu(*p))
return result;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
*err = -EFBIG;
- if (!create)
- goto dont_create;
/* Check file limits.. */
{
@@ -285,7 +226,6 @@ repeat:
limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (new_block >= limit) {
send_sig(SIGXFSZ, current, 0);
-dont_create:
*err = -EFBIG;
return NULL;
}
@@ -313,34 +253,41 @@ dont_create:
ext2_debug ("goal = %d.\n", goal);
tmp = ext2_alloc_block (inode, goal, err);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
- result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ result = getblk (inode->i_dev, tmp, blocksize);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
}
- memset(result->b_data, 0, inode->i_sb->s_blocksize);
+ memset(result->b_data, 0, blocksize);
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ BUG();
ext2_free_blocks (inode, tmp, 1);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
*err = 0;
- *created = 1;
+ *new = 1;
}
*p = cpu_to_le32(tmp);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_blocks += blocks;
+ inode->i_blocks += blocksize/512;
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
@@ -357,24 +304,23 @@ dont_create:
* NULL return in the data case is mandatory.
*/
static struct buffer_head * block_getblk (struct inode * inode,
- struct buffer_head * bh, int nr, int create, int blocksize,
- int new_block, int * err, int metadata, int *phys_block, int *created)
+ struct buffer_head * bh, int nr,
+ int new_block, int * err, int metadata, long *phys, int *new)
{
int tmp, goal = 0;
u32 * p;
struct buffer_head * result;
- int blocks = inode->i_sb->s_blocksize / 512;
+ int blocksize = inode->i_sb->s_blocksize;
unsigned long limit;
-
+
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
- if (!buffer_uptodate(bh)) {
- brelse (bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
p = (u32 *) bh->b_data + nr;
repeat:
@@ -382,31 +328,24 @@ repeat:
if (tmp) {
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
- if (tmp == le32_to_cpu(*p)) {
- brelse (bh);
- return result;
- }
+ if (tmp == le32_to_cpu(*p))
+ goto out;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse (bh);
- return NULL;
+ *phys = tmp;
+ /* result == NULL */
+ goto out;
}
}
*err = -EFBIG;
- if (!create) {
- brelse (bh);
- return NULL;
- }
limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (new_block >= limit) {
- brelse (bh);
send_sig(SIGXFSZ, current, 0);
- return NULL;
+ goto out;
}
}
@@ -423,10 +362,8 @@ repeat:
goal = bh->b_blocknr;
}
tmp = ext2_alloc_block (inode, goal, err);
- if (!tmp) {
- brelse (bh);
- return NULL;
- }
+ if (!tmp)
+ goto out;
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
if (*p) {
@@ -438,12 +375,10 @@ repeat:
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
- *phys_block = tmp;
- result = NULL;
- *err = 0;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
}
- if (le32_to_cpu(*p)) {
+ if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
@@ -455,117 +390,162 @@ repeat:
wait_on_buffer (bh);
}
inode->i_ctime = CURRENT_TIME;
- inode->i_blocks += blocks;
+ inode->i_blocks += blocksize/512;
mark_inode_dirty(inode);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
+ *err = 0;
+out:
brelse (bh);
return result;
}
-int ext2_getblk_block (struct inode * inode, long block,
- int create, int * err, int * created)
+int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
- struct buffer_head * bh, *tmp;
- 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);
- int phys_block, ret;
+ int ret, err, new;
+ struct buffer_head *bh;
+ unsigned long ptr, phys;
+ /*
+ * block pointers per block
+ */
+ unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ const int direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = ptrs,
+ double_blocks = (1 << (ptrs_bits * 2)),
+ triple_blocks = (1 << (ptrs_bits * 3));
- lock_kernel();
- ret = 0;
- *err = -EIO;
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
- goto abort;
- }
- 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");
- goto abort;
+ if (!create) {
+ /*
+ * Will clean this up further, ext2_block_map() should use the
+ * bh instead of an integer block-number interface.
+ */
+ phys = ext2_block_map(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
+ return 0;
}
+
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+
+ if (iblock < 0)
+ goto abort_negative;
+ if (iblock > direct_blocks + indirect_blocks +
+ double_blocks + triple_blocks)
+ goto abort_too_big;
+
/*
* If this is a sequential block allocation, set the next_alloc_block
* to this block now so that all the indblock and data block
* allocations use the same goal zone
*/
- ext2_debug ("block %lu, next %lu, goal %lu.\n", block,
+ ext2_debug ("block %lu, next %lu, goal %lu.\n", iblock,
inode->u.ext2_i.i_next_alloc_block,
inode->u.ext2_i.i_next_alloc_goal);
- if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
+ if (iblock == inode->u.ext2_i.i_next_alloc_block + 1) {
inode->u.ext2_i.i_next_alloc_block++;
inode->u.ext2_i.i_next_alloc_goal++;
}
- *err = 0; // -ENOSPC;
- b = block;
- *created = 0;
- if (block < EXT2_NDIR_BLOCKS) {
- /*
- * data page.
- */
- tmp = inode_getblk (inode, block, create, b,
- err, 0, &phys_block, created);
- goto out;
- }
- block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err, 1, NULL, NULL);
- tmp = block_getblk (inode, bh, block, create,
- inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
- goto out;
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err, 1, NULL, NULL);
- bh = block_getblk (inode, bh, block >> addr_per_block_bits,
- create, inode->i_sb->s_blocksize, b, err, 1, NULL, NULL);
- tmp = block_getblk (inode, bh, block & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
+ err = 0;
+ ptr = iblock;
+
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+ block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+
+ if (ptr < direct_blocks) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- block -= (1 << (addr_per_block_bits * 2));
- bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err, 1, NULL,NULL);
- bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
- create, inode->i_sb->s_blocksize, b, err, 1, NULL,NULL);
- bh = block_getblk (inode, bh, (block >> addr_per_block_bits) &
- (addr_per_block - 1), create, inode->i_sb->s_blocksize,
- b, err, 1, NULL,NULL);
- tmp = block_getblk (inode, bh, block & (addr_per_block - 1), create,
- inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
+ ptr -= direct_blocks;
+ if (ptr < indirect_blocks) {
+ bh = GET_INODE_PTR(EXT2_IND_BLOCK);
+ goto get_indirect;
+ }
+ ptr -= indirect_blocks;
+ if (ptr < double_blocks) {
+ bh = GET_INODE_PTR(EXT2_DIND_BLOCK);
+ goto get_double;
+ }
+ ptr -= double_blocks;
+ bh = GET_INODE_PTR(EXT2_TIND_BLOCK);
+ bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2));
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1));
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1));
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- if (!phys_block)
- goto abort;
- if (*err)
+ if (bh)
+ BUG(); // temporary debugging check
+ if (err)
goto abort;
- ret = phys_block;
+ if (!phys)
+ BUG(); // must not happen either
+
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped); /* safe */
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
abort:
unlock_kernel();
- return ret;
+ return err;
+
+abort_negative:
+ ext2_warning (inode->i_sb, "ext2_get_block", "block < 0");
+ goto abort;
+
+abort_too_big:
+ ext2_warning (inode->i_sb, "ext2_get_block", "block > big");
+ goto abort;
}
-struct buffer_head * ext2_getblk (struct inode * inode, long block,
- int create, int * err)
+struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
{
- struct buffer_head *tmp = NULL;
- int phys_block;
- int created;
-
- phys_block = ext2_getblk_block (inode, block, create, err, &created);
-
- if (phys_block) {
- tmp = getblk (inode->i_dev, phys_block, inode->i_sb->s_blocksize);
- if (created) {
- memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = ext2_get_block(inode, block, &dummy, create);
+ *err = error;
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
struct buffer_head * ext2_bread (struct inode * inode, int block,
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 885929f70..9666118ee 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -555,7 +555,7 @@ static int empty_dir (struct inode * inode)
while (offset < inode->i_size ) {
if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
brelse (bh);
- bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
+ bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
if (!bh) {
#if 0
ext2_error (sb, "empty_dir",
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index b0ebcb91b..5f73159c3 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -43,7 +43,7 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL, /* rename */
ext2_readlink, /* readlink */
ext2_follow_link, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index b6f57efb0..d824edb0b 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -129,7 +129,7 @@ static int check_block_empty(struct inode *inode, struct buffer_head *bh,
if (*(ind++))
goto in_use;
- if (bh->b_count == 1) {
+ if (atomic_read(&bh->b_count) == 1) {
int tmp;
tmp = le32_to_cpu(*p);
*p = 0;
@@ -141,7 +141,7 @@ static int check_block_empty(struct inode *inode, struct buffer_head *bh,
bforget(bh);
if (ind_bh)
mark_buffer_dirty(ind_bh, 1);
- ext2_free_blocks (inode, tmp, 1);
+ ext2_free_blocks(inode, tmp, 1);
goto out;
}
retry = 1;
@@ -158,11 +158,10 @@ out:
}
#define DATA_BUFFER_USED(bh) \
- (bh->b_count || buffer_locked(bh))
+ (atomic_read(&bh->b_count) || buffer_locked(bh))
static int trunc_direct (struct inode * inode)
{
- struct buffer_head * bh;
int i, retry = 0;
unsigned long block_to_free = 0, free_count = 0;
int blocks = inode->i_sb->s_blocksize / 512;
@@ -175,19 +174,9 @@ static int trunc_direct (struct inode * inode)
if (!tmp)
continue;
- bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (bh) {
- if (DATA_BUFFER_USED(bh)) {
- retry = 1;
- continue;
- }
- bh->b_count++;
- }
-
*p = 0;
inode->i_blocks -= blocks;
mark_inode_dirty(inode);
- bforget(bh);
/* accumulate blocks to free if they're contiguous */
if (free_count == 0)
@@ -206,8 +195,7 @@ static int trunc_direct (struct inode * inode)
return retry;
}
-static int trunc_indirect (struct inode * inode, int offset, u32 * p,
- struct buffer_head *dind_bh)
+static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buffer_head *dind_bh)
{
struct buffer_head * ind_bh;
int i, tmp, retry = 0;
@@ -242,28 +230,15 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p,
indirect_block = 0;
for (i = indirect_block ; i < addr_per_block ; i++) {
u32 * ind = i + (u32 *) ind_bh->b_data;
- struct buffer_head * bh;
wait_on_buffer(ind_bh);
tmp = le32_to_cpu(*ind);
if (!tmp)
continue;
- /*
- * Use find_buffer so we don't block here.
- */
- bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (bh) {
- if (DATA_BUFFER_USED(bh)) {
- retry = 1;
- continue;
- }
- bh->b_count++;
- }
*ind = 0;
inode->i_blocks -= blocks;
mark_inode_dirty(inode);
- bforget(bh);
mark_buffer_dirty(ind_bh, 1);
/* accumulate blocks to free if they're contiguous */
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 7c9518181..5d964da2b 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -57,12 +57,14 @@ struct inode_operations fat_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ fat_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- fat_bmap, /* bmap */
+ NULL, /* flushpage */
fat_truncate, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
/* #Specification: msdos / special devices / mmap
@@ -107,12 +109,14 @@ struct inode_operations fat_file_inode_operations_1024 = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ NULL, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
fat_truncate, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static struct file_operations fat_file_operations_readpage = {
@@ -142,12 +146,14 @@ struct inode_operations fat_file_inode_operations_readpage = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
fat_readpage, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
fat_truncate, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
#define MSDOS_PREFETCH 32
diff --git a/fs/fifo.c b/fs/fifo.c
index e18183fc9..4566f97f4 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -179,7 +179,7 @@ struct inode_operations fifo_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/file_table.c b/fs/file_table.c
index 45b68daec..80c3a08ba 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -80,7 +80,7 @@ struct file * get_empty_filp(void)
nr_free_files--;
new_one:
memset(f, 0, sizeof(*f));
- f->f_count = 1;
+ atomic_set(&f->f_count, 1);
f->f_version = ++event;
f->f_uid = current->fsuid;
f->f_gid = current->fsgid;
@@ -120,7 +120,7 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
{
memset(filp, 0, sizeof(*filp));
filp->f_mode = mode;
- filp->f_count = 1;
+ atomic_set(&filp->f_count, 1);
filp->f_dentry = dentry;
filp->f_uid = current->fsuid;
filp->f_gid = current->fsgid;
@@ -133,21 +133,17 @@ int init_private_file(struct file *filp, struct dentry *dentry, int mode)
void fput(struct file *file)
{
- int count = file->f_count-1;
-
- if (!count) {
+ if (atomic_dec_and_test(&file->f_count)) {
locks_remove_flock(file);
__fput(file);
- file->f_count = 0;
remove_filp(file);
insert_file_free(file);
- } else
- file->f_count = count;
+ }
}
void put_filp(struct file *file)
{
- if(--file->f_count == 0) {
+ if (atomic_dec_and_test(&file->f_count)) {
remove_filp(file);
insert_file_free(file);
}
diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c
index 189b0107e..a5ce908a7 100644
--- a/fs/hfs/dir_cap.c
+++ b/fs/hfs/dir_cap.c
@@ -87,12 +87,14 @@ struct inode_operations hfs_cap_ndir_inode_operations = {
hfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
struct inode_operations hfs_cap_fdir_inode_operations = {
@@ -108,12 +110,14 @@ struct inode_operations hfs_cap_fdir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
struct inode_operations hfs_cap_rdir_inode_operations = {
@@ -129,12 +133,14 @@ struct inode_operations hfs_cap_rdir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
/*================ File-local functions ================*/
diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c
index 17e53798a..d68f7ed6a 100644
--- a/fs/hfs/dir_dbl.c
+++ b/fs/hfs/dir_dbl.c
@@ -86,12 +86,14 @@ struct inode_operations hfs_dbl_dir_inode_operations = {
dbl_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c
index 21d4ca9af..aa8a90220 100644
--- a/fs/hfs/dir_nat.c
+++ b/fs/hfs/dir_nat.c
@@ -93,9 +93,10 @@ struct inode_operations hfs_nat_ndir_inode_operations = {
hfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
@@ -115,9 +116,10 @@ struct inode_operations hfs_nat_hdir_inode_operations = {
nat_hdr_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/hfs/file.c b/fs/hfs/file.c
index d3796e275..6b01cd9e0 100644
--- a/fs/hfs/file.c
+++ b/fs/hfs/file.c
@@ -63,9 +63,10 @@ struct inode_operations hfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ hfs_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- hfs_bmap, /* bmap */
+ NULL, /* flushpage */
hfs_file_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c
index 789073d19..e96dd7f20 100644
--- a/fs/hfs/file_cap.c
+++ b/fs/hfs/file_cap.c
@@ -77,9 +77,10 @@ struct inode_operations hfs_cap_info_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block - none */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap - none */
+ NULL, /* flushpage */
cap_info_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c
index d112b3498..58a12133a 100644
--- a/fs/hfs/file_hdr.c
+++ b/fs/hfs/file_hdr.c
@@ -78,10 +78,11 @@ struct inode_operations hfs_hdr_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block - XXX: not available since
+ header part has no disk block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap - XXX: not available since
- header part has no disk block */
+ NULL, /* flushpage */
hdr_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/hpfs/Makefile b/fs/hpfs/Makefile
index 46f1ffae0..2ebaece02 100644
--- a/fs/hpfs/Makefile
+++ b/fs/hpfs/Makefile
@@ -1,5 +1,5 @@
O_TARGET := hpfs.o
-O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o mmap.o name.o namei.o super.o
+O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o name.o namei.o super.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c
index f2c4a3532..62410ca26 100644
--- a/fs/hpfs/anode.c
+++ b/fs/hpfs/anode.c
@@ -301,13 +301,20 @@ void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree)
anode = hpfs_map_anode(s, ano, &bh);
btree1 = &anode->btree;
} else btree1 = btree;
- for (i = 0; i < btree1->n_used_nodes; i++)
- if (btree1->u.internal[i].down == oano)
- if ((pos = i + 1) < btree1->n_used_nodes) goto go_down;
- else goto go_up;
- hpfs_error(s, "reference to anode %08x not found in anode %08x (probably bad up pointer)",
- oano, level ? ano : -1);
- if (level) brelse(bh);
+ for (i = 0; i < btree1->n_used_nodes; i++) {
+ if (btree1->u.internal[i].down == oano) {
+ if ((pos = i + 1) < btree1->n_used_nodes)
+ goto go_down;
+ else
+ goto go_up;
+ }
+ }
+ hpfs_error(s,
+ "reference to anode %08x not found in anode %08x "
+ "(probably bad up pointer)",
+ oano, level ? ano : -1);
+ if (level)
+ brelse(bh);
}
/* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */
diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c
index 6dac91fd8..d7abdc991 100644
--- a/fs/hpfs/ea.c
+++ b/fs/hpfs/ea.c
@@ -233,10 +233,10 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
goto bail;
fnode->ea_anode = 0;
len++;
- }
- else if (!fnode->ea_anode)
- if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) len++;
- else {
+ } else if (!fnode->ea_anode) {
+ if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) {
+ len++;
+ } else {
/* Aargh... don't know how to create ea anodes :-( */
/*struct buffer_head *bh;
struct anode *anode;
@@ -280,10 +280,15 @@ void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data
fnode->ea_secno = new_sec;
len = (pos + 511) >> 9;
}
- if (fnode->ea_anode)
- if (hpfs_add_sector_to_btree(s, fnode->ea_secno, 0, len) != -1)
+ }
+ if (fnode->ea_anode) {
+ if (hpfs_add_sector_to_btree(s, fnode->ea_secno,
+ 0, len) != -1) {
len++;
- else goto bail;
+ } else {
+ goto bail;
+ }
+ }
}
h[0] = 0;
h[1] = strlen(key);
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 7cea8dcdc..fbb1f2f6c 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -53,143 +53,101 @@ void hpfs_truncate(struct inode *i)
{
if (IS_IMMUTABLE(i)) return /*-EPERM*/;
i->i_hpfs_n_secs = 0;
- hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
i->i_blocks = 1 + ((i->i_size + 511) >> 9);
+ hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
hpfs_write_inode(i);
}
-ssize_t hpfs_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+int hpfs_getblk_block(struct inode *inode, long block, int create, int *err, int *created)
{
- struct inode *inode = filp->f_dentry->d_inode;
- int i,j;
- int a = generic_file_read(filp, buf, count, ppos);
- if (inode->i_hpfs_conv != CONV_TEXT || a < 0) {
- return a;
- }
- for (i = 0, j = 0; i < a; i++) {
- char c;
- int error;
- if ((error = get_user(c, buf + i))) return error;
- if (c != '\r') {
- if (i != j) put_user(c, buf + j);
- j++;
+ int add;
+ int sec = 0;
+ down(&inode->i_sem);
+ if (err) *err = 0;
+ if (created) *created = 0;
+ if (!inode->i_blocks) {
+ hpfs_error(inode->i_sb, "hpfs_get_block: inode %08x has no blocks", inode->i_ino);
+ if (err) *err = -EFSERROR;
+ up(&inode->i_sem);
+ return 0;
+ }
+ if (block < ((add = inode->i_blocks - 1))) {
+ int bm;
+ if (!(bm = hpfs_bmap(inode, block))) {
+ hpfs_error(inode->i_sb, "hpfs_get_block: cound not bmap block %08x, inode %08x, size %08x", (int)block, inode->i_ino, (int)inode->i_size);
+ *err = -EFSERROR;
}
+ up(&inode->i_sem);
+ return bm;
}
- return j;
+ if (!create) {
+ if (err) *err = -EFBIG;
+ up(&inode->i_sem);
+ return 0;
+ }
+ if (created) *created = 1;
+ while (add <= block) {
+ if ((sec = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, add)) == -1) {
+ if (err) *err = -ENOSPC;
+ hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
+ return 0;
+ } /* FIXME: clear block */
+ add++;
+ }
+ inode->i_blocks = add + 1;
+ up(&inode->i_sem);
+ return sec;
}
-ssize_t hpfs_file_write(struct file *filp, const char *buf, size_t count,
- loff_t *ppos)
+/* copied from ext2fs */
+static int hpfs_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, int update)
{
- struct inode *i = filp->f_dentry->d_inode;
- int carry, error = 0;
- const char *start = buf;
- if (!i) return -EINVAL;
- if (!S_ISREG(i->i_mode)) return -EINVAL;
- if (IS_IMMUTABLE(i)) return -EPERM;
- if (filp->f_flags & O_APPEND) *ppos = i->i_size;
- if (count <= 0) return 0;
- if ((unsigned)(*ppos+count) >= 0x80000000U || (unsigned)count >= 0x80000000U) return -EFBIG;
- carry = 0;
- while (count || carry) {
- int ii, add = 0;
- secno sec = 0; /* Go away, uninitialized variable warning */
- int offset, size, written;
- char ch;
- struct buffer_head *bh;
- char *data;
- offset = *ppos & 0x1ff;
- size = count > 0x200 - offset ? 0x200 - offset : count;
- if ((*ppos >> 9) < ((i->i_size + 0x1ff) >> 9)) {
- i->i_hpfs_n_secs = 0;
- if (!(sec = hpfs_bmap(i, *ppos >> 9))) {
- hpfs_error(i->i_sb, "bmap failed, file %08x, fsec %08x",
- i->i_ino, *ppos >> 9);
- error =- EFSERROR;
- break;
- }
- } else for (ii = (i->i_size + 0x1ff) >> 9, add = 1; ii <= *ppos >> 9; ii++) {
- if ((sec = hpfs_add_sector_to_btree(i->i_sb, i->i_ino, 1, ii)) == -1) {
- hpfs_truncate(i);
- return -ENOSPC;
- }
- if (*ppos != i->i_size)
- if ((data = hpfs_get_sector(i->i_sb, sec, &bh))) {
- memset(data, 0, 512);
- mark_buffer_dirty(bh, 0);
- brelse(bh);
- }
- i->i_size = 0x200 * ii + 1;
- i->i_blocks++;
- /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
- if (i->i_sb->s_hpfs_chk >= 2) {
- secno bsec;
- bsec = hpfs_bmap(i, ii);
- if (sec != bsec) {
- hpfs_error(i->i_sb, "sec == %08x, bmap returns %08x", sec, bsec);
- error = -EFSERROR;
- break;
- }
- }
- PRINTK(("file_write: added %08x\n", sec));
- }
- if (!sec || sec == 15) {
- hpfs_error(i->i_sb, "bmap returned empty sector");
- error = -EFSERROR;
- break;
- }
- if (i->i_sb->s_hpfs_chk)
- if (hpfs_chk_sectors(i->i_sb, sec, 1, "data")) {
- error = -EFSERROR;
- break;
- }
- if ((!offset && size == 0x200) || add)
- data = hpfs_get_sector(i->i_sb, sec, &bh);
- else data = hpfs_map_sector(i->i_sb, sec, &bh, 0);
- if (!data) {
- error = -EIO;
- break;
- }
- if (i->i_hpfs_conv != CONV_TEXT) {
- memcpy_fromfs(data + offset, buf, written = size);
- buf += size;
- } else {
- int left;
- char *to;
- /* LF->CR/LF conversion, stolen from fat fs */
- written = left = 0x200 - offset;
- to = (char *) bh->b_data + (*ppos & 0x1ff);
- if (carry) {
- *to++ = '\n';
- left--;
- carry = 0;
- }
- for (size = 0; size < count && left; size++) {
- if ((error = get_user(ch, buf++))) break;
- if (ch == '\n') {
- *to++ = '\r';
- left--;
- }
- if (!left) carry = 1;
- else {
- *to++ = ch;
- left--;
- }
- }
- written -= left;
+ if (!bh->b_blocknr) {
+ int error, created;
+ unsigned long blocknr;
+
+ blocknr = hpfs_getblk_block(inode, block, 1, &error, &created);
+ if (!blocknr) {
+ if (!error)
+ error = -ENOSPC;
+ return error;
}
- update_vm_cache(i, *ppos, bh->b_data + (*ppos & 0x1ff), written);
- *ppos += written;
- if (*ppos > i->i_size) {
- i->i_size = *ppos;
- /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+
+ bh->b_dev = inode->i_dev;
+ bh->b_blocknr = blocknr;
+
+ if (!update)
+ return 0;
+
+ if (created) {
+ memset(bh->b_data, 0, bh->b_size);
+ set_bit(BH_Uptodate, &bh->b_state);
+ return 0;
}
- mark_buffer_dirty(bh, 0);
- brelse(bh);
- count -= size;
}
- if (start == buf) return error;
- i->i_mtime = CURRENT_TIME;
- /*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
- return buf - start;
+
+ if (!update)
+ return 0;
+
+ lock_kernel();
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ unlock_kernel();
+
+ return buffer_uptodate(bh) ? 0 : -EIO;
+}
+
+ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+
+ retval = generic_file_write(file, buf, count,
+ ppos, block_write_partial_page);
+ if (retval > 0) {
+ struct inode *inode = file->f_dentry->d_inode;
+ inode->i_mtime = CURRENT_TIME;
+ inode->i_hpfs_dirty = 1;
+ }
+ return retval;
}
+
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
index cdb2c709e..050b63597 100644
--- a/fs/hpfs/hpfs_fn.h
+++ b/fs/hpfs/hpfs_fn.h
@@ -21,6 +21,7 @@
#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
#include <stdarg.h>
@@ -259,6 +260,7 @@ secno hpfs_bmap(struct inode *, unsigned);
void hpfs_truncate(struct inode *);
ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
ssize_t hpfs_file_write(struct file *, const char *, size_t, loff_t *);
+int hpfs_writepage (struct file *, struct page *);
/* inode.c */
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 17984d667..efc776218 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -11,7 +11,7 @@
static const struct file_operations hpfs_file_ops =
{
NULL, /* lseek - default */
- hpfs_file_read, /* read */
+ generic_file_read, /* read */
hpfs_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* poll - default */
@@ -41,11 +41,13 @@ static const struct inode_operations hpfs_file_iops =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
- NULL, /* writepage */
(int (*)(struct inode *, int))
- &hpfs_bmap, /* bmap */
- &hpfs_truncate, /* truncate */
+#warning Someone needs to code up hpfs_get_block properly... -DaveM
+ &hpfs_bmap, /* get_block */
+ block_read_full_page, /* readpage */
+ hpfs_writepage, /* writepage */
+ block_flushpage, /* flushpage */
+ hpfs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* revalidate */
@@ -84,13 +86,14 @@ static const struct inode_operations hpfs_dir_iops =
hpfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* revalidate */
+ NULL /* revalidate */
};
const struct inode_operations hpfs_symlink_iops =
@@ -107,13 +110,14 @@ const struct inode_operations hpfs_symlink_iops =
NULL, /* rename */
hpfs_readlink, /* readlink */
hpfs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* revalidate */
+ NULL /* revalidate */
};
@@ -125,7 +129,6 @@ void hpfs_read_inode(struct inode *i)
unsigned char *ea;
int ea_size;
i->i_op = 0;
- /*i->i_hpfs_sem = MUTEX;*/
init_MUTEX(&i->i_hpfs_sem);
i->i_uid = sb->s_hpfs_uid;
i->i_gid = sb->s_hpfs_gid;
diff --git a/fs/hpfs/mmap.c b/fs/hpfs/mmap.c
deleted file mode 100644
index 3fd544664..000000000
--- a/fs/hpfs/mmap.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * linux/fs/hpfs/mmap.c
- *
- * taken from fat filesystem
- *
- * Written by Jacques Gelinas (jacques@solucorp.qc.ca)
- * Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993)
- *
- * Modified for HPFS by Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz)
- *
- * mmap handling for hpfs filesystem
- * (generic_file_mmap may be used only on filesystems that keep zeros
- * in last file sector beyond end)
- */
-
-/*
- * generic_file_mmap doesn't erase the space beyond file end in last sector. :-(
- * Hpfs doesn't keep zeros in last sector. This causes problems with kernel
- * mkdep.c and probably other programs. Additionally this could be a security
- * hole - some interesting data, like pieces of /etc/shadow could be found
- * beyond file end.
- *
- * So, I can't use generic mmap. mmap from fat filesystem looks good, so I used
- * it.
- *
- * BTW. fat uses generic mmap on normal disks. Doesn't it also have above bugs?
- * I don't think Msdos erases space in last sector.
- *
- * If you fix generic_file_mmap, you can remove this file and use it.
- */
-
-#include "hpfs_fn.h"
-
-/*
- * Fill in the supplied page for mmap
- */
-
-static unsigned long hpfs_file_mmap_nopage(
- struct vm_area_struct * area,
- unsigned long address,
- int error_code)
-{
- /*struct inode * inode = area->vm_inode;*/
- struct inode * inode = area->vm_file->f_dentry->d_inode;
- unsigned long page;
- unsigned int clear;
- loff_t pos;
- long gap; /* distance from eof to pos */
-
- page = __get_free_page(GFP_KERNEL);
- if (!page)
- return page;
- address &= PAGE_MASK;
- pos = address - area->vm_start + area->vm_offset;
-
- clear = 0;
- gap = inode->i_size - pos;
- if (gap <= 0){
- /* mmaping beyond end of file */
- clear = PAGE_SIZE;
- }else{
- int cur_read;
- int need_read;
- /*struct file *filp = area->vm_file;*/
- struct file filp;
- if (gap < PAGE_SIZE){
- clear = PAGE_SIZE - gap;
- }
- filp.f_reada = 0;
- filp.f_pos = pos;
- filp.f_dentry=area->vm_file->f_dentry;
- need_read = PAGE_SIZE - clear;
- {
- mm_segment_t cur_fs = get_fs();
- set_fs (KERNEL_DS);
- cur_read = generic_file_read (&filp,(char*)page
- ,need_read,&pos);
- set_fs (cur_fs);
- }
- if (cur_read != need_read){
- hpfs_error(inode->i_sb, "Error while reading an mmap file %08x", inode->i_ino);
- }
- }
- if (clear > 0){
- memset ((char*)page+PAGE_SIZE-clear,0,clear);
- }
- return page;
-}
-
-struct vm_operations_struct hpfs_file_mmap = {
- NULL, /* open */
- NULL, /* close */
- NULL, /* unmap */
- NULL, /* protect */
- NULL, /* sync */
- NULL, /* advise */
- hpfs_file_mmap_nopage, /* nopage */
- NULL, /* wppage */
- NULL, /* swapout */
- NULL, /* swapin */
-};
-
-/*
- * This is used for a general mmap of an msdos file
- * Returns 0 if ok, or a negative error code if not.
- */
-int hpfs_mmap(struct file * file, struct vm_area_struct * vma)
-{
- struct inode *inode = file->f_dentry->d_inode;
- /*printk("start mmap\n");*/
- if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */
- return -EINVAL;
- if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
- return -EINVAL;
- if (!inode->i_sb || !S_ISREG(inode->i_mode))
- return -EACCES;
- /*if (!IS_RDONLY(inode)) {
- inode->i_atime = CURRENT_TIME;
- mark_inode_dirty(inode);
- }*/
-
- vma->vm_file = file;
- /*inode->i_count++;*/
- file->f_count++;
- vma->vm_ops = &hpfs_file_mmap;
- /*printk("end mmap\n");*/
- return 0;
-}
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index a50f2a49b..c6291c83a 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -283,7 +283,7 @@ int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
return 1;
}
-static inline void hpfs_help()
+static inline void hpfs_help(void)
{
printk("\n\
HPFS filesystem options:\n\
diff --git a/fs/inode.c b/fs/inode.c
index ba9cc7a78..01fc64d23 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -231,7 +231,7 @@ void write_inode_now(struct inode *inode)
void clear_inode(struct inode *inode)
{
if (inode->i_nrpages)
- truncate_inode_pages(inode, 0);
+ BUG();
wait_on_inode(inode);
if (IS_QUOTAINIT(inode))
DQUOT_DROP(inode);
@@ -261,6 +261,8 @@ static void dispose_list(struct list_head * head)
if (tmp == head)
break;
inode = list_entry(tmp, struct inode, i_list);
+ if (inode->i_nrpages)
+ truncate_inode_pages(inode, 0);
clear_inode(inode);
count++;
}
@@ -735,6 +737,8 @@ void iput(struct inode *inode)
if (op && op->delete_inode) {
void (*delete)(struct inode *) = op->delete_inode;
spin_unlock(&inode_lock);
+ if (inode->i_nrpages)
+ truncate_inode_pages(inode, 0);
delete(inode);
spin_lock(&inode_lock);
}
@@ -778,8 +782,14 @@ kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count));
int bmap(struct inode * inode, int block)
{
- if (inode->i_op && inode->i_op->bmap)
- return inode->i_op->bmap(inode, block);
+ struct buffer_head tmp;
+
+ if (inode->i_op && inode->i_op->get_block) {
+ tmp.b_state = 0;
+ tmp.b_blocknr = 0;
+ inode->i_op->get_block(inode, block, &tmp, 0);
+ return tmp.b_blocknr;
+ }
return 0;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8d18e453a..e9f8e09b6 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -18,14 +18,21 @@ static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
switch (cmd) {
case FIBMAP:
+ {
+ struct buffer_head tmp;
+
if (inode->i_op == NULL)
return -EBADF;
- if (inode->i_op->bmap == NULL)
+ if (inode->i_op->get_block == NULL)
return -EINVAL;
if ((error = get_user(block, (int *) arg)) != 0)
return error;
- block = inode->i_op->bmap(inode,block);
- return put_user(block, (int *) arg);
+
+ tmp.b_state = 0;
+ tmp.b_blocknr = 0;
+ inode->i_op->get_block(inode, block, &tmp, 0);
+ return put_user(tmp.b_blocknr, (int *) arg);
+ }
case FIGETBSZ:
if (inode->i_sb == NULL)
return -EBADF;
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 23ca159c7..bc64dfdd5 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -57,11 +57,14 @@ struct inode_operations isofs_dir_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int isofs_name_translate(char * old, int len, char * new)
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index ce85b367a..fd9b124ed 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -48,10 +48,12 @@ struct inode_operations isofs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- isofs_bmap, /* bmap */
+ isofs_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 01d37a849..1cf86ae63 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -55,7 +55,7 @@ static int isofs_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
#endif
-void isofs_put_super(struct super_block *sb)
+static void isofs_put_super(struct super_block *sb)
{
#ifdef CONFIG_JOLIET
if (sb->u.isofs_sb.s_nls_iocharset) {
@@ -73,6 +73,9 @@ void isofs_put_super(struct super_block *sb)
return;
}
+static void isofs_read_inode(struct inode *);
+static int isofs_statfs (struct super_block *, struct statfs *, int);
+
static struct super_operations isofs_sops = {
isofs_read_inode,
NULL, /* write_inode */
@@ -487,8 +490,8 @@ static unsigned int isofs_get_last_session(kdev_t dev,s32 session )
* Note: a check_disk_change() has been done immediately prior
* to this call, so we don't need to check again.
*/
-struct super_block *isofs_read_super(struct super_block *s, void *data,
- int silent)
+static struct super_block *isofs_read_super(struct super_block *s, void *data,
+ int silent)
{
kdev_t dev = s->s_dev;
struct buffer_head * bh = NULL, *pri_bh = NULL;
@@ -894,7 +897,7 @@ out_unlock:
return NULL;
}
-int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+static int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -910,96 +913,115 @@ int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
}
-static int do_isofs_bmap(struct inode * inode,int block)
+/* Life is simpler than for other filesystem since we never
+ * have to create a new block, only find an existing one.
+ */
+int isofs_get_block(struct inode *inode, long iblock,
+ struct buffer_head *bh_result, int create)
{
- off_t b_off, offset, size;
- struct inode *ino;
+ off_t b_off, offset, sect_size;
unsigned int firstext;
unsigned long nextino;
- int i;
+ int i, err;
- if (block<0) {
- printk("_isofs_bmap: block<0");
- return 0;
- }
+ lock_kernel();
- b_off = block << ISOFS_BUFFER_BITS(inode);
+ err = -EROFS;
+ if (create)
+ goto abort_create_attempted;
- /*
- * If we are beyond the end of this file, don't give out any
+ err = -EIO;
+ if (iblock < 0)
+ goto abort_negative;
+
+ b_off = iblock << ISOFS_BUFFER_BITS(inode);
+
+ /* If we are beyond the end of this file, don't give out any
* blocks.
*/
- if( b_off > inode->i_size )
- {
- off_t max_legal_read_offset;
-
- /*
- * If we are *way* beyond the end of the file, print a message.
- * Access beyond the end of the file up to the next page boundary
- * is normal, however because of the way the page cache works.
- * In this case, we just return 0 so that we can properly fill
- * the page with useless information without generating any
- * I/O errors.
- */
- max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
- & ~(PAGE_SIZE - 1);
- if( b_off >= max_legal_read_offset )
- {
-
- printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block,
- inode->i_size);
- }
- return 0;
- }
+ if (b_off > inode->i_size) {
+ off_t max_legal_read_offset;
+
+ /* If we are *way* beyond the end of the file, print a message.
+ * Access beyond the end of the file up to the next page boundary
+ * is normal, however because of the way the page cache works.
+ * In this case, we just return 0 so that we can properly fill
+ * the page with useless information without generating any
+ * I/O errors.
+ */
+ max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
+ & ~(PAGE_SIZE - 1);
+ if (b_off >= max_legal_read_offset)
+ goto abort_beyond_end;
+ }
+
+ offset = 0;
+ firstext = inode->u.isofs_i.i_first_extent;
+ sect_size = inode->u.isofs_i.i_section_size;
+ nextino = inode->u.isofs_i.i_next_section_ino;
- offset = 0;
- firstext = inode->u.isofs_i.i_first_extent;
- size = inode->u.isofs_i.i_section_size;
- nextino = inode->u.isofs_i.i_next_section_ino;
-#ifdef DEBUG
- printk("first inode: inode=%x nextino=%x firstext=%u size=%lu\n",
- inode->i_ino, nextino, firstext, size);
-#endif
i = 0;
if (nextino) {
- while(b_off >= offset + size) {
- offset += size;
-
- if(nextino == 0) return 0;
- ino = iget(inode->i_sb, nextino);
- if(!ino) return 0;
- firstext = ino->u.isofs_i.i_first_extent;
- size = ino->u.isofs_i.i_section_size;
-#ifdef DEBUG
- printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
- inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
-#endif
- nextino = ino->u.isofs_i.i_next_section_ino;
- iput(ino);
-
- if(++i > 100) {
- printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
- printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
- inode->i_ino, block, firstext, (unsigned)size, nextino);
- return 0;
- }
+ while (b_off >= (offset + sect_size)) {
+ struct inode *ninode;
+
+ offset += sect_size;
+ if (nextino == 0)
+ goto abort;
+ ninode = iget(inode->i_sb, nextino);
+ if (!ninode)
+ goto abort;
+ firstext = ninode->u.isofs_i.i_first_extent;
+ sect_size = ninode->u.isofs_i.i_section_size;
+ nextino = ninode->u.isofs_i.i_next_section_ino;
+ iput(ninode);
+
+ if (++i > 100)
+ goto abort_too_many_sections;
}
}
-#ifdef DEBUG
- printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n",
- inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
-#endif
- return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
-}
-int isofs_bmap(struct inode * inode,int block)
-{
- int retval;
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr =
+ (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
+ bh_result->b_state |= (1UL << BH_Mapped);
+ err = 0;
- lock_kernel();
- retval = do_isofs_bmap(inode, block);
+abort:
unlock_kernel();
- return retval;
+ return err;
+
+abort_create_attempted:
+ printk("_isofs_bmap: Kernel tries to allocate a block\n");
+ goto abort;
+
+abort_negative:
+ printk("_isofs_bmap: block < 0\n");
+ goto abort;
+
+abort_beyond_end:
+ printk("_isofs_bmap: block >= EOF (%ld, %ld)\n",
+ iblock, inode->i_size);
+ goto abort;
+
+abort_too_many_sections:
+ printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+ printk("isofs_bmap: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n",
+ inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino);
+ goto abort;
+}
+
+int isofs_bmap(struct inode *inode, int block)
+{
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = isofs_get_block(inode, block, &dummy, 0);
+ if (!error)
+ return dummy.b_blocknr;
+ return 0;
}
static void test_and_set_uid(uid_t *p, uid_t value)
@@ -1101,7 +1123,7 @@ out_toomany:
goto out;
}
-void isofs_read_inode(struct inode * inode)
+static void isofs_read_inode(struct inode * inode)
{
struct super_block *sb = inode->i_sb;
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
diff --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c
index 5de4a8748..e5a7a2c72 100644
--- a/fs/isofs/symlink.c
+++ b/fs/isofs/symlink.c
@@ -38,11 +38,14 @@ struct inode_operations isofs_symlink_inode_operations = {
NULL, /* rename */
isofs_readlink, /* readlink */
isofs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int isofs_readlink(struct dentry * dentry, char * buffer, int buflen)
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index e8b208f65..02cfb07f4 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -140,6 +140,7 @@ nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
host->h_expires = jiffies + NLM_HOST_EXPIRE;
host->h_count = 1;
+ init_waitqueue_head(&host->h_gracewait);
host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */
host->h_exportent = clnt;
diff --git a/fs/locks.c b/fs/locks.c
index 301b92c9e..728985c34 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -563,11 +563,14 @@ int locks_verify_area(int read_write, struct inode *inode, struct file *filp,
/* Candidates for mandatory locking have the setgid bit set
* but no group execute bit - an otherwise meaningless combination.
*/
- if (IS_MANDLOCK(inode) &&
- (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
- return (locks_mandatory_area(read_write, inode, filp, offset,
- count));
- return (0);
+ if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+ int retval;
+ lock_kernel();
+ retval = locks_mandatory_area(read_write, inode, filp, offset, count);
+ unlock_kernel();
+ return retval;
+ }
+ return 0;
}
int locks_mandatory_locked(struct inode *inode)
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 187925903..a44d5d69d 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -52,11 +52,14 @@ struct inode_operations minix_dir_inode_operations = {
minix_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int minix_readdir(struct file * filp,
diff --git a/fs/minix/file.c b/fs/minix/file.c
index d6b7ecb17..14d478bde 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -27,50 +27,14 @@
#include <linux/fs.h>
#include <linux/minix_fs.h>
-static int minix_writepage(struct file *file, struct page *page)
-{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- unsigned long block;
- int *p, nr[PAGE_SIZE/BLOCK_SIZE];
- int i, err, created;
- struct buffer_head *bh;
-
- i = PAGE_SIZE / BLOCK_SIZE;
- block = page->offset / BLOCK_SIZE;
- p = nr;
- bh = page->buffers;
- do {
- if (bh && bh->b_blocknr)
- *p = bh->b_blocknr;
- else
- *p = minix_getblk_block(inode, block, 1, &err, &created);
- if (!*p)
- return -EIO;
- i--;
- block++;
- p++;
- if (bh)
- bh = bh->b_this_page;
- } while(i > 0);
-
- /* IO start */
- brw_page(WRITE, page, inode->i_dev, nr, BLOCK_SIZE, 1);
- return 0;
-}
-
-static long minix_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char *buf)
-{
- return block_write_one_page(file, page, offset, bytes, buf, minix_getblk_block);
-}
-
/*
* Write to a file (through the page cache).
*/
static ssize_t
minix_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- return generic_file_write(file, buf, count, ppos, minix_write_one_page);
+ return generic_file_write(file, buf, count,
+ ppos, block_write_partial_page);
}
/*
@@ -88,7 +52,10 @@ static struct file_operations minix_file_operations = {
NULL, /* no special open is needed */
NULL, /* flush */
NULL, /* release */
- minix_sync_file /* fsync */
+ minix_sync_file, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL /* revalidate */
};
struct inode_operations minix_file_inode_operations = {
@@ -104,12 +71,12 @@ struct inode_operations minix_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
- minix_writepage, /* writepage */
- minix_bmap, /* bmap */
+ minix_get_block, /* get_block */
+ block_read_full_page, /* readpage */
+ block_write_full_page, /* writepage */
+ block_flushpage, /* flushpage */
minix_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
NULL, /* revalidate */
- block_flushpage, /* flushpage */
};
diff --git a/fs/minix/fsync.c b/fs/minix/fsync.c
index ef3d15db9..2fcdddf15 100644
--- a/fs/minix/fsync.c
+++ b/fs/minix/fsync.c
@@ -53,7 +53,7 @@ static int V1_sync_block (struct inode * inode, unsigned short * block, int wait
return 0;
}
ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
+ atomic_dec(&bh->b_count);
return 0;
}
@@ -190,7 +190,7 @@ static int V2_sync_block (struct inode * inode, unsigned long * block, int wait)
return 0;
}
ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
+ atomic_dec(&bh->b_count);
return 0;
}
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 088de42dc..e5352090d 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -19,6 +19,7 @@
#include <linux/stat.h>
#include <linux/locks.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -361,112 +362,127 @@ static int V1_block_bmap(struct buffer_head * bh, int nr)
return tmp;
}
-static int V1_minix_bmap(struct inode * inode,int block)
+static int V1_minix_block_map(struct inode * inode, long block)
{
- int i;
+ int i, ret;
- if (block<0) {
+ ret = 0;
+ lock_kernel();
+ if (block < 0) {
printk("minix_bmap: block<0");
- return 0;
+ goto out;
}
if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
printk("minix_bmap: block>big");
- return 0;
+ goto out;
+ }
+ if (block < 7) {
+ ret = V1_inode_bmap(inode,block);
+ goto out;
}
- if (block < 7)
- return V1_inode_bmap(inode,block);
block -= 7;
if (block < 512) {
i = V1_inode_bmap(inode,7);
if (!i)
- return 0;
- return V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
+ goto out;
+ ret = V1_block_bmap(bread(inode->i_dev, i,
+ BLOCK_SIZE), block);
+ goto out;
}
block -= 512;
i = V1_inode_bmap(inode,8);
if (!i)
- return 0;
+ goto out;
i = V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9);
if (!i)
- return 0;
- return V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 511);
+ goto out;
+ ret = V1_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+ block & 511);
+out:
+ unlock_kernel();
+ return ret;
}
/*
* The minix V2 fs bmap functions.
*/
-#define V2_inode_bmap(inode,nr) (((unsigned long *)(inode)->u.minix_i.u.i2_data)[(nr)])
+#define V2_inode_bmap(inode,nr) (((unsigned int *)(inode)->u.minix_i.u.i2_data)[(nr)])
static int V2_block_bmap(struct buffer_head * bh, int nr)
{
int tmp;
if (!bh)
return 0;
- tmp = ((unsigned long *) bh->b_data)[nr];
+ tmp = ((unsigned int *) bh->b_data)[nr];
brelse(bh);
return tmp;
}
-static int V2_minix_bmap(struct inode * inode, int block)
+static int V2_minix_block_map(struct inode * inode, int block)
{
- int i;
+ int i, ret;
- if (block<0) {
+ ret = 0;
+ lock_kernel();
+ if (block < 0) {
printk("minix_bmap: block<0");
- return 0;
+ goto out;
}
if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
printk("minix_bmap: block>big");
- return 0;
+ goto out;
+ }
+ if (block < 7) {
+ ret = V2_inode_bmap(inode,block);
+ goto out;
}
- if (block < 7)
- return V2_inode_bmap(inode,block);
block -= 7;
if (block < 256) {
- i = V2_inode_bmap(inode,7);
+ i = V2_inode_bmap(inode, 7);
if (!i)
- return 0;
- return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
+ goto out;
+ ret = V2_block_bmap(bread(inode->i_dev, i,
+ BLOCK_SIZE), block);
+ goto out;
}
block -= 256;
- if (block < 256*256) {
- i = V2_inode_bmap(inode,8);
+ if (block < (256 * 256)) {
+ i = V2_inode_bmap(inode, 8);
if (!i)
- return 0;
- i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block >> 8);
+ goto out;
+ i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+ block >> 8);
if (!i)
- return 0;
- return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255);
+ goto out;
+ ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+ block & 255);
+ goto out;
}
- block -= 256*256;
- i = V2_inode_bmap(inode,9);
+ block -= (256 * 256);
+ i = V2_inode_bmap(inode, 9);
if (!i)
- return 0;
- i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block >> 16);
+ goto out;
+ i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+ block >> 16);
if (!i)
- return 0;
- i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),(block >> 8) & 255);
+ goto out;
+ i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+ (block >> 8) & 255);
if (!i)
- return 0;
- return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255);
-}
-
-/*
- * The global minix fs bmap function.
- */
-int minix_bmap(struct inode * inode, int block)
-{
- if (INODE_VERSION(inode) == MINIX_V1)
- return V1_minix_bmap(inode, block);
- else
- return V2_minix_bmap(inode, block);
+ goto out;
+ ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+ block & 255);
+out:
+ unlock_kernel();
+ return ret;
}
/*
* The minix V1 fs getblk functions.
*/
-static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr, int create,
- int metadata, int *phys_block, int *created)
+static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr,
+ int new_block, int *err,
+ int metadata, int *phys, int *new)
{
int tmp;
unsigned short *p;
@@ -483,15 +499,30 @@ repeat:
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
- if (!create)
- return NULL;
+ *err = -EFBIG;
+
+ /* Check file limits.. */
+ {
+ unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= BLOCK_SIZE_BITS;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ *err = -EFBIG;
+ return NULL;
+ }
+ }
+ }
+
tmp = minix_new_block(inode->i_sb);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
@@ -504,12 +535,18 @@ repeat:
mark_buffer_dirty(result, 1);
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ BUG();
minix_free_block(inode->i_sb, tmp);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
- *created = 1;
+ *err = 0;
+ *new = 1;
}
*p = tmp;
@@ -519,22 +556,22 @@ repeat:
}
static struct buffer_head * V1_block_getblk(struct inode * inode,
- struct buffer_head * bh, int nr, int create,
- int metadata, int *phys_block, int *created)
+ struct buffer_head * bh, int nr, int new_block, int *err,
+ int metadata, int *phys, int *new)
{
int tmp;
unsigned short *p;
struct buffer_head * result;
+ unsigned long limit;
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
- brelse(bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
p = nr + (unsigned short *) bh->b_data;
repeat:
@@ -542,27 +579,29 @@ repeat:
if (tmp) {
if (metadata) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
- if (tmp == *p) {
- brelse(bh);
- return result;
- }
+ if (tmp == *p)
+ goto out;
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse(bh);
- return NULL;
+ *phys = tmp;
+ goto out;
}
}
- if (!create) {
- brelse(bh);
- return NULL;
+ *err = -EFBIG;
+
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= BLOCK_SIZE_BITS;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ goto out;
+ }
}
+
tmp = minix_new_block(inode->i_sb);
- if (!tmp) {
- brelse(bh);
- return NULL;
- }
+ if (!tmp)
+ goto out;
if (metadata) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
@@ -574,69 +613,118 @@ repeat:
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
- if (*p) {
- minix_free_block(inode->i_sb, tmp);
- goto repeat;
- }
- *phys_block = tmp;
- result = NULL;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
+ }
+ if (*p) {
+ minix_free_block(inode->i_sb, tmp);
+ brelse(result);
+ goto repeat;
}
*p = tmp;
mark_buffer_dirty(bh, 1);
+ *err = 0;
+out:
brelse(bh);
return result;
}
-int V1_getblk_block(struct inode * inode, long block, int create, int *err, int *created)
+static int V1_get_block(struct inode * inode, long block,
+ struct buffer_head *bh_result, int create)
{
- struct buffer_head *bh, *tmp;
- int phys_block;
+ int ret, err, new, phys, ptr;
+ struct buffer_head *bh;
- *err = -EIO;
- if (block < 0) {
- printk("minix_getblk: block<0");
- return 0;
- }
- if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) {
- printk("minix_getblk: block>big");
+ if (!create) {
+ phys = V1_minix_block_map(inode, block);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
return 0;
}
- *created = 0;
- if (block < 7) {
- tmp = V1_inode_getblk(inode, block, create,
- 0, &phys_block, created);
+
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+ if (block < 0)
+ goto abort_negative;
+ if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)
+ goto abort_too_big;
+
+ err = 0;
+ ptr = block;
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ V1_inode_getblk(inode, x, block, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ V1_inode_getblk(inode, x, block, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ V1_block_getblk(inode, bh, x, block, &err, 0, &phys, &new)
+#define GET_INDIRECT_PTR(x) \
+ V1_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL)
+
+ if (ptr < 7) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- block -= 7;
- if (block < 512) {
- bh = V1_inode_getblk(inode, 7, create, 1, NULL, NULL);
- tmp = V1_block_getblk(inode, bh, block, create,
- 0, &phys_block, created);
- goto out;
+ ptr -= 7;
+ if (ptr < 512) {
+ bh = GET_INODE_PTR(7);
+ goto get_indirect;
}
- block -= 512;
- bh = V1_inode_getblk(inode, 8, create, 1, NULL, NULL);
- bh = V1_block_getblk(inode, bh, (block>>9) & 511, create, 1, NULL, NULL);
- tmp = V1_block_getblk(inode, bh, block & 511, create, 0, &phys_block, created);
+ ptr -= 512;
+ bh = GET_INODE_PTR(8);
+ bh = GET_INDIRECT_PTR((ptr >> 9) & 511);
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & 511);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- *err = 0;
- return phys_block;
+ if (err)
+ goto abort;
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
+abort:
+ unlock_kernel();
+ return err;
+
+abort_negative:
+ printk("minix_getblk: block<0");
+ goto abort;
+
+abort_too_big:
+ printk("minix_getblk: block>big");
+ goto abort;
}
/*
* The minix V2 fs getblk functions.
*/
-static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr, int create,
- int metadata, int *phys_block, int *created)
+static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr,
+ int new_block, int *err,
+ int metadata, int *phys, int *new)
{
int tmp;
- unsigned long *p;
+ unsigned int *p;
struct buffer_head * result;
- p = (unsigned long *) inode->u.minix_i.u.i2_data + nr;
+ p = (unsigned int *) inode->u.minix_i.u.i2_data + nr;
repeat:
tmp = *p;
if (tmp) {
@@ -647,15 +735,30 @@ repeat:
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
- if (!create)
- return NULL;
+ *err = -EFBIG;
+
+ /* Check file limits.. */
+ {
+ unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= BLOCK_SIZE_BITS;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ *err = -EFBIG;
+ return NULL;
+ }
+ }
+ }
+
tmp = minix_new_block(inode->i_sb);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
@@ -668,12 +771,18 @@ repeat:
mark_buffer_dirty(result, 1);
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ BUG();
minix_free_block(inode->i_sb, tmp);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
- *created = 1;
+ *err = 0;
+ *new = 1;
}
*p = tmp;
@@ -683,50 +792,52 @@ repeat:
}
static struct buffer_head * V2_block_getblk(struct inode * inode,
- struct buffer_head * bh, int nr, int create,
- int metadata, int *phys_block, int *created)
+ struct buffer_head * bh, int nr, int new_block, int *err,
+ int metadata, int *phys, int *new)
{
int tmp;
- unsigned long *p;
+ unsigned int *p;
struct buffer_head * result;
+ unsigned long limit;
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
- brelse(bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
- p = nr + (unsigned long *) bh->b_data;
+ p = nr + (unsigned int *) bh->b_data;
repeat:
tmp = *p;
if (tmp) {
if (metadata) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
- if (tmp == *p) {
- brelse(bh);
- return result;
- }
+ if (tmp == *p)
+ goto out;
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse(bh);
- return NULL;
+ *phys = tmp;
+ goto out;
}
}
- if (!create) {
- brelse(bh);
- return NULL;
+ *err = -EFBIG;
+
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= BLOCK_SIZE_BITS;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ goto out;
+ }
}
+
tmp = minix_new_block(inode->i_sb);
- if (!tmp) {
- brelse(bh);
- return NULL;
- }
+ if (!tmp)
+ goto out;
if (metadata) {
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
@@ -738,103 +849,151 @@ repeat:
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
- if (*p) {
- minix_free_block(inode->i_sb, tmp);
- goto repeat;
- }
- *phys_block = tmp;
- result = NULL;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
+ }
+ if (*p) {
+ minix_free_block(inode->i_sb, tmp);
+ brelse(result);
+ goto repeat;
}
*p = tmp;
mark_buffer_dirty(bh, 1);
+ *err = 0;
+out:
brelse(bh);
return result;
}
-int V2_getblk_block(struct inode * inode, int block, int create, int *err, int *created)
+static int V2_get_block(struct inode * inode, long block,
+ struct buffer_head *bh_result, int create)
{
- struct buffer_head * bh, *tmp;
- int phys_block;
+ int ret, err, new, phys, ptr;
+ struct buffer_head * bh;
- *err = -EIO;
- if (block < 0) {
- printk("minix_getblk: block<0");
- return 0;
- }
- if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) {
- printk("minix_getblk: block>big");
+ if (!create) {
+ phys = V2_minix_block_map(inode, block);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
return 0;
}
- *created = 0;
- if (block < 7) {
- tmp = V2_inode_getblk(inode, block, create,
- 0, &phys_block, created);
+
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+ if (block < 0)
+ goto abort_negative;
+ if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)
+ goto abort_too_big;
+
+ err = 0;
+ ptr = block;
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ V2_inode_getblk(inode, x, block, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ V2_inode_getblk(inode, x, block, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ V2_block_getblk(inode, bh, x, block, &err, 0, &phys, &new)
+#define GET_INDIRECT_PTR(x) \
+ V2_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL)
+
+ if (ptr < 7) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- block -= 7;
- if (block < 256) {
- bh = V2_inode_getblk(inode, 7, create, 1, NULL, NULL);
- tmp = V2_block_getblk(inode, bh, block, create,
- 0, &phys_block, created);
- goto out;
+ ptr -= 7;
+ if (ptr < 256) {
+ bh = GET_INODE_PTR(7);
+ goto get_indirect;
}
- block -= 256;
- if (block < 256*256) {
- bh = V2_inode_getblk(inode, 8, create, 1, NULL, NULL);
- bh = V2_block_getblk(inode, bh, (block>>8) & 255, create,
- 1, NULL, NULL);
- tmp = V2_block_getblk(inode, bh, block & 255, create,
- 0, &phys_block, created);
- goto out;
+ ptr -= 256;
+ if (ptr < 256*256) {
+ bh = GET_INODE_PTR(8);
+ goto get_double;
}
- block -= 256*256;
- bh = V2_inode_getblk(inode, 9, create, 1, NULL, NULL);
- bh = V2_block_getblk(inode, bh, (block >> 16) & 255, create, 1, NULL, NULL);
- bh = V2_block_getblk(inode, bh, (block >> 8) & 255, create, 1, NULL, NULL);
- tmp = V2_block_getblk(inode, bh, block & 255, create, 0, &phys_block, created);
+ ptr -= 256*256;
+ bh = GET_INODE_PTR(9);
+ bh = GET_INDIRECT_PTR((ptr >> 16) & 255);
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> 8) & 255);
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & 255);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- *err = 0;
- return phys_block;
+ if (err)
+ goto abort;
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
+abort:
+ unlock_kernel();
+ return err;
+
+abort_negative:
+ printk("minix_getblk: block<0");
+ goto abort;
+
+abort_too_big:
+ printk("minix_getblk: block>big");
+ goto abort;
}
-int minix_getblk_block (struct inode *inode, long block,
- int create, int *err, int *created)
+int minix_get_block(struct inode *inode, long block,
+ struct buffer_head *bh_result, int create)
{
if (INODE_VERSION(inode) == MINIX_V1)
- return V1_getblk_block(inode, block, create, err, created);
+ return V1_get_block(inode, block, bh_result, create);
else
- return V2_getblk_block(inode, block, create, err, created);
+ return V2_get_block(inode, block, bh_result, create);
}
/*
* the global minix fs getblk function.
*/
-struct buffer_head *minix_getblk (struct inode *inode, int block, int create)
+struct buffer_head *minix_getblk(struct inode *inode, int block, int create)
{
- struct buffer_head *tmp = NULL;
- int phys_block;
- int err, created;
-
- phys_block = minix_getblk_block(inode, block, create, &err, &created);
- if (phys_block) {
- tmp = getblk(inode->i_dev, phys_block, BLOCK_SIZE);
- if (created) {
- memset(tmp->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = minix_get_block(inode, block, &dummy, create);
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, BLOCK_SIZE);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
struct buffer_head * minix_bread(struct inode * inode, int block, int create)
{
struct buffer_head * bh;
- bh = minix_getblk(inode,block,create);
+ bh = minix_getblk(inode, block, create);
if (!bh || buffer_uptodate(bh))
return bh;
ll_rw_block(READ, 1, &bh);
diff --git a/fs/minix/symlink.c b/fs/minix/symlink.c
index 4f3661105..3a8951b09 100644
--- a/fs/minix/symlink.c
+++ b/fs/minix/symlink.c
@@ -33,11 +33,14 @@ struct inode_operations minix_symlink_inode_operations = {
NULL, /* rename */
minix_readlink, /* readlink */
minix_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static struct dentry * minix_follow_link(struct dentry * dentry,
diff --git a/fs/minix/truncate.c b/fs/minix/truncate.c
index 4718e092e..6724d0064 100644
--- a/fs/minix/truncate.c
+++ b/fs/minix/truncate.c
@@ -33,7 +33,7 @@
*/
#define DATA_BUFFER_USED(bh) \
- ((bh->b_count > 1) || buffer_locked(bh))
+ (atomic_read(&bh->b_count) || buffer_locked(bh))
/*
* The functions for minix V1 fs truncation.
@@ -121,7 +121,7 @@ repeat:
if (*(ind++))
break;
if (i >= 512) {
- if (ind_bh->b_count != 1)
+ if (atomic_read(&ind_bh->b_count) != 1)
retry = 1;
else {
tmp = *p;
@@ -166,7 +166,7 @@ repeat:
if (*(dind++))
break;
if (i >= 512) {
- if (dind_bh->b_count != 1)
+ if (atomic_read(&dind_bh->b_count) != 1)
retry = 1;
else {
tmp = *p;
@@ -285,7 +285,7 @@ repeat:
if (*(ind++))
break;
if (i >= 256) {
- if (ind_bh->b_count != 1)
+ if (atomic_read(&ind_bh->b_count) != 1)
retry = 1;
else {
tmp = *p;
@@ -330,7 +330,7 @@ repeat:
if (*(dind++))
break;
if (i >= 256) {
- if (dind_bh->b_count != 1)
+ if (atomic_read(&dind_bh->b_count) != 1)
retry = 1;
else {
tmp = *p;
@@ -376,7 +376,7 @@ repeat:
if (*(tind++))
break;
if (i >= 256) {
- if (tind_bh->b_count != 1)
+ if (atomic_read(&tind_bh->b_count) != 1)
retry = 1;
else {
tmp = *p;
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 8175724d7..fa5e4aed5 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -627,9 +627,10 @@ struct inode_operations msdos_dir_inode_operations = {
msdos_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 680f011a1..1f92a89fb 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -92,9 +92,10 @@ struct inode_operations ncp_dir_inode_operations =
ncp_rename, /* rename */
NULL, /* readlink */
NULL, /* follow link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index bb61e2464..3e16cf408 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -295,6 +295,13 @@ struct inode_operations ncp_file_inode_operations =
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* bmap */
- NULL /* truncate */
+ NULL, /* follow_link */
+ NULL, /* get_block */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* flushpage */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index a923c218c..578b2b985 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -59,12 +59,14 @@ struct inode_operations ncp_symlink_inode_operations={
NULL, /* rename */
ncp_readlink, /* readlink */
ncp_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
/* ----- follow a symbolic link ------------------------------------------ */
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index d41505862..31d76e5c6 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -78,7 +78,7 @@ struct inode_operations nfs_dir_inode_operations = {
nfs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -884,6 +884,8 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
nfs_flush_dircache(dir);
error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (!error)
+ dir->i_nlink++;
return error;
}
@@ -909,8 +911,8 @@ dentry->d_inode->i_count, dentry->d_inode->i_nlink);
/* Update i_nlink and invalidate dentry. */
if (!error) {
d_drop(dentry);
- if (dentry->d_inode->i_nlink)
- dentry->d_inode->i_nlink --;
+ if (dir->i_nlink)
+ dir->i_nlink--;
}
return error;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index d3066f4cd..2fed65b38 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -71,7 +71,7 @@ struct inode_operations nfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
nfs_readpage, /* readpage */
nfs_writepage, /* writepage */
NULL, /* flushpage */
@@ -167,7 +167,7 @@ nfs_fsync(struct file *file, struct dentry *dentry)
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static long nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
long status;
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index c6fc4d685..6cd892740 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -43,7 +43,7 @@ struct inode_operations nfs_symlink_inode_operations = {
NULL, /* rename */
nfs_readlink, /* readlink */
nfs_follow_link, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 911a5261e..8b63cbf66 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -467,7 +467,7 @@ nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsig
* The IO completion will then free the page and the dentry.
*/
get_page(page);
- file->f_count++;
+ atomic_inc(&file->f_count);
/* Schedule request */
synchronous = schedule_write_request(req, synchronous);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 582b1854f..63294ae29 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -342,7 +342,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
memset(filp, 0, sizeof(*filp));
filp->f_op = inode->i_op->default_file_ops;
- filp->f_count = 1;
+ atomic_set(&filp->f_count, 1);
filp->f_flags = wflag? O_WRONLY : O_RDONLY;
filp->f_mode = wflag? FMODE_WRITE : FMODE_READ;
filp->f_dentry = dentry;
@@ -360,7 +360,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
/* I nearly added put_filp() call here, but this filp
* is really on callers stack frame. -DaveM
*/
- filp->f_count--;
+ atomic_dec(&filp->f_count);
}
}
out_nfserr:
diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c
index d9430c2cc..cc6bfe2e3 100644
--- a/fs/ntfs/fs.c
+++ b/fs/ntfs/fs.c
@@ -439,9 +439,10 @@ static struct inode_operations ntfs_inode_operations_nobmap = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
@@ -621,9 +622,10 @@ static struct inode_operations ntfs_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage,
+ ntfs_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- ntfs_bmap,
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
@@ -669,9 +671,10 @@ static struct inode_operations ntfs_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/open.c b/fs/open.c
index e9da4e32d..deb898f76 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -790,7 +790,7 @@ int filp_close(struct file *filp, fl_owner_t id)
int retval;
struct dentry *dentry = filp->f_dentry;
- if (filp->f_count == 0) {
+ if (!atomic_read(&filp->f_count)) {
printk("VFS: Close: file count is 0\n");
return 0;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 9830418cc..71f20bec5 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -8,6 +8,7 @@
#include <linux/file.h>
#include <linux/poll.h>
#include <linux/malloc.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -28,16 +29,12 @@
/* in case of paging and multiple read/write on the same pipe. (FGC) */
-static ssize_t pipe_read(struct file * filp, char * buf,
- size_t count, loff_t *ppos)
+static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count)
{
struct inode * inode = filp->f_dentry->d_inode;
ssize_t chars = 0, size = 0, read = 0;
char *pipebuf;
- if (ppos != &filp->f_pos)
- return -ESPIPE;
-
if (filp->f_flags & O_NONBLOCK) {
if (PIPE_LOCK(*inode))
return -EAGAIN;
@@ -82,17 +79,13 @@ static ssize_t pipe_read(struct file * filp, char * buf,
return -EAGAIN;
return 0;
}
-
-static ssize_t pipe_write(struct file * filp, const char * buf,
- size_t count, loff_t *ppos)
+
+static ssize_t do_pipe_write(struct file * filp, const char * buf, size_t count)
{
struct inode * inode = filp->f_dentry->d_inode;
ssize_t chars = 0, free = 0, written = 0, err=0;
char *pipebuf;
- if (ppos != &filp->f_pos)
- return -ESPIPE;
-
if (!PIPE_READERS(*inode)) { /* no readers */
send_sig(SIGPIPE,current,0);
return -EPIPE;
@@ -147,6 +140,32 @@ errout:
return written ? written : err;
}
+static ssize_t pipe_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+
+ if (ppos != &filp->f_pos)
+ return -ESPIPE;
+
+ lock_kernel();
+ retval = do_pipe_read(filp, buf, count);
+ unlock_kernel();
+ return retval;
+}
+
+static ssize_t pipe_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
+{
+ ssize_t retval;
+
+ if (ppos != &filp->f_pos)
+ return -ESPIPE;
+
+ lock_kernel();
+ retval = do_pipe_write(filp, buf, count);
+ unlock_kernel();
+ return retval;
+}
+
static long long pipe_lseek(struct file * file, long long offset, int orig)
{
return -ESPIPE;
@@ -461,7 +480,7 @@ struct inode_operations pipe_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 33717830f..f108511fb 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -1545,7 +1545,7 @@ struct inode_operations proc_array_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -1596,7 +1596,7 @@ struct inode_operations proc_arraylong_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 8579dd8c5..118e94956 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -45,7 +45,7 @@ static struct inode_operations proc_base_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 2bbb51d28..a900d01bf 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -51,7 +51,7 @@ struct inode_operations proc_fd_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 4e59fed73..1a2fe0f6e 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -60,7 +60,7 @@ struct inode_operations proc_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -86,7 +86,7 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c
index 3cfccab96..bfe6c8c2e 100644
--- a/fs/proc/kmsg.c
+++ b/fs/proc/kmsg.c
@@ -72,7 +72,7 @@ struct inode_operations proc_kmsg_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/link.c b/fs/proc/link.c
index 3a5639825..647dc339f 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -49,7 +49,7 @@ struct inode_operations proc_link_inode_operations = {
NULL, /* rename */
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/mem.c b/fs/proc/mem.c
index 0e89f7645..4d599c77b 100644
--- a/fs/proc/mem.c
+++ b/fs/proc/mem.c
@@ -336,7 +336,7 @@ struct inode_operations proc_mem_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/net.c b/fs/proc/net.c
index 1ad226de0..b4e18bc49 100644
--- a/fs/proc/net.c
+++ b/fs/proc/net.c
@@ -113,7 +113,7 @@ struct inode_operations proc_net_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/omirr.c b/fs/proc/omirr.c
index 562aa11c5..f738827a7 100644
--- a/fs/proc/omirr.c
+++ b/fs/proc/omirr.c
@@ -289,7 +289,7 @@ struct inode_operations proc_omirr_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index dcb007f11..72bb194cf 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -577,11 +577,14 @@ static struct inode_operations openpromfs_prop_inode_ops = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static struct file_operations openpromfs_nodenum_ops = {
@@ -611,11 +614,14 @@ static struct inode_operations openpromfs_nodenum_inode_ops = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static struct file_operations openprom_alias_operations = {
@@ -645,11 +651,14 @@ static struct inode_operations openprom_alias_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int lookup_children(u16 n, const char * name, int len)
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 594f00858..140281015 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -57,7 +57,7 @@ struct inode_operations devtree_symlink_inode_operations = {
NULL, /* rename */
devtree_readlink, /* readlink */
devtree_follow_link, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 67171fa07..d08860c26 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -71,7 +71,7 @@ struct inode_operations proc_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -97,7 +97,7 @@ struct inode_operations proc_dyna_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -142,7 +142,7 @@ static struct inode_operations proc_root_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -302,7 +302,7 @@ struct inode_operations proc_openprom_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -490,7 +490,7 @@ static struct inode_operations proc_self_inode_operations = {
NULL, /* rename */
proc_self_readlink, /* readlink */
proc_self_follow_link, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
@@ -513,7 +513,7 @@ static struct inode_operations proc_link_inode_operations = {
NULL, /* rename */
proc_readlink, /* readlink */
proc_follow_link, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/scsi.c b/fs/proc/scsi.c
index ae2679b6d..679fa383f 100644
--- a/fs/proc/scsi.c
+++ b/fs/proc/scsi.c
@@ -71,7 +71,7 @@ struct inode_operations proc_scsi_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/proc/sysvipc.c b/fs/proc/sysvipc.c
index c6e32894d..7fff0ed03 100644
--- a/fs/proc/sysvipc.c
+++ b/fs/proc/sysvipc.c
@@ -130,7 +130,7 @@ struct inode_operations proc_sysvipc_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* flushpage */
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index 029fd9061..8b27142a3 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -114,10 +114,12 @@ struct inode_operations qnx4_dir_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index ab923b7f0..2e2b9c2fb 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -189,16 +189,18 @@ struct inode_operations qnx4_file_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ qnx4_bmap, /* get_block */
qnx4_readpage, /* readpage */
NULL, /* writepage */
- qnx4_bmap, /* bmap */
+ NULL, /* flushpage */
#ifdef CONFIG_QNX4FS_RW
qnx4_truncate, /* truncate */
#else
NULL,
#endif
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int qnx4_readpage(struct file *file, struct page *page)
diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c
index 826ee8a09..4cea74fe5 100644
--- a/fs/qnx4/fsync.c
+++ b/fs/qnx4/fsync.c
@@ -55,7 +55,7 @@ static int sync_block(struct inode *inode, unsigned short *block, int wait)
return 0;
}
ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
+ atomic_dec(&bh->b_count);
return 0;
}
diff --git a/fs/qnx4/symlinks.c b/fs/qnx4/symlinks.c
index 457258670..c360d8b72 100644
--- a/fs/qnx4/symlinks.c
+++ b/fs/qnx4/symlinks.c
@@ -43,11 +43,14 @@ struct inode_operations qnx4_symlink_inode_operations =
NULL, /* rename */
qnx4_readlink, /* readlink */
qnx4_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static struct dentry *qnx4_follow_link(struct dentry *dentry,
diff --git a/fs/read_write.c b/fs/read_write.c
index c7ea90a69..cf207fed0 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -117,28 +117,22 @@ asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
{
ssize_t ret;
struct file * file;
- ssize_t (*read)(struct file *, char *, size_t, loff_t *);
-
- lock_kernel();
ret = -EBADF;
file = fget(fd);
- if (!file)
- goto bad_file;
- if (!(file->f_mode & FMODE_READ))
- goto out;
- ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
- file, file->f_pos, count);
- if (ret)
- goto out;
- ret = -EINVAL;
- if (!file->f_op || !(read = file->f_op->read))
- goto out;
- ret = read(file, buf, count, &file->f_pos);
-out:
- fput(file);
-bad_file:
- unlock_kernel();
+ if (file) {
+ if (file->f_mode & FMODE_READ) {
+ ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+ file, file->f_pos, count);
+ if (!ret) {
+ ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+ ret = -EINVAL;
+ if (file->f_op && (read = file->f_op->read) != NULL)
+ ret = read(file, buf, count, &file->f_pos);
+ }
+ }
+ fput(file);
+ }
return ret;
}
@@ -146,31 +140,23 @@ asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
{
ssize_t ret;
struct file * file;
- struct inode * inode;
- ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
-
- lock_kernel();
ret = -EBADF;
file = fget(fd);
- if (!file)
- goto bad_file;
- if (!(file->f_mode & FMODE_WRITE))
- goto out;
- inode = file->f_dentry->d_inode;
- ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+ if (file) {
+ if (file->f_mode & FMODE_WRITE) {
+ struct inode *inode = file->f_dentry->d_inode;
+ ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
file->f_pos, count);
- if (ret)
- goto out;
- ret = -EINVAL;
- if (!file->f_op || !(write = file->f_op->write))
- goto out;
-
- ret = write(file, buf, count, &file->f_pos);
-out:
- fput(file);
-bad_file:
- unlock_kernel();
+ if (!ret) {
+ ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+ ret = -EINVAL;
+ if (file->f_op && (write = file->f_op->write) != NULL)
+ ret = write(file, buf, count, &file->f_pos);
+ }
+ }
+ fput(file);
+ }
return ret;
}
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index d35b0d130..e16802e97 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -1,7 +1,7 @@
/*
* ROMFS file system, Linux implementation
*
- * Copyright (C) 1997 Janos Farkas <chexum@shadow.banki.hu>
+ * Copyright (C) 1997-1999 Janos Farkas <chexum@shadow.banki.hu>
*
* Using parts of the minix filesystem
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -57,6 +57,7 @@
#include <linux/fs.h>
#include <linux/locks.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -320,7 +321,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
const char *name; /* got from dentry */
int len;
- res = 0; /* instead of ENOENT */
+ res = -EACCES; /* placeholder for "no data here" */
offset = dir->i_ino & ROMFH_MASK;
if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
goto out;
@@ -335,8 +336,9 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
len = dentry->d_name.len;
for(;;) {
- if (!offset || offset >= maxoff
- || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
+ if (!offset || offset >= maxoff)
+ goto out0;
+ if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
goto out;
/* try to match the first 16 bytes of name */
@@ -365,19 +367,28 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = ntohl(ri.spec) & ROMFH_MASK;
- if ((inode = iget(dir->i_sb, offset))==NULL) {
- res = -EACCES;
- } else {
- d_add(dentry, inode);
- }
+ if ((inode = iget(dir->i_sb, offset)))
+ goto outi;
-out:
- return ERR_PTR(res);
+ /*
+ * it's a bit funky, _lookup needs to return an error code
+ * (negative) or a NULL, both as a dentry. ENOENT should not
+ * be returned, instead we need to create a negative dentry by
+ * d_add(dentry, NULL); and return 0 as no error.
+ * (Although as I see, it only matters on writable file
+ * systems).
+ */
+
+out0: inode = NULL;
+outi: res = 0;
+ d_add (dentry, inode);
+
+out: return ERR_PTR(res);
}
/*
* Ok, we do readpage, to be able to execute programs. Unfortunately,
- * we can't use bmap, since we have looser alignments.
+ * we can't use bmap, since we may have looser alignments.
*/
static int
@@ -389,12 +400,13 @@ romfs_readpage(struct file * file, struct page * page)
unsigned long offset, avail, readlen;
int result = -EIO;
- atomic_inc(&page->count);
- set_bit(PG_locked, &page->flags);
-
+ lock_kernel();
+ get_page(page);
buf = page_address(page);
- clear_bit(PG_uptodate, &page->flags);
- clear_bit(PG_error, &page->flags);
+
+ /* hack? */
+ page->owner = (int)current;
+
offset = page->offset;
if (offset < inode->i_size) {
avail = inode->i_size-offset;
@@ -403,18 +415,19 @@ romfs_readpage(struct file * file, struct page * page)
if (readlen < PAGE_SIZE) {
memset((void *)(buf+readlen),0,PAGE_SIZE-readlen);
}
- set_bit(PG_uptodate, &page->flags);
+ SetPageUptodate(page);
result = 0;
}
}
if (result) {
- set_bit(PG_error, &page->flags);
memset((void *)buf, 0, PAGE_SIZE);
+ SetPageError(page);
}
- clear_bit(PG_locked, &page->flags);
- wake_up(&page->wait);
+ UnlockPage(page);
+
free_page(buf);
+ unlock_kernel();
return result;
}
@@ -508,12 +521,14 @@ static struct inode_operations romfs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block -- not really */
romfs_readpage, /* readpage */
NULL, /* writepage */
- NULL, /* bmap -- not really */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
+ NULL /* revalidate */
};
static struct file_operations romfs_dir_operations = {
@@ -550,12 +565,14 @@ static struct inode_operations romfs_dir_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
+ NULL /* revalidate */
};
static struct inode_operations romfs_link_inode_operations = {
@@ -571,18 +588,20 @@ static struct inode_operations romfs_link_inode_operations = {
NULL, /* rename */
romfs_readlink, /* readlink */
romfs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
+ NULL /* revalidate */
};
static mode_t romfs_modemap[] =
{
- 0, S_IFDIR, S_IFREG, S_IFLNK+0777,
- S_IFBLK, S_IFCHR, S_IFSOCK, S_IFIFO
+ 0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
+ S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
};
static struct inode_operations *romfs_inoops[] =
@@ -591,10 +610,10 @@ static struct inode_operations *romfs_inoops[] =
&romfs_dir_inode_operations,
&romfs_file_inode_operations,
&romfs_link_inode_operations,
- &blkdev_inode_operations, /* standard handlers */
- &chrdev_inode_operations,
- NULL, /* socket */
- NULL, /* fifo */
+ NULL, /* device/fifo/socket nodes, */
+ NULL, /* set by init_special_inode */
+ NULL,
+ NULL,
};
static void
@@ -627,34 +646,30 @@ romfs_read_inode(struct inode *i)
i->i_mtime = i->i_atime = i->i_ctime = 0;
i->i_uid = i->i_gid = 0;
- i->i_op = romfs_inoops[nextfh & ROMFH_TYPE];
-
- /* Precalculate the data offset */
- ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
- if (ino >= 0)
- ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
- else
- ino = 0;
-
- i->u.romfs_i.i_metasize = ino;
- i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
-
- /* Compute permissions */
- ino = S_IRUGO|S_IWUSR;
- ino |= romfs_modemap[nextfh & ROMFH_TYPE];
- if (nextfh & ROMFH_EXEC) {
- ino |= S_IXUGO;
- }
- i->i_mode = ino;
-
- if (S_ISFIFO(ino))
- init_fifo(i);
- else if (S_ISDIR(ino))
- i->i_size = i->u.romfs_i.i_metasize;
- else if (S_ISBLK(ino) || S_ISCHR(ino)) {
- i->i_mode &= ~(S_IRWXG|S_IRWXO);
- ino = ntohl(ri.spec);
- i->i_rdev = MKDEV(ino>>16,ino&0xffff);
+ /* Precalculate the data offset */
+ ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
+ if (ino >= 0)
+ ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
+ else
+ ino = 0;
+
+ i->u.romfs_i.i_metasize = ino;
+ i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
+
+ /* Compute permissions */
+ ino = romfs_modemap[nextfh & ROMFH_TYPE];
+ /* only "normal" files have ops */
+ if ((i->i_op = romfs_inoops[nextfh & ROMFH_TYPE])) {
+ if (nextfh & ROMFH_EXEC)
+ ino |= S_IXUGO;
+ i->i_mode = ino;
+ if (S_ISDIR(ino))
+ i->i_size = i->u.romfs_i.i_metasize;
+ } else {
+ /* depending on MBZ for sock/fifos */
+ nextfh = ntohl(ri.spec);
+ nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
+ init_special_inode(i, ino, nextfh);
}
}
diff --git a/fs/select.c b/fs/select.c
index e47e3b0b4..4cb1a6d55 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -64,9 +64,9 @@ void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table
if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
struct poll_table_entry * entry;
ok_table:
- entry = p->entry + p->nr;
- entry->filp = filp;
- filp->f_count++;
+ entry = p->entry + p->nr;
+ entry->filp = filp;
+ atomic_inc(&filp->f_count);
entry->wait_address = wait_address;
init_waitqueue_entry(&entry->wait, current);
add_wait_queue(wait_address,&entry->wait);
@@ -181,17 +181,13 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
off = i / __NFDBITS;
if (!(bit & BITS(fds, off)))
continue;
- /*
- * The poll_wait routine will increment f_count if
- * the file is added to the wait table, so we don't
- * need to increment it now.
- */
- file = fcheck(i);
+ file = fget(i);
mask = POLLNVAL;
if (file) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, wait);
+ fput(file);
}
if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) {
SET(bit, __RES_IN(fds,off));
@@ -347,14 +343,14 @@ static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait,
mask = 0;
fd = fdpnt->fd;
if (fd >= 0) {
- /* poll_wait increments f_count if needed */
- struct file * file = fcheck(fd);
+ struct file * file = fget(fd);
mask = POLLNVAL;
if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, wait);
mask &= fdpnt->events | POLLERR | POLLHUP;
+ fput(file);
}
if (mask) {
wait = NULL;
diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c
index 870ebac74..cbaa646b3 100644
--- a/fs/smbfs/dir.c
+++ b/fs/smbfs/dir.c
@@ -59,9 +59,10 @@ struct inode_operations smb_dir_inode_operations =
smb_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index cfb2d82da..682b511f6 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -404,9 +404,10 @@ struct inode_operations smb_file_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
smb_readpage, /* readpage */
smb_writepage, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
smb_file_permission, /* permission */
NULL, /* smap */
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 627186cae..cf3539823 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -6,9 +6,7 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
-
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c
index 375ff6f75..f5240a75c 100644
--- a/fs/sysv/balloc.c
+++ b/fs/sysv/balloc.c
@@ -201,7 +201,7 @@ int sysv_new_block(struct super_block * sb)
unlock_super(sb);
return 0;
}
- if (bh->b_count != 1) {
+ if (atomic_read(&bh->b_count) != 1) {
printk("sysv_new_block: block already in use\n");
unlock_super(sb);
return 0;
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index a28a7ba8e..d76f1d6b3 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -59,11 +59,14 @@ struct inode_operations sysv_dir_inode_operations = {
sysv_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 19443f289..3019c913f 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -33,50 +33,14 @@
#include <linux/fs.h>
#include <linux/sysv_fs.h>
-static int sysv_writepage (struct file * file, struct page * page)
-{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- unsigned long block;
- int *p, nr[PAGE_SIZE/512];
- int i, err, created;
- struct buffer_head *bh;
-
- i = PAGE_SIZE >> inode->i_sb->sv_block_size_bits;
- block = page->offset >> inode->i_sb->sv_block_size_bits;
- p = nr;
- bh = page->buffers;
- do {
- if (bh && bh->b_blocknr)
- *p = bh->b_blocknr;
- else
- *p = sysv_getblk_block (inode, block, 1, &err, &created);
- if (!*p)
- return -EIO;
- i--;
- block++;
- p++;
- if (bh)
- bh = bh->b_this_page;
- } while (i > 0);
-
- /* IO start */
- brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->sv_block_size, 1);
- return 0;
-}
-
-static long sysv_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
-{
- return block_write_one_page(file, page, offset, bytes, buf, sysv_getblk_block);
-}
-
/*
* Write to a file (through the page cache).
*/
static ssize_t
sysv_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- return generic_file_write(file, buf, count, ppos, sysv_write_one_page);
+ return generic_file_write(file, buf, count,
+ ppos, block_write_partial_page);
}
/*
@@ -113,12 +77,12 @@ struct inode_operations sysv_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
- sysv_writepage, /* writepage */
- sysv_bmap, /* bmap */
+ sysv_get_block, /* get_block */
+ block_read_full_page, /* readpage */
+ block_write_full_page, /* writepage */
+ block_flushpage, /* flushpage */
sysv_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* revalidate */
- block_flushpage, /* flushpage */
+ NULL /* revalidate */
};
diff --git a/fs/sysv/fsync.c b/fs/sysv/fsync.c
index ddffd7de2..b0e1138c7 100644
--- a/fs/sysv/fsync.c
+++ b/fs/sysv/fsync.c
@@ -54,7 +54,7 @@ static int sync_block (struct inode * inode, u32 *blockp, int convert, int wait)
return 0;
}
ll_rw_block(WRITE, 1, &bh);
- bh->b_count--;
+ atomic_dec(&bh->b_count);
return 0;
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index d335b5b50..ff10e778d 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -31,6 +31,7 @@
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <asm/byteorder.h>
#include <asm/uaccess.h>
@@ -62,6 +63,11 @@ static void sysv_delete_inode(struct inode *inode)
sysv_free_inode(inode);
}
+static void sysv_put_super(struct super_block *);
+static void sysv_write_super(struct super_block *);
+static void sysv_read_inode(struct inode *);
+static int sysv_notify_change(struct dentry *, struct iattr *);
+static int sysv_statfs(struct super_block *, struct statfs *, int);
static struct super_operations sysv_sops = {
sysv_read_inode,
@@ -338,8 +344,8 @@ static struct super_block * detected_coherent (struct super_block *sb, struct bu
return sb;
}
-struct super_block *sysv_read_super(struct super_block *sb,void *data,
- int silent)
+static struct super_block *sysv_read_super(struct super_block *sb,
+ void *data, int silent)
{
struct buffer_head *bh;
const char *found;
@@ -519,7 +525,7 @@ struct super_block *sysv_read_super(struct super_block *sb,void *data,
}
/* This is only called on sync() and umount(), when s_dirt=1. */
-void sysv_write_super (struct super_block *sb)
+static void sysv_write_super(struct super_block *sb)
{
lock_super(sb);
if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) {
@@ -542,7 +548,7 @@ void sysv_write_super (struct super_block *sb)
unlock_super(sb);
}
-void sysv_put_super(struct super_block *sb)
+static void sysv_put_super(struct super_block *sb)
{
/* we can assume sysv_write_super() has already been called,
and that the superblock is locked */
@@ -555,7 +561,7 @@ void sysv_put_super(struct super_block *sb)
MOD_DEC_USE_COUNT;
}
-int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
{
struct statfs tmp;
@@ -597,59 +603,72 @@ static int block_bmap(struct super_block * sb, struct buffer_head * bh, int nr,
return tmp + sb->sv_block_base;
}
-int sysv_bmap(struct inode * inode,int block_nr)
+static unsigned int sysv_block_map(struct inode *inode, unsigned int block)
{
- unsigned int block = block_nr;
- struct super_block * sb = inode->i_sb;
- int convert;
- int i;
- struct buffer_head * bh;
+ struct super_block *sb;
+ int i, ret, convert;
- if (block < 10)
- return inode_bmap(sb,inode,block);
+ ret = 0;
+ lock_kernel();
+ sb = inode->i_sb;
+ if (block < 10) {
+ ret = inode_bmap(sb, inode, block);
+ goto out;
+ }
block -= 10;
convert = sb->sv_convert;
if (block < sb->sv_ind_per_block) {
- i = inode_bmap(sb,inode,10);
+ i = inode_bmap(sb, inode, 10);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- return block_bmap(sb, bh, block, convert);
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ block, convert);
+ goto out;
}
block -= sb->sv_ind_per_block;
if (block < sb->sv_ind_per_block_2) {
- i = inode_bmap(sb,inode,11);
+ i = inode_bmap(sb, inode, 11);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_bits, convert);
+ goto out;
+ i = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block >> sb->sv_ind_per_block_bits), convert);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block & sb->sv_ind_per_block_1), convert);
+ goto out;
}
block -= sb->sv_ind_per_block_2;
if (block < sb->sv_ind_per_block_3) {
- i = inode_bmap(sb,inode,12);
+ i = inode_bmap(sb, inode, 12);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_2_bits, convert);
+ goto out;
+ i = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block >> sb->sv_ind_per_block_2_bits), convert);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- i = block_bmap(sb, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,convert);
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ ((block >> sb->sv_ind_per_block_bits) &
+ sb->sv_ind_per_block_1), convert);
if (!i)
- return 0;
- bh = bread(inode->i_dev,i,sb->sv_block_size);
- return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
- }
- if ((int)block<0) {
- printk("sysv_bmap: block<0");
- return 0;
+ goto out;
+ ret = block_bmap(sb,
+ bread(inode->i_dev, i, sb->sv_block_size),
+ (block & sb->sv_ind_per_block_1), convert);
+ goto out;
}
- printk("sysv_bmap: block>big");
- return 0;
+ if ((int)block < 0)
+ printk("sysv_block_map: block < 0\n");
+ else
+ printk("sysv_block_map: block > big\n");
+out:
+ unlock_kernel();
+ return ret;
}
/* End of bmap support. */
@@ -657,8 +676,8 @@ int sysv_bmap(struct inode * inode,int block_nr)
/* Access selected blocks of regular files (or directories) */
-static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create,
- int metadata, int *phys_block, int *created)
+static struct buffer_head *inode_getblk(struct inode *inode, int nr, int new_block,
+ int *err, int metadata, long *phys, int *new)
{
struct super_block *sb;
u32 tmp;
@@ -677,15 +696,30 @@ repeat:
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
- if (!create)
- return NULL;
+ *err = -EFBIG;
+
+ /* Check file limits.. */
+ {
+ unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= sb->sv_block_size_bits;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ *err = -EFBIG;
+ return NULL;
+ }
+ }
+ }
+
tmp = sysv_new_block(sb);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
result = sv_getblk(sb, inode->i_dev, tmp);
if (*p) {
@@ -695,12 +729,18 @@ repeat:
}
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ BUG();
sysv_free_block(sb, tmp);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
- *created = 1;
+ *err = 0;
+ *new = 1;
}
*p = tmp;
@@ -709,24 +749,24 @@ repeat:
return result;
}
-static struct buffer_head * block_getblk(struct inode * inode,
- struct buffer_head * bh, int nr, int create,
- int metadata, int *phys_block, int *created)
+static struct buffer_head *block_getblk(struct inode *inode,
+ struct buffer_head *bh, int nr, int new_block, int *err,
+ int metadata, long *phys, int *new)
{
struct super_block *sb;
u32 tmp, block;
sysv_zone_t *p;
struct buffer_head * result;
+ unsigned long limit;
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block(READ, 1, &bh);
wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
- brelse(bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
sb = inode->i_sb;
p = nr + (sysv_zone_t *) bh->b_data;
@@ -737,120 +777,175 @@ repeat:
if (tmp) {
if (metadata) {
result = sv_getblk(sb, bh->b_dev, block);
- if (tmp == *p) {
- brelse(bh);
- return result;
- }
+ if (tmp == *p)
+ goto out;
brelse(result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse(bh);
- return NULL;
+ *phys = tmp;
+ goto out;
}
}
- if (!create) {
- brelse(bh);
- return NULL;
+ *err = -EFBIG;
+
+ limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+ if (limit < RLIM_INFINITY) {
+ limit >>= sb->sv_block_size_bits;
+ if (new_block >= limit) {
+ send_sig(SIGXFSZ, current, 0);
+ goto out;
+ }
}
+
block = sysv_new_block(sb);
- if (!block) {
- brelse(bh);
- return NULL;
- }
+ if (!block)
+ goto out;
if (metadata) {
result = sv_getblk(sb, bh->b_dev, block);
if (*p) {
- sysv_free_block(sb,block);
+ sysv_free_block(sb, block);
brelse(result);
goto repeat;
}
+ memset(result->b_data, 0, sb->sv_block_size);
+ mark_buffer_uptodate(result, 1);
+ mark_buffer_dirty(result, 1);
} else {
- *phys_block = tmp;
- result = NULL;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
+ }
+ if (*p) {
+ sysv_free_block(sb, block);
+ brelse(result);
+ goto repeat;
}
*p = (sb->sv_convert ? to_coh_ulong(block) : block);
mark_buffer_dirty(bh, 1);
+ *err = 0;
+out:
brelse(bh);
return result;
}
-int sysv_getblk_block(struct inode *inode, long block, int create,
- int *err, int *created)
+int sysv_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
- struct super_block *sb = inode->i_sb;
- struct buffer_head *bh, *tmp;
- int phys_block;
+ struct super_block *sb;
+ int ret, err, new;
+ struct buffer_head *bh;
+ unsigned long ptr, phys;
- *err = -EIO;
- if (block < 0) {
- printk("sysv_getblk: block<0");
- return 0;
- }
- if (block > sb->sv_ind_per_block_3) {
- printk("sysv_getblk: block>big");
+ if (!create) {
+ phys = sysv_block_map(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
return 0;
}
- if (block < 10) {
- tmp = inode_getblk(inode, block, create,
- 0, &phys_block, created);
+
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+ sb = inode->i_sb;
+ if (iblock < 0)
+ goto abort_negative;
+ if (iblock > sb->sv_ind_per_block_3)
+ goto abort_too_big;
+
+ err = 0;
+ ptr = iblock;
+
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+ block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+
+ if (ptr < 10) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- block -= 10;
- if (block < sb->sv_ind_per_block) {
- bh = inode_getblk(inode, 10, create, 1, NULL, NULL);
- tmp = block_getblk(inode, bh, block, create,
- 0, &phys_block, created);
- goto out;
+ ptr -= 10;
+ if (ptr < sb->sv_ind_per_block) {
+ bh = GET_INODE_PTR(10);
+ goto get_indirect;
}
- block -= sb->sv_ind_per_block;
- if (block < sb->sv_ind_per_block_2) {
- bh = inode_getblk(inode, 11, create, 1, NULL, NULL);
- bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create,
- 1, NULL, NULL);
- tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
- 0, &phys_block, created);
- goto out;
+ ptr -= sb->sv_ind_per_block;
+ if (ptr < sb->sv_ind_per_block_2) {
+ bh = GET_INODE_PTR(11);
+ goto get_double;
}
- block -= sb->sv_ind_per_block_2;
- bh = inode_getblk(inode, 12, create, 1, NULL, NULL);
- bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create,
- 1, NULL, NULL);
- bh = block_getblk(inode, bh,
- (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,
- create, 1, NULL, NULL);
- tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
- 0, &phys_block, created);
+ ptr -= sb->sv_ind_per_block_2;
+ bh = GET_INODE_PTR(12);
+ bh = GET_INDIRECT_PTR(ptr >> sb->sv_ind_per_block_2_bits);
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1);
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & sb->sv_ind_per_block_1);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- *err = 0;
- return phys_block;
+ if (err)
+ goto abort;
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
+abort:
+ unlock_kernel();
+ return err;
+
+abort_negative:
+ printk("sysv_getblk: block < 0\n");
+ goto abort;
+
+abort_too_big:
+ printk("sysv_getblk: block > big\n");
+ goto abort;
}
-struct buffer_head *sysv_getblk (struct inode *inode, unsigned int block, int create)
+struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
{
- struct buffer_head *tmp = NULL;
- int phys_block;
- int err, created;
-
- phys_block = sysv_getblk_block(inode, block, create, &err, &created);
- if (phys_block) {
- tmp = getblk(inode->i_dev, phys_block, BLOCK_SIZE);
- if (created) {
- memset(tmp->b_data, 0, BLOCK_SIZE);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = sysv_get_block(inode, block, &dummy, create);
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, BLOCK_SIZE);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
-struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create)
+struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create)
{
- struct buffer_head * bh;
+ struct buffer_head *bh;
- bh = sysv_getblk(inode,block,create);
+ bh = sysv_getblk(inode, block, create);
if (!bh || buffer_uptodate(bh))
return bh;
ll_rw_block(READ, 1, &bh);
@@ -903,7 +998,7 @@ static inline void coh_write3byte (unsigned char * p, unsigned long val)
*(unsigned short *)(p+1) = (unsigned short) val;
}
-void sysv_read_inode(struct inode * inode)
+static void sysv_read_inode(struct inode *inode)
{
struct super_block * sb = inode->i_sb;
struct buffer_head * bh;
@@ -971,7 +1066,7 @@ void sysv_read_inode(struct inode * inode)
}
/* To avoid inconsistencies between inodes in memory and inodes on disk. */
-int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
+static int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
int error;
diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c
index 5ebaec7cc..df611d589 100644
--- a/fs/sysv/symlink.c
+++ b/fs/sysv/symlink.c
@@ -39,11 +39,14 @@ struct inode_operations sysv_symlink_inode_operations = {
NULL, /* rename */
sysv_readlink, /* readlink */
sysv_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
static struct dentry *sysv_follow_link(struct dentry * dentry,
diff --git a/fs/sysv/truncate.c b/fs/sysv/truncate.c
index a8c0e0745..db0f72506 100644
--- a/fs/sysv/truncate.c
+++ b/fs/sysv/truncate.c
@@ -36,7 +36,7 @@
*/
#define DATA_BUFFER_USED(bh) \
- ((bh->b_count > 1) || buffer_locked(bh))
+ (atomic_read(&bh->b_count) || buffer_locked(bh))
/* We throw away any data beyond inode->i_size. */
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 6a79c4a5e..b93d04f0b 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -55,10 +55,8 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
while (!error && !stored && filp->f_pos < inode->i_size) {
lblk = (filp->f_pos) >> sb->s_blocksize_bits;
- /* XXX - ufs_bmap() call needs error checking */
- blk = ufs_bmap(inode, lblk);
- bh = bread (sb->s_dev, blk, sb->s_blocksize);
- if (!bh) {
+ blk = ufs_frag_map(inode, lblk);
+ if (!blk || !(bh = bread (sb->s_dev, blk, sb->s_blocksize))) {
/* XXX - error - skip to the next block */
printk("ufs_readdir: "
"dir inode %lu has a hole at offset %lu\n",
@@ -209,10 +207,12 @@ struct inode_operations ufs_dir_inode_operations = {
ufs_rename, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
ufs_permission, /* permission */
NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index 9e027cfc3..33d68ba5d 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -87,49 +87,23 @@ static inline void remove_suid(struct inode *inode)
}
}
-static int ufs_writepage (struct file *file, struct page *page)
-{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
- unsigned long block;
- int *p, nr[PAGE_SIZE/512];
- int i, err, created;
- struct buffer_head *bh;
-
- i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
- block = page->offset >> inode->i_sb->s_blocksize_bits;
- p = nr;
- bh = page->buffers;
- do {
- if (bh && bh->b_blocknr)
- *p = bh->b_blocknr;
- else
- *p = ufs_getfrag_block(inode, block, 1, &err, &created);
- if (!*p)
- return -EIO;
- i--;
- block++;
- p++;
- if (bh)
- bh = bh->b_this_page;
- } while (i > 0);
-
- brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
- return 0;
-}
-
-static long ufs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char *buf)
-{
- return block_write_one_page(file, page, offset, bytes, buf, ufs_getfrag_block);
-}
-
/*
* Write to a file (through the page cache).
*/
static ssize_t
ufs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- return generic_file_write(file, buf, count, ppos, ufs_write_one_page);
+ ssize_t retval;
+
+ retval = generic_file_write(file, buf, count,
+ ppos, block_write_partial_page);
+ if (retval > 0) {
+ struct inode *inode = file->f_dentry->d_inode;
+ remove_suid(inode);
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ }
+ return retval;
}
/*
@@ -176,12 +150,12 @@ struct inode_operations ufs_file_inode_operations = {
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
- ufs_writepage, /* writepage */
- ufs_bmap, /* bmap */
+ ufs_getfrag_block, /* get_block */
+ block_read_full_page, /* readpage */
+ block_write_full_page, /* writepage */
+ block_flushpage, /* flushpage */
ufs_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
- NULL, /* revalidate */
- block_flushpage, /* flushpage */
+ NULL /* revalidate */
};
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 636b0aabd..3d9c8f602 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -36,6 +36,7 @@
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/mm.h>
+#include <linux/smp_lock.h>
#include "swab.h"
#include "util.h"
@@ -82,10 +83,10 @@ static void ufs_print_inode(struct inode * inode)
#define ufs_inode_bmap(inode, nr) \
(SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask))
-static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr,
+static inline unsigned int ufs_block_bmap (struct buffer_head * bh, unsigned nr,
struct ufs_sb_private_info * uspi, unsigned swab)
{
- unsigned tmp;
+ unsigned int tmp;
UFSD(("ENTER, nr %u\n", nr))
if (!bh)
@@ -96,86 +97,90 @@ static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr,
return tmp;
}
-int ufs_bmap (struct inode * inode, int fragment)
+int ufs_frag_map(struct inode *inode, int frag)
{
- struct super_block * sb;
- struct ufs_sb_private_info * uspi;
- unsigned tmp;
- unsigned swab;
+ struct super_block *sb;
+ struct ufs_sb_private_info *uspi;
+ unsigned int swab;
+ int i, ret;
+
+ ret = 0;
+ lock_kernel();
sb = inode->i_sb;
uspi = sb->u.ufs_sb.s_uspi;
swab = sb->u.ufs_sb.s_swab;
-
- UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
-
- if (fragment >= ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
- ufs_warning (sb, "ufs_bmap", "block > big");
- return 0;
+ if (frag < 0) {
+ ufs_warning(sb, "ufs_frag_map", "frag < 0");
+ goto out;
}
-
- /*
- * direct fragment
- */
- if (fragment < UFS_NDIR_FRAGMENT)
- return (uspi->s_sbbase + ufs_inode_bmap (inode, fragment));
-
- /*
- * indirect fragment
- */
- fragment -= UFS_NDIR_FRAGMENT;
- if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
- tmp = ufs_inode_bmap (inode,
- UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift));
- if (!tmp)
- return 0;
- return (uspi->s_sbbase +
- ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab));
+ if (frag >=
+ ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
+ << uspi->s_fpbshift)) {
+ ufs_warning(sb, "ufs_frag_map", "frag > big");
+ goto out;
}
- /*
- * dindirect fragment
- */
- fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
- if (fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
- tmp = ufs_inode_bmap (inode,
- UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift));
- if (!tmp)
- return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
- if (!tmp)
- return 0;
- return (uspi->s_sbbase +
- ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab));
+ if (frag < UFS_NDIR_FRAGMENT) {
+ ret = uspi->s_sbbase + ufs_inode_bmap(inode, frag);
+ goto out;
}
- /*
- * tindirect fragment
- */
- fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
- tmp = ufs_inode_bmap (inode,
- UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift));
- if (!tmp)
- return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- (fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab);
- if (!tmp)
- return 0;
- tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
- if (!tmp)
- return 0;
- return (uspi->s_sbbase +
- ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
- fragment & uspi->s_apbmask, uspi, swab));
+ frag -= UFS_NDIR_FRAGMENT;
+ if (frag < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+ i = ufs_inode_bmap(inode,
+ UFS_IND_FRAGMENT + (frag >> uspi->s_apbshift));
+ if (!i)
+ goto out;
+ ret = (uspi->s_sbbase +
+ ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+ sb->s_blocksize),
+ frag & uspi->s_apbmask, uspi, swab));
+ }
+ frag -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+ if (frag < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+ i = ufs_inode_bmap (inode,
+ UFS_DIND_FRAGMENT + (frag >> uspi->s_2apbshift));
+ if (!i)
+ goto out;
+ i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+ sb->s_blocksize),
+ (frag >> uspi->s_apbshift) & uspi->s_apbmask,
+ uspi, swab);
+ if (!i)
+ goto out;
+ ret = (uspi->s_sbbase +
+ ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+ sb->s_blocksize),
+ (frag & uspi->s_apbmask), uspi, swab));
+ goto out;
+ }
+ frag -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+ i = ufs_inode_bmap(inode,
+ UFS_TIND_FRAGMENT + (frag >> uspi->s_3apbshift));
+ if (!i)
+ goto out;
+ i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+ (frag >> uspi->s_2apbshift) & uspi->s_apbmask,
+ uspi, swab);
+ if (!i)
+ goto out;
+ i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+ (frag >> uspi->s_apbshift) & uspi->s_apbmask,
+ uspi, swab);
+ if (!i)
+ goto out;
+ ret = (uspi->s_sbbase +
+ ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+ (frag & uspi->s_apbmask), uspi, swab));
+out:
+ unlock_kernel();
+ return ret;
}
-static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
- unsigned fragment, unsigned new_fragment, int create,
- unsigned required, int *err, int metadata, int *phys_block, int *created)
+static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
+ unsigned int fragment, unsigned int new_fragment,
+ unsigned int required, int *err, int metadata, long *phys, int *new)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
@@ -184,7 +189,7 @@ static struct buffer_head * ufs_inode_getfrag (struct inode * inode,
unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
unsigned tmp, goal;
u32 * p, * p2;
- unsigned swab;
+ unsigned int swab;
UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
inode->i_ino, fragment, new_fragment, required))
@@ -206,18 +211,17 @@ repeat:
sb->s_blocksize);
if (tmp == SWAB32(*p)) {
UFSD(("EXIT, result %u\n", tmp + blockoff))
- return result;
+ return result;
}
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
*err = -EFBIG;
- if (!create)
- return NULL;
+
limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= sb->s_blocksize_bits;
@@ -226,6 +230,7 @@ repeat:
return NULL;
}
}
+
lastblock = ufs_fragstoblks (lastfrag);
lastblockoff = ufs_fragnum (lastfrag);
/*
@@ -270,10 +275,10 @@ repeat:
}
if (!tmp) {
if ((!blockoff && SWAB32(*p)) ||
- (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+ (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
goto repeat;
- else
- return NULL;
+ *err = -ENOSPC;
+ return NULL;
}
/* The nullification of framgents done in ufs/balloc.c is
@@ -283,10 +288,10 @@ repeat:
if (metadata) {
result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
} else {
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
*err = 0;
- *created = 1;
+ *new = 1;
}
inode->i_ctime = CURRENT_TIME;
@@ -297,16 +302,16 @@ repeat:
return result;
}
-static struct buffer_head * ufs_block_getfrag (struct inode * inode,
- struct buffer_head * bh, unsigned fragment, unsigned new_fragment,
- int create, unsigned blocksize, int * err, int metadata, int *phys_block, int *created)
+static struct buffer_head * ufs_block_getfrag (struct inode *inode,
+ struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment,
+ unsigned int blocksize, int * err, int metadata, long *phys, int *new)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct buffer_head * result;
unsigned tmp, goal, block, blockoff;
u32 * p;
- unsigned swab;
+ unsigned int swab;
sb = inode->i_sb;
swab = sb->u.ufs_sb.s_swab;
@@ -316,15 +321,14 @@ static struct buffer_head * ufs_block_getfrag (struct inode * inode,
UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
- if (!buffer_uptodate(bh)) {
- brelse (bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
p = (u32 *) bh->b_data + block;
@@ -334,24 +338,18 @@ repeat:
if (metadata) {
result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff,
sb->s_blocksize);
- if (tmp == SWAB32(*p)) {
- brelse (bh);
- UFSD(("EXIT, result %u\n", tmp + blockoff))
- return result;
- }
+ if (tmp == SWAB32(*p))
+ goto out;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse (bh);
- return NULL;
+ *phys = tmp;
+ goto out;
}
}
*err = -EFBIG;
- if (!create) {
- brelse (bh);
- return NULL;
- } else {
+
+ {
unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= sb->s_blocksize_bits;
@@ -368,12 +366,9 @@ repeat:
goal = bh->b_blocknr + uspi->s_fpb;
tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
if (!tmp) {
- if (SWAB32(*p)) {
+ if (SWAB32(*p))
goto repeat;
- } else {
- brelse (bh);
- return NULL;
- }
+ goto out;
}
/* The nullification of framgents done in ufs/balloc.c is
@@ -383,10 +378,8 @@ repeat:
if (metadata) {
result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
} else {
- *phys_block = tmp;
- result = NULL;
- *err = 0;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
}
mark_buffer_dirty(bh, 1);
@@ -396,122 +389,137 @@ repeat:
}
inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
+out:
brelse (bh);
UFSD(("EXIT, result %u\n", tmp + blockoff))
return result;
}
-int ufs_getfrag_block (struct inode * inode, long fragment,
- int create, int * err, int *created)
+int ufs_getfrag_block (struct inode *inode, long fragment, struct buffer_head *bh_result, int create)
{
struct super_block * sb;
struct ufs_sb_private_info * uspi;
- struct buffer_head * bh, * tmp;
- unsigned f;
- unsigned swab;
- int phys_block;
+ struct buffer_head * bh;
+ unsigned int swab;
+ int ret, err, new;
+ unsigned long ptr, phys;
sb = inode->i_sb;
uspi = sb->u.ufs_sb.s_uspi;
swab = sb->u.ufs_sb.s_swab;
- *err = -EIO;
- UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
- if (fragment < 0) {
- ufs_warning (sb, "ufs_getblk", "block < 0");
- return 0;
- }
- if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
- ufs_warning (sb, "ufs_getblk", "block > big");
+ if (!create) {
+ phys = ufs_frag_map(inode, fragment);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
return 0;
}
- *err = -ENOSPC;
- f = fragment;
- *created = 0;
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+
+ UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+ if (fragment < 0)
+ goto abort_negative;
+ if (fragment >
+ ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
+ << uspi->s_fpbshift))
+ goto abort_too_big;
+
+ err = 0;
+ ptr = fragment;
/*
- * Direct fragment
- */
- if (fragment < UFS_NDIR_FRAGMENT) {
- tmp = ufs_inode_getfrag (inode, fragment, fragment, create, 1,
- err, 0, &phys_block, created);
- goto out;
- }
- /*
- * Indirect fragment
- */
- fragment -= UFS_NDIR_FRAGMENT;
- if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
- bh = ufs_inode_getfrag (inode,
- UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift),
- f, create, uspi->s_fpb, err, 1, NULL, NULL);
- tmp = ufs_block_getfrag (inode, bh,
- fragment & uspi->s_apbmask,
- f, create, sb->s_blocksize,
- err, 0, &phys_block, created);
- goto out;
- }
- /*
- * Dindirect fragment
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
*/
- fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
- if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
- bh = ufs_inode_getfrag (inode,
- UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift),
- f, create, uspi->s_fpb, err,
- 1, NULL, NULL);
- bh = ufs_block_getfrag (inode, bh,
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask,
- f, create, sb->s_blocksize, err,
- 1, NULL, NULL);
- tmp = ufs_block_getfrag (inode, bh,
- fragment & uspi->s_apbmask,
- f, create, sb->s_blocksize, err,
- 0, &phys_block, created);
+#define GET_INODE_DATABLOCK(x) \
+ ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+ &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+ ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+ &err, 1, NULL, NULL);
+
+ if (ptr < UFS_NDIR_FRAGMENT) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- /*
- * Tindirect fragment
- */
- fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
- bh = ufs_inode_getfrag (inode,
- UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift),
- f, create, uspi->s_fpb, err, 1, NULL, NULL);
- bh = ufs_block_getfrag (inode, bh,
- (fragment >> uspi->s_2apbshift) & uspi->s_apbmask,
- f, create, sb->s_blocksize, err, 1, NULL, NULL);
- bh = ufs_block_getfrag (inode, bh,
- (fragment >> uspi->s_apbshift) & uspi->s_apbmask,
- f, create, sb->s_blocksize, err, 1, NULL, NULL);
- tmp = ufs_block_getfrag (inode, bh,
- fragment & uspi->s_apbmask,
- f, create, sb->s_blocksize, err, 0, &phys_block, created);
+ ptr -= UFS_NDIR_FRAGMENT;
+ if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+ bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift));
+ goto get_indirect;
+ }
+ ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+ if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+ bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift));
+ goto get_double;
+ }
+ ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+ bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift));
+ bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask);
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask);
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- if (!phys_block)
- return 0;
- if (*err)
- return 0;
- return phys_block;
+ if (err)
+ goto abort;
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
+abort:
+ unlock_kernel();
+ return err;
+
+abort_negative:
+ ufs_warning(sb, "ufs_get_block", "block < 0");
+ goto abort;
+
+abort_too_big:
+ ufs_warning(sb, "ufs_get_block", "block > big");
+ goto abort;
}
struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
int create, int *err)
{
- struct buffer_head *tmp = NULL;
- int phys_block, created;
-
- phys_block = ufs_getfrag_block(inode, fragment, create, err, &created);
- if (phys_block) {
- tmp = getblk(inode->i_dev, phys_block, inode->i_sb->s_blocksize);
- if (created) {
- memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ struct buffer_head dummy;
+ int error;
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = ufs_getfrag_block(inode, fragment, &dummy, create);
+ *err = error;
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index db3f11f23..12937adcf 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -271,6 +271,8 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
ufs_set_opt (*mount_options, UFSTYPE_44BSD);
else if (!strcmp (value, "nextstep"))
ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
+ else if (!strcmp (value, "nextstep-cd"))
+ ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
else if (!strcmp (value, "openstep"))
ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
else if (!strcmp (value, "sunx86"))
@@ -465,7 +467,7 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
}
if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
printk("You didn't specify the type of your ufs filesystem\n\n"
- " mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|openstep ....\n\n"
+ " mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
"default is ufstype=old\n");
ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
@@ -535,6 +537,20 @@ struct super_block * ufs_read_super (struct super_block * sb, void * data,
}
break;
+ case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
+ UFSD(("ufstype=nextstep-cd\n"))
+ uspi->s_fsize = block_size = 2048;
+ uspi->s_fmask = ~(2048 - 1);
+ uspi->s_fshift = 11;
+ uspi->s_sbsize = super_block_size = 2048;
+ uspi->s_sbbase = 0;
+ flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
+ if (!(sb->s_flags & MS_RDONLY)) {
+ printk(KERN_INFO "ufstype=nextstep-cd is supported read-only\n");
+ sb->s_flags |= MS_RDONLY;
+ }
+ break;
+
case UFS_MOUNT_UFSTYPE_OPENSTEP:
UFSD(("ufstype=openstep\n"))
uspi->s_fsize = block_size = 1024;
@@ -592,6 +608,7 @@ again:
#endif
if ((((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP)
+ || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD)
|| ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP))
&& uspi->s_sbbase < 256) {
ubh_brelse_uspi(uspi);
@@ -616,8 +633,8 @@ magic_found:
printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize);
goto failed;
}
- if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) {
- printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize);
+ if (uspi->s_fsize != 512 && uspi->s_fsize != 1024 && uspi->s_fsize != 2048) {
+ printk("ufs_read_super: fs_fsize %u != {512, 1024, 2048}\n", uspi->s_fsize);
goto failed;
}
if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
index 39b54e05d..3df5c40a6 100644
--- a/fs/ufs/symlink.c
+++ b/fs/ufs/symlink.c
@@ -129,10 +129,12 @@ struct inode_operations ufs_symlink_inode_operations = {
NULL, /* rename */
ufs_readlink, /* readlink */
ufs_follow_link, /* follow_link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
- NULL /* smap */
+ NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 4649a4253..b7214fc49 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -63,7 +63,7 @@
#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
#define DATA_BUFFER_USED(bh) \
- ((bh->b_count > 1) || buffer_locked(bh))
+ (atomic_read(&bh->b_count) || buffer_locked(bh))
static int ufs_trunc_direct (struct inode * inode)
{
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 11978a752..e6d5f3a5b 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -137,8 +137,8 @@ unsigned ubh_max_bcount (struct ufs_buffer_head * ubh)
if (!ubh)
return 0;
for ( i = 0; i < ubh->count; i++ )
- if ( ubh->bh[i]->b_count > max )
- max = ubh->bh[i]->b_count;
+ if ( atomic_read(&ubh->bh[i]->b_count) > max )
+ max = atomic_read(&ubh->bh[i]->b_count);
return max;
}
diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c
index 0f26103c4..34fe302d7 100644
--- a/fs/umsdos/dir.c
+++ b/fs/umsdos/dir.c
@@ -832,9 +832,10 @@ struct inode_operations umsdos_dir_inode_operations =
UMSDOS_rename, /* rename */
NULL, /* readlink */
NULL, /* followlink */
- generic_readpage, /* readpage */
+ fat_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- fat_bmap, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/umsdos/file.c b/fs/umsdos/file.c
index 339d82801..d3d8a74e6 100644
--- a/fs/umsdos/file.c
+++ b/fs/umsdos/file.c
@@ -99,12 +99,14 @@ struct inode_operations umsdos_file_inode_operations =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- generic_readpage, /* readpage */
+ fat_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- fat_bmap, /* bmap */
+ NULL, /* flushpage */
UMSDOS_truncate, /* truncate */
NULL, /* permission */
- fat_smap /* smap */
+ fat_smap, /* smap */
+ NULL /* revalidate */
};
/* For other with larger and unaligned file system */
@@ -137,12 +139,14 @@ struct inode_operations umsdos_file_inode_operations_no_bmap =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow link */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
UMSDOS_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
+ NULL /* revalidate */
};
/* For other with larger and unaligned file system with readpage */
@@ -175,10 +179,12 @@ struct inode_operations umsdos_file_inode_operations_readpage =
NULL, /* rename */
NULL, /* readlink */
NULL, /* follow link */
+ NULL, /* get_block */
fat_readpage, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
UMSDOS_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
+ NULL /* revalidate */
};
diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
index 7951bb8f8..c7bb8fb1b 100644
--- a/fs/umsdos/rdir.c
+++ b/fs/umsdos/rdir.c
@@ -249,7 +249,7 @@ struct inode_operations umsdos_rdir_inode_operations =
NULL, /* followlink */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* get_block */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c
index 97ea2da41..2d08a35d8 100644
--- a/fs/umsdos/symlink.c
+++ b/fs/umsdos/symlink.c
@@ -135,9 +135,10 @@ struct inode_operations umsdos_symlink_inode_operations =
NULL, /* rename */
UMSDOS_readlink, /* readlink */
UMSDOS_followlink, /* followlink */
- generic_readpage, /* readpage */
+ fat_bmap, /* get_block */
+ block_read_full_page, /* readpage */
NULL, /* writepage */
- fat_bmap, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
NULL, /* permission */
NULL, /* smap */
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index d372ead15..ad241c3cd 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -1232,11 +1232,14 @@ struct inode_operations vfat_dir_inode_operations = {
vfat_rename, /* rename */
NULL, /* readlink */
NULL, /* followlink */
+ NULL, /* get_block */
NULL, /* readpage */
NULL, /* writepage */
- NULL, /* bmap */
+ NULL, /* flushpage */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL /* revalidate */
};
struct super_block *vfat_read_super(struct super_block *sb,void *data,