Messages in this thread | | | Date | Sat, 7 Sep 2002 17:39:04 -0700 (PDT) | From | Patrick Mochel <> | Subject | Re: [RFC][PATCH] x86 BIOS Enhanced Disk Device (EDD) polling |
| |
> Sweet, we're an axis now! That's much better than the other terms Pat > and I have been called in the past... And everyone knows what's the > next size jump up from axis :)
Yes, this is definitely cause for celebration. I've always believed that I was a straight line around which objects rotated. Thanks for the reassurance ;)
> So here's how driverfs fits into the big picture in one sentance: > > Anything that does not have to do with processes > will go into driverfs.
This is true, as per discussions in Ottawa in June. This will take a long time, and is not as clear cut as we make it out to sound. For example, porting things like meminfo and cpuinfo will likely never happen. Though, we intend to have equivalent information in driverfs. Things like stats will also take a long, if not indefinite amount of, time to convert because of performance concerns.
But, the obvious candidates for transition are things like /proc/bus/*, /proc/ide, /proc/scsi, and at least the /proc/sys/cpu/ part of /proc/sys/.
We've been working on solidifying the various top-level infrastructural pieces, like device classes, so that the organization of, and correlation between objects in, driverfs makes sense to at least developers. As always, mo' better stuff is coming RSN..
> So in this example, we are exporting a number of boot devices as the > bios told us, so apply the rule stated above, and determine if it should > go into /proc or not[1].
This is interesting, and I look forward to delving into the code. ACPI is doing something very similar. One thing I would like to do is create a 'platform' or 'firmware' top-level directory in driverfs in which all the various firmware drivers can display the data they ascertain from the firmware. Stay tuned..
> [1] Yes, it's still a bit difficult to figure how to add files to > driverfs, if you aren't starting with a "struct device" or "struct > device_driver", but I have seen some very nice documentation on how to > do it properly written by Pat involving a wonderful example of beer, and > I'm sure that once he gets back into internet connectivity range, he'll > be updating it and adding it to the Documentation directory. That > should be by the end of the week or so.
Two examples are attached:
pub.c: A subsystem that maintains a list of beers that are dyanamically registered and unregistered. This example is very similar to what is already there wrt devices and drivers.
When the module is loaded, a top-level directory is created called 'pub', and a subdirectory is created in that: 'beer'.
A struct beer describes a beer type. A couple of example beers are defined and are registered with the pub subsystem (pubsystem?). A directory is created for each, and a number of attributes are exported on behalf of the beer by the pubsystem. All are read-only for now. (Wouldn't you love to change the attributes of a beer? ;)
The things to note are the following:
- struct beer_attribute.
This describes an attribute and includes type-safe callbacks to read and write the attributes.
- BEER_ATTR() macro
This helps you define an attribute for a beer. It creates a structure called beer_attr_<name>, where <name> is the name of the attribute, and initializes it properly.
- struct driverfs_ops
This defines the callbacks that driverfs actually calls. These are responsible for converting between the generic structures to the pubsystem-specific structures (see to_beer() and to_beer_attr() macros).
This code is pretty much identical to what already exists. I'm not claiming its perfect, and not many eyes have really looked at what's going on. I'm sure I'll hear if I'm doing something completely retarded, and am looking forward to it.
If anyone is really that bored (and sick), extend the pub to include objects of struct wine, etc. :)
pat.c: An in-kernel representation of myself.
This example exports attributes concerning my current state. I've been threatening for some time to write patfs, but I decided to port patfs to driverfs and eat my own dog food. It's pretty shoddy, and doesn't include a decent way to update my current attributes. But, it's good for about 3 seconds of entertainment.
There is no registration of objects and no dynamic directory or file creation. I am singular and may not be replicated.
When the module loads, a top-level directory is created named 'pat'. An array of files are then created, each one for a particular attribute of my self on this dreary Oregon Saturday.
For defining attributes, I defined struct simple_attribute, which has no type-specific callbacks; they pass only the buffer, count, and offset. Because of this, the driverfs_ops for the patsystem are simple.
[ struct simple_attribute can, and likely will be, defined in a common header for others to use. There is a lot more work that I've done in this area and I'm currently trying to figure out what to do with it all..]
Everything else in it is pretty self-explanatory (I hope). The patsystem is pretty much as simple as it gets for exporting attributes of a subsystem.
The documentation in Documentation/filesystems/driverfs.txt is up to date. If anyone has any questions, please ask. Other than that, go wild.
-pat /* * pub.c - exploting driverfs for fun and profit * * Copyright (c) 2002 Patrick Mochel * Open Source Development Lab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * This is a sample subsystem to illustrate how easy it is to latch on to * driverfs and exploit it. It is the 'pub' subsystem. Objects of type 'beer' * can be registered and unregistered with the pub via beer_register and * beer_unregister. * * Every time a beer is registered with the pub subsystem, a directory is * created for it. The pub subsystem could then create files on behalf of * the beer, in the beer's directory. Once the beer has registered, it * can create files for itself in its directory. A second, more robust * example will surely follow. * * Compiled with
CFLAGS = -Wall -O2 -fomit-frame-pointer -DMODULE -D__KERNEL__ IDIR = /home/mochel/src/kernel/devel/linux-2.5/include
pub.o::pub.c $(CC) $(CFLAGS) -I$(IDIR) -c -o $@ $< */
#include <linux/module.h> #include <linux/string.h> #include <linux/init.h> #include <linux/stat.h> #include <linux/err.h> #include <linux/driverfs_fs.h>
struct beer { char * name; char * style; char * nation; u32 founded; u32 alcohol; u32 calories; struct list_head node; struct driver_dir_entry dir; };
struct beer_attribute { struct attribute attr; ssize_t (*show)(struct beer * beer, char * buf, size_t count, loff_t off); ssize_t (*store)(struct beer * beer, const char * buf, size_t count, loff_t off); };
#define BEER_ATTR(_name,_mode,_show,_store) \ struct beer_attribute beer_attr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ };
#define to_beer_attr(_attr) container_of(_attr,struct beer_attribute,attr)
#define to_beer(_dir) container_of(_dir,struct beer,dir)
static LIST_HEAD(beer_list);
static struct driver_dir_entry pub_dir = { .name = "pub", .mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO), };
static struct driver_dir_entry pub_beer_dir = { .name = "beer", .mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO), };
/* driverfs ops for beer attribute files */
static int empty_attr_open(struct driver_dir_entry * dir) { /* nothing to do */ return 0; }
static int empty_attr_close(struct driver_dir_entry * dir) { /* nothing to do */ return 0; }
static ssize_t beer_attr_show(struct driver_dir_entry * dir, struct attribute * attr, char * buf, size_t count, loff_t off) { struct beer * beer = to_beer(dir); struct beer_attribute * beer_attr = to_beer_attr(attr); ssize_t ret = 0;
if (beer_attr->show) ret = beer_attr->show(beer,buf,count,off); return ret; }
static ssize_t beer_attr_store(struct driver_dir_entry * dir, struct attribute * attr, const char * buf, size_t count, loff_t off) { struct beer * beer = to_beer(dir); struct beer_attribute * beer_attr = to_beer_attr(attr); ssize_t ret = 0;
if (beer_attr->store) ret = beer_attr->store(beer,buf,count,off); return ret; }
static struct driverfs_ops beer_attr_ops = { .open = empty_attr_open, .close = empty_attr_close, .show = beer_attr_show, .store = beer_attr_store, };
/* default attributes for beer */
static ssize_t style_show(struct beer * beer, char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",beer->style); }
static BEER_ATTR(style,0444,style_show,NULL);
static ssize_t nation_show(struct beer * beer, char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",beer->nation); }
static BEER_ATTR(nation,0444,nation_show,NULL);
static ssize_t founded_show(struct beer * beer, char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%u\n",beer->founded); }
static BEER_ATTR(founded,0444,founded_show,NULL);
static ssize_t alcohol_show(struct beer * beer, char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%u\n",beer->alcohol); }
static BEER_ATTR(alcohol,0444,alcohol_show,NULL);
static ssize_t calories_show(struct beer * beer, char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%u\n",beer->calories); }
static BEER_ATTR(calories,0444,calories_show,NULL);
static struct beer_attribute * def_attrs[] = { &beer_attr_style, &beer_attr_nation, &beer_attr_founded, &beer_attr_alcohol, &beer_attr_calories, NULL, };
int beer_create_file(struct beer * beer, struct beer_attribute * attr) { int error = -EINVAL; if (beer) error = driverfs_create_file(&attr->attr,&beer->dir); return error; }
void beer_remove_file(struct beer * beer, struct beer_attribute * attr) { if (beer) driverfs_remove_file(&beer->dir,attr->attr.name); }
static void beer_remove_dir(struct beer * beer) { driverfs_remove_dir(&beer->dir); }
static int populate_dir(struct beer * beer) { struct beer_attribute * attr; int i; int error = 0; for (i = 0; (attr = def_attrs[i]); i++) { if ((error = beer_create_file(beer,attr))) { beer_remove_dir(beer); break; } } return error; }
static int beer_make_dir(struct beer * beer) { int error;
beer->dir.name = beer->name; beer->dir.ops = &beer_attr_ops;
error = driverfs_create_dir(&beer->dir,&pub_beer_dir); if (!error) error = populate_dir(beer); return error; }
int beer_register(struct beer * beer) { int error; error = beer_make_dir(beer); if (!error) list_add_tail(&beer->node,&beer_list); return error; }
void beer_unregister(struct beer * beer) { beer_remove_dir(beer); list_del_init(&beer->node); }
static struct beer guinness_beer = { .name = "Guinness", .style = "stout", .nation = "Ireland", .founded = 1759, .alcohol = 473, .calories = 43, };
static struct beer pabst_beer = { .name = "Pabst", .style = "pilsner", .nation = "USA", .founded = 1844, .alcohol = 578, .calories = 45, };
static int __init pub_init(void) { driverfs_create_dir(&pub_dir,NULL); driverfs_create_dir(&pub_beer_dir,&pub_dir); beer_register(&guinness_beer); beer_register(&pabst_beer); return 0; }
static void __exit pub_exit(void) { beer_unregister(&guinness_beer); beer_unregister(&pabst_beer); driverfs_remove_dir(&pub_beer_dir); driverfs_remove_dir(&pub_dir); }
subsys_initcall(pub_init); module_exit(pub_exit); /* * pat.c - an in-kernel representation of myself. * * Copyright (c) 2002 Patrick Mochel * Open Source Development Lab * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Compiled with
CFLAGS = -Wall -O2 -fomit-frame-pointer -DMODULE -D__KERNEL__ IDIR = /home/mochel/src/kernel/devel/linux-2.5/include
pat.o::pat.c $(CC) $(CFLAGS) -I$(IDIR) -c -o $@ $< */
#include <linux/module.h> #include <linux/string.h> #include <linux/init.h> #include <linux/stat.h> #include <linux/err.h> #include <linux/driverfs_fs.h>
struct simple_attribute { struct attribute attr; ssize_t (*show)(char * buf, size_t count, loff_t off); };
#define SIMPLE_ATTR(_name,_mode,_show) \ struct simple_attribute sattr_##_name = { \ .attr = {.name = __stringify(_name), .mode = _mode }, \ .show = _show, \ };
static char * who = "myself"; static char * what = "working"; static char * when = "not for long"; static char * where = "office"; static char * why = "catching up"; static char * how = "hungover"; static u32 dollars = 6; static u32 cents = 89; static char * beverage = "coffee"; static int bev_size = 12;
#define to_simple_attr(_attr) container_of(_attr,struct simple_attribute,attr)
/* driverfs ops for displaying my attributes */
static int pat_attr_show(struct driver_dir_entry * dir, struct attribute * attr, char * buf, size_t count, loff_t off) { struct simple_attribute * sattr = to_simple_attr(attr); if (sattr->show) return sattr->show(buf,count,off); return 0; }
static struct driverfs_ops pat_attr_ops = { .show pat_attr_show, };
static struct driver_dir_entry pat_dir = { .name = "pat", .mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO), .ops = &pat_attr_ops, };
/* exporting my attributes */
static ssize_t show_who(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",who); }
static SIMPLE_ATTR(who,0444,show_who);
static ssize_t show_what(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",what); }
static SIMPLE_ATTR(what,0444,show_what);
static ssize_t show_when(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",when); }
static SIMPLE_ATTR(when,0444,show_when);
static ssize_t show_where(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",where); }
static SIMPLE_ATTR(where,0444,show_where);
static ssize_t show_why(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",why); }
static SIMPLE_ATTR(why,0444,show_why);
static ssize_t show_how(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",how); }
static SIMPLE_ATTR(how,0444,show_how);
static ssize_t show_cash(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%u.%u\n",dollars,cents); }
static SIMPLE_ATTR(cash,0444,show_cash);
static ssize_t show_beverage(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%s\n",beverage); }
static SIMPLE_ATTR(beverage,0444,show_beverage);
static ssize_t show_bev_size(char * buf, size_t count, loff_t off) { return off ? 0 : snprintf(buf,50,"%u\n",bev_size); }
static SIMPLE_ATTR(bev_size,0444,show_bev_size);
static struct simple_attribute * pat_attrs[] = { &sattr_who, &sattr_what, &sattr_when, &sattr_where, &sattr_why, &sattr_how, &sattr_cash, &sattr_beverage, &sattr_bev_size, NULL, };
static int populate_dir(void) { struct simple_attribute * attr; int i; int error = 0; for (i = 0; (attr = pat_attrs[i]); i++) { if ((error = driverfs_create_file(&attr->attr,&pat_dir))) break; } return error; }
static int __init pat_init(void) { driverfs_create_dir(&pat_dir,NULL); return populate_dir(); }
static void __exit pat_exit(void) { driverfs_remove_dir(&pat_dir); }
subsys_initcall(pat_init); module_exit(pat_exit);
| |