patch-2.3.99-pre9 linux/fs/dcache.c

Next file: linux/fs/devfs/base.c
Previous file: linux/fs/cramfs/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.99-pre8/linux/fs/dcache.c linux/fs/dcache.c
@@ -131,7 +131,8 @@
 	 * Each fs will have to watch for this.
 	 */
 	if (dentry->d_op && dentry->d_op->d_delete) {
-		dentry->d_op->d_delete(dentry);
+		if (dentry->d_op->d_delete(dentry))
+			d_drop(dentry);
 
 		count = dentry->d_count - 1;
 		if (count != 0)
@@ -220,6 +221,53 @@
 	return 0;
 }
 
+/**
+ * d_find_alias - grab a hashed alias of inode
+ * @inode: inode in question
+ *
+ * If inode has a hashed alias - acquire the reference to alias and
+ * return it. Otherwise return NULL. Notice that if inode is a directory
+ * there can be only one alias and it can be unhashed only if it has
+ * no children.
+ */
+
+struct dentry * d_find_alias(struct inode *inode)
+{
+	struct list_head *head, *next, *tmp;
+	struct dentry *alias;
+
+	head = &inode->i_dentry;
+	next = inode->i_dentry.next;
+	while (next != head) {
+		tmp = next;
+		next = tmp->next;
+		alias = list_entry(tmp, struct dentry, d_alias);
+		if (!d_unhashed(alias))
+			return dget(alias);
+	}
+	return NULL;
+}
+
+/*
+ *	Try to kill dentries associated with this inode.
+ * WARNING: you must own a reference to inode.
+ */
+void d_prune_aliases(struct inode *inode)
+{
+	struct list_head *tmp, *head = &inode->i_dentry;
+restart:
+	tmp = head;
+	while ((tmp = tmp->next) != head) {
+		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
+		if (!dentry->d_count) {
+			dget(dentry);
+			d_drop(dentry);
+			dput(dentry);
+			goto restart;
+		}
+	}
+}
+
 /*
  * Throw away a dentry - free the inode, dput the parent.
  * This requires that the LRU list has already been
@@ -384,37 +432,6 @@
 	return 0; /* No mount points found in tree */
 }
 
-int d_active_refs(struct dentry *root)
-{
-	struct dentry *this_parent = root;
-	struct list_head *next;
-	int count = root->d_count;
-
-repeat:
-	next = this_parent->d_subdirs.next;
-resume:
-	while (next != &this_parent->d_subdirs) {
-		struct list_head *tmp = next;
-		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
-		next = tmp->next;
-		/* Decrement count for unused children */
-		count += (dentry->d_count - 1);
-		if (!list_empty(&dentry->d_subdirs)) {
-			this_parent = dentry;
-			goto repeat;
-		}
-	}
-	/*
-	 * All done at this level ... ascend and resume the search.
-	 */
-	if (this_parent != root) {
-		next = this_parent->d_child.next; 
-		this_parent = this_parent->d_parent;
-		goto resume;
-	}
-	return count;
-}
-
 /*
  * Search the dentry child list for the specified parent,
  * and move any unused dentries to the end of the unused
@@ -788,7 +805,7 @@
  * Note that we have to be a lot more careful about getting the hash
  * switched - we have to switch the hash value properly even if it
  * then no longer matches the actual (corrupted) string of the target.
- * The has value has to match the hash queue that the dentry is on..
+ * The hash value has to match the hash queue that the dentry is on..
  */
 static inline void switch_names(struct dentry * dentry, struct dentry * target)
 {
@@ -948,7 +965,12 @@
 asmlinkage long sys_getcwd(char *buf, unsigned long size)
 {
 	int error;
-	struct dentry *pwd = current->fs->pwd; 
+	struct vfsmount *pwdmnt;
+	struct dentry *pwd;
+
+	lock_kernel();
+	pwdmnt = mntget(current->fs->pwdmnt);
+	pwd = dget(current->fs->pwd);
 
 	error = -ENOENT;
 	/* Has the current directory has been unlinked? */
@@ -959,9 +981,7 @@
 			unsigned long len;
 			char * cwd;
 
-			lock_kernel();
 			cwd = d_path(pwd, current->fs->pwdmnt, page, PAGE_SIZE);
-			unlock_kernel();
 
 			error = -ERANGE;
 			len = PAGE_SIZE + page - cwd;
@@ -973,6 +993,9 @@
 			free_page((unsigned long) page);
 		}
 	}
+	dput(pwd);
+	mntput(pwdmnt);
+	unlock_kernel();
 	return error;
 }
 
@@ -1008,6 +1031,34 @@
 		break;
 	}
 	return result;
+}
+
+void d_genocide(struct dentry *root)
+{
+	struct dentry *this_parent = root;
+	struct list_head *next;
+
+repeat:
+	next = this_parent->d_subdirs.next;
+resume:
+	while (next != &this_parent->d_subdirs) {
+		struct list_head *tmp = next;
+		struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
+		next = tmp->next;
+		if (d_unhashed(dentry)||!dentry->d_inode)
+			continue;
+		if (!list_empty(&dentry->d_subdirs)) {
+			this_parent = dentry;
+			goto repeat;
+		}
+		dentry->d_count--;
+	}
+	if (this_parent != root) {
+		next = this_parent->d_child.next; 
+		this_parent->d_count--;
+		this_parent = this_parent->d_parent;
+		goto resume;
+	}
 }
 
 /**

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)