summaryrefslogtreecommitdiffstats
path: root/include/sys/sunddi.h
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2009-02-04 15:15:41 -0800
committerBrian Behlendorf <[email protected]>2009-02-04 15:15:41 -0800
commit36b313dacf2f60f526fe98b7e9d1a6bbcbb250d2 (patch)
treef6441a23afb2eebbe2490dae46abd5aad8beede7 /include/sys/sunddi.h
parent31a033ecd49c2f691d6a377db2882ed941f47481 (diff)
Linux VM integration / device special files
Support added to provide reasonable values for the global Solaris VM variables: minfree, desfree, lotsfree, needfree. These values are set to the sum of their per-zone linux counterparts which should be close enough for Solaris consumers. When a non-GPL app links against the SPL we cannot use the udev interfaces, which means non of the device special files are created. Because of this I had added a poor mans udev which cause the SPL to invoke an upcall and create the basic devices when a minor is registered. When a minor is unregistered we use the vnode interface to unlink the special file.
Diffstat (limited to 'include/sys/sunddi.h')
-rw-r--r--include/sys/sunddi.h34
1 files changed, 31 insertions, 3 deletions
diff --git a/include/sys/sunddi.h b/include/sys/sunddi.h
index d2e71ebd5..404b14b38 100644
--- a/include/sys/sunddi.h
+++ b/include/sys/sunddi.h
@@ -32,12 +32,15 @@
#include <sys/sunldi.h>
#include <sys/mutex.h>
#include <sys/u8_textprep.h>
+#include <sys/vnode.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <spl-device.h>
+#define DDI_MAX_NAME_LEN 32
+
typedef int ddi_devid_t;
typedef enum {
@@ -80,6 +83,7 @@ typedef struct pollhead {
typedef struct dev_info {
kmutex_t di_lock;
+ char di_name[DDI_MAX_NAME_LEN];
struct dev_ops *di_ops;
struct cdev *di_cdev;
spl_class *di_class;
@@ -202,6 +206,7 @@ extern void __ddi_remove_minor_node(dev_info_t *dip, char *name);
extern int ddi_quiesce_not_needed(dev_info_t *dip);
extern int __mod_install(struct modlinkage *modlp);
extern int __mod_remove(struct modlinkage *modlp);
+extern int __mod_mknod(char *name, char *type, int major, int minor);
extern int ddi_strtoul(const char *, char **, int, unsigned long *);
extern int ddi_strtol(const char *, char **, int, long *);
@@ -226,7 +231,16 @@ ddi_remove_minor_node(dev_info_t *di, char *name)
di->di_class = NULL;
di->di_dev = 0;
}
-#endif
+#else
+ /* When we do not have access to the GPL-only device interfaces we
+ * are forced to do something crude. We unlink the special device
+ * file in /dev/ ourselves from within the kernel. On the upside we
+ * are already providing this functionality for Solaris, and it is
+ * easy to leverage the Solaris API to perform the unlink. */
+ if (strlen(di->di_name) > 0)
+ vn_remove(di->di_name, UIO_SYSSPACE, RMFILE);
+
+#endif /* HAVE_GPL_ONLY_SYMBOLS */
__ddi_remove_minor_node(di, name);
}
@@ -254,14 +268,28 @@ ddi_create_minor_node(dev_info_t *di, char *name, int spec_type,
di->di_class = NULL;
ddi_remove_minor_node(di, name);
CERROR("Error creating %s class, %d\n", name, rc);
- RETURN(DDI_FAILURE);
+ return DDI_FAILURE;
}
/* Do not append a 0 to devices with minor nums of 0 */
di->di_device = spl_device_create(di->di_class, NULL, di->di_dev, NULL,
(di->di_minor == 0) ? "%s" : "%s%d",
name, di->di_minor);
-#endif
+#else
+ /* When we do not have access to the GPL-only device interfaces we
+ * are forced to do something horible. We use a user mode helper to
+ * create the special device file in /dev/. By futher extending the
+ * Solaris vnode implementation we could potentially do a vn_create()
+ * from within the kernel but that's still a hack. */
+ if (name) {
+ rc = __mod_mknod(di->di_name, "c", di->di_major, di->di_minor);
+ if (rc) {
+ CERROR("Error mknod %s, %d\n", di->di_name, rc);
+ ddi_remove_minor_node(di, name);
+ }
+ }
+
+#endif /* HAVE_GPL_ONLY_SYMBOLS */
return rc;
}