From: Bob Peterson <rpeterso@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [GFS2 PATCH 11/15] GFS2: Add new function gfs2_inode_lookup_for_del
Date: Mon, 5 Oct 2015 10:36:33 -0500 [thread overview]
Message-ID: <1444059397-4705-12-git-send-email-rpeterso@redhat.com> (raw)
In-Reply-To: <1444059397-4705-1-git-send-email-rpeterso@redhat.com>
This patch adds a new specialized function to look up an inode
for the purposes of deleting it. Before, we used to call function
gfs2_lookup_by_inum, but the new function closes some timing
windows involving the iopen and inode glocks coming and going,
since they typically outlive their inodes.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
---
fs/gfs2/glock.c | 9 ++--
fs/gfs2/inode.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
fs/gfs2/inode.h | 2 +
3 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index e5dfbcd..59f089c 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -569,16 +569,17 @@ static void delete_work_func(struct work_struct *work)
struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete);
struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
struct gfs2_inode *ip;
- struct inode *inode;
+ struct inode *inode = NULL;
u64 no_addr = gl->gl_name.ln_number;
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);
- else
- inode = gfs2_lookup_by_inum(sdp, no_addr, NULL, GFS2_BLKST_UNLINKED);
+
+ if (inode == NULL || IS_ERR(inode))
+ inode = gfs2_inode_lookup_for_del(sdp->sd_vfs, no_addr);
+
if (inode && !IS_ERR(inode)) {
d_prune_aliases(inode);
iput(inode);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 06c208b..1c57f7d 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -153,6 +153,139 @@ fail:
return ERR_PTR(error);
}
+/**
+ * gfs2_inode_lookup_for_del - Lookup an unlinked inode so we can delete it
+ * @sb: The super block
+ * @no_addr: The inode number
+ *
+ * Returns: A VFS inode, or an error
+ *
+ * We jump through some hoops here to avoid a special case in which the block
+ * has been freed and already reallocated for a different inode while after
+ * the iopen callback was received to signify a remote unlink that needs
+ * deleting. In that case, we don't want to return the inode to the caller
+ * to delete the inode. We also need to do an inode_refresh to ensure that
+ * whomever recreated the dinode gets a proper i_nlink count, otherwise the
+ * vfs might think it's unlinked and still needs deleting.
+ */
+struct inode *gfs2_inode_lookup_for_del(struct super_block *sb, u64 no_addr)
+{
+ struct inode *inode;
+ struct gfs2_inode *ip;
+ struct gfs2_glock *io_gl = NULL;
+ struct gfs2_holder i_gh;
+ int error, btype;
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct address_space *mapping;
+ BUG_ON(no_addr == 0);
+ inode = iget_locked(sb, (unsigned long)no_addr);
+ ip = GFS2_I(inode);
+
+ if (!inode)
+ return ERR_PTR(-ENOBUFS);
+
+ if (!(inode->i_state & I_NEW)) {
+ BUG_ON(ip->i_no_addr != no_addr);
+ return inode;
+ }
+
+ ip->i_no_addr = no_addr;
+
+ error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE,
+ &ip->i_gl);
+ if (unlikely(error))
+ goto fail;
+ /* If this is a brand new inode, but a recycled glock, we've got a
+ reference problem. In clear_inode it does an extra glock_put so the
+ next time we do clear_inode for this inode, we'll get in trouble.
+ So we hold the glock to bump the reference count. */
+ if (ip->i_gl->gl_flags != 0) /* New inode, recycled glock */
+ ip->i_gl->gl_lockref.count++;
+
+ ip->i_gl->gl_object = ip;
+
+ error = gfs2_glock_get(sdp, no_addr, &gfs2_iopen_glops, CREATE,
+ &io_gl);
+ if (unlikely(error))
+ goto fail_put;
+
+ ip->i_iopen_gh.gh_gl = NULL;
+ gfs2_glock_put(io_gl);
+ io_gl = NULL;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, &i_gh);
+ if (error)
+ goto fail_put;
+
+ /* Inode glock must be locked already */
+ btype = gfs2_get_blk_type(sdp, no_addr);
+ if (btype < 0) {
+ error = btype;
+ goto fail_refresh;
+ }
+ if (btype == GFS2_BLKST_FREE || btype == GFS2_BLKST_USED) {
+ error = -ESTALE;
+ goto fail_refresh;
+ }
+
+ /* At this point it's either UNLINKED or DINODE */
+
+ /* If there aren't any pages associated with it and it's a new inode,
+ * we shouldn't be messing with it, even to read in pages. We should
+ * just exit and let whomever's using it carry on. If we do inode
+ * refresh, we'll end up adding pages to the cache that we'd otherwise
+ * need to truncate with truncate_inode_page().
+ */
+ mapping = gfs2_glock2aspace(ip->i_gl);
+ if (mapping->nrpages == 0 && btype == GFS2_BLKST_DINODE) {
+ error = -ESTALE;
+ goto fail_refresh;
+ }
+ /* At this point, we've got a dinode with pages associated with it
+ * or it's unlinked. If it's unlinked, we need to do inode_refresh
+ * so that our put() will delete it normally through gfs2_delete_inode.
+ * If it has pages associated with it, we may have grabbed the glock
+ * while it was being created, so we need to refresh it before
+ * exiting.
+ */
+ error = gfs2_inode_refresh(GFS2_I(inode));
+ if (error)
+ goto fail_refresh;
+
+ if (btype == GFS2_BLKST_DINODE) {
+ /* Now we know this is a dinode (not unlinked), but we know
+ * there were already pages associated with it. So it's safe
+ * to exit:
+ */
+ error = -ESTALE;
+ goto fail_refresh;
+ }
+
+ gfs2_set_iop(inode);
+ unlock_new_inode(inode);
+ gfs2_glock_dq_uninit(&i_gh);
+ gfs2_glock_put(ip->i_gl);
+ return inode;
+
+fail_refresh:
+ ip->i_gl->gl_object = NULL; /* See note below */
+ gfs2_glock_dq_uninit(&i_gh);
+fail_put:
+ /* This setting of gl_object to NULL is done by the other lookup
+ * functions. But if it races with someone reusing the dinode, we
+ * don't want to mess them up. It seems necessary in order to prevent
+ * buffer_heads from being attached after the i_gh is acquired.
+ * But it seems like it has the potential to screw up people trying
+ * to re-use the glock for a new incarnation of the inode.
+ * For now, I'm going to move it inside the dq_uninit.
+ */
+ /*ip->i_gl->gl_object = NULL;*/
+ gfs2_glock_put(ip->i_gl);
+fail:
+ iget_failed(inode);
+ return ERR_PTR(error);
+}
+
struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
u64 *no_formal_ino, unsigned int blktype)
{
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 22c27a8..031e301 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -96,6 +96,8 @@ err:
extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type,
u64 no_addr, u64 no_formal_ino,
int non_block);
+extern struct inode *gfs2_inode_lookup_for_del(struct super_block *sb,
+ u64 no_addr);
extern struct inode *gfs2_lookup_by_inum(struct gfs2_sbd *sdp, u64 no_addr,
u64 *no_formal_ino,
unsigned int blktype);
--
2.4.3
next prev parent reply other threads:[~2015-10-05 15:36 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-05 15:36 [Cluster-devel] [GFS2 PATCH 00/15] Fifteen patches related to file unlink->delete->new Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 01/15] GFS2: Update master statfs buffer with sd_statfs_spin locked Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 02/15] GFS2: Allow fail_gunlock3 to set the free_vfs_inode bit Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 03/15] GFS2: Protect log tail calculations with inside locks Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 04/15] GFS2: Wait for iopen glock dequeues Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 05/15] GFS2: Reintroduce a timeout in function gfs2_gl_hash_clear Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 06/15] GFS2: Prevent gl_delete work for re-used inodes Bob Peterson
2015-10-06 18:40 ` Andrew W Elble
2015-10-06 19:02 ` Bob Peterson
2015-10-06 19:33 ` Andrew W Elble
2015-10-12 19:15 ` Andrew W Elble
2015-10-13 17:28 ` Andrew W Elble
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 07/15] GFS2: Truncate address space mapping when deleting an inode Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 08/15] GFS2: Don't filter out I_FREEING inodes anymore Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 09/15] GFS2: generalize gfs2_check_blk_type Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 10/15] GFS2: Change from tr_touched to tr_bufs Bob Peterson
2015-10-05 15:36 ` Bob Peterson [this message]
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 12/15] gfs2: Remove unused param non_block from gfs2_inode_lookup Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 13/15] gfs2: Use new variable i_gl instead of ip->i_gl Bob Peterson
2015-10-06 18:31 ` Andrew W Elble
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 14/15] GFS2: Hold onto iopen glock longer when dinode creation fails Bob Peterson
2015-10-05 15:36 ` [Cluster-devel] [GFS2 PATCH 15/15] GFS2: Rework gfs2_evict_inode to prevent collisions with openers Bob Peterson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1444059397-4705-12-git-send-email-rpeterso@redhat.com \
--to=rpeterso@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).