diff options
Diffstat (limited to 'fs/afs/super.c')
-rw-r--r-- | fs/afs/super.c | 142 |
1 files changed, 120 insertions, 22 deletions
diff --git a/fs/afs/super.c b/fs/afs/super.c index 77e68759788f..497350a5463b 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -24,12 +24,6 @@ | |||
24 | 24 | ||
25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ | 25 | #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ |
26 | 26 | ||
27 | struct afs_mount_params { | ||
28 | int rwpath; | ||
29 | struct afs_cell *default_cell; | ||
30 | struct afs_volume *volume; | ||
31 | }; | ||
32 | |||
33 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, | 27 | static void afs_i_init_once(void *foo, struct kmem_cache *cachep, |
34 | unsigned long flags); | 28 | unsigned long flags); |
35 | 29 | ||
@@ -150,8 +144,8 @@ static int want_no_value(char *const *_value, const char *option) | |||
150 | * - this function has been shamelessly adapted from the ext3 fs which | 144 | * - this function has been shamelessly adapted from the ext3 fs which |
151 | * shamelessly adapted it from the msdos fs | 145 | * shamelessly adapted it from the msdos fs |
152 | */ | 146 | */ |
153 | static int afs_super_parse_options(struct afs_mount_params *params, | 147 | static int afs_parse_options(struct afs_mount_params *params, |
154 | char *options, const char **devname) | 148 | char *options, const char **devname) |
155 | { | 149 | { |
156 | struct afs_cell *cell; | 150 | struct afs_cell *cell; |
157 | char *key, *value; | 151 | char *key, *value; |
@@ -183,8 +177,8 @@ static int afs_super_parse_options(struct afs_mount_params *params, | |||
183 | cell = afs_cell_lookup(value, strlen(value)); | 177 | cell = afs_cell_lookup(value, strlen(value)); |
184 | if (IS_ERR(cell)) | 178 | if (IS_ERR(cell)) |
185 | return PTR_ERR(cell); | 179 | return PTR_ERR(cell); |
186 | afs_put_cell(params->default_cell); | 180 | afs_put_cell(params->cell); |
187 | params->default_cell = cell; | 181 | params->cell = cell; |
188 | } else { | 182 | } else { |
189 | printk("kAFS: Unknown mount option: '%s'\n", key); | 183 | printk("kAFS: Unknown mount option: '%s'\n", key); |
190 | ret = -EINVAL; | 184 | ret = -EINVAL; |
@@ -199,6 +193,99 @@ error: | |||
199 | } | 193 | } |
200 | 194 | ||
201 | /* | 195 | /* |
196 | * parse a device name to get cell name, volume name, volume type and R/W | ||
197 | * selector | ||
198 | * - this can be one of the following: | ||
199 | * "%[cell:]volume[.]" R/W volume | ||
200 | * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0), | ||
201 | * or R/W (rwpath=1) volume | ||
202 | * "%[cell:]volume.readonly" R/O volume | ||
203 | * "#[cell:]volume.readonly" R/O volume | ||
204 | * "%[cell:]volume.backup" Backup volume | ||
205 | * "#[cell:]volume.backup" Backup volume | ||
206 | */ | ||
207 | static int afs_parse_device_name(struct afs_mount_params *params, | ||
208 | const char *name) | ||
209 | { | ||
210 | struct afs_cell *cell; | ||
211 | const char *cellname, *suffix; | ||
212 | int cellnamesz; | ||
213 | |||
214 | _enter(",%s", name); | ||
215 | |||
216 | if (!name) { | ||
217 | printk(KERN_ERR "kAFS: no volume name specified\n"); | ||
218 | return -EINVAL; | ||
219 | } | ||
220 | |||
221 | if ((name[0] != '%' && name[0] != '#') || !name[1]) { | ||
222 | printk(KERN_ERR "kAFS: unparsable volume name\n"); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | /* determine the type of volume we're looking for */ | ||
227 | params->type = AFSVL_ROVOL; | ||
228 | params->force = false; | ||
229 | if (params->rwpath || name[0] == '%') { | ||
230 | params->type = AFSVL_RWVOL; | ||
231 | params->force = true; | ||
232 | } | ||
233 | name++; | ||
234 | |||
235 | /* split the cell name out if there is one */ | ||
236 | params->volname = strchr(name, ':'); | ||
237 | if (params->volname) { | ||
238 | cellname = name; | ||
239 | cellnamesz = params->volname - name; | ||
240 | params->volname++; | ||
241 | } else { | ||
242 | params->volname = name; | ||
243 | cellname = NULL; | ||
244 | cellnamesz = 0; | ||
245 | } | ||
246 | |||
247 | /* the volume type is further affected by a possible suffix */ | ||
248 | suffix = strrchr(params->volname, '.'); | ||
249 | if (suffix) { | ||
250 | if (strcmp(suffix, ".readonly") == 0) { | ||
251 | params->type = AFSVL_ROVOL; | ||
252 | params->force = true; | ||
253 | } else if (strcmp(suffix, ".backup") == 0) { | ||
254 | params->type = AFSVL_BACKVOL; | ||
255 | params->force = true; | ||
256 | } else if (suffix[1] == 0) { | ||
257 | } else { | ||
258 | suffix = NULL; | ||
259 | } | ||
260 | } | ||
261 | |||
262 | params->volnamesz = suffix ? | ||
263 | suffix - params->volname : strlen(params->volname); | ||
264 | |||
265 | _debug("cell %*.*s [%p]", | ||
266 | cellnamesz, cellnamesz, cellname ?: "", params->cell); | ||
267 | |||
268 | /* lookup the cell record */ | ||
269 | if (cellname || !params->cell) { | ||
270 | cell = afs_cell_lookup(cellname, cellnamesz); | ||
271 | if (IS_ERR(cell)) { | ||
272 | printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", | ||
273 | cellname ?: ""); | ||
274 | return PTR_ERR(cell); | ||
275 | } | ||
276 | afs_put_cell(params->cell); | ||
277 | params->cell = cell; | ||
278 | } | ||
279 | |||
280 | _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s", | ||
281 | params->cell->name, params->cell, | ||
282 | params->volnamesz, params->volnamesz, params->volname, | ||
283 | suffix ?: "-", params->type, params->force ? " FORCE" : ""); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | /* | ||
202 | * check a superblock to see if it's the one we're looking for | 289 | * check a superblock to see if it's the one we're looking for |
203 | */ | 290 | */ |
204 | static int afs_test_super(struct super_block *sb, void *data) | 291 | static int afs_test_super(struct super_block *sb, void *data) |
@@ -244,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
244 | fid.vid = as->volume->vid; | 331 | fid.vid = as->volume->vid; |
245 | fid.vnode = 1; | 332 | fid.vnode = 1; |
246 | fid.unique = 1; | 333 | fid.unique = 1; |
247 | inode = afs_iget(sb, &fid); | 334 | inode = afs_iget(sb, params->key, &fid); |
248 | if (IS_ERR(inode)) | 335 | if (IS_ERR(inode)) |
249 | goto error_inode; | 336 | goto error_inode; |
250 | 337 | ||
@@ -285,31 +372,40 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
285 | struct afs_mount_params params; | 372 | struct afs_mount_params params; |
286 | struct super_block *sb; | 373 | struct super_block *sb; |
287 | struct afs_volume *vol; | 374 | struct afs_volume *vol; |
375 | struct key *key; | ||
288 | int ret; | 376 | int ret; |
289 | 377 | ||
290 | _enter(",,%s,%p", dev_name, options); | 378 | _enter(",,%s,%p", dev_name, options); |
291 | 379 | ||
292 | memset(¶ms, 0, sizeof(params)); | 380 | memset(¶ms, 0, sizeof(params)); |
293 | 381 | ||
294 | /* parse the options */ | 382 | /* parse the options and device name */ |
295 | if (options) { | 383 | if (options) { |
296 | ret = afs_super_parse_options(¶ms, options, &dev_name); | 384 | ret = afs_parse_options(¶ms, options, &dev_name); |
297 | if (ret < 0) | 385 | if (ret < 0) |
298 | goto error; | 386 | goto error; |
299 | if (!dev_name) { | ||
300 | printk("kAFS: no volume name specified\n"); | ||
301 | ret = -EINVAL; | ||
302 | goto error; | ||
303 | } | ||
304 | } | 387 | } |
305 | 388 | ||
389 | |||
390 | ret = afs_parse_device_name(¶ms, dev_name); | ||
391 | if (ret < 0) | ||
392 | goto error; | ||
393 | |||
394 | /* try and do the mount securely */ | ||
395 | key = afs_request_key(params.cell); | ||
396 | if (IS_ERR(key)) { | ||
397 | _leave(" = %ld [key]", PTR_ERR(key)); | ||
398 | ret = PTR_ERR(key); | ||
399 | goto error; | ||
400 | } | ||
401 | params.key = key; | ||
402 | |||
306 | /* parse the device name */ | 403 | /* parse the device name */ |
307 | vol = afs_volume_lookup(dev_name, params.default_cell, params.rwpath); | 404 | vol = afs_volume_lookup(¶ms); |
308 | if (IS_ERR(vol)) { | 405 | if (IS_ERR(vol)) { |
309 | ret = PTR_ERR(vol); | 406 | ret = PTR_ERR(vol); |
310 | goto error; | 407 | goto error; |
311 | } | 408 | } |
312 | |||
313 | params.volume = vol; | 409 | params.volume = vol; |
314 | 410 | ||
315 | /* allocate a deviceless superblock */ | 411 | /* allocate a deviceless superblock */ |
@@ -337,13 +433,14 @@ static int afs_get_sb(struct file_system_type *fs_type, | |||
337 | 433 | ||
338 | simple_set_mnt(mnt, sb); | 434 | simple_set_mnt(mnt, sb); |
339 | afs_put_volume(params.volume); | 435 | afs_put_volume(params.volume); |
340 | afs_put_cell(params.default_cell); | 436 | afs_put_cell(params.cell); |
341 | _leave(" = 0 [%p]", sb); | 437 | _leave(" = 0 [%p]", sb); |
342 | return 0; | 438 | return 0; |
343 | 439 | ||
344 | error: | 440 | error: |
345 | afs_put_volume(params.volume); | 441 | afs_put_volume(params.volume); |
346 | afs_put_cell(params.default_cell); | 442 | afs_put_cell(params.cell); |
443 | key_put(params.key); | ||
347 | _leave(" = %d", ret); | 444 | _leave(" = %d", ret); |
348 | return ret; | 445 | return ret; |
349 | } | 446 | } |
@@ -375,6 +472,7 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, | |||
375 | memset(vnode, 0, sizeof(*vnode)); | 472 | memset(vnode, 0, sizeof(*vnode)); |
376 | inode_init_once(&vnode->vfs_inode); | 473 | inode_init_once(&vnode->vfs_inode); |
377 | init_waitqueue_head(&vnode->update_waitq); | 474 | init_waitqueue_head(&vnode->update_waitq); |
475 | mutex_init(&vnode->permits_lock); | ||
378 | spin_lock_init(&vnode->lock); | 476 | spin_lock_init(&vnode->lock); |
379 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); | 477 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); |
380 | mutex_init(&vnode->cb_broken_lock); | 478 | mutex_init(&vnode->cb_broken_lock); |