summaryrefslogtreecommitdiffstats
path: root/fs/gfs2/inode.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-08 21:47:09 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-08 21:47:09 +0200
commitca687877e05ad1bf5b4cefd9cdd091044626deac (patch)
tree6b61bf62f2d87729fcbdd125f483792a71165016 /fs/gfs2/inode.c
parentMerge tag 's390-5.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/... (diff)
parentMerge branch 'gfs2-iopen' into for-next (diff)
downloadlinux-ca687877e05ad1bf5b4cefd9cdd091044626deac.tar.xz
linux-ca687877e05ad1bf5b4cefd9cdd091044626deac.zip
Merge tag 'gfs2-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2
Pull gfs2 updates from Andreas Gruenbacher: - An iopen glock locking scheme rework that speeds up deletes of inodes accessed from multiple nodes - Various bug fixes and debugging improvements - Convert gfs2-glocks.txt to ReST * tag 'gfs2-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: gfs2: fix use-after-free on transaction ail lists gfs2: new slab for transactions gfs2: initialize transaction tr_ailX_lists earlier gfs2: Smarter iopen glock waiting gfs2: Wake up when setting GLF_DEMOTE gfs2: Check inode generation number in delete_work_func gfs2: Move inode generation number check into gfs2_inode_lookup gfs2: Minor gfs2_lookup_by_inum cleanup gfs2: Try harder to delete inodes locally gfs2: Give up the iopen glock on contention gfs2: Turn gl_delete into a delayed work gfs2: Keep track of deleted inode generations in LVBs gfs2: Allow ASPACE glocks to also have an lvb gfs2: instrumentation wrt log_flush stuck gfs2: introduce new gfs2_glock_assert_withdraw gfs2: print mapping->nrpages in glock dump for address space glocks gfs2: Only do glock put in gfs2_create_inode for free inodes gfs2: Allow lock_nolock mount to specify jid=X gfs2: Don't ignore inode write errors during inode_go_sync docs: filesystems: convert gfs2-glocks.txt to ReST
Diffstat (limited to 'fs/gfs2/inode.c')
-rw-r--r--fs/gfs2/inode.c47
1 files changed, 36 insertions, 11 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index a1337bf31e49..370c3a4b31ac 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -115,6 +115,10 @@ static void gfs2_set_iop(struct inode *inode)
* placeholder because it doesn't otherwise make sense), the on-disk block type
* is verified to be @blktype.
*
+ * When @no_formal_ino is non-zero, this function will return ERR_PTR(-ESTALE)
+ * if it detects that @no_formal_ino doesn't match the actual inode generation
+ * number. However, it doesn't always know unless @type is DT_UNKNOWN.
+ *
* Returns: A VFS inode, or an error
*/
@@ -158,6 +162,11 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
if (error)
goto fail;
+ error = -ESTALE;
+ if (no_formal_ino &&
+ gfs2_inode_already_deleted(ip->i_gl, no_formal_ino))
+ goto fail;
+
if (blktype != GFS2_BLKST_FREE) {
error = gfs2_check_blk_type(sdp, no_addr,
blktype);
@@ -171,6 +180,7 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
if (unlikely(error))
goto fail;
+ gfs2_cancel_delete_work(ip->i_iopen_gh.gh_gl);
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
gfs2_glock_put(io_gl);
io_gl = NULL;
@@ -189,13 +199,23 @@ struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned int type,
inode->i_mode = DT2IF(type);
}
+ if (gfs2_holder_initialized(&i_gh))
+ gfs2_glock_dq_uninit(&i_gh);
+
gfs2_set_iop(inode);
+ }
- unlock_new_inode(inode);
+ if (no_formal_ino && ip->i_no_formal_ino &&
+ no_formal_ino != ip->i_no_formal_ino) {
+ if (inode->i_state & I_NEW)
+ goto fail;
+ iput(inode);
+ return ERR_PTR(-ESTALE);
}
- if (gfs2_holder_initialized(&i_gh))
- gfs2_glock_dq_uninit(&i_gh);
+ if (inode->i_state & I_NEW)
+ unlock_new_inode(inode);
+
return inode;
fail:
@@ -207,23 +227,26 @@ fail:
return ERR_PTR(error);
}
+/**
+ * gfs2_lookup_by_inum - look up an inode by inode number
+ * @sdp: The super block
+ * @no_addr: The inode number
+ * @no_formal_ino: The inode generation number (0 for any)
+ * @blktype: Requested block type (see gfs2_inode_lookup)
+ */
struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
- u64 *no_formal_ino, unsigned int blktype)
+ u64 no_formal_ino, unsigned int blktype)
{
struct super_block *sb = sdp->sd_vfs;
struct inode *inode;
int error;
- inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, 0, blktype);
+ inode = gfs2_inode_lookup(sb, DT_UNKNOWN, no_addr, no_formal_ino,
+ blktype);
if (IS_ERR(inode))
return inode;
- /* Two extra checks for NFS only */
if (no_formal_ino) {
- error = -ESTALE;
- if (GFS2_I(inode)->i_no_formal_ino != *no_formal_ino)
- goto fail_iput;
-
error = -EIO;
if (GFS2_I(inode)->i_diskflags & GFS2_DIF_SYSTEM)
goto fail_iput;
@@ -725,6 +748,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
if (error)
goto fail_gunlock2;
+ gfs2_cancel_delete_work(ip->i_iopen_gh.gh_gl);
glock_set_object(ip->i_iopen_gh.gh_gl, ip);
gfs2_set_iop(inode);
insert_inode_hash(inode);
@@ -781,7 +805,8 @@ fail_gunlock2:
fail_free_inode:
if (ip->i_gl) {
glock_clear_object(ip->i_gl, ip);
- gfs2_glock_put(ip->i_gl);
+ if (free_vfs_inode) /* else evict will do the put for us */
+ gfs2_glock_put(ip->i_gl);
}
gfs2_rs_delete(ip, NULL);
gfs2_qa_put(ip);