ChangeSet 1.1757.66.13, 2004/07/14 14:47:36-07:00, ddstreet@ieee.org [PATCH] USB: fix usbfs mount options ignored bug Ok here is a patch to make the mount options work. In addition to implementing the remount function, it removes the parse_options() call from usb_fill_super and adds a "ignore" flag around the mounting that gets done in create_special_files. The parse_options call in usb_fill_super is removed because it is not needed when remount is implemented. The ignore_mount flag is needed because the simple_pin_fs function calls remount with no mount options - i.e. it's not a real mount. So the mount options would be cleared out. The ignore_mount flag causes the remount function to only act on real mounts. Signed-off-by: Greg Kroah-Hartman drivers/usb/core/inode.c | 108 ++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 103 insertions(+), 5 deletions(-) diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c --- a/drivers/usb/core/inode.c 2004-07-14 16:45:14 -07:00 +++ b/drivers/usb/core/inode.c 2004-07-14 16:45:14 -07:00 @@ -48,6 +48,7 @@ static struct vfsmount *usbfs_mount; static int usbdevfs_mount_count; /* = 0 */ static int usbfs_mount_count; /* = 0 */ +static int ignore_mount = 0; static struct dentry *devices_usbdevfs_dentry; static struct dentry *devices_usbfs_dentry; @@ -88,6 +89,17 @@ char *p; int option; + /* (re)set to defaults. */ + devuid = 0; + busuid = 0; + listuid = 0; + devgid = 0; + busgid = 0; + listgid = 0; + devmode = S_IWUSR | S_IRUGO; + busmode = S_IXUGO | S_IRUGO; + listmode = S_IRUGO; + while ((p = strsep(&data, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; @@ -151,6 +163,89 @@ return 0; } +static void update_special(struct dentry *special) +{ + special->d_inode->i_uid = listuid; + special->d_inode->i_gid = listgid; + special->d_inode->i_mode = S_IFREG | listmode; +} + +static void update_dev(struct dentry *dev) +{ + dev->d_inode->i_uid = devuid; + dev->d_inode->i_gid = devgid; + dev->d_inode->i_mode = S_IFREG | devmode; +} + +static void update_bus(struct dentry *bus) +{ + struct dentry *dev = NULL; + + bus->d_inode->i_uid = busuid; + bus->d_inode->i_gid = busgid; + bus->d_inode->i_mode = S_IFDIR | busmode; + + down(&bus->d_inode->i_sem); + + list_for_each_entry(dev, &bus->d_subdirs, d_child) + if (dev->d_inode) + update_dev(dev); + + up(&bus->d_inode->i_sem); +} + +static void update_sb(struct super_block *sb) +{ + struct dentry *root = sb->s_root; + struct dentry *bus = NULL; + + if (!root) + return; + + down(&root->d_inode->i_sem); + + list_for_each_entry(bus, &root->d_subdirs, d_child) { + if (bus->d_inode) { + switch (S_IFMT & bus->d_inode->i_mode) { + case S_IFDIR: + update_bus(bus); + break; + case S_IFREG: + update_special(bus); + break; + default: + warn("Unknown node %s mode %x found on remount!\n",bus->d_name.name,bus->d_inode->i_mode); + break; + } + } + } + + up(&root->d_inode->i_sem); +} + +static int remount(struct super_block *sb, int *flags, char *data) +{ + /* If this is not a real mount, + * i.e. it's a simple_pin_fs from create_special_files, + * then ignore it. + */ + if (ignore_mount) + return 0; + + if (parse_options(sb, data)) { + warn("usbfs: mount parameter error:"); + return -EINVAL; + } + + if (usbfs_mount && usbfs_mount->mnt_sb) + update_sb(usbfs_mount->mnt_sb); + + if (usbdevfs_mount && usbdevfs_mount->mnt_sb) + update_sb(usbdevfs_mount->mnt_sb); + + return 0; +} + static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev) { struct inode *inode = new_inode(sb); @@ -349,6 +444,7 @@ static struct super_operations usbfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, + .remount_fs = remount, }; static int usbfs_fill_super(struct super_block *sb, void *data, int silent) @@ -356,11 +452,6 @@ struct inode *inode; struct dentry *root; - if (parse_options(sb, data)) { - warn("usbfs: mount parameter error:"); - return -EINVAL; - } - sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = USBDEVICE_SUPER_MAGIC; @@ -523,6 +614,11 @@ struct dentry *parent; int retval; + /* the simple_pin_fs calls will call remount with no options + * without this flag that would overwrite the real mount options (if any) + */ + ignore_mount = 1; + /* create the devices special file */ retval = simple_pin_fs("usbdevfs", &usbdevfs_mount, &usbdevfs_mount_count); if (retval) { @@ -535,6 +631,8 @@ err ("Unable to get usbfs mount"); goto error_clean_usbdevfs_mount; } + + ignore_mount = 0; parent = usbfs_mount->mnt_sb->s_root; devices_usbfs_dentry = fs_create_file ("devices",