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)); }
/* function called with partition name and volid ID, and which removes all * inodes marked with the specified volume ID. If the volume is a read-only * clone, we'll only remove the header inodes, since they're the only inodes * marked with that volume ID. If you want to reclaim all the data, you should * nuke the read-write volume ID. * * Note also that nuking a read-write volume effectively nukes all RO volumes * cloned from that RW volume ID, too, since everything except for their * indices will be gone. */ int nuke(char *aname, afs_int32 avolid) { /* first process the partition containing this junk */ struct afs_stat_st tstat; struct ilist *ti, *ni, *li=NULL; afs_int32 code; int i, forceSal; char wpath[100]; char *lastDevComp; struct DiskPartition64 *dp; #ifdef AFS_NAMEI_ENV char *path; namei_t ufs_name; #endif /* AFS_NAMEI_ENV */ #ifndef AFS_NAMEI_ENV char devName[64]; #endif /* !AFS_NAMEI_ENV */ IHandle_t *fileH; struct ilist *allInodes = 0; if (avolid == 0) return EINVAL; code = afs_stat(aname, &tstat); if (code || (dp = VGetPartition(aname, 0)) == NULL) { printf("volnuke: partition %s does not exist.\n", aname); if (!code) { code = EINVAL; } return code; } /* get the device name for the partition */ #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV) lastDevComp = aname; #else #ifdef AFS_NT40_ENV lastDevComp = &aname[strlen(aname) - 1]; *lastDevComp = toupper(*lastDevComp); #else { char *tfile = vol_DevName(tstat.st_dev, wpath); if (!tfile) { printf("volnuke: can't find %s's device.\n", aname); return 1; } strcpy(devName, tfile); /* save this from the static buffer */ } /* aim lastDevComp at the 'foo' of '/dev/foo' */ lastDevComp = strrchr(devName, OS_DIRSEPC); /* either points at slash, or there is no slash; adjust appropriately */ if (lastDevComp) lastDevComp++; else lastDevComp = devName; #endif /* AFS_NT40_ENV */ #endif /* AFS_NAMEI_ENV && !AFS_NT40_ENV */ ObtainWriteLock(&localLock); /* OK, we have the mounted on place, aname, the device name (in devName). * all we need to do to call ListViceInodes is find the inodes for the * volume we're nuking. */ code = ListViceInodes(lastDevComp, aname, INVALID_FD, NukeProc, avolid, &forceSal, 0, wpath, &allInodes); if (code == 0) { /* actually do the idecs now */ for (ti = allInodes; ti; ti = ti->next) { for (i = 0; i < ti->freePtr; i++) { #ifndef AFS_PTHREAD_ENV IOMGR_Poll(); /* keep RPC running */ #endif /* !AFS_PTHREAD_ENV */ /* idec this inode into oblivion */ #ifdef AFS_NAMEI_ENV #ifdef AFS_NT40_ENV IH_INIT(fileH, (int)(*lastDevComp - 'A'), avolid, ti->inode[i]); #else IH_INIT(fileH, (int)volutil_GetPartitionID(aname), avolid, ti->inode[i]); #endif /* AFS_NT40_ENV */ namei_HandleToName(&ufs_name, fileH); path = ufs_name.n_path; IH_RELEASE(fileH); if (OS_UNLINK(path) < 0) { Log("Nuke: Failed to remove %s\n", path); } #else /* AFS_NAMEI_ENV */ IH_INIT(fileH, (int)tstat.st_dev, avolid, ti->inode[i]); { int j; for (j = 0; j < ti->count[i]; j++) { code = IH_DEC(fileH, ti->inode[i], avolid); } } IH_RELEASE(fileH); #endif /* AFS_NAMEI_ENV */ } ni = ti->next; if (li) free(li); li = ti; } if (li) free(li); code = 0; /* we really don't care about it except for debugging */ allInodes = NULL; /* at this point, we should try to remove the volume header file itself. * the volume header file is the file named VNNNNN.vol in the UFS file * system, and is a normal file. As such, it is not stamped with the * volume's ID in its inode, and has to be removed explicitly. */ code = VDestroyVolumeDiskHeader(dp, avolid, 0); } else { /* just free things */ for (ti = allInodes; ti; ti = ni) { ni = ti->next; if (li) free(li); li = ti; } if (li) free(li); allInodes = NULL; } ReleaseWriteLock(&localLock); return code; }