mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Philipp Reisner <philipp.reisner@linbit.com>
To: linux-kernel@vger.kernel.org, Jens Axboe <axboe@kernel.dk>
Cc: drbd-dev@lists.linbit.com
Subject: [PATCH 13/23] drbd: debugfs: deal with destructor racing with open of debugfs file
Date: Thu,  3 Jul 2014 10:43:05 +0200	[thread overview]
Message-ID: <1404376995-4877-14-git-send-email-philipp.reisner@linbit.com> (raw)
In-Reply-To: <1404376995-4877-1-git-send-email-philipp.reisner@linbit.com>

From: Lars Ellenberg <lars.ellenberg@linbit.com>

Try to close the race between open() and debugfs_remove_recursive()
from inside an object destructor.
Once open succeeds, the object should stay around.
Open should not succeed if the object has already reached its destructor.

This may be overkill, but to make that happen, we check for existence of
a parent directory, "stale-ness" of "this" dentry, and serialize
kref_get_unless_zero() on the outermost object relevant for this file
with d_delete() on this dentry (using the parent's i_mutex).

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
---
 drivers/block/drbd/drbd_debugfs.c | 58 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 54 insertions(+), 4 deletions(-)

diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c
index d393aee..51c64ec 100644
--- a/drivers/block/drbd/drbd_debugfs.c
+++ b/drivers/block/drbd/drbd_debugfs.c
@@ -177,8 +177,8 @@ static int in_flight_summary_show(struct seq_file *m, void *pos)
 	connection = first_connection(resource);
 	/* This does not happen, actually.
 	 * But be robust and prepare for future code changes. */
-	if (!connection)
-		return 0;
+	if (!connection || !kref_get_unless_zero(&connection->kref))
+		return -ESTALE;
 
 	seq_puts(m, "oldest application requests\n");
 	seq_print_resource_transfer_log_summary(m, resource, connection, jif);
@@ -187,12 +187,62 @@ static int in_flight_summary_show(struct seq_file *m, void *pos)
 	jif = jiffies - jif;
 	if (jif)
 		seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif));
+	kref_put(&connection->kref, drbd_destroy_connection);
 	return 0;
 }
 
+/* simple_positive(file->f_dentry) respectively debugfs_positive(),
+ * but neither is "reachable" from here.
+ * So we have our own inline version of it above.  :-( */
+static inline int debugfs_positive(struct dentry *dentry)
+{
+        return dentry->d_inode && !d_unhashed(dentry);
+}
+
+/* make sure at *open* time that the respective object won't go away. */
+static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *),
+		                void *data, struct kref *kref,
+				void (*release)(struct kref *))
+{
+	struct dentry *parent;
+	int ret = -ESTALE;
+
+	/* Are we still linked,
+	 * or has debugfs_remove() already been called? */
+	parent = file->f_dentry->d_parent;
+	/* not sure if this can happen: */
+	if (!parent || !parent->d_inode)
+		goto out;
+	/* serialize with d_delete() */
+	mutex_lock(&parent->d_inode->i_mutex);
+	if (!debugfs_positive(file->f_dentry))
+		goto out_unlock;
+	/* Make sure the object is still alive */
+	if (kref_get_unless_zero(kref))
+		ret = 0;
+out_unlock:
+	mutex_unlock(&parent->d_inode->i_mutex);
+	if (!ret) {
+		ret = single_open(file, show, data);
+		if (ret)
+			kref_put(kref, release);
+	}
+out:
+	return ret;
+}
+
 static int in_flight_summary_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, in_flight_summary_show, inode->i_private);
+	struct drbd_resource *resource = inode->i_private;
+	return drbd_single_open(file, in_flight_summary_show, resource,
+				&resource->kref, drbd_destroy_resource);
+}
+
+static int in_flight_summary_release(struct inode *inode, struct file *file)
+{
+	struct drbd_resource *resource = inode->i_private;
+	kref_put(&resource->kref, drbd_destroy_resource);
+	return single_release(inode, file);
 }
 
 static const struct file_operations in_flight_summary_fops = {
@@ -200,7 +250,7 @@ static const struct file_operations in_flight_summary_fops = {
 	.open		= in_flight_summary_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= single_release,
+	.release	= in_flight_summary_release,
 };
 
 void drbd_debugfs_resource_add(struct drbd_resource *resource)
-- 
1.9.1


  parent reply	other threads:[~2014-07-03  8:49 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-07-03  8:42 [PATCH 00/23] RFC DRBD fixes Philipp Reisner
2014-07-03  8:42 ` [PATCH 01/23] drbd: poison free'd device, resource and connection structs Philipp Reisner
2014-07-03  8:42 ` [PATCH 02/23] drbd: fix drbd_destroy_device reference count updates Philipp Reisner
2014-07-03  8:42 ` [PATCH 03/23] drbd: track meta data IO intent, start and submit time Philipp Reisner
2014-07-03  8:42 ` [PATCH 04/23] drbd: gather detailed timing statistics for drbd_requests Philipp Reisner
2014-07-03  8:42 ` [PATCH 05/23] drbd: add lists to find oldest pending requests Philipp Reisner
2014-07-03  8:42 ` [PATCH 06/23] drbd: add caching oldest request pointers for replication stages Philipp Reisner
2014-07-03  8:42 ` [PATCH 07/23] drbd: improve throttling decisions of background resynchronisation Philipp Reisner
2014-07-03  8:43 ` [PATCH 08/23] drbd: track timing details of peer_requests Philipp Reisner
2014-07-03  8:43 ` [PATCH 09/23] drbd: register peer requests on read_ee early Philipp Reisner
2014-07-03  8:43 ` [PATCH 10/23] drbd: track details of bitmap IO Philipp Reisner
2014-07-03  8:43 ` [PATCH 11/23] drbd: debugfs: add basic hierarchy Philipp Reisner
2014-07-03  8:43 ` [PATCH 12/23] drbd: debugfs: add in_flight_summary data Philipp Reisner
2014-07-03  8:43 ` Philipp Reisner [this message]
2014-07-03  8:43 ` [PATCH 14/23] drbd: debugfs: Add in_flight_summary Philipp Reisner
2014-07-03  8:43 ` [PATCH 15/23] drbd: debugfs: add callback_history Philipp Reisner
2014-07-03  8:43 ` [PATCH 16/23] drbd: debugfs: add per volume oldest_requests Philipp Reisner
2014-07-03  8:43 ` [PATCH 17/23] drbd: debugfs: add version tag to debugfs files Philipp Reisner
2014-07-03  8:43 ` [PATCH 18/23] drbd: debugfs: add per connection oldest requests Philipp Reisner
2014-07-03  8:43 ` [PATCH 19/23] drbd: debugfs: add per device data_gen_id Philipp Reisner
2014-07-03  8:43 ` [PATCH 20/23] drbd: resync should only lock out specific ranges Philipp Reisner
2014-07-03  8:43 ` [PATCH 21/23] drbd: drop spurious parameters from _drbd_md_sync_page_io Philipp Reisner
2014-07-03  8:43 ` [PATCH 22/23] drbd: implicitly truncate cpu-mask Philipp Reisner
2014-07-03  8:43 ` [PATCH 23/23] drbd: silence underflow warning in read_in_block() Philipp Reisner

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=1404376995-4877-14-git-send-email-philipp.reisner@linbit.com \
    --to=philipp.reisner@linbit.com \
    --cc=axboe@kernel.dk \
    --cc=drbd-dev@lists.linbit.com \
    --cc=linux-kernel@vger.kernel.org \
    /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

all inboxes | Powered by JetHome®