From 2a3c22eeb53d42e9e872fd3698bd807678942be5 Mon Sep 17 00:00:00 2001
From: shirish <shirish@linuxssp.site>
Date: Mon, 18 Aug 2014 20:30:46 -0500
Subject: [PATCH 3/8] cifs: shared_superblock - various routines to search
 disconnected root dentry

[ddiss@suse.de: rebase against master with cifs_d_delete %pd debug msg]
---
 fs/cifs/cifsproto.h |  1 +
 fs/cifs/dir.c       | 95 +++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 86 insertions(+), 10 deletions(-)

diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1243bd3..ca2dfbe9 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -204,6 +204,7 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
 					 struct tcon_link *tlink,
 					 struct cifs_pending_open *open);
 extern void cifs_del_pending_open(struct cifs_pending_open *open);
+extern void cifs_free_rdelem(struct cifs_rdelem *);
 
 #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL)
 extern void cifs_dfs_release_automount_timer(void);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index c3eb998..a3106e1 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -704,6 +704,58 @@ mknod_out:
 	return rc;
 }
 
+struct cifs_rdelem *
+find_rdelem_by_inode(struct inode *rdinode, struct cifs_sb_info * cifs_sb)
+{
+	struct cifs_rdelem *rdelem;
+
+	spin_lock(&cifs_sb->rtdislock);
+	list_for_each_entry(rdelem, &cifs_sb->rtdislist, rdlist) {
+		if (rdelem->rdinode == rdinode) {
+			list_del(&rdelem->rdlist);
+			spin_unlock(&cifs_sb->rtdislock);
+			return rdelem;
+		}
+	}
+	spin_unlock(&cifs_sb->rtdislock);
+	return NULL;
+}
+
+static struct cifs_rdelem *
+find_rdelem_by_dentry(const struct dentry *rdentry,
+			struct cifs_sb_info * cifs_sb)
+{
+	struct cifs_rdelem *rdelem;
+
+	spin_lock(&cifs_sb->rtdislock);
+	list_for_each_entry(rdelem, &cifs_sb->rtdislist, rdlist) {
+		if (rdelem->rdentry == rdentry) {
+			list_del(&rdelem->rdlist);
+			spin_unlock(&cifs_sb->rtdislock);
+			return rdelem;
+		}
+	}
+	spin_unlock(&cifs_sb->rtdislock);
+	return NULL;
+}
+
+void
+find_rdelem_by_path(char *full_path, struct inode **newInode,
+			struct cifs_sb_info * cifs_sb)
+{
+	struct cifs_rdelem *rdelem;
+
+	spin_lock(&cifs_sb->rtdislock);
+	list_for_each_entry(rdelem, &cifs_sb->rtdislist, rdlist) {
+		if (!strcmp(rdelem->rdname, full_path)) {
+			*newInode = ilookup(rdelem->rdinode->i_sb,
+						rdelem->rdinode->i_ino);
+			break;
+		}
+	}
+	spin_unlock(&cifs_sb->rtdislock);
+}
+
 struct dentry *
 cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
 	    unsigned int flags)
@@ -785,6 +837,35 @@ lookup_out:
 	return ERR_PTR(rc);
 }
 
+static void
+cifs_d_common_releasedelete(const struct dentry *dentry)
+{
+	struct cifs_rdelem *rdelem;
+	struct cifs_sb_info *cifs_sb;
+
+	cifs_sb = CIFS_SB(dentry->d_sb);
+
+	/* disconnected root dentries that did not get spliced */
+	if (IS_ROOT(dentry) && dentry->d_flags & DCACHE_DISCONNECTED) {
+		rdelem = find_rdelem_by_dentry(dentry, cifs_sb);
+		if (rdelem)
+			cifs_free_rdelem(rdelem);
+	}
+}
+
+static int
+cifs_d_delete(const struct dentry *dentry)
+{
+	cifs_d_common_releasedelete(dentry);
+	return 0;
+}
+
+static void
+cifs_d_release(struct dentry *dentry)
+{
+	cifs_d_common_releasedelete(dentry);
+}
+
 static int
 cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 {
@@ -834,19 +915,11 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
 	return 1;
 }
 
-/* static int cifs_d_delete(struct dentry *direntry)
-{
-	int rc = 0;
-
-	cifs_dbg(FYI, "In cifs d_delete, name = %pd\n", direntry);
-
-	return rc;
-}     */
-
 const struct dentry_operations cifs_dentry_ops = {
 	.d_revalidate = cifs_d_revalidate,
 	.d_automount = cifs_dfs_d_automount,
-/* d_delete:       cifs_d_delete,      */ /* not needed except for debugging */
+	.d_delete = cifs_d_delete,
+	.d_release = cifs_d_release,
 };
 
 static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
@@ -921,4 +994,6 @@ const struct dentry_operations cifs_ci_dentry_ops = {
 	.d_hash = cifs_ci_hash,
 	.d_compare = cifs_ci_compare,
 	.d_automount = cifs_dfs_d_automount,
+	.d_delete = cifs_d_delete,
+	.d_release = cifs_d_release,
 };
-- 
2.1.4

