/** * create and write a volume disk header to disk. * * @param[in] hdr volume disk header * @param[in] dp disk partition object * * @return operation status * @retval 0 success * @retval EEXIST volume header already exists * @retval EIO failed to write volume header * * @internal */ afs_int32 VCreateVolumeDiskHeader(VolumeDiskHeader_t * hdr, struct DiskPartition64 * dp) { afs_int32 code = 0; #ifdef AFS_DEMAND_ATTACH_FS SYNC_response res; #endif /* AFS_DEMAND_ATTACH_FS */ code = _VWriteVolumeDiskHeader(hdr, dp, O_CREAT | O_EXCL); if (code) { goto done; } #ifdef AFS_DEMAND_ATTACH_FS memset(&res, 0, sizeof(res)); code = FSYNC_VGCAdd(dp->name, hdr->parent, hdr->id, FSYNC_WHATEVER, &res); if (code) { Log("VCreateVolumeDiskHeader: FSYNC_VGCAdd(%s, %lu, %lu) failed " "with code %ld reason %ld\n", dp->name, afs_printable_uint32_lu(hdr->parent), afs_printable_uint32_lu(hdr->id), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); } #endif /* AFS_DEMAND_ATTACH_FS */ done: return code; }
/** * read an existing volume disk header. * * @param[in] volid volume id * @param[in] dp disk partition object * @param[out] hdr volume disk header or NULL * * @note if hdr is NULL, this is essentially an existence test for the vol * header * * @return operation status * @retval 0 success * @retval -1 volume header doesn't exist * @retval EIO failed to read volume header * * @internal */ afs_int32 VReadVolumeDiskHeader(VolumeId volid, struct DiskPartition64 * dp, VolumeDiskHeader_t * hdr) { afs_int32 code = 0; int fd; char path[MAXPATHLEN]; snprintf(path, sizeof(path), "%s" OS_DIRSEP VFORMAT, VPartitionPath(dp), afs_printable_uint32_lu(volid)); fd = open(path, O_RDONLY); if (fd < 0) { Log("VReadVolumeDiskHeader: Couldn't open header for volume %lu (errno %d).\n", afs_printable_uint32_lu(volid), errno); code = -1; } else if (hdr && read(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) { Log("VReadVolumeDiskHeader: Couldn't read header for volume %lu.\n", afs_printable_uint32_lu(volid)); code = EIO; } if (fd >= 0) { close(fd); } return code; }
int afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s) { struct afscp_volume *v; struct afscp_server *server; struct AFSCallBack cb; struct AFSVolSync vs; struct AFSFid tf = fid->fid; struct afscp_statent *stored, key; void *cached; int code, i, j; time_t now; v = afscp_VolumeById(fid->cell, fid->fid.Volume); if (v == NULL) { return -1; } memset(&key, 0, sizeof(key)); memcpy(&key.me, fid, sizeof(*fid)); cached = tfind(&key, &v->statcache, statcompare); if (cached != NULL) { stored = *(struct afscp_statent **)cached; pthread_mutex_lock(&(stored->mtx)); memmove(s, &stored->status, sizeof(*s)); afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n", fid->cell->id, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique)); if (stored->nwaiters) pthread_cond_broadcast(&(stored->cv)); pthread_mutex_unlock(&(stored->mtx)); return 0; } code = ENOENT; for (i = 0; i < v->nservers; i++) { server = afscp_ServerByIndex(v->servers[i]); if (server && server->naddrs > 0) { for (j = 0; j < server->naddrs; j++) { time(&now); code = RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs); if (code == 0) { afscp_AddCallBack(server, &fid->fid, s, &cb, now); /* calls _StatStuff */ afs_dprintf(("Stat %d.%lu.%lu.%lu" " ok: type %ld size %ld\n", fid->cell->id, afs_printable_uint32_lu(fid->fid.Volume), afs_printable_uint32_lu(fid->fid.Vnode), afs_printable_uint32_lu(fid->fid.Unique), afs_printable_int32_ld(s->FileType), afs_printable_int32_ld(s->Length))); return 0; } } } } afscp_errno = code; return -1; }
/** * destroy a volume disk header. * * @param[in] dp disk partition object * @param[in] volid volume id * @param[in] parent parent's volume id, 0 if unknown * * @return operation status * @retval 0 success * * @note if parent is 0, the parent volume ID will be looked up from the * fileserver * * @note for non-DAFS, parent is currently ignored */ afs_int32 VDestroyVolumeDiskHeader(struct DiskPartition64 * dp, VolumeId volid, VolumeId parent) { afs_int32 code = 0; char path[MAXPATHLEN]; #ifdef AFS_DEMAND_ATTACH_FS SYNC_response res; #endif /* AFS_DEMAND_ATTACH_FS */ (void)afs_snprintf(path, sizeof(path), "%s/" VFORMAT, VPartitionPath(dp), afs_printable_uint32_lu(volid)); code = unlink(path); if (code) { Log("VDestroyVolumeDiskHeader: Couldn't unlink disk header, error = %d\n", errno); goto done; } #ifdef AFS_DEMAND_ATTACH_FS memset(&res, 0, sizeof(res)); if (!parent) { FSSYNC_VGQry_response_t q_res; code = FSYNC_VGCQuery(dp->name, volid, &q_res, &res); if (code) { Log("VDestroyVolumeDiskHeader: FSYNC_VGCQuery(%s, %lu) failed " "with code %ld, reason %ld\n", dp->name, afs_printable_uint32_lu(volid), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); goto done; } parent = q_res.rw; } code = FSYNC_VGCDel(dp->name, parent, volid, FSYNC_WHATEVER, &res); if (code) { Log("VDestroyVolumeDiskHeader: FSYNC_VGCDel(%s, %lu, %lu) failed " "with code %ld reason %ld\n", dp->name, afs_printable_uint32_lu(parent), afs_printable_uint32_lu(volid), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); } #endif /* AFS_DEMAND_ATTACH_FS */ done: return code; }
/** * add an entry to the hash table. * * @param[in] dp disk partition object * @param[in] volid volume id * @param[in] ent volume group object * @param[out] hash_out address in which to store pointer to hash entry * * @pre VOL_LOCK held * * @return operation status * @retval 0 success * @retval EEXIST hash entry for volid already exists, and it points to * a different VG entry * * @internal */ static int _VVGC_hash_entry_add(struct DiskPartition64 * dp, VolumeId volid, VVGCache_entry_t * ent, VVGCache_hash_entry_t ** hash_out) { int code = 0; VVGCache_hash_entry_t * hent; int hash = VVGC_HASH(volid); VVGCache_entry_t *nent; code = _VVGC_lookup(dp, volid, &nent, hash_out); if (!code) { if (ent != nent) { ViceLog(0, ("_VVGC_hash_entry_add: tried to add a duplicate " " nonmatching entry for vol %lu: original " "(%"AFS_PTR_FMT",%lu) new (%"AFS_PTR_FMT",%lu)\n", afs_printable_uint32_lu(volid), nent, afs_printable_uint32_lu(nent->rw), ent, afs_printable_uint32_lu(ent->rw))); return EEXIST; } ViceLog(1, ("_VVGC_hash_entry_add: tried to add duplicate " "hash entry for vol %lu, VG %lu", afs_printable_uint32_lu(volid), afs_printable_uint32_lu(ent->rw))); /* accept attempts to add matching duplicate entries; just * pretend we added it */ return 0; } code = _VVGC_hash_entry_alloc(&hent); if (code) { goto done; } hent->entry = ent; hent->dp = dp; hent->volid = volid; queue_Append(&VVGCache_hash_table.hash_buckets[hash], hent); done: if (hash_out) { *hash_out = hent; } return code; }
/** * flush all cache entries for a given disk partition. * * @param[in] part disk partition object * * @pre VOL_LOCK held * * @return operation status * @retval 0 success * * @internal */ int _VVGC_flush_part_r(struct DiskPartition64 * part) { int code = 0, res; int i; VVGCache_hash_entry_t * ent, * nent; for (i = 0; i < VolumeHashTable.Size; i++) { for (queue_Scan(&VVGCache_hash_table.hash_buckets[i], ent, nent, VVGCache_hash_entry)) { if (ent->dp == part) { VolumeId volid = ent->volid; res = _VVGC_hash_entry_del(ent); if (res) { ViceLog(0, ("_VVGC_flush_part_r: error %d deleting hash entry for %lu\n", res, afs_printable_uint32_lu(volid))); code = res; } } } } return code; }
/** * write an existing volume disk header. * * @param[in] hdr volume disk header * @param[in] dp disk partition object * @param[in] cr assert if O_CREAT | O_EXCL should be passed to open() * * @return operation status * @retval 0 success * @retval -1 volume header doesn't exist * @retval EIO failed to write volume header * * @internal */ static afs_int32 _VWriteVolumeDiskHeader(VolumeDiskHeader_t * hdr, struct DiskPartition64 * dp, int flags) { afs_int32 code = 0; int fd; char path[MAXPATHLEN]; #ifdef AFS_DEMAND_ATTACH_FS /* prevent racing with VGC scanners reading the vol header while we are * writing it */ code = VPartHeaderLock(dp, READ_LOCK); if (code) { return EIO; } #endif /* AFS_DEMAND_ATTACH_FS */ flags |= O_RDWR; (void)afs_snprintf(path, sizeof(path), "%s/" VFORMAT, VPartitionPath(dp), afs_printable_uint32_lu(hdr->id)); fd = open(path, flags, 0644); if (fd < 0) { code = errno; Log("_VWriteVolumeDiskHeader: Couldn't open header for volume %lu, " "error = %d\n", afs_printable_uint32_lu(hdr->id), errno); } else if (write(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) { Log("_VWriteVolumeDiskHeader: Couldn't write header for volume %lu, " "error = %d\n", afs_printable_uint32_lu(hdr->id), errno); code = EIO; } if (fd >= 0) { if (close(fd) != 0) { Log("_VWriteVolumeDiskHeader: Error closing header for volume " "%lu, errno %d\n", afs_printable_uint32_lu(hdr->id), errno); } } #ifdef AFS_DEMAND_ATTACH_FS VPartHeaderUnlock(dp, READ_LOCK); #endif /* AFS_DEMAND_ATTACH_FS */ return code; }
static int VolOpQuery(struct cmd_syndesc * as, void * rock) { struct fssync_state state; SYNC_PROTO_BUF_DECL(res_buf); SYNC_response res; FSSYNC_VolOp_info vop; res.hdr.response_len = sizeof(res.hdr); res.payload.buf = res_buf; res.payload.len = SYNC_PROTO_MAX_LEN; common_prolog(as, &state); common_volop_prolog(as, &state); do_volop(&state, FSYNC_VOL_QUERY_VOP, &res); if (!(res.hdr.flags & SYNC_FLAG_DAFS_EXTENSIONS)) { printf("*** file server not compiled with demand attach extensions.\n"); printf("*** pending volume operation metadata not available.\n"); } if (res.hdr.response == SYNC_OK) { memcpy(&vop, res.payload.buf, sizeof(FSSYNC_VolOp_info)); printf("pending_vol_op = {\n"); printf("\tcom = {\n"); printf("\t\tproto_version = %u\n", vop.com.proto_version); printf("\t\tpkt_seq = %u\n", vop.com.pkt_seq); printf("\t\tcom_seq = %u\n", vop.com.com_seq); printf("\t\tprogramType = %d (%s)\n", vop.com.programType, VPTypeToString(vop.com.programType)); printf("\t\tpid = %d\n", vop.com.pid); printf("\t\ttid = %d\n", vop.com.tid); printf("\t\tcommand = %d (%s)\n", vop.com.command, FSYNC_com2string(vop.com.command)); printf("\t\treason = %d (%s)\n", vop.com.reason, FSYNC_reason2string(vop.com.reason)); printf("\t\tcommand_len = %u\n", vop.com.command_len); printf("\t\tflags = 0x%lux\n", afs_printable_uint32_lu(vop.com.flags)); printf("\t}\n"); printf("\tvop = {\n"); printf("\t\tvolume = %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(vop.vop.volume)); if (strnlen(vop.vop.partName, sizeof(vop.vop.partName)) < sizeof(vop.vop.partName)) { printf("\t\tpartName = '%s'\n", vop.vop.partName); } else { printf("\t\tpartName = (illegal string)\n"); } printf("\t}\n"); printf("}\n"); } return 0; }
/** * put back a reference to an entry. * * @param[in] dp disk partition object * @param[in] entry cache entry * * @pre VOL_LOCK held * * @warning do not attempt to deref pointer after calling this interface * * @return operation status * @retval 0 success * * @note dp is needed to lookup the RW hash entry to unlink, if we are * putting back the final reference and freeing * * @internal */ static int _VVGC_entry_put(struct DiskPartition64 * dp, VVGCache_entry_t * entry) { int code = 0; osi_Assert(entry->refcnt > 0); if (--entry->refcnt == 0) { VVGCache_entry_t *nentry; VVGCache_hash_entry_t *hentry; /* first, try to delete the RW id hash entry pointing to this * entry */ code = _VVGC_lookup(dp, entry->rw, &nentry, &hentry); if (!code) { if (nentry != entry) { /* looking up the rw of this entry points to a different * entry; should not happen */ ViceLog(0, ("VVGC_entry_put: error: entry lookup for entry %lu " "found different entry than was passed", afs_printable_uint32_lu(entry->rw))); code = -1; } else { code = _VVGC_hash_entry_unlink(hentry); hentry = NULL; } } else if (code == ENOENT) { /* ignore ENOENT; this shouldn't happen, since the RW hash * entry should always exist if the entry does... but we * were going to delete it anyway, so try to continue */ ViceLog(0, ("VVGC_entry_put: warning: tried to unlink entry for " "vol %lu, but RW hash entry doesn't exist; continuing " "anyway...\n", afs_printable_uint32_lu(entry->rw))); code = 0; } /* now, just free the entry itself */ if (!code) { code = _VVGC_entry_free(entry); } } return code; }
/** * lock an offset in a file descriptor. * * @param[in] fd file descriptor to lock * @param[in] offset offset in file to lock * @param[in] locktype READ_LOCK or WRITE_LOCK * @param[in] nonblock 1 to fail immediately, 0 to wait to acquire lock * * @return operation status * @retval 0 success * @retval EBUSY someone else is holding a conflicting lock and nonblock=1 was * specified * @retval EIO error acquiring file lock */ static_inline int _VLockFd(FD_t fd, afs_uint32 offset, int locktype, int nonblock) { int l_type = F_WRLCK; int cmd = AFS_SETLKW; struct afs_st_flock sf; if (locktype == READ_LOCK) { l_type = F_RDLCK; } if (nonblock) { cmd = AFS_SETLK; } sf.l_start = offset; sf.l_len = 1; sf.l_type = l_type; sf.l_whence = SEEK_SET; if (fcntl(fd, cmd, &sf)) { if (nonblock && (errno == EACCES || errno == EAGAIN)) { /* We asked for a nonblocking lock, and it was already locked */ sf.l_pid = 0; if (fcntl(fd, F_GETLK, &sf) != 0 || sf.l_pid == 0) { Log("_VLockFd: fcntl failed with error %d when trying to " "query the conflicting lock for fd %d (locktype=%d, " "offset=%lu)\n", errno, fd, locktype, afs_printable_uint32_lu(offset)); } else { Log("_VLockFd: conflicting lock held on fd %d, offset %lu by " "pid %ld (locktype=%d)\n", fd, afs_printable_uint32_lu(offset), (long int)sf.l_pid, locktype); } return EBUSY; } Log("_VLockFd: fcntl failed with error %d when trying to lock " "fd %d (locktype=%d, offset=%lu)\n", errno, fd, locktype, afs_printable_uint32_lu(offset)); return EIO; } return 0; }
/** * add a volid to the entry's child list. * * @param[in] ent volume group object * @param[in] volid volume id * * @return operation status * @retval 0 success * @retval -1 child table is full * * @internal */ static int _VVGC_entry_cl_add(VVGCache_entry_t * ent, VolumeId volid) { int code = 0, i; int empty_idx = -1; /* search table to avoid duplicates */ for (i = 0; i < VOL_VG_MAX_VOLS; i++) { if (ent->children[i] == volid) { ViceLog(1, ("VVGC_entry_cl_add: tried to add duplicate vol " "%lu to VG %lu\n", afs_printable_uint32_lu(volid), afs_printable_uint32_lu(ent->rw))); goto done; } if (empty_idx == -1 && !ent->children[i]) { empty_idx = i; /* don't break; make sure we go through all children so we don't * add a duplicate entry */ } } /* verify table isn't full */ if (empty_idx == -1) { code = -1; ViceLog(0, ("VVGC_entry_cl_add: tried to add vol %lu to VG %lu, but VG " "is full\n", afs_printable_uint32_lu(volid), afs_printable_uint32_lu(ent->rw))); goto done; } /* add entry */ ent->children[empty_idx] = volid; /* inc refcount */ code = _VVGC_entry_get(ent); done: return code; }
/** * delete an entry from the volume group cache. * * @param[in] dp disk partition object * @param[in] parent parent volume id * @param[in] child child volume id * * @pre VOL_LOCK held * * @internal * * @return operation status * @retval 0 success */ int _VVGC_entry_purge_r(struct DiskPartition64 * dp, VolumeId parent, VolumeId child) { int code = 0, res; VVGCache_entry_t * parent_ent, * child_ent; VVGCache_hash_entry_t * child_hent; /* check mappings for each volid */ res = _VVGC_lookup(dp, parent, &parent_ent, NULL); if (res) { code = res; goto done; } res = _VVGC_lookup(dp, child, &child_ent, &child_hent); if (res) { code = res; goto done; } /* if the mappings don't match, we have a serious error */ if (parent_ent != child_ent) { ViceLog(0, ("VVGCache_entry_del: trying to delete vol %lu from VG %lu, " "but vol %lu points to VGC entry %"AFS_PTR_FMT" and VG %lu " "points to VGC entry %"AFS_PTR_FMT"\n", afs_printable_uint32_lu(child), afs_printable_uint32_lu(parent), afs_printable_uint32_lu(child), child_ent, afs_printable_uint32_lu(parent), parent_ent)); code = -1; goto done; } code = _VVGC_hash_entry_del(child_hent); done: return code; }
static int handleit(struct cmd_syndesc *as, void *arock) { struct cmd_item *ti; int err = 0; afs_uint32 volumeId = 0; char *partName = 0; struct DiskPartition64 *partP = NULL; #ifndef AFS_NT40_ENV if (geteuid() != 0) { printf("vol-info must be run as root; sorry\n"); exit(1); } #endif if (as->parms[0].items) online = 1; else online = 0; if (as->parms[1].items) DumpVnodes = 1; else DumpVnodes = 0; if (as->parms[2].items) DumpDate = 1; else DumpDate = 0; if (as->parms[3].items) DumpInodeNumber = 1; else DumpInodeNumber = 0; if (as->parms[4].items) InodeTimes = 1; else InodeTimes = 0; if ((ti = as->parms[5].items)) partName = ti->data; if ((ti = as->parms[6].items)) volumeId = strtoul(ti->data, NULL, 10); if (as->parms[7].items) dheader = 1; else dheader = 0; if (as->parms[8].items) { dsizeOnly = 1; dheader = 1; DumpVnodes = 1; } else dsizeOnly = 0; if (as->parms[9].items) { fixheader = 1; } else fixheader = 0; if (as->parms[10].items) { saveinodes = 1; dheader = 1; DumpVnodes = 1; } else saveinodes = 0; if (as->parms[11].items) { orphaned = 1; DumpVnodes = 1; } else #if defined(AFS_NAMEI_ENV) if (as->parms[12].items) { PrintFileNames = 1; DumpVnodes = 1; } else #endif orphaned = 0; DInit(10); err = VAttachPartitions(); if (err) { printf("%d partitions had errors during attach.\n", err); } if (partName) { partP = VGetPartition(partName, 0); if (!partP) { printf("%s is not an AFS partition name on this server.\n", partName); exit(1); } } if (!volumeId) { if (!partP) { HandleAllPart(); } else { HandlePart(partP); } } else { char name1[128]; if (!partP) { partP = FindCurrentPartition(); if (!partP) { printf("Current partition is not a vice partition.\n"); exit(1); } } (void)afs_snprintf(name1, sizeof name1, VFORMAT, afs_printable_uint32_lu(volumeId)); if (dsizeOnly && !saveinodes) printf ("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n"); HandleVolume(partP, name1); } return 0; }
/** * verify that the fileserver still thinks we have a volume checked out. * * In DAFS, a non-fileserver program accesses a volume by checking it out from * the fileserver (FSYNC_VOL_OFF or FSYNC_VOL_NEEDVOLUME), and then locks the * volume. There is a possibility that the fileserver crashes or restarts for * some reason between volume checkout and locking; if this happens, the * fileserver could attach the volume before we had a chance to lock it. This * function serves to detect if this has happened; it must be called after * volume checkout and locking to make sure the fileserver still thinks we * have the volume. (If it doesn't, we should try to check it out again.) * * @param[in] volume volume ID * @param[in] partition partition name string * @param[in] command the command that was used to checkout the volume * @param[in] reason the reason code used to checkout the volume * * @return operation status * @retval SYNC_OK the fileserver could not have attached the volume since * it was checked out (either it thinks it is still checked * out, or it doesn't know about the volume) * @retval SYNC_DENIED fileserver may have restarted since checkout; checkout * should be reattempted * @retval SYNC_COM_ERROR internal/fatal error */ afs_int32 FSYNC_VerifyCheckout(VolumeId volume, char * partition, afs_int32 command, afs_int32 reason) { SYNC_response res; FSSYNC_VolOp_info vop; afs_int32 code; afs_int32 pid; res.hdr.response_len = sizeof(res.hdr); res.payload.buf = &vop; res.payload.len = sizeof(vop); code = FSYNC_VolOp(volume, partition, FSYNC_VOL_QUERY_VOP, FSYNC_WHATEVER, &res); if (code != SYNC_OK) { if (res.hdr.reason == FSYNC_NO_PENDING_VOL_OP) { Log("FSYNC_VerifyCheckout: fileserver claims no vop for vol %lu " "part %s; fileserver may have restarted since checkout\n", afs_printable_uint32_lu(volume), partition); return SYNC_DENIED; } if (res.hdr.reason == FSYNC_UNKNOWN_VOLID || res.hdr.reason == FSYNC_WRONG_PART) { /* if the fileserver does not know about this volume on this * partition, there's no way it could have attached it, so we're * fine */ return SYNC_OK; } Log("FSYNC_VerifyCheckout: FSYNC_VOL_QUERY_VOP failed for vol %lu " "part %s with code %ld reason %ld\n", afs_printable_uint32_lu(volume), partition, afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); return SYNC_COM_ERROR; } pid = getpid(); /* Check if the current vol op is us. Checking pid is probably enough, but * be a little bit paranoid. We could also probably check tid, but I'm not * completely confident of its reliability on all platforms (on pthread * envs, we coerce a pthread_t to an afs_int32, which is not guaranteed * to mean anything significant). */ if (vop.com.programType == programType && vop.com.pid == pid && vop.com.command == command && vop.com.reason == reason) { /* looks like the current pending vol op is the same one as the one * with which we checked it out. success. */ return SYNC_OK; } Log("FSYNC_VerifyCheckout: vop for vol %lu part %s does not match " "expectations (got pt %ld pid %ld cmd %ld reason %ld, but expected " "pt %ld pid %ld cmd %ld reason %ld); fileserver may have restarted " "since checkout\n", afs_printable_uint32_lu(volume), partition, afs_printable_int32_ld(vop.com.programType), afs_printable_int32_ld(vop.com.pid), afs_printable_int32_ld(vop.com.command), afs_printable_int32_ld(vop.com.reason), afs_printable_int32_ld(programType), afs_printable_int32_ld(pid), afs_printable_int32_ld(command), afs_printable_int32_ld(reason)); return SYNC_DENIED; }
struct afscp_volume * afscp_VolumeByName(struct afscp_cell *cell, const char *vname, afs_int32 intype) { union allvldbentry u; struct afscp_volume *ret, key; struct afscp_server *server; afs_int32 code, vtype, type, srv; void *s; #ifdef AFSCP_DEBUG struct in_addr i; #endif if (intype == RWVOL) vtype = VLSF_RWVOL; else if (intype == ROVOL) vtype = VLSF_ROVOL; else if (intype == BACKVOL) vtype = VLSF_BACKVOL; else { afscp_errno = EINVAL; return NULL; } memset(&key, 0, sizeof(key)); strlcpy(key.name, vname, sizeof(key.name)); key.voltype = vtype; s = tfind(&key, &cell->volsbyname, ncompare); if (s) { ret = *(struct afscp_volume **)s; return ret; } type = 0; code = ubik_VL_GetEntryByNameU(cell->vlservers, 0, (char *)vname, &u.u); if (code == RXGEN_OPCODE) { type = 1; code = ubik_VL_GetEntryByNameN(cell->vlservers, 0, (char *)vname, &u.n); if (code == RXGEN_OPCODE) { type = 2; code = ubik_VL_GetEntryByNameO(cell->vlservers, 0, (char *)vname, &u.o); } } if (code != 0) { afscp_errno = code; return NULL; } ret = calloc(1, sizeof(struct afscp_volume)); if (ret == NULL) { afscp_errno = ENOMEM; return NULL; } strlcpy(ret->name, u.u.name, sizeof(ret->name)); ret->nservers = 0; ret->cell = cell; switch (type) { case 0: ret->id = u.u.volumeId[intype]; for (srv = 0; srv < u.u.nServers; srv++) { if ((u.u.serverFlags[srv] & vtype) == 0) continue; afs_dprintf(("uvldbentry server %d flags: %x\n", srv, u.u.serverFlags[srv])); if ((u.u.serverFlags[srv] & VLSF_UUID) == 0) server = afscp_ServerByAddr(cell, u.u.serverNumber[srv].time_low); else server = afscp_ServerById(cell, &u.u.serverNumber[srv]); if (!server) continue; ret->servers[ret->nservers++] = server->index; } break; case 1: ret->id = u.n.volumeId[intype]; for (srv = 0; srv < u.n.nServers; srv++) { if ((u.n.serverFlags[srv] & vtype) == 0) continue; server = afscp_ServerByAddr(cell, u.n.serverNumber[srv]); if (!server) continue; ret->servers[ret->nservers++] = server->index; } break; case 2: ret->id = u.o.volumeId[intype]; for (srv = 0; srv < u.o.nServers; srv++) { if ((u.o.serverFlags[srv] & vtype) == 0) continue; server = afscp_ServerByAddr(cell, u.o.serverNumber[srv]); if (!server) continue; ret->servers[ret->nservers++] = server->index; } break; } if (!ret->nservers || !ret->id) { free(ret); return NULL; } ret->voltype = intype; #ifdef AFSCP_DEBUG server = afscp_ServerByIndex(ret->servers[0]); if (server != NULL) i.s_addr = server->addrs[0]; else i.s_addr = 0; #endif afs_dprintf(("New volume BYNAME %s (%lu) on %s (%d)\n", ret->name, afs_printable_uint32_lu(ret->id), inet_ntoa(i), ret->servers[0])); s = tsearch(&key, &cell->volsbyname, ncompare); if (s) *(struct afscp_volume **)s = ret; key.id = ret->id; s = tsearch(&key, &cell->volsbyid, icompare); if (s) *(struct afscp_volume **)s = ret; return ret; }
struct afscp_volume * afscp_VolumeById(struct afscp_cell *cell, afs_uint32 id) { union allvldbentry u; struct afscp_volume *ret, key; struct afscp_server *server; afs_int32 code, vtype, type, srv; int voltype = -1; char idbuffer[16]; void *s; #ifdef AFSCP_DEBUG struct in_addr i; #endif memset(&key, 0, sizeof(key)); key.id = id; s = tfind(&key, &cell->volsbyid, icompare); if (s) { ret = *(struct afscp_volume **)s; return ret; } snprintf(idbuffer, sizeof(idbuffer), "%lu", afs_printable_uint32_lu(id)); type = 0; code = ubik_VL_GetEntryByNameU(cell->vlservers, 0, idbuffer, &u.u); if (code == RXGEN_OPCODE) { type = 1; code = ubik_VL_GetEntryByIDN(cell->vlservers, 0, id, -1, &u.n); if (code == RXGEN_OPCODE) { type = 2; code = ubik_VL_GetEntryByID(cell->vlservers, 0, id, -1, &u.o); } } if (code != 0) { afscp_errno = code; return NULL; } ret = calloc(1, sizeof(struct afscp_volume)); if (ret == NULL) { afscp_errno = ENOMEM; return NULL; } strlcpy(ret->name, u.u.name, sizeof(ret->name)); ret->nservers = 0; ret->cell = cell; switch (type) { case 0: if (id == u.u.volumeId[RWVOL]) { vtype = VLSF_RWVOL; voltype = RWVOL; } else if (id == u.u.volumeId[ROVOL]) { vtype = VLSF_ROVOL; voltype = ROVOL; } else if (id == u.u.volumeId[BACKVOL]) { vtype = VLSF_BACKVOL; voltype = BACKVOL; } else { vtype = 0; voltype = -1; } for (srv = 0; srv < u.u.nServers; srv++) { if ((u.u.serverFlags[srv] & vtype) == 0) continue; if ((u.u.serverFlags[srv] & VLSF_UUID) == 0) server = afscp_ServerByAddr(cell, u.u.serverNumber[srv].time_low); else server = afscp_ServerById(cell, &u.u.serverNumber[srv]); if (!server) continue; ret->servers[ret->nservers++] = server->index; } break; case 1: if (id == u.n.volumeId[RWVOL]) { vtype = VLSF_RWVOL; voltype = RWVOL; } else if (id == u.n.volumeId[ROVOL]) { vtype = VLSF_ROVOL; voltype = ROVOL; } else if (id == u.n.volumeId[BACKVOL]) { vtype = VLSF_BACKVOL; voltype = BACKVOL; } else { vtype = 0; voltype = -1; } for (srv = 0; srv < u.n.nServers; srv++) { if ((u.n.serverFlags[srv] & vtype) == 0) continue; server = afscp_ServerByAddr(cell, u.n.serverNumber[srv]); if (server == NULL) continue; ret->servers[ret->nservers++] = server->index; } break; case 2: if (id == u.o.volumeId[RWVOL]) { vtype = VLSF_RWVOL; voltype = RWVOL; } else if (id == u.o.volumeId[ROVOL]) { vtype = VLSF_ROVOL; voltype = ROVOL; } else if (id == u.o.volumeId[BACKVOL]) { vtype = VLSF_BACKVOL; voltype = BACKVOL; } else { vtype = 0; voltype = -1; } for (srv = 0; srv < u.o.nServers; srv++) { if ((u.o.serverFlags[srv] & vtype) == 0) continue; server = afscp_ServerByAddr(cell, u.o.serverNumber[srv]); if (server == NULL) continue; ret->servers[ret->nservers++] = server->index; } break; } ret->voltype = voltype; #ifdef AFSCP_DEBUG server = afscp_ServerByIndex(ret->servers[0]); if (server) i.s_addr = server->addrs[0]; else i.s_addr = 0; #endif afs_dprintf(("New volume BYID %s (%lu) on %s (%d)\n", ret->name, afs_printable_uint32_lu(ret->id), inet_ntoa(i), ret->servers[0])); s = tsearch(&key, &cell->volsbyid, icompare); if (s) *(struct afscp_volume **)s = ret; strlcpy(key.name, ret->name, sizeof(key.name)); s = tsearch(&key, &cell->volsbyname, ncompare); if (s) *(struct afscp_volume **)s = ret; return ret; }
/** * write an existing volume disk header. * * @param[in] hdr volume disk header * @param[in] dp disk partition object * * @return operation status * @retval 0 success * @retval ENOENT volume header doesn't exist * @retval EIO failed to write volume header */ afs_int32 VWriteVolumeDiskHeader(VolumeDiskHeader_t * hdr, struct DiskPartition64 * dp) { afs_int32 code; #ifdef AFS_DEMAND_ATTACH_FS VolumeDiskHeader_t oldhdr; int delvgc = 0, addvgc = 0; SYNC_response res; /* first, see if anything with the volume IDs have changed; if so, we * need to update the VGC */ code = VReadVolumeDiskHeader(hdr->id, dp, &oldhdr); if (code == 0 && (oldhdr.id != hdr->id || oldhdr.parent != hdr->parent)) { /* the vol id or parent vol id changed; need to delete the VGC entry * for the old vol id/parent, and add the new one */ delvgc = 1; addvgc = 1; } else if (code) { /* couldn't get the old header info; add the new header info to the * VGC in case it hasn't been added yet */ addvgc = 1; } #endif /* AFS_DEMAND_ATTACH_FS */ code = _VWriteVolumeDiskHeader(hdr, dp, 0); if (code) { goto done; } #ifdef AFS_DEMAND_ATTACH_FS if (delvgc) { memset(&res, 0, sizeof(res)); code = FSYNC_VGCDel(dp->name, oldhdr.parent, oldhdr.id, FSYNC_WHATEVER, &res); /* unknown vol id is okay; it just further suggests the old header * data was bogus, which is fine since we're trying to fix it */ if (code && res.hdr.reason != FSYNC_UNKNOWN_VOLID) { Log("VWriteVolumeDiskHeader: FSYNC_VGCDel(%s, %lu, %lu) " "failed with code %ld reason %ld\n", dp->name, afs_printable_uint32_lu(oldhdr.parent), afs_printable_uint32_lu(oldhdr.id), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); } } if (addvgc) { memset(&res, 0, sizeof(res)); code = FSYNC_VGCAdd(dp->name, hdr->parent, hdr->id, FSYNC_WHATEVER, &res); if (code) { Log("VWriteVolumeDiskHeader: FSYNC_VGCAdd(%s, %lu, %lu) " "failed with code %ld reason %ld\n", dp->name, afs_printable_uint32_lu(hdr->parent), afs_printable_uint32_lu(hdr->id), afs_printable_int32_ld(code), afs_printable_int32_ld(res.hdr.reason)); } } #endif /* AFS_DEMAND_ATTACH_FS */ done: return code; }
Volume * VCreateVolume_r(Error * ec, char *partname, VolumeId volumeId, VolumeId parentId) { /* Should be the same as volumeId if there is * no parent */ VolumeDiskData vol; int i, rc; char headerName[VMAXPATHLEN], volumePath[VMAXPATHLEN]; Device device; struct DiskPartition64 *partition; struct VolumeDiskHeader diskHeader; IHandle_t *handle; FdHandle_t *fdP; Inode nearInode AFS_UNUSED = 0; char *part, *name; struct stat st; struct VolumeHeader tempHeader; struct afs_inode_info stuff[MAXINODETYPE]; afs_ino_str_t stmp; # ifdef AFS_DEMAND_ATTACH_FS int locktype = 0; # endif /* AFS_DEMAND_ATTACH_FS */ init_inode_info(&tempHeader, stuff); *ec = 0; memset(&vol, 0, sizeof(vol)); vol.id = volumeId; vol.parentId = parentId; vol.copyDate = time(0); /* The only date which really means when this * @i(instance) of this volume was created. * Creation date does not mean this */ /* Initialize handle for error case below. */ handle = NULL; /* Verify that the parition is valid before writing to it. */ if (!(partition = VGetPartition_r(partname, 0))) { Log("VCreateVolume: partition %s is not in service.\n", partname); *ec = VNOVOL; return NULL; } #if defined(NEARINODE_HINT) nearInodeHash(volumeId, nearInode); nearInode %= partition->f_files; #endif VGetVolumePath(ec, vol.id, &part, &name); if (*ec == VNOVOL || !strcmp(partition->name, part)) { /* this case is ok */ } else { /* return EXDEV if it's a clone to an alternate partition * otherwise assume it's a move */ if (vol.parentId != vol.id) { *ec = EXDEV; return NULL; } } *ec = 0; # ifdef AFS_DEMAND_ATTACH_FS /* volume doesn't exist yet, but we must lock it to try to prevent something * else from reading it when we're e.g. half way through creating it (or * something tries to create the same volume at the same time) */ locktype = VVolLockType(V_VOLUPD, 1); rc = VLockVolumeByIdNB(volumeId, partition, locktype); if (rc) { Log("VCreateVolume: vol %lu already locked by someone else\n", afs_printable_uint32_lu(volumeId)); *ec = VNOVOL; return NULL; } # else /* AFS_DEMAND_ATTACH_FS */ VLockPartition_r(partname); # endif /* !AFS_DEMAND_ATTACH_FS */ memset(&tempHeader, 0, sizeof(tempHeader)); tempHeader.stamp.magic = VOLUMEHEADERMAGIC; tempHeader.stamp.version = VOLUMEHEADERVERSION; tempHeader.id = vol.id; tempHeader.parent = vol.parentId; vol.stamp.magic = VOLUMEINFOMAGIC; vol.stamp.version = VOLUMEINFOVERSION; vol.destroyMe = DESTROY_ME; snprintf(headerName, sizeof headerName, VFORMAT, afs_printable_VolumeId_lu(vol.id)); snprintf(volumePath, sizeof volumePath, "%s" OS_DIRSEP "%s", VPartitionPath(partition), headerName); rc = stat(volumePath, &st); if (rc == 0 || errno != ENOENT) { if (rc == 0) { Log("VCreateVolume: Header file %s already exists!\n", volumePath); *ec = VVOLEXISTS; } else { Log("VCreateVolume: Error %d trying to stat header file %s\n", errno, volumePath); *ec = VNOVOL; } goto bad_noheader; } device = partition->device; for (i = 0; i < MAXINODETYPE; i++) { struct afs_inode_info *p = &stuff[i]; if (p->obsolete) continue; #ifdef AFS_NAMEI_ENV *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition), nearInode, (p->inodeType == VI_LINKTABLE) ? vol.parentId : vol.id, INODESPECIAL, p->inodeType, vol.parentId); if (!(VALID_INO(*(p->inode)))) { if (errno == EEXIST && (p->inodeType == VI_LINKTABLE)) { /* Increment the reference count instead. */ IHandle_t *lh; int code; *(p->inode) = namei_MakeSpecIno(vol.parentId, VI_LINKTABLE); IH_INIT(lh, device, parentId, *(p->inode)); fdP = IH_OPEN(lh); if (fdP == NULL) { IH_RELEASE(lh); goto bad; } code = IH_INC(lh, *(p->inode), parentId); FDH_REALLYCLOSE(fdP); IH_RELEASE(lh); if (code < 0) goto bad; continue; } } #else *(p->inode) = IH_CREATE(NULL, device, VPartitionPath(partition), nearInode, vol.id, INODESPECIAL, p->inodeType, vol.parentId); #endif if (!VALID_INO(*(p->inode))) { Log("VCreateVolume: Problem creating %s file associated with volume header %s\n", p->description, volumePath); bad: if (handle) IH_RELEASE(handle); RemoveInodes(stuff, device, vol.parentId, vol.id); if (!*ec) { *ec = VNOVOL; } VDestroyVolumeDiskHeader(partition, volumeId, parentId); bad_noheader: # ifdef AFS_DEMAND_ATTACH_FS if (locktype) { VUnlockVolumeById(volumeId, partition); } # endif /* AFS_DEMAND_ATTACH_FS */ return NULL; } IH_INIT(handle, device, vol.parentId, *(p->inode)); fdP = IH_OPEN(handle); if (fdP == NULL) { Log("VCreateVolume: Problem iopen inode %s (err=%d)\n", PrintInode(stmp, *(p->inode)), errno); goto bad; } if (FDH_PWRITE(fdP, (char *)&p->stamp, sizeof(p->stamp), 0) != sizeof(p->stamp)) { Log("VCreateVolume: Problem writing to inode %s (err=%d)\n", PrintInode(stmp, *(p->inode)), errno); FDH_REALLYCLOSE(fdP); goto bad; } FDH_REALLYCLOSE(fdP); IH_RELEASE(handle); nearInode = *(p->inode); } IH_INIT(handle, device, vol.parentId, tempHeader.volumeInfo); fdP = IH_OPEN(handle); if (fdP == NULL) { Log("VCreateVolume: Problem iopen inode %s (err=%d)\n", PrintInode(stmp, tempHeader.volumeInfo), errno); goto bad; } if (FDH_PWRITE(fdP, (char *)&vol, sizeof(vol), 0) != sizeof(vol)) { Log("VCreateVolume: Problem writing to inode %s (err=%d)\n", PrintInode(stmp, tempHeader.volumeInfo), errno); FDH_REALLYCLOSE(fdP); goto bad; } FDH_CLOSE(fdP); IH_RELEASE(handle); VolumeHeaderToDisk(&diskHeader, &tempHeader); rc = VCreateVolumeDiskHeader(&diskHeader, partition); if (rc) { Log("VCreateVolume: Error %d trying to write volume header for " "volume %" AFS_VOLID_FMT " on partition %s; volume not created\n", rc, afs_printable_VolumeId_lu(vol.id), VPartitionPath(partition)); if (rc == EEXIST) { *ec = VVOLEXISTS; } goto bad; } # ifdef AFS_DEMAND_ATTACH_FS if (locktype) { VUnlockVolumeById(volumeId, partition); } # endif /* AFS_DEMAND_ATTACH_FS */ return (VAttachVolumeByName_r(ec, partname, headerName, V_SECRETLY)); }
/** * add an entry to the volume group cache. * * @param[in] dp disk partition object * @param[in] parent parent volume id * @param[in] child child volume id * @param[out] newvg if non-NULL, *newvg is 1 if adding this added a * new VG, 0 if we added to an existing VG * * @pre VOL_LOCK held * * @return operation status * @retval 0 success * @retval -1 parent and child are already registered in * different VGs */ int VVGCache_entry_add_r(struct DiskPartition64 * dp, VolumeId parent, VolumeId child, afs_int32 *newvg) { int code = 0, res; VVGCache_entry_t * child_ent, * parent_ent; if (newvg) { *newvg = 0; } /* check for existing entries */ res = _VVGC_lookup(dp, child, &child_ent, NULL); if (res && res != ENOENT) { code = res; goto done; } res = _VVGC_lookup(dp, parent, &parent_ent, NULL); if (res && res != ENOENT) { code = res; goto done; } /* * branch based upon existence of parent and child nodes */ if (parent_ent && child_ent) { /* both exist. we're done. * if they point different places, then report the error. */ if (child_ent != parent_ent) { code = -1; } if (parent == child) { /* if we're adding the RW entry as a child, the RW id may * not be in the child array yet, so make sure not to skip * over that */ goto cladd; } goto done; } else if (!parent_ent && child_ent) { /* child exists. * update vg root volid, and add hash entry. */ parent_ent = child_ent; parent_ent->rw = parent; code = _VVGC_hash_entry_add(dp, parent, parent_ent, NULL); goto done; } else if (!child_ent && !parent_ent) { code = _VVGC_entry_add(dp, parent, &parent_ent, NULL); if (code) { goto done; } if (newvg) { *newvg = 1; } if (child == parent) { /* if we're the RW, skip over adding the child hash entry; * we already added the hash entry when creating the entry */ child_ent = parent_ent; goto cladd; } } osi_Assert(!child_ent); child_ent = parent_ent; code = _VVGC_hash_entry_add(dp, child, child_ent, NULL); if (code) { goto done; } cladd: code = _VVGC_entry_cl_add(child_ent, child); done: if (code && code != EINVAL) { ViceLog(0, ("VVGCache_entry_add: error %d trying to add vol %lu to VG" " %lu on partition %s", code, afs_printable_uint32_lu(child), afs_printable_uint32_lu(parent), VPartitionPath(dp))); } if (code == 0 && VVGCache.part[dp->index].state == VVGC_PART_STATE_UPDATING) { /* we successfully added the entry; make sure it's not on the * to-delete list, so it doesn't get deleted later */ code = _VVGC_dlist_del_r(dp, parent, child); if (code && code != ENOENT) { ViceLog(0, ("VVGCache_entry_add: error %d trying to remove vol " "%lu (parent %lu) from the to-delete list for part " "%s.\n", code, afs_printable_uint32_lu(child), afs_printable_uint32_lu(parent), VPartitionPath(dp))); } else { code = 0; } } return code; }