From: Jan Blunck <jblunck@suse.de>
To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org
Cc: viro@zeniv.linux.org.uk, bharata@in.ibm.com, dwmw2@infradead.org,
mszeredi@suse.cz, vaurora@redhat.com
Subject: [PATCH 07/32] VFS: Introduce dput() variant that maintains a kill-list
Date: Mon, 18 May 2009 18:09:03 +0200 [thread overview]
Message-ID: <1242662968-11684-8-git-send-email-jblunck@suse.de> (raw)
In-Reply-To: <1242662968-11684-1-git-send-email-jblunck@suse.de>
This patch introduces a new variant of dput(). This becomes necessary to
prevent a recursive call to dput() from the union mount code.
void __dput(struct dentry *dentry, struct list_head *list, int greedy);
struct dentry *__d_kill(struct dentry *dentry, struct list_head *list,
int greedy);
__dput() works mostly like the original dput() did. The main difference is
that if it the greedy argument is zero it will put the parent on a special
list instead of trying to get rid of it directly.
Therefore the union mount code can safely call __dput() when it wants to get
rid of underlying dentry references during a dput(). After calling __dput()
or __d_kill() the caller must make sure that __d_kill_final() is called on all
dentries on the kill list. __d_kill_final() is actually doing the
dentry_iput() and is also dereferencing the parent.
Signed-off-by: Jan Blunck <jblunck@suse.de>
Signed-off-by: Valerie Aurora (Henson) <vaurora@redhat.com>
---
fs/dcache.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 105 insertions(+), 10 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 085f527..8bfbcd7 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -157,14 +157,19 @@ static void dentry_lru_del_init(struct dentry *dentry)
}
/**
- * d_kill - kill dentry and return parent
+ * __d_kill - kill dentry and return parent
* @dentry: dentry to kill
+ * @list: kill list
+ * @greedy: return parent instead of putting it on the kill list
*
* The dentry must already be unhashed and removed from the LRU.
*
- * If this is the root of the dentry tree, return NULL.
+ * If this is the root of the dentry tree, return NULL. If greedy is zero, we
+ * put the parent of this dentry on the kill list instead. The callers must
+ * make sure that __d_kill_final() is called on all dentries on the kill list.
*/
-static struct dentry *d_kill(struct dentry *dentry)
+static struct dentry *__d_kill(struct dentry *dentry, struct list_head *list,
+ int greedy)
__releases(dentry->d_lock)
__releases(dcache_lock)
{
@@ -172,6 +177,20 @@ static struct dentry *d_kill(struct dentry *dentry)
list_del(&dentry->d_u.d_child);
dentry_stat.nr_dentry--; /* For d_free, below */
+
+ /*
+ * If we are not greedy we just put this on a list for later processing
+ * (follow up to parent, releasing of inode and freeing dentry memory).
+ */
+ if (!greedy) {
+ list_del_init(&dentry->d_alias);
+ /* at this point nobody can reach this dentry */
+ list_add(&dentry->d_lru, list);
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&dcache_lock);
+ return NULL;
+ }
+
/*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
if (IS_ROOT(dentry))
@@ -182,6 +201,54 @@ static struct dentry *d_kill(struct dentry *dentry)
return parent;
}
+void __dput(struct dentry *, struct list_head *, int);
+
+static void __d_kill_final(struct dentry *dentry, struct list_head *list)
+{
+ struct dentry *parent;
+ struct inode *inode = dentry->d_inode;
+
+ if (inode) {
+ dentry->d_inode = NULL;
+ if (!inode->i_nlink)
+ fsnotify_inoderemove(inode);
+ if (dentry->d_op && dentry->d_op->d_iput)
+ dentry->d_op->d_iput(dentry, inode);
+ else
+ iput(inode);
+ }
+
+ if (IS_ROOT(dentry))
+ parent = NULL;
+ else
+ parent = dentry->d_parent;
+ d_free(dentry);
+ __dput(parent, list, 1);
+}
+
+/**
+ * d_kill - kill dentry and return parent
+ * @dentry: dentry to kill
+ *
+ * The dentry must already be unhashed and removed from the LRU.
+ *
+ * If this is the root of the dentry tree, return NULL.
+ */
+static struct dentry *d_kill(struct dentry *dentry)
+{
+ LIST_HEAD(mortuary);
+ struct dentry *parent;
+
+ parent = __d_kill(dentry, &mortuary, 1);
+ while (!list_empty(&mortuary)) {
+ dentry = list_entry(mortuary.next, struct dentry, d_lru);
+ list_del(&dentry->d_lru);
+ __d_kill_final(dentry, &mortuary);
+ }
+
+ return parent;
+}
+
/*
* This is dput
*
@@ -199,19 +266,24 @@ static struct dentry *d_kill(struct dentry *dentry)
* Real recursion would eat up our stack space.
*/
-/*
- * dput - release a dentry
- * @dentry: dentry to release
+/**
+ * __dput - release a dentry
+ * @dentry: dentry to release
+ * @list: kill list argument for __d_kill()
+ * @greedy: greedy argument for __d_kill()
*
* Release a dentry. This will drop the usage count and if appropriate
* call the dentry unlink method as well as removing it from the queues and
* releasing its resources. If the parent dentries were scheduled for release
- * they too may now get deleted.
+ * they too may now get deleted if @greedy is not zero. Otherwise parent is
+ * added to the kill list. The callers must make sure that __d_kill_final() is
+ * called on all dentries on the kill list.
+ *
+ * You probably want to use dput() instead.
*
* no dcache lock, please.
*/
-
-void dput(struct dentry *dentry)
+void __dput(struct dentry *dentry, struct list_head *list, int greedy)
{
if (!dentry)
return;
@@ -252,12 +324,35 @@ unhash_it:
kill_it:
/* if dentry was on the d_lru list delete it from there */
dentry_lru_del(dentry);
- dentry = d_kill(dentry);
+ dentry = __d_kill(dentry, list, greedy);
if (dentry)
goto repeat;
}
/**
+ * dput - release a dentry
+ * @dentry: dentry to release
+ *
+ * Release a dentry. This will drop the usage count and if appropriate
+ * call the dentry unlink method as well as removing it from the queues and
+ * releasing its resources. If the parent dentries were scheduled for release
+ * they too may now get deleted.
+ *
+ * no dcache lock, please.
+ */
+void dput(struct dentry *dentry)
+{
+ LIST_HEAD(mortuary);
+
+ __dput(dentry, &mortuary, 1);
+ while (!list_empty(&mortuary)) {
+ dentry = list_entry(mortuary.next, struct dentry, d_lru);
+ list_del(&dentry->d_lru);
+ __d_kill_final(dentry, &mortuary);
+ }
+}
+
+/**
* d_invalidate - invalidate a dentry
* @dentry: dentry to invalidate
*
--
1.6.1.3
next prev parent reply other threads:[~2009-05-18 16:09 UTC|newest]
Thread overview: 72+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-18 16:08 [PATCH 00/32] VFS based Union Mount (V3) Jan Blunck
2009-05-18 16:08 ` [PATCH 01/32] atomic: Only take lock when the counter drops to zero on UP as well Jan Blunck
2009-05-18 16:08 ` [PATCH 02/32] VFS: BUG() if somebody tries to rehash an already hashed dentry Jan Blunck
2009-05-18 16:08 ` [PATCH 03/32] VFS: propagate mnt_flags into do_loopback Jan Blunck
2009-05-18 16:09 ` [PATCH 04/32] VFS: Make lookup_hash() return a struct path Jan Blunck
2009-05-18 16:09 ` [PATCH 05/32] VFS: Remove unnecessary micro-optimization in cached_lookup() Jan Blunck
2009-05-18 16:09 ` [PATCH 06/32] VFS: Make real_lookup() return a struct path Jan Blunck
2009-05-18 16:09 ` Jan Blunck [this message]
2009-05-18 16:09 ` [PATCH 08/32] whiteout: Don't return information about whiteouts to userspace Jan Blunck
2009-05-18 16:09 ` [PATCH 09/32] whiteout: Add vfs_whiteout() and whiteout inode operation Jan Blunck
2009-05-18 16:09 ` [PATCH 10/32] whiteout: Set S_OPAQUE inode flag when creating directories Jan Blunck
2009-05-18 16:09 ` [PATCH 11/32] whiteout: Add whiteout support to tmpfs Jan Blunck
2009-05-18 16:09 ` [PATCH 12/32] whiteout: Split of ext2_append_link() from ext2_add_link() Jan Blunck
2009-05-18 16:09 ` [PATCH 13/32] whiteout: Add whiteout support to ext2 Jan Blunck
2009-05-18 16:09 ` [PATCH 14/32] whiteout: Add path_whiteout() helper Jan Blunck
2009-05-18 16:09 ` [PATCH 15/32] union-mount: Documentation Jan Blunck
2009-05-25 6:25 ` hooanon05
2009-05-25 8:03 ` Arnd Bergmann
2009-05-25 8:43 ` hooanon05
2009-06-18 19:05 ` Valerie Aurora
2009-06-19 1:53 ` hooanon05
2009-05-18 16:09 ` [PATCH 16/32] union-mount: Introduce MNT_UNION and MS_UNION flags Jan Blunck
2009-05-18 16:09 ` [PATCH 17/32] union-mount: Introduce union_mount structure Jan Blunck
2009-05-18 16:09 ` [PATCH 18/32] union-mount: Drive the union cache via dcache Jan Blunck
2009-05-18 16:09 ` [PATCH 19/32] union-mount: Some checks during namespace changes Jan Blunck
2009-05-18 16:09 ` [PATCH 20/32] union-mount: Changes to the namespace handling Jan Blunck
2009-05-18 16:09 ` [PATCH 21/32] union-mount: Make lookup work for union-mounted file systems Jan Blunck
2009-05-19 16:15 ` Miklos Szeredi
2009-05-19 17:30 ` Valerie Aurora
2009-05-20 10:21 ` Miklos Szeredi
2009-05-18 16:09 ` [PATCH 22/32] union-mount: stop lookup when directory has S_OPAQUE flag set Jan Blunck
2009-05-18 16:09 ` [PATCH 23/32] union-mount: stop lookup when finding a whiteout Jan Blunck
2009-05-18 16:09 ` [PATCH 24/32] union-mount: in-kernel file copy between union mounted filesystems Jan Blunck
2009-05-18 16:09 ` [PATCH 25/32] union-mount: check for logically empty directory (FIXME) Jan Blunck
2009-05-18 16:09 ` [PATCH 26/32] union-mount: call do_whiteout() on unlink and rmdir Jan Blunck
2009-05-18 16:09 ` [PATCH 27/32] union-mount: Always create topmost directory on open Jan Blunck
2009-05-18 16:09 ` [PATCH 28/32] union-mount: Basic fallthru definitions Jan Blunck
2009-05-18 16:09 ` [PATCH 29/32] union mount: Support for fallthru entries in union mount lookup Jan Blunck
2009-05-18 16:09 ` [PATCH 30/32] union mount: ext2 fallthru support Jan Blunck
2009-05-18 16:32 ` Andreas Dilger
2009-05-19 9:42 ` Jan Blunck
2009-05-19 14:05 ` Andreas Dilger
2009-05-19 16:13 ` Jan Blunck
2009-05-18 16:09 ` [PATCH 31/32] union-mount: tmpfs " Jan Blunck
2009-05-18 16:09 ` [PATCH 32/32] union-mount: Copy up directory entries on first readdir() Jan Blunck
2009-05-18 20:40 ` [PATCH] Userland for VFS based Union Mount (V3) Valerie Aurora
2009-05-21 13:53 ` Andreas Dilger
2009-06-18 3:22 ` Valerie Aurora
2009-05-19 9:48 ` [PATCH 00/32] " Miklos Szeredi
2009-05-19 10:29 ` Jan Blunck
2009-05-19 10:35 ` Miklos Szeredi
2009-05-19 10:39 ` Jan Blunck
2009-05-19 11:54 ` Arnd Bergmann
2009-05-19 11:54 ` Arnd Bergmann
2009-05-19 12:15 ` Jan Blunck
2009-05-19 12:21 ` Arnd Bergmann
2009-05-19 13:10 ` Jan Blunck
2009-05-19 17:23 ` Valerie Aurora
2009-05-20 9:05 ` Miklos Szeredi
2009-06-08 19:44 ` Valerie Aurora
2009-06-16 15:19 ` Miklos Szeredi
2009-05-21 12:54 ` Jan Rekorajski
2009-06-08 19:57 ` Valerie Aurora
2009-06-08 19:57 ` Valerie Aurora
2009-06-08 22:44 ` Jan Rekorajski
2009-06-08 22:48 ` Valerie Aurora
2009-06-08 22:48 ` Valerie Aurora
2009-06-15 9:55 ` Jan Rekorajski
2009-06-18 3:23 ` Valerie Aurora
2009-06-18 3:23 ` Valerie Aurora
2009-06-04 11:38 ` Scott James Remnant
2009-06-09 22:15 ` Valerie Aurora
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=1242662968-11684-8-git-send-email-jblunck@suse.de \
--to=jblunck@suse.de \
--cc=bharata@in.ibm.com \
--cc=dwmw2@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mszeredi@suse.cz \
--cc=vaurora@redhat.com \
--cc=viro@zeniv.linux.org.uk \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.