Commit 2e4f3c02239d4c7c454604715db619bc971b15eb
Committed by
Greg Kroah-Hartman
1 parent
8dd70705c4
Exists in
master
and in
7 other branches
USB: mount options: fix usbfs
Add a .show_options super operation to usbfs. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 1 changed file with 36 additions and 6 deletions Inline Diff
drivers/usb/core/inode.c
1 | /*****************************************************************************/ | 1 | /*****************************************************************************/ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * inode.c -- Inode/Dentry functions for the USB device file system. | 4 | * inode.c -- Inode/Dentry functions for the USB device file system. |
5 | * | 5 | * |
6 | * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) | 6 | * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) |
7 | * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com) | 7 | * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com) |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation; either version 2 of the License, or | 11 | * the Free Software Foundation; either version 2 of the License, or |
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | * | 13 | * |
14 | * This program is distributed in the hope that it will be useful, | 14 | * This program is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License | 19 | * You should have received a copy of the GNU General Public License |
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
22 | * | 22 | * |
23 | * History: | 23 | * History: |
24 | * 0.1 04.01.2000 Created | 24 | * 0.1 04.01.2000 Created |
25 | * 0.2 10.12.2001 converted to use the vfs layer better | 25 | * 0.2 10.12.2001 converted to use the vfs layer better |
26 | */ | 26 | */ |
27 | 27 | ||
28 | /*****************************************************************************/ | 28 | /*****************************************************************************/ |
29 | 29 | ||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/mount.h> | 32 | #include <linux/mount.h> |
33 | #include <linux/pagemap.h> | 33 | #include <linux/pagemap.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/proc_fs.h> | 35 | #include <linux/proc_fs.h> |
36 | #include <linux/usb.h> | 36 | #include <linux/usb.h> |
37 | #include <linux/namei.h> | 37 | #include <linux/namei.h> |
38 | #include <linux/usbdevice_fs.h> | 38 | #include <linux/usbdevice_fs.h> |
39 | #include <linux/parser.h> | 39 | #include <linux/parser.h> |
40 | #include <linux/notifier.h> | 40 | #include <linux/notifier.h> |
41 | #include <linux/seq_file.h> | ||
41 | #include <asm/byteorder.h> | 42 | #include <asm/byteorder.h> |
42 | #include "usb.h" | 43 | #include "usb.h" |
43 | #include "hcd.h" | 44 | #include "hcd.h" |
44 | 45 | ||
46 | #define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO) | ||
47 | #define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO) | ||
48 | #define USBFS_DEFAULT_LISTMODE S_IRUGO | ||
49 | |||
45 | static struct super_operations usbfs_ops; | 50 | static struct super_operations usbfs_ops; |
46 | static const struct file_operations default_file_operations; | 51 | static const struct file_operations default_file_operations; |
47 | static struct vfsmount *usbfs_mount; | 52 | static struct vfsmount *usbfs_mount; |
48 | static int usbfs_mount_count; /* = 0 */ | 53 | static int usbfs_mount_count; /* = 0 */ |
49 | static int ignore_mount = 0; | 54 | static int ignore_mount = 0; |
50 | 55 | ||
51 | static struct dentry *devices_usbfs_dentry; | 56 | static struct dentry *devices_usbfs_dentry; |
52 | static int num_buses; /* = 0 */ | 57 | static int num_buses; /* = 0 */ |
53 | 58 | ||
54 | static uid_t devuid; /* = 0 */ | 59 | static uid_t devuid; /* = 0 */ |
55 | static uid_t busuid; /* = 0 */ | 60 | static uid_t busuid; /* = 0 */ |
56 | static uid_t listuid; /* = 0 */ | 61 | static uid_t listuid; /* = 0 */ |
57 | static gid_t devgid; /* = 0 */ | 62 | static gid_t devgid; /* = 0 */ |
58 | static gid_t busgid; /* = 0 */ | 63 | static gid_t busgid; /* = 0 */ |
59 | static gid_t listgid; /* = 0 */ | 64 | static gid_t listgid; /* = 0 */ |
60 | static umode_t devmode = S_IWUSR | S_IRUGO; | 65 | static umode_t devmode = USBFS_DEFAULT_DEVMODE; |
61 | static umode_t busmode = S_IXUGO | S_IRUGO; | 66 | static umode_t busmode = USBFS_DEFAULT_BUSMODE; |
62 | static umode_t listmode = S_IRUGO; | 67 | static umode_t listmode = USBFS_DEFAULT_LISTMODE; |
63 | 68 | ||
69 | static int usbfs_show_options(struct seq_file *seq, struct vfsmount *mnt) | ||
70 | { | ||
71 | if (devuid != 0) | ||
72 | seq_printf(seq, ",devuid=%u", devuid); | ||
73 | if (devgid != 0) | ||
74 | seq_printf(seq, ",devgid=%u", devgid); | ||
75 | if (devmode != USBFS_DEFAULT_DEVMODE) | ||
76 | seq_printf(seq, ",devmode=%o", devmode); | ||
77 | if (busuid != 0) | ||
78 | seq_printf(seq, ",busuid=%u", busuid); | ||
79 | if (busgid != 0) | ||
80 | seq_printf(seq, ",busgid=%u", busgid); | ||
81 | if (busmode != USBFS_DEFAULT_BUSMODE) | ||
82 | seq_printf(seq, ",busmode=%o", busmode); | ||
83 | if (listuid != 0) | ||
84 | seq_printf(seq, ",listuid=%u", listuid); | ||
85 | if (listgid != 0) | ||
86 | seq_printf(seq, ",listgid=%u", listgid); | ||
87 | if (listmode != USBFS_DEFAULT_LISTMODE) | ||
88 | seq_printf(seq, ",listmode=%o", listmode); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
64 | enum { | 93 | enum { |
65 | Opt_devuid, Opt_devgid, Opt_devmode, | 94 | Opt_devuid, Opt_devgid, Opt_devmode, |
66 | Opt_busuid, Opt_busgid, Opt_busmode, | 95 | Opt_busuid, Opt_busgid, Opt_busmode, |
67 | Opt_listuid, Opt_listgid, Opt_listmode, | 96 | Opt_listuid, Opt_listgid, Opt_listmode, |
68 | Opt_err, | 97 | Opt_err, |
69 | }; | 98 | }; |
70 | 99 | ||
71 | static match_table_t tokens = { | 100 | static match_table_t tokens = { |
72 | {Opt_devuid, "devuid=%u"}, | 101 | {Opt_devuid, "devuid=%u"}, |
73 | {Opt_devgid, "devgid=%u"}, | 102 | {Opt_devgid, "devgid=%u"}, |
74 | {Opt_devmode, "devmode=%o"}, | 103 | {Opt_devmode, "devmode=%o"}, |
75 | {Opt_busuid, "busuid=%u"}, | 104 | {Opt_busuid, "busuid=%u"}, |
76 | {Opt_busgid, "busgid=%u"}, | 105 | {Opt_busgid, "busgid=%u"}, |
77 | {Opt_busmode, "busmode=%o"}, | 106 | {Opt_busmode, "busmode=%o"}, |
78 | {Opt_listuid, "listuid=%u"}, | 107 | {Opt_listuid, "listuid=%u"}, |
79 | {Opt_listgid, "listgid=%u"}, | 108 | {Opt_listgid, "listgid=%u"}, |
80 | {Opt_listmode, "listmode=%o"}, | 109 | {Opt_listmode, "listmode=%o"}, |
81 | {Opt_err, NULL} | 110 | {Opt_err, NULL} |
82 | }; | 111 | }; |
83 | 112 | ||
84 | static int parse_options(struct super_block *s, char *data) | 113 | static int parse_options(struct super_block *s, char *data) |
85 | { | 114 | { |
86 | char *p; | 115 | char *p; |
87 | int option; | 116 | int option; |
88 | 117 | ||
89 | /* (re)set to defaults. */ | 118 | /* (re)set to defaults. */ |
90 | devuid = 0; | 119 | devuid = 0; |
91 | busuid = 0; | 120 | busuid = 0; |
92 | listuid = 0; | 121 | listuid = 0; |
93 | devgid = 0; | 122 | devgid = 0; |
94 | busgid = 0; | 123 | busgid = 0; |
95 | listgid = 0; | 124 | listgid = 0; |
96 | devmode = S_IWUSR | S_IRUGO; | 125 | devmode = USBFS_DEFAULT_DEVMODE; |
97 | busmode = S_IXUGO | S_IRUGO; | 126 | busmode = USBFS_DEFAULT_BUSMODE; |
98 | listmode = S_IRUGO; | 127 | listmode = USBFS_DEFAULT_LISTMODE; |
99 | 128 | ||
100 | while ((p = strsep(&data, ",")) != NULL) { | 129 | while ((p = strsep(&data, ",")) != NULL) { |
101 | substring_t args[MAX_OPT_ARGS]; | 130 | substring_t args[MAX_OPT_ARGS]; |
102 | int token; | 131 | int token; |
103 | if (!*p) | 132 | if (!*p) |
104 | continue; | 133 | continue; |
105 | 134 | ||
106 | token = match_token(p, tokens, args); | 135 | token = match_token(p, tokens, args); |
107 | switch (token) { | 136 | switch (token) { |
108 | case Opt_devuid: | 137 | case Opt_devuid: |
109 | if (match_int(&args[0], &option)) | 138 | if (match_int(&args[0], &option)) |
110 | return -EINVAL; | 139 | return -EINVAL; |
111 | devuid = option; | 140 | devuid = option; |
112 | break; | 141 | break; |
113 | case Opt_devgid: | 142 | case Opt_devgid: |
114 | if (match_int(&args[0], &option)) | 143 | if (match_int(&args[0], &option)) |
115 | return -EINVAL; | 144 | return -EINVAL; |
116 | devgid = option; | 145 | devgid = option; |
117 | break; | 146 | break; |
118 | case Opt_devmode: | 147 | case Opt_devmode: |
119 | if (match_octal(&args[0], &option)) | 148 | if (match_octal(&args[0], &option)) |
120 | return -EINVAL; | 149 | return -EINVAL; |
121 | devmode = option & S_IRWXUGO; | 150 | devmode = option & S_IRWXUGO; |
122 | break; | 151 | break; |
123 | case Opt_busuid: | 152 | case Opt_busuid: |
124 | if (match_int(&args[0], &option)) | 153 | if (match_int(&args[0], &option)) |
125 | return -EINVAL; | 154 | return -EINVAL; |
126 | busuid = option; | 155 | busuid = option; |
127 | break; | 156 | break; |
128 | case Opt_busgid: | 157 | case Opt_busgid: |
129 | if (match_int(&args[0], &option)) | 158 | if (match_int(&args[0], &option)) |
130 | return -EINVAL; | 159 | return -EINVAL; |
131 | busgid = option; | 160 | busgid = option; |
132 | break; | 161 | break; |
133 | case Opt_busmode: | 162 | case Opt_busmode: |
134 | if (match_octal(&args[0], &option)) | 163 | if (match_octal(&args[0], &option)) |
135 | return -EINVAL; | 164 | return -EINVAL; |
136 | busmode = option & S_IRWXUGO; | 165 | busmode = option & S_IRWXUGO; |
137 | break; | 166 | break; |
138 | case Opt_listuid: | 167 | case Opt_listuid: |
139 | if (match_int(&args[0], &option)) | 168 | if (match_int(&args[0], &option)) |
140 | return -EINVAL; | 169 | return -EINVAL; |
141 | listuid = option; | 170 | listuid = option; |
142 | break; | 171 | break; |
143 | case Opt_listgid: | 172 | case Opt_listgid: |
144 | if (match_int(&args[0], &option)) | 173 | if (match_int(&args[0], &option)) |
145 | return -EINVAL; | 174 | return -EINVAL; |
146 | listgid = option; | 175 | listgid = option; |
147 | break; | 176 | break; |
148 | case Opt_listmode: | 177 | case Opt_listmode: |
149 | if (match_octal(&args[0], &option)) | 178 | if (match_octal(&args[0], &option)) |
150 | return -EINVAL; | 179 | return -EINVAL; |
151 | listmode = option & S_IRWXUGO; | 180 | listmode = option & S_IRWXUGO; |
152 | break; | 181 | break; |
153 | default: | 182 | default: |
154 | err("usbfs: unrecognised mount option \"%s\" " | 183 | err("usbfs: unrecognised mount option \"%s\" " |
155 | "or missing value\n", p); | 184 | "or missing value\n", p); |
156 | return -EINVAL; | 185 | return -EINVAL; |
157 | } | 186 | } |
158 | } | 187 | } |
159 | 188 | ||
160 | return 0; | 189 | return 0; |
161 | } | 190 | } |
162 | 191 | ||
163 | static void update_special(struct dentry *special) | 192 | static void update_special(struct dentry *special) |
164 | { | 193 | { |
165 | special->d_inode->i_uid = listuid; | 194 | special->d_inode->i_uid = listuid; |
166 | special->d_inode->i_gid = listgid; | 195 | special->d_inode->i_gid = listgid; |
167 | special->d_inode->i_mode = S_IFREG | listmode; | 196 | special->d_inode->i_mode = S_IFREG | listmode; |
168 | } | 197 | } |
169 | 198 | ||
170 | static void update_dev(struct dentry *dev) | 199 | static void update_dev(struct dentry *dev) |
171 | { | 200 | { |
172 | dev->d_inode->i_uid = devuid; | 201 | dev->d_inode->i_uid = devuid; |
173 | dev->d_inode->i_gid = devgid; | 202 | dev->d_inode->i_gid = devgid; |
174 | dev->d_inode->i_mode = S_IFREG | devmode; | 203 | dev->d_inode->i_mode = S_IFREG | devmode; |
175 | } | 204 | } |
176 | 205 | ||
177 | static void update_bus(struct dentry *bus) | 206 | static void update_bus(struct dentry *bus) |
178 | { | 207 | { |
179 | struct dentry *dev = NULL; | 208 | struct dentry *dev = NULL; |
180 | 209 | ||
181 | bus->d_inode->i_uid = busuid; | 210 | bus->d_inode->i_uid = busuid; |
182 | bus->d_inode->i_gid = busgid; | 211 | bus->d_inode->i_gid = busgid; |
183 | bus->d_inode->i_mode = S_IFDIR | busmode; | 212 | bus->d_inode->i_mode = S_IFDIR | busmode; |
184 | 213 | ||
185 | mutex_lock(&bus->d_inode->i_mutex); | 214 | mutex_lock(&bus->d_inode->i_mutex); |
186 | 215 | ||
187 | list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) | 216 | list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) |
188 | if (dev->d_inode) | 217 | if (dev->d_inode) |
189 | update_dev(dev); | 218 | update_dev(dev); |
190 | 219 | ||
191 | mutex_unlock(&bus->d_inode->i_mutex); | 220 | mutex_unlock(&bus->d_inode->i_mutex); |
192 | } | 221 | } |
193 | 222 | ||
194 | static void update_sb(struct super_block *sb) | 223 | static void update_sb(struct super_block *sb) |
195 | { | 224 | { |
196 | struct dentry *root = sb->s_root; | 225 | struct dentry *root = sb->s_root; |
197 | struct dentry *bus = NULL; | 226 | struct dentry *bus = NULL; |
198 | 227 | ||
199 | if (!root) | 228 | if (!root) |
200 | return; | 229 | return; |
201 | 230 | ||
202 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); | 231 | mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); |
203 | 232 | ||
204 | list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { | 233 | list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { |
205 | if (bus->d_inode) { | 234 | if (bus->d_inode) { |
206 | switch (S_IFMT & bus->d_inode->i_mode) { | 235 | switch (S_IFMT & bus->d_inode->i_mode) { |
207 | case S_IFDIR: | 236 | case S_IFDIR: |
208 | update_bus(bus); | 237 | update_bus(bus); |
209 | break; | 238 | break; |
210 | case S_IFREG: | 239 | case S_IFREG: |
211 | update_special(bus); | 240 | update_special(bus); |
212 | break; | 241 | break; |
213 | default: | 242 | default: |
214 | warn("Unknown node %s mode %x found on remount!\n",bus->d_name.name,bus->d_inode->i_mode); | 243 | warn("Unknown node %s mode %x found on remount!\n",bus->d_name.name,bus->d_inode->i_mode); |
215 | break; | 244 | break; |
216 | } | 245 | } |
217 | } | 246 | } |
218 | } | 247 | } |
219 | 248 | ||
220 | mutex_unlock(&root->d_inode->i_mutex); | 249 | mutex_unlock(&root->d_inode->i_mutex); |
221 | } | 250 | } |
222 | 251 | ||
223 | static int remount(struct super_block *sb, int *flags, char *data) | 252 | static int remount(struct super_block *sb, int *flags, char *data) |
224 | { | 253 | { |
225 | /* If this is not a real mount, | 254 | /* If this is not a real mount, |
226 | * i.e. it's a simple_pin_fs from create_special_files, | 255 | * i.e. it's a simple_pin_fs from create_special_files, |
227 | * then ignore it. | 256 | * then ignore it. |
228 | */ | 257 | */ |
229 | if (ignore_mount) | 258 | if (ignore_mount) |
230 | return 0; | 259 | return 0; |
231 | 260 | ||
232 | if (parse_options(sb, data)) { | 261 | if (parse_options(sb, data)) { |
233 | warn("usbfs: mount parameter error:"); | 262 | warn("usbfs: mount parameter error:"); |
234 | return -EINVAL; | 263 | return -EINVAL; |
235 | } | 264 | } |
236 | 265 | ||
237 | if (usbfs_mount && usbfs_mount->mnt_sb) | 266 | if (usbfs_mount && usbfs_mount->mnt_sb) |
238 | update_sb(usbfs_mount->mnt_sb); | 267 | update_sb(usbfs_mount->mnt_sb); |
239 | 268 | ||
240 | return 0; | 269 | return 0; |
241 | } | 270 | } |
242 | 271 | ||
243 | static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev) | 272 | static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t dev) |
244 | { | 273 | { |
245 | struct inode *inode = new_inode(sb); | 274 | struct inode *inode = new_inode(sb); |
246 | 275 | ||
247 | if (inode) { | 276 | if (inode) { |
248 | inode->i_mode = mode; | 277 | inode->i_mode = mode; |
249 | inode->i_uid = current->fsuid; | 278 | inode->i_uid = current->fsuid; |
250 | inode->i_gid = current->fsgid; | 279 | inode->i_gid = current->fsgid; |
251 | inode->i_blocks = 0; | 280 | inode->i_blocks = 0; |
252 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 281 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
253 | switch (mode & S_IFMT) { | 282 | switch (mode & S_IFMT) { |
254 | default: | 283 | default: |
255 | init_special_inode(inode, mode, dev); | 284 | init_special_inode(inode, mode, dev); |
256 | break; | 285 | break; |
257 | case S_IFREG: | 286 | case S_IFREG: |
258 | inode->i_fop = &default_file_operations; | 287 | inode->i_fop = &default_file_operations; |
259 | break; | 288 | break; |
260 | case S_IFDIR: | 289 | case S_IFDIR: |
261 | inode->i_op = &simple_dir_inode_operations; | 290 | inode->i_op = &simple_dir_inode_operations; |
262 | inode->i_fop = &simple_dir_operations; | 291 | inode->i_fop = &simple_dir_operations; |
263 | 292 | ||
264 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | 293 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
265 | inc_nlink(inode); | 294 | inc_nlink(inode); |
266 | break; | 295 | break; |
267 | } | 296 | } |
268 | } | 297 | } |
269 | return inode; | 298 | return inode; |
270 | } | 299 | } |
271 | 300 | ||
272 | /* SMP-safe */ | 301 | /* SMP-safe */ |
273 | static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, | 302 | static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode, |
274 | dev_t dev) | 303 | dev_t dev) |
275 | { | 304 | { |
276 | struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); | 305 | struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); |
277 | int error = -EPERM; | 306 | int error = -EPERM; |
278 | 307 | ||
279 | if (dentry->d_inode) | 308 | if (dentry->d_inode) |
280 | return -EEXIST; | 309 | return -EEXIST; |
281 | 310 | ||
282 | if (inode) { | 311 | if (inode) { |
283 | d_instantiate(dentry, inode); | 312 | d_instantiate(dentry, inode); |
284 | dget(dentry); | 313 | dget(dentry); |
285 | error = 0; | 314 | error = 0; |
286 | } | 315 | } |
287 | return error; | 316 | return error; |
288 | } | 317 | } |
289 | 318 | ||
290 | static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) | 319 | static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode) |
291 | { | 320 | { |
292 | int res; | 321 | int res; |
293 | 322 | ||
294 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; | 323 | mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; |
295 | res = usbfs_mknod (dir, dentry, mode, 0); | 324 | res = usbfs_mknod (dir, dentry, mode, 0); |
296 | if (!res) | 325 | if (!res) |
297 | inc_nlink(dir); | 326 | inc_nlink(dir); |
298 | return res; | 327 | return res; |
299 | } | 328 | } |
300 | 329 | ||
301 | static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode) | 330 | static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode) |
302 | { | 331 | { |
303 | mode = (mode & S_IALLUGO) | S_IFREG; | 332 | mode = (mode & S_IALLUGO) | S_IFREG; |
304 | return usbfs_mknod (dir, dentry, mode, 0); | 333 | return usbfs_mknod (dir, dentry, mode, 0); |
305 | } | 334 | } |
306 | 335 | ||
307 | static inline int usbfs_positive (struct dentry *dentry) | 336 | static inline int usbfs_positive (struct dentry *dentry) |
308 | { | 337 | { |
309 | return dentry->d_inode && !d_unhashed(dentry); | 338 | return dentry->d_inode && !d_unhashed(dentry); |
310 | } | 339 | } |
311 | 340 | ||
312 | static int usbfs_empty (struct dentry *dentry) | 341 | static int usbfs_empty (struct dentry *dentry) |
313 | { | 342 | { |
314 | struct list_head *list; | 343 | struct list_head *list; |
315 | 344 | ||
316 | spin_lock(&dcache_lock); | 345 | spin_lock(&dcache_lock); |
317 | 346 | ||
318 | list_for_each(list, &dentry->d_subdirs) { | 347 | list_for_each(list, &dentry->d_subdirs) { |
319 | struct dentry *de = list_entry(list, struct dentry, d_u.d_child); | 348 | struct dentry *de = list_entry(list, struct dentry, d_u.d_child); |
320 | if (usbfs_positive(de)) { | 349 | if (usbfs_positive(de)) { |
321 | spin_unlock(&dcache_lock); | 350 | spin_unlock(&dcache_lock); |
322 | return 0; | 351 | return 0; |
323 | } | 352 | } |
324 | } | 353 | } |
325 | 354 | ||
326 | spin_unlock(&dcache_lock); | 355 | spin_unlock(&dcache_lock); |
327 | return 1; | 356 | return 1; |
328 | } | 357 | } |
329 | 358 | ||
330 | static int usbfs_unlink (struct inode *dir, struct dentry *dentry) | 359 | static int usbfs_unlink (struct inode *dir, struct dentry *dentry) |
331 | { | 360 | { |
332 | struct inode *inode = dentry->d_inode; | 361 | struct inode *inode = dentry->d_inode; |
333 | mutex_lock(&inode->i_mutex); | 362 | mutex_lock(&inode->i_mutex); |
334 | drop_nlink(dentry->d_inode); | 363 | drop_nlink(dentry->d_inode); |
335 | dput(dentry); | 364 | dput(dentry); |
336 | mutex_unlock(&inode->i_mutex); | 365 | mutex_unlock(&inode->i_mutex); |
337 | d_delete(dentry); | 366 | d_delete(dentry); |
338 | return 0; | 367 | return 0; |
339 | } | 368 | } |
340 | 369 | ||
341 | static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) | 370 | static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) |
342 | { | 371 | { |
343 | int error = -ENOTEMPTY; | 372 | int error = -ENOTEMPTY; |
344 | struct inode * inode = dentry->d_inode; | 373 | struct inode * inode = dentry->d_inode; |
345 | 374 | ||
346 | mutex_lock(&inode->i_mutex); | 375 | mutex_lock(&inode->i_mutex); |
347 | dentry_unhash(dentry); | 376 | dentry_unhash(dentry); |
348 | if (usbfs_empty(dentry)) { | 377 | if (usbfs_empty(dentry)) { |
349 | drop_nlink(dentry->d_inode); | 378 | drop_nlink(dentry->d_inode); |
350 | drop_nlink(dentry->d_inode); | 379 | drop_nlink(dentry->d_inode); |
351 | dput(dentry); | 380 | dput(dentry); |
352 | inode->i_flags |= S_DEAD; | 381 | inode->i_flags |= S_DEAD; |
353 | drop_nlink(dir); | 382 | drop_nlink(dir); |
354 | error = 0; | 383 | error = 0; |
355 | } | 384 | } |
356 | mutex_unlock(&inode->i_mutex); | 385 | mutex_unlock(&inode->i_mutex); |
357 | if (!error) | 386 | if (!error) |
358 | d_delete(dentry); | 387 | d_delete(dentry); |
359 | dput(dentry); | 388 | dput(dentry); |
360 | return error; | 389 | return error; |
361 | } | 390 | } |
362 | 391 | ||
363 | 392 | ||
364 | /* default file operations */ | 393 | /* default file operations */ |
365 | static ssize_t default_read_file (struct file *file, char __user *buf, | 394 | static ssize_t default_read_file (struct file *file, char __user *buf, |
366 | size_t count, loff_t *ppos) | 395 | size_t count, loff_t *ppos) |
367 | { | 396 | { |
368 | return 0; | 397 | return 0; |
369 | } | 398 | } |
370 | 399 | ||
371 | static ssize_t default_write_file (struct file *file, const char __user *buf, | 400 | static ssize_t default_write_file (struct file *file, const char __user *buf, |
372 | size_t count, loff_t *ppos) | 401 | size_t count, loff_t *ppos) |
373 | { | 402 | { |
374 | return count; | 403 | return count; |
375 | } | 404 | } |
376 | 405 | ||
377 | static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) | 406 | static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) |
378 | { | 407 | { |
379 | loff_t retval = -EINVAL; | 408 | loff_t retval = -EINVAL; |
380 | 409 | ||
381 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); | 410 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); |
382 | switch(orig) { | 411 | switch(orig) { |
383 | case 0: | 412 | case 0: |
384 | if (offset > 0) { | 413 | if (offset > 0) { |
385 | file->f_pos = offset; | 414 | file->f_pos = offset; |
386 | retval = file->f_pos; | 415 | retval = file->f_pos; |
387 | } | 416 | } |
388 | break; | 417 | break; |
389 | case 1: | 418 | case 1: |
390 | if ((offset + file->f_pos) > 0) { | 419 | if ((offset + file->f_pos) > 0) { |
391 | file->f_pos += offset; | 420 | file->f_pos += offset; |
392 | retval = file->f_pos; | 421 | retval = file->f_pos; |
393 | } | 422 | } |
394 | break; | 423 | break; |
395 | default: | 424 | default: |
396 | break; | 425 | break; |
397 | } | 426 | } |
398 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 427 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); |
399 | return retval; | 428 | return retval; |
400 | } | 429 | } |
401 | 430 | ||
402 | static int default_open (struct inode *inode, struct file *file) | 431 | static int default_open (struct inode *inode, struct file *file) |
403 | { | 432 | { |
404 | if (inode->i_private) | 433 | if (inode->i_private) |
405 | file->private_data = inode->i_private; | 434 | file->private_data = inode->i_private; |
406 | 435 | ||
407 | return 0; | 436 | return 0; |
408 | } | 437 | } |
409 | 438 | ||
410 | static const struct file_operations default_file_operations = { | 439 | static const struct file_operations default_file_operations = { |
411 | .read = default_read_file, | 440 | .read = default_read_file, |
412 | .write = default_write_file, | 441 | .write = default_write_file, |
413 | .open = default_open, | 442 | .open = default_open, |
414 | .llseek = default_file_lseek, | 443 | .llseek = default_file_lseek, |
415 | }; | 444 | }; |
416 | 445 | ||
417 | static struct super_operations usbfs_ops = { | 446 | static struct super_operations usbfs_ops = { |
418 | .statfs = simple_statfs, | 447 | .statfs = simple_statfs, |
419 | .drop_inode = generic_delete_inode, | 448 | .drop_inode = generic_delete_inode, |
420 | .remount_fs = remount, | 449 | .remount_fs = remount, |
450 | .show_options = usbfs_show_options, | ||
421 | }; | 451 | }; |
422 | 452 | ||
423 | static int usbfs_fill_super(struct super_block *sb, void *data, int silent) | 453 | static int usbfs_fill_super(struct super_block *sb, void *data, int silent) |
424 | { | 454 | { |
425 | struct inode *inode; | 455 | struct inode *inode; |
426 | struct dentry *root; | 456 | struct dentry *root; |
427 | 457 | ||
428 | sb->s_blocksize = PAGE_CACHE_SIZE; | 458 | sb->s_blocksize = PAGE_CACHE_SIZE; |
429 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 459 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
430 | sb->s_magic = USBDEVICE_SUPER_MAGIC; | 460 | sb->s_magic = USBDEVICE_SUPER_MAGIC; |
431 | sb->s_op = &usbfs_ops; | 461 | sb->s_op = &usbfs_ops; |
432 | sb->s_time_gran = 1; | 462 | sb->s_time_gran = 1; |
433 | inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); | 463 | inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); |
434 | 464 | ||
435 | if (!inode) { | 465 | if (!inode) { |
436 | dbg("%s: could not get inode!",__FUNCTION__); | 466 | dbg("%s: could not get inode!",__FUNCTION__); |
437 | return -ENOMEM; | 467 | return -ENOMEM; |
438 | } | 468 | } |
439 | 469 | ||
440 | root = d_alloc_root(inode); | 470 | root = d_alloc_root(inode); |
441 | if (!root) { | 471 | if (!root) { |
442 | dbg("%s: could not get root dentry!",__FUNCTION__); | 472 | dbg("%s: could not get root dentry!",__FUNCTION__); |
443 | iput(inode); | 473 | iput(inode); |
444 | return -ENOMEM; | 474 | return -ENOMEM; |
445 | } | 475 | } |
446 | sb->s_root = root; | 476 | sb->s_root = root; |
447 | return 0; | 477 | return 0; |
448 | } | 478 | } |
449 | 479 | ||
450 | /* | 480 | /* |
451 | * fs_create_by_name - create a file, given a name | 481 | * fs_create_by_name - create a file, given a name |
452 | * @name: name of file | 482 | * @name: name of file |
453 | * @mode: type of file | 483 | * @mode: type of file |
454 | * @parent: dentry of directory to create it in | 484 | * @parent: dentry of directory to create it in |
455 | * @dentry: resulting dentry of file | 485 | * @dentry: resulting dentry of file |
456 | * | 486 | * |
457 | * This function handles both regular files and directories. | 487 | * This function handles both regular files and directories. |
458 | */ | 488 | */ |
459 | static int fs_create_by_name (const char *name, mode_t mode, | 489 | static int fs_create_by_name (const char *name, mode_t mode, |
460 | struct dentry *parent, struct dentry **dentry) | 490 | struct dentry *parent, struct dentry **dentry) |
461 | { | 491 | { |
462 | int error = 0; | 492 | int error = 0; |
463 | 493 | ||
464 | /* If the parent is not specified, we create it in the root. | 494 | /* If the parent is not specified, we create it in the root. |
465 | * We need the root dentry to do this, which is in the super | 495 | * We need the root dentry to do this, which is in the super |
466 | * block. A pointer to that is in the struct vfsmount that we | 496 | * block. A pointer to that is in the struct vfsmount that we |
467 | * have around. | 497 | * have around. |
468 | */ | 498 | */ |
469 | if (!parent ) { | 499 | if (!parent ) { |
470 | if (usbfs_mount && usbfs_mount->mnt_sb) { | 500 | if (usbfs_mount && usbfs_mount->mnt_sb) { |
471 | parent = usbfs_mount->mnt_sb->s_root; | 501 | parent = usbfs_mount->mnt_sb->s_root; |
472 | } | 502 | } |
473 | } | 503 | } |
474 | 504 | ||
475 | if (!parent) { | 505 | if (!parent) { |
476 | dbg("Ah! can not find a parent!"); | 506 | dbg("Ah! can not find a parent!"); |
477 | return -EFAULT; | 507 | return -EFAULT; |
478 | } | 508 | } |
479 | 509 | ||
480 | *dentry = NULL; | 510 | *dentry = NULL; |
481 | mutex_lock(&parent->d_inode->i_mutex); | 511 | mutex_lock(&parent->d_inode->i_mutex); |
482 | *dentry = lookup_one_len(name, parent, strlen(name)); | 512 | *dentry = lookup_one_len(name, parent, strlen(name)); |
483 | if (!IS_ERR(dentry)) { | 513 | if (!IS_ERR(dentry)) { |
484 | if ((mode & S_IFMT) == S_IFDIR) | 514 | if ((mode & S_IFMT) == S_IFDIR) |
485 | error = usbfs_mkdir (parent->d_inode, *dentry, mode); | 515 | error = usbfs_mkdir (parent->d_inode, *dentry, mode); |
486 | else | 516 | else |
487 | error = usbfs_create (parent->d_inode, *dentry, mode); | 517 | error = usbfs_create (parent->d_inode, *dentry, mode); |
488 | } else | 518 | } else |
489 | error = PTR_ERR(dentry); | 519 | error = PTR_ERR(dentry); |
490 | mutex_unlock(&parent->d_inode->i_mutex); | 520 | mutex_unlock(&parent->d_inode->i_mutex); |
491 | 521 | ||
492 | return error; | 522 | return error; |
493 | } | 523 | } |
494 | 524 | ||
495 | static struct dentry *fs_create_file (const char *name, mode_t mode, | 525 | static struct dentry *fs_create_file (const char *name, mode_t mode, |
496 | struct dentry *parent, void *data, | 526 | struct dentry *parent, void *data, |
497 | const struct file_operations *fops, | 527 | const struct file_operations *fops, |
498 | uid_t uid, gid_t gid) | 528 | uid_t uid, gid_t gid) |
499 | { | 529 | { |
500 | struct dentry *dentry; | 530 | struct dentry *dentry; |
501 | int error; | 531 | int error; |
502 | 532 | ||
503 | dbg("creating file '%s'",name); | 533 | dbg("creating file '%s'",name); |
504 | 534 | ||
505 | error = fs_create_by_name (name, mode, parent, &dentry); | 535 | error = fs_create_by_name (name, mode, parent, &dentry); |
506 | if (error) { | 536 | if (error) { |
507 | dentry = NULL; | 537 | dentry = NULL; |
508 | } else { | 538 | } else { |
509 | if (dentry->d_inode) { | 539 | if (dentry->d_inode) { |
510 | if (data) | 540 | if (data) |
511 | dentry->d_inode->i_private = data; | 541 | dentry->d_inode->i_private = data; |
512 | if (fops) | 542 | if (fops) |
513 | dentry->d_inode->i_fop = fops; | 543 | dentry->d_inode->i_fop = fops; |
514 | dentry->d_inode->i_uid = uid; | 544 | dentry->d_inode->i_uid = uid; |
515 | dentry->d_inode->i_gid = gid; | 545 | dentry->d_inode->i_gid = gid; |
516 | } | 546 | } |
517 | } | 547 | } |
518 | 548 | ||
519 | return dentry; | 549 | return dentry; |
520 | } | 550 | } |
521 | 551 | ||
522 | static void fs_remove_file (struct dentry *dentry) | 552 | static void fs_remove_file (struct dentry *dentry) |
523 | { | 553 | { |
524 | struct dentry *parent = dentry->d_parent; | 554 | struct dentry *parent = dentry->d_parent; |
525 | 555 | ||
526 | if (!parent || !parent->d_inode) | 556 | if (!parent || !parent->d_inode) |
527 | return; | 557 | return; |
528 | 558 | ||
529 | mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); | 559 | mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); |
530 | if (usbfs_positive(dentry)) { | 560 | if (usbfs_positive(dentry)) { |
531 | if (dentry->d_inode) { | 561 | if (dentry->d_inode) { |
532 | if (S_ISDIR(dentry->d_inode->i_mode)) | 562 | if (S_ISDIR(dentry->d_inode->i_mode)) |
533 | usbfs_rmdir(parent->d_inode, dentry); | 563 | usbfs_rmdir(parent->d_inode, dentry); |
534 | else | 564 | else |
535 | usbfs_unlink(parent->d_inode, dentry); | 565 | usbfs_unlink(parent->d_inode, dentry); |
536 | dput(dentry); | 566 | dput(dentry); |
537 | } | 567 | } |
538 | } | 568 | } |
539 | mutex_unlock(&parent->d_inode->i_mutex); | 569 | mutex_unlock(&parent->d_inode->i_mutex); |
540 | } | 570 | } |
541 | 571 | ||
542 | /* --------------------------------------------------------------------- */ | 572 | /* --------------------------------------------------------------------- */ |
543 | 573 | ||
544 | static int usb_get_sb(struct file_system_type *fs_type, | 574 | static int usb_get_sb(struct file_system_type *fs_type, |
545 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 575 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
546 | { | 576 | { |
547 | return get_sb_single(fs_type, flags, data, usbfs_fill_super, mnt); | 577 | return get_sb_single(fs_type, flags, data, usbfs_fill_super, mnt); |
548 | } | 578 | } |
549 | 579 | ||
550 | static struct file_system_type usb_fs_type = { | 580 | static struct file_system_type usb_fs_type = { |
551 | .owner = THIS_MODULE, | 581 | .owner = THIS_MODULE, |
552 | .name = "usbfs", | 582 | .name = "usbfs", |
553 | .get_sb = usb_get_sb, | 583 | .get_sb = usb_get_sb, |
554 | .kill_sb = kill_litter_super, | 584 | .kill_sb = kill_litter_super, |
555 | }; | 585 | }; |
556 | 586 | ||
557 | /* --------------------------------------------------------------------- */ | 587 | /* --------------------------------------------------------------------- */ |
558 | 588 | ||
559 | static int create_special_files (void) | 589 | static int create_special_files (void) |
560 | { | 590 | { |
561 | struct dentry *parent; | 591 | struct dentry *parent; |
562 | int retval; | 592 | int retval; |
563 | 593 | ||
564 | /* the simple_pin_fs calls will call remount with no options | 594 | /* the simple_pin_fs calls will call remount with no options |
565 | * without this flag that would overwrite the real mount options (if any) | 595 | * without this flag that would overwrite the real mount options (if any) |
566 | */ | 596 | */ |
567 | ignore_mount = 1; | 597 | ignore_mount = 1; |
568 | 598 | ||
569 | /* create the devices special file */ | 599 | /* create the devices special file */ |
570 | retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count); | 600 | retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count); |
571 | if (retval) { | 601 | if (retval) { |
572 | err ("Unable to get usbfs mount"); | 602 | err ("Unable to get usbfs mount"); |
573 | goto exit; | 603 | goto exit; |
574 | } | 604 | } |
575 | 605 | ||
576 | ignore_mount = 0; | 606 | ignore_mount = 0; |
577 | 607 | ||
578 | parent = usbfs_mount->mnt_sb->s_root; | 608 | parent = usbfs_mount->mnt_sb->s_root; |
579 | devices_usbfs_dentry = fs_create_file ("devices", | 609 | devices_usbfs_dentry = fs_create_file ("devices", |
580 | listmode | S_IFREG, parent, | 610 | listmode | S_IFREG, parent, |
581 | NULL, &usbfs_devices_fops, | 611 | NULL, &usbfs_devices_fops, |
582 | listuid, listgid); | 612 | listuid, listgid); |
583 | if (devices_usbfs_dentry == NULL) { | 613 | if (devices_usbfs_dentry == NULL) { |
584 | err ("Unable to create devices usbfs file"); | 614 | err ("Unable to create devices usbfs file"); |
585 | retval = -ENODEV; | 615 | retval = -ENODEV; |
586 | goto error_clean_mounts; | 616 | goto error_clean_mounts; |
587 | } | 617 | } |
588 | 618 | ||
589 | goto exit; | 619 | goto exit; |
590 | 620 | ||
591 | error_clean_mounts: | 621 | error_clean_mounts: |
592 | simple_release_fs(&usbfs_mount, &usbfs_mount_count); | 622 | simple_release_fs(&usbfs_mount, &usbfs_mount_count); |
593 | exit: | 623 | exit: |
594 | return retval; | 624 | return retval; |
595 | } | 625 | } |
596 | 626 | ||
597 | static void remove_special_files (void) | 627 | static void remove_special_files (void) |
598 | { | 628 | { |
599 | if (devices_usbfs_dentry) | 629 | if (devices_usbfs_dentry) |
600 | fs_remove_file (devices_usbfs_dentry); | 630 | fs_remove_file (devices_usbfs_dentry); |
601 | devices_usbfs_dentry = NULL; | 631 | devices_usbfs_dentry = NULL; |
602 | simple_release_fs(&usbfs_mount, &usbfs_mount_count); | 632 | simple_release_fs(&usbfs_mount, &usbfs_mount_count); |
603 | } | 633 | } |
604 | 634 | ||
605 | void usbfs_update_special (void) | 635 | void usbfs_update_special (void) |
606 | { | 636 | { |
607 | struct inode *inode; | 637 | struct inode *inode; |
608 | 638 | ||
609 | if (devices_usbfs_dentry) { | 639 | if (devices_usbfs_dentry) { |
610 | inode = devices_usbfs_dentry->d_inode; | 640 | inode = devices_usbfs_dentry->d_inode; |
611 | if (inode) | 641 | if (inode) |
612 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 642 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
613 | } | 643 | } |
614 | } | 644 | } |
615 | 645 | ||
616 | static void usbfs_add_bus(struct usb_bus *bus) | 646 | static void usbfs_add_bus(struct usb_bus *bus) |
617 | { | 647 | { |
618 | struct dentry *parent; | 648 | struct dentry *parent; |
619 | char name[8]; | 649 | char name[8]; |
620 | int retval; | 650 | int retval; |
621 | 651 | ||
622 | /* create the special files if this is the first bus added */ | 652 | /* create the special files if this is the first bus added */ |
623 | if (num_buses == 0) { | 653 | if (num_buses == 0) { |
624 | retval = create_special_files(); | 654 | retval = create_special_files(); |
625 | if (retval) | 655 | if (retval) |
626 | return; | 656 | return; |
627 | } | 657 | } |
628 | ++num_buses; | 658 | ++num_buses; |
629 | 659 | ||
630 | sprintf (name, "%03d", bus->busnum); | 660 | sprintf (name, "%03d", bus->busnum); |
631 | 661 | ||
632 | parent = usbfs_mount->mnt_sb->s_root; | 662 | parent = usbfs_mount->mnt_sb->s_root; |
633 | bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, | 663 | bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, |
634 | bus, NULL, busuid, busgid); | 664 | bus, NULL, busuid, busgid); |
635 | if (bus->usbfs_dentry == NULL) { | 665 | if (bus->usbfs_dentry == NULL) { |
636 | err ("error creating usbfs bus entry"); | 666 | err ("error creating usbfs bus entry"); |
637 | return; | 667 | return; |
638 | } | 668 | } |
639 | } | 669 | } |
640 | 670 | ||
641 | static void usbfs_remove_bus(struct usb_bus *bus) | 671 | static void usbfs_remove_bus(struct usb_bus *bus) |
642 | { | 672 | { |
643 | if (bus->usbfs_dentry) { | 673 | if (bus->usbfs_dentry) { |
644 | fs_remove_file (bus->usbfs_dentry); | 674 | fs_remove_file (bus->usbfs_dentry); |
645 | bus->usbfs_dentry = NULL; | 675 | bus->usbfs_dentry = NULL; |
646 | } | 676 | } |
647 | 677 | ||
648 | --num_buses; | 678 | --num_buses; |
649 | if (num_buses <= 0) { | 679 | if (num_buses <= 0) { |
650 | remove_special_files(); | 680 | remove_special_files(); |
651 | num_buses = 0; | 681 | num_buses = 0; |
652 | } | 682 | } |
653 | } | 683 | } |
654 | 684 | ||
655 | static void usbfs_add_device(struct usb_device *dev) | 685 | static void usbfs_add_device(struct usb_device *dev) |
656 | { | 686 | { |
657 | char name[8]; | 687 | char name[8]; |
658 | int i; | 688 | int i; |
659 | int i_size; | 689 | int i_size; |
660 | 690 | ||
661 | sprintf (name, "%03d", dev->devnum); | 691 | sprintf (name, "%03d", dev->devnum); |
662 | dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, | 692 | dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, |
663 | dev->bus->usbfs_dentry, dev, | 693 | dev->bus->usbfs_dentry, dev, |
664 | &usbdev_file_operations, | 694 | &usbdev_file_operations, |
665 | devuid, devgid); | 695 | devuid, devgid); |
666 | if (dev->usbfs_dentry == NULL) { | 696 | if (dev->usbfs_dentry == NULL) { |
667 | err ("error creating usbfs device entry"); | 697 | err ("error creating usbfs device entry"); |
668 | return; | 698 | return; |
669 | } | 699 | } |
670 | 700 | ||
671 | /* Set the size of the device's file to be | 701 | /* Set the size of the device's file to be |
672 | * equal to the size of the device descriptors. */ | 702 | * equal to the size of the device descriptors. */ |
673 | i_size = sizeof (struct usb_device_descriptor); | 703 | i_size = sizeof (struct usb_device_descriptor); |
674 | for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) { | 704 | for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) { |
675 | struct usb_config_descriptor *config = | 705 | struct usb_config_descriptor *config = |
676 | (struct usb_config_descriptor *)dev->rawdescriptors[i]; | 706 | (struct usb_config_descriptor *)dev->rawdescriptors[i]; |
677 | i_size += le16_to_cpu(config->wTotalLength); | 707 | i_size += le16_to_cpu(config->wTotalLength); |
678 | } | 708 | } |
679 | if (dev->usbfs_dentry->d_inode) | 709 | if (dev->usbfs_dentry->d_inode) |
680 | dev->usbfs_dentry->d_inode->i_size = i_size; | 710 | dev->usbfs_dentry->d_inode->i_size = i_size; |
681 | } | 711 | } |
682 | 712 | ||
683 | static void usbfs_remove_device(struct usb_device *dev) | 713 | static void usbfs_remove_device(struct usb_device *dev) |
684 | { | 714 | { |
685 | struct dev_state *ds; | 715 | struct dev_state *ds; |
686 | struct siginfo sinfo; | 716 | struct siginfo sinfo; |
687 | 717 | ||
688 | if (dev->usbfs_dentry) { | 718 | if (dev->usbfs_dentry) { |
689 | fs_remove_file (dev->usbfs_dentry); | 719 | fs_remove_file (dev->usbfs_dentry); |
690 | dev->usbfs_dentry = NULL; | 720 | dev->usbfs_dentry = NULL; |
691 | } | 721 | } |
692 | while (!list_empty(&dev->filelist)) { | 722 | while (!list_empty(&dev->filelist)) { |
693 | ds = list_entry(dev->filelist.next, struct dev_state, list); | 723 | ds = list_entry(dev->filelist.next, struct dev_state, list); |
694 | wake_up_all(&ds->wait); | 724 | wake_up_all(&ds->wait); |
695 | list_del_init(&ds->list); | 725 | list_del_init(&ds->list); |
696 | if (ds->discsignr) { | 726 | if (ds->discsignr) { |
697 | sinfo.si_signo = ds->discsignr; | 727 | sinfo.si_signo = ds->discsignr; |
698 | sinfo.si_errno = EPIPE; | 728 | sinfo.si_errno = EPIPE; |
699 | sinfo.si_code = SI_ASYNCIO; | 729 | sinfo.si_code = SI_ASYNCIO; |
700 | sinfo.si_addr = ds->disccontext; | 730 | sinfo.si_addr = ds->disccontext; |
701 | kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); | 731 | kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid); |
702 | } | 732 | } |
703 | } | 733 | } |
704 | } | 734 | } |
705 | 735 | ||
706 | static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) | 736 | static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) |
707 | { | 737 | { |
708 | switch (action) { | 738 | switch (action) { |
709 | case USB_DEVICE_ADD: | 739 | case USB_DEVICE_ADD: |
710 | usbfs_add_device(dev); | 740 | usbfs_add_device(dev); |
711 | break; | 741 | break; |
712 | case USB_DEVICE_REMOVE: | 742 | case USB_DEVICE_REMOVE: |
713 | usbfs_remove_device(dev); | 743 | usbfs_remove_device(dev); |
714 | break; | 744 | break; |
715 | case USB_BUS_ADD: | 745 | case USB_BUS_ADD: |
716 | usbfs_add_bus(dev); | 746 | usbfs_add_bus(dev); |
717 | break; | 747 | break; |
718 | case USB_BUS_REMOVE: | 748 | case USB_BUS_REMOVE: |
719 | usbfs_remove_bus(dev); | 749 | usbfs_remove_bus(dev); |
720 | } | 750 | } |
721 | 751 | ||
722 | usbfs_update_special(); | 752 | usbfs_update_special(); |
723 | usbfs_conn_disc_event(); | 753 | usbfs_conn_disc_event(); |
724 | return NOTIFY_OK; | 754 | return NOTIFY_OK; |
725 | } | 755 | } |
726 | 756 | ||
727 | static struct notifier_block usbfs_nb = { | 757 | static struct notifier_block usbfs_nb = { |
728 | .notifier_call = usbfs_notify, | 758 | .notifier_call = usbfs_notify, |
729 | }; | 759 | }; |
730 | 760 | ||
731 | /* --------------------------------------------------------------------- */ | 761 | /* --------------------------------------------------------------------- */ |
732 | 762 | ||
733 | static struct proc_dir_entry *usbdir = NULL; | 763 | static struct proc_dir_entry *usbdir = NULL; |
734 | 764 | ||
735 | int __init usbfs_init(void) | 765 | int __init usbfs_init(void) |
736 | { | 766 | { |
737 | int retval; | 767 | int retval; |
738 | 768 | ||
739 | retval = register_filesystem(&usb_fs_type); | 769 | retval = register_filesystem(&usb_fs_type); |
740 | if (retval) | 770 | if (retval) |
741 | return retval; | 771 | return retval; |
742 | 772 | ||
743 | usb_register_notify(&usbfs_nb); | 773 | usb_register_notify(&usbfs_nb); |
744 | 774 | ||
745 | /* create mount point for usbfs */ | 775 | /* create mount point for usbfs */ |
746 | usbdir = proc_mkdir("usb", proc_bus); | 776 | usbdir = proc_mkdir("usb", proc_bus); |
747 | 777 | ||
748 | return 0; | 778 | return 0; |
749 | } | 779 | } |
750 | 780 | ||
751 | void usbfs_cleanup(void) | 781 | void usbfs_cleanup(void) |
752 | { | 782 | { |
753 | usb_unregister_notify(&usbfs_nb); | 783 | usb_unregister_notify(&usbfs_nb); |
754 | unregister_filesystem(&usb_fs_type); | 784 | unregister_filesystem(&usb_fs_type); |
755 | if (usbdir) | 785 | if (usbdir) |
756 | remove_proc_entry("usb", proc_bus); | 786 | remove_proc_entry("usb", proc_bus); |
757 | } | 787 | } |
758 | 788 | ||
759 | 789 |