/* * fill in a volume location record, consulting the cache and the VL server * both */ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl, struct key *key) { struct afs_cache_vlocation vldb; int ret; _enter(""); ASSERTCMP(vl->valid, ==, 0); memset(&vldb, 0, sizeof(vldb)); /* see if we have an in-cache copy (will set vl->valid if there is) */ #ifdef AFS_CACHING_SUPPORT cachefs_acquire_cookie(cell->cache, &afs_volume_cache_index_def, vlocation, &vl->cache); #endif if (vl->valid) { /* try to update a known volume in the cell VL databases by * ID as the name may have changed */ _debug("found in cache"); ret = afs_vlocation_update_record(vl, key, &vldb); } else { /* try to look up an unknown volume in the cell VL databases by * name */ ret = afs_vlocation_access_vl_by_name(vl, key, &vldb); if (ret < 0) { printk("kAFS: failed to locate '%s' in cell '%s'\n", vl->vldb.name, vl->cell->name); return ret; } } afs_vlocation_apply_update(vl, &vldb); _leave(" = 0"); return 0; }
/* * inode retrieval */ inline int afs_iget(struct super_block *sb, struct afs_fid *fid, struct inode **_inode) { struct afs_iget_data data = { .fid = *fid }; struct afs_super_info *as; struct afs_vnode *vnode; struct inode *inode; int ret; _enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique); as = sb->s_fs_info; data.volume = as->volume; inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set, &data); if (!inode) { _leave(" = -ENOMEM"); return -ENOMEM; } vnode = AFS_FS_I(inode); /* deal with an existing inode */ if (!(inode->i_state & I_NEW)) { ret = afs_vnode_fetch_status(vnode); if (ret==0) *_inode = inode; else iput(inode); _leave(" = %d", ret); return ret; } #ifdef AFS_CACHING_SUPPORT /* set up caching before reading the status, as fetch-status reads the * first page of symlinks to see if they're really mntpts */ cachefs_acquire_cookie(vnode->volume->cache, NULL, vnode, &vnode->cache); #endif /* okay... it's a new inode */ inode->i_flags |= S_NOATIME; vnode->flags |= AFS_VNODE_CHANGED; ret = afs_inode_fetch_status(inode); if (ret<0) goto bad_inode; /* success */ unlock_new_inode(inode); *_inode = inode; _leave(" = 0 [CB { v=%u x=%lu t=%u }]", vnode->cb_version, vnode->cb_timeout.timo_jif, vnode->cb_type); return 0; /* failure */ bad_inode: make_bad_inode(inode); unlock_new_inode(inode); iput(inode); _leave(" = %d [bad]", ret); return ret; } /* end afs_iget() */
/* * lookup a volume by name * - this can be one of the following: * "%[cell:]volume[.]" R/W volume * "#[cell:]volume[.]" R/O or R/W volume (rwparent=0), * or R/W (rwparent=1) volume * "%[cell:]volume.readonly" R/O volume * "#[cell:]volume.readonly" R/O volume * "%[cell:]volume.backup" Backup volume * "#[cell:]volume.backup" Backup volume * * The cell name is optional, and defaults to the current cell. * * See "The Rules of Mount Point Traversal" in Chapter 5 of the AFS SysAdmin * Guide * - Rule 1: Explicit type suffix forces access of that type or nothing * (no suffix, then use Rule 2 & 3) * - Rule 2: If parent volume is R/O, then mount R/O volume by preference, R/W * if not available * - Rule 3: If parent volume is R/W, then only mount R/W volume unless * explicitly told otherwise */ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params) { struct afs_vlocation *vlocation = NULL; struct afs_volume *volume = NULL; struct afs_server *server = NULL; char srvtmask; int ret, loop; _enter("{%*.*s,%d}", params->volnamesz, params->volnamesz, params->volname, params->rwpath); /* lookup the volume location record */ vlocation = afs_vlocation_lookup(params->cell, params->key, params->volname, params->volnamesz); if (IS_ERR(vlocation)) { ret = PTR_ERR(vlocation); vlocation = NULL; goto error; } /* make the final decision on the type we want */ ret = -ENOMEDIUM; if (params->force && !(vlocation->vldb.vidmask & (1 << params->type))) goto error; srvtmask = 0; for (loop = 0; loop < vlocation->vldb.nservers; loop++) srvtmask |= vlocation->vldb.srvtmask[loop]; if (params->force) { if (!(srvtmask & (1 << params->type))) goto error; } else if (srvtmask & AFS_VOL_VTM_RO) { params->type = AFSVL_ROVOL; } else if (srvtmask & AFS_VOL_VTM_RW) { params->type = AFSVL_RWVOL; } else { goto error; } down_write(¶ms->cell->vl_sem); /* is the volume already active? */ if (vlocation->vols[params->type]) { /* yes - re-use it */ volume = vlocation->vols[params->type]; afs_get_volume(volume); goto success; } /* create a new volume record */ _debug("creating new volume record"); ret = -ENOMEM; volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL); if (!volume) goto error_up; atomic_set(&volume->usage, 1); volume->type = params->type; volume->type_force = params->force; volume->cell = params->cell; volume->vid = vlocation->vldb.vid[params->type]; init_rwsem(&volume->server_sem); /* look up all the applicable server records */ for (loop = 0; loop < 8; loop++) { if (vlocation->vldb.srvtmask[loop] & (1 << volume->type)) { server = afs_lookup_server( volume->cell, &vlocation->vldb.servers[loop]); if (IS_ERR(server)) { ret = PTR_ERR(server); goto error_discard; } volume->servers[volume->nservers] = server; volume->nservers++; } } /* attach the cache and volume location */ #ifdef AFS_CACHING_SUPPORT cachefs_acquire_cookie(vlocation->cache, &afs_vnode_cache_index_def, volume, &volume->cache); #endif afs_get_vlocation(vlocation); volume->vlocation = vlocation; vlocation->vols[volume->type] = volume; success: _debug("kAFS selected %s volume %08x", afs_voltypes[volume->type], volume->vid); up_write(¶ms->cell->vl_sem); afs_put_vlocation(vlocation); _leave(" = %p", volume); return volume; /* clean up */ error_up: up_write(¶ms->cell->vl_sem); error: afs_put_vlocation(vlocation); _leave(" = %d", ret); return ERR_PTR(ret); error_discard: up_write(¶ms->cell->vl_sem); for (loop = volume->nservers - 1; loop >= 0; loop--) afs_put_server(volume->servers[loop]); kfree(volume); goto error; }