lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 19 Jan 2011 17:42:08 +0100
From:	Lino Sanfilippo <LinoSanfilippo@....de>
To:	eparis@...hat.com
Cc:	linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
	Lino Sanfilippo <LinoSanfilippo@....de>
Subject: [PATCH 05/14] fsnotify: synchronize mark_srcu after a mark has been removed from a fsobject

Instead of synchronizing mark_srcu after when a group is being destroyed,
we call it for each mark that is unlinked from its inode.
Synchronizing ensures that no more readers (callers of fsnotify()) are
referencing the mark when we decrement the marks ref count (and thus
possibly free it).
Since we can call synchronize_srcu without holding a lock, we dont need
to destroy the marks in a dedicated kernel thread any more.

Signed-off-by: Lino Sanfilippo <LinoSanfilippo@....de>
---
 fs/notify/group.c         |    2 --
 fs/notify/inode_mark.c    |   38 +++++++++++++++++++++++++++++---------
 fs/notify/vfsmount_mark.c |   30 +++++++++++++++++++++++-------
 3 files changed, 52 insertions(+), 18 deletions(-)

diff --git a/fs/notify/group.c b/fs/notify/group.c
index cc341d3..0dcf497 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -55,8 +55,6 @@ static void fsnotify_destroy_group(struct fsnotify_group *group)
 	/* clear all inode marks for this group */
 	fsnotify_clear_marks_by_group(group);
 
-	synchronize_srcu(&fsnotify_mark_srcu);
-
 	/* past the point of no return, matches the initial value of 1 */
 	if (atomic_dec_and_test(&group->num_marks))
 		fsnotify_final_destroy_group(group);
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 8d35a84..7403404 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -60,24 +60,44 @@ void fsnotify_recalc_inode_mask(struct inode *inode)
 
 void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
 {
-	struct inode *inode = mark->i.inode;
+	struct inode *inode;
 
-	assert_spin_locked(&mark->lock);
-	assert_spin_locked(&mark->group->mark_lock);
+	/* prepare removal from inode */
+	spin_lock(&mark->lock);
+	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
+		spin_unlock(&mark->lock);
+		return;
+	}
+	inode = mark->i.inode;
+	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
+	spin_unlock(&mark->lock);
 
+	/* remove mark from inode */
 	spin_lock(&inode->i_lock);
-
 	hlist_del_init_rcu(&mark->i.i_list);
-	mark->i.inode = NULL;
-
 	/*
 	 * this mark is now off the inode->i_fsnotify_marks list and we
 	 * hold the inode->i_lock, so this is the perfect time to update the
 	 * inode->i_fsnotify_mask
 	 */
 	fsnotify_recalc_inode_mask_locked(inode);
-
 	spin_unlock(&inode->i_lock);
+
+	/* wait until no readers (callers of fsnotify()) reference this
+	   mark any more */
+	synchronize_srcu(&fsnotify_mark_srcu);
+
+	/* do rest of removal */
+	spin_lock(&mark->lock);
+	if (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED) {
+		iput(inode);
+		mark->flags &= ~FSNOTIFY_MARK_FLAG_OBJECT_PINNED;
+		mark->i.inode = NULL;
+	}
+	spin_unlock(&mark->lock);
+
+	/* release ref from list */
+	fsnotify_put_mark(mark);
 }
 
 /*
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c
index 35dc586..20286e3 100644
--- a/fs/notify/vfsmount_mark.c
+++ b/fs/notify/vfsmount_mark.c
@@ -84,19 +84,35 @@ void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt)
 
 void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark)
 {
-	struct vfsmount *mnt = mark->m.mnt;
+	struct vfsmount *mnt;
 
-	assert_spin_locked(&mark->lock);
-	assert_spin_locked(&mark->group->mark_lock);
+	/* prepare removal from vfsmount */
+	spin_lock(&mark->lock);
+	if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
+		spin_unlock(&mark->lock);
+		return;
+	}
+	mnt = mark->m.mnt;
+	mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
+	spin_unlock(&mark->lock);
 
+	/* remove mark from vfsmount */
 	spin_lock(&mnt->mnt_root->d_lock);
-
 	hlist_del_init_rcu(&mark->m.m_list);
-	mark->m.mnt = NULL;
-
 	fsnotify_recalc_vfsmount_mask_locked(mnt);
-
 	spin_unlock(&mnt->mnt_root->d_lock);
+
+	/* wait until no readers (callers of fsnotify()) reference this
+	   mark any more */
+	synchronize_srcu(&fsnotify_mark_srcu);
+
+	/* do rest of removal */
+	spin_lock(&mark->lock);
+	mark->m.mnt = NULL;
+	spin_unlock(&mark->lock);
+
+	/* release ref from list */
+	fsnotify_put_mark(mark);
 }
 
 static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group,
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ