lkml.org 
[lkml]   [1997]   [Sep]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectimplementation of shrink_dcache_sb
I've attached a preliminary implementation of a shrink_dcache_sb()
function to be used when unmounting a device or invalidating a device's
inodes. This provides finer control over the dcache by not forcing a
full shrink when we just need to remove a device.

To provide reasonable efficiency I move all leaf nodes to a temporary
list, prune them from there, and then repeat as needed. Note that it
doesn't matter if one of the dentries on the temporary list goes back
into use while waiting to be freed; it will simply be unlinked from the
list.

In testing so far this seems to work fine. I'm calling it from do_umount
and from smbfs when invalidating inodes.

Comments or suggested improvements welcome. The patch is against
pre-2.1.56.

Regards,
Bill--- fs/dcache.c.old Sat Sep 13 21:36:53 1997
+++ fs/dcache.c Tue Sep 16 15:08:26 1997
@@ -119,13 +119,13 @@
* something (at which point we need to unuse
* all dentries).
*/
-void prune_dcache(int count)
+static void __prune_dcache(struct list_head *head, unsigned int count)
{
for (;;) {
struct dentry *dentry;
- struct list_head *tmp = dentry_unused.prev;
+ struct list_head *tmp = head->prev;

- if (tmp == &dentry_unused)
+ if (tmp == head)
break;
list_del(tmp);
INIT_LIST_HEAD(tmp);
@@ -149,6 +149,53 @@
}
}

+void prune_dcache(int count)
+{
+ __prune_dcache(&dentry_unused, count);
+}
+
+/* N.B. move to include/linux/dcache.h */
+extern void shrink_dcache_sb(struct super_block *);
+/*
+ * Shrink the dcache for the specified super block.
+ * This allows us to unmount a device without disturbing
+ * the dcache for the other devices.
+ *
+ * We move the selected dentries to a temporary list,
+ * and then shrink that in the usual manner.
+ */
+void shrink_dcache_sb(struct super_block * sb)
+{
+ struct list_head *tmp, *prev;
+ struct dentry *dentry;
+ LIST_HEAD(temp);
+
+repeat:
+ prev = dentry_unused.prev;
+ while (prev != &dentry_unused) {
+ tmp = prev;
+ prev = tmp->prev;
+ dentry = list_entry(tmp, struct dentry, d_lru);
+ /*
+ * If the dentry is in use, we can always remove it.
+ * This makes less work for the next pass ...
+ */
+ if (dentry->d_count) {
+ list_del(tmp);
+ INIT_LIST_HEAD(tmp);
+ continue;
+ }
+ if (dentry->d_sb == sb) {
+ list_del(tmp);
+ list_add(tmp, &temp);
+ }
+ }
+ if (!list_empty(&temp)) {
+ __prune_dcache(&temp, 0);
+ goto repeat;
+ }
+}
+
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)

struct dentry * d_alloc(struct dentry * parent, const struct qstr *name)
\
 
 \ /
  Last update: 2005-03-22 13:40    [W:0.039 / U:0.112 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site