diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-05-19 19:26:35 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-05-19 19:26:35 -0700 |
| commit | 6033f0244d5e29cc16670e4106b9a823ecedfb6c (patch) | |
| tree | 415c4d9af0be0b9583ededab16473d3bd33c3640 | |
| parent | 80be221757caf0b316622eb1852ecabd77e1163d (diff) | |
| parent | 9b406173ebec1ced8c3071d6df1f025aa9a1d488 (diff) | |
Merge
| -rw-r--r-- | Documentation/filesystems/Locking | 2 | ||||
| -rw-r--r-- | Documentation/filesystems/porting | 35 | ||||
| -rw-r--r-- | fs/Makefile | 2 | ||||
| -rw-r--r-- | fs/coda/cnode.c | 100 | ||||
| -rw-r--r-- | fs/coda/inode.c | 14 | ||||
| -rw-r--r-- | fs/inode.c | 186 | ||||
| -rw-r--r-- | fs/nfs/inode.c | 44 | ||||
| -rw-r--r-- | fs/reiserfs/inode.c | 62 | ||||
| -rw-r--r-- | fs/reiserfs/super.c | 14 | ||||
| -rw-r--r-- | include/linux/fs.h | 30 | ||||
| -rw-r--r-- | include/linux/nfs_fs.h | 2 | ||||
| -rw-r--r-- | include/linux/reiserfs_fs.h | 8 | ||||
| -rw-r--r-- | kernel/ksyms.c | 3 |
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); |
