From 40a79032efbe6e26aa0c921ee864fef4b0e3a881 Mon Sep 17 00:00:00 2001 From: braam Date: Wed, 2 Apr 2003 13:12:21 +0000 Subject: [PATCH] update patches for 2.4.20. The HP kernel might well work if we are lucky. the redhat 2.4.20 kernel is next in line --- .../patches/dev_read_only_2.4.20.patch | 73 + lustre/kernel_patches/patches/exports_2.4.20.patch | 4129 ++++++++++++++++++++ .../kernel_patches/patches/vfs_intent-2.4.20.patch | 1468 +++++++ lustre/kernel_patches/pc/dev_read_only_2.4.20.pc | 3 + lustre/kernel_patches/pc/exports_2.4.20.pc | 4 + lustre/kernel_patches/pc/vfs_intent-2.4.20.pc | 9 + lustre/kernel_patches/series/hp-pnnl-2.4.20 | 8 + lustre/kernel_patches/series/hp-pnnl-2.4.20.orig | 8 + lustre/kernel_patches/series/rh-2.4.20 | 11 + 9 files changed, 5713 insertions(+) create mode 100644 lustre/kernel_patches/patches/dev_read_only_2.4.20.patch create mode 100644 lustre/kernel_patches/patches/exports_2.4.20.patch create mode 100644 lustre/kernel_patches/patches/vfs_intent-2.4.20.patch create mode 100644 lustre/kernel_patches/pc/dev_read_only_2.4.20.pc create mode 100644 lustre/kernel_patches/pc/exports_2.4.20.pc create mode 100644 lustre/kernel_patches/pc/vfs_intent-2.4.20.pc create mode 100644 lustre/kernel_patches/series/hp-pnnl-2.4.20 create mode 100644 lustre/kernel_patches/series/hp-pnnl-2.4.20.orig create mode 100644 lustre/kernel_patches/series/rh-2.4.20 diff --git a/lustre/kernel_patches/patches/dev_read_only_2.4.20.patch b/lustre/kernel_patches/patches/dev_read_only_2.4.20.patch new file mode 100644 index 0000000..c6ebe7c --- /dev/null +++ b/lustre/kernel_patches/patches/dev_read_only_2.4.20.patch @@ -0,0 +1,73 @@ + drivers/block/blkpg.c | 35 +++++++++++++++++++++++++++++++++++ + drivers/block/loop.c | 3 +++ + drivers/ide/ide-disk.c | 4 ++++ + 3 files changed, 42 insertions(+) + +--- linux-rh-2.4.20-6/drivers/block/blkpg.c~dev_read_only_2.4.20 Mon Mar 31 23:41:44 2003 ++++ linux-rh-2.4.20-6-braam/drivers/block/blkpg.c Mon Mar 31 23:41:44 2003 +@@ -297,3 +297,38 @@ int blk_ioctl(kdev_t dev, unsigned int c + } + + EXPORT_SYMBOL(blk_ioctl); ++ ++#define NUM_DEV_NO_WRITE 16 ++static int dev_no_write[NUM_DEV_NO_WRITE]; ++ ++/* ++ * Debug code for turning block devices "read-only" (will discard writes ++ * silently). This is for filesystem crash/recovery testing. ++ */ ++void dev_set_rdonly(kdev_t dev, int no_write) ++{ ++ if (dev) { ++ printk(KERN_WARNING "Turning device %s read-only\n", ++ bdevname(dev)); ++ dev_no_write[no_write] = 0xdead0000 + dev; ++ } ++} ++ ++int dev_check_rdonly(kdev_t dev) { ++ int i; ++ ++ for (i = 0; i < NUM_DEV_NO_WRITE; i++) { ++ if ((dev_no_write[i] & 0xffff0000) == 0xdead0000 && ++ dev == (dev_no_write[i] & 0xffff)) ++ return 1; ++ } ++ return 0; ++} ++ ++void dev_clear_rdonly(int no_write) { ++ dev_no_write[no_write] = 0; ++} ++ ++EXPORT_SYMBOL(dev_set_rdonly); ++EXPORT_SYMBOL(dev_check_rdonly); ++EXPORT_SYMBOL(dev_clear_rdonly); +--- linux-rh-2.4.20-6/drivers/block/loop.c~dev_read_only_2.4.20 Mon Mar 31 23:41:44 2003 ++++ linux-rh-2.4.20-6-braam/drivers/block/loop.c Mon Mar 31 23:41:44 2003 +@@ -491,6 +491,9 @@ static int loop_make_request(request_que + spin_unlock_irq(&lo->lo_lock); + + if (rw == WRITE) { ++ if (dev_check_rdonly(rbh->b_rdev)) ++ goto err; ++ + if (lo->lo_flags & LO_FLAGS_READ_ONLY) + goto err; + } else if (rw == READA) { +--- linux-rh-2.4.20-6/drivers/ide/ide-disk.c~dev_read_only_2.4.20 Mon Mar 31 23:41:44 2003 ++++ linux-rh-2.4.20-6-braam/drivers/ide/ide-disk.c Mon Mar 31 23:43:28 2003 +@@ -551,6 +551,10 @@ static ide_startstop_t lba_48_rw_disk(id + */ + static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) + { ++ if (rq->cmd == WRITE && dev_check_rdonly(rq->rq_dev)) { ++ ide_end_request(1, HWGROUP(drive)); ++ return ide_stopped; ++ } + if (!blk_fs_request(rq)) { + printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); + idedisk_end_request(drive, 0); + +_ diff --git a/lustre/kernel_patches/patches/exports_2.4.20.patch b/lustre/kernel_patches/patches/exports_2.4.20.patch new file mode 100644 index 0000000..aa77f64 --- /dev/null +++ b/lustre/kernel_patches/patches/exports_2.4.20.patch @@ -0,0 +1,4129 @@ + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++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<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 ++#include ++ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * 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 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 ++#include ++ ++/* ++ * 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 ++ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 ++ */ ++ ++#define __KERNEL_SYSCALLS__ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#if defined(CONFIG_PROC_FS) ++#include ++#endif ++#ifdef CONFIG_KMOD ++#include ++#endif ++#ifdef CONFIG_KALLSYMS ++#include ++#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); + +_ diff --git a/lustre/kernel_patches/patches/vfs_intent-2.4.20.patch b/lustre/kernel_patches/patches/vfs_intent-2.4.20.patch new file mode 100644 index 0000000..8a5c674 --- /dev/null +++ b/lustre/kernel_patches/patches/vfs_intent-2.4.20.patch @@ -0,0 +1,1468 @@ + 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 + + #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 + #include + ++#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); + +_ diff --git a/lustre/kernel_patches/pc/dev_read_only_2.4.20.pc b/lustre/kernel_patches/pc/dev_read_only_2.4.20.pc new file mode 100644 index 0000000..4760ad1 --- /dev/null +++ b/lustre/kernel_patches/pc/dev_read_only_2.4.20.pc @@ -0,0 +1,3 @@ +drivers/block/blkpg.c +drivers/block/loop.c +drivers/ide/ide-disk.c diff --git a/lustre/kernel_patches/pc/exports_2.4.20.pc b/lustre/kernel_patches/pc/exports_2.4.20.pc new file mode 100644 index 0000000..6472a11 --- /dev/null +++ b/lustre/kernel_patches/pc/exports_2.4.20.pc @@ -0,0 +1,4 @@ +fs/ext3/Makefile +fs/ext3/super.c +include/linux/fs.h +kernel/ksyms.c diff --git a/lustre/kernel_patches/pc/vfs_intent-2.4.20.pc b/lustre/kernel_patches/pc/vfs_intent-2.4.20.pc new file mode 100644 index 0000000..dd2b1c8 --- /dev/null +++ b/lustre/kernel_patches/pc/vfs_intent-2.4.20.pc @@ -0,0 +1,9 @@ +fs/dcache.c +fs/namei.c +fs/nfsd/vfs.c +fs/open.c +fs/stat.c +fs/exec.c +include/linux/dcache.h +include/linux/fs.h +kernel/ksyms.c diff --git a/lustre/kernel_patches/series/hp-pnnl-2.4.20 b/lustre/kernel_patches/series/hp-pnnl-2.4.20 new file mode 100644 index 0000000..7708d1e --- /dev/null +++ b/lustre/kernel_patches/series/hp-pnnl-2.4.20 @@ -0,0 +1,8 @@ +dev_read_only_hp.patch +exports_hp.patch +kmem_cache_validate_hp.patch +lustre_version.patch +vfs_intent_hp.patch +invalidate_show.patch +iod-stock-24-exports_hp.patch +export-truncate.patch diff --git a/lustre/kernel_patches/series/hp-pnnl-2.4.20.orig b/lustre/kernel_patches/series/hp-pnnl-2.4.20.orig new file mode 100644 index 0000000..bf276fb --- /dev/null +++ b/lustre/kernel_patches/series/hp-pnnl-2.4.20.orig @@ -0,0 +1,8 @@ +dev_read_only_hp.patch +exports_hp.patch +kmem_cache_validate_hp.patch +jbd-transno-cb.patch +lustre_version.patch +vfs_intent_hp.patch +invalidate_show.patch +iod-stock-24-exports_hp.patch diff --git a/lustre/kernel_patches/series/rh-2.4.20 b/lustre/kernel_patches/series/rh-2.4.20 new file mode 100644 index 0000000..20614be --- /dev/null +++ b/lustre/kernel_patches/series/rh-2.4.20 @@ -0,0 +1,11 @@ +dev_read_only_2.4.20.patch +exports_2.4.20.patch +kmem_cache_validate_hp.patch +lustre_version.patch +vfs_intent-2.4.20.patch +invalidate_show.patch +iod-rmap-exports.patch +export-truncate.patch +uml_check_get_page.patch +uml_no_panic.patch +uml_compile_fixes.patch -- 1.8.3.1