... and the same for ipathfs

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index 4496f28..0db9c41 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -1,7 +1,7 @@
 ccflags-y := -DIPATH_IDSTR='"QLogic kernel.org driver"' \
 	-DIPATH_KERN_TYPE=0
 
-obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
+obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o ib_ipath_fs.o
 
 ib_ipath-y := \
 	ipath_cq.o \
diff --git a/drivers/infiniband/hw/ipath/ib_ipath_fs.c b/drivers/infiniband/hw/ipath/ib_ipath_fs.c
new file mode 100644
index 0000000..bac0aac
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ib_ipath_fs.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
+ * Copyright (c) 2006 PathScale, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+
+#include "ipath_kernel.h"
+
+#define IPATHFS_MAGIC 0x726a77
+
+struct infinipath_stats ipath_stats;
+EXPORT_SYMBOL(ipath_stats);
+static ssize_t atomic_stats_read(struct file *file, char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	return simple_read_from_buffer(buf, count, ppos, &ipath_stats,
+				       sizeof ipath_stats);
+}
+
+static const struct file_operations atomic_stats_ops = {
+	.read = atomic_stats_read,
+	.llseek = default_llseek,
+};
+
+
+static int ipathfs_fill_super(struct super_block *sb, void *data,
+			      int silent)
+{
+	static struct tree_descr files[] = {
+		[2] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
+		{""},
+	};
+
+	return simple_fill_super(sb, IPATHFS_MAGIC, files);
+}
+
+static struct dentry *ipathfs_mount(struct file_system_type *fs_type,
+			int flags, const char *dev_name, void *data)
+{
+	return mount_single(fs_type, flags, data, ipathfs_fill_super);
+}
+
+static struct file_system_type ipathfs_fs_type = {
+	.owner =	THIS_MODULE,
+	.name =		"ipathfs",
+	.mount =	ipathfs_mount,
+	.kill_sb =	kill_litter_super,
+};
+
+static struct vfsmount *mnt;
+static int count;
+
+struct dentry *ipathfs_pin(void)
+{
+	int err = simple_pin_fs(&ipathfs_fs_type, &mnt, &count);
+	return err ? ERR_PTR(err) : mnt->mnt_root;
+}
+EXPORT_SYMBOL(ipathfs_pin);
+
+void ipathfs_unpin(void)
+{
+	simple_release_fs(&mnt, &count);
+}
+EXPORT_SYMBOL(ipathfs_unpin);
+
+static int __init ipath_init_ipathfs(void)
+{
+	return register_filesystem(&ipathfs_fs_type);
+}
+
+static void __exit ipath_exit_ipathfs(void)
+{
+	unregister_filesystem(&ipathfs_fs_type);
+}
+module_init(ipath_init_ipathfs)
+module_exit(ipath_exit_ipathfs)
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index bfca37b..95cca2c 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -2518,18 +2518,8 @@
 		goto bail_unit;
 	}
 
-	ret = ipath_init_ipathfs();
-	if (ret < 0) {
-		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
-		       "ipathfs: error %d\n", -ret);
-		goto bail_pci;
-	}
-
 	goto bail;
 
-bail_pci:
-	pci_unregister_driver(&ipath_driver);
-
 bail_unit:
 	idr_destroy(&unit_table);
 
@@ -2539,8 +2529,6 @@
 
 static void __exit infinipath_cleanup(void)
 {
-	ipath_exit_ipathfs();
-
 	ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
 	pci_unregister_driver(&ipath_driver);
 
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index a4de9d5..9ee3a2f 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -41,10 +41,6 @@
 
 #include "ipath_kernel.h"
 
-#define IPATHFS_MAGIC 0x726a77
-
-static struct super_block *ipath_super;
-
 static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
 			 umode_t mode, const struct file_operations *fops,
 			 void *data)
@@ -82,7 +78,6 @@
 {
 	int error;
 
-	*dentry = NULL;
 	mutex_lock(&parent->d_inode->i_mutex);
 	*dentry = lookup_one_len(name, parent, strlen(name));
 	if (!IS_ERR(*dentry))
@@ -95,18 +90,6 @@
 	return error;
 }
 
-static ssize_t atomic_stats_read(struct file *file, char __user *buf,
-				 size_t count, loff_t *ppos)
-{
-	return simple_read_from_buffer(buf, count, ppos, &ipath_stats,
-				       sizeof ipath_stats);
-}
-
-static const struct file_operations atomic_stats_ops = {
-	.read = atomic_stats_read,
-	.llseek = default_llseek,
-};
-
 static ssize_t atomic_counters_read(struct file *file, char __user *buf,
 				    size_t count, loff_t *ppos)
 {
@@ -230,7 +213,7 @@
 	.llseek = default_llseek,
 };
 
-static int create_device_files(struct super_block *sb,
+static int create_device_files(struct dentry *root,
 			       struct ipath_devdata *dd)
 {
 	struct dentry *dir, *tmp;
@@ -238,12 +221,13 @@
 	int ret;
 
 	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
-	ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
+	ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, root, &dir,
 			  &simple_dir_operations, dd);
 	if (ret) {
 		printk(KERN_ERR "create_file(%s) failed: %d\n", unit, ret);
 		goto bail;
 	}
+	dd->ipathfs_dir = dir;
 
 	ret = create_file("atomic_counters", S_IFREG|S_IRUGO, dir, &tmp,
 			  &atomic_counters_ops, dd);
@@ -295,128 +279,40 @@
 	return ret;
 }
 
-static int remove_device_files(struct super_block *sb,
-			       struct ipath_devdata *dd)
+static int remove_device_files(struct ipath_devdata *dd)
 {
-	struct dentry *dir, *root;
-	char unit[10];
+	struct dentry *dir = dd->ipathfs_dir;
+	struct dentry *root;
 	int ret;
 
-	root = dget(sb->s_root);
+	if (!dir)
+		return 0;
+
+	root = dir->d_sb->s_root;
 	mutex_lock(&root->d_inode->i_mutex);
-	snprintf(unit, sizeof unit, "%02d", dd->ipath_unit);
-	dir = lookup_one_len(unit, root, strlen(unit));
-
-	if (IS_ERR(dir)) {
-		ret = PTR_ERR(dir);
-		printk(KERN_ERR "Lookup of %s failed\n", unit);
-		goto bail;
-	}
-
 	remove_file(dir, "flash");
 	remove_file(dir, "atomic_counters");
 	d_delete(dir);
 	ret = simple_rmdir(root->d_inode, dir);
-
-bail:
 	mutex_unlock(&root->d_inode->i_mutex);
-	dput(root);
-	return ret;
-}
-
-static int ipathfs_fill_super(struct super_block *sb, void *data,
-			      int silent)
-{
-	struct ipath_devdata *dd, *tmp;
-	unsigned long flags;
-	int ret;
-
-	static struct tree_descr files[] = {
-		[2] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
-		{""},
-	};
-
-	ret = simple_fill_super(sb, IPATHFS_MAGIC, files);
-	if (ret) {
-		printk(KERN_ERR "simple_fill_super failed: %d\n", ret);
-		goto bail;
-	}
-
-	spin_lock_irqsave(&ipath_devs_lock, flags);
-
-	list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
-		spin_unlock_irqrestore(&ipath_devs_lock, flags);
-		ret = create_device_files(sb, dd);
-		if (ret)
-			goto bail;
-		spin_lock_irqsave(&ipath_devs_lock, flags);
-	}
-
-	spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
-bail:
-	return ret;
-}
-
-static struct dentry *ipathfs_mount(struct file_system_type *fs_type,
-			int flags, const char *dev_name, void *data)
-{
-	struct dentry *ret;
-	ret = mount_single(fs_type, flags, data, ipathfs_fill_super);
-	if (!IS_ERR(ret))
-		ipath_super = ret->d_sb;
-	return ret;
-}
-
-static void ipathfs_kill_super(struct super_block *s)
-{
-	kill_litter_super(s);
-	ipath_super = NULL;
-}
-
-int ipathfs_add_device(struct ipath_devdata *dd)
-{
-	int ret;
-
-	if (ipath_super == NULL) {
-		ret = 0;
-		goto bail;
-	}
-
-	ret = create_device_files(ipath_super, dd);
-
-bail:
 	return ret;
 }
 
 int ipathfs_remove_device(struct ipath_devdata *dd)
 {
-	int ret;
-
-	if (ipath_super == NULL) {
-		ret = 0;
-		goto bail;
-	}
-
-	ret = remove_device_files(ipath_super, dd);
-
-bail:
+	int ret = remove_device_files(dd);
+	ipathfs_unpin();
 	return ret;
 }
 
-static struct file_system_type ipathfs_fs_type = {
-	.owner =	THIS_MODULE,
-	.name =		"ipathfs",
-	.mount =	ipathfs_mount,
-	.kill_sb =	ipathfs_kill_super,
-};
-
-int __init ipath_init_ipathfs(void)
+int ipathfs_add_device(struct ipath_devdata *dd)
 {
-	return register_filesystem(&ipathfs_fs_type);
-}
-
-void __exit ipath_exit_ipathfs(void)
-{
-	unregister_filesystem(&ipathfs_fs_type);
+	struct dentry *root = ipathfs_pin();
+	int ret = PTR_ERR(root);
+	if (!IS_ERR(root)) {
+		ret = create_device_files(root, dd);
+		if (ret)
+			ipathfs_remove_device(dd);
+	}
+	return ret;
 }
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 6559af6..9069779 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -828,6 +828,7 @@
 	 */
 	spinlock_t ipath_sdepb_lock;
 	u8 ipath_presets_needed; /* Set if presets to be restored next DOWN */
+	struct dentry *ipathfs_dir;
 };
 
 /* ipath_hol_state values (stopping/starting user proc, send flushing) */
@@ -1290,11 +1291,12 @@
 void ipath_device_remove_group(struct device *, struct ipath_devdata *);
 int ipath_expose_reset(struct device *);
 
-int ipath_init_ipathfs(void);
-void ipath_exit_ipathfs(void);
 int ipathfs_add_device(struct ipath_devdata *);
 int ipathfs_remove_device(struct ipath_devdata *);
 
+struct dentry *ipathfs_pin(void);
+void ipathfs_unpin(void);
+
 /*
  * dma_addr wrappers - all 0's invalid for hw
  */
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index f63e143..5cab5e9 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -33,8 +33,6 @@
 
 #include "ipath_kernel.h"
 
-struct infinipath_stats ipath_stats;
-
 /**
  * ipath_snap_cntr - snapshot a chip counter
  * @dd: the infinipath device