/* 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); }
/** * 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_VolumeId_lu(volid)); fd = open(path, O_RDONLY); if (fd < 0) { Log("VReadVolumeDiskHeader: Couldn't open header for volume %" AFS_VOLID_FMT " (errno %d).\n", afs_printable_VolumeId_lu(volid), errno); code = -1; } else if (hdr && read(fd, hdr, sizeof(*hdr)) != sizeof(*hdr)) { Log("VReadVolumeDiskHeader: Couldn't read header for volume %" AFS_VOLID_FMT ".\n", afs_printable_VolumeId_lu(volid)); code = EIO; } if (fd >= 0) { close(fd); } return code; }
static void VInitPartition_r(char *path, char *devname, Device dev) { struct DiskPartition64 *dp, *op; dp = malloc(sizeof(struct DiskPartition64)); /* Add it to the end, to preserve order when we print statistics */ for (op = DiskPartitionList; op; op = op->next) { if (!op->next) break; } if (op) op->next = dp; else DiskPartitionList = dp; dp->next = 0; dp->name = strdup(path); dp->index = volutil_GetPartitionID(path); #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV) /* Create a lockfile for the partition, of the form /vicepa/Lock/vicepa */ dp->devName = malloc(2 * strlen(path) + 6); strcpy(dp->devName, path); strcat(dp->devName, OS_DIRSEP); strcat(dp->devName, "Lock"); mkdir(dp->devName, 0700); strcat(dp->devName, path); close(afs_open(dp->devName, O_RDWR | O_CREAT, 0600)); dp->device = dp->index; #else dp->devName = strdup(devname); dp->device = dev; #endif dp->lock_fd = INVALID_FD; dp->flags = 0; dp->f_files = 1; /* just a default value */ #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV) if (programType == fileServer) (void)namei_ViceREADME(VPartitionPath(dp)); #endif VSetPartitionDiskUsage_r(dp); #ifdef AFS_DEMAND_ATTACH_FS AddPartitionToTable_r(dp); queue_Init(&dp->vol_list.head); CV_INIT(&dp->vol_list.cv, "vol list", CV_DEFAULT, 0); dp->vol_list.len = 0; dp->vol_list.busy = 0; { char lockpath[MAXPATHLEN+1]; snprintf(lockpath, MAXPATHLEN, "%s/" AFS_PARTLOCK_FILE, dp->name); lockpath[MAXPATHLEN] = '\0'; VLockFileInit(&dp->headerLockFile, lockpath); snprintf(lockpath, MAXPATHLEN, "%s/" AFS_VOLUMELOCK_FILE, dp->name); lockpath[MAXPATHLEN] = '\0'; VLockFileInit(&dp->volLockFile, lockpath); } VDiskLockInit(&dp->headerLock, &dp->headerLockFile, 1); #endif /* AFS_DEMAND_ATTACH_FS */ }
void HandlePart(struct DiskPartition64 *partP) { int nvols = 0; DIR *dirp; struct dirent *dp; #ifdef AFS_NT40_ENV char pname[64]; char *p = pname; (void)sprintf(pname, "%s\\", VPartitionPath(partP)); #else char *p = VPartitionPath(partP); #endif if ((dirp = opendir(p)) == NULL) { printf("Can't read directory %s; giving up\n", p); exit(1); } if (dsizeOnly && !saveinodes) printf ("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n"); while ((dp = readdir(dirp))) { p = (char *)strrchr(dp->d_name, '.'); if (p != NULL && strcmp(p, VHDREXT) == 0) { HandleVolume(partP, dp->d_name); Totvolsize += totvolsize; TVauxsize += Vauxsize; TVvnodesize += Vvnodesize; TVdiskused += Vdiskused; nvols++; } } closedir(dirp); if (dsizeOnly) { printf("\nPart Totals %12d%9d%10d%10d%9d (%d volumes)\n\n", TVdiskused, TVauxsize, TVvnodesize, Totvolsize, Totvolsize - TVdiskused, nvols); } }
/** * 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; }
/** * scanner thread. */ static void * _VVGC_scanner_thread(void * args) { struct DiskPartition64 *part = args; int code; code = _VVGC_scan_partition(part); if (code) { ViceLog(0, ("Error: _VVGC_scan_partition failed with code %d for partition %s\n", code, VPartitionPath(part))); } return NULL; }
/** * lock a partition's vol headers. * * @param[in] dp the partition to lock * @param[in] locktype READ_LOCK or WRITE_LOCK * * @return operation status * @retval 0 success */ int VPartHeaderLock(struct DiskPartition64 *dp, int locktype) { int code; /* block on acquiring the lock */ int nonblock = 0; code = VGetDiskLock(&dp->headerLock, locktype, nonblock); if (code) { Log("VPartHeaderLock: error %d locking partititon %s\n", code, VPartitionPath(dp)); } 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; }
void HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtime) { struct VolumeHeader header; struct VolumeDiskHeader diskHeader; struct afs_stat status, stat; register int fd; Volume *vp; IHandle_t *ih; char headerName[1024]; afs_int32 n; (void)afs_snprintf(headerName, sizeof headerName, "%s/%s", VPartitionPath(dp), name); if ((fd = afs_open(headerName, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) { fprintf(stderr, "Cannot read volume header %s\n", name); close(fd); exit(1); } n = read(fd, &diskHeader, sizeof(diskHeader)); if (n != sizeof(diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) { fprintf(stderr, "Error reading volume header %s\n", name); exit(1); } if (diskHeader.stamp.version != VOLUMEHEADERVERSION) { fprintf(stderr, "Volume %s, version number is incorrect; volume needs salvage\n", name); exit(1); } DiskToVolumeHeader(&header, &diskHeader); close(fd); vp = AttachVolume(dp, name, &header); if (!vp) { fprintf(stderr, "Error attaching volume header %s\n", name); exit(1); } DoMyVolDump(vp, dp, filename, fromtime); }
void VSetPartitionDiskUsage_r(register struct DiskPartition64 *dp) { ULARGE_INTEGER free_user, total, free_total; int ufree, tot, tfree; if (!GetDiskFreeSpaceEx (VPartitionPath(dp), &free_user, &total, &free_total)) { printf("Failed to get disk space info for %s, error = %d\n", dp->name, GetLastError()); return; } /* Convert to 1K units. */ ufree = (int)Int64ShraMod32(free_user.QuadPart, 10); tot = (int)Int64ShraMod32(total.QuadPart, 10); tfree = (int)Int64ShraMod32(free_total.QuadPart, 10); dp->minFree = tfree - ufree; /* only used in VPrintDiskStats_r */ dp->totalUsable = tot; dp->free = tfree; }
void VLockPartition_r(char *name) { struct DiskPartition64 *dp = VGetPartition_r(name, 0); OVERLAPPED lap; if (!dp) return; if (dp->lock_fd == INVALID_FD) { char path[64]; int rc; (void)sprintf(path, "%s\\%s", VPartitionPath(dp), LOCKFILE); dp->lock_fd = (FD_t)CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL); assert(dp->lock_fd != INVALID_FD); memset(&lap, 0, sizeof(lap)); rc = LockFileEx((HANDLE) dp->lock_fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &lap); assert(rc); } }
/** * 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; }
/** * start a background scan. * * @param[in] dp disk partition object * * @return operation status * @retval 0 success * @retval -1 internal error * @retval -3 racing against another thread * * @internal */ int _VVGC_scan_start(struct DiskPartition64 * dp) { int code = 0; pthread_t tid; pthread_attr_t attrs; int i; if (_VVGC_state_change(dp, VVGC_PART_STATE_UPDATING) == VVGC_PART_STATE_UPDATING) { /* race */ ViceLog(0, ("VVGC_scan_partition: race detected; aborting scanning partition %s\n", VPartitionPath(dp))); code = -3; goto error; } /* initialize partition's to-delete list */ VVGCache.part[dp->index].dlist_hash_buckets = malloc(VolumeHashTable.Size * sizeof(struct rx_queue)); if (!VVGCache.part[dp->index].dlist_hash_buckets) { code = -1; goto error; } for (i = 0; i < VolumeHashTable.Size; i++) { queue_Init(&VVGCache.part[dp->index].dlist_hash_buckets[i]); } code = pthread_attr_init(&attrs); if (code) { goto error; } code = pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED); if (code) { goto error; } code = pthread_create(&tid, &attrs, &_VVGC_scanner_thread, dp); if (code) { VVGCache_part_state_t old_state; ViceLog(0, ("_VVGC_scan_start: pthread_create failed with %d\n", code)); old_state = _VVGC_state_change(dp, VVGC_PART_STATE_INVALID); osi_Assert(old_state == VVGC_PART_STATE_UPDATING); } error: if (code) { ViceLog(0, ("_VVGC_scan_start failed with code %d for partition %s\n", code, VPartitionPath(dp))); if (VVGCache.part[dp->index].dlist_hash_buckets) { free(VVGCache.part[dp->index].dlist_hash_buckets); VVGCache.part[dp->index].dlist_hash_buckets = NULL; } } return code; }
/** * scan a disk partition for .vol files * * @param[in] part disk partition object * * @pre VOL_LOCK is NOT held * * @return operation status * @retval 0 success * @retval -1 invalid disk partition object * @retval -2 failed to flush stale entries for this partition * * @internal */ static int _VVGC_scan_partition(struct DiskPartition64 * part) { int code, res; DIR *dirp = NULL; VVGCache_scan_table_t tbl; char *part_path = NULL; code = _VVGC_scan_table_init(&tbl); if (code) { ViceLog(0, ("VVGC_scan_partition: could not init scan table; error = %d\n", code)); goto done; } part_path = VPartitionPath(part); if (part_path == NULL) { ViceLog(0, ("VVGC_scan_partition: invalid partition object given; aborting scan\n")); code = -1; goto done; } VOL_LOCK; res = _VVGC_flush_part_r(part); if (res) { ViceLog(0, ("VVGC_scan_partition: error flushing partition %s; error = %d\n", VPartitionPath(part), res)); code = -2; } VOL_UNLOCK; if (code) { goto done; } dirp = opendir(part_path); if (dirp == NULL) { ViceLog(0, ("VVGC_scan_partition: could not open %s, aborting scan; error = %d\n", part_path, errno)); code = -1; goto done; } ViceLog(5, ("VVGC_scan_partition: scanning partition %s for VG cache\n", part_path)); code = VWalkVolumeHeaders(part, part_path, _VVGC_RecordHeader, _VVGC_UnlinkHeader, &tbl); if (code < 0) { goto done; } _VVGC_scan_table_flush(&tbl, part); done: if (dirp) { closedir(dirp); dirp = NULL; } if (code) { ViceLog(0, ("VVGC_scan_partition: error %d while scanning %s\n", code, part_path)); } else { ViceLog(0, ("VVGC_scan_partition: finished scanning %s: %lu volumes in %lu groups\n", part_path, tbl.newvols, tbl.newvgs)); } VOL_LOCK; _VVGC_flush_dlist(part); free(VVGCache.part[part->index].dlist_hash_buckets); VVGCache.part[part->index].dlist_hash_buckets = NULL; if (code) { _VVGC_state_change(part, VVGC_PART_STATE_INVALID); } else { _VVGC_state_change(part, VVGC_PART_STATE_VALID); } VOL_UNLOCK; return code; }
/** * flush thread-local scan table to the global VG cache. * * @param[in] tbl scan table * @param[in] dp disk partition object * * @pre VOL_LOCK is NOT held * * @return operation status * @retval 0 success * @retval nonzero a VVGCache_entry_add_r operation failed during a * flush of the thread-local table * * @internal */ static int _VVGC_scan_table_flush(VVGCache_scan_table_t * tbl, struct DiskPartition64 * dp) { int code = 0, res, i; afs_int32 newvg = 0; unsigned long newvols, newvgs; newvols = tbl->newvols; newvgs = tbl->newvgs; VOL_LOCK; for (i = 0; i < tbl->idx; i++) { /* * We need to check the 'to-delete' list and prevent adding any entries * that are on it. The volser could potentially create a volume in one * VG, then delete it and put it on another VG. If we are doing a scan * when that happens, tbl->entries could have the entries for trying to * put the vol on both VGs, though at least one of them will also be on * the dlist. If we put everything in tbl->entries on the VGC then try * to delete afterwards, putting one entry on the VGC cause an error, * and we'll fail to add it. So instead, avoid adding any new VGC * entries if it is on the dlist. */ if (_VVGC_dlist_lookup_r(dp, tbl->entries[i].parent, tbl->entries[i].volid)) { continue; } res = VVGCache_entry_add_r(dp, tbl->entries[i].parent, tbl->entries[i].volid, &newvg); if (res) { code = res; } else { newvols++; newvgs += newvg; } } /* flush the to-delete list while we're here. We don't need to preserve * the list across the entire scan, and flushing it each time we flush * a scan table will keep the size of the dlist down */ _VVGC_flush_dlist(dp); VOL_UNLOCK; ViceLog(125, ("VVGC_scan_table_flush: flushed %d entries from " "scan table to global VG cache\n", tbl->idx)); ViceLog(125, ("VVGC_scan_table_flush: %s total: %lu vols, %lu groups\n", VPartitionPath(dp), newvols, newvgs)); res = _VVGC_scan_table_init(tbl); if (res) { code = res; } tbl->newvols = newvols; tbl->newvgs = newvgs; return code; }
void HandleVolume(struct DiskPartition64 *dp, char *name) { struct VolumeHeader header; struct VolumeDiskHeader diskHeader; struct afs_stat status, stat; int fd; Volume *vp; IHandle_t *ih; char headerName[1024]; if (online) { printf("volinfo: -online not supported\n"); exit(1); } else { afs_int32 n; (void)afs_snprintf(headerName, sizeof headerName, "%s/%s", VPartitionPath(dp), name); if ((fd = afs_open(headerName, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) { printf("Volinfo: Cannot read volume header %s\n", name); close(fd); exit(1); } n = read(fd, &diskHeader, sizeof(diskHeader)); if (n != sizeof(diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) { printf("Volinfo: Error reading volume header %s\n", name); exit(1); } if (diskHeader.stamp.version != VOLUMEHEADERVERSION) { printf ("Volinfo: Volume %s, version number is incorrect; volume needs salvage\n", name); exit(1); } DiskToVolumeHeader(&header, &diskHeader); if (dheader) { FdHandle_t *fdP; afs_sfsize_t size = 0; afs_sfsize_t code; if (afs_fstat(fd, &stat) == -1) { perror("stat"); exit(1); } if (!dsizeOnly && !saveinodes) { size = stat.st_size; printf("Volume header (size = %d):\n", (int)size); printf("\tstamp\t= 0x%x\n", header.stamp.version); printf("\tVolId\t= %u\n", header.id); } IH_INIT(ih, dp->device, header.parent, header.volumeInfo); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening volume info"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tparent\t= %u\n", header.parent); printf("\tInfo inode\t= %s (size = %d)\n", PrintInode(NULL, header.volumeInfo), (int)code); } IH_INIT(ih, dp->device, header.parent, header.smallVnodeIndex); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening small vnode index"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tSmall inode\t= %s (size = %d)\n", PrintInode(NULL, header.smallVnodeIndex), (int)code); } IH_INIT(ih, dp->device, header.parent, header.largeVnodeIndex); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening large vnode index"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tLarge inode\t= %s (size = %d)\n", PrintInode(NULL, header.largeVnodeIndex), (int)code); #ifndef AFS_NT40_ENV printf("Total aux volume size = %d\n\n", (int)size); #endif } #ifdef AFS_NAMEI_ENV IH_INIT(ih, dp->device, header.parent, header.linkTable); fdP = IH_OPEN(ih); if (fdP == NULL) { perror("opening link table index"); exit(1); } code = FDH_SIZE(fdP); if (code == -1) { perror("fstat"); exit(1); } FDH_REALLYCLOSE(fdP); IH_RELEASE(ih); size += code; if (!dsizeOnly && !saveinodes) { printf("\tLink inode\t= %s (size = %d)\n", PrintInode(NULL, header.linkTable), (int)code); printf("Total aux volume size = %d\n\n", (int)size); } #endif Vauxsize = size; Vauxsize_k = size / 1024; } close(fd); vp = AttachVolume(dp, name, &header); if (!vp) { printf("Volinfo: Error attaching volume header %s\n", name); return; } } PrintHeader(vp); if (DumpVnodes) { if (!dsizeOnly && !saveinodes) printf("\nLarge vnodes (directories)\n"); PrintVnodes(vp, vLarge); if (!dsizeOnly && !saveinodes) { printf("\nSmall vnodes(files, symbolic links)\n"); fflush(stdout); } if (saveinodes) printf("Saving all volume files to current directory ...\n"); PrintVnodes(vp, vSmall); } if (dsizeOnly) { totvolsize = Vauxsize_k + Vvnodesize_k; if (saveinodes) printf ("Volume-Id\t Volsize Auxsize Inodesize AVolsize SizeDiff (VolName)\n"); printf("%u\t%9d%9d%10d%10d%9d\t%24s\n", V_id(vp), Vdiskused, Vauxsize_k, Vvnodesize_k, totvolsize, totvolsize - Vdiskused, V_name(vp)); } free(vp->header); free(vp); }
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)); }