From 5f39448d46d307b08f58eba59b8e0147b9e9fc45 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 7 Mar 2011 16:58:56 +1100 Subject: [PATCH] lafs_iget takes a filesystem-inode rather than a super_block. On the path to reducing the number of superblocks.... each superblock can hold multiple subset filesystems so we need more than the inode number to identify a file - we need the filesystem inode too. So change lafs_iget to take a filesystem inode rather than a superblock. We still need to get at the superblock. In a few patches we can just use ->i_sb, but for now it might not be the same so stash it in i_private. Signed-off-by: NeilBrown --- dir.c | 4 +-- inode.c | 96 ++++++++++++++++++++++++++++++------------------------ lafs.h | 2 +- roll.c | 63 ++++++++++++++++++----------------- snapshot.c | 14 ++++---- super.c | 13 +++++--- 6 files changed, 106 insertions(+), 86 deletions(-) diff --git a/dir.c b/dir.c index beab1b3..e0e6d4c 100644 --- a/dir.c +++ b/dir.c @@ -631,7 +631,7 @@ lafs_dir_roll_mini(struct inode *dir, int handle, int dirop, int last; if (inum) - inode = lafs_iget(dir->i_sb, inum, SYNC); + inode = lafs_iget(LAFSI(dir)->filesys, inum, SYNC); if (IS_ERR(inode)) return PTR_ERR(inode); if (!inode && dirop != DIROP_REN_TARGET) @@ -1803,7 +1803,7 @@ lafs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) if (err < 0) ERR_PTR(err); - ino = lafs_iget(dir->i_sb, inum, SYNC); + ino = lafs_iget(LAFSI(dir)->filesys, inum, SYNC); if (IS_ERR(ino)) return ERR_PTR(PTR_ERR(ino)); diff --git a/inode.c b/inode.c index 4e10c22..7605323 100644 --- a/inode.c +++ b/inode.c @@ -20,64 +20,74 @@ static void check_atime_ref(struct inode *ino, int async); * is slightly non-trivial. * iget*_locked will normally wait for any inode with one * of the flags I_FREEING I_CLEAR I_WILL_FREE I_NEW - * to either be unhashed or has the flag cleared. + * to either be unhashed or have the flag cleared. * We cannot afford that wait in the cleaner as we could deadlock. * So we use iget5_locked and provide a test function that fails * if it finds the inode with any of those flags set. - * If it does see the inode like that it clear the inum - * that is passed in (by reference) so that it knows to continue + * If it does see the inode like that it sets a flag in the 'ikey' + * that is passed in by reference so that it knows to continue * failing (for consistency) and so that the 'set' function * we provide can know to fail the 'set'. * The result of this is that if iget finds an inode it would - * have to wait on, the inum is cleared and NULL is returned. + * have to wait on, a flag is set and NULL is returned. * An unfortunate side effect is that an inode will be allocated * and then destroyed to no avail. * This is avoided by calling ilookup5 first. This also allows * us to only allocate/load the data block if there really seems * to be a need. */ -#define NO_INO (~(ino_t)0) +struct ikey { + ino_t inum; + struct inode *fsys; + bool was_busy; +}; + +static int sync_itest(struct inode *inode, void *data) +{ + struct ikey *ik = data; + + if (inode->i_ino != ik->inum || + LAFSI(inode)->filesys != ik->fsys) + return 0; + return 1; +} + static int async_itest(struct inode *inode, void *data) { - ino_t *inump = data; - ino_t inum = *inump; + struct ikey *ik = data; - if (inum == NO_INO) + if (ik->was_busy) /* found and is freeing */ return 0; - if (inode->i_ino != inum) + if (!sync_itest(inode, data)) return 0; if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) { - *inump = NO_INO; + ik->was_busy = true; return 0; } return 1; } -static int async_iset(struct inode *inode, void *data) +static int iset(struct inode *inode, void *data) { - ino_t *inump = data; - if (!*inump) + struct ikey *ik = data; + if (ik->was_busy) return -EBUSY; - inode->i_ino = *inump; + inode->i_ino = ik->inum; + LAFSI(inode)->filesys = ik->fsys; return 0; } struct inode * -lafs_iget(struct super_block *sb, ino_t inum, int async) +lafs_iget(struct inode *fsys, ino_t inum, int async) { /* find, and load if needed, this inum */ struct inode *ino = NULL; struct inode *oldino; struct datablock *b = NULL; - struct inode *inodefile; - struct sb_key *k; + struct ikey ik = { .inum = inum, .fsys = fsys, }; int err = 0; - - BUG_ON(inum == NO_INO); - - k = sb->s_fs_info; - inodefile = k->root; + struct super_block *sb = fsys->i_private; if (async) { /* We cannot afford to block on 'freeing_inode' @@ -88,13 +98,13 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) * alloc/free if the inode is locked in some way. */ while (!ino) { - ino_t inum2 = inum; + err = 0; - ino = ilookup5(sb, inum, async_itest, &inum2); + ino = ilookup5(sb, inum, async_itest, &ik); if (ino) break; - if (inum2 == NO_INO) + if (ik.was_busy) err = -EAGAIN; /* For async we will always want the dblock loaded, @@ -102,7 +112,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) * to fail -EAGAIN once we have an I_NEW inode. */ if (!b) - b = lafs_get_block(inodefile, inum, NULL, + b = lafs_get_block(fsys, inum, NULL, GFP_NOFS, MKREF(iget)); if (!b) return ERR_PTR(-ENOMEM); @@ -112,12 +122,11 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) if (!err) { /* Have the block, so safe to iget */ - inum2 = inum; ino = iget5_locked(sb, inum, - async_itest, async_iset, - &inum2); + async_itest, iset, + &ik); if (!ino) { - if (inum2 == NO_INO) + if (ik.was_busy) err = -EAGAIN; else err = -ENOMEM; @@ -132,7 +141,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) } } } else - ino = iget_locked(sb, inum); + ino = iget5_locked(sb, inum, sync_itest, iset, &ik); if (!ino) { putdref(b, MKREF(iget)); @@ -149,7 +158,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) return ERR_PTR(-ENOENT); } - LAFSI(ino)->filesys = igrab(inodefile); + igrab(LAFSI(ino)->filesys); /* surprisingly the inode bdi does not default to the * super_blocks bdi... @@ -158,7 +167,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) /* Need to load block 'inum' from an inode file... */ if (!b) { - b = lafs_get_block(inodefile, inum, NULL, GFP_KERNEL, MKREF(iget)); + b = lafs_get_block(fsys, inum, NULL, GFP_KERNEL, MKREF(iget)); if (!b) err = -ENOMEM; else @@ -200,7 +209,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async) out: if (b && test_and_clear_bit(B_Async, &b->b.flags)) { putdref(b, MKREF(async)); - lafs_wake_thread(fs_from_sb(sb)); + lafs_wake_thread(fs_from_inode(fsys)); } putdref(b, MKREF(iget)); return ino; @@ -227,7 +236,7 @@ lafs_iget_fs(struct fs *fs, int fsnum, int inum, int async) struct inode *filesys; struct super_block *sb2; - filesys = lafs_iget(sb, fsnum, async); + filesys = lafs_iget(fs->ss[0].root, fsnum, async); if (IS_ERR(filesys)) return filesys; if (LAFSI(filesys)->type != TypeInodeFile) { @@ -240,15 +249,18 @@ lafs_iget_fs(struct fs *fs, int fsnum, int inum, int async) iput(filesys); return ERR_PTR(PTR_ERR(sb2)); } - rv = lafs_iget(sb2, inum, async); + rv = lafs_iget(filesys, inum, async); if (IS_ERR(rv)) deactivate_locked_super(sb2); else up_write(&sb2->s_umount); - } else { - rv = lafs_iget(sb, inum, async); + } else if (inum) { + rv = lafs_iget(fs->ss[0].root, inum, async); if (!IS_ERR(rv)) atomic_inc(&sb->s_active); + } else { + rv = igrab(fs->ss[0].root); + atomic_inc(&sb->s_active); } return rv; } @@ -1543,7 +1555,7 @@ static int choose_free_inum(struct fs *fs, struct super_block *sb, u32 *inump, struct datablock **bp, int *restarted) { - struct inode *im = lafs_iget(sb, 1, SYNC); + struct inode *im = lafs_iget(ino_from_sb(sb), 1, SYNC); loff_t bnum; struct datablock *b; char *buf; @@ -1814,7 +1826,7 @@ retry: lafs_iounlock_block(&b->b); inode_map_new_commit(&imni); - ino = lafs_iget(sb, b->b.fileaddr, SYNC); + ino = lafs_iget(ino_from_sb(sb), b->b.fileaddr, SYNC); if (IS_ERR(ino)) { lafs_cluster_update_abort(&ui); LAFS_BUG(1, &b->b); @@ -1843,7 +1855,7 @@ abort: static int inode_map_free(struct fs *fs, struct super_block *sb, u32 inum) { - struct inode *im = lafs_iget(sb, 1, SYNC); + struct inode *im = lafs_iget(ino_from_sb(sb), 1, SYNC); int bit; unsigned long *buf; struct datablock *b; @@ -1894,7 +1906,7 @@ int lafs_inode_inuse(struct fs *fs, struct super_block *sb, u32 inum) /* This is used during roll-forward to register a newly created * inode in the inode map */ - struct inode *im = lafs_iget(sb, 1, SYNC); + struct inode *im = lafs_iget(ino_from_sb(sb), 1, SYNC); int bit; unsigned long *buf; struct datablock *b; diff --git a/lafs.h b/lafs.h index 1be0354..5b1afbf 100644 --- a/lafs.h +++ b/lafs.h @@ -138,7 +138,7 @@ int lafs_super_wait(struct fs *fs); /* inode.c */ void lafs_add_atime_offset(struct timespec *atime, int offset); int __must_check lafs_mount(struct fs *fs); -struct inode *lafs_iget(struct super_block *fs, ino_t inum, int async); +struct inode *lafs_iget(struct inode *filesys, ino_t inum, int async); struct inode *lafs_iget_fs(struct fs *fs, int fsnum, int inum, int async); int __must_check lafs_import_inode(struct inode *ino, struct datablock *b); void lafs_inode_checkpin(struct inode *ino); diff --git a/roll.c b/roll.c index f1dd269..0639606 100644 --- a/roll.c +++ b/roll.c @@ -783,8 +783,9 @@ int lafs_mount(struct fs *fs) { struct datablock *b = NULL; - struct inode *ino; + struct inode *rootino; struct inode *rootdir; + struct inode *aino, *oino; struct dentry *de; int err; int d; @@ -792,14 +793,16 @@ lafs_mount(struct fs *fs) int orphan_count; fs->rolled = 0; - fs->ss[0].root = ino = iget_locked(fs->prime_sb, 0); - LAFSI(ino)->filesys = ino; - k->root = ino; + fs->ss[0].root = rootino = iget_locked(fs->prime_sb, 0); + k->root = rootino; + LAFSI(rootino)->filesys = rootino; + + rootino->i_private = fs->prime_sb; err = -ENOMEM; - if (!ino) + if (!rootino) goto err; - b = lafs_get_block(ino, 0, NULL, GFP_KERNEL, MKREF(mount)); + b = lafs_get_block(rootino, 0, NULL, GFP_KERNEL, MKREF(mount)); if (!b) goto err; set_bit(B_Root, &b->b.flags); @@ -812,15 +815,15 @@ lafs_mount(struct fs *fs) if (err) goto err; - err = lafs_import_inode(ino, b); + err = lafs_import_inode(rootino, b); if (err) goto err; putdref(b, MKREF(mount)); b = NULL; - unlock_new_inode(ino); + unlock_new_inode(rootino); - rootdir = lafs_iget(fs->prime_sb, 2, SYNC); + rootdir = lafs_iget(rootino, 2, SYNC); err = PTR_ERR(rootdir); if (IS_ERR(rootdir)) goto err; @@ -832,29 +835,29 @@ lafs_mount(struct fs *fs) } fs->prime_sb->s_root = de; - ino = lafs_iget(fs->prime_sb, 8, SYNC); - err = PTR_ERR(ino); - if (IS_ERR(ino)) + oino = lafs_iget(rootino, 8, SYNC); + err = PTR_ERR(oino); + if (IS_ERR(oino)) goto err; - if (LAFSI(ino)->type != TypeOrphanList) { - iput(ino); + if (LAFSI(oino)->type != TypeOrphanList) { + iput(oino); err = -EINVAL; goto err; } - fs->orphans = ino; + fs->orphans = oino; for (d = 0; d < fs->devices ; d++) { - ino = lafs_iget(fs->prime_sb, - fs->devs[d].usage_inum, - SYNC); - err = PTR_ERR(ino); - if (IS_ERR(ino)) + struct inode *sino = lafs_iget(rootino, + fs->devs[d].usage_inum, + SYNC); + err = PTR_ERR(sino); + if (IS_ERR(sino)) goto err; - if (LAFSI(ino)->type != TypeSegmentMap) { - iput(ino); + if (LAFSI(sino)->type != TypeSegmentMap) { + iput(sino); err = -EINVAL; goto err; } - fs->devs[d].segsum = ino; + fs->devs[d].segsum = sino; } orphan_count = lafs_count_orphans(fs->orphans); LAFSI(fs->orphans)->md.orphan.nextfree = orphan_count; @@ -873,15 +876,15 @@ lafs_mount(struct fs *fs) INIT_LIST_HEAD(&fs->cleaner.seg[d].cleaning); } - ino = lafs_iget(fs->prime_sb, 3, SYNC); - if (!IS_ERR(ino)) { - if (LAFSI(ino)->type != TypeAccessTime) { - iput(ino); + aino = lafs_iget(rootino, 3, SYNC); + if (!IS_ERR(aino)) { + if (LAFSI(aino)->type != TypeAccessTime) { + iput(aino); err = -EINVAL; } else - LAFSI(fs->ss[0].root)->md.fs.accesstime = ino; - } else if (PTR_ERR(ino) != -ENOENT) - err = PTR_ERR(ino); + LAFSI(fs->ss[0].root)->md.fs.accesstime = aino; + } else if (PTR_ERR(aino) != -ENOENT) + err = PTR_ERR(aino); err: putdref(b, MKREF(mount)); diff --git a/snapshot.c b/snapshot.c index 4489ed3..23cf5a3 100644 --- a/snapshot.c +++ b/snapshot.c @@ -161,15 +161,17 @@ lafs_snap_get_sb(struct file_system_type *fstype, /* already existed */ kfree(sk); } else { - struct inode *rootdir; + struct inode *rootino, *rootdir; struct datablock *b; sb->s_flags = flags | MS_RDONLY; atomic_inc(&fs->prime_sb->s_active); - fs->ss[s].root = sk->k.root = iget_locked(sb, 0); - LAFSI(fs->ss[s].root)->filesys = fs->ss[s].root; - b = lafs_get_block(fs->ss[s].root, 0, NULL, GFP_KERNEL, + rootino = iget_locked(sb, 0); + rootino->i_private = sb; + fs->ss[s].root = sk->k.root = rootino; + LAFSI(rootino)->filesys = rootino; + b = lafs_get_block(rootino, 0, NULL, GFP_KERNEL, MKREF(snap)); b->b.physaddr = fs->ss[s].root_addr; set_bit(B_PhysValid, &b->b.flags); @@ -181,12 +183,12 @@ lafs_snap_get_sb(struct file_system_type *fstype, if (!err) err = lafs_import_inode(fs->ss[s].root, b); putdref(b, MKREF(snap)); - unlock_new_inode(fs->ss[s].root); + unlock_new_inode(rootino); if (err) { deactivate_locked_super(sb); goto fail; } - rootdir = lafs_iget(sb, 2, SYNC); + rootdir = lafs_iget(rootino, 2, SYNC); sb->s_root = d_alloc_root(rootdir); sb->s_op = fs->prime_sb->s_op; sb->s_flags |= MS_ACTIVE; diff --git a/super.c b/super.c index e473565..46e8eec 100644 --- a/super.c +++ b/super.c @@ -1025,6 +1025,8 @@ struct super_block *lafs_get_subset_sb(struct inode *ino) struct inode *rootdir, *imapfile; int err = 0; + ino->i_private = sb; + igrab(ino); sb->s_blocksize = fs->blocksize; sb->s_blocksize_bits = fs->blocksize_bits; @@ -1032,7 +1034,7 @@ struct super_block *lafs_get_subset_sb(struct inode *ino) sb->s_op = &lafs_sops; sb->s_export_op = &lafs_export_ops; sb->s_time_gran = 2; - rootdir = lafs_iget(sb, 2, SYNC); + rootdir = lafs_iget(ino, 2, SYNC); if (IS_ERR(rootdir) && PTR_ERR(rootdir) == -ENOENT) { rootdir = lafs_new_inode(fs, sb, NULL, TypeDir, 2, 0755, NULL); @@ -1044,7 +1046,7 @@ struct super_block *lafs_get_subset_sb(struct inode *ino) err = PTR_ERR(rootdir); else { sb->s_root = d_alloc_root(rootdir); - imapfile = lafs_iget(sb, 1, SYNC); + imapfile = lafs_iget(ino, 1, SYNC); if (IS_ERR(imapfile) && PTR_ERR(imapfile) == -ENOENT) imapfile = lafs_new_inode(fs, sb, NULL, TypeInodeMap, 1, 0, NULL); @@ -1056,7 +1058,7 @@ struct super_block *lafs_get_subset_sb(struct inode *ino) } if (!err) { - struct inode *atime = lafs_iget(sb, 3, SYNC); + struct inode *atime = lafs_iget(ino, 3, SYNC); if (!IS_ERR(atime)) { if (LAFSI(atime)->type != TypeAccessTime) { iput(atime); @@ -1265,7 +1267,7 @@ static struct inode *lafs_nfs_get_inode(struct super_block *sb, { struct inode *inode; - inode = lafs_iget(sb, ino, SYNC); + inode = lafs_iget(ino_from_sb(sb), ino, SYNC); if (IS_ERR(inode)) return ERR_CAST(inode); if (generation && inode->i_generation != generation) { @@ -1293,7 +1295,8 @@ static struct dentry *lafs_fh_to_parent(struct super_block *sb, struct fid *fid, static struct dentry *lafs_get_parent(struct dentry *child) { ino_t inum = LAFSI(child->d_inode)->md.file.parent; - struct inode *inode = lafs_iget(child->d_inode->i_sb, inum, SYNC); + struct inode *inode = lafs_iget(LAFSI(child->d_inode)->filesys, + inum, SYNC); if (IS_ERR(inode)) return ERR_CAST(inode); return d_obtain_alias(inode); -- 2.39.5