--- /dev/null
+ fs/ext3/Makefile | 18
+ fs/ext3/super.c | 1779 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/fs.h | 1680 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/ksyms.c | 632 ++++++++++++++++++
+ 4 files changed, 4109 insertions(+)
+
+--- /dev/null Fri Aug 30 17:31:37 2002
++++ linux-rh-2.4.20-6-braam/fs/ext3/Makefile Mon Mar 31 23:43:54 2003
+@@ -0,0 +1,18 @@
++#
++# Makefile for the linux ext2-filesystem routines.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definitions are now in the main makefile...
++
++O_TARGET := ext3.o
++
++export-objs := super.o
++
++obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
++ ioctl.o namei.o super.o symlink.o
++obj-m := $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- /dev/null Fri Aug 30 17:31:37 2002
++++ linux-rh-2.4.20-6-braam/fs/ext3/super.c Mon Mar 31 23:43:54 2003
+@@ -0,0 +1,1779 @@
++/*
++ * linux/fs/ext3/super.c
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card@masi.ibp.fr)
++ * Laboratoire MASI - Institut Blaise Pascal
++ * Universite Pierre et Marie Curie (Paris VI)
++ *
++ * from
++ *
++ * linux/fs/minix/inode.c
++ *
++ * Copyright (C) 1991, 1992 Linus Torvalds
++ *
++ * Big-endian to little-endian byte-swapping/bitmaps by
++ * David S. Miller (davem@caip.rutgers.edu), 1995
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/jbd.h>
++#include <linux/ext3_fs.h>
++#include <linux/ext3_jbd.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/locks.h>
++#include <linux/blkdev.h>
++#include <linux/smp_lock.h>
++#include <linux/random.h>
++#include <asm/uaccess.h>
++
++#ifdef CONFIG_JBD_DEBUG
++static int ext3_ro_after; /* Make fs read-only after this many jiffies */
++#endif
++
++static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
++static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
++ int);
++static void ext3_commit_super (struct super_block * sb,
++ struct ext3_super_block * es,
++ int sync);
++static void ext3_mark_recovery_complete(struct super_block * sb,
++ struct ext3_super_block * es);
++static void ext3_clear_journal_err(struct super_block * sb,
++ struct ext3_super_block * es);
++
++static int ext3_sync_fs(struct super_block * sb);
++
++#ifdef CONFIG_JBD_DEBUG
++int journal_no_write[2];
++
++/*
++ * Debug code for turning filesystems "read-only" after a specified
++ * amount of time. This is for crash/recovery testing.
++ */
++
++static void make_rdonly(kdev_t dev, int *no_write)
++{
++ if (dev) {
++ printk(KERN_WARNING "Turning device %s read-only\n",
++ bdevname(dev));
++ *no_write = 0xdead0000 + dev;
++ }
++}
++
++static void turn_fs_readonly(unsigned long arg)
++{
++ struct super_block *sb = (struct super_block *)arg;
++
++ make_rdonly(sb->s_dev, &journal_no_write[0]);
++ make_rdonly(EXT3_SB(sb)->s_journal->j_dev, &journal_no_write[1]);
++ wake_up(&EXT3_SB(sb)->ro_wait_queue);
++}
++
++static void setup_ro_after(struct super_block *sb)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ init_timer(&sbi->turn_ro_timer);
++ if (ext3_ro_after) {
++ printk(KERN_DEBUG "fs will go read-only in %d jiffies\n",
++ ext3_ro_after);
++ init_waitqueue_head(&sbi->ro_wait_queue);
++ journal_no_write[0] = 0;
++ journal_no_write[1] = 0;
++ sbi->turn_ro_timer.function = turn_fs_readonly;
++ sbi->turn_ro_timer.data = (unsigned long)sb;
++ sbi->turn_ro_timer.expires = jiffies + ext3_ro_after;
++ ext3_ro_after = 0;
++ add_timer(&sbi->turn_ro_timer);
++ }
++}
++
++static void clear_ro_after(struct super_block *sb)
++{
++ del_timer_sync(&EXT3_SB(sb)->turn_ro_timer);
++ journal_no_write[0] = 0;
++ journal_no_write[1] = 0;
++ ext3_ro_after = 0;
++}
++#else
++#define setup_ro_after(sb) do {} while (0)
++#define clear_ro_after(sb) do {} while (0)
++#endif
++
++
++static char error_buf[1024];
++
++/* Determine the appropriate response to ext3_error on a given filesystem */
++
++static int ext3_error_behaviour(struct super_block *sb)
++{
++ /* First check for mount-time options */
++ if (test_opt (sb, ERRORS_PANIC))
++ return EXT3_ERRORS_PANIC;
++ if (test_opt (sb, ERRORS_RO))
++ return EXT3_ERRORS_RO;
++ if (test_opt (sb, ERRORS_CONT))
++ return EXT3_ERRORS_CONTINUE;
++
++ /* If no overrides were specified on the mount, then fall back
++ * to the default behaviour set in the filesystem's superblock
++ * on disk. */
++ switch (le16_to_cpu(sb->u.ext3_sb.s_es->s_errors)) {
++ case EXT3_ERRORS_PANIC:
++ return EXT3_ERRORS_PANIC;
++ case EXT3_ERRORS_RO:
++ return EXT3_ERRORS_RO;
++ default:
++ break;
++ }
++ return EXT3_ERRORS_CONTINUE;
++}
++
++/* Deal with the reporting of failure conditions on a filesystem such as
++ * inconsistencies detected or read IO failures.
++ *
++ * On ext2, we can store the error state of the filesystem in the
++ * superblock. That is not possible on ext3, because we may have other
++ * write ordering constraints on the superblock which prevent us from
++ * writing it out straight away; and given that the journal is about to
++ * be aborted, we can't rely on the current, or future, transactions to
++ * write out the superblock safely.
++ *
++ * We'll just use the journal_abort() error code to record an error in
++ * the journal instead. On recovery, the journal will compain about
++ * that error until we've noted it down and cleared it.
++ */
++
++static void ext3_handle_error(struct super_block *sb)
++{
++ struct ext3_super_block *es = EXT3_SB(sb)->s_es;
++
++ EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
++ es->s_state |= cpu_to_le32(EXT3_ERROR_FS);
++
++ if (sb->s_flags & MS_RDONLY)
++ return;
++
++ if (ext3_error_behaviour(sb) != EXT3_ERRORS_CONTINUE) {
++ EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT;
++ journal_abort(EXT3_SB(sb)->s_journal, -EIO);
++ }
++
++ if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC)
++ panic ("EXT3-fs (device %s): panic forced after error\n",
++ bdevname(sb->s_dev));
++
++ if (ext3_error_behaviour(sb) == EXT3_ERRORS_RO) {
++ printk (KERN_CRIT "Remounting filesystem read-only\n");
++ sb->s_flags |= MS_RDONLY;
++ }
++
++ ext3_commit_super(sb, es, 1);
++}
++
++void ext3_error (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ va_start (args, fmt);
++ vsprintf (error_buf, fmt, args);
++ va_end (args);
++
++ printk (KERN_CRIT "EXT3-fs error (device %s): %s: %s\n",
++ bdevname(sb->s_dev), function, error_buf);
++
++ ext3_handle_error(sb);
++}
++
++const char *ext3_decode_error(struct super_block * sb, int errno, char nbuf[16])
++{
++ char *errstr = NULL;
++
++ switch (errno) {
++ case -EIO:
++ errstr = "IO failure";
++ break;
++ case -ENOMEM:
++ errstr = "Out of memory";
++ break;
++ case -EROFS:
++ if (!sb || EXT3_SB(sb)->s_journal->j_flags & JFS_ABORT)
++ errstr = "Journal has aborted";
++ else
++ errstr = "Readonly filesystem";
++ break;
++ default:
++ /* If the caller passed in an extra buffer for unknown
++ * errors, textualise them now. Else we just return
++ * NULL. */
++ if (nbuf) {
++ /* Check for truncated error codes... */
++ if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
++ errstr = nbuf;
++ }
++
++ break;
++ }
++
++ return errstr;
++}
++
++/* __ext3_std_error decodes expected errors from journaling functions
++ * automatically and invokes the appropriate error response. */
++
++void __ext3_std_error (struct super_block * sb, const char * function,
++ int errno)
++{
++ char nbuf[16];
++ const char *errstr = ext3_decode_error(sb, errno, nbuf);
++
++ printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n",
++ bdevname(sb->s_dev), function, errstr);
++
++ ext3_handle_error(sb);
++}
++
++/*
++ * ext3_abort is a much stronger failure handler than ext3_error. The
++ * abort function may be used to deal with unrecoverable failures such
++ * as journal IO errors or ENOMEM at a critical moment in log management.
++ *
++ * We unconditionally force the filesystem into an ABORT|READONLY state,
++ * unless the error response on the fs has been set to panic in which
++ * case we take the easy way out and panic immediately.
++ */
++
++void ext3_abort (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ printk (KERN_CRIT "ext3_abort called.\n");
++
++ va_start (args, fmt);
++ vsprintf (error_buf, fmt, args);
++ va_end (args);
++
++ if (ext3_error_behaviour(sb) == EXT3_ERRORS_PANIC)
++ panic ("EXT3-fs panic (device %s): %s: %s\n",
++ bdevname(sb->s_dev), function, error_buf);
++
++ printk (KERN_CRIT "EXT3-fs abort (device %s): %s: %s\n",
++ bdevname(sb->s_dev), function, error_buf);
++
++ if (sb->s_flags & MS_RDONLY)
++ return;
++
++ printk (KERN_CRIT "Remounting filesystem read-only\n");
++ sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS;
++ sb->s_flags |= MS_RDONLY;
++ sb->u.ext3_sb.s_mount_opt |= EXT3_MOUNT_ABORT;
++ journal_abort(EXT3_SB(sb)->s_journal, -EIO);
++}
++
++/* Deal with the reporting of failure conditions while running, such as
++ * inconsistencies in operation or invalid system states.
++ *
++ * Use ext3_error() for cases of invalid filesystem states, as that will
++ * record an error on disk and force a filesystem check on the next boot.
++ */
++NORET_TYPE void ext3_panic (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ va_start (args, fmt);
++ vsprintf (error_buf, fmt, args);
++ va_end (args);
++
++ /* this is to prevent panic from syncing this filesystem */
++ /* AKPM: is this sufficient? */
++ sb->s_flags |= MS_RDONLY;
++ panic ("EXT3-fs panic (device %s): %s: %s\n",
++ bdevname(sb->s_dev), function, error_buf);
++}
++
++void ext3_warning (struct super_block * sb, const char * function,
++ const char * fmt, ...)
++{
++ va_list args;
++
++ va_start (args, fmt);
++ vsprintf (error_buf, fmt, args);
++ va_end (args);
++ printk (KERN_WARNING "EXT3-fs warning (device %s): %s: %s\n",
++ bdevname(sb->s_dev), function, error_buf);
++}
++
++void ext3_update_dynamic_rev(struct super_block *sb)
++{
++ struct ext3_super_block *es = EXT3_SB(sb)->s_es;
++
++ if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV)
++ return;
++
++ ext3_warning(sb, __FUNCTION__,
++ "updating to rev %d because of new feature flag, "
++ "running e2fsck is recommended",
++ EXT3_DYNAMIC_REV);
++
++ es->s_first_ino = cpu_to_le32(EXT3_GOOD_OLD_FIRST_INO);
++ es->s_inode_size = cpu_to_le16(EXT3_GOOD_OLD_INODE_SIZE);
++ es->s_rev_level = cpu_to_le32(EXT3_DYNAMIC_REV);
++ /* leave es->s_feature_*compat flags alone */
++ /* es->s_uuid will be set by e2fsck if empty */
++
++ /*
++ * The rest of the superblock fields should be zero, and if not it
++ * means they are likely already in use, so leave them alone. We
++ * can leave it up to e2fsck to clean up any inconsistencies there.
++ */
++}
++
++/*
++ * Open the external journal device
++ */
++static struct block_device *ext3_blkdev_get(kdev_t dev)
++{
++ struct block_device *bdev;
++ int err = -ENODEV;
++
++ bdev = bdget(kdev_t_to_nr(dev));
++ if (bdev == NULL)
++ goto fail;
++ err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
++ if (err < 0)
++ goto fail;
++ return bdev;
++
++fail:
++ printk(KERN_ERR "EXT3: failed to open journal device %s: %d\n",
++ bdevname(dev), err);
++ return NULL;
++}
++
++/*
++ * Release the journal device
++ */
++static int ext3_blkdev_put(struct block_device *bdev)
++{
++ return blkdev_put(bdev, BDEV_FS);
++}
++
++static int ext3_blkdev_remove(struct ext3_sb_info *sbi)
++{
++ struct block_device *bdev;
++ int ret = -ENODEV;
++
++ bdev = sbi->journal_bdev;
++ if (bdev) {
++ ret = ext3_blkdev_put(bdev);
++ sbi->journal_bdev = 0;
++ }
++ return ret;
++}
++
++#define orphan_list_entry(l) list_entry((l), struct inode, u.ext3_i.i_orphan)
++
++static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi)
++{
++ struct list_head *l;
++
++ printk(KERN_ERR "sb orphan head is %d\n",
++ le32_to_cpu(sbi->s_es->s_last_orphan));
++
++ printk(KERN_ERR "sb_info orphan list:\n");
++ list_for_each(l, &sbi->s_orphan) {
++ struct inode *inode = orphan_list_entry(l);
++ printk(KERN_ERR " "
++ "inode 0x%04x:%ld at %p: mode %o, nlink %d, next %d\n",
++ inode->i_dev, inode->i_ino, inode,
++ inode->i_mode, inode->i_nlink,
++ le32_to_cpu(NEXT_ORPHAN(inode)));
++ }
++}
++
++void ext3_put_super (struct super_block * sb)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ struct ext3_super_block *es = sbi->s_es;
++ kdev_t j_dev = sbi->s_journal->j_dev;
++ int i;
++
++ journal_destroy(sbi->s_journal);
++ if (!(sb->s_flags & MS_RDONLY)) {
++ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++ es->s_state = le16_to_cpu(sbi->s_mount_state);
++ BUFFER_TRACE(sbi->s_sbh, "marking dirty");
++ mark_buffer_dirty(sbi->s_sbh);
++ ext3_commit_super(sb, es, 1);
++ }
++
++ for (i = 0; i < sbi->s_gdb_count; i++)
++ brelse(sbi->s_group_desc[i]);
++ kfree(sbi->s_group_desc);
++ for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++)
++ brelse(sbi->s_inode_bitmap[i]);
++ for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++)
++ brelse(sbi->s_block_bitmap[i]);
++ brelse(sbi->s_sbh);
++
++ /* Debugging code just in case the in-memory inode orphan list
++ * isn't empty. The on-disk one can be non-empty if we've
++ * detected an error and taken the fs readonly, but the
++ * in-memory list had better be clean by this point. */
++ if (!list_empty(&sbi->s_orphan))
++ dump_orphan_list(sb, sbi);
++ J_ASSERT(list_empty(&sbi->s_orphan));
++
++ invalidate_buffers(sb->s_dev);
++ if (j_dev != sb->s_dev) {
++ /*
++ * Invalidate the journal device's buffers. We don't want them
++ * floating about in memory - the physical journal device may
++ * hotswapped, and it breaks the `ro-after' testing code.
++ */
++ fsync_no_super(j_dev);
++ invalidate_buffers(j_dev);
++ ext3_blkdev_remove(sbi);
++ }
++ clear_ro_after(sb);
++
++ return;
++}
++
++static struct super_operations ext3_sops = {
++ read_inode: ext3_read_inode, /* BKL held */
++ write_inode: ext3_write_inode, /* BKL not held. Don't need */
++ dirty_inode: ext3_dirty_inode, /* BKL not held. We take it */
++ put_inode: ext3_put_inode, /* BKL not held. Don't need */
++ delete_inode: ext3_delete_inode, /* BKL not held. We take it */
++ put_super: ext3_put_super, /* BKL held */
++ write_super: ext3_write_super, /* BKL held */
++ sync_fs: ext3_sync_fs,
++ write_super_lockfs: ext3_write_super_lockfs, /* BKL not held. Take it */
++ unlockfs: ext3_unlockfs, /* BKL not held. We take it */
++ statfs: ext3_statfs, /* BKL held */
++ remount_fs: ext3_remount, /* BKL held */
++};
++
++static int want_value(char *value, char *option)
++{
++ if (!value || !*value) {
++ printk(KERN_NOTICE "EXT3-fs: the %s option needs an argument\n",
++ option);
++ return -1;
++ }
++ return 0;
++}
++
++static int want_null_value(char *value, char *option)
++{
++ if (*value) {
++ printk(KERN_NOTICE "EXT3-fs: Invalid %s argument: %s\n",
++ option, value);
++ return -1;
++ }
++ return 0;
++}
++
++static int want_numeric(char *value, char *option, unsigned long *number)
++{
++ if (want_value(value, option))
++ return -1;
++ *number = simple_strtoul(value, &value, 0);
++ if (want_null_value(value, option))
++ return -1;
++ return 0;
++}
++
++/*
++ * This function has been shamelessly adapted from the msdos fs
++ */
++static int parse_options (char * options, unsigned long * sb_block,
++ struct ext3_sb_info *sbi,
++ unsigned long * inum,
++ int is_remount)
++{
++ unsigned long *mount_options = &sbi->s_mount_opt;
++ uid_t *resuid = &sbi->s_resuid;
++ gid_t *resgid = &sbi->s_resgid;
++ char * this_char;
++ char * value;
++
++ if (!options)
++ return 1;
++ for (this_char = strtok (options, ",");
++ this_char != NULL;
++ this_char = strtok (NULL, ",")) {
++ if ((value = strchr (this_char, '=')) != NULL)
++ *value++ = 0;
++ if (!strcmp (this_char, "bsddf"))
++ clear_opt (*mount_options, MINIX_DF);
++ else if (!strcmp (this_char, "nouid32")) {
++ set_opt (*mount_options, NO_UID32);
++ }
++ else if (!strcmp (this_char, "abort"))
++ set_opt (*mount_options, ABORT);
++ else if (!strcmp (this_char, "check")) {
++ if (!value || !*value || !strcmp (value, "none"))
++ clear_opt (*mount_options, CHECK);
++ else
++#ifdef CONFIG_EXT3_CHECK
++ set_opt (*mount_options, CHECK);
++#else
++ printk(KERN_ERR
++ "EXT3 Check option not supported\n");
++#endif
++ }
++ else if (!strcmp (this_char, "debug"))
++ set_opt (*mount_options, DEBUG);
++ else if (!strcmp (this_char, "errors")) {
++ if (want_value(value, "errors"))
++ return 0;
++ if (!strcmp (value, "continue")) {
++ clear_opt (*mount_options, ERRORS_RO);
++ clear_opt (*mount_options, ERRORS_PANIC);
++ set_opt (*mount_options, ERRORS_CONT);
++ }
++ else if (!strcmp (value, "remount-ro")) {
++ clear_opt (*mount_options, ERRORS_CONT);
++ clear_opt (*mount_options, ERRORS_PANIC);
++ set_opt (*mount_options, ERRORS_RO);
++ }
++ else if (!strcmp (value, "panic")) {
++ clear_opt (*mount_options, ERRORS_CONT);
++ clear_opt (*mount_options, ERRORS_RO);
++ set_opt (*mount_options, ERRORS_PANIC);
++ }
++ else {
++ printk (KERN_ERR
++ "EXT3-fs: Invalid errors option: %s\n",
++ value);
++ return 0;
++ }
++ }
++ else if (!strcmp (this_char, "grpid") ||
++ !strcmp (this_char, "bsdgroups"))
++ set_opt (*mount_options, GRPID);
++ else if (!strcmp (this_char, "minixdf"))
++ set_opt (*mount_options, MINIX_DF);
++ else if (!strcmp (this_char, "nocheck"))
++ clear_opt (*mount_options, CHECK);
++ else if (!strcmp (this_char, "nogrpid") ||
++ !strcmp (this_char, "sysvgroups"))
++ clear_opt (*mount_options, GRPID);
++ else if (!strcmp (this_char, "resgid")) {
++ unsigned long v;
++ if (want_numeric(value, "resgid", &v))
++ return 0;
++ *resgid = v;
++ }
++ else if (!strcmp (this_char, "resuid")) {
++ unsigned long v;
++ if (want_numeric(value, "resuid", &v))
++ return 0;
++ *resuid = v;
++ }
++ else if (!strcmp (this_char, "sb")) {
++ if (want_numeric(value, "sb", sb_block))
++ return 0;
++ }
++#ifdef CONFIG_JBD_DEBUG
++ else if (!strcmp (this_char, "ro-after")) {
++ unsigned long v;
++ if (want_numeric(value, "ro-after", &v))
++ return 0;
++ ext3_ro_after = v;
++ }
++#endif
++ /* Silently ignore the quota options */
++ else if (!strcmp (this_char, "grpquota")
++ || !strcmp (this_char, "noquota")
++ || !strcmp (this_char, "quota")
++ || !strcmp (this_char, "usrquota"))
++ /* Don't do anything ;-) */ ;
++ else if (!strcmp (this_char, "journal")) {
++ /* @@@ FIXME */
++ /* Eventually we will want to be able to create
++ a journal file here. For now, only allow the
++ user to specify an existing inode to be the
++ journal file. */
++ if (is_remount) {
++ printk(KERN_ERR "EXT3-fs: cannot specify "
++ "journal on remount\n");
++ return 0;
++ }
++
++ if (want_value(value, "journal"))
++ return 0;
++ if (!strcmp (value, "update"))
++ set_opt (*mount_options, UPDATE_JOURNAL);
++ else if (want_numeric(value, "journal", inum))
++ return 0;
++ }
++ else if (!strcmp (this_char, "noload"))
++ set_opt (*mount_options, NOLOAD);
++ else if (!strcmp (this_char, "data")) {
++ int data_opt = 0;
++
++ if (want_value(value, "data"))
++ return 0;
++ if (!strcmp (value, "journal"))
++ data_opt = EXT3_MOUNT_JOURNAL_DATA;
++ else if (!strcmp (value, "ordered"))
++ data_opt = EXT3_MOUNT_ORDERED_DATA;
++ else if (!strcmp (value, "writeback"))
++ data_opt = EXT3_MOUNT_WRITEBACK_DATA;
++ else {
++ printk (KERN_ERR
++ "EXT3-fs: Invalid data option: %s\n",
++ value);
++ return 0;
++ }
++ if (is_remount) {
++ if ((*mount_options & EXT3_MOUNT_DATA_FLAGS) !=
++ data_opt) {
++ printk(KERN_ERR
++ "EXT3-fs: cannot change data "
++ "mode on remount\n");
++ return 0;
++ }
++ } else {
++ *mount_options &= ~EXT3_MOUNT_DATA_FLAGS;
++ *mount_options |= data_opt;
++ }
++ } else if (!strcmp (this_char, "commit")) {
++ unsigned long v;
++ if (want_numeric(value, "commit", &v))
++ return 0;
++ sbi->s_commit_interval = (HZ * v);
++ } else {
++ printk (KERN_ERR
++ "EXT3-fs: Unrecognized mount option %s\n",
++ this_char);
++ return 0;
++ }
++ }
++ return 1;
++}
++
++static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
++ int read_only)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ int res = 0;
++
++ if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) {
++ printk (KERN_ERR "EXT3-fs warning: revision level too high, "
++ "forcing read-only mode\n");
++ res = MS_RDONLY;
++ }
++ if (read_only)
++ return res;
++ if (!(sbi->s_mount_state & EXT3_VALID_FS))
++ printk (KERN_WARNING "EXT3-fs warning: mounting unchecked fs, "
++ "running e2fsck is recommended\n");
++ else if ((sbi->s_mount_state & EXT3_ERROR_FS))
++ printk (KERN_WARNING
++ "EXT3-fs warning: mounting fs with errors, "
++ "running e2fsck is recommended\n");
++ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
++ le16_to_cpu(es->s_mnt_count) >=
++ (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
++ printk (KERN_WARNING
++ "EXT3-fs warning: maximal mount count reached, "
++ "running e2fsck is recommended\n");
++ else if (le32_to_cpu(es->s_checkinterval) &&
++ (le32_to_cpu(es->s_lastcheck) +
++ le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
++ printk (KERN_WARNING
++ "EXT3-fs warning: checktime reached, "
++ "running e2fsck is recommended\n");
++#if 0
++ /* @@@ We _will_ want to clear the valid bit if we find
++ inconsistencies, to force a fsck at reboot. But for
++ a plain journaled filesystem we can keep it set as
++ valid forever! :) */
++ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS);
++#endif
++ if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
++ es->s_max_mnt_count =
++ (__s16) cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT);
++ es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
++ es->s_mtime = cpu_to_le32(CURRENT_TIME);
++ ext3_update_dynamic_rev(sb);
++ EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++ ext3_commit_super (sb, es, 1);
++ if (test_opt (sb, DEBUG))
++ printk (KERN_INFO
++ "[EXT3 FS %s, %s, bs=%lu, gc=%lu, "
++ "bpg=%lu, ipg=%lu, mo=%04lx]\n",
++ EXT3FS_VERSION, EXT3FS_DATE, sb->s_blocksize,
++ sbi->s_groups_count,
++ EXT3_BLOCKS_PER_GROUP(sb),
++ EXT3_INODES_PER_GROUP(sb),
++ sbi->s_mount_opt);
++ printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ",
++ bdevname(sb->s_dev));
++ if (EXT3_SB(sb)->s_journal->j_inode == NULL) {
++ printk("external journal on %s\n",
++ bdevname(EXT3_SB(sb)->s_journal->j_dev));
++ } else {
++ printk("internal journal\n");
++ }
++#ifdef CONFIG_EXT3_CHECK
++ if (test_opt (sb, CHECK)) {
++ ext3_check_blocks_bitmap (sb);
++ ext3_check_inodes_bitmap (sb);
++ }
++#endif
++ setup_ro_after(sb);
++ return res;
++}
++
++static int ext3_check_descriptors (struct super_block * sb)
++{
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
++ struct ext3_group_desc * gdp = NULL;
++ int desc_block = 0;
++ int i;
++
++ ext3_debug ("Checking group descriptors");
++
++ for (i = 0; i < sbi->s_groups_count; i++)
++ {
++ if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
++ gdp = (struct ext3_group_desc *)
++ sbi->s_group_desc[desc_block++]->b_data;
++ if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
++ le32_to_cpu(gdp->bg_block_bitmap) >=
++ block + EXT3_BLOCKS_PER_GROUP(sb))
++ {
++ ext3_error (sb, "ext3_check_descriptors",
++ "Block bitmap for group %d"
++ " not in group (block %lu)!",
++ i, (unsigned long)
++ le32_to_cpu(gdp->bg_block_bitmap));
++ return 0;
++ }
++ if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
++ le32_to_cpu(gdp->bg_inode_bitmap) >=
++ block + EXT3_BLOCKS_PER_GROUP(sb))
++ {
++ ext3_error (sb, "ext3_check_descriptors",
++ "Inode bitmap for group %d"
++ " not in group (block %lu)!",
++ i, (unsigned long)
++ le32_to_cpu(gdp->bg_inode_bitmap));
++ return 0;
++ }
++ if (le32_to_cpu(gdp->bg_inode_table) < block ||
++ le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >=
++ block + EXT3_BLOCKS_PER_GROUP(sb))
++ {
++ ext3_error (sb, "ext3_check_descriptors",
++ "Inode table for group %d"
++ " not in group (block %lu)!",
++ i, (unsigned long)
++ le32_to_cpu(gdp->bg_inode_table));
++ return 0;
++ }
++ block += EXT3_BLOCKS_PER_GROUP(sb);
++ gdp++;
++ }
++ return 1;
++}
++
++
++/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at
++ * the superblock) which were deleted from all directories, but held open by
++ * a process at the time of a crash. We walk the list and try to delete these
++ * inodes at recovery time (only with a read-write filesystem).
++ *
++ * In order to keep the orphan inode chain consistent during traversal (in
++ * case of crash during recovery), we link each inode into the superblock
++ * orphan list_head and handle it the same way as an inode deletion during
++ * normal operation (which journals the operations for us).
++ *
++ * We only do an iget() and an iput() on each inode, which is very safe if we
++ * accidentally point at an in-use or already deleted inode. The worst that
++ * can happen in this case is that we get a "bit already cleared" message from
++ * ext3_free_inode(). The only reason we would point at a wrong inode is if
++ * e2fsck was run on this filesystem, and it must have already done the orphan
++ * inode cleanup for us, so we can safely abort without any further action.
++ */
++static void ext3_orphan_cleanup (struct super_block * sb,
++ struct ext3_super_block * es)
++{
++ unsigned int s_flags = sb->s_flags;
++ int nr_orphans = 0, nr_truncates = 0;
++ if (!es->s_last_orphan) {
++ jbd_debug(4, "no orphan inodes to clean up\n");
++ return;
++ }
++
++ if (s_flags & MS_RDONLY) {
++ printk(KERN_INFO "EXT3-fs: %s: orphan cleanup on readonly fs\n",
++ bdevname(sb->s_dev));
++ sb->s_flags &= ~MS_RDONLY;
++ }
++
++ if (sb->u.ext3_sb.s_mount_state & EXT3_ERROR_FS) {
++ if (es->s_last_orphan)
++ jbd_debug(1, "Errors on filesystem, "
++ "clearing orphan list.\n");
++ es->s_last_orphan = 0;
++ jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
++ return;
++ }
++
++ while (es->s_last_orphan) {
++ struct inode *inode;
++
++ if (!(inode =
++ ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
++ es->s_last_orphan = 0;
++ break;
++ }
++
++ list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
++ if (inode->i_nlink) {
++ printk(KERN_DEBUG "%s: truncating inode %ld to %Ld "
++ "bytes\n", __FUNCTION__, inode->i_ino,
++ inode->i_size);
++ jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
++ inode->i_ino, inode->i_size);
++ ext3_truncate(inode);
++ nr_truncates++;
++ } else {
++ printk(KERN_DEBUG "%s: deleting unreferenced "
++ "inode %ld\n", __FUNCTION__, inode->i_ino);
++ jbd_debug(2, "deleting unreferenced inode %ld\n",
++ inode->i_ino);
++ nr_orphans++;
++ }
++ iput(inode); /* The delete magic happens here! */
++ }
++
++#define PLURAL(x) (x), ((x)==1) ? "" : "s"
++
++ if (nr_orphans)
++ printk(KERN_INFO "EXT3-fs: %s: %d orphan inode%s deleted\n",
++ bdevname(sb->s_dev), PLURAL(nr_orphans));
++ if (nr_truncates)
++ printk(KERN_INFO "EXT3-fs: %s: %d truncate%s cleaned up\n",
++ bdevname(sb->s_dev), PLURAL(nr_truncates));
++ sb->s_flags = s_flags; /* Restore MS_RDONLY status */
++}
++
++#define log2(n) ffz(~(n))
++
++/*
++ * Maximal file size. There is a direct, and {,double-,triple-}indirect
++ * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
++ * We need to be 1 filesystem block less than the 2^32 sector limit.
++ */
++static loff_t ext3_max_size(int bits)
++{
++ loff_t res = EXT3_NDIR_BLOCKS;
++ res += 1LL << (bits-2);
++ res += 1LL << (2*(bits-2));
++ res += 1LL << (3*(bits-2));
++ res <<= bits;
++ if (res > (512LL << 32) - (1 << bits))
++ res = (512LL << 32) - (1 << bits);
++ return res;
++}
++
++struct super_block * ext3_read_super (struct super_block * sb, void * data,
++ int silent)
++{
++ struct buffer_head * bh;
++ struct ext3_super_block *es = 0;
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ unsigned long sb_block = 1;
++ unsigned long logic_sb_block = 1;
++ unsigned long offset = 0;
++ unsigned long journal_inum = 0;
++ kdev_t dev = sb->s_dev;
++ int blocksize;
++ int hblock;
++ int db_count;
++ int i;
++ int needs_recovery;
++
++#ifdef CONFIG_JBD_DEBUG
++ ext3_ro_after = 0;
++#endif
++ /*
++ * See what the current blocksize for the device is, and
++ * use that as the blocksize. Otherwise (or if the blocksize
++ * is smaller than the default) use the default.
++ * This is important for devices that have a hardware
++ * sectorsize that is larger than the default.
++ */
++ blocksize = EXT3_MIN_BLOCK_SIZE;
++ hblock = get_hardsect_size(dev);
++ if (blocksize < hblock)
++ blocksize = hblock;
++
++ sbi->s_mount_opt = 0;
++ sbi->s_resuid = EXT3_DEF_RESUID;
++ sbi->s_resgid = EXT3_DEF_RESGID;
++ if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) {
++ sb->s_dev = 0;
++ goto out_fail;
++ }
++
++ sb->s_blocksize = blocksize;
++ set_blocksize (dev, blocksize);
++
++ /*
++ * The ext3 superblock will not be buffer aligned for other than 1kB
++ * block sizes. We need to calculate the offset from buffer start.
++ */
++ if (blocksize != EXT3_MIN_BLOCK_SIZE) {
++ logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize;
++ offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
++ }
++
++ if (!(bh = sb_bread(sb, logic_sb_block))) {
++ printk (KERN_ERR "EXT3-fs: unable to read superblock\n");
++ goto out_fail;
++ }
++ /*
++ * Note: s_es must be initialized as soon as possible because
++ * some ext3 macro-instructions depend on its value
++ */
++ es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
++ sbi->s_es = es;
++ sb->s_magic = le16_to_cpu(es->s_magic);
++ if (sb->s_magic != EXT3_SUPER_MAGIC) {
++ if (!silent)
++ printk(KERN_ERR
++ "VFS: Can't find ext3 filesystem on dev %s.\n",
++ bdevname(dev));
++ goto failed_mount;
++ }
++ if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
++ (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
++ EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
++ EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U)))
++ printk(KERN_WARNING
++ "EXT3-fs warning: feature flags set on rev 0 fs, "
++ "running e2fsck is recommended\n");
++ /*
++ * Check feature flags regardless of the revision level, since we
++ * previously didn't change the revision level when setting the flags,
++ * so there is a chance incompat flags are set on a rev 0 filesystem.
++ */
++ if ((i = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))) {
++ printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
++ "unsupported optional features (%x).\n",
++ bdevname(dev), i);
++ goto failed_mount;
++ }
++ if (!(sb->s_flags & MS_RDONLY) &&
++ (i = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))){
++ printk(KERN_ERR "EXT3-fs: %s: couldn't mount RDWR because of "
++ "unsupported optional features (%x).\n",
++ bdevname(dev), i);
++ goto failed_mount;
++ }
++ sb->s_blocksize_bits = le32_to_cpu(es->s_log_block_size) + 10;
++ sb->s_blocksize = 1 << sb->s_blocksize_bits;
++
++ if (sb->s_blocksize < EXT3_MIN_BLOCK_SIZE ||
++ sb->s_blocksize > EXT3_MAX_BLOCK_SIZE) {
++ printk(KERN_ERR
++ "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n",
++ blocksize, bdevname(dev));
++ goto failed_mount;
++ }
++
++ sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits);
++
++ if (sb->s_blocksize != blocksize) {
++ blocksize = sb->s_blocksize;
++
++ /*
++ * Make sure the blocksize for the filesystem is larger
++ * than the hardware sectorsize for the machine.
++ */
++ if (sb->s_blocksize < hblock) {
++ printk(KERN_ERR "EXT3-fs: blocksize %d too small for "
++ "device blocksize %d.\n", blocksize, hblock);
++ goto failed_mount;
++ }
++
++ brelse (bh);
++ set_blocksize (dev, sb->s_blocksize);
++ logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize;
++ offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
++ bh = sb_bread(sb, logic_sb_block);
++ if (!bh) {
++ printk(KERN_ERR
++ "EXT3-fs: Can't read superblock on 2nd try.\n");
++ return NULL;
++ }
++ es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
++ sbi->s_es = es;
++ if (es->s_magic != le16_to_cpu(EXT3_SUPER_MAGIC)) {
++ printk (KERN_ERR
++ "EXT3-fs: Magic mismatch, very weird !\n");
++ goto failed_mount;
++ }
++ }
++
++ if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) {
++ sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE;
++ sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO;
++ } else {
++ sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
++ sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
++ if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
++ printk (KERN_ERR
++ "EXT3-fs: unsupported inode size: %d\n",
++ sbi->s_inode_size);
++ goto failed_mount;
++ }
++ }
++ sbi->s_frag_size = EXT3_MIN_FRAG_SIZE <<
++ le32_to_cpu(es->s_log_frag_size);
++ if (blocksize != sbi->s_frag_size) {
++ printk(KERN_ERR
++ "EXT3-fs: fragsize %lu != blocksize %u (unsupported)\n",
++ sbi->s_frag_size, blocksize);
++ goto failed_mount;
++ }
++ sbi->s_frags_per_block = 1;
++ sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
++ sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
++ sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
++ sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb);
++ sbi->s_itb_per_group = sbi->s_inodes_per_group /sbi->s_inodes_per_block;
++ sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc);
++ sbi->s_sbh = bh;
++ if (sbi->s_resuid == EXT3_DEF_RESUID)
++ sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
++ if (sbi->s_resgid == EXT3_DEF_RESGID)
++ sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
++ sbi->s_mount_state = le16_to_cpu(es->s_state);
++ sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
++ sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
++
++ if (sbi->s_blocks_per_group > blocksize * 8) {
++ printk (KERN_ERR
++ "EXT3-fs: #blocks per group too big: %lu\n",
++ sbi->s_blocks_per_group);
++ goto failed_mount;
++ }
++ if (sbi->s_frags_per_group > blocksize * 8) {
++ printk (KERN_ERR
++ "EXT3-fs: #fragments per group too big: %lu\n",
++ sbi->s_frags_per_group);
++ goto failed_mount;
++ }
++ if (sbi->s_inodes_per_group > blocksize * 8) {
++ printk (KERN_ERR
++ "EXT3-fs: #inodes per group too big: %lu\n",
++ sbi->s_inodes_per_group);
++ goto failed_mount;
++ }
++
++ sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
++ le32_to_cpu(es->s_first_data_block) +
++ EXT3_BLOCKS_PER_GROUP(sb) - 1) /
++ EXT3_BLOCKS_PER_GROUP(sb);
++ db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
++ EXT3_DESC_PER_BLOCK(sb);
++ sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
++ GFP_KERNEL);
++ if (sbi->s_group_desc == NULL) {
++ printk (KERN_ERR "EXT3-fs: not enough memory\n");
++ goto failed_mount;
++ }
++ for (i = 0; i < db_count; i++) {
++ sbi->s_group_desc[i] = sb_bread(sb, logic_sb_block + i + 1);
++ if (!sbi->s_group_desc[i]) {
++ printk (KERN_ERR "EXT3-fs: "
++ "can't read group descriptor %d\n", i);
++ db_count = i;
++ goto failed_mount2;
++ }
++ }
++ if (!ext3_check_descriptors (sb)) {
++ printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n");
++ goto failed_mount2;
++ }
++ for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) {
++ sbi->s_inode_bitmap_number[i] = 0;
++ sbi->s_inode_bitmap[i] = NULL;
++ sbi->s_block_bitmap_number[i] = 0;
++ sbi->s_block_bitmap[i] = NULL;
++ }
++ sbi->s_loaded_inode_bitmaps = 0;
++ sbi->s_loaded_block_bitmaps = 0;
++ sbi->s_gdb_count = db_count;
++ get_random_bytes(&sbi->s_next_generation, sizeof(u32));
++ /*
++ * set up enough so that it can read an inode
++ */
++ sb->s_op = &ext3_sops;
++ INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
++
++ sb->s_root = 0;
++
++ needs_recovery = (es->s_last_orphan != 0 ||
++ EXT3_HAS_INCOMPAT_FEATURE(sb,
++ EXT3_FEATURE_INCOMPAT_RECOVER));
++
++ /*
++ * The first inode we look at is the journal inode. Don't try
++ * root first: it may be modified in the journal!
++ */
++ if (!test_opt(sb, NOLOAD) &&
++ EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
++ if (ext3_load_journal(sb, es))
++ goto failed_mount2;
++ } else if (journal_inum) {
++ if (ext3_create_journal(sb, es, journal_inum))
++ goto failed_mount2;
++ } else {
++ if (!silent)
++ printk (KERN_ERR
++ "ext3: No journal on filesystem on %s\n",
++ bdevname(dev));
++ goto failed_mount2;
++ }
++
++ /* We have now updated the journal if required, so we can
++ * validate the data journaling mode. */
++ switch (test_opt(sb, DATA_FLAGS)) {
++ case 0:
++ /* No mode set, assume a default based on the journal
++ capabilities: ORDERED_DATA if the journal can
++ cope, else JOURNAL_DATA */
++ if (journal_check_available_features
++ (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE))
++ set_opt(sbi->s_mount_opt, ORDERED_DATA);
++ else
++ set_opt(sbi->s_mount_opt, JOURNAL_DATA);
++ break;
++
++ case EXT3_MOUNT_ORDERED_DATA:
++ case EXT3_MOUNT_WRITEBACK_DATA:
++ if (!journal_check_available_features
++ (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) {
++ printk(KERN_ERR "EXT3-fs: Journal does not support "
++ "requested data journaling mode\n");
++ goto failed_mount3;
++ }
++ default:
++ break;
++ }
++
++ /*
++ * The journal_load will have done any necessary log recovery,
++ * so we can safely mount the rest of the filesystem now.
++ */
++
++ sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO));
++ if (!sb->s_root || !S_ISDIR(sb->s_root->d_inode->i_mode) ||
++ !sb->s_root->d_inode->i_blocks || !sb->s_root->d_inode->i_size) {
++ if (sb->s_root) {
++ dput(sb->s_root);
++ sb->s_root = NULL;
++ printk(KERN_ERR
++ "EXT3-fs: corrupt root inode, run e2fsck\n");
++ } else
++ printk(KERN_ERR "EXT3-fs: get root inode failed\n");
++ goto failed_mount3;
++ }
++
++ ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
++ /*
++ * akpm: core read_super() calls in here with the superblock locked.
++ * That deadlocks, because orphan cleanup needs to lock the superblock
++ * in numerous places. Here we just pop the lock - it's relatively
++ * harmless, because we are now ready to accept write_super() requests,
++ * and aviro says that's the only reason for hanging onto the
++ * superblock lock.
++ */
++ EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS;
++ unlock_super(sb); /* akpm: sigh */
++ ext3_orphan_cleanup(sb, es);
++ lock_super(sb);
++ EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS;
++ if (needs_recovery)
++ printk (KERN_INFO "EXT3-fs: recovery complete.\n");
++ ext3_mark_recovery_complete(sb, es);
++ printk (KERN_INFO "EXT3-fs: mounted filesystem with %s data mode.\n",
++ test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal":
++ test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
++ "writeback");
++
++ return sb;
++
++failed_mount3:
++ journal_destroy(sbi->s_journal);
++failed_mount2:
++ for (i = 0; i < db_count; i++)
++ brelse(sbi->s_group_desc[i]);
++ kfree(sbi->s_group_desc);
++failed_mount:
++ ext3_blkdev_remove(sbi);
++ brelse(bh);
++out_fail:
++ return NULL;
++}
++
++/*
++ * Setup any per-fs journal parameters now. We'll do this both on
++ * initial mount, once the journal has been initialised but before we've
++ * done any recovery; and again on any subsequent remount.
++ */
++static void ext3_init_journal_params(struct ext3_sb_info *sbi,
++ journal_t *journal)
++{
++ if (sbi->s_commit_interval)
++ journal->j_commit_interval = sbi->s_commit_interval;
++ /* We could also set up an ext3-specific default for the commit
++ * interval here, but for now we'll just fall back to the jbd
++ * default. */
++}
++
++
++static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
++{
++ struct inode *journal_inode;
++ journal_t *journal;
++
++ /* First, test for the existence of a valid inode on disk. Bad
++ * things happen if we iget() an unused inode, as the subsequent
++ * iput() will try to delete it. */
++
++ journal_inode = iget(sb, journal_inum);
++ if (!journal_inode) {
++ printk(KERN_ERR "EXT3-fs: no journal found.\n");
++ return NULL;
++ }
++ if (!journal_inode->i_nlink) {
++ make_bad_inode(journal_inode);
++ iput(journal_inode);
++ printk(KERN_ERR "EXT3-fs: journal inode is deleted.\n");
++ return NULL;
++ }
++
++ jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
++ journal_inode, journal_inode->i_size);
++ if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
++ printk(KERN_ERR "EXT3-fs: invalid journal inode.\n");
++ iput(journal_inode);
++ return NULL;
++ }
++
++ journal = journal_init_inode(journal_inode);
++ if (!journal) {
++ printk(KERN_ERR "EXT3-fs: Could not load journal inode\n");
++ iput(journal_inode);
++ }
++ ext3_init_journal_params(EXT3_SB(sb), journal);
++ return journal;
++}
++
++static journal_t *ext3_get_dev_journal(struct super_block *sb,
++ int dev)
++{
++ struct buffer_head * bh;
++ journal_t *journal;
++ int start;
++ int len;
++ int hblock, blocksize;
++ unsigned long sb_block;
++ unsigned long offset;
++ kdev_t journal_dev = to_kdev_t(dev);
++ struct ext3_super_block * es;
++ struct block_device *bdev;
++
++ bdev = ext3_blkdev_get(journal_dev);
++ if (bdev == NULL)
++ return NULL;
++
++ blocksize = sb->s_blocksize;
++ hblock = get_hardsect_size(journal_dev);
++ if (blocksize < hblock) {
++ printk(KERN_ERR
++ "EXT3-fs: blocksize too small for journal device.\n");
++ goto out_bdev;
++ }
++
++ sb_block = EXT3_MIN_BLOCK_SIZE / blocksize;
++ offset = EXT3_MIN_BLOCK_SIZE % blocksize;
++ set_blocksize(dev, blocksize);
++ if (!(bh = bread(dev, sb_block, blocksize))) {
++ printk(KERN_ERR "EXT3-fs: couldn't read superblock of "
++ "external journal\n");
++ goto out_bdev;
++ }
++
++ es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
++ if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) ||
++ !(le32_to_cpu(es->s_feature_incompat) &
++ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
++ printk(KERN_ERR "EXT3-fs: external journal has "
++ "bad superblock\n");
++ brelse(bh);
++ goto out_bdev;
++ }
++
++ if (memcmp(EXT3_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) {
++ printk(KERN_ERR "EXT3-fs: journal UUID does not match\n");
++ brelse(bh);
++ goto out_bdev;
++ }
++
++ len = le32_to_cpu(es->s_blocks_count);
++ start = sb_block + 1;
++ brelse(bh); /* we're done with the superblock */
++
++ journal = journal_init_dev(journal_dev, sb->s_dev,
++ start, len, blocksize);
++ if (!journal) {
++ printk(KERN_ERR "EXT3-fs: failed to create device journal\n");
++ goto out_bdev;
++ }
++ ll_rw_block(READ, 1, &journal->j_sb_buffer);
++ wait_on_buffer(journal->j_sb_buffer);
++ if (!buffer_uptodate(journal->j_sb_buffer)) {
++ printk(KERN_ERR "EXT3-fs: I/O error on journal device\n");
++ goto out_journal;
++ }
++ if (ntohl(journal->j_superblock->s_nr_users) != 1) {
++ printk(KERN_ERR "EXT3-fs: External journal has more than one "
++ "user (unsupported) - %d\n",
++ ntohl(journal->j_superblock->s_nr_users));
++ goto out_journal;
++ }
++ EXT3_SB(sb)->journal_bdev = bdev;
++ ext3_init_journal_params(EXT3_SB(sb), journal);
++ return journal;
++out_journal:
++ journal_destroy(journal);
++out_bdev:
++ ext3_blkdev_put(bdev);
++ return NULL;
++}
++
++static int ext3_load_journal(struct super_block * sb,
++ struct ext3_super_block * es)
++{
++ journal_t *journal;
++ int journal_inum = le32_to_cpu(es->s_journal_inum);
++ int journal_dev = le32_to_cpu(es->s_journal_dev);
++ int err = 0;
++ int really_read_only;
++
++ really_read_only = is_read_only(sb->s_dev);
++
++ /*
++ * Are we loading a blank journal or performing recovery after a
++ * crash? For recovery, we need to check in advance whether we
++ * can get read-write access to the device.
++ */
++
++ if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) {
++ if (sb->s_flags & MS_RDONLY) {
++ printk(KERN_INFO "EXT3-fs: INFO: recovery "
++ "required on readonly filesystem.\n");
++ if (really_read_only) {
++ printk(KERN_ERR "EXT3-fs: write access "
++ "unavailable, cannot proceed.\n");
++ return -EROFS;
++ }
++ printk (KERN_INFO "EXT3-fs: write access will "
++ "be enabled during recovery.\n");
++ }
++ }
++
++ if (journal_inum && journal_dev) {
++ printk(KERN_ERR "EXT3-fs: filesystem has both journal "
++ "and inode journals!\n");
++ return -EINVAL;
++ }
++
++ if (journal_inum) {
++ if (!(journal = ext3_get_journal(sb, journal_inum)))
++ return -EINVAL;
++ } else {
++ if (!(journal = ext3_get_dev_journal(sb, journal_dev)))
++ return -EINVAL;
++ }
++
++
++ if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
++ err = journal_update_format(journal);
++ if (err) {
++ printk(KERN_ERR "EXT3-fs: error updating journal.\n");
++ journal_destroy(journal);
++ return err;
++ }
++ }
++
++ if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER))
++ err = journal_wipe(journal, !really_read_only);
++ if (!err)
++ err = journal_load(journal);
++
++ if (err) {
++ printk(KERN_ERR "EXT3-fs: error loading journal.\n");
++ journal_destroy(journal);
++ return err;
++ }
++
++ EXT3_SB(sb)->s_journal = journal;
++ ext3_clear_journal_err(sb, es);
++ return 0;
++}
++
++static int ext3_create_journal(struct super_block * sb,
++ struct ext3_super_block * es,
++ int journal_inum)
++{
++ journal_t *journal;
++
++ if (sb->s_flags & MS_RDONLY) {
++ printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to "
++ "create journal.\n");
++ return -EROFS;
++ }
++
++ if (!(journal = ext3_get_journal(sb, journal_inum)))
++ return -EINVAL;
++
++ printk(KERN_INFO "EXT3-fs: creating new journal on inode %d\n",
++ journal_inum);
++
++ if (journal_create(journal)) {
++ printk(KERN_ERR "EXT3-fs: error creating journal.\n");
++ journal_destroy(journal);
++ return -EIO;
++ }
++
++ EXT3_SB(sb)->s_journal = journal;
++
++ ext3_update_dynamic_rev(sb);
++ EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++ EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL);
++
++ es->s_journal_inum = cpu_to_le32(journal_inum);
++ sb->s_dirt = 1;
++
++ /* Make sure we flush the recovery flag to disk. */
++ ext3_commit_super(sb, es, 1);
++
++ return 0;
++}
++
++static void ext3_commit_super (struct super_block * sb,
++ struct ext3_super_block * es,
++ int sync)
++{
++ es->s_wtime = cpu_to_le32(CURRENT_TIME);
++ BUFFER_TRACE(sb->u.ext3_sb.s_sbh, "marking dirty");
++ mark_buffer_dirty(sb->u.ext3_sb.s_sbh);
++ if (sync) {
++ ll_rw_block(WRITE, 1, &sb->u.ext3_sb.s_sbh);
++ wait_on_buffer(sb->u.ext3_sb.s_sbh);
++ }
++}
++
++
++/*
++ * Have we just finished recovery? If so, and if we are mounting (or
++ * remounting) the filesystem readonly, then we will end up with a
++ * consistent fs on disk. Record that fact.
++ */
++static void ext3_mark_recovery_complete(struct super_block * sb,
++ struct ext3_super_block * es)
++{
++ journal_flush(EXT3_SB(sb)->s_journal);
++ if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
++ sb->s_flags & MS_RDONLY) {
++ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++ sb->s_dirt = 0;
++ ext3_commit_super(sb, es, 1);
++ }
++}
++
++/*
++ * If we are mounting (or read-write remounting) a filesystem whose journal
++ * has recorded an error from a previous lifetime, move that error to the
++ * main filesystem now.
++ */
++static void ext3_clear_journal_err(struct super_block * sb,
++ struct ext3_super_block * es)
++{
++ journal_t *journal;
++ int j_errno;
++ const char *errstr;
++
++ journal = EXT3_SB(sb)->s_journal;
++
++ /*
++ * Now check for any error status which may have been recorded in the
++ * journal by a prior ext3_error() or ext3_abort()
++ */
++
++ j_errno = journal_errno(journal);
++ if (j_errno) {
++ char nbuf[16];
++
++ errstr = ext3_decode_error(sb, j_errno, nbuf);
++ ext3_warning(sb, __FUNCTION__, "Filesystem error recorded "
++ "from previous mount: %s", errstr);
++ ext3_warning(sb, __FUNCTION__, "Marking fs in need of "
++ "filesystem check.");
++
++ sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS;
++ es->s_state |= cpu_to_le16(EXT3_ERROR_FS);
++ ext3_commit_super (sb, es, 1);
++
++ journal_clear_err(journal);
++ }
++}
++
++/*
++ * Force the running and committing transactions to commit,
++ * and wait on the commit.
++ */
++int ext3_force_commit(struct super_block *sb)
++{
++ journal_t *journal;
++ int ret;
++
++ if (sb->s_flags & MS_RDONLY)
++ return 0;
++
++ journal = EXT3_SB(sb)->s_journal;
++ sb->s_dirt = 0;
++ lock_kernel(); /* important: lock down j_running_transaction */
++ ret = ext3_journal_force_commit(journal);
++ unlock_kernel();
++ return ret;
++}
++
++/*
++ * Ext3 always journals updates to the superblock itself, so we don't
++ * have to propagate any other updates to the superblock on disk at this
++ * point. Just start an async writeback to get the buffers on their way
++ * to the disk.
++ *
++ * This implicitly triggers the writebehind on sync().
++ */
++
++void ext3_write_super (struct super_block * sb)
++{
++ if (down_trylock(&sb->s_lock) == 0)
++ BUG();
++ sb->s_dirt = 0;
++ log_start_commit(EXT3_SB(sb)->s_journal, NULL);
++}
++
++static int ext3_sync_fs(struct super_block *sb)
++{
++ tid_t target;
++
++ sb->s_dirt = 0;
++ target = log_start_commit(EXT3_SB(sb)->s_journal, NULL);
++ log_wait_commit(EXT3_SB(sb)->s_journal, target);
++ return 0;
++}
++
++/*
++ * LVM calls this function before a (read-only) snapshot is created. This
++ * gives us a chance to flush the journal completely and mark the fs clean.
++ */
++void ext3_write_super_lockfs(struct super_block *sb)
++{
++ sb->s_dirt = 0;
++
++ lock_kernel(); /* 2.4.5 forgot to do this for us */
++ if (!(sb->s_flags & MS_RDONLY)) {
++ journal_t *journal = EXT3_SB(sb)->s_journal;
++
++ /* Now we set up the journal barrier. */
++ unlock_super(sb);
++ journal_lock_updates(journal);
++ journal_flush(journal);
++ lock_super(sb);
++
++ /* Journal blocked and flushed, clear needs_recovery flag. */
++ EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++ ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1);
++ }
++ unlock_kernel();
++}
++
++/*
++ * Called by LVM after the snapshot is done. We need to reset the RECOVER
++ * flag here, even though the filesystem is not technically dirty yet.
++ */
++void ext3_unlockfs(struct super_block *sb)
++{
++ if (!(sb->s_flags & MS_RDONLY)) {
++ lock_kernel();
++ lock_super(sb);
++ /* Reser the needs_recovery flag before the fs is unlocked. */
++ EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++ ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1);
++ unlock_super(sb);
++ journal_unlock_updates(EXT3_SB(sb)->s_journal);
++ unlock_kernel();
++ }
++}
++
++int ext3_remount (struct super_block * sb, int * flags, char * data)
++{
++ struct ext3_super_block * es;
++ struct ext3_sb_info *sbi = EXT3_SB(sb);
++ unsigned long tmp;
++
++ clear_ro_after(sb);
++
++ /*
++ * Allow the "check" option to be passed as a remount option.
++ */
++ if (!parse_options(data, &tmp, sbi, &tmp, 1))
++ return -EINVAL;
++
++ if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
++ ext3_abort(sb, __FUNCTION__, "Abort forced by user");
++
++ es = sbi->s_es;
++
++ ext3_init_journal_params(sbi, sbi->s_journal);
++
++ if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
++ if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
++ return -EROFS;
++
++ if (*flags & MS_RDONLY) {
++ /*
++ * First of all, the unconditional stuff we have to do
++ * to disable replay of the journal when we next remount
++ */
++ sb->s_flags |= MS_RDONLY;
++
++ /*
++ * OK, test if we are remounting a valid rw partition
++ * readonly, and if so set the rdonly flag and then
++ * mark the partition as valid again.
++ */
++ if (!(es->s_state & cpu_to_le16(EXT3_VALID_FS)) &&
++ (sbi->s_mount_state & EXT3_VALID_FS))
++ es->s_state = cpu_to_le16(sbi->s_mount_state);
++
++ ext3_mark_recovery_complete(sb, es);
++ } else {
++ int ret;
++ if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb,
++ ~EXT3_FEATURE_RO_COMPAT_SUPP))) {
++ printk(KERN_WARNING "EXT3-fs: %s: couldn't "
++ "remount RDWR because of unsupported "
++ "optional features (%x).\n",
++ bdevname(sb->s_dev), ret);
++ return -EROFS;
++ }
++ /*
++ * Mounting a RDONLY partition read-write, so reread
++ * and store the current valid flag. (It may have
++ * been changed by e2fsck since we originally mounted
++ * the partition.)
++ */
++ ext3_clear_journal_err(sb, es);
++ sbi->s_mount_state = le16_to_cpu(es->s_state);
++ if (!ext3_setup_super (sb, es, 0))
++ sb->s_flags &= ~MS_RDONLY;
++ }
++ }
++ setup_ro_after(sb);
++ return 0;
++}
++
++int ext3_statfs (struct super_block * sb, struct statfs * buf)
++{
++ struct ext3_super_block *es = EXT3_SB(sb)->s_es;
++ unsigned long overhead;
++ int i;
++
++ if (test_opt (sb, MINIX_DF))
++ overhead = 0;
++ else {
++ /*
++ * Compute the overhead (FS structures)
++ */
++
++ /*
++ * All of the blocks before first_data_block are
++ * overhead
++ */
++ overhead = le32_to_cpu(es->s_first_data_block);
++
++ /*
++ * Add the overhead attributed to the superblock and
++ * block group descriptors. If the sparse superblocks
++ * feature is turned on, then not all groups have this.
++ */
++ for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++)
++ overhead += ext3_bg_has_super(sb, i) +
++ ext3_bg_num_gdb(sb, i);
++
++ /*
++ * Every block group has an inode bitmap, a block
++ * bitmap, and an inode table.
++ */
++ overhead += (EXT3_SB(sb)->s_groups_count *
++ (2 + EXT3_SB(sb)->s_itb_per_group));
++ }
++
++ buf->f_type = EXT3_SUPER_MAGIC;
++ buf->f_bsize = sb->s_blocksize;
++ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
++ buf->f_bfree = ext3_count_free_blocks (sb);
++ buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
++ if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
++ buf->f_bavail = 0;
++ buf->f_files = le32_to_cpu(es->s_inodes_count);
++ buf->f_ffree = ext3_count_free_inodes (sb);
++ buf->f_namelen = EXT3_NAME_LEN;
++ return 0;
++}
++
++static DECLARE_FSTYPE_DEV(ext3_fs_type, "ext3", ext3_read_super);
++
++static int __init init_ext3_fs(void)
++{
++ return register_filesystem(&ext3_fs_type);
++}
++
++static void __exit exit_ext3_fs(void)
++{
++ unregister_filesystem(&ext3_fs_type);
++}
++
++EXPORT_SYMBOL(ext3_bread);
++
++MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
++MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions");
++MODULE_LICENSE("GPL");
++module_init(init_ext3_fs)
++module_exit(exit_ext3_fs)
+--- /dev/null Fri Aug 30 17:31:37 2002
++++ linux-rh-2.4.20-6-braam/include/linux/fs.h Mon Mar 31 23:46:17 2003
+@@ -0,0 +1,1680 @@
++#ifndef _LINUX_FS_H
++#define _LINUX_FS_H
++
++/*
++ * This file has definitions for some important file table
++ * structures etc.
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <linux/limits.h>
++#include <linux/wait.h>
++#include <linux/types.h>
++#include <linux/vfs.h>
++#include <linux/net.h>
++#include <linux/kdev_t.h>
++#include <linux/ioctl.h>
++#include <linux/list.h>
++#include <linux/dcache.h>
++#include <linux/stat.h>
++#include <linux/cache.h>
++#include <linux/stddef.h>
++#include <linux/string.h>
++
++#include <asm/atomic.h>
++#include <asm/bitops.h>
++
++struct poll_table_struct;
++
++
++/*
++ * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
++ * the file limit at runtime and only root can increase the per-process
++ * nr_file rlimit, so it's safe to set up a ridiculously high absolute
++ * upper limit on files-per-process.
++ *
++ * Some programs (notably those using select()) may have to be
++ * recompiled to take full advantage of the new limits..
++ */
++
++/* Fixed constants first: */
++#undef NR_OPEN
++#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */
++#define INR_OPEN 1024 /* Initial setting for nfile rlimits */
++
++#define BLOCK_SIZE_BITS 10
++#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
++
++/* And dynamically-tunable limits and defaults: */
++struct files_stat_struct {
++ int nr_files; /* read only */
++ int nr_free_files; /* read only */
++ int max_files; /* tunable */
++};
++extern struct files_stat_struct files_stat;
++
++struct inodes_stat_t {
++ int nr_inodes;
++ int nr_unused;
++ int dummy[5];
++};
++extern struct inodes_stat_t inodes_stat;
++
++extern int leases_enable, dir_notify_enable, lease_break_time;
++
++#define NR_FILE 8192 /* this can well be larger on a larger system */
++#define NR_RESERVED_FILES 10 /* reserved for root */
++#define NR_SUPER 256
++
++#define MAY_EXEC 1
++#define MAY_WRITE 2
++#define MAY_READ 4
++
++#define FMODE_READ 1
++#define FMODE_WRITE 2
++
++#define READ 0
++#define WRITE 1
++#define READA 2 /* read-ahead - don't block if no resources */
++#define SPECIAL 4 /* For non-blockdevice requests in request queue */
++
++#define SEL_IN 1
++#define SEL_OUT 2
++#define SEL_EX 4
++
++/* public flags for file_system_type */
++#define FS_REQUIRES_DEV 1
++#define FS_NO_DCACHE 2 /* Only dcache the necessary things. */
++#define FS_NO_PRELIM 4 /* prevent preloading of dentries, even if
++ * FS_NO_DCACHE is not set.
++ */
++#define FS_SINGLE 8 /* Filesystem that can have only one superblock */
++#define FS_NOMOUNT 16 /* Never mount from userland */
++#define FS_LITTER 32 /* Keeps the tree in dcache */
++#define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon
++ * as nfs_rename() will be cleaned up
++ */
++/*
++ * These are the fs-independent mount-flags: up to 32 flags are supported
++ */
++#define MS_RDONLY 1 /* Mount read-only */
++#define MS_NOSUID 2 /* Ignore suid and sgid bits */
++#define MS_NODEV 4 /* Disallow access to device special files */
++#define MS_NOEXEC 8 /* Disallow program execution */
++#define MS_SYNCHRONOUS 16 /* Writes are synced at once */
++#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
++#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
++#define MS_NOATIME 1024 /* Do not update access times. */
++#define MS_NODIRATIME 2048 /* Do not update directory access times */
++#define MS_BIND 4096
++#define MS_MOVE 8192
++#define MS_REC 16384
++#define MS_VERBOSE 32768
++#define MS_ACTIVE (1<<30)
++#define MS_NOUSER (1<<31)
++
++/*
++ * Superblock flags that can be altered by MS_REMOUNT
++ */
++#define MS_RMT_MASK (MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|\
++ MS_NODIRATIME)
++
++/*
++ * Old magic mount flag and mask
++ */
++#define MS_MGC_VAL 0xC0ED0000
++#define MS_MGC_MSK 0xffff0000
++
++/* Inode flags - they have nothing to superblock flags now */
++
++#define S_SYNC 1 /* Writes are synced at once */
++#define S_NOATIME 2 /* Do not update access times */
++#define S_QUOTA 4 /* Quota initialized for file */
++#define S_APPEND 8 /* Append-only file */
++#define S_IMMUTABLE 16 /* Immutable file */
++#define S_DEAD 32 /* removed, but still open directory */
++#define S_NOQUOTA 64 /* Inode is not counted to quota */
++
++/*
++ * Note that nosuid etc flags are inode-specific: setting some file-system
++ * flags just means all the inodes inherit those flags by default. It might be
++ * possible to override it selectively if you really wanted to with some
++ * ioctl() that is not currently implemented.
++ *
++ * Exception: MS_RDONLY is always applied to the entire file system.
++ *
++ * Unfortunately, it is possible to change a filesystems flags with it mounted
++ * with files in use. This means that all of the inodes will not have their
++ * i_flags updated. Hence, i_flags no longer inherit the superblock mount
++ * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org
++ */
++#define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg))
++
++#define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
++#define IS_SYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
++#define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK)
++
++#define IS_QUOTAINIT(inode) ((inode)->i_flags & S_QUOTA)
++#define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA)
++#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND)
++#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE)
++#define IS_NOATIME(inode) (__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
++#define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME)
++
++#define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
++
++/* the read-only stuff doesn't really belong here, but any other place is
++ probably as bad and I don't want to create yet another include file. */
++
++#define BLKROSET _IO(0x12,93) /* set device read-only (0 = read-write) */
++#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
++#define BLKRRPART _IO(0x12,95) /* re-read partition table */
++#define BLKGETSIZE _IO(0x12,96) /* return device size /512 (long *arg) */
++#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
++#define BLKRASET _IO(0x12,98) /* Set read ahead for block device */
++#define BLKRAGET _IO(0x12,99) /* get current read ahead setting */
++#define BLKFRASET _IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
++#define BLKFRAGET _IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
++#define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
++#define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
++#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
++#if 0
++#define BLKPG _IO(0x12,105)/* See blkpg.h */
++#define BLKELVGET _IOR(0x12,106,sizeof(blkelv_ioctl_arg_t))/* elevator get */
++#define BLKELVSET _IOW(0x12,107,sizeof(blkelv_ioctl_arg_t))/* elevator set */
++/* This was here just to show that the number is taken -
++ probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */
++#endif
++/* A jump here: 108-111 have been used for various private purposes. */
++#define BLKBSZGET _IOR(0x12,112,sizeof(int))
++#define BLKBSZSET _IOW(0x12,113,sizeof(int))
++#define BLKGETSIZE64 _IOR(0x12,114,sizeof(u64)) /* return device size in bytes (u64 *arg) */
++
++#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
++#define FIBMAP _IO(0x00,1) /* bmap access */
++#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
++
++#ifdef __KERNEL__
++
++#include <asm/semaphore.h>
++#include <asm/byteorder.h>
++
++extern void update_atime (struct inode *);
++#define UPDATE_ATIME(inode) update_atime (inode)
++
++extern void buffer_init(unsigned long);
++extern void inode_init(unsigned long);
++extern void mnt_init(unsigned long);
++extern void files_init(unsigned long mempages);
++extern void majorhog_init(void);
++
++/* bh state bits */
++enum bh_state_bits {
++ BH_Uptodate, /* 1 if the buffer contains valid data */
++ BH_Dirty, /* 1 if the buffer is dirty */
++ BH_Lock, /* 1 if the buffer is locked */
++ BH_Req, /* 0 if the buffer has been invalidated */
++ BH_Mapped, /* 1 if the buffer has a disk mapping */
++ BH_New, /* 1 if the buffer is new and not yet written out */
++ BH_Async, /* 1 if the buffer is under end_buffer_io_async I/O */
++ BH_Wait_IO, /* 1 if we should write out this buffer */
++ BH_Launder, /* 1 if we can throttle on this buffer */
++ BH_Attached, /* 1 if b_inode_buffers is linked into a list */
++ BH_JBD, /* 1 if it has an attached journal_head */
++
++ BH_PrivateStart,/* not a state bit, but the first bit available
++ * for private allocation by other entities
++ */
++};
++
++#define MAX_BUF_PER_PAGE (PAGE_CACHE_SIZE / 512)
++
++/*
++ * Try to keep the most commonly used fields in single cache lines (16
++ * bytes) to improve performance. This ordering should be
++ * particularly beneficial on 32-bit processors.
++ *
++ * We use the first 16 bytes for the data which is used in searches
++ * over the block hash lists (ie. getblk() and friends).
++ *
++ * The second 16 bytes we use for lru buffer scans, as used by
++ * sync_buffers() and refill_freelist(). -- sct
++ */
++struct buffer_head {
++ /* First cache line: */
++ struct buffer_head *b_next; /* Hash queue list */
++ unsigned long b_blocknr; /* block number */
++ unsigned short b_size; /* block size */
++ unsigned short b_list; /* List that this buffer appears */
++ kdev_t b_dev; /* device (B_FREE = free) */
++
++ atomic_t b_count; /* users using this block */
++ kdev_t b_rdev; /* Real device */
++ unsigned long b_state; /* buffer state bitmap (see above) */
++ unsigned long b_flushtime; /* Time when (dirty) buffer should be written */
++
++ struct buffer_head *b_next_free;/* lru/free list linkage */
++ struct buffer_head *b_prev_free;/* doubly linked list of buffers */
++ struct buffer_head *b_this_page;/* circular list of buffers in one page */
++ struct buffer_head *b_reqnext; /* request queue */
++
++ struct buffer_head **b_pprev; /* doubly linked list of hash-queue */
++ char * b_data; /* pointer to data block */
++ struct page *b_page; /* the page this bh is mapped to */
++ void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
++ void *b_private; /* reserved for b_end_io */
++ void *b_journal_head; /* ext3 journal_heads */
++ unsigned long b_rsector; /* Real buffer location on disk */
++ wait_queue_head_t b_wait;
++
++ struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */
++};
++
++typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
++void init_buffer(struct buffer_head *, bh_end_io_t *, void *);
++
++#define __buffer_state(bh, state) (((bh)->b_state & (1UL << BH_##state)) != 0)
++
++#define buffer_uptodate(bh) __buffer_state(bh,Uptodate)
++#define buffer_dirty(bh) __buffer_state(bh,Dirty)
++#define buffer_locked(bh) __buffer_state(bh,Lock)
++#define buffer_req(bh) __buffer_state(bh,Req)
++#define buffer_mapped(bh) __buffer_state(bh,Mapped)
++#define buffer_new(bh) __buffer_state(bh,New)
++#define buffer_async(bh) __buffer_state(bh,Async)
++#define buffer_launder(bh) __buffer_state(bh,Launder)
++
++#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK)
++
++extern void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset);
++
++#define touch_buffer(bh) mark_page_accessed(bh->b_page)
++
++
++#include <linux/pipe_fs_i.h>
++#include <linux/minix_fs_i.h>
++#include <linux/ext2_fs_i.h>
++#include <linux/ext3_fs_i.h>
++#include <linux/hpfs_fs_i.h>
++#include <linux/ntfs_fs_i.h>
++#include <linux/msdos_fs_i.h>
++#include <linux/umsdos_fs_i.h>
++#include <linux/iso_fs_i.h>
++#include <linux/nfs_fs_i.h>
++#include <linux/sysv_fs_i.h>
++#include <linux/affs_fs_i.h>
++#include <linux/ufs_fs_i.h>
++#include <linux/efs_fs_i.h>
++#include <linux/coda_fs_i.h>
++#include <linux/romfs_fs_i.h>
++#include <linux/shmem_fs.h>
++#include <linux/smb_fs_i.h>
++#include <linux/hfs_fs_i.h>
++#include <linux/adfs_fs_i.h>
++#include <linux/qnx4_fs_i.h>
++#include <linux/reiserfs_fs_i.h>
++#include <linux/bfs_fs_i.h>
++#include <linux/udf_fs_i.h>
++#include <linux/ncp_fs_i.h>
++#include <linux/proc_fs_i.h>
++#include <linux/usbdev_fs_i.h>
++#include <linux/jffs2_fs_i.h>
++#include <linux/cramfs_fs_sb.h>
++
++/*
++ * Attribute flags. These should be or-ed together to figure out what
++ * has been changed!
++ */
++#define ATTR_MODE 1
++#define ATTR_UID 2
++#define ATTR_GID 4
++#define ATTR_SIZE 8
++#define ATTR_ATIME 16
++#define ATTR_MTIME 32
++#define ATTR_CTIME 64
++#define ATTR_ATIME_SET 128
++#define ATTR_MTIME_SET 256
++#define ATTR_FORCE 512 /* Not a change, but a change it */
++#define ATTR_ATTR_FLAG 1024
++
++/*
++ * This is the Inode Attributes structure, used for notify_change(). It
++ * uses the above definitions as flags, to know which values have changed.
++ * Also, in this manner, a Filesystem can look at only the values it cares
++ * about. Basically, these are the attributes that the VFS layer can
++ * request to change from the FS layer.
++ *
++ * Derek Atkins <warlord@MIT.EDU> 94-10-20
++ */
++struct iattr {
++ unsigned int ia_valid;
++ umode_t ia_mode;
++ uid_t ia_uid;
++ gid_t ia_gid;
++ loff_t ia_size;
++ time_t ia_atime;
++ time_t ia_mtime;
++ time_t ia_ctime;
++ unsigned int ia_attr_flags;
++};
++
++/*
++ * This is the inode attributes flag definitions
++ */
++#define ATTR_FLAG_SYNCRONOUS 1 /* Syncronous write */
++#define ATTR_FLAG_NOATIME 2 /* Don't update atime */
++#define ATTR_FLAG_APPEND 4 /* Append-only file */
++#define ATTR_FLAG_IMMUTABLE 8 /* Immutable file */
++#define ATTR_FLAG_NODIRATIME 16 /* Don't update atime for directory */
++
++/*
++ * Includes for diskquotas and mount structures.
++ */
++#include <linux/quota.h>
++#include <linux/mount.h>
++
++/*
++ * oh the beauties of C type declarations.
++ */
++struct page;
++struct address_space;
++struct kiobuf;
++
++struct address_space_operations {
++ int (*writepage)(struct page *);
++ int (*readpage)(struct file *, struct page *);
++ int (*sync_page)(struct page *);
++ /*
++ * ext3 requires that a successful prepare_write() call be followed
++ * by a commit_write() call - they must be balanced
++ */
++ int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
++ int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
++ /* Unfortunately this kludge is needed for FIBMAP. Don't use it */
++ int (*bmap)(struct address_space *, long);
++ int (*flushpage) (struct page *, unsigned long);
++ int (*releasepage) (struct page *, int);
++#define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */
++ int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
++ void (*removepage)(struct page *); /* called when page gets removed from the inode */
++};
++
++struct address_space {
++ struct list_head clean_pages; /* list of clean pages */
++ struct list_head dirty_pages; /* list of dirty pages */
++ struct list_head locked_pages; /* list of locked pages */
++ unsigned long nrpages; /* number of total pages */
++ struct address_space_operations *a_ops; /* methods */
++ struct inode *host; /* owner: inode, block_device */
++ struct vm_area_struct *i_mmap; /* list of private mappings */
++ struct vm_area_struct *i_mmap_shared; /* list of shared mappings */
++ spinlock_t i_shared_lock; /* and spinlock protecting it */
++ int gfp_mask; /* how to allocate the pages */
++};
++
++struct char_device {
++ struct list_head hash;
++ atomic_t count;
++ dev_t dev;
++ atomic_t openers;
++ struct semaphore sem;
++};
++
++struct block_device {
++ struct list_head bd_hash;
++ atomic_t bd_count;
++ struct inode * bd_inode;
++ dev_t bd_dev; /* not a kdev_t - it's a search key */
++ int bd_openers;
++ const struct block_device_operations *bd_op;
++ struct semaphore bd_sem; /* open/close mutex */
++ struct list_head bd_inodes;
++};
++
++struct inode {
++ struct list_head i_hash;
++ struct list_head i_list;
++ struct list_head i_dentry;
++
++ struct list_head i_dirty_buffers;
++ struct list_head i_dirty_data_buffers;
++
++ unsigned long i_ino;
++ atomic_t i_count;
++ kdev_t i_dev;
++ umode_t i_mode;
++ unsigned int i_nlink;
++ uid_t i_uid;
++ gid_t i_gid;
++ kdev_t i_rdev;
++ loff_t i_size;
++ time_t i_atime;
++ time_t i_mtime;
++ time_t i_ctime;
++ unsigned int i_blkbits;
++ unsigned long i_blksize;
++ unsigned long i_blocks;
++ unsigned long i_version;
++ unsigned short i_bytes;
++ struct semaphore i_sem;
++ struct semaphore i_zombie;
++ struct inode_operations *i_op;
++ struct file_operations *i_fop; /* former ->i_op->default_file_ops */
++ struct super_block *i_sb;
++ wait_queue_head_t i_wait;
++ struct file_lock *i_flock;
++ struct address_space *i_mapping;
++ struct address_space i_data;
++ struct dquot *i_dquot[MAXQUOTAS];
++ /* These three should probably be a union */
++ struct list_head i_devices;
++ struct pipe_inode_info *i_pipe;
++ struct block_device *i_bdev;
++ struct char_device *i_cdev;
++
++ unsigned long i_dnotify_mask; /* Directory notify events */
++ struct dnotify_struct *i_dnotify; /* for directory notifications */
++
++ unsigned long i_state;
++
++ unsigned int i_flags;
++ unsigned char i_sock;
++
++ atomic_t i_writecount;
++ unsigned int i_attr_flags;
++ __u32 i_generation;
++ union {
++ struct minix_inode_info minix_i;
++ struct ext2_inode_info ext2_i;
++ struct ext3_inode_info ext3_i;
++ struct hpfs_inode_info hpfs_i;
++ struct ntfs_inode_info ntfs_i;
++ struct msdos_inode_info msdos_i;
++ struct umsdos_inode_info umsdos_i;
++ struct iso_inode_info isofs_i;
++ struct nfs_inode_info nfs_i;
++ struct sysv_inode_info sysv_i;
++ struct affs_inode_info affs_i;
++ struct ufs_inode_info ufs_i;
++ struct efs_inode_info efs_i;
++ struct romfs_inode_info romfs_i;
++ struct shmem_inode_info shmem_i;
++ struct coda_inode_info coda_i;
++ struct smb_inode_info smbfs_i;
++ struct hfs_inode_info hfs_i;
++ struct adfs_inode_info adfs_i;
++ struct qnx4_inode_info qnx4_i;
++ struct reiserfs_inode_info reiserfs_i;
++ struct bfs_inode_info bfs_i;
++ struct udf_inode_info udf_i;
++ struct ncp_inode_info ncpfs_i;
++ struct proc_inode_info proc_i;
++ struct socket socket_i;
++ struct usbdev_inode_info usbdev_i;
++ struct jffs2_inode_info jffs2_i;
++ void *generic_ip;
++ } u;
++};
++
++static inline void inode_add_bytes(struct inode *inode, loff_t bytes)
++{
++ inode->i_blocks += bytes >> 9;
++ bytes &= 511;
++ inode->i_bytes += bytes;
++ if (inode->i_bytes >= 512) {
++ inode->i_blocks++;
++ inode->i_bytes -= 512;
++ }
++}
++
++static inline void inode_sub_bytes(struct inode *inode, loff_t bytes)
++{
++ inode->i_blocks -= bytes >> 9;
++ bytes &= 511;
++ if (inode->i_bytes < bytes) {
++ inode->i_blocks--;
++ inode->i_bytes += 512;
++ }
++ inode->i_bytes -= bytes;
++}
++
++static inline loff_t inode_get_bytes(struct inode *inode)
++{
++ return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes;
++}
++
++static inline void inode_set_bytes(struct inode *inode, loff_t bytes)
++{
++ inode->i_blocks = bytes >> 9;
++ inode->i_bytes = bytes & 511;
++}
++
++struct fown_struct {
++ int pid; /* pid or -pgrp where SIGIO should be sent */
++ uid_t uid, euid; /* uid/euid of process setting the owner */
++ int signum; /* posix.1b rt signal to be delivered on IO */
++};
++
++struct file {
++ struct list_head f_list;
++ struct dentry *f_dentry;
++ struct vfsmount *f_vfsmnt;
++ struct file_operations *f_op;
++ atomic_t f_count;
++ unsigned int f_flags;
++ mode_t f_mode;
++ loff_t f_pos;
++ unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
++ struct fown_struct f_owner;
++ unsigned int f_uid, f_gid;
++ int f_error;
++
++ unsigned long f_version;
++
++ /* needed for tty driver, and maybe others */
++ void *private_data;
++
++ /* preallocated helper kiobuf to speedup O_DIRECT */
++ struct kiobuf *f_iobuf;
++ long f_iobuf_lock;
++};
++extern spinlock_t files_lock;
++#define file_list_lock() spin_lock(&files_lock);
++#define file_list_unlock() spin_unlock(&files_lock);
++
++#define get_file(x) atomic_inc(&(x)->f_count)
++#define file_count(x) atomic_read(&(x)->f_count)
++
++extern int init_private_file(struct file *, struct dentry *, int);
++
++#define MAX_NON_LFS ((1UL<<31) - 1)
++
++/* Page cache limit. The filesystems should put that into their s_maxbytes
++ limits, otherwise bad things can happen in VM. */
++#if BITS_PER_LONG==32
++#define MAX_LFS_FILESIZE (((u64)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
++#elif BITS_PER_LONG==64
++#define MAX_LFS_FILESIZE 0x7fffffffffffffff
++#endif
++
++#define FL_POSIX 1
++#define FL_FLOCK 2
++#define FL_BROKEN 4 /* broken flock() emulation */
++#define FL_ACCESS 8 /* for processes suspended by mandatory locking */
++#define FL_LOCKD 16 /* lock held by rpc.lockd */
++#define FL_LEASE 32 /* lease held on this file */
++
++/*
++ * The POSIX file lock owner is determined by
++ * the "struct files_struct" in the thread group
++ * (or NULL for no owner - BSD locks).
++ *
++ * Lockd stuffs a "host" pointer into this.
++ */
++typedef struct files_struct *fl_owner_t;
++
++struct file_lock {
++ struct file_lock *fl_next; /* singly linked list for this inode */
++ struct list_head fl_link; /* doubly linked list of all locks */
++ struct list_head fl_block; /* circular list of blocked processes */
++ fl_owner_t fl_owner;
++ unsigned int fl_pid;
++ wait_queue_head_t fl_wait;
++ struct file *fl_file;
++ unsigned char fl_flags;
++ unsigned char fl_type;
++ loff_t fl_start;
++ loff_t fl_end;
++
++ void (*fl_notify)(struct file_lock *); /* unblock callback */
++ void (*fl_insert)(struct file_lock *); /* lock insertion callback */
++ void (*fl_remove)(struct file_lock *); /* lock removal callback */
++
++ struct fasync_struct * fl_fasync; /* for lease break notifications */
++ unsigned long fl_break_time; /* for nonblocking lease breaks */
++
++ union {
++ struct nfs_lock_info nfs_fl;
++ } fl_u;
++};
++
++/* The following constant reflects the upper bound of the file/locking space */
++#ifndef OFFSET_MAX
++#define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1)))
++#define OFFSET_MAX INT_LIMIT(loff_t)
++#define OFFT_OFFSET_MAX INT_LIMIT(off_t)
++#endif
++
++extern struct list_head file_lock_list;
++
++#include <linux/fcntl.h>
++
++extern int fcntl_getlk(unsigned int, struct flock *);
++extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
++extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
++extern asmlinkage long sys_dup(unsigned int fildes);
++extern asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
++extern asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count);
++extern asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count);
++extern asmlinkage long sys_chroot(const char * filename);
++extern asmlinkage long sys_chdir(const char * filename);
++
++
++extern int fcntl_getlk64(unsigned int, struct flock64 *);
++extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *);
++
++/* fs/locks.c */
++extern void locks_init_lock(struct file_lock *);
++extern void locks_copy_lock(struct file_lock *, struct file_lock *);
++extern void locks_remove_posix(struct file *, fl_owner_t);
++extern void locks_remove_flock(struct file *);
++extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
++extern int posix_lock_file(struct file *, struct file_lock *, unsigned int);
++extern void posix_block_lock(struct file_lock *, struct file_lock *);
++extern void posix_unblock_lock(struct file_lock *);
++extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);
++extern int __get_lease(struct inode *inode, unsigned int flags);
++extern time_t lease_get_mtime(struct inode *);
++extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
++extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
++
++struct fasync_struct {
++ int magic;
++ int fa_fd;
++ struct fasync_struct *fa_next; /* singly linked list */
++ struct file *fa_file;
++};
++
++#define FASYNC_MAGIC 0x4601
++
++/* SMP safe fasync helpers: */
++extern int fasync_helper(int, struct file *, int, struct fasync_struct **);
++/* can be called from interrupts */
++extern void kill_fasync(struct fasync_struct **, int, int);
++/* only for net: no internal synchronization */
++extern void __kill_fasync(struct fasync_struct *, int, int);
++
++struct nameidata {
++ struct dentry *dentry;
++ struct vfsmount *mnt;
++ struct qstr last;
++ unsigned int flags;
++ int last_type;
++};
++
++/*
++ * Umount options
++ */
++
++#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
++#define MNT_DETACH 0x00000002 /* Just detach from the tree */
++
++#include <linux/minix_fs_sb.h>
++#include <linux/ext2_fs_sb.h>
++#include <linux/ext3_fs_sb.h>
++#include <linux/hpfs_fs_sb.h>
++#include <linux/ntfs_fs_sb.h>
++#include <linux/msdos_fs_sb.h>
++#include <linux/iso_fs_sb.h>
++#include <linux/nfs_fs_sb.h>
++#include <linux/sysv_fs_sb.h>
++#include <linux/affs_fs_sb.h>
++#include <linux/ufs_fs_sb.h>
++#include <linux/efs_fs_sb.h>
++#include <linux/romfs_fs_sb.h>
++#include <linux/smb_fs_sb.h>
++#include <linux/hfs_fs_sb.h>
++#include <linux/adfs_fs_sb.h>
++#include <linux/qnx4_fs_sb.h>
++#include <linux/reiserfs_fs_sb.h>
++#include <linux/bfs_fs_sb.h>
++#include <linux/udf_fs_sb.h>
++#include <linux/ncp_fs_sb.h>
++#include <linux/usbdev_fs_sb.h>
++#include <linux/cramfs_fs_sb.h>
++#include <linux/jffs2_fs_sb.h>
++
++extern struct list_head super_blocks;
++extern spinlock_t sb_lock;
++
++#define sb_entry(list) list_entry((list), struct super_block, s_list)
++#define S_BIAS (1<<30)
++struct super_block {
++ struct list_head s_list; /* Keep this first */
++ kdev_t s_dev;
++ unsigned long s_blocksize;
++ unsigned char s_blocksize_bits;
++ unsigned char s_dirt;
++ unsigned long long s_maxbytes; /* Max file size */
++ struct file_system_type *s_type;
++ struct super_operations *s_op;
++ struct dquot_operations *dq_op;
++ struct quotactl_ops *s_qcop;
++ unsigned long s_flags;
++ unsigned long s_magic;
++ struct dentry *s_root;
++ struct rw_semaphore s_umount;
++ struct semaphore s_lock;
++ int s_count;
++ atomic_t s_active;
++
++ struct list_head s_dirty; /* dirty inodes */
++ struct list_head s_locked_inodes;/* inodes being synced */
++ struct list_head s_files;
++
++ struct block_device *s_bdev;
++ struct list_head s_instances;
++ struct quota_info s_dquot; /* Diskquota specific options */
++
++ union {
++ struct minix_sb_info minix_sb;
++ struct ext2_sb_info ext2_sb;
++ struct ext3_sb_info ext3_sb;
++ struct hpfs_sb_info hpfs_sb;
++ struct ntfs_sb_info ntfs_sb;
++ struct msdos_sb_info msdos_sb;
++ struct isofs_sb_info isofs_sb;
++ struct nfs_sb_info nfs_sb;
++ struct sysv_sb_info sysv_sb;
++ struct affs_sb_info affs_sb;
++ struct ufs_sb_info ufs_sb;
++ struct efs_sb_info efs_sb;
++ struct shmem_sb_info shmem_sb;
++ struct romfs_sb_info romfs_sb;
++ struct smb_sb_info smbfs_sb;
++ struct hfs_sb_info hfs_sb;
++ struct adfs_sb_info adfs_sb;
++ struct qnx4_sb_info qnx4_sb;
++ struct reiserfs_sb_info reiserfs_sb;
++ struct bfs_sb_info bfs_sb;
++ struct udf_sb_info udf_sb;
++ struct ncp_sb_info ncpfs_sb;
++ struct usbdev_sb_info usbdevfs_sb;
++ struct jffs2_sb_info jffs2_sb;
++ struct cramfs_sb_info cramfs_sb;
++ void *generic_sbp;
++ } u;
++ /*
++ * The next field is for VFS *only*. No filesystems have any business
++ * even looking at it. You had been warned.
++ */
++ struct semaphore s_vfs_rename_sem; /* Kludge */
++
++ /* The next field is used by knfsd when converting a (inode number based)
++ * file handle into a dentry. As it builds a path in the dcache tree from
++ * the bottom up, there may for a time be a subpath of dentrys which is not
++ * connected to the main tree. This semaphore ensure that there is only ever
++ * one such free path per filesystem. Note that unconnected files (or other
++ * non-directories) are allowed, but not unconnected diretories.
++ */
++ struct semaphore s_nfsd_free_path_sem;
++};
++
++/*
++ * VFS helper functions..
++ */
++extern int vfs_create(struct inode *, struct dentry *, int);
++extern int vfs_mkdir(struct inode *, struct dentry *, int);
++extern int vfs_mknod(struct inode *, struct dentry *, int, dev_t);
++extern int vfs_symlink(struct inode *, struct dentry *, const char *);
++extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
++extern int vfs_rmdir(struct inode *, struct dentry *);
++extern int vfs_unlink(struct inode *, struct dentry *);
++extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
++
++/*
++ * File types
++ */
++#define DT_UNKNOWN 0
++#define DT_FIFO 1
++#define DT_CHR 2
++#define DT_DIR 4
++#define DT_BLK 6
++#define DT_REG 8
++#define DT_LNK 10
++#define DT_SOCK 12
++#define DT_WHT 14
++
++/*
++ * This is the "filldir" function type, used by readdir() to let
++ * the kernel specify what kind of dirent layout it wants to have.
++ * This allows the kernel to read directories into kernel space or
++ * to have different dirent layouts depending on the binary type.
++ */
++typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
++
++struct block_device_operations {
++ int (*open) (struct inode *, struct file *);
++ int (*release) (struct inode *, struct file *);
++ int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
++ int (*check_media_change) (kdev_t);
++ int (*revalidate) (kdev_t);
++ struct module *owner;
++};
++
++/*
++ * NOTE:
++ * read, write, poll, fsync, readv, writev can be called
++ * without the big kernel lock held in all filesystems.
++ */
++struct file_operations {
++ struct module *owner;
++ loff_t (*llseek) (struct file *, loff_t, int);
++ ssize_t (*read) (struct file *, char *, size_t, loff_t *);
++ ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
++ int (*readdir) (struct file *, void *, filldir_t);
++ unsigned int (*poll) (struct file *, struct poll_table_struct *);
++ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
++ int (*mmap) (struct file *, struct vm_area_struct *);
++ int (*open) (struct inode *, struct file *);
++ int (*flush) (struct file *);
++ int (*release) (struct inode *, struct file *);
++ int (*fsync) (struct file *, struct dentry *, int datasync);
++ int (*fasync) (int, struct file *, int);
++ int (*lock) (struct file *, int, struct file_lock *);
++ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
++ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
++ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
++ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
++};
++
++struct inode_operations {
++ int (*create) (struct inode *,struct dentry *,int);
++ struct dentry * (*lookup) (struct inode *,struct dentry *);
++ int (*link) (struct dentry *,struct inode *,struct dentry *);
++ int (*unlink) (struct inode *,struct dentry *);
++ int (*symlink) (struct inode *,struct dentry *,const char *);
++ int (*mkdir) (struct inode *,struct dentry *,int);
++ int (*rmdir) (struct inode *,struct dentry *);
++ int (*mknod) (struct inode *,struct dentry *,int,int);
++ int (*rename) (struct inode *, struct dentry *,
++ struct inode *, struct dentry *);
++ int (*readlink) (struct dentry *, char *,int);
++ int (*follow_link) (struct dentry *, struct nameidata *);
++ void (*truncate) (struct inode *);
++ int (*permission) (struct inode *, int);
++ int (*revalidate) (struct dentry *);
++ int (*setattr) (struct dentry *, struct iattr *);
++ int (*getattr) (struct dentry *, struct iattr *);
++ int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
++ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
++ ssize_t (*listxattr) (struct dentry *, char *, size_t);
++ int (*removexattr) (struct dentry *, const char *);
++};
++
++struct seq_file;
++
++/*
++ * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
++ * without the big kernel lock held in all filesystems.
++ */
++struct super_operations {
++ struct inode *(*alloc_inode)(struct super_block *sb);
++ void (*destroy_inode)(struct inode *);
++
++ void (*read_inode) (struct inode *);
++
++ /* reiserfs kludge. reiserfs needs 64 bits of information to
++ ** find an inode. We are using the read_inode2 call to get
++ ** that information. We don't like this, and are waiting on some
++ ** VFS changes for the real solution.
++ ** iget4 calls read_inode2, iff it is defined
++ */
++ void (*read_inode2) (struct inode *, void *) ;
++ void (*dirty_inode) (struct inode *);
++ void (*write_inode) (struct inode *, int);
++ void (*put_inode) (struct inode *);
++ void (*delete_inode) (struct inode *);
++ void (*put_super) (struct super_block *);
++ void (*write_super) (struct super_block *);
++ int (*sync_fs) (struct super_block *);
++ void (*write_super_lockfs) (struct super_block *);
++ void (*unlockfs) (struct super_block *);
++ int (*statfs) (struct super_block *, struct statfs *);
++ int (*remount_fs) (struct super_block *, int *, char *);
++ void (*clear_inode) (struct inode *);
++ void (*umount_begin) (struct super_block *);
++
++ /* Following are for knfsd to interact with "interesting" filesystems
++ * Currently just reiserfs, but possibly FAT and others later
++ *
++ * fh_to_dentry is given a filehandle fragement with length, and a type flag
++ * and must return a dentry for the referenced object or, if "parent" is
++ * set, a dentry for the parent of the object.
++ * If a dentry cannot be found, a "root" dentry should be created and
++ * flaged as DCACHE_NFSD_DISCONNECTED. nfsd_iget is an example implementation.
++ *
++ * dentry_to_fh is given a dentry and must generate the filesys specific
++ * part of the file handle. Available length is passed in *lenp and used
++ * length should be returned therein.
++ * If need_parent is set, then dentry_to_fh should encode sufficient information
++ * to find the (current) parent.
++ * dentry_to_fh should return a 1byte "type" which will be passed back in
++ * the fhtype arguement to fh_to_dentry. Type of 0 is reserved.
++ * If filesystem was exportable before the introduction of fh_to_dentry,
++ * types 1 and 2 should be used is that same way as the generic code.
++ * Type 255 means error.
++ *
++ * Lengths are in units of 4bytes, not bytes.
++ */
++ struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent);
++ int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent);
++ int (*show_options)(struct seq_file *, struct vfsmount *);
++};
++
++/* Inode state bits.. */
++#define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */
++#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
++#define I_DIRTY_PAGES 4 /* Data-related inode changes pending */
++#define I_LOCK 8
++#define I_FREEING 16
++#define I_CLEAR 32
++
++#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
++
++extern void __mark_inode_dirty(struct inode *, int);
++static inline void mark_inode_dirty(struct inode *inode)
++{
++ __mark_inode_dirty(inode, I_DIRTY);
++}
++
++static inline void mark_inode_dirty_sync(struct inode *inode)
++{
++ __mark_inode_dirty(inode, I_DIRTY_SYNC);
++}
++
++static inline void mark_inode_dirty_pages(struct inode *inode)
++{
++ __mark_inode_dirty(inode, I_DIRTY_PAGES);
++}
++
++struct file_system_type {
++ const char *name;
++ int fs_flags;
++ struct super_block *(*read_super) (struct super_block *, void *, int);
++ struct module *owner;
++ struct file_system_type * next;
++ struct list_head fs_supers;
++};
++
++#define DECLARE_FSTYPE(var,type,read,flags) \
++struct file_system_type var = { \
++ name: type, \
++ read_super: read, \
++ fs_flags: flags, \
++ owner: THIS_MODULE, \
++}
++
++#define DECLARE_FSTYPE_DEV(var,type,read) \
++ DECLARE_FSTYPE(var,type,read,FS_REQUIRES_DEV)
++
++/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
++#define fops_get(fops) \
++ (((fops) && (fops)->owner) \
++ ? ( try_inc_mod_count((fops)->owner) ? (fops) : NULL ) \
++ : (fops))
++
++#define fops_put(fops) \
++do { \
++ if ((fops) && (fops)->owner) \
++ __MOD_DEC_USE_COUNT((fops)->owner); \
++} while(0)
++
++extern int register_filesystem(struct file_system_type *);
++extern int unregister_filesystem(struct file_system_type *);
++extern struct vfsmount *kern_mount(struct file_system_type *);
++extern int may_umount(struct vfsmount *);
++struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
++extern long do_mount(char *, char *, char *, unsigned long, void *);
++
++#define kern_umount mntput
++
++extern int vfs_statfs(struct super_block *, struct statfs *);
++
++/* Return value for VFS lock functions - tells locks.c to lock conventionally
++ * REALLY kosha for root NFS and nfs_lock
++ */
++#define LOCK_USE_CLNT 1
++
++#define FLOCK_VERIFY_READ 1
++#define FLOCK_VERIFY_WRITE 2
++
++extern int locks_mandatory_locked(struct inode *);
++extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
++
++/*
++ * Candidates for mandatory locking have the setgid bit set
++ * but no group execute bit - an otherwise meaningless combination.
++ */
++#define MANDATORY_LOCK(inode) \
++ (IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
++
++static inline int locks_verify_locked(struct inode *inode)
++{
++ if (MANDATORY_LOCK(inode))
++ return locks_mandatory_locked(inode);
++ return 0;
++}
++
++static inline int locks_verify_area(int read_write, struct inode *inode,
++ struct file *filp, loff_t offset,
++ size_t count)
++{
++ if (inode->i_flock && MANDATORY_LOCK(inode))
++ return locks_mandatory_area(read_write, inode, filp, offset, count);
++ return 0;
++}
++
++static inline int locks_verify_truncate(struct inode *inode,
++ struct file *filp,
++ loff_t size)
++{
++ if (inode->i_flock && MANDATORY_LOCK(inode))
++ return locks_mandatory_area(
++ FLOCK_VERIFY_WRITE, inode, filp,
++ size < inode->i_size ? size : inode->i_size,
++ (size < inode->i_size ? inode->i_size - size
++ : size - inode->i_size)
++ );
++ return 0;
++}
++
++static inline int get_lease(struct inode *inode, unsigned int mode)
++{
++ if (inode->i_flock)
++ return __get_lease(inode, mode);
++ return 0;
++}
++
++/* fs/open.c */
++
++asmlinkage long sys_open(const char *, int, int);
++asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
++extern int do_truncate(struct dentry *, loff_t start);
++
++extern struct file *filp_open(const char *, int, int);
++extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
++extern int filp_close(struct file *, fl_owner_t id);
++extern char * getname(const char *);
++
++/* fs/dcache.c */
++extern void vfs_caches_init(unsigned long);
++
++#define __getname() kmem_cache_alloc(names_cachep, SLAB_KERNEL)
++#define putname(name) kmem_cache_free(names_cachep, (void *)(name))
++
++enum {BDEV_FILE, BDEV_SWAP, BDEV_FS, BDEV_RAW};
++extern int register_blkdev(unsigned int, const char *, struct block_device_operations *);
++extern int unregister_blkdev(unsigned int, const char *);
++extern struct block_device *bdget(dev_t);
++extern int bd_acquire(struct inode *inode);
++extern void bd_forget(struct inode *inode);
++extern void bdput(struct block_device *);
++extern struct char_device *cdget(dev_t);
++extern void cdput(struct char_device *);
++extern int blkdev_open(struct inode *, struct file *);
++extern int blkdev_close(struct inode *, struct file *);
++extern struct file_operations def_blk_fops;
++extern struct address_space_operations def_blk_aops;
++extern struct file_operations def_fifo_fops;
++extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
++extern int blkdev_get(struct block_device *, mode_t, unsigned, int);
++extern int blkdev_put(struct block_device *, int);
++
++/* fs/devices.c */
++extern const struct block_device_operations *get_blkfops(unsigned int);
++extern int register_chrdev(unsigned int, const char *, struct file_operations *);
++extern int unregister_chrdev(unsigned int, const char *);
++extern int chrdev_open(struct inode *, struct file *);
++extern const char * bdevname(kdev_t);
++extern const char * cdevname(kdev_t);
++extern const char * kdevname(kdev_t);
++extern void init_special_inode(struct inode *, umode_t, int);
++
++/* Invalid inode operations -- fs/bad_inode.c */
++extern void make_bad_inode(struct inode *);
++extern int is_bad_inode(struct inode *);
++
++extern struct file_operations read_fifo_fops;
++extern struct file_operations write_fifo_fops;
++extern struct file_operations rdwr_fifo_fops;
++extern struct file_operations read_pipe_fops;
++extern struct file_operations write_pipe_fops;
++extern struct file_operations rdwr_pipe_fops;
++
++extern int fs_may_remount_ro(struct super_block *);
++
++extern int FASTCALL(try_to_free_buffers(struct page *, unsigned int));
++extern void refile_buffer(struct buffer_head * buf);
++extern void create_empty_buffers(struct page *, kdev_t, unsigned long);
++extern void end_buffer_io_sync(struct buffer_head *bh, int uptodate);
++
++/* reiserfs_writepage needs this */
++extern void set_buffer_async_io(struct buffer_head *bh) ;
++
++#define BUF_CLEAN 0
++#define BUF_LOCKED 1 /* Buffers scheduled for write */
++#define BUF_DIRTY 2 /* Dirty buffers, not yet scheduled for write */
++#define NR_LIST 3
++
++static inline void get_bh(struct buffer_head * bh)
++{
++ atomic_inc(&(bh)->b_count);
++}
++
++static inline void put_bh(struct buffer_head *bh)
++{
++ smp_mb__before_atomic_dec();
++ atomic_dec(&bh->b_count);
++}
++
++/*
++ * This is called by bh->b_end_io() handlers when I/O has completed.
++ */
++static inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
++{
++ if (on)
++ set_bit(BH_Uptodate, &bh->b_state);
++ else
++ clear_bit(BH_Uptodate, &bh->b_state);
++}
++
++#define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
++
++static inline void __mark_buffer_clean(struct buffer_head *bh)
++{
++ refile_buffer(bh);
++}
++
++static inline void mark_buffer_clean(struct buffer_head * bh)
++{
++ if (atomic_set_buffer_clean(bh))
++ __mark_buffer_clean(bh);
++}
++
++extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
++extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
++extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
++
++extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
++
++static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
++{
++ buffer_insert_list(bh, &inode->i_dirty_buffers);
++}
++
++static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
++{
++ buffer_insert_list(bh, &inode->i_dirty_data_buffers);
++}
++
++static inline int atomic_set_buffer_dirty(struct buffer_head *bh)
++{
++ return test_and_set_bit(BH_Dirty, &bh->b_state);
++}
++
++static inline void mark_buffer_async(struct buffer_head * bh, int on)
++{
++ if (on)
++ set_bit(BH_Async, &bh->b_state);
++ else
++ clear_bit(BH_Async, &bh->b_state);
++}
++
++static inline void set_buffer_attached(struct buffer_head *bh)
++{
++ set_bit(BH_Attached, &bh->b_state);
++}
++
++static inline void clear_buffer_attached(struct buffer_head *bh)
++{
++ clear_bit(BH_Attached, &bh->b_state);
++}
++
++static inline int buffer_attached(struct buffer_head *bh)
++{
++ return test_bit(BH_Attached, &bh->b_state);
++}
++
++/*
++ * If an error happens during the make_request, this function
++ * has to be recalled. It marks the buffer as clean and not
++ * uptodate, and it notifys the upper layer about the end
++ * of the I/O.
++ */
++static inline void buffer_IO_error(struct buffer_head * bh)
++{
++ mark_buffer_clean(bh);
++ /*
++ * b_end_io has to clear the BH_Uptodate bitflag in the error case!
++ */
++ bh->b_end_io(bh, 0);
++}
++
++static inline void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
++{
++ mark_buffer_dirty(bh);
++ buffer_insert_inode_queue(bh, inode);
++}
++
++extern void set_buffer_flushtime(struct buffer_head *);
++extern void balance_dirty(void);
++extern int check_disk_change(kdev_t);
++extern int invalidate_inodes(struct super_block *);
++extern int invalidate_device(kdev_t, int);
++extern void invalidate_inode_pages(struct inode *);
++extern void invalidate_inode_pages2(struct address_space *);
++extern void invalidate_inode_buffers(struct inode *);
++#define invalidate_buffers(dev) __invalidate_buffers((dev), 0)
++#define destroy_buffers(dev) __invalidate_buffers((dev), 1)
++extern void invalidate_bdev(struct block_device *, int);
++extern void __invalidate_buffers(kdev_t dev, int);
++extern void sync_inodes(kdev_t);
++extern void sync_unlocked_inodes(void);
++extern void write_inode_now(struct inode *, int);
++extern int sync_buffers(kdev_t, int);
++extern void sync_dev(kdev_t);
++extern int fsync_dev(kdev_t);
++extern int fsync_dev_lockfs(kdev_t);
++extern int fsync_super(struct super_block *);
++extern int fsync_no_super(kdev_t);
++extern void sync_inodes_sb(struct super_block *);
++extern int fsync_buffers_list(struct list_head *);
++static inline int fsync_inode_buffers(struct inode *inode)
++{
++ return fsync_buffers_list(&inode->i_dirty_buffers);
++}
++static inline int fsync_inode_data_buffers(struct inode *inode)
++{
++ return fsync_buffers_list(&inode->i_dirty_data_buffers);
++}
++extern int inode_has_buffers(struct inode *);
++extern int filemap_fdatasync(struct address_space *);
++extern int filemap_fdatawait(struct address_space *);
++extern void sync_supers(kdev_t dev, int wait);
++extern void sync_supers_lockfs(kdev_t);
++extern void unlockfs(kdev_t);
++extern int bmap(struct inode *, int);
++extern int notify_change(struct dentry *, struct iattr *);
++extern int permission(struct inode *, int);
++extern int vfs_permission(struct inode *, int);
++extern int get_write_access(struct inode *);
++extern int deny_write_access(struct file *);
++static inline void put_write_access(struct inode * inode)
++{
++ atomic_dec(&inode->i_writecount);
++}
++static inline void allow_write_access(struct file *file)
++{
++ if (file)
++ atomic_inc(&file->f_dentry->d_inode->i_writecount);
++}
++extern int do_pipe(int *);
++
++extern int open_namei(const char *, int, int, struct nameidata *);
++
++extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
++extern struct file * open_exec(const char *);
++
++/* fs/dcache.c -- generic fs support functions */
++extern int is_subdir(struct dentry *, struct dentry *);
++extern ino_t find_inode_number(struct dentry *, struct qstr *);
++
++/*
++ * Kernel pointers have redundant information, so we can use a
++ * scheme where we can return either an error code or a dentry
++ * pointer with the same return value.
++ *
++ * This should be a per-architecture thing, to allow different
++ * error and pointer decisions.
++ */
++static inline void *ERR_PTR(long error)
++{
++ return (void *) error;
++}
++
++static inline long PTR_ERR(const void *ptr)
++{
++ return (long) ptr;
++}
++
++static inline long IS_ERR(const void *ptr)
++{
++ return (unsigned long)ptr > (unsigned long)-1000L;
++}
++
++/*
++ * The bitmask for a lookup event:
++ * - follow links at the end
++ * - require a directory
++ * - ending slashes ok even for nonexistent files
++ * - internal "there are more path compnents" flag
++ */
++#define LOOKUP_FOLLOW (1)
++#define LOOKUP_DIRECTORY (2)
++#define LOOKUP_CONTINUE (4)
++#define LOOKUP_POSITIVE (8)
++#define LOOKUP_PARENT (16)
++#define LOOKUP_NOALT (32)
++#define LOOKUP_ATOMIC (64)
++/*
++ * Type of the last component on LOOKUP_PARENT
++ */
++enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
++
++/*
++ * "descriptor" for what we're up to with a read for sendfile().
++ * This allows us to use the same read code yet
++ * have multiple different users of the data that
++ * we read from a file.
++ *
++ * The simplest case just copies the data to user
++ * mode.
++ */
++typedef struct {
++ size_t written;
++ size_t count;
++ char * buf;
++ int error;
++} read_descriptor_t;
++
++typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
++
++/* needed for stackable file system support */
++extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
++
++extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
++extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
++extern int FASTCALL(path_walk(const char *, struct nameidata *));
++extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
++extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
++extern void path_release(struct nameidata *);
++extern int follow_down(struct vfsmount **, struct dentry **);
++extern int follow_up(struct vfsmount **, struct dentry **);
++extern struct dentry * lookup_one_len(const char *, struct dentry *, int);
++extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
++#define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
++#define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
++
++extern void inode_init_once(struct inode *);
++extern void iput(struct inode *);
++extern void force_delete(struct inode *);
++extern struct inode * igrab(struct inode *);
++extern ino_t iunique(struct super_block *, ino_t);
++
++typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
++extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
++static inline struct inode *iget(struct super_block *sb, unsigned long ino)
++{
++ return iget4(sb, ino, NULL, NULL);
++}
++
++extern void clear_inode(struct inode *);
++extern struct inode *new_inode(struct super_block *sb);
++extern void remove_suid(struct inode *inode);
++
++extern void insert_inode_hash(struct inode *);
++extern void remove_inode_hash(struct inode *);
++extern struct file * get_empty_filp(void);
++extern void file_move(struct file *f, struct list_head *list);
++extern struct buffer_head * get_hash_table(kdev_t, int, int);
++extern struct buffer_head * getblk(kdev_t, int, int);
++extern void ll_rw_block(int, int, struct buffer_head * bh[]);
++extern void submit_bh(int, struct buffer_head *);
++extern int is_read_only(kdev_t);
++extern void __brelse(struct buffer_head *);
++static inline void brelse(struct buffer_head *buf)
++{
++ if (buf)
++ __brelse(buf);
++}
++extern void __bforget(struct buffer_head *);
++static inline void bforget(struct buffer_head *buf)
++{
++ if (buf)
++ __bforget(buf);
++}
++extern int set_blocksize(kdev_t, int);
++extern int sb_set_blocksize(struct super_block *, int);
++extern int sb_min_blocksize(struct super_block *, int);
++extern struct buffer_head * bread(kdev_t, int, int);
++static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
++{
++ return bread(sb->s_dev, block, sb->s_blocksize);
++}
++static inline struct buffer_head * sb_getblk(struct super_block *sb, int block)
++{
++ return getblk(sb->s_dev, block, sb->s_blocksize);
++}
++static inline struct buffer_head * sb_get_hash_table(struct super_block *sb, int block)
++{
++ return get_hash_table(sb->s_dev, block, sb->s_blocksize);
++}
++extern void wakeup_bdflush(void);
++extern void put_unused_buffer_head(struct buffer_head * bh);
++extern struct buffer_head * get_unused_buffer_head(int async);
++
++extern int brw_page(int, struct page *, kdev_t, int [], int);
++
++typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int);
++
++/* Generic buffer handling for block filesystems.. */
++extern int try_to_release_page(struct page * page, int gfp_mask);
++extern int discard_bh_page(struct page *, unsigned long, int);
++#define block_flushpage(page, offset) discard_bh_page(page, offset, 1)
++#define block_invalidate_page(page) discard_bh_page(page, 0, 0)
++extern int block_symlink(struct inode *, const char *, int);
++extern int block_write_full_page(struct page*, get_block_t*);
++extern int block_read_full_page(struct page*, get_block_t*);
++extern int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
++extern int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
++ unsigned long *);
++extern int generic_cont_expand(struct inode *inode, loff_t size) ;
++extern int block_commit_write(struct page *page, unsigned from, unsigned to);
++extern int block_sync_page(struct page *);
++
++int generic_block_bmap(struct address_space *, long, get_block_t *);
++int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
++int block_truncate_page(struct address_space *, loff_t, get_block_t *);
++extern int generic_direct_IO(int, struct inode *, struct kiobuf *, unsigned long, int, get_block_t *);
++extern int waitfor_one_page(struct page *);
++extern int writeout_one_page(struct page *);
++
++extern int generic_file_mmap(struct file *, struct vm_area_struct *);
++extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
++extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
++extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
++extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t, int);
++extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
++extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
++extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
++extern int generic_file_open(struct inode * inode, struct file * filp);
++
++extern struct file_operations generic_ro_fops;
++
++extern int vfs_readlink(struct dentry *, char *, int, const char *);
++extern int vfs_follow_link(struct nameidata *, const char *);
++extern int page_readlink(struct dentry *, char *, int);
++extern int page_follow_link(struct dentry *, struct nameidata *);
++extern struct inode_operations page_symlink_inode_operations;
++
++extern int vfs_readdir(struct file *, filldir_t, void *);
++extern int dcache_dir_open(struct inode *, struct file *);
++extern int dcache_dir_close(struct inode *, struct file *);
++extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
++extern int dcache_dir_fsync(struct file *, struct dentry *, int);
++extern int dcache_readdir(struct file *, void *, filldir_t);
++extern struct file_operations dcache_dir_ops;
++
++extern int vfs_stat(char *, struct kstat *);
++extern int vfs_lstat(char *, struct kstat *);
++extern int vfs_fstat(unsigned int, struct kstat *);
++
++extern struct file_system_type *get_fs_type(const char *name);
++extern struct super_block *get_super(kdev_t);
++extern void drop_super(struct super_block *sb);
++static inline int is_mounted(kdev_t dev)
++{
++ struct super_block *sb = get_super(dev);
++ if (sb) {
++ drop_super(sb);
++ return 1;
++ }
++ return 0;
++}
++extern kdev_t ROOT_DEV;
++extern char root_device_name[];
++
++
++extern void show_buffers(void);
++
++#ifdef CONFIG_BLK_DEV_INITRD
++extern unsigned int real_root_dev;
++#endif
++
++extern ssize_t char_read(struct file *, char *, size_t, loff_t *);
++extern ssize_t block_read(struct file *, char *, size_t, loff_t *);
++extern int read_ahead[];
++
++extern ssize_t char_write(struct file *, const char *, size_t, loff_t *);
++extern ssize_t block_write(struct file *, const char *, size_t, loff_t *);
++
++extern int file_fsync(struct file *, struct dentry *, int);
++extern int generic_buffer_fdatasync(struct inode *inode, unsigned long start_idx, unsigned long end_idx);
++extern int generic_osync_inode(struct inode *, int);
++#define OSYNC_METADATA (1<<0)
++#define OSYNC_DATA (1<<1)
++#define OSYNC_INODE (1<<2)
++
++extern int inode_change_ok(struct inode *, struct iattr *);
++extern int inode_setattr(struct inode *, struct iattr *);
++
++/*
++ * Common dentry functions for inclusion in the VFS
++ * or in other stackable file systems. Some of these
++ * functions were in linux/fs/ C (VFS) files.
++ *
++ */
++
++/*
++ * Locking the parent is needed to:
++ * - serialize directory operations
++ * - make sure the parent doesn't change from
++ * under us in the middle of an operation.
++ *
++ * NOTE! Right now we'd rather use a "struct inode"
++ * for this, but as I expect things to move toward
++ * using dentries instead for most things it is
++ * probably better to start with the conceptually
++ * better interface of relying on a path of dentries.
++ */
++static inline struct dentry *lock_parent(struct dentry *dentry)
++{
++ struct dentry *dir = dget(dentry->d_parent);
++
++ down(&dir->d_inode->i_sem);
++ return dir;
++}
++
++static inline struct dentry *get_parent(struct dentry *dentry)
++{
++ return dget(dentry->d_parent);
++}
++
++static inline void unlock_dir(struct dentry *dir)
++{
++ up(&dir->d_inode->i_sem);
++ dput(dir);
++}
++
++/*
++ * Whee.. Deadlock country. Happily there are only two VFS
++ * operations that does this..
++ */
++static inline void double_down(struct semaphore *s1, struct semaphore *s2)
++{
++ if (s1 != s2) {
++ if ((unsigned long) s1 < (unsigned long) s2) {
++ struct semaphore *tmp = s2;
++ s2 = s1; s1 = tmp;
++ }
++ down(s1);
++ }
++ down(s2);
++}
++
++/*
++ * Ewwwwwwww... _triple_ lock. We are guaranteed that the 3rd argument is
++ * not equal to 1st and not equal to 2nd - the first case (target is parent of
++ * source) would be already caught, the second is plain impossible (target is
++ * its own parent and that case would be caught even earlier). Very messy.
++ * I _think_ that it works, but no warranties - please, look it through.
++ * Pox on bloody lusers who mandated overwriting rename() for directories...
++ */
++
++static inline void triple_down(struct semaphore *s1,
++ struct semaphore *s2,
++ struct semaphore *s3)
++{
++ if (s1 != s2) {
++ if ((unsigned long) s1 < (unsigned long) s2) {
++ if ((unsigned long) s1 < (unsigned long) s3) {
++ struct semaphore *tmp = s3;
++ s3 = s1; s1 = tmp;
++ }
++ if ((unsigned long) s1 < (unsigned long) s2) {
++ struct semaphore *tmp = s2;
++ s2 = s1; s1 = tmp;
++ }
++ } else {
++ if ((unsigned long) s1 < (unsigned long) s3) {
++ struct semaphore *tmp = s3;
++ s3 = s1; s1 = tmp;
++ }
++ if ((unsigned long) s2 < (unsigned long) s3) {
++ struct semaphore *tmp = s3;
++ s3 = s2; s2 = tmp;
++ }
++ }
++ down(s1);
++ } else if ((unsigned long) s2 < (unsigned long) s3) {
++ struct semaphore *tmp = s3;
++ s3 = s2; s2 = tmp;
++ }
++ down(s2);
++ down(s3);
++}
++
++static inline void double_up(struct semaphore *s1, struct semaphore *s2)
++{
++ up(s1);
++ if (s1 != s2)
++ up(s2);
++}
++
++static inline void triple_up(struct semaphore *s1,
++ struct semaphore *s2,
++ struct semaphore *s3)
++{
++ up(s1);
++ if (s1 != s2)
++ up(s2);
++ up(s3);
++}
++
++static inline void double_lock(struct dentry *d1, struct dentry *d2)
++{
++ double_down(&d1->d_inode->i_sem, &d2->d_inode->i_sem);
++}
++
++static inline void double_unlock(struct dentry *d1, struct dentry *d2)
++{
++ double_up(&d1->d_inode->i_sem,&d2->d_inode->i_sem);
++ dput(d1);
++ dput(d2);
++}
++
++#endif /* __KERNEL__ */
++
++#endif /* _LINUX_FS_H */
+--- /dev/null Fri Aug 30 17:31:37 2002
++++ linux-rh-2.4.20-6-braam/kernel/ksyms.c Mon Mar 31 23:43:55 2003
+@@ -0,0 +1,632 @@
++/*
++ * Herein lies all the functions/variables that are "exported" for linkage
++ * with dynamically loaded kernel modules.
++ * Jon.
++ *
++ * - Stacked module support and unified symbol table added (June 1994)
++ * - External symbol table support added (December 1994)
++ * - Versions on symbols added (December 1994)
++ * by Bjorn Ekwall <bj0rn@blox.se>
++ */
++
++#define __KERNEL_SYSCALLS__
++#include <linux/config.h>
++#include <linux/slab.h>
++#include <linux/smp.h>
++#include <linux/module.h>
++#include <linux/blkdev.h>
++#include <linux/cdrom.h>
++#include <linux/kernel_stat.h>
++#include <linux/vmalloc.h>
++#include <linux/sys.h>
++#include <linux/utsname.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/serial.h>
++#include <linux/locks.h>
++#include <linux/delay.h>
++#include <linux/random.h>
++#include <linux/reboot.h>
++#include <linux/pagemap.h>
++#include <linux/sysctl.h>
++#include <linux/hdreg.h>
++#include <linux/skbuff.h>
++#include <linux/genhd.h>
++#include <linux/blkpg.h>
++#include <linux/swap.h>
++#include <linux/ctype.h>
++#include <linux/file.h>
++#include <linux/iobuf.h>
++#include <linux/console.h>
++#include <linux/poll.h>
++#include <linux/mmzone.h>
++#include <linux/mm.h>
++#include <linux/capability.h>
++#include <linux/highuid.h>
++#include <linux/brlock.h>
++#include <linux/fs.h>
++#include <linux/tty.h>
++#include <linux/in6.h>
++#include <linux/completion.h>
++#include <linux/seq_file.h>
++#include <linux/dnotify.h>
++#include <asm/checksum.h>
++#include <linux/unistd.h>
++
++
++#if defined(CONFIG_PROC_FS)
++#include <linux/proc_fs.h>
++#endif
++#ifdef CONFIG_KMOD
++#include <linux/kmod.h>
++#endif
++#ifdef CONFIG_KALLSYMS
++#include <linux/kallsyms.h>
++#endif
++
++extern void set_device_ro(kdev_t dev,int flag);
++
++extern void *sys_call_table;
++
++extern struct timezone sys_tz;
++extern int request_dma(unsigned int dmanr, char * deviceID);
++extern void free_dma(unsigned int dmanr);
++extern spinlock_t dma_spin_lock;
++extern int panic_timeout;
++
++
++#ifdef CONFIG_MODVERSIONS
++const struct module_symbol __export_Using_Versions
++__attribute__((section("__ksymtab"))) = {
++ 1 /* Version version */, "Using_Versions"
++};
++#endif
++
++
++EXPORT_SYMBOL(inter_module_register);
++EXPORT_SYMBOL(inter_module_unregister);
++EXPORT_SYMBOL(inter_module_get);
++EXPORT_SYMBOL(inter_module_get_request);
++EXPORT_SYMBOL(inter_module_put);
++EXPORT_SYMBOL(try_inc_mod_count);
++
++#ifdef CONFIG_KALLSYMS
++extern const char __start___kallsyms[];
++extern const char __stop___kallsyms[];
++EXPORT_SYMBOL(__start___kallsyms);
++EXPORT_SYMBOL(__stop___kallsyms);
++
++
++#endif
++
++/* process memory management */
++EXPORT_SYMBOL(do_mmap_pgoff);
++EXPORT_SYMBOL(do_munmap);
++EXPORT_SYMBOL(do_brk);
++EXPORT_SYMBOL(exit_mm);
++EXPORT_SYMBOL(exit_files);
++EXPORT_SYMBOL(exit_fs);
++EXPORT_SYMBOL(exit_sighand);
++
++/* internal kernel memory management */
++EXPORT_SYMBOL(_alloc_pages);
++EXPORT_SYMBOL(__alloc_pages);
++EXPORT_SYMBOL(alloc_pages_node);
++EXPORT_SYMBOL(__get_free_pages);
++EXPORT_SYMBOL(get_zeroed_page);
++EXPORT_SYMBOL(__free_pages);
++EXPORT_SYMBOL(free_pages);
++EXPORT_SYMBOL(num_physpages);
++EXPORT_SYMBOL(kmem_find_general_cachep);
++EXPORT_SYMBOL(kmem_cache_create);
++EXPORT_SYMBOL(kmem_cache_destroy);
++EXPORT_SYMBOL(kmem_cache_shrink);
++EXPORT_SYMBOL(kmem_cache_alloc);
++EXPORT_SYMBOL(kmem_cache_free);
++EXPORT_SYMBOL(kmem_cache_size);
++EXPORT_SYMBOL(kmalloc);
++EXPORT_SYMBOL(kfree);
++EXPORT_SYMBOL(vfree);
++EXPORT_SYMBOL(__vmalloc);
++EXPORT_SYMBOL(vmalloc_to_page);
++EXPORT_SYMBOL(mem_map);
++EXPORT_SYMBOL(remap_page_range);
++EXPORT_SYMBOL(max_mapnr);
++EXPORT_SYMBOL(high_memory);
++EXPORT_SYMBOL(vmtruncate);
++EXPORT_SYMBOL(find_vma);
++EXPORT_SYMBOL(get_unmapped_area);
++EXPORT_SYMBOL(init_mm);
++#ifdef CONFIG_HIGHMEM
++EXPORT_SYMBOL(kmap_high);
++EXPORT_SYMBOL(kunmap_high);
++EXPORT_SYMBOL(highmem_start_page);
++EXPORT_SYMBOL(create_bounce);
++EXPORT_SYMBOL(kmap_prot);
++EXPORT_SYMBOL(kmap_pte);
++#endif
++
++/* filesystem internal functions */
++EXPORT_SYMBOL(def_blk_fops);
++EXPORT_SYMBOL(update_atime);
++EXPORT_SYMBOL(get_fs_type);
++EXPORT_SYMBOL(get_super);
++EXPORT_SYMBOL(drop_super);
++EXPORT_SYMBOL(getname);
++EXPORT_SYMBOL(names_cachep);
++EXPORT_SYMBOL(fput);
++EXPORT_SYMBOL(fget);
++EXPORT_SYMBOL(igrab);
++EXPORT_SYMBOL(iunique);
++EXPORT_SYMBOL(iget4);
++EXPORT_SYMBOL(iput);
++EXPORT_SYMBOL(inode_init_once);
++EXPORT_SYMBOL(force_delete);
++EXPORT_SYMBOL(follow_up);
++EXPORT_SYMBOL(follow_down);
++EXPORT_SYMBOL(lookup_mnt);
++EXPORT_SYMBOL(path_init);
++EXPORT_SYMBOL(path_walk);
++EXPORT_SYMBOL(path_release);
++EXPORT_SYMBOL(__user_walk);
++EXPORT_SYMBOL(lookup_one_len);
++EXPORT_SYMBOL(lookup_hash);
++EXPORT_SYMBOL(sys_close);
++EXPORT_SYMBOL(sys_read);
++EXPORT_SYMBOL(sys_write);
++EXPORT_SYMBOL(sys_dup);
++EXPORT_SYMBOL(sys_chroot);
++EXPORT_SYMBOL(sys_chdir);
++EXPORT_SYMBOL(sys_fcntl);
++EXPORT_SYMBOL(do_pipe);
++EXPORT_SYMBOL(dcache_lock);
++EXPORT_SYMBOL(d_alloc_root);
++EXPORT_SYMBOL(d_delete);
++EXPORT_SYMBOL(dget_locked);
++EXPORT_SYMBOL(d_validate);
++EXPORT_SYMBOL(d_rehash);
++EXPORT_SYMBOL(d_invalidate); /* May be it will be better in dcache.h? */
++EXPORT_SYMBOL(d_move);
++EXPORT_SYMBOL(d_instantiate);
++EXPORT_SYMBOL(d_alloc);
++EXPORT_SYMBOL(d_lookup);
++EXPORT_SYMBOL(__d_path);
++EXPORT_SYMBOL(mark_buffer_dirty);
++EXPORT_SYMBOL(set_buffer_async_io); /* for reiserfs_writepage */
++EXPORT_SYMBOL(__mark_buffer_dirty);
++EXPORT_SYMBOL(__mark_inode_dirty);
++EXPORT_SYMBOL(fd_install);
++EXPORT_SYMBOL(get_empty_filp);
++EXPORT_SYMBOL(init_private_file);
++EXPORT_SYMBOL(filp_open);
++EXPORT_SYMBOL(filp_close);
++EXPORT_SYMBOL(put_filp);
++EXPORT_SYMBOL(files_lock);
++EXPORT_SYMBOL(check_disk_change);
++EXPORT_SYMBOL(__invalidate_buffers);
++EXPORT_SYMBOL(invalidate_bdev);
++EXPORT_SYMBOL(invalidate_inodes);
++EXPORT_SYMBOL(invalidate_device);
++EXPORT_SYMBOL(invalidate_inode_pages);
++EXPORT_SYMBOL(truncate_inode_pages);
++EXPORT_SYMBOL(fsync_dev);
++EXPORT_SYMBOL_GPL(fsync_dev_lockfs);
++EXPORT_SYMBOL_GPL(unlockfs);
++EXPORT_SYMBOL(fsync_no_super);
++EXPORT_SYMBOL(permission);
++EXPORT_SYMBOL(vfs_permission);
++EXPORT_SYMBOL(inode_setattr);
++EXPORT_SYMBOL(inode_change_ok);
++EXPORT_SYMBOL(write_inode_now);
++EXPORT_SYMBOL(notify_change);
++EXPORT_SYMBOL(set_blocksize);
++EXPORT_SYMBOL(sb_set_blocksize);
++EXPORT_SYMBOL(sb_min_blocksize);
++EXPORT_SYMBOL(getblk);
++EXPORT_SYMBOL(cdget);
++EXPORT_SYMBOL(cdput);
++EXPORT_SYMBOL(bdget);
++EXPORT_SYMBOL(bdput);
++EXPORT_SYMBOL(bread);
++EXPORT_SYMBOL(__brelse);
++EXPORT_SYMBOL(__bforget);
++EXPORT_SYMBOL(ll_rw_block);
++EXPORT_SYMBOL(submit_bh);
++EXPORT_SYMBOL(unlock_buffer);
++EXPORT_SYMBOL(__wait_on_buffer);
++EXPORT_SYMBOL(___wait_on_page);
++EXPORT_SYMBOL(generic_direct_IO);
++EXPORT_SYMBOL(discard_bh_page);
++EXPORT_SYMBOL(block_write_full_page);
++EXPORT_SYMBOL(block_read_full_page);
++EXPORT_SYMBOL(block_prepare_write);
++EXPORT_SYMBOL(block_sync_page);
++EXPORT_SYMBOL(generic_cont_expand);
++EXPORT_SYMBOL(cont_prepare_write);
++EXPORT_SYMBOL(generic_commit_write);
++EXPORT_SYMBOL(block_truncate_page);
++EXPORT_SYMBOL(generic_block_bmap);
++EXPORT_SYMBOL(generic_file_read);
++EXPORT_SYMBOL(do_generic_file_read);
++EXPORT_SYMBOL(generic_file_write);
++EXPORT_SYMBOL(generic_file_mmap);
++EXPORT_SYMBOL(generic_ro_fops);
++EXPORT_SYMBOL(generic_buffer_fdatasync);
++EXPORT_SYMBOL(page_hash_bits);
++EXPORT_SYMBOL(page_hash_table);
++EXPORT_SYMBOL(file_lock_list);
++EXPORT_SYMBOL(locks_init_lock);
++EXPORT_SYMBOL(locks_copy_lock);
++EXPORT_SYMBOL(posix_lock_file);
++EXPORT_SYMBOL(posix_test_lock);
++EXPORT_SYMBOL(posix_block_lock);
++EXPORT_SYMBOL(posix_unblock_lock);
++EXPORT_SYMBOL(posix_locks_deadlock);
++EXPORT_SYMBOL(locks_mandatory_area);
++EXPORT_SYMBOL(dput);
++EXPORT_SYMBOL(have_submounts);
++EXPORT_SYMBOL(d_find_alias);
++EXPORT_SYMBOL(d_prune_aliases);
++EXPORT_SYMBOL(prune_dcache);
++EXPORT_SYMBOL(shrink_dcache_sb);
++EXPORT_SYMBOL(shrink_dcache_parent);
++EXPORT_SYMBOL_GPL(flush_dentry_attributes);
++EXPORT_SYMBOL(find_inode_number);
++EXPORT_SYMBOL(is_subdir);
++EXPORT_SYMBOL(get_unused_fd);
++EXPORT_SYMBOL(vfs_create);
++EXPORT_SYMBOL(vfs_mkdir);
++EXPORT_SYMBOL(vfs_mknod);
++EXPORT_SYMBOL(vfs_symlink);
++EXPORT_SYMBOL(vfs_link);
++EXPORT_SYMBOL(vfs_rmdir);
++EXPORT_SYMBOL(vfs_unlink);
++EXPORT_SYMBOL(vfs_rename);
++EXPORT_SYMBOL(vfs_statfs);
++EXPORT_SYMBOL(generic_read_dir);
++EXPORT_SYMBOL(generic_file_llseek);
++EXPORT_SYMBOL(no_llseek);
++EXPORT_SYMBOL(__pollwait);
++EXPORT_SYMBOL(poll_freewait);
++EXPORT_SYMBOL(ROOT_DEV);
++EXPORT_SYMBOL(__find_get_page);
++EXPORT_SYMBOL(__find_lock_page);
++EXPORT_SYMBOL(find_or_create_page);
++EXPORT_SYMBOL(grab_cache_page_nowait);
++EXPORT_SYMBOL(read_cache_page);
++EXPORT_SYMBOL(set_page_dirty);
++EXPORT_SYMBOL(vfs_readlink);
++EXPORT_SYMBOL(vfs_follow_link);
++EXPORT_SYMBOL(page_readlink);
++EXPORT_SYMBOL(page_follow_link);
++EXPORT_SYMBOL(page_symlink_inode_operations);
++EXPORT_SYMBOL(block_symlink);
++EXPORT_SYMBOL(vfs_readdir);
++EXPORT_SYMBOL(__get_lease);
++EXPORT_SYMBOL(lease_get_mtime);
++EXPORT_SYMBOL(lock_may_read);
++EXPORT_SYMBOL(lock_may_write);
++EXPORT_SYMBOL(dcache_dir_open);
++EXPORT_SYMBOL(dcache_dir_close);
++EXPORT_SYMBOL(dcache_dir_lseek);
++EXPORT_SYMBOL(dcache_dir_fsync);
++EXPORT_SYMBOL(dcache_readdir);
++EXPORT_SYMBOL(dcache_dir_ops);
++
++/* lustre */
++EXPORT_SYMBOL(panic_notifier_list);
++EXPORT_SYMBOL(pagecache_lock_cacheline);
++EXPORT_SYMBOL(do_kern_mount);
++
++/* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */
++EXPORT_SYMBOL(default_llseek);
++EXPORT_SYMBOL(dentry_open);
++EXPORT_SYMBOL(filemap_nopage);
++EXPORT_SYMBOL(filemap_sync);
++EXPORT_SYMBOL(filemap_fdatasync);
++EXPORT_SYMBOL(filemap_fdatawait);
++EXPORT_SYMBOL(lock_page);
++EXPORT_SYMBOL(unlock_page);
++EXPORT_SYMBOL_GPL(wakeup_page_waiters);
++
++/* device registration */
++EXPORT_SYMBOL(register_chrdev);
++EXPORT_SYMBOL(unregister_chrdev);
++EXPORT_SYMBOL(register_blkdev);
++EXPORT_SYMBOL(unregister_blkdev);
++EXPORT_SYMBOL(tty_register_driver);
++EXPORT_SYMBOL(tty_unregister_driver);
++EXPORT_SYMBOL(tty_std_termios);
++
++/* block device driver support */
++EXPORT_SYMBOL(blksize_size);
++EXPORT_SYMBOL(hardsect_size);
++EXPORT_SYMBOL(blk_size);
++EXPORT_SYMBOL(blk_dev);
++EXPORT_SYMBOL(is_read_only);
++EXPORT_SYMBOL(set_device_ro);
++EXPORT_SYMBOL(bmap);
++EXPORT_SYMBOL(sync_dev);
++EXPORT_SYMBOL(devfs_register_partitions);
++EXPORT_SYMBOL(blkdev_open);
++EXPORT_SYMBOL(blkdev_get);
++EXPORT_SYMBOL(blkdev_put);
++EXPORT_SYMBOL(ioctl_by_bdev);
++EXPORT_SYMBOL(grok_partitions);
++EXPORT_SYMBOL(register_disk);
++EXPORT_SYMBOL(tq_disk);
++EXPORT_SYMBOL(init_buffer);
++EXPORT_SYMBOL(refile_buffer);
++EXPORT_SYMBOL(max_sectors);
++EXPORT_SYMBOL(max_readahead);
++
++/* tty routines */
++EXPORT_SYMBOL(tty_hangup);
++EXPORT_SYMBOL(tty_wait_until_sent);
++EXPORT_SYMBOL(tty_check_change);
++EXPORT_SYMBOL(tty_hung_up_p);
++EXPORT_SYMBOL(tty_flip_buffer_push);
++EXPORT_SYMBOL(tty_get_baud_rate);
++EXPORT_SYMBOL(do_SAK);
++
++/* filesystem registration */
++EXPORT_SYMBOL(register_filesystem);
++EXPORT_SYMBOL(unregister_filesystem);
++EXPORT_SYMBOL(kern_mount);
++EXPORT_SYMBOL(__mntput);
++EXPORT_SYMBOL(may_umount);
++
++/* executable format registration */
++EXPORT_SYMBOL(register_binfmt);
++EXPORT_SYMBOL(unregister_binfmt);
++EXPORT_SYMBOL(search_binary_handler);
++EXPORT_SYMBOL(prepare_binprm);
++EXPORT_SYMBOL(compute_creds);
++EXPORT_SYMBOL(remove_arg_zero);
++EXPORT_SYMBOL(set_binfmt);
++
++/* sysctl table registration */
++EXPORT_SYMBOL(register_sysctl_table);
++EXPORT_SYMBOL(unregister_sysctl_table);
++EXPORT_SYMBOL(sysctl_string);
++EXPORT_SYMBOL(sysctl_intvec);
++EXPORT_SYMBOL(sysctl_jiffies);
++EXPORT_SYMBOL(proc_dostring);
++EXPORT_SYMBOL(proc_dointvec);
++EXPORT_SYMBOL(proc_dointvec_jiffies);
++EXPORT_SYMBOL(proc_dointvec_minmax);
++EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
++EXPORT_SYMBOL(proc_doulongvec_minmax);
++
++/* interrupt handling */
++EXPORT_SYMBOL(add_timer);
++EXPORT_SYMBOL(del_timer);
++EXPORT_SYMBOL(request_irq);
++EXPORT_SYMBOL(free_irq);
++#if !defined(CONFIG_IA64) /* irq_stat is part of struct cpuinfo_ia64 */
++EXPORT_SYMBOL(irq_stat);
++#endif
++
++/* waitqueue handling */
++EXPORT_SYMBOL(add_wait_queue);
++EXPORT_SYMBOL(add_wait_queue_exclusive);
++EXPORT_SYMBOL(remove_wait_queue);
++
++EXPORT_SYMBOL_GPL(flush_signal_handlers);
++
++/* completion handling */
++EXPORT_SYMBOL(wait_for_completion);
++EXPORT_SYMBOL(complete);
++
++/* The notion of irq probe/assignment is foreign to S/390 */
++
++#if !defined(CONFIG_ARCH_S390)
++EXPORT_SYMBOL(probe_irq_on);
++EXPORT_SYMBOL(probe_irq_off);
++#endif
++
++#ifdef CONFIG_SMP
++EXPORT_SYMBOL(del_timer_sync);
++#endif
++EXPORT_SYMBOL(mod_timer);
++EXPORT_SYMBOL(tq_timer);
++EXPORT_SYMBOL(tq_immediate);
++
++#ifdef CONFIG_SMP
++/* Various random spinlocks we want to export */
++EXPORT_SYMBOL(tqueue_lock);
++
++/* Big-Reader lock implementation */
++EXPORT_SYMBOL(__brlock_array);
++#ifndef __BRLOCK_USE_ATOMICS
++EXPORT_SYMBOL(__br_write_locks);
++#endif
++EXPORT_SYMBOL(__br_write_lock);
++EXPORT_SYMBOL(__br_write_unlock);
++#endif
++
++/* Kiobufs */
++EXPORT_SYMBOL(alloc_kiovec);
++EXPORT_SYMBOL(free_kiovec);
++EXPORT_SYMBOL(expand_kiobuf);
++
++EXPORT_SYMBOL(map_user_kiobuf);
++EXPORT_SYMBOL(unmap_kiobuf);
++EXPORT_SYMBOL(lock_kiovec);
++EXPORT_SYMBOL(unlock_kiovec);
++EXPORT_SYMBOL(brw_kiovec);
++EXPORT_SYMBOL(kiobuf_wait_for_io);
++
++/* dma handling */
++EXPORT_SYMBOL(request_dma);
++EXPORT_SYMBOL(free_dma);
++EXPORT_SYMBOL(dma_spin_lock);
++#ifdef HAVE_DISABLE_HLT
++EXPORT_SYMBOL(disable_hlt);
++EXPORT_SYMBOL(enable_hlt);
++#endif
++
++/* resource handling */
++EXPORT_SYMBOL(request_resource);
++EXPORT_SYMBOL(release_resource);
++EXPORT_SYMBOL(allocate_resource);
++EXPORT_SYMBOL(check_resource);
++EXPORT_SYMBOL(__request_region);
++EXPORT_SYMBOL(__check_region);
++EXPORT_SYMBOL(__release_region);
++EXPORT_SYMBOL(ioport_resource);
++EXPORT_SYMBOL(iomem_resource);
++
++/* process management */
++EXPORT_SYMBOL(complete_and_exit);
++EXPORT_SYMBOL(__wake_up);
++EXPORT_SYMBOL(wake_up_process);
++EXPORT_SYMBOL(sleep_on);
++EXPORT_SYMBOL(sleep_on_timeout);
++EXPORT_SYMBOL(interruptible_sleep_on);
++EXPORT_SYMBOL(interruptible_sleep_on_timeout);
++EXPORT_SYMBOL(schedule);
++EXPORT_SYMBOL(schedule_timeout);
++EXPORT_SYMBOL(yield);
++EXPORT_SYMBOL(__cond_resched);
++EXPORT_SYMBOL(set_user_nice);
++#ifdef CONFIG_SMP
++EXPORT_SYMBOL_GPL(set_cpus_allowed);
++#endif
++EXPORT_SYMBOL(nr_context_switches);
++EXPORT_SYMBOL(jiffies);
++EXPORT_SYMBOL(xtime);
++EXPORT_SYMBOL(do_gettimeofday);
++EXPORT_SYMBOL(do_settimeofday);
++
++#if LOWLATENCY_NEEDED
++EXPORT_SYMBOL(set_running_and_schedule);
++
++
++
++#endif
++
++#if !defined(__ia64__)
++EXPORT_SYMBOL(loops_per_jiffy);
++#endif
++
++EXPORT_SYMBOL(kstat);
++
++/* misc */
++EXPORT_SYMBOL(panic);
++EXPORT_SYMBOL_GPL(panic_notifier_list);
++EXPORT_SYMBOL_GPL(panic_timeout);
++EXPORT_SYMBOL(__out_of_line_bug);
++EXPORT_SYMBOL(sprintf);
++EXPORT_SYMBOL(snprintf);
++EXPORT_SYMBOL(sscanf);
++EXPORT_SYMBOL(vsprintf);
++EXPORT_SYMBOL(vsnprintf);
++EXPORT_SYMBOL(vsscanf);
++EXPORT_SYMBOL(kdevname);
++EXPORT_SYMBOL(bdevname);
++EXPORT_SYMBOL(cdevname);
++EXPORT_SYMBOL(simple_strtol);
++EXPORT_SYMBOL(simple_strtoul);
++EXPORT_SYMBOL(simple_strtoull);
++EXPORT_SYMBOL(system_utsname); /* UTS data */
++EXPORT_SYMBOL(uts_sem); /* UTS semaphore */
++EXPORT_SYMBOL(machine_restart);
++EXPORT_SYMBOL(machine_halt);
++EXPORT_SYMBOL(machine_power_off);
++EXPORT_SYMBOL(_ctype);
++EXPORT_SYMBOL(secure_tcp_sequence_number);
++EXPORT_SYMBOL(get_random_bytes);
++EXPORT_SYMBOL(securebits);
++EXPORT_SYMBOL(cap_bset);
++EXPORT_SYMBOL(reparent_to_init);
++EXPORT_SYMBOL(daemonize);
++EXPORT_SYMBOL(csum_partial); /* for networking and md */
++EXPORT_SYMBOL(seq_escape);
++EXPORT_SYMBOL(seq_printf);
++EXPORT_SYMBOL(seq_open);
++EXPORT_SYMBOL(seq_release);
++EXPORT_SYMBOL(seq_read);
++EXPORT_SYMBOL(seq_lseek);
++extern int disable_all_usb;
++EXPORT_SYMBOL(disable_all_usb);
++
++/* Program loader interfaces */
++EXPORT_SYMBOL(setup_arg_pages);
++EXPORT_SYMBOL(copy_strings_kernel);
++EXPORT_SYMBOL(do_execve);
++EXPORT_SYMBOL(flush_old_exec);
++EXPORT_SYMBOL(kernel_read);
++EXPORT_SYMBOL(open_exec);
++
++/* Miscellaneous access points */
++EXPORT_SYMBOL(si_meminfo);
++
++/* Added to make file system as module */
++EXPORT_SYMBOL(sys_tz);
++EXPORT_SYMBOL(file_fsync);
++EXPORT_SYMBOL(fsync_buffers_list);
++EXPORT_SYMBOL(clear_inode);
++EXPORT_SYMBOL(___strtok);
++EXPORT_SYMBOL(init_special_inode);
++EXPORT_SYMBOL(read_ahead);
++EXPORT_SYMBOL(get_hash_table);
++EXPORT_SYMBOL(new_inode);
++EXPORT_SYMBOL(insert_inode_hash);
++EXPORT_SYMBOL(remove_inode_hash);
++EXPORT_SYMBOL(buffer_insert_list);
++EXPORT_SYMBOL(make_bad_inode);
++EXPORT_SYMBOL(is_bad_inode);
++EXPORT_SYMBOL(event);
++EXPORT_SYMBOL(brw_page);
++EXPORT_SYMBOL(__inode_dir_notify);
++
++#ifdef CONFIG_UID16
++EXPORT_SYMBOL(overflowuid);
++EXPORT_SYMBOL(overflowgid);
++#endif
++EXPORT_SYMBOL(fs_overflowuid);
++EXPORT_SYMBOL(fs_overflowgid);
++
++/* all busmice */
++EXPORT_SYMBOL(fasync_helper);
++EXPORT_SYMBOL(kill_fasync);
++
++EXPORT_SYMBOL(disk_name); /* for md.c */
++
++/* binfmt_aout */
++EXPORT_SYMBOL(get_write_access);
++
++/* library functions */
++EXPORT_SYMBOL(strnicmp);
++EXPORT_SYMBOL(strspn);
++EXPORT_SYMBOL(strsep);
++
++/* software interrupts */
++EXPORT_SYMBOL(tasklet_hi_vec);
++EXPORT_SYMBOL(tasklet_vec);
++EXPORT_SYMBOL(bh_task_vec);
++EXPORT_SYMBOL(init_bh);
++EXPORT_SYMBOL(remove_bh);
++EXPORT_SYMBOL(tasklet_init);
++EXPORT_SYMBOL(tasklet_kill);
++EXPORT_SYMBOL(__run_task_queue);
++EXPORT_SYMBOL(do_softirq);
++EXPORT_SYMBOL(raise_softirq);
++EXPORT_SYMBOL(cpu_raise_softirq);
++EXPORT_SYMBOL(__tasklet_schedule);
++EXPORT_SYMBOL(__tasklet_hi_schedule);
++
++/* init task, for moving kthread roots - ought to export a function ?? */
++
++EXPORT_SYMBOL(init_task_union);
++
++EXPORT_SYMBOL(tasklist_lock);
++EXPORT_SYMBOL_GPL(next_thread);
++EXPORT_SYMBOL_GPL(find_task_by_pid);
++EXPORT_SYMBOL(sys_wait4);
++EXPORT_SYMBOL_GPL(set_special_pids);
++/* debug */
++extern void check_tasklist_locked(void);
++EXPORT_SYMBOL_GPL(check_tasklist_locked);
++EXPORT_SYMBOL(dump_stack);
+
+_
--- /dev/null
+ fs/dcache.c | 19 ++
+ fs/exec.c | 14 +
+ fs/namei.c | 364 +++++++++++++++++++++++++++++++++++++++++--------
+ fs/nfsd/vfs.c | 2
+ fs/open.c | 118 ++++++++++++++-
+ fs/stat.c | 8 -
+ include/linux/dcache.h | 28 +++
+ include/linux/fs.h | 33 ++++
+ kernel/ksyms.c | 1
+ 9 files changed, 505 insertions(+), 82 deletions(-)
+
+--- linux-rh-2.4.20-6/fs/dcache.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/fs/dcache.c Tue Apr 1 01:03:23 2003
+@@ -186,6 +186,13 @@ int d_invalidate(struct dentry * dentry)
+ spin_unlock(&dcache_lock);
+ return 0;
+ }
++
++ /* network invalidation by Lustre */
++ if (dentry->d_flags & DCACHE_LUSTRE_INVALID) {
++ spin_unlock(&dcache_lock);
++ return 0;
++ }
++
+ /*
+ * Check whether to do a partial shrink_dcache
+ * to get rid of unused child entries.
+@@ -840,13 +847,19 @@ void d_delete(struct dentry * dentry)
+ * Adds a dentry to the hash according to its name.
+ */
+
+-void d_rehash(struct dentry * entry)
++void __d_rehash(struct dentry * entry, int lock)
+ {
+ struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);
+ if (!list_empty(&entry->d_hash)) BUG();
+- spin_lock(&dcache_lock);
++ if (lock) spin_lock(&dcache_lock);
+ list_add(&entry->d_hash, list);
+- spin_unlock(&dcache_lock);
++ if (lock) spin_unlock(&dcache_lock);
++}
++EXPORT_SYMBOL(__d_rehash);
++
++void d_rehash(struct dentry * entry)
++{
++ __d_rehash(entry, 1);
+ }
+
+ #define do_switch(x,y) do { \
+--- linux-rh-2.4.20-6/fs/namei.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/fs/namei.c Wed Apr 2 02:12:53 2003
+@@ -1,3 +1,4 @@
++
+ /*
+ * linux/fs/namei.c
+ *
+@@ -94,6 +95,13 @@
+ * XEmacs seems to be relying on it...
+ */
+
++void intent_release(struct dentry *de, struct lookup_intent *it)
++{
++ if (it && de->d_op && de->d_op->d_intent_release)
++ de->d_op->d_intent_release(de, it);
++
++}
++
+ /* In order to reduce some races, while at the same time doing additional
+ * checking and hopefully speeding things up, we copy filenames to the
+ * kernel data space before using them..
+@@ -260,10 +268,19 @@ void path_release(struct nameidata *nd)
+ * Internal lookup() using the new generic dcache.
+ * SMP-safe
+ */
+-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
++static struct dentry *cached_lookup(struct dentry *parent, struct qstr *name,
++ int flags, struct lookup_intent *it)
+ {
+ struct dentry * dentry = d_lookup(parent, name);
+
++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate2) {
++ if (!dentry->d_op->d_revalidate2(dentry, flags, it) &&
++ !d_invalidate(dentry)) {
++ dput(dentry);
++ dentry = NULL;
++ }
++ return dentry;
++ } else
+ if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
+ if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
+ dput(dentry);
+@@ -281,11 +298,14 @@ static struct dentry * cached_lookup(str
+ * make sure that nobody added the entry to the dcache in the meantime..
+ * SMP-safe
+ */
+-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
++static struct dentry *real_lookup(struct dentry *parent, struct qstr *name,
++ int flags, struct lookup_intent *it)
+ {
+ struct dentry * result;
+ struct inode *dir = parent->d_inode;
+
++again:
++
+ down(&dir->i_sem);
+ /*
+ * First re-do the cached lookup just in case it was created
+@@ -300,6 +320,9 @@ static struct dentry * real_lookup(struc
+ result = ERR_PTR(-ENOMEM);
+ if (dentry) {
+ lock_kernel();
++ if (dir->i_op->lookup2)
++ result = dir->i_op->lookup2(dir, dentry, it);
++ else
+ result = dir->i_op->lookup(dir, dentry);
+ unlock_kernel();
+ if (result)
+@@ -321,6 +344,12 @@ static struct dentry * real_lookup(struc
+ dput(result);
+ result = ERR_PTR(-ENOENT);
+ }
++ } else if (result->d_op && result->d_op->d_revalidate2) {
++ if (!result->d_op->d_revalidate2(result, flags, it) &&
++ !d_invalidate(result)) {
++ dput(result);
++ goto again;
++ }
+ }
+ return result;
+ }
+@@ -334,7 +363,8 @@ int max_recursive_link = 5;
+ * Without that kind of total limit, nasty chains of consecutive
+ * symlinks can cause almost arbitrarily long lookups.
+ */
+-static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd)
++static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd,
++ struct lookup_intent *it)
+ {
+ int err;
+ if (current->link_count >= max_recursive_link)
+@@ -348,10 +378,14 @@ static inline int do_follow_link(struct
+ current->link_count++;
+ current->total_link_count++;
+ UPDATE_ATIME(dentry->d_inode);
+- err = dentry->d_inode->i_op->follow_link(dentry, nd);
++ if (dentry->d_inode->i_op->follow_link2)
++ err = dentry->d_inode->i_op->follow_link2(dentry, nd, it);
++ else
++ err = dentry->d_inode->i_op->follow_link(dentry, nd);
+ current->link_count--;
+ return err;
+ loop:
++ intent_release(dentry, it);
+ path_release(nd);
+ return -ELOOP;
+ }
+@@ -381,15 +415,26 @@ int follow_up(struct vfsmount **mnt, str
+ return __follow_up(mnt, dentry);
+ }
+
+-static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry)
++static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry,
++ struct lookup_intent *it)
+ {
+ struct vfsmount *mounted;
+
+ spin_lock(&dcache_lock);
+ mounted = lookup_mnt(*mnt, *dentry);
+ if (mounted) {
++ int opc = 0, mode = 0;
+ *mnt = mntget(mounted);
+ spin_unlock(&dcache_lock);
++ if (it) {
++ opc = it->it_op;
++ mode = it->it_mode;
++ }
++ intent_release(*dentry, it);
++ if (it) {
++ it->it_op = opc;
++ it->it_mode = mode;
++ }
+ dput(*dentry);
+ mntput(mounted->mnt_parent);
+ *dentry = dget(mounted->mnt_root);
+@@ -401,7 +446,7 @@ static inline int __follow_down(struct v
+
+ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
+ {
+- return __follow_down(mnt,dentry);
++ return __follow_down(mnt,dentry,NULL);
+ }
+
+ static inline void follow_dotdot(struct nameidata *nd)
+@@ -437,7 +482,7 @@ static inline void follow_dotdot(struct
+ mntput(nd->mnt);
+ nd->mnt = parent;
+ }
+- while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry))
++ while (d_mountpoint(nd->dentry) && __follow_down(&nd->mnt, &nd->dentry, NULL))
+ ;
+ }
+
+@@ -449,7 +494,8 @@ static inline void follow_dotdot(struct
+ *
+ * We expect 'base' to be positive and a directory.
+ */
+-int link_path_walk(const char * name, struct nameidata *nd)
++int link_path_walk_it(const char *name, struct nameidata *nd,
++ struct lookup_intent *it)
+ {
+ struct dentry *dentry;
+ struct inode *inode;
+@@ -526,18 +572,18 @@ int link_path_walk(const char * name, st
+ break;
+ }
+ /* This does the actual lookups.. */
+- dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
++ dentry = cached_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL);
+ if (!dentry) {
+ err = -EWOULDBLOCKIO;
+ if (atomic)
+ break;
+- dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE);
++ dentry = real_lookup(nd->dentry, &this, LOOKUP_CONTINUE, NULL);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ break;
+ }
+ /* Check mountpoints.. */
+- while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
++ while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry, NULL))
+ ;
+
+ err = -ENOENT;
+@@ -548,8 +594,8 @@ int link_path_walk(const char * name, st
+ if (!inode->i_op)
+ goto out_dput;
+
+- if (inode->i_op->follow_link) {
+- err = do_follow_link(dentry, nd);
++ if (inode->i_op->follow_link || inode->i_op->follow_link2) {
++ err = do_follow_link(dentry, nd, NULL);
+ dput(dentry);
+ if (err)
+ goto return_err;
+@@ -565,7 +611,7 @@ int link_path_walk(const char * name, st
+ nd->dentry = dentry;
+ }
+ err = -ENOTDIR;
+- if (!inode->i_op->lookup)
++ if (!inode->i_op->lookup && !inode->i_op->lookup2)
+ break;
+ continue;
+ /* here ends the main loop */
+@@ -592,22 +638,23 @@ last_component:
+ if (err < 0)
+ break;
+ }
+- dentry = cached_lookup(nd->dentry, &this, 0);
++ dentry = cached_lookup(nd->dentry, &this, 0, NULL);
+ if (!dentry) {
+ err = -EWOULDBLOCKIO;
+ if (atomic)
+ break;
+- dentry = real_lookup(nd->dentry, &this, 0);
++ dentry = real_lookup(nd->dentry, &this, 0, NULL);
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ break;
+ }
+- while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry))
++ while (d_mountpoint(dentry) && __follow_down(&nd->mnt, &dentry, NULL))
+ ;
+ inode = dentry->d_inode;
+ if ((lookup_flags & LOOKUP_FOLLOW)
+- && inode && inode->i_op && inode->i_op->follow_link) {
+- err = do_follow_link(dentry, nd);
++ && inode && inode->i_op &&
++ inode->i_op->follow_link || inode->i_op->follow_link2) {
++ err = do_follow_link(dentry, nd, it);
+ dput(dentry);
+ if (err)
+ goto return_err;
+@@ -621,7 +668,8 @@ last_component:
+ goto no_inode;
+ if (lookup_flags & LOOKUP_DIRECTORY) {
+ err = -ENOTDIR;
+- if (!inode->i_op || !inode->i_op->lookup)
++ if (!inode->i_op ||
++ (!inode->i_op->lookup && !inode->i_op->lookup2))
+ break;
+ }
+ goto return_base;
+@@ -645,6 +693,30 @@ return_reval:
+ * Check the cached dentry for staleness.
+ */
+ dentry = nd->dentry;
++ revalidate_again:
++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate2) {
++ err = -ESTALE;
++ if (!dentry->d_op->d_revalidate2(dentry, 0, it)) {
++ struct dentry *new;
++ err = permission(dentry->d_parent->d_inode,
++ MAY_EXEC);
++ if (err)
++ break;
++ new = real_lookup(dentry->d_parent,
++ &dentry->d_name, 0, NULL);
++ d_invalidate(dentry);
++ dput(dentry);
++ dentry = new;
++ goto revalidate_again;
++ }
++ } else
++ if (dentry && dentry->d_op && dentry->d_op->d_revalidate2) {
++ err = -ESTALE;
++ if (!dentry->d_op->d_revalidate2(dentry, 0, it)) {
++ d_invalidate(dentry);
++ break;
++ }
++ } else
+ if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
+ err = -ESTALE;
+ if (!dentry->d_op->d_revalidate(dentry, 0)) {
+@@ -658,15 +730,28 @@ out_dput:
+ dput(dentry);
+ break;
+ }
++ if (err)
++ intent_release(nd->dentry, it);
+ path_release(nd);
+ return_err:
+ return err;
+ }
+
++int link_path_walk(const char * name, struct nameidata *nd)
++{
++ return link_path_walk_it(name, nd, NULL);
++}
++
++int path_walk_it(const char * name, struct nameidata *nd, struct lookup_intent *it)
++{
++ current->total_link_count = 0;
++ return link_path_walk_it(name, nd, it);
++}
++
+ int path_walk(const char * name, struct nameidata *nd)
+ {
+ current->total_link_count = 0;
+- return link_path_walk(name, nd);
++ return link_path_walk_it(name, nd, NULL);
+ }
+
+ /* SMP-safe */
+@@ -751,6 +836,14 @@ walk_init_root(const char *name, struct
+ }
+
+ /* SMP-safe */
++int path_lookup_it(const char *path, unsigned flags, struct nameidata *nd, struct lookup_intent *it)
++{
++ int error = 0;
++ if (path_init(path, flags, nd))
++ error = path_walk_it(path, nd, it);
++ return error;
++}
++
+ int path_lookup(const char *path, unsigned flags, struct nameidata *nd)
+ {
+ int error = 0;
+@@ -779,7 +872,8 @@ int path_init(const char *name, unsigned
+ * needs parent already locked. Doesn't follow mounts.
+ * SMP-safe.
+ */
+-struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
++struct dentry * lookup_hash_it(struct qstr *name, struct dentry * base,
++ struct lookup_intent *it)
+ {
+ struct dentry * dentry;
+ struct inode *inode;
+@@ -802,13 +896,16 @@ struct dentry * lookup_hash(struct qstr
+ goto out;
+ }
+
+- dentry = cached_lookup(base, name, 0);
++ dentry = cached_lookup(base, name, 0, it);
+ if (!dentry) {
+ struct dentry *new = d_alloc(base, name);
+ dentry = ERR_PTR(-ENOMEM);
+ if (!new)
+ goto out;
+ lock_kernel();
++ if (inode->i_op->lookup2)
++ dentry = inode->i_op->lookup2(inode, new, it);
++ else
+ dentry = inode->i_op->lookup(inode, new);
+ unlock_kernel();
+ if (!dentry)
+@@ -820,6 +917,12 @@ out:
+ return dentry;
+ }
+
++struct dentry * lookup_hash(struct qstr *name, struct dentry * base)
++{
++ return lookup_hash_it(name, base, NULL);
++}
++
++
+ /* SMP-safe */
+ struct dentry * lookup_one_len(const char * name, struct dentry * base, int len)
+ {
+@@ -841,7 +944,7 @@ struct dentry * lookup_one_len(const cha
+ }
+ this.hash = end_name_hash(hash);
+
+- return lookup_hash(&this, base);
++ return lookup_hash_it(&this, base, NULL);
+ access:
+ return ERR_PTR(-EACCES);
+ }
+@@ -872,6 +975,23 @@ int __user_walk(const char *name, unsign
+ return err;
+ }
+
++int __user_walk_it(const char *name, unsigned flags, struct nameidata *nd,
++ struct lookup_intent *it)
++{
++ char *tmp;
++ int err;
++
++ tmp = getname(name);
++ err = PTR_ERR(tmp);
++ if (!IS_ERR(tmp)) {
++ err = 0;
++ if (path_init(tmp, flags, nd))
++ err = path_walk_it(tmp, nd, it);
++ putname(tmp);
++ }
++ return err;
++}
++
+ /*
+ * It's inline, so penalty for filesystems that don't use sticky bit is
+ * minimal.
+@@ -1010,7 +1130,8 @@ exit_lock:
+ * for symlinks (where the permissions are checked later).
+ * SMP-safe
+ */
+-int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
++int open_namei_it(const char *pathname, int flag, int mode,
++ struct nameidata *nd, struct lookup_intent *it)
+ {
+ int acc_mode, error = 0;
+ struct inode *inode;
+@@ -1024,7 +1145,7 @@ int open_namei(const char * pathname, in
+ * The simplest case - just a plain lookup.
+ */
+ if (!(flag & O_CREAT)) {
+- error = path_lookup(pathname, lookup_flags(flag), nd);
++ error = path_lookup_it(pathname, lookup_flags(flag), nd, it);
+ if (error)
+ return error;
+ dentry = nd->dentry;
+@@ -1034,6 +1155,10 @@ int open_namei(const char * pathname, in
+ /*
+ * Create - we need to know the parent.
+ */
++ if (it) {
++ it->it_mode = mode;
++ it->it_op |= IT_CREAT;
++ }
+ error = path_lookup(pathname, LOOKUP_PARENT, nd);
+ if (error)
+ return error;
+@@ -1049,7 +1174,7 @@ int open_namei(const char * pathname, in
+
+ dir = nd->dentry;
+ down(&dir->d_inode->i_sem);
+- dentry = lookup_hash(&nd->last, nd->dentry);
++ dentry = lookup_hash_it(&nd->last, nd->dentry, it);
+
+ do_last:
+ error = PTR_ERR(dentry);
+@@ -1058,6 +1183,7 @@ do_last:
+ goto exit;
+ }
+
++ it->it_mode = mode;
+ /* Negative dentry, just create the file */
+ if (!dentry->d_inode) {
+ error = vfs_create(dir->d_inode, dentry,
+@@ -1086,12 +1212,13 @@ do_last:
+ error = -ELOOP;
+ if (flag & O_NOFOLLOW)
+ goto exit_dput;
+- while (__follow_down(&nd->mnt,&dentry) && d_mountpoint(dentry));
++ while (__follow_down(&nd->mnt,&dentry,it) && d_mountpoint(dentry));
+ }
+ error = -ENOENT;
+ if (!dentry->d_inode)
+ goto exit_dput;
+- if (dentry->d_inode->i_op && dentry->d_inode->i_op->follow_link)
++ if (dentry->d_inode->i_op && (dentry->d_inode->i_op->follow_link ||
++ dentry->d_inode->i_op->follow_link2))
+ goto do_link;
+
+ dput(nd->dentry);
+@@ -1165,7 +1292,7 @@ ok:
+ if (!error) {
+ DQUOT_INIT(inode);
+
+- error = do_truncate(dentry, 0);
++ error = do_truncate(dentry, 0, 1);
+ }
+ put_write_access(inode);
+ if (error)
+@@ -1177,8 +1304,10 @@ ok:
+ return 0;
+
+ exit_dput:
++ intent_release(dentry, it);
+ dput(dentry);
+ exit:
++ intent_release(nd->dentry, it);
+ path_release(nd);
+ return error;
+
+@@ -1197,7 +1326,12 @@ do_link:
+ * are done. Procfs-like symlinks just set LAST_BIND.
+ */
+ UPDATE_ATIME(dentry->d_inode);
+- error = dentry->d_inode->i_op->follow_link(dentry, nd);
++ if (dentry->d_inode->i_op->follow_link2)
++ error = dentry->d_inode->i_op->follow_link2(dentry, nd, it);
++ else
++ error = dentry->d_inode->i_op->follow_link(dentry, nd);
++ if (error)
++ intent_release(dentry, it);
+ dput(dentry);
+ if (error)
+ return error;
+@@ -1219,13 +1353,20 @@ do_link:
+ }
+ dir = nd->dentry;
+ down(&dir->d_inode->i_sem);
+- dentry = lookup_hash(&nd->last, nd->dentry);
++ dentry = lookup_hash_it(&nd->last, nd->dentry, it);
+ putname(nd->last.name);
+ goto do_last;
+ }
+
++int open_namei(const char *pathname, int flag, int mode, struct nameidata *nd)
++{
++ return open_namei_it(pathname, flag, mode, nd, NULL);
++}
++
++
+ /* SMP-safe */
+-static struct dentry *lookup_create(struct nameidata *nd, int is_dir)
++static struct dentry *lookup_create(struct nameidata *nd, int is_dir,
++ struct lookup_intent *it)
+ {
+ struct dentry *dentry;
+
+@@ -1233,7 +1374,7 @@ static struct dentry *lookup_create(stru
+ dentry = ERR_PTR(-EEXIST);
+ if (nd->last_type != LAST_NORM)
+ goto fail;
+- dentry = lookup_hash(&nd->last, nd->dentry);
++ dentry = lookup_hash_it(&nd->last, nd->dentry, it);
+ if (IS_ERR(dentry))
+ goto fail;
+ if (!is_dir && nd->last.name[nd->last.len] && !dentry->d_inode)
+@@ -1289,7 +1430,19 @@ asmlinkage long sys_mknod(const char * f
+ error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+ if (error)
+ goto out;
+- dentry = lookup_create(&nd, 0);
++
++ if (nd.dentry->d_inode->i_op->mknod2) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++ error = op->mknod2(nd.dentry->d_inode,
++ nd.last.name,
++ nd.last.len,
++ mode, dev);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto out2;
++ }
++
++ dentry = lookup_create(&nd, 0, NULL);
+ error = PTR_ERR(dentry);
+
+ mode &= ~current->fs->umask;
+@@ -1310,6 +1463,7 @@ asmlinkage long sys_mknod(const char * f
+ dput(dentry);
+ }
+ up(&nd.dentry->d_inode->i_sem);
++out2:
+ path_release(&nd);
+ out:
+ putname(tmp);
+@@ -1357,7 +1511,17 @@ asmlinkage long sys_mkdir(const char * p
+ error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+ if (error)
+ goto out;
+- dentry = lookup_create(&nd, 1);
++ if (nd.dentry->d_inode->i_op->mkdir2) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++ error = op->mkdir2(nd.dentry->d_inode,
++ nd.last.name,
++ nd.last.len,
++ mode);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto out2;
++ }
++ dentry = lookup_create(&nd, 1, NULL);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = vfs_mkdir(nd.dentry->d_inode, dentry,
+@@ -1365,6 +1529,8 @@ asmlinkage long sys_mkdir(const char * p
+ dput(dentry);
+ }
+ up(&nd.dentry->d_inode->i_sem);
++out2:
++ path_release(&nd);
+ path_release(&nd);
+ out:
+ putname(tmp);
+@@ -1465,8 +1631,33 @@ asmlinkage long sys_rmdir(const char * p
+ error = -EBUSY;
+ goto exit1;
+ }
++ if (nd.dentry->d_inode->i_op->rmdir2) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++ struct dentry *last;
++
++ down(&nd.dentry->d_inode->i_sem);
++ last = lookup_hash_it(&nd.last, nd.dentry, NULL);
++ up(&nd.dentry->d_inode->i_sem);
++ if (IS_ERR(last)) {
++ error = PTR_ERR(last);
++ goto exit1;
++ }
++ if (d_mountpoint(last)) {
++ dput(last);
++ error = -EBUSY;
++ goto exit1;
++ }
++ dput(last);
++
++ error = op->rmdir2(nd.dentry->d_inode,
++ nd.last.name,
++ nd.last.len);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto exit1;
++ }
+ down(&nd.dentry->d_inode->i_sem);
+- dentry = lookup_hash(&nd.last, nd.dentry);
++ dentry = lookup_hash_it(&nd.last, nd.dentry, NULL);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = vfs_rmdir(nd.dentry->d_inode, dentry);
+@@ -1518,14 +1709,23 @@ asmlinkage long sys_unlink(const char *
+ if(IS_ERR(name))
+ return PTR_ERR(name);
+
+- error = path_lookup(name, LOOKUP_PARENT, &nd);
++ error = path_lookup_it(name, LOOKUP_PARENT, &nd, NULL);
+ if (error)
+ goto exit;
+ error = -EISDIR;
+ if (nd.last_type != LAST_NORM)
+ goto exit1;
++ if (nd.dentry->d_inode->i_op->unlink2) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++ error = op->unlink2(nd.dentry->d_inode,
++ nd.last.name,
++ nd.last.len);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto exit1;
++ }
+ down(&nd.dentry->d_inode->i_sem);
+- dentry = lookup_hash(&nd.last, nd.dentry);
++ dentry = lookup_hash_it(&nd.last, nd.dentry, NULL);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ /* Why not before? Because we want correct error value */
+@@ -1592,15 +1792,26 @@ asmlinkage long sys_symlink(const char *
+ error = path_lookup(to, LOOKUP_PARENT, &nd);
+ if (error)
+ goto out;
+- dentry = lookup_create(&nd, 0);
++ if (nd.dentry->d_inode->i_op->symlink2) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++ error = op->symlink2(nd.dentry->d_inode,
++ nd.last.name,
++ nd.last.len,
++ from);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto out2;
++ }
++ dentry = lookup_create(&nd, 0, NULL);
+ error = PTR_ERR(dentry);
+ if (!IS_ERR(dentry)) {
+ error = vfs_symlink(nd.dentry->d_inode, dentry, from);
+ dput(dentry);
+ }
+ up(&nd.dentry->d_inode->i_sem);
++ out2:
+ path_release(&nd);
+-out:
++ out:
+ putname(to);
+ }
+ putname(from);
+@@ -1676,7 +1887,17 @@ asmlinkage long sys_link(const char * ol
+ error = -EXDEV;
+ if (old_nd.mnt != nd.mnt)
+ goto out_release;
+- new_dentry = lookup_create(&nd, 0);
++ if (nd.dentry->d_inode->i_op->link2) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++ error = op->link2(old_nd.dentry->d_inode,
++ nd.dentry->d_inode,
++ nd.last.name,
++ nd.last.len);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto out_release;
++ }
++ new_dentry = lookup_create(&nd, 0, NULL);
+ error = PTR_ERR(new_dentry);
+ if (!IS_ERR(new_dentry)) {
+ error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+@@ -1720,7 +1941,8 @@ exit:
+ * locking].
+ */
+ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
+- struct inode *new_dir, struct dentry *new_dentry)
++ struct inode *new_dir, struct dentry *new_dentry,
++ struct lookup_intent *it)
+ {
+ int error;
+ struct inode *target;
+@@ -1778,6 +2000,7 @@ int vfs_rename_dir(struct inode *old_dir
+ error = -EBUSY;
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
++ intent_release(new_dentry, it);
+ if (target) {
+ if (!error)
+ target->i_flags |= S_DEAD;
+@@ -1799,7 +2022,8 @@ out_unlock:
+ }
+
+ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
+- struct inode *new_dir, struct dentry *new_dentry)
++ struct inode *new_dir, struct dentry *new_dentry,
++ struct lookup_intent *it)
+ {
+ int error;
+
+@@ -1830,6 +2054,7 @@ int vfs_rename_other(struct inode *old_d
+ error = -EBUSY;
+ else
+ error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
++ intent_release(new_dentry, it);
+ double_up(&old_dir->i_zombie, &new_dir->i_zombie);
+ if (error)
+ return error;
+@@ -1841,13 +2066,14 @@ int vfs_rename_other(struct inode *old_d
+ }
+
+ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+- struct inode *new_dir, struct dentry *new_dentry)
++ struct inode *new_dir, struct dentry *new_dentry,
++ struct lookup_intent *it)
+ {
+ int error;
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
+- error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
++ error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry,it);
+ else
+- error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
++ error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry,it);
+ if (!error) {
+ if (old_dir == new_dir)
+ inode_dir_notify(old_dir, DN_RENAME);
+@@ -1889,7 +2115,7 @@ static inline int do_rename(const char *
+
+ double_lock(new_dir, old_dir);
+
+- old_dentry = lookup_hash(&oldnd.last, old_dir);
++ old_dentry = lookup_hash_it(&oldnd.last, old_dir, NULL);
+ error = PTR_ERR(old_dentry);
+ if (IS_ERR(old_dentry))
+ goto exit3;
+@@ -1905,16 +2131,37 @@ static inline int do_rename(const char *
+ if (newnd.last.name[newnd.last.len])
+ goto exit4;
+ }
+- new_dentry = lookup_hash(&newnd.last, new_dir);
++ new_dentry = lookup_hash_it(&newnd.last, new_dir, NULL);
+ error = PTR_ERR(new_dentry);
+ if (IS_ERR(new_dentry))
+ goto exit4;
+
++ if (old_dir->d_inode->i_op->rename2) {
++ lock_kernel();
++ /* don't rename mount point. mds will take care of
++ * the rest sanity checking */
++ if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) {
++ error = -EBUSY;
++ goto exit5;
++ }
++
++ error = old_dir->d_inode->i_op->rename2(old_dir->d_inode,
++ new_dir->d_inode,
++ oldnd.last.name,
++ oldnd.last.len,
++ newnd.last.name,
++ newnd.last.len);
++ unlock_kernel();
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto exit5;
++ }
++
+ lock_kernel();
+ error = vfs_rename(old_dir->d_inode, old_dentry,
+- new_dir->d_inode, new_dentry);
++ new_dir->d_inode, new_dentry, NULL);
+ unlock_kernel();
+-
++exit5:
+ dput(new_dentry);
+ exit4:
+ dput(old_dentry);
+@@ -1965,7 +2212,8 @@ out:
+ }
+
+ static inline int
+-__vfs_follow_link(struct nameidata *nd, const char *link)
++__vfs_follow_link(struct nameidata *nd, const char *link,
++ struct lookup_intent *it)
+ {
+ int res = 0;
+ char *name;
+@@ -1978,7 +2226,7 @@ __vfs_follow_link(struct nameidata *nd,
+ /* weird __emul_prefix() stuff did it */
+ goto out;
+ }
+- res = link_path_walk(link, nd);
++ res = link_path_walk_it(link, nd, it);
+ out:
+ if (current->link_count || res || nd->last_type!=LAST_NORM)
+ return res;
+@@ -2002,7 +2250,13 @@ fail:
+
+ int vfs_follow_link(struct nameidata *nd, const char *link)
+ {
+- return __vfs_follow_link(nd, link);
++ return __vfs_follow_link(nd, link, NULL);
++}
++
++int vfs_follow_link_it(struct nameidata *nd, const char *link,
++ struct lookup_intent *it)
++{
++ return __vfs_follow_link(nd, link, it);
+ }
+
+ /* get the link contents into pagecache */
+@@ -2044,7 +2298,7 @@ int page_follow_link(struct dentry *dent
+ {
+ struct page *page = NULL;
+ char *s = page_getlink(dentry, &page);
+- int res = __vfs_follow_link(nd, s);
++ int res = __vfs_follow_link(nd, s, NULL);
+ if (page) {
+ kunmap(page);
+ page_cache_release(page);
+--- linux-rh-2.4.20-6/fs/nfsd/vfs.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/fs/nfsd/vfs.c Tue Apr 1 01:03:23 2003
+@@ -1293,7 +1293,7 @@ nfsd_rename(struct svc_rqst *rqstp, stru
+ err = nfserr_perm;
+ } else
+ #endif
+- err = vfs_rename(fdir, odentry, tdir, ndentry);
++ err = vfs_rename(fdir, odentry, tdir, ndentry, NULL);
+ if (!err && EX_ISSYNC(tfhp->fh_export)) {
+ nfsd_sync_dir(tdentry);
+ nfsd_sync_dir(fdentry);
+--- linux-rh-2.4.20-6/fs/open.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/fs/open.c Tue Apr 1 01:03:23 2003
+@@ -19,6 +19,8 @@
+ #include <asm/uaccess.h>
+
+ #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
++extern int path_walk_it(const char *name, struct nameidata *nd,
++ struct lookup_intent *it);
+
+ int vfs_statfs(struct super_block *sb, struct statfs *buf)
+ {
+@@ -95,9 +97,10 @@ void fd_install(unsigned int fd, struct
+ write_unlock(&files->file_lock);
+ }
+
+-int do_truncate(struct dentry *dentry, loff_t length)
++int do_truncate(struct dentry *dentry, loff_t length, int called_from_open)
+ {
+ struct inode *inode = dentry->d_inode;
++ struct inode_operations *op = dentry->d_inode->i_op;
+ int error;
+ struct iattr newattrs;
+
+@@ -108,7 +111,14 @@ int do_truncate(struct dentry *dentry, l
+ down(&inode->i_sem);
+ newattrs.ia_size = length;
+ newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+- error = notify_change(dentry, &newattrs);
++ if (called_from_open)
++ newattrs.ia_valid |= ATTR_FROM_OPEN;
++ if (op->setattr_raw) {
++ newattrs.ia_valid |= ATTR_RAW;
++ newattrs.ia_ctime = CURRENT_TIME;
++ error = op->setattr_raw(inode, &newattrs);
++ } else
++ error = notify_change(dentry, &newattrs);
+ up(&inode->i_sem);
+ return error;
+ }
+@@ -118,12 +128,13 @@ static inline long do_sys_truncate(const
+ struct nameidata nd;
+ struct inode * inode;
+ int error;
++ struct lookup_intent it = { .it_op = IT_GETATTR };
+
+ error = -EINVAL;
+ if (length < 0) /* sorry, but loff_t says... */
+ goto out;
+
+- error = user_path_walk(path, &nd);
++ error = user_path_walk_it(path, &nd, &it);
+ if (error)
+ goto out;
+ inode = nd.dentry->d_inode;
+@@ -163,11 +174,13 @@ static inline long do_sys_truncate(const
+ error = locks_verify_truncate(inode, NULL, length);
+ if (!error) {
+ DQUOT_INIT(inode);
+- error = do_truncate(nd.dentry, length);
++ intent_release(nd.dentry, &it);
++ error = do_truncate(nd.dentry, length, 0);
+ }
+ put_write_access(inode);
+
+ dput_and_out:
++ intent_release(nd.dentry, &it);
+ path_release(&nd);
+ out:
+ return error;
+@@ -215,7 +228,7 @@ static inline long do_sys_ftruncate(unsi
+
+ error = locks_verify_truncate(inode, file, length);
+ if (!error)
+- error = do_truncate(dentry, length);
++ error = do_truncate(dentry, length, 0);
+ out_putf:
+ fput(file);
+ out:
+@@ -260,11 +273,13 @@ asmlinkage long sys_utime(char * filenam
+ struct inode * inode;
+ struct iattr newattrs;
+
+- error = user_path_walk(filename, &nd);
++ error = user_path_walk_it(filename, &nd, NULL);
+ if (error)
+ goto out;
+ inode = nd.dentry->d_inode;
+
++ /* this is safe without a Lustre lock because it only depends
++ on the super block */
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto dput_and_out;
+@@ -279,11 +294,29 @@ asmlinkage long sys_utime(char * filenam
+ goto dput_and_out;
+
+ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+- } else {
++ }
++
++ if (inode->i_op->setattr_raw) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++ newattrs.ia_valid |= ATTR_RAW;
++ error = op->setattr_raw(inode, &newattrs);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto dput_and_out;
++ }
++
++ error = -EROFS;
++ if (IS_RDONLY(inode))
++ goto dput_and_out;
++
++ error = -EPERM;
++ if (!times) {
+ if (current->fsuid != inode->i_uid &&
+ (error = permission(inode,MAY_WRITE)) != 0)
+ goto dput_and_out;
+ }
++
+ error = notify_change(nd.dentry, &newattrs);
+ dput_and_out:
+ path_release(&nd);
+@@ -304,12 +337,14 @@ asmlinkage long sys_utimes(char * filena
+ struct inode * inode;
+ struct iattr newattrs;
+
+- error = user_path_walk(filename, &nd);
++ error = user_path_walk_it(filename, &nd, NULL);
+
+ if (error)
+ goto out;
+ inode = nd.dentry->d_inode;
+
++ /* this is safe without a Lustre lock because it only depends
++ on the super block */
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto dput_and_out;
+@@ -324,7 +359,20 @@ asmlinkage long sys_utimes(char * filena
+ newattrs.ia_atime = times[0].tv_sec;
+ newattrs.ia_mtime = times[1].tv_sec;
+ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+- } else {
++ }
++
++ if (inode->i_op->setattr_raw) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++ newattrs.ia_valid |= ATTR_RAW;
++ error = op->setattr_raw(inode, &newattrs);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto dput_and_out;
++ }
++
++ error = -EPERM;
++ if (!utimes) {
+ if (current->fsuid != inode->i_uid &&
+ (error = permission(inode,MAY_WRITE)) != 0)
+ goto dput_and_out;
+@@ -347,6 +395,7 @@ asmlinkage long sys_access(const char *
+ int old_fsuid, old_fsgid;
+ kernel_cap_t old_cap;
+ int res;
++ struct lookup_intent it = { .it_op = IT_GETATTR };
+
+ if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
+ return -EINVAL;
+@@ -364,13 +413,14 @@ asmlinkage long sys_access(const char *
+ else
+ current->cap_effective = current->cap_permitted;
+
+- res = user_path_walk(filename, &nd);
++ res = user_path_walk_it(filename, &nd, &it);
+ if (!res) {
+ res = permission(nd.dentry->d_inode, mode);
+ /* SuS v2 requires we report a read only fs too */
+ if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
+ && !special_file(nd.dentry->d_inode->i_mode))
+ res = -EROFS;
++ intent_release(nd.dentry, &it);
+ path_release(&nd);
+ }
+
+@@ -385,8 +435,11 @@ asmlinkage long sys_chdir(const char * f
+ {
+ int error;
+ struct nameidata nd;
++ struct lookup_intent it = { .it_op = IT_GETATTR };
+
+- error = __user_walk(filename,LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,&nd);
++ error = __user_walk_it(filename,
++ LOOKUP_POSITIVE|LOOKUP_FOLLOW|LOOKUP_DIRECTORY,
++ &nd, &it);
+ if (error)
+ goto out;
+
+@@ -397,6 +450,7 @@ asmlinkage long sys_chdir(const char * f
+ set_fs_pwd(current->fs, nd.mnt, nd.dentry);
+
+ dput_and_out:
++ intent_release(nd.dentry, &it);
+ path_release(&nd);
+ out:
+ return error;
+@@ -436,9 +490,10 @@ asmlinkage long sys_chroot(const char *
+ {
+ int error;
+ struct nameidata nd;
++ struct lookup_intent it = { .it_op = IT_GETATTR };
+
+- error = __user_walk(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
+- LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
++ error = __user_walk_it(filename, LOOKUP_POSITIVE | LOOKUP_FOLLOW |
++ LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd, &it);
+ if (error)
+ goto out;
+
+@@ -454,6 +509,7 @@ asmlinkage long sys_chroot(const char *
+ set_fs_altroot();
+ error = 0;
+ dput_and_out:
++ intent_release(nd.dentry, &it);
+ path_release(&nd);
+ out:
+ return error;
+@@ -508,6 +564,18 @@ asmlinkage long sys_chmod(const char * f
+ if (IS_RDONLY(inode))
+ goto dput_and_out;
+
++ if (inode->i_op->setattr_raw) {
++ struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++ newattrs.ia_mode = mode;
++ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
++ newattrs.ia_valid |= ATTR_RAW;
++ error = op->setattr_raw(inode, &newattrs);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ goto dput_and_out;
++ }
++
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto dput_and_out;
+@@ -538,6 +606,20 @@ static int chown_common(struct dentry *
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto out;
++
++ if (inode->i_op->setattr_raw) {
++ struct inode_operations *op = dentry->d_inode->i_op;
++
++ newattrs.ia_uid = user;
++ newattrs.ia_gid = group;
++ newattrs.ia_valid = ATTR_UID | ATTR_GID;
++ newattrs.ia_valid |= ATTR_RAW;
++ error = op->setattr_raw(inode, &newattrs);
++ /* the file system wants to use normal vfs path now */
++ if (error != -EOPNOTSUPP)
++ return error;
++ }
++
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out;
+@@ -658,7 +740,8 @@ struct file *filp_open(const char * file
+ return ERR_PTR(error);
+ }
+
+-struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
++struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
++ int flags, struct lookup_intent *it)
+ {
+ struct file * f;
+ struct inode *inode;
+@@ -701,6 +784,7 @@ struct file *dentry_open(struct dentry *
+ }
+ f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
+
++ intent_release(dentry, it);
+ return f;
+
+ cleanup_all:
+@@ -715,11 +799,17 @@ cleanup_all:
+ cleanup_file:
+ put_filp(f);
+ cleanup_dentry:
++ intent_release(dentry, it);
+ dput(dentry);
+ mntput(mnt);
+ return ERR_PTR(error);
+ }
+
++struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
++{
++ return dentry_open_it(dentry, mnt, flags, NULL);
++}
++
+ /*
+ * Find an empty file descriptor entry, and mark it busy.
+ */
+--- linux-rh-2.4.20-6/fs/stat.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/fs/stat.c Tue Apr 1 01:03:23 2003
+@@ -111,10 +111,12 @@ int vfs_stat(char *name, struct kstat *s
+ {
+ struct nameidata nd;
+ int error;
++ struct lookup_intent it = { .it_op = IT_GETATTR };
+
+- error = user_path_walk(name, &nd);
++ error = user_path_walk_it(name, &nd, &it);
+ if (!error) {
+ error = do_getattr(nd.mnt, nd.dentry, stat);
++ intent_release(nd.dentry, &it);
+ path_release(&nd);
+ }
+ return error;
+@@ -124,10 +126,12 @@ int vfs_lstat(char *name, struct kstat *
+ {
+ struct nameidata nd;
+ int error;
++ struct lookup_intent it = { .it_op = IT_GETATTR };
+
+- error = user_path_walk_link(name, &nd);
++ error = user_path_walk_link_it(name, &nd, &it);
+ if (!error) {
+ error = do_getattr(nd.mnt, nd.dentry, stat);
++ intent_release(nd.dentry, &it);
+ path_release(&nd);
+ }
+ return error;
+--- linux-rh-2.4.20-6/fs/exec.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/fs/exec.c Wed Apr 2 00:29:56 2003
+@@ -114,8 +114,9 @@ asmlinkage long sys_uselib(const char *
+ struct file * file;
+ struct nameidata nd;
+ int error;
++ struct lookup_intent it = { .it_op = IT_OPEN, .it_flags = O_RDONLY };
+
+- error = user_path_walk(library, &nd);
++ error = user_path_walk_it(library, &nd, &it);
+ if (error)
+ goto out;
+
+@@ -127,7 +128,8 @@ asmlinkage long sys_uselib(const char *
+ if (error)
+ goto exit;
+
+- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++ file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it);
++ intent_release(nd.dentry, &it);
+ error = PTR_ERR(file);
+ if (IS_ERR(file))
+ goto out;
+@@ -382,8 +384,9 @@ struct file *open_exec(const char *name)
+ struct inode *inode;
+ struct file *file;
+ int err = 0;
++ struct lookup_intent it = { .it_op = IT_OPEN, .it_flags = O_RDONLY };
+
+- err = path_lookup(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd);
++ err = path_lookup_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd, &it);
+ file = ERR_PTR(err);
+ if (!err) {
+ inode = nd.dentry->d_inode;
+@@ -395,7 +398,8 @@ struct file *open_exec(const char *name)
+ err = -EACCES;
+ file = ERR_PTR(err);
+ if (!err) {
+- file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++ file = dentry_open_it(nd.dentry, nd.mnt, O_RDONLY, &it);
++ intent_release(nd.dentry, &it);
+ if (!IS_ERR(file)) {
+ err = deny_write_access(file);
+ if (err) {
+@@ -1279,7 +1283,7 @@ int do_coredump(long signr, int exit_cod
+ goto close_fail;
+ if (!file->f_op->write)
+ goto close_fail;
+- if (do_truncate(file->f_dentry, 0) != 0)
++ if (do_truncate(file->f_dentry, 0, 0) != 0)
+ goto close_fail;
+
+ retval = binfmt->core_dump(signr, regs, file);
+--- linux-rh-2.4.20-6/include/linux/dcache.h~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/include/linux/dcache.h Tue Apr 1 01:03:23 2003
+@@ -7,6 +7,25 @@
+ #include <linux/mount.h>
+ #include <linux/kernel.h>
+
++#define IT_OPEN (1)
++#define IT_CREAT (1<<1)
++#define IT_READDIR (1<<2)
++#define IT_GETATTR (1<<3)
++#define IT_LOOKUP (1<<4)
++#define IT_UNLINK (1<<5)
++
++struct lookup_intent {
++ int it_op;
++ int it_mode;
++ int it_flags;
++ int it_disposition;
++ int it_status;
++ struct iattr *it_iattr;
++ __u64 it_lock_handle[2];
++ int it_lock_mode;
++ void *it_data;
++};
++
+ /*
+ * linux/include/linux/dcache.h
+ *
+@@ -82,6 +101,7 @@ struct dentry {
+ unsigned long d_time; /* used by d_revalidate */
+ struct dentry_operations *d_op;
+ struct super_block * d_sb; /* The root of the dentry tree */
++ struct lookup_intent *d_it;
+ unsigned long d_vfs_flags;
+ void * d_fsdata; /* fs-specific data */
+ void * d_extra_attributes; /* TUX-specific data */
+@@ -96,8 +116,15 @@ struct dentry_operations {
+ int (*d_delete)(struct dentry *);
+ void (*d_release)(struct dentry *);
+ void (*d_iput)(struct dentry *, struct inode *);
++ int (*d_revalidate2)(struct dentry *, int, struct lookup_intent *);
++ void (*d_intent_release)(struct dentry *, struct lookup_intent *);
+ };
+
++/* defined in fs/namei.c */
++extern void intent_release(struct dentry *de, struct lookup_intent *it);
++/* defined in fs/dcache.c */
++extern void __d_rehash(struct dentry * entry, int lock);
++
+ /* the dentry parameter passed to d_hash and d_compare is the parent
+ * directory of the entries to be compared. It is used in case these
+ * functions need any directory specific information for determining
+@@ -129,6 +156,7 @@ d_iput: no no yes
+ * s_nfsd_free_path semaphore will be down
+ */
+ #define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
++#define DCACHE_LUSTRE_INVALID 0x0010 /* Lustre invalidated */
+
+ extern spinlock_t dcache_lock;
+
+--- linux-rh-2.4.20-6/include/linux/fs.h~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/include/linux/fs.h Wed Apr 2 02:13:01 2003
+@@ -1,3 +1,6 @@
++
++
++
+ #ifndef _LINUX_FS_H
+ #define _LINUX_FS_H
+
+@@ -337,6 +340,8 @@ extern void set_bh_page(struct buffer_he
+ #define ATTR_MTIME_SET 256
+ #define ATTR_FORCE 512 /* Not a change, but a change it */
+ #define ATTR_ATTR_FLAG 1024
++#define ATTR_RAW 2048 /* file system, not vfs will massage attrs */
++#define ATTR_FROM_OPEN 4096 /* called from open path, ie O_TRUNC */
+
+ /*
+ * This is the Inode Attributes structure, used for notify_change(). It
+@@ -574,6 +579,7 @@ struct file {
+
+ /* needed for tty driver, and maybe others */
+ void *private_data;
++ struct lookup_intent *f_intent;
+
+ /* preallocated helper kiobuf to speedup O_DIRECT */
+ struct kiobuf *f_iobuf;
+@@ -821,7 +827,9 @@ extern int vfs_symlink(struct inode *, s
+ extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
+ extern int vfs_rmdir(struct inode *, struct dentry *);
+ extern int vfs_unlink(struct inode *, struct dentry *);
+-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
++int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
++ struct inode *new_dir, struct dentry *new_dentry,
++ struct lookup_intent *it);
+
+ /*
+ * File types
+@@ -882,20 +890,33 @@ struct file_operations {
+ struct inode_operations {
+ int (*create) (struct inode *,struct dentry *,int);
+ struct dentry * (*lookup) (struct inode *,struct dentry *);
++ struct dentry * (*lookup2) (struct inode *,struct dentry *, struct lookup_intent *);
+ int (*link) (struct dentry *,struct inode *,struct dentry *);
++ int (*link2) (struct inode *,struct inode *, const char *, int);
+ int (*unlink) (struct inode *,struct dentry *);
++ int (*unlink2) (struct inode *, const char *, int);
+ int (*symlink) (struct inode *,struct dentry *,const char *);
++ int (*symlink2) (struct inode *, const char *, int, const char *);
+ int (*mkdir) (struct inode *,struct dentry *,int);
++ int (*mkdir2) (struct inode *, const char *, int,int);
+ int (*rmdir) (struct inode *,struct dentry *);
++ int (*rmdir2) (struct inode *, const char *, int);
+ int (*mknod) (struct inode *,struct dentry *,int,int);
++ int (*mknod2) (struct inode *, const char *, int,int,int);
+ int (*rename) (struct inode *, struct dentry *,
+ struct inode *, struct dentry *);
++ int (*rename2) (struct inode *, struct inode *,
++ const char *oldname, int oldlen,
++ const char *newname, int newlen);
+ int (*readlink) (struct dentry *, char *,int);
+ int (*follow_link) (struct dentry *, struct nameidata *);
++ int (*follow_link2) (struct dentry *, struct nameidata *,
++ struct lookup_intent *it);
+ void (*truncate) (struct inode *);
+ int (*permission) (struct inode *, int);
+ int (*revalidate) (struct dentry *);
+ int (*setattr) (struct dentry *, struct iattr *);
++ int (*setattr_raw) (struct inode *, struct iattr *);
+ int (*getattr) (struct dentry *, struct iattr *);
+ int (*setxattr) (struct dentry *, const char *, void *, size_t, int);
+ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
+@@ -1091,10 +1112,13 @@ static inline int get_lease(struct inode
+
+ asmlinkage long sys_open(const char *, int, int);
+ asmlinkage long sys_close(unsigned int); /* yes, it's really unsigned */
+-extern int do_truncate(struct dentry *, loff_t start);
++extern int do_truncate(struct dentry *, loff_t start, int called_from_open);
+
+ extern struct file *filp_open(const char *, int, int);
+ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
++extern struct file *dentry_open_it(struct dentry *dentry, struct vfsmount *mnt,
++ int flags, struct lookup_intent *it);
++extern int path_lookup_it(const char *path, unsigned flags, struct nameidata *nd, struct lookup_intent *it);
+ extern int filp_close(struct file *, fl_owner_t id);
+ extern char * getname(const char *);
+
+@@ -1385,6 +1409,7 @@ typedef int (*read_actor_t)(read_descrip
+ extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
+
+ extern int FASTCALL(__user_walk(const char *, unsigned, struct nameidata *));
++extern int FASTCALL(__user_walk_it(const char *, unsigned, struct nameidata *, struct lookup_intent *it));
+ extern int FASTCALL(path_init(const char *, unsigned, struct nameidata *));
+ extern int FASTCALL(path_walk(const char *, struct nameidata *));
+ extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
+@@ -1396,6 +1421,8 @@ extern struct dentry * lookup_one_len(co
+ extern struct dentry * lookup_hash(struct qstr *, struct dentry *);
+ #define user_path_walk(name,nd) __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
+ #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
++#define user_path_walk_it(name,nd,it) __user_walk_it(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd, it)
++#define user_path_walk_link_it(name,nd,it) __user_walk_it(name, LOOKUP_POSITIVE, nd, it)
+
+ extern void inode_init_once(struct inode *);
+ extern void iput(struct inode *);
+@@ -1495,6 +1522,8 @@ extern struct file_operations generic_ro
+
+ extern int vfs_readlink(struct dentry *, char *, int, const char *);
+ extern int vfs_follow_link(struct nameidata *, const char *);
++extern int vfs_follow_link_it(struct nameidata *, const char *,
++ struct lookup_intent *it);
+ extern int page_readlink(struct dentry *, char *, int);
+ extern int page_follow_link(struct dentry *, struct nameidata *);
+ extern struct inode_operations page_symlink_inode_operations;
+--- linux-rh-2.4.20-6/kernel/ksyms.c~vfs_intent-2.4.20 Tue Apr 1 01:03:23 2003
++++ linux-rh-2.4.20-6-braam/kernel/ksyms.c Tue Apr 1 01:03:23 2003
+@@ -298,6 +298,7 @@ EXPORT_SYMBOL(read_cache_page);
+ EXPORT_SYMBOL(set_page_dirty);
+ EXPORT_SYMBOL(vfs_readlink);
+ EXPORT_SYMBOL(vfs_follow_link);
++EXPORT_SYMBOL(vfs_follow_link_it);
+ EXPORT_SYMBOL(page_readlink);
+ EXPORT_SYMBOL(page_follow_link);
+ EXPORT_SYMBOL(page_symlink_inode_operations);
+
+_