/* VIsAlwaysAttach() checks whether a /vicepX directory should always be * attached (return value 1), or only attached when it is a separately * mounted partition (return value 0). For non-NAMEI environments, it * always returns 0. * * *awouldattach will be set to 1 if the given path at least looks like a vice * partition (that is, if we return 0, the only thing preventing this partition * from being attached is the existence of the AlwaysAttach file), or to 0 * otherwise. *awouldattach is set regardless of whether or not the partition * should always be attached or not. */ static int VIsAlwaysAttach(char *part, int *awouldattach) { #ifdef AFS_NAMEI_ENV struct afs_stat_st st; char checkfile[256]; int ret; #endif /* AFS_NAMEI_ENV */ if (awouldattach) { *awouldattach = 0; } #ifdef AFS_NAMEI_ENV if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) return 0; if (awouldattach) { *awouldattach = 1; } strncpy(checkfile, part, 100); strcat(checkfile, OS_DIRSEP); strcat(checkfile, VICE_ALWAYSATTACH_FILE); ret = afs_stat(checkfile, &st); return (ret < 0) ? 0 : 1; #else /* AFS_NAMEI_ENV */ return 0; #endif /* AFS_NAMEI_ENV */ }
static int fs_stateCreateDump(struct fs_dump_state * state) { int fd, ret = 0; char savedump[MAXPATHLEN]; struct afs_stat status; afs_snprintf(savedump, sizeof(savedump), "%s.old", state->fn); if (afs_stat(state->fn, &status) == 0) { renamefile(state->fn, savedump); } if (((fd = afs_open(state->fn, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) == -1) || (afs_fstat(fd, &status) == -1)) { ViceLog(0, ("fs_stateCreateDump: failed to create state dump file '%s'\n", state->fn)); ret = 1; goto done; } state->fd = fd; state->mode = FS_STATE_DUMP_MODE; memset(state->hdr, 0, sizeof(struct fs_state_header)); fs_stateIncEOF(state, sizeof(struct fs_state_header)); #ifdef FS_STATE_USE_MMAP if (fs_stateSizeFile(state)) { ViceLog(0, ("fs_stateCreateDump: failed to resize state dump file '%s'\n", state->fn)); ret = 1; goto done; } if (fs_stateMapFile(state)) { ViceLog(0, ("fs_stateCreateDump: failed to memory map state dump file '%s'\n", state->fn)); ret = 1; goto done; } #endif ret = fs_stateInvalidateDump(state); done: return ret; }
/* VAttachPartitions2() looks for and attaches /vicepX partitions * where a special file (VICE_ALWAYSATTACH_FILE) exists. This is * used to attach /vicepX directories which aren't on dedicated * partitions, in the NAMEI fileserver. */ static void VAttachPartitions2(void) { #ifdef AFS_NAMEI_ENV DIR *dirp; struct dirent *de; char pname[32]; int wouldattach; dirp = opendir(OS_DIRSEP); while ((de = readdir(dirp))) { strcpy(pname, OS_DIRSEP); strncat(pname, de->d_name, 20); pname[sizeof(pname) - 1] = '\0'; /* Only keep track of "/vicepx" partitions since automounter * may hose us */ if (VIsAlwaysAttach(pname, &wouldattach)) { VCheckPartition(pname, "", 0); } else { struct afs_stat_st st; if (wouldattach && VGetPartition(pname, 0) == NULL && afs_stat(pname, &st) == 0 && S_ISDIR(st.st_mode)) { /* This is a /vicep* dir, and it has not been attached as a * partition. This probably means that this is a /vicep* dir * that is not a separate partition, so just give a notice so * admins are not confused as to why their /vicep* dirs are not * being attached. * * It is possible that the dir _is_ a separate partition and we * failed to attach it earlier, making this message a bit * confusing. But that should be rare, and an error message * about the failure will already be logged right before this, * so it should be clear enough. */ Log("VAttachPartitions: not attaching %s; either it is not a " "separate partition, or it failed to attach (create the " "file %s/" VICE_ALWAYSATTACH_FILE " to force attachment)\n", pname, pname); } } } closedir(dirp); #endif /* AFS_NAMEI_ENV */ }
/* VIsNeverAttach() checks whether a /vicepX directory should never be * attached (return value 1), or follow the normal mounting logic. The * Always Attach flag may override the NeverAttach flag. */ static int VIsNeverAttach(char *part) { struct afs_stat_st st; char checkfile[256]; int ret; if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) return 0; strncpy(checkfile, part, 100); strcat(checkfile, OS_DIRSEP); strcat(checkfile, VICE_NEVERATTACH_FILE); ret = afs_stat(checkfile, &st); return (ret < 0) ? 0 : 1; }
/* VIsAlwaysAttach() checks whether a /vicepX directory should always be * attached (return value 1), or only attached when it is a separately * mounted partition (return value 0). For non-NAMEI environments, it * always returns 0. */ static int VIsAlwaysAttach(char *part) { #ifdef AFS_NAMEI_ENV struct afs_stat st; char checkfile[256]; int ret; if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) return 0; strncpy(checkfile, part, 100); strcat(checkfile, "/"); strcat(checkfile, VICE_ALWAYSATTACH_FILE); ret = afs_stat(checkfile, &st); return (ret < 0) ? 0 : 1; #else /* AFS_NAMEI_ENV */ return 0; #endif /* AFS_NAMEI_ENV */ }
int VAttachPartitions(void) { struct DiskPartition64 *partP, *prevP, *nextP; struct vpt_iter iter; struct vptab entry; if (vpt_Start(&iter) < 0) { Log("No partitions to attach.\n"); return 0; } while (0 == vpt_NextEntry(&iter, &entry)) { if (!VValidVPTEntry(&entry)) { continue; } /* This test for duplicates relies on the fact that the method * of storing the partition names in the NT registry means the same * partition name will never appear twice in the list. */ for (partP = DiskPartitionList; partP; partP = partP->next) { if (*partP->devName == *entry.vp_dev) { Log("Same drive (%s) used for both partition %s and partition %s, ignoring both.\n", entry.vp_dev, partP->name, entry.vp_name); partP->flags = PART_DUPLICATE; break; /* Only one entry will ever be in this list. */ } } if (partP) continue; /* found a duplicate */ if (VCheckPartition(entry.vp_dev) < 0) continue; /* This test allows for manually inserting the FORCESALVAGE flag * and thereby invoking the salvager. scandisk obviously won't be * doing this for us. */ if (programType == fileServer) { struct afs_stat status; char salvpath[MAXPATHLEN]; strcpy(salvpath, entry.vp_dev); strcat(salvpath, "\\FORCESALVAGE"); if (afs_stat(salvpath, &status) == 0) { Log("VAttachPartitions: Found %s; aborting\n", salvpath); exit(1); } } VInitPartition(entry.vp_name, entry.vp_dev, *entry.vp_dev - 'A'); } vpt_Finish(&iter); /* Run through partition list and clear out the dupes. */ prevP = nextP = NULL; for (partP = DiskPartitionList; partP; partP = nextP) { nextP = partP->next; if (partP->flags == PART_DUPLICATE) { if (prevP) prevP->next = partP->next; else DiskPartitionList = partP->next; free(partP); } else prevP = partP; } return 0; }
/* VAttachPartitions() finds the vice partitions on this server. Calls * VCheckPartition() to do some basic checks on the partition. If the partition * is a valid vice partition, VCheckPartition will add it to the DiskPartition * list. * Returns the number of errors returned by VCheckPartition. An error in * VCheckPartition means that partition is a valid vice partition but the * fileserver should not start because of the error found on that partition. * * AFS_NAMEI_ENV * No specific user space file system checks, since we don't know what * is being used for vice partitions. * * Use partition name as devname. */ int VCheckPartition(char *part, char *devname) { struct afs_stat status; #if !defined(AFS_LINUX20_ENV) && !defined(AFS_NT40_ENV) char AFSIDatPath[MAXPATHLEN]; #endif /* Only keep track of "/vicepx" partitions since it can get hairy * when NFS mounts are involved.. */ if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) { return 0; } if (afs_stat(part, &status) < 0) { Log("VInitVnodes: Couldn't find file system %s; ignored\n", part); return 0; } #ifndef AFS_AIX32_ENV if (programType == fileServer) { char salvpath[MAXPATHLEN]; strcpy(salvpath, part); strcat(salvpath, "/FORCESALVAGE"); if (afs_stat(salvpath, &status) == 0) { Log("VInitVnodes: Found %s; aborting\n", salvpath); return -1; } } #endif #if !defined(AFS_LINUX20_ENV) && !defined(AFS_NT40_ENV) strcpy(AFSIDatPath, part); strcat(AFSIDatPath, "/AFSIDat"); #ifdef AFS_NAMEI_ENV if (afs_stat(AFSIDatPath, &status) < 0) { DIR *dirp; struct dirent *dp; dirp = opendir(part); assert(dirp); while ((dp = readdir(dirp))) { if (dp->d_name[0] == 'V') { Log("This program is compiled with AFS_NAMEI_ENV, but partition %s seems to contain volumes which don't use the namei-interface; aborting\n", part); closedir(dirp); return -1; } } closedir(dirp); } #else /* AFS_NAMEI_ENV */ if (afs_stat(AFSIDatPath, &status) == 0) { Log("This program is compiled without AFS_NAMEI_ENV, but partition %s seems to contain volumes which use the namei-interface; aborting\n", part); return -1; } #ifdef AFS_SGI_XFS_IOPS_ENV if (VerifyXFSInodeSize(part, status.st_fstype) < 0) return -1; #endif #endif /* AFS_NAMEI_ENV */ #endif /* !AFS_LINUX20_ENV && !AFS_NT40_ENV */ #if defined(AFS_DUX40_ENV) && !defined(AFS_NAMEI_ENV) if (status.st_ino != ROOTINO) { Log("%s is not a mounted file system; ignored.\n", part); return 0; } #endif VInitPartition(part, devname, status.st_dev); return 0; }
/* 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; }
/* VAttachPartitions() finds the vice partitions on this server. Calls * VCheckPartition() to do some basic checks on the partition. If the partition * is a valid vice partition, VCheckPartition will add it to the DiskPartition * list. * Returns the number of errors returned by VCheckPartition. An error in * VCheckPartition means that partition is a valid vice partition but the * fileserver should not start because of the error found on that partition. * * AFS_NAMEI_ENV * No specific user space file system checks, since we don't know what * is being used for vice partitions. * * Use partition name as devname. */ static int VCheckPartition(char *part, char *devname, int logging) { struct afs_stat_st status; #if !defined(AFS_LINUX20_ENV) && !defined(AFS_NT40_ENV) char AFSIDatPath[MAXPATHLEN]; #endif /* Only keep track of "/vicepx" partitions since it can get hairy * when NFS mounts are involved.. */ if (strncmp(part, VICE_PARTITION_PREFIX, VICE_PREFIX_SIZE)) { return 0; } if (volutil_GetPartitionID(part) == -1) { Log("Warning: %s is a bad partition name; ignored.\n", part); return 0; } if (afs_stat(part, &status) < 0) { Log("VInitVnodes: Couldn't find file system %s; ignored\n", part); return 0; } if (logging) { Log("This program is compiled without AFS_NAMEI_ENV, and " "partition %s is mounted with the 'logging' option. " "Using the inode fileserver backend with 'logging' UFS " "partitions causes volume corruption, so please either " "mount the partition without logging, or use the namei " "fileserver backend. Aborting...\n", part); return -1; } #ifndef AFS_AIX32_ENV if (programType == fileServer) { char salvpath[MAXPATHLEN]; strcpy(salvpath, part); strcat(salvpath, "/FORCESALVAGE"); if (afs_stat(salvpath, &status) == 0) { Log("VInitVnodes: Found %s; aborting\n", salvpath); return -1; } } #endif #if !defined(AFS_LINUX20_ENV) && !defined(AFS_NT40_ENV) strcpy(AFSIDatPath, part); strcat(AFSIDatPath, "/AFSIDat"); #ifdef AFS_NAMEI_ENV if (afs_stat(AFSIDatPath, &status) < 0) { DIR *dirp; struct dirent *dp; dirp = opendir(part); opr_Assert(dirp); while ((dp = readdir(dirp))) { if (dp->d_name[0] == 'V') { Log("This program is compiled with AFS_NAMEI_ENV, but partition %s seems to contain volumes which don't use the namei-interface; aborting\n", part); closedir(dirp); return -1; } } closedir(dirp); } #else /* AFS_NAMEI_ENV */ if (afs_stat(AFSIDatPath, &status) == 0) { Log("This program is compiled without AFS_NAMEI_ENV, but partition %s seems to contain volumes which use the namei-interface; aborting\n", part); return -1; } #ifdef AFS_SGI_XFS_IOPS_ENV if (VerifyXFSInodeSize(part, status.st_fstype) < 0) return -1; #endif #endif /* AFS_NAMEI_ENV */ #endif /* !AFS_LINUX20_ENV && !AFS_NT40_ENV */ VInitPartition(part, devname, status.st_dev); return 0; }