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 <greg@kroah.com>


 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",
