summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-05-19 19:26:35 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-05-19 19:26:35 -0700
commit6033f0244d5e29cc16670e4106b9a823ecedfb6c (patch)
tree415c4d9af0be0b9583ededab16473d3bd33c3640
parent80be221757caf0b316622eb1852ecabd77e1163d (diff)
parent9b406173ebec1ced8c3071d6df1f025aa9a1d488 (diff)
Merge
-rw-r--r--Documentation/filesystems/Locking2
-rw-r--r--Documentation/filesystems/porting35
-rw-r--r--fs/Makefile2
-rw-r--r--fs/coda/cnode.c100
-rw-r--r--fs/coda/inode.c14
-rw-r--r--fs/inode.c186
-rw-r--r--fs/nfs/inode.c44
-rw-r--r--fs/reiserfs/inode.c62
-rw-r--r--fs/reiserfs/super.c14
-rw-r--r--include/linux/fs.h30
-rw-r--r--include/linux/nfs_fs.h2
-rw-r--r--include/linux/reiserfs_fs.h8
-rw-r--r--kernel/ksyms.c3
13 files changed, 325 insertions, 177 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 1acc415a99a3..72288b4d8f9e 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -115,7 +115,7 @@ statfs: yes no no
remount_fs: yes yes maybe (see below)
umount_begin: yes no maybe (see below)
-->read_inode() is not a method - it's a callback used in iget()/iget4().
+->read_inode() is not a method - it's a callback used in iget().
rules for mount_sem are not too nice - it is going to die and be replaced
by better scheme anyway.
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index df06a180b650..5e1e47711009 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -152,3 +152,38 @@ settles down a bit.
s_export_op is now required for exporting a filesystem.
isofs, ext2, ext3, resierfs, fat
can be used as examples of very different filesystems.
+
+---
+[mandatory]
+
+iget4() and the read_inode2 callback have been superseded by iget5_locked()
+which has the following prototype,
+
+ struct inode *iget5_locked(struct super_block *sb, unsigned long ino,
+ int (*test)(struct inode *, void *),
+ int (*set)(struct inode *, void *),
+ void *data);
+
+'test' is an additional function that can be used when the inode
+number is not sufficient to identify the actual file object. 'set'
+should be a non-blocking function that initializes those parts of a
+newly created inode to allow the test function to succeed. 'data' is
+passed as an opaque value to both test and set functions.
+
+When the inode has been created by iget5_locked(), it will be returned with
+the I_NEW flag set and will still be locked. read_inode has not been
+called so the file system still has to finalize the initialization. Once
+the inode is initialized it must be unlocked by calling unlock_new_inode().
+
+The filesystem is responsible for setting (and possibly testing) i_ino
+when appropriate. There is also a simpler iget_locked function that
+just takes the superblock and inode number as arguments and does the
+test and set for you.
+
+e.g.
+ inode = iget_locked(sb, ino);
+ if (inode->i_state & I_NEW) {
+ read_inode_from_disk(inode);
+ unlock_new_inode(inode);
+ }
+
diff --git a/fs/Makefile b/fs/Makefile
index 2449b05e367a..1d40929ad7bd 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -7,7 +7,7 @@
O_TARGET := fs.o
-export-objs := filesystems.o open.o dcache.o buffer.o bio.o
+export-objs := filesystems.o open.o dcache.o buffer.o bio.o inode.o
mod-subdirs := nls
obj-y := open.o read_write.o devices.o file_table.o buffer.o \
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 6d260b30d551..60ee649aacc5 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -25,11 +25,6 @@ inline int coda_isnullfid(ViceFid *fid)
return 1;
}
-static int coda_inocmp(struct inode *inode, unsigned long ino, void *opaque)
-{
- return (coda_fideq((ViceFid *)opaque, &(ITOC(inode)->c_fid)));
-}
-
static struct inode_operations coda_symlink_inode_operations = {
readlink: page_readlink,
follow_link: page_follow_link,
@@ -55,26 +50,44 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
init_special_inode(inode, inode->i_mode, attr->va_rdev);
}
+static int coda_test_inode(struct inode *inode, void *data)
+{
+ ViceFid *fid = (ViceFid *)data;
+ return coda_fideq(&(ITOC(inode)->c_fid), fid);
+}
+
+static int coda_set_inode(struct inode *inode, void *data)
+{
+ ViceFid *fid = (ViceFid *)data;
+ ITOC(inode)->c_fid = *fid;
+ return 0;
+}
+
+static int coda_fail_inode(struct inode *inode, void *data)
+{
+ return -1;
+}
+
struct inode * coda_iget(struct super_block * sb, ViceFid * fid,
struct coda_vattr * attr)
{
struct inode *inode;
struct coda_inode_info *cii;
- ino_t ino = coda_f2i(fid);
+ struct coda_sb_info *sbi = coda_sbp(sb);
+ unsigned long hash = coda_f2i(fid);
- inode = iget4(sb, ino, coda_inocmp, fid);
+ inode = iget5_locked(sb, hash, coda_test_inode, coda_set_inode, fid);
if (!inode)
return ERR_PTR(-ENOMEM);
- /* check if the inode is already initialized */
- cii = ITOC(inode);
- if (coda_isnullfid(&cii->c_fid))
- /* new, empty inode found... initializing */
- cii->c_fid = *fid;
-
- /* we shouldnt see inode collisions anymore */
- if (!coda_fideq(fid, &cii->c_fid)) BUG();
+ if (inode->i_state & I_NEW) {
+ cii = ITOC(inode);
+ /* we still need to set i_ino for things like stat(2) */
+ inode->i_ino = hash;
+ list_add(&cii->c_cilist, &sbi->sbi_cihead);
+ unlock_new_inode(inode);
+ }
/* always replace the attributes, type might have changed */
coda_fill_inode(inode, attr);
@@ -112,6 +125,7 @@ void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid,
struct ViceFid *newfid)
{
struct coda_inode_info *cii;
+ unsigned long hash = coda_f2i(newfid);
cii = ITOC(inode);
@@ -122,60 +136,46 @@ void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid,
/* XXX we probably need to hold some lock here! */
remove_inode_hash(inode);
cii->c_fid = *newfid;
- inode->i_ino = coda_f2i(newfid);
- insert_inode_hash(inode);
+ inode->i_ino = hash;
+ __insert_inode_hash(inode, hash);
}
/* convert a fid to an inode. */
struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb)
{
- ino_t nr;
struct inode *inode;
- struct coda_inode_info *cii;
+ unsigned long hash = coda_f2i(fid);
if ( !sb ) {
printk("coda_fid_to_inode: no sb!\n");
return NULL;
}
- nr = coda_f2i(fid);
- inode = iget4(sb, nr, coda_inocmp, fid);
- if ( !inode ) {
- printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n",
- sb, (long)nr);
+ inode = iget5_locked(sb, hash, coda_test_inode, coda_fail_inode, fid);
+ if ( !inode )
return NULL;
- }
- cii = ITOC(inode);
+ /* we should never see newly created inodes because we intentionally
+ * fail in the initialization callback */
+ BUG_ON(inode->i_state & I_NEW);
- /* The inode could already be purged due to memory pressure */
- if (coda_isnullfid(&cii->c_fid)) {
- inode->i_nlink = 0;
- iput(inode);
- return NULL;
- }
-
- /* we shouldn't see inode collisions anymore */
- if ( !coda_fideq(fid, &cii->c_fid) ) BUG();
-
- return inode;
+ return inode;
}
/* the CONTROL inode is made without asking attributes from Venus */
int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
{
- int error = 0;
-
- *inode = iget(sb, CTL_INO);
- if ( *inode ) {
- (*inode)->i_op = &coda_ioctl_inode_operations;
- (*inode)->i_fop = &coda_ioctl_operations;
- (*inode)->i_mode = 0444;
- error = 0;
- } else {
- error = -ENOMEM;
- }
-
- return error;
+ int error = -ENOMEM;
+
+ *inode = new_inode(sb);
+ if (*inode) {
+ (*inode)->i_ino = CTL_INO;
+ (*inode)->i_op = &coda_ioctl_inode_operations;
+ (*inode)->i_fop = &coda_ioctl_operations;
+ (*inode)->i_mode = 0444;
+ error = 0;
+ }
+
+ return error;
}
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 8a68f2a13461..621074e23410 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -33,7 +33,6 @@
#include <linux/coda_cache.h>
/* VFS super_block ops */
-static void coda_read_inode(struct inode *);
static void coda_clear_inode(struct inode *);
static void coda_put_super(struct super_block *);
static int coda_statfs(struct super_block *sb, struct statfs *buf);
@@ -92,7 +91,6 @@ struct super_operations coda_super_operations =
{
alloc_inode: coda_alloc_inode,
destroy_inode: coda_destroy_inode,
- read_inode: coda_read_inode,
clear_inode: coda_clear_inode,
put_super: coda_put_super,
statfs: coda_statfs,
@@ -229,18 +227,6 @@ static void coda_put_super(struct super_block *sb)
kfree(sbi);
}
-/* all filling in of inodes postponed until lookup */
-static void coda_read_inode(struct inode *inode)
-{
- struct coda_sb_info *sbi = coda_sbp(inode->i_sb);
- struct coda_inode_info *cii;
-
- if (!sbi) BUG();
-
- cii = ITOC(inode);
- list_add(&cii->c_cilist, &sbi->sbi_cihead);
-}
-
static void coda_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
diff --git a/fs/inode.c b/fs/inode.c
index 503e500b6584..25c7eb858377 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -12,6 +12,7 @@
#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/writeback.h>
+#include <linux/module.h>
#include <linux/backing-dev.h>
/*
@@ -443,7 +444,32 @@ int shrink_icache_memory(int priority, int gfp_mask)
* by hand after calling find_inode now! This simplifies iunique and won't
* add any additional branch in the common code.
*/
-static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
+static struct inode * find_inode(struct super_block * sb, struct list_head *head, int (*test)(struct inode *, void *), void *data)
+{
+ struct list_head *tmp;
+ struct inode * inode;
+
+ tmp = head;
+ for (;;) {
+ tmp = tmp->next;
+ inode = NULL;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_hash);
+ if (inode->i_sb != sb)
+ continue;
+ if (!test(inode, data))
+ continue;
+ break;
+ }
+ return inode;
+}
+
+/*
+ * find_inode_fast is the fast path version of find_inode, see the comment at
+ * iget_locked for details.
+ */
+static struct inode * find_inode_fast(struct super_block * sb, struct list_head *head, unsigned long ino)
{
struct list_head *tmp;
struct inode * inode;
@@ -459,8 +485,6 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
continue;
if (inode->i_sb != sb)
continue;
- if (find_actor && !find_actor(inode, ino, opaque))
- continue;
break;
}
return inode;
@@ -492,13 +516,28 @@ struct inode *new_inode(struct super_block *sb)
return inode;
}
+void unlock_new_inode(struct inode *inode)
+{
+ /*
+ * This is special! We do not need the spinlock
+ * when clearing I_LOCK, because we're guaranteed
+ * that nobody else tries to do anything about the
+ * state of the inode when it is locked, as we
+ * just created it (so there can be no old holders
+ * that haven't tested I_LOCK).
+ */
+ inode->i_state &= ~(I_LOCK|I_NEW);
+ wake_up(&inode->i_wait);
+}
+
+
/*
* This is called without the inode lock held.. Be careful.
*
* We no longer cache the sb_flags in i_flags - see fs.h
* -- rmk@arm.uk.linux.org
*/
-static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
+static struct inode * get_new_inode(struct super_block *sb, struct list_head *head, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data)
{
struct inode * inode;
@@ -508,37 +547,68 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
spin_lock(&inode_lock);
/* We released the lock, so.. */
- old = find_inode(sb, ino, head, find_actor, opaque);
+ old = find_inode(sb, head, test, data);
if (!old) {
+ if (set(inode, data))
+ goto set_failed;
+
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_hash, head);
- inode->i_ino = ino;
- inode->i_state = I_LOCK;
+ inode->i_state = I_LOCK|I_NEW;
spin_unlock(&inode_lock);
- /* reiserfs specific hack right here. We don't
- ** want this to last, and are looking for VFS changes
- ** that will allow us to get rid of it.
- ** -- mason@suse.com
- */
- if (sb->s_op->read_inode2) {
- sb->s_op->read_inode2(inode, opaque) ;
- } else {
- sb->s_op->read_inode(inode);
- }
-
- /*
- * This is special! We do not need the spinlock
- * when clearing I_LOCK, because we're guaranteed
- * that nobody else tries to do anything about the
- * state of the inode when it is locked, as we
- * just created it (so there can be no old holders
- * that haven't tested I_LOCK).
+ /* Return the locked inode with I_NEW set, the
+ * caller is responsible for filling in the contents
*/
- inode->i_state &= ~I_LOCK;
- wake_up(&inode->i_wait);
+ return inode;
+ }
+
+ /*
+ * Uhhuh, somebody else created the same inode under
+ * us. Use the old inode instead of the one we just
+ * allocated.
+ */
+ __iget(old);
+ spin_unlock(&inode_lock);
+ destroy_inode(inode);
+ inode = old;
+ wait_on_inode(inode);
+ }
+ return inode;
+
+set_failed:
+ spin_unlock(&inode_lock);
+ destroy_inode(inode);
+ return NULL;
+}
+
+/*
+ * get_new_inode_fast is the fast path version of get_new_inode, see the
+ * comment at iget_locked for details.
+ */
+static struct inode * get_new_inode_fast(struct super_block *sb, struct list_head *head, unsigned long ino)
+{
+ struct inode * inode;
+ inode = alloc_inode(sb);
+ if (inode) {
+ struct inode * old;
+
+ spin_lock(&inode_lock);
+ /* We released the lock, so.. */
+ old = find_inode_fast(sb, head, ino);
+ if (!old) {
+ inode->i_ino = ino;
+ inodes_stat.nr_inodes++;
+ list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_hash, head);
+ inode->i_state = I_LOCK|I_NEW;
+ spin_unlock(&inode_lock);
+
+ /* Return the locked inode with I_NEW set, the
+ * caller is responsible for filling in the contents
+ */
return inode;
}
@@ -556,9 +626,9 @@ static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, s
return inode;
}
-static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
+static inline unsigned long hash(struct super_block *sb, unsigned long hashval)
{
- unsigned long tmp = i_ino + ((unsigned long) sb / L1_CACHE_BYTES);
+ unsigned long tmp = hashval + ((unsigned long) sb / L1_CACHE_BYTES);
tmp = tmp + (tmp >> I_HASHBITS);
return tmp & I_HASHMASK;
}
@@ -590,7 +660,8 @@ ino_t iunique(struct super_block *sb, ino_t max_reserved)
retry:
if (counter > max_reserved) {
head = inode_hashtable + hash(sb,counter);
- inode = find_inode(sb, res = counter++, head, NULL, NULL);
+ res = counter++;
+ inode = find_inode_fast(sb, head, res);
if (!inode) {
spin_unlock(&inode_lock);
return res;
@@ -618,14 +689,18 @@ struct inode *igrab(struct inode *inode)
return inode;
}
-
-struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
+/*
+ * This is iget without the read_inode portion of get_new_inode
+ * the filesystem gets back a new locked and hashed inode and gets
+ * to fill it in before unlocking it via unlock_new_inode().
+ */
+struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data)
{
- struct list_head * head = inode_hashtable + hash(sb,ino);
+ struct list_head * head = inode_hashtable + hash(sb, hashval);
struct inode * inode;
spin_lock(&inode_lock);
- inode = find_inode(sb, ino, head, find_actor, opaque);
+ inode = find_inode(sb, head, test, data);
if (inode) {
__iget(inode);
spin_unlock(&inode_lock);
@@ -638,22 +713,57 @@ struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find
* get_new_inode() will do the right thing, re-trying the search
* in case it had to block at any point.
*/
- return get_new_inode(sb, ino, head, find_actor, opaque);
+ return get_new_inode(sb, head, test, set, data);
}
+/*
+ * Because most filesystems are based on 32-bit unique inode numbers some
+ * functions are duplicated to keep iget_locked as a fast path. We can avoid
+ * unnecessary pointer dereferences and function calls for this specific
+ * case. The duplicated functions (find_inode_fast and get_new_inode_fast)
+ * have the same pre- and post-conditions as their original counterparts.
+ */
+struct inode *iget_locked(struct super_block *sb, unsigned long ino)
+{
+ struct list_head * head = inode_hashtable + hash(sb, ino);
+ struct inode * inode;
+
+ spin_lock(&inode_lock);
+ inode = find_inode_fast(sb, head, ino);
+ if (inode) {
+ __iget(inode);
+ spin_unlock(&inode_lock);
+ wait_on_inode(inode);
+ return inode;
+ }
+ spin_unlock(&inode_lock);
+
+ /*
+ * get_new_inode_fast() will do the right thing, re-trying the search
+ * in case it had to block at any point.
+ */
+ return get_new_inode_fast(sb, head, ino);
+}
+
+EXPORT_SYMBOL(iget5_locked);
+EXPORT_SYMBOL(iget_locked);
+EXPORT_SYMBOL(unlock_new_inode);
+
/**
- * insert_inode_hash - hash an inode
+ * __insert_inode_hash - hash an inode
* @inode: unhashed inode
+ * @hashval: unsigned long value used to locate this object in the
+ * inode_hashtable.
*
* Add an inode to the inode hash for this superblock. If the inode
* has no superblock it is added to a separate anonymous chain.
*/
-void insert_inode_hash(struct inode *inode)
+void __insert_inode_hash(struct inode *inode, unsigned long hashval)
{
struct list_head *head = &anon_hash_chain;
if (inode->i_sb)
- head = inode_hashtable + hash(inode->i_sb, inode->i_ino);
+ head = inode_hashtable + hash(inode->i_sb, hashval);
spin_lock(&inode_lock);
list_add(&inode->i_hash, head);
spin_unlock(&inode_lock);
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 5a105fc344eb..ea03c0e8a850 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -47,7 +47,6 @@ static void nfs_invalidate_inode(struct inode *);
static struct inode *nfs_alloc_inode(struct super_block *sb);
static void nfs_destroy_inode(struct inode *);
-static void nfs_read_inode(struct inode *);
static void nfs_write_inode(struct inode *,int);
static void nfs_delete_inode(struct inode *);
static void nfs_put_super(struct super_block *);
@@ -59,7 +58,6 @@ static int nfs_show_options(struct seq_file *, struct vfsmount *);
static struct super_operations nfs_sops = {
alloc_inode: nfs_alloc_inode,
destroy_inode: nfs_destroy_inode,
- read_inode: nfs_read_inode,
write_inode: nfs_write_inode,
delete_inode: nfs_delete_inode,
put_super: nfs_put_super,
@@ -98,15 +96,6 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
return nfs_fileid_to_ino_t(fattr->fileid);
}
-/*
- * The "read_inode" function doesn't actually do anything:
- * the real data is filled in later in nfs_fhget.
- */
-static void
-nfs_read_inode(struct inode * inode)
-{
-}
-
static void
nfs_write_inode(struct inode *inode, int sync)
{
@@ -592,7 +581,7 @@ struct nfs_find_desc {
* i_ino.
*/
static int
-nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
+nfs_find_actor(struct inode *inode, void *opaque)
{
struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque;
struct nfs_fh *fh = desc->fh;
@@ -610,6 +599,18 @@ nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
return 1;
}
+static int
+nfs_init_locked(struct inode *inode, void *opaque)
+{
+ struct nfs_find_desc *desc = (struct nfs_find_desc *)opaque;
+ struct nfs_fh *fh = desc->fh;
+ struct nfs_fattr *fattr = desc->fattr;
+
+ NFS_FILEID(inode) = fattr->fileid;
+ memcpy(NFS_FH(inode), fh, sizeof(struct nfs_fh));
+ return 0;
+}
+
/*
* This is our own version of iget that looks up inodes by file handle
* instead of inode number. We use this technique instead of using
@@ -640,7 +641,7 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
fattr: fattr
};
struct inode *inode = NULL;
- unsigned long ino;
+ unsigned long hash;
if ((fattr->valid & NFS_ATTR_FATTR) == 0)
goto out_no_inode;
@@ -650,20 +651,21 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
goto out_no_inode;
}
- ino = nfs_fattr_to_ino_t(fattr);
+ hash = nfs_fattr_to_ino_t(fattr);
- if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
+ if (!(inode = iget5_locked(sb, hash, nfs_find_actor, nfs_init_locked, &desc)))
goto out_no_inode;
- if (NFS_NEW(inode)) {
+ if (inode->i_state & I_NEW) {
__u64 new_size, new_mtime;
loff_t new_isize;
time_t new_atime;
+ /* We set i_ino for the few things that still rely on it,
+ * such as stat(2) */
+ inode->i_ino = hash;
+
/* We can't support UPDATE_ATIME(), since the server will reset it */
- NFS_FLAGS(inode) &= ~NFS_INO_NEW;
- NFS_FILEID(inode) = fattr->fileid;
- memcpy(NFS_FH(inode), fh, sizeof(struct nfs_fh));
inode->i_flags |= S_NOATIME;
inode->i_mode = fattr->mode;
/* Why so? Because we want revalidate for devices/FIFOs, and
@@ -711,6 +713,8 @@ __nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+
+ unlock_new_inode(inode);
} else
nfs_refresh_inode(inode, fattr);
dprintk("NFS: __nfs_fhget(%s/%Ld ct=%d)\n",
@@ -1231,7 +1235,7 @@ static struct inode *nfs_alloc_inode(struct super_block *sb)
nfsi = (struct nfs_inode *)kmem_cache_alloc(nfs_inode_cachep, SLAB_KERNEL);
if (!nfsi)
return NULL;
- nfsi->flags = NFS_INO_NEW;
+ nfsi->flags = 0;
nfsi->mm_cred = NULL;
return &nfsi->vfs_inode;
}
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 9c0b7c00af4f..2c1e3ee268b0 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -33,7 +33,7 @@ void reiserfs_delete_inode (struct inode * inode)
lock_kernel() ;
/* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
- if (INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
+ if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
down (&inode->i_sem);
journal_begin(&th, inode->i_sb, jbegin_count) ;
@@ -886,7 +886,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block,
// item version directly
//
-// called by read_inode
+// called by read_locked_inode
static void init_inode (struct inode * inode, struct path * path)
{
struct buffer_head * bh;
@@ -1117,7 +1117,7 @@ void reiserfs_update_sd (struct reiserfs_transaction_handle *th,
return;
}
-/* reiserfs_read_inode2 is called to read the inode off disk, and it
+/* reiserfs_read_locked_inode is called to read the inode off disk, and it
** does a make_bad_inode when things go wrong. But, we need to make sure
** and clear the key in the private portion of the inode, otherwise a
** corresponding iput might try to delete whatever object the inode last
@@ -1128,32 +1128,29 @@ static void reiserfs_make_bad_inode(struct inode *inode) {
make_bad_inode(inode);
}
-void reiserfs_read_inode(struct inode *inode) {
- reiserfs_make_bad_inode(inode) ;
-}
-
-
//
// initially this function was derived from minix or ext2's analog and
// evolved as the prototype did
//
+int reiserfs_init_locked_inode (struct inode * inode, void *p)
+{
+ struct reiserfs_iget_args *args = (struct reiserfs_iget_args *)p ;
+ inode->i_ino = args->objectid;
+ INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->dirid);
+ return 0;
+}
+
/* looks for stat data in the tree, and fills up the fields of in-core
inode stat data fields */
-void reiserfs_read_inode2 (struct inode * inode, void *p)
+void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args *args)
{
INITIALIZE_PATH (path_to_sd);
struct cpu_key key;
- struct reiserfs_iget4_args *args = (struct reiserfs_iget4_args *)p ;
unsigned long dirino;
int retval;
- if (!p) {
- reiserfs_make_bad_inode(inode) ;
- return;
- }
-
- dirino = args->objectid ;
+ dirino = args->dirid ;
/* set version 1, version 2 could be used too, because stat data
key is the same in both versions */
@@ -1166,7 +1163,7 @@ void reiserfs_read_inode2 (struct inode * inode, void *p)
/* look for the object's stat data */
retval = search_item (inode->i_sb, &key, &path_to_sd);
if (retval == IO_ERROR) {
- reiserfs_warning ("vs-13070: reiserfs_read_inode2: "
+ reiserfs_warning ("vs-13070: reiserfs_read_locked_inode: "
"i/o failure occurred trying to find stat data of %K\n",
&key);
reiserfs_make_bad_inode(inode) ;
@@ -1198,7 +1195,7 @@ void reiserfs_read_inode2 (struct inode * inode, void *p)
during mount (fs/reiserfs/super.c:finish_unfinished()). */
if( ( inode -> i_nlink == 0 ) &&
! REISERFS_SB(inode -> i_sb) -> s_is_unlinked_ok ) {
- reiserfs_warning( "vs-13075: reiserfs_read_inode2: "
+ reiserfs_warning( "vs-13075: reiserfs_read_locked_inode: "
"dead inode read from disk %K. "
"This is likely to be race with knfsd. Ignore\n",
&key );
@@ -1210,39 +1207,44 @@ void reiserfs_read_inode2 (struct inode * inode, void *p)
}
/**
- * reiserfs_find_actor() - "find actor" reiserfs supplies to iget4().
+ * reiserfs_find_actor() - "find actor" reiserfs supplies to iget5_locked().
*
* @inode: inode from hash table to check
- * @inode_no: inode number we are looking for
- * @opaque: "cookie" passed to iget4(). This is &reiserfs_iget4_args.
+ * @opaque: "cookie" passed to iget5_locked(). This is &reiserfs_iget_args.
*
- * This function is called by iget4() to distinguish reiserfs inodes
+ * This function is called by iget5_locked() to distinguish reiserfs inodes
* having the same inode numbers. Such inodes can only exist due to some
* error condition. One of them should be bad. Inodes with identical
* inode numbers (objectids) are distinguished by parent directory ids.
*
*/
-static int reiserfs_find_actor( struct inode *inode,
- unsigned long inode_no, void *opaque )
+int reiserfs_find_actor( struct inode *inode, void *opaque )
{
- struct reiserfs_iget4_args *args;
+ struct reiserfs_iget_args *args;
args = opaque;
/* args is already in CPU order */
- return le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args -> objectid;
+ return (inode->i_ino == args->objectid) &&
+ (le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args->dirid);
}
struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key)
{
struct inode * inode;
- struct reiserfs_iget4_args args ;
+ struct reiserfs_iget_args args ;
- args.objectid = key->on_disk_key.k_dir_id ;
- inode = iget4 (s, key->on_disk_key.k_objectid,
- reiserfs_find_actor, (void *)(&args));
+ args.objectid = key->on_disk_key.k_objectid ;
+ args.dirid = key->on_disk_key.k_dir_id ;
+ inode = iget5_locked (s, key->on_disk_key.k_objectid,
+ reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args));
if (!inode)
return ERR_PTR(-ENOMEM) ;
+ if (inode->i_state & I_NEW) {
+ reiserfs_read_locked_inode(inode, &args);
+ unlock_new_inode(inode);
+ }
+
if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
/* either due to i/o error or a stale NFS handle */
iput (inode);
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 46d63a4defbf..b52e704d6c7f 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -484,8 +484,6 @@ struct super_operations reiserfs_sops =
{
alloc_inode: reiserfs_alloc_inode,
destroy_inode: reiserfs_destroy_inode,
- read_inode: reiserfs_read_inode,
- read_inode2: reiserfs_read_inode2,
write_inode: reiserfs_write_inode,
dirty_inode: reiserfs_dirty_inode,
delete_inode: reiserfs_delete_inode,
@@ -1007,7 +1005,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
int old_format = 0;
unsigned long blocks;
int jinit_done = 0 ;
- struct reiserfs_iget4_args args ;
+ struct reiserfs_iget_args args ;
struct reiserfs_super_block * rs;
char *jdev_name;
struct reiserfs_sb_info *sbi;
@@ -1069,13 +1067,19 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
printk("clm-7000: Detected readonly device, marking FS readonly\n") ;
s->s_flags |= MS_RDONLY ;
}
- args.objectid = REISERFS_ROOT_PARENT_OBJECTID ;
- root_inode = iget4 (s, REISERFS_ROOT_OBJECTID, 0, (void *)(&args));
+ args.objectid = REISERFS_ROOT_OBJECTID ;
+ args.dirid = REISERFS_ROOT_PARENT_OBJECTID ;
+ root_inode = iget5_locked (s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args));
if (!root_inode) {
printk ("reiserfs_fill_super: get root inode failed\n");
goto error;
}
+ if (root_inode->i_state & I_NEW) {
+ reiserfs_read_locked_inode(root_inode, &args);
+ unlock_new_inode(root_inode);
+ }
+
s->s_root = d_alloc_root(root_inode);
if (!s->s_root) {
iput(root_inode);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9b2bfa8cc3d6..bb2e243a1713 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -771,13 +771,6 @@ struct super_operations {
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 *);
@@ -801,6 +794,7 @@ struct super_operations {
#define I_LOCK 8
#define I_FREEING 16
#define I_CLEAR 32
+#define I_NEW 64
#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
@@ -1208,19 +1202,33 @@ 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 *);
+extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
+extern struct inode * iget_locked(struct super_block *, unsigned long);
+extern void unlock_new_inode(struct inode *);
+
static inline struct inode *iget(struct super_block *sb, unsigned long ino)
{
- return iget4(sb, ino, NULL, NULL);
+ struct inode *inode = iget_locked(sb, ino);
+
+ if (inode && (inode->i_state & I_NEW)) {
+ sb->s_op->read_inode(inode);
+ unlock_new_inode(inode);
+ }
+
+ return inode;
}
extern void __iget(struct inode * inode);
extern void clear_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
extern void remove_suid(struct dentry *);
-extern void insert_inode_hash(struct inode *);
+
+extern void __insert_inode_hash(struct inode *, unsigned long hashval);
extern void remove_inode_hash(struct inode *);
+static inline void insert_inode_hash(struct inode *inode) {
+ __insert_inode_hash(inode, inode->i_ino);
+}
+
extern struct file * get_empty_filp(void);
extern void file_move(struct file *f, struct list_head *list);
extern void ll_rw_block(int, int, struct buffer_head * bh[]);
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 499b246788f4..a8a2259a8343 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -170,7 +170,6 @@ struct nfs_inode {
#define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */
#define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */
#define NFS_INO_FLUSH 0x0020 /* inode is due for flushing */
-#define NFS_INO_NEW 0x0040 /* hadn't been filled yet */
static inline struct nfs_inode *NFS_I(struct inode *inode)
{
@@ -208,7 +207,6 @@ do { \
#define NFS_FLAGS(inode) (NFS_I(inode)->flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE)
-#define NFS_NEW(inode) (NFS_FLAGS(inode) & NFS_INO_NEW)
#define NFS_FILEID(inode) (NFS_I(inode)->fileid)
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index e98ccaf9d217..173279f6ff0a 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -1564,8 +1564,9 @@ extern struct item_operations * item_ops [TYPE_ANY + 1];
#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
-struct reiserfs_iget4_args {
+struct reiserfs_iget_args {
__u32 objectid ;
+ __u32 dirid ;
} ;
/***************************************************************************/
@@ -1818,8 +1819,9 @@ void padd_item (char * item, int total_length, int length);
/* inode.c */
-void reiserfs_read_inode (struct inode * inode) ;
-void reiserfs_read_inode2(struct inode * inode, void *p) ;
+void reiserfs_read_locked_inode(struct inode * inode, struct reiserfs_iget_args *args) ;
+int reiserfs_find_actor(struct inode * inode, void *p) ;
+int reiserfs_init_locked_inode(struct inode * inode, void *p) ;
void reiserfs_delete_inode (struct inode * inode);
void reiserfs_write_inode (struct inode * inode, int) ;
struct dentry *reiserfs_get_dentry(struct super_block *, void *) ;
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 3963850911bc..c00aef0e313e 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -137,7 +137,6 @@ 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);
@@ -540,7 +539,7 @@ EXPORT_SYMBOL(clear_inode);
EXPORT_SYMBOL(init_special_inode);
EXPORT_SYMBOL(__get_hash_table);
EXPORT_SYMBOL(new_inode);
-EXPORT_SYMBOL(insert_inode_hash);
+EXPORT_SYMBOL(__insert_inode_hash);
EXPORT_SYMBOL(remove_inode_hash);
EXPORT_SYMBOL(buffer_insert_list);
EXPORT_SYMBOL(make_bad_inode);