diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/aops.c | 2 | ||||
-rw-r--r-- | fs/gfs2/dir.c | 6 | ||||
-rw-r--r-- | fs/gfs2/export.c | 2 | ||||
-rw-r--r-- | fs/gfs2/glock.c | 10 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 1 | ||||
-rw-r--r-- | fs/gfs2/inode.c | 71 | ||||
-rw-r--r-- | fs/gfs2/inode.h | 5 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 2 | ||||
-rw-r--r-- | fs/gfs2/super.c | 26 |
9 files changed, 46 insertions, 79 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 93f0746..aa016e4 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -1082,7 +1082,7 @@ static ssize_t gfs2_direct_IO(struct kiocb *iocb, struct iov_iter *iter, * the first place, mapping->nr_pages will always be zero. */ if (mapping->nrpages) { - loff_t lstart = offset & (PAGE_CACHE_SIZE - 1); + loff_t lstart = offset & ~(PAGE_CACHE_SIZE - 1); loff_t len = iov_iter_count(iter); loff_t end = PAGE_ALIGN(offset + len) - 1; diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index 6a92592..4a01f30 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -798,7 +798,7 @@ static int get_first_leaf(struct gfs2_inode *dip, u32 index, int error; error = get_leaf_nr(dip, index, &leaf_no); - if (!error) + if (!IS_ERR_VALUE(error)) error = get_leaf(dip, leaf_no, bh_out); return error; @@ -1014,7 +1014,7 @@ static int dir_split_leaf(struct inode *inode, const struct qstr *name) index = name->hash >> (32 - dip->i_depth); error = get_leaf_nr(dip, index, &leaf_no); - if (error) + if (IS_ERR_VALUE(error)) return error; /* Get the old leaf block */ @@ -1660,7 +1660,7 @@ struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *name, brelse(bh); if (fail_on_exist) return ERR_PTR(-EEXIST); - inode = gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino, 0); + inode = gfs2_inode_lookup(dir->i_sb, dtype, addr, formal_ino); if (!IS_ERR(inode)) GFS2_I(inode)->i_rahead = rahead; return inode; diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 5d15e94..d5bda85 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -137,7 +137,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, struct gfs2_sbd *sdp = sb->s_fs_info; struct inode *inode; - inode = gfs2_ilookup(sb, inum->no_addr, 0); + inode = gfs2_ilookup(sb, inum->no_addr); if (inode) { if (GFS2_I(inode)->i_no_formal_ino != inum->no_formal_ino) { iput(inode); diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a4ff7b5..6539131 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -572,17 +572,24 @@ static void delete_work_func(struct work_struct *work) struct inode *inode; u64 no_addr = gl->gl_name.ln_number; + /* If someone's using this glock to create a new dinode, the block must + have been freed by another node, then re-used, in which case our + iopen callback is too late after the fact. Ignore it. */ + if (test_bit(GLF_INODE_CREATING, &gl->gl_flags)) + goto out; + ip = gl->gl_object; /* Note: Unsafe to dereference ip as we don't hold right refs/locks */ if (ip) - inode = gfs2_ilookup(sdp->sd_vfs, no_addr, 1); + inode = gfs2_ilookup(sdp->sd_vfs, no_addr); else inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED); if (inode && !IS_ERR(inode)) { d_prune_aliases(inode); iput(inode); } +out: gfs2_glock_put(gl); } @@ -1015,6 +1022,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh) handle_callback(gl, LM_ST_UNLOCKED, 0, false); list_del_init(&gh->gh_list); + clear_bit(HIF_HOLDER, &gh->gh_iflags); if (find_first_holder(gl) == NULL) { if (glops->go_unlock) { GLOCK_BUG_ON(gl, test_and_set_bit(GLF_LOCK, &gl->gl_flags)); diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 845fb09..a6a3389 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -328,6 +328,7 @@ enum { GLF_LRU = 13, GLF_OBJECT = 14, /* Used only for tracing */ GLF_BLOCKING = 15, + GLF_INODE_CREATING = 16, /* Inode creation occurring */ }; struct gfs2_glock { diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 352f958..bb30f9a 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -37,61 +37,9 @@ #include "super.h" #include "glops.h" -struct gfs2_skip_data { - u64 no_addr; - int skipped; - int non_block; -}; - -static int iget_test(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_skip_data *data = opaque; - - if (ip->i_no_addr == data->no_addr) { - if (data->non_block && - inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { - data->skipped = 1; - return 0; - } - return 1; - } - return 0; -} - -static int iget_set(struct inode *inode, void *opaque) -{ - struct gfs2_inode *ip = GFS2_I(inode); - struct gfs2_skip_data *data = opaque; - - if (data->skipped) - return -ENOENT; - inode->i_ino = (unsigned long)(data->no_addr); - ip->i_no_addr = data->no_addr; - return 0; -} - -struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int non_block) +struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr) { - unsigned long hash = (unsigned long)no_addr; - struct gfs2_skip_data data; - - data.no_addr = no_addr; - data.skipped = 0; - data.non_block = non_block; - return ilookup5(sb, hash, iget_test, &data); -} - -static struct inode *gfs2_iget(struct super_block *sb, u64 no_addr, - int non_block) -{ - struct gfs2_skip_data data; - unsigned long hash = (unsigned long)no_addr; - - data.no_addr = no_addr; - data.skipped = 0; - data.non_block = non_block; - return iget5_locked(sb, hash, iget_test, iget_set, &data); + return ilookup(sb, (unsigned long)no_addr); } /** @@ -132,21 +80,21 @@ static void gfs2_set_iop(struct inode *inode) * @sb: The super block * @no_addr: The inode number * @type: The type of the inode - * non_block: Can we block on inodes that are being freed? * * Returns: A VFS inode, or an error */ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type, - u64 no_addr, u64 no_formal_ino, int non_block) + u64 no_addr, u64 no_formal_ino) { struct inode *inode; struct gfs2_inode *ip; struct gfs2_glock *io_gl = NULL; int error; - inode = gfs2_iget(sb, no_addr, non_block); + inode = iget_locked(sb, (unsigned long)no_addr); ip = GFS2_I(inode); + ip->i_no_addr = no_addr; if (!inode) return ERR_PTR(-ENOMEM); @@ -221,7 +169,7 @@ struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, if (error) goto fail; - inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, 1); + inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0); if (IS_ERR(inode)) goto fail; @@ -592,7 +540,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; struct gfs2_inode *dip = GFS2_I(dir), *ip; struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode); - struct gfs2_glock *io_gl; + struct gfs2_glock *io_gl = NULL; int error, free_vfs_inode = 1; u32 aflags = 0; unsigned blocks = 1; @@ -729,6 +677,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, if (error) goto fail_gunlock2; + BUG_ON(test_and_set_bit(GLF_INODE_CREATING, &io_gl->gl_flags)); + error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh); if (error) goto fail_gunlock2; @@ -771,12 +721,15 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry, } gfs2_glock_dq_uninit(ghs); gfs2_glock_dq_uninit(ghs + 1); + clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags); return error; fail_gunlock3: gfs2_glock_dq_uninit(&ip->i_iopen_gh); gfs2_glock_put(io_gl); fail_gunlock2: + if (io_gl) + clear_bit(GLF_INODE_CREATING, &io_gl->gl_flags); gfs2_glock_dq_uninit(ghs + 1); fail_free_inode: if (ip->i_gl) diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index ba4d949..e1af0d4 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h @@ -94,12 +94,11 @@ err: } extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, - u64 no_addr, u64 no_formal_ino, - int non_block); + u64 no_addr, u64 no_formal_ino); extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr, u64 *no_formal_ino, unsigned int blktype); -extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr, int nonblock); +extern struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr); extern int gfs2_inode_refresh(struct gfs2_inode *ip); diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index dbed9e2..49b0bff 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -454,7 +454,7 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, struct dentry *dentry; struct inode *inode; - inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0); + inode = gfs2_inode_lookup(sb, DT_DIR, no_addr, 0); if (IS_ERR(inode)) { fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); return PTR_ERR(inode); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 8f960a5..f8a0cd8 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1551,12 +1551,16 @@ static void gfs2_evict_inode(struct inode *inode) goto out_truncate; } - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; - gfs2_glock_dq_wait(&ip->i_iopen_gh); - gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh); - error = gfs2_glock_nq(&ip->i_iopen_gh); - if (error) - goto out_truncate; + if (ip->i_iopen_gh.gh_gl && + test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; + gfs2_glock_dq_wait(&ip->i_iopen_gh); + gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, + &ip->i_iopen_gh); + error = gfs2_glock_nq(&ip->i_iopen_gh); + if (error) + goto out_truncate; + } /* Case 1 starts here */ @@ -1606,11 +1610,13 @@ out_unlock: if (gfs2_rs_active(&ip->i_res)) gfs2_rs_deltree(&ip->i_res); - if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { - ip->i_iopen_gh.gh_flags |= GL_NOCACHE; - gfs2_glock_dq_wait(&ip->i_iopen_gh); + if (ip->i_iopen_gh.gh_gl) { + if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags)) { + ip->i_iopen_gh.gh_flags |= GL_NOCACHE; + gfs2_glock_dq_wait(&ip->i_iopen_gh); + } + gfs2_holder_uninit(&ip->i_iopen_gh); } - gfs2_holder_uninit(&ip->i_iopen_gh); gfs2_glock_dq_uninit(&gh); if (error && error != GLR_TRYFAILED && error != -EROFS) fs_warn(sdp, "gfs2_evict_inode: %d\n", error); |