Hi, Here's a patch against 2.5.1-pre11 from me that makes the usbdevfs use the vfs much better. It also removes the usbdevfs structures from the inode and superblock structures, and fixes a bug in which the "special" files were not getting updated when a USB driver was registered or deregistered.
thanks, greg k-h diff -Nru a/drivers/usb/devio.c b/drivers/usb/devio.c --- a/drivers/usb/devio.c Thu Dec 13 12:52:38 2001 +++ b/drivers/usb/devio.c Thu Dec 13 12:52:38 2001 @@ -471,9 +471,7 @@ */ lock_kernel(); ret = -ENOENT; - if (ITYPE(inode->i_ino) != IDEVICE) - goto out; - dev = inode->u.usbdev_i.p.dev; + dev = inode->u.generic_ip; if (!dev) goto out; ret = -ENOMEM; diff -Nru a/drivers/usb/inode.c b/drivers/usb/inode.c --- a/drivers/usb/inode.c Thu Dec 13 12:52:39 2001 +++ b/drivers/usb/inode.c Thu Dec 13 12:52:39 2001 @@ -3,8 +3,8 @@ /* * inode.c -- Inode/Dentry functions for the USB device file system. * - * Copyright (C) 2000 - * Thomas Sailer ([EMAIL PROTECTED]) + * Copyright (C) 2000 Thomas Sailer ([EMAIL PROTECTED]) + * Copyright (c) 2001 Greg Kroah-Hartman ([EMAIL PROTECTED]) * * 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 @@ -20,10 +20,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $ - * * History: * 0.1 04.01.2000 Created + * 0.2 10.12.2001 converted to use the vfs layer better */ /*****************************************************************************/ @@ -32,146 +31,40 @@ #include <linux/config.h> #include <linux/module.h> #include <linux/fs.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> -#include <linux/locks.h> +#include <linux/pagemap.h> #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/usb.h> #include <linux/usbdevice_fs.h> -#include <asm/uaccess.h> - -/* --------------------------------------------------------------------- */ - -/* - * This list of superblocks is still used, - * but since usbdevfs became FS_SINGLE - * there is only one super_block. - */ -static LIST_HEAD(superlist); - -struct special { - const char *name; - struct file_operations *fops; - struct inode *inode; - struct list_head inodes; -}; - -static struct special special[] = { - { "devices", &usbdevfs_devices_fops, }, - { "drivers", &usbdevfs_drivers_fops, } -}; - -#define NRSPECIAL (sizeof(special)/sizeof(special[0])) - -/* --------------------------------------------------------------------- */ - -static int dnumber(struct dentry *dentry) -{ - const char *name; - unsigned int s; - - if (dentry->d_name.len != 3) - return -1; - name = dentry->d_name.name; - if (name[0] < '0' || name[0] > '9' || - name[1] < '0' || name[1] > '9' || - name[2] < '0' || name[2] > '9') - return -1; - s = name[0] - '0'; - s = s * 10 + name[1] - '0'; - s = s * 10 + name[2] - '0'; - return s; -} - -/* - * utility functions; should be called with the kernel lock held - * to protect against busses/devices appearing/disappearing - */ - -static void new_dev_inode(struct usb_device *dev, struct super_block *sb) -{ - struct inode *inode; - unsigned int devnum = dev->devnum; - unsigned int busnum = dev->bus->busnum; - - if (devnum < 1 || devnum > 127 || busnum > 255) - return; - inode = iget(sb, IDEVICE | (busnum << 8) | devnum); - if (!inode) { - printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum); - return; - } - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_uid = sb->u.usbdevfs_sb.devuid; - inode->i_gid = sb->u.usbdevfs_sb.devgid; - inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG; - inode->i_fop = &usbdevfs_device_file_operations; - inode->i_size = sizeof(struct usb_device_descriptor); - inode->u.usbdev_i.p.dev = dev; - list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); - list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes); -} -static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb) -{ - unsigned int i; - if (!dev) - return; - new_dev_inode(dev, sb); - for (i = 0; i < dev->maxchild; i++) { - if (!dev->children[i]) - continue; - recurse_new_dev_inode(dev->children[i], sb); - } -} - -static void new_bus_inode(struct usb_bus *bus, struct super_block *sb) -{ - struct inode *inode; - unsigned int busnum = bus->busnum; - - if (busnum > 255) - return; - inode = iget(sb, IBUS | (busnum << 8)); - if (!inode) { - printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum); - return; - } - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_uid = sb->u.usbdevfs_sb.busuid; - inode->i_gid = sb->u.usbdevfs_sb.busgid; - inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR; - inode->i_op = &usbdevfs_bus_inode_operations; - inode->i_fop = &usbdevfs_bus_file_operations; - inode->u.usbdev_i.p.bus = bus; - list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); - list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes); -} - -static void free_inode(struct inode *inode) -{ - inode->u.usbdev_i.p.bus = NULL; - inode->u.usbdev_i.p.dev = NULL; - inode->i_mode &= ~S_IRWXUGO; - inode->i_uid = inode->i_gid = 0; - inode->i_size = 0; - list_del(&inode->u.usbdev_i.slist); - INIT_LIST_HEAD(&inode->u.usbdev_i.slist); - list_del(&inode->u.usbdev_i.dlist); - INIT_LIST_HEAD(&inode->u.usbdev_i.dlist); - iput(inode); -} +static struct super_operations usbfs_ops; +static struct address_space_operations usbfs_aops; +static struct file_operations usbfs_dir_operations; +static struct file_operations default_file_operations; +static struct inode_operations usbfs_dir_inode_operations; +static struct vfsmount *usbfs_mount; +static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; +static int mount_count; /* = 0 */ + +static struct dentry *devices_dentry; +static struct dentry *drivers_dentry; +static int num_buses; /* = 0 */ + +static uid_t devuid; /* = 0 */ +static uid_t busuid; /* = 0 */ +static uid_t listuid; /* = 0 */ +static gid_t devgid; /* = 0 */ +static gid_t busgid; /* = 0 */ +static gid_t listgid; /* = 0 */ +static umode_t devmode = S_IWUSR | S_IRUGO; +static umode_t busmode = S_IXUGO | S_IRUGO; +static umode_t listmode = S_IRUGO; static int parse_options(struct super_block *s, char *data) { - uid_t devuid = 0, busuid = 0, listuid = 0; - gid_t devgid = 0, busgid = 0, listgid = 0; - umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO; char *curopt = NULL, *value; - /* parse options */ if (data) curopt = strtok(data, ","); for (; curopt; curopt = strtok(NULL, ",")) { @@ -242,481 +135,572 @@ } } - s->u.usbdevfs_sb.devuid = devuid; - s->u.usbdevfs_sb.devgid = devgid; - s->u.usbdevfs_sb.devmode = devmode; - s->u.usbdevfs_sb.busuid = busuid; - s->u.usbdevfs_sb.busgid = busgid; - s->u.usbdevfs_sb.busmode = busmode; - s->u.usbdevfs_sb.listuid = listuid; - s->u.usbdevfs_sb.listgid = listgid; - s->u.usbdevfs_sb.listmode = listmode; + return 0; +} + + +/* --------------------------------------------------------------------- */ +static struct dentry *usbfs_lookup (struct inode *dir, struct dentry *dentry) +{ + d_add(dentry, NULL); + return NULL; +} + +static int usbfs_statfs(struct super_block *sb, struct statfs *buf) +{ + buf->f_type = USBDEVICE_SUPER_MAGIC; + buf->f_bsize = PAGE_CACHE_SIZE; + buf->f_namelen = NAME_MAX; return 0; } -static struct usb_bus *usbdevfs_findbus(int busnr) +static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int dev) { - struct list_head *list; - struct usb_bus *bus; + struct inode *inode = new_inode(sb); - down (&usb_bus_list_lock); - for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { - bus = list_entry(list, struct usb_bus, bus_list); - if (bus->busnum == busnr) { - up (&usb_bus_list_lock); - return bus; + if (inode) { + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_rdev = NODEV; + inode->i_mapping->a_ops = &usbfs_aops; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &default_file_operations; + break; + case S_IFDIR: + inode->i_op = &usbfs_dir_inode_operations; + inode->i_fop = &usbfs_dir_operations; + break; } - } - up (&usb_bus_list_lock); - return NULL; + } + return inode; } -#if 0 -static struct usb_device *finddev(struct usb_device *dev, int devnr) +static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, + int dev) { - unsigned int i; - struct usb_device *d2; + struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); + int error = -ENOSPC; - if (!dev) - return NULL; - if (dev->devnum == devnr) - return dev; - for (i = 0; i < dev->maxchild; i++) { - if (!dev->children[i]) - continue; - if ((d2 = finddev(dev->children[i], devnr))) - return d2; - } - return NULL; + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; } -static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr) +static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) { - return finddev(bus->root_hub, devnr); + return usbfs_mknod (dir, dentry, mode | S_IFDIR, 0); } -#endif -/* --------------------------------------------------------------------- */ +static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode) +{ + return usbfs_mknod (dir, dentry, mode | S_IFREG, 0); +} -static int usbdevfs_revalidate(struct dentry *dentry, int flags) +static int usbfs_link (struct dentry *old_dentry, struct inode *dir, + struct dentry *dentry) { - struct inode *inode = dentry->d_inode; + struct inode *inode = old_dentry->d_inode; - if (!inode) - return 0; - if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus) - return 0; - if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev) - return 0; - return 1; + if(S_ISDIR(inode->i_mode)) + return -EPERM; + + inode->i_nlink++; + atomic_inc(&inode->i_count); + dget(dentry); + d_instantiate(dentry, inode); + return 0; } -static struct dentry_operations usbdevfs_dentry_operations = { - d_revalidate: usbdevfs_revalidate, -}; +static inline int usbfs_positive (struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} -static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry) +static int usbfs_empty (struct dentry *dentry) { - int busnr; - unsigned long ino = 0; - unsigned int i; - struct inode *inode; + struct list_head *list; - /* sanity check */ - if (dir->i_ino != IROOT) - return ERR_PTR(-EINVAL); - dentry->d_op = &usbdevfs_dentry_operations; - busnr = dnumber(dentry); - if (busnr >= 0 && busnr <= 255) - ino = IBUS | (busnr << 8); - if (!ino) { - for (i = 0; i < NRSPECIAL; i++) { - if (strlen(special[i].name) == dentry->d_name.len && - !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) { - ino = ISPECIAL | (i + IROOT + 1); - break; - } + spin_lock(&dcache_lock); + + list_for_each(list, &dentry->d_subdirs) { + struct dentry *de = list_entry(list, struct dentry, d_child); + if (usbfs_positive(de)) { + spin_unlock(&dcache_lock); + return 0; } } - if (!ino) - return ERR_PTR(-ENOENT); - inode = iget(dir->i_sb, ino); - if (!inode) - return ERR_PTR(-EINVAL); - if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) { - iput(inode); - inode = NULL; - } - d_add(dentry, inode); - return NULL; + + spin_unlock(&dcache_lock); + return 1; } -static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry) +static int usbfs_unlink (struct inode *dir, struct dentry *dentry) { - struct inode *inode; - int devnr; + int error = -ENOTEMPTY; - /* sanity check */ - if (ITYPE(dir->i_ino) != IBUS) - return ERR_PTR(-EINVAL); - dentry->d_op = &usbdevfs_dentry_operations; - devnr = dnumber(dentry); - if (devnr < 1 || devnr > 127) - return ERR_PTR(-ENOENT); - inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr); - if (!inode) - return ERR_PTR(-EINVAL); - if (inode && inode->u.usbdev_i.p.dev == NULL) { - iput(inode); - inode = NULL; + if (usbfs_empty(dentry)) { + struct inode *inode = dentry->d_inode; + + inode->i_nlink--; + dput(dentry); + error = 0; } - d_add(dentry, inode); - return NULL; + return error; } -static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir) +static int usbfs_rename (struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { - struct inode *inode = filp->f_dentry->d_inode; - unsigned long ino = inode->i_ino; - struct special *spec; - struct list_head *list; - struct usb_bus *bus; - char numbuf[8]; - unsigned int i; - - /* sanity check */ - if (ino != IROOT) - return -EINVAL; - i = filp->f_pos; - switch (i) { - case 0: - if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0) - return 0; - filp->f_pos++; - i++; - /* fall through */ + int error = -ENOTEMPTY; - case 1: - if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0) - return 0; - filp->f_pos++; - i++; - /* fall through */ - - default: - - while (i >= 2 && i < 2+NRSPECIAL) { - spec = &special[filp->f_pos-2]; - if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0) - return 0; - filp->f_pos++; - i++; - } - if (i < 2+NRSPECIAL) - return 0; - i -= 2+NRSPECIAL; - down (&usb_bus_list_lock); - for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { - if (i > 0) { - i--; - continue; - } - bus = list_entry(list, struct usb_bus, bus_list); - sprintf(numbuf, "%03d", bus->busnum); - if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0) - break; - filp->f_pos++; + if (usbfs_empty(new_dentry)) { + struct inode *inode = new_dentry->d_inode; + if (inode) { + inode->i_nlink--; + dput(new_dentry); } - up (&usb_bus_list_lock); - return 0; + error = 0; } + return error; } -static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir) +#define usbfs_rmdir usbfs_unlink + +/* default file operations */ +static ssize_t default_read_file (struct file *file, char *buf, + size_t count, loff_t *ppos) { - char numbuf[8]; - unsigned int i; + return 0; +} - if (!dev) - return pos; - sprintf(numbuf, "%03d", dev->devnum); - if (pos > 0) - pos--; - else { - if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0) - return -1; - filp->f_pos++; - } - for (i = 0; i < dev->maxchild; i++) { - if (!dev->children[i]) - continue; - pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir); - if (pos < 0) - return -1; - } - return pos; +static ssize_t default_write_file (struct file *file, const char *buf, + size_t count, loff_t *ppos) +{ + return count; } -static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir) +static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) { - struct inode *inode = filp->f_dentry->d_inode; - unsigned long ino = inode->i_ino; - struct usb_bus *bus; + loff_t retval = -EINVAL; - /* sanity check */ - if (ITYPE(ino) != IBUS) - return -EINVAL; - switch ((unsigned int)filp->f_pos) { + switch(orig) { case 0: - if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0) - return 0; - filp->f_pos++; - /* fall through */ - + if (offset > 0) { + file->f_pos = offset; + retval = file->f_pos; + } + break; case 1: - if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0) - return 0; - filp->f_pos++; - /* fall through */ - + if ((offset + file->f_pos) > 0) { + file->f_pos += offset; + retval = file->f_pos; + } + break; default: - lock_kernel(); - bus = usbdevfs_findbus(IBUSNR(ino)); - bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir); - unlock_kernel(); - return 0; + break; } + return retval; +} + +static int default_open (struct inode *inode, struct file *filp) +{ + if (inode->u.generic_ip) + filp->private_data = inode->u.generic_ip; + + return 0; } -static struct file_operations usbdevfs_root_file_operations = { - readdir: usbdevfs_root_readdir, +static int default_sync_file (struct file *file, struct dentry *dentry, + int datasync) +{ + return 0; +} + +static struct address_space_operations usbfs_aops = { }; -static struct inode_operations usbdevfs_root_inode_operations = { - lookup: usbdevfs_root_lookup, +static struct file_operations usbfs_dir_operations = { + read: generic_read_dir, + readdir: dcache_readdir, + fsync: default_sync_file, }; -static struct file_operations usbdevfs_bus_file_operations = { - readdir: usbdevfs_bus_readdir, +static struct file_operations default_file_operations = { + read: default_read_file, + write: default_write_file, + open: default_open, + llseek: default_file_lseek, + fsync: default_sync_file, + mmap: generic_file_mmap, }; -static struct inode_operations usbdevfs_bus_inode_operations = { - lookup: usbdevfs_bus_lookup, +static struct inode_operations usbfs_dir_inode_operations = { + create: usbfs_create, + lookup: usbfs_lookup, + link: usbfs_link, + unlink: usbfs_unlink, + mkdir: usbfs_mkdir, + rmdir: usbfs_rmdir, + mknod: usbfs_mknod, + rename: usbfs_rename, }; -static void usbdevfs_read_inode(struct inode *inode) -{ - struct special *spec; +static struct super_operations usbfs_ops = { + statfs: usbfs_statfs, + put_inode: force_delete, +}; - inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME; - inode->i_mode = S_IFREG; - inode->i_gid = inode->i_uid = 0; - INIT_LIST_HEAD(&inode->u.usbdev_i.dlist); - INIT_LIST_HEAD(&inode->u.usbdev_i.slist); - inode->u.usbdev_i.p.dev = NULL; - inode->u.usbdev_i.p.bus = NULL; - switch (ITYPE(inode->i_ino)) { - case ISPECIAL: - if (inode->i_ino == IROOT) { - inode->i_op = &usbdevfs_root_inode_operations; - inode->i_fop = &usbdevfs_root_file_operations; - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - return; - } - if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL) - return; - spec = &special[inode->i_ino-(IROOT+1)]; - inode->i_fop = spec->fops; - return; +static struct super_block *usbfs_read_super (struct super_block *sb, void *data, + int silent) +{ + struct inode *inode; + struct dentry *root; - case IDEVICE: - return; + if (parse_options(sb, data)) { + warn("usbfs: mount parameter error:"); + return NULL; + } - case IBUS: - return; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = USBDEVICE_SUPER_MAGIC; + sb->s_op = &usbfs_ops; + inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - default: - return; - } -} + if (!inode) { + dbg("%s: could not get inode!\n",__FUNCTION__); + return NULL; + } -static void usbdevfs_put_super(struct super_block *sb) -{ - list_del(&sb->u.usbdevfs_sb.slist); - INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist); - while (!list_empty(&sb->u.usbdevfs_sb.ilist)) - free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist)); + root = d_alloc_root(inode); + if (!root) { + dbg("%s: could not get root dentry!\n",__FUNCTION__); + iput(inode); + return NULL; + } + sb->s_root = root; + return sb; } -static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf) +/** + * fs_create_by_name - create a file, given a name + * @name: name of file + * @mode: type of file + * @parent: dentry of directory to create it in + * @dentry: resulting dentry of file + * + * There is a bit of overhead in creating a file - basically, we + * have to hash the name of the file, then look it up. This will + * prevent files of the same name. + * We then call the proper vfs_ function to take care of all the + * file creation details. + * This function handles both regular files and directories. + */ +static int fs_create_by_name (const char *name, mode_t mode, + struct dentry *parent, struct dentry **dentry) { - buf->f_type = USBDEVICE_SUPER_MAGIC; - buf->f_bsize = PAGE_SIZE/sizeof(long); /* ??? */ - buf->f_bfree = 0; - buf->f_bavail = 0; - buf->f_ffree = 0; - buf->f_namelen = NAME_MAX; - return 0; -} + struct dentry *d = NULL; + struct qstr qstr; + int error; -static int usbdevfs_remount(struct super_block *s, int *flags, char *data) -{ - struct list_head *ilist = s->u.usbdevfs_sb.ilist.next; - struct inode *inode; - int ret; + /* If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent ) { + if (usbfs_mount && usbfs_mount->mnt_sb) { + parent = usbfs_mount->mnt_sb->s_root; + } + } - if ((ret = parse_options(s, data))) { - printk(KERN_WARNING "usbdevfs: remount parameter error\n"); - return ret; + if (!parent) { + dbg("Ah! can not find a parent!\n"); + return -EFAULT; } - for (; ilist != &s->u.usbdevfs_sb.ilist; ilist = ilist->next) { - inode = list_entry(ilist, struct inode, u.usbdev_i.slist); + *dentry = NULL; + qstr.name = name; + qstr.len = strlen(name); + qstr.hash = full_name_hash(name,qstr.len); - switch (ITYPE(inode->i_ino)) { - case ISPECIAL : - inode->i_uid = s->u.usbdevfs_sb.listuid; - inode->i_gid = s->u.usbdevfs_sb.listgid; - inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG; - break; - case IBUS : - inode->i_uid = s->u.usbdevfs_sb.busuid; - inode->i_gid = s->u.usbdevfs_sb.busgid; - inode->i_mode = s->u.usbdevfs_sb.busmode | S_IFDIR; + parent = dget(parent); + + down(&parent->d_inode->i_sem); + + d = lookup_hash(&qstr,parent); + + error = PTR_ERR(d); + if (!IS_ERR(d)) { + switch(mode & S_IFMT) { + case 0: + case S_IFREG: + error = vfs_create(parent->d_inode,d,mode); break; - case IDEVICE : - inode->i_uid = s->u.usbdevfs_sb.devuid; - inode->i_gid = s->u.usbdevfs_sb.devgid; - inode->i_mode = s->u.usbdevfs_sb.devmode | S_IFREG; + case S_IFDIR: + error = vfs_mkdir(parent->d_inode,d,mode); break; + default: + err("cannot create special files\n"); } + *dentry = d; } + up(&parent->d_inode->i_sem); - return 0; + dput(parent); + return error; } -static struct super_operations usbdevfs_sops = { - read_inode: usbdevfs_read_inode, - put_super: usbdevfs_put_super, - statfs: usbdevfs_statfs, - remount_fs: usbdevfs_remount, -}; - -struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent) +static struct dentry *fs_create_file (const char *name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops, + uid_t uid, gid_t gid) { - struct inode *root_inode, *inode; - struct list_head *blist; - struct usb_bus *bus; - unsigned int i; + struct dentry *dentry; + int error; - if (parse_options(s, data)) { - printk(KERN_WARNING "usbdevfs: mount parameter error\n"); - return NULL; + dbg("creating file '%s'\n",name); + + error = fs_create_by_name(name,mode,parent,&dentry); + if (error) { + dentry = NULL; + } else { + if (dentry->d_inode) { + if (data) + dentry->d_inode->u.generic_ip = data; + if (fops) + dentry->d_inode->i_fop = fops; + dentry->d_inode->i_uid = uid; + dentry->d_inode->i_gid = gid; + } } - /* fill superblock */ - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = USBDEVICE_SUPER_MAGIC; - s->s_op = &usbdevfs_sops; - INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist); - INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist); - root_inode = iget(s, IROOT); - if (!root_inode) - goto out_no_root; - s->s_root = d_alloc_root(root_inode); - if (!s->s_root) - goto out_no_root; - list_add_tail(&s->u.usbdevfs_sb.slist, &superlist); - for (i = 0; i < NRSPECIAL; i++) { - if (!(inode = iget(s, IROOT+1+i))) - continue; - inode->i_uid = s->u.usbdevfs_sb.listuid; - inode->i_gid = s->u.usbdevfs_sb.listgid; - inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG; - special[i].inode = inode; - list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist); - list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes); - } - down (&usb_bus_list_lock); - for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) { - bus = list_entry(blist, struct usb_bus, bus_list); - new_bus_inode(bus, s); - recurse_new_dev_inode(bus->root_hub, s); - } - up (&usb_bus_list_lock); - return s; - - out_no_root: - printk("usbdevfs_read_super: get root inode failed\n"); - iput(root_inode); - return NULL; + return dentry; } +static void fs_remove_file (struct dentry *dentry) +{ + struct dentry *parent = dentry->d_parent; + + if (!parent || !parent->d_inode) + return; + + down(&parent->d_inode->i_sem); + if (usbfs_positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + vfs_rmdir(parent->d_inode,dentry); + else + vfs_unlink(parent->d_inode,dentry); + } + + dput(dentry); + } + up(&parent->d_inode->i_sem); +} + +/* --------------------------------------------------------------------- */ + + + /* - * The usbdevfs name is now depreciated (as of 2.5.1). + * The usbdevfs name is now deprecated (as of 2.5.1). * It will be removed when the 2.7.x development cycle is started. * You have been warned :) */ -static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE); -static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbdevfs_read_super, FS_SINGLE); +static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbfs_read_super, FS_SINGLE); +static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbfs_read_super, FS_SINGLE); /* --------------------------------------------------------------------- */ +static int get_mount (void) +{ + struct vfsmount *mnt; -static void update_special_inodes (void) + spin_lock (&mount_lock); + if (usbfs_mount) { + mntget(usbfs_mount); + ++mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + + spin_unlock (&mount_lock); + mnt = kern_mount (&usbdevice_fs_type); + if (IS_ERR(mnt)) { + err ("could not mount the fs...erroring out!\n"); + return -ENODEV; + } + spin_lock (&mount_lock); + if (!usbfs_mount) { + usbfs_mount = mnt; + ++mount_count; + spin_unlock (&mount_lock); + goto go_ahead; + } + mntget(usbfs_mount); + ++mount_count; + spin_unlock (&mount_lock); + mntput(mnt); + +go_ahead: + dbg("mount_count = %d\n", mount_count); + return 0; +} + +static void remove_mount (void) +{ + struct vfsmount *mnt; + + spin_lock (&mount_lock); + mnt = usbfs_mount; + --mount_count; + if (!mount_count) + usbfs_mount = NULL; + + spin_unlock (&mount_lock); + mntput(mnt); + dbg("mount_count = %d\n", mount_count); +} + +static int create_special_files (void) +{ + int retval; + + /* create the devices and drivers special files */ + retval = get_mount (); + if (retval) + return retval; + devices_dentry = fs_create_file ("devices", + listmode | S_IFREG, + NULL, NULL, + &usbdevfs_devices_fops, + listuid, listgid); + if (devices_dentry == NULL) { + err ("Unable to create devices usbfs file"); + return -ENODEV; + } + + drivers_dentry = fs_create_file ("drivers", + listmode | S_IFREG, + NULL, NULL, + &usbdevfs_drivers_fops, + listuid, listgid); + if (drivers_dentry == NULL) { + err ("Unable to create drivers usbfs file"); + return -ENODEV; + } + + return 0; +} + +static void remove_special_files (void) +{ + if (devices_dentry) + fs_remove_file (devices_dentry); + if (drivers_dentry) + fs_remove_file (drivers_dentry); + devices_dentry = NULL; + drivers_dentry = NULL; + remove_mount(); +} + +void usbfs_update_special (void) { - int i; - for (i = 0; i < NRSPECIAL; i++) { - struct inode *inode = special[i].inode; + struct inode *inode; + + if (devices_dentry) { + inode = devices_dentry->d_inode; + if (inode) + inode->i_atime = inode->i_mtime = inode->i_ctime = +CURRENT_TIME; + } + if (drivers_dentry) { + inode = devices_dentry->d_inode; if (inode) inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; } } - -void usbdevfs_add_bus(struct usb_bus *bus) +void usbfs_add_bus(struct usb_bus *bus) { - struct list_head *slist; + char name[8]; + int retval; + + /* create the special files if this is the first bus added */ + if (num_buses == 0) { + retval = create_special_files(); + if (retval) + return; + } + ++num_buses; + + sprintf (name, "%03d", bus->busnum); + bus->dentry = fs_create_file (name, + busmode | S_IFDIR, + NULL, bus, NULL, + busuid, busgid); + if (bus->dentry == NULL) + return; - lock_kernel(); - for (slist = superlist.next; slist != &superlist; slist = slist->next) - new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist)); - update_special_inodes(); - unlock_kernel(); + usbfs_update_special(); usbdevfs_conn_disc_event(); } -void usbdevfs_remove_bus(struct usb_bus *bus) + +void usbfs_remove_bus(struct usb_bus *bus) { - lock_kernel(); - while (!list_empty(&bus->inodes)) - free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist)); - update_special_inodes(); - unlock_kernel(); + if (bus->dentry) { + fs_remove_file (bus->dentry); + bus->dentry = NULL; + } + + --num_buses; + if (num_buses <= 0) { + remove_special_files(); + num_buses = 0; + } + + usbfs_update_special(); usbdevfs_conn_disc_event(); } -void usbdevfs_add_device(struct usb_device *dev) +void usbfs_add_device(struct usb_device *dev) { - struct list_head *slist; + char name[8]; - lock_kernel(); - for (slist = superlist.next; slist != &superlist; slist = slist->next) - new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist)); - update_special_inodes(); - unlock_kernel(); + sprintf (name, "%03d", dev->devnum); + dev->dentry = fs_create_file (name, + devmode | S_IFREG, + dev->bus->dentry, dev, + &usbdevfs_device_file_operations, + devuid, devgid); + if (dev->dentry == NULL) + return; + + usbfs_update_special(); usbdevfs_conn_disc_event(); } -void usbdevfs_remove_device(struct usb_device *dev) +void usbfs_remove_device(struct usb_device *dev) { struct dev_state *ds; struct siginfo sinfo; - lock_kernel(); - while (!list_empty(&dev->inodes)) - free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist)); + if (dev->dentry) { + fs_remove_file (dev->dentry); + dev->dentry = NULL; + } while (!list_empty(&dev->filelist)) { ds = list_entry(dev->filelist.next, struct dev_state, list); list_del(&ds->list); @@ -732,9 +716,7 @@ send_sig_info(ds->discsignr, &sinfo, ds->disctask); } } - - update_special_inodes(); - unlock_kernel(); + usbfs_update_special(); usbdevfs_conn_disc_event(); } @@ -744,39 +726,42 @@ static struct proc_dir_entry *usbdir = NULL; #endif -int __init usbdevfs_init(void) +int __init usbfs_init(void) { - int ret; + int retval; - for (ret = 0; ret < NRSPECIAL; ret++) { - INIT_LIST_HEAD(&special[ret].inodes); - } - if ((ret = usb_register(&usbdevfs_driver))) - return ret; - if ((ret = register_filesystem(&usb_fs_type))) { + retval = usb_register(&usbdevfs_driver); + if (retval) + return retval; + + retval = register_filesystem(&usb_fs_type); + if (retval) { usb_deregister(&usbdevfs_driver); - return ret; + return retval; } - if ((ret = register_filesystem(&usbdevice_fs_type))) { + retval = register_filesystem(&usbdevice_fs_type); + if (retval) { unregister_filesystem(&usb_fs_type); usb_deregister(&usbdevfs_driver); - return ret; + return retval; } + #ifdef CONFIG_PROC_FS /* create mount point for usbdevfs */ usbdir = proc_mkdir("usb", proc_bus); #endif - return ret; + + return 0; } -void __exit usbdevfs_cleanup(void) +void __exit usbfs_cleanup(void) { usb_deregister(&usbdevfs_driver); unregister_filesystem(&usb_fs_type); unregister_filesystem(&usbdevice_fs_type); #ifdef CONFIG_PROC_FS - if (usbdir) - remove_proc_entry("usb", proc_bus); + if (usbdir) + remove_proc_entry("usb", proc_bus); #endif } diff -Nru a/drivers/usb/usb.c b/drivers/usb/usb.c --- a/drivers/usb/usb.c Thu Dec 13 12:52:39 2001 +++ b/drivers/usb/usb.c Thu Dec 13 12:52:39 2001 @@ -97,6 +97,8 @@ usb_scan_devices(); + usbfs_update_special(); + return 0; } @@ -192,6 +194,8 @@ usb_drivers_purge(driver, bus->root_hub); } up (&usb_bus_list_lock); + + usbfs_update_special(); } /** @@ -421,7 +425,6 @@ bus->bandwidth_isoc_reqs = 0; INIT_LIST_HEAD(&bus->bus_list); - INIT_LIST_HEAD(&bus->inodes); atomic_set(&bus->refcnt, 1); @@ -468,7 +471,7 @@ list_add(&bus->bus_list, &usb_bus_list); up (&usb_bus_list_lock); - usbdevfs_add_bus(bus); + usbfs_add_bus(bus); info("new USB bus registered, assigned bus number %d", bus->busnum); } @@ -494,7 +497,7 @@ list_del(&bus->bus_list); up (&usb_bus_list_lock); - usbdevfs_remove_bus(bus); + usbfs_remove_bus(bus); clear_bit(bus->busnum, busmap.busmap); @@ -923,7 +926,7 @@ /* a simple/common case: one config, one interface, one driver * with current altsetting being a reasonable setting. - * everything needs a smart agent and usbdevfs; or can rely on + * everything needs a smart agent and usbfs; or can rely on * device-specific binding policies. */ envp [i++] = scratch; @@ -1016,7 +1019,6 @@ dev->bus = bus; dev->parent = parent; atomic_set(&dev->refcnt, 1); - INIT_LIST_HEAD(&dev->inodes); INIT_LIST_HEAD(&dev->filelist); init_MUTEX(&dev->serialize); @@ -1906,7 +1908,7 @@ /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - usbdevfs_remove_device(dev); + usbfs_remove_device(dev); } /* Free up the device itself */ @@ -2579,7 +2581,7 @@ #endif /* now that the basic setup is over, add a /proc/bus/usb entry */ - usbdevfs_add_device(dev); + usbfs_add_device(dev); /* find drivers willing to handle this device */ usb_find_drivers(dev); @@ -2660,7 +2662,7 @@ { init_MUTEX(&usb_bus_list_lock); usb_major_init(); - usbdevfs_init(); + usbfs_init(); usb_hub_init(); return 0; @@ -2672,7 +2674,7 @@ static void __exit usb_exit(void) { usb_major_cleanup(); - usbdevfs_cleanup(); + usbfs_cleanup(); usb_hub_cleanup(); } diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Thu Dec 13 12:52:39 2001 +++ b/include/linux/fs.h Thu Dec 13 12:52:39 2001 @@ -312,7 +312,6 @@ #include <linux/udf_fs_i.h> #include <linux/ncp_fs_i.h> #include <linux/proc_fs_i.h> -#include <linux/usbdev_fs_i.h> #include <linux/jffs2_fs_i.h> #include <linux/cramfs_fs_sb.h> @@ -503,7 +502,6 @@ struct ncp_inode_info ncpfs_i; struct proc_inode_info proc_i; struct socket socket_i; - struct usbdev_inode_info usbdev_i; struct jffs2_inode_info jffs2_i; void *generic_ip; } u; @@ -687,7 +685,6 @@ #include <linux/bfs_fs_sb.h> #include <linux/udf_fs_sb.h> #include <linux/ncp_fs_sb.h> -#include <linux/usbdev_fs_sb.h> #include <linux/cramfs_fs_sb.h> #include <linux/jffs2_fs_sb.h> @@ -745,7 +742,6 @@ struct bfs_sb_info bfs_sb; struct udf_sb_info udf_sb; struct ncp_sb_info ncpfs_sb; - struct usbdev_sb_info usbdevfs_sb; struct jffs2_sb_info jffs2_sb; struct cramfs_sb_info cramfs_sb; void *generic_sbp; diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Thu Dec 13 12:52:39 2001 +++ b/include/linux/usb.h Thu Dec 13 12:52:39 2001 @@ -521,7 +521,7 @@ struct semaphore serialize; - /* ioctl -- userspace apps can talk to drivers through usbdevfs */ + /* ioctl -- userspace apps can talk to drivers through usbfs */ int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf); /* support for "new-style" USB hotplugging */ @@ -989,8 +989,7 @@ int bandwidth_int_reqs; /* number of Interrupt requesters */ int bandwidth_isoc_reqs; /* number of Isoc. requesters */ - /* usbdevfs inode list */ - struct list_head inodes; + struct dentry *dentry; /* usbfs dentry entry for the bus */ atomic_t refcnt; }; @@ -1090,9 +1089,8 @@ void *hcpriv; /* Host Controller private data */ - /* usbdevfs inode list */ - struct list_head inodes; struct list_head filelist; + struct dentry *dentry; /* usbfs dentry entry for the device */ /* * Child devices - these can be either new devices @@ -1254,7 +1252,7 @@ /* * bus and driver list - * exported only for usbdevfs (not visible outside usbcore) + * exported only for usbfs (not visible outside usbcore) */ extern struct list_head usb_driver_list; @@ -1271,23 +1269,25 @@ * these are expected to be called from the USB core/hub thread * with the kernel lock held */ -extern void usbdevfs_add_bus(struct usb_bus *bus); -extern void usbdevfs_remove_bus(struct usb_bus *bus); -extern void usbdevfs_add_device(struct usb_device *dev); -extern void usbdevfs_remove_device(struct usb_device *dev); +extern void usbfs_add_bus(struct usb_bus *bus); +extern void usbfs_remove_bus(struct usb_bus *bus); +extern void usbfs_add_device(struct usb_device *dev); +extern void usbfs_remove_device(struct usb_device *dev); +extern void usbfs_update_special (void); -extern int usbdevfs_init(void); -extern void usbdevfs_cleanup(void); +extern int usbfs_init(void); +extern void usbfs_cleanup(void); #else /* CONFIG_USB_DEVICEFS */ -static inline void usbdevfs_add_bus(struct usb_bus *bus) {} -static inline void usbdevfs_remove_bus(struct usb_bus *bus) {} -static inline void usbdevfs_add_device(struct usb_device *dev) {} -static inline void usbdevfs_remove_device(struct usb_device *dev) {} +static inline void usbfs_add_bus(struct usb_bus *bus) {} +static inline void usbfs_remove_bus(struct usb_bus *bus) {} +static inline void usbfs_add_device(struct usb_device *dev) {} +static inline void usbfs_remove_device(struct usb_device *dev) {} +static inline void usbfs_update_special (void) {} -static inline int usbdevfs_init(void) { return 0; } -static inline void usbdevfs_cleanup(void) { } +static inline int usbfs_init(void) { return 0; } +static inline void usbfs_cleanup(void) { } #endif /* CONFIG_USB_DEVICEFS */ diff -Nru a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h --- a/include/linux/usbdevice_fs.h Thu Dec 13 12:52:39 2001 +++ b/include/linux/usbdevice_fs.h Thu Dec 13 12:52:39 2001 @@ -150,17 +150,6 @@ #include <linux/list.h> #include <asm/semaphore.h> -/* - * inode number macros - */ -#define ITYPE(x) ((x)&(0xf<<28)) -#define ISPECIAL (0<<28) -#define IBUS (1<<28) -#define IDEVICE (2<<28) -#define IBUSNR(x) (((x)>>8)&0xff) -#define IDEVNR(x) ((x)&0xff) - -#define IROOT 1 struct dev_state { struct list_head list; /* state list */ diff -Naur -X ../dontdiff linux/include/linux/usbdev_fs_i.h ../linux-2.5/include/linux/usbdev_fs_i.h --- linux/include/linux/usbdev_fs_i.h Mon Jan 10 11:32:48 2000 +++ ../linux-2.5/include/linux/usbdev_fs_i.h Wed Dec 31 16:00:00 1969 @@ -1,11 +0,0 @@ -struct usb_device; -struct usb_bus; - -struct usbdev_inode_info { - struct list_head dlist; - struct list_head slist; - union { - struct usb_device *dev; - struct usb_bus *bus; - } p; -}; diff -Naur -X ../dontdiff linux/include/linux/usbdev_fs_sb.h ../linux-2.5/include/linux/usbdev_fs_sb.h --- linux/include/linux/usbdev_fs_sb.h Tue May 22 10:25:36 2001 +++ ../linux-2.5/include/linux/usbdev_fs_sb.h Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -struct usbdev_sb_info { - struct list_head slist; - struct list_head ilist; - uid_t devuid; - gid_t devgid; - umode_t devmode; - uid_t busuid; - gid_t busgid; - umode_t busmode; - uid_t listuid; - gid_t listgid; - umode_t listmode; -}; _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel