[PATCH 03/17] VFS: Implement handling for pathless pioctls

David Howells dhowells at redhat.com
Tue Jun 16 16:39:01 EDT 2009


From: Wang Lei <wang840925 at gmail.com>

Implement handling for pathless pioctls.  Because these take no path argument,
there's no way to know for certain which filesystem they're aimed at, so we
have to switch on command number instead.  This patch allows interested parties
to register handlers.  Each registered handler function is tried in turn until
one doesn't return -EOPNOTSUPP.

This is required because OpenAFS implemented a number of AFS calls that don't
get given a path as they're aimed at AFS in general, and not at a particular
file, volume or cell in the AFS world.

Signed-off-by: Wang Lei <wang840925 at gmail.com>
Signed-off-by: David Howells <dhowells at redhat.com>
---

 fs/compat_pioctl.c     |   14 ++++--
 fs/pioctl.c            |  114 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/pioctl.h |   12 +++++
 3 files changed, 130 insertions(+), 10 deletions(-)


diff --git a/fs/compat_pioctl.c b/fs/compat_pioctl.c
index 9f2de77..36b0553 100644
--- a/fs/compat_pioctl.c
+++ b/fs/compat_pioctl.c
@@ -75,11 +75,15 @@ long compat_sys_pioctl(const char __user *filename, int cmd,
 		kargs.out = NULL;
 	}
 
-	error = user_path(filename, &path);
-	if (!error) {
-		if (path.dentry->d_inode)
-			error = vfs_pioctl(path.dentry, cmd, &kargs);
-		path_put(&path);
+	if (!filename) {
+		error = vfs_pioctl(NULL, cmd, &kargs);
+	} else {
+		error = user_path(filename, &path);
+		if (!error) {
+			if (path.dentry->d_inode)
+				error = vfs_pioctl(path.dentry, cmd, &kargs);
+			path_put(&path);
+		}
 	}
 	kfree(kargs.in);
 
diff --git a/fs/pioctl.c b/fs/pioctl.c
index c17f220..1fe4bf8 100644
--- a/fs/pioctl.c
+++ b/fs/pioctl.c
@@ -1,5 +1,6 @@
 /* Path-based I/O control
  *
+ * Copyright (C) 2009 Wang Lei <wang840925 at gmail.com>
  * Copyright (C) 2009 David Howells <dhowells at redhat.com>
  * Copyright (C) 2008 Jacob Thebault-Spieker <summatusmentis at gmail.com>
  *
@@ -12,15 +13,47 @@
 #include <linux/syscalls.h>
 #include <linux/uaccess.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/namei.h>
 #include <linux/pioctl.h>
 #include <linux/slab.h>
 
+static struct pathless_pioctl_handler *pathless_pioctls;
+static DECLARE_RWSEM(pathless_pioctls_rwsem);
+
+/*
+ * Traverse the pathless pioctl handlers list, to find the appropriate handler
+ */
+static long pathless_pioctl(int cmd, struct vice_ioctl *arg)
+{
+	struct pathless_pioctl_handler *p;
+	long ret;
+
+	down_read(&pathless_pioctls_rwsem);
+	p = pathless_pioctls;
+	while (p) {
+		if (try_module_get(p->owner)) {
+			ret = p->pioctl(cmd, arg);
+			module_put(p->owner);
+			if (ret != -EOPNOTSUPP) {
+				up_write(&pathless_pioctls_rwsem);
+				return ret;
+			}
+		}
+		p = p->next;
+	}
+	up_read(&pathless_pioctls_rwsem);
+	return -EOPNOTSUPP;
+}
+
 /*
  * VFS entry point for path-based I/O control
  */
 long vfs_pioctl(struct dentry *dentry, int cmd, struct vice_ioctl *arg)
 {
+	if (!dentry)
+		return pathless_pioctl(cmd, arg);
+
 	if (!dentry->d_inode->i_op || !dentry->d_inode->i_op->pioctl)
 		return -EPERM;
 
@@ -28,6 +61,73 @@ long vfs_pioctl(struct dentry *dentry, int cmd, struct vice_ioctl *arg)
 }
 
 /*
+ * Find the pointer to an pathless pioctl handler or the point at which it
+ * should be inserted
+ */
+static struct pathless_pioctl_handler **find_pathless_pioctl(
+			struct pathless_pioctl_handler *handler)
+{
+	struct pathless_pioctl_handler **p;
+
+	for (p = &pathless_pioctls; *p; p = &(*p)->next)
+		if ((*p) == handler)
+			break;
+	return p;
+}
+
+/**
+ * pathless_pioctl_register - Register a pathless pioctl handler
+ * @handler: The handler to be registered
+ *
+ * Add a handler to the list of pathless pioctl handlers, making sure that the
+ * handler is not already registered.
+ */
+int pathless_pioctl_register(struct pathless_pioctl_handler *handler)
+{
+	int res = 0;
+	struct pathless_pioctl_handler **p;
+
+	if (handler->next)
+		return -EBUSY;
+
+	down_write(&pathless_pioctls_rwsem);
+	p = find_pathless_pioctl(handler);
+	if (*p)
+		res = -EBUSY;
+	else
+		*p = handler;
+	up_write(&pathless_pioctls_rwsem);
+	return res;
+}
+EXPORT_SYMBOL(pathless_pioctl_register);
+
+/**
+ * pathless_pioctl_unregister - Unregister a pathless pioctl handler
+ * @handler: The handler to be unregistered
+ *
+ * Remove the special handler from the list of pathless pioctl handlers, making
+ * sure that the handler is already registered.
+ */
+int pathless_pioctl_unregister(struct pathless_pioctl_handler *handler)
+{
+	struct pathless_pioctl_handler **p;
+
+	down_write(&pathless_pioctls_rwsem);
+	for (p = &pathless_pioctls; *p; p = &(*p)->next) {
+		if (*p == handler) {
+			*p = handler->next;
+			handler->next = NULL;
+			up_write(&pathless_pioctls_rwsem);
+			return 0;
+		}
+		
+	}
+	up_write(&pathless_pioctls_rwsem);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(pathless_pioctl_unregister);
+
+/*
  * Path-based I/O control system call
  */
 SYSCALL_DEFINE4(pioctl,
@@ -82,11 +182,15 @@ SYSCALL_DEFINE4(pioctl,
 		kargs.out = NULL;
 	}
 
-	error = user_path(filename, &path);
-	if (!error) {
-		if (path.dentry->d_inode)
-			error = vfs_pioctl(path.dentry, cmd, &kargs);
-		path_put(&path);
+	if (!filename) {
+		error = vfs_pioctl(NULL, cmd, &kargs);
+	} else {
+		error = user_path(filename, &path);
+		if (!error) {
+			if (path.dentry->d_inode)
+				error = vfs_pioctl(path.dentry, cmd, &kargs);
+			path_put(&path);
+		}
 	}
 	kfree(kargs.in);
 
diff --git a/include/linux/pioctl.h b/include/linux/pioctl.h
index 8e979f4..a4c1082 100644
--- a/include/linux/pioctl.h
+++ b/include/linux/pioctl.h
@@ -41,6 +41,18 @@ struct vice_ioctl {
  */
 extern long vfs_pioctl(struct dentry *, int, struct vice_ioctl *);
 
+/*
+ * Pathless pioctl handler type
+ */
+struct pathless_pioctl_handler {
+	struct module *owner;
+	struct pathless_pioctl_handler *next;
+	long (*pioctl)(int cmd, struct vice_ioctl *);
+};
+
+extern int pathless_pioctl_register(struct pathless_pioctl_handler *);
+extern int pathless_pioctl_unregister(struct pathless_pioctl_handler *);
+
 #else
 
 /*




More information about the linux-afs mailing list