static int do_volop(struct fssync_state * state, afs_int32 command, SYNC_response * res) { afs_int32 code; SYNC_PROTO_BUF_DECL(res_buf); SYNC_response res_l; if (!res) { res = &res_l; res->payload.len = SYNC_PROTO_MAX_LEN; res->payload.buf = res_buf; } fprintf(stderr, "calling FSYNC_VolOp with command code %d (%s)\n", command, FSYNC_com2string(command)); code = FSYNC_VolOp(state->vop->volume, state->vop->partName, command, state->reason, res); debug_response(code, res); VDisconnectFS(); return 0; }
/* Try to detect if the fileserver is DAFS, and if so, re-exec as the * DAFS-enabled fssync-debug (dafssync_debug). If we fail to detect or * exec, just try to proceed anyway as if the server is not DAFS */ static void dafs_prolog(void) { SYNC_response res; SYNC_PROTO_BUF_DECL(res_buf); afs_int32 code; char *dfssd; res.payload.len = SYNC_PROTO_MAX_LEN; res.payload.buf = res_buf; /* LISTVOLUMES is a no-op; we just want to get the response header flags * to see if the server reports itself as DAFS or not */ code = FSYNC_VolOp(0, NULL, FSYNC_VOL_LISTVOLUMES, FSYNC_WHATEVER, &res); if (code) { /* probably failed to contact the fileserver; later code will provide * some warning/error indication */ return; } if (!(res.hdr.flags & SYNC_FLAG_DAFS_EXTENSIONS)) { /* fileserver is not DAFS, so we don't need to do anything */ return; } dfssd = afs_exec_alt(fssd_argc, fssd_argv, "da", NULL); fprintf(stderr, "\n*** server asserted demand attach extensions, but we failed\n" "*** to exec a DAFS-enabled fssync-debug '%s' (errno=%d);\n" "*** attempting to proceed without it.\n\n", dfssd, errno); free(dfssd); }
/* No lock needed. Only the volserver will call this, and only one transaction * can have a given volume (volid/partition pair) in use at a time */ void VPurgeVolume(Error * ec, Volume * vp) { struct DiskPartition64 *tpartp = vp->partition; char purgePath[MAXPATHLEN]; /* so VCheckDetach doesn't try to update the volume header and * dump spurious errors into the logs */ V_inUse(vp) = 0; /* N.B. it's important here to use the partition pointed to by the * volume header. This routine can, under some circumstances, be called * when two volumes with the same id exist on different partitions. */ (void)afs_snprintf(purgePath, sizeof purgePath, "%s/%s", VPartitionPath(vp->partition), VolumeExternalName(V_id(vp))); PurgeIndex_r(vp, vLarge); PurgeIndex_r(vp, vSmall); PurgeHeader_r(vp); unlink(purgePath); /* * Call the fileserver to break all call backs for that volume */ FSYNC_VolOp(V_id(vp), tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL); }
/** * perform an asynchronous volume group scan. * * @param[in] partition vice partition string * @param[in] reason FSSYNC reason code * * @note if partition is NULL, all vice partitions will be scanned. * * @return operation status * @retval SYNC_OK success */ afs_int32 FSYNC_VGCScan(char * partition, int reason) { int command; if (partition == NULL) { command = FSYNC_VG_SCAN_ALL; partition = ""; } else { command = FSYNC_VG_SCAN; } return FSYNC_VolOp(0, partition, command, reason, NULL); }
/** * query the volume group cache. * * @param[in] part vice partition path * @param[in] volid volume id * @param[out] qry query response object * @param[out] res SYNC response message * * @return operation status * @retval SYNC_OK success */ afs_int32 FSYNC_VGCQuery(char * part, VolumeId volid, FSSYNC_VGQry_response_t * qry, SYNC_response *res) { SYNC_response lres; if (!res) { res = &lres; } res->hdr.response_len = sizeof(res->hdr); res->payload.buf = qry; res->payload.len = sizeof(*qry); return FSYNC_VolOp(volid, part, FSYNC_VG_QUERY, 0, res); }
static int do_volop(struct state * state, afs_int32 command, SYNC_response * res) { afs_int32 code; SYNC_PROTO_BUF_DECL(res_buf); SYNC_response res_l; if (!res) { res = &res_l; res->payload.len = SYNC_PROTO_MAX_LEN; res->payload.buf = res_buf; } fprintf(stderr, "calling FSYNC_VolOp with command code %d (%s)\n", command, command_code_to_string(command)); code = FSYNC_VolOp(state->vop->volume, state->vop->partName, command, state->reason, res); switch (code) { case SYNC_OK: case SYNC_DENIED: break; default: fprintf(stderr, "possible sync protocol error. return code was %d\n", code); } fprintf(stderr, "FSYNC_VolOp returned %d (%s)\n", code, response_code_to_string(code)); fprintf(stderr, "protocol response code was %d (%s)\n", res->hdr.response, response_code_to_string(res->hdr.response)); fprintf(stderr, "protocol reason code was %d (%s)\n", res->hdr.reason, reason_code_to_string(res->hdr.reason)); VDisconnectFS(); }
/** * 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; }