summaryrefslogtreecommitdiff
path: root/fs/afs/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/afs/super.c')
-rw-r--r--fs/afs/super.c142
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 @@
#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
-struct afs_mount_params {
- int rwpath;
- struct afs_cell *default_cell;
- struct afs_volume *volume;
-};
-
static void afs_i_init_once(void *foo, struct kmem_cache *cachep,
unsigned long flags);
@@ -150,8 +144,8 @@ static int want_no_value(char *const *_value, const char *option)
* - this function has been shamelessly adapted from the ext3 fs which
* shamelessly adapted it from the msdos fs
*/
-static int afs_super_parse_options(struct afs_mount_params *params,
- char *options, const char **devname)
+static int afs_parse_options(struct afs_mount_params *params,
+ char *options, const char **devname)
{
struct afs_cell *cell;
char *key, *value;
@@ -183,8 +177,8 @@ static int afs_super_parse_options(struct afs_mount_params *params,
cell = afs_cell_lookup(value, strlen(value));
if (IS_ERR(cell))
return PTR_ERR(cell);
- afs_put_cell(params->default_cell);
- params->default_cell = cell;
+ afs_put_cell(params->cell);
+ params->cell = cell;
} else {
printk("kAFS: Unknown mount option: '%s'\n", key);
ret = -EINVAL;
@@ -199,6 +193,99 @@ error:
}
/*
+ * parse a device name to get cell name, volume name, volume type and R/W
+ * selector
+ * - this can be one of the following:
+ * "%[cell:]volume[.]" R/W volume
+ * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0),
+ * or R/W (rwpath=1) volume
+ * "%[cell:]volume.readonly" R/O volume
+ * "#[cell:]volume.readonly" R/O volume
+ * "%[cell:]volume.backup" Backup volume
+ * "#[cell:]volume.backup" Backup volume
+ */
+static int afs_parse_device_name(struct afs_mount_params *params,
+ const char *name)
+{
+ struct afs_cell *cell;
+ const char *cellname, *suffix;
+ int cellnamesz;
+
+ _enter(",%s", name);
+
+ if (!name) {
+ printk(KERN_ERR "kAFS: no volume name specified\n");
+ return -EINVAL;
+ }
+
+ if ((name[0] != '%' && name[0] != '#') || !name[1]) {
+ printk(KERN_ERR "kAFS: unparsable volume name\n");
+ return -EINVAL;
+ }
+
+ /* determine the type of volume we're looking for */
+ params->type = AFSVL_ROVOL;
+ params->force = false;
+ if (params->rwpath || name[0] == '%') {
+ params->type = AFSVL_RWVOL;
+ params->force = true;
+ }
+ name++;
+
+ /* split the cell name out if there is one */
+ params->volname = strchr(name, ':');
+ if (params->volname) {
+ cellname = name;
+ cellnamesz = params->volname - name;
+ params->volname++;
+ } else {
+ params->volname = name;
+ cellname = NULL;
+ cellnamesz = 0;
+ }
+
+ /* the volume type is further affected by a possible suffix */
+ suffix = strrchr(params->volname, '.');
+ if (suffix) {
+ if (strcmp(suffix, ".readonly") == 0) {
+ params->type = AFSVL_ROVOL;
+ params->force = true;
+ } else if (strcmp(suffix, ".backup") == 0) {
+ params->type = AFSVL_BACKVOL;
+ params->force = true;
+ } else if (suffix[1] == 0) {
+ } else {
+ suffix = NULL;
+ }
+ }
+
+ params->volnamesz = suffix ?
+ suffix - params->volname : strlen(params->volname);
+
+ _debug("cell %*.*s [%p]",
+ cellnamesz, cellnamesz, cellname ?: "", params->cell);
+
+ /* lookup the cell record */
+ if (cellname || !params->cell) {
+ cell = afs_cell_lookup(cellname, cellnamesz);
+ if (IS_ERR(cell)) {
+ printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n",
+ cellname ?: "");
+ return PTR_ERR(cell);
+ }
+ afs_put_cell(params->cell);
+ params->cell = cell;
+ }
+
+ _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
+ params->cell->name, params->cell,
+ params->volnamesz, params->volnamesz, params->volname,
+ suffix ?: "-", params->type, params->force ? " FORCE" : "");
+
+ return 0;
+}
+
+/*
* check a superblock to see if it's the one we're looking for
*/
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)
fid.vid = as->volume->vid;
fid.vnode = 1;
fid.unique = 1;
- inode = afs_iget(sb, &fid);
+ inode = afs_iget(sb, params->key, &fid);
if (IS_ERR(inode))
goto error_inode;
@@ -285,31 +372,40 @@ static int afs_get_sb(struct file_system_type *fs_type,
struct afs_mount_params params;
struct super_block *sb;
struct afs_volume *vol;
+ struct key *key;
int ret;
_enter(",,%s,%p", dev_name, options);
memset(&params, 0, sizeof(params));
- /* parse the options */
+ /* parse the options and device name */
if (options) {
- ret = afs_super_parse_options(&params, options, &dev_name);
+ ret = afs_parse_options(&params, options, &dev_name);
if (ret < 0)
goto error;
- if (!dev_name) {
- printk("kAFS: no volume name specified\n");
- ret = -EINVAL;
- goto error;
- }
}
+
+ ret = afs_parse_device_name(&params, dev_name);
+ if (ret < 0)
+ goto error;
+
+ /* try and do the mount securely */
+ key = afs_request_key(params.cell);
+ if (IS_ERR(key)) {
+ _leave(" = %ld [key]", PTR_ERR(key));
+ ret = PTR_ERR(key);
+ goto error;
+ }
+ params.key = key;
+
/* parse the device name */
- vol = afs_volume_lookup(dev_name, params.default_cell, params.rwpath);
+ vol = afs_volume_lookup(&params);
if (IS_ERR(vol)) {
ret = PTR_ERR(vol);
goto error;
}
-
params.volume = vol;
/* allocate a deviceless superblock */
@@ -337,13 +433,14 @@ static int afs_get_sb(struct file_system_type *fs_type,
simple_set_mnt(mnt, sb);
afs_put_volume(params.volume);
- afs_put_cell(params.default_cell);
+ afs_put_cell(params.cell);
_leave(" = 0 [%p]", sb);
return 0;
error:
afs_put_volume(params.volume);
- afs_put_cell(params.default_cell);
+ afs_put_cell(params.cell);
+ key_put(params.key);
_leave(" = %d", ret);
return ret;
}
@@ -375,6 +472,7 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
memset(vnode, 0, sizeof(*vnode));
inode_init_once(&vnode->vfs_inode);
init_waitqueue_head(&vnode->update_waitq);
+ mutex_init(&vnode->permits_lock);
spin_lock_init(&vnode->lock);
INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
mutex_init(&vnode->cb_broken_lock);