[Ocfs2-commits] jlbec commits r1970 - trunk/fs/usysfs
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Thu Mar 10 19:12:49 CST 2005
Author: jlbec
Signed-off-by: zab
Signed-off-by: manish
Date: 2005-03-10 19:12:47 -0600 (Thu, 10 Mar 2005)
New Revision: 1970
Modified:
trunk/fs/usysfs/bobtest.c
trunk/fs/usysfs/dir.c
trunk/fs/usysfs/mount.c
trunk/fs/usysfs/usysfs.h
Log:
o Create ukset wrapper to kset
o Move default_attrs from ukobj_type to ukset
o Fix dcache handling (d_drop() is your friend).
Signed-off-by: zab
Signed-off-by: manish
Modified: trunk/fs/usysfs/bobtest.c
===================================================================
--- trunk/fs/usysfs/bobtest.c 2005-03-10 23:56:53 UTC (rev 1969)
+++ trunk/fs/usysfs/bobtest.c 2005-03-11 01:12:47 UTC (rev 1970)
@@ -10,8 +10,12 @@
#include "usysfs.h"
+
+/*
+ * Bobs - default_set as part of subsystem.
+ */
struct robert {
- struct kset kset;
+ struct ukset ukset;
};
struct robert_attribute {
@@ -21,7 +25,9 @@
static inline struct robert *to_robert(struct kobject *kobj)
{
- return kobj ? container_of(to_kset(kobj), struct robert, kset) : NULL;
+ return kobj ?
+ container_of(to_ukset(to_kset(kobj)), struct robert, ukset) :
+ NULL;
}
static ssize_t robert_print_read(struct robert *robert, char *page)
@@ -76,10 +82,12 @@
};
static struct robert robert = {
- .kset = {
- .kobj = {
- .name = "robert",
- .ktype = &uktype_robert.ktype,
+ .ukset = {
+ .kset = {
+ .kobj = {
+ .name = "robert",
+ .ktype = &uktype_robert.ktype,
+ },
},
},
};
@@ -200,7 +208,7 @@
struct bobset {
- struct kset kset;
+ struct ukset ukset;
int n_bobs;
};
@@ -211,7 +219,9 @@
static inline struct bobset *to_bobset(struct kset *kset)
{
- return kset ? container_of(kset, struct bobset, kset) : NULL;
+ return kset ?
+ container_of(to_ukset(kset), struct bobset, ukset) :
+ NULL;
}
static ssize_t bobset_attr_show(struct kobject *kobj,
@@ -248,7 +258,7 @@
};
static struct kset *bobset_sets[] = {
- &robert.kset,
+ &robert.ukset.kset,
NULL,
};
@@ -263,8 +273,7 @@
memset(bob, 0, sizeof(struct bob));
- strcpy(bob->kobj.name, name);
- bob->kobj.k_name = bob->kobj.name;
+ kobject_set_name(&bob->kobj, name);
bob->kobj.ktype = &uktype_bob.ktype;
kobject_init(&bob->kobj);
@@ -290,32 +299,391 @@
},
.make_object = make_bob,
.drop_object = drop_bob,
- .default_sets = bobset_sets,
};
static struct bobset bobset = {
- .kset = {
- .kobj = {
- .name = "bobset",
- .ktype = &uktype_bobset.ktype,
+ .ukset = {
+ .kset = {
+ .kobj = {
+ .name = "bobset",
+ .ktype = &uktype_bobset.ktype,
+ },
},
+ .default_sets = bobset_sets,
},
.n_bobs = 0,
};
-void kset_init(struct kset *k)
+/*
+ * Toms - default_set as part of a created set.
+ */
+struct jerry {
+ struct ukset ukset;
+ int showme;
+ int storeme;
+};
+
+struct jerry_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct jerry *, char *);
+ ssize_t (*store)(struct jerry *, const char *, size_t);
+};
+
+static inline struct jerry *to_jerry(struct kobject *kobj)
{
- kobject_init(&k->kobj);
- INIT_LIST_HEAD(&k->list);
+ return kobj ?
+ container_of(to_ukset(to_kset(kobj)), struct jerry, ukset) :
+ NULL;
}
+static ssize_t jerry_showme_read(struct jerry *jerry, char *page)
+{
+ ssize_t pos;
+
+ pos = sprintf(page, "%d\n", jerry->showme);
+ jerry->showme++;
+
+ return pos;
+}
+
+static ssize_t jerry_storeme_read(struct jerry *jerry, char *page)
+{
+ return sprintf(page, "%d\n", jerry->storeme);
+}
+
+static ssize_t jerry_storeme_write(struct jerry *jerry, const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ char *p = (char *) page;
+
+ tmp = simple_strtoul(p, &p, 10);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ if (tmp > INT_MAX)
+ return -ERANGE;
+
+ jerry->storeme = tmp;
+
+ return count;
+}
+
+static struct jerry_attribute jerry_attr_showme = {
+ .attr = { .name = "showme", .mode = S_IRUGO },
+ .show = jerry_showme_read,
+};
+static struct jerry_attribute jerry_attr_storeme = {
+ .attr = { .name = "storeme", .mode = S_IRUGO | S_IWUSR },
+ .show = jerry_storeme_read,
+ .store = jerry_storeme_write,
+};
+static struct attribute *jerry_attrs[] = {
+ &jerry_attr_showme.attr,
+ &jerry_attr_storeme.attr,
+ NULL,
+};
+
+static ssize_t jerry_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *page)
+{
+ struct jerry *jerry = to_jerry(kobj);
+ struct jerry_attribute *jerry_attr =
+ container_of(attr, struct jerry_attribute, attr);
+ ssize_t ret = 0;
+
+ if (jerry_attr->show)
+ ret = jerry_attr->show(jerry, page);
+ return ret;
+}
+
+static ssize_t jerry_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *page, size_t count)
+{
+ struct jerry *jerry = to_jerry(kobj);
+ struct jerry_attribute *jerry_attr =
+ container_of(attr, struct jerry_attribute, attr);
+ ssize_t ret = -EINVAL;
+
+ if (jerry_attr->store)
+ ret = jerry_attr->store(jerry, page, count);
+ return ret;
+}
+
+struct sysfs_ops jerry_sysfs_ops = {
+ .show = &jerry_attr_show,
+ .store = &jerry_attr_store,
+};
+
+static void jerry_release(struct kobject *kobj)
+{
+ kfree(to_jerry(kobj));
+}
+
+static struct ukobj_type uktype_jerry = {
+ .ktype = {
+ .release = jerry_release,
+ .sysfs_ops = &jerry_sysfs_ops,
+ .default_attrs = jerry_attrs,
+ },
+ .owner = THIS_MODULE,
+};
+
+
+struct tom {
+ struct ukset ukset;
+ int showme;
+ int storeme;
+};
+
+struct tom_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct tom *, char *);
+ ssize_t (*store)(struct tom *, const char *, size_t);
+};
+
+static inline struct tom *to_tom(struct kobject *kobj)
+{
+ return kobj ?
+ container_of(to_ukset(to_kset(kobj)), struct tom, ukset) :
+ NULL;
+}
+
+static ssize_t tom_showme_read(struct tom *tom, char *page)
+{
+ ssize_t pos;
+
+ pos = sprintf(page, "%d\n", tom->showme);
+ tom->showme++;
+
+ return pos;
+}
+
+static ssize_t tom_storeme_read(struct tom *tom, char *page)
+{
+ return sprintf(page, "%d\n", tom->storeme);
+}
+
+static ssize_t tom_storeme_write(struct tom *tom, const char *page,
+ size_t count)
+{
+ unsigned long tmp;
+ char *p = (char *) page;
+
+ tmp = simple_strtoul(p, &p, 10);
+ if (!p || (*p && (*p != '\n')))
+ return -EINVAL;
+
+ if (tmp > INT_MAX)
+ return -ERANGE;
+
+ tom->storeme = tmp;
+
+ return count;
+}
+
+static struct tom_attribute tom_attr_showme = {
+ .attr = { .name = "showme", .mode = S_IRUGO },
+ .show = tom_showme_read,
+};
+static struct tom_attribute tom_attr_storeme = {
+ .attr = { .name = "storeme", .mode = S_IRUGO | S_IWUSR },
+ .show = tom_storeme_read,
+ .store = tom_storeme_write,
+};
+static struct attribute *tom_attrs[] = {
+ &tom_attr_showme.attr,
+ &tom_attr_storeme.attr,
+ NULL,
+};
+
+static ssize_t tom_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *page)
+{
+ struct tom *tom = to_tom(kobj);
+ struct tom_attribute *tom_attr =
+ container_of(attr, struct tom_attribute, attr);
+ ssize_t ret = 0;
+
+ if (tom_attr->show)
+ ret = tom_attr->show(tom, page);
+ return ret;
+}
+
+static ssize_t tom_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *page, size_t count)
+{
+ struct tom *tom = to_tom(kobj);
+ struct tom_attribute *tom_attr =
+ container_of(attr, struct tom_attribute, attr);
+ ssize_t ret = -EINVAL;
+
+ if (tom_attr->store)
+ ret = tom_attr->store(tom, page, count);
+ return ret;
+}
+
+struct sysfs_ops tom_sysfs_ops = {
+ .show = &tom_attr_show,
+ .store = &tom_attr_store,
+};
+
+static void tom_release(struct kobject *kobj)
+{
+ struct tom *tom = to_tom(kobj);
+ kfree(to_jerry(&tom->ukset.default_sets[0]->kobj));
+ kfree(tom);
+}
+
+static struct ukobj_type uktype_tom = {
+ .ktype = {
+ .release = tom_release,
+ .sysfs_ops = &tom_sysfs_ops,
+ .default_attrs = tom_attrs,
+ },
+ .make_object = usysfs_make_no_object,
+ .owner = THIS_MODULE,
+};
+
+
+struct tomset {
+ struct ukset ukset;
+ int n_toms;
+};
+
+struct tomset_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct tomset *, char *);
+};
+
+static inline struct tomset *to_tomset(struct kset *kset)
+{
+ return kset ?
+ container_of(to_ukset(kset), struct tomset, ukset) :
+ NULL;
+}
+
+static ssize_t tomset_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *page)
+{
+ struct tomset *tomset = to_tomset(to_kset(kobj));
+ struct tomset_attribute *tomset_attr =
+ container_of(attr, struct tomset_attribute, attr);
+ ssize_t ret = 0;
+
+ if (tomset_attr->show)
+ ret = tomset_attr->show(tomset, page);
+ return ret;
+}
+
+static struct sysfs_ops tomset_sysfs_ops = {
+ .show = &tomset_attr_show,
+};
+
+static ssize_t tomset_toms_read(struct tomset *tomset, char *page)
+{
+ return sprintf(page, "%d Toms love you\n", tomset->n_toms);
+}
+
+static struct tomset_attribute tomset_attr_toms = {
+ .attr = { .name = "toms", .mode = S_IRUGO },
+ .show = tomset_toms_read
+};
+
+static struct attribute *tomset_attrs[] = {
+ &tomset_attr_toms.attr,
+ NULL,
+};
+
+static struct kset *make_tom(struct kset *kset, const char *name)
+{
+ struct tomset *tomset = to_tomset(kset);
+ struct tom *tom;
+ struct jerry *jerry;
+
+ tom = kmalloc(sizeof(struct tom), GFP_KERNEL);
+ if (!tom)
+ return NULL;
+
+ memset(tom, 0, sizeof(struct tom));
+ tom->ukset.default_sets = kmalloc(sizeof(struct kset *) * 2,
+ GFP_KERNEL);
+ if (!tom->ukset.default_sets) {
+ kfree(tom);
+ return NULL;
+ }
+
+ jerry = kmalloc(sizeof(struct jerry), GFP_KERNEL);
+ if (!jerry) {
+ kfree(tom->ukset.default_sets);
+ kfree(tom);
+ return NULL;
+ }
+
+ memset(jerry, 0, sizeof(struct jerry));
+
+ kobject_set_name(&tom->ukset.kset.kobj, name);
+ tom->ukset.kset.kobj.ktype = &uktype_tom.ktype;
+ ukset_init(&tom->ukset);
+
+ tom->showme = 0;
+ tom->storeme = 0;
+ tomset->n_toms++;
+
+ kobject_set_name(&jerry->ukset.kset.kobj, "jer");
+ jerry->ukset.kset.kobj.ktype = &uktype_jerry.ktype;
+ ukset_init(&jerry->ukset);
+
+ tom->ukset.default_sets[0] = &jerry->ukset.kset;
+ tom->ukset.default_sets[1] = NULL;
+
+ return &tom->ukset.kset;
+}
+
+static void drop_tom(struct kset *kset, struct kobject *kobj)
+{
+ struct tomset *tomset = to_tomset(kset);
+
+ tomset->n_toms--;
+ kobject_put(kobj);
+}
+
+static struct ukobj_type uktype_tomset = {
+ .ktype = {
+ .sysfs_ops = &tomset_sysfs_ops,
+ .default_attrs = tomset_attrs,
+ },
+ .make_kset = make_tom,
+ .drop_object = drop_tom,
+};
+
+static struct tomset tomset = {
+ .ukset = {
+ .kset = {
+ .kobj = {
+ .name = "tomset",
+ .ktype = &uktype_tomset.ktype,
+ },
+ },
+ },
+ .n_toms = 0,
+};
+
static int __init bobtest_init(void)
{
int ret;
- kset_init(&bobset.kset);
- kset_init(&robert.kset);
- ret = usysfs_register_subsystem(&bobset.kset);
+ ukset_init(&bobset.ukset);
+ ukset_init(&robert.ukset);
+ ukset_init(&tomset.ukset);
+ ret = usysfs_register_subsystem(&bobset.ukset.kset);
+ if (!ret)
+ ret = usysfs_register_subsystem(&tomset.ukset.kset);
if (ret)
printk(KERN_ERR "bobtest: Registration returned %d\n", ret);
@@ -324,7 +692,8 @@
static void __exit bobtest_exit(void)
{
- usysfs_unregister_subsystem(&bobset.kset);
+ usysfs_unregister_subsystem(&tomset.ukset.kset);
+ usysfs_unregister_subsystem(&bobset.ukset.kset);
}
module_init(bobtest_init);
Modified: trunk/fs/usysfs/dir.c
===================================================================
--- trunk/fs/usysfs/dir.c 2005-03-10 23:56:53 UTC (rev 1969)
+++ trunk/fs/usysfs/dir.c 2005-03-11 01:12:47 UTC (rev 1970)
@@ -364,8 +364,21 @@
continue;
list_del_init(&sd->s_sibling);
child = sd->s_dentry;
+ down(&child->d_inode->i_sem);
usysfs_drop_set(sd->s_element);
- d_delete(child);
+ up(&child->d_inode->i_sem);
+
+ /*
+ * This is important. If the child is still hashed,
+ * dput() will just put it somewhere safe. So there
+ * will not be a chain back to dput()ing the parent.
+ * At least, not until umount. This means dentries
+ * hanging about. Bad Idea Jeans. d_delete() would
+ * leave it hashed, but negative. That's good for
+ * stuff coming from the VFS, not for our hand-built
+ * default_sets. d_drop unhashes. Bingo!
+ */
+ d_drop(child);
dput(child);
usysfs_put(sd);
}
@@ -376,13 +389,19 @@
dput(dentry);
}
+/*
+ * This fakes mkdir(2) on a default_sets[] entry. It
+ * creates a dentry, instantiates it, and then does fixup
+ * on the sd->s_type.
+ */
static int create_default_set(struct kset *parent_kset,
struct kset *kset)
{
int ret;
struct qstr name;
+ struct usysfs_dirent *sd;
+ /* We trust the caller holds a reference to parent */
struct dentry *child, *parent = parent_kset->kobj.dentry;
- struct usysfs_dirent *sd;
if (!kset->kobj.k_name)
kset->kobj.k_name = kset->kobj.name;
@@ -401,14 +420,7 @@
sd = child->d_fsdata;
sd->s_type = USYSFS_DEFAULT_DIR;
} else {
- /*
- * XXX: fs/namei.c does d_delete() outside
- * of i_sem. For easy error chaining, we're
- * doing it inside i_sem. It doesn't appear
- * to be a problem, but someone smack me if I'm
- * wrong.
- */
- d_delete(child);
+ d_drop(child);
dput(child);
}
}
@@ -418,17 +430,17 @@
static int populate_sets(struct kset *kset)
{
- struct ukobj_type *uktype = to_uktype(kset->kobj.ktype);
+ struct ukset *ukset = to_ukset(kset);
struct kset *new_set;
struct dentry *dentry = kset->kobj.dentry;
int ret = 0;
int i;
- if (uktype && uktype->default_sets) {
+ if (ukset && ukset->default_sets) {
down(&dentry->d_inode->i_sem);
- for (i = 0; uktype->default_sets[i]; i++) {
- new_set = uktype->default_sets[i];
+ for (i = 0; ukset->default_sets[i]; i++) {
+ new_set = ukset->default_sets[i];
ret = create_default_set(kset, new_set);
if (ret)
@@ -474,6 +486,21 @@
kobject_get(kobj);
}
+/*
+ * The goal is that usysfs_instantiate_object() (and
+ * usysfs_instantiate_set()) can be called from either the VFS or this
+ * module. That is, they assume that the objects have been created,
+ * the dentry allocated, and the dcache is all ready to go.
+ *
+ * If they fail, they must clean up after themselves as if they
+ * had never been called. The caller (VFS or local function) will
+ * handle cleaning up the dcache bits.
+ *
+ * usysfs_drop_set() and usysfs_drop_object() behave similarly on the
+ * way out. They assume that the proper semaphores are held, they
+ * clean up the usysfs objects, and they expect their callers will
+ * handle the dcache bits.
+ */
static int usysfs_instantiate_object(struct kobject *parent_kobj,
struct kobject *kobj,
struct dentry *dentry)
@@ -555,8 +582,9 @@
snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);
if (uktype->make_kset) {
kset = uktype->make_kset(to_kset(parent_kobj), name);
- kobj = &kset->kobj;
+ kobj = kset ? &kset->kobj : NULL;
} else {
+ kset = NULL;
kobj = uktype->make_object(to_kset(parent_kobj), name);
}
kfree(name);
@@ -570,9 +598,15 @@
if (uktype) {
owner = uktype->owner;
if (try_module_get(owner)) {
- ret = usysfs_instantiate_object(parent_kobj,
- kobj, dentry);
+ if (kset)
+ ret = usysfs_instantiate_set(parent_kobj,
+ kobj,
+ dentry);
+ else
+ ret = usysfs_instantiate_object(parent_kobj,
+ kobj, dentry);
if (ret) {
+ /* XXX: Should be ->drop_object() */
kobject_put(parent_kobj);
module_put(owner);
}
@@ -582,6 +616,7 @@
return ret;
}
+/* Sets must have make_kset() or make_object() */
static int is_set(struct kobject *kobj)
{
int ret = 0;
@@ -593,8 +628,6 @@
ret = 1;
else if (uktype->make_object)
ret = 1;
- else if (uktype->default_sets)
- ret = 1;
}
return ret;
@@ -851,7 +884,6 @@
struct qstr name;
struct dentry *dentry;
struct usysfs_dirent *sd;
- struct kset *root_set;
err = usysfs_pin_fs();
if (err)
@@ -875,12 +907,11 @@
d_add(dentry, NULL);
sd = usysfs_sb->s_root->d_fsdata;
- root_set = sd->s_element;
- err = usysfs_instantiate_set(&root_set->kobj, &k->kobj, dentry);
+ err = usysfs_instantiate_set(sd->s_element, &k->kobj, dentry);
if (!err)
dentry = NULL;
else
- d_delete(dentry);
+ d_drop(dentry);
up(&usysfs_sb->s_root->d_inode->i_sem);
@@ -905,9 +936,11 @@
printk(KERN_ERR "usysfs: Tried to unregister non-empty subsystem!\n");
}
usysfs_drop_set(&k->kobj);
+ /* See comment in drop_sets() regarding d_drop() */
+ d_drop(k->kobj.dentry);
+
up(&usysfs_sb->s_root->d_inode->i_sem);
- d_delete(k->kobj.dentry);
dput(k->kobj.dentry);
usysfs_release_fs();
}
Modified: trunk/fs/usysfs/mount.c
===================================================================
--- trunk/fs/usysfs/mount.c 2005-03-10 23:56:53 UTC (rev 1969)
+++ trunk/fs/usysfs/mount.c 2005-03-11 01:12:47 UTC (rev 1970)
@@ -34,27 +34,36 @@
#endif
};
-static struct kset usysfs_root_set = {
- .kobj = {
- .name = "root",
- .k_name = usysfs_root_set.kobj.name,
+static struct ukset usysfs_root_set = {
+ .kset = {
+ .kobj = {
+ .name = "root",
+ .k_name = usysfs_root_set.kset.kobj.name,
+ },
},
};
static struct usysfs_dirent usysfs_root = {
.s_sibling = LIST_HEAD_INIT(usysfs_root.s_sibling),
.s_children = LIST_HEAD_INIT(usysfs_root.s_children),
- .s_element = &usysfs_root_set,
+ .s_element = &usysfs_root_set.kset.kobj,
.s_type = USYSFS_ROOT,
};
/* Kernel idiots 1, universe 0 */
-void kset_init(struct kset *k)
+static void kset_init_copy(struct kset *k)
{
kobject_init(&k->kobj);
INIT_LIST_HEAD(&k->list);
}
+void ukset_init(struct ukset *ukset)
+{
+ kset_init_copy(&ukset->kset);
+}
+
+EXPORT_SYMBOL_GPL(ukset_init);
+
static int usysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
@@ -83,8 +92,8 @@
iput(inode);
return -ENOMEM;
}
- kset_init(&usysfs_root_set);
- usysfs_root_set.kobj.dentry = root;
+ ukset_init(&usysfs_root_set);
+ usysfs_root_set.kset.kobj.dentry = root;
root->d_fsdata = &usysfs_root;
sb->s_root = root;
return 0;
Modified: trunk/fs/usysfs/usysfs.h
===================================================================
--- trunk/fs/usysfs/usysfs.h 2005-03-10 23:56:53 UTC (rev 1969)
+++ trunk/fs/usysfs/usysfs.h 2005-03-11 01:12:47 UTC (rev 1970)
@@ -35,19 +35,20 @@
/*
* Usysfs objects must have a ->ktype of type ukobj_type.
* If allow_link() exists, the object can symlink(2) out to other
- * objects. If the object is a kset, it may support mkdir(2). If the
+ * objects. If the object is a kset, it may support mkdir(2). Kset
+ * objects must supply one of make_kset() and make_object(). If the
* object supports make_kset(), one can create kset children. If it
* supports make_object(), one can create kobject children. If it has
- * default_sets, it has automatically created kset children.
- * default_sets may coexist alongsize make_kset() or make_object(), but
- * an object can only have one or zero of mkae_kset() and make_object().
- * If the kset has commit(), it supports pending and commited (active)
- * objects.
+ * default_sets on ukset->default_sets, it has automatically created
+ * kset children. default_sets may coexist alongsize make_kset() or
+ * make_object(), but if the kset wishes to have only default_sets
+ * children (disallowing mkdir(2)), it must provide
+ * usysfs_make_no_object() as the value for make_object(). If the kset
+ * has commit(), it supports pending and commited (active) objects.
*/
struct ukobj_type {
struct kobj_type ktype;
struct module *owner;
- struct kset **default_sets;
int (*allow_link)(struct kobject *src, struct kobject *target);
struct kobject *(*make_object)(struct kset *kset, const char *name);
struct kset *(*make_kset)(struct kset *kset, const char *name);
@@ -62,7 +63,30 @@
NULL;
}
+static inline struct kobject *usysfs_make_no_object(struct kset *kset,
+ const char *name)
+{
+ return NULL;
+}
+
+/*
+ * Usysfs ksets must actually be of type ukset. This allows default
+ * child sets to be created.
+ */
+struct ukset {
+ struct kset kset;
+ struct kset **default_sets;
+};
+
+static inline struct ukset *to_ukset(struct kset *kset)
+{
+ return kset ? container_of(kset, struct ukset, kset) : NULL;
+}
+
+extern void ukset_init(struct ukset *ukset);
+
+
/**
* Use these macros to make defining attributes easier. See include/linux/device.h
* for examples..
More information about the Ocfs2-commits
mailing list